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

PagePartBundle/PagePartAdmin/PagePartAdmin.php (1 issue)

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\PagePartBundle\PagePartAdmin;
4
5
use Doctrine\ORM\EntityManager;
6
use Doctrine\ORM\EntityManagerInterface;
7
use Kunstmaan\AdminBundle\Entity\EntityInterface;
8
use Kunstmaan\PagePartBundle\Entity\PagePartRef;
9
use Kunstmaan\PagePartBundle\Event\Events;
10
use Kunstmaan\PagePartBundle\Event\PagePartEvent;
11
use Kunstmaan\PagePartBundle\Helper\HasPagePartsInterface;
12
use Kunstmaan\PagePartBundle\Helper\PagePartInterface;
13
use Kunstmaan\PagePartBundle\Repository\PagePartRefRepository;
14
use Kunstmaan\UtilitiesBundle\Helper\ClassLookup;
15
use Symfony\Component\DependencyInjection\ContainerInterface;
16
use Symfony\Component\Form\FormBuilderInterface;
17
use Symfony\Component\HttpFoundation\Request;
18
19
/**
20
 * PagePartAdmin
21
 */
22
class PagePartAdmin
23
{
24
    /**
25
     * @var PagePartAdminConfiguratorInterface
26
     */
27
    protected $configurator;
28
29
    /**
30
     * @var EntityManager|EntityManagerInterface
31
     */
32
    protected $em;
33
34
    /**
35
     * @var HasPagePartsInterface
36
     */
37
    protected $page;
38
39
    /**
40
     * @var string
41
     */
42
    protected $context;
43
44
    /**
45
     * @var ContainerInterface
46
     */
47
    protected $container;
48
49
    /**
50
     * @var PagePartInterface[]
51
     */
52
    protected $pageParts = [];
53
54
    /**
55
     * @var PagePartRef[]
56
     */
57
    protected $pagePartRefs = [];
58
59
    /**
60
     * @var PagePartInterface[]
61
     */
62
    protected $newPageParts = [];
63
64
    /**
65
     * @param PagePartAdminConfiguratorInterface $configurator The configurator
66
     * @param EntityManagerInterface             $em           The entity manager
67
     * @param HasPagePartsInterface              $page         The page
68
     * @param string|null                        $context      The context
69
     * @param ContainerInterface|null            $container    The container
70
     *
71
     * @throws \InvalidArgumentException
72
     */
73
    public function __construct(PagePartAdminConfiguratorInterface $configurator, EntityManagerInterface $em, HasPagePartsInterface $page, $context = null, ContainerInterface $container = null)
74
    {
75
        if (!($page instanceof EntityInterface)) {
76
            throw new \InvalidArgumentException('Page must be an instance of EntityInterface.');
77
        }
78
79
        $this->configurator = $configurator;
80
        $this->em = $em;
81
        $this->page = $page;
82
        $this->container = $container;
83
84
        if ($context) {
85
            $this->context = $context;
86
        } elseif ($this->configurator->getContext()) {
87
            $this->context = $this->configurator->getContext();
88
        } else {
89
            $this->context = 'main';
90
        }
91
92
        $this->initializePageParts();
93
    }
94
95
    /**
96
     * Get all pageparts from the database, and store them.
97
     */
98
    private function initializePageParts()
99
    {
100
        // Get all the pagepartrefs
101
        /** @var PagePartRefRepository $ppRefRepo */
102
        $ppRefRepo = $this->em->getRepository(PagePartRef::class);
103
        $ppRefs = $ppRefRepo->getPagePartRefs($this->page, $this->context);
104
105
        // Group pagepartrefs per type
106
        $types = [];
107
        foreach ($ppRefs as $pagePartRef) {
108
            $types[$pagePartRef->getPagePartEntityname()][] = $pagePartRef->getPagePartId();
109
            $this->pagePartRefs[$pagePartRef->getId()] = $pagePartRef;
110
        }
111
112
        // Fetch all the pageparts (only one query per pagepart type)
113
        /** @var EntityInterface[] $pageParts */
114
        $pageParts = [];
115 View Code Duplication
        foreach ($types as $classname => $ids) {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
116
            $result = $this->em->getRepository($classname)->findBy(['id' => $ids]);
117
            $pageParts = array_merge($pageParts, $result);
118
        }
119
120
        // Link the pagepartref to the pagepart
121
        foreach ($this->pagePartRefs as $pagePartRef) {
122
            foreach ($pageParts as $key => $pagePart) {
123
                if (ClassLookup::getClass($pagePart) == $pagePartRef->getPagePartEntityname()
124
                    && $pagePart->getId() == $pagePartRef->getPagePartId()
125
                ) {
126
                    $this->pageParts[$pagePartRef->getId()] = $pagePart;
127
                    unset($pageParts[$key]);
128
129
                    break;
130
                }
131
            }
132
        }
133
    }
134
135
    /**
136
     * @return EntityInterface
137
     */
138
    public function getPage()
139
    {
140
        return $this->page;
141
    }
142
143
    public function preBindRequest(Request $request)
144
    {
145
        // Fetch all sub-entities that should be removed
146
        $subPagePartsToDelete = [];
147
        foreach (array_keys($request->request->all()) as $key) {
148
            // Example value: delete_pagepartadmin_74_tags_3
149
            if (preg_match('/^delete_pagepartadmin_(\\d+)_(\\w+)_(\\d+)$/i', $key, $matches)) {
150
                $subPagePartsToDelete[$matches[1]][] = ['name' => $matches[2], 'id' => $matches[3]];
151
            }
152
        }
153
154
        $doFlush = false;
155
        foreach ($this->pagePartRefs as $pagePartRef) {
156
            // Remove pageparts
157
            if ('true' == $request->get($pagePartRef->getId() . '_deleted')) {
158
                $pagePart = $this->pageParts[$pagePartRef->getId()];
159
                $this->em->remove($pagePart);
160
                $this->em->remove($pagePartRef);
161
162
                unset($this->pageParts[$pagePartRef->getId()], $this->pagePartRefs[$pagePartRef->getId()]);
163
                $doFlush = true;
164
            }
165
166
            // Remove sub-entities from pageparts
167
            if (\array_key_exists($pagePartRef->getId(), $subPagePartsToDelete)) {
168
                $pagePart = $this->pageParts[$pagePartRef->getId()];
169
                foreach ($subPagePartsToDelete[$pagePartRef->getId()] as $deleteInfo) {
170
                    /** @var EntityInterface[] $objects */
171
                    $objects = \call_user_func([$pagePart, 'get' . ucfirst($deleteInfo['name'])]);
172
173
                    foreach ($objects as $object) {
174
                        if ($object->getId() == $deleteInfo['id']) {
175
                            $this->em->remove($object);
176
                            $doFlush = true;
177
                        }
178
                    }
179
                }
180
            }
181
        }
182
183
        if ($doFlush) {
184
            $this->em->flush();
185
        }
186
187
        // Create the objects for the new pageparts
188
        $this->newPageParts = [];
189
        $newRefIds = $request->get($this->context . '_new');
190
191
        if (\is_array($newRefIds)) {
192
            foreach ($newRefIds as $newId) {
193
                $type = $request->get($this->context . '_type_' . $newId);
194
                $this->newPageParts[$newId] = new $type();
195
            }
196
        }
197
198
        // Sort pageparts again
199
        $sequences = $request->get($this->context . '_sequence');
200
        if (!\is_null($sequences)) {
201
            $tempPageparts = $this->pageParts;
202
            $this->pageParts = [];
203
            foreach ($sequences as $sequence) {
204
                if (\array_key_exists($sequence, $this->newPageParts)) {
205
                    $this->pageParts[$sequence] = $this->newPageParts[$sequence];
206
                } elseif (\array_key_exists($sequence, $tempPageparts)) {
207
                    $this->pageParts[$sequence] = $tempPageparts[$sequence];
208
                } else {
209
                    $this->pageParts[$sequence] = $this->getPagePart($sequence, array_search($sequence, $sequences) + 1);
210
                }
211
            }
212
213
            unset($tempPageparts);
214
        }
215
    }
216
217
    public function bindRequest(Request $request)
218
    {
219
    }
220
221
    public function adaptForm(FormBuilderInterface $formbuilder)
222
    {
223
        $data = $formbuilder->getData();
224
225
        foreach ($this->pageParts as $pagePartRefId => $pagePart) {
226
            $data['pagepartadmin_' . $pagePartRefId] = $pagePart;
227
            $formbuilder->add('pagepartadmin_' . $pagePartRefId, $pagePart->getDefaultAdminType());
228
        }
229
230
        foreach ($this->newPageParts as $newPagePartRefId => $newPagePart) {
231
            $data['pagepartadmin_' . $newPagePartRefId] = $newPagePart;
232
            $formbuilder->add('pagepartadmin_' . $newPagePartRefId, $newPagePart->getDefaultAdminType());
233
        }
234
235
        $formbuilder->setData($data);
236
    }
237
238
    public function persist(Request $request)
239
    {
240
        /** @var PagePartRefRepository $ppRefRepo */
241
        $ppRefRepo = $this->em->getRepository(PagePartRef::class);
242
243
        // Add new pageparts on the correct position + Re-order and save pageparts if needed
244
        $sequences = $request->get($this->context . '_sequence', []);
245
        $sequencescount = \count($sequences);
246
        for ($i = 0; $i < $sequencescount; ++$i) {
247
            $pagePartRefId = $sequences[$i];
248
249
            if (\array_key_exists($pagePartRefId, $this->newPageParts)) {
250
                $pagePart = $this->newPageParts[$pagePartRefId];
251
                $this->em->persist($pagePart);
252
                $this->em->flush($pagePart);
253
254
                $ppRefRepo->addPagePart($this->page, $pagePart, $i + 1, $this->context, false);
255
            } elseif (\array_key_exists($pagePartRefId, $this->pagePartRefs)) {
256
                $pagePartRef = $this->pagePartRefs[$pagePartRefId];
257
                if ($pagePartRef instanceof PagePartRef && $pagePartRef->getSequencenumber() != ($i + 1)) {
258
                    $pagePartRef->setSequencenumber($i + 1);
259
                    $pagePartRef->setContext($this->context);
260
                    $this->em->persist($pagePartRef);
261
                }
262
                $pagePart = $pagePartRef->getPagePart($this->em);
263
            }
264
265
            if (isset($pagePart)) {
266
                $this->container->get('event_dispatcher')->dispatch(
267
                    Events::POST_PERSIST,
268
                    new PagePartEvent($pagePart)
269
                );
270
            }
271
        }
272
    }
273
274
    /**
275
     * @return string|null
276
     */
277
    public function getContext()
278
    {
279
        return $this->context;
280
    }
281
282
    /**
283
     * This getter returns an array holding info on page part types that can be added to the page.
284
     * The types are filtererd here, based on the amount of page parts of a certain type that can be added to the page.
285
     *
286
     * @return array
287
     */
288
    public function getPossiblePagePartTypes()
289
    {
290
        $possiblePPTypes = $this->configurator->getPossiblePagePartTypes();
291
        $result = [];
292
293
        // filter page part types that can only be added x times to the page context.
294
        // to achieve this, provide a 'pagelimit' parameter when adding the pp type in your PagePartAdminConfiguration
295
        if (!empty($possiblePPTypes)) {
296
            foreach ($possiblePPTypes as $possibleTypeData) {
297
                if (\array_key_exists('pagelimit', $possibleTypeData)) {
298
                    $pageLimit = $possibleTypeData['pagelimit'];
299
                    /** @var PagePartRefRepository $entityRepository */
300
                    $entityRepository = $this->em->getRepository(PagePartRef::class);
301
                    $formPPCount = $entityRepository->countPagePartsOfType(
302
                        $this->page,
303
                        $possibleTypeData['class'],
304
                        $this->configurator->getContext()
305
                    );
306
                    if ($formPPCount < $pageLimit) {
307
                        $result[] = $possibleTypeData;
308
                    }
309
                } else {
310
                    $result[] = $possibleTypeData;
311
                }
312
            }
313
        }
314
315
        return $result;
316
    }
317
318
    /**
319
     * @return string
320
     */
321
    public function getName()
322
    {
323
        return $this->configurator->getName();
324
    }
325
326
    /**
327
     * @return array
328
     */
329
    public function getPagePartMap()
330
    {
331
        return $this->pageParts;
332
    }
333
334
    /**
335
     * @return string
336
     */
337
    public function getType(PagePartInterface $pagepart)
338
    {
339
        $possiblePagePartTypes = $this->configurator->getPossiblePagePartTypes();
340
        foreach ($possiblePagePartTypes as &$pageparttype) {
341
            if ($pageparttype['class'] == ClassLookup::getClass($pagepart)) {
342
                return $pageparttype['name'];
343
            }
344
        }
345
346
        return 'no name';
347
    }
348
349
    /**
350
     * @param int $id
351
     * @param int $sequenceNumber
352
     *
353
     * @return PagePartInterface
354
     */
355
    public function getPagePart($id, $sequenceNumber)
356
    {
357
        /** @var PagePartRefRepository $ppRefRepo */
358
        $ppRefRepo = $this->em->getRepository(PagePartRef::class);
359
360
        return $ppRefRepo->getPagePart($id, $this->context, $sequenceNumber);
361
    }
362
363
    /**
364
     * @param object $pagepart
365
     *
366
     * @return string
367
     */
368
    public function getClassName($pagepart)
369
    {
370
        return \get_class($pagepart);
371
    }
372
}
373