Merge pull request #57 from Codappix/feature/cms-8-support

Feature: Support TYPO3 8
This commit is contained in:
Daniel Siepmann 2017-09-05 20:29:45 +02:00 committed by GitHub
commit 8494901b58
19 changed files with 289 additions and 190 deletions

View file

@ -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

View 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;
}
}

View 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;
}
}

View file

@ -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);
}
} }

View file

@ -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);

View file

@ -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;
} }
} }

View file

@ -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'));
} }

View file

@ -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:

View file

@ -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.');
} }

View file

@ -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,

View file

@ -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"

View file

@ -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);
} }
} }

View file

@ -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'
; ;

View file

@ -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.'

View file

@ -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()
); );
} }
} }

View file

@ -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"

View file

@ -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": [

View file

@ -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' => [],
], ],

View file

@ -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,
], ],
], ],
], ],