Autowiring
Mautic 5 添加了对 Symfony 的 :xref:`symfony-autowiring 和 :xref:`symfony-autoconfigure 服务支持。
早期版本需要将服务定义在 *Bundle/Config/config.php 文件中。这在 Mautic 5 中仍然有效,但在 Mautic 6 中将被移除。
请按照以下步骤从硬编码的服务迁移到自动注入的服务。
优点
新服务不再需要在
app/bundles/*Bundle/Config/config.php文件中有任何定义。插件也一样。Symfony 会根据构造函数的参数类型推断所需的服务。如果服务未在其他服务中用作依赖项,则它们将被删除,例如 订阅者、命令**和 **表单类型。
您可以将现有的服务定义简化为仅设置字符串别名,以保持向后兼容性并使控制器正常工作。
app/config/services.php会自动配置所有 bundle,包括插件,因此如果 bundle 没有进行任何特殊的修改,它应该可以开箱即用。传统的服务定义位于
*Bundle/Config/config.php文件中,但在 Mautic 6 中将被移除。
这同样适用于插件以及核心 bundle。
介绍 services.php
*Bundle/Config/services.php 是存储 PHP 服务特殊情况的正确位置。通过这样做,Mautic 更接近 Symfony 的默认应用程序。在 Mautic 5 的生命周期结束时,理想状态是所有服务都已自动注入或定义在 services.php 文件中。
如果您的插件没有此文件,它将使用 :xref:`default_services_config。 它排除了 Mautic bundle 应排除的经典目录,并为您自动将实体存储库作为服务注册。
但是,每个 bundle 都应该有自己的 services.php 文件,因为每个 bundle 负责定义其自身的服务。一个基本的 services.php 文件如下所示:
<?php
declare(strict_types=1);
use Mautic\CoreBundle\DependencyInjection\MauticCoreExtension;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return function (ContainerConfigurator $configurator) {
$services = $configurator->services()
->defaults()
->autowire()
->autoconfigure()
->public();
$excludes = [
'SomeDirectoryYouWantToExclude',
];
$services->load('MauticPlugin\\[YourPluginName]Bundle\\', '../')
->exclude('../{'.implode(',', array_merge(MauticCoreExtension::DEFAULT_EXCLUDES, $excludes)).'}');
};
Note
将 [YourPluginName] 替换为您的插件名称。
这允许您声明 bundle 服务是自动注入和自动配置的。默认情况下,所有服务都应该是私有的,但 Controller 和其他旧服务直接从容器加载依赖项,而不是通过构造函数使用依赖注入。关于这一点,请参见下面的内容。
您可以在 $excludes 数组中定义希望排除的目录或文件。稍后,它们将与默认排除的所有目录合并,并存储在 MauticCoreExtension::DEFAULT_EXCLUDES 常量中。
如果您希望将实体仓库作为服务加载,可以使用以下行:
$services->load('MauticPlugin\\[YourPluginName]Bundle\\Entity\\', '../Entity/*Repository.php');
大多数 Mautic bundle 将实体(DTO 对象)和存储库(服务)放在同一个目录中,因此采用这种方法。默认情况下排除 Entity 目录,现在您必须仅选择以 Repository.php 结尾的文件,并将它们作为服务加载。
要使用 services.php 文件,您必须为您的 bundle 创建一个 Extension 文件。以下是一个示例:
// *Bundle/DependencyInjection/[YourPluginName]Extension.php
<?php
declare(strict_types=1);
namespace MauticPlugin\[YourPluginName]Bundle\DependencyInjection;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;
use Symfony\Component\DependencyInjection\Loader\PhpFileLoader;
class Mautic[YourPluginName]Extension extends Extension
{
/**
* @param mixed[] $configs
*/
public function load(array $configs, ContainerBuilder $container): void
{
$loader = new PhpFileLoader($container, new FileLocator(__DIR__.'/../Config'));
$loader->load('services.php');
}
}
命名对于 Mautic 能够使用此文件非常重要。它必须位于 DependencyInjection 目录中,并且您必须将其命名为 bundle 的根目录中的主 bundle 类相同的名称。因此,如果您的文件名例如是 MauticConfigBundle.php,那么您必须将此新文件的名称设置为 DependencyInjection/MauticConfigExtension.php。
将 Bundle.php 替换为 Extension.php,即可获得此新文件的名称。
为什么从自动注入中排除目录?
如果您不从自动注入中排除目录,Symfony 会尝试自动注入所有 PHP 类,这在某些情况下会失败。例如,DTO 或值对象类不应该被自动注入。它们是在应用程序执行期间创建的,并且不是旨在成为服务的。此类包括实体或事件。以下是完整的目录列表:xref:excluded_directories。
如何迁移?
只要您喜欢删除不必要代码,您就会享受这个过程。
移除 Commands、Subscribers 和 Forms
一个有趣的事实是,**命令**自从 Mautic 3 开始就支持自动注入。因此,您可以从 config.php 中删除它们,清除缓存,它们将像以前一样工作。
在 Mautic 5 中,您可以删除 订阅者 和 表单 的服务定义,因为它们不被用作其他服务的依赖项。
关于核心模块的服务兼容性
对于核心模块,重要的是要考虑向后兼容性并维护服务别名。如果您是插件开发者,可以直接使用完全限定类名 (FQCN)。如果这样做,请将新版本的插件发布为主要版本,以警告您的插件的用户。您永远不知道用户如何在生产环境中使用的插件。
在核心模块中,保留服务别名。例如,对于以下服务定义:
```php // config.php ‘mautic.campaign.model.campaign’ => [
‘class’ => MauticCampaignBundleModelCampaignModel::class, ‘arguments’ => [
‘mautic.lead.model.list’, ‘mautic.form.model.form’, ‘mautic.campaign.event_collector’, ‘mautic.campaign.membership.builder’, ‘mautic.tracker.contact’,
],
],
您可以删除所有前面的代码,并像这样创建别名:
`php
// services.php
$services->alias('mautic.campaign.model.campaign', \Mautic\CampaignBundle\Model\CampaignModel::class);
`
您也可以跳过创建别名的步骤,删除 config.php 中的所有服务定义,并将所有字符串服务定义替换为直接从容器加载的完全限定类名:
`diff
- $container->get('mautic.campaign.model.campaign');
+ $container->get(\Mautic\CampaignBundle\Model\CampaignModel::class);
`
使用接口而不是实现
Symfony 会在您的服务中使用例如 Http\Adapter\Guzzle7\Client 作为依赖项,而不是其接口 Psr\Http\Client\ClientInterface 时发出警告。不用担心,错误消息会明确告知您这一点。
特殊情况
某些服务不仅需要其他服务作为依赖项,有时还需要参数。例如,以下服务:
```php // config.php ‘mautic.config.form.escape_transformer’ => [
‘class’ => MauticConfigBundleFormTypeEscapeTransformer::class, ‘arguments’ => [
‘%mautic.config_allowed_parameters%’,
],
],
如果您删除此定义并让自动注入来处理它,您将收到以下错误消息:
无法自动注入服务 “MauticConfigBundleFormTypeEscapeTransformer”: __construct() 方法的参数 “$allowedParameters” 提示类型为 “array”,您应该显式配置其值。
它不知道要传递哪个数组参数。因此,您必须定义它:
- // services.php
$services->get(MauticConfigBundleFormTypeEscapeTransformer::class)->arg(‘$allowedParameters’, ‘%mautic.config_allowed_parameters%’);
最大的优势是,Mautic正在变得更接近一个标准的Symfony应用程序,它具有自动依赖注入功能,因此所有这些特殊情况都已在 :xref:`manually_wiring_arguments`中进行了详细记录。
控制器中的依赖注入
控制器可以使用经典的依赖注入或:xref:action_based_di。 如果您只需要在单个操作中使用依赖项,请使用后一种选项。 对于新的控制器,请考虑:xref:invokable_controllers。