Completed
Push — feature-20rc1 ( 008ae2 )
by Rob
16:55
created

AttributeGuessersCompilerPass::getReflection()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 5
nc 2
nop 2
1
<?php
2
3
/*
4
 * This file is part of the `liip/LiipImagineBundle` project.
5
 *
6
 * (c) https://github.com/liip/LiipImagineBundle/graphs/contributors
7
 *
8
 * For the full copyright and license information, please view the LICENSE.md
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Liip\ImagineBundle\DependencyInjection\Compiler;
13
14
use Liip\ImagineBundle\Exception\InvalidArgumentException;
15
use Liip\ImagineBundle\File\Attributes\Guesser\ContentTypeGuesserInterface;
16
use Liip\ImagineBundle\File\Attributes\Guesser\ExtensionGuesserInterface;
17
use Symfony\Component\DependencyInjection\Compiler\PriorityTaggedServiceTrait;
18
use Symfony\Component\DependencyInjection\ContainerBuilder;
19
use Symfony\Component\DependencyInjection\Definition;
20
use Symfony\Component\DependencyInjection\Reference;
21
use Symfony\Component\HttpFoundation\File\MimeType\ExtensionGuesserInterface as SymfonyExtensionGuesserInterface;
22
use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesserInterface;
23
24
/**
25
 * @author Rob Frawley 2nd <[email protected]>
26
 */
27
class AttributeGuessersCompilerPass extends AbstractCompilerPass
28
{
29
    use PriorityTaggedServiceTrait;
30
31
    /**
32
     * @var string
33
     */
34
    private $tagNameFormat;
35
36
    /**
37
     * @var string
38
     */
39
    private $serviceFormat;
40
41
    /**
42
     * @param string $guesserTagNameFormat
43
     * @param string $proxyServiceIdFormat
44
     */
45
    public function __construct(
46
        string $guesserTagNameFormat = 'liip_imagine.file_attributes.guesser.%s',
47
        string $proxyServiceIdFormat = 'liip_imagine.file_attributes.guesser_proxy.%s'
48
    ) {
49
        $this->tagNameFormat = $guesserTagNameFormat;
50
        $this->serviceFormat = $proxyServiceIdFormat;
51
    }
52
53
    /**
54
     * {@inheritdoc}
55
     */
56
    public function process(ContainerBuilder $container): void
57
    {
58
        $this->processGuesserProxyContext(
59
            $container,
60
            'content_type',
61
            [ContentTypeGuesserInterface::class, MimeTypeGuesserInterface::class]
62
        );
63
64
        $this->processGuesserProxyContext(
65
            $container,
66
            'extension',
67
            [ExtensionGuesserInterface::class, SymfonyExtensionGuesserInterface::class]
68
        );
69
    }
70
71
    /**
72
     * @param ContainerBuilder $container
73
     * @param string           $context
74
     * @param string[]         $interfaces
75
     */
76
    private function processGuesserProxyContext(ContainerBuilder $container, string $context, array $interfaces): void
77
    {
78
        if ($container->hasDefinition($id = sprintf($this->serviceFormat, $context))) {
79
            $proxy = $container->getDefinition($id);
80
81
            foreach ($this->findAndSortTaggedServices(sprintf($this->tagNameFormat, $context), $container) as $r) {
82
                $this->registerGuesserWithProxy(
83
                    $container,
84
                    $context,
85
                    $proxy,
86
                    $r,
87
                    $interfaces
88
                );
89
            }
90
        }
91
    }
92
93
    /**
94
     * @param ContainerBuilder $container
95
     * @param string           $context
96
     * @param Definition       $proxy
97
     * @param Reference        $guesser
98
     * @param string[]         $interfaces
99
     */
100
    private function registerGuesserWithProxy(ContainerBuilder $container, string $context, Definition $proxy, Reference $guesser, array $interfaces): void
101
    {
102
        $reflection = $this->getReflection($container, $guesser);
103
        $interfaces = array_filter($interfaces, function (string $interface) use ($reflection) {
104
            return $reflection->implementsInterface($interface);
105
        });
106
107
        if (empty($interfaces)) {
108
            throw new InvalidArgumentException(
109
                'Class "%s" used for %s guesser service "%s" must implement one of "%s".',
110
                $reflection->getName(), $context, (string) $guesser, implode(', ', $interfaces)
0 ignored issues
show
Bug introduced by
Consider using $reflection->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
111
            );
112
        }
113
114
        $proxy->addMethodCall('register', [$guesser]);
115
        $this->log($container, 'Registered %s attribute guesser: %s', $context, (string) $guesser);
116
    }
117
118
    /**
119
     * @param ContainerBuilder $container
120
     * @param string           $id
121
     *
122
     * @return string
123
     */
124
    private function getClassName(ContainerBuilder $container, string $id): string
125
    {
126
        return $container
127
            ->getParameterBag()
128
            ->resolveValue(
129
                $container->getDefinition($id)->getClass()
130
            );
131
    }
132
133
    /**
134
     * @param ContainerBuilder $container
135
     * @param string           $id
136
     *
137
     * @return \ReflectionClass
138
     */
139
    private function getReflection(ContainerBuilder $container, string $id): \ReflectionClass
140
    {
141
        $class = $this->getClassName($container, $id);
142
143
        if (null !== $reflection = $container->getReflectionClass($class, false)) {
144
            return $reflection;
145
        }
146
147
        throw new InvalidArgumentException('Class "%s" used for service "%s" cannot be found.', $class, $id);
148
    }
149
}
150