Completed
Push — master ( 6af386...8c8746 )
by Olivier
03:38
created

TransformationPass::assertTypeNotDefined()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 1
nop 2
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of the ICanBoogie package.
5
 *
6
 * (c) Olivier Laviale <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace ICanBoogie\Transformation\Symfony;
13
14
use ICanBoogie\Transformation\PSR\TransformationProvider;
15
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
16
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
17
use Symfony\Component\DependencyInjection\ContainerBuilder;
18
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
19
use Symfony\Component\DependencyInjection\Exception\LogicException;
20
use Symfony\Component\DependencyInjection\TypedReference;
21
22
/**
23
 * Registers the transformation provider.
24
 */
25
class TransformationPass implements CompilerPassInterface
26
{
27
    const DEFAULT_SERVICE_ID = 'transformation.provider';
28
    const DEFAULT_TAG = 'transformation';
29
    const DEFAULT_TYPE_PROPERTY = 'type';
30
31
    /**
32
     * @var string
33
     */
34
    private $serviceId;
35
36
    /**
37
     * @var string
38
     */
39
    private $tag;
40
41
    /**
42
     * @var string
43
     */
44
    private $typeProperty;
45
46
    /**
47
     * @param string $serviceId
48
     * @param string $tag
49
     * @param string $typeProperty
50
     */
51
    public function __construct(
52
        $serviceId = self::DEFAULT_SERVICE_ID,
53
        $tag = self::DEFAULT_TAG,
54
        $typeProperty = self::DEFAULT_TYPE_PROPERTY
55
    ) {
56
        $this->serviceId = $serviceId;
57
        $this->tag = $tag;
58
        $this->typeProperty = $typeProperty;
59
    }
60
61
    /**
62
     * @inheritdoc
63
     */
64
    public function process(ContainerBuilder $container)
65
    {
66
        list($mapping, $refMap) = $this->buildMappingAndRefMap($container);
67
68
        $container
69
            ->register($this->serviceId, TransformationProvider::class)
70
            ->setArguments([
71
                $mapping,
72
                ServiceLocatorTagPass::register($container, $refMap),
73
            ]);
74
    }
75
76
    /**
77
     * @param ContainerBuilder $container
78
     *
79
     * @return array
80
     */
81
    private function buildMappingAndRefMap(ContainerBuilder $container)
82
    {
83
        $transformers = $container->findTaggedServiceIds($this->tag, true);
84
        $mapping = [];
85
        $refMap = [];
86
87
        foreach ($transformers as $id => $tags) {
88
            $type = $this->resolveType($tags, $id);
89
            $this->assertTypeNotDefined($type, $mapping);
90
            $mapping[$type] = $id;
91
            $refMap[$id] = new TypedReference($id, $container->getDefinition($id)->getClass());
92
        }
93
94
        return [ $mapping, $refMap ];
95
    }
96
97
    /**
98
     * @param array $tags
99
     * @param string $id
100
     *
101
     * @return string
102
     */
103
    private function resolveType(array $tags, string $id): string
104
    {
105
        $typeProperty = $this->typeProperty;
106
107
        if (empty($tags[0][$typeProperty])) {
108
            throw new InvalidArgumentException(
109
                "The `$typeProperty` property is required for service `$id`."
110
            );
111
        }
112
113
        return $tags[0][$typeProperty];
114
    }
115
116
    /**
117
     * @param string $type
118
     * @param array $mapping
119
     */
120
    private function assertTypeNotDefined(string $type, array $mapping): void
121
    {
122
        if (isset($mapping[$type])) {
123
            throw new LogicException(
124
                "The type `$type` already has a transformation: `{$mapping[$type]}`."
125
            );
126
        }
127
    }
128
}
129