Completed
Push — master ( a3962e...49a1cf )
by Kévin
8s
created

DunglasActionExtension::getClasses()   C

Complexity

Conditions 7
Paths 13

Size

Total Lines 40
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
c 2
b 1
f 0
dl 0
loc 40
rs 6.7272
cc 7
eloc 25
nc 13
nop 1
1
<?php
2
3
/*
4
 * (c) Kévin Dunglas <[email protected]>
5
 *
6
 * This source file is subject to the MIT license that is bundled
7
 * with this source code in the file LICENSE.
8
 */
9
10
namespace Dunglas\ActionBundle\DependencyInjection;
11
12
use Symfony\Component\Config\Resource\DirectoryResource;
13
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
14
use Symfony\Component\DependencyInjection\ContainerBuilder;
15
use Symfony\Component\DependencyInjection\Reference;
16
use Symfony\Component\Finder\Finder;
17
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
18
19
/**
20
 * {@inheritdoc}
21
 *
22
 * @author Kévin Dunglas <[email protected]>
23
 */
24
class DunglasActionExtension extends Extension
25
{
26
    /**
27
     * {@inheritdoc}
28
     */
29
    public function load(array $configs, ContainerBuilder $container)
30
    {
31
        $configuration = new Configuration();
32
        $config = $this->processConfiguration($configuration, $configs);
33
        $kernelRootDir = $container->getParameter('kernel.root_dir');
34
35
        $directoryList = [];
36
        foreach ($config['directories'] as $pattern) {
37
            list($classes, $directories) = $this->getClasses($kernelRootDir.DIRECTORY_SEPARATOR.$pattern);
38
            $directoryList = array_merge($directoryList, $directories);
39
40
            foreach ($classes as $class) {
41
                $this->registerClass($container, $class, $config['tags']);
42
            }
43
        }
44
45
        $directories = [];
46
        foreach ($directoryList as $directory => $v) {
47
            $directory = realpath($directory);
48
            $container->addResource(new DirectoryResource($directory));
49
            $directories[$directory] = true;
50
        }
51
52
        $container->setParameter('dunglas_action.directories', $directories);
53
    }
54
55
    /**
56
     * Gets the list of class names in the given directory.
57
     *
58
     * @param string $directory
59
     *
60
     * @return array
61
     */
62
    private function getClasses($directory)
63
    {
64
        $classes = [];
65
        $directoryList = [];
66
        $includedFiles = [];
67
68
        $finder = new Finder();
69
        try {
70
            $finder->in($directory)->files()->name('*.php');
71
        } catch (\InvalidArgumentException $e) {
72
            return [[], []];
73
        }
74
75
        foreach ($finder as $file) {
76
            $directoryList[$file->getPath()] = true;
77
            $sourceFile = $file->getRealpath();
78
            if (!preg_match('(^phar:)i', $sourceFile)) {
79
                $sourceFile = realpath($sourceFile);
80
            }
81
82
            require_once $sourceFile;
83
            $includedFiles[$sourceFile] = true;
84
        }
85
86
        $declared = get_declared_classes();
87
        foreach ($declared as $className) {
88
            $reflectionClass = new \ReflectionClass($className);
89
            $sourceFile = $reflectionClass->getFileName();
90
91
            if ($reflectionClass->isAbstract()) {
92
                continue;
93
            }
94
95
            if (isset($includedFiles[$sourceFile])) {
96
                $classes[$className] = true;
97
            }
98
        }
99
100
        return [array_keys($classes), $directoryList];
101
    }
102
103
    /**
104
     * Registers an action in the container.
105
     *
106
     * @param ContainerBuilder $container
107
     * @param string           $className
108
     * @param array            $tags
109
     */
110
    private function registerClass(ContainerBuilder $container, $className, array $tags)
111
    {
112
        if ($container->has($className)) {
113
            return;
114
        }
115
116
        $definition = $container->register($className, $className);
117
        $definition->setAutowired(true);
118
119
        // Inject the container if applicable
120
        if (is_a($className, ContainerAwareInterface::class, true)) {
121
            $definition->addMethodCall('setContainer', [new Reference('service_container')]);
122
        }
123
124
        foreach ($tags as $tagClassName => $classTags) {
125
            if (!is_a($className, $tagClassName, true)) {
126
                continue;
127
            }
128
129
            foreach ($classTags as $classTag) {
130
                $definition->addTag($classTag[0], $classTag[1]);
131
            }
132
        }
133
    }
134
}
135