Merge pull request #98 from Codappix/feature/provide-form-finisher

FEATURE: Provide form finisher for integration into form extension
This commit is contained in:
Daniel Siepmann 2017-11-10 22:05:34 +01:00 committed by GitHub
commit 7472cab660
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 278 additions and 0 deletions

View file

@ -0,0 +1,71 @@
<?php
namespace Codappix\SearchCore\Integration\Form\Finisher;
/*
* 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.
*/
use TYPO3\CMS\Form\Domain\Finishers\AbstractFinisher;
use TYPO3\CMS\Form\Domain\Finishers\Exception\FinisherException;
/**
* Integrates search_core indexing into TYPO3 Form extension.
*
* Add this finisher AFTER all database operations, as search_core will fetch
* information from database.
*/
class DataHandlerFinisher extends AbstractFinisher
{
/**
* @var \Codappix\SearchCore\Domain\Service\DataHandler
* @inject
*/
protected $dataHandler;
/**
* @var array
*/
protected $defaultOptions = [
'indexIdentifier' => null,
'recordUid' => null,
'action' => '',
];
protected function executeInternal()
{
$action = $this->parseOption('action');
$record = ['uid' => (int) $this->parseOption('recordUid')];
$tableName = $this->parseOption('indexIdentifier');
if ($action === '' || $tableName === '' || !is_string($tableName) || $record['uid'] === 0) {
throw new FinisherException('Not all necessary options were set.', 1510313095);
}
switch ($action) {
case 'update':
$this->dataHandler->update($tableName, $record);
break;
case 'add':
$this->dataHandler->add($tableName, $record);
break;
case 'delete':
$this->dataHandler->delete($tableName, $record['uid']);
break;
}
}
}

View file

@ -15,6 +15,8 @@ configuration needs. Still it's possible to configure the indexer.
Also custom classes can be used as indexers. Also custom classes can be used as indexers.
Furthermore a finisher for TYPO3 Form-Extension is provided to integrate indexing.
.. _features_search: .. _features_search:
Searching Searching

View file

@ -43,6 +43,34 @@ The tables have to be configured via :ref:`configuration_options_index`.
Not all hook operations are supported yet, see :issue:`27`. Not all hook operations are supported yet, see :issue:`27`.
.. _usage_form_finisher:
Form finisher
-------------
A form finisher is provided to integrate indexing into form extension.
Add form finisher to your available finishers and configure it like:
.. code-block:: yaml
:linenos:
-
identifier: SearchCoreIndexer
options:
action: 'delete'
indexIdentifier: 'fe_users'
recordUid: '{FeUser.user.uid}'
All three options are necessary, where
``action``
Is one of ``delete``, ``update`` or ``add``.
``indexIdentifier``
Is a configured index identifier.
``recordUid``
Has to be the uid of the record to index.
.. _usage_searching: .. _usage_searching:
Searching / Frontend Plugin Searching / Frontend Plugin

View file

@ -21,13 +21,23 @@ namespace Codappix\SearchCore\Tests\Unit;
*/ */
use TYPO3\CMS\Core\Tests\UnitTestCase as CoreTestCase; use TYPO3\CMS\Core\Tests\UnitTestCase as CoreTestCase;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Object\ObjectManager;
use TYPO3\CMS\Form\Service\TranslationService;
abstract class AbstractUnitTestCase extends CoreTestCase abstract class AbstractUnitTestCase extends CoreTestCase
{ {
/**
* @var array A backup of registered singleton instances
*/
protected $singletonInstances = [];
public function setUp() public function setUp()
{ {
parent::setUp(); parent::setUp();
$this->singletonInstances = GeneralUtility::getSingletonInstances();
// Disable caching backends to make TYPO3 parts work in unit test mode. // Disable caching backends to make TYPO3 parts work in unit test mode.
\TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance( \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
@ -39,6 +49,12 @@ abstract class AbstractUnitTestCase extends CoreTestCase
]); ]);
} }
public function tearDown()
{
GeneralUtility::resetSingletonInstances($this->singletonInstances);
parent::tearDown();
}
/** /**
* @return \TYPO3\CMS\Core\Log\LogManager * @return \TYPO3\CMS\Core\Log\LogManager
*/ */
@ -58,4 +74,25 @@ abstract class AbstractUnitTestCase extends CoreTestCase
return $logger; return $logger;
} }
/**
* Configure translation service mock for Form Finisher.
*
* This way parseOption will always return the configured value.
*/
protected function configureMockedTranslationService()
{
$translationService = $this->getMockBuilder(TranslationService::class)->getMock();
$translationService->expects($this->any())
->method('translateFinisherOption')
->willReturnCallback(function ($formRuntime, $finisherIdentifier, $optionKey, $optionValue) {
return $optionValue;
});
$objectManager = $this->getMockBuilder(ObjectManager::class)->getMock();
$objectManager->expects($this->any())
->method('get')
->with(TranslationService::class)
->willReturn($translationService);
GeneralUtility::setSingletonInstance(ObjectManager::class, $objectManager);
}
} }

View file

@ -0,0 +1,140 @@
<?php
namespace Codappix\SearchCore\Tests\Unit\Integration\Form\Finisher;
/*
* 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.
*/
use Codappix\SearchCore\Domain\Service\DataHandler;
use Codappix\SearchCore\Integration\Form\Finisher\DataHandlerFinisher;
use Codappix\SearchCore\Tests\Unit\AbstractUnitTestCase;
use TYPO3\CMS\Form\Domain\Finishers\Exception\FinisherException;
use TYPO3\CMS\Form\Domain\Finishers\FinisherContext;
class DataHandlerFinisherTest extends AbstractUnitTestCase
{
/**
* @var DataHandlerFinisher
*/
protected $subject;
/**
* @var DataHandler
*/
protected $dataHandlerMock;
/**
* @var FinisherContext
*/
protected $finisherContextMock;
public function setUp()
{
parent::setUp();
$this->configureMockedTranslationService();
$this->dataHandlerMock = $this->getMockBuilder(DataHandler::class)
->disableOriginalConstructor()
->getMock();
$this->finisherContextMock = $this->getMockBuilder(FinisherContext::class)
->disableOriginalConstructor()
->getMock();
$this->subject = new DataHandlerFinisher();
$this->inject($this->subject, 'dataHandler', $this->dataHandlerMock);
}
/**
* @test
* @dataProvider possibleFinisherSetup
*/
public function validConfiguration(string $action, array $nonCalledActions, $expectedSecondArgument)
{
$this->subject->setOptions([
'indexIdentifier' => 'test_identifier',
'recordUid' => '23',
'action' => $action,
]);
foreach ($nonCalledActions as $nonCalledAction) {
$this->dataHandlerMock->expects($this->never())->method($nonCalledAction);
}
$this->dataHandlerMock->expects($this->once())->method($action)
->with('test_identifier', $expectedSecondArgument);
$this->subject->execute($this->finisherContextMock);
}
public function possibleFinisherSetup() : array
{
return [
'valid add configuration' => [
'action' => 'add',
'nonCalledActions' => ['delete', 'update'],
'expectedSecondArgument' => ['uid' => 23],
],
'valid update configuration' => [
'action' => 'update',
'nonCalledActions' => ['delete', 'add'],
'expectedSecondArgument' => ['uid' => 23],
],
'valid delete configuration' => [
'action' => 'delete',
'nonCalledActions' => ['update', 'add'],
'expectedSecondArgument' => 23,
],
];
}
/**
* @test
* @dataProvider invalidFinisherSetup
*/
public function nothingHappensIfUnknownActionIsConfigured(array $options)
{
$this->subject->setOptions($options);
foreach (['add', 'update', 'delete'] as $nonCalledAction) {
$this->dataHandlerMock->expects($this->never())->method($nonCalledAction);
}
$this->expectException(FinisherException::class);
$this->subject->execute($this->finisherContextMock);
}
public function invalidFinisherSetup() : array
{
return [
'missing options' => [
'options' => [],
],
'missing action option' => [
'options' => [
'indexIdentifier' => 'identifier',
'recordUid' => '20',
],
],
'missing record uid option' => [
'options' => [
'indexIdentifier' => 'identifier',
'action' => 'update',
],
],
];
}
}