From 4ef8aa5f494cfbb5dec3f7a1129c59cc745905cb Mon Sep 17 00:00:00 2001 From: jkummer Date: Fri, 8 Feb 2019 00:20:01 +0100 Subject: [PATCH] [TASK] Upgrade compatibility and support command line execution - Offers compatibility with TYPO3 9.5.x and EXT:news v7.x includes temporary requirement of EXT:typo3db_legacy - Support commandline support for all important tasks documents also for EXT:typo3_console - Implements EXT:fal_ttnews migration from EXT:news_falttnewsimport adds migration for tt_news 'forceFirstImageIsPreview' - Implements EXT:realurl migration for unique alias & path_segment - Adjust Readme for first instructions --- ...FalMediaShowInPreviewCommandController.php | 51 +++++++ .../FalTtNewsMigrationCommandController.php | 139 ++++++++++++++++++ ...lUniqueAliasMigrationCommandController.php | 123 ++++++++++++++++ .../Command/TtNewsImportCommandController.php | 37 +++++ Classes/Jobs/TTNewsNewsImportJob.php | 2 +- Readme.rst | 103 +++++++++++-- ext_emconf.php | 4 +- ext_localconf.php | 6 +- 8 files changed, 451 insertions(+), 14 deletions(-) create mode 100644 Classes/Command/FalMediaShowInPreviewCommandController.php create mode 100644 Classes/Command/FalTtNewsMigrationCommandController.php create mode 100644 Classes/Command/RealUrlUniqueAliasMigrationCommandController.php create mode 100644 Classes/Command/TtNewsImportCommandController.php diff --git a/Classes/Command/FalMediaShowInPreviewCommandController.php b/Classes/Command/FalMediaShowInPreviewCommandController.php new file mode 100644 index 0000000..be0a4da --- /dev/null +++ b/Classes/Command/FalMediaShowInPreviewCommandController.php @@ -0,0 +1,51 @@ +getDatabaseConnection()->exec_SELECTquery( + 'uid', + 'sys_file_reference', + 'tablenames = \'tx_news_domain_model_news\' AND fieldname = \'fal_media\' AND deleted = 0', + 'uid_foreign', + 'sorting DESC', + '' + ); + $count = 0; + while ($row = $this->getDatabaseConnection()->sql_fetch_assoc($res)) { + $this->getDatabaseConnection()->exec_UPDATEquery( + 'sys_file_reference', + 'uid = ' . $row['uid'], + ['showinpreview' => 1], + false + ); + $count++; + } + echo $count . ' news.fal_media entries checked for showinpreview.'; + } + + /** + * @return \TYPO3\CMS\Core\Database\DatabaseConnection + */ + protected function getDatabaseConnection() + { + return $GLOBALS['TYPO3_DB']; + } +} diff --git a/Classes/Command/FalTtNewsMigrationCommandController.php b/Classes/Command/FalTtNewsMigrationCommandController.php new file mode 100644 index 0000000..77bf904 --- /dev/null +++ b/Classes/Command/FalTtNewsMigrationCommandController.php @@ -0,0 +1,139 @@ + RENOLIT SE + */ +class FalTtNewsMigrationCommandController extends CommandController +{ + + /** + * Migrate ext:fal_ttnews file references to ext:news + * Move file references from tt_news to news + * + * @return void + * @cli + */ + public function migrateFalTtNewsCommand() + { + $tables = [0 => 'tt_news', 1 => 'tx_news_domain_model_news', 2 => 'sys_file_reference']; + $updatedNews = 0; + $resetFileReferences = ['tx_falttnews_fal_images' => 0, 'tx_falttnews_fal_media' => 0]; + $movedReferences = 0; + + // get news records which were imported + $news = $this->getDatabaseConnection()->exec_SELECTgetRows( + 'uid, import_id, import_source', $tables[1], 'import_source LIKE \'TT_NEWS_IMPORT\'' + ); + //\TYPO3\CMS\Core\Utility\DebugUtility::debug($news); + foreach ($news as $n) { + $updateFields = []; + // get original tt_news + $tt_n = $this->getSingleTtNews($n['import_id']); + if (!empty($tt_n)) { + if (isset($tt_n['tx_falttnews_fal_images']) && (int) $tt_n['tx_falttnews_fal_images'] > 0) { + $updateFields['fal_media'] = $tt_n['tx_falttnews_fal_images']; + } + if (isset($tt_n['tx_falttnews_fal_media']) && (int) $tt_n['tx_falttnews_fal_media'] > 0) { + $updateFields['fal_related_files'] = $tt_n['tx_falttnews_fal_media']; + } + } + // set the number of file references for news + if (!empty($updateFields)) { + $this->getDatabaseConnection()->exec_UPDATEquery($tables[1], 'uid = ' . (int) $n['uid'], $updateFields); + $updatedNews++; + $this->getDatabaseConnection()->exec_UPDATEquery($tables[0], 'uid = ' . (int) $n['import_id'], $resetFileReferences); + // get file references + $movedRef = $this->rewriteSingleNewsReferences($n['import_id'], $n['uid']); + $movedReferences = $movedReferences + $movedRef; + } + } + + if ($updatedNews > 0) { + echo 'A total of ' . $movedReferences . ' file references for ' . $updatedNews . ' news has been moved.'; + } else { + echo 'No file references for moving found, no changes.'; + } + } + + /** + * rewrite sys_file_references for a single news entry + * @param integer $uid_foreign + * @param integer $uid_foreign_new + * @return integer + */ + protected function rewriteSingleNewsReferences($uid_foreign, $uid_foreign_new) + { + $movedReferences = 0; + $table = 'sys_file_reference'; + // get single news record which were imported + $references = $this->getDatabaseConnection()->exec_SELECTgetRows( + 'uid, uid_foreign, tablenames, fieldname', $table, 'uid_foreign=' . (int) $uid_foreign . ' AND tablenames = \'tt_news\'' + ); + if (count($references) > 0) { + foreach ($references as $reference) { + if ($reference['fieldname'] === 'tx_falttnews_fal_images') { + $updateFieldsMedia = [ + 'uid_foreign' => $uid_foreign_new, + 'tablenames' => 'tx_news_domain_model_news', + 'fieldname' => 'fal_media' + ]; + $this->getDatabaseConnection()->exec_UPDATEquery($table, 'uid=' . (int) $reference['uid'] . ' AND tablenames=\'tt_news\' AND fieldname=\'tx_falttnews_fal_images\'', $updateFieldsMedia); + $movedReferences++; + } + if ($reference['fieldname'] === 'tx_falttnews_fal_media') { + $updateFieldsFiles = [ + 'uid_foreign' => $uid_foreign_new, + 'tablenames' => 'tx_news_domain_model_news', + 'fieldname' => 'fal_related_files' + ]; + $this->getDatabaseConnection()->exec_UPDATEquery($table, 'uid=' . (int) $reference['uid'] . ' AND tablenames=\'tt_news\' AND fieldname=\'tx_falttnews_fal_media\'', $updateFieldsFiles); + $movedReferences++; + } + } + } + return $movedReferences; + } + + /** + * get single news by uid from table + * @param integer $uid + * @param string $table + * @return array + */ + protected function getSingleTtNews($uid) + { + // get single news record which were imported + $news = $this->getDatabaseConnection()->exec_SELECTgetSingleRow( + 'uid, tx_falttnews_fal_images, tx_falttnews_fal_media', 'tt_news', 'uid=' . (int) $uid + ); + if (isset($news['uid'])) { + return $news; + } else { + return []; + } + } + + /** + * @return \TYPO3\CMS\Extbase\Object\ObjectManager + */ + protected function getObjectManager() + { + return GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Object\ObjectManager::class); + } + + /** + * @return \TYPO3\CMS\Core\Database\DatabaseConnection + */ + protected function getDatabaseConnection() + { + return $GLOBALS['TYPO3_DB']; + } +} diff --git a/Classes/Command/RealUrlUniqueAliasMigrationCommandController.php b/Classes/Command/RealUrlUniqueAliasMigrationCommandController.php new file mode 100644 index 0000000..9df13d6 --- /dev/null +++ b/Classes/Command/RealUrlUniqueAliasMigrationCommandController.php @@ -0,0 +1,123 @@ += 2.0 + $queries[] = 'INSERT INTO tx_realurl_uniqalias (pid,tablename,field_id,value_alias,value_id,lang,expire) SELECT pid,tablename,field_id,value_alias,value_id,lang,expire FROM tx_realurl_uniqalias_migration;'; + // Drop temporarly table + $queries[] = 'DROP TABLE tx_realurl_uniqalias_migration;'; + // Run each query + $countSuccessfulExecutedQueries = 0; + foreach ($queries as $query) { + if ($this->executeQuery($query) === false) { + break; + } + $countSuccessfulExecutedQueries++; + } + $results = $countSuccessfulExecutedQueries . ' queries of ' . count($queries) . ' executed. '; + if ($this->error) { + $results .= 'Break with error! ' . $this->error; + } else { + $results .= 'Without errors.'; + } + echo $results; + } + + /** + * Command for tx_realurl_uniqalias into slug/path_segment migration + * Copies realurl alias to news where path_segment if is empty. + * Requires, that path_segment was not automaticly filled before! + * This can still lead in empty slugs field, which can be updated via installtool + * Use: Upgrade Wizard "Updates slug field 'path_segment' of EXT:news records" (identifier: ’newsSlug’)
 + * Or helhum/typo3-console: '$ typo3cms upgrade:wizard newsSlug' + * + * @return void + * @cli + */ + public function migrateRealurlUniqueAliasIntoPathSegmentCommand() + { + $result = ''; + $query = ' +UPDATE tx_news_domain_model_news AS n +JOIN tx_realurl_uniqalias AS r ON (n.uid = r.value_id AND n.sys_language_uid = r.lang AND r.tablename = \'tx_news_domain_model_news\') +SET n.path_segment = r.value_alias +WHERE (n.path_segment IS NULL OR n.path_segment = \'\');'; + // Run + if ($this->executeQuery($query) === false) { + $result .= 'Break with error! ' . $this->error; + } else { + $result .= 'Done.'; + } + echo $result; + } + + /** + * Execute SQL query + * + * @param string $query + * @return bool + */ + protected function executeQuery($query) + { + $resource = $this->getDatabaseConnection()->sql_query($query); + if ($this->getDatabaseConnection()->sql_error()) { + $this->error = 'SQL-ERROR for ' . $query . ': ' . htmlspecialchars($this->getDatabaseConnection()->sql_error()); + return false; + } else { + return true; + } + } + + /** + * @return \TYPO3\CMS\Core\Database\DatabaseConnection + */ + protected function getDatabaseConnection() + { + return $GLOBALS['TYPO3_DB']; + } +} diff --git a/Classes/Command/TtNewsImportCommandController.php b/Classes/Command/TtNewsImportCommandController.php new file mode 100644 index 0000000..11a5717 --- /dev/null +++ b/Classes/Command/TtNewsImportCommandController.php @@ -0,0 +1,37 @@ +objectManager->get(\BeechIt\NewsTtnewsimport\Jobs\TTNewsCategoryImportJob::class); + $job->run(0); + } + + /** + * Import tt_news news records + * + * @cli + */ + public function importTtNewsNewsCommand() + { + $job = $this->objectManager->get(\BeechIt\NewsTtnewsimport\Jobs\TTNewsNewsImportJob::class); + $job->run(0); + } +} diff --git a/Classes/Jobs/TTNewsNewsImportJob.php b/Classes/Jobs/TTNewsNewsImportJob.php index cc42e5a..2c541ad 100644 --- a/Classes/Jobs/TTNewsNewsImportJob.php +++ b/Classes/Jobs/TTNewsNewsImportJob.php @@ -36,7 +36,7 @@ class TTNewsNewsImportJob extends AbstractImportJob { /** * @var int */ - protected $numberOfRecordsPerRun = 30; + #protected $numberOfRecordsPerRun = 30; // Do not limit! Import all if running on console protected $importServiceSettings = array( 'findCategoriesByImportSource' => 'TT_NEWS_CATEGORY_IMPORT' diff --git a/Readme.rst b/Readme.rst index d90e75a..b44508b 100644 --- a/Readme.rst +++ b/Readme.rst @@ -3,9 +3,12 @@ TYPO3 extension "news_ttnewsimport" This extension imports records from `EXT:tt_news` to `EXT:news` with support for multiple 3rd party extensions which enhance tt_news. +Execution via shell is supported and recommend for all important tasks. For EXT:typo3_console use `./typo3cms` instead of `./typo3/cli_dispatch.phpsh extbase`. + **Requirements** * TYPO3 CMS >= 6.2 + * EXT:typo3db_legacy for TYPO3 CMS >= 9 * Ext:news >= 3.0 **License** @@ -21,20 +24,41 @@ The records `tt_news` are migrated to `tx_news_domain_model_news` and `tt_news_c The following 3rd party extensions are supported during the migration and are not needed anymore: -* DAM: The dam records are migrated using the new FAL API. -* jg_youtubeinnews: YouTube links are migrated to EXT:news media elements -* tl_news_linktext: Related links are migrated to ext:news link elements +* EXT:dam: The dam records are migrated using the new FAL API. +* EXT:jg_youtubeinnews: YouTube links are migrated to EXT:news media elements +* EXT:tl_news_linktext: Related links are migrated to ext:news link elements * EXT:mbl_newsevent are migrated to the available fields of EXT:roq_newsevent (News event extension for EXT:news) +* EXT:fal_ttnews: Existing relations are migrated to EXT:news fal_media elements (EXT:news v7.x) Usage ^^^^^ +Import of tt_news entries can be done manually via TYPO3 backend module of EXT:news or using shell. + +**Important**: First start import of categories if any, as they will be considered for news entries. + +**A) Import manually via TYPO3 backend module** + +This extension registers new import classes for EXT:news and are available in backend modul. + * After installing the extension, switch to the module "**News Import**". * Select the wizard you need and press *Start*. -Important: First start import of categories if any. Afterwards reopen the module to import news. +**Important:** Reopen the module after importing categories to import news. If you don't reopen the module, some news can be imported twice. +**B) Import using shell** + +.. code-block:: bash + + # Import tt_news category records + ./typo3/cli_dispatch.phpsh extbase ttnewsimport:importttnewscategory + +.. code-block:: bash + + # Import tt_news news records + ./typo3/cli_dispatch.phpsh extbase ttnewsimport:importttnewsnews + Plugin migration ---------------- @@ -82,6 +106,8 @@ Usage **Important:** Run the plugin migration **after** the record migration! +**Hint:** Since TYPO3 version 9.5 command 'run' (which creates a new record below the existing plugin) will not work, if workspace versioned tt_content plugins exists with negative pids. Command 'replace' still works for TYPO3 9.5 + .. code-block:: bash # Gives you some information about how many plugins are still to be migrated @@ -89,26 +115,83 @@ Usage .. code-block:: bash - # Creates the plugins for *EXT:news* by creating a new record below the plugin of *EXT:tt_news*. - # This makes it possible for you to cross check the migration and adapt the plugins. + # Creates the plugins for *EXT:news* by creating a new record below the plugin of *EXT:tt_news* + # This makes it possible for you to cross check the migration and adapt the plugins ./typo3/cli_dispatch.phpsh extbase ttnewspluginmigrate:run .. code-block:: bash - # Replace tt_news plugins directly without creating copies. + # Replace tt_news plugins directly without creating copies ./typo3/cli_dispatch.phpsh extbase ttnewspluginmigrate:replace .. code-block:: bash - # Hide the old tt_news plugins. + # Hide the old tt_news plugins ./typo3/cli_dispatch.phpsh extbase ttnewspluginmigrate:removeOldPlugins - # Deletes the old tt_news plugins. + # Deletes the old tt_news plugins ./typo3/cli_dispatch.phpsh extbase ttnewspluginmigrate:removeOldPlugins delete=1 +Optional +-------- + +FAL +^^^ + +If EXT:fal_ttnews was used, there exists two options to migrate images/media. + +**A) Migrate manually use of updater by EXT:news_falttnewsimport** + +Download EXT:news_falttnewsimport from TER. Run the update script via ExtensionManager and unsinstall afterwards. + +**B) Migrate using shell** + +The update routine from EXT:news_falttnewsimport is implemented as command and can be executed via shell: + +.. code-block:: bash + + # Migrate fal_ttnews entries + ./typo3/cli_dispatch.phpsh extbase falttnewsmigration:migratefalttnews + +In case of EXT:tt_news plugin setting `forceFirstImageIsPreview` was used, and similar feature requires for EXT:news, each first `fal_media` entry for each news entries must be set to `showinpreview = 1` (compatible wit EXT:news v7.x): + +.. code-block:: bash + + # Set showinpreview for first news.fal_media + ./typo3/cli_dispatch.phpsh extbase falmediashowinpreview:setfirstfalmediashowinpreview + +RealUrl & Routing +^^^^^^^^^^^^^^^^^ + +In case of using EXT:realurl (TYPO3 v8.7 and below) aliases for news with similar titles should be keept. EXT:news documentation offers a SQL update to do so, which is implemented here and can be executed via shell: + +.. code-block:: bash + + # Migrate tt_news realurl unique alias + ./typo3/cli_dispatch.phpsh extbase realurluniquealiasmigration:migratettnewsrealurluniquealias + +**HINT:** The script supports EXT:realurl v2.x For versions below 2.x see class `RealUrlUniqueAliasMigrationCommandController` and switch the uncomment lines in `migrateTtNewsRealurlUniqueAliasCommand` method. + +EXT:news v7 introduces news `path_segment` for URL generation, which is compatible with EXT:realurl until TYPO3 v8.7. +TYPO3 v9.5 introduced Routing, where news `path_segment` is recommend to use for URL generation. +To keep aliases as created by EXT:realurl they should migrated to news `path_segment`: + +.. code-block:: bash + + # Migrate realurl unique alias into news.path_segment + ./typo3/cli_dispatch.phpsh extbase realurluniquealiasmigration:migraterealurluniquealiasintopathsegment + +This will only work for empty news `path_segment`! + +The result can still lead in empty slugs fields, which can be manually updated via installtool upgrade wizard "Updates slug field 'path_segment' of EXT:news records" or using EXT:typo3-console: + +.. code-block:: bash + + # Run upgrade wizard:newsSlug + ./typo3cms upgrade:wizard newsSlug Known issues -^^^^^^^^^^^^ +------------ see FAQ Section in Documentation/Misc/Index.rst diff --git a/ext_emconf.php b/ext_emconf.php index 546a8f9..9e4b564 100644 --- a/ext_emconf.php +++ b/ext_emconf.php @@ -24,9 +24,9 @@ 'version' => '2.0.0', 'constraints' => array( 'depends' => array( - 'typo3' => '6.2.4-8.99.99', + 'typo3' => '6.2.4-9.5.99', 'php' => '5.3.0-0.0.0', - 'news' => '3.0.0', + 'news' => '3.0.0-7.99.99', ), 'conflicts' => array( ), diff --git a/ext_localconf.php b/ext_localconf.php index 873aa3b..a9b6bc6 100644 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -4,5 +4,9 @@ } if (TYPO3_MODE === 'BE') { - $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['extbase']['commandControllers'][] = 'BeechIt\\NewsTtnewsimport\\Command\\TtNewsPluginMigrateCommandController'; + $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['extbase']['commandControllers'][] = 'BeechIt\\NewsTtnewsimport\\Command\\TtNewsImportCommandController'; + $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['extbase']['commandControllers'][] = 'BeechIt\\NewsTtnewsimport\\Command\\TtNewsPluginMigrateCommandController'; + $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['extbase']['commandControllers'][] = 'BeechIt\\NewsTtnewsimport\\Command\\FalTtNewsMigrationCommandController'; + $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['extbase']['commandControllers'][] = 'BeechIt\\NewsTtnewsimport\\Command\\FalMediaShowInPreviewCommandController'; + $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['extbase']['commandControllers'][] = 'BeechIt\\NewsTtnewsimport\\Command\\RealUrlUniqueAliasMigrationCommandController'; }