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

Kunstmaan/NodeBundle/Repository/NodeRepository.php (1 issue)

Labels
Severity

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