Completed
Push — wip-test ( 1e3fe5...02cf76 )
by
unknown
20:52
created

CoreAdmin::renameTab()   B

Complexity

Conditions 5
Paths 5

Size

Total Lines 24
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 24
rs 8.5125
cc 5
eloc 15
nc 5
nop 4
1
<?php
2
3
/*
4
 * This file is part of the Blast Project package.
5
 *
6
 * Copyright (C) 2015-2017 Libre Informatique
7
 *
8
 * This file is licenced under the GNU LGPL v3.
9
 * For the full copyright and license information, please view the LICENSE.md
10
 * file that was distributed with this source code.
11
 */
12
13
namespace Blast\CoreBundle\Admin;
14
15
use Sonata\AdminBundle\Datagrid\DatagridMapper;
16
use Sonata\AdminBundle\Datagrid\ListMapper;
17
use Sonata\AdminBundle\Form\FormMapper;
18
use Sonata\AdminBundle\Mapper\BaseMapper;
19
use Sonata\AdminBundle\Show\ShowMapper;
20
use Sonata\AdminBundle\Route\RouteCollection;
21
use Sonata\AdminBundle\Admin\AbstractAdmin as SonataAdmin;
22
use Sonata\DoctrineORMAdminBundle\Admin\FieldDescription;
23
use Blast\CoreBundle\Tools\Reflection\ClassAnalyzer;
24
use Blast\CoreBundle\Admin\Traits\CollectionsManager;
25
use Blast\CoreBundle\Admin\Traits\Mapper;
26
use Blast\CoreBundle\Admin\Traits\Templates;
27
use Blast\CoreBundle\Admin\Traits\PreEvents;
28
use Blast\CoreBundle\Admin\Traits\ManyToManyManager;
29
use Blast\CoreBundle\Admin\Traits\Actions;
30
use Blast\CoreBundle\Admin\Traits\ListActions;
31
use Blast\CoreBundle\CodeGenerator\CodeGeneratorRegistry;
32
use Symfony\Component\PropertyAccess\PropertyAccess;
33
34
abstract class CoreAdmin extends SonataAdmin implements \JsonSerializable
35
{
36
    use CollectionsManager,
37
        ManyToManyManager,
38
        Mapper,
39
        Templates,
40
        PreEvents,
41
        Actions,
42
        ListActions
43
    ;
44
45
    protected $extraTemplates = [];
46
47
    /**
48
     * Configure routes for list actions.
49
     *
50
     * @param RouteCollection $collection
51
     */
52
    protected function configureRoutes(RouteCollection $collection)
53
    {
54
        parent::configureRoutes($collection);
55
        $collection->add('duplicate', $this->getRouterIdParameter() . '/duplicate');
56
        $collection->add('generateEntityCode');
57
    }
58
59 View Code Duplication
    public function getBaseRouteName()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
60
    {
61
        $configuredBaseRoute = $this->getBaseRouteMapping();
62
        
63
        if (count($configuredBaseRoute) > 0) {
64
            $this->cachedBaseRouteName = null;
0 ignored issues
show
Bug introduced by
The property cachedBaseRouteName cannot be accessed from this context as it is declared private in class Sonata\AdminBundle\Admin\AbstractAdmin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
65
            if (isset($configuredBaseRoute['name']) && $this->baseRouteName === null) {
66
                $this->baseRouteName = $configuredBaseRoute['name'];
67
            }
68
        }
69
70
        return parent::getBaseRouteName();
71
    }
72
73 View Code Duplication
    public function getBaseRoutePattern()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
74
    {
75
        $configuredBaseRoute = $this->getBaseRouteMapping();
76
77
        if (count($configuredBaseRoute) > 0) {
78
            $this->cachedBaseRoutePattern = null;
0 ignored issues
show
Bug introduced by
The property cachedBaseRoutePattern cannot be accessed from this context as it is declared private in class Sonata\AdminBundle\Admin\AbstractAdmin.

This check looks for access to properties that are not accessible from the current context.

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
79
            if (isset($configuredBaseRoute['pattern']) && $this->baseRoutePattern === null) {
80
                $this->baseRoutePattern = $configuredBaseRoute['pattern'];
81
            }
82
        }
83
84
        return parent::getBaseRoutePattern();
85
    }
86
87
    public function getFormTheme()
88
    {
89
        return array_merge($this->formTheme, $this->getFormThemeMapping());
90
    }
91
92
    /**
93
     * @param DatagridMapper $mapper
94
     */
95
    protected function configureDatagridFilters(DatagridMapper $mapper)
96
    {
97
        if (!$this->configureMapper($mapper)) {
98
            $this->fallbackConfiguration($mapper, __FUNCTION__);
99
        }
100
    }
101
102
    /**
103
     * @param ListMapper $mapper
104
     */
105
    protected function configureListFields(ListMapper $mapper)
106
    {
107
        if (!$this->configureMapper($mapper)) {
108
            $this->fallbackConfiguration($mapper, __FUNCTION__);
109
        }
110
    }
111
112
    /**
113
     * @param FormMapper $mapper
114
     */
115
    protected function configureFormFields(FormMapper $mapper)
116
    {
117
        if (!$this->configureMapper($mapper)) {
118
            $this->fallbackConfiguration($mapper, __FUNCTION__);
119
        }
120
    }
121
122
    /**
123
     * @param ShowMapper $mapper
124
     */
125
    protected function configureShowFields(ShowMapper $mapper)
126
    {
127
        if (!$this->configureMapper($mapper)) {
128
            $this->fallbackConfiguration($mapper, __FUNCTION__);
129
        }
130
    }
131
132
    /**
133
     * @param BaseMapper $mapper
134
     */
135
    protected function fixShowRoutes(BaseMapper $mapper)
0 ignored issues
show
Unused Code introduced by
The parameter $mapper is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
136
    {
137
        foreach (['getShow', 'getList'] as $fct) {
138
            foreach ($this->$fct()->getElements() as $field) {
139
                if ($field instanceof FieldDescription) {
140
                    $options = $field->getOptions();
141
                    if ($options['route']['name'] != 'edit') {
142
                        continue;
143
                    }
144
                    
145
                    $options['route']['name'] = 'show';
146
                    $field->setOptions($options);
147
                }
148
            }
149
        }
150
151
        return $this;
152
    }
153
154
    protected function getCurrentComposition()
155
    {
156
        // traits of the current Entity
157
        $classes = ClassAnalyzer::getTraits($this->getClass());
158
        // inheritance of the current Entity
159
        foreach (array_reverse([$this->getClass()] + class_parents($this->getClass())) as $class) {
160
            $classes[] = $class;
161
        }
162
        // inheritance of the current Admin
163
        foreach (array_reverse([$this->getOriginalClass()] + $this->getParentClasses()) as $admin) {
164
            $classes[] = $admin;
165
        }
166
167
        return $classes;
168
    }
169
170
    private function fallbackConfiguration(BaseMapper $mapper, $function)
171
    {
172
        // fallback
173
        $rm = new \ReflectionMethod($this->getParentClass(), $function);
174
        if ($rm->class == $this->getParentClass()) {
175
            $this->configureFields($function, $mapper, $this->getParentClass());
176
        }
177
    }
178
179
    /**
180
     * Returns the level of depth of an array.
181
     *
182
     * @param array $array
183
     * @param int   $level : do not use, just used for recursivity
184
     *
185
     * @return int : depth
186
     */
187
    private static function arrayDepth($array, $level = 0)
188
    {
189
        if (!$array) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $array of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
190
            return $level;
191
        }
192
193
        if (!is_array($array)) {
194
            return $level;
195
        }
196
197
        ++$level;
198
        foreach ($array as $key => $value) {
199
            if (is_array($value)) {
200
                $level = $level < self::arrayDepth($value, $level) ? self::arrayDepth($value, $level) : $level;
201
            }
202
        }
203
204
        return $level;
205
    }
206
207
    protected function getOriginalClass()
208
    {
209
        return get_called_class();
210
    }
211
212
    protected function getParentClasses()
213
    {
214
        return class_parents($this->getOriginalClass());
215
    }
216
217
    protected function getParentClass()
218
    {
219
        return get_parent_class($this->getOriginalClass());
220
    }
221
222
    protected function getGrandParentClass()
223
    {
224
        return get_parent_class(get_parent_class($this->getOriginalClass()));
225
    }
226
227
    /**
228
     * @param string $view     'list', 'show', 'form', etc
229
     * @param string $template template name
230
     */
231
    public function addExtraTemplate($view, $template)
232
    {
233
        if (empty($this->extraTemplates[$view])) {
234
            $this->extraTemplates[$view] = [];
235
        }
236
        if (!in_array($template, $this->extraTemplates[$view])) {
237
            $this->extraTemplates[$view][] = $template;
238
        }
239
    }
240
241
    /**
242
     * @param string $view 'list', 'show', 'form', etc
243
     *
244
     * @return array array of template names
245
     */
246
    public function getExtraTemplates($view)
247
    {
248
        if (empty($this->extraTemplates[$view])) {
249
            $this->extraTemplates[$view] = [];
250
        }
251
252
        return $this->extraTemplates[$view];
253
    }
254
255
    /**
256
     * @param string $view 'list', 'show', 'form', etc
257
     * @param array  $link link (array keys should be: 'label', 'url', 'class', 'title')
258
     */
259
    public function addHelperLink($view, $link)
260
    {
261
        if (empty($this->helperLinks[$view])) {
262
            $this->helperLinks[$view] = [];
263
        }
264
265
        // Do not add links without URL
266
        if (empty($link['url'])) {
267
            return;
268
        }
269
270
        // Do not add two links with the same URL
271
        foreach ($this->helperLinks[$view] as $l) {
272
            if ($l['url'] == $link['url']) {
273
                return;
274
            }
275
        }
276
277
        $this->helperLinks[$view][] = $link;
278
    }
279
280
    /**
281
     * @param string $view 'list', 'show', 'form', etc
282
     *
283
     * @return array array of links (each link is an array with keys 'label', 'url', 'class' and 'title')
284
     */
285
    public function getHelperLinks($view)
286
    {
287
        if (empty($this->helperLinks[$view])) {
288
            $this->helperLinks[$view] = [];
289
        }
290
291
        return $this->helperLinks[$view];
292
    }
293
294
    /**
295
     * Checks if a Bundle is installed.
296
     *
297
     * @param string $bundle Bundle name or class FQN
298
     */
299
    public function bundleExists($bundle)
300
    {
301
        $kernelBundles = $this->getConfigurationPool()->getContainer()->getParameter('kernel.bundles');
302
        if (array_key_exists($bundle, $kernelBundles)) {
303
            return true;
304
        }
305
        if (in_array($bundle, $kernelBundles)) {
306
            return true;
307
        }
308
309
        return false;
310
    }
311
312
    
313
 /**
314
     * Rename a tab after fields have been configured.
315
     *
316
     * TODO: groups of the renamed tab are still prefixed with the old tab name
317
     *
318
     * @param type $tabs       the tabs from Show Or Form
319
     * @param type $tabName    the name of the tab to be renamed
320
     * @param type $newTabName the new name for the tab
321
     */
322
    public function renameTab($tabs, $tabName, $newTabName, $keepOrder = true)
323
    {
324
        if (!$tabs) {
325
            return;
326
        }
327
328
        if (!isset($tabs[$tabName])) {
329
            throw new \Exception(sprintf('Tab %s does not exist.', $tabName));
330
        }
331
332
        if (isset($tabs[$newTabName])) {
333
            return;
334
        }
335
336
        if ($keepOrder) {
337
            $keys = array_keys($tabs);
338
            $keys[array_search($tabName, $keys)] = $newTabName;
339
            $tabs = array_combine($keys, $tabs);
340
        } else {
341
            $tabs[$newTabName] = $tabs[$tabName];
342
            unset($tabs[$tabName]);
343
        }
344
            return $tabs;
345
    }
346
    
347
    /**
348
     * Rename a form tab after form fields have been configured.
349
     *
350
     * @param type $tabName    the name of the tab to be renamed
351
     * @param type $newTabName the new name for the tab
352
     */
353
    public function renameFormTab($tabName, $newTabName, $keepOrder = true)
354
    {
355
        $tabs = $this->renameTab($this->getFormTabs(), $tabName, $newTabName, $keepOrder);
0 ignored issues
show
Documentation introduced by
$this->getFormTabs() is of type array|boolean, but the function expects a object<Blast\CoreBundle\Admin\type>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
356
        if (isset($tabs)) {
357
            $this->setFormTabs($tabs);
358
        }
359
    }
360
        
361
    /**
362
     * Rename a show tab after show fields have been configured.
363
     *
364
     * @param type $tabName    the name of the tab to be renamed
365
     * @param type $newTabName the new name for the tab
366
     */
367
    public function renameShowTab($tabName, $newTabName, $keepOrder = true)
368
    {
369
        $tabs = $this->renameTab($this->getShowTabs(), $tabName, $newTabName, $keepOrder);
0 ignored issues
show
Documentation introduced by
$this->getShowTabs() is of type array|boolean, but the function expects a object<Blast\CoreBundle\Admin\type>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
370
        if (isset($tabs)) {
371
            $this->setShowTabs($tabs);
372
        }
373
    }
374
375
    /**
376
     * Rename a form group.
377
     *
378
     * @param string $group        the old group name
379
     * @param string $tab          the tab the group belongs to
380
     * @param string $newGroupName the new group name
381
     *
382
     * @return self
383
     */
384
    public function renameFormGroup($group, $tab, $newGroupName)
385
    {
386
        $groups = $this->getFormGroups();
387
388
        // When the default tab is used, the tabname is not prepended to the index in the group array
389
        if ($tab !== 'default') {
390
            $group = $tab . '.' . $group;
391
        }
392
        $newGroup = ($tab !== 'default') ? $tab . '.' . $newGroupName : $newGroupName;
393
394
        if (isset($groups[$newGroup])) {
395
            throw new \Exception(sprintf('%s form group already exists.', $newGroup));
396
        }
397
        if (!array_key_exists($group, $groups)) {
398
            throw new \Exception(sprintf('form group « %s » doesn\'t exist.', $group));
399
        }
400
401
        $groups[$newGroup] = $groups[$group];
402
        $groups[$newGroup]['name'] = $newGroupName;
403
        unset($groups[$group]);
404
405
        $tabs = $this->getFormTabs();
406
        $key = array_search($group, $tabs[$tab]['groups']);
407
408
        if (false !== $key) {
409
            $tabs[$tab]['groups'][$key] = $newGroup;
410
        }
411
412
        $this->setFormTabs($tabs);
0 ignored issues
show
Bug introduced by
It seems like $tabs defined by $this->getFormTabs() on line 405 can also be of type boolean; however, Sonata\AdminBundle\Admin...actAdmin::setFormTabs() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
413
        $this->setFormGroups($groups);
0 ignored issues
show
Bug introduced by
It seems like $groups defined by $this->getFormGroups() on line 386 can also be of type boolean; however, Sonata\AdminBundle\Admin...tAdmin::setFormGroups() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
414
415
        return $this;
416
    }
417
418
    /**
419
     * Removes tab in current form Mapper.
420
     *
421
     * @param string|array $tabNames name or array of names of tabs to be removed
422
     * @param FormMapper   $mapper   Sonata Admin form mapper
423
     */
424
    public function removeTab($tabNames, $mapper)
425
    {
426
        $currentTabs = $this->getFormTabs();
427
        if (is_array($currentTabs)) {
428
            foreach ($currentTabs as $k => $item) {
429
                if (is_array($tabNames) && in_array($item['name'], $tabNames) || !is_array($tabNames) && $item['name'] === $tabNames) {
430
                    foreach ($item['groups'] as $groupName) {
431
                        $this->removeAllFieldsFromFormGroup($groupName, $mapper);
432
                    }
433
                    unset($currentTabs[$k]);
434
                }
435
            }
436
            $this->setFormTabs($currentTabs);
437
        }
438
    }
439
440
    /**
441
     * Removes all fields from form groups and remove them from mapper.
442
     *
443
     * @param string     $groupName Name of the group to remove
444
     * @param FormMapper $mapper    Sonata Admin form mapper
445
     */
446
    public function removeAllFieldsFromFormGroup($groupName, $mapper)
447
    {
448
        $formGroups = $this->getFormGroups();
449
        if (is_array($formGroups)) {
450
            foreach ($formGroups as $name => $formGroup) {
451
                if ($name === $groupName) {
452
                    // @todo: may replace $formGroups[$name] by $formGroup
453
                    foreach ($formGroups[$name]['fields'] as $key => $field) {
454
                        $mapper->remove($key);
455
                    }
456
                }
457
            }
458
        }
459
    }
460
461
    public function jsonSerialize()
462
    {
463
        $propertiesToShow = [
464
            'baseRouteName',
465
            'baseRoutePattern',
466
            'extraTemplates',
467
            'listFieldDescriptions',
468
            'showFieldDescriptions',
469
            'formFieldDescriptions',
470
            'filterFieldDescriptions',
471
            'maxPerPage',
472
            'maxPageLinks',
473
            'classnameLabel',
474
            'translationDomain',
475
            'formOptions',
476
            'datagridValues',
477
            'perPageOptions',
478
            'pagerType',
479
            'code',
480
            'label',
481
            'routes',
482
            'subject',
483
            'children',
484
            'parent',
485
            'baseCodeRoute',
486
            'uniqid',
487
            'extensions',
488
            'class',
489
            'subClasses',
490
            'list',
491
            'show',
492
            'form',
493
            'filter',
494
            'formGroups',
495
            'formTabs',
496
            'showGroups',
497
            'showTabs',
498
            'managedCollections',
499
            'helperLinks',
500
            'titles',
501
        ];
502
503
        $properties = [];
504
        foreach ($this as $key => $value) {
0 ignored issues
show
Bug introduced by
The expression $this of type this<Blast\CoreBundle\Admin\CoreAdmin> is not traversable.
Loading history...
505
            if (in_array($key, $propertiesToShow)) {
506
                $properties[$key] = $value;
507
            }
508
        }
509
510
        return $properties;
511
    }
512
513
    /**
514
     * {@inheritdoc}
515
     */
516
    public function prePersist($object)
517
    {
518
        parent::prePersist($object);
519
520
        $hasCodeGenerator = CodeGeneratorRegistry::hasGeneratorForClass(get_class($object));
521
        if ($hasCodeGenerator) {
522
            $accessor = PropertyAccess::createPropertyAccessor();
523
            foreach (CodeGeneratorRegistry::getCodeGenerators(get_class($object)) as $name => $generator) {
524
                $accessor->setValue($object, $name, $generator->generate($object));
525
            }
526
        }
527
    }
528
}
529