* All rights reserved * * This script is part of the TYPO3 project. The TYPO3 project is * free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * The GNU General Public License can be found at * http://www.gnu.org/copyleft/gpl.html. * * This script is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * This copyright notice MUST APPEAR in all copies of the script! ***************************************************************/ use WapplerSystems\Meilisearch\Access\Rootline; use WapplerSystems\Meilisearch\Domain\Site\SiteRepository; use WapplerSystems\Meilisearch\Domain\Variants\IdBuilder; use WapplerSystems\Meilisearch\Domain\Site\Site; use WapplerSystems\Meilisearch\System\Meilisearch\Document\Document; use WapplerSystems\Meilisearch\Typo3PageContentExtractor; use WapplerSystems\Meilisearch\Util; use TYPO3\CMS\Core\Utility\GeneralUtility; use TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController; /** * Builder class to build an MeilisearchDocument * * Responsible to build \WapplerSystems\Meilisearch\System\Meilisearch\Document\Document * * @author Timo Hund */ class Builder { /** * @var IdBuilder */ protected $variantIdBuilder; /** * Builder constructor. * @param IdBuilder|null $variantIdBuilder */ public function __construct(IdBuilder $variantIdBuilder = null) { $this->variantIdBuilder = $variantIdBuilder ?? GeneralUtility::makeInstance(IdBuilder::class); } /** * This method can be used to build an Document from a TYPO3 page. * * @param TypoScriptFrontendController $page * @param string $url * @param Rootline $pageAccessRootline * @param string $mountPointParameter * @return array */ public function fromPage(TypoScriptFrontendController $page, $url, Rootline $pageAccessRootline, $mountPointParameter): array { $document = []; $site = $this->getSiteByPageId($page->id); $pageRecord = $page->page; $accessGroups = $this->getDocumentIdGroups($pageAccessRootline); $documentId = $this->getPageDocumentId($page, $accessGroups, $mountPointParameter); $document['id'] = $documentId; $document['site'] = $site->getDomain(); $document['siteHash'] = $site->getSiteHash(); $document['appKey'] = 'EXT:meilisearch'; $document['type'] = 'pages'; // system fields $document['uid'] = $page->id; $document['pid'] = $pageRecord['pid']; // variantId $variantId = $this->variantIdBuilder->buildFromTypeAndUid('pages', $page->id); $document['variantId'] = $variantId; $document['typeNum'] = $page->type; $document['created'] = $pageRecord['crdate']; $document['changed'] = $pageRecord['SYS_LASTCHANGED']; $rootline = $this->getRootLineFieldValue($page->id, $mountPointParameter); $document['rootline'] = $rootline; // access $this->addAccessField($document, $pageAccessRootline); $this->addEndtimeField($document, $pageRecord); // content // @extensionScannerIgnoreLine $contentExtractor = $this->getExtractorForPageContent($page->content); $document['title'] = $contentExtractor->getPageTitle(); $document['subTitle'] = $pageRecord['subtitle']; $document['navTitle'] = $pageRecord['nav_title']; $document['author'] = $pageRecord['author']; $document['description'] = $pageRecord['description']; $document['abstract'] = $pageRecord['abstract']; $document['content'] = $contentExtractor->getIndexableContent(); $document['url'] = $url; $this->addKeywordsField($document, $pageRecord); $this->addTagContentFields($document, $contentExtractor->getTagContent()); return $document; } /** * Creates a Meilisearch document with the basic / core fields set already. * * @param array $itemRecord * @param string $type * @param int $rootPageUid * @param string $accessRootLine * @return array */ public function fromRecord(array $itemRecord, string $type, int $rootPageUid, string $accessRootLine): array { /* @var $document Document */ $document = GeneralUtility::makeInstance(Document::class); $site = $this->getSiteByPageId($rootPageUid); $documentId = $this->getDocumentId($type, $site->getRootPageId(), $itemRecord['uid']); // required fields $document['id'] = $documentId; $document['type'] = $type; $document['appKey'] = 'EXT:meilisearch'; // site, siteHash $document['site'] = $site->getDomain(); $document['siteHash'] = $site->getSiteHash(); // uid, pid $document['uid'] = $itemRecord['uid']; $document['pid'] = $itemRecord['pid']; // variantId $variantId = $this->variantIdBuilder->buildFromTypeAndUid($type, $itemRecord['uid']); $document['variantId'] = $variantId; // created, changed if (!empty($GLOBALS['TCA'][$type]['ctrl']['crdate'])) { $document['created'] = $itemRecord[$GLOBALS['TCA'][$type]['ctrl']['crdate']]; } if (!empty($GLOBALS['TCA'][$type]['ctrl']['tstamp'])) { $document['changed'] = $itemRecord[$GLOBALS['TCA'][$type]['ctrl']['tstamp']]; } // access, endtime $document['access'] = $accessRootLine; if (!empty($GLOBALS['TCA'][$type]['ctrl']['enablecolumns']['endtime']) && $itemRecord[$GLOBALS['TCA'][$type]['ctrl']['enablecolumns']['endtime']] != 0 ) { $document['endtime'] = $itemRecord[$GLOBALS['TCA'][$type]['ctrl']['enablecolumns']['endtime']]; } return $document; } /** * @param TypoScriptFrontendController $page * @param string $accessGroups * @param string $mountPointParameter * @return string */ protected function getPageDocumentId(TypoScriptFrontendController $frontendController, string $accessGroups, string $mountPointParameter): string { return Util::getPageDocumentId($frontendController->id, $frontendController->type, Util::getLanguageUid(), $accessGroups, $mountPointParameter); } /** * @param string $type * @param int $rootPageId * @param int $recordUid * @return string */ protected function getDocumentId(string $type, int $rootPageId, int $recordUid): string { return Util::getDocumentId($type, $rootPageId, $recordUid); } /** * @param integer $pageId * @return Site */ protected function getSiteByPageId($pageId) { $siteRepository = GeneralUtility::makeInstance(SiteRepository::class); return $siteRepository->getSiteByPageId($pageId); } /** * @param string $pageContent * @return Typo3PageContentExtractor */ protected function getExtractorForPageContent($pageContent) { return GeneralUtility::makeInstance(Typo3PageContentExtractor::class, /** @scrutinizer ignore-type */ $pageContent); } /** * Builds the content for the rootline field. * * @param int $pageId * @param string $mountPointParameter * @return string */ protected function getRootLineFieldValue($pageId, $mountPointParameter) { $rootline = $pageId; if ($mountPointParameter !== '') { $rootline .= ',' . $mountPointParameter; } return $rootline; } /** * Gets a comma separated list of frontend user groups to use for the * document ID. * * @param Rootline $pageAccessRootline * @return string A comma separated list of frontend user groups. */ protected function getDocumentIdGroups(Rootline $pageAccessRootline) { $groups = $pageAccessRootline->getGroups(); $groups = Rootline::cleanGroupArray($groups); if (empty($groups)) { $groups[] = 0; } $groups = implode(',', $groups); return $groups; } /** * Adds the access field to the document if needed. * * @param array $document * @param Rootline $pageAccessRootline */ protected function addAccessField(array &$document, Rootline $pageAccessRootline) { $access = (string)$pageAccessRootline; if (trim($access) !== '') { $document['access'] = $access; } } /** * Adds the endtime field value to the Document. * * @param array $document * @param array $pageRecord */ protected function addEndtimeField(array &$document, $pageRecord) { if ($pageRecord['endtime']) { $document['endtime'] = $pageRecord['endtime']; } } /** * Adds keywords, multi valued. * * @param array $document * @param array $pageRecord */ protected function addKeywordsField(array &$document, $pageRecord) { if (!isset($pageRecord['keywords'])) { return; } $keywords = array_unique(GeneralUtility::trimExplode(',', $pageRecord['keywords'], true)); foreach ($keywords as $keyword) { $document['keywords'] = $keyword; } } /** * Add content from several tags like headers, anchors, ... * * @param array $document * @param array $tagContent */ protected function addTagContentFields(array &$document, $tagContent = []) { foreach ($tagContent as $fieldName => $fieldValue) { $document[$fieldName] = $fieldValue; } } }