Completed
Push — master ( 696b8e...2e195b )
by
unknown
03:17
created

Mapper::manageCallback()   B

Complexity

Conditions 5
Paths 10

Size

Total Lines 25
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 25
rs 8.439
cc 5
eloc 14
nc 10
nop 3
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\Traits;
14
15
use Sonata\AdminBundle\Datagrid\ListMapper;
16
use Sonata\AdminBundle\Form\FormMapper;
17
use Sonata\AdminBundle\Mapper\BaseGroupedMapper;
18
use Sonata\AdminBundle\Mapper\BaseMapper;
19
use Sonata\AdminBundle\Show\ShowMapper;
20
use Symfony\Component\Validator\Constraints\NotBlank;
21
use Symfony\Component\Form\ChoiceList\Loader\CallbackChoiceLoader;
22
use Exception;
23
24
trait Mapper
25
{
26
    /**
27
     * Force tabulations on Show views.
28
     *
29
     * @var bool
30
     */
31
    protected $forceTabs = false;
32
33
    /**
34
     * Links in the view navbar.
35
     *
36
     * @var array
37
     */
38
    protected $helperLinks = [];
39
40
    /**
41
     * Admin titles (for list, show, edit and create).
42
     *
43
     * @var string
44
     */
45
    public $titles = [];
46
47
    /**
48
     * Admin title templates (for list, show, edit and create).
49
     *
50
     * @var array
51
     */
52
    public $titleTemplates = [];
53
54
    protected function configureMapper(BaseMapper $mapper)
55
    {
56
        $classes = $this->getCurrentComposition();
0 ignored issues
show
Bug introduced by
It seems like getCurrentComposition() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
57
        $blast = $this
0 ignored issues
show
Bug introduced by
It seems like getConfigurationPool() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
58
            ->getConfigurationPool()
59
            ->getContainer()
60
            ->getParameter('blast')
61
        ;
62
        $this
0 ignored issues
show
Bug introduced by
It seems like getConfigurationPool() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
63
            ->getConfigurationPool()
64
            ->getContainer()
65
            ->get('logger')
66
            ->debug(sprintf(
67
                '[BlastCoreBundle] Processing the configuration in this order: %s',
68
                 implode(', ', $classes)
69
            ))
70
        ;
71
72
        $fcts = [
73
            'tabs' => $mapper instanceof ShowMapper ?
74
                ['getter' => 'getShowTabs', 'setter' => 'setShowTabs'] :
75
                ['getter' => 'getFormTabs', 'setter' => 'setFormTabs'],
76
            'groups' => $mapper instanceof ShowMapper ?
77
                ['getter' => 'getShowGroups', 'setter' => 'setShowGroups'] :
78
                ['getter' => 'getFormGroups', 'setter' => 'setFormGroups'],
79
        ];
80
81
        // Figure out if we have to display tabs on the Show view
82
        $this->forceTabs = false;
83
        if ($mapper instanceof ShowMapper) {
84
            foreach ($classes as $class) {
85
                if (isset($blast[$class])) {
86
                    foreach (array_reverse($list = array_merge([get_class($mapper)], array_values(class_parents($mapper)))) as $mapper_class) {
87
                        if (!empty($blast[$class][$mapper_class]['forceTabs'])) {
88
                            $this->forceTabs = true;
89
                        }
90
                    }
91
                }
92
            }
93
        }
94
95
        // builds the configuration, based on the Mapper class
96
        foreach ($classes as $class) {
97
            if (!isset($blast[$class])) {
98
                continue;
99
            }
100
101
            // copy stuff from elsewhere
102
            foreach (array_reverse($list = array_merge([get_class($mapper)], array_values(class_parents($mapper)))) as $mapper_class) {
103
                if (isset($blast[$class][$mapper_class]) && !empty($blast[$class][$mapper_class]['_copy'])) {
104
                    if (!is_array($blast[$class][$mapper_class]['_copy'])) {
105
                        $blast[$class][$mapper_class]['_copy'] = [$blast[$class][$mapper_class]['_copy']];
106
                    }
107
                    foreach ($blast[$class][$mapper_class]['_copy'] as $copy) {
108
                        $list = array_merge(
109
                                $list, array_merge([$copy], array_values(class_parents($copy)))
110
                        );
111
                    }
112
                }
113
            }
114
115
            $specialKeys = ['_actions', '_list_actions', '_batch_actions', '_export_formats', '_extra_templates', '_helper_links'];
116
117
            // process data...
118
            foreach (array_reverse($list) as $mapper_class) {
119
                if (!isset($blast[$class][$mapper_class])) {
120
                    continue;
121
                }
122
123
                // remove fields
124
                if (isset($blast[$class][$mapper_class]['remove'])) {
125 View Code Duplication
                    if (isset($blast['all'][$mapper_class]['remove'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
126
                        $blast[$class][$mapper_class]['remove'] = array_merge_recursive(
127
                            $blast[$class][$mapper_class]['remove'],
128
                            $blast['all'][$mapper_class]['remove']
129
                        );
130
                    }
131
132
                    foreach ($blast[$class][$mapper_class]['remove'] as $key => $field) {
133
                        if (in_array($key, $specialKeys)) {
134
                            continue;
135
                        }
136
137
                        if ($mapper->has($key)) {
138
                            $mapper->remove($key);
139
140
                            // compensating the partial removal in Sonata Admin, that does not touch the groups when removing a field
141 View Code Duplication
                            if ($mapper instanceof BaseGroupedMapper) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
142
                                foreach ($groups = $this->{$fcts['groups']['getter']}() as $groupkey => $group) {
143
                                    if (isset($group['fields'][$key])) {
144
                                        unset($groups[$groupkey]['fields'][$key]);
145
                                        if (!$groups[$groupkey]['fields']) {
146
                                            unset($groups[$groupkey]);
147
                                        }
148
                                        $this->{$fcts['groups']['setter']}($groups);
149
                                    }
150
                                }
151
                            }
152
                        }
153
                    }
154
                }
155
156
                // add fields & more
157
                if (isset($blast[$class][$mapper_class]['add'])) {
158 View Code Duplication
                    if (isset($blast['all'][$mapper_class]['add'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
159
                        $blast[$class][$mapper_class]['add'] = array_merge(
160
                                    $blast[$class][$mapper_class]['add'],
161
                                    $blast['all'][$mapper_class]['add']
162
                                );
163
                    }
164
165
                    // do not parse _batch_actions & co
166
                    foreach ($specialKeys as $sk) {
167 View Code Duplication
                        if (isset($blast[$class][$mapper_class]['add'][$sk])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
168
                            unset($blast[$class][$mapper_class]['add'][$sk]);
169
                        }
170
                    }
171
172
                    $this->addContent($mapper, $blast[$class][$mapper_class]['add']);
173
                }
174
175
                // set Admin titles
176
                $titleTemplate = isset($blast[$class][$mapper_class]['titleTemplate']) ? $blast[$class][$mapper_class]['titleTemplate'] : null;
177
                $title = isset($blast[$class][$mapper_class]['title']) ? $blast[$class][$mapper_class]['title'] : null;
178
                $this->setTitles($mapper, $titleTemplate, $title);
179
            }
180
        }
181
182
        if ($mapper instanceof BaseGroupedMapper) { // ShowMapper and FormMapper
183
            // removing empty groups
184
            $groups = $this->{$fcts['groups']['getter']}();
185
            if (is_array($groups)) {
186
                foreach ($groups as $groupkey => $group) {
187
                    if (!$group['fields']) {
188
                        unset($groups[$groupkey]);
189
                    }
190
                }
191
                $this->{$fcts['groups']['setter']}($groups);
192
            }
193
194
            // removing empty tabs
195
            $tabs = $this->{$fcts['tabs']['getter']}();
196 View Code Duplication
            if (is_array($tabs)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
197
                foreach ($tabs as $tabkey => $tab) {
198
                    foreach ($tab['groups'] as $groupkey => $group) {
199
                        if (!isset($this->{$fcts['groups']['getter']}()[$group])) {
200
                            unset($tabs[$tabkey]['groups'][$groupkey]);
201
                        }
202
                    }
203
204
                    if (!$tabs[$tabkey]['groups']) {
205
                        unset($tabs[$tabkey]);
206
                    }
207
                }
208
                $this->{$fcts['tabs']['setter']}($tabs);
209
            }
210
        }
211
212
        $this->fixTemplates($mapper);
0 ignored issues
show
Bug introduced by
It seems like fixTemplates() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
213
214
        if (!$mapper instanceof FormMapper) {
215
            $this->fixShowRoutes($mapper);
0 ignored issues
show
Bug introduced by
It seems like fixShowRoutes() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
216
        }
217
218
        // Debug profiler
219
        $this->getConfigurationPool()->getContainer()->get('blast_core.profiler.collector')
0 ignored issues
show
Bug introduced by
It seems like getConfigurationPool() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
220
            ->collect('Mapper', $mapper)
221
            ->collect('Classes', $classes);
222
223
        return $this;
224
    }
225
226
    /**
227
     * @param BaseMapper $mapper
228
     * @param array      $group
229
     *
230
     * @return BaseMapper
231
     */
232
    protected function addContent(BaseMapper $mapper, $group)
233
    {
234
        // helper links
235
        $this->parseHelperLinks();
236
237
        // flat organization (DatagridMapper / ListMapper...)
238
        if (!$mapper instanceof BaseGroupedMapper) {
239
            //list actions
240
            $this->addActions();
0 ignored issues
show
Bug introduced by
It seems like addActions() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
241
            $this->removeActions();
0 ignored issues
show
Bug introduced by
It seems like removeActions() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
242
243
            // options pre-treatment
244
            $options = [];
245
            if (isset($group['_options'])) {
246
                $options = $group['_options'];
247
                unset($group['_options']);
248
            }
249
250
            // content
251
            foreach ($group as $add => $opts) {
252
                $this->addField($mapper, $add, $opts);
253
            }
254
255
            // options
256
            if (isset($options['fieldsOrder'])) {
257
                $mapper->reorder($options['fieldsOrder']);
258
            }
259
260
            // extra templates
261
            $this->parseExtraTemplates();
262
263
            return $mapper;
264
        }
265
266
        $fcts = [
267
            'tabs' => $mapper instanceof ShowMapper ?
268
            ['getter' => 'getShowTabs', 'setter' => 'setShowTabs'] :
269
            ['getter' => 'getFormTabs', 'setter' => 'setFormTabs'],
270
            'groups' => $mapper instanceof ShowMapper ?
271
            ['getter' => 'getShowGroups', 'setter' => 'setShowGroups'] :
272
            ['getter' => 'getFormGroups', 'setter' => 'setFormGroups'],
273
        ];
274
275
        // if a grouped organization can be shapped
276
        // options
277
        $tabsOptions = null;
278
        if (isset($group['_options'])) {
279
            $tabsOptions = $group['_options'];
280
            unset($group['_options']);
281
        }
282
283
        // content
284
        foreach ($group as $tab => $tabcontent) { // loop on content...
285
            if (self::arrayDepth($tabcontent) < 1) {
286
                // direct add
287
                $this->addField($mapper, $tab, $tabcontent);
288
                $mapper->end()->end();
289
            } else {
290
                // groups/withs order
291
                $groupsOrder = null;
292
                if (isset($tabcontent['_options']['groupsOrder'])) {
293
                    $groupsOrder = $tabcontent['_options']['groupsOrder'];
294
                    unset($tabcontent['_options']['groupsOrder']);
295
                }
296
297
                $endgroup = $endtab = false;
298
299
                // tab
300
                if (!empty($tabcontent['_options']['hideTitle']) || $mapper instanceof ShowMapper && !$this->forceTabs) {
301
                    // display tabs as groups
302
                    $tabs = $this->{$fcts['tabs']['getter']}();
303
                    $groups = $this->{$fcts['groups']['getter']}();
304
                    if (isset($tabs[$tab])) {
305
                        $tabs[$tab]['auto_created'] = true;
306
                        $this->{$fcts['tabs']['setter']}($tabs);
307
308
                        foreach ($groups as $groupkey => $group) {
309
                            if (!isset($groups[$group['name']])) {
310
                                $groups[$group['name']] = $group;
311
                                unset($groups[$groupkey]);
312
                            }
313
                        }
314
                        $this->{$fcts['groups']['setter']}($groups);
315
                    }
316
                } else {
317
                    $mapper->tab($tab, isset($tabcontent['_options']) ? $tabcontent['_options'] : []);
318
                    $endtab = true;
319
                }
320
321
                // adding count of collections items in tab
322
                if (isset($tabcontent['_options']['countChildItems']) && is_array($tabcontent['_options']['countChildItems'])) {
323
                    $tabs = $this->{$fcts['tabs']['getter']}();
324
                    if (strpos($tabs[$tab]['class'], 'countable-tab') === false) {
325
                        $tabs[$tab]['class'] .= ' countable-tab';
326
327
                        foreach ($tabcontent['_options']['countChildItems'] as $fieldToCount) {
328
                            if (strpos($tabs[$tab]['class'], 'count-' . $fieldToCount) === false) {
329
                                $tabs[$tab]['class'] .= ' count-' . $fieldToCount;
330
                            }
331
                        }
332
333
                        $this->{$fcts['tabs']['setter']}($tabs);
334
                    }
335
                }
336
337
                // clearing tabcontent options
338
                if (isset($tabcontent['_options'])) {
339
                    unset($tabcontent['_options']);
340
                }
341
342
                $finalOrder = null;
0 ignored issues
show
Unused Code introduced by
$finalOrder is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
343
344
                // with
345
                if (self::arrayDepth($tabcontent) > 0) {
346
                    foreach ($tabcontent as $with => $withcontent) {
347
                        $opt = isset($withcontent['_options']) ? $withcontent['_options'] : [];
348
                        $finalOrder = (isset($opt['fieldsOrder']) ? $opt['fieldsOrder'] : null);
349
350
                        if (empty($opt['hideTitle'])) {
351
                            $endtab = true;
352
                            $endgroup = true;
353
                            $mapper->with($with, $opt);
354
                        }
355
                        if (isset($withcontent['_options'])) {
356
                            unset($withcontent['_options']);
357
                        }
358
359
                        // final adds
360
                        if (self::arrayDepth($withcontent) > 0) {
361
                            foreach ($withcontent as $name => $options) {
362
                                $fieldDescriptionOptions = [];
363
                                if (isset($options['_options'])) {
364
                                    $fieldDescriptionOptions = $options['_options'];
365
                                    unset($options['_options']);
366
                                }
367
                                $this->addField($mapper, $name, $options, $fieldDescriptionOptions);
368
                                $endgroup = $endtab = true;
369
                            }
370
                        }
371
372
                        if ($finalOrder != null) {
373
                            $mapper->reorder($finalOrder);
374
                        }
375
376
                        if ($endgroup) {
377
                            $mapper->end();
378
                        }
379
                    }
380
                }
381
382
                // order groups / withs (using tabs, because they are prioritary at the end)
383
                if (isset($groupsOrder)) {
384
                    // preparing
385
                    $otabs = $mapper->getAdmin()->{$fcts['tabs']['getter']}();
386
                    $groups = $mapper->getAdmin()->{$fcts['groups']['getter']}();
0 ignored issues
show
Unused Code introduced by
$groups is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
387
388
                    // pre-ordering
389
                    $newgroups = [];
390
                    $buf = empty($otabs[$tab]['auto_created']) ? "$tab." : '';
391
                    foreach ($groupsOrder as $groupname) {
392
                        if (isset($otabs[$tab]) && in_array("$buf$groupname", $otabs[$tab]['groups'])) {
393
                            $newgroups[] = "$buf$groupname";
394
                        }
395
                    }
396
397
                    // ordering tabs
398
                    foreach (empty($otabs[$tab]['groups']) ? [] : $otabs[$tab]['groups'] as $groupname) {
399
                        if (!in_array($groupname, $newgroups)) {
400
                            $newgroups[] = $groupname;
401
                        }
402
                    }
403
                    $otabs[$tab]['groups'] = $newgroups;
404
405
                    // "persisting"
406
                    $mapper->getAdmin()->{$fcts['tabs']['setter']}($otabs);
407
                }
408
409
                if ($endtab) {
410
                    $mapper->end();
411
                }
412
            }
413
        }
414
415
        // ordering tabs
416
        if (isset($tabsOptions['tabsOrder']) && $tabs = $this->{$fcts['tabs']['getter']}()) {
417
            $newtabs = [];
418
            foreach ($tabsOptions['tabsOrder'] as $tabname) {
419
                if (isset($tabs[$tabname])) {
420
                    $newtabs[$tabname] = $tabs[$tabname];
421
                }
422
            }
423
            foreach ($tabs as $tabname => $tab) {
424
                if (!isset($newtabs[$tabname])) {
425
                    $newtabs[$tabname] = $tab;
426
                }
427
            }
428
            $this->{$fcts['tabs']['setter']}($newtabs);
429
        }
430
431
        // ordering the ShowMapper
432
        if ($mapper instanceof ShowMapper) {
433
            foreach ($group as $tabName => $tabContent) {
434
                $tabOptions = null;
435
                if (isset($tabContent['_options'])) {
436
                    $tabOptions = $tabContent['_options'];
437
                    unset($tabContent['_options']);
438
                }
439
440
                if (isset($tabOptions['groupsOrder'])) {
441
                    $tabs = $this->{$fcts['tabs']['getter']}();
442
                    $groups = $this->{$fcts['groups']['getter']}();
443
444
                    $groupOrder = $tabOptions['groupsOrder'];
445
446
                    $properOrderedArray = array_merge(array_flip($groupOrder), $groups);
447
448
                    $this->{$fcts['groups']['setter']}($properOrderedArray);
449
                    $this->{$fcts['tabs']['setter']}($tabs);
450
                }
451
            }
452
        }
453
454
        return $mapper;
455
    }
456
457
    protected function addField(BaseMapper $mapper, $name, $options = [], $fieldDescriptionOptions = [])
458
    {
459
        // avoid duplicates
460
        if ($mapper->has($name)) {
461
            $mapper->remove($name);
462
        }
463
464
        if (!is_array($options)) {
465
            $options = [];
466
        }
467
468 View Code Duplication
        if (isset($options['only_new'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
469
            if ($options['only_new'] && $this->subject && !$this->subject->isNew()) {
0 ignored issues
show
Bug introduced by
The property subject does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
470
                return $mapper;
471
            }
472
            unset($options['only_new']);
473
        }
474
475 View Code Duplication
        if (isset($options['only_not_new'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
476
            if ($options['only_not_new'] && (!$this->subject || $this->subject->isNew())) {
477
                return $mapper;
478
            }
479
            unset($options['only_not_new']);
480
        }
481
482
        $type = null;
483
        if (isset($options['type'])) {
484
            $type = $options['type'];
485
            unset($options['type']);
486
        }
487
488
        if (isset($options['required']) && $options['required'] === true) {
489
            $options['constraints'] = [new NotBlank()];
490
        }
491
492
        if (isset($options['query'])) {
493
            $this->manageQueryCallback($mapper, $options);
494
        }
495
496
        if (isset($options['choicesCallback'])) {
497
            $this->manageChoicesCallback($mapper, $options);
498
        }
499
500
        if (isset($options['serviceCallback'])) {
501
            $this->manageServiceCallback($mapper, $options);
502
        }
503
504
        // save-and-remove CoreBundle-specific options
505
        $extras = [];
506
        foreach ([
507
            'template' => 'setTemplate',
508
            'initializeAssociationAdmin' => null,
509
        ] as $extra => $method) {
510
            if (isset($fieldDescriptionOptions[$extra])) {
511
                $extras[$extra] = [$method, $fieldDescriptionOptions[$extra]];
512
                unset($fieldDescriptionOptions[$extra]);
513
            }
514
        }
515
516
        $mapper->add($name, $type, $options, $fieldDescriptionOptions);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Sonata\AdminBundle\Mapper\BaseMapper as the method add() does only exist in the following sub-classes of Sonata\AdminBundle\Mapper\BaseMapper: Sonata\AdminBundle\Datagrid\DatagridMapper, Sonata\AdminBundle\Datagrid\ListMapper, Sonata\AdminBundle\Form\FormMapper, Sonata\AdminBundle\Show\ShowMapper. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
517
518
        // apply extra options
519
        foreach ($extras as $extra => $call) {
520
            if ($call[0]) {
521
                $mapper->get($name)->{$call[0]}($call[1]);
522
            } else {
523
                switch ($extra) {
524
                    case 'initializeAssociationAdmin':
525
                        // only if "true"
526
                        if (!$call[1]) {
527
                            break;
528
                        }
529
530
                        // initialize the association-admin
531
                        $mapper->get($name)->getAssociationAdmin()->configureShowFields(new ShowMapper(
532
                                $mapper->get($name)->getAssociationAdmin()->getShowBuilder(), $mapper->get($name)->getAssociationAdmin()->getShow(), $mapper->get($name)->getAssociationAdmin()
533
                        ));
534
535
                        // set the efficient template
536
                        if (!isset($extras['template'])) {
537
                            $mapper->get($name)->setTemplate('BlastCoreBundle:CRUD:show_association_admin.html.twig');
538
                        }
539
                        break;
540
                }
541
            }
542
        }
543
544
        return $mapper;
545
    }
546
547
    protected function configureFields($function, BaseMapper $mapper, $class = null)
548
    {
549
        if (!$class) {
550
            $class = $this->getOriginalClass();
0 ignored issues
show
Bug introduced by
It seems like getOriginalClass() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
551
        }
552
553
        return $class::$function($mapper);
554
    }
555
556
    /**
557
     * @param array $actions
558
     * */
559
    protected function handleBatchActions(array $actions = [])
560
    {
561
        $blast = $this->getConfigurationPool()->getContainer()->getParameter('blast');
0 ignored issues
show
Bug introduced by
It seems like getConfigurationPool() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
562
        $mapperClass = ListMapper::class;
563
        $actionKey = '_batch_actions';
564
565
        foreach ($this->getCurrentComposition() as $class) {
0 ignored issues
show
Bug introduced by
It seems like getCurrentComposition() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
566
            if (isset($blast[$class][$mapperClass])) {
567
                $config = $blast[$class][$mapperClass];
568
569 View Code Duplication
                if (isset($blast['all'][$mapperClass])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
570
                    $config = array_merge_recursive(
571
                        $config,
572
                        $blast['all'][$mapperClass]
573
                    );
574
                }
575
576
                // remove / reset
577
                if (isset($config['remove'][$actionKey])) {
578
                    $actions = parent::getBatchActions();
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (getBatchActions() instead of handleBatchActions()). Are you sure this is correct? If so, you might want to change this to $this->getBatchActions().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
579
580
                    foreach ($config['remove'][$actionKey] as $action) {
581
                        if (isset($actions[$action])) {
582
                            unset($actions[$action]);
583
                        }
584
                    }
585
                }
586
587
                // add
588
                if (isset($config['add'][$actionKey])) {
589
                    $buf = $config['add'][$actionKey];
590
591
                    foreach ($buf as $action => $props) {
592
                        $name = 'batch_action_' . $action;
593
594
                        foreach ([
595
                            'label' => $name,
596
                            'params' => [],
597
                            'translation_domain' => $this->getTranslationDomain(),
0 ignored issues
show
Bug introduced by
It seems like getTranslationDomain() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
598
                            'action' => $name,
599
                            'route' => 'batch_' . $action,
600
                        ] as $field => $value) {
601
                            if (empty($props[$field])) {
602
                                $props[$field] = $value;
603
                            }
604
                        }
605
606
                        $actions[$action] = $props;
607
                    }
608
                }
609
            }
610
        }
611
612
        return $actions;
613
    }
614
615
    /**
616
     * @param array $actions
617
     * */
618
    protected function handleListActions(array $actions = [])
0 ignored issues
show
Unused Code introduced by
The parameter $actions 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...
619
    {
620
        $this->_listActionLoaded = true;
0 ignored issues
show
Bug introduced by
The property _listActionLoaded does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
621
        $blast = $this->getConfigurationPool()->getContainer()->getParameter('blast');
0 ignored issues
show
Bug introduced by
It seems like getConfigurationPool() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
622
623
        foreach ($this->getCurrentComposition() as $class) {
0 ignored issues
show
Bug introduced by
It seems like getCurrentComposition() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
624
            // remove / reset
625 View Code Duplication
            if (isset($blast[$class][ListMapper::class]['remove']['_list_actions'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
626
                foreach ($blast[$class][ListMapper::class]['remove']['_list_actions'] as $action) {
627
                    $this->removeListAction($action);
0 ignored issues
show
Bug introduced by
It seems like removeListAction() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
628
                }
629
            }
630
631
            // add
632
            if (isset($blast[$class][ListMapper::class]['add']['_list_actions'])) {
633
                foreach ($blast[$class][ListMapper::class]['add']['_list_actions'] as $action => $props) {
634
                    $props['translation_domain'] = isset($props['translation_domain']) ? $props['translation_domain'] : $this->getTranslationDomain();
0 ignored issues
show
Bug introduced by
It seems like getTranslationDomain() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
635
                    $this->addListAction($action, $props);
0 ignored issues
show
Bug introduced by
It seems like addListAction() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
636
                }
637
            }
638
        }
639
640
        return $this->getListActions();
0 ignored issues
show
Bug introduced by
It seems like getListActions() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
641
    }
642
643
    /**
644
     * @param array $formats
645
     * */
646
    protected function addPresetExportFormats(array $formats = [])
647
    {
648
        $blast = $this->getConfigurationPool()->getContainer()->getParameter('blast');
0 ignored issues
show
Bug introduced by
It seems like getConfigurationPool() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
649
        $this->exportFields = $formats;
0 ignored issues
show
Bug introduced by
The property exportFields does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
650
651
        foreach ($this->getCurrentComposition() as $class) {
0 ignored issues
show
Bug introduced by
It seems like getCurrentComposition() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
652
            // remove / reset
653
            if (isset($blast[$class][ListMapper::class]['remove']['_export_format'])) {
654
                $this->exportFields = [];
655
            }
656
657
            // add
658
            if (isset($blast[$class][ListMapper::class]['add']['_export_format'])) {
659
                foreach ($blast[$class][ListMapper::class]['add']['_export_format'] as $format => $fields) {
660
                    // if no fields are defined (not an associative array)
661
                    if (intval($format) . '' == '' . $format && !is_array($fields)) {
662
                        $format = $fields;
663
                        $this->exportFields[$format] = $fields = [];
664
                    }
665
666
                    // if a copy of an other format is requested
667
                    if (!is_array($fields) && isset($blast[$class][ListMapper::class]['add']['_export_format'][$fields])) {
668
                        $blast[$class][ListMapper::class]['add']['_export_format'][$format] = // the global fields array
669
                                $fields = // the local  fields array
670
                                $blast[$class][ListMapper::class]['add']['_export_format'][$fields];  // the source fields array
671
                    }
672
673
                    // removes a specific format
674
                    if (substr($format, 0, 1) == '-') {
675
                        unset($this->exportFields[substr($format, 1)]);
676
                        continue;
677
                    }
678
679
                    // if an order is defined, use it to order the extracted fields
680
                    if (!$fields && isset($blast[$class][ListMapper::class]['add']['_options']['fieldsOrder'])) {
681
                        // get back default fields
682
                        $tmp = parent::getExportFields();
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (getExportFields() instead of addPresetExportFormats()). Are you sure this is correct? If so, you might want to change this to $this->getExportFields().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
683
                        $fields = [];
684
685
                        // takes the ordered fields
686 View Code Duplication
                        foreach ($blast[$class][ListMapper::class]['add']['_options']['fieldsOrder'] as $field) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
687
                            if (in_array($field, $tmp)) {
688
                                $fields[] = $field;
689
                            }
690
                        }
691
692
                        // then the forgotten fields as they come
693 View Code Duplication
                        foreach ($tmp as $field) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
694
                            if (!in_array($field, $blast[$class][ListMapper::class]['add']['_options']['fieldsOrder'])) {
695
                                $fields[] = $field;
696
                            }
697
                        }
698
                    }
699
                    $this->exportFields[$format] = $fields;
700
                }
701
            }
702
        }
703
704
        return $this->exportFields;
705
    }
706
707
    /**
708
     * @todo parse ShowMapper and FormMapper
709
     */
710
    protected function parseExtraTemplates()
711
    {
712
        $blast = $this->getConfigurationPool()->getContainer()->getParameter('blast');
0 ignored issues
show
Bug introduced by
It seems like getConfigurationPool() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
713
714
        foreach ($this->getCurrentComposition() as $class) {
0 ignored issues
show
Bug introduced by
It seems like getCurrentComposition() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
715
            // remove / reset
716
            if (isset($blast[$class][ListMapper::class]['remove']['_extra_templates'])) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
717
                // TODO
718
            }
719
720
            // add
721 View Code Duplication
            if (isset($blast[$class][ListMapper::class]['add']['_extra_templates'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
722
                foreach ($blast[$class][ListMapper::class]['add']['_extra_templates'] as $template) {
723
                    $this->addExtraTemplate('list', $template);
0 ignored issues
show
Bug introduced by
It seems like addExtraTemplate() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
724
                }
725
            }
726
        }
727
    }
728
729
    protected function parseHelperLinks()
730
    {
731
        $blast = $this->getConfigurationPool()->getContainer()->getParameter('blast');
0 ignored issues
show
Bug introduced by
It seems like getConfigurationPool() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
732
        $mappers = [
733
            'list' => ListMapper::class,
734
            'show' => ShowMapper::class,
735
            'form' => FormMapper::class,
736
        ];
737
738
        foreach ($this->getCurrentComposition() as $class) {
0 ignored issues
show
Bug introduced by
It seems like getCurrentComposition() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
739
            foreach ($mappers as $mapper => $mapper_class) {
740
                // remove / reset
741
                if (isset($blast[$class][$mapper_class]['remove']['_helper_links'])) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
742
                    // TODO
743
                }
744
745
                // add
746 View Code Duplication
                if (isset($blast[$class][$mapper_class]['add']['_helper_links'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
747
                    foreach ($blast[$class][$mapper_class]['add']['_helper_links'] as $link) {
748
                        $this->addHelperLink($mapper, $link);
0 ignored issues
show
Bug introduced by
It seems like addHelperLink() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
749
                    }
750
                }
751
            }
752
        }
753
    }
754
755
    protected function setTitles(BaseMapper $mapper, $titleTemplate, $title)
756
    {
757
        $contexts = [
758
            ListMapper::class => 'list',
759
            ShowMapper::class => 'show',
760
            FormMapper::class => 'form',
761
        ];
762
        if (!isset($contexts[get_class($mapper)])) {
763
            return;
764
        }
765
766
        $context = $contexts[get_class($mapper)];
767
        if ($titleTemplate) {
768
            $this->titleTemplates[$context] = $titleTemplate;
769
        }
770
        if ($title) {
771
            $this->titles[$context] = $title;
772
        }
773
    }
774
775
    protected function getFormThemeMapping()
776
    {
777
        $theme = [];
778
        $blast = $this->getConfigurationPool()->getContainer()->getParameter('blast');
0 ignored issues
show
Bug introduced by
It seems like getConfigurationPool() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
779
780
        foreach ($this->getCurrentComposition() as $class) {
0 ignored issues
show
Bug introduced by
It seems like getCurrentComposition() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
781
            if (isset($blast[$class])) {
782
                if (isset($blast[$class]['form_theme'])) {
783
                    $theme = array_merge($theme, $blast[$class]['form_theme']);
784
                }
785
            }
786
        }
787
788
        return $theme;
789
    }
790
791
    protected function getBaseRouteMapping()
792
    {
793
        $baseRoute = [];
794
        $blast = $this->getConfigurationPool()->getContainer()->getParameter('blast');
0 ignored issues
show
Bug introduced by
It seems like getConfigurationPool() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
795
796
        foreach ($this->getCurrentComposition() as $class) {
0 ignored issues
show
Bug introduced by
It seems like getCurrentComposition() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
797
            if (isset($blast[$class]) && isset($blast[$class]['baseRoute'])) {
798
                $reflexionClass = new \ReflectionClass($class);
799
                if (!$reflexionClass->isTrait()) {
800
                    $baseRoute = array_merge($baseRoute, $blast[$class]['baseRoute']);
801
                }
802
            }
803
        }
804
805
        return $baseRoute;
806
    }
807
808
    protected function manageCallback($mapper, &$options, $callbackType)
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...
809
    {
810
        $option = $options[$callbackType];
811
812
        $entityClass = isset($options['class']) ? $options['class'] : $this->getClass();
0 ignored issues
show
Bug introduced by
It seems like getClass() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
813
814
        if (!is_array($option)) {
815
            throw new Exception('« $callbackType » option must be an array : ["FQDN"=>"static method name"]');
816
        }
817
818
        list($serviceNameOrClass, $methodName, $targetOptions) = $option;
819
820
        if ($this->getConfigurationPool()->getContainer()->has($serviceNameOrClass)) {
0 ignored issues
show
Bug introduced by
It seems like getConfigurationPool() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
821
            $callBackFunction = [$this->getConfigurationPool()->getContainer()->get($serviceNameOrClass), $methodName];
0 ignored issues
show
Bug introduced by
It seems like getConfigurationPool() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
822
        } else {
823
            $callBackFunction = call_user_func($serviceNameOrClass . '::' . $methodName, $this->getModelManager(), $entityClass);
0 ignored issues
show
Bug introduced by
It seems like getModelManager() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
824
        }
825
826
        if ($targetOptions !== null) {
827
            $options[$targetOptions] = $callBackFunction;
828
            unset($options[$callbackType]);
829
        }
830
831
        return $callBackFunction;
832
    }
833
834
    protected function manageQueryCallback($mapper, &$options)
835
    {
836
        $callback = $this->manageCallback($mapper, $options, 'query');
837
        $options['query'] = $callback;
838
    }
839
840
    protected function manageChoicesCallback($mapper, &$options)
841
    {
842
        $callback = $this->manageCallback($mapper, $options, 'choicesCallback');
843
844
        $options['choices'] = $callback;
845
        $options['choice_loader'] = new CallbackChoiceLoader(function () use ($options) {
846
            return $options['choices'];
847
        });
848
    }
849
850
    public function manageServiceCallback($mapper, &$options)
851
    {
852
        $this->manageCallback($mapper, $options, 'serviceCallback');
853
    }
854
}
855