Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[DX][DI] Add compiler pass which check extistence of service class name #11315

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,8 @@ public function testGetControllerOnNonUndefinedFunction($controller, $exceptionN
public function getUndefinedControllers()
{
return array(
array('foo', '\LogicException', 'Unable to parse the controller name "foo".'),
array('foo::bar', '\InvalidArgumentException', 'Class "foo" does not exist.'),
array('myfoo', '\LogicException', 'Unable to parse the controller name "myfoo".'),
array('myfoo::bar', '\InvalidArgumentException', 'Class "myfoo" does not exist.'),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why changing these tests ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

array('stdClass', '\LogicException', 'Unable to parse the controller name "stdClass".'),
array(
'Symfony\Component\HttpKernel\Tests\Controller\ControllerResolverTest::bar',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Exception\BadServiceClassException;

/**
* Checks your service exists by checking its definition "class" and "factory_class" keys
*
* @author Leszek "l3l0" Prabucki <[email protected]>
*/
class CheckServiceClassPass implements CompilerPassInterface
{
/**
* Checks if ContainerBuilder services exists
*
* @param ContainerBuilder $container The ContainerBuilder instances
*/
public function process(ContainerBuilder $container)
{
$parameterBag = $container->getParameterBag();
foreach ($container->getDefinitions() as $id => $definition) {
if ($this->allowsToCheckClassExistenceForClass($definition) && !class_exists($parameterBag->resolveValue($definition->getClass()))) {
throw new BadServiceClassException($id, $definition->getClass(), 'class');
}
if ($this->allowsToCheckClassExistenceForFactoryClass($definition) && !class_exists($parameterBag->resolveValue($definition->getFactoryClass()))) {
throw new BadServiceClassException($id, $definition->getFactoryClass(), 'factory_class');
}
}
}

private function allowsToCheckClassExistenceForClass(Definition $definition)
{
return $definition->getClass() && !$this->isFactoryDefinition($definition) && !$definition->isSynthetic();
}

private function allowsToCheckClassExistenceForFactoryClass(Definition $definition)
{
return $definition->getFactoryClass() && !$definition->isSynthetic();
}

private function isFactoryDefinition(Definition $definition)
{
return $definition->getFactoryClass() || $definition->getFactoryService();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in case of a definition using factoryClass, it should check that the factory class exists

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah right :) I will add that.

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ public function __construct()
new RemoveUnusedDefinitionsPass(),
)),
new CheckExceptionOnInvalidReferenceBehaviorPass(),
new CheckServiceClassPass(),
);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\DependencyInjection\Exception;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing license note.


class BadServiceClassException extends RuntimeException
{
public function __construct($id, $className, $key)
{
parent::__construct(
sprintf(
'Class "%s" not found. Check the spelling on the "%s" configuration for your "%s" service.',
$className,
$key,
$id
)
);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be on one line.

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\DependencyInjection\Tests\Compiler;

use Symfony\Component\DependencyInjection\Compiler\CheckServiceClassPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;

class CheckServiceClassPassTest extends \PHPUnit_Framework_TestCase
{
/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\BadServiceClassException
* @expectedExceptionMessage Class "\InvalidName\TestClass" not found. Check the spelling on the "class" configuration for your "a" service.
*/
public function testThrowsBadNameExceptionWhenServiceHasInvalidClassName()
{
$container = new ContainerBuilder();
$container->register('a', '\InvalidName\TestClass');

$this->process($container);
}

public function testDoesNotThrowExceptionIfClassExists()
{
$container = new ContainerBuilder();
$container->register('a', '\Symfony\Component\DependencyInjection\Compiler\CheckServiceClassPass');
$container->register('b', '\stdClass');
$container->register('c', '\Symfony\Component\DependencyInjection\Tests\Compiler\MyTestService');
$container
->register('d', '\stdClass')
->setFactoryService('\Symfony\Component\DependencyInjection\Tests\Compiler\MyTestService')
->setFactoryMethod('factoryMethod')
;

$this->process($container);
}

public function testSynteticServicesClassNamesAreNotChecked()
{
$container = new ContainerBuilder();
$container
->register('a', '\InvalidName\TestClass')
->setSynthetic(true)
;

$this->process($container);
}

/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\BadServiceClassException
* @expectedExceptionMessage Class "\InvalidName\TestClass" not found. Check the spelling on the "factory_class" configuration for your "a" service.
*/
public function testFactoryMethodServicesClassNamesAreNotChecked()
{
$container = new ContainerBuilder();
$container
->register('a', '\stdClass')
->setFactoryClass('\InvalidName\TestClass')
->setFactoryMethod('factoryMethod')
;

$this->process($container);
}

public function testServicesWithoutNameAreNotChecked()
{
$container = new ContainerBuilder();
$container
->register('a')
;

$this->process($container);
}

public function testSynteticServicesNameAreNotChecked()
{
$container = new ContainerBuilder();
$container
->register('a', '\InvalidName\TestClass')
->setSynthetic(true)
;

$this->process($container);
}

protected function process(ContainerBuilder $container)
{
$pass = new CheckServiceClassPass();
$pass->process($container);
}
}

class MyTestService
{
public function factoryMethod()
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,20 @@ public function testProcessInlinesWhenThereAreMultipleReferencesButFromTheSameDe
$this->assertFalse($container->hasDefinition('b'));
$this->assertFalse($container->hasDefinition('c'), 'Service C was not inlined.');
}

/**
* @expectedException \Symfony\Component\DependencyInjection\Exception\BadServiceClassException
* @expectedExceptionMessage Class "\NotExist\InvalidClass" not found. Check the spelling on the "class" configuration for your "a" service.
*/
public function testFriendlyErrorIsThrowedWhenServiceHasBadClassName()
{
$container = new ContainerBuilder();

$container
->register('a', '\NotExist\InvalidClass')
;

$container->compile();
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php

require_once __DIR__.'/../includes/classes.php';
require_once __DIR__.'/../includes/foo.php';

use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,19 @@
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;

//Services have to exist
class FooClass
{
}

class BAR
{
}

class Foo
{
}

class ProjectExtension implements ExtensionInterface
{
public function load(array $configs, ContainerBuilder $configuration)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,15 @@ public function __construct(BarClass $bar)
$this->bar = $bar;
}
}

class Baz
{
}

class Request
{
}

class ConfClass
{
}