Completed
Branch dev (a083dd)
by Arnaud
03:08
created

AdminFactory::create()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 41
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 21
CRAP Score 2

Importance

Changes 14
Bugs 3 Features 2
Metric Value
c 14
b 3
f 2
dl 0
loc 41
ccs 21
cts 21
cp 1
rs 8.8571
cc 2
eloc 25
nc 2
nop 2
crap 2
1
<?php
2
3
namespace LAG\AdminBundle\Admin\Factory;
4
5
use Doctrine\ORM\EntityManager;
6
use LAG\AdminBundle\Admin\Admin;
7
use LAG\AdminBundle\Admin\AdminInterface;
8
use LAG\AdminBundle\Admin\Configuration\AdminConfiguration;
9
use LAG\AdminBundle\Admin\Configuration\ApplicationConfiguration;
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
use Symfony\Component\OptionsResolver\OptionsResolver;
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 ApplicationConfiguration
52
     */
53
    protected $application;
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 $adminConfiguration;
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 ApplicationConfiguration $application
83
     * @param array $adminConfiguration
84
     * @param ActionFactory $actionFactory
85
     * @param MessageHandlerInterface $messageHandler
86
     */
87 6
    public function __construct(
88
        EventDispatcherInterface $eventDispatcher,
89
        EntityManager $entityManager,
90
        ApplicationConfiguration $application,
91
        array $adminConfiguration,
92
        ActionFactory $actionFactory,
93
        MessageHandlerInterface $messageHandler
94
    ) {
95 6
        $this->eventDispatcher = $eventDispatcher;
96 6
        $this->entityManager = $entityManager;
97 6
        $this->application = $application;
98 6
        $this->adminConfiguration = $adminConfiguration;
99 6
        $this->actionFactory = $actionFactory;
100 6
        $this->messageHandler = $messageHandler;
101 6
        $this->dataProviders = new ParameterBag();
102 6
    }
103
104
    /**
105
     * Create admins from configuration and load them into the pool. Dispatch ADMIN_CREATE event.
106
     */
107 4
    public function init()
108
    {
109 4
        if ($this->isInit) {
110
            return;
111
        }
112 4
        $event = new AdminFactoryEvent();
113 4
        $event->setAdminsConfiguration($this->adminConfiguration);
114 4
        $this->eventDispatcher->dispatch(AdminFactoryEvent::ADMIN_CREATION, $event);
115 4
        $this->adminConfiguration = $event->getAdminsConfiguration();
116
117 4
        foreach ($this->adminConfiguration as $name => $configuration) {
118 4
            $event = new AdminEvent();
119 4
            $event->setConfiguration($configuration);
120 4
            $this->eventDispatcher->dispatch(AdminEvent::ADMIN_CREATE, $event);
121 4
            $this->admins[$name] = $this->create($name, $event->getConfiguration());
122
        }
123 4
        $this->isInit = true;
124 4
    }
125
126
    /**
127
     * Create an Admin from configuration values. It will be added to AdminFactory admin's list.
128
     *
129
     * @param string $name
130
     * @param array $configuration
131
     * @return Admin
132
     * @throws Exception
133
     */
134 5
    public function create($name, array $configuration)
135
    {
136
        // resolve admin configuration
137 5
        $configuration = $this->resolveConfiguration($configuration);
138
        // retrieve metadata from entity manager
139 5
        $configuration['metadata'] = $this
140 5
            ->entityManager
141 5
            ->getClassMetadata($configuration['entity']);
142
        // create AdminConfiguration object
143 5
        $adminConfiguration = new AdminConfiguration($configuration);
144
145
        // retrieve a data provider
146 5
        $dataProvider = $this->getDataProvider(
147 5
            $adminConfiguration->getEntityName(),
148 5
            $adminConfiguration->getDataProvider()
149
        );
150
151
        // create Admin object
152 5
        $admin = new Admin(
153
            $name,
154
            $dataProvider,
155
            $adminConfiguration,
156 5
            $this->messageHandler
157
        );
158
        // adding actions
159 5
        foreach ($adminConfiguration->getActions() as $actionName => $actionConfiguration) {
160
            // dispatching action create event for dynamic action creation
161 5
            $event = new AdminEvent();
162 5
            $event->setConfiguration($actionConfiguration);
163 5
            $event->setAdmin($admin);
164 5
            $event->setActionName($actionName);
165 5
            $this->eventDispatcher->dispatch(AdminEvent::ACTION_CREATE, $event);
166
            // creating action from configuration
167
            $action = $this
168 5
                ->actionFactory
169 5
                ->create($actionName, $event->getConfiguration(), $admin);
170
            // adding action to admin
171 5
            $admin->addAction($action);
172
        }
173 5
        return $admin;
174
    }
175
176
    /**
177
     * Return an admin from a Symfony request.
178
     *
179
     * @param Request $request
180
     * @return AdminInterface
181
     * @throws Exception
182
     */
183 1
    public function getAdminFromRequest(Request $request)
184
    {
185 1
        $routeParameters = $request->get('_route_params');
186
187 1
        if (!$routeParameters) {
188
            throw new Exception('Cannot find admin _route_params parameters for request');
189
        }
190 1
        if (!array_key_exists('_admin', $routeParameters)) {
191
            throw new Exception('Cannot find admin from request. "_admin" route parameter is missing');
192
        }
193 1
        if (!array_key_exists('_action', $routeParameters)) {
194
            throw new Exception('Cannot find admin action from request. "_action" route parameter is missing');
195
        }
196 1
        $admin = $this->getAdmin($routeParameters['_admin']);
197
198 1
        return $admin;
199
    }
200
201
    /**
202
     * Return a admin by its name.
203
     *
204
     * @param $name
205
     * @return Admin
206
     * @throws Exception
207
     */
208 5
    public function getAdmin($name)
209
    {
210 5
        if (!array_key_exists($name, $this->admins)) {
211 3
            throw new Exception(sprintf('Admin with name "%s" not found. Check your admin configuration', $name));
212
        }
213
214 3
        return $this->admins[$name];
215
    }
216
217
    /**
218
     * Return all admins.
219
     *
220
     * @return Admin[]
221
     */
222 1
    public function getAdmins()
223
    {
224 1
        return $this->admins;
225
    }
226
227
    /**
228
     * Add user custom repositories (called in the repository compiler pass), to avoid injecting the service container
229
     *
230
     * @param string $name
231
     * @param DataProviderInterface $dataProvider
232
     */
233 1
    public function addDataProvider($name, DataProviderInterface $dataProvider)
234
    {
235
        $this
236 1
            ->dataProviders
237 1
            ->set($name, $dataProvider);
238 1
    }
239
240
    /**
241
     * Return a configured data provider or create an new instance of the default one.
242
     *
243
     * @param string $entityClass
244
     * @param string|null $name
245
     * @return DataProvider|mixed
246
     * @throws Exception
247
     */
248 5
    protected function getDataProvider($entityClass, $name = null)
249
    {
250
        // create or get repository according to the configuration
251 5
        if ($name) {
252
            // custom data provider class must be loaded by the compiler pass
253
            if (!$this->dataProviders->has($name)) {
254
                throw new Exception(sprintf(
255
                    'Data provider %s not found. Did you add the @data_provider tag in your service',
256
                    $name
257
                ));
258
            }
259
            $dataProvider = $this
260
                ->dataProviders
261
                ->get($name);
262
        } else {
263
            // no data provider is configured, we create a new one
264
            $repository = $this
265 5
                ->entityManager
266 5
                ->getRepository($entityClass);
267
268 5
            if (!($repository instanceof RepositoryInterface)) {
269
                $repositoryClass = get_class($repository);
270
                throw new Exception("Repository {$repositoryClass} should implements " . RepositoryInterface::class);
271
            }
272
273 5
            $dataProvider = new DataProvider($repository);
274
        }
275 5
        return $dataProvider;
276
    }
277
278
    /**
279
     * Resolve admin configuration.
280
     *
281
     * @param array $configuration
282
     * @return array
283
     */
284 5
    protected function resolveConfiguration(array $configuration)
285
    {
286 5
        $resolver = new OptionsResolver();
287
        // optional options
288 5
        $resolver->setDefaults([
289
            'actions' => [
290
                'list' => [],
291
                'create' => [],
292
                'edit' => [],
293
                'delete' => [],
294 5
            ],
295
            'batch' => true,
296 5
            'manager' => 'LAG\AdminBundle\Manager\GenericManager',
297 5
            'routing_url_pattern' => $this->application->getRoutingUrlPattern(),
298 5
            'routing_name_pattern' => $this->application->getRoutingNamePattern(),
299 5
            'controller' => 'LAGAdminBundle:CRUD',
300 5
            'max_per_page' => $this->application->getMaxPerPage(),
301
            'data_provider' => null
302
        ]);
303
        // required options
304 5
        $resolver->setRequired([
305 5
            'entity',
306
            'form',
307
        ]);
308
309 5
        return $resolver->resolve($configuration);
310
    }
311
}
312