让我们谈谈如何停止项目之间的复制粘贴并将代码转移到可重复使用的插件包Symfony 5中。在实践中总结了一系列关于包的经验的文章,将从创建最小的包,重构演示应用程序到测试以及包发布周期的实践中进行。
设计捆绑包时,您需要考虑应将其封装在捆绑包中,以及用户应该可以访问的内容。捆绑软件应该具有固定功能还是应该具有灵活性并允许其自身扩展?如果需要灵活性,那么您需要提供一些集成点来扩展捆绑软件及其界面。
让我们尝试在演示应用程序中提供这些要点。在这篇文章中:
如果您不一致地完成本教程,请从存储库下载该应用程序,然后切换到3-integration分支。
有关在文件中安装和启动项目的说明README.md
。
您可以在4-extend分支中找到本文代码的最终版本。
任务
日历具有将事件导出到GoogleCalendar或iCalendar的功能。
我们的任务是使捆绑软件更加灵活,并使捆绑软件用户能够在应用程序中使用自己的导出格式对其进行扩展。
例如,将导出添加到JSON文件。让我们开始吧。

活动的导出是如何组织的?
要了解如何添加新格式,让我们看看EventExporter的工作原理。
导出逻辑在EventExporter
位于的组件中实现services/EventExporter
。我们已经将其移至包中并更正了名称空间名称。主要组件文件是:
ExporterInterface
模拟事件导出格式并ExporterManager
,
ExporterInterface
.
— , ( Google Calendar), ( iCalendar). inline. EventController::export()
, .
,
2 AbtractInlineExporter
AbstractFileExporter
. ( ), , (ExportedFile
).
2 — GoogleCalendarExporter
ICalendarExporter
.
, inline , , .
- JSON-.
:
git checkout 4-extend -- src/Service/EventExporter/JsonExporter.php
src/Service/EventExporter/JsonExporter.php
:
<?php
declare(strict_types=1);
namespace App\Service\EventExporter;
use bravik\CalendarBundle\Entity\Event;
use bravik\CalendarBundle\Service\EventExporter\AbstractFileExporter;
use bravik\CalendarBundle\Service\EventExporter\ExportedFile;
class JsonExporter extends AbstractFileExporter
{
private const DATE_FORMAT = 'Y-m-d H:i:s';
public function getName(): string
{
return ' JSON';
}
public function getType(): string
{
return 'json-file';
}
public function export(Event $event): ExportedFile
{
$data = [
'id' => $event->getId(),
'title' => $event->getTitle(),
'description' => $event->getDescription(),
'venueName' => $event->getVenueName(),
'venueAddress' => $event->getVenueAddress(),
'startsAt' => $event->getStartsAt()->format(self::DATE_FORMAT),
'endsAt' => $event->getEndsAt() ? $event->getEndsAt()->format(self::DATE_FORMAT) : null,
];
return new ExportedFile('event.json', 'application/json', json_encode($data));
}
}
DI- config/services.yaml
. ExporterManager
.
Symfony - . , , ExporterManager
services.yaml
. :
bravik\CalendarBundle\Service\EventExporter\ExporterManager:
arguments:
$exporters:
- '@bravik\CalendarBundle\Service\EventExporter\Exporters\GoogleCalendarExporter'
- '@bravik\CalendarBundle\Service\EventExporter\Exporters\ICalendarExporter'
- 'App\Service\EventExporter\Exporters\JsonExporter'
: , , , .
, - , , ExporterManager
- ? .
, . .
ExporterManager.
, , ExporterManager::registerExporter()
. . , - registerExporter
. DI-.
Symfony . — , DI- - . , ExporterManager
.
JsonExporter
services.yaml
-:
App\Service\EventExporter\JsonExporter:
tags: ['bravik.calendar.exporter']
services.yaml
:
bravik\CalendarBundle\Service\EventExporter\Exporters\GoogleCalendarExporter:
tags: ['bravik.calendar.exporter']
bravik\CalendarBundle\Service\EventExporter\Exporters\ICalendarExporter:
tags: ['bravik.calendar.exporter']
, , , vendor.package.name
.
Symfony 3.4 .
bravik.calendar.exporter
ExporterManager
. services.yaml
:
bravik\CalendarBundle\Service\EventExporter\ExporterManager:
arguments:
$exporters: !tagged bravik.calendar.exporter
!tagged <tag-name>
iterable
, . typehint ExporterManager
:
public function __construct(iterable $exporters) {
}
, .
, « » « JSON», JSON-.
( - , 4-extend .)
!tagged <tag-name>
, , — , . .
Compiler Pass
services.yaml
DI- . . Symfony , , PHP-. Symfony .
Compiler Pass. Symfony Compiler Pass.
, , ExporterManager
.
bundles/CalendarBundle/src/DependencyInjection/Compiler/ExporterRegistrationPass.php
, CompilerPassInterface
:
namespace bravik\CalendarBundle\DependencyInjection\Compiler;
use bravik\CalendarBundle\Service\EventExporter\ExporterManager;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
class ExporterRegistrationPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
if (!$container->has(ExporterManager::class)) {
return;
}
$exporterManagerDefinition = $container->findDefinition(ExporterManager::class);
$taggedServices = $container->findTaggedServiceIds('bravik.calendar.exporter');
$exporterReferences = [];
foreach ($taggedServices as $id => $tags) {
$exporterReferences[] = new Reference($id);
}
$exporterManagerDefinition->setArguments(['$exporters' => $exporterReferences]);
}
}
Compiler Pass src/CalendarBundle
. Bundle
Bundle::build()
:
public function build(ContainerBuilder $container)
{
parent::build($container);
$container->addCompilerPass(new ExporterRegistrationPass());
}
, pass , die("pass")
process
. pass
— .
?
ExporterManager
, DI-.
ExporterManager
:
$exporterManagerDefinition = $container->findDefinition(ExporterManager::class);
Definition
?
, - (Definition).
DI- , , «». Definition
«»: , .
, - . , , , DI- .
, -. bravik.calendar.exporter
.
$taggedServices = $container->findTaggedServiceIds('bravik.calendar.exporter');
, Reference
, , ExporterManager
, $exporters
.
$exporterReferences = [];
foreach ($taggedServices as $id => $tags) {
$exporterReferences[] = new Reference($id);
}
$exporterManagerDefinition->setArguments(['$exporters' => $exporterReferences]);
services.yaml
ExporterManager
:
bravik\CalendarBundle\Service\EventExporter\ExporterManager: ~
, .
(autoconfiguration)
services.yaml
.
, 2 :
bravik\CalendarBundle\Service\EventExporter\Exporters\GoogleCalendarExporter:
tags: ['bravik.calendar.exporter']
bravik\CalendarBundle\Service\EventExporter\Exporters\ICalendarExporter:
tags: ['bravik.calendar.exporter']
:
App\Service\EventExporter\JsonExporter:
tags: ['bravik.calendar.exporter']
, 3, 30 . .
, .
ExporterInterface
.
№1. _instanceof
services.yaml
:
_instanceof:
# Apply tag to all ExporterInterface implementations
bravik\CalendarBundle\Service\EventExporter\ExporterInterface:
tags: ['bravik.calendar.exporter']
— !
App\Service\EventExporter\JsonExporter
, .
, , . , .
№2. Symfony
, DependencyInjection/CalendarExtension
load()
:
public function load(array $configs, ContainerBuilder $container)
{
$container->registerForAutoconfiguration(ExporterInterface::class)
->addTag('bravik.calendar.exporter');
}
Symfony , , .
, ExporterManager
. :
# Register all EventExporter classes as injectable services
bravik\CalendarBundle\Service\EventExporter\:
resource: '../src/Service/EventExporter/*'
.
Symfony, , . Symfony: , , Compiler Pass .
4-extend.
, , Symfony .
您可以阅读有关重新定义服务以及使用服务别名创建扩展点的一些更高级的示例:
(https://symfonycasts.com/screencast/symfony-bundle/override-service#play)
该系列的其他文章:
1.部分最小包
2的一部分,我们拿出包中的代码和模板
第3部分集成与主机捆绑的:模板,样式,JS
第4部分接口扩展包
第5部分参数及配置
部分6.测试,该包内microapplication
第7发布周期,安装和更新