Created
April 18, 2019 12:02
-
-
Save dbu/d2fb477fb13255632eaa6d580ebd022a to your computer and use it in GitHub Desktop.
symfony compiler pass to detect invalid classes on service configurations
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
declare(strict_types=1); | |
namespace Infrastructure\Symfony\DependencyInjection\Compiler; | |
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; | |
use Symfony\Component\DependencyInjection\ContainerBuilder; | |
use Symfony\Component\DependencyInjection\Definition; | |
/** | |
* Look at *all* service definitions and validate that their classes exist. | |
* | |
* With autoconfigure but no autowire, we otherwise never see invalid class | |
* names for listeners or such. | |
* | |
* This needs to be a compilar pass running at PassConfig::TYPE_BEFORE_REMOVING. | |
* A command would only see the services that have not been removed from the | |
* container. | |
* | |
* Inspired by https://github.com/matthiasnoback/symfony-service-definition-validator/ which is | |
* very outdated and validates some things that Symfony will detect and report. | |
*/ | |
class ValidateServiceDefinitions implements CompilerPassInterface | |
{ | |
private const KNOWN_UNUSED_SERVICES = [ | |
'beberlei_metrics.util.buzz.curl' => true, // not cleaned out by bundle | |
'beberlei_metrics.util.buzz.browser' => true, // not cleaned out by bundle | |
'form.type.entity' => true, // breaks when loading the php file | |
'debug.file_link_formatter.url_format' => true, // configured to by "string" | |
'service_container' => true, // ContainerInterface but no factory | |
]; | |
public function process(ContainerBuilder $container): void | |
{ | |
foreach ($container->getDefinitions() as $serviceId => $definition) { | |
if ($definition->isAbstract() || \array_key_exists($serviceId, self::KNOWN_UNUSED_SERVICES)) { | |
continue; | |
} | |
$class = $definition->getClass(); | |
if ($class) { | |
$class = $container->getParameterBag()->resolveValue($class); | |
if (!class_exists($class)) { | |
if (null === $definition->getFactory() || !interface_exists($class)) { | |
throw new \Exception(sprintf('Service %s is configured to use the nonexistent class %s', $serviceId, $class)); | |
} | |
} | |
} elseif (!$definition->isSynthetic()) { | |
throw new \Exception(sprintf('Service %s has no class', $serviceId)); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment