GraphDefinitionBuilder.php 6.41 KB
Newer Older
1
<?php declare(strict_types=1);
2
/*
Guillaume Perréal's avatar
CS.    
Guillaume Perréal committed
3
4
 * Copyright (C) 2016-2017 IRSTEA
 * All rights reserved.
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 */

namespace Irstea\PlantUmlBundle\DependencyInjection\Builder;

use Irstea\PlantUmlBundle\Doctrine\EntityFinder;
use Irstea\PlantUmlBundle\Finder\ClassFinder;
use Irstea\PlantUmlBundle\Finder\FilteringFinder;
use Irstea\PlantUmlBundle\Model\ClassVisitor;
use Irstea\PlantUmlBundle\Model\Graph;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
use Symfony\Component\DependencyInjection\Reference;

/**
Guillaume Perréal's avatar
CS.    
Guillaume Perréal committed
20
 * Description of GraphDefinitionBuilder.
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
 */
class GraphDefinitionBuilder
{
    /**
     * @var ContainerBuilder
     */
    private $container;

    /**
     * @var string
     */
    private $baseId;

    /**
     * @var array
     */
    private $config;

    /**
     * @var ClassFilterBuilder
     */
    private $filterBuilder;

    /**
     * @var Reference
     */
    private $entityManager;

    /**
     * @var Definition
     */
    private $definition = null;

    /**
     * @param ContainerBuilder $container
Guillaume Perréal's avatar
CS.    
Guillaume Perréal committed
56
57
     * @param string           $baseId
     * @param array            $config
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
     */
    public function __construct(ContainerBuilder $container, $baseId, array $config, ClassFilterBuilder $filterBuilder)
    {
        $this->container = $container;
        $this->baseId = $baseId;
        $this->config = $config;
        $this->filterBuilder = $filterBuilder;

        $emId = $config['sources']['entity_manager'];
        $this->entityManager = new Reference("doctrine.orm.${emId}_entity_manager");
    }

    /**
     * @return Definition
     */
    public function build()
    {
        if (!$this->definition) {
            return $this->definition = $this->doBuild();
        }
Guillaume Perréal's avatar
CS.    
Guillaume Perréal committed
78

79
80
81
82
83
84
85
86
87
        return $this->definition;
    }

    /**
     * @return Definition
     */
    protected function doBuild()
    {
        list($source, $sourceFilter) = $this->buildSources();
88

89
90
91
92
        $layoutFilter = $this->filterBuilder->build($this->config['layout']) ?: $sourceFilter;
        $decorator = $this->buildFilteredDecorator();
        $namespace = $this->buildNamespace();

Guillaume Perréal's avatar
CS.    
Guillaume Perréal committed
93
        $visitor = $this->setDefinition('visitor', ClassVisitor::class, $decorator, $layoutFilter, $namespace);
94
95
96
97
98
99
100
101
102
103
104
105
106

        return new Definition(Graph::class, [$visitor, $source]);
    }

    /**
     * @return Refernce[]
     */
    protected function buildSources()
    {
        $finder = $this->buildFinder();
        $filter = $this->filterBuilder->build($this->config['sources']);

        if ($filter) {
Guillaume Perréal's avatar
CS.    
Guillaume Perréal committed
107
108
            $filtered = $this->setDefinition('finder', FilteringFinder::class, $finder, $filter);

109
110
111
112
113
114
115
116
117
118
119
120
121
            return [$filtered, $filter];
        }

        return [$finder, null];
    }

    /**
     * @return Reference
     */
    protected function buildFinder()
    {
        $config = $this->config['sources'];

Guillaume Perréal's avatar
CS.    
Guillaume Perréal committed
122
        switch ($config['type']) {
123
            case 'entities':
Guillaume Perréal's avatar
CS.    
Guillaume Perréal committed
124
                return $this->setDefinition('finder.entities', EntityFinder::class, $this->entityManager);
125
            case 'classes':
Guillaume Perréal's avatar
CS.    
Guillaume Perréal committed
126
                return $this->setDefinition('finder.classes', ClassFinder::class, $config['directories']);
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
        }
    }

    /**
     * @return Reference
     */
    protected function buildFilteredDecorator()
    {
        $decorator = $this->buildDecorator();
        if (!$decorator) {
            return $decorator;
        }

        $filter = $this->filterBuilder->build($this->config['decoration']);
        if (!$filter) {
            return $decorator;
        }

        return $this->setDefinitionDecorator('decorator', 'irstea.plant_uml.decorator.filtered.template', $decorator, $filter);
    }

    /**
     * @return Reference
     */
    protected function buildDecorator()
    {
        $config = $this->config['decoration']['decorators'];

        if (empty($config)) {
            return null;
        }

        if (count($config) === 1) {
            return $this->buildTypedDecorator($config[0]);
        }

        $decorators = [];
        foreach ($config as $type) {
            $decorators[] = $this->buildTypedDecorator($type);
        }

        return $this->setDefinitionDecorator(
            'decorator.all',
            'irstea.plant_uml.decorator.composite.template',
            $decorators
        );
    }

    /**
     * @param string $type
Guillaume Perréal's avatar
CS.    
Guillaume Perréal committed
177
     *
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
     * @return Reference
     */
    protected function buildTypedDecorator($type)
    {
        if (in_array($type, ['entity', 'associations', 'fields'])) {
            return $this->setDefinitionDecorator(
                "decorator.$type",
                "irstea.plant_uml.decorator.$type.template",
                $this->entityManager
            );
        }

        return new Reference("irstea.plant_uml.decorator.$type");
    }

    /**
Guillaume Perréal's avatar
Guillaume Perréal committed
194
     * @return Reference
195
196
197
198
     */
    protected function buildNamespace()
    {
        $type = $this->config['layout']['namespaces'];
199

Guillaume Perréal's avatar
CS.    
Guillaume Perréal committed
200
        if ($type === 'entities') {
201
202
203
204
205
206
207
            return $this->setDefinitionDecorator(
                "namespace.$type",
                "irstea.plant_uml.namespaces.$type.template",
                $this->entityManager
            );
        }

208
209
        return $this->setDefinitionDecorator(
            "namespace.$type",
210
            "irstea.plant_uml.namespaces.$type.template"
211
        );
212
213
214
    }

    /**
Guillaume Perréal's avatar
CS.    
Guillaume Perréal committed
215
     * @param string            $localId
216
     * @param string|Definition $classOrDef
Guillaume Perréal's avatar
CS.    
Guillaume Perréal committed
217
218
     * @param array             ...$arguments
     *
219
220
221
222
223
224
225
226
227
228
229
     * @return Reference
     */
    protected function setDefinition($localId, $classOrDef, ...$arguments)
    {
        if ($classOrDef instanceof Definition) {
            $definition = $classOrDef;
        } else {
            $definition = new Definition($classOrDef, $arguments);
        }
        $id = $this->globalId($localId);
        $this->container->setDefinition($id, $definition);
Guillaume Perréal's avatar
CS.    
Guillaume Perréal committed
230

231
232
233
234
235
236
        return new Reference($id);
    }

    /**
     * @param string $localId
     * @param string $templateId
Guillaume Perréal's avatar
CS.    
Guillaume Perréal committed
237
238
     * @param array  ...$arguments
     *
239
240
241
242
243
244
     * @return Reference
     */
    protected function setDefinitionDecorator($localId, $templateId, ...$arguments)
    {
        $def = new DefinitionDecorator($templateId);
        $def->setArguments($arguments);
Guillaume Perréal's avatar
CS.    
Guillaume Perréal committed
245

246
247
248
249
250
        return $this->setDefinition($localId, $def);
    }

    /**
     * @param string $localId
Guillaume Perréal's avatar
CS.    
Guillaume Perréal committed
251
     *
252
253
254
255
256
257
258
     * @return string
     */
    protected function globalId($localId)
    {
        return "{$this->baseId}.$localId";
    }
}