Completed
Push — master ( bb19ec...a4f748 )
by Philip
04:50
created

Service::initLocales()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 10
ccs 7
cts 7
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 7
nc 2
nop 1
crap 2
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\Loader\YamlFileLoader;
17
use Symfony\Component\Translation\Translator;
18
19
/**
20
 * The Service setups and initializes the whole CRUD system and is initialized via the framework
21
 * specific implementation, the Silex one for example.
22
 * It offers access to AbstractData instances, one for each defined entity off the CRUD YAML file
23
 * and various other helper functions.
24
 */
25
class Service
26
{
27
28
    /**
29
     * Holds the data instances.
30
     * @var array
31
     */
32
    protected $datas;
33
34
    /**
35
     * Holds the map for overriding templates.
36
     * @var array
37
     */
38
    protected $templates;
39
40
    /**
41
     * Holds whether CRUDlex manages i18n.
42
     * @var bool
43
     */
44
    protected $manageI18n = true;
45
46
    /**
47
     * Holds the URL generator.
48
     * @var \Symfony\Component\Routing\Generator\UrlGeneratorInterface
49
     */
50
    protected $urlGenerator;
51
52
    /**
53
     * Initializes the available locales.
54
     *
55
     * @param Translator $translator
56
     * the translator
57
     *
58
     * @return array
59
     * the available locales
60
     */
61 78
    protected function initLocales(Translator $translator)
62
    {
63 78
        $locales   = $this->getLocales();
64 78
        $localeDir = __DIR__.'/../locales';
65 78
        $translator->addLoader('yaml', new YamlFileLoader());
66 78
        foreach ($locales as $locale) {
67 78
            $translator->addResource('yaml', $localeDir.'/'.$locale.'.yml', $locale);
68
        }
69 78
        return $locales;
70
    }
71
72
    /**
73
     * Initializes the children of the data entries.
74
     */
75 78
    protected function initChildren()
76
    {
77 78
        foreach ($this->datas as $name => $data) {
78 78
            $fields = $data->getDefinition()->getFieldNames();
79 78
            foreach ($fields as $field) {
80 78
                if ($data->getDefinition()->getType($field) == 'reference') {
81 78
                    $this->datas[$data->getDefinition()->getSubTypeField($field, 'reference', 'entity')]->getDefinition()->addChild($data->getDefinition()->getTable(), $field, $name);
82
                }
83
            }
84
        }
85 78
    }
86
87
    /**
88
     * Gets a map with localized entity labels from the CRUD YML.
89
     *
90
     * @param array $locales
91
     * the available locales
92
     * @param array $crud
93
     * the CRUD entity map
94
     *
95
     * @return array
96
     * the map with localized entity labels
97
     */
98 78
    protected function getLocaleLabels(array $locales, array $crud)
99
    {
100 78
        $localeLabels = [];
101 78
        foreach ($locales as $locale) {
102 78
            if (array_key_exists('label_'.$locale, $crud)) {
103 78
                $localeLabels[$locale] = $crud['label_'.$locale];
104
            }
105
        }
106 78
        return $localeLabels;
107
    }
108
109
    /**
110
     * Configures the EntityDefinition according to the given
111
     * CRUD entity map.
112
     *
113
     * @param EntityDefinition $definition
114
     * the definition to configure
115
     * @param array $crud
116
     * the CRUD entity map
117
     */
118 78
    protected function configureDefinition(EntityDefinition $definition, array $crud)
119
    {
120
        $toConfigure = [
121 78
            'deleteCascade',
122
            'listFields',
123
            'filter',
124
            'childrenLabelFields',
125
            'pageSize',
126
            'initialSortField',
127
            'initialSortAscending',
128
            'navBarGroup',
129
            'optimisticLocking',
130
            'hardDeletion',
131
        ];
132 78
        foreach ($toConfigure as $field) {
133 78
            if (array_key_exists($field, $crud)) {
134 78
                $function = 'set'.ucfirst($field);
135 78
                $definition->$function($crud[$field]);
136
            }
137
        }
138 78
    }
139
140
    /**
141
     * Creates and setups an EntityDefinition instance.
142
     *
143
     * @param Translator $translator
144
     * the Translator to use for some standard field labels
145
     * @param EntityDefinitionFactoryInterface $entityDefinitionFactory
146
     * the EntityDefinitionFactory to use
147
     * @param array $locales
148
     * the available locales
149
     * @param array $crud
150
     * the parsed YAML of a CRUD entity
151
     * @param string $name
152
     * the name of the entity
153
     *
154
     * @return EntityDefinition
155
     * the EntityDefinition good to go
156
     */
157 78
    protected function createDefinition(Translator $translator, EntityDefinitionFactoryInterface $entityDefinitionFactory, array $locales, array $crud, $name)
158
    {
159 78
        $label               = array_key_exists('label', $crud) ? $crud['label'] : $name;
160 78
        $localeLabels        = $this->getLocaleLabels($locales, $crud);
161
        $standardFieldLabels = [
162 78
            'id' => $translator->trans('crudlex.label.id'),
163 78
            'created_at' => $translator->trans('crudlex.label.created_at'),
164 78
            'updated_at' => $translator->trans('crudlex.label.updated_at')
165
        ];
166
167 78
        $definition = $entityDefinitionFactory->createEntityDefinition(
168 78
            $crud['table'],
169 78
            $crud['fields'],
170 78
            $label,
171 78
            $localeLabels,
172 78
            $standardFieldLabels,
173 78
            $this
174
        );
175 78
        $this->configureDefinition($definition, $crud);
176 78
        return $definition;
177
    }
178
179
    /**
180
     * Initializes the instance.
181
     *
182
     * @param string $crudFile
183
     * the CRUD YAML file
184
     * @param string|null $crudFileCachingDirectory
185
     * the writable directory to store the CRUD YAML file cache
186
     * @param UrlGeneratorInterface $urlGenerator
187
     * the URL generator to use
188
     * @param Translator $translator
189
     * the translator to use
190
     * @param DataFactoryInterface $dataFactory
191
     * the data factory to use
192
     * @param EntityDefinitionFactoryInterface $entityDefinitionFactory
193
     * the EntityDefinitionFactory to use
194
     * @param FilesystemInterface $filesystem
195
     * the filesystem to use
196
     * @param EntityDefinitionValidatorInterface|null $validator
197
     * the validator to use, null if no validation required
198
     */
199 79
    public function __construct($crudFile, $crudFileCachingDirectory, UrlGeneratorInterface $urlGenerator, Translator $translator, DataFactoryInterface $dataFactory, EntityDefinitionFactoryInterface $entityDefinitionFactory, FilesystemInterface $filesystem, ?EntityDefinitionValidatorInterface $validator)
200
    {
201
202 79
        $this->urlGenerator = $urlGenerator;
203
204 79
        $this->templates = [];
205 79
        $this->setTemplate('layout', '@crud/layout.twig');
206
207 79
        $reader     = new YamlReader($crudFileCachingDirectory);
208 79
        $parsedYaml = $reader->read($crudFile);
209
210 78
        if ($validator !== null) {
211 78
            $validator->validate($parsedYaml);
212
        }
213
214 78
        $locales     = $this->initLocales($translator);
215 78
        $this->datas = [];
216 78
        foreach ($parsedYaml as $name => $crud) {
217 78
            $definition         = $this->createDefinition($translator, $entityDefinitionFactory, $locales, $crud, $name);
218 78
            $this->datas[$name] = $dataFactory->createData($definition, $filesystem);
219
        }
220
221 78
        $this->initChildren();
222
223 78
    }
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 70
    public function getData($name)
235
    {
236 70
        if (!array_key_exists($name, $this->datas)) {
237 3
            return null;
238
        }
239 70
        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 5
    public function getEntities()
249
    {
250 5
        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 11
                $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 79
    public function setTemplate($key, $template)
285
    {
286 79
        $this->templates[$key] = $template;
287 79
    }
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 the available locales.
343
     *
344
     * @return array
345
     * the available locales
346
     */
347 78
    public function getLocales()
348
    {
349 78
        $localeDir     = __DIR__.'/../locales';
350 78
        $languageFiles = scandir($localeDir);
351 78
        $locales       = [];
352 78
        foreach ($languageFiles as $languageFile) {
353 78
            if (in_array($languageFile, ['.', '..'])) {
354 78
                continue;
355
            }
356 78
            $extensionPos = strpos($languageFile, '.yml');
357 78
            if ($extensionPos !== false) {
358 78
                $locale    = substr($languageFile, 0, $extensionPos);
359 78
                $locales[] = $locale;
360
            }
361
        }
362 78
        sort($locales);
363 78
        return $locales;
364
    }
365
366
    /**
367
     * Gets whether CRUDlex manages the i18n.
368
     * @return bool
369
     * true if so
370
     */
371 11
    public function isManageI18n()
372
    {
373 11
        return $this->manageI18n;
374
    }
375
376
    /**
377
     * Sets whether CRUDlex manages the i18n.
378
     * @param bool $manageI18n
379
     * true if so
380
     */
381 1
    public function setManageI18n($manageI18n)
382
    {
383 1
        $this->manageI18n = $manageI18n;
384 1
    }
385
386
    /**
387
     * Generates an URL.
388
     * @param string $name
389
     * the name of the route
390
     * @param mixed $parameters
391
     * an array of parameters
392
     * @return null|string
393
     * the generated URL
394
     */
395 11
    public function generateURL($name, $parameters)
396
    {
397 11
        return $this->urlGenerator->generate($name, $parameters);
398
    }
399
400
}
401