Model-View-Controller - MVC
Mautic 使用 MVP 结构来管理用户与前端(视图)的交互方式,以及后端如何处理这些交互(控制器和模型)。
在 Symfony 中,因此在 Mautic 中,控制器 是 MVC 结构的中心部分。路由确定当用户发出请求时,哪个控制器方法会被执行。然后,控制器与 模型 交互以检索或操作数据,最后渲染一个 视图 以向用户显示结果。
控制器
将路由映射到控制器方法
配置中定义的 route 决定了控制器方法。以下是一个示例:
'plugin_helloworld_admin' => [
'path' => '/hello/admin',
'controller' => 'MauticPlugin\HelloWorldBundle\Controller\DefaultController:adminAction'
],
在示例中,浏览器对 /hello/admin 的访问会触发 MauticPlugin\HelloWorldBundle\Controller\DefaultController::adminAction()。
路由占位符
Symfony 会自动将路由占位符作为参数传递给控制器的 method。方法的参数必须与占位符名称匹配。
例如:
'plugin_helloworld_world' => [
'path' => '/hello/{world}',
'controller' => 'MauticPlugin\HelloWorldBundle\Controller\DefaultController::worldAction',
'defaults' => [
'world' => 'earth'
],
'requirements' => [
'world' => 'earth|mars'
]
],
对应的 method:
public function worldAction(string $world = 'earth')
Note
由于路由为 world 定义了默认值,因此控制器方法也必须反映此默认值。
如果没有定义默认值,则占位符将成为必需的参数:
'plugin_helloworld_world' => [
'path' => '/hello/{world}',
'controller' => 'MauticPlugin\HelloWorldBundle\Controller\DefaultController::worldAction',
'requirements' => [
'world' => 'earth|mars'
]
],
对应的控制器方法通过省略默认值来反映这一点:
public function worldAction(string $world)
扩展 Mautic 的控制器
Mautic 具有一些提供辅助函数的控制器。
1. CommonController - Mautic\CoreBundle\Controller\CommonController
CommonController 还提供了以下辅助方法:
1.1 delegateView($args)
Mautic 是基于 AJAX 的,因此它必须同时支持标准的 HTTP 请求和 AJAX 请求。delegateView 方法充当一个包装器,用于检测请求类型并返回适当的响应——对于 HTTP 请求,返回完整的 DOM;对于 AJAX 请求,返回部分 DOM。
$args 数组包含生成两种类型响应所需的元素。
它接受以下 delegateView() 的参数:
Key |
Required |
Type |
Description |
|---|---|---|---|
|
REQUIRED |
string |
定义要加载的视图模板。应采用 BundleName:ViewName:template.html.php 的格式。请参阅 Views 以获取更多信息。 |
|
OPTIONAL |
array |
包含变量及其值的数组,这些变量可供模板使用。每个键都成为模板中可用的一种变量。 |
|
OPTIONAL |
array |
包含作为 AJAX 响应的一部分返回的变量,由 Mautic 和/或插件的 onload JavaScript 回调函数使用。 |
由于 Mautic 使用 AJAX,因此它使用 passthroughVars 数组中的元素来操作用户界面。
对于包含主要内容(例如,用户将点击的路由)的响应,您应该至少设置 activeLink 和 route。
Key |
Required |
Type |
Description |
|---|---|---|---|
|
OPTIONAL |
string |
设置 Mautic 应动态激活的菜单项的 ID,以匹配 AJAX 响应。 |
route |
OPTIONAL |
string |
这会将路由推送到浏览器的地址栏,以匹配 AJAX 响应。 |
|
OPTIONAL |
string |
它生成要在 Mautic 将 AJAX 内容注入到 DOM 后调用的 JavaScript 方法。如果设置为 helloWorldDetails,Mautic 会检查并执行 Mautic.helloWorldDetailsOnLoad()。 |
callback |
OPTIONAL |
string |
在 Mautic 注入响应之前,它会执行命名空间中的一个 JavaScript 函数。如果设置了该值,Mautic 将将响应传递给此函数,而不会处理内容。 |
redirect |
OPTIONAL |
string |
要强制执行的页面重定向 URL,而不是注入 AJAX 内容。 |
target |
OPTIONAL |
string |
用于注入内容的 jQuery 选择器。默认为应用程序的主要内容选择器。 |
|
OPTIONAL |
string |
如果设置为 true,Mautic 将使用 AJAX 内容替换目标选择器。 |
1.2 delegateRedirect($url)
委派重定向的适当响应:
如果为 AJAX 请求:返回包含 {redirect: $url} 的 JSON 响应。
如果是 HTTP 请求:执行标准的重定向头信息。
1.3 postActionRedirect($args)
Similar to delegateView(), but used after an action like saving a Form. Accepts the same $args as delegateView(), plus:
Key |
Required |
Type |
Description |
|---|---|---|---|
|
OPTIONAL |
string |
URL to redirect to. Defaults to |
flashes |
OPTIONAL |
array |
Array of flash messages to display after redirecting. |
|
OPTIONAL |
boolean |
If |
2. FormController - Mautic\CoreBundle\Controller\FormController
This controller extends CommonController and provides helper methods for managing Forms.
<?php
// plugins/HelloWorldBundle/Controller/DefaultController.php
namespace MauticPlugin\HelloWorldBundle\Controller;
use Mautic\CoreBundle\Controller\FormController;
class DefaultController extends FormController
{
public function worldAction(string $world = 'earth', WorldModel $model): Response
{
// Retrieve details about the world
$worldDetails = $model->getWorldDetails($world);
return $this->delegateView(
[
'viewParameters' => [
'world' => $world,
'details' => $worldDetails
],
'contentTemplate' => 'HelloWorldBundle:World:details.html.php',
'passthroughVars' => [
'activeLink' => 'plugin_helloworld_world',
'route' => $this->generateUrl('plugin_helloworld_world', ['world' => $world]),
'mauticContent' => 'helloWorldDetails'
]
]
);
}
public function contactAction(ContactModel $model): Response
{
// Create the form object
$form = $this->formFactory->create(ContactFormType::class);
// Handle form submission if POST
if ($this->request->getMethod() == 'POST') {
$flashes = [];
// 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)) {
- // Send the email
$model->sendContactEmail($form->getData());
// Set success flash message $flashes[] = [
‘type’ => ‘notice’, ‘msg’ => ‘plugin.helloworld.notice.thank_you’, ‘msgVars’ => [
‘%name%’ => $form[‘name’]->getData()
]
];
}
}
- if ($cancelled || $valid) {
// Redirect to /hello/world
- return $this->postActionRedirect(
- [
‘returnUrl’ => $this->generateUrl(‘plugin_helloworld_world’), ‘contentTemplate’ => ‘MauticPluginHelloWorldBundleControllerDefaultController:worldAction’, ‘flashes’ => $flashes
]
);
} // Otherwise show the form again with validation error messages
}
// Display the form return $this->delegateView(
- [
- ‘viewParameters’ => [
‘form’ => $form->createView()
), ‘contentTemplate’ => ‘@HelloWorld/Contact/form.html.twig’, ‘passthroughVars’ => [
‘activeLink’ => ‘plugin_helloworld_contact’, ‘route’ => $this->generateUrl(‘plugin_helloworld_contact’)
]
]
);
}
}
3. AjaxController - Mautic\CoreBundle\Controller\AjaxController
This controller also extends CommonController and is a companion to some of the built-in JavaScript helpers.
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
<?php
// plugins/HelloWorldBundle/Model/ContactModel.php
namespace MauticPlugin\HelloWorldBundle\Model;
use Mautic\CoreBundle\Model\CommonModel;
final class ContactModel extends CommonModel
{
/**
* Send contact email
*/
public function sendContactEmail(array $data): void
{
$mailer->message->addTo(
$this->coreParametersHelper->get('mailer_from_email')
);
$this->message->setFrom(
array($data['email'] => $data['name'])
);
$mailer->message->setSubject($data['subject']);
$mailer->message->setBody($data['message']);
$mailer->send();
}
}
Base model classes
您可以扩展以下任何一个基本类,以使用 Mautic 的辅助方法:
1. AbstractCommonModel - \Mautic\CoreBundle\Model\AbstractCommonModel
此基本类提供对模型中常用的服务的访问:
Property |
Service |
Description |
|---|---|---|
|
Entity manager |
Handles database interactions via Doctrine. |
|
Security service |
Provides access to the current User and permission checks. |
|
Event dispatcher |
Dispatches and listens for Mautic events. |
|
Translator service |
Handles language translations. |
2. FormModel - \Mautic\CoreBundle\Model\FormModel
FormModel 类扩展了 AbstractCommonModel,并包含用于处理实体和存储库的辅助方法。 更多信息,请参阅 /plugins/data 部分。
获取模型对象
要在控制器中检索模型对象时,请使用 Symfony 的 fetching services。
如果在另一个服务或模型中使用模型,请将模型服务作为依赖项注入,而不是使用辅助方法。
视图
Mautic 中的视图接收来自控制器的传入数据并将其显示给用户。 您可以在控制器或其他模板中渲染模板。
控制器使用 delegateView() 方法来渲染视图,该方法依赖于 contentTemplate 来确定要呈现的视图。
视图表示格式如下:
@BundleName/ViewName/template.html.twig
例如,@HelloWorld/Contact/form.html.twig 指向文件 /path/to/mautic/plugins/HelloWorldBundle/Resources/views/Contact/form.html.twig。
要在 Resources/views 下的子文件夹中使用视图:
@BundleName/ViewName/Subfolder/template.html.twig
视图参数
作为控制器中的 delegateView() 方法传递的 viewParameters 数组,在视图中可用作变量。
例如,如果控制器传递以下内容:
'viewParameters' => [
'world' => 'mars'
],
那么模板中将可以使用名为 $world 的变量,其值为 mars。
避免覆盖这些保留的变量,因为 Mautic 默认提供它们:
$view: 包含用于扩展或呈现模板的辅助对象。$app: 提供对请求和会话对象的访问,可以通过$app->getRequest()和$app->getSession()访问。
扩展视图
Please refer to the extends tag section in Twig templating language to learn how to extend views.
Rendering views within views
You can render one view inside another:
echo $view->render('BundleName:ViewName:template.html.php', array('parameter' => 'value'));
Template helpers
There are several template helper objects and helper view templates built into Mautic.
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.
Setting slot content
Use set() to define the content of a slot. If the slot already exists, the new content overwrites the existing one.
// Set a slot with content
$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.
// Append string content
$view['slots']->append('name', ' and more content');
// Append array content
$view['slots']->append('existingArray', array(
'append' => 'me'
));
Retrieving slot content
To get the content of a slot, use get(). If the slot doesn’t exist, you can define a default value.
// Retrieve slot content or fallback to default
$content = $view['slots']->get('name', 'default value');
Outputting slot content
The output() method renders slot content. It allows parent templates to pull in and display content from sub-templates.
// Render the slot content; no echo required
$view['slots']->output('name');
Checking slot existence
You can confirm if a slot exists using has() before performing actions on it.
// Check if a slot is defined
if ($view['slots']->has('name')) {
// Perform some action
}
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.
The assets helper
The assets helper - accessed via $view['assets'] - loads various Assets into the DOM, such as images, scripts, and stylesheets.
Note
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.
assets helper 也提供了一种将脚本和样式表插入到 head 中的方法,用于通过 $view['assets']->includeScript() 和 $view['assets']->includeStylesheet() 加载的 AJAX 内容。
加载图像
使用 getUrl() 生成指向 Asset 的正确相对 URL,例如图像。
// 生成指向图像的相对 URL
echo '<img src="' . $view['assets']->getUrl('plugins/HelloWorldBundle/assets/images/earth.png') . '" />';
插入 JavaScript
使用 includeScript() 动态地将一个 JavaScript 文件插入到 head 中。这对于需要重新注入脚本的 AJAX 加载视图特别有用。
// 动态地将脚本插入到 head 中
echo $view['assets']->includeScript('plugins/HelloWorldBundle/assets/helloworld.js');
插入样式表
使用 includeStylesheet() 动态地将一个 CSS 文件包含到 head 中。
// 动态地将样式表插入到 head 中
echo $view['assets']->includeStylesheet('plugins/HelloWorldBundle/assets/helloworld.css');
这些方法使您能够正确处理 Assets,无论 Mautic 的安装位置或环境如何。它们还支持通过 AJAX 加载的内容的动态包含。
router helper
router helper - 通过 $view['router'] 访问 - 在视图中生成命名路由的 URL。
<a href="<?php echo $view['router']->generate(
'plugin_helloworld_world',
array('world' => 'mars')
); ?>" data-toggle="ajax">Mars</a>
这会生成一个指向路由 plugin_helloworld_world 的链接,其中动态参数 world 设置为 mars。
translator helper
translator helper,通过 $view['translator'] 访问,用于在视图中使用 Mautic 的翻译系统来翻译字符串。
<h1>
<?php echo $view['translator']->trans(
'plugin.helloworld.worlds',
array('%world%' => 'Mars')
); ?>
</h1>
这个示例将占位符 %world% 替换为 Mars,并输出翻译后的字符串。
有关如何处理翻译的更多信息,请参阅 Translator。
$view['translator'] 遵循与 Translator documentation 中描述的相同约定,从而允许在模板中实现动态、本地化的内容。
date helper
date helper - 通过 $view['date'] 访问 - 根据系统和用户设置来格式化日期。
// 可以是字符串或 \DateTime 对象。如果是字符串,则假定为本地时间
$datetime = '2015-04-12 20:56:00';
// 使用系统设置中的完整日期和时间格式进行格式化
$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.
The form helper
The form helper, accessed via $view['form'], is used to render Form objects passed from the controller.
<?php echo $view['form']->form($form); ?>
This helper outputs the complete HTML Form using the Form object - typically a Symfony Form - passed to the view.
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".
<a href="<?php echo $view['router']->generate('plugin_helloworld_world', ['world' => 'mars']); ?>" data-toggle="ajax">
Mars
</a>
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.
<a href="<?php echo $view['router']->generate('plugin_helloworld_world', ['world' => 'mars']); ?>"
data-toggle="ajaxmodal"
data-target="#MauticSharedModal"
data-header="<?php echo $view['translator']->trans('plugin.helloworld.worlds', ['%world%' => 'Mars']); ?>">
Mars
</a>
data-targetdefines the selector for the modal that receives injected content. Mautic provides a shared modal with the ID#MauticSharedModal.data-headersets the modal’s title or header.
AJAX Forms
When using Symfony’s Form services, Mautic automatically enables AJAX for 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.
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, 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:
'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 allows destroying objects if necessary.
Both callbacks receive two arguments:
Argument |
Description |
|---|---|
|
The selector used as the AJAX content target. |
|
The response object from the AJAX call - |
Page refresh support
Ensure the correct onload function triggers on full page refresh by setting the mauticContent slot in the view using:
$view['slots']->set('mauticContent', 'helloWorldDetails');