mirror of
https://github.com/Codappix/search_core.git
synced 2024-11-22 14:36:11 +01:00
Merge pull request #57 from Codappix/feature/cms-8-support
Feature: Support TYPO3 8
This commit is contained in:
commit
8494901b58
19 changed files with 289 additions and 190 deletions
|
@ -11,7 +11,6 @@ before_install:
|
||||||
language: php
|
language: php
|
||||||
|
|
||||||
php:
|
php:
|
||||||
- 7.0
|
|
||||||
- 7.1
|
- 7.1
|
||||||
|
|
||||||
env:
|
env:
|
||||||
|
@ -24,7 +23,6 @@ env:
|
||||||
- typo3DatabaseHost="127.0.0.1"
|
- typo3DatabaseHost="127.0.0.1"
|
||||||
- typo3DatabaseUsername="travis"
|
- typo3DatabaseUsername="travis"
|
||||||
- typo3DatabasePassword=""
|
- typo3DatabasePassword=""
|
||||||
- TYPO3_VERSION="~7.6"
|
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
fast_finish: true
|
fast_finish: true
|
||||||
|
|
50
Classes/Database/Doctrine/Join.php
Normal file
50
Classes/Database/Doctrine/Join.php
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
<?php
|
||||||
|
namespace Codappix\SearchCore\Database\Doctrine;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2017 Daniel Siepmann <coding@daniel-siepmann.de>
|
||||||
|
*
|
||||||
|
* This program 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 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Join
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $table = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $condition = '';
|
||||||
|
|
||||||
|
public function __construct(string $table, string $condition)
|
||||||
|
{
|
||||||
|
$this->table = $table;
|
||||||
|
$this->condition = $condition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTable() : string
|
||||||
|
{
|
||||||
|
return $this->table;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCondition() : string
|
||||||
|
{
|
||||||
|
return $this->condition;
|
||||||
|
}
|
||||||
|
}
|
50
Classes/Database/Doctrine/Where.php
Normal file
50
Classes/Database/Doctrine/Where.php
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
<?php
|
||||||
|
namespace Codappix\SearchCore\Database\Doctrine;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2017 Daniel Siepmann <coding@daniel-siepmann.de>
|
||||||
|
*
|
||||||
|
* This program 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 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program 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.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Where
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $statement = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $parameters = [];
|
||||||
|
|
||||||
|
public function __construct(string $statement, array $parameters)
|
||||||
|
{
|
||||||
|
$this->statement = $statement;
|
||||||
|
$this->parameters = $parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getStatement() : string
|
||||||
|
{
|
||||||
|
return $this->statement;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getParameters() : array
|
||||||
|
{
|
||||||
|
return $this->parameters;
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,6 +22,9 @@ namespace Codappix\SearchCore\Domain\Index;
|
||||||
|
|
||||||
use Codappix\SearchCore\Configuration\ConfigurationContainerInterface;
|
use Codappix\SearchCore\Configuration\ConfigurationContainerInterface;
|
||||||
use Codappix\SearchCore\Connection\ConnectionInterface;
|
use Codappix\SearchCore\Connection\ConnectionInterface;
|
||||||
|
use TYPO3\CMS\Core\Database\ConnectionPool;
|
||||||
|
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
|
||||||
|
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will index the given table using configuration from TCA.
|
* Will index the given table using configuration from TCA.
|
||||||
|
@ -55,14 +58,12 @@ class TcaIndexer extends AbstractIndexer
|
||||||
*/
|
*/
|
||||||
protected function getRecords($offset, $limit)
|
protected function getRecords($offset, $limit)
|
||||||
{
|
{
|
||||||
$records = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
|
$records = $this->getQuery()
|
||||||
$this->tcaTableService->getFields(),
|
->setFirstResult($offset)
|
||||||
$this->tcaTableService->getTableClause(),
|
->setMaxResults($limit)
|
||||||
$this->tcaTableService->getWhereClause(),
|
->execute()
|
||||||
'',
|
->fetchAll();
|
||||||
'',
|
|
||||||
(int) $offset . ',' . (int) $limit
|
|
||||||
);
|
|
||||||
if ($records === null) {
|
if ($records === null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -82,12 +83,9 @@ class TcaIndexer extends AbstractIndexer
|
||||||
*/
|
*/
|
||||||
protected function getRecord($identifier)
|
protected function getRecord($identifier)
|
||||||
{
|
{
|
||||||
$record = $GLOBALS['TYPO3_DB']->exec_SELECTgetSingleRow(
|
$query = $this->getQuery();
|
||||||
$this->tcaTableService->getFields(),
|
$query = $query->andWhere($this->tcaTableService->getTableName() . '.uid = ' . (int) $identifier);
|
||||||
$this->tcaTableService->getTableClause(),
|
$record = $query->execute()->fetch();
|
||||||
$this->tcaTableService->getWhereClause()
|
|
||||||
. ' AND ' . $this->tcaTableService->getTableName() . '.uid = ' . (int) $identifier
|
|
||||||
);
|
|
||||||
|
|
||||||
if ($record === false || $record === null) {
|
if ($record === false || $record === null) {
|
||||||
throw new NoRecordFoundException(
|
throw new NoRecordFoundException(
|
||||||
|
@ -107,4 +105,29 @@ class TcaIndexer extends AbstractIndexer
|
||||||
{
|
{
|
||||||
return $this->tcaTableService->getTableName();
|
return $this->tcaTableService->getTableName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function getQuery($tcaTableService = null) : QueryBuilder
|
||||||
|
{
|
||||||
|
if ($tcaTableService === null) {
|
||||||
|
$tcaTableService = $this->tcaTableService;
|
||||||
|
}
|
||||||
|
$queryBuilder = $this->getDatabaseConnection()->getQueryBuilderForTable($tcaTableService->getTableName());
|
||||||
|
$where = $tcaTableService->getWhereClause();
|
||||||
|
$query = $queryBuilder->select(... $tcaTableService->getFields())
|
||||||
|
->from($tcaTableService->getTableClause())
|
||||||
|
->where($where->getStatement())
|
||||||
|
->setParameters($where->getParameters());
|
||||||
|
|
||||||
|
foreach ($tcaTableService->getJoins() as $join) {
|
||||||
|
$query->from($join->getTable());
|
||||||
|
$query->andWhere($join->getCondition());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getDatabaseConnection()
|
||||||
|
{
|
||||||
|
return GeneralUtility::makeInstance(ConnectionPool::class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,12 +75,7 @@ class PagesIndexer extends TcaIndexer
|
||||||
*/
|
*/
|
||||||
protected function fetchContentForPage($uid)
|
protected function fetchContentForPage($uid)
|
||||||
{
|
{
|
||||||
$contentElements = $GLOBALS['TYPO3_DB']->exec_SELECTgetRows(
|
$contentElements = $this->getQuery($this->contentTableService)->execute()->fetchAll();
|
||||||
$this->contentTableService->getFields(),
|
|
||||||
$this->contentTableService->getTableClause(),
|
|
||||||
$this->contentTableService->getWhereClause() .
|
|
||||||
sprintf(' AND %s.pid = %u', $this->contentTableService->getTableName(), $uid)
|
|
||||||
);
|
|
||||||
|
|
||||||
if ($contentElements === null) {
|
if ($contentElements === null) {
|
||||||
$this->logger->debug('No content for page ' . $uid);
|
$this->logger->debug('No content for page ' . $uid);
|
||||||
|
|
|
@ -20,8 +20,7 @@ namespace Codappix\SearchCore\Domain\Index\TcaIndexer;
|
||||||
* 02110-1301, USA.
|
* 02110-1301, USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use TYPO3\CMS\Backend\Form\FormDataCompiler;
|
use TYPO3\CMS\Backend\Utility\BackendUtility;
|
||||||
use TYPO3\CMS\Backend\Form\FormDataGroup\TcaDatabaseRecord;
|
|
||||||
use TYPO3\CMS\Core\SingletonInterface as Singleton;
|
use TYPO3\CMS\Core\SingletonInterface as Singleton;
|
||||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||||
|
|
||||||
|
@ -33,130 +32,65 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||||
*/
|
*/
|
||||||
class RelationResolver implements Singleton
|
class RelationResolver implements Singleton
|
||||||
{
|
{
|
||||||
/**
|
public function resolveRelationsForRecord(TcaTableService $service, array &$record) : void
|
||||||
* Resolve relations for the given record.
|
|
||||||
*
|
|
||||||
* @param TcaTableService $service
|
|
||||||
* @param array $record
|
|
||||||
*/
|
|
||||||
public function resolveRelationsForRecord(TcaTableService $service, array &$record)
|
|
||||||
{
|
{
|
||||||
$formData = GeneralUtility::makeInstance(
|
|
||||||
FormDataCompiler::class,
|
|
||||||
GeneralUtility::makeInstance(TcaDatabaseRecord::class)
|
|
||||||
)->compile([
|
|
||||||
'tableName' => $service->getTableName(),
|
|
||||||
'vanillaUid' => (int)$record['uid'],
|
|
||||||
'command' => 'edit',
|
|
||||||
]);
|
|
||||||
$record = $formData['databaseRow'];
|
|
||||||
|
|
||||||
foreach (array_keys($record) as $column) {
|
foreach (array_keys($record) as $column) {
|
||||||
|
// TODO: Define / configure fields to exclude?!
|
||||||
|
if ($column === 'pid') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$record[$column] = BackendUtility::getProcessedValueExtra(
|
||||||
|
$service->getTableName(),
|
||||||
|
$column,
|
||||||
|
$record[$column],
|
||||||
|
0,
|
||||||
|
$record['uid']
|
||||||
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$config = $service->getColumnConfig($column);
|
$config = $service->getColumnConfig($column);
|
||||||
|
|
||||||
|
if ($this->isRelation($config)) {
|
||||||
|
$record[$column] = $this->resolveValue($record[$column], $config);
|
||||||
|
}
|
||||||
} catch (InvalidArgumentException $e) {
|
} catch (InvalidArgumentException $e) {
|
||||||
// Column is not configured.
|
// Column is not configured.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! $this->isRelation($config) || !is_array($formData['processedTca']['columns'][$column])) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$record[$column] = $this->resolveValue($record[$column], $formData['processedTca']['columns'][$column]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Resolve the given value from TYPO3 API response.
|
|
||||||
*
|
|
||||||
* @param string $value The value from FormEngine to resolve.
|
|
||||||
* @param array $tcaColumn The tca config of the relation.
|
|
||||||
*
|
|
||||||
* @return array<String>|string
|
|
||||||
*/
|
|
||||||
protected function resolveValue($value, array $tcaColumn)
|
protected function resolveValue($value, array $tcaColumn)
|
||||||
{
|
{
|
||||||
if ($value === '' || $value === '0') {
|
if ($value === '' || $value === 'N/A') {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
if ($tcaColumn['config']['type'] === 'select') {
|
|
||||||
return $this->resolveSelectValue($value, $tcaColumn);
|
if ($tcaColumn['type'] === 'select' && strpos($value, ';') !== false) {
|
||||||
}
|
|
||||||
if ($tcaColumn['config']['type'] === 'group' && strpos($value, '|') !== false) {
|
|
||||||
return $this->resolveForeignDbValue($value);
|
return $this->resolveForeignDbValue($value);
|
||||||
}
|
}
|
||||||
if ($tcaColumn['config']['type'] === 'inline') {
|
if (in_array($tcaColumn['type'], ['inline', 'group', 'select'])) {
|
||||||
return $this->resolveInlineValue($tcaColumn);
|
return $this->resolveInlineValue($value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected function isRelation(array &$config) : bool
|
||||||
* @param array Column config.
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
protected function isRelation(array &$config)
|
|
||||||
{
|
{
|
||||||
return isset($config['foreign_table'])
|
return isset($config['foreign_table'])
|
||||||
|| (isset($config['items']) && is_array($config['items']))
|
|| (isset($config['renderType']) && $config['renderType'] !== 'selectSingle')
|
||||||
|| (isset($config['internal_type']) && strtolower($config['internal_type']) === 'db')
|
|| (isset($config['internal_type']) && strtolower($config['internal_type']) === 'db')
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected function resolveForeignDbValue(string $value) : array
|
||||||
* Resolves internal representation of select to array of labels.
|
|
||||||
*
|
|
||||||
* @param array $value
|
|
||||||
* @param array $tcaColumn
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
protected function resolveSelectValue(array $values, array $tcaColumn)
|
|
||||||
{
|
{
|
||||||
$resolvedValues = [];
|
return array_map('trim', explode(';', $value));
|
||||||
|
|
||||||
foreach ($tcaColumn['config']['items'] as $item) {
|
|
||||||
if (in_array($item[1], $values)) {
|
|
||||||
$resolvedValues[] = $item[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($tcaColumn['config']['renderType'] === 'selectSingle' || $tcaColumn['config']['maxitems'] === 1) {
|
|
||||||
return current($resolvedValues);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $resolvedValues;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected function resolveInlineValue(string $value) : array
|
||||||
* @param string $value
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
protected function resolveForeignDbValue($value)
|
|
||||||
{
|
{
|
||||||
$titles = [];
|
return array_map('trim', explode(',', $value));
|
||||||
|
|
||||||
foreach (explode(',', urldecode($value)) as $title) {
|
|
||||||
$titles[] = explode('|', $title)[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $titles;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param array $tcaColumn
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
protected function resolveInlineValue(array $tcaColumn)
|
|
||||||
{
|
|
||||||
$titles = [];
|
|
||||||
|
|
||||||
foreach ($tcaColumn['children'] as $selected) {
|
|
||||||
$titles[] = $selected['recordTitle'];
|
|
||||||
}
|
|
||||||
|
|
||||||
return $titles;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,8 @@ namespace Codappix\SearchCore\Domain\Index\TcaIndexer;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use Codappix\SearchCore\Configuration\ConfigurationContainerInterface;
|
use Codappix\SearchCore\Configuration\ConfigurationContainerInterface;
|
||||||
|
use Codappix\SearchCore\Database\Doctrine\Join;
|
||||||
|
use Codappix\SearchCore\Database\Doctrine\Where;
|
||||||
use Codappix\SearchCore\Domain\Index\IndexingException;
|
use Codappix\SearchCore\Domain\Index\IndexingException;
|
||||||
use TYPO3\CMS\Backend\Utility\BackendUtility;
|
use TYPO3\CMS\Backend\Utility\BackendUtility;
|
||||||
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
use TYPO3\CMS\Core\Utility\GeneralUtility;
|
||||||
|
@ -107,7 +109,7 @@ class TcaTableService
|
||||||
/**
|
/**
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getTableName()
|
public function getTableName() : string
|
||||||
{
|
{
|
||||||
return $this->tableName;
|
return $this->tableName;
|
||||||
}
|
}
|
||||||
|
@ -115,13 +117,9 @@ class TcaTableService
|
||||||
/**
|
/**
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getTableClause()
|
public function getTableClause() : string
|
||||||
{
|
{
|
||||||
if ($this->tableName === 'pages') {
|
return $this->tableName;
|
||||||
return $this->tableName;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->tableName . ' LEFT JOIN pages on ' . $this->tableName . '.pid = pages.uid';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -130,7 +128,7 @@ class TcaTableService
|
||||||
* @param array &$records
|
* @param array &$records
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function filterRecordsByRootLineBlacklist(array &$records)
|
public function filterRecordsByRootLineBlacklist(array &$records) : void
|
||||||
{
|
{
|
||||||
$records = array_filter(
|
$records = array_filter(
|
||||||
$records,
|
$records,
|
||||||
|
@ -144,7 +142,7 @@ class TcaTableService
|
||||||
* Adjust record accordingly to configuration.
|
* Adjust record accordingly to configuration.
|
||||||
* @param array &$record
|
* @param array &$record
|
||||||
*/
|
*/
|
||||||
public function prepareRecord(array &$record)
|
public function prepareRecord(array &$record) : void
|
||||||
{
|
{
|
||||||
$this->relationResolver->resolveRelationsForRecord($this, $record);
|
$this->relationResolver->resolveRelationsForRecord($this, $record);
|
||||||
|
|
||||||
|
@ -156,22 +154,10 @@ class TcaTableService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function getWhereClause() : Where
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getWhereClause()
|
|
||||||
{
|
{
|
||||||
$whereClause = '1=1'
|
$parameters = [];
|
||||||
. BackendUtility::BEenableFields($this->tableName)
|
$whereClause = $this->getSystemWhereClause();
|
||||||
. BackendUtility::deleteClause($this->tableName)
|
|
||||||
. ' AND pages.no_search = 0'
|
|
||||||
;
|
|
||||||
|
|
||||||
if ($this->tableName !== 'pages') {
|
|
||||||
$whereClause .= BackendUtility::BEenableFields('pages')
|
|
||||||
. BackendUtility::deleteClause('pages')
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
$userDefinedWhere = $this->configuration->getIfExists('indexing.' . $this->getTableName() . '.additionalWhereClause');
|
$userDefinedWhere = $this->configuration->getIfExists('indexing.' . $this->getTableName() . '.additionalWhereClause');
|
||||||
if (is_string($userDefinedWhere)) {
|
if (is_string($userDefinedWhere)) {
|
||||||
|
@ -179,22 +165,16 @@ class TcaTableService
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->isBlacklistedRootLineConfigured()) {
|
if ($this->isBlacklistedRootLineConfigured()) {
|
||||||
$whereClause .= ' AND pages.uid NOT IN ('
|
$parameters[':blacklistedRootLine'] = $this->getBlacklistedRootLine();
|
||||||
. implode(',', $this->getBlacklistedRootLine())
|
$whereClause .= ' AND pages.uid NOT IN (:blacklistedRootLine)'
|
||||||
. ')'
|
. ' AND pages.pid NOT IN (:blacklistedRootLine)';
|
||||||
. ' AND pages.pid NOT IN ('
|
|
||||||
. implode(',', $this->getBlacklistedRootLine())
|
|
||||||
. ')';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->logger->debug('Generated where clause.', [$this->tableName, $whereClause]);
|
$this->logger->debug('Generated where clause.', [$this->tableName, $whereClause]);
|
||||||
return $whereClause;
|
return new Where($whereClause, $parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function getFields() : array
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getFields()
|
|
||||||
{
|
{
|
||||||
$fields = array_merge(
|
$fields = array_merge(
|
||||||
['uid','pid'],
|
['uid','pid'],
|
||||||
|
@ -211,14 +191,46 @@ class TcaTableService
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->logger->debug('Generated fields.', [$this->tableName, $fields]);
|
$this->logger->debug('Generated fields.', [$this->tableName, $fields]);
|
||||||
return implode(',', $fields);
|
return $fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getJoins() : array
|
||||||
|
{
|
||||||
|
if ($this->tableName === 'pages') {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
new Join('pages', 'pages.uid = ' . $this->tableName . '.pid'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate SQL for TYPO3 as a system, to make sure only available records
|
||||||
|
* are fetched.
|
||||||
|
*/
|
||||||
|
public function getSystemWhereClause() : string
|
||||||
|
{
|
||||||
|
$whereClause = '1=1'
|
||||||
|
. BackendUtility::BEenableFields($this->tableName)
|
||||||
|
. BackendUtility::deleteClause($this->tableName)
|
||||||
|
. ' AND pages.no_search = 0'
|
||||||
|
;
|
||||||
|
|
||||||
|
if ($this->tableName !== 'pages') {
|
||||||
|
$whereClause .= BackendUtility::BEenableFields('pages')
|
||||||
|
. BackendUtility::deleteClause('pages')
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $whereClause;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string
|
* @param string
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
protected function isSystemField($columnName)
|
protected function isSystemField($columnName) : bool
|
||||||
{
|
{
|
||||||
$systemFields = [
|
$systemFields = [
|
||||||
// Versioning fields,
|
// Versioning fields,
|
||||||
|
@ -242,7 +254,7 @@ class TcaTableService
|
||||||
* @return array
|
* @return array
|
||||||
* @throws InvalidArgumentException
|
* @throws InvalidArgumentException
|
||||||
*/
|
*/
|
||||||
public function getColumnConfig($columnName)
|
public function getColumnConfig($columnName) : array
|
||||||
{
|
{
|
||||||
if (!isset($this->tca['columns'][$columnName])) {
|
if (!isset($this->tca['columns'][$columnName])) {
|
||||||
throw new InvalidArgumentException(
|
throw new InvalidArgumentException(
|
||||||
|
@ -265,7 +277,7 @@ class TcaTableService
|
||||||
* @param array &$record
|
* @param array &$record
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
protected function isRecordBlacklistedByRootline(array &$record)
|
protected function isRecordBlacklistedByRootline(array &$record) : bool
|
||||||
{
|
{
|
||||||
$pageUid = $record['pid'];
|
$pageUid = $record['pid'];
|
||||||
if ($this->tableName === 'pages') {
|
if ($this->tableName === 'pages') {
|
||||||
|
@ -322,7 +334,7 @@ class TcaTableService
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
protected function isBlackListedRootLineConfigured()
|
protected function isBlackListedRootLineConfigured() : bool
|
||||||
{
|
{
|
||||||
return (bool) $this->configuration->getIfExists('indexing.' . $this->getTableName() . '.rootLineBlacklist');
|
return (bool) $this->configuration->getIfExists('indexing.' . $this->getTableName() . '.rootLineBlacklist');
|
||||||
}
|
}
|
||||||
|
@ -332,7 +344,7 @@ class TcaTableService
|
||||||
*
|
*
|
||||||
* @return array<Int>
|
* @return array<Int>
|
||||||
*/
|
*/
|
||||||
protected function getBlackListedRootLine()
|
protected function getBlackListedRootLine() : array
|
||||||
{
|
{
|
||||||
return GeneralUtility::intExplode(',', $this->configuration->getIfExists('indexing.' . $this->getTableName() . '.rootLineBlacklist'));
|
return GeneralUtility::intExplode(',', $this->configuration->getIfExists('indexing.' . $this->getTableName() . '.rootLineBlacklist'));
|
||||||
}
|
}
|
||||||
|
|
9
Makefile
9
Makefile
|
@ -1,17 +1,18 @@
|
||||||
mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
|
mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
|
||||||
current_dir := $(dir $(mkfile_path))
|
current_dir := $(dir $(mkfile_path))
|
||||||
|
|
||||||
TYPO3_WEB_DIR := $(current_dir).Build/Web
|
TYPO3_WEB_DIR := $(current_dir).Build/web
|
||||||
|
TYPO3_PATH_ROOT := $(current_dir).Build/web
|
||||||
# Allow different versions on travis
|
# Allow different versions on travis
|
||||||
TYPO3_VERSION ?= ~7.6
|
TYPO3_VERSION ?= ~8.7
|
||||||
typo3DatabaseName ?= "searchcore_test"
|
typo3DatabaseName ?= "searchcore_test2"
|
||||||
typo3DatabaseUsername ?= "dev"
|
typo3DatabaseUsername ?= "dev"
|
||||||
typo3DatabasePassword ?= "dev"
|
typo3DatabasePassword ?= "dev"
|
||||||
typo3DatabaseHost ?= "127.0.0.1"
|
typo3DatabaseHost ?= "127.0.0.1"
|
||||||
|
|
||||||
.PHONY: install
|
.PHONY: install
|
||||||
install: clean
|
install: clean
|
||||||
COMPOSER_PROCESS_TIMEOUT=1000 composer require -vv --dev --prefer-source --ignore-platform-reqs typo3/cms="$(TYPO3_VERSION)"
|
COMPOSER_PROCESS_TIMEOUT=1000 composer require -vv --dev --prefer-dist --ignore-platform-reqs typo3/cms="$(TYPO3_VERSION)"
|
||||||
git checkout composer.json
|
git checkout composer.json
|
||||||
|
|
||||||
functionalTests:
|
functionalTests:
|
||||||
|
|
|
@ -55,7 +55,7 @@ class FilterTest extends AbstractFunctionalTestCase
|
||||||
|
|
||||||
$searchRequest->setFilter(['CType' => 'HTML']);
|
$searchRequest->setFilter(['CType' => 'HTML']);
|
||||||
$result = $searchService->search($searchRequest);
|
$result = $searchService->search($searchRequest);
|
||||||
$this->assertSame('5', $result->getResults()[0]['uid'], 'Did not get the expected result entry.');
|
$this->assertSame(5, $result->getResults()[0]['uid'], 'Did not get the expected result entry.');
|
||||||
$this->assertSame(1, count($result), 'Did not receive the single filtered element.');
|
$this->assertSame(1, count($result), 'Did not receive the single filtered element.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,29 @@ class IndexTcaTableTest extends AbstractFunctionalTestCase
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @test
|
||||||
|
*/
|
||||||
|
public function indexSingleBasicTtContent()
|
||||||
|
{
|
||||||
|
\TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(ObjectManager::class)
|
||||||
|
->get(IndexerFactory::class)
|
||||||
|
->getIndexer('tt_content')
|
||||||
|
->indexDocument(6)
|
||||||
|
;
|
||||||
|
|
||||||
|
$response = $this->client->request('typo3content/_search?q=*:*');
|
||||||
|
|
||||||
|
$this->assertTrue($response->isOK(), 'Elastica did not answer with ok code.');
|
||||||
|
$this->assertSame($response->getData()['hits']['total'], 1, 'Not exactly 1 document was indexed.');
|
||||||
|
$this->assertArraySubset(
|
||||||
|
['_source' => ['header' => 'indexed content element']],
|
||||||
|
$response->getData()['hits']['hits'][0],
|
||||||
|
false,
|
||||||
|
'Record was not indexed.'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @test
|
* @test
|
||||||
* @expectedException \Codappix\SearchCore\Domain\Index\IndexingException
|
* @expectedException \Codappix\SearchCore\Domain\Index\IndexingException
|
||||||
|
@ -152,7 +175,7 @@ class IndexTcaTableTest extends AbstractFunctionalTestCase
|
||||||
['_source' => [
|
['_source' => [
|
||||||
'uid' => '11',
|
'uid' => '11',
|
||||||
'CType' => 'Header', // Testing items
|
'CType' => 'Header', // Testing items
|
||||||
'categories' => ['Category 1', 'Category 2'], // Testing mm (with sorting)
|
'categories' => ['Category 2', 'Category 1'], // Testing mm
|
||||||
]],
|
]],
|
||||||
$response->getData()['hits']['hits'][0],
|
$response->getData()['hits']['hits'][0],
|
||||||
false,
|
false,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<phpunit
|
<phpunit
|
||||||
backupGlobals="true"
|
backupGlobals="true"
|
||||||
backupStaticAttributes="false"
|
backupStaticAttributes="false"
|
||||||
bootstrap="../../.Build/vendor/typo3/cms/typo3/sysext/core/Build/FunctionalTestsBootstrap.php"
|
bootstrap="../../.Build/vendor/typo3/testing-framework/Resources/Core/Build/FunctionalTestsBootstrap.php"
|
||||||
|
|
||||||
colors="true"
|
colors="true"
|
||||||
convertErrorsToExceptions="false"
|
convertErrorsToExceptions="false"
|
||||||
|
|
|
@ -50,7 +50,6 @@ abstract class AbstractDataHandlerTest extends AbstractFunctionalTestCase
|
||||||
->setMethods(['add', 'update', 'delete'])
|
->setMethods(['add', 'update', 'delete'])
|
||||||
->getMock();
|
->getMock();
|
||||||
|
|
||||||
// This way TYPO3 will use our mock instead of a new instance.
|
GeneralUtility::setSingletonInstance(DataHandlerHook::class, new DataHandlerHook($this->subject));
|
||||||
$GLOBALS['T3_VAR']['getUserObj']['&' . DataHandlerHook::class] = new DataHandlerHook($this->subject);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,8 @@ class ProcessesAllowedTablesTest extends AbstractDataHandlerTest
|
||||||
*/
|
*/
|
||||||
public function deletionWillBeTriggeredForTtContent()
|
public function deletionWillBeTriggeredForTtContent()
|
||||||
{
|
{
|
||||||
$this->subject->expects($this->exactly(1))->method('delete')
|
$this->subject->expects($this->exactly(1))
|
||||||
|
->method('delete')
|
||||||
->with($this->equalTo('tt_content'), $this->equalTo('1'));
|
->with($this->equalTo('tt_content'), $this->equalTo('1'));
|
||||||
|
|
||||||
$tce = GeneralUtility::makeInstance(Typo3DataHandler::class);
|
$tce = GeneralUtility::makeInstance(Typo3DataHandler::class);
|
||||||
|
@ -71,9 +72,9 @@ class ProcessesAllowedTablesTest extends AbstractDataHandlerTest
|
||||||
->with(
|
->with(
|
||||||
$this->equalTo('tt_content'),
|
$this->equalTo('tt_content'),
|
||||||
$this->callback(function ($record) {
|
$this->callback(function ($record) {
|
||||||
return isset($record['uid']) && $record['uid'] === '1'
|
return isset($record['uid']) && $record['uid'] === 1
|
||||||
&& isset($record['pid']) && $record['pid'] === '1'
|
&& isset($record['pid']) && $record['pid'] === 1
|
||||||
&& isset($record['colPos']) && $record['colPos'] === '1'
|
&& isset($record['colPos']) && $record['colPos'] === 1
|
||||||
;
|
;
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
@ -99,7 +100,7 @@ class ProcessesAllowedTablesTest extends AbstractDataHandlerTest
|
||||||
->with(
|
->with(
|
||||||
$this->equalTo('tt_content'),
|
$this->equalTo('tt_content'),
|
||||||
$this->callback(function ($record) {
|
$this->callback(function ($record) {
|
||||||
return isset($record['uid']) && $record['uid'] === 2
|
return isset($record['uid']) && $record['uid'] === '2'
|
||||||
&& isset($record['pid']) && $record['pid'] === 1
|
&& isset($record['pid']) && $record['pid'] === 1
|
||||||
&& isset($record['header']) && $record['header'] === 'a new record'
|
&& isset($record['header']) && $record['header'] === 'a new record'
|
||||||
;
|
;
|
||||||
|
|
|
@ -37,10 +37,6 @@ class RelationResolverTest extends AbstractFunctionalTestCase
|
||||||
$objectManager = GeneralUtility::makeInstance(ObjectManager::class);
|
$objectManager = GeneralUtility::makeInstance(ObjectManager::class);
|
||||||
$table = 'sys_file';
|
$table = 'sys_file';
|
||||||
|
|
||||||
// Only by adding the field to showitem, it will be processed by FormEngine.
|
|
||||||
// We use this field to test inline relations, as there is only one alternative.
|
|
||||||
$GLOBALS['TCA']['sys_file']['types'][1]['showitem'] .= ',metadata';
|
|
||||||
|
|
||||||
$subject = $objectManager->get(TcaTableService::class, $table);
|
$subject = $objectManager->get(TcaTableService::class, $table);
|
||||||
$record = BackendUtility::getRecord($table, 1);
|
$record = BackendUtility::getRecord($table, 1);
|
||||||
$subject->prepareRecord($record);
|
$subject->prepareRecord($record);
|
||||||
|
@ -113,8 +109,8 @@ class RelationResolverTest extends AbstractFunctionalTestCase
|
||||||
|
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
[
|
[
|
||||||
'Category 1',
|
|
||||||
'Category 2',
|
'Category 2',
|
||||||
|
'Category 1',
|
||||||
],
|
],
|
||||||
$record['categories'],
|
$record['categories'],
|
||||||
'Foreign mm select relation was not resolved as expected.'
|
'Foreign mm select relation was not resolved as expected.'
|
||||||
|
|
|
@ -60,10 +60,18 @@ class TcaTableServiceTest extends AbstractUnitTestCase
|
||||||
->method('getIfExists')
|
->method('getIfExists')
|
||||||
->withConsecutive(['indexing.table.additionalWhereClause'], ['indexing.table.rootLineBlacklist'])
|
->withConsecutive(['indexing.table.additionalWhereClause'], ['indexing.table.rootLineBlacklist'])
|
||||||
->will($this->onConsecutiveCalls(null, false));
|
->will($this->onConsecutiveCalls(null, false));
|
||||||
|
$this->subject->expects($this->once())
|
||||||
|
->method('getSystemWhereClause')
|
||||||
|
->will($this->returnValue('1=1 AND pages.no_search = 0'));
|
||||||
|
|
||||||
|
$whereClause = $this->subject->getWhereClause();
|
||||||
$this->assertSame(
|
$this->assertSame(
|
||||||
'1=1 AND pages.no_search = 0',
|
'1=1 AND pages.no_search = 0',
|
||||||
$this->subject->getWhereClause()
|
$whereClause->getStatement()
|
||||||
|
);
|
||||||
|
$this->assertSame(
|
||||||
|
[],
|
||||||
|
$whereClause->getParameters()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,10 +84,18 @@ class TcaTableServiceTest extends AbstractUnitTestCase
|
||||||
->method('getIfExists')
|
->method('getIfExists')
|
||||||
->withConsecutive(['indexing.table.additionalWhereClause'], ['indexing.table.rootLineBlacklist'])
|
->withConsecutive(['indexing.table.additionalWhereClause'], ['indexing.table.rootLineBlacklist'])
|
||||||
->will($this->onConsecutiveCalls('table.field = "someValue"', false));
|
->will($this->onConsecutiveCalls('table.field = "someValue"', false));
|
||||||
|
$this->subject->expects($this->once())
|
||||||
|
->method('getSystemWhereClause')
|
||||||
|
->will($this->returnValue('1=1 AND pages.no_search = 0'));
|
||||||
|
|
||||||
|
$whereClause = $this->subject->getWhereClause();
|
||||||
$this->assertSame(
|
$this->assertSame(
|
||||||
'1=1 AND pages.no_search = 0 AND table.field = "someValue"',
|
'1=1 AND pages.no_search = 0 AND table.field = "someValue"',
|
||||||
$this->subject->getWhereClause()
|
$whereClause->getStatement()
|
||||||
|
);
|
||||||
|
$this->assertSame(
|
||||||
|
[],
|
||||||
|
$whereClause->getParameters()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<phpunit
|
<phpunit
|
||||||
backupGlobals="false"
|
backupGlobals="false"
|
||||||
backupStaticAttributes="false"
|
backupStaticAttributes="false"
|
||||||
bootstrap="../../.Build/vendor/typo3/cms/typo3/sysext/core/Build/UnitTestsBootstrap.php"
|
bootstrap="../../.Build/vendor/typo3/testing-framework/Resources/Core/Build/UnitTestsBootstrap.php"
|
||||||
|
|
||||||
colors="true"
|
colors="true"
|
||||||
convertErrorsToExceptions="false"
|
convertErrorsToExceptions="false"
|
||||||
|
|
|
@ -16,12 +16,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"require" : {
|
"require" : {
|
||||||
"php": ">=5.6.0",
|
"php": ">=7.1.0",
|
||||||
"typo3/cms": "~7.6",
|
"typo3/cms": "~8.7",
|
||||||
"ruflin/elastica": "~3.2"
|
"ruflin/elastica": "~3.2"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "~5.7.0"
|
"typo3/testing-framework": "~1.1.0",
|
||||||
|
"phpunit/phpunit": "~6.2.0"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"optimize-autoloader": true,
|
"optimize-autoloader": true,
|
||||||
|
@ -30,14 +31,14 @@
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"post-autoload-dump": [
|
"post-autoload-dump": [
|
||||||
"mkdir -p .Build/Web/typo3conf/ext/",
|
"mkdir -p .Build/web/typo3conf/ext/",
|
||||||
"[ -L .Build/Web/typo3conf/ext/search_core ] || ln -snvf ../../../../. .Build/Web/typo3conf/ext/search_core"
|
"[ -L .Build/web/typo3conf/ext/search_core ] || ln -snvf ../../../../. .Build/web/typo3conf/ext/search_core"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"extra": {
|
"extra": {
|
||||||
"typo3/cms": {
|
"typo3/cms": {
|
||||||
"cms-package-dir": "{$vendor-dir}/typo3/cms",
|
"cms-package-dir": "{$vendor-dir}/typo3/cms",
|
||||||
"web-dir": ".Build/Web"
|
"web-dir": ".Build/web"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"authors": [
|
"authors": [
|
||||||
|
|
|
@ -7,8 +7,8 @@ $EM_CONF[$_EXTKEY] = [
|
||||||
'clearCacheOnLoad' => 1,
|
'clearCacheOnLoad' => 1,
|
||||||
'constraints' => [
|
'constraints' => [
|
||||||
'depends' => [
|
'depends' => [
|
||||||
'typo3' => '7.6.0-7.6.99',
|
'typo3' => '8.7.0-8.7.99',
|
||||||
'php' => '5.6.0-7.99.99'
|
'php' => '7.1.0-7.99.99'
|
||||||
],
|
],
|
||||||
'conflicts' => [],
|
'conflicts' => [],
|
||||||
],
|
],
|
||||||
|
|
|
@ -16,10 +16,10 @@ call_user_func(
|
||||||
],
|
],
|
||||||
't3lib/class.t3lib_tcemain.php' => [
|
't3lib/class.t3lib_tcemain.php' => [
|
||||||
'processCmdmapClass' => [
|
'processCmdmapClass' => [
|
||||||
$extensionKey => '&' . \Codappix\SearchCore\Hook\DataHandler::class,
|
$extensionKey => \Codappix\SearchCore\Hook\DataHandler::class,
|
||||||
],
|
],
|
||||||
'processDatamapClass' => [
|
'processDatamapClass' => [
|
||||||
$extensionKey => '&' . \Codappix\SearchCore\Hook\DataHandler::class,
|
$extensionKey => \Codappix\SearchCore\Hook\DataHandler::class,
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
|
Loading…
Reference in a new issue