Add command to allow import of a single configuration.

The command is also available as scheduler task.
This finally allows to regularly execute imports.
This also allows to import from CLI context
with differently configured timeouts.
This commit is contained in:
Daniel Siepmann 2023-08-28 15:29:08 +02:00
parent cc072f0683
commit 773098623e
7 changed files with 339 additions and 55 deletions

View file

@ -0,0 +1,92 @@
<?php
declare(strict_types=1);
/*
* Copyright (C) 2023 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.
*/
namespace WerkraumMedia\ThueCat\Command;
use Exception;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use TYPO3\CMS\Core\Core\Bootstrap;
use WerkraumMedia\ThueCat\Domain\Import\Importer;
use WerkraumMedia\ThueCat\Domain\Repository\Backend\ImportConfigurationRepository;
class ImportConfigurationCommand extends Command
{
/**
* @var ImportConfigurationRepository
*/
private $importConfigurationRepository;
/**
* @var Importer
*/
private $importer;
public function __construct(
ImportConfigurationRepository $importConfigurationRepository,
Importer $importer
) {
parent::__construct();
$this->importConfigurationRepository = $importConfigurationRepository;
$this->importer = $importer;
}
protected function configure(): void
{
$this->setDescription('Executes a single import based on the given configuration.');
$this->addArgument(
'configuration',
InputArgument::REQUIRED,
'The UID of the import configuration to use'
);
}
protected function execute(InputInterface $input, OutputInterface $output)
{
Bootstrap::initializeBackendAuthentication();
$configurationUid = $input->getArgument('configuration');
if (is_numeric($configurationUid)) {
$configurationUid = (int)$configurationUid;
} else {
throw new Exception('No numeric uid for configuration provided.', 1643267138);
}
$configuration = $this->importConfigurationRepository->findOneByUid($configurationUid);
if ($configuration === null) {
throw new Exception('No configuration found for uid: ' . $configurationUid, 1693228522);
}
$importLog = $this->importer->importConfiguration($configuration);
if ($importLog->hasErrors()) {
return Command::FAILURE;
}
return Command::SUCCESS;
}
}

View file

@ -26,6 +26,7 @@ namespace WerkraumMedia\ThueCat\Domain\Repository\Backend;
use TYPO3\CMS\Extbase\Object\ObjectManagerInterface; use TYPO3\CMS\Extbase\Object\ObjectManagerInterface;
use TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings; use TYPO3\CMS\Extbase\Persistence\Generic\Typo3QuerySettings;
use TYPO3\CMS\Extbase\Persistence\Repository; use TYPO3\CMS\Extbase\Persistence\Repository;
use WerkraumMedia\ThueCat\Domain\Import\ImportConfiguration;
class ImportConfigurationRepository extends Repository class ImportConfigurationRepository extends Repository
{ {
@ -39,4 +40,16 @@ class ImportConfigurationRepository extends Repository
$this->setDefaultQuerySettings($querySettings); $this->setDefaultQuerySettings($querySettings);
} }
/**
* @return ImportConfiguration|null
*/
public function findOneByUid(int $uid)
{
$query = $this->createQuery();
$query->matching($query->equals('uid', $uid));
return $query->execute()->getFirst();
}
} }

View file

@ -7,6 +7,11 @@ services:
WerkraumMedia\ThueCat\: WerkraumMedia\ThueCat\:
resource: '../Classes/*' resource: '../Classes/*'
WerkraumMedia\ThueCat\Command\ImportConfigurationCommand:
tags:
- name: 'console.command'
command: 'thuecat:importviaconfiguration'
WerkraumMedia\ThueCat\Domain\Import\Importer\FetchData: WerkraumMedia\ThueCat\Domain\Import\Importer\FetchData:
arguments: arguments:
$requestFactory: '@WerkraumMedia\ThueCat\Domain\Import\RequestFactory' $requestFactory: '@WerkraumMedia\ThueCat\Domain\Import\RequestFactory'

View file

@ -0,0 +1,31 @@
2.1.0
=====
Breaking
--------
Nothing
Features
--------
* Add command to allow import of a single configuration.
The command is also available as scheduler task.
This finally allows to regularly execute imports.
This also allows to import from CLI context with differently configured timeouts.
Fixes
-----
Nothing
Tasks
-----
Nothing
Deprecation
-----------
Nothing

View file

@ -0,0 +1,92 @@
<?php
declare(strict_types=1);
/*
* Copyright (C) 2023 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.
*/
namespace WerkraumMedia\ThueCat\Tests\Functional;
use TYPO3\CMS\Core\Localization\LanguageService;
use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase;
abstract class AbstractImportTest extends FunctionalTestCase
{
protected function setUp(): void
{
$this->coreExtensionsToLoad = array_merge($this->coreExtensionsToLoad, [
'core',
'backend',
'extbase',
'frontend',
]);
$this->testExtensionsToLoad = array_merge($this->testExtensionsToLoad, [
'typo3conf/ext/thuecat/',
]);
$this->pathsToLinkInTestInstance = array_merge($this->pathsToLinkInTestInstance, [
'typo3conf/ext/thuecat/Tests/Functional/Fixtures/Import/Sites/' => 'typo3conf/sites',
]);
$this->configurationToUseInTestInstance = array_merge($this->configurationToUseInTestInstance, [
'LOG' => [
'WerkraumMedia' => [
'writerConfiguration' => [
\TYPO3\CMS\Core\Log\LogLevel::DEBUG => [
\TYPO3\CMS\Core\Log\Writer\FileWriter::class => [
'logFileInfix' => 'debug',
],
],
],
],
],
'EXTENSIONS' => [
'thuecat' => [
'apiKey' => null,
],
],
]);
parent::setUp();
GuzzleClientFaker::registerClient();
$this->setUpBackendUserFromFixture(1);
$GLOBALS['LANG'] = $this->getContainer()->get(LanguageService::class);
}
protected function assertPostConditions(): void
{
$path = self::getInstancePath() . '/typo3temp/var/log/typo3_0493d91d8e.log';
$this->assertSame(
'',
file_get_contents($path),
'The TYPO3 log file contained content while expecting to be empty.'
);
}
protected function tearDown(): void
{
unset($GLOBALS['LANG']);
GuzzleClientFaker::tearDown();
parent::tearDown();
}
}

View file

@ -0,0 +1,105 @@
<?php
declare(strict_types=1);
/*
* Copyright (C) 2023 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.
*/
namespace WerkraumMedia\ThueCat\Tests\Functional;
use Exception;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Exception\RuntimeException;
use Symfony\Component\Console\Tester\CommandTester;
use WerkraumMedia\ThueCat\Command\ImportConfigurationCommand;
/**
* @covers \WerkraumMedia\ThueCat\Command\ImportConfigurationCommand
* @testdox The 'thuecat:importviaconfiguration' command
*/
final class ImportConfigurationCommandTest extends AbstractImportTest
{
/**
* @test
*/
public function canImport(): void
{
$subject = $this->getContainer()->get(ImportConfigurationCommand::class);
self::assertInstanceOf(Command::class, $subject);
$this->importDataSet(__DIR__ . '/Fixtures/Import/ImportsFreshOrganization.xml');
GuzzleClientFaker::appendResponseFromFile(__DIR__ . '/Fixtures/Import/Guzzle/thuecat.org/resources/018132452787-ngbe.json');
$tester = new CommandTester($subject);
$tester->execute(['configuration' => 1], ['capture_stderr_separately' => true]);
$this->assertCSVDataSet('EXT:thuecat/Tests/Functional/Fixtures/Import/ImportsFreshOrganization.csv');
}
/**
* @test
*/
public function throwsExceptionOnNoneExistingConfiguration(): void
{
$subject = $this->getContainer()->get(ImportConfigurationCommand::class);
self::assertInstanceOf(Command::class, $subject);
$tester = new CommandTester($subject);
$this->expectException(Exception::class);
$this->expectExceptionMessage('No configuration found for uid: 1');
$this->expectExceptionCode(1693228522);
$tester->execute(['configuration' => 1], ['capture_stderr_separately' => true]);
}
/**
* @test
*/
public function throwsExceptionOnMissingArgument(): void
{
$subject = $this->getContainer()->get(ImportConfigurationCommand::class);
self::assertInstanceOf(Command::class, $subject);
$tester = new CommandTester($subject);
$this->expectException(RuntimeException::class);
$this->expectExceptionMessage('Not enough arguments (missing: "configuration")');
$this->expectExceptionCode(0);
$tester->execute([], ['capture_stderr_separately' => true]);
}
/**
* @test
*/
public function throwsExceptionOnNoneNumericConfigurationArgument(): void
{
$subject = $this->getContainer()->get(ImportConfigurationCommand::class);
self::assertInstanceOf(Command::class, $subject);
$tester = new CommandTester($subject);
$this->expectException(Exception::class);
$this->expectExceptionMessage('No numeric uid for configuration provided.');
$this->expectExceptionCode(1643267138);
$tester->execute(['configuration' => 'a'], ['capture_stderr_separately' => true]);
}
}

View file

@ -23,8 +23,6 @@ namespace WerkraumMedia\ThueCat\Tests\Functional;
* 02110-1301, USA. * 02110-1301, USA.
*/ */
use TYPO3\CMS\Core\Localization\LanguageService;
use TYPO3\TestingFramework\Core\Functional\FunctionalTestCase as TestCase;
use WerkraumMedia\ThueCat\Domain\Import\Importer; use WerkraumMedia\ThueCat\Domain\Import\Importer;
use WerkraumMedia\ThueCat\Domain\Repository\Backend\ImportConfigurationRepository; use WerkraumMedia\ThueCat\Domain\Repository\Backend\ImportConfigurationRepository;
@ -59,60 +57,8 @@ use WerkraumMedia\ThueCat\Domain\Repository\Backend\ImportConfigurationRepositor
* *
* @testdox The import * @testdox The import
*/ */
class ImportTest extends TestCase class ImportTest extends AbstractImportTest
{ {
protected $coreExtensionsToLoad = [
'core',
'backend',
'extbase',
'frontend',
];
protected $testExtensionsToLoad = [
'typo3conf/ext/thuecat/',
];
protected $pathsToLinkInTestInstance = [
'typo3conf/ext/thuecat/Tests/Functional/Fixtures/Import/Sites/' => 'typo3conf/sites',
];
protected $configurationToUseInTestInstance = [
'LOG' => [
'WerkraumMedia' => [
'writerConfiguration' => [
\TYPO3\CMS\Core\Log\LogLevel::DEBUG => [
\TYPO3\CMS\Core\Log\Writer\FileWriter::class => [
'logFileInfix' => 'debug',
],
],
],
],
],
'EXTENSIONS' => [
'thuecat' => [
'apiKey' => null,
],
],
];
protected function setUp(): void
{
parent::setUp();
GuzzleClientFaker::registerClient();
$this->setUpBackendUserFromFixture(1);
$GLOBALS['LANG'] = $this->getContainer()->get(LanguageService::class);
}
protected function tearDown(): void
{
unset($GLOBALS['LANG']);
GuzzleClientFaker::tearDown();
parent::tearDown();
}
/** /**
* @test * @test
*/ */