Completed
Push — master ( a9ac86...2a4579 )
by Philip
19:09 queued 59s
created

ServiceProvider::getLocaleLabels()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 10
ccs 8
cts 8
cp 1
rs 9.4285
cc 3
eloc 6
nc 3
nop 2
crap 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 CRUDlex\Silex\TwigSetup;
15
use League\Flysystem\Adapter\Local;
16
use League\Flysystem\Filesystem;
17
use Pimple\Container;
18
use Pimple\ServiceProviderInterface;
19
use Silex\Api\BootableProviderInterface;
20
use Silex\Application;
21
use Silex\Provider\LocaleServiceProvider;
22
use Silex\Provider\SessionServiceProvider;
23
use Silex\Provider\TranslationServiceProvider;
24
use Silex\Provider\TwigServiceProvider;
25
use Symfony\Component\Translation\Loader\YamlFileLoader;
26
use Symfony\Component\Translation\Translator;
27
28
/**
29
 * The ServiceProvider setups and initializes the whole CRUD system.
30
 * After adding it to your Silex-setup, it offers access to AbstractData
31
 * instances, one for each defined entity off the CRUD YAML file.
32
 */
33
class ServiceProvider implements ServiceProviderInterface, BootableProviderInterface
34
{
35
36
    /**
37
     * Holds the data instances.
38
     * @var array
39
     */
40
    protected $datas;
41
42
    /**
43
     * Initializes needed but yet missing service providers.
44
     *
45
     * @param Container $app
46
     * the application container
47
     */
48 77
    protected function initMissingServiceProviders(Container $app)
49
    {
50
51 77
        if (!$app->offsetExists('translator')) {
52 77
            $app->register(new LocaleServiceProvider());
53 77
            $app->register(new TranslationServiceProvider(), [
54 77
                'locale_fallbacks' => ['en'],
55 77
            ]);
56 77
        }
57
58 77
        if (!$app->offsetExists('session')) {
59 67
            $app->register(new SessionServiceProvider());
60 67
        }
61
62 77
        if (!$app->offsetExists('twig')) {
63 67
            $app->register(new TwigServiceProvider());
64 67
        }
65 77
        $app['twig.loader.filesystem']->addPath(__DIR__.'/../views/', 'crud');
66 77
    }
67
68
    /**
69
     * Initializes the available locales.
70
     *
71
     * @param Translator $translator
72
     * the translator
73
     *
74
     * @return array
75
     * the available locales
76
     */
77 76
    protected function initLocales(Translator $translator)
78
    {
79 76
        $locales   = $this->getLocales();
80 76
        $localeDir = __DIR__.'/../locales';
81 76
        $translator->addLoader('yaml', new YamlFileLoader());
82 76
        foreach ($locales as $locale) {
83 76
            $translator->addResource('yaml', $localeDir.'/'.$locale.'.yml', $locale);
84 76
        }
85 76
        return $locales;
86
    }
87
88
    /**
89
     * Initializes the children of the data entries.
90
     */
91 76
    protected function initChildren()
92
    {
93 76
        foreach ($this->datas as $name => $data) {
94 76
            $fields = $data->getDefinition()->getFieldNames();
95 76
            foreach ($fields as $field) {
96 76
                if ($data->getDefinition()->getType($field) == 'reference') {
97 75
                    $this->datas[$data->getDefinition()->getSubTypeField($field, 'reference', 'entity')]->getDefinition()->addChild($data->getDefinition()->getTable(), $field, $name);
98 75
                }
99 76
            }
100 76
        }
101 76
    }
102
103
    /**
104
     * Gets a map with localized entity labels from the CRUD YML.
105
     *
106
     * @param array $locales
107
     * the available locales
108
     * @param array $crud
109
     * the CRUD entity map
110
     *
111
     * @return array
112
     * the map with localized entity labels
113
     */
114 76
    protected function getLocaleLabels(array $locales, array $crud)
115
    {
116 76
        $localeLabels = [];
117 76
        foreach ($locales as $locale) {
118 76
            if (array_key_exists('label_'.$locale, $crud)) {
119 76
                $localeLabels[$locale] = $crud['label_'.$locale];
120 76
            }
121 76
        }
122 76
        return $localeLabels;
123
    }
124
125
    /**
126
     * Configures the EntityDefinition according to the given
127
     * CRUD entity map.
128
     *
129
     * @param EntityDefinition $definition
130
     * the definition to configure
131
     * @param array $crud
132
     * the CRUD entity map
133
     */
134 76
    protected function configureDefinition(EntityDefinition $definition, array $crud)
135
    {
136
        $toConfigure = [
137 76
            'deleteCascade',
138 76
            'listFields',
139 76
            'filter',
140 76
            'childrenLabelFields',
141 76
            'pageSize',
142 76
            'initialSortField',
143 76
            'initialSortAscending',
144 76
            'navBarGroup',
145 76
            'optimisticLocking',
146 76
            'hardDeletion',
147 76
        ];
148 76
        foreach ($toConfigure as $field) {
149 76
            if (array_key_exists($field, $crud)) {
150 76
                $function = 'set'.ucfirst($field);
151 76
                $definition->$function($crud[$field]);
152 76
            }
153 76
        }
154 76
    }
155
156
    /**
157
     * Creates and setups an EntityDefinition instance.
158
     *
159
     * @param Translator $translator
160
     * the Translator to use for some standard field labels
161
     * @param EntityDefinitionFactoryInterface $entityDefinitionFactory
162
     * the EntityDefinitionFactory to use
163
     * @param array $locales
164
     * the available locales
165
     * @param array $crud
166
     * the parsed YAML of a CRUD entity
167
     * @param string $name
168
     * the name of the entity
169
     *
170
     * @return EntityDefinition
171
     * the EntityDefinition good to go
172
     */
173 76
    protected function createDefinition(Translator $translator, EntityDefinitionFactoryInterface $entityDefinitionFactory, array $locales, array $crud, $name)
174
    {
175 76
        $label               = array_key_exists('label', $crud) ? $crud['label'] : $name;
176 76
        $localeLabels        = $this->getLocaleLabels($locales, $crud);
177
        $standardFieldLabels = [
178 76
            'id' => $translator->trans('crudlex.label.id'),
179 76
            'created_at' => $translator->trans('crudlex.label.created_at'),
180 76
            'updated_at' => $translator->trans('crudlex.label.updated_at')
181 76
        ];
182
183 76
        $definition = $entityDefinitionFactory->createEntityDefinition(
184 76
            $crud['table'],
185 76
            $crud['fields'],
186 76
            $label,
187 76
            $localeLabels,
188 76
            $standardFieldLabels,
189
            $this
190 76
        );
191 76
        $this->configureDefinition($definition, $crud);
192 76
        return $definition;
193
    }
194
195
    /**
196
     * Validates the parsed entity definition.
197
     *
198
     * @param Container $app
199
     * the application container
200
     * @param array $entityDefinition
201
     * the entity definition to validate
202
     */
203 76
    protected function validateEntityDefinition(Container $app, array $entityDefinition)
204
    {
205 76
        $doValidate = !$app->offsetExists('crud.validateentitydefinition') || $app['crud.validateentitydefinition'] === true;
206 76
        if ($doValidate) {
207 75
            $validator = $app->offsetExists('crud.entitydefinitionvalidator')
208 75
                ? $app['crud.entitydefinitionvalidator']
209 75
                : new EntityDefinitionValidator();
210 75
            $validator->validate($entityDefinition);
211 75
        }
212 76
    }
213
214
    /**
215
     * Initializes the instance.
216
     *
217
     * @param string|null $crudFileCachingDirectory
218
     * the writable directory to store the CRUD YAML file cache
219
     * @param Container $app
220
     * the application container
221
     */
222 77
    public function init($crudFileCachingDirectory, Container $app)
223
    {
224
225 77
        $reader     = new YamlReader($crudFileCachingDirectory);
226 77
        $parsedYaml = $reader->read($app['crud.file']);
227
228 76
        $this->validateEntityDefinition($app, $parsedYaml);
229
230 76
        $locales                 = $this->initLocales($app['translator']);
231 76
        $this->datas             = [];
232 76
        $entityDefinitionFactory = $app->offsetExists('crud.entitydefinitionfactory') ? $app['crud.entitydefinitionfactory'] : new EntityDefinitionFactory();
233 76
        foreach ($parsedYaml as $name => $crud) {
234 76
            $definition         = $this->createDefinition($app['translator'], $entityDefinitionFactory, $locales, $crud, $name);
235 76
            $this->datas[$name] = $app['crud.datafactory']->createData($definition, $app['crud.filesystem']);
236 76
        }
237
238 76
        $this->initChildren();
239
240 76
    }
241
242
    /**
243
     * Implements ServiceProviderInterface::register() registering $app['crud'].
244
     * $app['crud'] contains an instance of the ServiceProvider afterwards.
245
     *
246
     * @param Container $app
247
     * the Container instance of the Silex application
248
     */
249 11
    public function register(Container $app)
250
    {
251 11
        if (!$app->offsetExists('crud.filesystem')) {
252 11
            $app['crud.filesystem'] = new Filesystem(new Local(getcwd()));
253 11
        }
254 11
        $app['crud'] = function() use ($app) {
255 11
            $result                   = new static();
256 11
            $crudFileCachingDirectory = $app->offsetExists('crud.filecachingdirectory') ? $app['crud.filecachingdirectory'] : null;
257 11
            $result->init($crudFileCachingDirectory, $app);
258 11
            return $result;
259
        };
260 11
    }
261
262
    /**
263
     * Initializes the crud service right after boot.
264
     *
265
     * @param Application $app
266
     * the Container instance of the Silex application
267
     */
268 77
    public function boot(Application $app)
269
    {
270 77
        $this->initMissingServiceProviders($app);
271 77
        $twigSetup = new TwigSetup();
272 77
        $twigSetup->registerTwigExtensions($app);
273 77
    }
274
275
    /**
276
     * Getter for the AbstractData instances.
277
     *
278
     * @param string $name
279
     * the entity name of the desired Data instance
280
     *
281
     * @return AbstractData
282
     * the AbstractData instance or null on invalid name
283
     */
284 70
    public function getData($name)
285
    {
286 70
        if (!array_key_exists($name, $this->datas)) {
287 8
            return null;
288
        }
289 70
        return $this->datas[$name];
290
    }
291
292
    /**
293
     * Getter for all available entity names.
294
     *
295
     * @return string[]
296
     * a list of all available entity names
297
     */
298 7
    public function getEntities()
299
    {
300 7
        return array_keys($this->datas);
301
    }
302
303
    /**
304
     * Getter for the entities for the navigation bar.
305
     *
306
     * @return string[]
307
     * a list of all available entity names with their group
308
     */
309 10
    public function getEntitiesNavBar()
310
    {
311 10
        $result = [];
312 10
        foreach ($this->datas as $entity => $data) {
313 10
            $navBarGroup = $data->getDefinition()->getNavBarGroup();
314 10
            if ($navBarGroup !== 'main') {
315 10
                $result[$navBarGroup][] = $entity;
316 10
            } else {
317
                $result[$entity] = 'main';
318
            }
319 10
        }
320 10
        return $result;
321
    }
322
323
    /**
324
     * Determines the Twig template to use for the given parameters depending on
325
     * the existance of certain keys in the Container $app in this order:
326
     *
327
     * crud.$section.$action.$entity
328
     * crud.$section.$action
329
     * crud.$section
330
     *
331
     * If nothing exists, this string is returned: "@crud/<action>.twig"
332
     *
333
     * @param Container $app
334
     * the Silex application
335
     * @param string $section
336
     * the section of the template, either "layout" or "template"
337
     * @param string $action
338
     * the current calling action like "create" or "show"
339
     * @param string $entity
340
     * the current calling entity
341
     *
342
     * @return string
343
     * the best fitting template
344
     */
345 11
    public function getTemplate(Container $app, $section, $action, $entity)
346
    {
347 11
        $crudSection       = 'crud.'.$section;
348 11
        $crudSectionAction = $crudSection.'.'.$action;
349
350
        $offsets = [
351 11
            $crudSectionAction.'.'.$entity,
352 11
            $crudSection.'.'.$entity,
353 11
            $crudSectionAction,
354
            $crudSection
355 11
        ];
356 11
        foreach ($offsets as $offset) {
357 11
            if ($app->offsetExists($offset)) {
358 9
                return $app[$offset];
359
            }
360 11
        }
361
362 11
        return '@crud/'.$action.'.twig';
363
    }
364
365
    /**
366
     * Sets the locale to be used.
367
     *
368
     * @param string $locale
369
     * the locale to be used.
370
     */
371 10
    public function setLocale($locale)
372
    {
373 10
        foreach ($this->datas as $data) {
374 10
            $data->getDefinition()->setLocale($locale);
375 10
        }
376 10
    }
377
378
    /**
379
     * Gets the available locales.
380
     *
381
     * @return array
382
     * the available locales
383
     */
384 77
    public function getLocales()
385
    {
386 77
        $localeDir     = __DIR__.'/../locales';
387 77
        $languageFiles = scandir($localeDir);
388 77
        $locales       = [];
389 77
        foreach ($languageFiles as $languageFile) {
390 77
            if (in_array($languageFile, ['.', '..'])) {
391 77
                continue;
392
            }
393 77
            $extensionPos = strpos($languageFile, '.yml');
394 77
            if ($extensionPos !== false) {
395 77
                $locale    = substr($languageFile, 0, $extensionPos);
396 77
                $locales[] = $locale;
397 77
            }
398 77
        }
399 77
        sort($locales);
400 77
        return $locales;
401
    }
402
403
}
404