Issues (689)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/Admin/Traits/Mapper.php (59 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

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
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
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
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
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
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
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
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
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
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
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
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
            ->collectOnce('Mapper', $mapper)
221
            ->collectOnce('Managed 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
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
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
$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
$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
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
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
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['constraints'])) {
489
            foreach ($options['constraints'] as $k => $constraint) {
490
                $options['constraints'][$k] = new $constraint();
491
            }
492
        }
493
494
        if (isset($options['required']) && $options['required'] === true) {
495
            $options['constraints'] = [new NotBlank()];
496
        }
497
498
        if (isset($options['query'])) {
499
            $this->manageQueryCallback($mapper, $options);
500
        }
501
502
        if (isset($options['choicesCallback'])) {
503
            $this->manageChoicesCallback($mapper, $options);
504
        }
505
506
        if (isset($options['serviceCallback'])) {
507
            $this->manageServiceCallback($mapper, $options);
508
        }
509
510
        // save-and-remove CoreBundle-specific options
511
        $extras = [];
512
        foreach ([
513
            'template' => 'setTemplate',
514
            'initializeAssociationAdmin' => null,
515
        ] as $extra => $method) {
516
            if (isset($fieldDescriptionOptions[$extra])) {
517
                $extras[$extra] = [$method, $fieldDescriptionOptions[$extra]];
518
                unset($fieldDescriptionOptions[$extra]);
519
            }
520
        }
521
522
        $mapper->add($name, $type, $options, $fieldDescriptionOptions);
0 ignored issues
show
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...
523
524
        // apply extra options
525
        foreach ($extras as $extra => $call) {
526
            if ($call[0]) {
527
                $mapper->get($name)->{$call[0]}($call[1]);
528
            } else {
529
                switch ($extra) {
530
                    case 'initializeAssociationAdmin':
531
                        // only if "true"
532
                        if (!$call[1]) {
533
                            break;
534
                        }
535
536
                        // initialize the association-admin
537
                        $mapper->get($name)->getAssociationAdmin()->configureShowFields(new ShowMapper(
538
                                $mapper->get($name)->getAssociationAdmin()->getShowBuilder(), $mapper->get($name)->getAssociationAdmin()->getShow(), $mapper->get($name)->getAssociationAdmin()
539
                        ));
540
541
                        // set the efficient template
542
                        if (!isset($extras['template'])) {
543
                            $mapper->get($name)->setTemplate('BlastCoreBundle:CRUD:show_association_admin.html.twig');
544
                        }
545
                        break;
546
                }
547
            }
548
        }
549
550
        return $mapper;
551
    }
552
553
    protected function configureFields($function, BaseMapper $mapper, $class = null)
554
    {
555
        if (!$class) {
556
            $class = $this->getOriginalClass();
0 ignored issues
show
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...
557
        }
558
559
        return $class::$function($mapper);
560
    }
561
562
    /**
563
     * @param array $actions
564
     * */
565
    protected function handleBatchActions(array $actions = [])
566
    {
567
        $blast = $this->getConfigurationPool()->getContainer()->getParameter('blast');
0 ignored issues
show
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...
568
        $mapperClass = ListMapper::class;
569
        $actionKey = '_batch_actions';
570
571
        foreach ($this->getCurrentComposition() as $class) {
0 ignored issues
show
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...
572
            if (isset($blast[$class][$mapperClass])) {
573
                $config = $blast[$class][$mapperClass];
574
575 View Code Duplication
                if (isset($blast['all'][$mapperClass])) {
0 ignored issues
show
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...
576
                    $config = array_merge_recursive(
577
                        $config,
578
                        $blast['all'][$mapperClass]
579
                    );
580
                }
581
582
                // remove / reset
583
                if (isset($config['remove'][$actionKey])) {
584
                    $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...
585
586
                    foreach ($config['remove'][$actionKey] as $action) {
587
                        if (isset($actions[$action])) {
588
                            unset($actions[$action]);
589
                        }
590
                    }
591
                }
592
593
                // add
594
                if (isset($config['add'][$actionKey])) {
595
                    $buf = $config['add'][$actionKey];
596
597
                    foreach ($buf as $action => $props) {
598
                        $name = 'batch_action_' . $action;
599
600
                        foreach ([
601
                            'label' => $name,
602
                            'params' => [],
603
                            'translation_domain' => $this->getTranslationDomain(),
0 ignored issues
show
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...
604
                            'action' => $name,
605
                            'route' => 'batch_' . $action,
606
                        ] as $field => $value) {
607
                            if (empty($props[$field])) {
608
                                $props[$field] = $value;
609
                            }
610
                        }
611
612
                        $actions[$action] = $props;
613
                    }
614
                }
615
            }
616
        }
617
618
        return $actions;
619
    }
620
621
    /**
622
     * @param array $actions
623
     * */
624
    protected function handleListActions(array $actions = [])
0 ignored issues
show
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...
625
    {
626
        $this->_listActionLoaded = true;
0 ignored issues
show
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...
627
        $blast = $this->getConfigurationPool()->getContainer()->getParameter('blast');
0 ignored issues
show
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...
628
629
        foreach ($this->getCurrentComposition() as $class) {
0 ignored issues
show
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...
630
            // remove / reset
631 View Code Duplication
            if (isset($blast[$class][ListMapper::class]['remove']['_list_actions'])) {
0 ignored issues
show
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...
632
                foreach ($blast[$class][ListMapper::class]['remove']['_list_actions'] as $action) {
633
                    $this->removeListAction($action);
0 ignored issues
show
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...
634
                }
635
            }
636
637
            // add
638
            if (isset($blast[$class][ListMapper::class]['add']['_list_actions'])) {
639
                foreach ($blast[$class][ListMapper::class]['add']['_list_actions'] as $action => $props) {
640
                    $props['translation_domain'] = isset($props['translation_domain']) ? $props['translation_domain'] : $this->getTranslationDomain();
0 ignored issues
show
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...
641
                    $this->addListAction($action, $props);
0 ignored issues
show
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...
642
                }
643
            }
644
        }
645
646
        return $this->getListActions();
0 ignored issues
show
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...
647
    }
648
649
    /**
650
     * @param array $formats
651
     * */
652
    protected function addPresetExportFormats(array $formats = [])
653
    {
654
        $blast = $this->getConfigurationPool()->getContainer()->getParameter('blast');
0 ignored issues
show
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...
655
        $this->exportFields = $formats;
0 ignored issues
show
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...
656
657
        foreach ($this->getCurrentComposition() as $class) {
0 ignored issues
show
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...
658
            // remove / reset
659
            if (isset($blast[$class][ListMapper::class]['remove']['_export_format'])) {
660
                $this->exportFields = [];
661
            }
662
663
            // add
664
            if (isset($blast[$class][ListMapper::class]['add']['_export_format'])) {
665
                foreach ($blast[$class][ListMapper::class]['add']['_export_format'] as $format => $fields) {
666
                    // if no fields are defined (not an associative array)
667
                    if (intval($format) . '' == '' . $format && !is_array($fields)) {
668
                        $format = $fields;
669
                        $this->exportFields[$format] = $fields = [];
670
                    }
671
672
                    // if a copy of an other format is requested
673
                    if (!is_array($fields) && isset($blast[$class][ListMapper::class]['add']['_export_format'][$fields])) {
674
                        $blast[$class][ListMapper::class]['add']['_export_format'][$format] = // the global fields array
675
                                $fields = // the local  fields array
676
                                $blast[$class][ListMapper::class]['add']['_export_format'][$fields];  // the source fields array
677
                    }
678
679
                    // removes a specific format
680
                    if (substr($format, 0, 1) == '-') {
681
                        unset($this->exportFields[substr($format, 1)]);
682
                        continue;
683
                    }
684
685
                    // if an order is defined, use it to order the extracted fields
686
                    if (!$fields && isset($blast[$class][ListMapper::class]['add']['_options']['fieldsOrder'])) {
687
                        // get back default fields
688
                        $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...
689
                        $fields = [];
690
691
                        // takes the ordered fields
692 View Code Duplication
                        foreach ($blast[$class][ListMapper::class]['add']['_options']['fieldsOrder'] as $field) {
0 ignored issues
show
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...
693
                            if (in_array($field, $tmp)) {
694
                                $fields[] = $field;
695
                            }
696
                        }
697
698
                        // then the forgotten fields as they come
699 View Code Duplication
                        foreach ($tmp as $field) {
0 ignored issues
show
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...
700
                            if (!in_array($field, $blast[$class][ListMapper::class]['add']['_options']['fieldsOrder'])) {
701
                                $fields[] = $field;
702
                            }
703
                        }
704
                    }
705
                    $this->exportFields[$format] = $fields;
706
                }
707
            }
708
        }
709
710
        return $this->exportFields;
711
    }
712
713
    /**
714
     * @todo parse ShowMapper and FormMapper
715
     */
716
    protected function parseExtraTemplates()
717
    {
718
        $blast = $this->getConfigurationPool()->getContainer()->getParameter('blast');
0 ignored issues
show
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...
719
720
        foreach ($this->getCurrentComposition() as $class) {
0 ignored issues
show
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...
721
            // remove / reset
722
            if (isset($blast[$class][ListMapper::class]['remove']['_extra_templates'])) {
0 ignored issues
show
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...
723
                // TODO
724
            }
725
726
            // add
727 View Code Duplication
            if (isset($blast[$class][ListMapper::class]['add']['_extra_templates'])) {
0 ignored issues
show
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...
728
                foreach ($blast[$class][ListMapper::class]['add']['_extra_templates'] as $template) {
729
                    $this->addExtraTemplate('list', $template);
0 ignored issues
show
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...
730
                }
731
            }
732
        }
733
    }
734
735
    protected function parseHelperLinks()
736
    {
737
        $blast = $this->getConfigurationPool()->getContainer()->getParameter('blast');
0 ignored issues
show
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...
738
        $mappers = [
739
            'list' => ListMapper::class,
740
            'show' => ShowMapper::class,
741
            'form' => FormMapper::class,
742
        ];
743
744
        foreach ($this->getCurrentComposition() as $class) {
0 ignored issues
show
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...
745
            foreach ($mappers as $mapper => $mapper_class) {
746
                // remove / reset
747
                if (isset($blast[$class][$mapper_class]['remove']['_helper_links'])) {
0 ignored issues
show
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...
748
                    // TODO
749
                }
750
751
                // add
752 View Code Duplication
                if (isset($blast[$class][$mapper_class]['add']['_helper_links'])) {
0 ignored issues
show
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...
753
                    foreach ($blast[$class][$mapper_class]['add']['_helper_links'] as $link) {
754
                        $this->addHelperLink($mapper, $link);
0 ignored issues
show
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...
755
                    }
756
                }
757
            }
758
        }
759
    }
760
761
    protected function setTitles(BaseMapper $mapper, $titleTemplate, $title)
762
    {
763
        $contexts = [
764
            ListMapper::class => 'list',
765
            ShowMapper::class => 'show',
766
            FormMapper::class => 'form',
767
        ];
768
        if (!isset($contexts[get_class($mapper)])) {
769
            return;
770
        }
771
772
        $context = $contexts[get_class($mapper)];
773
        if ($titleTemplate) {
774
            $this->titleTemplates[$context] = $titleTemplate;
775
        }
776
        if ($title) {
777
            $this->titles[$context] = $title;
778
        }
779
    }
780
781
    protected function getFormThemeMapping()
782
    {
783
        $theme = [];
784
        $blast = $this->getConfigurationPool()->getContainer()->getParameter('blast');
0 ignored issues
show
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...
785
786
        foreach ($this->getCurrentComposition() as $class) {
0 ignored issues
show
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...
787
            if (isset($blast[$class])) {
788
                if (isset($blast[$class]['form_theme'])) {
789
                    $theme = array_merge($theme, $blast[$class]['form_theme']);
790
                }
791
            }
792
        }
793
794
        return $theme;
795
    }
796
797
    protected function getBaseRouteMapping()
798
    {
799
        $baseRoute = [];
800
        $blast = $this->getConfigurationPool()->getContainer()->getParameter('blast');
0 ignored issues
show
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...
801
802
        foreach ($this->getCurrentComposition() as $class) {
0 ignored issues
show
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...
803
            if (isset($blast[$class]) && isset($blast[$class]['baseRoute'])) {
804
                $reflexionClass = new \ReflectionClass($class);
805
                if (!$reflexionClass->isTrait()) {
806
                    $baseRoute = array_merge($baseRoute, $blast[$class]['baseRoute']);
807
                }
808
            }
809
        }
810
811
        return $baseRoute;
812
    }
813
814
    protected function manageCallback($mapper, &$options, $callbackType)
0 ignored issues
show
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...
815
    {
816
        $option = $options[$callbackType];
817
818
        $entityClass = isset($options['class']) ? $options['class'] : $this->getClass();
0 ignored issues
show
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...
819
820
        if (!is_array($option)) {
821
            throw new Exception('« $callbackType » option must be an array : ["FQDN"=>"static method name"]');
822
        }
823
824
        list($serviceNameOrClass, $methodName) = $option;
825
826
        $targetOptions = (isset($option[2]) ? $option[2] : null);
827
828
        if ($this->getConfigurationPool()->getContainer()->has($serviceNameOrClass)) {
0 ignored issues
show
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...
829
            $callBackFunction = [$this->getConfigurationPool()->getContainer()->get($serviceNameOrClass), $methodName];
0 ignored issues
show
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...
830
        } else {
831
            $callBackFunction = call_user_func($serviceNameOrClass . '::' . $methodName, $this->getModelManager(), $entityClass);
0 ignored issues
show
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...
832
        }
833
834
        if ($targetOptions !== null) {
835
            $options[$targetOptions] = $callBackFunction;
836
            unset($options[$callbackType]);
837
        }
838
839
        return $callBackFunction;
840
    }
841
842
    protected function manageQueryCallback($mapper, &$options)
843
    {
844
        $callback = $this->manageCallback($mapper, $options, 'query');
845
        $options['query'] = $callback;
846
    }
847
848
    protected function manageChoicesCallback($mapper, &$options)
849
    {
850
        $callback = $this->manageCallback($mapper, $options, 'choicesCallback');
851
852
        $options['choices'] = $callback;
853
        $options['choice_loader'] = new CallbackChoiceLoader(function () use ($options) {
854
            return $options['choices'];
855
        });
856
        unset($options['choicesCallback']);
857
    }
858
859
    public function manageServiceCallback($mapper, &$options)
860
    {
861
        $this->manageCallback($mapper, $options, 'serviceCallback');
862
    }
863
}
864