Completed
Push — master ( 9b5821...aba493 )
by Ruud
307:53 queued 297:17
created

Kunstmaan/NodeBundle/Repository/NodeRepository.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\NodeBundle\Repository;
4
5
use Gedmo\Tree\Entity\Repository\NestedTreeRepository;
6
use Kunstmaan\AdminBundle\Entity\BaseUser;
7
use Kunstmaan\AdminBundle\Helper\Security\Acl\AclHelper;
8
use Kunstmaan\AdminBundle\Helper\Security\Acl\AclNativeHelper;
9
use Kunstmaan\AdminBundle\Helper\Security\Acl\Permission\PermissionDefinition;
10
use Kunstmaan\NodeBundle\Entity\HasNodeInterface;
11
use Kunstmaan\NodeBundle\Entity\Node;
12
use Kunstmaan\NodeBundle\Entity\NodeTranslation;
13
use Kunstmaan\NodeBundle\Entity\NodeVersion;
14
use Kunstmaan\NodeBundle\Helper\HiddenFromNavInterface;
15
use Kunstmaan\UtilitiesBundle\Helper\ClassLookup;
16
17
/**
18
 * NodeRepository
19
 */
20
class NodeRepository extends NestedTreeRepository
21
{
22
    /**
23
     * @param string    $lang                 The locale
24
     * @param string    $permission           The permission (read, write, ...)
25
     * @param AclHelper $aclHelper            The acl helper
26
     * @param bool      $includeHiddenFromNav include the hiddenfromnav nodes
27
     *                                        or not
28
     *
29
     * @return Node[]
30
     */
31
    public function getTopNodes(
32
        $lang,
33
        $permission,
34
        AclHelper $aclHelper,
35
        $includeHiddenFromNav = false
36
    ) {
37
        $result = $this->getChildNodes(
38
            null,
39
            $lang,
40
            $permission,
41
            $aclHelper,
42
            $includeHiddenFromNav
43
        );
44
45
        return $result;
46
    }
47
48
    /**
49
     * @param int|null  $parentId             The parent node id
50
     * @param string    $lang                 The locale
51
     * @param string    $permission           The permission (read, write, ...)
52
     * @param AclHelper $aclHelper            The acl helper
53
     * @param bool      $includeHiddenFromNav Include nodes hidden from
54
     *                                        navigation or not
55
     * @param Node      $rootNode             Root node of the current tree
56
     *
57
     * @return Node[]
58
     */
59
    public function getChildNodes(
60
        $parentId,
61
        $lang,
62
        $permission,
63
        AclHelper $aclHelper,
64
        $includeHiddenFromNav = false,
65
        $includeHiddenWithInternalName = false,
66
        $rootNode = null
67
    ) {
68
        $qb = $this->createQueryBuilder('b')
69
            ->select('b', 't', 'v')
70
            ->leftJoin('b.nodeTranslations', 't', 'WITH', 't.lang = :lang')
71
            ->leftJoin(
72
                't.publicNodeVersion',
73
                'v',
74
                'WITH',
75
                't.publicNodeVersion = v.id'
76
            )
77
            ->where('b.deleted = 0')
78
            ->setParameter('lang', $lang)
79
            ->addOrderBy('t.weight', 'ASC')
80
            ->addOrderBy('t.title', 'ASC');
81
82
        if (!$includeHiddenFromNav) {
83
            if ($includeHiddenWithInternalName) {
84
                $qb->andWhere(
85
                    '(b.hiddenFromNav != true OR b.internalName IS NOT NULL)'
86
                );
87
            } else {
88
                $qb->andWhere('b.hiddenFromNav != true');
89
            }
90
        }
91
92 View Code Duplication
        if (\is_null($parentId)) {
93
            $qb->andWhere('b.parent is NULL');
94
        } elseif ($parentId !== false) {
95
            $qb->andWhere('b.parent = :parent')
96
                ->setParameter('parent', $parentId);
97
        }
98
        if ($rootNode) {
99
            $qb->andWhere('b.lft >= :left')
100
                ->andWhere('b.rgt <= :right')
101
                ->setParameter('left', $rootNode->getLeft())
102
                ->setParameter('right', $rootNode->getRight());
103
        }
104
105
        $query = $aclHelper->apply(
106
            $qb,
107
            new PermissionDefinition(array($permission))
108
        );
109
110
        return $query->getResult();
111
    }
112
113
    /**
114
     * @param HasNodeInterface $hasNode
115
     *
116
     * @return Node|null
117
     */
118
    public function getNodeFor(HasNodeInterface $hasNode)
119
    {
120
        /* @var NodeVersion $nodeVersion */
121
        $nodeVersion = $this->getEntityManager()->getRepository(
122
            'KunstmaanNodeBundle:NodeVersion'
123
        )->getNodeVersionFor(
124
            $hasNode
125
        );
126
        if (!\is_null($nodeVersion)) {
127
            /* @var NodeTranslation $nodeTranslation */
128
            $nodeTranslation = $nodeVersion->getNodeTranslation();
129
            if (!\is_null($nodeTranslation)) {
130
                return $nodeTranslation->getNode();
131
            }
132
        }
133
134
        return null;
135
    }
136
137
    /**
138
     * @param int    $id         The id
139
     * @param string $entityName The class name
140
     *
141
     * @return Node|null
142
     */
143
    public function getNodeForIdAndEntityname($id, $entityName)
144
    {
145
        /* @var NodeVersion $nodeVersion */
146
        $nodeVersion = $this->getEntityManager()->getRepository(
147
            'KunstmaanNodeBundle:NodeVersion'
148
        )->findOneBy(
149
            array('refId' => $id, 'refEntityName' => $entityName)
150
        );
151
        if ($nodeVersion) {
152
            return $nodeVersion->getNodeTranslation()->getNode();
153
        }
154
155
        return null;
156
    }
157
158
    /**
159
     * @param Node   $parentNode The parent node (may be null)
160
     * @param string $slug       The slug
161
     *
162
     * @return Node|null
163
     */
164
    public function getNodeForSlug(Node $parentNode, $slug)
165
    {
166
        $slugParts = explode('/', $slug);
167
        $result = null;
168
        foreach ($slugParts as $slugPart) {
169
            if ($parentNode) {
170
                if ($r = $this->findOneBy(
171
                    array(
172
                        'slug' => $slugPart,
173
                        'parent.parent' => $parentNode->getId(),
174
                    )
175
                )
176
                ) {
177
                    $result = $r;
178
                }
179
            } elseif ($r = $this->findOneBy(['slug' => $slugPart])) {
0 ignored issues
show
Are you sure the assignment to $r is correct as $this->findOneBy(array('slug' => $slugPart)) (which targets Doctrine\ORM\EntityRepository::findOneBy()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
180
                $result = $r;
181
            }
182
        }
183
184
        return $result;
185
    }
186
187
    /**
188
     * @param HasNodeInterface $hasNode      The object to link to
189
     * @param string           $lang         The locale
190
     * @param BaseUser         $owner        The user
191
     * @param string           $internalName The internal name (may be null)
192
     *
193
     * @throws \InvalidArgumentException
194
     *
195
     * @return Node
196
     */
197
    public function createNodeFor(
198
        HasNodeInterface $hasNode,
199
        $lang,
200
        BaseUser $owner,
201
        $internalName = null
202
    ) {
203
        $em = $this->getEntityManager();
204
        $node = new Node();
205
        $node->setRef($hasNode);
206
        if (!$hasNode->getId() > 0) {
207
            throw new \InvalidArgumentException(
208
                'the entity of class '.
209
                $node->getRefEntityName(
210
                ).' has no id, maybe you forgot to flush first'
211
            );
212
        }
213
        $node->setDeleted(false);
214
        $node->setInternalName($internalName);
215
        $parent = $hasNode->getParent();
216
        if ($parent) {
217
            /* @var NodeVersion $parentNodeVersion */
218
            $parentNodeVersion = $em->getRepository(
219
                'KunstmaanNodeBundle:NodeVersion'
220
            )->findOneBy(
221
                array(
222
                    'refId' => $parent->getId(),
223
                    'refEntityName' => ClassLookup::getClass($parent),
224
                )
225
            );
226
            if ($parentNodeVersion) {
227
                $node->setParent(
228
                    $parentNodeVersion->getNodeTranslation()->getNode()
229
                );
230
            }
231
        }
232
        if ($hasNode instanceof HiddenFromNavInterface) {
233
            $node->setHiddenFromNav($hasNode->isHiddenFromNav());
234
        }
235
        $em->persist($node);
236
        $em->flush();
237
        $em->refresh($node);
238
        $em->getRepository('KunstmaanNodeBundle:NodeTranslation')
239
            ->createNodeTranslationFor(
240
                $hasNode,
241
                $lang,
242
                $node,
243
                $owner
244
            );
245
246
        return $node;
247
    }
248
249
    /**
250
     * Get all the information needed to build a menu tree with one query.
251
     * We only fetch the fields we need, instead of fetching full objects to
252
     * limit the memory usage.
253
     *
254
     * @param string          $lang                 The locale
255
     * @param string          $permission           The permission (read,
256
     *                                              write, ...)
257
     * @param AclNativeHelper $aclNativeHelper      The acl helper
258
     * @param bool            $includeHiddenFromNav Include nodes hidden from
259
     *                                              navigation or not
260
     * @param Node            $rootNode             The root node of the
261
     *                                              current site
262
     *
263
     * @return array
264
     */
265
    public function getAllMenuNodes(
266
        $lang,
267
        $permission,
268
        AclNativeHelper $aclNativeHelper,
269
        $includeHiddenFromNav = false,
270
        Node $rootNode = null
271
    ) {
272
        $connection = $this->_em->getConnection();
273
        $qb = $connection->createQueryBuilder();
274
        $databasePlatformName = $connection->getDatabasePlatform()->getName();
275
        $createIfStatement = function (
276
            $expression,
277
            $trueValue,
278
            $falseValue
279
        ) use ($databasePlatformName) {
280
            switch ($databasePlatformName) {
281
                case 'sqlite':
282
                    $statement = 'CASE WHEN %s THEN %s ELSE %s END';
283
284
                    break;
285
286
                default:
287
                    $statement = 'IF(%s, %s, %s)';
288
            }
289
290
            return sprintf($statement, $expression, $trueValue, $falseValue);
291
        };
292
293
        $sql = <<<SQL
294
n.id, n.parent_id AS parent, t.url, t.id AS nt_id,
295
{$createIfStatement('t.weight IS NULL', 'v.weight', 't.weight')} AS weight,
296
{$createIfStatement('t.title IS NULL', 'v.title', 't.title')} AS title,
297
{$createIfStatement('t.online IS NULL', '0', 't.online')} AS online,
298
n.hidden_from_nav AS hidden,
299
n.ref_entity_name AS ref_entity_name
300
SQL;
301
302
        $qb->select($sql)
303
            ->from('kuma_nodes', 'n')
304
            ->leftJoin(
305
                'n',
306
                'kuma_node_translations',
307
                't',
308
                '(t.node_id = n.id AND t.lang = :lang)'
309
            )
310
            ->leftJoin(
311
                'n',
312
                'kuma_node_translations',
313
                'v',
314
                '(v.node_id = n.id AND v.lang <> :lang)'
315
            )
316
            ->where('n.deleted = 0')
317
            ->addGroupBy('n.id')
318
            ->addOrderBy('t.weight', 'ASC')
319
            ->addOrderBy('t.title', 'ASC');
320
321
        if (!$includeHiddenFromNav) {
322
            $qb->andWhere('n.hidden_from_nav <> 0');
323
        }
324
325
        if (!\is_null($rootNode)) {
326
            $qb->andWhere('n.lft >= :left')
327
                ->andWhere('n.rgt <= :right');
328
        }
329
330
        $permissionDef = new PermissionDefinition(array($permission));
331
        $permissionDef->setEntity('Kunstmaan\NodeBundle\Entity\Node');
332
        $permissionDef->setAlias('n');
333
        $qb = $aclNativeHelper->apply($qb, $permissionDef);
334
335
        $stmt = $this->_em->getConnection()->prepare($qb->getSQL());
336
        $stmt->bindValue(':lang', $lang);
337
        if (!\is_null($rootNode)) {
338
            $stmt->bindValue(':left', $rootNode->getLeft());
339
            $stmt->bindValue(':right', $rootNode->getRight());
340
        }
341
        $stmt->execute();
342
343
        return $stmt->fetchAll();
344
    }
345
346
    /**
347
     * Get all parents of a given node. We can go multiple levels up.
348
     *
349
     * @param Node   $node
350
     * @param string $lang
351
     *
352
     * @return Node[]
353
     */
354 View Code Duplication
    public function getAllParents(Node $node = null, $lang = null)
355
    {
356
        if (\is_null($node)) {
357
            return array();
358
        }
359
360
        $qb = $this->createQueryBuilder('node');
361
362
        // Directly hydrate the nodeTranslation and nodeVersion
363
        $qb->select('node', 't', 'v')
364
            ->innerJoin('node.nodeTranslations', 't')
365
            ->leftJoin(
366
                't.publicNodeVersion',
367
                'v',
368
                'WITH',
369
                't.publicNodeVersion = v.id'
370
            )
371
            ->where('node.deleted = 0');
372
373
        if ($lang) {
374
            $qb->andWhere('t.lang = :lang')
375
                ->setParameter('lang', $lang);
376
        }
377
378
        $qb->andWhere(
379
            $qb->expr()->andX(
380
                $qb->expr()->lte('node.lft', $node->getLeft()),
381
                $qb->expr()->gte('node.rgt', $node->getRight())
382
            )
383
        );
384
385
        $qb->addOrderBy('node.lft', 'ASC');
386
387
        return $qb->getQuery()->getResult();
388
    }
389
390
    /**
391
     * Get the root node of a given node.
392
     *
393
     * @param Node   $node
394
     * @param string $lang
395
     *
396
     * @return Node
397
     */
398 View Code Duplication
    public function getRootNodeFor(Node $node = null, $lang = null)
399
    {
400
        if (\is_null($node)) {
401
            return null;
402
        }
403
404
        $qb = $this->createQueryBuilder('node');
405
406
        // Directly hydrate the nodeTranslation and nodeVersion
407
        $qb->select('node', 't', 'v')
408
            ->innerJoin('node.nodeTranslations', 't')
409
            ->leftJoin(
410
                't.publicNodeVersion',
411
                'v',
412
                'WITH',
413
                't.publicNodeVersion = v.id'
414
            )
415
            ->where('node.deleted = 0')
416
            ->andWhere('node.parent IS NULL');
417
418
        if ($lang) {
419
            $qb->andWhere('t.lang = :lang')
420
                ->setParameter('lang', $lang);
421
        }
422
423
        $qb->andWhere(
424
            $qb->expr()->andX(
425
                $qb->expr()->lte('node.lft', $node->getLeft()),
426
                $qb->expr()->gte('node.rgt', $node->getRight())
427
            )
428
        );
429
430
        return $qb->getQuery()->getOneOrNullResult();
431
    }
432
433
    /**
434
     * @return Node[]
435
     */
436
    public function getAllTopNodes()
437
    {
438
        $qb = $this->createQueryBuilder('b')
439
            ->select('b', 't', 'v')
440
            ->leftJoin('b.nodeTranslations', 't')
441
            ->leftJoin(
442
                't.publicNodeVersion',
443
                'v',
444
                'WITH',
445
                't.publicNodeVersion = v.id'
446
            )
447
            ->where('b.deleted = 0')
448
            ->andWhere('b.parent IS NULL');
449
450
        return $qb->getQuery()->getResult();
451
    }
452
453
    /**
454
     * Get an array of Nodes based on the internal name.
455
     *
456
     * @param string        $internalName   The internal name of the node
457
     * @param string        $lang           The locale
458
     * @param int|null|bool $parentId       The parent id
459
     * @param bool          $includeOffline Include offline nodes
460
     *
461
     * @return Node[]
462
     */
463
    public function getNodesByInternalName(
464
        $internalName,
465
        $lang,
466
        $parentId = false,
467
        $includeOffline = false
468
    ) {
469
        $qb = $this->createQueryBuilder('n')
470
            ->select('n', 't', 'v')
471
            ->innerJoin('n.nodeTranslations', 't')
472
            ->leftJoin(
473
                't.publicNodeVersion',
474
                'v',
475
                'WITH',
476
                't.publicNodeVersion = v.id'
477
            )
478
            ->where('n.deleted = 0')
479
            ->andWhere('n.internalName = :internalName')
480
            ->setParameter('internalName', $internalName)
481
            ->andWhere('t.lang = :lang')
482
            ->setParameter('lang', $lang)
483
            ->addOrderBy('t.weight', 'ASC')
484
            ->addOrderBy('t.title', 'ASC');
485
486
        if (!$includeOffline) {
487
            $qb->andWhere('t.online = true');
488
        }
489
490 View Code Duplication
        if (\is_null($parentId)) {
491
            $qb->andWhere('n.parent is NULL');
492
        } elseif ($parentId === false) {
493
            // Do nothing
494
        } else {
495
            $qb->andWhere('n.parent = :parent')
496
                ->setParameter('parent', $parentId);
497
        }
498
499
        $query = $qb->getQuery();
500
501
        return $query->getResult();
502
    }
503
504
    /**
505
     * Get a single node by internal name.
506
     *
507
     * @param string $internalName The internal name of the node
508
     *
509
     * @return Node
510
     */
511
    public function getNodeByInternalName($internalName)
512
    {
513
        $qb = $this->createQueryBuilder('n')
514
            ->select('n')
515
            ->where('n.deleted = 0')
516
            ->andWhere('n.internalName = :internalName')
517
            ->setParameter('internalName', $internalName);
518
519
        return $qb->getQuery()->getOneOrNullResult();
520
    }
521
522
    /**
523
     * Finds all different page classes currently registered as nodes
524
     *
525
     * @return string[]
526
     */
527
    public function findAllDistinctPageClasses()
528
    {
529
        $qb = $this->createQueryBuilder('n')
530
            ->select('n.refEntityName')
531
            ->where('n.deleted = 0')
532
            ->distinct(true);
533
534
        return $qb->getQuery()->getArrayResult();
535
    }
536
}
537