Completed
Push — 3.x ( 647698...abeb07 )
by Oskar
04:38
created

Pool::hasAdminByAdminCode()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 13
rs 9.8333
c 0
b 0
f 0
cc 3
nc 3
nop 1
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 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.51 and will cause a \TypeError 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
253
        $codes = explode('|', $adminCode);
254
        $code = trim(array_shift($codes));
255
256
        if ('' === $code) {
257
            throw new \InvalidArgumentException('Root admin code must contain a valid admin reference, empty string given.');
258
        }
259
260
        $admin = $this->getInstance($code);
261
262
        foreach ($codes as $code) {
263
            if (!\in_array($code, $this->adminServiceIds, true)) {
264
                @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...
265
                    '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.',
266
                    __METHOD__
267
                ), E_USER_DEPRECATED);
268
269
                // NEXT_MAJOR : throw `\InvalidArgumentException` instead
270
            }
271
272
            if (!$admin->hasChild($code)) {
273
                @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...
274
                    'Passing an invalid admin hierarchy inside argument 1 for %s() is deprecated since sonata-project/admin-bundle 3.51 and will throw an exception in 4.0.',
275
                    __METHOD__
276
                ), E_USER_DEPRECATED);
277
278
                // NEXT_MAJOR : remove the previous `trigger_error()` call, uncomment the following exception and declare AdminInterface as return type
279
                // throw new \InvalidArgumentException(sprintf(
280
                //    'Argument 1 passed to %s() must contain a valid admin hierarchy, "%s" is not a valid child for "%s"',
281
                //    __METHOD__,
282
                //    $code,
283
                //    $admin->getCode()
284
                // ));
285
286
                return false;
287
            }
288
289
            $admin = $admin->getChild($code);
290
        }
291
292
        return $admin;
293
    }
294
295
    /**
296
     * Checks if an admin with a certain admin code exists.
297
     */
298
    final public function hasAdminByAdminCode(string $adminCode): bool
299
    {
300
        try {
301
            if (!$this->getAdminByAdminCode($adminCode) instanceof AdminInterface) {
302
                // NEXT_MAJOR : remove `if (...instanceof...) { return false; }` as getAdminByAdminCode() will then always throw an \InvalidArgumentException when somethings wrong
303
                return false;
304
            }
305
        } catch (\InvalidArgumentException $e) {
306
            return false;
307
        }
308
309
        return true;
310
    }
311
312
    /**
313
     * Returns a new admin instance depends on the given code.
314
     *
315
     * @param string $id
316
     *
317
     * @throws \InvalidArgumentException
318
     *
319
     * @return AdminInterface
320
     */
321
    public function getInstance($id)
322
    {
323
        if (!\in_array($id, $this->adminServiceIds, true)) {
324
            $msg = sprintf('Admin service "%s" not found in admin pool.', $id);
325
            $shortest = -1;
326
            $closest = null;
327
            $alternatives = [];
328
            foreach ($this->adminServiceIds as $adminServiceId) {
329
                $lev = levenshtein($id, $adminServiceId);
330
                if ($lev <= $shortest || $shortest < 0) {
331
                    $closest = $adminServiceId;
332
                    $shortest = $lev;
333
                }
334
                if ($lev <= \strlen($adminServiceId) / 3 || false !== strpos($adminServiceId, $id)) {
335
                    $alternatives[$adminServiceId] = $lev;
336
                }
337
            }
338
            if (null !== $closest) {
339
                asort($alternatives);
340
                unset($alternatives[$closest]);
341
                $msg = sprintf(
342
                    'Admin service "%s" not found in admin pool. Did you mean "%s" or one of those: [%s]?',
343
                    $id,
344
                    $closest,
345
                    implode(', ', array_keys($alternatives))
346
                );
347
            }
348
            throw new \InvalidArgumentException($msg);
349
        }
350
351
        $admin = $this->container->get($id);
352
353
        if (!$admin instanceof AdminInterface) {
354
            throw new InvalidArgumentException(sprintf('Found service "%s" is not a valid admin service', $id));
355
        }
356
357
        return $admin;
358
    }
359
360
    /**
361
     * @return ContainerInterface|null
362
     */
363
    public function getContainer()
364
    {
365
        return $this->container;
366
    }
367
368
    public function setAdminGroups(array $adminGroups)
369
    {
370
        $this->adminGroups = $adminGroups;
371
    }
372
373
    /**
374
     * @return array
375
     */
376
    public function getAdminGroups()
377
    {
378
        return $this->adminGroups;
379
    }
380
381
    public function setAdminServiceIds(array $adminServiceIds)
382
    {
383
        $this->adminServiceIds = $adminServiceIds;
384
    }
385
386
    /**
387
     * @return array
388
     */
389
    public function getAdminServiceIds()
390
    {
391
        return $this->adminServiceIds;
392
    }
393
394
    public function setAdminClasses(array $adminClasses)
395
    {
396
        $this->adminClasses = $adminClasses;
397
    }
398
399
    /**
400
     * @return array
401
     */
402
    public function getAdminClasses()
403
    {
404
        return $this->adminClasses;
405
    }
406
407
    final public function setTemplateRegistry(MutableTemplateRegistryInterface $templateRegistry)
408
    {
409
        $this->templateRegistry = $templateRegistry;
410
    }
411
412
    /**
413
     * @deprecated since 3.34, will be dropped in 4.0. Use TemplateRegistry "sonata.admin.global_template_registry" instead
414
     */
415
    public function setTemplates(array $templates)
416
    {
417
        // NEXT MAJOR: Remove this line
418
        $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...
419
420
        $this->templateRegistry->setTemplates($templates);
421
    }
422
423
    /**
424
     * @deprecated since 3.34, will be dropped in 4.0. Use TemplateRegistry "sonata.admin.global_template_registry" instead
425
     *
426
     * @return array
427
     */
428
    public function getTemplates()
429
    {
430
        return $this->templateRegistry->getTemplates();
431
    }
432
433
    /**
434
     * @deprecated since 3.34, will be dropped in 4.0. Use TemplateRegistry "sonata.admin.global_template_registry" instead
435
     *
436
     * @param string $name
437
     *
438
     * @return string|null
439
     */
440
    public function getTemplate($name)
441
    {
442
        return $this->templateRegistry->getTemplate($name);
443
    }
444
445
    /**
446
     * @return string
447
     */
448
    public function getTitleLogo()
449
    {
450
        return $this->titleLogo;
451
    }
452
453
    /**
454
     * @return string
455
     */
456
    public function getTitle()
457
    {
458
        return $this->title;
459
    }
460
461
    /**
462
     * @param string $name
463
     * @param mixed  $default
464
     *
465
     * @return mixed
466
     */
467
    public function getOption($name, $default = null)
468
    {
469
        if (isset($this->options[$name])) {
470
            return $this->options[$name];
471
        }
472
473
        return $default;
474
    }
475
476
    public function getPropertyAccessor()
477
    {
478
        if (null === $this->propertyAccessor) {
479
            $this->propertyAccessor = PropertyAccess::createPropertyAccessor();
480
        }
481
482
        return $this->propertyAccessor;
483
    }
484
}
485