Completed
Push — 3.x ( bf184d...e95e95 )
by Grégoire
04:32
created

Pool   C

Complexity

Total Complexity 53

Size/Duplication

Total Lines 442
Duplicated Lines 0 %

Coupling/Cohesion

Components 4
Dependencies 4

Importance

Changes 0
Metric Value
wmc 53
lcom 4
cbo 4
dl 0
loc 442
rs 6.96
c 0
b 0
f 0

24 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 13 1
A getGroups() 0 12 3
A hasGroup() 0 4 1
B getDashboardGroups() 0 29 7
A getAdminsByGroup() 0 18 4
A getAdminByClass() 0 20 4
A hasAdminByClass() 0 4 1
B getAdminByAdminCode() 0 53 6
B getInstance() 0 38 9
A getContainer() 0 4 1
A setAdminGroups() 0 4 1
A getAdminGroups() 0 4 1
A setAdminServiceIds() 0 4 1
A getAdminServiceIds() 0 4 1
A setAdminClasses() 0 4 1
A getAdminClasses() 0 4 1
A setTemplateRegistry() 0 4 1
A setTemplates() 0 7 1
A getTemplates() 0 4 1
A getTemplate() 0 4 1
A getTitleLogo() 0 4 1
A getTitle() 0 4 1
A getOption() 0 8 2
A getPropertyAccessor() 0 8 2

How to fix   Complexity   

Complex Class

Complex classes like Pool often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Pool, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Sonata Project package.
7
 *
8
 * (c) Thomas Rabaix <[email protected]>
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Sonata\AdminBundle\Admin;
15
16
use InvalidArgumentException;
17
use Sonata\AdminBundle\Templating\MutableTemplateRegistryInterface;
18
use Symfony\Component\DependencyInjection\ContainerInterface;
19
use Symfony\Component\PropertyAccess\PropertyAccess;
20
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
21
22
/**
23
 * @author Thomas Rabaix <[email protected]>
24
 */
25
class Pool
26
{
27
    /**
28
     * @var ContainerInterface
29
     */
30
    protected $container;
31
32
    /**
33
     * @var string[]
34
     */
35
    protected $adminServiceIds = [];
36
37
    /**
38
     * @var array
39
     */
40
    protected $adminGroups = [];
41
42
    /**
43
     * @var array
44
     */
45
    protected $adminClasses = [];
46
47
    /**
48
     * @deprecated since 3.34, will be dropped in 4.0. Use TemplateRegistry "sonata.admin.global_template_registry" instead
49
     *
50
     * @var array
51
     */
52
    protected $templates = [];
53
54
    /**
55
     * @var array
56
     */
57
    protected $assets = [];
58
59
    /**
60
     * @var string
61
     */
62
    protected $title;
63
64
    /**
65
     * @var string
66
     */
67
    protected $titleLogo;
68
69
    /**
70
     * @var array
71
     */
72
    protected $options;
73
74
    /**
75
     * @var PropertyAccessorInterface
76
     */
77
    protected $propertyAccessor;
78
79
    /**
80
     * @var MutableTemplateRegistryInterface
81
     */
82
    private $templateRegistry;
83
84
    /**
85
     * @param string $title
86
     * @param string $logoTitle
87
     * @param array  $options
88
     */
89
    public function __construct(
90
        ContainerInterface $container,
91
        $title,
92
        $logoTitle,
93
        $options = [],
94
        PropertyAccessorInterface $propertyAccessor = null
95
    ) {
96
        $this->container = $container;
97
        $this->title = $title;
98
        $this->titleLogo = $logoTitle;
99
        $this->options = $options;
100
        $this->propertyAccessor = $propertyAccessor;
101
    }
102
103
    /**
104
     * @return array
105
     */
106
    public function getGroups()
107
    {
108
        $groups = $this->adminGroups;
109
110
        foreach ($this->adminGroups as $name => $adminGroup) {
111
            foreach ($adminGroup as $id => $options) {
112
                $groups[$name][$id] = $this->getInstance($id);
113
            }
114
        }
115
116
        return $groups;
117
    }
118
119
    /**
120
     * Returns whether an admin group exists or not.
121
     *
122
     * @param string $group
123
     *
124
     * @return bool
125
     */
126
    public function hasGroup($group)
127
    {
128
        return isset($this->adminGroups[$group]);
129
    }
130
131
    /**
132
     * @return array
133
     */
134
    public function getDashboardGroups()
135
    {
136
        $groups = $this->adminGroups;
137
138
        foreach ($this->adminGroups as $name => $adminGroup) {
139
            if (isset($adminGroup['items'])) {
140
                foreach ($adminGroup['items'] as $key => $item) {
141
                    // Only Admin Group should be returned
142
                    if ('' !== $item['admin']) {
143
                        $admin = $this->getInstance($item['admin']);
144
145
                        if ($admin->showIn(AbstractAdmin::CONTEXT_DASHBOARD)) {
146
                            $groups[$name]['items'][$key] = $admin;
147
                        } else {
148
                            unset($groups[$name]['items'][$key]);
149
                        }
150
                    } else {
151
                        unset($groups[$name]['items'][$key]);
152
                    }
153
                }
154
            }
155
156
            if (empty($groups[$name]['items'])) {
157
                unset($groups[$name]);
158
            }
159
        }
160
161
        return $groups;
162
    }
163
164
    /**
165
     * Returns all admins related to the given $group.
166
     *
167
     * @param string $group
168
     *
169
     * @throws \InvalidArgumentException
170
     *
171
     * @return AdminInterface[]
172
     */
173
    public function getAdminsByGroup($group)
174
    {
175
        if (!isset($this->adminGroups[$group])) {
176
            throw new \InvalidArgumentException(sprintf('Group "%s" not found in admin pool.', $group));
177
        }
178
179
        $admins = [];
180
181
        if (!isset($this->adminGroups[$group]['items'])) {
182
            return $admins;
183
        }
184
185
        foreach ($this->adminGroups[$group]['items'] as $item) {
186
            $admins[] = $this->getInstance($item['admin']);
187
        }
188
189
        return $admins;
190
    }
191
192
    /**
193
     * Return the admin related to the given $class.
194
     *
195
     * @param string $class
196
     *
197
     * @return \Sonata\AdminBundle\Admin\AdminInterface|null
198
     */
199
    public function getAdminByClass($class)
200
    {
201
        if (!$this->hasAdminByClass($class)) {
202
            return null;
203
        }
204
205
        if (!\is_array($this->adminClasses[$class])) {
206
            throw new \RuntimeException('Invalid format for the Pool::adminClass property');
207
        }
208
209
        if (\count($this->adminClasses[$class]) > 1) {
210
            throw new \RuntimeException(sprintf(
211
                'Unable to find a valid admin for the class: %s, there are too many registered: %s',
212
                $class,
213
                implode(', ', $this->adminClasses[$class])
214
            ));
215
        }
216
217
        return $this->getInstance($this->adminClasses[$class][0]);
218
    }
219
220
    /**
221
     * @param string $class
222
     *
223
     * @return bool
224
     */
225
    public function hasAdminByClass($class)
226
    {
227
        return isset($this->adminClasses[$class]);
228
    }
229
230
    /**
231
     * Returns an admin class by its Admin code
232
     * ie : sonata.news.admin.post|sonata.news.admin.comment => return the child class of post.
233
     *
234
     * @param string $adminCode
235
     *
236
     * @throws \InvalidArgumentException if the root admin code is an empty string
237
     *
238
     * @return \Sonata\AdminBundle\Admin\AdminInterface|false
239
     */
240
    public function getAdminByAdminCode($adminCode)
241
    {
242
        if (!\is_string($adminCode)) {
243
            @trigger_error(sprintf(
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
244
                'Passing a non string value as argument 1 for %s() is deprecated since sonata-project/admin-bundle 3.x and will throw an exception in 4.0.',
245
                __METHOD__
246
            ), E_USER_DEPRECATED);
247
248
            return false;
249
250
            // NEXT_MAJOR : remove this condition check and declare "string" as type without default value for argument 1
251
        }
252
        $codes = explode('|', $adminCode);
253
        $code = trim(array_shift($codes));
254
255
        if ('' === $code) {
256
            throw new \InvalidArgumentException('Root admin code must contain a valid admin reference, empty string given.');
257
        }
258
259
        $admin = $this->getInstance($code);
260
261
        foreach ($codes as $code) {
262
            if (!\in_array($code, $this->adminServiceIds, true)) {
263
                @trigger_error(sprintf(
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
264
                    'Passing an invalid admin code as argument 1 for %s() is deprecated since sonata-project/admin-bundle 3.50 and will throw an exception in 4.0.',
265
                    __METHOD__
266
                ), E_USER_DEPRECATED);
267
268
                // NEXT_MAJOR : throw `\InvalidArgumentException` instead
269
            }
270
271
            if (!$admin->hasChild($code)) {
272
                @trigger_error(sprintf(
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
273
                    'Passing an invalid admin hierarchy inside argument 1 for %s() is deprecated since sonata-project/admin-bundle 3.x and will throw an exception in 4.0.',
274
                    __METHOD__
275
                ), E_USER_DEPRECATED);
276
277
                // NEXT_MAJOR : remove the previous `trigger_error()` call, uncomment the following excception and declare AdminInterface as return type
278
                // throw new InvalidArgumentException(sprintf(
279
                //    'Argument 1 passed to %s() must contain a valid admin hierarchy, "%s" is not a valid child for "%s"',
280
                //    __METHOD__,
281
                //    $code,
282
                //    $admin->getCode()
283
                // ));
284
285
                return false;
286
            }
287
288
            $admin = $admin->getChild($code);
289
        }
290
291
        return $admin;
292
    }
293
294
    /**
295
     * Returns a new admin instance depends on the given code.
296
     *
297
     * @param string $id
298
     *
299
     * @throws \InvalidArgumentException
300
     *
301
     * @return AdminInterface
302
     */
303
    public function getInstance($id)
304
    {
305
        if (!\in_array($id, $this->adminServiceIds, true)) {
306
            $msg = sprintf('Admin service "%s" not found in admin pool.', $id);
307
            $shortest = -1;
308
            $closest = null;
309
            $alternatives = [];
310
            foreach ($this->adminServiceIds as $adminServiceId) {
311
                $lev = levenshtein($id, $adminServiceId);
312
                if ($lev <= $shortest || $shortest < 0) {
313
                    $closest = $adminServiceId;
314
                    $shortest = $lev;
315
                }
316
                if ($lev <= \strlen($adminServiceId) / 3 || false !== strpos($adminServiceId, $id)) {
317
                    $alternatives[$adminServiceId] = $lev;
318
                }
319
            }
320
            if (null !== $closest) {
321
                asort($alternatives);
322
                unset($alternatives[$closest]);
323
                $msg = sprintf(
324
                    'Admin service "%s" not found in admin pool. Did you mean "%s" or one of those: [%s]?',
325
                    $id,
326
                    $closest,
327
                    implode(', ', array_keys($alternatives))
328
                );
329
            }
330
            throw new \InvalidArgumentException($msg);
331
        }
332
333
        $admin = $this->container->get($id);
334
335
        if (!$admin instanceof AdminInterface) {
336
            throw new InvalidArgumentException(sprintf('Found service "%s" is not a valid admin service', $id));
337
        }
338
339
        return $admin;
340
    }
341
342
    /**
343
     * @return ContainerInterface|null
344
     */
345
    public function getContainer()
346
    {
347
        return $this->container;
348
    }
349
350
    public function setAdminGroups(array $adminGroups)
351
    {
352
        $this->adminGroups = $adminGroups;
353
    }
354
355
    /**
356
     * @return array
357
     */
358
    public function getAdminGroups()
359
    {
360
        return $this->adminGroups;
361
    }
362
363
    public function setAdminServiceIds(array $adminServiceIds)
364
    {
365
        $this->adminServiceIds = $adminServiceIds;
366
    }
367
368
    /**
369
     * @return array
370
     */
371
    public function getAdminServiceIds()
372
    {
373
        return $this->adminServiceIds;
374
    }
375
376
    public function setAdminClasses(array $adminClasses)
377
    {
378
        $this->adminClasses = $adminClasses;
379
    }
380
381
    /**
382
     * @return array
383
     */
384
    public function getAdminClasses()
385
    {
386
        return $this->adminClasses;
387
    }
388
389
    final public function setTemplateRegistry(MutableTemplateRegistryInterface $templateRegistry)
390
    {
391
        $this->templateRegistry = $templateRegistry;
392
    }
393
394
    /**
395
     * @deprecated since 3.34, will be dropped in 4.0. Use TemplateRegistry "sonata.admin.global_template_registry" instead
396
     */
397
    public function setTemplates(array $templates)
398
    {
399
        // NEXT MAJOR: Remove this line
400
        $this->templates = $templates;
0 ignored issues
show
Deprecated Code introduced by
The property Sonata\AdminBundle\Admin\Pool::$templates has been deprecated with message: since 3.34, will be dropped in 4.0. Use TemplateRegistry "sonata.admin.global_template_registry" instead

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
401
402
        $this->templateRegistry->setTemplates($templates);
403
    }
404
405
    /**
406
     * @deprecated since 3.34, will be dropped in 4.0. Use TemplateRegistry "sonata.admin.global_template_registry" instead
407
     *
408
     * @return array
409
     */
410
    public function getTemplates()
411
    {
412
        return $this->templateRegistry->getTemplates();
413
    }
414
415
    /**
416
     * @deprecated since 3.34, will be dropped in 4.0. Use TemplateRegistry "sonata.admin.global_template_registry" instead
417
     *
418
     * @param string $name
419
     *
420
     * @return string|null
421
     */
422
    public function getTemplate($name)
423
    {
424
        return $this->templateRegistry->getTemplate($name);
425
    }
426
427
    /**
428
     * @return string
429
     */
430
    public function getTitleLogo()
431
    {
432
        return $this->titleLogo;
433
    }
434
435
    /**
436
     * @return string
437
     */
438
    public function getTitle()
439
    {
440
        return $this->title;
441
    }
442
443
    /**
444
     * @param string $name
445
     * @param mixed  $default
446
     *
447
     * @return mixed
448
     */
449
    public function getOption($name, $default = null)
450
    {
451
        if (isset($this->options[$name])) {
452
            return $this->options[$name];
453
        }
454
455
        return $default;
456
    }
457
458
    public function getPropertyAccessor()
459
    {
460
        if (null === $this->propertyAccessor) {
461
            $this->propertyAccessor = PropertyAccess::createPropertyAccessor();
462
        }
463
464
        return $this->propertyAccessor;
465
    }
466
}
467