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) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $context of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
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) {
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