Completed
Push — dev ( 3e1fc7...a387b8 )
by Arnaud
04:24 queued 49s
created

AdminFactory::createAction()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 35
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 22
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 35
ccs 22
cts 22
cp 1
rs 8.8571
c 0
b 0
f 0
cc 1
eloc 24
nc 1
nop 3
crap 1
1
<?php
2
3
namespace LAG\AdminBundle\Admin\Factory;
4
5
use Doctrine\ORM\EntityManager;
6
use LAG\AdminBundle\Action\ActionInterface;
7
use LAG\AdminBundle\Action\Factory\ActionFactory;
8
use LAG\AdminBundle\Admin\Admin;
9
use LAG\AdminBundle\Admin\AdminInterface;
10
use LAG\AdminBundle\Configuration\Factory\ConfigurationFactory;
11
use LAG\AdminBundle\DataProvider\DataProvider;
12
use LAG\AdminBundle\DataProvider\DataProviderInterface;
13
use LAG\AdminBundle\Admin\Event\AdminEvent;
14
use LAG\AdminBundle\Admin\Event\AdminEvents;
15
use Exception;
16
use LAG\AdminBundle\Message\MessageHandlerInterface;
17
use LAG\AdminBundle\Repository\RepositoryInterface;
18
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;
19
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
20
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
21
use Symfony\Component\HttpFoundation\Request;
22
23
/**
24
 * AdminFactory.
25
 *
26
 * Create admin from configuration
27
 */
28
class AdminFactory
29
{
30
    /**
31
     * @var array
32
     */
33
    protected $admins = [];
34
35
    /**
36
     * @var bool
37
     */
38
    protected $isInit = false;
39
40
    /**
41
     * @var EventDispatcherInterface
42
     */
43
    protected $eventDispatcher;
44
45
    /**
46
     * @var EntityManager
47
     */
48
    protected $entityManager;
49
50
    /**
51
     * @var ConfigurationFactory
52
     */
53
    protected $configurationFactory;
54
55
    /**
56
     * User custom data provider, indexed by service id
57
     *
58
     * @var ParameterBagInterface
59
     */
60
    protected $dataProviders;
61
62
    /**
63
     * @var array
64
     */
65
    protected $adminConfigurations;
66
67
    /**
68
     * @var ActionFactory
69
     */
70
    protected $actionFactory;
71
72
    /**
73
     * @var MessageHandlerInterface
74
     */
75
    protected $messageHandler;
76
77
    /**
78
     * AdminFactory constructor.
79
     *
80
     * @param EventDispatcherInterface $eventDispatcher
81
     * @param EntityManager $entityManager
82
     * @param ConfigurationFactory $configurationFactory
83
     * @param array $adminConfigurations
84
     * @param ActionFactory $actionFactory
85
     * @param MessageHandlerInterface $messageHandler
86
     */
87 9
    public function __construct(
88
        array $adminConfigurations,
89
        EventDispatcherInterface $eventDispatcher,
90
        EntityManager $entityManager,
91
        ConfigurationFactory $configurationFactory,
92
        ActionFactory $actionFactory,
93
        MessageHandlerInterface $messageHandler
94
    ) {
95 9
        $this->eventDispatcher = $eventDispatcher;
96 9
        $this->entityManager = $entityManager;
97 9
        $this->configurationFactory = $configurationFactory;
98 9
        $this->adminConfigurations = $adminConfigurations;
99 9
        $this->actionFactory = $actionFactory;
100 9
        $this->messageHandler = $messageHandler;
101 9
        $this->dataProviders = new ParameterBag();
102 9
    }
103
104
    /**
105
     * Create admins from configuration and load them into the pool. Dispatch ADMIN_CREATE event.
106
     */
107 5
    public function init()
108
    {
109
        // init only once
110 5
        if ($this->isInit) {
111 1
            return;
112
        }
113
        // dispatch an event to allow configuration modification before resolving and creating admins
114 5
        $event = $this->dispatchEvent(
115
            AdminEvents::BEFORE_CONFIGURATION
116 5
        );
117
118
        // get back the modified configuration
119 5
        $this->adminConfigurations = $event->getAdminsConfiguration();
120
121
        // create Admins according to the given configuration
122 5
        foreach ($this->adminConfigurations as $name => $configuration) {
123
124
            // dispatch an event to allow modification on a specific admin
125 4
            $event = $this->dispatchEvent(
126 4
                AdminEvents::ADMIN_CREATE,
127 4
                $name,
128
                $configuration
129 4
            );
130
131
            // create Admin object, with the configuration modified by the events
132 4
            $this->admins[$name] = $this->create($name, $event->getAdminConfiguration());
133
134
            // dispatch post-create event
135 4
            $this
136
                ->eventDispatcher
137 4
                ->dispatch(AdminEvents::ADMIN_CREATED, $event);
138 5
        }
139 5
        $this->isInit = true;
140 5
    }
141
142
    /**
143
     * Create an Admin from configuration values. It will be added to AdminFactory admin's list.
144
     *
145
     * @param string $name
146
     * @param array $configuration
147
     * @return Admin
148
     * @throws Exception
149
     */
150 5
    public function create($name, array $configuration)
151
    {
152
        // create AdminConfiguration object
153 5
        $adminConfiguration = $this
154
            ->configurationFactory
155 5
            ->createAdminConfiguration($configuration);
156
157
        // retrieve a data provider
158 5
        $dataProvider = $this->getDataProvider(
159 5
            $adminConfiguration->getParameter('entity'),
160 5
            $adminConfiguration->getParameter('data_provider')
161 5
        );
162
163
        // create Admin object
164 5
        $admin = new Admin(
165 5
            $name,
166 5
            $dataProvider,
167 5
            $adminConfiguration,
168 5
            $this->messageHandler,
169 5
            $this->eventDispatcher
170 5
        );
171
172
        // adding actions
173 5
        foreach ($adminConfiguration->getParameter('actions') as $actionName => $actionConfiguration) {
174
            // create action and add it to the admin instance
175 5
            $this->createAction($admin, $actionName, $actionConfiguration);
176 5
        }
177
178 5
        return $admin;
179
    }
180
181
    /**
182
     * Return an admin from a Symfony request.
183
     *
184
     * @param Request $request
185
     * @return AdminInterface
186
     * @throws Exception
187
     */
188 1
    public function getAdminFromRequest(Request $request)
189
    {
190 1
        $routeParameters = $request->get('_route_params');
191
192 1
        if (!$routeParameters) {
193
            throw new Exception('Cannot find admin from request. _route_params parameters for request not found');
194
        }
195 1
        if (!array_key_exists('_admin', $routeParameters)) {
196
            throw new Exception('Cannot find admin from request. "_admin" route parameter is missing');
197
        }
198 1
        if (!array_key_exists('_action', $routeParameters)) {
199
            throw new Exception('Cannot find admin action from request. "_action" route parameter is missing');
200
        }
201 1
        $admin = $this->getAdmin($routeParameters['_admin']);
202
203 1
        return $admin;
204
    }
205
206
    /**
207
     * Return a admin by its name.
208
     *
209
     * @param $name
210
     * @return Admin
211
     * @throws Exception
212
     */
213 5
    public function getAdmin($name)
214
    {
215 5
        if (!array_key_exists($name, $this->admins)) {
216 3
            throw new Exception(sprintf('Admin with name "%s" not found. Check your admin configuration', $name));
217
        }
218
219 3
        return $this->admins[$name];
220
    }
221
222
    /**
223
     * Return all admins.
224
     *
225
     * @return AdminInterface[]
226
     */
227 2
    public function getAdmins()
228
    {
229 2
        return $this->admins;
230
    }
231
232
    /**
233
     * Add user custom repositories (called in the repository compiler pass), to avoid injecting the service container
234
     *
235
     * @param string $name
236
     * @param DataProviderInterface $dataProvider
237
     */
238 1
    public function addDataProvider($name, DataProviderInterface $dataProvider)
239
    {
240 1
        $this
241
            ->dataProviders
242 1
            ->set($name, $dataProvider);
243 1
    }
244
245
    /**
246
     * Return a configured data provider or create an new instance of the default one.
247
     *
248
     * @param string $entityClass
249
     * @param string|null $name
250
     * @return DataProvider|mixed
251
     * @throws Exception
252
     */
253 5
    protected function getDataProvider($entityClass, $name = null)
254
    {
255
        // create or get repository according to the configuration
256 5
        if ($name) {
257
            // removing arobase if exists
258
            if (substr($name, 0, 1) == '@') {
259
                $name = substr($name, 1);
260
            }
261
262
            // custom data provider class must be loaded by the compiler pass
263
            if (!$this->dataProviders->has($name)) {
264
                throw new Exception(sprintf(
265
                    'Data provider %s not found. Did you add the @data_provider tag in your service ?',
266
                    $name
267
                ));
268
            }
269
            $dataProvider = $this
270
                ->dataProviders
271
                ->get($name);
272
        } else {
273
            // no data provider is configured, we create a new one
274 5
            $repository = $this
275
                ->entityManager
276 5
                ->getRepository($entityClass);
277
278 5
            if (!($repository instanceof RepositoryInterface)) {
279
                $repositoryClass = get_class($repository);
280
                throw new Exception("Repository {$repositoryClass} should implements ".RepositoryInterface::class);
281
            }
282
283 5
            $dataProvider = new DataProvider($repository);
284
        }
285 5
        return $dataProvider;
286
    }
287
288
    /**
289
     * Create an Action from the configuration, and add it to the Admin.
290
     *
291
     * @param AdminInterface $admin
292
     * @param $actionName
293
     * @param array $actionConfiguration
294
     */
295 5
    protected function createAction(AdminInterface $admin, $actionName, array $actionConfiguration)
296
    {
297
        // dispatching action create event for dynamic action creation
298 5
        $event = $this->dispatchEvent(
299 5
            AdminEvents::ACTION_CREATE,
300 5
            $admin->getName(),
301
            $admin
302 5
                ->getConfiguration()
303 5
                ->getParameters(),
304 5
            $admin,
305 5
            $actionName,
306
            $actionConfiguration
307 5
        );
308
309
        // creating action from configuration
310 5
        $action = $this
311
            ->actionFactory
312 5
            ->create($actionName, $event->getActionConfiguration(), $admin);
313
314
        // adding action to admin
315 5
        $admin->addAction($action);
316
317
        // dispatch post-create event
318 5
        $this->dispatchEvent(
319 5
            AdminEvents::ACTION_CREATED,
320 5
            $admin->getName(),
321
            $admin
322 5
                ->getConfiguration()
323 5
                ->getParameters(),
324 5
            $admin,
325 5
            $actionName,
326 5
            $actionConfiguration,
327
            $action
328 5
        );
329 5
    }
330
331 6
    protected function dispatchEvent(
332
        $eventName,
333
        $adminName = '',
334
        array $adminConfiguration = [],
335
        AdminInterface $admin = null,
336
        $actionName = '',
337
        array $actionConfiguration = [],
338
        ActionInterface $action = null
339
    ) {
340
        // create the event instance and set parameters according to the context
341 6
        $event = new AdminEvent();
342 6
        $event->setAdminsConfiguration($this->adminConfigurations);
343 6
        $event->setAdminConfiguration($adminConfiguration);
344 6
        $event->setActionConfiguration($actionConfiguration);
345 6
        $event->setActionName($actionName);
346 6
        $event->setAdminName($adminName);
347
348 6
        if (null !== $admin) {
349 5
            $event->setAdmin($admin);
350 5
        }
351 6
        if (null !== $action) {
352 5
            $event->setAction($action);
353 5
        }
354
355
        // dispatch the created event
356 6
        $this
357
            ->eventDispatcher
358 6
            ->dispatch($eventName, $event);
359
360 6
        return $event;
361
    }
362
}
363