Completed
Push — master ( 2dfdd6...83034c )
by Kévin
04:07 queued 01:54
created

DunglasActionExtension::getClasses()   C

Complexity

Conditions 7
Paths 13

Size

Total Lines 40
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
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\FileLocator;
13
use Symfony\Component\Config\Resource\DirectoryResource;
14
use Symfony\Component\DependencyInjection\ContainerBuilder;
15
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
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
        $scannedDirectories = [];
36
        foreach ($config['directories'] as $pattern) {
37
            list($classes, $directories) = $this->getClasses($kernelRootDir.DIRECTORY_SEPARATOR.$pattern);
38
            $scannedDirectories = array_merge($scannedDirectories, $directories);
39
40
            foreach ($classes as $class) {
41
                $this->registerClass($container, $class, $config['tags']);
42
            }
43
        }
44
45
        foreach ($scannedDirectories as $directory => $v) {
46
            $container->addResource(new DirectoryResource($directory));
47
        }
48
49
        $container->setParameter('dunglas_action.directories', $scannedDirectories);
50
51
        if (class_exists('Symfony\Component\Routing\Loader\AnnotationDirectoryLoader')) {
52
            $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
53
            $loader->load('routing.xml');
54
        }
55
    }
56
57
    /**
58
     * Gets the list of class names in the given directory.
59
     *
60
     * @param string $directory
61
     *
62
     * @return array
63
     */
64
    private function getClasses($directory)
65
    {
66
        $classes = [];
67
        $scannedDirectories = [];
68
        $includedFiles = [];
69
70
        $finder = new Finder();
71
        try {
72
            $finder->in($directory)->files()->name('*.php');
73
        } catch (\InvalidArgumentException $e) {
74
            return [[], []];
75
        }
76
77
        foreach ($finder as $file) {
78
            $scannedDirectories[$file->getPath()] = true;
79
            $sourceFile = $file->getRealpath();
80
            if (!preg_match('(^phar:)i', $sourceFile)) {
81
                $sourceFile = realpath($sourceFile);
82
            }
83
84
            require_once $sourceFile;
85
            $includedFiles[$sourceFile] = true;
86
        }
87
88
        $declared = get_declared_classes();
89
        foreach ($declared as $className) {
90
            $reflectionClass = new \ReflectionClass($className);
91
            $sourceFile = $reflectionClass->getFileName();
92
93
            if ($reflectionClass->isAbstract()) {
94
                continue;
95
            }
96
97
            if (isset($includedFiles[$sourceFile])) {
98
                $classes[$className] = true;
99
            }
100
        }
101
102
        return [array_keys($classes), $scannedDirectories];
103
    }
104
105
    /**
106
     * Registers an action in the container.
107
     *
108
     * @param ContainerBuilder $container
109
     * @param string           $className
110
     * @param array            $tags
111
     */
112
    private function registerClass(ContainerBuilder $container, $className, array $tags)
113
    {
114
        if ($container->has($className)) {
115
            return;
116
        }
117
118
        $definition = $container->register($className, $className);
119
        $definition->setAutowired(true);
120
121
        foreach ($tags as $tagClassName => $classTags) {
122
            if (!is_a($className, $tagClassName, true)) {
123
                continue;
124
            }
125
126
            foreach ($classTags as $classTag) {
127
                $definition->addTag($classTag[0], $classTag[1]);
128
            }
129
        }
130
    }
131
}
132