mirror of
https://github.com/Sylius/Sylius.git
synced 2026-07-14 09:02:12 +00:00
Refactor template events related code - extract registry & renderer
This commit is contained in:
parent
05c9e8fc7d
commit
6566f7227d
16 changed files with 352 additions and 124 deletions
|
|
@ -10,9 +10,15 @@ parameters:
|
|||
- '**/DependencyInjection/Configuration.php'
|
||||
|
||||
# Test dependencies
|
||||
- '**/Bundle/*/spec/**.php'
|
||||
- '**/Bundle/*/test/app/**.php'
|
||||
- '**/Bundle/*/test/src/**.php'
|
||||
- '**/Bundle/*/Tests/Functional/app/**.php'
|
||||
- '**/Bundle/*/Tests/Functional/var/**.php'
|
||||
|
||||
# Vendor files in subpackages
|
||||
- '**/Bundle/*/vendor/**.php'
|
||||
- '**/Component/*/vendor/**.php'
|
||||
|
||||
# These packages aren't in require-dev of the global package
|
||||
- '**MongoDB**'
|
||||
|
|
|
|||
|
|
@ -13,8 +13,11 @@ declare(strict_types=1);
|
|||
|
||||
namespace Sylius\Bundle\UiBundle\DependencyInjection;
|
||||
|
||||
use Sylius\Bundle\UiBundle\Registry\TemplateBlock;
|
||||
use Sylius\Bundle\UiBundle\Registry\TemplateBlockRegistryInterface;
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
|
||||
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
|
||||
use Zend\Stdlib\SplPriorityQueue;
|
||||
|
|
@ -36,27 +39,22 @@ final class SyliusUiExtension extends Extension
|
|||
*/
|
||||
private function loadEvents(array $eventsConfig, ContainerBuilder $container): void
|
||||
{
|
||||
$templateEventExtensionDefinition = $container->getDefinition('sylius.twig.extension.template_event');
|
||||
$templateBlockRegistryDefinition = $container->findDefinition(TemplateBlockRegistryInterface::class);
|
||||
|
||||
$blocksForEvents = [];
|
||||
foreach ($eventsConfig as $eventName => $eventConfiguration) {
|
||||
$blocksPriorityQueue = new SplPriorityQueue();
|
||||
|
||||
foreach ($eventConfiguration['blocks'] as $blockName => $details) {
|
||||
if (!$details['enabled']) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$blocksPriorityQueue->insert($details['template'], $details['priority']);
|
||||
}
|
||||
|
||||
if ($blocksPriorityQueue->count() === 0) {
|
||||
continue;
|
||||
$blocksPriorityQueue->insert(
|
||||
new Definition(TemplateBlock::class, [$blockName, $details['template'], $details['priority'], $details['enabled']]),
|
||||
$details['priority']
|
||||
);
|
||||
}
|
||||
|
||||
$blocksForEvents[$eventName] = $blocksPriorityQueue->toArray();
|
||||
}
|
||||
|
||||
$templateEventExtensionDefinition->setArgument(1, $blocksForEvents);
|
||||
$templateBlockRegistryDefinition->setArgument(0, $blocksForEvents);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
61
src/Sylius/Bundle/UiBundle/Registry/TemplateBlock.php
Normal file
61
src/Sylius/Bundle/UiBundle/Registry/TemplateBlock.php
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Paweł Jędrzejewski
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sylius\Bundle\UiBundle\Registry;
|
||||
|
||||
final class TemplateBlock
|
||||
{
|
||||
/** @var string */
|
||||
private $name;
|
||||
|
||||
/** @var string */
|
||||
private $template;
|
||||
|
||||
/** @var int */
|
||||
private $priority;
|
||||
|
||||
/** @var bool */
|
||||
private $enabled;
|
||||
|
||||
public function __construct(
|
||||
string $name,
|
||||
string $template,
|
||||
int $priority,
|
||||
bool $enabled
|
||||
) {
|
||||
$this->name = $name;
|
||||
$this->template = $template;
|
||||
$this->priority = $priority;
|
||||
$this->enabled = $enabled;
|
||||
}
|
||||
|
||||
public function name(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function template(): string
|
||||
{
|
||||
return $this->template;
|
||||
}
|
||||
|
||||
public function priority(): int
|
||||
{
|
||||
return $this->priority;
|
||||
}
|
||||
|
||||
public function enabled(): bool
|
||||
{
|
||||
return $this->enabled;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Paweł Jędrzejewski
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sylius\Bundle\UiBundle\Registry;
|
||||
|
||||
final class TemplateBlockRegistry implements TemplateBlockRegistryInterface
|
||||
{
|
||||
/** @psalm-var array<string, list<TemplateBlock>> */
|
||||
private $eventsToTemplateBlocks;
|
||||
|
||||
public function __construct(array $eventsToTemplateBlocks)
|
||||
{
|
||||
$this->eventsToTemplateBlocks = $eventsToTemplateBlocks;
|
||||
}
|
||||
|
||||
public function all(): array
|
||||
{
|
||||
return $this->eventsToTemplateBlocks;
|
||||
}
|
||||
|
||||
public function findEnabledForEvent(string $eventName): array
|
||||
{
|
||||
return array_values(array_filter(
|
||||
$this->eventsToTemplateBlocks[$eventName] ?? [],
|
||||
static function (TemplateBlock $templateBlock): bool {
|
||||
return $templateBlock->enabled();
|
||||
}
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Paweł Jędrzejewski
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sylius\Bundle\UiBundle\Registry;
|
||||
|
||||
interface TemplateBlockRegistryInterface
|
||||
{
|
||||
/**
|
||||
* @return TemplateBlock[][]
|
||||
*
|
||||
* @psalm-return array<string, list<TemplateBlock>>
|
||||
*/
|
||||
public function all(): array;
|
||||
|
||||
/**
|
||||
* @return TemplateBlock[]
|
||||
*
|
||||
* @psalm-return list<TemplateBlock>
|
||||
*/
|
||||
public function findEnabledForEvent(string $eventName): array;
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Paweł Jędrzejewski
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sylius\Bundle\UiBundle\Renderer;
|
||||
|
||||
use Sylius\Bundle\UiBundle\Registry\TemplateBlockRegistryInterface;
|
||||
use Twig\Environment;
|
||||
|
||||
final class TemplateEventRenderer implements TemplateEventRendererInterface
|
||||
{
|
||||
/** @var TemplateBlockRegistryInterface */
|
||||
private $templateBlockRegistry;
|
||||
|
||||
/** @var Environment */
|
||||
private $twig;
|
||||
|
||||
/** @var bool */
|
||||
private $debug;
|
||||
|
||||
public function __construct(TemplateBlockRegistryInterface $templateBlockRegistry, Environment $twig, bool $debug)
|
||||
{
|
||||
$this->templateBlockRegistry = $templateBlockRegistry;
|
||||
$this->twig = $twig;
|
||||
$this->debug = $debug;
|
||||
}
|
||||
|
||||
public function render(string $eventName, array $context = []): string
|
||||
{
|
||||
$templateBlocks = $this->templateBlockRegistry->findEnabledForEvent($eventName);
|
||||
$renderedTemplates = [];
|
||||
|
||||
foreach ($templateBlocks as $templateBlock) {
|
||||
if ($this->debug && strrpos($templateBlock->template(), '.html.twig') !== false) {
|
||||
$renderedTemplates[] = sprintf(
|
||||
'<!-- event name: "%s", block name: "%s", template: "%s", priority: %d -->',
|
||||
$eventName,
|
||||
$templateBlock->name(),
|
||||
$templateBlock->template(),
|
||||
$templateBlock->priority()
|
||||
);
|
||||
}
|
||||
$renderedTemplates[] = $this->twig->render($templateBlock->template(), $context);
|
||||
}
|
||||
|
||||
return implode("\n", $renderedTemplates);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Paweł Jędrzejewski
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sylius\Bundle\UiBundle\Renderer;
|
||||
|
||||
interface TemplateEventRendererInterface
|
||||
{
|
||||
public function render(string $eventName, array $context = []): string;
|
||||
}
|
||||
|
|
@ -15,12 +15,7 @@
|
|||
<imports>
|
||||
<import resource="services/controller.xml" />
|
||||
<import resource="services/form.xml" />
|
||||
<import resource="services/template_event.xml" />
|
||||
<import resource="services/twig.xml" />
|
||||
</imports>
|
||||
|
||||
<services>
|
||||
<service id="sylius.ui.sonata_multiple_block_event_listener" class="Sylius\Bundle\UiBundle\Block\MultipleBlockEventListener">
|
||||
<argument type="collection" />
|
||||
</service>
|
||||
</services>
|
||||
</container>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
|
||||
This file is part of the Sylius package.
|
||||
|
||||
(c) Paweł Jędrzejewski
|
||||
|
||||
For the full copyright and license information, please view the LICENSE
|
||||
file that was distributed with this source code.
|
||||
|
||||
-->
|
||||
|
||||
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
|
||||
<services>
|
||||
<service id="Sylius\Bundle\UiBundle\Registry\TemplateBlockRegistryInterface" class="Sylius\Bundle\UiBundle\Registry\TemplateBlockRegistry">
|
||||
<argument type="collection" />
|
||||
</service>
|
||||
|
||||
<service id="Sylius\Bundle\UiBundle\Renderer\TemplateEventRendererInterface" class="Sylius\Bundle\UiBundle\Renderer\TemplateEventRenderer">
|
||||
<argument type="service" id="Sylius\Bundle\UiBundle\Registry\TemplateBlockRegistryInterface" />
|
||||
<argument type="service" id="twig" />
|
||||
<argument>%kernel.debug%</argument>
|
||||
</service>
|
||||
</services>
|
||||
</container>
|
||||
|
|
@ -34,8 +34,7 @@
|
|||
</service>
|
||||
|
||||
<service id="sylius.twig.extension.template_event" class="Sylius\Bundle\UiBundle\Twig\TemplateEventExtension" public="false">
|
||||
<argument type="service" id="twig" />
|
||||
<argument type="collection" />
|
||||
<argument type="service" id="Sylius\Bundle\UiBundle\Renderer\TemplateEventRendererInterface" />
|
||||
<tag name="twig.extension" />
|
||||
</service>
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,9 @@ namespace Sylius\Bundle\UiBundle\Tests\DependencyInjection;
|
|||
|
||||
use Matthias\SymfonyDependencyInjectionTest\PhpUnit\AbstractExtensionTestCase;
|
||||
use Sylius\Bundle\UiBundle\DependencyInjection\SyliusUiExtension;
|
||||
use Sylius\Bundle\UiBundle\Registry\TemplateBlock;
|
||||
use Sylius\Bundle\UiBundle\Registry\TemplateBlockRegistryInterface;
|
||||
use Symfony\Component\DependencyInjection\Definition;
|
||||
|
||||
final class SyliusUiExtensionTest extends AbstractExtensionTestCase
|
||||
{
|
||||
|
|
@ -32,39 +35,20 @@ final class SyliusUiExtensionTest extends AbstractExtensionTestCase
|
|||
]]);
|
||||
|
||||
$this->assertContainerBuilderHasServiceDefinitionWithArgument(
|
||||
'sylius.twig.extension.template_event',
|
||||
1,
|
||||
TemplateBlockRegistryInterface::class,
|
||||
0,
|
||||
[
|
||||
'first_event' => [
|
||||
'first.html.twig',
|
||||
'second.html.twig',
|
||||
new Definition(TemplateBlock::class, ['first_block', 'first.html.twig', 0, true]),
|
||||
new Definition(TemplateBlock::class, ['second_block', 'second.html.twig', 0, true]),
|
||||
],
|
||||
'second_event' => [
|
||||
'another.html.twig',
|
||||
new Definition(TemplateBlock::class, ['another_block', 'another.html.twig', 0, true]),
|
||||
],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_does_not_register_disabled_blocks(): void
|
||||
{
|
||||
$this->load(['events' => [
|
||||
'event_name' => ['blocks' => [
|
||||
'first_block' => ['template' => 'first.html.twig', 'enabled' => false, 'priority' => 0],
|
||||
'second_block' => ['template' => 'second.html.twig', 'enabled' => true, 'priority' => 0],
|
||||
]],
|
||||
]]);
|
||||
|
||||
$this->assertContainerBuilderHasServiceDefinitionWithArgument(
|
||||
'sylius.twig.extension.template_event',
|
||||
1,
|
||||
['event_name' => [
|
||||
'second.html.twig',
|
||||
]]
|
||||
);
|
||||
}
|
||||
|
||||
/** @test */
|
||||
public function it_sorts_blocks_by_their_priority_and_uses_fifo_ordering(): void
|
||||
{
|
||||
|
|
@ -78,13 +62,13 @@ final class SyliusUiExtensionTest extends AbstractExtensionTestCase
|
|||
]]);
|
||||
|
||||
$this->assertContainerBuilderHasServiceDefinitionWithArgument(
|
||||
'sylius.twig.extension.template_event',
|
||||
1,
|
||||
TemplateBlockRegistryInterface::class,
|
||||
0,
|
||||
['event_name' => [
|
||||
'first.html.twig',
|
||||
'second.html.twig',
|
||||
'third.html.twig',
|
||||
'fourth.html.twig',
|
||||
new Definition(TemplateBlock::class, ['first_block', 'first.html.twig', 5, true]),
|
||||
new Definition(TemplateBlock::class, ['second_block', 'second.html.twig', 0, true]),
|
||||
new Definition(TemplateBlock::class, ['third_block', 'third.html.twig', 0, true]),
|
||||
new Definition(TemplateBlock::class, ['fourth_block', 'fourth.html.twig', -5, true]),
|
||||
]]
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ use Twig\TwigFilter;
|
|||
|
||||
final class MergeRecursiveExtension extends AbstractExtension
|
||||
{
|
||||
public function getFilters(): array
|
||||
public function getFilters(): array
|
||||
{
|
||||
return [
|
||||
new TwigFilter(
|
||||
|
|
|
|||
|
|
@ -13,45 +13,24 @@ declare(strict_types=1);
|
|||
|
||||
namespace Sylius\Bundle\UiBundle\Twig;
|
||||
|
||||
use Twig\Environment;
|
||||
use Sylius\Bundle\UiBundle\Renderer\TemplateEventRendererInterface;
|
||||
use Twig\Extension\AbstractExtension;
|
||||
use Twig\TwigFunction;
|
||||
|
||||
final class TemplateEventExtension extends AbstractExtension
|
||||
{
|
||||
/** @var Environment */
|
||||
private $twig;
|
||||
/** @var TemplateEventRendererInterface */
|
||||
private $templateEventRenderer;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*
|
||||
* @psalm-var array<string, list<string>>
|
||||
*/
|
||||
private $eventsToTemplates;
|
||||
|
||||
public function __construct(Environment $twig, array $eventsToTemplates)
|
||||
public function __construct(TemplateEventRendererInterface $templateEventRenderer)
|
||||
{
|
||||
$this->twig = $twig;
|
||||
$this->eventsToTemplates = $eventsToTemplates;
|
||||
$this->templateEventRenderer = $templateEventRenderer;
|
||||
}
|
||||
|
||||
public function getFunctions(): array
|
||||
{
|
||||
return [
|
||||
new TwigFunction('sylius_template_event', [$this, 'renderBlocksForEvent'], ['is_safe' => ['html']]),
|
||||
new TwigFunction('sylius_template_event', [$this->templateEventRenderer, 'render'], ['is_safe' => ['html']]),
|
||||
];
|
||||
}
|
||||
|
||||
public function renderBlocksForEvent(string $event, array $options = []): string
|
||||
{
|
||||
$templates = $this->eventsToTemplates[$event] ?? [];
|
||||
|
||||
$renderedTemplates = [];
|
||||
|
||||
foreach ($templates as $template) {
|
||||
$renderedTemplates[] = $this->twig->render($template, $options);
|
||||
}
|
||||
|
||||
return implode("\n", $renderedTemplates);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Paweł Jędrzejewski
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace spec\Sylius\Bundle\UiBundle\Registry;
|
||||
|
||||
use PhpSpec\ObjectBehavior;
|
||||
use Sylius\Bundle\UiBundle\Registry\TemplateBlock;
|
||||
use Sylius\Bundle\UiBundle\Registry\TemplateBlockRegistryInterface;
|
||||
|
||||
final class TemplateBlockRegistrySpec extends ObjectBehavior
|
||||
{
|
||||
function let(): void
|
||||
{
|
||||
$this->beConstructedWith([]);
|
||||
}
|
||||
|
||||
function it_is_a_template_block_registry(): void
|
||||
{
|
||||
$this->shouldImplement(TemplateBlockRegistryInterface::class);
|
||||
}
|
||||
|
||||
function it_returns_all_template_blocks(): void
|
||||
{
|
||||
$templateBlock = new TemplateBlock('block_name', 'block.html.twig', 10, true);
|
||||
|
||||
$this->beConstructedWith(['event' => [$templateBlock]]);
|
||||
|
||||
$this->all()->shouldReturn(['event' => [$templateBlock]]);
|
||||
}
|
||||
|
||||
function it_returns_enabled_template_blocks_for_a_given_event(): void
|
||||
{
|
||||
$firstTemplateBlock = new TemplateBlock('first_block', 'first.html.twig', 0, true);
|
||||
$secondTemplateBlock = new TemplateBlock('second_block', 'second.html.twig', 10, false);
|
||||
$thirdTemplateBlock = new TemplateBlock('third_block', 'third.html.twig', 50, true);
|
||||
|
||||
$this->beConstructedWith(['event' => [$firstTemplateBlock, $secondTemplateBlock], 'another_event' => [$thirdTemplateBlock]]);
|
||||
|
||||
$this->findEnabledForEvent('event')->shouldReturn([$firstTemplateBlock]);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Paweł Jędrzejewski
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace spec\Sylius\Bundle\UiBundle\Registry;
|
||||
|
||||
use PhpSpec\ObjectBehavior;
|
||||
|
||||
final class TemplateBlockSpec extends ObjectBehavior
|
||||
{
|
||||
function it_represents_a_template_block(): void
|
||||
{
|
||||
$this->beConstructedWith('block_name', 'block.html.twig', 10, false);
|
||||
|
||||
$this->name()->shouldReturn('block_name');
|
||||
$this->template()->shouldReturn('block.html.twig');
|
||||
$this->priority()->shouldReturn(10);
|
||||
$this->enabled()->shouldReturn(false);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,47 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Sylius package.
|
||||
*
|
||||
* (c) Paweł Jędrzejewski
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace spec\Sylius\Bundle\UiBundle\Twig;
|
||||
|
||||
use PhpSpec\ObjectBehavior;
|
||||
use Prophecy\Argument;
|
||||
use Twig\Environment;
|
||||
|
||||
final class TemplateEventExtensionSpec extends ObjectBehavior
|
||||
{
|
||||
function it_renders_blocks_for_given_event(Environment $twig): void
|
||||
{
|
||||
$this->beConstructedWith($twig, [
|
||||
'event_name' => [
|
||||
'first.html.twig',
|
||||
'second.html.twig',
|
||||
],
|
||||
]);
|
||||
|
||||
$twig->render('first.html.twig', ['option' => 'value'])->willReturn('First template');
|
||||
$twig->render('second.html.twig', ['option' => 'value'])->willReturn('Second template');
|
||||
|
||||
$this->renderBlocksForEvent('event_name', ['option' => 'value'])->shouldReturn(
|
||||
"First template\nSecond template"
|
||||
);
|
||||
}
|
||||
|
||||
function it_returns_empty_string_if_there_are_no_blocks_registered_for_given_event(Environment $twig): void
|
||||
{
|
||||
$this->beConstructedWith($twig, ['event_name' => ['first.html.twig']]);
|
||||
|
||||
$twig->render(Argument::cetera())->shouldNotBeCalled();
|
||||
|
||||
$this->renderBlocksForEvent('another_event')->shouldReturn('');
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue