‪TYPO3CMS  9.5
BackendLayoutIconUpdateWizard.php
Go to the documentation of this file.
1 <?php
2 declare(strict_types = 1);
4 
17 use Doctrine\DBAL\DBALException;
18 use Psr\Log\LoggerAwareInterface;
19 use Psr\Log\LoggerAwareTrait;
20 use Symfony\Component\Console\Output\OutputInterface;
29 
36 {
37  use LoggerAwareTrait;
38 
42  protected ‪$output;
43 
47  protected ‪$storage;
48 
54  protected ‪$table = 'backend_layout';
55 
61  protected ‪$fieldToMigrate = 'icon';
62 
68  protected ‪$sourcePath = 'uploads/media/';
69 
76  protected ‪$targetPath = '_migrated/backend_layouts/';
77 
81  public function ‪getIdentifier(): string
82  {
83  return 'backendLayoutIcons';
84  }
85 
89  public function ‪getTitle(): string
90  {
91  return 'Migrate all file relations from backend_layout.icon to sys_file_references';
92  }
93 
97  public function ‪getDescription(): string
98  {
99  return 'This update wizard goes through all files that are referenced in the'
100  . ' backend_layout.icon field and adds the files to the FAL File Index.'
101  . ' It also moves the files from uploads/ to the fileadmin/_migrated/ path.';
102  }
103 
107  public function ‪updateNecessary(): bool
108  {
109  return !empty($this->‪getRecordsFromTable());
110  }
111 
115  public function ‪getPrerequisites(): array
116  {
117  return [
118  DatabaseUpdatedPrerequisite::class
119  ];
120  }
121 
125  public function ‪setOutput(OutputInterface ‪$output): void
126  {
127  $this->output = ‪$output;
128  }
129 
135  public function ‪executeUpdate(): bool
136  {
137  $result = true;
138  try {
139  $storages = GeneralUtility::makeInstance(StorageRepository::class)->findAll();
140  $this->storage = $storages[0];
141  $records = $this->‪getRecordsFromTable();
142  foreach ($records as $record) {
143  $this->‪migrateField($record);
144  }
145  } catch (\‪Exception $e) {
146  // If something goes wrong, migrateField() logs an error
147  $result = false;
148  }
149  return $result;
150  }
151 
159  protected function ‪getRecordsFromTable()
160  {
161  $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
162  $queryBuilder = $connectionPool->getQueryBuilderForTable($this->table);
163  $queryBuilder->getRestrictions()->removeAll();
164  try {
165  return $queryBuilder
166  ->select('uid', 'pid', $this->fieldToMigrate)
167  ->from($this->table)
168  ->where(
169  $queryBuilder->expr()->isNotNull($this->fieldToMigrate),
170  $queryBuilder->expr()->neq(
171  $this->fieldToMigrate,
172  $queryBuilder->createNamedParameter('', \PDO::PARAM_STR)
173  ),
174  $queryBuilder->expr()->comparison(
175  'CAST(CAST(' . $queryBuilder->quoteIdentifier($this->fieldToMigrate) . ' AS DECIMAL) AS CHAR)',
177  'CAST(' . $queryBuilder->quoteIdentifier($this->fieldToMigrate) . ' AS CHAR)'
178  )
179  )
180  ->orderBy('uid')
181  ->execute()
182  ->fetchAll();
183  } catch (DBALException $e) {
184  throw new \RuntimeException(
185  'Database query failed. Error was: ' . $e->getPrevious()->getMessage(),
186  1511950673
187  );
188  }
189  }
190 
197  protected function ‪migrateField($row)
198  {
199  $fieldItems = GeneralUtility::trimExplode(',', $row[$this->fieldToMigrate], true);
200  if (empty($fieldItems) || is_numeric($row[$this->fieldToMigrate])) {
201  return;
202  }
203  $fileadminDirectory = rtrim(‪$GLOBALS['TYPO3_CONF_VARS']['BE']['fileadminDir'], '/') . '/';
204  $i = 0;
205 
206  $storageUid = (int)$this->storage->getUid();
207  $connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
208 
209  foreach ($fieldItems as $item) {
210  $fileUid = null;
211  ‪$sourcePath = ‪Environment::getPublicPath() . '/' . $this->sourcePath . $item;
212  $targetDirectory = ‪Environment::getPublicPath() . '/' . $fileadminDirectory . ‪$this->targetPath;
213  ‪$targetPath = $targetDirectory . ‪PathUtility::basenameDuringBootstrap($item);
214 
215  // maybe the file was already moved, so check if the original file still exists
216  if (file_exists(‪$sourcePath)) {
217  if (!is_dir($targetDirectory)) {
218  GeneralUtility::mkdir_deep($targetDirectory);
219  }
220 
221  // see if the file already exists in the storage
222  $fileSha1 = sha1_file(‪$sourcePath);
223 
224  $queryBuilder = $connectionPool->getQueryBuilderForTable('sys_file');
225  $queryBuilder->getRestrictions()->removeAll();
226  $existingFileRecord = $queryBuilder->select('uid')->from('sys_file')->where(
227  $queryBuilder->expr()->eq(
228  'sha1',
229  $queryBuilder->createNamedParameter($fileSha1, \PDO::PARAM_STR)
230  ),
231  $queryBuilder->expr()->eq(
232  'storage',
233  $queryBuilder->createNamedParameter($storageUid, \PDO::PARAM_INT)
234  )
235  )->execute()->fetch();
236 
237  // the file exists, the file does not have to be moved again
238  if (is_array($existingFileRecord)) {
239  $fileUid = $existingFileRecord['uid'];
240  } else {
241  // just move the file (no duplicate)
243  }
244  }
245 
246  if ($fileUid === null) {
247  // get the File object if it hasn't been fetched before
248  try {
249  // if the source file does not exist, we should just continue, but leave a message in the docs;
250  // ideally, the user would be informed after the update as well.
252  $file = $this->storage->getFile($this->targetPath . $item);
253  $fileUid = $file->getUid();
254  } catch (\InvalidArgumentException $e) {
255  // no file found, no reference can be set
256  $this->logger->notice(
257  'File ' . $this->sourcePath . $item . ' does not exist. Reference was not migrated.',
258  [
259  'table' => $this->table,
260  'record' => $row,
261  'field' => $this->fieldToMigrate,
262  ]
263  );
264  $format = 'File \'%s\' does not exist. Referencing field: %s.%d.%s. The reference was not migrated.';
265  $this->output->writeln(sprintf(
266  $format,
267  $this->sourcePath . $item,
268  $this->table,
269  $row['uid'],
270  $this->fieldToMigrate
271  ));
272  continue;
273  }
274  }
275 
276  if ($fileUid > 0) {
277  ‪$fields = [
278  'fieldname' => ‪$this->fieldToMigrate,
279  'table_local' => 'sys_file',
280  'pid' => $this->table === 'pages' ? $row['uid'] : $row['pid'],
281  'uid_foreign' => $row['uid'],
282  'uid_local' => $fileUid,
283  'tablenames' => ‪$this->table,
284  'crdate' => time(),
285  'tstamp' => time(),
286  'sorting' => $i + 256,
287  'sorting_foreign' => $i,
288  ];
289 
290  $queryBuilder = $connectionPool->getQueryBuilderForTable('sys_file_reference');
291  $queryBuilder->insert('sys_file_reference')->values(‪$fields)->execute();
292  ++$i;
293  }
294  }
295 
296  // Update referencing table's original field to now contain the count of references,
297  // but only if all new references could be set
298  if ($i === count($fieldItems)) {
299  $queryBuilder = $connectionPool->getQueryBuilderForTable($this->table);
300  $queryBuilder->update($this->table)->where(
301  $queryBuilder->expr()->eq(
302  'uid',
303  $queryBuilder->createNamedParameter($row['uid'], \PDO::PARAM_INT)
304  )
305  )->set($this->fieldToMigrate, $i)->execute();
306  }
307  }
308 }
‪TYPO3\CMS\Core\Utility\PathUtility\basenameDuringBootstrap
‪static string basenameDuringBootstrap($path)
Definition: PathUtility.php:290
‪TYPO3\CMS\Core\Utility\PathUtility
Definition: PathUtility.php:23
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder
Definition: ExpressionBuilder.php:33
‪TYPO3\CMS\Core\Core\Environment\getPublicPath
‪static string getPublicPath()
Definition: Environment.php:153
‪TYPO3\CMS\Install\Updates\BackendLayoutIconUpdateWizard\getTitle
‪string getTitle()
Definition: BackendLayoutIconUpdateWizard.php:83
‪TYPO3\CMS\Install\Updates\BackendLayoutIconUpdateWizard\$output
‪OutputInterface $output
Definition: BackendLayoutIconUpdateWizard.php:41
‪TYPO3\CMS\Install\Updates\ChattyInterface
Definition: ChattyInterface.php:25
‪TYPO3\CMS\Install\Updates\BackendLayoutIconUpdateWizard\$targetPath
‪string $targetPath
Definition: BackendLayoutIconUpdateWizard.php:70
‪TYPO3\CMS\Install\Updates\BackendLayoutIconUpdateWizard
Definition: BackendLayoutIconUpdateWizard.php:36
‪$fields
‪$fields
Definition: pages.php:4
‪TYPO3\CMS\Install\Updates
Definition: AbstractDownloadExtensionUpdate.php:3
‪TYPO3\CMS\Install\Updates\BackendLayoutIconUpdateWizard\setOutput
‪setOutput(OutputInterface $output)
Definition: BackendLayoutIconUpdateWizard.php:119
‪TYPO3\CMS\Install\Updates\BackendLayoutIconUpdateWizard\migrateField
‪migrateField($row)
Definition: BackendLayoutIconUpdateWizard.php:191
‪TYPO3\CMS\Install\Updates\BackendLayoutIconUpdateWizard\getIdentifier
‪string getIdentifier()
Definition: BackendLayoutIconUpdateWizard.php:75
‪TYPO3\CMS\Install\Updates\BackendLayoutIconUpdateWizard\getPrerequisites
‪string[] getPrerequisites()
Definition: BackendLayoutIconUpdateWizard.php:109
‪TYPO3\CMS\Core\Resource\StorageRepository
Definition: StorageRepository.php:29
‪TYPO3\CMS\Core\Resource\File
Definition: File.php:23
‪TYPO3\CMS\Core\Database\Query\Expression\ExpressionBuilder\NEQ
‪const NEQ
Definition: ExpressionBuilder.php:35
‪TYPO3\CMS\Core\Resource\Exception
Definition: Exception.php:21
‪TYPO3\CMS\Install\Updates\UpgradeWizardInterface
Definition: UpgradeWizardInterface.php:22
‪TYPO3\CMS\Core\Resource\ResourceStorage
Definition: ResourceStorage.php:74
‪$GLOBALS
‪$GLOBALS['TYPO3_CONF_VARS']['EXTCONF']['adminpanel']['modules']
Definition: ext_localconf.php:5
‪TYPO3\CMS\Core\Core\Environment
Definition: Environment.php:39
‪TYPO3\CMS\Install\Updates\BackendLayoutIconUpdateWizard\getRecordsFromTable
‪array getRecordsFromTable()
Definition: BackendLayoutIconUpdateWizard.php:153
‪TYPO3\CMS\Install\Updates\BackendLayoutIconUpdateWizard\executeUpdate
‪bool executeUpdate()
Definition: BackendLayoutIconUpdateWizard.php:129
‪TYPO3\CMS\Install\Updates\BackendLayoutIconUpdateWizard\getDescription
‪string getDescription()
Definition: BackendLayoutIconUpdateWizard.php:91
‪TYPO3\CMS\Core\Database\ConnectionPool
Definition: ConnectionPool.php:44
‪TYPO3\CMS\Core\Utility\GeneralUtility
Definition: GeneralUtility.php:45
‪TYPO3\CMS\Install\Updates\BackendLayoutIconUpdateWizard\$fieldToMigrate
‪string $fieldToMigrate
Definition: BackendLayoutIconUpdateWizard.php:57
‪TYPO3\CMS\Install\Updates\BackendLayoutIconUpdateWizard\$table
‪string $table
Definition: BackendLayoutIconUpdateWizard.php:51
‪TYPO3\CMS\Install\Updates\BackendLayoutIconUpdateWizard\updateNecessary
‪bool updateNecessary()
Definition: BackendLayoutIconUpdateWizard.php:101
‪TYPO3\CMS\Install\Updates\BackendLayoutIconUpdateWizard\$storage
‪ResourceStorage $storage
Definition: BackendLayoutIconUpdateWizard.php:45
‪TYPO3\CMS\Install\Updates\BackendLayoutIconUpdateWizard\$sourcePath
‪string $sourcePath
Definition: BackendLayoutIconUpdateWizard.php:63