* 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\Solr\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 ApacheSolrDocument * * Responsible to build \WapplerSystems\Meilisearch\System\Solr\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 Document|object */ public function fromPage(TypoScriptFrontendController $page, $url, Rootline $pageAccessRootline, $mountPointParameter): Document { /* @var $document Document */ $document = GeneralUtility::makeInstance(Document::class); $site = $this->getSiteByPageId($page->id); $pageRecord = $page->page; $accessGroups = $this->getDocumentIdGroups($pageAccessRootline); $documentId = $this->getPageDocumentId($page, $accessGroups, $mountPointParameter); $document->setField('id', $documentId); $document->setField('site', $site->getDomain()); $document->setField('siteHash', $site->getSiteHash()); $document->setField('appKey', 'EXT:meilisearch'); $document->setField('type', 'pages'); // system fields $document->setField('uid', $page->id); $document->setField('pid', $pageRecord['pid']); // variantId $variantId = $this->variantIdBuilder->buildFromTypeAndUid('pages', $page->id); $document->setField('variantId', $variantId); $document->setField('typeNum', $page->type); $document->setField('created', $pageRecord['crdate']); $document->setField('changed', $pageRecord['SYS_LASTCHANGED']); $rootline = $this->getRootLineFieldValue($page->id, $mountPointParameter); $document->setField('rootline', $rootline); // access $this->addAccessField($document, $pageAccessRootline); $this->addEndtimeField($document, $pageRecord); // content // @extensionScannerIgnoreLine $contentExtractor = $this->getExtractorForPageContent($page->content); $document->setField('title', $contentExtractor->getPageTitle()); $document->setField('subTitle', $pageRecord['subtitle']); $document->setField('navTitle', $pageRecord['nav_title']); $document->setField('author', $pageRecord['author']); $document->setField('description', $pageRecord['description']); $document->setField('abstract', $pageRecord['abstract']); $document->setField('content', $contentExtractor->getIndexableContent()); $document->setField('url', $url); $this->addKeywordsField($document, $pageRecord); $this->addTagContentFields($document, $contentExtractor->getTagContent()); return $document; } /** * Creates a Solr document with the basic / core fields set already. * * @param array $itemRecord * @param string $type * @param int $rootPageUid * @param string $accessRootLine * @return Document */ public function fromRecord(array $itemRecord, string $type, int $rootPageUid, string $accessRootLine): Document { /* @var $document Document */ $document = GeneralUtility::makeInstance(Document::class); $site = $this->getSiteByPageId($rootPageUid); $documentId = $this->getDocumentId($type, $site->getRootPageId(), $itemRecord['uid']); // required fields $document->setField('id', $documentId); $document->setField('type', $type); $document->setField('appKey', 'EXT:meilisearch'); // site, siteHash $document->setField('site', $site->getDomain()); $document->setField('siteHash', $site->getSiteHash()); // uid, pid $document->setField('uid', $itemRecord['uid']); $document->setField('pid', $itemRecord['pid']); // variantId $variantId = $this->variantIdBuilder->buildFromTypeAndUid($type, $itemRecord['uid']); $document->setField('variantId', $variantId); // created, changed if (!empty($GLOBALS['TCA'][$type]['ctrl']['crdate'])) { $document->setField('created', $itemRecord[$GLOBALS['TCA'][$type]['ctrl']['crdate']]); } if (!empty($GLOBALS['TCA'][$type]['ctrl']['tstamp'])) { $document->setField('changed', $itemRecord[$GLOBALS['TCA'][$type]['ctrl']['tstamp']]); } // access, endtime $document->setField('access', $accessRootLine); if (!empty($GLOBALS['TCA'][$type]['ctrl']['enablecolumns']['endtime']) && $itemRecord[$GLOBALS['TCA'][$type]['ctrl']['enablecolumns']['endtime']] != 0 ) { $document->setField('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 Document $document * @param Rootline $pageAccessRootline */ protected function addAccessField(Document $document, Rootline $pageAccessRootline) { $access = (string)$pageAccessRootline; if (trim($access) !== '') { $document->setField('access', $access); } } /** * Adds the endtime field value to the Document. * * @param Document $document * @param array $pageRecord */ protected function addEndtimeField(Document $document, $pageRecord) { if ($pageRecord['endtime']) { $document->setField('endtime', $pageRecord['endtime']); } } /** * Adds keywords, multi valued. * * @param Document $document * @param array $pageRecord */ protected function addKeywordsField(Document $document, $pageRecord) { if (!isset($pageRecord['keywords'])) { return; } $keywords = array_unique(GeneralUtility::trimExplode(',', $pageRecord['keywords'], true)); foreach ($keywords as $keyword) { $document->addField('keywords', $keyword); } } /** * Add content from several tags like headers, anchors, ... * * @param Document $document * @param array $tagContent */ protected function addTagContentFields(Document $document, $tagContent = []) { foreach ($tagContent as $fieldName => $fieldValue) { $document->setField($fieldName, $fieldValue); } } }