Passed
Pull Request — master (#300)
by Arnaud
14:15 queued 08:05
created

LoadListener   A

Complexity

Total Complexity 11

Size/Duplication

Total Lines 87
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 38
c 0
b 0
f 0
dl 0
loc 87
rs 10
wmc 11

3 Methods

Rating   Name   Duplication   Size   Complexity  
B __invoke() 0 66 7
A __construct() 0 5 1
A extractIdentifier() 0 9 3
1
<?php
2
3
declare(strict_types=1);
4
5
namespace LAG\AdminBundle\Event\Listener\Data;
6
7
use LAG\AdminBundle\Admin\AdminAwareInterface;
8
use LAG\AdminBundle\Admin\AdminInterface;
9
use LAG\AdminBundle\DataProvider\DataSourceHandler\DataHandlerInterface;
10
use LAG\AdminBundle\DataProvider\Registry\DataProviderRegistryInterface;
11
use LAG\AdminBundle\Event\AdminEvents;
12
use LAG\AdminBundle\Event\Events\DataEvent;
13
use LAG\AdminBundle\Event\Events\DataFilterEvent;
14
use LAG\AdminBundle\Event\Events\DataOrderEvent;
15
use LAG\AdminBundle\Exception\Exception;
16
use Symfony\Component\HttpFoundation\Request;
17
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
18
19
/**
20
 * Load data from the database, according ot the configured strategy on the current action.
21
 */
22
class LoadListener
23
{
24
    public function __construct(
25
        private DataProviderRegistryInterface $registry,
26
        private DataHandlerInterface $dataHandler,
27
        private EventDispatcherInterface $eventDispatcher
28
    ) {
29
    }
30
31
    public function __invoke(DataEvent $event): void
32
    {
33
        $request = $event->getRequest();
34
        $admin = $event->getAdmin();
35
36
        // The load strategy is used to know how many entities should be load in the current action. It should be define
37
        // in the action instead of the admin as each action usually have a different load strategy
38
        $actionConfiguration = $admin->getAction()->getConfiguration();
39
        $strategy = $actionConfiguration->getLoadStrategy();
40
41
        // If another event already load data, do not load twice
42
        if ($event->getData() !== null) {
43
            return;
44
        }
45
        // The data provider is configured in the admin as it make no sense to have different data provider for each
46
        // action in the same admin. It should be a service tagged with a name
47
        $dataProviderName = $admin->getConfiguration()->getDataProvider();
48
        $dataProvider = $this->registry->get($dataProviderName);
49
50
        if ($dataProvider instanceof AdminAwareInterface) {
51
            $dataProvider->setAdmin($admin);
52
        }
53
54
        if ($strategy === AdminInterface::LOAD_STRATEGY_NONE) {
55
            $data = $dataProvider->create($admin->getEntityClass());
56
            $event->setData($data);
57
        }
58
59
        // Load only one entity from the database using its identifier (for the edit action for example)
60
        if ($strategy === AdminInterface::LOAD_STRATEGY_UNIQUE) {
61
            // Only single identifier are handled yet (no composite key)
62
            $identifier = $this->extractIdentifier($request, $actionConfiguration->getRouteParameters());
63
            $data = $dataProvider->get($admin->getEntityClass(), $identifier);
64
            $event->setData($data);
65
        }
66
67
        // Load several entities from the database (for the list action for example)
68
        if ($strategy === AdminInterface::LOAD_STRATEGY_MULTIPLE) {
69
            // Filters are provided in the FilterDataListener using the value from the configuration and the submitted
70
            // filters form. SO they should be taken from the event only
71
            $filters = $event->getFilters();
72
73
            // In the same way, if order is provided via an event (when clicking on a sortable column for instance) it
74
            // should override the default order configured in action
75
            $orderBy = $event->getOrderBy();
76
77
            if (\count($orderBy) === 0) {
78
                $orderBy = $actionConfiguration->getOrder();
79
            }
80
            $page = $request->get($actionConfiguration->getPageParameter(), 1);
81
82
            // Create a data source according to the data provider
83
            $data = $dataProvider->getCollection(
84
                $admin->getEntityClass(),
85
                $filters,
86
                $orderBy,
87
                $page,
88
                $actionConfiguration->getMaxPerPage()
89
            );
90
            // Dynamic filtering and ordering
91
            $this->eventDispatcher->dispatch(new DataFilterEvent($admin, $data, $filters), AdminEvents::ADMIN_FILTER);
92
            $this->eventDispatcher->dispatch(new DataOrderEvent($admin, $data, $orderBy), AdminEvents::ADMIN_ORDER);
93
94
            // Transform results into displayable data (a query builder into a pager for instance)
95
            $data = $this->dataHandler->handle($data);
96
            $event->setData($data);
97
        }
98
    }
99
100
    private function extractIdentifier(Request $request, array $routeRequirements): mixed
101
    {
102
        foreach ($routeRequirements as $name => $requirement) {
103
            if ($request->get($name) !== null) {
104
                return $request->get($name);
105
            }
106
        }
107
108
        throw new Exception('Unable to find a identifier in the request for the load strategy "unique"');
109
    }
110
}
111