Merge branch '2.2' into 2.3
* 2.2:
[HttpKernel] added a check for private event listeners/subscribers
[FrameworkBundle] fixed registration of the register listener pass
[Form] Fixed regression causing invalid "WHERE id IN ()" statements
[DependencyInjection] fixed a non-detected circular reference in PhpDumper (closes #8425)
[Form] Fixed regression in BooleanToStringTransformer from ed83752
[FrameworkBundle] removed obsolete code
[Process] Close unix pipes before calling `proc_close` to avoid a deadlock
Conflicts:
src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php
src/Symfony/Component/HttpKernel/DependencyInjection/RegisterListenersPass.php
src/Symfony/Component/Process/Process.php
This commit is contained in:
commit
0f78175dcd
@ -204,6 +204,16 @@ class EntityChoiceList extends ObjectChoiceList
|
|||||||
*/
|
*/
|
||||||
public function getChoicesForValues(array $values)
|
public function getChoicesForValues(array $values)
|
||||||
{
|
{
|
||||||
|
// Performance optimization
|
||||||
|
// Also prevents the generation of "WHERE id IN ()" queries through the
|
||||||
|
// entity loader. At least with MySQL and on the development machine
|
||||||
|
// this was tested on, no exception was thrown for such invalid
|
||||||
|
// statements, consequently no test fails when this code is removed.
|
||||||
|
// https://github.com/symfony/symfony/pull/8981#issuecomment-24230557
|
||||||
|
if (empty($values)) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
if (!$this->loaded) {
|
if (!$this->loaded) {
|
||||||
// Optimize performance in case we have an entity loader and
|
// Optimize performance in case we have an entity loader and
|
||||||
// a single-field identifier
|
// a single-field identifier
|
||||||
@ -247,6 +257,11 @@ class EntityChoiceList extends ObjectChoiceList
|
|||||||
*/
|
*/
|
||||||
public function getValuesForChoices(array $entities)
|
public function getValuesForChoices(array $entities)
|
||||||
{
|
{
|
||||||
|
// Performance optimization
|
||||||
|
if (empty($entities)) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
if (!$this->loaded) {
|
if (!$this->loaded) {
|
||||||
// Optimize performance for single-field identifiers. We already
|
// Optimize performance for single-field identifiers. We already
|
||||||
// know that the IDs are used as values
|
// know that the IDs are used as values
|
||||||
@ -282,6 +297,11 @@ class EntityChoiceList extends ObjectChoiceList
|
|||||||
*/
|
*/
|
||||||
public function getIndicesForChoices(array $entities)
|
public function getIndicesForChoices(array $entities)
|
||||||
{
|
{
|
||||||
|
// Performance optimization
|
||||||
|
if (empty($entities)) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
if (!$this->loaded) {
|
if (!$this->loaded) {
|
||||||
// Optimize performance for single-field identifiers. We already
|
// Optimize performance for single-field identifiers. We already
|
||||||
// know that the IDs are used as indices
|
// know that the IDs are used as indices
|
||||||
@ -317,6 +337,11 @@ class EntityChoiceList extends ObjectChoiceList
|
|||||||
*/
|
*/
|
||||||
public function getIndicesForValues(array $values)
|
public function getIndicesForValues(array $values)
|
||||||
{
|
{
|
||||||
|
// Performance optimization
|
||||||
|
if (empty($values)) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
if (!$this->loaded) {
|
if (!$this->loaded) {
|
||||||
// Optimize performance for single-field identifiers.
|
// Optimize performance for single-field identifiers.
|
||||||
|
|
||||||
|
@ -65,7 +65,9 @@ class FrameworkBundle extends Bundle
|
|||||||
|
|
||||||
$container->addCompilerPass(new RoutingResolverPass());
|
$container->addCompilerPass(new RoutingResolverPass());
|
||||||
$container->addCompilerPass(new ProfilerPass());
|
$container->addCompilerPass(new ProfilerPass());
|
||||||
$container->addCompilerPass(new RegisterListenersPass(), PassConfig::TYPE_AFTER_REMOVING);
|
// must be registered before removing private services as some might be listeners/subscribers
|
||||||
|
// but as late as possible to get resolved parameters
|
||||||
|
$container->addCompilerPass(new RegisterListenersPass(), PassConfig::TYPE_BEFORE_REMOVING);
|
||||||
$container->addCompilerPass(new TemplatingPass());
|
$container->addCompilerPass(new TemplatingPass());
|
||||||
$container->addCompilerPass(new AddConstraintValidatorsPass());
|
$container->addCompilerPass(new AddConstraintValidatorsPass());
|
||||||
$container->addCompilerPass(new AddValidatorInitializersPass());
|
$container->addCompilerPass(new AddValidatorInitializersPass());
|
||||||
|
@ -287,13 +287,12 @@ abstract class FrameworkExtensionTest extends TestCase
|
|||||||
protected function createContainer(array $data = array())
|
protected function createContainer(array $data = array())
|
||||||
{
|
{
|
||||||
return new ContainerBuilder(new ParameterBag(array_merge(array(
|
return new ContainerBuilder(new ParameterBag(array_merge(array(
|
||||||
'kernel.bundles' => array('FrameworkBundle' => 'Symfony\\Bundle\\FrameworkBundle\\FrameworkBundle'),
|
'kernel.bundles' => array('FrameworkBundle' => 'Symfony\\Bundle\\FrameworkBundle\\FrameworkBundle'),
|
||||||
'kernel.cache_dir' => __DIR__,
|
'kernel.cache_dir' => __DIR__,
|
||||||
'kernel.compiled_classes' => array(),
|
'kernel.debug' => false,
|
||||||
'kernel.debug' => false,
|
'kernel.environment' => 'test',
|
||||||
'kernel.environment' => 'test',
|
'kernel.name' => 'kernel',
|
||||||
'kernel.name' => 'kernel',
|
'kernel.root_dir' => __DIR__,
|
||||||
'kernel.root_dir' => __DIR__,
|
|
||||||
), $data)));
|
), $data)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -441,6 +441,12 @@ class PhpDumper extends Dumper
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if the instance is simple, the return statement has already been generated
|
||||||
|
// so, the only possible way to get there is because of a circular reference
|
||||||
|
if ($this->isSimpleInstance($id, $definition)) {
|
||||||
|
throw new ServiceCircularReferenceException($id, array($id));
|
||||||
|
}
|
||||||
|
|
||||||
$name = (string) $this->definitionVariables->offsetGet($iDefinition);
|
$name = (string) $this->definitionVariables->offsetGet($iDefinition);
|
||||||
$code .= $this->addServiceMethodCalls(null, $iDefinition, $name);
|
$code .= $this->addServiceMethodCalls(null, $iDefinition, $name);
|
||||||
$code .= $this->addServiceProperties(null, $iDefinition, $name);
|
$code .= $this->addServiceProperties(null, $iDefinition, $name);
|
||||||
|
@ -181,4 +181,19 @@ class PhpDumperTest extends \PHPUnit_Framework_TestCase
|
|||||||
|
|
||||||
$this->assertSame($bar, $container->get('foo')->bar, '->set() overrides an already defined service');
|
$this->assertSame($bar, $container->get('foo')->bar, '->set() overrides an already defined service');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException
|
||||||
|
*/
|
||||||
|
public function testCircularReference()
|
||||||
|
{
|
||||||
|
$container = new ContainerBuilder();
|
||||||
|
$container->register('foo', 'stdClass')->addArgument(new Reference('bar'));
|
||||||
|
$container->register('bar', 'stdClass')->setPublic(false)->addMethodCall('setA', array(new Reference('baz')));
|
||||||
|
$container->register('baz', 'stdClass')->addMethodCall('setA', array(new Reference('foo')));
|
||||||
|
$container->compile();
|
||||||
|
|
||||||
|
$dumper = new PhpDumper($container);
|
||||||
|
$dumper->dump();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,10 @@ class BooleanToStringTransformer implements DataTransformerInterface
|
|||||||
*/
|
*/
|
||||||
public function transform($value)
|
public function transform($value)
|
||||||
{
|
{
|
||||||
|
if (null === $value) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (!is_bool($value)) {
|
if (!is_bool($value)) {
|
||||||
throw new TransformationFailedException('Expected a Boolean.');
|
throw new TransformationFailedException('Expected a Boolean.');
|
||||||
}
|
}
|
||||||
|
@ -38,12 +38,10 @@ class BooleanToStringTransformerTest extends \PHPUnit_Framework_TestCase
|
|||||||
$this->assertNull($this->transformer->transform(false));
|
$this->assertNull($this->transformer->transform(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// https://github.com/symfony/symfony/issues/8989
|
||||||
* @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
|
public function testTransformAcceptsNull()
|
||||||
*/
|
|
||||||
public function testTransformFailsIfNull()
|
|
||||||
{
|
{
|
||||||
$this->transformer->transform(null);
|
$this->assertNull($this->transformer->transform(null));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -57,6 +57,11 @@ class RegisterListenersPass implements CompilerPassInterface
|
|||||||
$definition = $container->getDefinition($this->dispatcherService);
|
$definition = $container->getDefinition($this->dispatcherService);
|
||||||
|
|
||||||
foreach ($container->findTaggedServiceIds($this->listenerTag) as $id => $events) {
|
foreach ($container->findTaggedServiceIds($this->listenerTag) as $id => $events) {
|
||||||
|
$def = $container->getDefinition($id);
|
||||||
|
if (!$def->isPublic()) {
|
||||||
|
throw new \InvalidArgumentException(sprintf('The service "%s" must be public as event listeners are lazy-loaded.', $id));
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($events as $event) {
|
foreach ($events as $event) {
|
||||||
$priority = isset($event['priority']) ? $event['priority'] : 0;
|
$priority = isset($event['priority']) ? $event['priority'] : 0;
|
||||||
|
|
||||||
@ -77,8 +82,13 @@ class RegisterListenersPass implements CompilerPassInterface
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach ($container->findTaggedServiceIds($this->subscriberTag) as $id => $attributes) {
|
foreach ($container->findTaggedServiceIds($this->subscriberTag) as $id => $attributes) {
|
||||||
|
$def = $container->getDefinition($id);
|
||||||
|
if (!$def->isPublic()) {
|
||||||
|
throw new \InvalidArgumentException(sprintf('The service "%s" must be public as event subscribers are lazy-loaded.', $id));
|
||||||
|
}
|
||||||
|
|
||||||
// We must assume that the class value has been correctly filled, even if the service is created by a factory
|
// We must assume that the class value has been correctly filled, even if the service is created by a factory
|
||||||
$class = $container->getDefinition($id)->getClass();
|
$class = $def->getClass();
|
||||||
|
|
||||||
$refClass = new \ReflectionClass($class);
|
$refClass = new \ReflectionClass($class);
|
||||||
$interface = 'Symfony\Component\EventDispatcher\EventSubscriberInterface';
|
$interface = 'Symfony\Component\EventDispatcher\EventSubscriberInterface';
|
||||||
|
@ -31,6 +31,9 @@ class RegisterListenersPassTest extends \PHPUnit_Framework_TestCase
|
|||||||
);
|
);
|
||||||
|
|
||||||
$definition = $this->getMock('Symfony\Component\DependencyInjection\Definition');
|
$definition = $this->getMock('Symfony\Component\DependencyInjection\Definition');
|
||||||
|
$definition->expects($this->atLeastOnce())
|
||||||
|
->method('isPublic')
|
||||||
|
->will($this->returnValue(true));
|
||||||
$definition->expects($this->atLeastOnce())
|
$definition->expects($this->atLeastOnce())
|
||||||
->method('getClass')
|
->method('getClass')
|
||||||
->will($this->returnValue('stdClass'));
|
->will($this->returnValue('stdClass'));
|
||||||
@ -60,6 +63,9 @@ class RegisterListenersPassTest extends \PHPUnit_Framework_TestCase
|
|||||||
);
|
);
|
||||||
|
|
||||||
$definition = $this->getMock('Symfony\Component\DependencyInjection\Definition');
|
$definition = $this->getMock('Symfony\Component\DependencyInjection\Definition');
|
||||||
|
$definition->expects($this->atLeastOnce())
|
||||||
|
->method('isPublic')
|
||||||
|
->will($this->returnValue(true));
|
||||||
$definition->expects($this->atLeastOnce())
|
$definition->expects($this->atLeastOnce())
|
||||||
->method('getClass')
|
->method('getClass')
|
||||||
->will($this->returnValue('Symfony\Component\HttpKernel\Tests\DependencyInjection\SubscriberService'));
|
->will($this->returnValue('Symfony\Component\HttpKernel\Tests\DependencyInjection\SubscriberService'));
|
||||||
@ -81,6 +87,34 @@ class RegisterListenersPassTest extends \PHPUnit_Framework_TestCase
|
|||||||
$registerListenersPass = new RegisterListenersPass();
|
$registerListenersPass = new RegisterListenersPass();
|
||||||
$registerListenersPass->process($builder);
|
$registerListenersPass->process($builder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \InvalidArgumentException
|
||||||
|
* @expectedExceptionMessage The service "foo" must be public as event listeners are lazy-loaded.
|
||||||
|
*/
|
||||||
|
public function testPrivateEventListener()
|
||||||
|
{
|
||||||
|
$container = new ContainerBuilder();
|
||||||
|
$container->register('foo', 'stdClass')->setPublic(false)->addTag('kernel.event_listener', array());
|
||||||
|
$container->register('event_dispatcher', 'stdClass');
|
||||||
|
|
||||||
|
$registerListenersPass = new RegisterListenersPass();
|
||||||
|
$registerListenersPass->process($container);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \InvalidArgumentException
|
||||||
|
* @expectedExceptionMessage The service "foo" must be public as event subscribers are lazy-loaded.
|
||||||
|
*/
|
||||||
|
public function testPrivateEventSubscriber()
|
||||||
|
{
|
||||||
|
$container = new ContainerBuilder();
|
||||||
|
$container->register('foo', 'stdClass')->setPublic(false)->addTag('kernel.event_subscriber', array());
|
||||||
|
$container->register('event_dispatcher', 'stdClass');
|
||||||
|
|
||||||
|
$registerListenersPass = new RegisterListenersPass();
|
||||||
|
$registerListenersPass->process($container);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SubscriberService implements \Symfony\Component\EventDispatcher\EventSubscriberInterface
|
class SubscriberService implements \Symfony\Component\EventDispatcher\EventSubscriberInterface
|
||||||
|
@ -1053,9 +1053,14 @@ class Process
|
|||||||
$exitcode = -1;
|
$exitcode = -1;
|
||||||
|
|
||||||
if (is_resource($this->process)) {
|
if (is_resource($this->process)) {
|
||||||
|
// Unix pipes must be closed before calling proc_close to void deadlock
|
||||||
|
// see manual http://php.net/manual/en/function.proc-close.php
|
||||||
|
$this->processPipes->closeUnixPipes();
|
||||||
$exitcode = proc_close($this->process);
|
$exitcode = proc_close($this->process);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Windows only : when using file handles, some activity may occur after
|
||||||
|
// calling proc_close
|
||||||
while ($this->processPipes->hasOpenHandles()) {
|
while ($this->processPipes->hasOpenHandles()) {
|
||||||
usleep(100);
|
usleep(100);
|
||||||
foreach ($this->processPipes->readAndCloseHandles(true) as $type => $data) {
|
foreach ($this->processPipes->readAndCloseHandles(true) as $type => $data) {
|
||||||
|
@ -77,14 +77,24 @@ class ProcessPipes
|
|||||||
*/
|
*/
|
||||||
public function close()
|
public function close()
|
||||||
{
|
{
|
||||||
foreach ($this->pipes as $offset => $pipe) {
|
$this->closeUnixPipes();
|
||||||
fclose($pipe);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($this->fileHandles as $offset => $handle) {
|
foreach ($this->fileHandles as $offset => $handle) {
|
||||||
fclose($handle);
|
fclose($handle);
|
||||||
}
|
}
|
||||||
$this->fileHandles = $this->pipes = array();
|
$this->fileHandles = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes unix pipes.
|
||||||
|
*
|
||||||
|
* Nothing happens in case file handles are used.
|
||||||
|
*/
|
||||||
|
public function closeUnixPipes()
|
||||||
|
{
|
||||||
|
foreach ($this->pipes as $pipe) {
|
||||||
|
fclose($pipe);
|
||||||
|
}
|
||||||
|
$this->pipes = array();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Reference in New Issue
Block a user