Completed
Push — master ( 06c1ce...67d37c )
by Jeroen
06:20
created

Repository/NodeTranslationRepository.php (1 issue)

Check for PhpDoc comments which do parse

Documentation Minor

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 Doctrine\ORM\EntityRepository;
6
use Doctrine\ORM\Query\ResultSetMappingBuilder;
7
use Doctrine\ORM\QueryBuilder;
8
use Kunstmaan\AdminBundle\Entity\BaseUser;
9
use Kunstmaan\NodeBundle\Entity\HasNodeInterface;
10
use Kunstmaan\NodeBundle\Entity\Node;
11
use Kunstmaan\NodeBundle\Entity\NodeTranslation;
12
use Kunstmaan\NodeBundle\Entity\NodeVersion;
13
use Kunstmaan\UtilitiesBundle\Helper\ClassLookup;
14
15
/**
16
 * NodeRepository
17
 */
18
class NodeTranslationRepository extends EntityRepository
19
{
20
    /**
21
     * Get the QueryBuilder based on node id and language.
22
     *
23
     * @param int    $nodeId
24
     * @param string $lang
25
     *
26
     * @return array_shift($result)
0 ignored issues
show
The doc-type array_shift($result) could not be parsed: Expected "|" or "end of type", but got "(" at position 11. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
27
     */
28
    public function getNodeTranslationByNodeIdQueryBuilder($nodeId, $lang)
29
    {
30
        $qb = $this->createQueryBuilder('nt')
31
            ->select('nt')
32
            ->innerJoin('nt.node', 'n', 'WITH', 'nt.node = n.id')
33
            ->where('n.deleted != 1')
34
            ->andWhere('nt.online = 1')
35
            ->andWhere('nt.lang = :lang')
36
            ->setParameter('lang', $lang)
37
            ->andWhere('n.id = :node_id')
38
            ->setParameter('node_id', $nodeId)
39
            ->setFirstResult(0)
40
            ->setMaxResults(1);
41
42
        return $qb->getQuery()->getOneOrNullResult();
43
    }
44
45
    /**
46
     * Get max children weight
47
     *
48
     * @param Node   $parentNode
49
     * @param string $lang       (optional) Only return max weight for the
50
     *                           given language
51
     *
52
     * @return int
53
     */
54
    public function getMaxChildrenWeight(Node $parentNode = null, $lang = null)
55
    {
56
        $maxWeight = $this->getNodeTranslationsQueryBuilder($lang)
57
            ->select('max(nt.weight)')
58
            ->andWhere('n.parent = :parentNode')
59
            ->setParameter('parentNode', $parentNode)
60
            ->getQuery()
61
            ->getSingleScalarResult();
62
63
        return (int) $maxWeight;
64
    }
65
66
    /**
67
     * QueryBuilder to fetch node translations (ignoring nodes that have been
68
     * deleted)
69
     *
70
     * @param string $lang (optional) Only return NodeTranslations for the
71
     *                     given language
72
     *
73
     * @return \Doctrine\ORM\QueryBuilder
74
     */
75
    public function getNodeTranslationsQueryBuilder($lang = null)
76
    {
77
        $queryBuilder = $this->createQueryBuilder('nt')
78
            ->select('nt,n,v')
79
            ->innerJoin('nt.node', 'n')
80
            ->leftJoin(
81
                'nt.publicNodeVersion',
82
                'v',
83
                'WITH',
84
                'nt.publicNodeVersion = v.id'
85
            )
86
            ->where('n.deleted = false')
87
            ->orderBy('nt.weight')
88
            ->addOrderBy('nt.weight');
89
90
        if (!empty($lang)) {
91
            $queryBuilder
92
                ->andWhere('nt.lang = :lang')
93
                ->setParameter('lang', $lang);
94
        }
95
96
        return $queryBuilder;
97
    }
98
99
    /**
100
     * QueryBuilder to fetch node translations that are currently published
101
     * (ignoring nodes that have been deleted)
102
     *
103
     * @param string $lang (optional) Only return NodeTranslations for the
104
     *                     given language
105
     *
106
     * @return \Doctrine\ORM\QueryBuilder
107
     */
108
    public function getOnlineNodeTranslationsQueryBuilder($lang = null)
109
    {
110
        return $this->getNodeTranslationsQueryBuilder($lang)
111
            ->andWhere('nt.online = true');
112
    }
113
114
    /**
115
     * QueryBuilder to fetch immediate child NodeTranslations for a specific
116
     * node and (optional) language
117
     *
118
     * @return \Doctrine\ORM\QueryBuilder
119
     */
120
    public function getChildrenQueryBuilder(Node $parent, $lang = null)
121
    {
122
        return $this->getNodeTranslationsQueryBuilder($lang)
123
            ->andWhere('n.parent = :parent')
124
            ->setParameter('parent', $parent);
125
    }
126
127
    /**
128
     * QueryBuilder to fetch immediate child NodeTranslations for a specific
129
     * node and (optional) language that are currently published
130
     *
131
     * @return \Doctrine\ORM\QueryBuilder
132
     */
133
    public function getOnlineChildrenQueryBuilder(Node $parent, $lang = null)
134
    {
135
        return $this->getChildrenQueryBuilder($parent, $lang)
136
            ->andWhere('nt.online = true');
137
    }
138
139
    /**
140
     * Get all online child node translations for a given node and (optional)
141
     * language
142
     *
143
     * @param Node   $parent
144
     * @param string $lang   (optional, if not specified all languages will be
145
     *                       returned)
146
     *
147
     * @return array
148
     */
149
    public function getOnlineChildren(Node $parent, $lang = null)
150
    {
151
        return $this->getOnlineChildrenQueryBuilder($parent, $lang)
152
            ->getQuery()->getResult();
153
    }
154
155
    /**
156
     * Finds all nodetranslations where title is like the given $title parameter
157
     *
158
     *
159
     * @param string $title
160
     * @param string $lang  (optional, if not specified all languages will be
161
     *                      returned)
162
     *
163
     * @return array
164
     */
165
    public function getNodeTranslationsLikeTitle($title, $lang = null)
166
    {
167
        /** @var QueryBuilder $qb */
168
        $qb = $this->getNodeTranslationsQueryBuilder($lang);
169
        $qb->andWhere('nt.title like :title')
170
            ->setParameter('title', '%' . $title . '%');
171
172
        return $qb->getQuery()->getResult();
173
    }
174
175
    /**
176
     * Get the node translation for a node
177
     *
178
     * @param HasNodeInterface $hasNode
179
     *
180
     * @return NodeTranslation
181
     */
182
    public function getNodeTranslationFor(HasNodeInterface $hasNode)
183
    {
184
        /* @var NodeVersion $nodeVersion */
185
        $nodeVersion = $this->getEntityManager()
186
            ->getRepository('KunstmaanNodeBundle:NodeVersion')
187
            ->getNodeVersionFor($hasNode);
188
189
        if (!\is_null($nodeVersion)) {
190
            return $nodeVersion->getNodeTranslation();
191
        }
192
193
        return null;
194
    }
195
196
    /**
197
     * Get the node translation for a given slug string
198
     *
199
     * @param string               $slug       The slug
200
     * @param NodeTranslation|null $parentNode The parentnode
201
     *
202
     * @return NodeTranslation|null
203
     */
204
    public function getNodeTranslationForSlug(
205
        $slug,
206
        NodeTranslation $parentNode = null
207
    ) {
208
        if (empty($slug)) {
209
            return $this->getNodeTranslationForSlugPart(null, $slug);
210
        }
211
212
        $slugParts = explode('/', $slug);
213
        $result = $parentNode;
214
        foreach ($slugParts as $slugPart) {
215
            $result = $this->getNodeTranslationForSlugPart($result, $slugPart);
216
        }
217
218
        return $result;
219
    }
220
221
    /**
222
     * Returns the node translation for a given slug
223
     *
224
     * @param NodeTranslation|null $parentNode The parentNode
225
     * @param string               $slugPart   The slug part
226
     *
227
     * @return NodeTranslation|null
228
     */
229
    private function getNodeTranslationForSlugPart(
230
        NodeTranslation $parentNode = null,
231
        $slugPart = ''
232
    ) {
233
        $qb = $this->createQueryBuilder('t')
234
            ->select('t', 'v', 'n')
235
            ->innerJoin('t.node', 'n', 'WITH', 't.node = n.id')
236
            ->leftJoin(
237
                't.publicNodeVersion',
238
                'v',
239
                'WITH',
240
                't.publicNodeVersion = v.id'
241
            )
242
            ->where('n.deleted != 1')
243
            ->setFirstResult(0)
244
            ->setMaxResults(1);
245
246
        if ($parentNode !== null) {
247
            $qb->andWhere('t.slug = :slug')
248
                ->andWhere('n.parent = :parent')
249
                ->setParameter('slug', $slugPart)
250
                ->setParameter('parent', $parentNode->getNode()->getId());
251
        } else {
252
            /* if parent is null we should look for slugs that have no parent */
253
            $qb->andWhere('n.parent IS NULL');
254
            if (empty($slugPart)) {
255
                $qb->andWhere('t.slug is NULL');
256
            } else {
257
                $qb->andWhere('t.slug = :slug');
258
                $qb->setParameter('slug', $slugPart);
259
            }
260
        }
261
262
        return $qb->getQuery()->getOneOrNullResult();
263
    }
264
265
    /**
266
     * Get the node translation for a given url
267
     *
268
     * @param string          $urlSlug        The full url
269
     * @param string          $locale         The locale
270
     * @param bool            $includeDeleted Include deleted nodes
271
     * @param NodeTranslation $toExclude      Optional NodeTranslation instance
272
     *                                        you wish to exclude
273
     * @param Node            $rootNode       Optional Root node of the tree you
274
     *                                        wish to use
275
     *
276
     * @return array
277
     */
278
    public function getAllNodeTranslationsForUrl(
279
        $urlSlug,
280
        $locale = '',
281
        $includeDeleted = false,
282
        NodeTranslation $toExclude = null,
283
        Node $rootNode = null
284
    ) {
285
        $qb = $this->createQueryBuilder('b')
286
            ->select('b', 'v')
287
            ->innerJoin('b.node', 'n', 'WITH', 'b.node = n.id')
288
            ->leftJoin(
289
                'b.publicNodeVersion',
290
                'v',
291
                'WITH',
292
                'b.publicNodeVersion = v.id'
293
            )
294
            ->addOrderBy('b.online', 'DESC')
295
            ->setFirstResult(0)
296
            ->setMaxResults(1);
297
298
        if (!$includeDeleted) {
299
            $qb->andWhere('n.deleted = 0');
300
        }
301
302
        if (!empty($locale)) {
303
            $qb->andWhere('b.lang = :lang')
304
                ->setParameter('lang', $locale);
305
        }
306
307
        if (empty($urlSlug)) {
308
            $qb->andWhere('b.url IS NULL');
309
        } else {
310
            $qb->andWhere('b.url = :url');
311
            $qb->setParameter('url', $urlSlug);
312
        }
313
314
        if (!\is_null($toExclude)) {
315
            $qb->andWhere('NOT b.id = :exclude_id')
316
                ->setParameter('exclude_id', $toExclude->getId());
317
        }
318
319
        if ($rootNode) {
320
            $qb->andWhere('n.lft >= :left')
321
                ->andWhere('n.rgt <= :right')
322
                ->setParameter('left', $rootNode->getLeft())
323
                ->setParameter('right', $rootNode->getRight());
324
        }
325
326
        return $qb->getQuery()->getResult();
327
    }
328
329
    /**
330
     * Get the node translation for a given url
331
     *
332
     * @param string          $urlSlug        The full url
333
     * @param string          $locale         The locale
334
     * @param bool            $includeDeleted Include deleted nodes
335
     * @param NodeTranslation $toExclude      Optional NodeTranslation instance
336
     *                                        you wish to exclude
337
     * @param Node            $rootNode       Optional Root node of the tree you
338
     *                                        wish to use
339
     *
340
     * @return NodeTranslation|null
341
     */
342
    public function getNodeTranslationForUrl(
343
        $urlSlug,
344
        $locale = '',
345
        $includeDeleted = false,
346
        NodeTranslation $toExclude = null,
347
        Node $rootNode = null
348
    ) {
349
        $translations = $this->getAllNodeTranslationsForUrl($urlSlug, $locale, $includeDeleted, $toExclude, $rootNode);
350
351
        if (empty($translations)) {
352
            return null;
353
        }
354
355
        return $translations[0];
356
    }
357
358
    /**
359
     * Get all top node translations
360
     *
361
     * @return NodeTranslation[]
362
     */
363
    public function getTopNodeTranslations()
364
    {
365
        $qb = $this->createQueryBuilder('b')
366
            ->select('b', 'v')
367
            ->innerJoin('b.node', 'n', 'WITH', 'b.node = n.id')
368
            ->leftJoin(
369
                'b.publicNodeVersion',
370
                'v',
371
                'WITH',
372
                'b.publicNodeVersion = v.id'
373
            )
374
            ->where('n.parent IS NULL')
375
            ->andWhere('n.deleted != 1');
376
377
        return $qb->getQuery()->getResult();
378
    }
379
380
    /**
381
     * Create a node translation for a given node
382
     *
383
     * @param HasNodeInterface $hasNode The hasNode
384
     * @param string           $lang    The locale
385
     * @param Node             $node    The node
386
     * @param BaseUser         $owner   The user
387
     *
388
     * @throws \InvalidArgumentException
389
     *
390
     * @return NodeTranslation
391
     */
392
    public function createNodeTranslationFor(
393
        HasNodeInterface $hasNode,
394
        $lang,
395
        Node $node,
396
        BaseUser $owner
397
    ) {
398
        $em = $this->getEntityManager();
399
        $className = ClassLookup::getClass($hasNode);
400
        if (!$hasNode->getId() > 0) {
401
            throw new \InvalidArgumentException('The entity of class ' . $className . ' has no id, maybe you forgot to flush first');
402
        }
403
404
        $nodeTranslation = new NodeTranslation();
405
        $nodeTranslation
406
            ->setNode($node)
407
            ->setLang($lang)
408
            ->setTitle($hasNode->getTitle())
409
            ->setOnline(false)
410
            ->setWeight(0);
411
412
        $em->persist($nodeTranslation);
413
414
        $nodeVersion = $em->getRepository('KunstmaanNodeBundle:NodeVersion')
415
            ->createNodeVersionFor(
416
                $hasNode,
417
                $nodeTranslation,
418
                $owner,
419
                null
420
            );
421
422
        $nodeTranslation->setPublicNodeVersion($nodeVersion);
423
        $em->persist($nodeTranslation);
424
        $em->flush();
425
        $em->refresh($nodeTranslation);
426
        $em->refresh($node);
427
428
        return $nodeTranslation;
429
    }
430
431
    /**
432
     * Add a draft node version for a given node
433
     *
434
     * @param HasNodeInterface $hasNode The hasNode
435
     * @param string           $lang    The locale
436
     * @param Node             $node    The node
437
     * @param BaseUser         $owner   The user
438
     *
439
     * @throws \InvalidArgumentException
440
     *
441
     * @return NodeTranslation
442
     */
443
    public function addDraftNodeVersionFor(
444
        HasNodeInterface $hasNode,
445
        $lang,
446
        Node $node,
447
        BaseUser $owner
448
    ) {
449
        $em = $this->getEntityManager();
450
        $className = ClassLookup::getClass($hasNode);
451
        if (!$hasNode->getId() > 0) {
452
            throw new \InvalidArgumentException('The entity of class ' . $className . ' has no id, maybe you forgot to flush first');
453
        }
454
455
        $nodeTranslation = $em->getRepository('KunstmaanNodeBundle:NodeTranslation')->findOneBy(['lang' => $lang, 'node' => $node]);
456
457
        $em->getRepository('KunstmaanNodeBundle:NodeVersion')
458
            ->createNodeVersionFor(
459
                $hasNode,
460
                $nodeTranslation,
461
                $owner,
462
                null,
463
                NodeVersion::DRAFT_VERSION
464
            );
465
466
        $em->refresh($nodeTranslation);
467
        $em->refresh($node);
468
469
        return $nodeTranslation;
470
    }
471
472
    /**
473
     * Find best match for given URL and locale
474
     *
475
     * @param string $urlSlug The slug
476
     * @param string $locale  The locale
477
     *
478
     * @return NodeTranslation
479
     */
480
    public function getBestMatchForUrl($urlSlug, $locale)
481
    {
482
        $em = $this->getEntityManager();
483
484
        $rsm = new ResultSetMappingBuilder($em);
485
        $rsm->addRootEntityFromClassMetadata(
486
            'Kunstmaan\NodeBundle\Entity\NodeTranslation',
487
            'nt'
488
        );
489
490
        $query = $em
491
            ->createNativeQuery(
492
                'select nt.*
493
                from kuma_node_translations nt
494
                join kuma_nodes n on n.id = nt.node_id
495
                where n.deleted = 0 and nt.lang = :lang and locate(nt.url, :url) = 1
496
                order by length(nt.url) desc limit 1',
497
                $rsm
498
            );
499
        $query->setParameter('lang', $locale);
500
        $query->setParameter('url', $urlSlug);
501
502
        return $query->getOneOrNullResult();
503
    }
504
505
    /**
506
     * Test if all parents of the specified NodeTranslation have a node
507
     * translation for the specified language
508
     *
509
     * @param NodeTranslation $nodeTranslation The node translation
510
     * @param string          $language        The locale
511
     *
512
     * @return bool
513
     */
514
    public function hasParentNodeTranslationsForLanguage(
515
        NodeTranslation $nodeTranslation,
516
        $language
517
    ) {
518
        $parentNode = $nodeTranslation->getNode()->getParent();
519
        if ($parentNode !== null) {
520
            $parentNodeTranslation = $parentNode->getNodeTranslation(
521
                $language,
522
                true
523
            );
524
            if ($parentNodeTranslation !== null) {
525
                return $this->hasParentNodeTranslationsForLanguage(
526
                    $parentNodeTranslation,
527
                    $language
528
                );
529
            }
530
531
            return false;
532
        }
533
534
        return true;
535
    }
536
537
    /**
538
     * This will return 1 NodeTranslation by default (if one exists).
539
     * Just give it the internal name as defined on the Node in the database
540
     * and the language.
541
     *
542
     * It'll only return the latest version. It'll also hide deleted & offline
543
     * nodes.
544
     *
545
     * @param $language
546
     * @param $internalName
547
     */
548
    public function getNodeTranslationByLanguageAndInternalName(
549
        $language,
550
        $internalName
551
    ) {
552
        $qb = $this->createQueryBuilder('nt')
553
            ->select('nt', 'v')
554
            ->innerJoin('nt.node', 'n', 'WITH', 'nt.node = n.id')
555
            ->leftJoin(
556
                'nt.publicNodeVersion',
557
                'v',
558
                'WITH',
559
                'nt.publicNodeVersion = v.id'
560
            )
561
            ->where('n.deleted != 1')
562
            ->andWhere('nt.online = 1')
563
            ->setFirstResult(0)
564
            ->setMaxResults(1);
565
566
        $qb->andWhere('nt.lang = :lang')
567
            ->setParameter('lang', $language);
568
569
        $qb->andWhere('n.internalName = :internal_name')
570
            ->setParameter('internal_name', $internalName);
571
572
        return $qb->getQuery()->getOneOrNullResult();
573
    }
574
575
    public function getAllNodeTranslationsByRefEntityName($refEntityName)
576
    {
577
        $qb = $this->createQueryBuilder('nt')
578
            ->select('nt,n')
579
            ->innerJoin('nt.publicNodeVersion', 'nv')
580
            ->innerJoin('nt.node', 'n')
581
            ->where('nv.refEntityName = :refEntityName')
582
            ->setParameter('refEntityName', $refEntityName);
583
584
        return $qb->getQuery()->getResult();
585
    }
586
587
    public function getParentNodeTranslation(NodeTranslation $nodeTranslation)
588
    {
589
        $parent = $nodeTranslation->getNode()->getParent();
590
        if (\is_null($parent)) {
591
            return null;
592
        }
593
594
        $qb = $this->createQueryBuilder('nt')
595
            ->select('nt,n')
596
            ->innerJoin('nt.publicNodeVersion', 'nv')
597
            ->innerJoin('nt.node', 'n')
598
            ->where('nt.node = :parent')
599
            ->andWhere('n.deleted = 0')
600
            ->andWhere('nt.lang = :lang')
601
            ->setParameter('parent', $parent)
602
            ->setParameter('lang', $nodeTranslation->getLang());
603
604
        return $qb->getQuery()->getOneOrNullResult();
605
    }
606
}
607