[DI] dont mandate a class on inline services with a factory

This commit is contained in:
Nicolas Grekas 2019-10-01 10:48:45 +02:00
parent 2b71c6f221
commit a2665d17cd
4 changed files with 20 additions and 2 deletions

View File

@ -14,6 +14,7 @@ namespace Symfony\Component\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Exception\EnvParameterException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\Loader\FileLoader;
/**
* This pass validates each definition individually only taking the information
@ -43,7 +44,7 @@ class CheckDefinitionValidityPass implements CompilerPassInterface
}
// non-synthetic, non-abstract service has class
if (!$definition->isAbstract() && !$definition->isSynthetic() && !$definition->getClass()) {
if (!$definition->isAbstract() && !$definition->isSynthetic() && !$definition->getClass() && (!$definition->getFactory() || !preg_match(FileLoader::ANONYMOUS_ID_REGEXP, $id))) {
if ($definition->getFactory()) {
throw new RuntimeException(sprintf('Please add the class to service "%s" even if it is constructed by a factory since we might need to add method calls based on compile-time checks.', $id));
}

View File

@ -33,6 +33,7 @@ use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceExce
use Symfony\Component\DependencyInjection\ExpressionLanguage;
use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterface as ProxyDumper;
use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\NullDumper;
use Symfony\Component\DependencyInjection\Loader\FileLoader;
use Symfony\Component\DependencyInjection\Parameter;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ServiceLocator as BaseServiceLocator;
@ -1206,7 +1207,7 @@ EOF;
$ids = array_keys($ids);
sort($ids);
foreach ($ids as $id) {
if (preg_match('/^\.\d+_[^~]++~[._a-zA-Z\d]{7}$/', $id)) {
if (preg_match(FileLoader::ANONYMOUS_ID_REGEXP, $id)) {
continue;
}
$code .= ' '.$this->doExport($id)." => true,\n";

View File

@ -26,6 +26,8 @@ use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
*/
abstract class FileLoader extends BaseFileLoader
{
public const ANONYMOUS_ID_REGEXP = '/^\.\d+_[^~]++~[._a-zA-Z\d]{7}$/';
protected $container;
protected $isLoadingInstanceof = false;
protected $instanceof = [];

View File

@ -14,6 +14,7 @@ namespace Symfony\Component\DependencyInjection\Tests\Compiler;
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\Compiler\CheckDefinitionValidityPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
class CheckDefinitionValidityPassTest extends TestCase
{
@ -35,6 +36,19 @@ class CheckDefinitionValidityPassTest extends TestCase
$this->process($container);
}
public function testProcessDetectsFactoryWithoutClass()
{
$container = new ContainerBuilder();
$container->register('.123_anonymous_service_id_should_not_throw_~1234567')->setFactory('factory');
$this->process($container);
$this->expectException(RuntimeException::class);
$container->register('.any_non_anonymous_id_throws')->setFactory('factory');
$this->process($container);
}
public function testProcess()
{
$container = new ContainerBuilder();