From 56031db5cc815ceefece73c25b973d3109682812 Mon Sep 17 00:00:00 2001 From: Mathias Brodala Date: Thu, 10 Sep 2020 17:16:58 +0200 Subject: [PATCH 01/26] [TASK] Allow installation with TYPO3v10 --- composer.json | 10 +++++----- ext_emconf.php | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/composer.json b/composer.json index e65960fc..8f7940a4 100644 --- a/composer.json +++ b/composer.json @@ -12,11 +12,11 @@ "require": { "php": "^7.2", "elasticsearch/elasticsearch": "~5.0", - "typo3/cms-backend": "^8.7 || ^9.5", - "typo3/cms-core": "^8.7 || ^9.5", - "typo3/cms-extbase": "^8.7 || ^9.5", - "typo3/cms-fluid": "^8.7 || ^9.5", - "typo3/cms-frontend": "^8.7 || ^9.5" + "typo3/cms-backend": "^8.7 || ^9.5 || ^10.4", + "typo3/cms-core": "^8.7 || ^9.5 || ^10.4", + "typo3/cms-extbase": "^8.7 || ^9.5 || ^10.4", + "typo3/cms-fluid": "^8.7 || ^9.5 || ^10.4", + "typo3/cms-frontend": "^8.7 || ^9.5 || ^10.4" }, "require-dev": { "codedungeon/phpunit-result-printer": "^0.26.0", diff --git a/ext_emconf.php b/ext_emconf.php index a06d562f..6c56e9e5 100644 --- a/ext_emconf.php +++ b/ext_emconf.php @@ -11,7 +11,7 @@ 'version' => '3.0.4', 'constraints' => [ 'depends' => [ - 'typo3' => '8.7.0-9.9.99', + 'typo3' => '8.7.0-10.4.99', ], ], ]; From abbed529fb8bd3b04ba7c3f0f60e5678456ea0a8 Mon Sep 17 00:00:00 2001 From: Mathias Brodala Date: Thu, 10 Sep 2020 17:17:31 +0200 Subject: [PATCH 02/26] [TASK] Build against TYPO3v10 --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 0e38427c..f3f229d4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,6 +8,8 @@ env: global: - PHP_VERSION=7.2 jobs: + - TYPO3_VERSION=^10.4 + - TYPO3_VERSION=^10.4 PHP_VERSION=7.4 - TYPO3_VERSION=^9.5 - TYPO3_VERSION=^9.5 PHP_VERSION=7.4 - TYPO3_VERSION=^8.7 From 36d7d1bfca87777cabb47ab631996c89d51430d3 Mon Sep 17 00:00:00 2001 From: Mathias Brodala Date: Fri, 11 Sep 2020 12:52:33 +0200 Subject: [PATCH 03/26] [TASK] Replace deprecated $GLOBALS['TSFE']->sys_language_uid access See https://docs.typo3.org/c/typo3/cms-core/master/en-us/Changelog/9.4/Deprecation-85543-Language-relatedPropertiesInTypoScriptFrontendControllerAndPageRepository.html And https://docs.typo3.org/c/typo3/cms-core/master/en-us/Changelog/10.0/Breaking-87193-DeprecatedFunctionalityRemoved.html --- Classes/LanguageIdTrait.php | 20 +++++++++++ Classes/Query/AutosuggestQuery.php | 5 ++- Classes/Query/SearchQuery.php | 5 ++- Classes/Search.php | 5 ++- .../ViewHelpers/SiteLanguageViewHelper.php | 33 +++---------------- .../ViewHelper/SiteLanguageViewHelperTest.php | 29 +++++++--------- 6 files changed, 49 insertions(+), 48 deletions(-) create mode 100644 Classes/LanguageIdTrait.php diff --git a/Classes/LanguageIdTrait.php b/Classes/LanguageIdTrait.php new file mode 100644 index 00000000..41170e19 --- /dev/null +++ b/Classes/LanguageIdTrait.php @@ -0,0 +1,20 @@ +getPropertyFromAspect('language', 'id'); + } + + // @extensionScannerIgnoreLine + return $GLOBALS['TSFE']->sys_language_uid; // @phpstan-ignore-line + } +} diff --git a/Classes/Query/AutosuggestQuery.php b/Classes/Query/AutosuggestQuery.php index 8113caa8..b0180334 100644 --- a/Classes/Query/AutosuggestQuery.php +++ b/Classes/Query/AutosuggestQuery.php @@ -1,6 +1,7 @@ respectLanguage === true) { - $language = $this->language ?: $GLOBALS['TSFE']->sys_language_uid; + $language = $this->language ?: $this->getLanguageId(); $this->parameters['index'] = ExtconfService::hasIndex($language) ? ExtconfService::getIndex($language) : ExtconfService::getIndex(); } diff --git a/Classes/Query/SearchQuery.php b/Classes/Query/SearchQuery.php index 6ee5936a..41d7d512 100644 --- a/Classes/Query/SearchQuery.php +++ b/Classes/Query/SearchQuery.php @@ -1,6 +1,7 @@ respectLanguage === true) { - $language = $this->language ?: $GLOBALS['TSFE']->sys_language_uid; + $language = $this->language ?: $this->getLanguageId(); $this->parameters['index'] = ExtconfService::hasIndex($language) ? ExtconfService::getIndex($language) : ExtconfService::getIndex(); } diff --git a/Classes/Search.php b/Classes/Search.php index 1460f34b..a97d0f8c 100644 --- a/Classes/Search.php +++ b/Classes/Search.php @@ -3,6 +3,7 @@ use Elasticsearch\Client; use PAGEmachine\Searchable\Connection; +use PAGEmachine\Searchable\LanguageIdTrait; use PAGEmachine\Searchable\Service\ExtconfService; use TYPO3\CMS\Core\SingletonInterface; use TYPO3\CMS\Core\Utility\GeneralUtility; @@ -16,6 +17,8 @@ */ class Search implements SingletonInterface { + use LanguageIdTrait; + /** * Elasticsearch client * @var Client @@ -69,7 +72,7 @@ public function search($term, $options = [], $respectLanguage = true, $forceLang } if ($respectLanguage === true) { - $language = $forceLanguage ?: $GLOBALS['TSFE']->sys_language_uid; + $language = $forceLanguage ?: $this->getLanguageId(); $params['index'] = ExtconfService::hasIndex($language) ? ExtconfService::getIndex($language) : ExtconfService::getIndex(); } diff --git a/Classes/ViewHelpers/SiteLanguageViewHelper.php b/Classes/ViewHelpers/SiteLanguageViewHelper.php index 294cca2c..6395dd83 100644 --- a/Classes/ViewHelpers/SiteLanguageViewHelper.php +++ b/Classes/ViewHelpers/SiteLanguageViewHelper.php @@ -1,9 +1,7 @@ getTypoScriptFrontendController())) { - if (version_compare(VersionNumberUtility::getCurrentTypo3Version(), '9', '<')) { - // @phpstan-ignore-next-line - return $this->getTypoScriptFrontendController()->sys_language_uid; - } else { - return $this->getLanguageAspect()->getId(); - } + if (is_object($GLOBALS['TSFE'])) { + return $this->getLanguageId(); } return 0; } - - /** - * @return \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController|null - * @codeCoverageIgnore - */ - public function getTypoScriptFrontendController() - { - return $GLOBALS['TSFE']; - } - - /** - * @return \TYPO3\CMS\Core\Context\LanguageAspect - * @codeCoverageIgnore - */ - public function getLanguageAspect() - { - return GeneralUtility::makeInstance(Context::class)->getAspect('language'); - } } diff --git a/Tests/Unit/ViewHelper/SiteLanguageViewHelperTest.php b/Tests/Unit/ViewHelper/SiteLanguageViewHelperTest.php index eac5fbfa..15c824d4 100644 --- a/Tests/Unit/ViewHelper/SiteLanguageViewHelperTest.php +++ b/Tests/Unit/ViewHelper/SiteLanguageViewHelperTest.php @@ -7,7 +7,9 @@ use PAGEmachine\Searchable\ViewHelpers\SiteLanguageViewHelper; use PHPUnit\Framework\TestCase; +use TYPO3\CMS\Core\Context\Context; use TYPO3\CMS\Core\Context\LanguageAspect; +use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController; /** @@ -25,12 +27,12 @@ class SiteLanguageViewHelperTest extends TestCase */ protected function setUp() { - $this->viewHelper = $this->getMockBuilder(SiteLanguageViewHelper::class) - ->setMethods([ - 'getTypoScriptFrontendController', - 'getLanguageAspect', - ]) - ->getMock(); + $this->viewHelper = new SiteLanguageViewHelper(); + } + + protected function tearDown() + { + unset($GLOBALS['TSFE']); } /** @@ -38,19 +40,14 @@ protected function setUp() */ public function returnsCurrentLanguage() { - $tsfe = $this->prophesize(TypoScriptFrontendController::class); + $GLOBALS['TSFE'] = $this->prophesize(TypoScriptFrontendController::class)->reveal(); - if (\TYPO3\CMS\Core\Utility\VersionNumberUtility::convertVersionNumberToInteger(TYPO3_version) < 9000000) { - $tsfe->sys_language_uid = 1; + if (class_exists(Context::class)) { + GeneralUtility::makeInstance(Context::class)->setAspect('language', new LanguageAspect(1)); } else { - $languageAspect = $this->prophesize(LanguageAspect::class); - $languageAspect->getId()->willReturn(1); - - $this->viewHelper->method("getLanguageAspect")->will($this->returnValue($languageAspect->reveal())); + $GLOBALS['TSFE']->sys_language_uid = 1; } - $this->viewHelper->method("getTypoScriptFrontendController")->will($this->returnValue($tsfe->reveal())); - $this->assertEquals(1, $this->viewHelper->render()); } @@ -59,8 +56,6 @@ public function returnsCurrentLanguage() */ public function returnsZeroIfTsfeDoesNotExist() { - $this->viewHelper->method("getTypoScriptFrontendController")->will($this->returnValue(null)); - $this->assertEquals(0, $this->viewHelper->render()); } } From bda6c33dd2b5c26a57d50b1c4f4b99ea3003810d Mon Sep 17 00:00:00 2001 From: Mathias Brodala Date: Fri, 11 Sep 2020 16:03:00 +0200 Subject: [PATCH 04/26] [TASK] Ignore cross-version errors in PHPStan --- Classes/DataCollector/TCA/PlainValueProcessor.php | 4 ---- Classes/Utility/TsfeUtility.php | 2 +- phpstan.neon | 4 ++++ 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Classes/DataCollector/TCA/PlainValueProcessor.php b/Classes/DataCollector/TCA/PlainValueProcessor.php index 1eb561ee..cc2c42f1 100644 --- a/Classes/DataCollector/TCA/PlainValueProcessor.php +++ b/Classes/DataCollector/TCA/PlainValueProcessor.php @@ -78,10 +78,6 @@ public function processRadioField($value, $fieldTca) return $label; } - - /** - * @return \TYPO3\CMS\Lang\LanguageService - */ protected function getLanguageService() { return $GLOBALS['LANG']; diff --git a/Classes/Utility/TsfeUtility.php b/Classes/Utility/TsfeUtility.php index 390528e8..74d2a9a8 100644 --- a/Classes/Utility/TsfeUtility.php +++ b/Classes/Utility/TsfeUtility.php @@ -20,7 +20,7 @@ class TsfeUtility */ public static function createTSFE() { - \TYPO3\CMS\Frontend\Utility\EidUtility::initTCA(); + \TYPO3\CMS\Frontend\Utility\EidUtility::initTCA(); // @phpstan-ignore-line if (!is_object($GLOBALS['TSFE'])) { $GLOBALS['TSFE'] = GeneralUtility::makeInstance(TypoScriptFrontendController::class, $GLOBALS['TYPO3_CONF_VARS'], 1, ''); diff --git a/phpstan.neon b/phpstan.neon index 8269f12b..6eff9cd2 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -11,6 +11,10 @@ parameters: - '#Variable \$_EXTKEY might not be defined.#' - message: '#TYPO3\\CMS\\Core\\Context\\.+#' path: Classes/ViewHelpers/SiteLanguageViewHelper.php + - message: '#TYPO3\\CMS\\Extbase\\Mvc\\Controller\\CommandController#' + paths: + - ext_localconf.php + - Classes/Command/SearchableCommandController.php - message: '#TYPO3\\CMS\\Core\\Database\\PostProcessQueryHookInterface#' paths: - ext_localconf.php From cc1646ff7f1c6a1da86e4b3a833c3d00e358753c Mon Sep 17 00:00:00 2001 From: Mathias Brodala Date: Fri, 11 Sep 2020 16:40:46 +0200 Subject: [PATCH 05/26] [BUGFIX] Fix failing TcaDataCollector unit test The ObjectManager requires native dependency injection now so make sure we always use a mock in tests. --- .../DataCollector/TcaDataCollectorTest.php | 28 ++++++++----------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/Tests/Unit/DataCollector/TcaDataCollectorTest.php b/Tests/Unit/DataCollector/TcaDataCollectorTest.php index c9cf6c18..ab783eb4 100644 --- a/Tests/Unit/DataCollector/TcaDataCollectorTest.php +++ b/Tests/Unit/DataCollector/TcaDataCollectorTest.php @@ -17,11 +17,6 @@ */ class TcaDataCollectorTest extends UnitTestCase { - /** - * @var TcaDataCollector - */ - protected $tcaDataCollector; - /** * @var OverlayUtility */ @@ -52,11 +47,10 @@ protected function setUp() $this->overlayUtility = $this->prophesize(OverlayUtility::class); - $this->tcaDataCollector = new TcaDataCollector([]); - $this->objectManager = $this->prophesize(ObjectManager::class); $this->objectManager->get(Argument::any())->willReturn(null); + GeneralUtility::setSingletonInstance(FormDataRecord::class, $this->formDataRecord->reveal()); GeneralUtility::setSingletonInstance(PlainValueProcessor::class, $this->plainValueProcessor->reveal()); GeneralUtility::setSingletonInstance(OverlayUtility::class, $this->overlayUtility->reveal()); @@ -132,7 +126,7 @@ public function processesFlatRecord() ]; - $this->tcaDataCollector->__construct($configuration, 0, $this->objectManager->reveal()); + $tcaDataCollector = new TcaDataCollector($configuration, 0, $this->objectManager->reveal()); $this->formDataRecord->getRecord(123, 'example_table', [ 'uid', @@ -160,7 +154,7 @@ public function processesFlatRecord() 'radiofield' => 'radiovalue', ]; - $this->assertEquals($expectedOutput, $this->tcaDataCollector->getRecord(123)); + $this->assertEquals($expectedOutput, $tcaDataCollector->getRecord(123)); } /** @@ -218,7 +212,7 @@ public function processesRelations() 'processedTca' => $recordTca, ]; - $this->tcaDataCollector->__construct($configuration, 0, $this->objectManager->reveal()); + $tcaDataCollector = new TcaDataCollector($configuration, 0, $this->objectManager->reveal()); $this->formDataRecord->getRecord(123, 'example_table', Argument::type('array'))->willReturn($record); @@ -227,16 +221,16 @@ public function processesRelations() ->willReturn($record['databaseRow']); $resolver = $this->prophesize(SelectRelationResolver::class); - $resolver->resolveRelation("selectfield", $record['databaseRow'], $subCollector, $this->tcaDataCollector)->willReturn([[ + $resolver->resolveRelation("selectfield", $record['databaseRow'], $subCollector, $tcaDataCollector)->willReturn([[ 'uid' => 123, 'title' => 'foobar', ]]); $resolverManager = $this->prophesize(ResolverManager::class); - $resolverManager->findResolverForRelation("selectfield", $subCollector, $this->tcaDataCollector)->willReturn($resolver->reveal()); - $this->inject($this->tcaDataCollector, "resolverManager", $resolverManager->reveal()); + $resolverManager->findResolverForRelation("selectfield", $subCollector, $tcaDataCollector)->willReturn($resolver->reveal()); + $this->inject($tcaDataCollector, "resolverManager", $resolverManager->reveal()); - $this->tcaDataCollector->addSubCollector("es_selectfield", $subCollector->reveal()); + $tcaDataCollector->addSubCollector("es_selectfield", $subCollector->reveal()); $expectedOutput = [ 'uid' => 1, @@ -249,7 +243,7 @@ public function processesRelations() ], ]; - $this->assertEquals($expectedOutput, $this->tcaDataCollector->getRecord(123)); + $this->assertEquals($expectedOutput, $tcaDataCollector->getRecord(123)); } /** @@ -293,12 +287,12 @@ public function processesTranslations() 'processedTca' => $recordTca, ]; - $this->tcaDataCollector->__construct($configuration, 1); + $tcaDataCollector = new TcaDataCollector($configuration, 1, $this->objectManager->reveal()); $this->formDataRecord->getRecord(1, 'example_table', Argument::type('array'))->willReturn($record); $this->overlayUtility->languageOverlay('example_table', $baseRow, 1, Argument::type("array"), 1)->shouldBeCalled()->willReturn($translatedRow); - $this->assertEquals($translatedRow, $this->tcaDataCollector->getRecord(1)); + $this->assertEquals($translatedRow, $tcaDataCollector->getRecord(1)); } } From e3af625a18565b665384721562f664ba2b6f9868 Mon Sep 17 00:00:00 2001 From: Mathias Brodala Date: Fri, 11 Sep 2020 16:46:40 +0200 Subject: [PATCH 06/26] [TASK] Reduce usage of $_EXTKEY --- ext_localconf.php | 6 +++--- ext_tables.php | 34 +++++++++++++++++++++++++--------- phpstan.neon | 3 ++- 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/ext_localconf.php b/ext_localconf.php index c042dcd3..fcb373ea 100644 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -6,14 +6,14 @@ $GLOBALS['TYPO3_CONF_VARS']['SC_OPTIONS']['extbase']['commandControllers']['searchable'] = \PAGEmachine\Searchable\Command\SearchableCommandController::class; \TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin( - 'PAGEmachine.' . $_EXTKEY, + 'PAGEmachine.Searchable', 'Searchbar', ['Search' => 'searchbar'], ['Search' => 'searchbar'] ); \TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin( - 'PAGEmachine.' . $_EXTKEY, + 'PAGEmachine.Searchable', 'LiveSearchbar', ['Search' => 'liveSearchbar'], ['Search' => 'liveSearchbar'] @@ -21,7 +21,7 @@ \TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin( - 'PAGEmachine.' . $_EXTKEY, + 'PAGEmachine.Searchable', 'Results', ['Search' => 'results'], ['Search' => 'results'] diff --git a/ext_tables.php b/ext_tables.php index 4efcf698..2d0677e3 100644 --- a/ext_tables.php +++ b/ext_tables.php @@ -3,28 +3,44 @@ die('Access denied.'); } -\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addStaticFile('searchable', 'Configuration/TypoScript', 'Searchable'); +\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addStaticFile( + 'searchable', + 'Configuration/TypoScript', + 'Searchable' +); \TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin( - 'PAGEmachine.' . $_EXTKEY, + 'PAGEmachine.Searchable', 'Searchbar', 'Searchable: Search bar' ); \TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin( - 'PAGEmachine.' . $_EXTKEY, + 'PAGEmachine.Searchable', 'LiveSearchbar', 'Searchable: Live Search bar (AJAX)' ); -\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue('searchable_searchbar', 'FILE:EXT:' . $_EXTKEY . '/Configuration/Flexforms/Searchbar.xml'); -\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue('searchable_livesearchbar', 'FILE:EXT:' . $_EXTKEY . '/Configuration/Flexforms/LiveSearchbar.xml'); -\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue('searchable_results', 'FILE:EXT:' . $_EXTKEY . '/Configuration/Flexforms/Results.xml'); - +\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue( + 'searchable_searchbar', + 'FILE:EXT:searchable/Configuration/Flexforms/Searchbar.xml' +); +\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue( + 'searchable_livesearchbar', + 'FILE:EXT:searchable/Configuration/Flexforms/LiveSearchbar.xml' +); +\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue( + 'searchable_results', + 'FILE:EXT:searchable/Configuration/Flexforms/Results.xml' +); -\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::registerPageTSConfigFile('PAGEmachine.' . $_EXTKEY, 'FILE:EXT:' . $_EXTKEY . '/Configuration/PageTS/ContentElementWizard.ts', 'Searchable TSConfig'); +\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::registerPageTSConfigFile( + 'searchable', + 'FILE:EXT:searchable/Configuration/PageTS/ContentElementWizard.ts', + 'Searchable TSConfig' +); \TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin( - 'PAGEmachine.' . $_EXTKEY, + 'PAGEmachine.Searchable', 'Results', 'Searchable: Results' ); diff --git a/phpstan.neon b/phpstan.neon index 6eff9cd2..8746160b 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -8,7 +8,8 @@ parameters: - Classes ignoreErrors: - - '#Variable \$_EXTKEY might not be defined.#' + - message: '#Variable \$_EXTKEY might not be defined.#' + path: ext_emconf.php - message: '#TYPO3\\CMS\\Core\\Context\\.+#' path: Classes/ViewHelpers/SiteLanguageViewHelper.php - message: '#TYPO3\\CMS\\Extbase\\Mvc\\Controller\\CommandController#' From c09faa5eb74994698c0cc764b1b27b1988bf180b Mon Sep 17 00:00:00 2001 From: Mathias Brodala Date: Tue, 15 Sep 2020 15:36:02 +0200 Subject: [PATCH 07/26] [TASK] Use own response object See https://docs.typo3.org/c/typo3/cms-core/master/en-us/Changelog/9.5/Deprecation-84196-BackendControllerActionsDoNotReceivePreparedResponse.html And https://docs.typo3.org/c/typo3/cms-core/master/en-us/Changelog/10.0/Breaking-87193-DeprecatedFunctionalityRemoved.html --- Classes/Eid/AbstractEidHandler.php | 8 ++++---- Classes/Eid/LinkBuilder.php | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Classes/Eid/AbstractEidHandler.php b/Classes/Eid/AbstractEidHandler.php index 8edb85f6..fda170e0 100644 --- a/Classes/Eid/AbstractEidHandler.php +++ b/Classes/Eid/AbstractEidHandler.php @@ -3,6 +3,7 @@ use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; +use TYPO3\CMS\Core\Http\Response; /* * This file is part of the PAGEmachine Searchable project. @@ -24,18 +25,17 @@ abstract class AbstractEidHandler * Process request * * @param ServerRequestInterface $request - * @param ResponseInterface $response - * @return null|ResponseInterface */ - public function processRequest(ServerRequestInterface $request, ResponseInterface $response) + public function processRequest(ServerRequestInterface $request): ResponseInterface { $term = $request->getQueryParams()['term']; $this->options = $request->getQueryParams()['options']; $result = $this->getResults($term); - $response = $response->withHeader('Content-type', 'application/json'); + $response = (new Response())->withHeader('Content-Type', 'application/json; charset=utf-8'); $response->getBody()->write(json_encode($result)); + return $response; } diff --git a/Classes/Eid/LinkBuilder.php b/Classes/Eid/LinkBuilder.php index 9db3f6be..1ed55308 100644 --- a/Classes/Eid/LinkBuilder.php +++ b/Classes/Eid/LinkBuilder.php @@ -4,6 +4,7 @@ use PAGEmachine\Searchable\Utility\TsfeUtility; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; +use TYPO3\CMS\Core\Http\Response; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer; @@ -31,10 +32,8 @@ public function __construct() * Process request * * @param ServerRequestInterface $request - * @param ResponseInterface $response - * @return null|ResponseInterface */ - public function processRequest(ServerRequestInterface $request, ResponseInterface $response) + public function processRequest(ServerRequestInterface $request): ResponseInterface { $configuration = $request->getParsedBody()['configuration']; @@ -46,8 +45,9 @@ public function processRequest(ServerRequestInterface $request, ResponseInterfac } } - $response = $response->withHeader('Content-type', 'application/json'); + $response = (new Response())->withHeader('Content-Type', 'application/json; charset=utf-8'); $response->getBody()->write(json_encode($links)); + return $response; } From d7ab78caf24a29ea91e471eda5e795c8a358692c Mon Sep 17 00:00:00 2001 From: Mathias Brodala Date: Wed, 16 Sep 2020 16:34:23 +0200 Subject: [PATCH 08/26] [TASK] Move webserver for functional testing to a trait --- .../Functional/AbstractElasticsearchTest.php | 23 ++---------- Tests/Functional/WebserverTrait.php | 35 +++++++++++++++++++ 2 files changed, 38 insertions(+), 20 deletions(-) create mode 100644 Tests/Functional/WebserverTrait.php diff --git a/Tests/Functional/AbstractElasticsearchTest.php b/Tests/Functional/AbstractElasticsearchTest.php index 52825665..9e53aac9 100644 --- a/Tests/Functional/AbstractElasticsearchTest.php +++ b/Tests/Functional/AbstractElasticsearchTest.php @@ -8,7 +8,6 @@ use PAGEmachine\Searchable\Connection; use PAGEmachine\Searchable\Indexer\PagesIndexer; use PAGEmachine\Searchable\Service\IndexingService; -use Symfony\Component\Process\Process; use TYPO3\CMS\Core\Core\Bootstrap; use TYPO3\CMS\Core\Crypto\Random; use TYPO3\CMS\Core\Utility\ArrayUtility; @@ -18,6 +17,8 @@ abstract class AbstractElasticsearchTest extends FunctionalTestCase { + use WebserverTrait; + /** * @var array */ @@ -30,11 +31,6 @@ abstract class AbstractElasticsearchTest extends FunctionalTestCase */ private $indexNames; - /** - * @var Process - */ - private $serverProcess; - /** * @var IndexingService */ @@ -90,18 +86,7 @@ protected function setUp() $this->indexingService = $objectManager->get(IndexingService::class); $this->indexingService->setup(); - $this->serverProcess = new Process( - [ - PHP_BINARY, - '-S', - 'localhost:8080', - ], - $this->getInstancePath(), - [ - 'TYPO3_PATH_ROOT' => $this->getInstancePath(), - ] - ); - $this->serverProcess->start(); + $this->startWebserver(); $this->getDatabaseConnection()->insertArray('pages', [ 'uid' => 1, @@ -131,8 +116,6 @@ protected function tearDown() $this->getElasticsearchClient()->indices()->delete([ 'index' => implode(',', $this->indexNames), ]); - - $this->serverProcess->stop(); } protected function assertIndexEmpty(int $languageId = 0): void diff --git a/Tests/Functional/WebserverTrait.php b/Tests/Functional/WebserverTrait.php new file mode 100644 index 00000000..0d371305 --- /dev/null +++ b/Tests/Functional/WebserverTrait.php @@ -0,0 +1,35 @@ +getLogger(__CLASS__); + $serverProcess = new Process( + [ + PHP_BINARY, + '-S', + 'localhost:8080', + ], + $this->getInstancePath(), + [ + 'TYPO3_PATH_APP' => $this->getInstancePath(), + 'TYPO3_PATH_ROOT' => $this->getInstancePath(), + ] + ); + $serverProcess->start(function (string $type, string $output) use ($logger): void { + if ($type === Process::ERR) { + $logger->error($output); + } else { + $logger->info($output); + } + }); + } +} From cc58e4a4d659d7f05e28e780ad5efbe8047876d5 Mon Sep 17 00:00:00 2001 From: Mathias Brodala Date: Wed, 16 Sep 2020 16:34:45 +0200 Subject: [PATCH 09/26] [BUGFIX] Wait for webserver to be ready See https://github.com/symfony/symfony/issues/30025#issuecomment-693439367 --- Tests/Functional/WebserverTrait.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Tests/Functional/WebserverTrait.php b/Tests/Functional/WebserverTrait.php index 0d371305..ce6c81ee 100644 --- a/Tests/Functional/WebserverTrait.php +++ b/Tests/Functional/WebserverTrait.php @@ -31,5 +31,21 @@ private function startWebserver(): void $logger->info($output); } }); + + $this->waitForServer('localhost', 8080); + } + + private function waitForServer(string $host, int $port): void + { + for ($i = 0; $i < 60; $i++) { + $socket = fsockopen($host, $port); + + if ($socket !== false) { + break; + } + + // 50ms per try + usleep(50000); + } } } From c3ee6dd2a991bdec47817d0541bee8cf3ee52f8e Mon Sep 17 00:00:00 2001 From: Mathias Brodala Date: Wed, 16 Sep 2020 18:07:12 +0200 Subject: [PATCH 10/26] [BUGFIX] Forward prepared TYPO3_* env variables to webserver This is essential for the checks in SystemEnvironmentBuilder::initializeEnvironment() where TYPO3_PATH_ROOT and TYPO3_PATH_APP must be properly related to each other. These are defined in AbstractTestSystem::setTypo3Context() and involve some processing. With this the config/var path is always the same both for the test itself as well as the website accessed by the temporary webserver. --- Tests/Functional/WebserverTrait.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/Functional/WebserverTrait.php b/Tests/Functional/WebserverTrait.php index ce6c81ee..8b1b1a23 100644 --- a/Tests/Functional/WebserverTrait.php +++ b/Tests/Functional/WebserverTrait.php @@ -20,8 +20,8 @@ private function startWebserver(): void ], $this->getInstancePath(), [ - 'TYPO3_PATH_APP' => $this->getInstancePath(), - 'TYPO3_PATH_ROOT' => $this->getInstancePath(), + 'TYPO3_PATH_APP' => getenv('TYPO3_PATH_APP'), + 'TYPO3_PATH_ROOT' => getenv('TYPO3_PATH_ROOT'), ] ); $serverProcess->start(function (string $type, string $output) use ($logger): void { From fa570f82a17bd022818d3e9d7a1e9eca75ca835a Mon Sep 17 00:00:00 2001 From: Mathias Brodala Date: Wed, 16 Sep 2020 18:09:46 +0200 Subject: [PATCH 11/26] [TASK] Add middleware for URI building in TYPO3v9+ This adds a handler for "/-/searchable/urls" urls which expects a list of Typolink configurations and returns resolved links. --- Classes/Middleware/UriBuilder.php | 61 +++++++++ Configuration/RequestMiddlewares.php | 12 ++ .../Functional/Middleware/UriBuilderTest.php | 117 ++++++++++++++++++ phpstan.neon | 2 + 4 files changed, 192 insertions(+) create mode 100644 Classes/Middleware/UriBuilder.php create mode 100644 Configuration/RequestMiddlewares.php create mode 100644 Tests/Functional/Middleware/UriBuilderTest.php diff --git a/Classes/Middleware/UriBuilder.php b/Classes/Middleware/UriBuilder.php new file mode 100644 index 00000000..8ec9980a --- /dev/null +++ b/Classes/Middleware/UriBuilder.php @@ -0,0 +1,61 @@ +getUri()->getPath(), '/-/searchable/urls') !== 0) { + return $handler->handle($request); + } + + $this->bootFrontendController($request); + + $configurations = $request->getParsedBody()['configurations'] ?? []; + $uris = []; + $contentObjectRenderer = GeneralUtility::makeInstance(ContentObjectRenderer::class); + + foreach ($configurations as $index => $configuration) { + $uris[$index] = $contentObjectRenderer->typoLink_URL($configuration); + } + + $response = new JsonResponse($uris); + + return $response; + } + + private function bootFrontendController(ServerRequestInterface $request): void + { + $frontendController = GeneralUtility::makeInstance( + TypoScriptFrontendController::class, + GeneralUtility::makeInstance(Context::class), + $request->getAttribute('site'), + $request->getAttribute('language'), + $request->getAttribute('routing'), + $request->getAttribute('frontend.user') + ); + $frontendController->fetch_the_id($request); + + $GLOBALS['TSFE'] = $frontendController; + } +} diff --git a/Configuration/RequestMiddlewares.php b/Configuration/RequestMiddlewares.php new file mode 100644 index 00000000..4b90db45 --- /dev/null +++ b/Configuration/RequestMiddlewares.php @@ -0,0 +1,12 @@ + [ + 'fes/api/routing' => [ + 'target' => \PAGEmachine\Searchable\Middleware\UriBuilder::class, + 'before' => [ + 'typo3/cms-frontend/static-route-resolver', + ], + ], + ], +]; diff --git a/Tests/Functional/Middleware/UriBuilderTest.php b/Tests/Functional/Middleware/UriBuilderTest.php new file mode 100644 index 00000000..b4951337 --- /dev/null +++ b/Tests/Functional/Middleware/UriBuilderTest.php @@ -0,0 +1,117 @@ +getConnectionForTable('pages'); + $connection->bulkInsert( + 'pages', + [ + [ + 'uid' => 1, + 'pid' => 0, + 'title' => 'Root page', + 'slug' => '/', + ], + [ + 'uid' => 2, + 'pid' => 1, + 'title' => 'Some page', + 'slug' => '/some-page/', + ], + [ + 'uid' => 3, + 'pid' => 1, + 'title' => 'Other page', + 'slug' => '/other-page/', + ], + [ + 'uid' => 4, + 'pid' => 1, + 'title' => 'Nested page', + 'slug' => '/some-page/nested-page/', + ], + ], + [ + 'uid', + 'pid', + 'title', + 'slug', + ] + ); + + $siteConfiguration = GeneralUtility::makeInstance(SiteConfiguration::class); + $siteConfiguration->createNewBasicSite('test', 1, '/'); + + $response = GeneralUtility::makeInstance(RequestFactory::class)->request( + 'http://localhost:8080/-/searchable/urls', + 'POST', + [ + 'form_params' => [ + 'configurations' => [ + [ + 'parameter' => 3, + ], + [ + 'parameter' => 2, + ], + [ + 'parameter' => 4, + ], + ], + ], + 'http_errors' => false, + ] + ); + $result = json_decode((string)$response->getBody(), true); + $expected = [ + '/other-page/', + '/some-page/', + '/some-page/nested-page/', + ]; + + $this->assertEquals($expected, $result); + } + + /** + * @return void + */ + protected function setUp() + { + parent::setUp(); + + if (version_compare(VersionNumberUtility::getCurrentTypo3Version(), '9', '<')) { + $this->markTestSkipped('TYPO3v9+ only'); + } + + $this->startWebserver(); + } +} diff --git a/phpstan.neon b/phpstan.neon index 8746160b..3105c913 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -10,6 +10,8 @@ parameters: ignoreErrors: - message: '#Variable \$_EXTKEY might not be defined.#' path: ext_emconf.php + - message: '#Psr\\Http\\Server\\MiddlewareInterface#' + path: Classes/Middleware/UriBuilder.php - message: '#TYPO3\\CMS\\Core\\Context\\.+#' path: Classes/ViewHelpers/SiteLanguageViewHelper.php - message: '#TYPO3\\CMS\\Extbase\\Mvc\\Controller\\CommandController#' From cdd8de230eb6f7804844cf01dde36167b25e845f Mon Sep 17 00:00:00 2001 From: Mathias Brodala Date: Wed, 16 Sep 2020 18:26:51 +0200 Subject: [PATCH 12/26] [TASK] Set slugs in indexing test for TYPO3v9+ --- .../Functional/Service/IndexingServiceTest.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Tests/Functional/Service/IndexingServiceTest.php b/Tests/Functional/Service/IndexingServiceTest.php index b1353a50..d3ab2db6 100644 --- a/Tests/Functional/Service/IndexingServiceTest.php +++ b/Tests/Functional/Service/IndexingServiceTest.php @@ -56,6 +56,10 @@ public function indexesRecordsFully(): void 'title' => 'Test page', ]); + if (version_compare(VersionNumberUtility::getCurrentTypo3Version(), '9', '>=')) { + $this->getDatabaseConnection()->updateArray('pages', ['uid' => 2], ['slug' => '/test-page/']); + } + $this->assertIndexEmpty(); $this->indexingService->indexFull(); @@ -81,6 +85,10 @@ public function indexesRecordTranslations(): void 'title' => 'Test page', ]); + if (version_compare(VersionNumberUtility::getCurrentTypo3Version(), '9', '>=')) { + $this->getDatabaseConnection()->updateArray('pages', ['uid' => 2], ['slug' => '/test-page/']); + } + if (version_compare(VersionNumberUtility::getCurrentTypo3Version(), '9', '>=')) { $this->getDatabaseConnection()->insertArray('pages', [ 'uid' => 3, @@ -90,6 +98,10 @@ public function indexesRecordTranslations(): void 'doktype' => PageRepository::DOKTYPE_DEFAULT, 'title' => 'Translated test page', ]); + + if (version_compare(VersionNumberUtility::getCurrentTypo3Version(), '9', '>=')) { + $this->getDatabaseConnection()->updateArray('pages', ['uid' => 3], ['slug' => '/translated-test-page/']); + } } else { $this->getDatabaseConnection()->insertArray('pages_language_overlay', [ 'uid' => 3, @@ -125,6 +137,11 @@ public function indexesRecordsPartially(): void 'doktype' => PageRepository::DOKTYPE_DEFAULT, 'title' => 'Test page', ]); + + if (version_compare(VersionNumberUtility::getCurrentTypo3Version(), '9', '>=')) { + $this->getDatabaseConnection()->updateArray('pages', ['uid' => 2], ['slug' => '/test-page/']); + } + $this->indexingService->indexFull(); $this->assertDocumentInIndex([ From f2c1d985f06260972994a5c21a68bd055e254f4e Mon Sep 17 00:00:00 2001 From: Mathias Brodala Date: Wed, 16 Sep 2020 18:28:51 +0200 Subject: [PATCH 13/26] [TASK] Skip EidUtility usage if absent in TYPO3v10+ See https://docs.typo3.org/c/typo3/cms-core/master/en-us/Changelog/9.4/Deprecation-85878-EidUtilityAndVariousTSFEMethods.html And https://docs.typo3.org/c/typo3/cms-core/master/en-us/Changelog/10.0/Breaking-87193-DeprecatedFunctionalityRemoved.html?highlight=eidutil --- Classes/Utility/TsfeUtility.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Classes/Utility/TsfeUtility.php b/Classes/Utility/TsfeUtility.php index 74d2a9a8..e26bc4ee 100644 --- a/Classes/Utility/TsfeUtility.php +++ b/Classes/Utility/TsfeUtility.php @@ -3,6 +3,7 @@ use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController; +use TYPO3\CMS\Frontend\Utility\EidUtility; /* * This file is part of the PAGEmachine Searchable project. @@ -20,7 +21,11 @@ class TsfeUtility */ public static function createTSFE() { - \TYPO3\CMS\Frontend\Utility\EidUtility::initTCA(); // @phpstan-ignore-line + // @extensionScannerIgnoreLine + if (class_exists(EidUtility::class)) { + // @extensionScannerIgnoreLine + EidUtility::initTCA(); // @phpstan-ignore-line + } if (!is_object($GLOBALS['TSFE'])) { $GLOBALS['TSFE'] = GeneralUtility::makeInstance(TypoScriptFrontendController::class, $GLOBALS['TYPO3_CONF_VARS'], 1, ''); From 96698691f038c91620e62efbcd76907e74b39a06 Mon Sep 17 00:00:00 2001 From: Mathias Brodala Date: Wed, 16 Sep 2020 18:30:21 +0200 Subject: [PATCH 14/26] [TASK] Skip TSFE simulation for record overlays in TYPO3v10+ --- Classes/DataCollector/Utility/OverlayUtility.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Classes/DataCollector/Utility/OverlayUtility.php b/Classes/DataCollector/Utility/OverlayUtility.php index b9ee12be..8aa125c5 100644 --- a/Classes/DataCollector/Utility/OverlayUtility.php +++ b/Classes/DataCollector/Utility/OverlayUtility.php @@ -5,6 +5,7 @@ use PAGEmachine\Searchable\Utility\TsfeUtility; use TYPO3\CMS\Core\SingletonInterface; use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Core\Utility\VersionNumberUtility; use TYPO3\CMS\Frontend\Page\PageRepository; /* @@ -32,7 +33,10 @@ public static function getInstance() */ public function __construct(PageRepository $pageRepository = null) { - TsfeUtility::createTSFE(); + if (version_compare(VersionNumberUtility::getCurrentTypo3Version(), '10', '<')) { + TsfeUtility::createTSFE(); + } + $this->pageRepository = $pageRepository ?: GeneralUtility::makeInstance(PageRepository::class); } From 072e1b9b1864465556075541fe6aaffc723691fe Mon Sep 17 00:00:00 2001 From: Mathias Brodala Date: Thu, 17 Sep 2020 08:56:21 +0200 Subject: [PATCH 15/26] [TASK] Drop logging from functional test webserver For some reason the log file handle is missing sometimes leading to failing fwrite() calls in FileWriter. Thus drop this completely for now. --- Tests/Functional/WebserverTrait.php | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/Tests/Functional/WebserverTrait.php b/Tests/Functional/WebserverTrait.php index 8b1b1a23..9bc81d0b 100644 --- a/Tests/Functional/WebserverTrait.php +++ b/Tests/Functional/WebserverTrait.php @@ -4,15 +4,12 @@ namespace PAGEmachine\Searchable\Tests\Functional; use Symfony\Component\Process\Process; -use TYPO3\CMS\Core\Log\LogManager; -use TYPO3\CMS\Core\Utility\GeneralUtility; trait WebserverTrait { private function startWebserver(): void { - $logger = GeneralUtility::makeInstance(LogManager::class)->getLogger(__CLASS__); - $serverProcess = new Process( + (new Process( [ PHP_BINARY, '-S', @@ -23,14 +20,7 @@ private function startWebserver(): void 'TYPO3_PATH_APP' => getenv('TYPO3_PATH_APP'), 'TYPO3_PATH_ROOT' => getenv('TYPO3_PATH_ROOT'), ] - ); - $serverProcess->start(function (string $type, string $output) use ($logger): void { - if ($type === Process::ERR) { - $logger->error($output); - } else { - $logger->info($output); - } - }); + ))->start(); $this->waitForServer('localhost', 8080); } From 631c08e7c9ca9c38f81a15b6adc9c3b4f76e6f43 Mon Sep 17 00:00:00 2001 From: Mathias Brodala Date: Thu, 17 Sep 2020 09:01:40 +0200 Subject: [PATCH 16/26] [BUGFIX] Properly create SiteConfiguration in TYPO3v9 Only in TYPO3v10+ dependency injection takes care of passing the required constructor argument. --- Tests/Functional/Middleware/UriBuilderTest.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Tests/Functional/Middleware/UriBuilderTest.php b/Tests/Functional/Middleware/UriBuilderTest.php index b4951337..1af4f900 100644 --- a/Tests/Functional/Middleware/UriBuilderTest.php +++ b/Tests/Functional/Middleware/UriBuilderTest.php @@ -6,6 +6,7 @@ use Nimut\TestingFramework\TestCase\FunctionalTestCase; use PAGEmachine\Searchable\Tests\Functional\WebserverTrait; use TYPO3\CMS\Core\Configuration\SiteConfiguration; +use TYPO3\CMS\Core\Core\Environment; use TYPO3\CMS\Core\Database\ConnectionPool; use TYPO3\CMS\Core\Http\RequestFactory; use TYPO3\CMS\Core\Utility\GeneralUtility; @@ -68,7 +69,10 @@ public function buildsUriForTypolinkParameter(): void ] ); - $siteConfiguration = GeneralUtility::makeInstance(SiteConfiguration::class); + $siteConfiguration = GeneralUtility::makeInstance( + SiteConfiguration::class, + Environment::getConfigPath() . '/sites' + ); $siteConfiguration->createNewBasicSite('test', 1, '/'); $response = GeneralUtility::makeInstance(RequestFactory::class)->request( From d716df8f6e31144c04c73cd479e529d796586409 Mon Sep 17 00:00:00 2001 From: Mathias Brodala Date: Thu, 17 Sep 2020 09:19:02 +0200 Subject: [PATCH 17/26] [BUGFIX] Explicitly stop webserver again --- Tests/Functional/AbstractElasticsearchTest.php | 2 ++ Tests/Functional/Middleware/UriBuilderTest.php | 8 ++++++++ Tests/Functional/WebserverTrait.php | 17 ++++++++++++++--- 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/Tests/Functional/AbstractElasticsearchTest.php b/Tests/Functional/AbstractElasticsearchTest.php index 9e53aac9..d069a646 100644 --- a/Tests/Functional/AbstractElasticsearchTest.php +++ b/Tests/Functional/AbstractElasticsearchTest.php @@ -116,6 +116,8 @@ protected function tearDown() $this->getElasticsearchClient()->indices()->delete([ 'index' => implode(',', $this->indexNames), ]); + + $this->stopWebserver(); } protected function assertIndexEmpty(int $languageId = 0): void diff --git a/Tests/Functional/Middleware/UriBuilderTest.php b/Tests/Functional/Middleware/UriBuilderTest.php index 1af4f900..7ada5a1e 100644 --- a/Tests/Functional/Middleware/UriBuilderTest.php +++ b/Tests/Functional/Middleware/UriBuilderTest.php @@ -118,4 +118,12 @@ protected function setUp() $this->startWebserver(); } + + /** + * @return void + */ + protected function tearDown() + { + $this->stopWebserver(); + } } diff --git a/Tests/Functional/WebserverTrait.php b/Tests/Functional/WebserverTrait.php index 9bc81d0b..2513b1c4 100644 --- a/Tests/Functional/WebserverTrait.php +++ b/Tests/Functional/WebserverTrait.php @@ -7,9 +7,14 @@ trait WebserverTrait { - private function startWebserver(): void + /** + * @var Process + */ + private $serverProcess; + + protected function startWebserver(): void { - (new Process( + $this->serverProcess = new Process( [ PHP_BINARY, '-S', @@ -20,11 +25,17 @@ private function startWebserver(): void 'TYPO3_PATH_APP' => getenv('TYPO3_PATH_APP'), 'TYPO3_PATH_ROOT' => getenv('TYPO3_PATH_ROOT'), ] - ))->start(); + ); + $this->serverProcess->start(); $this->waitForServer('localhost', 8080); } + protected function stopWebserver(): void + { + $this->serverProcess->stop(0); + } + private function waitForServer(string $host, int $port): void { for ($i = 0; $i < 60; $i++) { From 0c70ed720f0334c9d5fbb15995defad5ee324085 Mon Sep 17 00:00:00 2001 From: Mathias Brodala Date: Thu, 17 Sep 2020 09:22:46 +0200 Subject: [PATCH 18/26] [BUGFIX] Update expected links in test for TYPO3v9+ --- Tests/Functional/Service/IndexingServiceTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/Functional/Service/IndexingServiceTest.php b/Tests/Functional/Service/IndexingServiceTest.php index d3ab2db6..39f2127a 100644 --- a/Tests/Functional/Service/IndexingServiceTest.php +++ b/Tests/Functional/Service/IndexingServiceTest.php @@ -68,7 +68,7 @@ public function indexesRecordsFully(): void 'uid' => 2, 'title' => 'Test page', 'searchable_meta' => [ - 'renderedLink' => 'index.php?id=2', + 'renderedLink' => version_compare(VersionNumberUtility::getCurrentTypo3Version(), '9', '>=') ? '/test-page/' : 'index.php?id=2', ], ]); } @@ -121,7 +121,7 @@ public function indexesRecordTranslations(): void 'uid' => 2, 'title' => 'Translated test page', 'searchable_meta' => [ - 'renderedLink' => 'index.php?id=2&L=1', + 'renderedLink' => version_compare(VersionNumberUtility::getCurrentTypo3Version(), '9', '>=') ? '/da/translated-test-page/' : 'index.php?id=2&L=1', ], ], 1); } From d1c6a796eea7e4c353d1359ce14b6fc3e2734abc Mon Sep 17 00:00:00 2001 From: Mathias Brodala Date: Thu, 17 Sep 2020 09:33:58 +0200 Subject: [PATCH 19/26] [TASK] Use cross-version setup for sites in tests again Unfortunately SiteConfiguration::createBasicSite() was added with TYPO3v10 so we need to stick to the basic variant of the testing framework instead. --- Tests/Functional/Middleware/UriBuilderTest.php | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/Tests/Functional/Middleware/UriBuilderTest.php b/Tests/Functional/Middleware/UriBuilderTest.php index 7ada5a1e..6f92e61b 100644 --- a/Tests/Functional/Middleware/UriBuilderTest.php +++ b/Tests/Functional/Middleware/UriBuilderTest.php @@ -5,8 +5,6 @@ use Nimut\TestingFramework\TestCase\FunctionalTestCase; use PAGEmachine\Searchable\Tests\Functional\WebserverTrait; -use TYPO3\CMS\Core\Configuration\SiteConfiguration; -use TYPO3\CMS\Core\Core\Environment; use TYPO3\CMS\Core\Database\ConnectionPool; use TYPO3\CMS\Core\Http\RequestFactory; use TYPO3\CMS\Core\Utility\GeneralUtility; @@ -69,11 +67,7 @@ public function buildsUriForTypolinkParameter(): void ] ); - $siteConfiguration = GeneralUtility::makeInstance( - SiteConfiguration::class, - Environment::getConfigPath() . '/sites' - ); - $siteConfiguration->createNewBasicSite('test', 1, '/'); + $this->setUpFrontendRootPage(1); $response = GeneralUtility::makeInstance(RequestFactory::class)->request( 'http://localhost:8080/-/searchable/urls', @@ -92,7 +86,6 @@ public function buildsUriForTypolinkParameter(): void ], ], ], - 'http_errors' => false, ] ); $result = json_decode((string)$response->getBody(), true); From 34c273f7ce76f184f0617bc25e28e5c757b21d87 Mon Sep 17 00:00:00 2001 From: Mathias Brodala Date: Thu, 17 Sep 2020 09:38:00 +0200 Subject: [PATCH 20/26] [BUGFIX] Fix TSFE booting for TYPO3v9 --- Classes/Middleware/UriBuilder.php | 16 ++++++++++++++++ Classes/Utility/TsfeUtility.php | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/Classes/Middleware/UriBuilder.php b/Classes/Middleware/UriBuilder.php index 8ec9980a..37f6e561 100644 --- a/Classes/Middleware/UriBuilder.php +++ b/Classes/Middleware/UriBuilder.php @@ -10,6 +10,7 @@ use TYPO3\CMS\Core\Context\Context; use TYPO3\CMS\Core\Http\JsonResponse; use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Core\Utility\VersionNumberUtility; use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer; use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController; @@ -46,6 +47,21 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface private function bootFrontendController(ServerRequestInterface $request): void { + if (version_compare(VersionNumberUtility::getCurrentTypo3Version(), '10', '<')) { + $frontendController = GeneralUtility::makeInstance( + TypoScriptFrontendController::class, + null, + 1, + 0 + ); + $frontendController->initFEuser(); + $frontendController->fetch_the_id(); + + $GLOBALS['TSFE'] = $frontendController; + + return; + } + $frontendController = GeneralUtility::makeInstance( TypoScriptFrontendController::class, GeneralUtility::makeInstance(Context::class), diff --git a/Classes/Utility/TsfeUtility.php b/Classes/Utility/TsfeUtility.php index e26bc4ee..de3f03b8 100644 --- a/Classes/Utility/TsfeUtility.php +++ b/Classes/Utility/TsfeUtility.php @@ -28,7 +28,7 @@ public static function createTSFE() } if (!is_object($GLOBALS['TSFE'])) { - $GLOBALS['TSFE'] = GeneralUtility::makeInstance(TypoScriptFrontendController::class, $GLOBALS['TYPO3_CONF_VARS'], 1, ''); + $GLOBALS['TSFE'] = GeneralUtility::makeInstance(TypoScriptFrontendController::class, $GLOBALS['TYPO3_CONF_VARS'], 1, 0); if (method_exists($GLOBALS['TSFE'], 'connectToDB')) { // TYPO3v9+ // @extensionScannerIgnoreLine From a15355b578ac429ebfd68e84a894b890763b3ce0 Mon Sep 17 00:00:00 2001 From: Mathias Brodala Date: Thu, 17 Sep 2020 10:19:17 +0200 Subject: [PATCH 21/26] [TASK] Merge AbstractEidLinkBuilder into AbstractLinkBuilder --- .../LinkBuilder/AbstractEidLinkBuilder.php | 128 ------------------ Classes/LinkBuilder/AbstractLinkBuilder.php | 107 ++++++++++++++- Classes/LinkBuilder/FileLinkBuilder.php | 2 +- Classes/LinkBuilder/LinkBuilderInterface.php | 2 +- Classes/LinkBuilder/PageLinkBuilder.php | 2 +- Classes/LinkBuilder/TypoLinkBuilder.php | 2 +- .../AbstractEidLinkBuilderTest.php | 51 ------- .../LinkBuilder/AbstractLinkBuilderTest.php | 26 ++++ 8 files changed, 135 insertions(+), 185 deletions(-) delete mode 100644 Classes/LinkBuilder/AbstractEidLinkBuilder.php delete mode 100644 Tests/Unit/LinkBuilder/AbstractEidLinkBuilderTest.php diff --git a/Classes/LinkBuilder/AbstractEidLinkBuilder.php b/Classes/LinkBuilder/AbstractEidLinkBuilder.php deleted file mode 100644 index 329f894b..00000000 --- a/Classes/LinkBuilder/AbstractEidLinkBuilder.php +++ /dev/null @@ -1,128 +0,0 @@ - 'title', - 'fixedParts' => [], - 'languageParam' => 'L', - ]; - - /** - * The default title if the title field is empty - * - * @var string - */ - protected $defaultTitle = "Link"; - - /** - * Creates links for a batch of records - * - * @param array $records - * @param int $language - * @return array $records - */ - public function createLinksForBatch($records, $language = 0) - { - $configurationArray = []; - $metaField = ExtconfService::getInstance()->getMetaFieldname(); - - foreach ($records as $key => $record) { - $linkConfiguration = $this->createLinkConfiguration($record, $language); - $linkConfiguration = $this->convertToTypoLinkConfig($linkConfiguration, $record); - - $configurationArray[$key] = $linkConfiguration; - } - - $links = $this->getFrontendLinks($configurationArray); - - foreach ($links as $key => $link) { - $records[$key][$metaField]['renderedLink'] = $link; - $records[$key][$metaField]['linkTitle'] = $this->getLinkTitle($records[$key]); - } - - return $records; - } - - /** - * Converts builder-specific configuration to TypoLink configuration - * This should be overridden with custom conversion logic - * - * @param array $configuration - * @param array $record - * @return array - */ - public function convertToTypoLinkConfig($configuration, $record) - { - return ['title' => $this->getLinkTitle($record), 'conf' => $configuration]; - } - - public function getFrontendLinks($configuration) - { - $domain = ExtconfService::getInstance()->getFrontendDomain(); - - return $this->doRequest($domain, $configuration); - } - - /** - * The actual request - * - * @param string $domain - * @param array $configuration - * @return array - */ - public function doRequest($domain, $configuration) - { - $requestFactory = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Http\RequestFactory::class); - $response = $requestFactory->request( - $domain, - 'POST', - [ - 'query' => [ - 'eID' => 'searchable_linkbuilder', - ], - 'form_params' => [ - 'configuration' => $configuration, - ], - 'http_errors' => false, - ] - ); - - return json_decode($response->getBody()->getContents(), true); - } - - /** - * Fetches the link title - * - * @param array $record - * @return string - */ - protected function getLinkTitle($record = []) - { - $title = $record[$this->config['titleField']]; - - if ($title == null) { - $title = $this->defaultTitle; - } - - return $title; - } -} diff --git a/Classes/LinkBuilder/AbstractLinkBuilder.php b/Classes/LinkBuilder/AbstractLinkBuilder.php index 2d0d0c90..e210583b 100644 --- a/Classes/LinkBuilder/AbstractLinkBuilder.php +++ b/Classes/LinkBuilder/AbstractLinkBuilder.php @@ -3,6 +3,8 @@ use PAGEmachine\Searchable\Configuration\DynamicConfigurationInterface; use PAGEmachine\Searchable\Service\ConfigurationMergerService; +use PAGEmachine\Searchable\Service\ExtconfService; +use TYPO3\CMS\Core\Utility\GeneralUtility; /* * This file is part of the PAGEmachine Searchable project. @@ -11,7 +13,7 @@ /** * AbstractLinkBuilder */ -abstract class AbstractLinkBuilder implements DynamicConfigurationInterface +abstract class AbstractLinkBuilder implements LinkBuilderInterface, DynamicConfigurationInterface { /** * DefaultConfiguration @@ -20,10 +22,18 @@ abstract class AbstractLinkBuilder implements DynamicConfigurationInterface * @var array */ protected static $defaultConfiguration = [ + 'titleField' => 'title', 'fixedParts' => [], 'languageParam' => 'L', ]; + /** + * The default title if the title field is empty + * + * @var string + */ + protected $defaultTitle = 'Link'; + /** * This function will be called by the ConfigurationManager. * It can be used to add default configuration @@ -71,6 +81,65 @@ public function createLinkConfiguration($record, $language) return $linkConfiguration; } + /** + * Creates links for a batch of records + * + * @param array $records + * @param int $language + * @return array $records + */ + public function createLinksForBatch($records, $language = 0) + { + $configurationArray = []; + $metaField = ExtconfService::getInstance()->getMetaFieldname(); + + foreach ($records as $key => $record) { + $linkConfiguration = $this->createLinkConfiguration($record, $language); + $linkConfiguration = $this->convertToTypoLinkConfig($linkConfiguration, $record); + + $configurationArray[$key] = $linkConfiguration; + } + + $links = $this->getFrontendLinks($configurationArray); + + foreach ($links as $key => $link) { + $records[$key][$metaField]['renderedLink'] = $link; + $records[$key][$metaField]['linkTitle'] = $this->getLinkTitle($records[$key]); + } + + return $records; + } + + /** + * Converts builder-specific configuration to TypoLink configuration + * This should be overridden with custom conversion logic + * + * @param array $configuration + * @param array $record + * @return array + */ + public function convertToTypoLinkConfig($configuration, $record) + { + return ['title' => $this->getLinkTitle($record), 'conf' => $configuration]; + } + + /** + * Fetches the link title + * + * @param array $record + * @return string + */ + protected function getLinkTitle($record = []) + { + $title = $record[$this->config['titleField']]; + + if ($title == null) { + $title = $this->defaultTitle; + } + + return $title; + } + /** * Adds a language parameter to the link config for translations * @@ -84,7 +153,7 @@ protected function addLanguageParameter($linkConfiguration, $language) if ($language > 0) { $linkConfiguration['additionalParams'][$this->config['languageParam']] = $language; } - + return $linkConfiguration; } @@ -108,4 +177,38 @@ protected function replaceFieldsRecursive($configuration, $record) return $configuration; } + + protected function getFrontendLinks($configuration) + { + $domain = ExtconfService::getInstance()->getFrontendDomain(); + + return $this->doRequest($domain, $configuration); + } + + /** + * The actual request + * + * @param string $domain + * @param array $configuration + * @return array + */ + protected function doRequest($domain, $configuration) + { + $requestFactory = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Http\RequestFactory::class); + $response = $requestFactory->request( + $domain, + 'POST', + [ + 'query' => [ + 'eID' => 'searchable_linkbuilder', + ], + 'form_params' => [ + 'configuration' => $configuration, + ], + 'http_errors' => false, + ] + ); + + return json_decode($response->getBody()->getContents(), true); + } } diff --git a/Classes/LinkBuilder/FileLinkBuilder.php b/Classes/LinkBuilder/FileLinkBuilder.php index ec37bb61..05cd0344 100644 --- a/Classes/LinkBuilder/FileLinkBuilder.php +++ b/Classes/LinkBuilder/FileLinkBuilder.php @@ -9,7 +9,7 @@ * FileLinkBuilder * Creates a file link (using t3://file) and processes it via eID to a real link */ -class FileLinkBuilder extends AbstractEidLinkBuilder implements LinkBuilderInterface +class FileLinkBuilder extends AbstractLinkBuilder { /** * DefaultConfiguration diff --git a/Classes/LinkBuilder/LinkBuilderInterface.php b/Classes/LinkBuilder/LinkBuilderInterface.php index d3579045..634ca98e 100644 --- a/Classes/LinkBuilder/LinkBuilderInterface.php +++ b/Classes/LinkBuilder/LinkBuilderInterface.php @@ -12,7 +12,7 @@ interface LinkBuilderInterface * * @param array $record * @param int $language - * @return string + * @return array */ public function createLinkConfiguration($record, $language); diff --git a/Classes/LinkBuilder/PageLinkBuilder.php b/Classes/LinkBuilder/PageLinkBuilder.php index 73b8995f..9f62595e 100644 --- a/Classes/LinkBuilder/PageLinkBuilder.php +++ b/Classes/LinkBuilder/PageLinkBuilder.php @@ -11,7 +11,7 @@ * PageLinkBuilder * Creates a link configuration array to be passed on to a Fluid link.page ViewHelper */ -class PageLinkBuilder extends AbstractEidLinkBuilder implements LinkBuilderInterface +class PageLinkBuilder extends AbstractLinkBuilder { /** * @var array diff --git a/Classes/LinkBuilder/TypoLinkBuilder.php b/Classes/LinkBuilder/TypoLinkBuilder.php index cd102324..8baf9936 100644 --- a/Classes/LinkBuilder/TypoLinkBuilder.php +++ b/Classes/LinkBuilder/TypoLinkBuilder.php @@ -11,7 +11,7 @@ * TypoLinkBuilder * Creates a link based on typolink configuration */ -class TypoLinkBuilder extends AbstractEidLinkBuilder implements LinkBuilderInterface +class TypoLinkBuilder extends AbstractLinkBuilder { /** * @var array diff --git a/Tests/Unit/LinkBuilder/AbstractEidLinkBuilderTest.php b/Tests/Unit/LinkBuilder/AbstractEidLinkBuilderTest.php deleted file mode 100644 index 9a3e9ba6..00000000 --- a/Tests/Unit/LinkBuilder/AbstractEidLinkBuilderTest.php +++ /dev/null @@ -1,51 +0,0 @@ -linkBuilder = $this->getMockForAbstractClass(AbstractEidLinkBuilder::class); - } - - /** - * @test - */ - public function convertsToTypoLinkConfig() - { - $record = ['title' => 'sometitle']; - - $builderConfig = [ - 'titleField' => 'title', - ]; - - $linkConfig = [ - 'foo' => 'bar', - ]; - - $typolinkConfig = [ - 'title' => 'sometitle', - 'conf' => ['foo' => 'bar'], - ]; - - $this->linkBuilder = $this->getAccessibleMockForAbstractClass(AbstractEidLinkBuilder::class, ['config' => $builderConfig]); - $linkConfiguration = $this->linkBuilder->convertToTypoLinkConfig($linkConfig, $record); - - $this->assertEquals($typolinkConfig, $linkConfiguration); - } -} diff --git a/Tests/Unit/LinkBuilder/AbstractLinkBuilderTest.php b/Tests/Unit/LinkBuilder/AbstractLinkBuilderTest.php index 560b0464..a0e217d9 100644 --- a/Tests/Unit/LinkBuilder/AbstractLinkBuilderTest.php +++ b/Tests/Unit/LinkBuilder/AbstractLinkBuilderTest.php @@ -155,4 +155,30 @@ public function unsetsEmptyDynamicFieldsAndUsesFixedPartInstead() $this->assertArraySubset(['pageUid' => '123'], $linkConfiguration); } + + /** + * @test + */ + public function convertsToTypoLinkConfig() + { + $record = ['title' => 'sometitle']; + + $builderConfig = [ + 'titleField' => 'title', + ]; + + $linkConfig = [ + 'foo' => 'bar', + ]; + + $typolinkConfig = [ + 'title' => 'sometitle', + 'conf' => ['foo' => 'bar'], + ]; + + $this->linkBuilder = $this->getAccessibleMockForAbstractClass(AbstractLinkBuilder::class, ['config' => $builderConfig]); + $linkConfiguration = $this->linkBuilder->convertToTypoLinkConfig($linkConfig, $record); + + $this->assertEquals($typolinkConfig, $linkConfiguration); + } } From 27691d39e373be7b2e75409d386fd6c4f5364eda Mon Sep 17 00:00:00 2001 From: Mathias Brodala Date: Thu, 17 Sep 2020 11:23:48 +0200 Subject: [PATCH 22/26] [TASK] Use middleware for link building in TYPO3v9+ --- Classes/LinkBuilder/AbstractLinkBuilder.php | 49 +++++++------------ .../LinkBuilder/Frontend/FrontendRequest.php | 39 +++++++++++++++ .../Frontend/FrontendRequestInterface.php | 11 +++++ .../Frontend/LegacyFrontendRequest.php | 41 ++++++++++++++++ ext_localconf.php | 4 +- 5 files changed, 113 insertions(+), 31 deletions(-) create mode 100644 Classes/LinkBuilder/Frontend/FrontendRequest.php create mode 100644 Classes/LinkBuilder/Frontend/FrontendRequestInterface.php create mode 100644 Classes/LinkBuilder/Frontend/LegacyFrontendRequest.php diff --git a/Classes/LinkBuilder/AbstractLinkBuilder.php b/Classes/LinkBuilder/AbstractLinkBuilder.php index e210583b..50fe7ac7 100644 --- a/Classes/LinkBuilder/AbstractLinkBuilder.php +++ b/Classes/LinkBuilder/AbstractLinkBuilder.php @@ -2,9 +2,13 @@ namespace PAGEmachine\Searchable\LinkBuilder; use PAGEmachine\Searchable\Configuration\DynamicConfigurationInterface; +use PAGEmachine\Searchable\LinkBuilder\Frontend\FrontendRequest; +use PAGEmachine\Searchable\LinkBuilder\Frontend\LegacyFrontendRequest; use PAGEmachine\Searchable\Service\ConfigurationMergerService; use PAGEmachine\Searchable\Service\ExtconfService; +use TYPO3\CMS\Core\Http\Uri; use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Core\Utility\VersionNumberUtility; /* * This file is part of the PAGEmachine Searchable project. @@ -51,12 +55,23 @@ public static function getDefaultConfiguration($currentSubconfiguration, $parent */ protected $config = []; + /** + * @var \PAGEmachine\Searchable\LinkBuilder\Frontend\FrontendRequestInterface + */ + protected $frontendRequest; + /** * @param array $config */ public function __construct($config = null) { $this->config = $config; + + if (version_compare(VersionNumberUtility::getCurrentTypo3Version(), '9', '<')) { + $this->frontendRequest = GeneralUtility::makeInstance(LegacyFrontendRequest::class); + } else { + $this->frontendRequest = GeneralUtility::makeInstance(FrontendRequest::class); + } } /** @@ -178,37 +193,11 @@ protected function replaceFieldsRecursive($configuration, $record) return $configuration; } - protected function getFrontendLinks($configuration) + protected function getFrontendLinks($configuration): array { - $domain = ExtconfService::getInstance()->getFrontendDomain(); - - return $this->doRequest($domain, $configuration); - } + $baseUri = new Uri(ExtconfService::getInstance()->getFrontendDomain()); + $uris = $this->frontendRequest->send($baseUri, $configuration); - /** - * The actual request - * - * @param string $domain - * @param array $configuration - * @return array - */ - protected function doRequest($domain, $configuration) - { - $requestFactory = GeneralUtility::makeInstance(\TYPO3\CMS\Core\Http\RequestFactory::class); - $response = $requestFactory->request( - $domain, - 'POST', - [ - 'query' => [ - 'eID' => 'searchable_linkbuilder', - ], - 'form_params' => [ - 'configuration' => $configuration, - ], - 'http_errors' => false, - ] - ); - - return json_decode($response->getBody()->getContents(), true); + return $uris; } } diff --git a/Classes/LinkBuilder/Frontend/FrontendRequest.php b/Classes/LinkBuilder/Frontend/FrontendRequest.php new file mode 100644 index 00000000..16f79351 --- /dev/null +++ b/Classes/LinkBuilder/Frontend/FrontendRequest.php @@ -0,0 +1,39 @@ +requestFactory = GeneralUtility::makeInstance(RequestFactory::class); + } + + public function send(UriInterface $baseUri, array $linkConfigurations): array + { + $response = $this->requestFactory->request( + (string)$baseUri->withPath('/-/searchable/urls'), + 'POST', + [ + 'form_params' => [ + 'configurations' => $linkConfigurations, + ], + 'http_errors' => false, + ] + ); + // \TYPO3\CMS\Extbase\Utility\DebuggerUtility::var_dump((string)$response->getBody(), __METHOD__, 8, defined('TYPO3_cliMode') || defined('TYPO3_REQUESTTYPE') && (TYPO3_REQUESTTYPE & TYPO3_REQUESTTYPE_CLI)); + $uris = json_decode((string)$response->getBody(), true); + + return $uris; + } +} diff --git a/Classes/LinkBuilder/Frontend/FrontendRequestInterface.php b/Classes/LinkBuilder/Frontend/FrontendRequestInterface.php new file mode 100644 index 00000000..26b480ab --- /dev/null +++ b/Classes/LinkBuilder/Frontend/FrontendRequestInterface.php @@ -0,0 +1,11 @@ +requestFactory = GeneralUtility::makeInstance(RequestFactory::class); + } + + public function send(UriInterface $baseUri, array $linkConfigurations): array + { + $response = $this->requestFactory->request( + (string)$baseUri, + 'POST', + [ + 'query' => [ + 'eID' => 'searchable_linkbuilder', + ], + 'form_params' => [ + 'configuration' => $linkConfigurations, + ], + 'http_errors' => false, + ] + ); + $uris = json_decode($response->getBody()->getContents(), true); + + return $uris; + } +} diff --git a/ext_localconf.php b/ext_localconf.php index fcb373ea..a534e8c9 100644 --- a/ext_localconf.php +++ b/ext_localconf.php @@ -106,7 +106,9 @@ //Register eid $GLOBALS['TYPO3_CONF_VARS']['FE']['eID_include']['searchable_autosuggest'] = \PAGEmachine\Searchable\Eid\Autosuggest::class . '::processRequest'; -$GLOBALS['TYPO3_CONF_VARS']['FE']['eID_include']['searchable_linkbuilder'] = \PAGEmachine\Searchable\Eid\LinkBuilder::class . '::processRequest'; +if (version_compare(\TYPO3\CMS\Core\Utility\VersionNumberUtility::getCurrentTypo3Version(), '9', '<')) { + $GLOBALS['TYPO3_CONF_VARS']['FE']['eID_include']['searchable_linkbuilder'] = \PAGEmachine\Searchable\Eid\LinkBuilder::class . '::processRequest'; +} $GLOBALS['TYPO3_CONF_VARS']['FE']['eID_include']['searchable_search'] = \PAGEmachine\Searchable\Eid\Search::class . '::processRequest'; // Register Hook for dynamic Plugin FlexForms From 80b1558bf3c77fcd0440ccf63ea3633293b6d584 Mon Sep 17 00:00:00 2001 From: Mathias Brodala Date: Thu, 17 Sep 2020 11:24:25 +0200 Subject: [PATCH 23/26] [TASK] Skip title when building links Since we are actually building URIs and not links here, there is no point in passing around an unused title here. --- Classes/Eid/LinkBuilder.php | 4 +-- Classes/LinkBuilder/AbstractLinkBuilder.php | 12 ++++----- Classes/LinkBuilder/FileLinkBuilder.php | 11 +++----- Classes/LinkBuilder/LinkBuilderInterface.php | 1 - Classes/LinkBuilder/PageLinkBuilder.php | 10 +++---- Classes/LinkBuilder/TypoLinkBuilder.php | 10 +++---- .../LinkBuilder/AbstractLinkBuilderTest.php | 26 ------------------- .../Unit/LinkBuilder/FileLinkBuilderTest.php | 12 ++++----- .../Unit/LinkBuilder/PageLinkBuilderTest.php | 4 +-- 9 files changed, 28 insertions(+), 62 deletions(-) diff --git a/Classes/Eid/LinkBuilder.php b/Classes/Eid/LinkBuilder.php index 1ed55308..15cda8f9 100644 --- a/Classes/Eid/LinkBuilder.php +++ b/Classes/Eid/LinkBuilder.php @@ -40,8 +40,8 @@ public function processRequest(ServerRequestInterface $request): ResponseInterfa $links = []; if ($configuration) { - foreach ($configuration as $key => $recordConfig) { - $links[$key] = $this->getLink($recordConfig['conf']); + foreach ($configuration as $key => $linkConfiguration) { + $links[$key] = $this->getLink($linkConfiguration); } } diff --git a/Classes/LinkBuilder/AbstractLinkBuilder.php b/Classes/LinkBuilder/AbstractLinkBuilder.php index 50fe7ac7..0131d9eb 100644 --- a/Classes/LinkBuilder/AbstractLinkBuilder.php +++ b/Classes/LinkBuilder/AbstractLinkBuilder.php @@ -99,7 +99,7 @@ public function createLinkConfiguration($record, $language) /** * Creates links for a batch of records * - * @param array $records + * @param array $records * @param int $language * @return array $records */ @@ -110,7 +110,7 @@ public function createLinksForBatch($records, $language = 0) foreach ($records as $key => $record) { $linkConfiguration = $this->createLinkConfiguration($record, $language); - $linkConfiguration = $this->convertToTypoLinkConfig($linkConfiguration, $record); + $linkConfiguration = $this->finalizeTypoLinkConfig($linkConfiguration, $record); $configurationArray[$key] = $linkConfiguration; } @@ -129,13 +129,13 @@ public function createLinksForBatch($records, $language = 0) * Converts builder-specific configuration to TypoLink configuration * This should be overridden with custom conversion logic * - * @param array $configuration - * @param array $record + * @param array $configuration + * @param array $record * @return array */ - public function convertToTypoLinkConfig($configuration, $record) + public function finalizeTypoLinkConfig($configuration, $record) { - return ['title' => $this->getLinkTitle($record), 'conf' => $configuration]; + return $configuration; } /** diff --git a/Classes/LinkBuilder/FileLinkBuilder.php b/Classes/LinkBuilder/FileLinkBuilder.php index 05cd0344..cf37c46b 100644 --- a/Classes/LinkBuilder/FileLinkBuilder.php +++ b/Classes/LinkBuilder/FileLinkBuilder.php @@ -23,15 +23,12 @@ class FileLinkBuilder extends AbstractLinkBuilder 'fileRecordField' => 'file', ]; - /** - * Converts builder-specific configuration to TypoLink configuration - * - * @param array $configuration - * @param array $record + * @param array $configuration + * @param array $record * @return array */ - public function convertToTypoLinkConfig($configuration, $record) + public function finalizeTypoLinkConfig($configuration, $record) { $fileRecord = $this->config['fileRecordField'] ? $record[$this->config['fileRecordField']] : $record; @@ -44,7 +41,7 @@ public function convertToTypoLinkConfig($configuration, $record) } $configuration['parameter'] = 't3://file?uid=' . $fileRecord['uid']; - return parent::convertToTypoLinkConfig($configuration, $record); + return $configuration; } /** diff --git a/Classes/LinkBuilder/LinkBuilderInterface.php b/Classes/LinkBuilder/LinkBuilderInterface.php index 634ca98e..7423ac77 100644 --- a/Classes/LinkBuilder/LinkBuilderInterface.php +++ b/Classes/LinkBuilder/LinkBuilderInterface.php @@ -16,7 +16,6 @@ interface LinkBuilderInterface */ public function createLinkConfiguration($record, $language); - /** * Creates links for a batch of records * diff --git a/Classes/LinkBuilder/PageLinkBuilder.php b/Classes/LinkBuilder/PageLinkBuilder.php index 9f62595e..6498f77f 100644 --- a/Classes/LinkBuilder/PageLinkBuilder.php +++ b/Classes/LinkBuilder/PageLinkBuilder.php @@ -37,17 +37,15 @@ class PageLinkBuilder extends AbstractLinkBuilder ]; /** - * Converts builder-specific configuration to TypoLink configuration - * - * @param array $configuration - * @param array $record + * @param array $configuration + * @param array $record * @return array */ - public function convertToTypoLinkConfig($configuration, $record) + public function finalizeTypoLinkConfig($configuration, $record) { $linkConfiguration = $this->convertFromPageViewHelperConfig($configuration); - return ['title' => $this->getLinkTitle($record), 'conf' => $linkConfiguration]; + return $linkConfiguration; } /** diff --git a/Classes/LinkBuilder/TypoLinkBuilder.php b/Classes/LinkBuilder/TypoLinkBuilder.php index 8baf9936..c240bb76 100644 --- a/Classes/LinkBuilder/TypoLinkBuilder.php +++ b/Classes/LinkBuilder/TypoLinkBuilder.php @@ -28,18 +28,16 @@ class TypoLinkBuilder extends AbstractLinkBuilder ]; /** - * Converts builder-specific configuration to TypoLink configuration - * - * @param array $configuration - * @param array $record + * @param array $configuration + * @param array $record * @return array */ - public function convertToTypoLinkConfig($configuration, $record) + public function finalizeTypoLinkConfig($configuration, $record) { if (!empty($configuration['additionalParams'])) { $configuration['additionalParams'] = GeneralUtility::implodeArrayForUrl('', $configuration['additionalParams']); } - return ['title' => $this->getLinkTitle($record), 'conf' => $configuration]; + return $configuration; } } diff --git a/Tests/Unit/LinkBuilder/AbstractLinkBuilderTest.php b/Tests/Unit/LinkBuilder/AbstractLinkBuilderTest.php index a0e217d9..560b0464 100644 --- a/Tests/Unit/LinkBuilder/AbstractLinkBuilderTest.php +++ b/Tests/Unit/LinkBuilder/AbstractLinkBuilderTest.php @@ -155,30 +155,4 @@ public function unsetsEmptyDynamicFieldsAndUsesFixedPartInstead() $this->assertArraySubset(['pageUid' => '123'], $linkConfiguration); } - - /** - * @test - */ - public function convertsToTypoLinkConfig() - { - $record = ['title' => 'sometitle']; - - $builderConfig = [ - 'titleField' => 'title', - ]; - - $linkConfig = [ - 'foo' => 'bar', - ]; - - $typolinkConfig = [ - 'title' => 'sometitle', - 'conf' => ['foo' => 'bar'], - ]; - - $this->linkBuilder = $this->getAccessibleMockForAbstractClass(AbstractLinkBuilder::class, ['config' => $builderConfig]); - $linkConfiguration = $this->linkBuilder->convertToTypoLinkConfig($linkConfig, $record); - - $this->assertEquals($typolinkConfig, $linkConfiguration); - } } diff --git a/Tests/Unit/LinkBuilder/FileLinkBuilderTest.php b/Tests/Unit/LinkBuilder/FileLinkBuilderTest.php index 961a0d99..575c9d98 100644 --- a/Tests/Unit/LinkBuilder/FileLinkBuilderTest.php +++ b/Tests/Unit/LinkBuilder/FileLinkBuilderTest.php @@ -46,9 +46,9 @@ public function createsFileLinkForToplevelFileRecord() $this->linkBuilder = new FileLinkBuilder($config); - $linkConfiguration = $this->linkBuilder->convertToTypoLinkConfig([], $record); + $linkConfiguration = $this->linkBuilder->finalizeTypoLinkConfig([], $record); - $this->assertEquals('t3://file?uid=22', $linkConfiguration['conf']['parameter']); + $this->assertEquals('t3://file?uid=22', $linkConfiguration['parameter']); } /** @@ -71,9 +71,9 @@ public function createsFileLinkForSingleSublevelFile() $this->linkBuilder = new FileLinkBuilder($config); - $linkConfiguration = $this->linkBuilder->convertToTypoLinkConfig([], $record); + $linkConfiguration = $this->linkBuilder->finalizeTypoLinkConfig([], $record); - $this->assertEquals('t3://file?uid=25', $linkConfiguration['conf']['parameter']); + $this->assertEquals('t3://file?uid=25', $linkConfiguration['parameter']); } /** @@ -98,8 +98,8 @@ public function createsFileLinkForNestedSublevelFile() $this->linkBuilder = new FileLinkBuilder($config); - $linkConfiguration = $this->linkBuilder->convertToTypoLinkConfig([], $record); + $linkConfiguration = $this->linkBuilder->finalizeTypoLinkConfig([], $record); - $this->assertEquals('t3://file?uid=25', $linkConfiguration['conf']['parameter']); + $this->assertEquals('t3://file?uid=25', $linkConfiguration['parameter']); } } diff --git a/Tests/Unit/LinkBuilder/PageLinkBuilderTest.php b/Tests/Unit/LinkBuilder/PageLinkBuilderTest.php index 8b1ee0a7..8a4e2f9a 100644 --- a/Tests/Unit/LinkBuilder/PageLinkBuilderTest.php +++ b/Tests/Unit/LinkBuilder/PageLinkBuilderTest.php @@ -65,8 +65,8 @@ public function convertsFromViewHelperConfigToTypoLinkConfig() ], ]; - $typolinkConfig = $this->pageLinkBuilder->convertToTypoLinkConfig($config, []); + $typolinkConfig = $this->pageLinkBuilder->finalizeTypoLinkConfig($config, []); - $this->assertEquals($expectedTypolinkConfig, $typolinkConfig['conf']); + $this->assertEquals($expectedTypolinkConfig, $typolinkConfig); } } From d87ce48f6442827144d2b7242c1f4ac484dba0b7 Mon Sep 17 00:00:00 2001 From: Mathias Brodala Date: Thu, 17 Sep 2020 11:25:01 +0200 Subject: [PATCH 24/26] [BUGFIX] Flush site configuration caches in TYPO3v9+ --- Tests/Functional/AbstractElasticsearchTest.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Tests/Functional/AbstractElasticsearchTest.php b/Tests/Functional/AbstractElasticsearchTest.php index d069a646..05010960 100644 --- a/Tests/Functional/AbstractElasticsearchTest.php +++ b/Tests/Functional/AbstractElasticsearchTest.php @@ -8,7 +8,9 @@ use PAGEmachine\Searchable\Connection; use PAGEmachine\Searchable\Indexer\PagesIndexer; use PAGEmachine\Searchable\Service\IndexingService; +use TYPO3\CMS\Core\Configuration\SiteConfiguration; use TYPO3\CMS\Core\Core\Bootstrap; +use TYPO3\CMS\Core\Core\Environment; use TYPO3\CMS\Core\Crypto\Random; use TYPO3\CMS\Core\Utility\ArrayUtility; use TYPO3\CMS\Core\Utility\GeneralUtility; @@ -97,6 +99,14 @@ protected function setUp() __DIR__ . '/Fixtures/TypoScript/page.typoscript', 'EXT:searchable/Configuration/Typoscript/setup.txt', ]); + // Update internally created site to flush all caches + if (class_exists(SiteConfiguration::class)) { + $siteConfiguration = GeneralUtility::makeInstance( + SiteConfiguration::class, + Environment::getConfigPath() . '/sites' + ); + $siteConfiguration->write('1', $siteConfiguration->load('1')); + } // Necessary for \TYPO3\CMS\Backend\Form\FormDataProvider\DatabaseUserPermissionCheck $this->setUpBackendUserFromFixture(1); From d53d86d69be7852b79038aee64b81436848f00ef Mon Sep 17 00:00:00 2001 From: Mathias Brodala Date: Thu, 17 Sep 2020 14:47:39 +0200 Subject: [PATCH 25/26] [BUGFIX] Always return integer in language ID trait For TYPO3v8 and within an eID search we must make sure to use the default language if nothing can be determined otherwise. --- Classes/LanguageIdTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Classes/LanguageIdTrait.php b/Classes/LanguageIdTrait.php index 41170e19..f509e06d 100644 --- a/Classes/LanguageIdTrait.php +++ b/Classes/LanguageIdTrait.php @@ -15,6 +15,6 @@ protected function getLanguageId(): int } // @extensionScannerIgnoreLine - return $GLOBALS['TSFE']->sys_language_uid; // @phpstan-ignore-line + return $GLOBALS['TSFE']->sys_language_uid ?? 0; // @phpstan-ignore-line } } From b0bbb02a42a2ecd133603862aa3aa0d348cd0a02 Mon Sep 17 00:00:00 2001 From: Mathias Brodala Date: Thu, 17 Sep 2020 14:57:54 +0200 Subject: [PATCH 26/26] [TASK] Ignore extension scanner match for command controller This controller is explicitly kept around for TYPO3v8 support. --- Classes/Command/SearchableCommandController.php | 1 + 1 file changed, 1 insertion(+) diff --git a/Classes/Command/SearchableCommandController.php b/Classes/Command/SearchableCommandController.php index 71204e98..324213fa 100644 --- a/Classes/Command/SearchableCommandController.php +++ b/Classes/Command/SearchableCommandController.php @@ -9,6 +9,7 @@ use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Extbase\Mvc\Controller\CommandController; +// @extensionScannerIgnoreLine class SearchableCommandController extends CommandController { /**