Skip to content

Commit

Permalink
avoid BC break when using custom resolver classes
Browse files Browse the repository at this point in the history
  • Loading branch information
dmaicher committed Apr 9, 2019
1 parent 2c526bc commit 2d99dde
Show file tree
Hide file tree
Showing 5 changed files with 140 additions and 11 deletions.
36 changes: 25 additions & 11 deletions DependencyInjection/Compiler/EntityListenerPass.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

namespace Doctrine\Bundle\DoctrineBundle\DependencyInjection\Compiler;

use Doctrine\Bundle\DoctrineBundle\Mapping\ContainerEntityListenerResolver;
use Doctrine\Bundle\DoctrineBundle\Mapping\EntityListenerServiceResolver;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Reference;

Expand Down Expand Up @@ -45,13 +47,8 @@ public function process(ContainerBuilder $container)
$this->attachToListener($container, $name, $id, $attributes);
}

$class = $resolver->getClass();

if (substr($class, 0, 1) === '%') {
// resolve container parameter first
$class = $container->getParameterBag()->resolveValue($resolver->getClass());
}
$resolverSupportsLazyListeners = is_a($class, EntityListenerServiceResolver::class, true);
$resolverClass = $this->getResolverClass($resolver, $container);
$resolverSupportsLazyListeners = is_a($resolverClass, EntityListenerServiceResolver::class, true);

$lazyByAttribute = isset($attributes['lazy']) && $attributes['lazy'];
if ($lazyByAttribute && ! $resolverSupportsLazyListeners) {
Expand All @@ -70,18 +67,23 @@ public function process(ContainerBuilder $container)

$resolver->addMethodCall('registerService', [$listener->getClass(), $id]);

if (! isset($lazyServiceReferencesByResolver[$resolverId])) {
$lazyServiceReferencesByResolver[$resolverId] = [];
// if the resolver uses the default class we will use a service locator for all listeners
if ($resolverClass === ContainerEntityListenerResolver::class) {
if (! isset($lazyServiceReferencesByResolver[$resolverId])) {
$lazyServiceReferencesByResolver[$resolverId] = [];
}
$lazyServiceReferencesByResolver[$resolverId][$id] = new Reference($id);
} else {
$listener->setPublic(true);
}
$lazyServiceReferencesByResolver[$resolverId][$id] = new Reference($id);
} else {
$resolver->addMethodCall('register', [new Reference($id)]);
}
}
}

foreach ($lazyServiceReferencesByResolver as $resolverId => $listenerReferences) {
$container->findDefinition($resolverId)->replaceArgument(0, ServiceLocatorTagPass::register($container, $listenerReferences));
$container->findDefinition($resolverId)->setArgument(0, ServiceLocatorTagPass::register($container, $listenerReferences));
}
}

Expand All @@ -107,4 +109,16 @@ private function attachToListener(ContainerBuilder $container, $name, $id, array

$container->findDefinition($listenerId)->addMethodCall('addEntityListener', $args);
}

private function getResolverClass(Definition $resolver, ContainerBuilder $container) : string
{
$resolverClass = $resolver->getClass();

if (substr($resolverClass, 0, 1) === '%') {
// resolve container parameter first
$resolverClass = $container->getParameterBag()->resolveValue($resolver->getClass());
}

return $resolverClass;
}
}
18 changes: 18 additions & 0 deletions Tests/DependencyInjection/AbstractDoctrineExtensionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -909,6 +909,24 @@ public function testAttachLazyEntityListener()
$this->assertDICDefinitionMethodCallOnce($resolver2, 'registerService', ['EntityListener2', 'entity_listener2']);
}

public function testAttachLazyEntityListenerForCustomResolver()
{
$container = $this->getContainer([]);
$loader = new DoctrineExtension();
$container->registerExtension($loader);
$container->addCompilerPass(new EntityListenerPass());

$this->loadFromFile($container, 'orm_entity_listener_custom_resolver');

$this->compileContainer($container);

$resolver = $container->getDefinition('custom_entity_listener_resolver');
$this->assertTrue($resolver->isPublic());
$this->assertEmpty($resolver->getArguments(), 'We must not change the arguments for custom services.');
$this->assertDICDefinitionMethodCallOnce($resolver, 'registerService', ['EntityListener', 'entity_listener']);
$this->assertTrue($container->getDefinition('entity_listener')->isPublic());
}

/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage EntityListenerServiceResolver
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

namespace Doctrine\Bundle\DoctrineBundle\Tests\DependencyInjection\Fixtures;

use Doctrine\Bundle\DoctrineBundle\Mapping\EntityListenerServiceResolver;

class CustomEntityListenerServiceResolver implements EntityListenerServiceResolver
{
/** @var EntityListenerServiceResolver */
private $resolver;

public function __construct(EntityListenerServiceResolver $resolver)
{
$this->resolver = $resolver;
}

/**
* {@inheritdoc}
*/
public function clear($className = null)
{
$this->resolver->clear($className);
}

/**
* {@inheritdoc}
*/
public function resolve($className)
{
return $this->resolver->resolve($className);
}

/**
* {@inheritdoc}
*/
public function register($object)
{
$this->resolver->register($object);
}

/**
* {@inheritdoc}
*/
public function registerService($className, $serviceId)
{
$this->resolver->registerService($className, $serviceId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?xml version="1.0" ?>

<container xmlns="http://symfony.com/schema/dic/services"
xmlns:doctrine="http://symfony.com/schema/dic/doctrine"
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
http://symfony.com/schema/dic/doctrine http://symfony.com/schema/dic/doctrine/doctrine-1.0.xsd">

<services>
<service id="custom_entity_listener_resolver" class="Doctrine\Bundle\DoctrineBundle\Tests\DependencyInjection\Fixtures\CustomEntityListenerServiceResolver" public="false"></service>

<service id="entity_listener" class="EntityListener" public="false">
<tag name="doctrine.orm.entity_listener" />
</service>
</services>

<doctrine:config>
<doctrine:dbal default-connection="default">
<doctrine:connection name="default" dbname="db" />
</doctrine:dbal>

<doctrine:orm default-entity-manager="em1">
<doctrine:entity-manager name="em1" entity-listener-resolver="custom_entity_listener_resolver" />
</doctrine:orm>
</doctrine:config>
</container>
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
services:
custom_entity_listener_resolver:
class: Doctrine\Bundle\DoctrineBundle\Tests\DependencyInjection\Fixtures\CustomEntityListenerServiceResolver
public: false

entity_listener:
class: EntityListener
public: false
tags:
- { name: doctrine.orm.entity_listener }

doctrine:
dbal:
default_connection: default
connections:
default:
dbname: db

orm:
default_entity_manager: em1
entity_managers:
em1:
entity_listener_resolver: custom_entity_listener_resolver

0 comments on commit 2d99dde

Please sign in to comment.