Service   A
last analyzed

Complexity

Total Complexity 34

Size/Duplication

Total Lines 352
Duplicated Lines 0 %

Coupling/Cohesion

Components 4
Dependencies 6

Test Coverage

Coverage 99.01%

Importance

Changes 0
Metric Value
wmc 34
lcom 4
cbo 6
dl 0
loc 352
ccs 100
cts 101
cp 0.9901
rs 9.68
c 0
b 0
f 0

15 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 24 3
A getData() 0 7 2
A getEntities() 0 4 1
A setTemplate() 0 4 1
A getTemplate() 0 18 3
A setLocale() 0 6 2
A isManageI18n() 0 4 1
A generateURL() 0 4 1
A getLocales() 0 18 4
A initChildren() 0 11 4
A getLocaleLabels() 0 11 3
A configureDefinition() 0 21 3
A createDefinition() 0 21 2
A setManageI18n() 0 4 1
A getEntitiesNavBar() 0 13 3
1
<?php
2
3
/*
4
 * This file is part of the CRUDlex package.
5
 *
6
 * (c) Philip Lehmann-Böhm <[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 CRUDlex;
13
14
use League\Flysystem\FilesystemInterface;
15
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
16
use Symfony\Component\Translation\TranslatorInterface;
17
18
/**
19
 * The Service setups and initializes the whole CRUD system and is initialized via the framework
20
 * specific implementation, the Silex one for example.
21
 * It offers access to AbstractData instances, one for each defined entity off the CRUD YAML file
22
 * and various other helper functions.
23
 */
24
class Service
25
{
26
27
    /**
28
     * Holds the data instances.
29
     * @var array
30
     */
31
    protected $datas;
32
33
    /**
34
     * Holds the map for overriding templates.
35
     * @var array
36
     */
37
    protected $templates;
38
39
    /**
40
     * Holds whether CRUDlex manages i18n.
41
     * @var bool
42
     */
43
    protected $manageI18n = true;
44
45
    /**
46
     * Holds the URL generator.
47
     * @var \Symfony\Component\Routing\Generator\UrlGeneratorInterface
48
     */
49
    protected $urlGenerator;
50
51
    /**
52
     * Gets the available locales.
53
     *
54
     * @return array
55
     * the available locales
56
     */
57 80
    public static function getLocales()
58
    {
59 80
        $localeDir     = __DIR__.'/../locales';
60 80
        $languageFiles = scandir($localeDir);
61 80
        $locales       = [];
62 80
        foreach ($languageFiles as $languageFile) {
63 80
            if (in_array($languageFile, ['.', '..'])) {
64 80
                continue;
65
            }
66 80
            $extensionPos = strpos($languageFile, '.yml');
67 80
            if ($extensionPos !== false) {
68 80
                $locale    = substr($languageFile, 0, $extensionPos);
69 80
                $locales[] = $locale;
70
            }
71
        }
72 80
        sort($locales);
73 80
        return $locales;
74
    }
75
76
    /**
77
     * Initializes the children of the data entries.
78
     */
79 79
    protected function initChildren()
80
    {
81 79
        foreach ($this->datas as $name => $data) {
82 79
            $fields = $data->getDefinition()->getFieldNames();
83 79
            foreach ($fields as $field) {
84 79
                if ($data->getDefinition()->getType($field) == 'reference') {
85 79
                    $this->datas[$data->getDefinition()->getSubTypeField($field, 'reference', 'entity')]->getDefinition()->addChild($data->getDefinition()->getTable(), $field, $name);
86
                }
87
            }
88
        }
89 79
    }
90
91
    /**
92
     * Gets a map with localized entity labels from the CRUD YML.
93
     *
94
     * @param array $crud
95
     * the CRUD entity map
96
     *
97
     * @return array
98
     * the map with localized entity labels
99
     */
100 79
    protected function getLocaleLabels(array $crud)
101
    {
102 79
        $locales      = $this->getLocales();
103 79
        $localeLabels = [];
104 79
        foreach ($locales as $locale) {
105 79
            if (array_key_exists('label_'.$locale, $crud)) {
106 79
                $localeLabels[$locale] = $crud['label_'.$locale];
107
            }
108
        }
109 79
        return $localeLabels;
110
    }
111
112
    /**
113
     * Configures the EntityDefinition according to the given
114
     * CRUD entity map.
115
     *
116
     * @param EntityDefinition $definition
117
     * the definition to configure
118
     * @param array $crud
119
     * the CRUD entity map
120
     */
121 79
    protected function configureDefinition(EntityDefinition $definition, array $crud)
122
    {
123
        $toConfigure = [
124 79
            'deleteCascade',
125
            'listFields',
126
            'filter',
127
            'childrenLabelFields',
128
            'pageSize',
129
            'initialSortField',
130
            'initialSortAscending',
131
            'navBarGroup',
132
            'optimisticLocking',
133
            'hardDeletion',
134
        ];
135 79
        foreach ($toConfigure as $field) {
136 79
            if (array_key_exists($field, $crud)) {
137 79
                $function = 'set'.ucfirst($field);
138 79
                $definition->$function($crud[$field]);
139
            }
140
        }
141 79
    }
142
143
    /**
144
     * Creates and setups an EntityDefinition instance.
145
     *
146
     * @param TranslatorInterface $translator
147
     * the Translator to use for some standard field labels
148
     * @param EntityDefinitionFactoryInterface $entityDefinitionFactory
149
     * the EntityDefinitionFactory to use
150
     * @param array $crud
151
     * the parsed YAML of a CRUD entity
152
     * @param string $name
153
     * the name of the entity
154
     *
155
     * @return EntityDefinition
156
     * the EntityDefinition good to go
157
     */
158 79
    protected function createDefinition(TranslatorInterface $translator, EntityDefinitionFactoryInterface $entityDefinitionFactory, array $crud, $name)
159
    {
160 79
        $label               = array_key_exists('label', $crud) ? $crud['label'] : $name;
161 79
        $localeLabels        = $this->getLocaleLabels($crud);
162
        $standardFieldLabels = [
163 79
            'id' => $translator->trans('crudlex.label.id'),
164 79
            'created_at' => $translator->trans('crudlex.label.created_at'),
165 79
            'updated_at' => $translator->trans('crudlex.label.updated_at')
166
        ];
167
168 79
        $definition = $entityDefinitionFactory->createEntityDefinition(
169 79
            $crud['table'],
170 79
            $crud['fields'],
171 79
            $label,
172 79
            $localeLabels,
173 79
            $standardFieldLabels,
174 79
            $this
175
        );
176 79
        $this->configureDefinition($definition, $crud);
177 79
        return $definition;
178
    }
179
180
    /**
181
     * Initializes the instance.
182
     *
183
     * @param string $crudFile
184
     * the CRUD YAML file
185
     * @param string|null $crudFileCachingDirectory
186
     * the writable directory to store the CRUD YAML file cache
187
     * @param UrlGeneratorInterface $urlGenerator
188
     * the URL generator to use
189
     * @param TranslatorInterface $translator
190
     * the translator to use
191
     * @param DataFactoryInterface $dataFactory
192
     * the data factory to use
193
     * @param EntityDefinitionFactoryInterface $entityDefinitionFactory
194
     * the EntityDefinitionFactory to use
195
     * @param FilesystemInterface $filesystem
196
     * the filesystem to use
197
     * @param EntityDefinitionValidatorInterface|null $validator
198
     * the validator to use, null if no validation required
199
     */
200 80
    public function __construct($crudFile, $crudFileCachingDirectory, UrlGeneratorInterface $urlGenerator, TranslatorInterface $translator, DataFactoryInterface $dataFactory, EntityDefinitionFactoryInterface $entityDefinitionFactory, FilesystemInterface $filesystem, ?EntityDefinitionValidatorInterface $validator)
201
    {
202
203 80
        $this->urlGenerator = $urlGenerator;
204
205 80
        $this->templates = [];
206 80
        $this->setTemplate('layout', '@crud/layout.twig');
207
208 80
        $reader     = new YamlReader($crudFileCachingDirectory);
209 80
        $parsedYaml = $reader->read($crudFile);
210
211 79
        if ($validator !== null) {
212 79
            $validator->validate($parsedYaml);
213
        }
214
215 79
        $this->datas = [];
216 79
        foreach ($parsedYaml as $name => $crud) {
217 79
            $definition         = $this->createDefinition($translator, $entityDefinitionFactory, $crud, $name);
218 79
            $this->datas[$name] = $dataFactory->createData($definition, $filesystem);
219
        }
220
221 79
        $this->initChildren();
222
223 79
    }
224
225
    /**
226
     * Getter for the AbstractData instances.
227
     *
228
     * @param string $name
229
     * the entity name of the desired Data instance
230
     *
231
     * @return AbstractData
232
     * the AbstractData instance or null on invalid name
233
     */
234 72
    public function getData($name)
235
    {
236 72
        if (!array_key_exists($name, $this->datas)) {
237 10
            return null;
238
        }
239 72
        return $this->datas[$name];
240
    }
241
242
    /**
243
     * Getter for all available entity names.
244
     *
245
     * @return string[]
246
     * a list of all available entity names
247
     */
248 6
    public function getEntities()
249
    {
250 6
        return array_keys($this->datas);
251
    }
252
253
    /**
254
     * Getter for the entities for the navigation bar.
255
     *
256
     * @return string[]
257
     * a list of all available entity names with their group
258
     */
259 11
    public function getEntitiesNavBar()
260
    {
261 11
        $result = [];
262 11
        foreach ($this->datas as $entity => $data) {
263 11
            $navBarGroup = $data->getDefinition()->getNavBarGroup();
264 11
            if ($navBarGroup !== 'main') {
265 11
                $result[$navBarGroup][] = $entity;
266
            } else {
267
                $result[$entity] = 'main';
268
            }
269
        }
270 11
        return $result;
271
    }
272
273
    /**
274
     * Sets a template to use instead of the build in ones.
275
     *
276
     * @param string $key
277
     * the template key to use in this format:
278
     * $section.$action.$entity
279
     * $section.$action
280
     * $section
281
     * @param string $template
282
     * the template to use for this key
283
     */
284 80
    public function setTemplate($key, $template)
285
    {
286 80
        $this->templates[$key] = $template;
287 80
    }
288
289
    /**
290
     * Determines the Twig template to use for the given parameters depending on
291
     * the existance of certain template keys set in this order:
292
     *
293
     * $section.$action.$entity
294
     * $section.$action
295
     * $section
296
     *
297
     * If nothing exists, this string is returned: "@crud/<action>.twig"
298
     *
299
     * @param string $section
300
     * the section of the template, either "layout" or "template"
301
     * @param string $action
302
     * the current calling action like "create" or "show"
303
     * @param string $entity
304
     * the current calling entity
305
     *
306
     * @return string
307
     * the best fitting template
308
     */
309 11
    public function getTemplate($section, $action, $entity)
310
    {
311 11
        $sectionAction = $section.'.'.$action;
312
313
        $offsets = [
314 11
            $sectionAction.'.'.$entity,
315 11
            $section.'.'.$entity,
316 11
            $sectionAction,
317 11
            $section
318
        ];
319 11
        foreach ($offsets as $offset) {
320 11
            if (array_key_exists($offset, $this->templates)) {
321 11
                return $this->templates[$offset];
322
            }
323
        }
324
325 11
        return '@crud/'.$action.'.twig';
326
    }
327
328
    /**
329
     * Sets the locale to be used.
330
     *
331
     * @param string $locale
332
     * the locale to be used.
333
     */
334 3
    public function setLocale($locale)
335
    {
336 3
        foreach ($this->datas as $data) {
337 3
            $data->getDefinition()->setLocale($locale);
338
        }
339 3
    }
340
341
    /**
342
     * Gets whether CRUDlex manages the i18n.
343
     * @return bool
344
     * true if so
345
     */
346 11
    public function isManageI18n()
347
    {
348 11
        return $this->manageI18n;
349
    }
350
351
    /**
352
     * Sets whether CRUDlex manages the i18n.
353
     * @param bool $manageI18n
354
     * true if so
355
     */
356 1
    public function setManageI18n($manageI18n)
357
    {
358 1
        $this->manageI18n = $manageI18n;
359 1
    }
360
361
    /**
362
     * Generates an URL.
363
     * @param string $name
364
     * the name of the route
365
     * @param mixed $parameters
366
     * an array of parameters
367
     * @return null|string
368
     * the generated URL
369
     */
370 11
    public function generateURL($name, $parameters)
371
    {
372 11
        return $this->urlGenerator->generate($name, $parameters);
373
    }
374
375
}
376