Exponential 5.x Kernel 7.5.40 Exponential New Stack (Symfony-based) Kernel — PHP Class Reference

Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php
Go to the documentation of this file.
1 <?php
2
7 namespace eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway;
8
9 use Doctrine\DBAL\Connection;
10 use Doctrine\DBAL\FetchMode;
11 use Doctrine\DBAL\Query\QueryBuilder;
12 use eZ\Publish\Core\Persistence\Legacy\Content\Language\MaskGenerator;
13 use eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway;
14 use eZ\Publish\Core\Persistence\Database\DatabaseHandler;
15 use eZ\Publish\Core\Persistence\Database\SelectQuery;
16 use eZ\Publish\Core\Persistence\Database\Query as DatabaseQuery;
17 use eZ\Publish\SPI\Persistence\Content\ContentInfo;
18 use eZ\Publish\SPI\Persistence\Content\Location;
19 use eZ\Publish\SPI\Persistence\Content\Location\UpdateStruct;
20 use eZ\Publish\SPI\Persistence\Content\Location\CreateStruct;
21 use eZ\Publish\API\Repository\Values\Content\Query;
22 use eZ\Publish\API\Repository\Values\Content\Query\SortClause;
23 use eZ\Publish\Core\Base\Exceptions\NotFoundException as NotFound;
24 use RuntimeException;
25 use PDO;
26
30 class DoctrineDatabase extends Gateway
31 {
36 const MAX_LIMIT = 1073741824;
37
43 protected $handler;
44
46 protected $connection;
47
53 protected $languageMaskGenerator;
54
61 public function __construct(DatabaseHandler $handler, MaskGenerator $languageMaskGenerator)
62 {
63 $this->handler = $handler;
64 $this->connection = $handler->getConnection();
65 $this->languageMaskGenerator = $languageMaskGenerator;
66 }
67
71 public function getBasicNodeData($nodeId, array $translations = null, bool $useAlwaysAvailable = true)
72 {
73 $q = $this->createNodeQueryBuilder($translations, $useAlwaysAvailable);
74 $q->andWhere(
75 $q->expr()->eq('t.node_id', $q->createNamedParameter($nodeId, PDO::PARAM_INT))
76 );
77
78 if ($row = $q->execute()->fetch(FetchMode::ASSOCIATIVE)) {
79 return $row;
80 }
81
82 throw new NotFound('location', $nodeId);
83 }
84
88 public function getNodeDataList(array $locationIds, array $translations = null, bool $useAlwaysAvailable = true): iterable
89 {
90 $q = $this->createNodeQueryBuilder($translations, $useAlwaysAvailable);
91 $q->andWhere(
92 $q->expr()->in(
93 't.node_id',
94 $q->createNamedParameter($locationIds, Connection::PARAM_INT_ARRAY)
95 )
96 );
97
98 return $q->execute()->fetchAll(FetchMode::ASSOCIATIVE);
99 }
100
104 public function getBasicNodeDataByRemoteId($remoteId, array $translations = null, bool $useAlwaysAvailable = true)
105 {
106 $q = $this->createNodeQueryBuilder($translations, $useAlwaysAvailable);
107 $q->andWhere(
108 $q->expr()->eq('t.remote_id', $q->createNamedParameter($remoteId, PDO::PARAM_STR))
109 );
110
111 if ($row = $q->execute()->fetch(FetchMode::ASSOCIATIVE)) {
112 return $row;
113 }
114
115 throw new NotFound('location', $remoteId);
116 }
117
127 public function loadLocationDataByContent($contentId, $rootLocationId = null)
128 {
129 $query = $this->handler->createSelectQuery();
130 $query
131 ->select('*')
132 ->from($this->handler->quoteTable('ezcontentobject_tree'))
133 ->where(
134 $query->expr->eq(
135 $this->handler->quoteColumn('contentobject_id'),
136 $query->bindValue($contentId)
137 )
138 );
139 if ($rootLocationId !== null) {
140 $this->applySubtreeLimitation($query, $rootLocationId);
141 }
142 $statement = $query->prepare();
143 $statement->execute();
144
145 return $statement->fetchAll(\PDO::FETCH_ASSOC);
146 }
147
151 public function loadLocationDataByTrashContent(int $contentId, ?int $rootLocationId = null): array
152 {
153 $query = $this->handler->createSelectQuery();
154 $query
155 ->select('*')
156 ->from($this->connection->quoteIdentifier('ezcontentobject_trash'))
157 ->where(
158 $query->expr->eq(
159 $this->handler->quoteColumn('contentobject_id'),
160 $query->bindValue($contentId)
161 )
162 );
163
164 if ($rootLocationId !== null) {
165 $this->applySubtreeLimitation($query, $rootLocationId, 'ezcontentobject_trash');
166 }
167 $statement = $query->prepare();
168 $statement->execute();
169
170 return $statement->fetchAll(FetchMode::ASSOCIATIVE);
171 }
172
176 public function loadParentLocationsDataForDraftContent($contentId, $drafts = null)
177 {
179 $query = $this->handler->createSelectQuery();
180 $query->selectDistinct(
181 'ezcontentobject_tree.*'
182 )->from(
183 $this->handler->quoteTable('ezcontentobject_tree')
184 )->innerJoin(
185 $this->handler->quoteTable('eznode_assignment'),
186 $query->expr->lAnd(
187 $query->expr->eq(
188 $this->handler->quoteColumn('node_id', 'ezcontentobject_tree'),
189 $this->handler->quoteColumn('parent_node', 'eznode_assignment')
190 ),
191 $query->expr->eq(
192 $this->handler->quoteColumn('contentobject_id', 'eznode_assignment'),
193 $query->bindValue($contentId, null, \PDO::PARAM_INT)
194 ),
195 $query->expr->eq(
196 $this->handler->quoteColumn('op_code', 'eznode_assignment'),
197 $query->bindValue(self::NODE_ASSIGNMENT_OP_CODE_CREATE, null, \PDO::PARAM_INT)
198 )
199 )
200 )->innerJoin(
201 $this->handler->quoteTable('ezcontentobject'),
202 $query->expr->lAnd(
203 $query->expr->lOr(
204 $query->expr->eq(
205 $this->handler->quoteColumn('contentobject_id', 'eznode_assignment'),
206 $this->handler->quoteColumn('id', 'ezcontentobject')
207 )
208 ),
209 $query->expr->eq(
210 $this->handler->quoteColumn('status', 'ezcontentobject'),
211 $query->bindValue(ContentInfo::STATUS_DRAFT, null, \PDO::PARAM_INT)
212 )
213 )
214 );
215
216 $statement = $query->prepare();
217 $statement->execute();
218
219 return $statement->fetchAll(\PDO::FETCH_ASSOC);
220 }
221
230 public function getSubtreeContent($sourceId, $onlyIds = false)
231 {
232 $query = $this->handler->createSelectQuery();
233 $query->select($onlyIds ? 'node_id, contentobject_id, depth' : '*')->from(
234 $this->handler->quoteTable('ezcontentobject_tree')
235 );
236 $this->applySubtreeLimitation($query, $sourceId);
237 $query->orderBy(
238 $this->handler->quoteColumn('depth', 'ezcontentobject_tree')
239 )->orderBy(
240 $this->handler->quoteColumn('node_id', 'ezcontentobject_tree')
241 );
242 $statement = $query->prepare();
243 $statement->execute();
244
245 $results = $statement->fetchAll($onlyIds ? (PDO::FETCH_COLUMN | PDO::FETCH_GROUP) : PDO::FETCH_ASSOC);
246 // array_map() is used to to map all elements stored as $results[$i][0] to $results[$i]
247 return $onlyIds ? array_map('reset', $results) : $results;
248 }
249
257 protected function applySubtreeLimitation(
258 DatabaseQuery $query,
259 $rootLocationId,
260 string $tableName = 'ezcontentobject_tree'
261 ): void {
262 $query->where(
263 $query->expr->like(
264 $this->handler->quoteColumn('path_string', $tableName),
265 $query->bindValue('%/' . $rootLocationId . '/%')
266 )
267 );
268 }
269
277 public function getChildren($locationId)
278 {
279 $query = $this->handler->createSelectQuery();
280 $query->select('*')->from(
281 $this->handler->quoteTable('ezcontentobject_tree')
282 )->where(
283 $query->expr->eq(
284 $this->handler->quoteColumn('parent_node_id', 'ezcontentobject_tree'),
285 $query->bindValue($locationId, null, \PDO::PARAM_INT)
286 )
287 );
288 $statement = $query->prepare();
289 $statement->execute();
290
291 return $statement->fetchAll(\PDO::FETCH_ASSOC);
292 }
293
305 public function moveSubtreeNodes(array $sourceNodeData, array $destinationNodeData)
306 {
307 $fromPathString = $sourceNodeData['path_string'];
308
310 $query = $this->handler->createSelectQuery();
311 $query
312 ->select(
313 $this->handler->quoteColumn('node_id'),
314 $this->handler->quoteColumn('parent_node_id'),
315 $this->handler->quoteColumn('path_string'),
316 $this->handler->quoteColumn('path_identification_string'),
317 $this->handler->quoteColumn('is_hidden')
318 )
319 ->from($this->handler->quoteTable('ezcontentobject_tree'))
320 ->where(
321 $query->expr->like(
322 $this->handler->quoteColumn('path_string'),
323 $query->bindValue($fromPathString . '%')
324 )
325 );
326 $statement = $query->prepare();
327 $statement->execute();
328
329 $rows = $statement->fetchAll();
330 $oldParentPathString = implode('/', array_slice(explode('/', $fromPathString), 0, -2)) . '/';
331 $oldParentPathIdentificationString = implode(
332 '/',
333 array_slice(explode('/', $sourceNodeData['path_identification_string']), 0, -1)
334 );
335
336 foreach ($rows as $row) {
337 // Prefixing ensures correct replacement when old parent is root node
338 $newPathString = str_replace(
339 'prefix' . $oldParentPathString,
340 $destinationNodeData['path_string'],
341 'prefix' . $row['path_string']
342 );
343 $replace = rtrim($destinationNodeData['path_identification_string'], '/');
344 if (empty($oldParentPathIdentificationString)) {
345 $replace .= '/';
346 }
347 $newPathIdentificationString = str_replace(
348 'prefix' . $oldParentPathIdentificationString,
349 $replace,
350 'prefix' . $row['path_identification_string']
351 );
352 $newParentId = $row['parent_node_id'];
353 if ($row['path_string'] === $fromPathString) {
354 $newParentId = (int)implode('', array_slice(explode('/', $newPathString), -3, 1));
355 }
356
358 $query = $this->handler->createUpdateQuery();
359 $query
360 ->update($this->handler->quoteTable('ezcontentobject_tree'))
361 ->set(
362 $this->handler->quoteColumn('path_string'),
363 $query->bindValue($newPathString)
364 )
365 ->set(
366 $this->handler->quoteColumn('path_identification_string'),
367 $query->bindValue($newPathIdentificationString)
368 )
369 ->set(
370 $this->handler->quoteColumn('depth'),
371 $query->bindValue(substr_count($newPathString, '/') - 2)
372 )
373 ->set(
374 $this->handler->quoteColumn('parent_node_id'),
375 $query->bindValue($newParentId)
376 );
377
378 if ($destinationNodeData['is_hidden'] || $destinationNodeData['is_invisible']) {
379 // CASE 1: Mark whole tree as invisible if destination is invisible and/or hidden
380 $query->set(
381 $this->handler->quoteColumn('is_invisible'),
382 $query->bindValue(1)
383 );
384 } elseif (!$sourceNodeData['is_hidden'] && $sourceNodeData['is_invisible']) {
385 // CASE 2: source is only invisible, we will need to re-calculate whole moved tree visibility
386 $query->set(
387 $this->handler->quoteColumn('is_invisible'),
388 $query->bindValue($this->isHiddenByParent($newPathString, $rows) ? 1 : 0)
389 );
390 } else {
391 // CASE 3: keep invisible flags as is (source is either hidden or not hidden/invisible at all)
392 }
393
394 $query->where(
395 $query->expr->eq(
396 $this->handler->quoteColumn('node_id'),
397 $query->bindValue($row['node_id'])
398 )
399 );
400 $query->prepare()->execute();
401 }
402 }
403
404 private function isHiddenByParent($pathString, array $rows)
405 {
406 $parentNodeIds = explode('/', trim($pathString, '/'));
407 array_pop($parentNodeIds); // remove self
408 foreach ($rows as $row) {
409 if ($row['is_hidden'] && in_array($row['node_id'], $parentNodeIds)) {
410 return true;
411 }
412 }
413
414 return false;
415 }
416
423 public function updateSubtreeModificationTime($pathString, $timestamp = null)
424 {
425 $nodes = array_filter(explode('/', $pathString));
426 $query = $this->handler->createUpdateQuery();
427 $query
428 ->update($this->handler->quoteTable('ezcontentobject_tree'))
429 ->set(
430 $this->handler->quoteColumn('modified_subnode'),
431 $query->bindValue(
432 $timestamp ?: time()
433 )
434 )
435 ->where(
436 $query->expr->in(
437 $this->handler->quoteColumn('node_id'),
438 $nodes
439 )
440 );
441 $query->prepare()->execute();
442 }
443
449 public function hideSubtree($pathString)
450 {
451 $this->setNodeWithChildrenInvisible($pathString);
452 $this->setNodeHidden($pathString);
453 }
454
458 public function setNodeWithChildrenInvisible(string $pathString): void
459 {
460 $query = $this->handler->createUpdateQuery();
461 $query
462 ->update($this->handler->quoteTable('ezcontentobject_tree'))
463 ->set(
464 $this->handler->quoteColumn('is_invisible'),
465 $query->bindValue(1)
466 )
467 ->set(
468 $this->handler->quoteColumn('modified_subnode'),
469 $query->bindValue(time())
470 )
471 ->where(
472 $query->expr->like(
473 $this->handler->quoteColumn('path_string'),
474 $query->bindValue($pathString . '%')
475 )
476 );
477
478 $query->prepare()->execute();
479 }
480
484 public function setNodeHidden(string $pathString): void
485 {
486 $this->setNodeHiddenStatus($pathString, true);
487 }
488
493 private function setNodeHiddenStatus(string $pathString, bool $isHidden): void
494 {
495 $query = $this->handler->createUpdateQuery();
496 $query
497 ->update($this->handler->quoteTable('ezcontentobject_tree'))
498 ->set(
499 $this->handler->quoteColumn('is_hidden'),
500 $query->bindValue((int) $isHidden)
501 )
502 ->where(
503 $query->expr->eq(
504 $this->handler->quoteColumn('path_string'),
505 $query->bindValue($pathString)
506 )
507 );
508
509 $query->prepare()->execute();
510 }
511
518 public function unHideSubtree($pathString)
519 {
520 $this->setNodeUnhidden($pathString);
521 $this->setNodeWithChildrenVisible($pathString);
522 }
523
529 public function setNodeWithChildrenVisible(string $pathString): void
530 {
531 // Check if any parent nodes are explicitly hidden
532 $query = $this->handler->createSelectQuery();
533 $query
534 ->select($this->handler->quoteColumn('path_string'))
535 ->from($this->handler->quoteTable('ezcontentobject_tree'))
536 ->leftJoin('ezcontentobject', 'ezcontentobject_tree.contentobject_id', 'ezcontentobject.id')
537 ->where(
538 $query->expr->lAnd(
539 $query->expr->lOr(
540 $query->expr->eq(
541 $this->handler->quoteColumn('is_hidden', 'ezcontentobject_tree'),
542 $query->bindValue(1)
543 ),
544 $query->expr->eq(
545 $this->handler->quoteColumn('is_hidden', 'ezcontentobject'),
546 $query->bindValue(1)
547 )
548 ),
549 $query->expr->in(
550 $this->handler->quoteColumn('node_id'),
551 array_filter(explode('/', $pathString))
552 )
553 )
554 );
555
556 $statement = $query->prepare();
557 $statement->execute();
558 if (count($statement->fetchAll(\PDO::FETCH_COLUMN))) {
559 // There are parent nodes set hidden, so that we can skip marking
560 // something visible again.
561 return;
562 }
563
564 // Find nodes of explicitly hidden subtrees in the subtree which
565 // should be unhidden
566 $query = $this->handler->createSelectQuery();
567 $query
568 ->select($this->handler->quoteColumn('path_string'))
569 ->from($this->handler->quoteTable('ezcontentobject_tree'))
570 ->leftJoin('ezcontentobject', 'ezcontentobject_tree.contentobject_id', 'ezcontentobject.id')
571 ->where(
572 $query->expr->lAnd(
573 $query->expr->lOr(
574 $query->expr->eq(
575 $this->handler->quoteColumn('is_hidden', 'ezcontentobject_tree'),
576 $query->bindValue(1)
577 ),
578 $query->expr->eq(
579 $this->handler->quoteColumn('is_hidden', 'ezcontentobject'),
580 $query->bindValue(1)
581 )
582 ),
583 $query->expr->like(
584 $this->handler->quoteColumn('path_string'),
585 $query->bindValue($pathString . '%')
586 )
587 )
588 );
589 $statement = $query->prepare();
590 $statement->execute();
591 $hiddenSubtrees = $statement->fetchAll(\PDO::FETCH_COLUMN);
592
593 $query = $this->handler->createUpdateQuery();
594 $query
595 ->update($this->handler->quoteTable('ezcontentobject_tree'))
596 ->set(
597 $this->handler->quoteColumn('is_invisible'),
598 $query->bindValue(0)
599 )
600 ->set(
601 $this->handler->quoteColumn('modified_subnode'),
602 $query->bindValue(time())
603 );
604
605 // Build where expression selecting the nodes, which should be made
606 // visible again
607 $where = $query->expr->like(
608 $this->handler->quoteColumn('path_string'),
609 $query->bindValue($pathString . '%')
610 );
611 if (count($hiddenSubtrees)) {
612 $handler = $this->handler;
613 $where = $query->expr->lAnd(
614 $where,
615 $query->expr->lAnd(
616 array_map(
617 function ($pathString) use ($query, $handler) {
618 return $query->expr->not(
619 $query->expr->like(
620 $handler->quoteColumn('path_string'),
621 $query->bindValue($pathString . '%')
622 )
623 );
624 },
625 $hiddenSubtrees
626 )
627 )
628 );
629 }
630 $query->where($where);
631 $query->prepare()->execute();
632 }
633
639 public function setNodeUnhidden(string $pathString): void
640 {
641 $this->setNodeHiddenStatus($pathString, false);
642 }
643
655 public function swap(int $locationId1, int $locationId2): bool
656 {
657 $queryBuilder = $this->connection->createQueryBuilder();
658 $expr = $queryBuilder->expr();
659 $queryBuilder
660 ->select('node_id', 'main_node_id', 'contentobject_id', 'contentobject_version')
661 ->from('ezcontentobject_tree')
662 ->where(
663 $expr->in(
664 'node_id',
665 ':locationIds'
666 )
667 )
668 ->setParameter('locationIds', [$locationId1, $locationId2], Connection::PARAM_INT_ARRAY)
669 ;
670 $statement = $queryBuilder->execute();
671 $contentObjects = [];
672 foreach ($statement->fetchAll(FetchMode::ASSOCIATIVE) as $row) {
673 $row['is_main_node'] = (int)$row['main_node_id'] === (int)$row['node_id'];
674 $contentObjects[$row['node_id']] = $row;
675 }
676
677 if (!isset($contentObjects[$locationId1], $contentObjects[$locationId2])) {
678 throw new RuntimeException(
679 sprintf(
680 '%s: failed to fetch either Location %d or Location %d',
681 __METHOD__,
682 $locationId1,
683 $locationId2
684 )
685 );
686 }
687 $content1data = $contentObjects[$locationId1];
688 $content2data = $contentObjects[$locationId2];
689
690 $queryBuilder = $this->connection->createQueryBuilder();
691 $queryBuilder
692 ->update('ezcontentobject_tree')
693 ->set('contentobject_id', ':contentId')
694 ->set('contentobject_version', ':versionNo')
695 ->set('main_node_id', ':mainNodeId')
696 ->where(
697 $expr->eq('node_id', ':locationId')
698 );
699
700 $queryBuilder
701 ->setParameter(':contentId', $content2data['contentobject_id'])
702 ->setParameter(':versionNo', $content2data['contentobject_version'])
703 ->setParameter(
704 ':mainNodeId',
705 // make main Location main again, preserve main Location id of non-main one
706 $content2data['is_main_node']
707 ? $content1data['node_id']
708 : $content2data['main_node_id']
709 )
710 ->setParameter('locationId', $locationId1);
711
712 // update Location 1 entry
713 $queryBuilder->execute();
714
715 $queryBuilder
716 ->setParameter(':contentId', $content1data['contentobject_id'])
717 ->setParameter(':versionNo', $content1data['contentobject_version'])
718 ->setParameter(
719 ':mainNodeId',
720 $content1data['is_main_node']
721 // make main Location main again, preserve main Location id of non-main one
722 ? $content2data['node_id']
723 : $content1data['main_node_id']
724 )
725 ->setParameter('locationId', $locationId2);
726
727 // update Location 2 entry
728 $queryBuilder->execute();
729
730 return true;
731 }
732
741 public function create(CreateStruct $createStruct, array $parentNode)
742 {
743 $location = new Location();
745 $query = $this->handler->createInsertQuery();
746 $query
747 ->insertInto($this->handler->quoteTable('ezcontentobject_tree'))
748 ->set(
749 $this->handler->quoteColumn('contentobject_id'),
750 $query->bindValue($location->contentId = $createStruct->contentId, null, \PDO::PARAM_INT)
751 )->set(
752 $this->handler->quoteColumn('contentobject_is_published'),
753 $query->bindValue(1, null, \PDO::PARAM_INT)
754 )->set(
755 $this->handler->quoteColumn('contentobject_version'),
756 $query->bindValue($createStruct->contentVersion, null, \PDO::PARAM_INT)
757 )->set(
758 $this->handler->quoteColumn('depth'),
759 $query->bindValue($location->depth = $parentNode['depth'] + 1, null, \PDO::PARAM_INT)
760 )->set(
761 $this->handler->quoteColumn('is_hidden'),
762 $query->bindValue($location->hidden = $createStruct->hidden, null, \PDO::PARAM_INT)
763 )->set(
764 $this->handler->quoteColumn('is_invisible'),
765 $query->bindValue($location->invisible = $createStruct->invisible, null, \PDO::PARAM_INT)
766 )->set(
767 $this->handler->quoteColumn('modified_subnode'),
768 $query->bindValue(time(), null, \PDO::PARAM_INT)
769 )->set(
770 $this->handler->quoteColumn('node_id'),
771 $this->handler->getAutoIncrementValue('ezcontentobject_tree', 'node_id')
772 )->set(
773 $this->handler->quoteColumn('parent_node_id'),
774 $query->bindValue($location->parentId = $parentNode['node_id'], null, \PDO::PARAM_INT)
775 )->set(
776 $this->handler->quoteColumn('path_identification_string'),
777 $query->bindValue($location->pathIdentificationString = $createStruct->pathIdentificationString, null, \PDO::PARAM_STR)
778 )->set(
779 $this->handler->quoteColumn('path_string'),
780 $query->bindValue('dummy') // Set later
781 )->set(
782 $this->handler->quoteColumn('priority'),
783 $query->bindValue($location->priority = $createStruct->priority, null, \PDO::PARAM_INT)
784 )->set(
785 $this->handler->quoteColumn('remote_id'),
786 $query->bindValue($location->remoteId = $createStruct->remoteId, null, \PDO::PARAM_STR)
787 )->set(
788 $this->handler->quoteColumn('sort_field'),
789 $query->bindValue($location->sortField = $createStruct->sortField, null, \PDO::PARAM_INT)
790 )->set(
791 $this->handler->quoteColumn('sort_order'),
792 $query->bindValue($location->sortOrder = $createStruct->sortOrder, null, \PDO::PARAM_INT)
793 );
794 $query->prepare()->execute();
795
796 $location->id = (int)$this->handler->lastInsertId($this->handler->getSequenceName('ezcontentobject_tree', 'node_id'));
797
798 $mainLocationId = $createStruct->mainLocationId === true ? $location->id : $createStruct->mainLocationId;
799 $location->pathString = $parentNode['path_string'] . $location->id . '/';
801 $query = $this->handler->createUpdateQuery();
802 $query
803 ->update($this->handler->quoteTable('ezcontentobject_tree'))
804 ->set(
805 $this->handler->quoteColumn('path_string'),
806 $query->bindValue($location->pathString)
807 )
808 ->set(
809 $this->handler->quoteColumn('main_node_id'),
810 $query->bindValue($mainLocationId, null, \PDO::PARAM_INT)
811 )
812 ->where(
813 $query->expr->eq(
814 $this->handler->quoteColumn('node_id'),
815 $query->bindValue($location->id, null, \PDO::PARAM_INT)
816 )
817 );
818 $query->prepare()->execute();
819
820 return $location;
821 }
822
830 public function createNodeAssignment(CreateStruct $createStruct, $parentNodeId, $type = self::NODE_ASSIGNMENT_OP_CODE_CREATE_NOP)
831 {
832 $isMain = ($createStruct->mainLocationId === true ? 1 : 0);
833
834 $query = $this->handler->createInsertQuery();
835 $query
836 ->insertInto($this->handler->quoteTable('eznode_assignment'))
837 ->set(
838 $this->handler->quoteColumn('contentobject_id'),
839 $query->bindValue($createStruct->contentId, null, \PDO::PARAM_INT)
840 )->set(
841 $this->handler->quoteColumn('contentobject_version'),
842 $query->bindValue($createStruct->contentVersion, null, \PDO::PARAM_INT)
843 )->set(
844 $this->handler->quoteColumn('from_node_id'),
845 $query->bindValue(0, null, \PDO::PARAM_INT) // unused field
846 )->set(
847 $this->handler->quoteColumn('id'),
848 $this->handler->getAutoIncrementValue('eznode_assignment', 'id')
849 )->set(
850 $this->handler->quoteColumn('is_main'),
851 $query->bindValue($isMain, null, \PDO::PARAM_INT) // Changed by the business layer, later
852 )->set(
853 $this->handler->quoteColumn('op_code'),
854 $query->bindValue($type, null, \PDO::PARAM_INT)
855 )->set(
856 $this->handler->quoteColumn('parent_node'),
857 $query->bindValue($parentNodeId, null, \PDO::PARAM_INT)
858 )->set(
859 // parent_remote_id column should contain the remote id of the corresponding Location
860 $this->handler->quoteColumn('parent_remote_id'),
861 $query->bindValue($createStruct->remoteId, null, \PDO::PARAM_STR)
862 )->set(
863 // remote_id column should contain the remote id of the node assignment itself,
864 // however this was never implemented completely in Legacy Stack, so we just set
865 // it to default value '0'
866 $this->handler->quoteColumn('remote_id'),
867 $query->bindValue('0', null, \PDO::PARAM_STR)
868 )->set(
869 $this->handler->quoteColumn('sort_field'),
870 $query->bindValue($createStruct->sortField, null, \PDO::PARAM_INT)
871 )->set(
872 $this->handler->quoteColumn('sort_order'),
873 $query->bindValue($createStruct->sortOrder, null, \PDO::PARAM_INT)
874 )->set(
875 $this->handler->quoteColumn('priority'),
876 $query->bindValue($createStruct->priority, null, \PDO::PARAM_INT)
877 )->set(
878 $this->handler->quoteColumn('is_hidden'),
879 $query->bindValue($createStruct->hidden, null, \PDO::PARAM_INT)
880 );
881 $query->prepare()->execute();
882 }
883
892 public function deleteNodeAssignment($contentId, $versionNo = null)
893 {
894 $query = $this->handler->createDeleteQuery();
895 $query->deleteFrom(
896 'eznode_assignment'
897 )->where(
898 $query->expr->eq(
899 $this->handler->quoteColumn('contentobject_id'),
900 $query->bindValue($contentId, null, \PDO::PARAM_INT)
901 )
902 );
903 if (isset($versionNo)) {
904 $query->where(
905 $query->expr->eq(
906 $this->handler->quoteColumn('contentobject_version'),
907 $query->bindValue($versionNo, null, \PDO::PARAM_INT)
908 )
909 );
910 }
911 $query->prepare()->execute();
912 }
913
922 public function updateNodeAssignment($contentObjectId, $oldParent, $newParent, $opcode)
923 {
924 $query = $this->handler->createUpdateQuery();
925 $query
926 ->update($this->handler->quoteTable('eznode_assignment'))
927 ->set(
928 $this->handler->quoteColumn('parent_node'),
929 $query->bindValue($newParent, null, \PDO::PARAM_INT)
930 )
931 ->set(
932 $this->handler->quoteColumn('op_code'),
933 $query->bindValue($opcode, null, \PDO::PARAM_INT)
934 )
935 ->where(
936 $query->expr->lAnd(
937 $query->expr->eq(
938 $this->handler->quoteColumn('contentobject_id'),
939 $query->bindValue($contentObjectId, null, \PDO::PARAM_INT)
940 ),
941 $query->expr->eq(
942 $this->handler->quoteColumn('parent_node'),
943 $query->bindValue($oldParent, null, \PDO::PARAM_INT)
944 )
945 )
946 );
947 $query->prepare()->execute();
948 }
949
958 public function createLocationsFromNodeAssignments($contentId, $versionNo)
959 {
960 // select all node assignments with OP_CODE_CREATE (3) for this content
961 $query = $this->handler->createSelectQuery();
962 $query
963 ->select('*')
964 ->from($this->handler->quoteTable('eznode_assignment'))
965 ->where(
966 $query->expr->lAnd(
967 $query->expr->eq(
968 $this->handler->quoteColumn('contentobject_id'),
969 $query->bindValue($contentId, null, \PDO::PARAM_INT)
970 ),
971 $query->expr->eq(
972 $this->handler->quoteColumn('contentobject_version'),
973 $query->bindValue($versionNo, null, \PDO::PARAM_INT)
974 ),
975 $query->expr->eq(
976 $this->handler->quoteColumn('op_code'),
977 $query->bindValue(self::NODE_ASSIGNMENT_OP_CODE_CREATE, null, \PDO::PARAM_INT)
978 )
979 )
980 )->orderBy('id');
981 $statement = $query->prepare();
982 $statement->execute();
983
984 // convert all these assignments to nodes
985
986 while ($row = $statement->fetch(\PDO::FETCH_ASSOC)) {
987 if ((bool)$row['is_main'] === true) {
988 $mainLocationId = true;
989 } else {
990 $mainLocationId = $this->getMainNodeId($contentId);
991 }
992
993 $parentLocationData = $this->getBasicNodeData($row['parent_node']);
994 $isInvisible = $row['is_hidden'] || $parentLocationData['is_hidden'] || $parentLocationData['is_invisible'];
995 $this->create(
996 new CreateStruct(
997 [
998 'contentId' => $row['contentobject_id'],
999 'contentVersion' => $row['contentobject_version'],
1000 'mainLocationId' => $mainLocationId,
1001 'remoteId' => $row['parent_remote_id'],
1002 'sortField' => $row['sort_field'],
1003 'sortOrder' => $row['sort_order'],
1004 'priority' => $row['priority'],
1005 'hidden' => $row['is_hidden'],
1006 'invisible' => $isInvisible,
1007 ]
1008 ),
1009 $parentLocationData
1010 );
1011
1012 $this->updateNodeAssignment(
1013 $row['contentobject_id'],
1014 $row['parent_node'],
1015 $row['parent_node'],
1016 self::NODE_ASSIGNMENT_OP_CODE_CREATE_NOP
1017 );
1018 }
1019 }
1020
1027 public function updateLocationsContentVersionNo($contentId, $versionNo)
1028 {
1029 $query = $this->handler->createUpdateQuery();
1030 $query->update(
1031 $this->handler->quoteTable('ezcontentobject_tree')
1032 )->set(
1033 $this->handler->quoteColumn('contentobject_version'),
1034 $query->bindValue($versionNo, null, \PDO::PARAM_INT)
1035 )->where(
1036 $query->expr->eq(
1037 $this->handler->quoteColumn('contentobject_id'),
1038 $contentId
1039 )
1040 );
1041 $query->prepare()->execute();
1042 }
1043
1051 private function getMainNodeId($contentId)
1052 {
1053 $query = $this->handler->createSelectQuery();
1054 $query
1055 ->select('node_id')
1056 ->from($this->handler->quoteTable('ezcontentobject_tree'))
1057 ->where(
1058 $query->expr->lAnd(
1059 $query->expr->eq(
1060 $this->handler->quoteColumn('contentobject_id'),
1061 $query->bindValue($contentId, null, \PDO::PARAM_INT)
1062 ),
1063 $query->expr->eq(
1064 $this->handler->quoteColumn('node_id'),
1065 $this->handler->quoteColumn('main_node_id')
1066 )
1067 )
1068 );
1069 $statement = $query->prepare();
1070 $statement->execute();
1071
1072 $result = $statement->fetchAll(\PDO::FETCH_ASSOC);
1073 if (count($result) === 1) {
1074 return (int)$result[0]['node_id'];
1075 } else {
1076 return false;
1077 }
1078 }
1079
1088 public function update(UpdateStruct $location, $locationId)
1089 {
1090 $query = $this->handler->createUpdateQuery();
1091
1092 $query
1093 ->update($this->handler->quoteTable('ezcontentobject_tree'))
1094 ->set(
1095 $this->handler->quoteColumn('priority'),
1096 $query->bindValue($location->priority)
1097 )
1098 ->set(
1099 $this->handler->quoteColumn('remote_id'),
1100 $query->bindValue($location->remoteId)
1101 )
1102 ->set(
1103 $this->handler->quoteColumn('sort_order'),
1104 $query->bindValue($location->sortOrder)
1105 )
1106 ->set(
1107 $this->handler->quoteColumn('sort_field'),
1108 $query->bindValue($location->sortField)
1109 )
1110 ->where(
1111 $query->expr->eq(
1112 $this->handler->quoteColumn('node_id'),
1113 $locationId
1114 )
1115 );
1116 $statement = $query->prepare();
1117 $statement->execute();
1118
1119 // Commented due to EZP-23302: Update Location fails if no change is performed with the update
1120 // Should be fixed with PDO::MYSQL_ATTR_FOUND_ROWS instead
1121 /*if ( $statement->rowCount() < 1 )
1122 {
1123 throw new NotFound( 'location', $locationId );
1124 }*/
1125 }
1126
1134 public function updatePathIdentificationString($locationId, $parentLocationId, $text)
1135 {
1136 $parentData = $this->getBasicNodeData($parentLocationId);
1137
1138 $newPathIdentificationString = empty($parentData['path_identification_string']) ?
1139 $text :
1140 $parentData['path_identification_string'] . '/' . $text;
1141
1143 $query = $this->handler->createUpdateQuery();
1144 $query->update(
1145 'ezcontentobject_tree'
1146 )->set(
1147 $this->handler->quoteColumn('path_identification_string'),
1148 $query->bindValue($newPathIdentificationString, null, \PDO::PARAM_STR)
1149 )->where(
1150 $query->expr->eq(
1151 $this->handler->quoteColumn('node_id'),
1152 $query->bindValue($locationId, null, \PDO::PARAM_INT)
1153 )
1154 );
1155 $query->prepare()->execute();
1156 }
1157
1163 public function removeLocation($locationId)
1164 {
1165 $query = $this->handler->createDeleteQuery();
1166 $query->deleteFrom(
1167 'ezcontentobject_tree'
1168 )->where(
1169 $query->expr->eq(
1170 $this->handler->quoteColumn('node_id'),
1171 $query->bindValue($locationId, null, \PDO::PARAM_INT)
1172 )
1173 );
1174 $query->prepare()->execute();
1175 }
1176
1189 public function getFallbackMainNodeData($contentId, $locationId)
1190 {
1191 $query = $this->handler->createSelectQuery();
1192 $query->select(
1193 $this->handler->quoteColumn('node_id'),
1194 $this->handler->quoteColumn('contentobject_version'),
1195 $this->handler->quoteColumn('parent_node_id')
1196 )->from(
1197 $this->handler->quoteTable('ezcontentobject_tree')
1198 )->where(
1199 $query->expr->lAnd(
1200 $query->expr->eq(
1201 $this->handler->quoteColumn('contentobject_id'),
1202 $query->bindValue($contentId, null, \PDO::PARAM_INT)
1203 ),
1204 $query->expr->neq(
1205 $this->handler->quoteColumn('node_id'),
1206 $query->bindValue($locationId, null, \PDO::PARAM_INT)
1207 )
1208 )
1209 )->orderBy('node_id', SelectQuery::ASC)->limit(1);
1210 $statement = $query->prepare();
1211 $statement->execute();
1212
1213 return $statement->fetch(\PDO::FETCH_ASSOC);
1214 }
1215
1225 public function trashLocation($locationId)
1226 {
1227 $locationRow = $this->getBasicNodeData($locationId);
1228
1230 $query = $this->handler->createInsertQuery();
1231 $query->insertInto($this->handler->quoteTable('ezcontentobject_trash'));
1232
1233 unset($locationRow['contentobject_is_published']);
1234 $locationRow['trashed'] = time();
1235 foreach ($locationRow as $key => $value) {
1236 $query->set($key, $query->bindValue($value));
1237 }
1238
1239 $query->prepare()->execute();
1240
1241 $this->removeLocation($locationRow['node_id']);
1242 $this->setContentStatus($locationRow['contentobject_id'], ContentInfo::STATUS_TRASHED);
1243 }
1244
1258 public function untrashLocation($locationId, $newParentId = null)
1259 {
1260 $row = $this->loadTrashByLocation($locationId);
1261
1262 $newLocation = $this->create(
1263 new CreateStruct(
1264 [
1265 'priority' => $row['priority'],
1266 'hidden' => $row['is_hidden'],
1267 'invisible' => $row['is_invisible'],
1268 'remoteId' => $row['remote_id'],
1269 'contentId' => $row['contentobject_id'],
1270 'contentVersion' => $row['contentobject_version'],
1271 'mainLocationId' => true, // Restored location is always main location
1272 'sortField' => $row['sort_field'],
1273 'sortOrder' => $row['sort_order'],
1274 ]
1275 ),
1276 $this->getBasicNodeData($newParentId ?: $row['parent_node_id'])
1277 );
1278
1279 $this->removeElementFromTrash($locationId);
1280 $this->setContentStatus($row['contentobject_id'], ContentInfo::STATUS_PUBLISHED);
1281
1282 return $newLocation;
1283 }
1284
1289 protected function setContentStatus($contentId, $status)
1290 {
1292 $query = $this->handler->createUpdateQuery();
1293 $query->update(
1294 'ezcontentobject'
1295 )->set(
1296 $this->handler->quoteColumn('status'),
1297 $query->bindValue($status, null, \PDO::PARAM_INT)
1298 )->where(
1299 $query->expr->eq(
1300 $this->handler->quoteColumn('id'),
1301 $query->bindValue($contentId, null, \PDO::PARAM_INT)
1302 )
1303 );
1304 $query->prepare()->execute();
1305 }
1306
1314 public function loadTrashByLocation($locationId)
1315 {
1316 $query = $this->handler->createSelectQuery();
1317 $query
1318 ->select('*')
1319 ->from($this->handler->quoteTable('ezcontentobject_trash'))
1320 ->where(
1321 $query->expr->eq(
1322 $this->handler->quoteColumn('node_id'),
1323 $query->bindValue($locationId)
1324 )
1325 );
1326 $statement = $query->prepare();
1327 $statement->execute();
1328
1329 if ($row = $statement->fetch(\PDO::FETCH_ASSOC)) {
1330 return $row;
1331 }
1332
1333 throw new NotFound('trash', $locationId);
1334 }
1335
1345 public function listTrashed($offset, $limit, array $sort = null)
1346 {
1347 $query = $this->handler->createSelectQuery();
1348 $query
1349 ->select('*')
1350 ->from($this->handler->quoteTable('ezcontentobject_trash'));
1351
1352 $sort = $sort ?: [];
1353 foreach ($sort as $condition) {
1354 $sortDirection = $condition->direction === Query::SORT_ASC ? SelectQuery::ASC : SelectQuery::DESC;
1355 switch (true) {
1356 case $condition instanceof SortClause\Location\Depth:
1357 $query->orderBy('depth', $sortDirection);
1358 break;
1359
1360 case $condition instanceof SortClause\Location\Path:
1361 $query->orderBy('path_string', $sortDirection);
1362 break;
1363
1364 case $condition instanceof SortClause\Location\Priority:
1365 $query->orderBy('priority', $sortDirection);
1366 break;
1367
1368 case $condition instanceof SortClause\Trash\DateTrashed:
1369 $query->orderBy('trashed', $sortDirection);
1370 break;
1371
1372 default:
1373 // Only handle location related sort clauses. The others
1374 // require data aggregation which is not sensible here.
1375 // Since also criteria are yet ignored, because they are
1376 // simply not used yet in eZ Publish, we skip that for now.
1377 throw new RuntimeException('Unhandled sort clause: ' . get_class($condition));
1378 }
1379 }
1380
1381 if ($limit !== null) {
1382 $query->limit($limit, $offset);
1383 }
1384
1385 $statement = $query->prepare();
1386 $statement->execute();
1387
1388 $rows = [];
1389 while ($row = $statement->fetch(\PDO::FETCH_ASSOC)) {
1390 $rows[] = $row;
1391 }
1392
1393 return $rows;
1394 }
1395
1396 public function countTrashed(): int
1397 {
1398 $dbPlatform = $this->connection->getDatabasePlatform();
1399 $query = $this->connection->createQueryBuilder()
1400 ->select($dbPlatform->getCountExpression('node_id'))
1401 ->from('ezcontentobject_trash');
1402
1403 return $query->execute()->fetchColumn();
1404 }
1405
1412 public function cleanupTrash()
1413 {
1414 $query = $this->handler->createDeleteQuery();
1415 $query->deleteFrom('ezcontentobject_trash');
1416 $query->prepare()->execute();
1417 }
1418
1425 public function removeElementFromTrash($id)
1426 {
1427 $query = $this->handler->createDeleteQuery();
1428 $query
1429 ->deleteFrom('ezcontentobject_trash')
1430 ->where(
1431 $query->expr->eq(
1432 $this->handler->quoteColumn('node_id'),
1433 $query->bindValue($id, null, \PDO::PARAM_INT)
1434 )
1435 );
1436 $query->prepare()->execute();
1437 }
1438
1447 public function setSectionForSubtree($pathString, $sectionId)
1448 {
1449 $selectContentIdsQuery = $this->connection->createQueryBuilder();
1450 $selectContentIdsQuery
1451 ->select('t.contentobject_id')
1452 ->from('ezcontentobject_tree', 't')
1453 ->where(
1454 $selectContentIdsQuery->expr()->like(
1455 't.path_string',
1456 $selectContentIdsQuery->createPositionalParameter("{$pathString}%")
1457 )
1458 );
1459
1460 $contentIds = array_map(
1461 'intval',
1462 $selectContentIdsQuery->execute()->fetchAll(PDO::FETCH_COLUMN)
1463 );
1464
1465 if (empty($contentIds)) {
1466 return false;
1467 }
1468
1469 $updateSectionQuery = $this->connection->createQueryBuilder();
1470 $updateSectionQuery
1471 ->update('ezcontentobject')
1472 ->set(
1473 'section_id',
1474 $updateSectionQuery->createPositionalParameter($sectionId, PDO::PARAM_INT)
1475 )
1476 ->where(
1477 $updateSectionQuery->expr()->in(
1478 'id',
1479 $contentIds
1480 )
1481 );
1482 $affectedRows = $updateSectionQuery->execute();
1483
1484 return $affectedRows > 0;
1485 }
1486
1494 public function countLocationsByContentId($contentId)
1495 {
1496 $q = $this->handler->createSelectQuery();
1497 $q
1498 ->select(
1499 $q->alias($q->expr->count('*'), 'count')
1500 )
1501 ->from($this->handler->quoteTable('ezcontentobject_tree'))
1502 ->where(
1503 $q->expr->eq(
1504 $this->handler->quoteColumn('contentobject_id'),
1505 $q->bindValue($contentId, null, \PDO::PARAM_INT)
1506 )
1507 );
1508 $stmt = $q->prepare();
1509 $stmt->execute();
1510 $res = $stmt->fetchAll(\PDO::FETCH_ASSOC);
1511
1512 return (int)$res[0]['count'];
1513 }
1514
1527 public function changeMainLocation($contentId, $locationId, $versionNo, $parentLocationId)
1528 {
1529 // Update ezcontentobject_tree table
1530 $q = $this->handler->createUpdateQuery();
1531 $q->update(
1532 $this->handler->quoteTable('ezcontentobject_tree')
1533 )->set(
1534 $this->handler->quoteColumn('main_node_id'),
1535 $q->bindValue($locationId, null, \PDO::PARAM_INT)
1536 )->where(
1537 $q->expr->eq(
1538 $this->handler->quoteColumn('contentobject_id'),
1539 $q->bindValue($contentId, null, \PDO::PARAM_INT)
1540 )
1541 );
1542 $q->prepare()->execute();
1543
1544 // Erase is_main in eznode_assignment table
1545 $q = $this->handler->createUpdateQuery();
1546 $q->update(
1547 $this->handler->quoteTable('eznode_assignment')
1548 )->set(
1549 $this->handler->quoteColumn('is_main'),
1550 $q->bindValue(0, null, \PDO::PARAM_INT)
1551 )->where(
1552 $q->expr->lAnd(
1553 $q->expr->eq(
1554 $this->handler->quoteColumn('contentobject_id'),
1555 $q->bindValue($contentId, null, \PDO::PARAM_INT)
1556 ),
1557 $q->expr->eq(
1558 $this->handler->quoteColumn('contentobject_version'),
1559 $q->bindValue($versionNo, null, \PDO::PARAM_INT)
1560 ),
1561 $q->expr->neq(
1562 $this->handler->quoteColumn('parent_node'),
1563 $q->bindValue($parentLocationId, null, \PDO::PARAM_INT)
1564 )
1565 )
1566 );
1567 $q->prepare()->execute();
1568
1569 // Set new is_main in eznode_assignment table
1570 $q = $this->handler->createUpdateQuery();
1571 $q->update(
1572 $this->handler->quoteTable('eznode_assignment')
1573 )->set(
1574 $this->handler->quoteColumn('is_main'),
1575 $q->bindValue(1, null, \PDO::PARAM_INT)
1576 )->where(
1577 $q->expr->lAnd(
1578 $q->expr->eq(
1579 $this->handler->quoteColumn('contentobject_id'),
1580 $q->bindValue($contentId, null, \PDO::PARAM_INT)
1581 ),
1582 $q->expr->eq(
1583 $this->handler->quoteColumn('contentobject_version'),
1584 $q->bindValue($versionNo, null, \PDO::PARAM_INT)
1585 ),
1586 $q->expr->eq(
1587 $this->handler->quoteColumn('parent_node'),
1588 $q->bindValue($parentLocationId, null, \PDO::PARAM_INT)
1589 )
1590 )
1591 );
1592 $q->prepare()->execute();
1593 }
1594
1602 public function countAllLocations()
1603 {
1604 $query = $this->getAllLocationsQueryBuilder(['count(node_id)']);
1605
1606 $statement = $query->execute();
1607
1608 return (int) $statement->fetch(PDO::FETCH_COLUMN);
1609 }
1610
1619 public function loadAllLocationsData($offset, $limit)
1620 {
1621 $query = $this
1622 ->getAllLocationsQueryBuilder(
1623 [
1624 'node_id',
1625 'priority',
1626 'is_hidden',
1627 'is_invisible',
1628 'remote_id',
1629 'contentobject_id',
1630 'parent_node_id',
1631 'path_identification_string',
1632 'path_string',
1633 'depth',
1634 'sort_field',
1635 'sort_order',
1636 ]
1637 )
1638 ->setFirstResult($offset)
1639 ->setMaxResults($limit)
1640 ->orderBy('depth', 'ASC')
1641 ->addOrderBy('node_id', 'ASC')
1642 ;
1643
1644 $statement = $query->execute();
1645
1646 return $statement->fetchAll(PDO::FETCH_ASSOC);
1647 }
1648
1658 private function getAllLocationsQueryBuilder(array $columns)
1659 {
1660 $query = $this->connection->createQueryBuilder();
1661 $query
1662 ->select($columns)
1663 ->from('ezcontentobject_tree')
1664 ->where($query->expr()->neq('node_id', 'parent_node_id'))
1665 ;
1666
1667 return $query;
1668 }
1669
1678 private function createNodeQueryBuilder(array $translations = null, bool $useAlwaysAvailable = true): QueryBuilder
1679 {
1680 $queryBuilder = $this->connection->createQueryBuilder();
1681 $queryBuilder
1682 ->select('t.*')
1683 ->from('ezcontentobject_tree', 't');
1684
1685 if (!empty($translations)) {
1686 $dbPlatform = $this->connection->getDatabasePlatform();
1687 $expr = $queryBuilder->expr();
1688 $mask = $this->languageMaskGenerator->generateLanguageMaskFromLanguageCodes(
1689 $translations,
1690 $useAlwaysAvailable
1691 );
1692
1693 $queryBuilder->leftJoin(
1694 't',
1695 'ezcontentobject',
1696 'c',
1697 $expr->eq('t.contentobject_id', 'c.id')
1698 );
1699
1700 $queryBuilder->where(
1701 $expr->orX(
1702 $expr->gt(
1703 $dbPlatform->getBitAndComparisonExpression('c.language_mask', $mask),
1704 0
1705 ),
1706 // Root location doesn't have language mask
1707 $expr->eq(
1708 't.node_id', 't.parent_node_id'
1709 )
1710 )
1711 );
1712 }
1713
1714 return $queryBuilder;
1715 }
1716 }
eZ\Publish\API\Repository\Values\Content\Query\SortClause\Location
This is the base for Location SortClause classes, used to set sorting of Location queries.
Definition: API/Repository/Values/Content/Query/SortClause/Location.php:15
eZ\Publish\API\Repository\Values\Content\Query
This class is used to perform a Content query.
Definition: API/Repository/Values/Content/Query.php:15
eZ\Publish\Core\Base\Exceptions\NotFoundException
Not Found Exception implementation.
Definition: Core/Base/Exceptions/NotFoundException.php:21
eZ\Publish\Core\Persistence\Legacy\Content\Language\MaskGenerator
Language MaskGenerator.
Definition: MaskGenerator.php:16
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase
Location gateway implementation using the Doctrine database.
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:31
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\$handler
$handler
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:43
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\hideSubtree
hideSubtree($pathString)
Sets a location to be hidden, and it self + all children to invisible.
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:449
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\updateLocationsContentVersionNo
updateLocationsContentVersionNo($contentId, $versionNo)
Updates all Locations of content identified with $contentId with $versionNo.
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:1027
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\countLocationsByContentId
countLocationsByContentId($contentId)
Returns how many locations given content object identified by $contentId has.
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:1494
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\getFallbackMainNodeData
getFallbackMainNodeData($contentId, $locationId)
Returns id of the next in line node to be set as a new main node.
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:1189
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\deleteNodeAssignment
deleteNodeAssignment($contentId, $versionNo=null)
Deletes node assignment for given $contentId and $versionNo.
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:892
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\getBasicNodeData
getBasicNodeData($nodeId, array $translations=null, bool $useAlwaysAvailable=true)
{Returns an array with basic node data.}
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:71
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\__construct
__construct(DatabaseHandler $handler, MaskGenerator $languageMaskGenerator)
Construct from database handler.
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:61
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\getAllLocationsQueryBuilder
getAllLocationsQueryBuilder(array $columns)
Get Query Builder for fetching data of all Locations except the Root node.
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:1658
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\getMainNodeId
getMainNodeId($contentId)
Searches for the main nodeId of $contentId in $versionId.
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:1051
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\loadAllLocationsData
loadAllLocationsData($offset, $limit)
Load data of every Location, except the Root node.
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:1619
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\loadLocationDataByContent
loadLocationDataByContent($contentId, $rootLocationId=null)
Loads data for all Locations for $contentId, optionally only in the subtree starting at $rootLocation...
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:127
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\updateNodeAssignment
updateNodeAssignment($contentObjectId, $oldParent, $newParent, $opcode)
Update node assignment table.
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:922
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\$languageMaskGenerator
$languageMaskGenerator
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:53
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\removeLocation
removeLocation($locationId)
Deletes ezcontentobject_tree row for given $locationId (node_id).
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:1163
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\listTrashed
listTrashed($offset, $limit, array $sort=null)
List trashed items.
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:1345
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\loadTrashByLocation
loadTrashByLocation($locationId)
Loads trash data specified by location ID.
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:1314
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\getBasicNodeDataByRemoteId
getBasicNodeDataByRemoteId($remoteId, array $translations=null, bool $useAlwaysAvailable=true)
{Returns an array with basic node data for the node with $remoteId.}
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:104
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\isHiddenByParent
isHiddenByParent($pathString, array $rows)
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:404
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\setNodeUnhidden
setNodeUnhidden(string $pathString)
Sets location to be unhidden.
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:639
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\removeElementFromTrash
removeElementFromTrash($id)
Removes trashed element identified by $id from trash.
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:1425
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\getChildren
getChildren($locationId)
Returns data for the first level children of the location identified by given $locationId.
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:277
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\countAllLocations
countAllLocations()
Get the total number of all Locations, except the Root node.
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:1602
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\createNodeAssignment
createNodeAssignment(CreateStruct $createStruct, $parentNodeId, $type=self::NODE_ASSIGNMENT_OP_CODE_CREATE_NOP)
Create an entry in the node assignment table.
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:830
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\getSubtreeContent
getSubtreeContent($sourceId, $onlyIds=false)
Find all content in the given subtree.
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:230
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\update
update(UpdateStruct $location, $locationId)
Updates an existing location.
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:1088
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\cleanupTrash
cleanupTrash()
Removes every entries in the trash.
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:1412
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\setSectionForSubtree
setSectionForSubtree($pathString, $sectionId)
Set section on all content objects in the subtree.
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:1447
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\changeMainLocation
changeMainLocation($contentId, $locationId, $versionNo, $parentLocationId)
Changes main location of content identified by given $contentId to location identified by given $loca...
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:1527
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\createLocationsFromNodeAssignments
createLocationsFromNodeAssignments($contentId, $versionNo)
Create locations from node assignments.
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:958
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\unHideSubtree
unHideSubtree($pathString)
Sets a location to be unhidden, and self + children to visible unless a parent is hiding the tree.
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:518
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\MAX_LIMIT
const MAX_LIMIT
2^30, since PHP_INT_MAX can cause overflows in DB systems, if PHP is run on 64 bit systems.
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:36
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\countTrashed
countTrashed()
Count trashed items.
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:1396
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\getNodeDataList
getNodeDataList(array $locationIds, array $translations=null, bool $useAlwaysAvailable=true)
{Returns an array with node data for several locations.Respect always available flag on content when ...
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:88
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\setNodeWithChildrenInvisible
setNodeWithChildrenInvisible(string $pathString)
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:458
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\setNodeHidden
setNodeHidden(string $pathString)
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:484
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\createNodeQueryBuilder
createNodeQueryBuilder(array $translations=null, bool $useAlwaysAvailable=true)
Create QueryBuilder for selecting node data.
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:1678
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\untrashLocation
untrashLocation($locationId, $newParentId=null)
Returns a trashed location to normal state.
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:1258
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\applySubtreeLimitation
applySubtreeLimitation(DatabaseQuery $query, $rootLocationId, string $tableName='ezcontentobject_tree')
Limits the given $query to the subtree starting at $rootLocationId.
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:257
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\setNodeWithChildrenVisible
setNodeWithChildrenVisible(string $pathString)
Sets a location + children to visible unless a parent is hiding the tree.
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:529
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\swap
swap(int $locationId1, int $locationId2)
Swaps the content object being pointed to by a location object.
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:655
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\setNodeHiddenStatus
setNodeHiddenStatus(string $pathString, bool $isHidden)
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:493
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\loadLocationDataByTrashContent
loadLocationDataByTrashContent(int $contentId, ?int $rootLocationId=null)
{Loads data for all Locations for $contentId in trash, optionally only in the subtree starting at $ro...
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:151
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\updateSubtreeModificationTime
updateSubtreeModificationTime($pathString, $timestamp=null)
Updated subtree modification time for all nodes on path.
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:423
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\DoctrineDatabase\$connection
$connection
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:46
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway
Base class for location gateways.
Definition: Persistence/Legacy/Content/Location/Gateway.php:16
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\trashLocation
trashLocation($locationId)
Sends a single location identified by given $locationId to the trash.
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\loadTrashByLocation
loadTrashByLocation($locationId)
Loads trash data specified by location ID.
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\setNodeWithChildrenVisible
setNodeWithChildrenVisible(string $pathString)
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\create
create(CreateStruct $createStruct, array $parentNode)
Creates a new location in given $parentNode.
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\removeLocation
removeLocation($locationId)
Deletes ezcontentobject_tree row for given $locationId (node_id).
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\setNodeWithChildrenInvisible
setNodeWithChildrenInvisible(string $pathString)
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\moveSubtreeNodes
moveSubtreeNodes(array $fromPathString, array $toPathString)
Update path strings to move nodes in the ezcontentobject_tree table.
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\loadParentLocationsDataForDraftContent
loadParentLocationsDataForDraftContent($contentId)
Loads data for all parent Locations for unpublished Content by given $contentId.
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\getBasicNodeData
getBasicNodeData($nodeId, array $translations=null, bool $useAlwaysAvailable=true)
Returns an array with basic node data.
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\setNodeHidden
setNodeHidden(string $pathString)
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\updatePathIdentificationString
updatePathIdentificationString($locationId, $parentLocationId, $text)
Updates path identification string for given $locationId.
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\removeElementFromTrash
removeElementFromTrash($id)
Removes trashed element identified by $id from trash.
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\setNodeUnhidden
setNodeUnhidden(string $pathString)
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway\updateNodeAssignment
updateNodeAssignment($contentObjectId, $oldParent, $newParent, $opcode)
Update node assignment table.
eZ\Publish\SPI\Persistence\Content\ContentInfo
This class provides all version independent information of the content object.
Definition: SPI/Persistence/Content/ContentInfo.php:17
eZ\Publish\SPI\Persistence\Content\ContentInfo\STATUS_DRAFT
const STATUS_DRAFT
Definition: SPI/Persistence/Content/ContentInfo.php:18
eZ\Publish\SPI\Persistence\Content\ContentInfo\STATUS_TRASHED
const STATUS_TRASHED
Definition: SPI/Persistence/Content/ContentInfo.php:20
eZ\Publish\SPI\Persistence\Content\ContentInfo\STATUS_PUBLISHED
const STATUS_PUBLISHED
Definition: SPI/Persistence/Content/ContentInfo.php:19
eZ\Publish\SPI\Persistence\Content\Location\CreateStruct
Definition: SPI/Persistence/Content/Location/CreateStruct.php:12
eZ\Publish\SPI\Persistence\Content\Location\UpdateStruct
Definition: Content/Location/UpdateStruct.php:12
eZ\Publish\SPI\Persistence\Content\Location\$remoteId
$remoteId
Definition: SPI/Persistence/Content/Location.php:73
eZ\Publish\SPI\Persistence\Content\Location\$contentId
$contentId
Definition: SPI/Persistence/Content/Location.php:80
eZ\Publish\SPI\Persistence\Content\Location\$id
$id
Definition: SPI/Persistence/Content/Location.php:39
eZ\Publish\SPI\Persistence\Content\Location\$pathString
$pathString
Definition: SPI/Persistence/Content/Location.php:105
eZ\Publish\Core\Persistence\Database\DatabaseHandler
Interface for relational database abstractions supported by eZ.
Definition: DatabaseHandler.php:18
eZ\Publish\Core\Persistence\Database\Query
Definition: Core/Persistence/Database/Query.php:18
eZ\Publish\Core\Persistence\Database\SelectQuery
Definition: SelectQuery.php:16
eZ\Publish\API\Repository\Values\Content\Query\SortClause
Definition: API/Repository/Values/Content/Query/SortClause/ContentId.php:7
eZ\Publish\Core\Persistence\Legacy\Content\Location\Gateway
Definition: Persistence/Legacy/Content/Location/Gateway/DoctrineDatabase.php:7
eZ\Publish\SPI\Persistence\Content\Location
Definition: SPI/Persistence/Content/Location/CreateStruct.php:7
Copyright © 1998 – 2026 7x. All rights reserved. Licensed under the GNU GPLv2+.