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