From 97d9b0f61e7c2fd22e0a2e9dae650a9f815422ec Mon Sep 17 00:00:00 2001 From: Toyibat Adele Date: Mon, 19 May 2025 23:20:40 +0100 Subject: [PATCH 01/16] docs: updated documentation for MVC component. --- docs/index.rst | 1 + docs/plugins/mvc.rst | 635 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 636 insertions(+) create mode 100644 docs/plugins/mvc.rst diff --git a/docs/index.rst b/docs/index.rst index df41b368..a2f03eaf 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -123,6 +123,7 @@ There are several ways to support Mautic other than contributing with code. plugins/translations plugins/continuous-integration plugins/from-4-to-5 + plugins/mvc .. toctree:: :maxdepth: 2 diff --git a/docs/plugins/mvc.rst b/docs/plugins/mvc.rst new file mode 100644 index 00000000..2188d253 --- /dev/null +++ b/docs/plugins/mvc.rst @@ -0,0 +1,635 @@ +MVC +### + +Mautic uses a **Model-View-Controller (MVC)** structure to manage how users interact with the frontend (**views**) and how those interactions are handled by the backend (**controllers and models**). Additionally, **Entity** and **Repository** classes are used to manage interactions with the database. + +In Symfony — and therefore in Mautic — the **controller** is the central part of the MVC structure. When a user makes a request, the route determines which controller method is executed. The controller then interacts with the **model** to retrieve or manipulate data, and finally renders a **view** to display the results to the user. + +Controllers +=========== +Matching Routes to controller methods +------------------------------------- + +The controller method called is determined by the route defined in the config. Take this example: + +.. code-block:: php + + 'plugin_helloworld_admin' => array( + 'path' => '/hello/admin', + 'controller' => 'HelloWorldBundle:Default:admin' + ), + +The controller is noted as ``HelloWorldBundle:Default:admin``. Broken down, that translates to: + +- ``HelloWorldBundle`` → ``\MauticPlugin\HelloWorldBundle\Controller`` +- ``Default`` → ``DefaultController`` +- ``admin`` → ``adminAction()`` + +Controller notation follows the format: :: + + BundleName:ControllerName:controllerMethod + +To use a controller within a subfolder of ``Controller``, use this format: :: + + BundleName:Subdirectory\ControllerName:controllerMethod + +Thus, when a browser calls up ``/hello/admin``, ``\MauticPlugin\HelloWorldBundle\Controller\DefaultController::adminAction()`` will be called. + +Route placeholders +------------------ + +Symfony automatically passes route placeholders into the controller’s method as arguments. The method’s parameters must match the placeholder names. + +Example: + +.. code-block:: php + + 'plugin_helloworld_world' => array( + 'path' => '/hello/{world}', + 'controller' => 'HelloWorldBundle:Default:world', + 'defaults' => array( + 'world' => 'earth' + ), + 'requirements' => array( + 'world' => 'earth|mars' + ) + ), + +The matching method: + +.. code-block:: php + + public function worldAction($world = 'earth') + +Notice: Since the route defines a default for ``world``, the controller method must also reflect this default. + +If the route looked like this instead: + +.. code-block:: php + + 'plugin_helloworld_world' => array( + 'path' => '/hello/{world}', + 'controller' => 'HelloWorldBundle:Default:world', + 'requirements' => array( + 'world' => 'earth|mars' + ) + ), + +Then the method must be: + +.. code-block:: php + + public function worldAction($world) + +Extending Mautic’s Controllers +------------------------------ + +Mautic has several controllers that provide some helper functions. + +``Mautic\CoreBundle\Controller\CommonController`` +------------------------------------------------- + +Controllers extending this will make ``MauticFactory`` available via ``$this->factory`` and ``Request`` via ``$this->request``. + +It also provides the following helper methods: + +**delegateView($args)** +Mautic is ajax driven and thus must support both http requests and ajax requests for content. +``delegateView`` is a wrapper method that determines if the request is for ajax content or the full DOM, then generates and returns the appropriate response. + +The ``$args`` argument is an array with the required elements for generating the view, ajax or http. +It will accept the following parameters: + +.. list-table:: Parameters for ``delegateView()`` + :widths: 20 10 10 60 + :header-rows: 1 + + * - Key + - Required + - Type + - Description + * - contentTemplate + - REQUIRED + - string + - Defines the view template to load. This should be in view notation of ``BundleName:ViewName:template.html.php``. Refer to views for more info. + * - viewParameters + - OPTIONAL + - array + - Array of variables with values made available to the template. Each key will be a variable available to the template. + * - passthroughVars + - OPTIONAL + - array + - Array of variables returned as part of the ajax response used by Mautic and/or the plugin’s onLoad JS callback. + +Due to the use of ajax, there are some elements of the ``passthroughVars`` array that Mautic will use internally to manipulate the user interface. +For responses that include main content (i.e., routes a user would click to), you should set at least ``activeLink`` and ``route``. + +.. list-table:: Common passthroughVars + :widths: 20 10 10 60 + :header-rows: 1 + + * - Key + - Required + - Type + - Description + * - activeLink + - OPTIONAL + - string + - The ID of the menu item that should be activated dynamically to match ajax response. + * - route + - OPTIONAL + - string + - The route that should be pushed to the browser’s address bar to match ajax response. + * - mauticContent + - OPTIONAL + - string + - Used to generate the JS method to call after ajax content is injected into the DOM. If set as ``helloWorldDetails``, Mautic will check for and execute ``Mautic.helloWorldDetailsOnLoad()``. + * - callback + - OPTIONAL + - string + - A Mautic namespaced JS function executed before response is injected. If set, Mautic passes the response to this function and does not process content. + * - redirect + - OPTIONAL + - string + - The URL to force a page redirect instead of injecting ajax content. + * - target + - OPTIONAL + - string + - jQuery selector to inject the content into. Defaults to app’s main content selector. + * - replaceContent + - OPTIONAL + - string + - If set to `'true'`, Mautic will replace the target selector with ajax content. + +**delegateRedirect($url)** +Delegates the appropriate response for redirects. +If ajax request: returns a json response with ``{redirect: $url}``. +If http request: performs a standard redirect header. + +**postActionRedirect($args)** +Similar to ``delegateView()``, but used after an action like saving a form. +Accepts the same ``$args`` as ``delegateView()``, plus: + +.. list-table:: Additional Parameters for ``postActionRedirect()`` + :widths: 20 10 10 60 + :header-rows: 1 + + * - Key + - Required + - Type + - Description + * - returnUrl + - OPTIONAL + - string + - URL to redirect to. Defaults to ``/s/dashboard``. Auto-populates ``passthroughVars[route]`` if not set. + * - flashes + - OPTIONAL + - array + - Array of flash messages to display after redirecting. + * - forwardController + - OPTIONAL + - bool + - If true (default), forwards to a controller method. If false, directly loads a view template. + + +FormController +-------------- + +Extends ``CommonController``. + +``Mautic\CoreBundle\Controller\FormController``. This controller extends ``CommonController`` and provides helper methods for managing forms :doc:`Forms `. + +.. code-block:: php + + getModel('helloworld.world'); + + // Retrieve details about the world + $worldDetails = $model->getWorldDetails($world); + + return $this->delegateView( + array( + 'viewParameters' => array( + 'world' => $world, + 'details' => $worldDetails + ), + 'contentTemplate' => 'HelloWorldBundle:World:details.html.php', + 'passthroughVars' => array( + 'activeLink' => 'plugin_helloworld_world', + 'route' => $this->generateUrl('plugin_helloworld_world', array('world' => $world)), + 'mauticContent' => 'helloWorldDetails' + ) + ) + ); + } + + /** + * Contact form + * + * @return JsonResponse|\Symfony\Component\HttpFoundation\Response + */ + public function contactAction() + { + // Create the form object + $form = $this->get('form.factory')->create('helloworld_contact'); + + // Handle form submission if POST + if ($this->request->getMethod() == 'POST') { + $flashes = array(); + + // isFormCancelled() checks if the cancel button was clicked + if ($cancelled = $this->isFormCancelled($form)) { + + // isFormValid() will bind the request to the form object and validate the data + if ($valid = $this->isFormValid($form)) { + + /** @var \MauticPlugin\HelloWorldBundle\Model\ContactModel $model */ + $model = $this->getModel('helloworld.contact'); + + // Send the email + $model->sendContactEmail($form->getData()); + + // Set success flash message + $flashes[] = array( + 'type' => 'notice', + 'msg' => 'plugin.helloworld.notice.thank_you', + 'msgVars' => array( + '%name%' => $form['name']->getData() + ) + ); + } + } + + if ($cancelled || $valid) { + // Redirect to /hello/world + + return $this->postActionRedirect( + array( + 'returnUrl' => $this->generateUrl('plugin_helloworld_world'), + 'contentTemplate' => 'HelloWorldBundle:Default:world', + 'flashes' => $flashes + ) + ); + } // Otherwise show the form again with validation error messages + } + + // Display the form + return $this->delegateView( + array( + 'viewParameters' => array( + 'form' => $form->createView() + ), + 'contentTemplate' => 'HelloWorldBundle:Contact:form.html.php', + 'passthroughVars' => array( + 'activeLink' => 'plugin_helloworld_contact', + 'route' => $this->generateUrl('plugin_helloworld_contact') + ) + ) + ); + } + } + + +AjaxController +-------------- + +``Mautic\CoreBundle\Controller\AjaxController``. This controller also extends ``CommonController`` and is a companion to some of the built-in Javascript helpers. See *Javascript methods* for more information. + +Models +====== + +Models are used to retrieve and process data between controllers and views. While not required in plugins, Mautic provides convenient ways to access model objects and use commonly needed methods if you choose to use them. + +Model Example +------------- + +.. code-block:: php + + mailer; + + $mailer->message->addTo( + $this->factory->getParameter('mailer_from_email') + ); + + $this->message->setFrom( + array($data['email'] => $data['name']) + ); + + $mailer->message->setSubject($data['subject']); + + $mailer->message->setBody($data['message']); + + $mailer->send(); + } + } + +Registering Model Classes +------------------------- + +Models should be registered as model services. The service name must follow the format: + +``mautic.UNIQUE_BUNDLE_IDENTIFIER.model.MODEL_IDENTIFIER`` + +- ``UNIQUE_BUNDLE_IDENTIFIER``: Any unique name for your plugin or bundle +- ``MODEL_IDENTIFIER``: A name unique within the bundle + +For example, the model shown above could be registered as: + +``mautic.helloworld.model.contact`` + +This allows Mautic’s helper functions to retrieve the model using the `getModel()` method. + +Base Model Classes +------------------ + +You can extend either of the following base classes to make use of Mautic's helper methods: + +**\Mautic\CoreBundle\Model\AbstractCommonModel** + +This base class offers access to services commonly used in models: + +.. list-table:: + :header-rows: 1 + + * - Property + - Service + - Description + * - ``$this->factory`` + - Factory service + - Provides access to other Mautic services. *Deprecated as of Mautic 2.0*; use dependency injection instead. + * - ``$this->em`` + - Entity manager + - Handles database interactions via Doctrine. + * - ``$this->security`` + - Security service + - Provides access to the current user and permission checks. + * - ``$this->dispatcher`` + - Event dispatcher + - Dispatches and listens for Mautic events. + * - ``$this->translator`` + - Translator service + - Handles language translations. + + +**\Mautic\CoreBundle\Model\FormModel** + +This extends ``AbstractCommonModel`` and includes helper methods for working with entities and repositories. For more information, see the :doc:`Database ` section. + +Getting Model Objects +--------------------- + +To retrieve a model object in a controller: + +.. code-block:: php + + getModel('lead'); // Shortcut for lead.lead + + /** @var \Mautic\LeadBundle\Model\ListModel $leadListModel */ + $leadListModel = $this->getModel('lead.list'); + + /** @var \MauticPlugin\HelloWorldBundle\Model\ContactModel $contactModel */ + $contactModel = $this->getModel('helloworld.contact'); + +If using a model inside another service or model, inject the model service as a dependency instead of using the helper method. + +Views +===== + +Views in Mautic take data passed from the Controller and display it to the user. Templates can be rendered from within controllers or other templates. + +Example Template Files +---------------------- + +**`details.html.php`** + +.. code-block:: php + + // plugins/HelloWorldBundle/Views/World/details.html.php + + if (!$app->getRequest()->isXmlHttpRequest()) { + $view['slots']->set('tmpl', 'Details'); + $view->extend('HelloWorldBundle:World:index.html.php'); + } + +
+ +
+ +**`index.html.php`** + +.. code-block:: php + + // plugins/HelloWorldBundle/Views/World/index.html.php + + $view->extend('MauticCoreBundle:Default:content.html.php'); + + $tmpl = $view['slots']->get('tmpl', 'Details'); + + $view['slots']->set('mauticContent', 'helloWorld' . $tmpl); + + $header = ($tmpl == 'World') + ? $view['translator']->trans( + 'plugin.helloworld.worlds', + array('%world%' => ucfirst($world)) + ) : $view['translator']->trans('plugin.helloworld.manage_worlds'); + $view['slots']->set('headerTitle', $header); + +
+ output('_content'); ?> +
+ +View Notation +------------- + +View templates follow this format: + +.. code-block:: text + + BundleName:ViewName:template.html.php + +Nested views can be referenced using backslashes: + +.. code-block:: text + + BundleName:ViewName\Subfolder:template.html.php + +Rendering Views +--------------- + +Use the Controller’s ``delegateView()`` method with the ``contentTemplate`` key to render a view. Variables passed in ``viewParameters`` become available in the template: + +.. code-block:: php + + 'viewParameters' => array( + 'world' => 'mars' + ) + +This allows ``$world`` to be used in the view. + +Available View Variables +------------------------ + +- **$view** — Provides access to template helpers and rendering functions. +- **$app** — Provides access to the request and session. + +Extending Views +--------------- + +To extend Mautic’s base templates: + +.. code-block:: php + + $view->extend('MauticCoreBundle:Default:content.html.php'); + +For slim templates (no menu or header): + +.. code-block:: php + + $view->extend('MauticCoreBundle:Default:slim.html.php'); + +For Ajax requests, use: + +.. code-block:: php + + $app->getRequest()->isXmlHttpRequest() + +Templates render inside-out. So: + +1. `details.html.php` is rendered first. +2. Injected into `index.html.php`. +3. Finally into `content.html.php`. + +Use ``$view['slots']->output('_content');`` to include sub-template content. + +Rendering Views Within Views +---------------------------- + +You can render one view inside another: + +.. code-block:: php + + echo $view->render('BundleName:ViewName:template.html.php', array('parameter' => 'value')); + +Template Helpers +================ + +Slots Helper +------------ + +.. code-block:: php + + $view['slots']->set('name', 'content'); + $view['slots']->append('name', ' more content'); + $content = $view['slots']->get('name', 'default'); + $view['slots']->output('name'); + +Asset Helper +------------ + +.. code-block:: php + + echo ''; + echo $view['assets']->includeScript('plugins/HelloWorldBundle/assets/helloworld.js'); + echo $view['assets']->includeStylesheet('plugins/HelloWorldBundle/assets/helloworld.css'); + +Router Helper +------------- + +.. code-block:: php + + Mars + +Translation Helper +------------------ + +.. code-block:: php + +

trans('plugin.helloworld.worlds', array('%world%' => 'Mars')); ?>

+ +Date Helper +----------- + +.. code-block:: php + + $datetime = '2015-04-12 20:56:00'; + $view['date']->toFull($datetime); + $view['date']->toShort($datetime); + $view['date']->toDate($datetime); + $view['date']->toTime($datetime); + $view['date']->toFullConcat($datetime); + $view['date']->toText($datetime); + $view['date']->toFull($datetime, 'Y-m-d H:i:s', 'UTC'); + +Form Helper +----------- + +.. code-block:: php + + form($form); ?> + +Ajax Integration +============ + +Ajax Links +---------- + +.. code-block:: php + + Mars + +Ajax Modals +----------- + +.. code-block:: php + + + Mars + + +Ajax Forms +---------- + +Forms rendered with Symfony form services are auto-ajaxified. + + From 5b0b900f8e8bcde882d172d9eacac12f645d5af3 Mon Sep 17 00:00:00 2001 From: Toyibat Adele Date: Mon, 26 May 2025 01:05:35 +0100 Subject: [PATCH 02/16] docs: Made changes to the documentation for MVC component. --- docs/plugins/mvc.rst | 509 +++++++++++++++++++++++++++++++------------ 1 file changed, 364 insertions(+), 145 deletions(-) diff --git a/docs/plugins/mvc.rst b/docs/plugins/mvc.rst index 2188d253..77410da4 100644 --- a/docs/plugins/mvc.rst +++ b/docs/plugins/mvc.rst @@ -1,16 +1,16 @@ MVC ### -Mautic uses a **Model-View-Controller (MVC)** structure to manage how users interact with the frontend (**views**) and how those interactions are handled by the backend (**controllers and models**). Additionally, **Entity** and **Repository** classes are used to manage interactions with the database. +Mautic uses a **Model-View-Controller (MVC)** structure to manage how users interact with the frontend (**views**) and how the backend handles those interactions (**controllers and models**). Additionally, **Entity** and **Repository** classes manage interactions with the database. -In Symfony — and therefore in Mautic — the **controller** is the central part of the MVC structure. When a user makes a request, the route determines which controller method is executed. The controller then interacts with the **model** to retrieve or manipulate data, and finally renders a **view** to display the results to the user. +In Symfony, and thus Mautic the **controller** is the central part of the MVC structure. The route determines which controller method executes when a user makes a request. The controller then interacts with the **model** to retrieve or manipulate data, and finally renders a **view** to display the results to the user. Controllers =========== Matching Routes to controller methods ------------------------------------- -The controller method called is determined by the route defined in the config. Take this example: +The :ref:`route defined in the config` determines which controller method is called. Take this example: .. code-block:: php @@ -19,19 +19,18 @@ The controller method called is determined by the route defined in the config. T 'controller' => 'HelloWorldBundle:Default:admin' ), -The controller is noted as ``HelloWorldBundle:Default:admin``. Broken down, that translates to: +The system identifies the controller as``HelloWorldBundle:Default:admin``. Broken down, that translates to: - ``HelloWorldBundle`` → ``\MauticPlugin\HelloWorldBundle\Controller`` - ``Default`` → ``DefaultController`` - ``admin`` → ``adminAction()`` -Controller notation follows the format: :: +.. note:: - BundleName:ControllerName:controllerMethod + Controller notation follows the format ``BundleName:ControllerName:controllerMethod.`` -To use a controller within a subfolder of ``Controller``, use this format: :: + To use a controller within a subfolder of ``Controller``, use this format ``BundleName:Subdirectory\\ControllerName:controllerMethod`` - BundleName:Subdirectory\ControllerName:controllerMethod Thus, when a browser calls up ``/hello/admin``, ``\MauticPlugin\HelloWorldBundle\Controller\DefaultController::adminAction()`` will be called. @@ -61,7 +60,9 @@ The matching method: public function worldAction($world = 'earth') -Notice: Since the route defines a default for ``world``, the controller method must also reflect this default. +.. note:: + + Since the route defines a default for ``world``, the controller method must also reflect this default. If the route looked like this instead: @@ -81,24 +82,24 @@ Then the method must be: public function worldAction($world) -Extending Mautic’s Controllers +Extending Mautic’s controllers ------------------------------ Mautic has several controllers that provide some helper functions. -``Mautic\CoreBundle\Controller\CommonController`` -------------------------------------------------- +1. CommonController (``Mautic\CoreBundle\Controller\CommonController``) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Controllers extending this will make ``MauticFactory`` available via ``$this->factory`` and ``Request`` via ``$this->request``. +Controllers extending this makes ``MauticFactory`` available via ``$this->factory`` and ``Request`` via ``$this->request``. It also provides the following helper methods: -**delegateView($args)** -Mautic is ajax driven and thus must support both http requests and ajax requests for content. -``delegateView`` is a wrapper method that determines if the request is for ajax content or the full DOM, then generates and returns the appropriate response. +delegateView($args) +^^^^^^^^^^^^^^^^^^^ + +Mautic is AJAX-driven, so it must support both standard http and AJAX requests. The ``delegateView`` method acts as a wrapper that detects the request type and returns the appropriate response—either a full DOM for http or a partial one for AJAX. -The ``$args`` argument is an array with the required elements for generating the view, ajax or http. -It will accept the following parameters: +The ``$args`` array contains the required elements for generating either type of response. It accepts the following parameters: .. list-table:: Parameters for ``delegateView()`` :widths: 20 10 10 60 @@ -108,21 +109,22 @@ It will accept the following parameters: - Required - Type - Description - * - contentTemplate + * - ``contentTemplate`` - REQUIRED - string - - Defines the view template to load. This should be in view notation of ``BundleName:ViewName:template.html.php``. Refer to views for more info. - * - viewParameters + - Defines the view template to load. This should be in view notation of ``BundleName:ViewName:template.html.php``. Refer to :ref:`Views` for more info. + * - ``viewParameters`` - OPTIONAL - array - - Array of variables with values made available to the template. Each key will be a variable available to the template. - * - passthroughVars + - Array of variables with values made available to the template. Each key becomes a variable available to the template. + * - ``passthroughVars`` - OPTIONAL - array - - Array of variables returned as part of the ajax response used by Mautic and/or the plugin’s onLoad JS callback. + - Array of variables returned as part of the AJAX response used by Mautic and/or the Plugin’s onLoad JS callback. + +Due to the use of AJAX, Mautic uses some elements of the ``passthroughVars`` array to manipulate the user interface. -Due to the use of ajax, there are some elements of the ``passthroughVars`` array that Mautic will use internally to manipulate the user interface. -For responses that include main content (i.e., routes a user would click to), you should set at least ``activeLink`` and ``route``. +For responses that include main content (for example, routes a user would click to), you should set at least ``activeLink`` and ``route``. .. list-table:: Common passthroughVars :widths: 20 10 10 60 @@ -132,26 +134,26 @@ For responses that include main content (i.e., routes a user would click to), yo - Required - Type - Description - * - activeLink + * - ``activeLink`` - OPTIONAL - string - - The ID of the menu item that should be activated dynamically to match ajax response. + - Sets the ID of the menu item that Mautic should activate dynamically to match the AJAX response. * - route - OPTIONAL - string - - The route that should be pushed to the browser’s address bar to match ajax response. - * - mauticContent + - This pushes the route to the browser’s address bar to match AJAX response. + * - ``mauticContent`` - OPTIONAL - string - - Used to generate the JS method to call after ajax content is injected into the DOM. If set as ``helloWorldDetails``, Mautic will check for and execute ``Mautic.helloWorldDetailsOnLoad()``. + - It generates the JS method to call after Mautic injects AJAX content into the DOM. If set as ``helloWorldDetails``, Mautic checks for and execute ``Mautic.helloWorldDetailsOnLoad()``. * - callback - OPTIONAL - string - - A Mautic namespaced JS function executed before response is injected. If set, Mautic passes the response to this function and does not process content. + - Mautic executes a namespaced JS function before injecting the response. If set, Mautic passes the response to this function and does not process content. * - redirect - OPTIONAL - string - - The URL to force a page redirect instead of injecting ajax content. + - The URL to force a page redirect instead of injecting AJAX content. * - target - OPTIONAL - string @@ -159,16 +161,20 @@ For responses that include main content (i.e., routes a user would click to), yo * - replaceContent - OPTIONAL - string - - If set to `'true'`, Mautic will replace the target selector with ajax content. + - If set to `'true'`, Mautic replaces the target selector with AJAX content. + +delegateRedirect($url) +^^^^^^^^^^^^^^^^^^^^^^ + +Delegates the appropriate response for redirects. -**delegateRedirect($url)** -Delegates the appropriate response for redirects. -If ajax request: returns a json response with ``{redirect: $url}``. -If http request: performs a standard redirect header. +- **If AJAX request**: returns a json response with ``{redirect: $url}``. +- **If http request**: performs a standard redirect header. -**postActionRedirect($args)** -Similar to ``delegateView()``, but used after an action like saving a form. -Accepts the same ``$args`` as ``delegateView()``, plus: +postActionRedirect($args) +^^^^^^^^^^^^^^^^^^^^^^^^^ + +Similar to ``delegateView()``, but used after an action like saving a Form. Accepts the same ``$args`` as ``delegateView()``, plus: .. list-table:: Additional Parameters for ``postActionRedirect()`` :widths: 20 10 10 60 @@ -178,26 +184,24 @@ Accepts the same ``$args`` as ``delegateView()``, plus: - Required - Type - Description - * - returnUrl + * - ``returnUrl`` - OPTIONAL - string - URL to redirect to. Defaults to ``/s/dashboard``. Auto-populates ``passthroughVars[route]`` if not set. * - flashes - OPTIONAL - array - - Array of flash messages to display after redirecting. - * - forwardController + - Array of flash messages to display after redirecting. See :doc:`Flash Messages ` for more information. + * - ``forwardController`` - OPTIONAL - bool - - If true (default), forwards to a controller method. If false, directly loads a view template. - + - If true (default), forwards to a controller method (``BundleName:ControllerName:method``). Set to ``false`` to load a view template (``BundleName:ViewName:template.html.php``) directly. -FormController --------------- -Extends ``CommonController``. +2. FormController (``Mautic\CoreBundle\Controller\FormController``) +------------------------------------------------------------------- -``Mautic\CoreBundle\Controller\FormController``. This controller extends ``CommonController`` and provides helper methods for managing forms :doc:`Forms `. +This controller extends ``CommonController`` and provides helper methods for managing :doc:`Forms `. .. code-block:: php @@ -308,17 +312,17 @@ Extends ``CommonController``. } -AjaxController --------------- +3. AjaxController (``Mautic\CoreBundle\Controller\AjaxController``) +------------------------------------------------------------------- -``Mautic\CoreBundle\Controller\AjaxController``. This controller also extends ``CommonController`` and is a companion to some of the built-in Javascript helpers. See *Javascript methods* for more information. +This controller also extends ``CommonController`` and is a companion to some of the built-in JavaScript helpers. See *JavaScript methods* for more information. Models ====== -Models are used to retrieve and process data between controllers and views. While not required in plugins, Mautic provides convenient ways to access model objects and use commonly needed methods if you choose to use them. +Models retrieve and process data between controllers and views. While not required in Plugins, Mautic provides convenient ways to access model objects and use commonly needed methods if you choose to use them. -Model Example +Model example ------------- .. code-block:: php @@ -360,15 +364,14 @@ Model Example Registering Model Classes ------------------------- - -Models should be registered as model services. The service name must follow the format: +Register Models as ``model`` :ref:`services`. The service name must follow the format: ``mautic.UNIQUE_BUNDLE_IDENTIFIER.model.MODEL_IDENTIFIER`` -- ``UNIQUE_BUNDLE_IDENTIFIER``: Any unique name for your plugin or bundle -- ``MODEL_IDENTIFIER``: A name unique within the bundle +- ``UNIQUE_BUNDLE_IDENTIFIER``: any unique name for your Plugin or bundle +- ``MODEL_IDENTIFIER``: a name unique within the bundle -For example, the model shown above could be registered as: +Register the model in the preceding example as:" ``mautic.helloworld.model.contact`` @@ -379,7 +382,8 @@ Base Model Classes You can extend either of the following base classes to make use of Mautic's helper methods: -**\Mautic\CoreBundle\Model\AbstractCommonModel** +1. AbstractCommonModel (``\Mautic\CoreBundle\Model\AbstractCommonModel``) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This base class offers access to services commonly used in models: @@ -406,7 +410,8 @@ This base class offers access to services commonly used in models: - Handles language translations. -**\Mautic\CoreBundle\Model\FormModel** +2. FormModel (``\Mautic\CoreBundle\Model\FormModel``) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ This extends ``AbstractCommonModel`` and includes helper methods for working with entities and repositories. For more information, see the :doc:`Database ` section. @@ -433,203 +438,417 @@ If using a model inside another service or model, inject the model service as a Views ===== -Views in Mautic take data passed from the Controller and display it to the user. Templates can be rendered from within controllers or other templates. +Views in Mautic take data passed from the controller and display it to the user. You can render templates from within controllers or other templates. -Example Template Files ----------------------- +The controller uses the ``delegateView()`` method to render views, which relies on the ``contentTemplate`` to determine which view to render. + +View notation follows this format: + +.. code-block:: none + + BundleName:ViewName:template.html.php + +For example, ``HelloWorldBundle:Contact:form.html.php`` points to the file ``/path/to/mautic/plugins/HelloWorldBundle/Views/Contact/form.html.php`` + +To use views inside subfolders under ``Views``, use backslash notation: + +.. code-block:: none + + BundleName:ViewName\Subfolder:template.html.php + +View parameters +--------------- + +The array passed as ``viewParameters`` in the controller’s ``delegateView()`` method becomes available as variables in the view. + +For example, if the controller passes: + +.. code-block:: php + + 'viewParameters' => array( + 'world' => 'mars' + ), + +Then the variable ``$world`` becomes available in the template with the value ``mars``. + +Some variables are always available and shouldn't be overridden: + +- ``$view``: contains helper objects for extending or rendering templates. +- ``$app``: provides access to request and session objects via ``$app->getRequest()`` and ``$app->getSession()``. + +Extending Views +--------------- + +Views commonly extend base templates to provide consistent layout and AJAX support. + +Example: + +.. code-block:: php -**`details.html.php`** + // Extends full document with menu, header, etc. + $view->extend('MauticCoreBundle:Default:content.html.php'); + +Or extend a "slim" template with minimal markup: + +.. code-block:: php + + $view->extend('MauticCoreBundle:Default:content.html.php'); + +To detect if a request is an AJAX request, use: + +.. code-block:: php + + $app->getRequest()->isXmlHttpRequest() + +or pass this information from the controller via ``viewParameters``. + +.. note:: + + Template rendering is inside-out. The rendering process starts with the sub-template ``HelloWorldBundle:World:details.html.php``, which injects its content into ``HelloWorldBundle:World:index.html.php``, and then into the base template ``MauticCoreBundle:Default:content.html.php``. + +To output the content of the sub-template inside the parent, use: + +.. code-block:: php + + $view['slots']->output('_content'); + +See the :ref:`slots helper` for more information. + +Example code +------------ .. code-block:: php // plugins/HelloWorldBundle/Views/World/details.html.php + // Check if the request is Ajax if (!$app->getRequest()->isXmlHttpRequest()) { + + // Set tmpl for parent template $view['slots']->set('tmpl', 'Details'); + + // Extend index.html.php as the parent $view->extend('HelloWorldBundle:World:index.html.php'); } - + ?> +
-**`index.html.php`** - .. code-block:: php // plugins/HelloWorldBundle/Views/World/index.html.php + // Extend the base content $view->extend('MauticCoreBundle:Default:content.html.php'); + // Get tmpl from sub-template $tmpl = $view['slots']->get('tmpl', 'Details'); - $view['slots']->set('mauticContent', 'helloWorld' . $tmpl); + // Tell Mautic to call JS onLoad method + $view['slots']->set('mauticContent', 'helloWorld'.$tmpl); + // Set the page and header title $header = ($tmpl == 'World') ? $view['translator']->trans( 'plugin.helloworld.worlds', array('%world%' => ucfirst($world)) ) : $view['translator']->trans('plugin.helloworld.manage_worlds'); $view['slots']->set('headerTitle', $header); - + ?> +
output('_content'); ?>
-View Notation -------------- -View templates follow this format: +Rendering Views within Views +---------------------------- -.. code-block:: text +You can render one view inside another: - BundleName:ViewName:template.html.php +.. code-block:: php -Nested views can be referenced using backslashes: + echo $view->render('BundleName:ViewName:template.html.php', array('parameter' => 'value')); -.. code-block:: text +Template helpers +================ +There are a number of template helper objects and helper view templates built into Mautic. - BundleName:ViewName\Subfolder:template.html.php +Slots helper +------------ -Rendering Views ---------------- +The ``slots`` helper allows sub-templates to pass content up to parent templates. Since Mautic templates render *inside-out*, a sub-template can define slot content that the parent template can access. However, sub-templates don't have access to content defined in a parent template. -Use the Controller’s ``delegateView()`` method with the ``contentTemplate`` key to render a view. Variables passed in ``viewParameters`` become available in the template: +Setting slot content +~~~~~~~~~~~~~~~~~~~~ +Use ``set()`` to define the content of a slot. If the slot already exists, the new content overwrites the existing one. .. code-block:: php - 'viewParameters' => array( - 'world' => 'mars' - ) + // Set a slot with content + $view['slots']->set('name', 'the content'); -This allows ``$world`` to be used in the view. +Appending slot content +~~~~~~~~~~~~~~~~~~~~~~ -Available View Variables ------------------------- +Use ``append()`` to add to an existing slot rather than replacing its content. This is useful for aggregating content across templates. -- **$view** — Provides access to template helpers and rendering functions. -- **$app** — Provides access to the request and session. +.. code-block:: php -Extending Views ---------------- + // Append string content + $view['slots']->append('name', ' and more content'); + + // Append array content + $view['slots']->append('existingArray', array( + 'append' => 'me' + )); -To extend Mautic’s base templates: +Retrieving slot content +~~~~~~~~~~~~~~~~~~~~~~~ + +To get the content of a slot, use ``get()``. If the slot doesn't exist, you can define a default value. .. code-block:: php - $view->extend('MauticCoreBundle:Default:content.html.php'); + // Retrieve slot content or fallback to default + $content = $view['slots']->get('name', 'default value'); -For slim templates (no menu or header): +Outputting slot content +~~~~~~~~~~~~~~~~~~~~~~~ + +To output the slot content, use ``output()``. This is typically used in parent templates where you want to inject content from a sub-template. .. code-block:: php - $view->extend('MauticCoreBundle:Default:slim.html.php'); + // Render the slot content; no echo required + $view['slots']->output('name'); + +Checking slot existence +~~~~~~~~~~~~~~~~~~~~~~~ -For Ajax requests, use: +You can confirm if a slot exists using ``has()`` before performing actions on it. .. code-block:: php - $app->getRequest()->isXmlHttpRequest() + // Check if a slot is defined + if ($view['slots']->has('name')) { + // Perform some action + } -Templates render inside-out. So: +``slots`` are central to how Mautic handles nested views and dynamic content flow. Use them to build modular, reusable templates where the child view defines what's shown and the parent controls the layout. -1. `details.html.php` is rendered first. -2. Injected into `index.html.php`. -3. Finally into `content.html.php`. +Asset helper +------------ -Use ``$view['slots']->output('_content');`` to include sub-template content. +The ``assets`` helper, accessed via ``$view['assets']``, is used to load assets into the DOM including images, script and stylesheets. -Rendering Views Within Views ----------------------------- +..note:: -You can render one view inside another: + ``$view['assets']`` should always be used to ensure that assets work with Mautic installed in the web root, installed in a subdirectory, ran under the dev environment (index_dev.php), and/or ran under the prod environment. + +The asset helper also provides a way to insert scripts and stylesheets into the head for AJAX loaded content using ``$view['assets']->includeScript()`` and ``$view['assets']->includeStylesheet()``. + +Loading images +~~~~~~~~~~~~~~ + +Use ``getUrl()`` to generate the correct relative URL to an asset like an image. .. code-block:: php - echo $view->render('BundleName:ViewName:template.html.php', array('parameter' => 'value')); + // Generate relative URL to image + echo ''; -Template Helpers -================ +Inserting JavaScript +~~~~~~~~~~~~~~~~~~~~ -Slots Helper ------------- +Use ``includeScript()`` to dynamically insert a JavaScript file into the head. This is especially useful for AJAX-loaded views where scripts need to be re-injected. .. code-block:: php - $view['slots']->set('name', 'content'); - $view['slots']->append('name', ' more content'); - $content = $view['slots']->get('name', 'default'); - $view['slots']->output('name'); + // Dynamically insert script into head + echo $view['assets']->includeScript('plugins/HelloWorldBundle/assets/helloworld.js'); -Asset Helper ------------- +Inserting stylesheets +~~~~~~~~~~~~~~~~~~~~~ + +Use ``includeStylesheet()`` to dynamically include a CSS file into the head. .. code-block:: php - echo ''; - echo $view['assets']->includeScript('plugins/HelloWorldBundle/assets/helloworld.js'); + // Dynamically insert stylesheet into head echo $view['assets']->includeStylesheet('plugins/HelloWorldBundle/assets/helloworld.css'); -Router Helper +These methods ensure that your assets are properly handled regardless of Mautic’s installation location or environment. They also support dynamic inclusion for content loaded via AJAX. + + +Router helper ------------- +The ``router`` helper, accessed via ``$view['router']``, is used to generate URLs to named routes within views. + .. code-block:: php - Mars + Mars + +This generates a link to the route ``plugin_helloworld_world`` with the dynamic parameter ``world`` set to ``mars``. -Translation Helper +For more details on defining and using routes, see :doc:`Router `. + +Translation helper ------------------ +The ``translator`` helper, accessed via ``$view['translator']``, is used to translate strings within views using Mautic's translation system. + .. code-block:: php -

trans('plugin.helloworld.worlds', array('%world%' => 'Mars')); ?>

+

+ trans( + 'plugin.helloworld.worlds', + array('%world%' => 'Mars') + ); ?> +

+ +This example replaces the ``%world%`` placeholder with ``Mars``, and output the translated string. + +For more on how to handle translations, see :doc:`Translator `. -Date Helper +``$view['translator']`` follows the same conventions described in the Translator documentation, allowing dynamic, localized content in templates. + +Date helper ----------- +The ``date`` helper, accessed via ``$view['date']``, is used to format dates according to system and/or user settings. + .. code-block:: php + // Can be a string or \DateTime object. If a string, it's assumed to be in local time $datetime = '2015-04-12 20:56:00'; - $view['date']->toFull($datetime); - $view['date']->toShort($datetime); - $view['date']->toDate($datetime); - $view['date']->toTime($datetime); - $view['date']->toFullConcat($datetime); - $view['date']->toText($datetime); - $view['date']->toFull($datetime, 'Y-m-d H:i:s', 'UTC'); - -Form Helper + + // Format using full date-time format from system settings + $fullDateTime = $view['date']->toFull($datetime); + + // Format using short date-time format + $shortDateTime = $view['date']->toShort($datetime); + + // Format using date-only format + $date = $view['date']->toDate($datetime); + + // Format using time-only format + $time = $view['date']->toTime($datetime); + + // Combine date-only and time-only formats + $datetime = $view['date']->toFullConcat($datetime); + + // Format as relative time: 'Yesterday, 8:02 pm' or 'x days ago' + $text = $view['date']->toText($datetime); + + // Format a date string in a different timezone + $fullDateTime = $view['date']->toFull($datetime, 'Y-m-d H:i:s', 'UTC'); + +The first argument to each method can be a ``\DateTime`` object or a string formatted as ``Y-m-d H:i:s``. If the date is not already in local time, pass the expected format as the second argument and the timezone as the third. + +Form helper ----------- +The ``form`` helper, accessed via ``$view['form']``, is used to render form objects passed from the controller. + .. code-block:: php form($form); ?> -Ajax Integration -============ +This helper outputs the full HTML Form using the Form object (typically a Symfony Form) passed to the view. -Ajax Links +For detailed usage, see :doc:`Forms Mars +.. code-block:: html+php -Ajax Modals + + Mars + + +AJAX modals ----------- -.. code-block:: php +Mautic uses Bootstrap modals, but Bootstrap alone doesn't support dynamically retrieving content more than once. To address this, Mautic provides the ``data-toggle="ajaxmodal"`` attribute. - - Mars + data-header="trans('plugin.helloworld.worlds', ['%world%' => 'Mars']); ?>"> + Mars -Ajax Forms +- ``data-target`` should be the selector for the modal where content will be injected. Mautic provides a shared modal with the ID ``#MauticSharedModal``. +- ``data-header`` sets the modal’s title/header. + +AJAX forms ---------- +When using Symfony’s Form services, Mautic automatically enables AJAX the Form. No additional configuration is necessary. + +AJAX content callbacks +---------------------- -Forms rendered with Symfony form services are auto-ajaxified. +Mautic allows you to hook into the lifecycle of AJAX content injection via JavaScript callbacks. + +.. code-block:: javascript + + Mautic.helloWorldDetailsOnLoad = function(container, response) { + // Manipulate content after load + }; + + Mautic.helloWorldDetailsOnUnload = function(container, response) { + // Clean up or remove bindings before unloading + }; + +The system executes these callbacks when it injects or removes content via AJAX. This is useful for initializing dynamic components such as charts, inputs with autocomplete, or other JS-driven features. + +To use this feature, pass the ``mauticContent`` key through the controller's ``delegateView()`` method. For example, the method ``Mautic.helloWorldDetailsOnLoad()`` calls for the following: + +.. code-block:: php + + 'passthroughVars' => [ + 'activeLink' => 'plugin_helloworld_world', + 'route' => $this->generateUrl('plugin_helloworld_world', ['world' => $world]), + 'mauticContent' => 'helloWorldDetails' + ] + +Loading content triggers ``Mautic.helloWorldDetailsOnLoad()`` and ``Mautic.helloWorldDetailsOnUnload()`` when the user browses away from the page. It also gives the opportunity to destroy objects if necessary. + +Both callbacks receive two arguments: + +.. list-table:: + :widths: 20 80 + :header-rows: 1 + + * - Argument + - Description + * - ``container`` + - The selector used as the AJAX content target. + * - ``response`` + - The response object from the AJAX call (from ``passthroughVars``). + +Page refresh support +-------------------- + +Ensure the correct ``OnLoad`` function triggers on full page refresh by setting the ``mauticContent`` slot in the view using: + +.. code-block:: php + $view['slots']->set('mauticContent', 'helloWorldDetails'); From 830d715271643bc19182522aa28ea396705b3bfe Mon Sep 17 00:00:00 2001 From: Toyibat Adele Date: Tue, 2 Dec 2025 01:18:52 +0100 Subject: [PATCH 03/16] Updated the MVC section. --- docs/plugins/mvc.rst | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/docs/plugins/mvc.rst b/docs/plugins/mvc.rst index 77410da4..15abb8d8 100644 --- a/docs/plugins/mvc.rst +++ b/docs/plugins/mvc.rst @@ -362,21 +362,6 @@ Model example } } -Registering Model Classes -------------------------- -Register Models as ``model`` :ref:`services`. The service name must follow the format: - -``mautic.UNIQUE_BUNDLE_IDENTIFIER.model.MODEL_IDENTIFIER`` - -- ``UNIQUE_BUNDLE_IDENTIFIER``: any unique name for your Plugin or bundle -- ``MODEL_IDENTIFIER``: a name unique within the bundle - -Register the model in the preceding example as:" - -``mautic.helloworld.model.contact`` - -This allows Mautic’s helper functions to retrieve the model using the `getModel()` method. - Base Model Classes ------------------ From df6949a57cee4422eb51f5cb88418d60135c903c Mon Sep 17 00:00:00 2001 From: Ayu Adiati <45172775+adiati98@users.noreply.github.com> Date: Thu, 29 Jan 2026 09:14:27 +0100 Subject: [PATCH 04/16] update inline code and code-blocks Co-authored-by: John Linhart --- docs/plugins/mvc.rst | 123 ++++++++++++++++++------------------------- 1 file changed, 50 insertions(+), 73 deletions(-) diff --git a/docs/plugins/mvc.rst b/docs/plugins/mvc.rst index 15abb8d8..255da7bd 100644 --- a/docs/plugins/mvc.rst +++ b/docs/plugins/mvc.rst @@ -14,10 +14,10 @@ The :ref:`route defined in the config` determines which contro .. code-block:: php - 'plugin_helloworld_admin' => array( + 'plugin_helloworld_admin' => [ 'path' => '/hello/admin', - 'controller' => 'HelloWorldBundle:Default:admin' - ), + 'controller' => 'MauticPlugin\HelloWorldBundle\Controller\DefaultController:adminAction' + ], The system identifies the controller as``HelloWorldBundle:Default:admin``. Broken down, that translates to: @@ -43,22 +43,22 @@ Example: .. code-block:: php - 'plugin_helloworld_world' => array( + 'plugin_helloworld_world' => [ 'path' => '/hello/{world}', - 'controller' => 'HelloWorldBundle:Default:world', - 'defaults' => array( + 'controller' => 'MauticPlugin\HelloWorldBundle\Controller\DefaultController::worldAction', + 'defaults' => [ 'world' => 'earth' - ), - 'requirements' => array( + ], + 'requirements' => [ 'world' => 'earth|mars' - ) - ), + ] + ], The matching method: .. code-block:: php - public function worldAction($world = 'earth') + public function worldAction(string $world = 'earth') .. note:: @@ -68,19 +68,19 @@ If the route looked like this instead: .. code-block:: php - 'plugin_helloworld_world' => array( + 'plugin_helloworld_world' => [ 'path' => '/hello/{world}', - 'controller' => 'HelloWorldBundle:Default:world', - 'requirements' => array( + 'controller' => 'MauticPlugin\HelloWorldBundle\Controller\DefaultController::worldAction', + 'requirements' => [ 'world' => 'earth|mars' - ) - ), + ] + ], Then the method must be: .. code-block:: php - public function worldAction($world) + public function worldAction(string $world) Extending Mautic’s controllers ------------------------------ @@ -214,50 +214,35 @@ This controller extends ``CommonController`` and provides helper methods for man class DefaultController extends FormController { - /** - * Display the world view - * - * @param string $world - * - * @return JsonResponse|\Symfony\Component\HttpFoundation\Response - */ - public function worldAction($world = 'earth') + public function worldAction(string $world = 'earth', WorldModel $model): Response { - /** @var \MauticPlugin\HelloWorldBundle\Model\WorldModel $model */ - $model = $this->getModel('helloworld.world'); - // Retrieve details about the world $worldDetails = $model->getWorldDetails($world); return $this->delegateView( - array( - 'viewParameters' => array( + [ + 'viewParameters' => [ 'world' => $world, 'details' => $worldDetails - ), + ], 'contentTemplate' => 'HelloWorldBundle:World:details.html.php', - 'passthroughVars' => array( + 'passthroughVars' => [ 'activeLink' => 'plugin_helloworld_world', - 'route' => $this->generateUrl('plugin_helloworld_world', array('world' => $world)), + 'route' => $this->generateUrl('plugin_helloworld_world', ['world' => $world]), 'mauticContent' => 'helloWorldDetails' - ) - ) + ] + ] ); } - /** - * Contact form - * - * @return JsonResponse|\Symfony\Component\HttpFoundation\Response - */ - public function contactAction() + public function contactAction(ContactModel $model): Response { // Create the form object - $form = $this->get('form.factory')->create('helloworld_contact'); + $form = $this->formFactory->create(ContactFormType::class); // Handle form submission if POST if ($this->request->getMethod() == 'POST') { - $flashes = array(); + $flashes = []; // isFormCancelled() checks if the cancel button was clicked if ($cancelled = $this->isFormCancelled($form)) { @@ -265,20 +250,17 @@ This controller extends ``CommonController`` and provides helper methods for man // isFormValid() will bind the request to the form object and validate the data if ($valid = $this->isFormValid($form)) { - /** @var \MauticPlugin\HelloWorldBundle\Model\ContactModel $model */ - $model = $this->getModel('helloworld.contact'); - // Send the email $model->sendContactEmail($form->getData()); // Set success flash message - $flashes[] = array( + $flashes[] = [ 'type' => 'notice', 'msg' => 'plugin.helloworld.notice.thank_you', - 'msgVars' => array( + 'msgVars' => [ '%name%' => $form['name']->getData() - ) - ); + ] + ]; } } @@ -286,27 +268,27 @@ This controller extends ``CommonController`` and provides helper methods for man // Redirect to /hello/world return $this->postActionRedirect( - array( + [ 'returnUrl' => $this->generateUrl('plugin_helloworld_world'), - 'contentTemplate' => 'HelloWorldBundle:Default:world', + 'contentTemplate' => 'MauticPlugin\HelloWorldBundle\Controller\DefaultController:worldAction', 'flashes' => $flashes - ) + ] ); } // Otherwise show the form again with validation error messages } // Display the form return $this->delegateView( - array( - 'viewParameters' => array( + [ + 'viewParameters' => [ 'form' => $form->createView() ), - 'contentTemplate' => 'HelloWorldBundle:Contact:form.html.php', - 'passthroughVars' => array( + 'contentTemplate' => '@HelloWorld/Contact/form.html.twig', + 'passthroughVars' => [ 'activeLink' => 'plugin_helloworld_contact', 'route' => $this->generateUrl('plugin_helloworld_contact') - ) - ) + ] + ] ); } } @@ -334,20 +316,15 @@ Model example use Mautic\CoreBundle\Model\CommonModel; - class ContactModel extends CommonModel + final class ContactModel extends CommonModel { /** * Send contact email - * - * @param array $data */ - public function sendContactEmail($data) + public function sendContactEmail(array $data): void { - // Get mailer helper - pass the mautic.helper.mailer service as a dependency - $mailer = $this->mailer; - $mailer->message->addTo( - $this->factory->getParameter('mailer_from_email') + $this->coreParametersHelper->get('mailer_from_email') ); $this->message->setFrom( @@ -431,15 +408,15 @@ View notation follows this format: .. code-block:: none - BundleName:ViewName:template.html.php + @BundleName/ViewName/template.html.twig -For example, ``HelloWorldBundle:Contact:form.html.php`` points to the file ``/path/to/mautic/plugins/HelloWorldBundle/Views/Contact/form.html.php`` +For example, ``@HelloWorld/Contact/form.html.twig`` points to the file ``/path/to/mautic/plugins/HelloWorldBundle/Resources/views/Contact/form.html.twig`` -To use views inside subfolders under ``Views``, use backslash notation: +To use views inside subfolders under ``Resources/views``: .. code-block:: none - BundleName:ViewName\Subfolder:template.html.php + @BundleName/ViewName/Subfolder/template.html.twig View parameters --------------- @@ -450,9 +427,9 @@ For example, if the controller passes: .. code-block:: php - 'viewParameters' => array( + 'viewParameters' => [ 'world' => 'mars' - ), + ], Then the variable ``$world`` becomes available in the template with the value ``mars``. From b946e78fa6536b443a385759974d9f2de334d0b5 Mon Sep 17 00:00:00 2001 From: Ayu Adiati Date: Thu, 29 Jan 2026 10:01:38 +0100 Subject: [PATCH 05/16] fix: formats and heading levels --- docs/plugins/mvc.rst | 169 ++++++++++++++++++++++--------------------- 1 file changed, 86 insertions(+), 83 deletions(-) diff --git a/docs/plugins/mvc.rst b/docs/plugins/mvc.rst index 255da7bd..ca7c1f94 100644 --- a/docs/plugins/mvc.rst +++ b/docs/plugins/mvc.rst @@ -1,16 +1,17 @@ MVC ### -Mautic uses a **Model-View-Controller (MVC)** structure to manage how users interact with the frontend (**views**) and how the backend handles those interactions (**controllers and models**). Additionally, **Entity** and **Repository** classes manage interactions with the database. +Mautic uses a **Model-View-Controller - MVC** structure to manage how users interact with the frontend - **views** and how the backend handles those interactions - **controllers and models**. Additionally, **Entity** and **Repository** classes manage interactions with the database. -In Symfony, and thus Mautic the **controller** is the central part of the MVC structure. The route determines which controller method executes when a user makes a request. The controller then interacts with the **model** to retrieve or manipulate data, and finally renders a **view** to display the results to the user. +In Symfony, and thus Mautic, the **controller** is the central part of the MVC structure. The route determines which controller method executes when a user makes a request. The controller then interacts with the **model** to retrieve or manipulate data, and finally renders a **view** to display the results to the user. Controllers -=========== +*********** + Matching Routes to controller methods -------------------------------------- +===================================== -The :ref:`route defined in the config` determines which controller method is called. Take this example: +The :ref:`route defined in the config` determines which controller method is called. Take this example: .. code-block:: php @@ -31,11 +32,10 @@ The system identifies the controller as``HelloWorldBundle:Default:admin``. Broke To use a controller within a subfolder of ``Controller``, use this format ``BundleName:Subdirectory\\ControllerName:controllerMethod`` - Thus, when a browser calls up ``/hello/admin``, ``\MauticPlugin\HelloWorldBundle\Controller\DefaultController::adminAction()`` will be called. Route placeholders ------------------- +================== Symfony automatically passes route placeholders into the controller’s method as arguments. The method’s parameters must match the placeholder names. @@ -80,29 +80,31 @@ Then the method must be: .. code-block:: php - public function worldAction(string $world) + public function worldAction(string $world) Extending Mautic’s controllers ------------------------------- +============================== Mautic has several controllers that provide some helper functions. -1. CommonController (``Mautic\CoreBundle\Controller\CommonController``) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +\1. CommonController - ``Mautic\CoreBundle\Controller\CommonController`` +------------------------------------------------------------------------ Controllers extending this makes ``MauticFactory`` available via ``$this->factory`` and ``Request`` via ``$this->request``. -It also provides the following helper methods: +The ``CommonController`` also provides the following helper methods: -delegateView($args) -^^^^^^^^^^^^^^^^^^^ +1.1 ``delegateView($args)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ Mautic is AJAX-driven, so it must support both standard http and AJAX requests. The ``delegateView`` method acts as a wrapper that detects the request type and returns the appropriate response—either a full DOM for http or a partial one for AJAX. -The ``$args`` array contains the required elements for generating either type of response. It accepts the following parameters: +The ``$args`` array contains the required elements for generating either type of response. -.. list-table:: Parameters for ``delegateView()`` - :widths: 20 10 10 60 +It accepts the following parameters for ``delegateView()``: + +.. list-table:: + :widths: 20 20 20 40 :header-rows: 1 * - Key @@ -124,10 +126,10 @@ The ``$args`` array contains the required elements for generating either type of Due to the use of AJAX, Mautic uses some elements of the ``passthroughVars`` array to manipulate the user interface. -For responses that include main content (for example, routes a user would click to), you should set at least ``activeLink`` and ``route``. +For responses that include main content - for example, routes a user would click to - you should set at least ``activeLink`` and ``route``. -.. list-table:: Common passthroughVars - :widths: 20 10 10 60 +.. list-table:: Common ``passthroughVars`` + :widths: 20 20 20 40 :header-rows: 1 * - Key @@ -163,21 +165,21 @@ For responses that include main content (for example, routes a user would click - string - If set to `'true'`, Mautic replaces the target selector with AJAX content. -delegateRedirect($url) -^^^^^^^^^^^^^^^^^^^^^^ +1.2 ``delegateRedirect($url)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Delegates the appropriate response for redirects. -- **If AJAX request**: returns a json response with ``{redirect: $url}``. -- **If http request**: performs a standard redirect header. +* **If AJAX request**: returns a json response with ``{redirect: $url}``. +* **If http request**: performs a standard redirect header. -postActionRedirect($args) -^^^^^^^^^^^^^^^^^^^^^^^^^ +1.3 ``postActionRedirect($args)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Similar to ``delegateView()``, but used after an action like saving a Form. Accepts the same ``$args`` as ``delegateView()``, plus: .. list-table:: Additional Parameters for ``postActionRedirect()`` - :widths: 20 10 10 60 + :widths: 20 20 20 40 :header-rows: 1 * - Key @@ -198,8 +200,8 @@ Similar to ``delegateView()``, but used after an action like saving a Form. Acce - If true (default), forwards to a controller method (``BundleName:ControllerName:method``). Set to ``false`` to load a view template (``BundleName:ViewName:template.html.php``) directly. -2. FormController (``Mautic\CoreBundle\Controller\FormController``) -------------------------------------------------------------------- +\2. FormController - ``Mautic\CoreBundle\Controller\FormController`` +==================================================================== This controller extends ``CommonController`` and provides helper methods for managing :doc:`Forms `. @@ -294,18 +296,18 @@ This controller extends ``CommonController`` and provides helper methods for man } -3. AjaxController (``Mautic\CoreBundle\Controller\AjaxController``) -------------------------------------------------------------------- +\3. AjaxController - ``Mautic\CoreBundle\Controller\AjaxController`` +==================================================================== This controller also extends ``CommonController`` and is a companion to some of the built-in JavaScript helpers. See *JavaScript methods* for more information. Models -====== +****** Models retrieve and process data between controllers and views. While not required in Plugins, Mautic provides convenient ways to access model objects and use commonly needed methods if you choose to use them. Model example -------------- +============= .. code-block:: php @@ -340,16 +342,17 @@ Model example } Base Model Classes ------------------- +================== You can extend either of the following base classes to make use of Mautic's helper methods: -1. AbstractCommonModel (``\Mautic\CoreBundle\Model\AbstractCommonModel``) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +\1. AbstractCommonModel - ``\Mautic\CoreBundle\Model\AbstractCommonModel`` +-------------------------------------------------------------------------- This base class offers access to services commonly used in models: .. list-table:: + :widths: 25 25 50 :header-rows: 1 * - Property @@ -371,14 +374,13 @@ This base class offers access to services commonly used in models: - Translator service - Handles language translations. - -2. FormModel (``\Mautic\CoreBundle\Model\FormModel``) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +\2. FormModel - ``\Mautic\CoreBundle\Model\FormModel`` +------------------------------------------------------ This extends ``AbstractCommonModel`` and includes helper methods for working with entities and repositories. For more information, see the :doc:`Database ` section. -Getting Model Objects ---------------------- +Getting model objects +===================== To retrieve a model object in a controller: @@ -398,7 +400,7 @@ To retrieve a model object in a controller: If using a model inside another service or model, inject the model service as a dependency instead of using the helper method. Views -===== +***** Views in Mautic take data passed from the controller and display it to the user. You can render templates from within controllers or other templates. @@ -419,7 +421,7 @@ To use views inside subfolders under ``Resources/views``: @BundleName/ViewName/Subfolder/template.html.twig View parameters ---------------- +=============== The array passed as ``viewParameters`` in the controller’s ``delegateView()`` method becomes available as variables in the view. @@ -435,11 +437,11 @@ Then the variable ``$world`` becomes available in the template with the value `` Some variables are always available and shouldn't be overridden: -- ``$view``: contains helper objects for extending or rendering templates. -- ``$app``: provides access to request and session objects via ``$app->getRequest()`` and ``$app->getSession()``. +* ``$view``: contains helper objects for extending or rendering templates. +* ``$app``: provides access to request and session objects via ``$app->getRequest()`` and ``$app->getSession()``. -Extending Views ---------------- +Extending views +=============== Views commonly extend base templates to provide consistent layout and AJAX support. @@ -466,7 +468,7 @@ or pass this information from the controller via ``viewParameters``. .. note:: - Template rendering is inside-out. The rendering process starts with the sub-template ``HelloWorldBundle:World:details.html.php``, which injects its content into ``HelloWorldBundle:World:index.html.php``, and then into the base template ``MauticCoreBundle:Default:content.html.php``. + Template rendering is inside-out. The rendering process starts with the sub-template ``HelloWorldBundle:World:details.html.php``, which injects its content into ``HelloWorldBundle:World:index.html.php``, and then into the base template ``MauticCoreBundle:Default:content.html.php``. To output the content of the sub-template inside the parent, use: @@ -477,7 +479,7 @@ To output the content of the sub-template inside the parent, use: See the :ref:`slots helper` for more information. Example code ------------- +============ .. code-block:: php @@ -524,9 +526,8 @@ Example code output('_content'); ?> - -Rendering Views within Views ----------------------------- +Rendering views within views +============================ You can render one view inside another: @@ -535,16 +536,18 @@ You can render one view inside another: echo $view->render('BundleName:ViewName:template.html.php', array('parameter' => 'value')); Template helpers -================ +**************** + There are a number of template helper objects and helper view templates built into Mautic. Slots helper ------------- +============ The ``slots`` helper allows sub-templates to pass content up to parent templates. Since Mautic templates render *inside-out*, a sub-template can define slot content that the parent template can access. However, sub-templates don't have access to content defined in a parent template. Setting slot content -~~~~~~~~~~~~~~~~~~~~ +-------------------- + Use ``set()`` to define the content of a slot. If the slot already exists, the new content overwrites the existing one. .. code-block:: php @@ -553,7 +556,7 @@ Use ``set()`` to define the content of a slot. If the slot already exists, the n $view['slots']->set('name', 'the content'); Appending slot content -~~~~~~~~~~~~~~~~~~~~~~ +---------------------- Use ``append()`` to add to an existing slot rather than replacing its content. This is useful for aggregating content across templates. @@ -568,7 +571,7 @@ Use ``append()`` to add to an existing slot rather than replacing its content. T )); Retrieving slot content -~~~~~~~~~~~~~~~~~~~~~~~ +----------------------- To get the content of a slot, use ``get()``. If the slot doesn't exist, you can define a default value. @@ -578,7 +581,7 @@ To get the content of a slot, use ``get()``. If the slot doesn't exist, you can $content = $view['slots']->get('name', 'default value'); Outputting slot content -~~~~~~~~~~~~~~~~~~~~~~~ +----------------------- To output the slot content, use ``output()``. This is typically used in parent templates where you want to inject content from a sub-template. @@ -588,7 +591,7 @@ To output the slot content, use ``output()``. This is typically used in parent t $view['slots']->output('name'); Checking slot existence -~~~~~~~~~~~~~~~~~~~~~~~ +----------------------- You can confirm if a slot exists using ``has()`` before performing actions on it. @@ -602,18 +605,18 @@ You can confirm if a slot exists using ``has()`` before performing actions on it ``slots`` are central to how Mautic handles nested views and dynamic content flow. Use them to build modular, reusable templates where the child view defines what's shown and the parent controls the layout. Asset helper ------------- +============ The ``assets`` helper, accessed via ``$view['assets']``, is used to load assets into the DOM including images, script and stylesheets. -..note:: +.. note:: - ``$view['assets']`` should always be used to ensure that assets work with Mautic installed in the web root, installed in a subdirectory, ran under the dev environment (index_dev.php), and/or ran under the prod environment. + ``$view['assets']`` should always be used to ensure that assets work with Mautic installed in the web root, installed in a subdirectory, ran under the dev environment - ``index_dev.php`` - and/or ran under the prod environment. The asset helper also provides a way to insert scripts and stylesheets into the head for AJAX loaded content using ``$view['assets']->includeScript()`` and ``$view['assets']->includeStylesheet()``. Loading images -~~~~~~~~~~~~~~ +-------------- Use ``getUrl()`` to generate the correct relative URL to an asset like an image. @@ -623,7 +626,7 @@ Use ``getUrl()`` to generate the correct relative URL to an asset like an image. echo ''; Inserting JavaScript -~~~~~~~~~~~~~~~~~~~~ +-------------------- Use ``includeScript()`` to dynamically insert a JavaScript file into the head. This is especially useful for AJAX-loaded views where scripts need to be re-injected. @@ -633,7 +636,7 @@ Use ``includeScript()`` to dynamically insert a JavaScript file into the head. T echo $view['assets']->includeScript('plugins/HelloWorldBundle/assets/helloworld.js'); Inserting stylesheets -~~~~~~~~~~~~~~~~~~~~~ +--------------------- Use ``includeStylesheet()`` to dynamically include a CSS file into the head. @@ -644,9 +647,8 @@ Use ``includeStylesheet()`` to dynamically include a CSS file into the head. These methods ensure that your assets are properly handled regardless of Mautic’s installation location or environment. They also support dynamic inclusion for content loaded via AJAX. - Router helper -------------- +============= The ``router`` helper, accessed via ``$view['router']``, is used to generate URLs to named routes within views. @@ -662,7 +664,7 @@ This generates a link to the route ``plugin_helloworld_world`` with the dynamic For more details on defining and using routes, see :doc:`Router `. Translation helper ------------------- +================== The ``translator`` helper, accessed via ``$view['translator']``, is used to translate strings within views using Mautic's translation system. @@ -682,7 +684,7 @@ For more on how to handle translations, see :doc:`Translator form($form); ?> -This helper outputs the full HTML Form using the Form object (typically a Symfony Form) passed to the view. +This helper outputs the full HTML Form using the Form object - typically a Symfony Form - passed to the view. -For detailed usage, see :doc:`Forms `. AJAX integration -================ +**************** + Mautic provides several helpers and conventions for handling AJAX-driven UI features including links, modals, forms, and lifecycle callbacks. AJAX links ----------- +========== To enable AJAX for a link, set the attribute ``data-toggle="ajax"``. @@ -743,7 +746,7 @@ To enable AJAX for a link, set the attribute ``data-toggle="ajax"``. AJAX modals ------------ +=========== Mautic uses Bootstrap modals, but Bootstrap alone doesn't support dynamically retrieving content more than once. To address this, Mautic provides the ``data-toggle="ajaxmodal"`` attribute. @@ -756,15 +759,16 @@ Mautic uses Bootstrap modals, but Bootstrap alone doesn't support dynamically re Mars -- ``data-target`` should be the selector for the modal where content will be injected. Mautic provides a shared modal with the ID ``#MauticSharedModal``. -- ``data-header`` sets the modal’s title/header. +* ``data-target`` should be the selector for the modal where content will be injected. Mautic provides a shared modal with the ID ``#MauticSharedModal``. +* ``data-header`` sets the modal’s title/header. + +AJAX Forms +========== -AJAX forms ----------- When using Symfony’s Form services, Mautic automatically enables AJAX the Form. No additional configuration is necessary. AJAX content callbacks ----------------------- +====================== Mautic allows you to hook into the lifecycle of AJAX content injection via JavaScript callbacks. @@ -795,7 +799,7 @@ Loading content triggers ``Mautic.helloWorldDetailsOnLoad()`` and ``Mautic.hello Both callbacks receive two arguments: .. list-table:: - :widths: 20 80 + :widths: 25 75 :header-rows: 1 * - Argument @@ -806,11 +810,10 @@ Both callbacks receive two arguments: - The response object from the AJAX call (from ``passthroughVars``). Page refresh support --------------------- +==================== Ensure the correct ``OnLoad`` function triggers on full page refresh by setting the ``mauticContent`` slot in the view using: .. code-block:: php $view['slots']->set('mauticContent', 'helloWorldDetails'); - From f0f3d7a719167410c2a5e9bf401db8c23784b473 Mon Sep 17 00:00:00 2001 From: Ayu Adiati <45172775+adiati98@users.noreply.github.com> Date: Thu, 29 Jan 2026 12:42:17 +0100 Subject: [PATCH 06/16] remove sentence as there's no MauticFactory anymore Co-authored-by: John Linhart --- docs/plugins/mvc.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/plugins/mvc.rst b/docs/plugins/mvc.rst index 255da7bd..91f55b2f 100644 --- a/docs/plugins/mvc.rst +++ b/docs/plugins/mvc.rst @@ -90,7 +90,6 @@ Mautic has several controllers that provide some helper functions. 1. CommonController (``Mautic\CoreBundle\Controller\CommonController``) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Controllers extending this makes ``MauticFactory`` available via ``$this->factory`` and ``Request`` via ``$this->request``. It also provides the following helper methods: From 677092347b740d84c7032601d0d2a6bd27c406e8 Mon Sep 17 00:00:00 2001 From: Ayu Adiati <45172775+adiati98@users.noreply.github.com> Date: Thu, 29 Jan 2026 12:42:52 +0100 Subject: [PATCH 07/16] remove sentence as it's no longer available Co-authored-by: John Linhart --- docs/plugins/mvc.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/plugins/mvc.rst b/docs/plugins/mvc.rst index 91f55b2f..0311da59 100644 --- a/docs/plugins/mvc.rst +++ b/docs/plugins/mvc.rst @@ -354,9 +354,6 @@ This base class offers access to services commonly used in models: * - Property - Service - Description - * - ``$this->factory`` - - Factory service - - Provides access to other Mautic services. *Deprecated as of Mautic 2.0*; use dependency injection instead. * - ``$this->em`` - Entity manager - Handles database interactions via Doctrine. From 5ce3489dfcc7b186a24d46e3c6903097462f8dc6 Mon Sep 17 00:00:00 2001 From: Ayu Adiati Date: Thu, 29 Jan 2026 13:08:41 +0100 Subject: [PATCH 08/16] add links --- docs/links/symfony_controller_accessing_services_docs.py | 7 +++++++ docs/links/twig_extends_tag_docs.py | 7 +++++++ 2 files changed, 14 insertions(+) create mode 100644 docs/links/symfony_controller_accessing_services_docs.py create mode 100644 docs/links/twig_extends_tag_docs.py diff --git a/docs/links/symfony_controller_accessing_services_docs.py b/docs/links/symfony_controller_accessing_services_docs.py new file mode 100644 index 00000000..a2094ab2 --- /dev/null +++ b/docs/links/symfony_controller_accessing_services_docs.py @@ -0,0 +1,7 @@ +from . import link + +link_name = "Symfony's autowiring" +link_text = "Symfony's autowiring" +link_url = "https://symfony.com/doc/current/controller.html#controller-accessing-services" + +link.xref_links.update({link_name: (link_text, link_url)}) diff --git a/docs/links/twig_extends_tag_docs.py b/docs/links/twig_extends_tag_docs.py new file mode 100644 index 00000000..07c84b6f --- /dev/null +++ b/docs/links/twig_extends_tag_docs.py @@ -0,0 +1,7 @@ +from . import link + +link_name = "Twig documentation" +link_text = "Twig documentation" +link_url = "https://twig.symfony.com/doc/3.x/tags/extends.html" + +link.xref_links.update({link_name: (link_text, link_url)}) From d6607a6d890dac48817b4c3fc4dec27ff25f922b Mon Sep 17 00:00:00 2001 From: Ayu Adiati Date: Thu, 29 Jan 2026 13:08:53 +0100 Subject: [PATCH 09/16] apply suggestions --- docs/plugins/mvc.rst | 112 ++----------------------------------------- 1 file changed, 3 insertions(+), 109 deletions(-) diff --git a/docs/plugins/mvc.rst b/docs/plugins/mvc.rst index 2dc1c949..83d78d30 100644 --- a/docs/plugins/mvc.rst +++ b/docs/plugins/mvc.rst @@ -1,7 +1,7 @@ MVC ### -Mautic uses a **Model-View-Controller - MVC** structure to manage how users interact with the frontend - **views** and how the backend handles those interactions - **controllers and models**. Additionally, **Entity** and **Repository** classes manage interactions with the database. +Mautic uses a **Model-View-Controller - MVC** structure to manage how users interact with the frontend - **views** and how the backend handles those interactions - **controllers and models**. In Symfony, and thus Mautic, the **controller** is the central part of the MVC structure. The route determines which controller method executes when a user makes a request. The controller then interacts with the **model** to retrieve or manipulate data, and finally renders a **view** to display the results to the user. @@ -20,18 +20,6 @@ The :ref:`route defined in the config` determines which control 'controller' => 'MauticPlugin\HelloWorldBundle\Controller\DefaultController:adminAction' ], -The system identifies the controller as``HelloWorldBundle:Default:admin``. Broken down, that translates to: - -- ``HelloWorldBundle`` → ``\MauticPlugin\HelloWorldBundle\Controller`` -- ``Default`` → ``DefaultController`` -- ``admin`` → ``adminAction()`` - -.. note:: - - Controller notation follows the format ``BundleName:ControllerName:controllerMethod.`` - - To use a controller within a subfolder of ``Controller``, use this format ``BundleName:Subdirectory\\ControllerName:controllerMethod`` - Thus, when a browser calls up ``/hello/admin``, ``\MauticPlugin\HelloWorldBundle\Controller\DefaultController::adminAction()`` will be called. Route placeholders @@ -378,20 +366,7 @@ This extends ``AbstractCommonModel`` and includes helper methods for working wit Getting model objects ===================== -To retrieve a model object in a controller: - -.. code-block:: php - - getModel('lead'); // Shortcut for lead.lead - - /** @var \Mautic\LeadBundle\Model\ListModel $leadListModel */ - $leadListModel = $this->getModel('lead.list'); - - /** @var \MauticPlugin\HelloWorldBundle\Model\ContactModel $contactModel */ - $contactModel = $this->getModel('helloworld.contact'); +To retrieve a model object in a controller use :xref:`Symfony's autowiring`. If using a model inside another service or model, inject the model service as a dependency instead of using the helper method. @@ -439,88 +414,7 @@ Some variables are always available and shouldn't be overridden: Extending views =============== -Views commonly extend base templates to provide consistent layout and AJAX support. - -Example: - -.. code-block:: php - - // Extends full document with menu, header, etc. - $view->extend('MauticCoreBundle:Default:content.html.php'); - -Or extend a "slim" template with minimal markup: - -.. code-block:: php - - $view->extend('MauticCoreBundle:Default:content.html.php'); - -To detect if a request is an AJAX request, use: - -.. code-block:: php - - $app->getRequest()->isXmlHttpRequest() - -or pass this information from the controller via ``viewParameters``. - -.. note:: - - Template rendering is inside-out. The rendering process starts with the sub-template ``HelloWorldBundle:World:details.html.php``, which injects its content into ``HelloWorldBundle:World:index.html.php``, and then into the base template ``MauticCoreBundle:Default:content.html.php``. - -To output the content of the sub-template inside the parent, use: - -.. code-block:: php - - $view['slots']->output('_content'); - -See the :ref:`slots helper` for more information. - -Example code -============ - -.. code-block:: php - - // plugins/HelloWorldBundle/Views/World/details.html.php - - // Check if the request is Ajax - if (!$app->getRequest()->isXmlHttpRequest()) { - - // Set tmpl for parent template - $view['slots']->set('tmpl', 'Details'); - - // Extend index.html.php as the parent - $view->extend('HelloWorldBundle:World:index.html.php'); - } - ?> - -
- -
- -.. code-block:: php - - // plugins/HelloWorldBundle/Views/World/index.html.php - - // Extend the base content - $view->extend('MauticCoreBundle:Default:content.html.php'); - - // Get tmpl from sub-template - $tmpl = $view['slots']->get('tmpl', 'Details'); - - // Tell Mautic to call JS onLoad method - $view['slots']->set('mauticContent', 'helloWorld'.$tmpl); - - // Set the page and header title - $header = ($tmpl == 'World') - ? $view['translator']->trans( - 'plugin.helloworld.worlds', - array('%world%' => ucfirst($world)) - ) : $view['translator']->trans('plugin.helloworld.manage_worlds'); - $view['slots']->set('headerTitle', $header); - ?> - -
- output('_content'); ?> -
+Please refer to the ``extends`` tag section in :xref:`Twig documentation` to learn how to extend views. Rendering views within views ============================ From 7ac8154fb8bf26a39765b95c71ebea180e7ab28b Mon Sep 17 00:00:00 2001 From: Ayu Adiati Date: Fri, 30 Jan 2026 11:49:14 +0100 Subject: [PATCH 10/16] change link name and text --- docs/links/symfony_controller_accessing_services_docs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/links/symfony_controller_accessing_services_docs.py b/docs/links/symfony_controller_accessing_services_docs.py index a2094ab2..80db517a 100644 --- a/docs/links/symfony_controller_accessing_services_docs.py +++ b/docs/links/symfony_controller_accessing_services_docs.py @@ -1,7 +1,7 @@ from . import link -link_name = "Symfony's autowiring" -link_text = "Symfony's autowiring" +link_name = "fetching services" +link_text = "fetching services" link_url = "https://symfony.com/doc/current/controller.html#controller-accessing-services" link.xref_links.update({link_name: (link_text, link_url)}) From 20eb815b2a77ec85fecc05bb0466fec344624611 Mon Sep 17 00:00:00 2001 From: Ayu Adiati Date: Fri, 30 Jan 2026 11:49:35 +0100 Subject: [PATCH 11/16] add words to accept.txt --- .github/styles/config/vocabularies/Mautic/accept.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/styles/config/vocabularies/Mautic/accept.txt b/.github/styles/config/vocabularies/Mautic/accept.txt index b51b49d4..11a03832 100644 --- a/.github/styles/config/vocabularies/Mautic/accept.txt +++ b/.github/styles/config/vocabularies/Mautic/accept.txt @@ -80,6 +80,7 @@ initialisms ISO JavaScript Joomla +jQuery Legacy Builder Libre Licensor @@ -94,6 +95,7 @@ middlewares MJML Multiselect multiselect +MVC MVP mysqldump Namespace From 3e6bc74b73ddb1d57ee6bb3d729b38bed97cd98f Mon Sep 17 00:00:00 2001 From: Ayu Adiati Date: Fri, 30 Jan 2026 11:49:55 +0100 Subject: [PATCH 12/16] address vale warnings and adjust words --- docs/plugins/mvc.rst | 207 ++++++++++++++++++++++++++++--------------- 1 file changed, 138 insertions(+), 69 deletions(-) diff --git a/docs/plugins/mvc.rst b/docs/plugins/mvc.rst index 83d78d30..0e6f53d3 100644 --- a/docs/plugins/mvc.rst +++ b/docs/plugins/mvc.rst @@ -1,9 +1,9 @@ -MVC -### +Model-View-Controller - MVC +########################### -Mautic uses a **Model-View-Controller - MVC** structure to manage how users interact with the frontend - **views** and how the backend handles those interactions - **controllers and models**. +Mautic uses an **MVP** structure to manage how Users interact with the frontend - **views** - and how the backend handles those interactions - **controllers and models**. -In Symfony, and thus Mautic, the **controller** is the central part of the MVC structure. The route determines which controller method executes when a user makes a request. The controller then interacts with the **model** to retrieve or manipulate data, and finally renders a **view** to display the results to the user. +In Symfony, and thus Mautic, the **controller** is the central part of the MVC structure. The route determines which controller method executes when a User makes a request. The controller then interacts with the **model** to retrieve or manipulate data, and finally renders a **view** to display the results to the User. Controllers *********** @@ -11,7 +11,11 @@ Controllers Matching Routes to controller methods ===================================== -The :ref:`route defined in the config` determines which controller method is called. Take this example: +.. vale off + +The :ref:`route defined in the config` determines the controller method. Take this example: + +.. vale on .. code-block:: php @@ -75,16 +79,23 @@ Extending Mautic’s controllers Mautic has several controllers that provide some helper functions. +.. vale off + \1. CommonController - ``Mautic\CoreBundle\Controller\CommonController`` ------------------------------------------------------------------------ +.. vale on The ``CommonController`` also provides the following helper methods: 1.1 ``delegateView($args)`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Mautic is AJAX-driven, so it must support both standard http and AJAX requests. The ``delegateView`` method acts as a wrapper that detects the request type and returns the appropriate response—either a full DOM for http or a partial one for AJAX. +.. vale off + +Mautic is AJAX-driven, so it must support both standard HTTP and AJAX requests. The ``delegateView`` method acts as a wrapper that detects the request type and returns the appropriate response—either a complete DOM for HTTP or a partial one for AJAX. + +.. vale on The ``$args`` array contains the required elements for generating either type of response. @@ -109,11 +120,17 @@ It accepts the following parameters for ``delegateView()``: * - ``passthroughVars`` - OPTIONAL - array - - Array of variables returned as part of the AJAX response used by Mautic and/or the Plugin’s onLoad JS callback. + - Array of variables returned as part of the AJAX response used by Mautic and/or the Plugin’s ``onload`` JavaScript callback. -Due to the use of AJAX, Mautic uses some elements of the ``passthroughVars`` array to manipulate the user interface. +.. vale off -For responses that include main content - for example, routes a user would click to - you should set at least ``activeLink`` and ``route``. +Because it uses AJAX, Mautic uses elements of the ``passthroughVars`` array to manipulate the user interface. + +.. vale on + +For responses that include main content - for example, routes a User would click to - you should set at least ``activeLink`` and ``route``. + +.. vale off .. list-table:: Common ``passthroughVars`` :widths: 20 20 20 40 @@ -130,15 +147,15 @@ For responses that include main content - for example, routes a user would click * - route - OPTIONAL - string - - This pushes the route to the browser’s address bar to match AJAX response. + - This pushes the route to the browser’s address bar to match the AJAX response. * - ``mauticContent`` - OPTIONAL - string - - It generates the JS method to call after Mautic injects AJAX content into the DOM. If set as ``helloWorldDetails``, Mautic checks for and execute ``Mautic.helloWorldDetailsOnLoad()``. + - It generates the JavaScript method to call after Mautic injects AJAX content into the DOM. If set as ``helloWorldDetails``, Mautic checks for and executes ``Mautic.helloWorldDetailsOnLoad()``. * - callback - OPTIONAL - string - - Mautic executes a namespaced JS function before injecting the response. If set, Mautic passes the response to this function and does not process content. + - Mautic executes namespace - a JavaScript function - before injecting the response. If set, Mautic passes the response to this function and doesn't process content. * - redirect - OPTIONAL - string @@ -146,18 +163,20 @@ For responses that include main content - for example, routes a user would click * - target - OPTIONAL - string - - jQuery selector to inject the content into. Defaults to app’s main content selector. - * - replaceContent + - jQuery selector to inject the content into. Defaults to the app’s main content selector. + * - ``replaceContent`` - OPTIONAL - string - - If set to `'true'`, Mautic replaces the target selector with AJAX content. + - If set to ``true``, Mautic replaces the target selector with AJAX content. + +.. vale on 1.2 ``delegateRedirect($url)`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Delegates the appropriate response for redirects. +Delegates the appropriate response for redirects: -* **If AJAX request**: returns a json response with ``{redirect: $url}``. +* **If AJAX request**: returns a JSON response with ``{redirect: $url}``. * **If http request**: performs a standard redirect header. 1.3 ``postActionRedirect($args)`` @@ -180,18 +199,21 @@ Similar to ``delegateView()``, but used after an action like saving a Form. Acce * - flashes - OPTIONAL - array - - Array of flash messages to display after redirecting. See :doc:`Flash Messages ` for more information. + - Array of flash messages to display after redirecting. See Flash Messages for more information. * - ``forwardController`` - OPTIONAL - - bool - - If true (default), forwards to a controller method (``BundleName:ControllerName:method``). Set to ``false`` to load a view template (``BundleName:ViewName:template.html.php``) directly. + - boolean + - If ``true`` - **default**, forwards to a controller method - ``BundleName:ControllerName:method``. Set to ``false`` to load a view template - ``BundleName:ViewName:template.html.php`` - directly. +.. vale off \2. FormController - ``Mautic\CoreBundle\Controller\FormController`` ==================================================================== This controller extends ``CommonController`` and provides helper methods for managing :doc:`Forms `. +.. vale on + .. code-block:: php security`` - Security service - - Provides access to the current user and permission checks. + - Provides access to the current User and permission checks. * - ``$this->dispatcher`` - Event dispatcher - Dispatches and listens for Mautic events. @@ -358,34 +387,42 @@ This base class offers access to services commonly used in models: - Translator service - Handles language translations. -\2. FormModel - ``\Mautic\CoreBundle\Model\FormModel`` ------------------------------------------------------- +.. vale off + +\2. ``FormModel`` - ``\Mautic\CoreBundle\Model\FormModel`` +---------------------------------------------------------- + +The ``FormModel`` class extends ``AbstractCommonModel`` and includes helper methods for working with entities and repositories. For more information, refer to the Database section. -This extends ``AbstractCommonModel`` and includes helper methods for working with entities and repositories. For more information, see the :doc:`Database ` section. +.. vale on Getting model objects ===================== -To retrieve a model object in a controller use :xref:`Symfony's autowiring`. +To retrieve a model object in a controller use Symfony's :xref:`fetching services`. If using a model inside another service or model, inject the model service as a dependency instead of using the helper method. Views ***** -Views in Mautic take data passed from the controller and display it to the user. You can render templates from within controllers or other templates. +Views in Mautic take data passed from the controller and display it to the User. You can render templates from within controllers or other templates. The controller uses the ``delegateView()`` method to render views, which relies on the ``contentTemplate`` to determine which view to render. -View notation follows this format: +The format for view notation is as follows: .. code-block:: none @BundleName/ViewName/template.html.twig -For example, ``@HelloWorld/Contact/form.html.twig`` points to the file ``/path/to/mautic/plugins/HelloWorldBundle/Resources/views/Contact/form.html.twig`` +.. vale off -To use views inside subfolders under ``Resources/views``: +For example, ``@HelloWorld/Contact/form.html.twig`` points to the file ``/path/to/mautic/plugins/HelloWorldBundle/Resources/views/Contact/form.html.twig``. + +.. vale on + +To use views inside sub-folders under ``Resources/views``: .. code-block:: none @@ -406,7 +443,7 @@ For example, if the controller passes: Then the variable ``$world`` becomes available in the template with the value ``mars``. -Some variables are always available and shouldn't be overridden: +Avoid overriding these reserved variables, as Mautic provides them by default: * ``$view``: contains helper objects for extending or rendering templates. * ``$app``: provides access to request and session objects via ``$app->getRequest()`` and ``$app->getSession()``. @@ -428,12 +465,12 @@ You can render one view inside another: Template helpers **************** -There are a number of template helper objects and helper view templates built into Mautic. +There are several template helper objects and helper view templates built into Mautic. -Slots helper -============ +The ``slots`` helper +==================== -The ``slots`` helper allows sub-templates to pass content up to parent templates. Since Mautic templates render *inside-out*, a sub-template can define slot content that the parent template can access. However, sub-templates don't have access to content defined in a parent template. +The ``slots`` helper allows sub-templates to pass content up to parent templates. Since Mautic templates render **inside-out**, a sub-template can define slot content that the parent template can access. However, sub-templates don't have access to content defined in a parent template. Setting slot content -------------------- @@ -448,7 +485,7 @@ Use ``set()`` to define the content of a slot. If the slot already exists, the n Appending slot content ---------------------- -Use ``append()`` to add to an existing slot rather than replacing its content. This is useful for aggregating content across templates. +Use ``append()`` to add to an existing ``slot`` rather than replacing its content. This is useful for aggregating content across templates. .. code-block:: php @@ -473,7 +510,7 @@ To get the content of a slot, use ``get()``. If the slot doesn't exist, you can Outputting slot content ----------------------- -To output the slot content, use ``output()``. This is typically used in parent templates where you want to inject content from a sub-template. +The ``output()`` method renders slot content. It allows parent templates to pull in and display content from sub-templates. .. code-block:: php @@ -492,23 +529,23 @@ You can confirm if a slot exists using ``has()`` before performing actions on it // Perform some action } -``slots`` are central to how Mautic handles nested views and dynamic content flow. Use them to build modular, reusable templates where the child view defines what's shown and the parent controls the layout. +The ``slots`` are central to how Mautic handles nested views and Dynamic Content flow. Use them to build modular, reusable templates where the child view defines what's shown and the parent controls the layout. -Asset helper -============ +The ``assets`` helper +===================== -The ``assets`` helper, accessed via ``$view['assets']``, is used to load assets into the DOM including images, script and stylesheets. +The ``assets`` helper - accessed via ``$view['assets']`` - loads various Assets into the DOM, such as images, scripts, and stylesheets. .. note:: - ``$view['assets']`` should always be used to ensure that assets work with Mautic installed in the web root, installed in a subdirectory, ran under the dev environment - ``index_dev.php`` - and/or ran under the prod environment. + Use ``$view['assets']`` to ensure your Assets work across environments. This allows Assets to load correctly whether you install Mautic in the web root or a subdirectory, and whether you run it in development - ``index_dev.php`` - or production environments. -The asset helper also provides a way to insert scripts and stylesheets into the head for AJAX loaded content using ``$view['assets']->includeScript()`` and ``$view['assets']->includeStylesheet()``. +The ``assets`` helper also provides a way to insert scripts and stylesheets into the head for AJAX-loaded content using ``$view['assets']->includeScript()`` and ``$view['assets']->includeStylesheet()``. Loading images -------------- -Use ``getUrl()`` to generate the correct relative URL to an asset like an image. +Use ``getUrl()`` to generate the correct relative URL to an Asset, such as an image. .. code-block:: php @@ -535,10 +572,10 @@ Use ``includeStylesheet()`` to dynamically include a CSS file into the head. // Dynamically insert stylesheet into head echo $view['assets']->includeStylesheet('plugins/HelloWorldBundle/assets/helloworld.css'); -These methods ensure that your assets are properly handled regardless of Mautic’s installation location or environment. They also support dynamic inclusion for content loaded via AJAX. +These methods enable you to handle your Assets properly, regardless of Mautic’s installation location or environment. They also support dynamic inclusion for content loaded via AJAX. -Router helper -============= +The ``router`` helper +===================== The ``router`` helper, accessed via ``$view['router']``, is used to generate URLs to named routes within views. @@ -551,10 +588,14 @@ The ``router`` helper, accessed via ``$view['router']``, is used to generate URL This generates a link to the route ``plugin_helloworld_world`` with the dynamic parameter ``world`` set to ``mars``. +.. vale off + For more details on defining and using routes, see :doc:`Router `. -Translation helper -================== +.. vale on + +The ``translator`` helper +========================= The ``translator`` helper, accessed via ``$view['translator']``, is used to translate strings within views using Mautic's translation system. @@ -567,16 +608,16 @@ The ``translator`` helper, accessed via ``$view['translator']``, is used to tran ); ?> -This example replaces the ``%world%`` placeholder with ``Mars``, and output the translated string. +This example replaces the ``%world%`` placeholder with ``Mars``, and outputs the translated string. For more on how to handle translations, see :doc:`Translator `. -``$view['translator']`` follows the same conventions described in the Translator documentation, allowing dynamic, localized content in templates. +The ``$view['translator']`` follows the same conventions described in the :doc:`Translator documentation `, allowing dynamic, localized content in templates. -Date helper -=========== +The ``date`` helper +=================== -The ``date`` helper, accessed via ``$view['date']``, is used to format dates according to system and/or user settings. +The ``date`` helper - accessed via ``$view['date']`` - formats dates according to system and User settings. .. code-block:: php @@ -606,40 +647,50 @@ The ``date`` helper, accessed via ``$view['date']``, is used to format dates acc The first argument to each method can be a ``\DateTime`` object or a string formatted as ``Y-m-d H:i:s``. If the date is not already in local time, pass the expected format as the second argument and the timezone as the third. -Form helper -=========== +The ``form`` helper +=================== -The ``form`` helper, accessed via ``$view['form']``, is used to render form objects passed from the controller. +The ``form`` helper, accessed via ``$view['form']``, is used to render Form objects passed from the controller. .. code-block:: php form($form); ?> -This helper outputs the full HTML Form using the Form object - typically a Symfony Form - passed to the view. +This helper outputs the complete HTML Form using the Form object - typically a Symfony Form - passed to the view. + +.. vale off For detailed usage, see :doc:`Forms `. -AJAX integration +.. vale on + +AJAX Integration **************** -Mautic provides several helpers and conventions for handling AJAX-driven UI features including links, modals, forms, and lifecycle callbacks. +Mautic provides several helpers and conventions for handling AJAX-driven UI features, including links, modals, Forms, and lifecycle callbacks. AJAX links ========== To enable AJAX for a link, set the attribute ``data-toggle="ajax"``. +.. vale off + .. code-block:: html+php Mars +.. vale on + AJAX modals =========== Mautic uses Bootstrap modals, but Bootstrap alone doesn't support dynamically retrieving content more than once. To address this, Mautic provides the ``data-toggle="ajaxmodal"`` attribute. +.. vale off + .. code-block:: html+php -* ``data-target`` should be the selector for the modal where content will be injected. Mautic provides a shared modal with the ID ``#MauticSharedModal``. -* ``data-header`` sets the modal’s title/header. +.. vale on + +* ``data-target`` defines the selector for the modal that receives injected content. Mautic provides a shared modal with the ID ``#MauticSharedModal``. +* ``data-header`` sets the modal’s title or header. + +.. vale off AJAX Forms ========== -When using Symfony’s Form services, Mautic automatically enables AJAX the Form. No additional configuration is necessary. +.. vale on + +When using Symfony’s Form services, Mautic automatically enables AJAX for the Form. No additional configuration is necessary. AJAX content callbacks ====================== @@ -672,7 +729,7 @@ Mautic allows you to hook into the lifecycle of AJAX content injection via JavaS // Clean up or remove bindings before unloading }; -The system executes these callbacks when it injects or removes content via AJAX. This is useful for initializing dynamic components such as charts, inputs with autocomplete, or other JS-driven features. +The system executes these callbacks when it injects or removes content via AJAX. This is useful for initializing dynamic Components such as charts, autocomplete inputs, or other JavaScript-driven features. To use this feature, pass the ``mauticContent`` key through the controller's ``delegateView()`` method. For example, the method ``Mautic.helloWorldDetailsOnLoad()`` calls for the following: @@ -684,7 +741,11 @@ To use this feature, pass the ``mauticContent`` key through the controller's ``d 'mauticContent' => 'helloWorldDetails' ] -Loading content triggers ``Mautic.helloWorldDetailsOnLoad()`` and ``Mautic.helloWorldDetailsOnUnload()`` when the user browses away from the page. It also gives the opportunity to destroy objects if necessary. +.. vale off + +Loading content triggers ``Mautic.helloWorldDetailsOnLoad()`` and ``Mautic.helloWorldDetailsOnUnload()`` when the User browses away from the page. It also allows destroying objects if necessary. + +.. vale on Both callbacks receive two arguments: @@ -697,12 +758,20 @@ Both callbacks receive two arguments: * - ``container`` - The selector used as the AJAX content target. * - ``response`` - - The response object from the AJAX call (from ``passthroughVars``). + - The response object from the AJAX call - ``passthroughVars``. + +.. vale off Page refresh support ==================== -Ensure the correct ``OnLoad`` function triggers on full page refresh by setting the ``mauticContent`` slot in the view using: +.. vale on + +.. vale off + +Ensure the correct ``onload`` function triggers on full page refresh by setting the ``mauticContent`` slot in the view using: + +.. vale on .. code-block:: php From 7bc0db5c76681c70f9101187075594b5d8124ac2 Mon Sep 17 00:00:00 2001 From: Ayu Adiati Date: Fri, 30 Jan 2026 12:18:14 +0100 Subject: [PATCH 13/16] add and remove internal links --- docs/plugins/config.rst | 2 ++ docs/plugins/mvc.rst | 38 +++++++++++++++----------------------- 2 files changed, 17 insertions(+), 23 deletions(-) diff --git a/docs/plugins/config.rst b/docs/plugins/config.rst index 92a74823..15556e5b 100644 --- a/docs/plugins/config.rst +++ b/docs/plugins/config.rst @@ -40,6 +40,8 @@ Mautic recognizes the Plugin through the general config options. - string - The version should be in a format compatible with :xref:`PHP's standardized version strings`. The Plugin Manager uses PHP's ``version_compare()`` to determine if the Plugin is eligible for an upgrade. +.. _routing config items: + Routing config items ******************** diff --git a/docs/plugins/mvc.rst b/docs/plugins/mvc.rst index 0e6f53d3..01dd7b41 100644 --- a/docs/plugins/mvc.rst +++ b/docs/plugins/mvc.rst @@ -8,12 +8,12 @@ In Symfony, and thus Mautic, the **controller** is the central part of the MVC s Controllers *********** -Matching Routes to controller methods +Matching routes to controller methods ===================================== .. vale off -The :ref:`route defined in the config` determines the controller method. Take this example: +The :ref:`route defined in the config ` determines the controller method. Take this example: .. vale on @@ -24,14 +24,14 @@ The :ref:`route defined in the config` determines the controlle 'controller' => 'MauticPlugin\HelloWorldBundle\Controller\DefaultController:adminAction' ], -Thus, when a browser calls up ``/hello/admin``, ``\MauticPlugin\HelloWorldBundle\Controller\DefaultController::adminAction()`` will be called. +In the example, a browser call to ``/hello/admin`` triggers ``MauticPlugin\HelloWorldBundle\Controller\DefaultController::adminAction()``. Route placeholders ================== Symfony automatically passes route placeholders into the controller’s method as arguments. The method’s parameters must match the placeholder names. -Example: +For example: .. code-block:: php @@ -56,7 +56,7 @@ The matching method: Since the route defines a default for ``world``, the controller method must also reflect this default. -If the route looked like this instead: +Without a defined default value, the placeholder becomes a required argument: .. code-block:: php @@ -68,7 +68,7 @@ If the route looked like this instead: ] ], -Then the method must be: +The corresponding controller method reflects this by omitting the default value: .. code-block:: php @@ -199,7 +199,7 @@ Similar to ``delegateView()``, but used after an action like saving a Form. Acce * - flashes - OPTIONAL - array - - Array of flash messages to display after redirecting. See Flash Messages for more information. + - Array of flash messages to display after redirecting. * - ``forwardController`` - OPTIONAL - boolean @@ -210,7 +210,7 @@ Similar to ``delegateView()``, but used after an action like saving a Form. Acce \2. FormController - ``Mautic\CoreBundle\Controller\FormController`` ==================================================================== -This controller extends ``CommonController`` and provides helper methods for managing :doc:`Forms `. +This controller extends ``CommonController`` and provides helper methods for managing Forms. .. vale on @@ -311,7 +311,7 @@ This controller extends ``CommonController`` and provides helper methods for man .. vale on -This controller also extends ``CommonController`` and is a companion to some of the built-in JavaScript helpers. See *JavaScript methods* for more information. +This controller also extends ``CommonController`` and is a companion to some of the built-in JavaScript helpers. Models ****** @@ -392,7 +392,7 @@ This base class offers access to services commonly used in models: \2. ``FormModel`` - ``\Mautic\CoreBundle\Model\FormModel`` ---------------------------------------------------------- -The ``FormModel`` class extends ``AbstractCommonModel`` and includes helper methods for working with entities and repositories. For more information, refer to the Database section. +The ``FormModel`` class extends ``AbstractCommonModel`` and includes helper methods for working with entities and repositories. For more information, refer to the :doc:`Entities and schema ` section. .. vale on @@ -588,12 +588,6 @@ The ``router`` helper, accessed via ``$view['router']``, is used to generate URL This generates a link to the route ``plugin_helloworld_world`` with the dynamic parameter ``world`` set to ``mars``. -.. vale off - -For more details on defining and using routes, see :doc:`Router `. - -.. vale on - The ``translator`` helper ========================= @@ -610,7 +604,11 @@ The ``translator`` helper, accessed via ``$view['translator']``, is used to tran This example replaces the ``%world%`` placeholder with ``Mars``, and outputs the translated string. -For more on how to handle translations, see :doc:`Translator `. +.. vale off + +For more on how to handle translations, see :doc:`Translator `. + +.. vale on The ``$view['translator']`` follows the same conventions described in the :doc:`Translator documentation `, allowing dynamic, localized content in templates. @@ -658,12 +656,6 @@ The ``form`` helper, accessed via ``$view['form']``, is used to render Form obje This helper outputs the complete HTML Form using the Form object - typically a Symfony Form - passed to the view. -.. vale off - -For detailed usage, see :doc:`Forms `. - -.. vale on - AJAX Integration **************** From 5d8819123a58e0c1ac7cb0f4a2ddc90aecd86f32 Mon Sep 17 00:00:00 2001 From: Ayu Adiati Date: Fri, 30 Jan 2026 12:21:49 +0100 Subject: [PATCH 14/16] fix broken internal links --- docs/plugins/mvc.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/plugins/mvc.rst b/docs/plugins/mvc.rst index 01dd7b41..ff149a93 100644 --- a/docs/plugins/mvc.rst +++ b/docs/plugins/mvc.rst @@ -392,7 +392,7 @@ This base class offers access to services commonly used in models: \2. ``FormModel`` - ``\Mautic\CoreBundle\Model\FormModel`` ---------------------------------------------------------- -The ``FormModel`` class extends ``AbstractCommonModel`` and includes helper methods for working with entities and repositories. For more information, refer to the :doc:`Entities and schema ` section. +The ``FormModel`` class extends ``AbstractCommonModel`` and includes helper methods for working with entities and repositories. For more information, refer to the :doc:`/plugins/data` section. .. vale on @@ -610,7 +610,7 @@ For more on how to handle translations, see :doc:`Translator `, allowing dynamic, localized content in templates. +The ``$view['translator']`` follows the same conventions described in the :doc:`Translator documentation `, allowing dynamic, localized content in templates. The ``date`` helper =================== From e97e9930079a550840d1296ee6a9e1fc8f205eab Mon Sep 17 00:00:00 2001 From: Ayu Adiati Date: Fri, 30 Jan 2026 12:26:16 +0100 Subject: [PATCH 15/16] change passive to active voice --- docs/plugins/mvc.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/plugins/mvc.rst b/docs/plugins/mvc.rst index ff149a93..9a105d9e 100644 --- a/docs/plugins/mvc.rst +++ b/docs/plugins/mvc.rst @@ -577,7 +577,7 @@ These methods enable you to handle your Assets properly, regardless of Mautic’ The ``router`` helper ===================== -The ``router`` helper, accessed via ``$view['router']``, is used to generate URLs to named routes within views. +The router helper - accessed via ``$view['router']`` - generates URLs for named routes within views. .. code-block:: php From 1e296ea89e3ff3d68f6c0650e49d465610a1bbe1 Mon Sep 17 00:00:00 2001 From: Ayu Adiati Date: Fri, 30 Jan 2026 12:26:16 +0100 Subject: [PATCH 16/16] change passive to active voice --- docs/plugins/mvc.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/plugins/mvc.rst b/docs/plugins/mvc.rst index ff149a93..f7e8b76f 100644 --- a/docs/plugins/mvc.rst +++ b/docs/plugins/mvc.rst @@ -577,7 +577,7 @@ These methods enable you to handle your Assets properly, regardless of Mautic’ The ``router`` helper ===================== -The ``router`` helper, accessed via ``$view['router']``, is used to generate URLs to named routes within views. +The ``router`` helper - accessed via ``$view['router']`` - generates URLs for named routes within views. .. code-block:: php