2021-04-17 00:26:33 +02:00
< ? php
namespace WapplerSystems\Meilisearch\IndexQueue\Initializer ;
/***************************************************************
* Copyright notice
*
* ( c ) 2011 - 2015 Ingo Renner < ingo @ typo3 . org >
* 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 .
* A copy is found in the textfile GPL . txt and important notices to the license
* from the author is found in LICENSE . txt distributed with these scripts .
*
*
* 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\Domain\Index\Queue\QueueItemRepository ;
use WapplerSystems\Meilisearch\Domain\Site\SiteRepository ;
use WapplerSystems\Meilisearch\IndexQueue\Item ;
use WapplerSystems\Meilisearch\IndexQueue\Queue ;
2021-04-17 21:20:54 +02:00
use WapplerSystems\Meilisearch\System\Logging\MeilisearchLogManager ;
2021-04-17 00:26:33 +02:00
use WapplerSystems\Meilisearch\System\Records\Pages\PagesRepository ;
use Doctrine\DBAL\DBALException ;
use TYPO3\CMS\Backend\Utility\BackendUtility ;
use TYPO3\CMS\Core\Database\Connection ;
use TYPO3\CMS\Core\Database\ConnectionPool ;
use TYPO3\CMS\Core\Messaging\FlashMessage ;
use TYPO3\CMS\Core\Utility\GeneralUtility ;
/**
* Index Queue initializer for pages which also covers resolution of mount
* pages .
*
* @ author Ingo Renner < ingo @ typo3 . org >
*/
class Page extends AbstractInitializer
{
/**
* The type of items this initializer is handling .
* @ var string
*/
protected $type = 'pages' ;
/**
* @ var PagesRepository
*/
protected $pagesRepository ;
/**
* Constructor , sets type and indexingConfigurationName to " pages " .
*
* @ param QueueItemRepository | null $queueItemRepository
* @ param PagesRepository | null $pagesRepository
*/
public function __construct ( QueueItemRepository $queueItemRepository = null , PagesRepository $pagesRepository = null )
{
parent :: __construct ( $queueItemRepository );
$this -> pagesRepository = $pagesRepository ? ? GeneralUtility :: makeInstance ( PagesRepository :: class );
}
/**
* Overrides the general setType () implementation , forcing type to " pages " .
*
* @ param string $type Type to initialize ( ignored ) .
*/
public function setType ( $type )
{
$this -> type = 'pages' ;
}
/**
* Initializes Index Queue page items for a site . Includes regular pages
* and mounted pages - no nested mount page structures though .
*
* @ return bool TRUE if initialization was successful , FALSE on error .
*/
public function initialize ()
{
$pagesInitialized = parent :: initialize ();
$mountPagesInitialized = $this -> initializeMountPages ();
return ( $pagesInitialized && $mountPagesInitialized );
}
/**
* Initialize a single page that is part of a mounted tree .
*
* @ param array $mountProperties Array of mount point properties mountPageSource , mountPageDestination , and mountPageOverlayed
* @ param int $mountPageId The ID of the mounted page
*/
public function initializeMountedPage ( array $mountProperties , $mountPageId )
{
$mountedPages = [ $mountPageId ];
$this -> addMountedPagesToIndexQueue ( $mountedPages , $mountProperties );
$this -> addIndexQueueItemIndexingProperties ( $mountProperties , $mountedPages );
}
/**
* Initializes Mount Pages to be indexed through the Index Queue . The Mount
* Pages are searched and their mounted virtual sub - trees are then resolved
* and added to the Index Queue as if they were actually present below the
* Mount Page .
*
* @ return bool TRUE if initialization of the Mount Pages was successful , FALSE otherwise
*/
protected function initializeMountPages ()
{
$mountPagesInitialized = false ;
$mountPages = $this -> pagesRepository -> findAllMountPagesByWhereClause ( $this -> buildPagesClause () . $this -> buildTcaWhereClause () . ' AND doktype = 7 AND no_search = 0' );
if ( empty ( $mountPages )) {
$mountPagesInitialized = true ;
return $mountPagesInitialized ;
}
$databaseConnection = $this -> queueItemRepository -> getConnectionForAllInTransactionInvolvedTables (
'tx_meilisearch_indexqueue_item' ,
'tx_meilisearch_indexqueue_indexing_property'
);
foreach ( $mountPages as $mountPage ) {
if ( ! $this -> validateMountPage ( $mountPage )) {
continue ;
}
$mountedPages = $this -> resolveMountPageTree ( $mountPage );
// handling mount_pid_ol behavior
if ( $mountPage [ 'mountPageOverlayed' ]) {
// the page shows the mounted page's content
$mountedPages [] = $mountPage [ 'mountPageSource' ];
} else {
// Add page like a regular page, as only the sub tree is
// mounted. The page itself has its own content.
$indexQueue = GeneralUtility :: makeInstance ( Queue :: class );
$indexQueue -> updateItem ( $this -> type , $mountPage [ 'uid' ]);
}
// This can happen when the mount point does not show the content of the
// mounted page and the mounted page does not have any subpages.
if ( empty ( $mountedPages )) {
continue ;
}
$databaseConnection -> beginTransaction ();
try {
$this -> addMountedPagesToIndexQueue ( $mountedPages , $mountPage );
$this -> addIndexQueueItemIndexingProperties ( $mountPage , $mountedPages );
$databaseConnection -> commit ();
$mountPagesInitialized = true ;
} catch ( \Exception $e ) {
$databaseConnection -> rollBack ();
$this -> logger -> log (
2021-04-17 21:20:54 +02:00
MeilisearchLogManager :: ERROR ,
2021-04-17 00:26:33 +02:00
'Index Queue initialization failed for mount pages' ,
[
$e -> __toString ()
]
);
break ;
}
}
return $mountPagesInitialized ;
}
/**
* Checks whether a Mount Page is properly configured .
*
* @ param array $mountPage A mount page
* @ return bool TRUE if the Mount Page is OK , FALSE otherwise
*/
protected function validateMountPage ( array $mountPage )
{
$isValidMountPage = true ;
if ( empty ( $mountPage [ 'mountPageSource' ])) {
$isValidMountPage = false ;
$flashMessage = GeneralUtility :: makeInstance (
FlashMessage :: class ,
'Property "Mounted page" must not be empty. Invalid Mount Page configuration for page ID ' . $mountPage [ 'uid' ] . '.' ,
'Failed to initialize Mount Page tree. ' ,
FlashMessage :: ERROR
);
// @extensionScannerIgnoreLine
$this -> flashMessageQueue -> addMessage ( $flashMessage );
}
if ( ! $this -> mountedPageExists ( $mountPage [ 'mountPageSource' ])) {
$isValidMountPage = false ;
$flashMessage = GeneralUtility :: makeInstance (
FlashMessage :: class ,
'The mounted page must be accessible in the frontend. '
. 'Invalid Mount Page configuration for page ID '
. $mountPage [ 'uid' ] . ', the mounted page with ID '
. $mountPage [ 'mountPageSource' ]
. ' is not accessible in the frontend.' ,
'Failed to initialize Mount Page tree. ' ,
FlashMessage :: ERROR
);
// @extensionScannerIgnoreLine
$this -> flashMessageQueue -> addMessage ( $flashMessage );
}
return $isValidMountPage ;
}
/**
* Checks whether the mounted page ( mount page source ) exists . That is ,
* whether it accessible in the frontend . So the record must exist
* ( deleted = 0 ) and must not be hidden ( hidden = 0 ) .
*
* @ param int $mountedPageId Mounted page ID
* @ return bool TRUE if the page is accessible in the frontend , FALSE otherwise .
*/
protected function mountedPageExists ( $mountedPageId )
{
$mountedPageExists = false ;
$mountedPage = BackendUtility :: getRecord ( 'pages' , $mountedPageId , 'uid' , ' AND hidden = 0' );
if ( ! empty ( $mountedPage )) {
$mountedPageExists = true ;
}
return $mountedPageExists ;
}
/**
* Adds the virtual / mounted pages to the Index Queue as if they would
* belong to the same site where they are mounted .
*
* @ param array $mountedPages An array of mounted page IDs
* @ param array $mountProperties Array with mount point properties ( mountPageSource , mountPageDestination , mountPageOverlayed )
*/
protected function addMountedPagesToIndexQueue ( array $mountedPages , array $mountProperties )
{
$mountPointIdentifier = $this -> getMountPointIdentifier ( $mountProperties );
$mountPointPageIsWithExistingQueueEntry = $this -> queueItemRepository -> findPageIdsOfExistingMountPagesByMountIdentifier ( $mountPointIdentifier );
$mountedPagesThatNeedToBeAdded = array_diff ( $mountedPages , $mountPointPageIsWithExistingQueueEntry );
if ( count ( $mountedPagesThatNeedToBeAdded ) === 0 ) {
//nothing to do
return ;
}
/* @var Connection $connection */
$connection = GeneralUtility :: makeInstance ( ConnectionPool :: class ) -> getConnectionForTable ( 'tx_meilisearch_indexqueue_item' );
$mountIdentifier = $this -> getMountPointIdentifier ( $mountProperties );
$initializationQuery = 'INSERT INTO tx_meilisearch_indexqueue_item (root, item_type, item_uid, indexing_configuration, indexing_priority, changed, has_indexing_properties, pages_mountidentifier, errors) '
. $this -> buildSelectStatement () . ', 1, ' . $connection -> quote ( $mountIdentifier , \PDO :: PARAM_STR ) . ',""'
. 'FROM pages '
. 'WHERE '
. 'uid IN(' . implode ( ',' , $mountedPagesThatNeedToBeAdded ) . ') '
. $this -> buildTcaWhereClause ()
. $this -> buildUserWhereClause ();
$logData = [ 'query' => $initializationQuery ];
try {
$logData [ 'rows' ] = $this -> queueItemRepository -> initializeByNativeSQLStatement ( $initializationQuery );
} catch ( DBALException $DBALException ) {
$logData [ 'error' ] = $DBALException -> getCode () . ': ' . $DBALException -> getMessage ();
}
$this -> logInitialization ( $logData );
}
/**
* Adds Index Queue item indexing properties for mounted pages . The page
* indexer later needs to know that he ' s dealing with a mounted page , the
* indexing properties will let make it possible for the indexer to
* distinguish the mounted pages .
*
* @ param array $mountPage An array with information about the root / destination Mount Page
* @ param array $mountedPages An array of mounted page IDs
*/
protected function addIndexQueueItemIndexingProperties ( array $mountPage , array $mountedPages )
{
$mountIdentifier = $this -> getMountPointIdentifier ( $mountPage );
$mountPageItems = $this -> queueItemRepository -> findAllIndexQueueItemsByRootPidAndMountIdentifierAndMountedPids ( $this -> site -> getRootPageId (), $mountIdentifier , $mountedPages );
foreach ( $mountPageItems as $mountPageItemRecord ) {
/* @var Item $mountPageItem */
$mountPageItem = GeneralUtility :: makeInstance ( Item :: class , /** @scrutinizer ignore-type */ $mountPageItemRecord );
$mountPageItem -> setIndexingProperty ( 'mountPageSource' , $mountPage [ 'mountPageSource' ]);
$mountPageItem -> setIndexingProperty ( 'mountPageDestination' , $mountPage [ 'mountPageDestination' ]);
$mountPageItem -> setIndexingProperty ( 'isMountedPage' , '1' );
$mountPageItem -> storeIndexingProperties ();
}
}
/**
* Builds an identifier of the given mount point properties .
*
* @ param array $mountProperties Array with mount point properties ( mountPageSource , mountPageDestination , mountPageOverlayed )
* @ return string String consisting of mountPageSource - mountPageDestination - mountPageOverlayed
*/
protected function getMountPointIdentifier ( array $mountProperties )
{
return $mountProperties [ 'mountPageSource' ]
. '-' . $mountProperties [ 'mountPageDestination' ]
. '-' . $mountProperties [ 'mountPageOverlayed' ];
}
// Mount Page resolution
/**
* Gets all the pages from a mounted page tree .
*
* @ param array $mountPage
* @ return array An array of page IDs in the mounted page tree
*/
protected function resolveMountPageTree ( $mountPage )
{
$mountPageSourceId = $mountPage [ 'mountPageSource' ];
$mountPageIdentifier = $this -> getMountPointIdentifier ( $mountPage );
$siteRepository = GeneralUtility :: makeInstance ( SiteRepository :: class );
/* @var $siteRepository SiteRepository */
$mountedSite = $siteRepository -> getSiteByPageId ( $mountPageSourceId , $mountPageIdentifier );
return $mountedSite ? $mountedSite -> getPages ( $mountPageSourceId ) : [];
}
}