Completed
Push — master ( eab2a6...645cff )
by Jeroen
30s queued 13s
created

NodeRepository::getChildCount()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 16
ccs 0
cts 9
cp 0
rs 9.7333
c 0
b 0
f 0
cc 2
nc 2
nop 3
crap 6
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
0 ignored issues
show
Documentation introduced by
Should the type for parameter $rootNode not be Node|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
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)) {
0 ignored issues
show
Duplication introduced by
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...
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(
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Doctrine\Persistence\ObjectRepository as the method getNodeVersionFor() does only exist in the following implementations of said interface: Kunstmaan\NodeBundle\Rep...y\NodeVersionRepository.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
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(
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $r is correct as $this->findOneBy(array('... $parentNode->getId())) (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...
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
Bug introduced by
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)
0 ignored issues
show
Documentation introduced by
Should the type for parameter $internalName not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
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('the entity of class '. $node->getRefEntityName().' has no id, maybe you forgot to flush first');
208
        }
209
        $node->setDeleted(false);
210
        $node->setInternalName($internalName);
211
        $parent = $hasNode->getParent();
212
        if ($parent) {
213
            /* @var NodeVersion $parentNodeVersion */
214
            $parentNodeVersion = $em->getRepository(
215
                'KunstmaanNodeBundle:NodeVersion'
216
            )->findOneBy(
217
                array(
218
                    'refId' => $parent->getId(),
219
                    'refEntityName' => ClassLookup::getClass($parent),
220
                )
221
            );
222
            if ($parentNodeVersion) {
223
                $node->setParent(
224
                    $parentNodeVersion->getNodeTranslation()->getNode()
225
                );
226
            }
227
        }
228
        if ($hasNode instanceof HiddenFromNavInterface) {
229
            $node->setHiddenFromNav($hasNode->isHiddenFromNav());
230
        }
231
        $em->persist($node);
232
        $em->flush();
233
        $em->refresh($node);
234
        $em->getRepository('KunstmaanNodeBundle:NodeTranslation')
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Doctrine\Persistence\ObjectRepository as the method createNodeTranslationFor() does only exist in the following implementations of said interface: Kunstmaan\NodeBundle\Rep...deTranslationRepository.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
235
            ->createNodeTranslationFor(
236
                $hasNode,
237
                $lang,
238
                $node,
239
                $owner
240
            );
241
242
        return $node;
243
    }
244
245
    /**
246
     * Get all the information needed to build a menu tree with one query.
247
     * We only fetch the fields we need, instead of fetching full objects to
248
     * limit the memory usage.
249
     *
250
     * @param string          $lang                 The locale
251
     * @param string          $permission           The permission (read,
252
     *                                              write, ...)
253
     * @param AclNativeHelper $aclNativeHelper      The acl helper
254
     * @param bool            $includeHiddenFromNav Include nodes hidden from
255
     *                                              navigation or not
256
     * @param Node            $rootNode             The root node of the
0 ignored issues
show
Documentation introduced by
Should the type for parameter $rootNode not be null|Node?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
257
     *                                              current site
258
     *
259
     * @return array
260
     */
261
    public function getAllMenuNodes(
262
        $lang,
263
        $permission,
264
        AclNativeHelper $aclNativeHelper,
265
        $includeHiddenFromNav = false,
266
        Node $rootNode = null
267
    ) {
268
        $connection = $this->_em->getConnection();
269
        $qb = $connection->createQueryBuilder();
270
        $databasePlatformName = $connection->getDatabasePlatform()->getName();
271
        $createIfStatement = function (
272
            $expression,
273
            $trueValue,
274
            $falseValue
275
        ) use ($databasePlatformName) {
276
            switch ($databasePlatformName) {
277
                case 'sqlite':
278
                    $statement = 'CASE WHEN %s THEN %s ELSE %s END';
279
280
                    break;
281
282
                default:
283
                    $statement = 'IF(%s, %s, %s)';
284
            }
285
286
            return sprintf($statement, $expression, $trueValue, $falseValue);
287
        };
288
289
        $sql = <<<SQL
290
n.id, n.parent_id AS parent, t.url, t.id AS nt_id,
291
{$createIfStatement('t.weight IS NULL', 'v.weight', 't.weight')} AS weight,
292
{$createIfStatement('t.title IS NULL', 'v.title', 't.title')} AS title,
293
{$createIfStatement('t.online IS NULL', '0', 't.online')} AS online,
294
n.hidden_from_nav AS hidden,
295
n.ref_entity_name AS ref_entity_name
296
SQL;
297
298
        $qb->select($sql)
299
            ->from('kuma_nodes', 'n')
300
            ->leftJoin(
301
                'n',
302
                'kuma_node_translations',
303
                't',
304
                '(t.node_id = n.id AND t.lang = :lang)'
305
            )
306
            ->leftJoin(
307
                'n',
308
                'kuma_node_translations',
309
                'v',
310
                '(v.node_id = n.id AND v.lang <> :lang)'
311
            )
312
            ->where('n.deleted = 0')
313
            ->addGroupBy('n.id')
314
            ->addOrderBy('t.weight', 'ASC')
315
            ->addOrderBy('t.title', 'ASC');
316
317
        if (!$includeHiddenFromNav) {
318
            $qb->andWhere('n.hidden_from_nav <> 0');
319
        }
320
321
        if (!\is_null($rootNode)) {
322
            $qb->andWhere('n.lft >= :left')
323
                ->andWhere('n.rgt <= :right');
324
        }
325
326
        $permissionDef = new PermissionDefinition(array($permission));
327
        $permissionDef->setEntity('Kunstmaan\NodeBundle\Entity\Node');
328
        $permissionDef->setAlias('n');
329
        $qb = $aclNativeHelper->apply($qb, $permissionDef);
330
331
        $stmt = $this->_em->getConnection()->prepare($qb->getSQL());
332
        $stmt->bindValue(':lang', $lang);
333
        if (!\is_null($rootNode)) {
334
            $stmt->bindValue(':left', $rootNode->getLeft());
335
            $stmt->bindValue(':right', $rootNode->getRight());
336
        }
337
        $stmt->execute();
338
339
        return $stmt->fetchAll();
340
    }
341
342
    /**
343
     * Get all parents of a given node. We can go multiple levels up.
344
     *
345
     * @param Node   $node
0 ignored issues
show
Documentation introduced by
Should the type for parameter $node not be null|Node?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
346
     * @param string $lang
0 ignored issues
show
Documentation introduced by
Should the type for parameter $lang not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
347
     *
348
     * @return Node[]
349
     */
350 View Code Duplication
    public function getAllParents(Node $node = null, $lang = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
351
    {
352
        if (\is_null($node)) {
353
            return array();
354
        }
355
356
        $qb = $this->createQueryBuilder('node');
357
358
        // Directly hydrate the nodeTranslation and nodeVersion
359
        $qb->select('node', 't', 'v')
360
            ->innerJoin('node.nodeTranslations', 't')
361
            ->leftJoin(
362
                't.publicNodeVersion',
363
                'v',
364
                'WITH',
365
                't.publicNodeVersion = v.id'
366
            )
367
            ->where('node.deleted = 0');
368
369
        if ($lang) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $lang 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...
370
            $qb->andWhere('t.lang = :lang')
371
                ->setParameter('lang', $lang);
372
        }
373
374
        $qb->andWhere(
375
            $qb->expr()->andX(
376
                $qb->expr()->lte('node.lft', $node->getLeft()),
377
                $qb->expr()->gte('node.rgt', $node->getRight())
378
            )
379
        );
380
381
        $qb->addOrderBy('node.lft', 'ASC');
382
383
        return $qb->getQuery()->getResult();
384
    }
385
386
    /**
387
     * Get the root node of a given node.
388
     *
389
     * @param Node   $node
0 ignored issues
show
Documentation introduced by
Should the type for parameter $node not be null|Node?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
390
     * @param string $lang
0 ignored issues
show
Documentation introduced by
Should the type for parameter $lang not be string|null?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
391
     *
392
     * @return Node
393
     */
394 View Code Duplication
    public function getRootNodeFor(Node $node = null, $lang = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
395
    {
396
        if (\is_null($node)) {
397
            return null;
398
        }
399
400
        $qb = $this->createQueryBuilder('node');
401
402
        // Directly hydrate the nodeTranslation and nodeVersion
403
        $qb->select('node', 't', 'v')
404
            ->innerJoin('node.nodeTranslations', 't')
405
            ->leftJoin(
406
                't.publicNodeVersion',
407
                'v',
408
                'WITH',
409
                't.publicNodeVersion = v.id'
410
            )
411
            ->where('node.deleted = 0')
412
            ->andWhere('node.parent IS NULL');
413
414
        if ($lang) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $lang 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...
415
            $qb->andWhere('t.lang = :lang')
416
                ->setParameter('lang', $lang);
417
        }
418
419
        $qb->andWhere(
420
            $qb->expr()->andX(
421
                $qb->expr()->lte('node.lft', $node->getLeft()),
422
                $qb->expr()->gte('node.rgt', $node->getRight())
423
            )
424
        );
425
426
        return $qb->getQuery()->getOneOrNullResult();
427
    }
428
429
    /**
430
     * @return Node[]
431
     */
432
    public function getAllTopNodes()
433
    {
434
        $qb = $this->createQueryBuilder('b')
435
            ->select('b', 't', 'v')
436
            ->leftJoin('b.nodeTranslations', 't')
437
            ->leftJoin(
438
                't.publicNodeVersion',
439
                'v',
440
                'WITH',
441
                't.publicNodeVersion = v.id'
442
            )
443
            ->where('b.deleted = 0')
444
            ->andWhere('b.parent IS NULL');
445
446
        return $qb->getQuery()->getResult();
447
    }
448
449
    /**
450
     * Get an array of Nodes based on the internal name.
451
     *
452
     * @param string        $internalName   The internal name of the node
453
     * @param string        $lang           The locale
454
     * @param int|null|bool $parentId       The parent id
455
     * @param bool          $includeOffline Include offline nodes
456
     *
457
     * @return Node[]
458
     */
459
    public function getNodesByInternalName(
460
        $internalName,
461
        $lang,
462
        $parentId = false,
463
        $includeOffline = false
464
    ) {
465
        $qb = $this->createQueryBuilder('n')
466
            ->select('n', 't', 'v')
467
            ->innerJoin('n.nodeTranslations', 't')
468
            ->leftJoin(
469
                't.publicNodeVersion',
470
                'v',
471
                'WITH',
472
                't.publicNodeVersion = v.id'
473
            )
474
            ->where('n.deleted = 0')
475
            ->andWhere('n.internalName = :internalName')
476
            ->setParameter('internalName', $internalName)
477
            ->andWhere('t.lang = :lang')
478
            ->setParameter('lang', $lang)
479
            ->addOrderBy('t.weight', 'ASC')
480
            ->addOrderBy('t.title', 'ASC');
481
482
        if (!$includeOffline) {
483
            $qb->andWhere('t.online = true');
484
        }
485
486 View Code Duplication
        if (\is_null($parentId)) {
0 ignored issues
show
Duplication introduced by
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...
487
            $qb->andWhere('n.parent is NULL');
488
        } elseif ($parentId === false) {
489
            // Do nothing
490
        } else {
491
            $qb->andWhere('n.parent = :parent')
492
                ->setParameter('parent', $parentId);
493
        }
494
495
        $query = $qb->getQuery();
496
497
        return $query->getResult();
498
    }
499
500
    /**
501
     * Get a single node by internal name.
502
     *
503
     * @param string $internalName The internal name of the node
504
     *
505
     * @return Node
506
     */
507
    public function getNodeByInternalName($internalName)
508
    {
509
        $qb = $this->createQueryBuilder('n')
510
            ->select('n')
511
            ->where('n.deleted = 0')
512
            ->andWhere('n.internalName = :internalName')
513
            ->setParameter('internalName', $internalName);
514
515
        return $qb->getQuery()->getOneOrNullResult();
516
    }
517
518
    /**
519
     * Finds all different page classes currently registered as nodes
520
     *
521
     * @return string[]
522
     */
523
    public function findAllDistinctPageClasses()
524
    {
525
        $qb = $this->createQueryBuilder('n')
526
            ->select('n.refEntityName')
527
            ->where('n.deleted = 0')
528
            ->distinct(true);
529
530
        return $qb->getQuery()->getArrayResult();
531
    }
532
533
    public function getChildCount(Node $node, bool $direct = false, bool $includeDeleted = false): int
534
    {
535
        $qb = $this->getChildrenQueryBuilder($node, $direct);
536
        $qb->resetDQLPart('orderBy');
537
538
        $aliases = $qb->getRootAliases();
539
        $alias = $aliases[0];
540
541
        $qb->select('COUNT('.$alias.')');
542
543
        if (false === $includeDeleted) {
544
            $qb->andWhere($alias.'.deleted = 0');
545
        }
546
547
        return (int) $qb->getQuery()->getSingleScalarResult();
548
    }
549
}
550