‪TYPO3CMS  ‪main
ReferenceIndexUpdater.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
20 use TYPO3\CMS\Backend\Utility\BackendUtility;
25 
35 {
41  protected array ‪$updateRegistry = [];
42 
51  protected array ‪$updateRegistryToItem = [];
52 
58  protected array ‪$dropRegistry = [];
59 
67  public function ‪registerForUpdate(string $table, int ‪$uid, int $workspace): void
68  {
69  if ($workspace && !BackendUtility::isTableWorkspaceEnabled($table)) {
70  // If a user is in some workspace and changes relations of not workspace aware
71  // records, the reference index update needs to be performed as if the user
72  // is in live workspace. This is detected here and the update is registered for live.
73  $workspace = 0;
74  }
75  if (!isset($this->updateRegistry[$workspace][$table])) {
76  $this->updateRegistry[$workspace][$table] = [];
77  }
78  if (!in_array(‪$uid, $this->updateRegistry[$workspace][$table], true)) {
79  $this->updateRegistry[$workspace][$table][] = ‪$uid;
80  }
81  }
82 
94  public function ‪registerUpdateForReferencesToItem(string $table, int ‪$uid, int $workspace, int $targetWorkspace = null): void
95  {
96  if ($workspace && !BackendUtility::isTableWorkspaceEnabled($table)) {
97  // If a user is in some workspace and changes relations of not workspace aware
98  // records, the reference index update needs to be performed as if the user
99  // is in live workspace. This is detected here and the update is registered for live.
100  $workspace = 0;
101  }
102  if ($targetWorkspace === null) {
103  $targetWorkspace = $workspace;
104  }
105  if (!isset($this->updateRegistryToItem[$workspace][$table])) {
106  $this->updateRegistryToItem[$workspace][$table] = [];
107  }
108  $recordAndTargetWorkspace = [
109  'uid' => ‪$uid,
110  'targetWorkspace' => $targetWorkspace,
111  ];
112  if (!in_array($recordAndTargetWorkspace, $this->updateRegistryToItem[$workspace][$table], true)) {
113  $this->updateRegistryToItem[$workspace][$table][] = $recordAndTargetWorkspace;
114  }
115  }
116 
127  public function ‪registerForDrop(string $table, int ‪$uid, int $workspace): void
128  {
129  if ($workspace && !BackendUtility::isTableWorkspaceEnabled($table)) {
130  // If a user is in some workspace and changes relations of not workspace aware
131  // records, the reference index update needs to be performed as if the user
132  // is in live workspace. This is detected here and the update is registered for live.
133  $workspace = 0;
134  }
135  if (!isset($this->dropRegistry[$workspace][$table])) {
136  $this->dropRegistry[$workspace][$table] = [];
137  }
138  if (!in_array(‪$uid, $this->dropRegistry[$workspace][$table], true)) {
139  $this->dropRegistry[$workspace][$table][] = ‪$uid;
140  }
141  }
142 
146  public function ‪update(): void
147  {
148  // Register updates to an item for update
149  foreach ($this->updateRegistryToItem as $workspace => $tableArray) {
150  foreach ($tableArray as $table => $recordArray) {
151  foreach ($recordArray as $item) {
152  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_refindex');
153  $statement = $queryBuilder
154  ->select('tablename', 'recuid')
155  ->from('sys_refindex')
156  ->where(
157  $queryBuilder->expr()->eq('ref_table', $queryBuilder->createNamedParameter($table)),
158  $queryBuilder->expr()->eq('ref_uid', $queryBuilder->createNamedParameter($item['uid'], ‪Connection::PARAM_INT)),
159  $queryBuilder->expr()->eq('workspace', $queryBuilder->createNamedParameter($workspace, ‪Connection::PARAM_INT))
160  )
161  ->executeQuery();
162  while ($row = $statement->fetchAssociative()) {
163  $this->‪registerForUpdate($row['tablename'], (int)$row['recuid'], (int)$item['targetWorkspace']);
164  }
165  }
166  }
167  }
168  $this->updateRegistryToItem = [];
169 
170  // Drop rows from reference index if requested. Note this is performed *after* update-to-item, to
171  // find rows pointing to a record and register updates before rows are dropped. Needed if a record
172  // changes the workspace during publish: In this case all records pointing to the record in a workspace
173  // need to be registered for update for live workspace and after that the workspace rows can be dropped.
174  foreach ($this->dropRegistry as $workspace => $tableArray) {
175  foreach ($tableArray as $table => $uidArray) {
176  foreach ($uidArray as ‪$uid) {
177  $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('sys_refindex');
178  $queryBuilder->delete('sys_refindex')
179  ->where(
180  $queryBuilder->expr()->eq('workspace', $queryBuilder->createNamedParameter($workspace, ‪Connection::PARAM_INT)),
181  $queryBuilder->expr()->or(
182  $queryBuilder->expr()->and(
183  $queryBuilder->expr()->eq('tablename', $queryBuilder->createNamedParameter($table)),
184  $queryBuilder->expr()->eq('recuid', $queryBuilder->createNamedParameter(‪$uid, ‪Connection::PARAM_INT))
185  ),
186  $queryBuilder->expr()->and(
187  $queryBuilder->expr()->eq('ref_table', $queryBuilder->createNamedParameter($table)),
188  $queryBuilder->expr()->eq('ref_uid', $queryBuilder->createNamedParameter(‪$uid, ‪Connection::PARAM_INT))
189  )
190  )
191  )
192  ->executeStatement();
193  }
194  }
195  }
196  $this->dropRegistry = [];
197 
198  // Perform reference index updates
199  $referenceIndex = GeneralUtility::makeInstance(ReferenceIndex::class);
200  foreach ($this->updateRegistry as $workspace => $tableArray) {
201  foreach ($tableArray as $table => $uidArray) {
202  foreach ($uidArray as ‪$uid) {
203  $referenceIndex->updateRefIndexTable($table, ‪$uid, false, $workspace);
204  }
205  }
206  }
207  $this->updateRegistry = [];
208  }
209 }
‪TYPO3\CMS\Core\Database\Connection\PARAM_INT
‪const PARAM_INT
Definition: Connection.php:52
‪TYPO3\CMS\Core\DataHandling\ReferenceIndexUpdater\$updateRegistryToItem
‪array $updateRegistryToItem
Definition: ReferenceIndexUpdater.php:51
‪TYPO3\CMS\Core\Database\ReferenceIndex
Definition: ReferenceIndex.php:40
‪TYPO3\CMS\Core\DataHandling
Definition: DataHandler.php:16
‪TYPO3\CMS\Core\DataHandling\ReferenceIndexUpdater\registerForDrop
‪registerForDrop(string $table, int $uid, int $workspace)
Definition: ReferenceIndexUpdater.php:127
‪TYPO3\CMS\Core\DataHandling\ReferenceIndexUpdater\$dropRegistry
‪array $dropRegistry
Definition: ReferenceIndexUpdater.php:58
‪TYPO3\CMS\Core\DataHandling\ReferenceIndexUpdater\registerForUpdate
‪registerForUpdate(string $table, int $uid, int $workspace)
Definition: ReferenceIndexUpdater.php:67
‪TYPO3\CMS\Core\DataHandling\ReferenceIndexUpdater\registerUpdateForReferencesToItem
‪registerUpdateForReferencesToItem(string $table, int $uid, int $workspace, int $targetWorkspace=null)
Definition: ReferenceIndexUpdater.php:94
‪TYPO3\CMS\Core\DataHandling\ReferenceIndexUpdater\$updateRegistry
‪array $updateRegistry
Definition: ReferenceIndexUpdater.php:41
‪TYPO3\CMS\Core\Database\Connection
Definition: Connection.php:41
‪TYPO3\CMS\Webhooks\Message\$uid
‪identifier readonly int $uid
Definition: PageModificationMessage.php:35
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:46
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:52
‪TYPO3\CMS\Core\DataHandling\ReferenceIndexUpdater
Definition: ReferenceIndexUpdater.php:35
‪TYPO3\CMS\Core\DataHandling\ReferenceIndexUpdater\update
‪update()
Definition: ReferenceIndexUpdater.php:146