From 224f945d82db7c827a98a226b949248710d87340 Mon Sep 17 00:00:00 2001 From: Daniel Siepmann Date: Fri, 9 Dec 2016 11:47:28 +0100 Subject: [PATCH] FEATURE: Add first code and tests to integrate travis ci --- .gitignore | 2 + Classes/Hook/DataHandler.php | 158 ++++++++++++++++++++++++++++ Classes/Service/DataHandler.php | 80 ++++++++++++++ Tests/Fakes/FakeLogManager.php | 39 +++++++ Tests/Unit/Hook/DataHandlerTest.php | 150 ++++++++++++++++++++++++++ Tests/Unit/UnitTests.xml | 22 ++++ composer.json | 26 ++++- 7 files changed, 476 insertions(+), 1 deletion(-) create mode 100644 .gitignore create mode 100644 Classes/Hook/DataHandler.php create mode 100644 Classes/Service/DataHandler.php create mode 100644 Tests/Fakes/FakeLogManager.php create mode 100644 Tests/Unit/Hook/DataHandlerTest.php create mode 100644 Tests/Unit/UnitTests.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f6db3ce --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +composer.lock +.Build diff --git a/Classes/Hook/DataHandler.php b/Classes/Hook/DataHandler.php new file mode 100644 index 0000000..761e593 --- /dev/null +++ b/Classes/Hook/DataHandler.php @@ -0,0 +1,158 @@ + + * + * 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\Backend\Utility\BackendUtility; +use TYPO3\CMS\Core\DataHandling\DataHandler as CoreDataHandler; +use TYPO3\CMS\Core\Log\LogManager; +use TYPO3\CMS\Core\Log\Logger; +use TYPO3\CMS\Core\SingletonInterface as Singleton; +use TYPO3\CMS\Core\Utility\GeneralUtility; +use TYPO3\CMS\Extbase\Object\ObjectManager; +use Leonmrni\SearchCore\Service\DataHandler as OwnDataHandler; + +/** + * Wrapper for TYPO3 Hooks to internal API. + */ +class DataHandler implements Singleton +{ + /** + * @var OwnDataHandler + */ + protected $dataHandler; + + /** + * @var \TYPO3\CMS\Core\Log\Logger + */ + protected $logger; + + /** + * Dependency injection as TYPO3 doesn't provide it on it's own. + * Still you can submit your own dataHandler. + * + * TODO: Inject datahandler only on use?! Using getter / setter or something else? + * Otherwise a connection to elastic and whole bootstrapping will be triggered. + * + * @param OwnDataHandler $dataHandler + * @param Logger $logger + */ + public function __construct(OwnDataHandler $dataHandler = null, Logger $logger = null) + { + $this->dataHandler = $dataHandler; + if ($this->dataHandler === null) { + $this->dataHandler = GeneralUtility::makeInstance(ObjectManager::class) + ->get(OwnDataHandler::class); + } + + $this->logger = $logger; + if ($this->logger === null) { + $this->logger = GeneralUtility::makeInstance(LogManager::class) + ->getLogger(__CLASS__); + } + } + + /** + * Called by CoreDataHandler on deletion of records. + * + * @param string $table + * @param int $uid + * @param array $record + * @param bool $recordWasDeleted + * @param CoreDataHandler $dataHandler + */ + public function processCmdmap_deleteAction($table, $uid, array $record, $recordWasDeleted, CoreDataHandler $dataHandler) + { + if (! $this->shouldProcessTable($table)) { + $this->logger->debug('Delete not processed, cause table is not allowed.', [$table]); + return; + } + + $this->dataHandler->delete($table, $uid); + } + + /** + * Called by CoreDataHandler on database operations, e.g. if new records were created or records were updated. + * + * @param string $status + * @param string $table + * @param string|int $uid + * @param array $fieldArray + * @param CoreDataHandler $dataHandler + */ + public function processDatamap_afterDatabaseOperations($status, $table, $uid, array $fieldArray, CoreDataHandler $dataHandler) + { + if (! $this->shouldProcessTable($table)) { + $this->logger->debug('Database update not processed, cause table is not allowed.', [$table]); + return; + } + + if ($status === 'new') { + $this->dataHandler->add($table, $dataHandler->substNEWwithIDs[$uid], $fieldArray); + return; + } + + if ($status === 'update') { + $this->dataHandler->update( + $table, + $uid, + $this->getRecord($table, $uid) + ); + return; + } + + $this->logger->debug('Database update not processed, cause status is unhandled.', [$status, $table, $uid, $fieldArray]); + } + + /** + * Returns array containing tables that should be processed by this hook. + * + * TODO: Fetch from config + * + * @return array + */ + protected function getTablesToProcess() + { + return [ + 'tt_content', + ]; + } + + /** + * @param string $table + * @return bool + */ + protected function shouldProcessTable($table) + { + return in_array($table, $this->getTablesToProcess()); + } + + /** + * Wrapper to allow unit testing. + * + * @param string $table + * @param int $uid + * @return array + */ + protected function getRecord($table, $uid) + { + return BackendUtility::getRecord($table, $uid); + } +} diff --git a/Classes/Service/DataHandler.php b/Classes/Service/DataHandler.php new file mode 100644 index 0000000..0febc5a --- /dev/null +++ b/Classes/Service/DataHandler.php @@ -0,0 +1,80 @@ + + * + * 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\Core\SingletonInterface as Singleton; + +/** + * Handles all data related things like updates, deletes and inserts. + * + * This is the place to add mappings of further parts to adjust the data before + * sending ot to connection. + */ +class DataHandler implements Singleton +{ + /** + * @var \TYPO3\CMS\Core\Log\Logger + */ + protected $logger; + + // TODO: Write construct with inject of connection + + /** + * Inject log manager to get concrete logger from it. + * + * @param \TYPO3\CMS\Core\Log\LogManager $logManager + */ + public function injectLogger(\TYPO3\CMS\Core\Log\LogManager $logManager) + { + $this->logger = $logManager->getLogger(__CLASS__); + } + + /** + * @param string $table + * @param int $identifier + */ + public function delete($table, $identifier) + { + $this->logger->debug('Record received for delete.', [$table, $identifier]); + // $this->connection->delete($table, $identifier); + } + + /** + * @param string $table + * @param int $identifier + * @param array $record + */ + public function add($table, $identifier, array $record) + { + $this->logger->debug('Record received for add.', [$table, $identifier, $record]); + // $this->connection->add($table, $identifier, $record); + } + + /** + * @param string $table + * @param int $identifier + */ + public function update($table, $identifier, array $record) + { + $this->logger->debug('Record received for update.', [$table, $identifier, $record]); + // $this->connection->update($table, $identifier, $record); + } +} diff --git a/Tests/Fakes/FakeLogManager.php b/Tests/Fakes/FakeLogManager.php new file mode 100644 index 0000000..6988721 --- /dev/null +++ b/Tests/Fakes/FakeLogManager.php @@ -0,0 +1,39 @@ + + * + * 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\Core\Log\LogManager; + +/** + * Fakes the LogManager to prevent dependencies and logging during tests. + */ +class FakeLogManager extends LogManager +{ + public function __construct() + { + $this->loggers['fake'] = new Logger('fake'); + } + + public function getLogger($name = '') + { + return $this->loggers['fake']; + } +} diff --git a/Tests/Unit/Hook/DataHandlerTest.php b/Tests/Unit/Hook/DataHandlerTest.php new file mode 100644 index 0000000..1569d21 --- /dev/null +++ b/Tests/Unit/Hook/DataHandlerTest.php @@ -0,0 +1,150 @@ + + * + * 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 Leonmrni\SearchCore\Hook\DataHandler as Hook; +use Leonmrni\SearchCore\Service\DataHandler; +use Leonmrni\SearchCore\Tests\Fakes\FakeLogManager; +use TYPO3\CMS\Core\DataHandling\DataHandler as CoreDataHandler; +use TYPO3\CMS\Core\Log\LogManager; +use TYPO3\CMS\Core\Tests\UnitTestCase; + +/** + * + */ +class DataHandlerTest extends UnitTestCase +{ + /** + * @var DataHandler|\PHPUnit_Framework_MockObject_MockObject|AccessibleObjectInterface + */ + protected $subject; + + /** + * @var Hook|\PHPUnit_Framework_MockObject_MockObject|AccessibleObjectInterface + */ + protected $hook; + + /** + * Set up the tests + */ + protected function setUp() + { + \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\CMS\Extbase\Object\Container\Container') + ->registerImplementation(LogManager::class, FakeLogManager::class); + + $this->subject = $this->getAccessibleMock(DataHandler::class); + $this->hook = $this->getAccessibleMock( + Hook::class, + [ + 'getTablesToProcess', + 'getRecord' + ], + [ + $this->subject, + ] + ); + + $this->hook->method('getTablesToProcess') + ->willReturn(['table']); + $this->hook->method('getRecord') + ->willReturn([ + 'title' => 'some title', + 'bodytext' => 'some text', + ]); + } + + /** + * @test + */ + public function notConfiguredTablesWillNotBeProcessed() + { + $table = 'noneConfiguredTable'; + $recordUid = 1; + $this->subject->expects($this->exactly(0))->method('delete'); + $this->subject->expects($this->exactly(0))->method('add'); + $this->subject->expects($this->exactly(0))->method('update'); + + $dataHandler = $this->getAccessibleMock(CoreDataHandler::class, [], [], '', false); + $dataHandler->substNEWwithIDs = ['NEW34' => $recordUid]; + + $this->hook->processCmdmap_deleteAction($table, $recordUid, [], false, $dataHandler); + $this->hook->processDatamap_afterDatabaseOperations('new', $table, 'NEW34', [], $dataHandler); + $this->hook->processDatamap_afterDatabaseOperations('update', $table, $recordUid, [], $dataHandler); + } + + /** + * @test + */ + public function configuredTablesWillBeProcessed() + { + $table = 'table'; + $recordUid = 1; + $this->subject->expects($this->once())->method('delete'); + $this->subject->expects($this->once())->method('add'); + $this->subject->expects($this->once())->method('update'); + + $dataHandler = $this->getAccessibleMock(CoreDataHandler::class, [], [], '', false); + $dataHandler->substNEWwithIDs = ['NEW34' => $recordUid]; + + $this->hook->processCmdmap_deleteAction($table, $recordUid, [], false, $dataHandler); + $this->hook->processDatamap_afterDatabaseOperations('new', $table, 'NEW34', [], $dataHandler); + $this->hook->processDatamap_afterDatabaseOperations('update', $table, $recordUid, [], $dataHandler); + } + + /** + * @test + */ + public function deletionWillBeTriggered() + { + $table = 'table'; + $recordUid = 1; + $this->subject->expects($this->once()) + ->method('delete') + ->with( + $this->equalTo($table), + $this->equalTo($recordUid) + ); + + $this->hook->processCmdmap_deleteAction($table, $recordUid, [], false, new CoreDataHandler()); + } + + /** + * @test + */ + public function updateWillBeTriggered() + { + $table = 'table'; + $recordUid = 1; + $record = [ + 'title' => 'some title', + 'bodytext' => 'some text', + ]; + $this->subject->expects($this->once()) + ->method('update') + ->with( + $this->equalTo($table), + $this->equalTo($recordUid), + $this->equalTo($record) + ); + + $this->hook->processDatamap_afterDatabaseOperations('update', $table, $recordUid, $record, new CoreDataHandler); + } +} diff --git a/Tests/Unit/UnitTests.xml b/Tests/Unit/UnitTests.xml new file mode 100644 index 0000000..93247f4 --- /dev/null +++ b/Tests/Unit/UnitTests.xml @@ -0,0 +1,22 @@ + + + + + . + + + diff --git a/composer.json b/composer.json index f6c4410..babad24 100644 --- a/composer.json +++ b/composer.json @@ -9,12 +9,36 @@ "Leonmrni\\SearchCore\\": "Classes" } }, + "autoload-dev": { + "psr-4": { + "Leonmrni\\SearchCore\\Tests\\": "Tests/", + "TYPO3\\CMS\\Core\\Tests\\": ".Build/vendor/typo3/cms/typo3/sysext/core/Tests/" + } + }, + "require" : { "php": ">=5.6.0", "typo3/cms": ">=6.2.0" }, "require-dev": { - "phpunit/phpunit": ">=4.8.0 <6.0.0" + "phpunit/phpunit": "~4.8.0" + }, + "config": { + "optimize-autoloader": true, + "vendor-dir": ".Build/vendor", + "bin-dir": ".Build/bin" + }, + "scripts": { + "post-autoload-dump": [ + "mkdir -p .Build/Web/typo3conf/ext/", + "[ -L .Build/Web/typo3conf/ext/search_core ] || ln -snvf ../../../../. .Build/Web/typo3conf/ext/search_core" + ] + }, + "extra": { + "typo3/cms": { + "cms-package-dir": "{$vendor-dir}/typo3/cms", + "web-dir": ".Build/Web" + } }, "authors": [ {