Completed
Pull Request — 5.6 (#2830)
by Jeroen
14:14
created

Configurator/AbstractAdminListConfigurator.php (2 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
namespace Kunstmaan\AdminListBundle\AdminList\Configurator;
4
5
use Doctrine\ORM\PersistentCollection;
6
use InvalidArgumentException;
7
use Kunstmaan\AdminListBundle\AdminList\BulkAction\BulkActionInterface;
8
use Kunstmaan\AdminListBundle\AdminList\Field;
9
use Kunstmaan\AdminListBundle\AdminList\FieldAlias;
10
use Kunstmaan\AdminListBundle\AdminList\FilterBuilder;
11
use Kunstmaan\AdminListBundle\AdminList\FilterType\FilterTypeInterface;
12
use Kunstmaan\AdminListBundle\AdminList\ItemAction\ItemActionInterface;
13
use Kunstmaan\AdminListBundle\AdminList\ItemAction\SimpleItemAction;
14
use Kunstmaan\AdminListBundle\AdminList\ListAction\ListActionInterface;
15
use Symfony\Component\Form\AbstractType;
16
use Symfony\Component\HttpFoundation\Request;
17
use Symfony\Component\PropertyAccess\PropertyAccess;
18
19
/**
20
 * Abstract admin list configurator, this implements the most common functionality from the
21
 * AdminListConfiguratorInterface and ExportListConfiguratorInterface
22
 */
23
abstract class AbstractAdminListConfigurator implements AdminListConfiguratorInterface, ExportListConfiguratorInterface
24
{
25
    const SUFFIX_ADD = 'add';
26
    const SUFFIX_EDIT = 'edit';
27
    const SUFFIX_EXPORT = 'export';
28
    const SUFFIX_DELETE = 'delete';
29
    const SUFFIX_VIEW = 'view';
30
31
    /**
32
     * @var Field[]
33
     */
34
    private $fields = [];
35
36
    /**
37
     * @var Field[]
38
     */
39
    private $exportFields = [];
40
41
    /**
42
     * @var ItemActionInterface[]
43
     */
44
    private $itemActions = [];
45
46
    /**
47
     * @var ListActionInterface[]
48
     */
49
    private $listActions = [];
50
51
    /**
52
     * @var BulkActionInterface[]
53
     */
54
    private $bulkActions = [];
55
56
    /**
57
     * @var AbstractType
58
     */
59
    private $type;
60
61
    /**
62
     * @var array
63
     */
64
    private $typeOptions = [];
65
66
    /**
67
     * @var string
68
     */
69
    private $listTemplate = '@KunstmaanAdminList/Default/list.html.twig';
70
71
    /**
72
     * @var string
73
     */
74
    private $addTemplate = '@KunstmaanAdminList/Default/add_or_edit.html.twig';
75
76
    /**
77
     * @var string
78
     */
79
    private $editTemplate = '@KunstmaanAdminList/Default/add_or_edit.html.twig';
80
81
    /**
82
     * @var string
83
     */
84
    private $viewTemplate = '@KunstmaanAdminList/Default/view.html.twig';
85
86
    /**
87
     * @var string
88
     */
89
    private $deleteTemplate = '@KunstmaanAdminList/Default/delete.html.twig';
90
91
    /**
92
     * @var FilterBuilder
93
     */
94
    private $filterBuilder;
95
96
    /**
97
     * @var int
98
     */
99
    protected $page = 1;
100
101
    /**
102
     * @var string
103
     */
104
    protected $orderBy = '';
105
106
    /**
107
     * @var string
108
     */
109
    protected $orderDirection = '';
110
111
    /**
112
     * Return current bundle name.
113
     *
114
     * @return string
115
     */
116
    abstract public function getBundleName();
117
118
    /**
119
     * Return current entity name.
120
     *
121
     * @return string
122
     */
123
    abstract public function getEntityName();
124
125
    /**
126
     * Return default repository name.
127
     *
128
     * @return string
129
     */
130 8
    public function getRepositoryName()
131
    {
132 8
        return sprintf('%s:%s', $this->getBundleName(), $this->getEntityName());
133
    }
134
135
    /**
136
     * Configure the fields you can filter on
137
     */
138
    public function buildFilters()
139
    {
140
    }
141
142
    /**
143
     * Configure the actions for each line
144
     */
145
    public function buildItemActions()
146
    {
147
    }
148
149
    /**
150
     * Configure the actions that can be executed on the whole list
151
     */
152
    public function buildListActions()
153
    {
154
    }
155
156
    /**
157
     * Configure the export fields
158
     */
159 1
    public function buildExportFields()
160
    {
161
        /*
162
         * This is only here to prevent a BC break!!!
163
         *
164
         * Just override this function if you want to set your own fields...
165
         */
166 1
        if (empty($this->fields)) {
167 1
            $this->buildFields();
168
        }
169 1
    }
170
171
    /**
172
     * Build iterator (if needed)
173
     */
174
    public function buildIterator()
175
    {
176
    }
177
178
    /**
179
     * Reset all built members
180
     */
181 1
    public function resetBuilds()
182
    {
183 1
        $this->fields = [];
184 1
        $this->exportFields = [];
185 1
        $this->filterBuilder = null;
186 1
        $this->itemActions = [];
187 1
        $this->listActions = [];
188 1
    }
189
190
    /**
191
     * Configure the types of items you can add
192
     *
193
     * @return array
0 ignored issues
show
Consider making the return type a bit more specific; maybe use array<string,array<string,string|array>>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
194
     */
195 1
    public function getAddUrlFor(array $params = [])
196
    {
197 1
        $params = array_merge($params, $this->getExtraParameters());
198
199 1
        $friendlyName = explode('\\', $this->getEntityName());
200 1
        $friendlyName = array_pop($friendlyName);
201 1
        $re = '/(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])/';
202 1
        $a = preg_split($re, $friendlyName);
203 1
        $superFriendlyName = implode(' ', $a);
204
205
        return [
206
            $superFriendlyName => [
207 1
                'path' => $this->getPathByConvention($this::SUFFIX_ADD),
208 1
                'params' => $params,
209
            ],
210
        ];
211
    }
212
213
    /**
214
     * Get the url to export the listed items
215
     *
216
     * @return array
217
     */
218 1
    public function getExportUrl()
219
    {
220 1
        $params = $this->getExtraParameters();
221
222
        return [
223 1
            'path' => $this->getPathByConvention($this::SUFFIX_EXPORT),
224 1
            'params' => array_merge(['_format' => 'csv'], $params),
225
        ];
226
    }
227
228
    /**
229
     * Get the view url for the given $item
230
     *
231
     * @param object|array $item
232
     *
233
     * @return array
234
     */
235 1
    public function getViewUrlFor($item)
236
    {
237 1
        if (\is_object($item)) {
238 1
            $id = $item->getid();
239
        } else {
240 1
            $id = $item['id'];
241
        }
242 1
        $params = ['id' => $id];
243 1
        $params = array_merge($params, $this->getExtraParameters());
244
245
        return [
246 1
            'path' => $this->getPathByConvention($this::SUFFIX_VIEW),
247 1
            'params' => $params,
248
        ];
249
    }
250
251
    /**
252
     * Return the url to list all the items
253
     *
254
     * @return array
0 ignored issues
show
Consider making the return type a bit more specific; maybe use array<string,string|array>.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
255
     */
256 1
    public function getIndexUrl()
257
    {
258 1
        $params = $this->getExtraParameters();
259
260
        return [
261 1
            'path' => $this->getPathByConvention(),
262 1
            'params' => $params,
263
        ];
264
    }
265
266
    /**
267
     * @param object $entity
268
     *
269
     * @throws InvalidArgumentException
270
     *
271
     * @return string
272
     */
273 3
    public function getAdminType($entity)
274
    {
275 3
        if (null !== $this->type) {
276 1
            return $this->type;
277
        }
278
279 2
        if (method_exists($entity, 'getAdminType')) {
280 1
            return $entity->getAdminType();
281
        }
282
283 1
        throw new InvalidArgumentException('You need to implement the getAdminType method in ' . \get_class($this) . ' or ' . \get_class($entity));
284
    }
285
286
    /**
287
     * @param string $type
288
     *
289
     * @return AbstractAdminListConfigurator
290
     */
291 6
    public function setAdminType($type)
292
    {
293 6
        $this->type = $type;
294
295 6
        return $this;
296
    }
297
298
    /**
299
     * @param array $typeOptions
300
     *
301
     * @return AbstractAdminListConfigurator
302
     */
303 5
    public function setAdminTypeOptions($typeOptions)
304
    {
305 5
        $this->typeOptions = $typeOptions;
306
307 5
        return $this;
308
    }
309
310
    /**
311
     * Return the default form admin type options
312
     *
313
     * @return array
314
     */
315 1
    public function getAdminTypeOptions()
316
    {
317 1
        return $this->typeOptions;
318
    }
319
320
    /**
321
     * @param object|array $item
322
     *
323
     * @return bool
324
     */
325 1
    public function canEdit($item)
326
    {
327 1
        return true;
328
    }
329
330
    /**
331
     * Configure if it's possible to delete the given $item
332
     *
333
     * @param object|array $item
334
     *
335
     * @return bool
336
     */
337 1
    public function canDelete($item)
338
    {
339 1
        return true;
340
    }
341
342
    /**
343
     * Configure if it's possible to add new items
344
     *
345
     * @return bool
346
     */
347 1
    public function canAdd()
348
    {
349 1
        return true;
350
    }
351
352 1
    public function canView($item)
353
    {
354 1
        return false;
355
    }
356
357
    /**
358
     * Configure if it's possible to add new items
359
     *
360
     * @return bool
361
     */
362 1
    public function canExport()
363
    {
364 1
        return false;
365
    }
366
367
    /**
368
     * @param string     $name     The field name
369
     * @param string     $header   The header title
370
     * @param bool       $sort     Sortable column or not
371
     * @param string     $template The template
372
     * @param FieldAlias $alias    The alias
373
     *
374
     * @return AbstractAdminListConfigurator
375
     */
376 8
    public function addField($name, $header, $sort, $template = null, FieldAlias $alias = null)
377
    {
378 8
        $this->fields[] = new Field($name, $header, $sort, $template, $alias);
379
380 8
        return $this;
381
    }
382
383
    /**
384
     * @param string     $name     The field name
385
     * @param string     $header   The header title
386
     * @param string     $template The template
387
     * @param FieldAlias $alias    The alias
388
     *
389
     * @return AbstractAdminListConfigurator
390
     */
391 1
    public function addExportField($name, $header, $template = null, FieldAlias $alias = null)
392
    {
393 1
        $this->exportFields[] = new Field($name, $header, false, $template, $alias);
394
395 1
        return $this;
396
    }
397
398
    /**
399
     * @param string              $columnName The column name
400
     * @param FilterTypeInterface $type       The filter type
401
     * @param string              $filterName The name of the filter
402
     * @param array               $options    Options
403
     *
404
     * @return AbstractAdminListConfigurator
405
     */
406 5
    public function addFilter(
407
        $columnName,
408
        FilterTypeInterface $type = null,
409
        $filterName = null,
410
        array $options = []
411
    ) {
412 5
        $this->getFilterBuilder()->add($columnName, $type, $filterName, $options);
413
414 5
        return $this;
415
    }
416
417
    /**
418
     * @return int
419
     */
420 3
    public function getLimit()
421
    {
422 3
        return 10;
423
    }
424
425
    /**
426
     * @return array
427
     */
428 1
    public function getSortFields()
429
    {
430 1
        $array = [];
431 1
        foreach ($this->getFields() as $field) {
432 1
            if ($field->isSortable()) {
433 1
                $array[] = $field->getName();
434
            }
435
        }
436
437 1
        return $array;
438
    }
439
440
    /**
441
     * @return Field[]
442
     */
443 9
    public function getFields()
444
    {
445 9
        return $this->fields;
446
    }
447
448
    /**
449
     * @return Field[]
450
     */
451 2
    public function getExportFields()
452
    {
453 2
        if (empty($this->exportFields)) {
454 1
            return $this->fields;
455
        }
456
457 1
        return $this->exportFields;
458
    }
459
460
    /**
461
     * @param string   $label          The label, only used when the template equals null
462
     * @param callable $routeGenerator The generator used to generate the url of an item, when generating the item will
463
     *                                 be provided
464
     * @param string   $icon           The icon, only used when the template equals null
465
     * @param string   $template       The template, when not specified the label is shown
466
     *
467
     * @return AbstractAdminListConfigurator
468
     */
469 1
    public function addSimpleItemAction($label, $routeGenerator, $icon, $template = null)
470
    {
471 1
        return $this->addItemAction(new SimpleItemAction($routeGenerator, $icon, $label, $template));
472
    }
473
474
    /**
475
     * @return AbstractAdminListConfigurator
476
     */
477 4
    public function addItemAction(ItemActionInterface $itemAction)
478
    {
479 4
        $this->itemActions[] = $itemAction;
480
481 4
        return $this;
482
    }
483
484
    /**
485
     * @return bool
486
     */
487 1
    public function hasItemActions()
488
    {
489 1
        return !empty($this->itemActions);
490
    }
491
492
    /**
493
     * @return ItemActionInterface[]
494
     */
495 3
    public function getItemActions()
496
    {
497 3
        return $this->itemActions;
498
    }
499
500
    /**
501
     * @return AdminListConfiguratorInterface
502
     */
503 1
    public function addListAction(ListActionInterface $listAction)
504
    {
505 1
        $this->listActions[] = $listAction;
506
507 1
        return $this;
508
    }
509
510
    /**
511
     * @return bool
512
     */
513 1
    public function hasListActions()
514
    {
515 1
        return !empty($this->listActions);
516
    }
517
518
    /**
519
     * @return ListActionInterface[]
520
     */
521 1
    public function getListActions()
522
    {
523 1
        return $this->listActions;
524
    }
525
526
    /**
527
     * @return AdminListConfiguratorInterface
528
     */
529 1
    public function addBulkAction(BulkActionInterface $bulkAction)
530
    {
531 1
        $this->bulkActions[] = $bulkAction;
532
533 1
        return $this;
534
    }
535
536
    /**
537
     * @return bool
538
     */
539 1
    public function hasBulkActions()
540
    {
541 1
        return !empty($this->bulkActions);
542
    }
543
544
    /**
545
     * @return BulkActionInterface[]
546
     */
547 1
    public function getBulkActions()
548
    {
549 1
        return $this->bulkActions;
550
    }
551
552
    /**
553
     * @return string
554
     */
555 2
    public function getListTemplate()
556
    {
557 2
        return $this->listTemplate;
558
    }
559
560
    /**
561
     * @param string $template
562
     *
563
     * @return AdminListConfiguratorInterface
564
     */
565 1
    public function setListTemplate($template)
566
    {
567 1
        $this->listTemplate = $template;
568
569 1
        return $this;
570
    }
571
572
    /**
573
     * @param array|object $item       The item
574
     * @param string       $columnName The column name
575
     *
576
     * @return mixed
577
     */
578 2
    public function getValue($item, $columnName)
579
    {
580 2
        if (\is_array($item)) {
581 2
            if (isset($item[$columnName])) {
582 2
                return $item[$columnName];
583
            }
584
585 1
            return '';
586
        }
587
588 1
        $accessor = PropertyAccess::createPropertyAccessor();
589
590 1
        if ($accessor->isReadable($item, $columnName)) {
591 1
            $result = $accessor->getValue($item, $columnName);
592
        } else {
593 1
            return sprintf('undefined function [get/is/has]%s()', $columnName);
594
        }
595
596 1
        return $result;
597
    }
598
599
    /**
600
     * @param array|object $item       The item
601
     * @param string       $columnName The column name
602
     *
603
     * @return string
604
     */
605 1
    public function getStringValue($item, $columnName)
606
    {
607 1
        $result = $this->getValue($item, $columnName);
608 1
        if (\is_bool($result)) {
609 1
            return $result ? 'true' : 'false';
610
        }
611 1
        if ($result instanceof \DateTimeInterface) {
612 1
            return $result->format('Y-m-d H:i:s');
613
        }
614
615 1
        if ($result instanceof PersistentCollection) {
616 1
            $results = [];
617
            /* @var Object $entry */
618 1
            foreach ($result as $entry) {
619 1
                $results[] = $entry->getName();
620
            }
621 1
            if (empty($results)) {
622 1
                return '';
623
            }
624
625 1
            return implode(', ', $results);
626
        }
627
628 1
        if (is_array($result)) {
629 1
            return implode(', ', $result);
630
        }
631
632 1
        return $result;
633
    }
634
635
    /**
636
     * @return string
637
     */
638 1
    public function getAddTemplate()
639
    {
640 1
        return $this->addTemplate;
641
    }
642
643
    /**
644
     * @param string $template
645
     *
646
     * @return AdminListConfiguratorInterface
647
     */
648 1
    public function setAddTemplate($template)
649
    {
650 1
        $this->addTemplate = $template;
651
652 1
        return $this;
653
    }
654
655
    /**
656
     * @return string
657
     */
658 1
    public function getViewTemplate()
659
    {
660 1
        return $this->viewTemplate;
661
    }
662
663
    /**
664
     * @param string $template
665
     *
666
     * @return AdminListConfiguratorInterface
667
     */
668 1
    public function setViewTemplate($template)
669
    {
670 1
        $this->viewTemplate = $template;
671
672 1
        return $this;
673
    }
674
675
    /**
676
     * @return string
677
     */
678 1
    public function getEditTemplate()
679
    {
680 1
        return $this->editTemplate;
681
    }
682
683
    /**
684
     * @param string $template
685
     *
686
     * @return AdminListConfiguratorInterface
687
     */
688 1
    public function setEditTemplate($template)
689
    {
690 1
        $this->editTemplate = $template;
691
692 1
        return $this;
693
    }
694
695
    /**
696
     * @return string
697
     */
698 1
    public function getDeleteTemplate()
699
    {
700 1
        return $this->deleteTemplate;
701
    }
702
703
    /**
704
     * @param string $template
705
     *
706
     * @return AdminListConfiguratorInterface
707
     */
708 1
    public function setDeleteTemplate($template)
709
    {
710 1
        $this->deleteTemplate = $template;
711
712 1
        return $this;
713
    }
714
715
    /**
716
     * You can override this method to do some custom things you need to do when adding an entity
717
     *
718
     * @param object $entity
719
     *
720
     * @return mixed
721
     */
722 1
    public function decorateNewEntity($entity)
723
    {
724 1
        return $entity;
725
    }
726
727
    /**
728
     * @return FilterBuilder
729
     */
730 10
    public function getFilterBuilder()
731
    {
732 10
        if (\is_null($this->filterBuilder)) {
733 9
            $this->filterBuilder = new FilterBuilder();
734
        }
735
736 10
        return $this->filterBuilder;
737
    }
738
739
    /**
740
     * @return AbstractAdminListConfigurator
741
     */
742 2
    public function setFilterBuilder(FilterBuilder $filterBuilder)
743
    {
744 2
        $this->filterBuilder = $filterBuilder;
745
746 2
        return $this;
747
    }
748
749
    /**
750
     * Bind current request.
751
     */
752 4
    public function bindRequest(Request $request)
753
    {
754 4
        $query = $request->query;
755 4
        $session = $request->getSession();
756
757 4
        $adminListName = 'listconfig_' . $request->get('_route');
758
759 4
        $this->page = $request->query->getInt('page', 1);
760
        // Allow alphanumeric, _ & . in order by parameter!
761 4
        $this->orderBy = preg_replace('/[^[a-zA-Z0-9\_\.]]/', '', $request->query->get('orderBy', ''));
762 4
        $this->orderDirection = $request->query->getAlpha('orderDirection');
763
764
        // there is a session and the filter param is not set
765 4 View Code Duplication
        if ($session->has($adminListName) && !$query->has('filter')) {
766 3
            $adminListSessionData = $request->getSession()->get($adminListName);
767 3
            if (!$query->has('page')) {
768 1
                $this->page = $adminListSessionData['page'];
769
            }
770
771 3
            if (!$query->has('orderBy')) {
772 3
                $this->orderBy = $adminListSessionData['orderBy'];
773
            }
774
775 3
            if (!$query->has('orderDirection')) {
776 3
                $this->orderDirection = $adminListSessionData['orderDirection'];
777
            }
778
        }
779
780
        // save current parameters
781 4
        $session->set(
782 4
            $adminListName,
783
            [
784 4
                'page' => $this->page,
785 4
                'orderBy' => $this->orderBy,
786 4
                'orderDirection' => $this->orderDirection,
787
            ]
788
        );
789
790 4
        $this->getFilterBuilder()->bindRequest($request);
791 4
    }
792
793
    /**
794
     * Return current page.
795
     *
796
     * @return int
797
     */
798 3
    public function getPage()
799
    {
800 3
        return $this->page;
801
    }
802
803
    /**
804
     * Return current sorting column.
805
     *
806
     * @return string
807
     */
808 1
    public function getOrderBy()
809
    {
810 1
        return $this->orderBy;
811
    }
812
813
    /**
814
     * Return current sorting direction.
815
     *
816
     * @return string
817
     */
818 1
    public function getOrderDirection()
819
    {
820 1
        return $this->orderDirection;
821
    }
822
823
    /**
824
     * @param string $suffix
825
     *
826
     * @return string
827
     */
828 9
    public function getPathByConvention($suffix = null)
829
    {
830 9
        $entityName = strtolower($this->getEntityName());
831 9
        $entityName = str_replace('\\', '_', $entityName);
832 9
        if (empty($suffix)) {
833 1
            return sprintf('%s_admin_%s', strtolower($this->getBundleName()), $entityName);
834
        }
835
836 8
        return sprintf('%s_admin_%s_%s', strtolower($this->getBundleName()), $entityName, $suffix);
837
    }
838
839
    /**
840
     * Get controller path.
841
     *
842
     * @return string
843
     */
844 1
    public function getControllerPath()
845
    {
846 1
        return sprintf('%s:%s', $this->getBundleName(), $this->getEntityName());
847
    }
848
849
    /**
850
     * Return extra parameters for use in list actions.
851
     *
852
     * @return array
853
     */
854 9
    public function getExtraParameters()
855
    {
856 9
        return [];
857
    }
858
}
859