Completed
Pull Request — dev (#9)
by Arnaud
12:24
created

AdminFactory::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 16
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 1

Importance

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