|  | <?php | 
        
          |  | declare(strict_types = 1); | 
        
          |  | namespace Vendor\Extension\Command; | 
        
          |  |  | 
        
          |  | use Symfony\Component\Console\Command\Command; | 
        
          |  | use Symfony\Component\Console\Input\InputInterface; | 
        
          |  | use Symfony\Component\Console\Output\OutputInterface; | 
        
          |  | use TYPO3\CMS\Core\Core\Environment; | 
        
          |  | use TYPO3\CMS\Core\Database\Connection; | 
        
          |  | use TYPO3\CMS\Core\Database\ConnectionPool; | 
        
          |  | use TYPO3\CMS\Core\Resource\ResourceFactory; | 
        
          |  | use TYPO3\CMS\Core\Utility\GeneralUtility; | 
        
          |  | use TYPO3\CMS\Frontend\Page\PageRepository; | 
        
          |  |  | 
        
          |  | class Migration extends Command | 
        
          |  | { | 
        
          |  | protected Connection $connectionContao; | 
        
          |  |  | 
        
          |  | protected Connection $connectionTypo3; | 
        
          |  |  | 
        
          |  | protected array $linkCaches = []; | 
        
          |  |  | 
        
          |  | const IMAGE_ORIENTATION_MAPPING = [ | 
        
          |  | '' => 0, | 
        
          |  | 'right' => 25, | 
        
          |  | 'left' => 26, | 
        
          |  | 'below' => 8, | 
        
          |  | 'above' => 0, | 
        
          |  | ]; | 
        
          |  |  | 
        
          |  | protected function configure() | 
        
          |  | { | 
        
          |  | parent::configure(); // TODO: Change the autogenerated stub | 
        
          |  | } | 
        
          |  |  | 
        
          |  | protected function initialize(InputInterface $input, OutputInterface $output) | 
        
          |  | { | 
        
          |  | parent::initialize($input, $output); | 
        
          |  | $this->connectionTypo3 = GeneralUtility::makeInstance(ConnectionPool::class) | 
        
          |  | ->getConnectionByName(ConnectionPool::DEFAULT_CONNECTION_NAME); | 
        
          |  | $this->connectionContao = GeneralUtility::makeInstance(ConnectionPool::class) | 
        
          |  | ->getConnectionByName('Contao'); | 
        
          |  | } | 
        
          |  |  | 
        
          |  | protected function execute(InputInterface $input, OutputInterface $output): int | 
        
          |  | { | 
        
          |  | $output->writeln('Starting migration...'); | 
        
          |  |  | 
        
          |  | $output->writeln('Checking for migration db...'); | 
        
          |  | if ($this->connectionContao) { | 
        
          |  | $output->writeln('Connection to migration db successful!'); | 
        
          |  | } else { | 
        
          |  | $output->writeln('Connection to migration db not possible!'); | 
        
          |  | return self::FAILURE; | 
        
          |  | } | 
        
          |  |  | 
        
          |  | $pagesMigrated = $this->migratePages(); | 
        
          |  | $output->writeln('Migrated ' . $pagesMigrated . ' pages.'); | 
        
          |  | $contentMigrated = $this->migrateContent(); | 
        
          |  | foreach ($contentMigrated as $type => $count) { | 
        
          |  | $output->writeln('Migrated ' . $count . ' elements of type "' . $type . '".'); | 
        
          |  | } | 
        
          |  | $backendUserMigrated = $this->migrateBackendUser(); | 
        
          |  | $output->writeln('Migrated ' . $backendUserMigrated . ' backend users.'); | 
        
          |  | $frontendUserMigrated = $this->migrateFrontendUser(); | 
        
          |  | $output->writeln('Migrated ' . $frontendUserMigrated['groups'] . ' frontend groups.'); | 
        
          |  | $output->writeln('Migrated ' . $frontendUserMigrated['users'] . ' frontend users.'); | 
        
          |  |  | 
        
          |  | $news = $this->migrateNews(); | 
        
          |  | $output->writeln('Migrated ' . $news . ' news articles.'); | 
        
          |  |  | 
        
          |  | $this->finalizeMigration(); | 
        
          |  |  | 
        
          |  | return self::SUCCESS; | 
        
          |  | } | 
        
          |  |  | 
        
          |  | private function migrateFrontendUser(): array | 
        
          |  | { | 
        
          |  | $this->connectionTypo3->truncate('fe_users'); | 
        
          |  | $usersToMigrate = $this->connectionContao->select(['*'], 'tl_member')->fetchAll(); | 
        
          |  |  | 
        
          |  | $this->connectionTypo3->insert( | 
        
          |  | 'pages', | 
        
          |  | [ | 
        
          |  | 'pid' => 1, | 
        
          |  | 'doktype' => PageRepository::DOKTYPE_SYSFOLDER, | 
        
          |  | 'title' => 'Benutzer' | 
        
          |  | ] | 
        
          |  | ); | 
        
          |  | $storagePid = $this->connectionTypo3->lastInsertId('pages'); | 
        
          |  |  | 
        
          |  | $this->connectionTypo3->truncate('fe_groups'); | 
        
          |  | $groups = $this->connectionContao->select(['*'], 'tl_member_group')->fetchAll(); | 
        
          |  |  | 
        
          |  | foreach ($groups as $group) { | 
        
          |  | $newGroup = [ | 
        
          |  | 'pid' => $storagePid, | 
        
          |  | 'uid' => $group['id'], | 
        
          |  | 'tstamp' => $group['tstamp'], | 
        
          |  | 'crdate' => $group['tstamp'], | 
        
          |  | 'title' => $group['name'], | 
        
          |  | 'felogin_redirectPid' => $group['jumpTo'], | 
        
          |  | ]; | 
        
          |  |  | 
        
          |  | $this->connectionTypo3->insert('fe_groups', $newGroup); | 
        
          |  | } | 
        
          |  |  | 
        
          |  | foreach ($usersToMigrate as $user) { | 
        
          |  | $zip = ''; | 
        
          |  | if (preg_match('/([\d]{4,5})/', $user['postal'], $matches)) { | 
        
          |  | $zip = $matches[0]; | 
        
          |  | } | 
        
          |  | $newUser = [ | 
        
          |  | 'uid' => $user['id'], | 
        
          |  | 'pid' => $storagePid, | 
        
          |  | 'tstamp' => $user['tstamp'], | 
        
          |  | 'first_name' => $user['firstname'], | 
        
          |  | 'last_name' => $user['lastname'], | 
        
          |  | 'company' => $user['company'], | 
        
          |  | 'address' => $user['street'], | 
        
          |  | 'zip' => $zip, | 
        
          |  | 'city' => $user['city'], | 
        
          |  | 'telephone' => $user['phone'], | 
        
          |  | 'email' => $user['email'], | 
        
          |  | 'www' => $user['website'], | 
        
          |  | 'username' => $user['username'], | 
        
          |  | 'password' => $user['password'], | 
        
          |  | 'crdate' => $user['dateAdded'], | 
        
          |  | 'lastlogin' => $user['lastLogin'], | 
        
          |  | 'title' => $user['jobtitle'], | 
        
          |  | 'date_of_birth' => $user['dateOfBirth'] ?: 0, | 
        
          |  | 'favourite_club' => $user['campaign'], | 
        
          |  | 'referer' => $user['business_connection'], | 
        
          |  | 'allow_email' => $user['allowEmail'] === 'email_member' ? 1 : 0, | 
        
          |  | 'gender' => $user['gender'] === 'female' ? 1 : 0, | 
        
          |  | 'usergroup' => implode(',', unserialize($user['groups'])) | 
        
          |  | ]; | 
        
          |  | if ($user['avatar']) { | 
        
          |  | $fileIdentifier = '/' . $user['avatar']; | 
        
          |  | if (file_exists(Environment::getPublicPath() . '/fileadmin' . $fileIdentifier)) { | 
        
          |  | $image = ResourceFactory::getInstance()->getFileObjectByStorageAndIdentifier(1, $fileIdentifier); | 
        
          |  |  | 
        
          |  | $this->connectionTypo3->insert( | 
        
          |  | 'sys_file_reference', | 
        
          |  | [ | 
        
          |  | 'uid_local' => $image->getUid(), | 
        
          |  | 'uid_foreign' => $user['id'], | 
        
          |  | 'tstamp' => time(), | 
        
          |  | 'crdate' => time(), | 
        
          |  | 'tablenames' => 'fe_users', | 
        
          |  | 'fieldname' => 'image', | 
        
          |  | 'title' => $user['firstname'] . ' ' . $user['lastname'], | 
        
          |  | ] | 
        
          |  | ); | 
        
          |  |  | 
        
          |  | $newUser['image'] = 1; | 
        
          |  | } | 
        
          |  | } | 
        
          |  |  | 
        
          |  | $this->connectionTypo3->insert('fe_users', $newUser); | 
        
          |  | } | 
        
          |  |  | 
        
          |  | return [ | 
        
          |  | 'users' => count($usersToMigrate), | 
        
          |  | 'groups' => count($groups) | 
        
          |  | ]; | 
        
          |  | } | 
        
          |  |  | 
        
          |  | private function migrateBackendUser(): int | 
        
          |  | { | 
        
          |  | $this->connectionTypo3->truncate('be_users'); | 
        
          |  | $usersToMigrate = $this->connectionContao->select(['*'], 'tl_user')->fetchAll(); | 
        
          |  |  | 
        
          |  | foreach ($usersToMigrate as $user) { | 
        
          |  | $newUser = [ | 
        
          |  | 'uid' => $user['id'], | 
        
          |  | 'tstamp' => $user['tstamp'], | 
        
          |  | 'username' => $user['username'], | 
        
          |  | 'realName' => $user['name'], | 
        
          |  | 'email' => $user['email'], | 
        
          |  | 'password' => $user['password'], | 
        
          |  | 'admin' => $user['admin'] ? 1 : 0, | 
        
          |  | 'lastlogin' => 0, | 
        
          |  | ]; | 
        
          |  |  | 
        
          |  | $this->connectionTypo3->insert('be_users', $newUser); | 
        
          |  | } | 
        
          |  |  | 
        
          |  | return count($usersToMigrate); | 
        
          |  | } | 
        
          |  |  | 
        
          |  | private function migratePages(): int | 
        
          |  | { | 
        
          |  | $this->connectionTypo3->truncate('pages'); | 
        
          |  | $pagesToMigrate = $this->connectionContao | 
        
          |  | ->select( | 
        
          |  | ['*'], | 
        
          |  | 'tl_page' | 
        
          |  | ) | 
        
          |  | ->fetchAll(); | 
        
          |  |  | 
        
          |  | foreach ($pagesToMigrate as $pageToMigrate) { | 
        
          |  | $noIndex = str_contains($pageToMigrate['robots'], 'noindex'); | 
        
          |  | $noFollow = str_contains($pageToMigrate['robots'], 'nofollow'); | 
        
          |  | $newPage = [ | 
        
          |  | 'uid' => $pageToMigrate['id'], | 
        
          |  | 'pid' => $pageToMigrate['pid'] ?: 0, | 
        
          |  | 'sorting' => $pageToMigrate['sorting'], | 
        
          |  | 'tstamp' => $pageToMigrate['tstamp'], | 
        
          |  | 'crdate' => $pageToMigrate['tstamp'], | 
        
          |  | 'title' => $pageToMigrate['title'], | 
        
          |  | 'slug' => '/' . $pageToMigrate['alias'], | 
        
          |  | 'is_siteroot' => $pageToMigrate['type'] === 'root' ? 1 : 0, | 
        
          |  | 'fe_group' => $pageToMigrate['protected'] ? -2 : 0, | 
        
          |  | 'no_search' => $pageToMigrate['noSearch'] ?: 0, | 
        
          |  | 'doktype' => 1, | 
        
          |  | 'nav_hide' => $pageToMigrate['hide'] ? 1 : 0, | 
        
          |  | 'hidden' => $pageToMigrate['published'] ? 0 : 1, | 
        
          |  | 'no_index' => $noIndex === true ? 1 : 0, | 
        
          |  | 'no_follow' => $noFollow === true ? 1 : 0, | 
        
          |  | ]; | 
        
          |  |  | 
        
          |  | if ($pageToMigrate['type'] === 'forward') { | 
        
          |  | $newPage['doktype'] = PageRepository::DOKTYPE_SHORTCUT; | 
        
          |  | $newPage['shortcut'] = $pageToMigrate['jumpTo']; | 
        
          |  | } | 
        
          |  |  | 
        
          |  | if ($pageToMigrate['type'] === 'root') { | 
        
          |  | $newPage['slug'] = '/'; | 
        
          |  | $this->connectionTypo3->truncate('sys_template'); | 
        
          |  | $this->connectionTypo3 | 
        
          |  | ->insert( | 
        
          |  | 'sys_template', | 
        
          |  | [ | 
        
          |  | 'title' => $pageToMigrate['title'], | 
        
          |  | 'pid' => $pageToMigrate['id'], | 
        
          |  | 'root' => 1, | 
        
          |  | 'clear' => 3 | 
        
          |  | ] | 
        
          |  | ); | 
        
          |  | } | 
        
          |  |  | 
        
          |  | if (!GeneralUtility::inList('root,regular,forward', $pageToMigrate['type'])) { | 
        
          |  | $newPage['nav_hide'] = 1; | 
        
          |  | } | 
        
          |  |  | 
        
          |  | $this->connectionTypo3->insert('pages', $newPage); | 
        
          |  | } | 
        
          |  |  | 
        
          |  | return count($pagesToMigrate); | 
        
          |  | } | 
        
          |  |  | 
        
          |  | private function migrateContent(): array | 
        
          |  | { | 
        
          |  | $containerConfiguration = [ | 
        
          |  | '2cols3366' => [ | 
        
          |  | 'children' => [ | 
        
          |  | 201, | 
        
          |  | 202 | 
        
          |  | ] | 
        
          |  | ], | 
        
          |  | '3cols' => [ | 
        
          |  | 'children' => [ | 
        
          |  | 301, | 
        
          |  | 302, | 
        
          |  | 303 | 
        
          |  | ] | 
        
          |  | ], | 
        
          |  | ]; | 
        
          |  | $migrated = []; | 
        
          |  | $this->connectionTypo3->truncate('tt_content'); | 
        
          |  | $this->connectionTypo3->truncate('sys_file_reference'); | 
        
          |  |  | 
        
          |  | $articles = $this->connectionContao->select(['*'], 'tl_article')->fetchAll(); | 
        
          |  |  | 
        
          |  | foreach ($articles as $article) { | 
        
          |  | $contentElements = $this->connectionContao->select( | 
        
          |  | ['*'], | 
        
          |  | 'tl_content', | 
        
          |  | ['pid' => $article['id']], | 
        
          |  | [], | 
        
          |  | ['sorting' => 'ASC'] | 
        
          |  | )->fetchAll(); | 
        
          |  |  | 
        
          |  | $column2With3366 = false; | 
        
          |  | $column3 = false; | 
        
          |  | $containerUid = 0; | 
        
          |  |  | 
        
          |  | foreach ($contentElements as $key => $contentElement) { | 
        
          |  | $newContentElement = []; | 
        
          |  | if ($key === 0 && str_contains($contentElement['cssID'], 'grid_1 alpha')) { | 
        
          |  | $column2With3366 = true; | 
        
          |  | $containerUid = $contentElement['id'] + 1000; | 
        
          |  | $newContainerElement = [ | 
        
          |  | 'uid' => $containerUid, | 
        
          |  | 'pid' => $article['pid'], | 
        
          |  | 'tstamp' => $contentElement['tstamp'], | 
        
          |  | 'crdate' => $contentElement['tstamp'], | 
        
          |  | 'CType' => '2cols-33-66', | 
        
          |  | 'colPos' => 0, | 
        
          |  | ]; | 
        
          |  | $this->connectionTypo3->insert( | 
        
          |  | 'tt_content', | 
        
          |  | $newContainerElement | 
        
          |  | ); | 
        
          |  | } | 
        
          |  | if ($key % 3 === 0 && str_contains($contentElement['cssID'], 'grid_1 omega')) { | 
        
          |  | $column3 = true; | 
        
          |  | $containerUid = $contentElement['id'] + 1000; | 
        
          |  | $newContainerElement = [ | 
        
          |  | 'uid' => $containerUid, | 
        
          |  | 'pid' => $article['pid'], | 
        
          |  | 'tstamp' => $contentElement['tstamp'], | 
        
          |  | 'crdate' => $contentElement['tstamp'], | 
        
          |  | 'sorting' => $contentElement['sorting'], | 
        
          |  | 'CType' => '3cols', | 
        
          |  | 'colPos' => 0, | 
        
          |  | ]; | 
        
          |  | $this->connectionTypo3->insert( | 
        
          |  | 'tt_content', | 
        
          |  | $newContainerElement | 
        
          |  | ); | 
        
          |  | } | 
        
          |  | switch ($contentElement['type']) { | 
        
          |  | case 'text': | 
        
          |  | case 'image': | 
        
          |  | case 'headline': | 
        
          |  | $header = unserialize($contentElement['headline']); | 
        
          |  | $bodytext = $this->cleanText($contentElement['text']); | 
        
          |  | $bodytext = $this->migrateLinks($bodytext); | 
        
          |  | $colPos = 0; | 
        
          |  | if ($column2With3366) { | 
        
          |  | $colPos = $containerConfiguration['2cols3366']['children'][$key]; | 
        
          |  | } | 
        
          |  | if ($column3) { | 
        
          |  | $column = $key % 3; | 
        
          |  | $colPos = $containerConfiguration['3cols']['children'][$column]; | 
        
          |  | } | 
        
          |  | $newContentElement = [ | 
        
          |  | 'uid' => $contentElement['id'], | 
        
          |  | 'pid' => $article['pid'], | 
        
          |  | 'sorting' => $contentElement['sorting'], | 
        
          |  | 'tstamp' => $contentElement['tstamp'], | 
        
          |  | 'crdate' => $contentElement['tstamp'], | 
        
          |  | 'hidden' => $contentElement['invisible'] ? 1 : 0, | 
        
          |  | 'CType' => 'text', | 
        
          |  | 'colPos' => $colPos, | 
        
          |  | 'bodytext' => $bodytext, | 
        
          |  | 'header' => $header['value'], | 
        
          |  | 'header_layout' => (int)substr($header['unit'], 1, 1), | 
        
          |  | 'tx_container_parent' => $containerUid | 
        
          |  | ]; | 
        
          |  |  | 
        
          |  | if ($contentElement['singleSRC'] && !str_contains($contentElement['cssID'], 'grid_1 omega')) { | 
        
          |  | $newContentElement['CType'] = 'textmedia'; | 
        
          |  | $fileIdentifier = '/' . $contentElement['singleSRC']; | 
        
          |  | if (file_exists(Environment::getPublicPath() . '/fileadmin' . $fileIdentifier)) { | 
        
          |  | $image = ResourceFactory::getInstance()->getFileObjectByStorageAndIdentifier(1, $fileIdentifier); | 
        
          |  |  | 
        
          |  | $this->connectionTypo3->insert( | 
        
          |  | 'sys_file_reference', | 
        
          |  | [ | 
        
          |  | 'uid_local' => $image->getUid(), | 
        
          |  | 'uid_foreign' => $contentElement['id'], | 
        
          |  | 'tstamp' => time(), | 
        
          |  | 'crdate' => time(), | 
        
          |  | 'tablenames' => 'tt_content', | 
        
          |  | 'fieldname' => 'assets', | 
        
          |  | 'title' => $contentElement['title'], | 
        
          |  | 'alternative' => $contentElement['alt'], | 
        
          |  | 'description' => $contentElement['caption'], | 
        
          |  | ] | 
        
          |  | ); | 
        
          |  |  | 
        
          |  | $newContentElement['assets'] = 1; | 
        
          |  | $newContentElement['imagecols'] = 1; | 
        
          |  | $newContentElement['imageorient'] = self::IMAGE_ORIENTATION_MAPPING[$contentElement['floating']]; | 
        
          |  | } | 
        
          |  | } | 
        
          |  | } | 
        
          |  | if ($newContentElement) { | 
        
          |  | $migrated[$newContentElement['CType']]++; | 
        
          |  | $this->connectionTypo3->insert( | 
        
          |  | 'tt_content', | 
        
          |  | $newContentElement | 
        
          |  | ); | 
        
          |  | } | 
        
          |  | } | 
        
          |  |  | 
        
          |  | } | 
        
          |  |  | 
        
          |  | return $migrated; | 
        
          |  | } | 
        
          |  |  | 
        
          |  | public function migrateNews(): int | 
        
          |  | { | 
        
          |  | $articles = $this->connectionContao->select(['*'], 'tl_news')->fetchAll(); | 
        
          |  |  | 
        
          |  | foreach ($articles as $article) { | 
        
          |  | $this->connectionTypo3->insert( | 
        
          |  | 'pages', | 
        
          |  | [ | 
        
          |  | 'title' => $article['headline'], | 
        
          |  | 'pid' => $article['pid'], | 
        
          |  | 'slug' => $article['alias'] ?? '', | 
        
          |  | 'publish_date' => $article['date'], | 
        
          |  | 'crdate' => $article['time'], | 
        
          |  | 'tstamp' => $article['time'], | 
        
          |  | 'doktype' => \T3G\AgencyPack\Blog\Constants::DOKTYPE_BLOG_POST | 
        
          |  | ] | 
        
          |  | ); | 
        
          |  | $pageUid = $this->connectionTypo3->lastInsertId('pages'); | 
        
          |  |  | 
        
          |  | $this->connectionTypo3->insert( | 
        
          |  | 'tt_content', | 
        
          |  | [ | 
        
          |  | 'pid' => $pageUid, | 
        
          |  | 'crdate' => $article['time'], | 
        
          |  | 'tstamp' => $article['time'], | 
        
          |  | 'CType' => 'text', | 
        
          |  | 'colPos' => 0, | 
        
          |  | 'bodytext' => $this->cleanText($article['teaser']), | 
        
          |  | 'sorting' => 1, | 
        
          |  | ] | 
        
          |  | ); | 
        
          |  |  | 
        
          |  | $newContentElement = [ | 
        
          |  | 'pid' => $pageUid, | 
        
          |  | 'crdate' => $article['time'], | 
        
          |  | 'tstamp' => $article['time'], | 
        
          |  | 'CType' => 'textmedia', | 
        
          |  | 'colPos' => 0, | 
        
          |  | 'bodytext' => $this->cleanText($article['text']), | 
        
          |  | 'sorting' => 2, | 
        
          |  | ]; | 
        
          |  |  | 
        
          |  | $this->connectionTypo3->insert( | 
        
          |  | 'tt_content', | 
        
          |  | $newContentElement | 
        
          |  | ); | 
        
          |  | $newContentElement['uid'] = $this->connectionTypo3->lastInsertId('tt_content'); | 
        
          |  |  | 
        
          |  | if ($article['singleSRC']) { | 
        
          |  | $fileIdentifier = '/' . $article['singleSRC']; | 
        
          |  | if (file_exists(Environment::getPublicPath() . '/fileadmin' . $fileIdentifier)) { | 
        
          |  | $image = ResourceFactory::getInstance()->getFileObjectByStorageAndIdentifier(1, $fileIdentifier); | 
        
          |  |  | 
        
          |  | $this->connectionTypo3->insert( | 
        
          |  | 'sys_file_reference', | 
        
          |  | [ | 
        
          |  | 'uid_local' => $image->getUid(), | 
        
          |  | 'uid_foreign' => $newContentElement['uid'], | 
        
          |  | 'tstamp' => time(), | 
        
          |  | 'crdate' => time(), | 
        
          |  | 'tablenames' => 'tt_content', | 
        
          |  | 'fieldname' => 'assets', | 
        
          |  | 'description' => $article['caption'], | 
        
          |  | ] | 
        
          |  | ); | 
        
          |  |  | 
        
          |  | $updateContentElement['assets'] = 1; | 
        
          |  | $updateContentElement['imagecols'] = 1; | 
        
          |  | $updateContentElement['imageorient'] = self::IMAGE_ORIENTATION_MAPPING[$article['floating']]; | 
        
          |  |  | 
        
          |  | $this->connectionTypo3->update( | 
        
          |  | 'tt_content', | 
        
          |  | $updateContentElement, | 
        
          |  | ['uid' => $newContentElement['uid']] | 
        
          |  | ); | 
        
          |  | } | 
        
          |  | } | 
        
          |  | } | 
        
          |  |  | 
        
          |  | return count($articles); | 
        
          |  | } | 
        
          |  |  | 
        
          |  | private function cleanText(?string $text): string | 
        
          |  | { | 
        
          |  | if (is_null($text)) { | 
        
          |  | return ''; | 
        
          |  | } | 
        
          |  | $remove = [ | 
        
          |  | '[nbsp]', | 
        
          |  | '<p>[nbsp]</p>', | 
        
          |  | ]; | 
        
          |  | $text = str_replace($remove, '', $text); | 
        
          |  | $text = preg_replace('/style="[^\"]*"/', '', $text); | 
        
          |  | $text = trim($text); | 
        
          |  |  | 
        
          |  | return $text; | 
        
          |  | } | 
        
          |  |  | 
        
          |  | private function migrateLinks(string $text): string | 
        
          |  | { | 
        
          |  | $linksFound = preg_match_all('/<a\s+(?:[^>]*?\s+)?href=(["\'])(.*?)\1/', $text, $links); | 
        
          |  | if ($linksFound) { | 
        
          |  | foreach ($links[2] as $originalLink) { | 
        
          |  | if (!isset($this->linkCaches[$originalLink])) { | 
        
          |  | $newLink = $originalLink; | 
        
          |  | preg_match('/\{\{link_url::(\d+)\}\}/', $originalLink, $directTargetPage); | 
        
          |  | if ($directTargetPage) { | 
        
          |  | $newLink = 't3://page?uid=' . $directTargetPage[1]; | 
        
          |  | } else { | 
        
          |  | $path = parse_url($originalLink, PHP_URL_PATH); | 
        
          |  | $slug = str_replace('.html', '', $path); | 
        
          |  | $slug = $slug[0] !== '/' ? '/' . $slug : $slug; | 
        
          |  |  | 
        
          |  | $targetPage = $this->connectionTypo3->select(['uid'], 'pages', ['slug' => $slug])->fetch(); | 
        
          |  | if ($targetPage) { | 
        
          |  | $newLink = 't3://page?uid=' . $targetPage['uid']; | 
        
          |  | } | 
        
          |  | } | 
        
          |  | $this->linkCaches[$originalLink] = $newLink; | 
        
          |  | } else { | 
        
          |  | $newLink = $this->linkCaches[$originalLink]; | 
        
          |  | } | 
        
          |  |  | 
        
          |  | $text = str_replace($originalLink, $newLink, $text); | 
        
          |  | } | 
        
          |  | } | 
        
          |  |  | 
        
          |  | return $text; | 
        
          |  | } | 
        
          |  |  | 
        
          |  | private function finalizeMigration(): void | 
        
          |  | { | 
        
          |  | foreach (glob(Environment::getProjectPath() . '/migrations/*.sql') as $file) { | 
        
          |  | if (file_exists($file)) { | 
        
          |  | $stmt = $this->connectionTypo3->prepare(file_get_contents($file)); | 
        
          |  | $stmt->execute(); | 
        
          |  | } | 
        
          |  | } | 
        
          |  | } | 
        
          |  | } |