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