Completed
Push — master ( 35d7a1...0caa76 )
by Kévin
04:41 queued 02:33
created

DunglasActionExtension::getDirectory()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 3
nc 4
nop 2
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($this->getDirectory($kernelRootDir, $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, '/\.php$/'));
49
            $directories[$directory] = true;
50
        }
51
52
        $container->setParameter('dunglas_action.directories', $directories);
53
    }
54
55
    /**
56
     * @param string $kernelRootDir
57
     * @param string $pattern
58
     *
59
     * @return string
60
     */
61
    private function getDirectory($kernelRootDir, $pattern)
62
    {
63
        $firstCharacter = substr($pattern, 0, 1);
64
65
        return ('/' !== $firstCharacter && DIRECTORY_SEPARATOR !== $firstCharacter) ? $kernelRootDir.DIRECTORY_SEPARATOR.$pattern : $pattern;
66
    }
67
68
    /**
69
     * Gets the list of class names in the given directory.
70
     *
71
     * @param string $directory
72
     *
73
     * @return array
74
     */
75
    private function getClasses($directory)
76
    {
77
        $classes = [];
78
        $directoryList = [];
79
        $includedFiles = [];
80
81
        $finder = new Finder();
82
        try {
83
            $finder->in($directory)->files()->name('*.php');
84
        } catch (\InvalidArgumentException $e) {
85
            return [[], []];
86
        }
87
88
        foreach ($finder as $file) {
89
            $directoryList[$file->getPath()] = true;
90
            $sourceFile = $file->getRealpath();
91
            if (!preg_match('(^phar:)i', $sourceFile)) {
92
                $sourceFile = realpath($sourceFile);
93
            }
94
95
            require_once $sourceFile;
96
            $includedFiles[$sourceFile] = true;
97
        }
98
99
        $declared = get_declared_classes();
100
        foreach ($declared as $className) {
101
            $reflectionClass = new \ReflectionClass($className);
102
            $sourceFile = $reflectionClass->getFileName();
103
104
            if ($reflectionClass->isAbstract()) {
105
                continue;
106
            }
107
108
            if (isset($includedFiles[$sourceFile])) {
109
                $classes[$className] = true;
110
            }
111
        }
112
113
        return [array_keys($classes), $directoryList];
114
    }
115
116
    /**
117
     * Registers an action in the container.
118
     *
119
     * @param ContainerBuilder $container
120
     * @param string           $className
121
     * @param array            $tags
122
     */
123
    private function registerClass(ContainerBuilder $container, $className, array $tags)
124
    {
125
        if ($container->has($className)) {
126
            return;
127
        }
128
129
        $definition = $container->register($className, $className);
130
        $definition->setAutowired(true);
131
132
        // Inject the container if applicable
133
        if (is_a($className, ContainerAwareInterface::class, true)) {
134
            $definition->addMethodCall('setContainer', [new Reference('service_container')]);
135
        }
136
137
        foreach ($tags as $tagClassName => $classTags) {
138
            if (!is_a($className, $tagClassName, true)) {
139
                continue;
140
            }
141
142
            foreach ($classTags as $classTag) {
143
                $definition->addTag($classTag[0], $classTag[1]);
144
            }
145
        }
146
    }
147
}
148