Skip to content
This repository was archived by the owner on Nov 9, 2022. It is now read-only.

Commit 0ffab9b

Browse files
author
Jirka Koutny
committed
Big refactoring
* Code simplified, old "hacks" removed * Better support for apps that use many 3rd party bundles
1 parent 25ef93c commit 0ffab9b

7 files changed

+101
-100
lines changed

AutowiringCompilerPass.php

+18-31
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,10 @@
55
use Kutny\AutowiringBundle\Compiler\ClassConstructorFiller;
66
use Kutny\AutowiringBundle\Compiler\ClassListBuilder;
77
use ReflectionClass;
8-
use Symfony\Component\Config\FileLocator;
98
use Symfony\Component\Config\Resource\FileResource;
109
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
1110
use Symfony\Component\DependencyInjection\ContainerBuilder;
1211
use Symfony\Component\DependencyInjection\Definition;
13-
use Symfony\Component\Yaml\Yaml;
1412

1513
class AutowiringCompilerPass implements CompilerPassInterface
1614
{
@@ -27,62 +25,51 @@ public function __construct(ClassConstructorFiller $classConstructorFiller, Clas
2725
public function process(ContainerBuilder $containerBuilder)
2826
{
2927
$classList = $this->classListBuilder->buildClassList($containerBuilder);
28+
$serviceDefinitions = $containerBuilder->getDefinitions();
3029

31-
$servicesForAutowiring = $this->getServicesForAutowiring($containerBuilder);
32-
$parameterBag = $containerBuilder->getParameterBag();
30+
$ignoredServicesRegExp = $this->getIgnoredServicesRegExp($containerBuilder);
3331

34-
foreach ($containerBuilder->getDefinitions() as $serviceId => $definition) {
35-
if (!in_array($serviceId, $servicesForAutowiring)) {
32+
foreach ($serviceDefinitions as $serviceId => $definition) {
33+
if ($definition->isAbstract() || !$definition->isPublic()) {
3634
continue;
3735
}
3836

39-
$this->watchServiceClassForChanges($definition, $containerBuilder);
40-
41-
if (!$definition->isPublic()) {
37+
if ($definition->getClass() === null) {
4238
continue;
4339
}
4440

45-
if ($definition->getFactoryClass() || $definition->getFactoryMethod()) {
41+
if ($ignoredServicesRegExp && preg_match($ignoredServicesRegExp, $serviceId)) {
4642
continue;
4743
}
4844

49-
$class = $parameterBag->resolveValue($definition->getClass());
50-
51-
if ($class === null) {
45+
if ($definition->getFactoryClass() || $definition->getFactoryMethod()) {
5246
continue;
5347
}
5448

55-
$reflection = new ReflectionClass($class);
49+
$this->watchServiceClassForChanges($definition, $containerBuilder);
50+
51+
$reflection = new ReflectionClass($definition->getClass());
5652
$constructor = $reflection->getConstructor();
5753

5854
if ($constructor !== null && $constructor->isPublic()) {
59-
$this->classConstructorFiller->autowireParams($constructor, $definition, $classList);
55+
$this->classConstructorFiller->autowireParams($constructor, $serviceId, $definition, $classList);
6056
}
6157
}
6258
}
6359

64-
private function getServicesForAutowiring(ContainerBuilder $containerBuilder)
60+
private function getIgnoredServicesRegExp(ContainerBuilder $containerBuilder)
6561
{
66-
$kernelRootDir = $containerBuilder->getParameter('kernel.root_dir');
67-
$symfonyEnvironment = $containerBuilder->getParameter('kernel.environment');
68-
$configDirectories = array($kernelRootDir . '/config');
69-
70-
$pathToConfigFile = $kernelRootDir . '/config/config_' . $symfonyEnvironment . '.yml';
71-
72-
$fileLocator = new FileLocator($configDirectories);
73-
$configLoader = new YamlConfigLoader($fileLocator);
74-
$serviceDefinitions = $configLoader->load($pathToConfigFile);
62+
$ignoredServices = $containerBuilder->getParameter('kutny_autowiring.ignored_services');
7563

76-
if (!array_key_exists('services', $serviceDefinitions) || !is_array($serviceDefinitions['services'])) {
77-
return array();
64+
if (empty($ignoredServices)) {
65+
return null;
7866
}
7967

80-
$serviceIds = array_keys($serviceDefinitions['services']);
81-
82-
return $serviceIds;
68+
return '~^(' . implode('|', $ignoredServices) . ')$~';
8369
}
8470

85-
private function watchServiceClassForChanges(Definition $definition, ContainerBuilder $containerBuilder) {
71+
private function watchServiceClassForChanges(Definition $definition, ContainerBuilder $containerBuilder)
72+
{
8673
$classReflection = new ReflectionClass($definition->getClass());
8774

8875
do {

DependencyInjection/Configuration.php

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
namespace Kutny\AutowiringBundle\DependencyInjection;
3+
4+
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
5+
use Symfony\Component\Config\Definition\ConfigurationInterface;
6+
7+
/**
8+
* This is the class that validates and merges configuration from your app/config files
9+
*
10+
* To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html#cookbook-bundles-extension-config-class}
11+
*/
12+
class Configuration implements ConfigurationInterface
13+
{
14+
/**
15+
* {@inheritDoc}
16+
*/
17+
public function getConfigTreeBuilder()
18+
{
19+
$treeBuilder = new TreeBuilder();
20+
$rootNode = $treeBuilder->root('kutny_autowiring');
21+
22+
$rootNode
23+
->children()
24+
->arrayNode('ignored_services')
25+
->defaultValue(array())
26+
->prototype('scalar')->end()
27+
->end()
28+
->end()
29+
->end();
30+
31+
return $treeBuilder;
32+
}
33+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
namespace Kutny\AutowiringBundle\DependencyInjection;
4+
5+
use Symfony\Component\DependencyInjection\ContainerBuilder;
6+
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
7+
8+
class KutnyAutowiringExtension extends Extension
9+
{
10+
11+
public function load(array $configs, ContainerBuilder $container)
12+
{
13+
$configuration = new Configuration();
14+
$config = $this->processConfiguration($configuration, $configs);
15+
16+
$container->setParameter('kutny_autowiring.ignored_services', $config['ignored_services']);
17+
}
18+
19+
}

KutnyAutowiringBundle.php

+3-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use Kutny\AutowiringBundle\Compiler\ClassConstructorFiller;
66
use Kutny\AutowiringBundle\Compiler\ClassListBuilder;
77
use Kutny\AutowiringBundle\Compiler\ParameterProcessor;
8+
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
89
use Symfony\Component\DependencyInjection\ContainerBuilder;
910
use Symfony\Component\HttpKernel\Bundle\Bundle;
1011

@@ -14,7 +15,8 @@ class KutnyAutowiringBundle extends Bundle
1415
public function build(ContainerBuilder $container)
1516
{
1617
$container->addCompilerPass(
17-
new AutowiringCompilerPass(new ClassConstructorFiller(new ParameterProcessor()), new ClassListBuilder())
18+
new AutowiringCompilerPass(new ClassConstructorFiller(new ParameterProcessor()), new ClassListBuilder()),
19+
PassConfig::TYPE_BEFORE_REMOVING
1820
);
1921
}
2022

README.md

+28
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,34 @@ public function registerBundles()
3232
}
3333
~~~~~
3434

35+
Configuration
36+
-------------
37+
38+
In most cases this bundle **does not require any configuration**. However if your app fails to start after installing this bundle giving you Kutny\AutowiringBundle\Compiler\CannotResolveParameterException, you may need to remove some services from autowiring. See example bellow:
39+
40+
**Example 1**:
41+
42+
You are receiving Kutny\AutowiringBundle\Compiler\CannotResolveParameterException with message like "Class Thrace\FormBundle\Form\Type\Select2Type (service **thrace_form.form.type.select2**), parameter $widget".
43+
44+
The problem is that Thrace\FormBundle\Form\Type\Select2Type service definition does not contain explicit $widget argument definition. It is very likely that the Thrace\FormBundle developer just forgot to define the $widget argument.
45+
KutnyAutowiringBundle expects all services to have all arguments defined (or have default values). As a result we have to disable autowiring for the thrace_form.form.type.select2 service by adding it (as a regular expression) among ignored_services:
46+
47+
~~~~~ yml
48+
49+
kutny_autowiring:
50+
ignored_services: ['thrace_form\.form\.type\.select2']
51+
52+
~~~~~
53+
54+
If you run into problems with more services from the Thrace\FormBundle bundle (thrace_form.form.type.select2, thrace_form.form.type.recaptcha, ...), you can easily add the whole "service namespace" to ignored_services using the following reqular expression:
55+
56+
~~~~~ yml
57+
58+
kutny_autowiring:
59+
ignored_services: ['thrace_form\.form\.type.*']
60+
61+
~~~~~
62+
3563
Example 1: Simple controller autowiring
3664
-----------------------------------------
3765

YamlConfigLoader.php

-58
This file was deleted.

YamlConfigLoader/ConfigFileIsEmptyException.php

-10
This file was deleted.

0 commit comments

Comments
 (0)