Skip to content

Commit

Permalink
Merge branch 'master' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
fsuter committed Dec 27, 2024
2 parents 30d2e57 + eabe7b0 commit 6ad0862
Show file tree
Hide file tree
Showing 21 changed files with 677 additions and 126 deletions.
6 changes: 6 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
2024-12-27 Francois Suter (Idéative) <[email protected]>

* Add a delete reaction, resolves #361
* Avoid accessing substructure when not of the expected type, resolves #360
* Release version 7.3.0

2024-11-24 Francois Suter (Idéative) <[email protected]>

* Improve passing properly structured data to DatamapPostprocessEvent, references #355
Expand Down
77 changes: 77 additions & 0 deletions Classes/Domain/Repository/ItemRepository.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php

declare(strict_types=1);

/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/

namespace Cobweb\ExternalImport\Domain\Repository;

use Cobweb\ExternalImport\Exception\InvalidRecordException;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Database\Query\Restriction\DeletedRestriction;
use TYPO3\CMS\Core\Utility\GeneralUtility;

/**
* Barebones repository for fetching an item from any database table,
* with a simple equality constraint
*/
class ItemRepository
{
/**
* Find an item in the given DB table, matching one or more constraints
* (with strict equality), return its primary key (uid)
*
* @throws \Doctrine\DBAL\DBALException
* @throws \Doctrine\DBAL\Driver\Exception
* @throws InvalidRecordException
*/
public function find(string $table, array $constraints, string $additionalConstraint = ''): int
{
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($table);
// Get any possible record, except an already deleted one
$queryBuilder->getRestrictions()
->removeAll()
->add(
GeneralUtility::makeInstance(
DeletedRestriction::class
)
);
$queryConstraints = [];
foreach ($constraints as $key => $value) {
$queryConstraints[] = $queryBuilder->expr()->eq(
$key,
is_string($value) ? $queryBuilder->createNamedParameter($value) : $value
);
}
if (!empty($additionalConstraint)) {
$queryConstraints[] = $additionalConstraint;
}
$result = $queryBuilder->select('uid')
->from($table)
->where(...$queryConstraints)
->executeQuery()
->fetchOne();
if ($result === false) {
throw new InvalidRecordException(
sprintf(
'No record found in table "%s" matching "%s',
$table,
serialize($constraints)
),
1735288514
);
}
return $result;
}
}
54 changes: 54 additions & 0 deletions Classes/Event/GetExternalKeyEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

declare(strict_types=1);

/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/

namespace Cobweb\ExternalImport\Event;

use Cobweb\ExternalImport\Domain\Model\Configuration;

final class GetExternalKeyEvent
{
protected array $data;
protected Configuration $configuration;
protected $externalKey;

public function __construct(array $data, Configuration $configuration, $externalKey = null)
{
$this->data = $data;
$this->configuration = $configuration;
$this->externalKey = $externalKey;
}

public function getData(): array
{
return $this->data;
}

public function getConfiguration(): Configuration
{
return $this->configuration;
}

public function getExternalKey()
{
return $this->externalKey;
}

public function setExternalKey($externalKey): void
{
$this->externalKey = $externalKey;
}
}
25 changes: 25 additions & 0 deletions Classes/Exception/InvalidConfigurationException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace Cobweb\ExternalImport\Exception;

/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/

use TYPO3\CMS\Core\Exception;

/**
* Exception for missing configuration.
*/
class InvalidConfigurationException extends Exception
{
}
25 changes: 25 additions & 0 deletions Classes/Exception/ReactionFailedException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

namespace Cobweb\ExternalImport\Exception;

/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/

use TYPO3\CMS\Core\Exception;

/**
* Exception for missing configuration.
*/
class ReactionFailedException extends Exception
{
}
10 changes: 6 additions & 4 deletions Classes/Handler/ArrayHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,12 @@ public function handleData($rawData, Importer $importer): array
)
);
$theValue = $event->getSubstructure();
$rows[$columnName] = $this->getSubstructureValues(
$theValue,
$columnData['substructureFields']
);
if (is_array($theValue)) {
$rows[$columnName] = $this->getSubstructureValues(
$theValue,
$columnData['substructureFields']
);
}
// Prepare for the case where no substructure was found
// If one was found, it is added later
$data[$referenceCounter][$columnName] = null;
Expand Down
15 changes: 10 additions & 5 deletions Classes/Handler/XmlHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,16 @@ public function handleData($rawData, Importer $importer): array
)
);
$nodeList = $event->getSubstructure();
$rows[$columnName] = $this->getSubstructureValues(
$nodeList,
$columnData['substructureFields'],
$xPathObject
);
if ($nodeList instanceof \DOMNodeList) {
$rows[$columnName] = $this->getSubstructureValues(
$nodeList,
$columnData['substructureFields'],
$xPathObject
);
}
// Prepare for the case where no substructure was found
// If one was found, it is added later
$data[$referenceCounter][$columnName] = null;
} else {
$data[$referenceCounter][$columnName] = $this->getValue(
$theRecord,
Expand Down
110 changes: 110 additions & 0 deletions Classes/Reaction/AbstractReaction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<?php

declare(strict_types=1);

/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/

namespace Cobweb\ExternalImport\Reaction;

use Cobweb\ExternalImport\Domain\Model\ConfigurationKey;
use Cobweb\ExternalImport\Domain\Repository\ConfigurationRepository;
use Cobweb\ExternalImport\Exception\InvalidPayloadException;
use Cobweb\ExternalImport\Exception\NoConfigurationException;
use Psr\EventDispatcher\EventDispatcherInterface;
use Psr\Http\Message\ResponseFactoryInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamFactoryInterface;
use TYPO3\CMS\Core\Utility\GeneralUtility;

/**
* Base class for External Import reactions
*/
abstract class AbstractReaction
{
protected ResponseFactoryInterface $responseFactory;
protected StreamFactoryInterface $streamFactory;
protected EventDispatcherInterface $eventDispatcher;

public function __construct(ResponseFactoryInterface $responseFactory, StreamFactoryInterface $streamFactory, EventDispatcherInterface $eventDispatcher)
{
$this->responseFactory = $responseFactory;
$this->streamFactory = $streamFactory;
$this->eventDispatcher = $eventDispatcher;
}

/**
* Prepares and returns the JSON response
*
* @param array $data
* @param int $statusCode
* @return ResponseInterface
*/
protected function jsonResponse(array $data, int $statusCode = 200): ResponseInterface
{
return $this->responseFactory
->createResponse($statusCode)
->withHeader('Content-Type', 'application/json')
->withBody($this->streamFactory->createStream((string)json_encode($data)));
}

/**
* Validates that the payloads contains the proper structure for the External Import reaction
* and that the configuration exists.
*/
protected function validatePayloadAndConfigurationKey(array $payload, string $configurationKey): ConfigurationKey
{
if (!isset($payload['data'])) {
throw new InvalidPayloadException(
'The payload does not contain any data to import',
1681482804
);
}

if ($configurationKey === '') {
if (!isset($payload['table'], $payload['index'])) {
throw new InvalidPayloadException(
'The payload must contain both a "table" and an "index" information',
1681482506
);
}

$configurationRepository = GeneralUtility::makeInstance(ConfigurationRepository::class);

try {
$configurationRepository->findByTableAndIndex($payload['table'], $payload['index']);
} catch (NoConfigurationException $e) {
throw new InvalidPayloadException(
'The "table" and "index" information given in the payload does not match an existing configuration',
1681482838,
$e
);
}

$configurationKeyObject = GeneralUtility::makeInstance(ConfigurationKey::class);
$configurationKeyObject->setTableAndIndex($payload['table'], (string)$payload['index']);
} else {
if (isset($payload['table'], $payload['index'])) {
throw new InvalidPayloadException(
'The payload must not contain a "table" and an "index" information',
1726559649
);
}

$configurationKeyObject = GeneralUtility::makeInstance(ConfigurationKey::class);
$configurationKeyObject->setConfigurationKey($configurationKey);
}

return $configurationKeyObject;
}
}
Loading

0 comments on commit 6ad0862

Please sign in to comment.