I created an upgradewizard which is not fully functional but implements absolute basic logic.
we might wanna reference that here.
Other than that i create the issue for people looking for help.
So - hi!
<?php
declare(strict_types=1);
namespace Your\Namespace\UpgradeWizard;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Output\StreamOutput;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
use TYPO3\CMS\Core\Utility\ExtensionManagementUtility;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Install\Updates\ChattyInterface;
use TYPO3\CMS\Install\Updates\UpgradeWizardInterface;
/**
* Class RedirectsUpgradeWizard.php
*
* Upgrade Wizard to perform a migration to the new redirects
*/
class UrlForwardingRedirectsUpgradeWizard implements UpgradeWizardInterface, ChattyInterface
{
/**
* @var string
*/
protected $table = 'sys_redirect';
/**
* @var StreamOutput
*/
protected $output;
/**
* Return the identifier for this wizard
* This should be the same string as used in the ext_localconf class registration
*
* @return string
*/
public function getIdentifier(): string
{
return 'url_forwarding_to_core_redirects';
}
/**
* Return the speaking name of this wizard
*
* @return string
*/
public function getTitle(): string
{
return 'Migrate EXT:url_forwarding redirects to EXT:redirects records';
}
/**
* Return the description for this wizard
*
* @return string
*/
public function getDescription(): string
{
return 'With v9 there are core redirects which make third party ext (mostly) obsolete.
This wizard migrates EXT:url_forwarding redirects to core redirects.';
}
/**
* Execute the update
* Called when a wizard reports that an update is necessary
*
* @return bool
*/
public function executeUpdate(): bool
{
if (ExtensionManagementUtility::isLoaded('redirects') === false) {
$this->output->writeln('EXT:redirects is not installed. Aborting.');
return false;
}
if ($this->coreTableExists() === false) {
$this->output->writeln(
'The database table of EXT:redirects do not exist. Please update your database'
. ' tables first. DO NOT REMOVE anything yet.'
);
return false;
}
$this->migrateRecords();
return true;
}
/**
* Is an update necessary?
* Is used to determine whether a wizard needs to be run.
* Check if data for migration exists.
*
* @return bool
*/
public function updateNecessary(): bool
{
$updateNeeded = false;
// Check if the database table even exists
if ($this->checkIfWizardIsRequired()) {
$updateNeeded = true;
}
return $updateNeeded;
}
/**
* Returns an array of class names of Prerequisite classes
* This way a wizard can define dependencies like "database up-to-date" or
* "reference index updated"
*
* @return string[]
*/
public function getPrerequisites(): array
{
return [];
}
/**
* Check if there are record within "tx_urlforwarding_domain_model_redirect" database table.
*
* @throws \InvalidArgumentException
* @return bool
*/
protected function checkIfWizardIsRequired(): bool
{
$connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
$queryBuilder = $connectionPool->getQueryBuilderForTable($this->table);
$queryBuilder->getRestrictions()->removeAll()->add(GeneralUtility::makeInstance(DeletedRestriction::class));
$numberOfEntries = $queryBuilder
->count('uid')
->from('tx_urlforwarding_domain_model_redirect')
// This is here in case you don't have the TCA of tx_urlforwarding_domain_model_redirect anymore, which is necessary for the DeletedRestriction
->where(
$queryBuilder->expr()->eq('tx_urlforwarding_domain_model_redirect.deleted', 0)
)
->execute()
->fetchColumn();
return $numberOfEntries > 0;
}
/**
* Setter injection for output into upgrade wizards
*
* @param OutputInterface $output
*/
public function setOutput(OutputInterface $output): void
{
$this->output = $output;
}
/**
* @return bool
*/
protected function coreTableExists(): bool
{
$databaseConnection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($this->table);
return $databaseConnection->getSchemaManager()->tablesExist([$this->table]);
}
/**
* @return void
*/
protected function migrateRecords()
{
$connectionPool = GeneralUtility::makeInstance(ConnectionPool::class);
$queryBuilder = $connectionPool->getQueryBuilderForTable('tx_urlforwarding_domain_model_redirect');
$queryBuilder->getRestrictions()->removeAll()->add(GeneralUtility::makeInstance(DeletedRestriction::class));
$redirectsToMigrate = $queryBuilder
->select('tx_urlforwarding_domain_model_redirect.*', 'sys_domain.domainName')
->from('tx_urlforwarding_domain_model_redirect')
->leftJoin(
'tx_urlforwarding_domain_model_redirect',
'tx_urlforwarding_domain_mm',
'tx_urlforwarding_domain_mm',
$queryBuilder->expr()->eq(
'tx_urlforwarding_domain_model_redirect.uid',
$queryBuilder->quoteIdentifier('tx_urlforwarding_domain_mm.uid_local'),
)
)
->leftJoin(
'tx_urlforwarding_domain_mm',
'sys_domain',
'sys_domain',
$queryBuilder->expr()->eq(
'sys_domain.uid',
$queryBuilder->quoteIdentifier('tx_urlforwarding_domain_mm.uid_foreign'),
)
)
// This is here in case you don't have the TCA of tx_urlforwarding_domain_model_redirect anymore, which is necessary for the DeletedRestriction
->where(
$queryBuilder->expr()->eq('tx_urlforwarding_domain_model_redirect.deleted', 0)
)
->execute()
->fetchAll();
// v10change TODO: issues:
// - handle regex
// - handle full url as source path/forward url
// - handle slash at the beginning (that seems working with or without)
// TODO: the following block is depending on your data structure/usage etc.
$skippedRedirects = [];
foreach ($redirectsToMigrate as $redirect) {
$skipRedirect = false;
$target = '';
switch ((int) $redirect['type']) {
case 0:
if (!$redirect['internal_page']) {
$skipRedirect = true;
break;
}
$target = 't3://page?uid=' . $redirect['internal_page'];
break;
case 1:
if (!$redirect['external_url']) {
$skipRedirect = true;
break;
}
$target = $redirect['external_url'];
break;
case 2:
if (!$redirect['internal_file']) {
$skipRedirect = true;
break;
}
$target = '/' . $redirect['internal_file'];
break;
}
if ($skipRedirect) {
$skippedRedirects[] = $redirect['uid'];
continue;
}
$migratedRedirect = [
'source_host' => $redirect['domainName'] ?? '*',
'source_path' => preg_replace('/\(\.html\)\?/', '', $redirect['forward_url']),
'target' => $target,
'target_statuscode' => $redirect['http_status'],
'hitcount' => $redirect['counter'],
'lasthiton' => $redirect['last_hit'],
'createdon' => $redirect['crdate'],
'updatedon' => $redirect['tstamp'],
'createdby' => $redirect['cruser_id'],
];
$newRedirects[] = $migratedRedirect;
}
$keys = [
'source_host',
'source_path',
'target',
'target_statuscode',
'hitcount',
'lasthiton',
'createdon',
'updatedon',
'createdby',
];
$connectionPool->getConnectionForTable($this->table)->bulkInsert(
$this->table,
$newRedirects,
$keys
);
if ($skippedRedirects) {
$this->output->writeln('redirects skipped due to invalid data (no redirect target): ' . implode(', ',
$skippedRedirects));
} else {
$this->output->writeln('no redirects skipped, all migrated');
}
}
}
I created an upgradewizard which is not fully functional but implements absolute basic logic.
we might wanna reference that here.
Other than that i create the issue for people looking for help.
So - hi!
https://gist.github.com/helsner/37c274b157d3a598a04737e9256b2039