Skip to content

Commit

Permalink
fix: reflection errors, and field mapping.
Browse files Browse the repository at this point in the history
  • Loading branch information
4allportaleabdullah committed Sep 23, 2024
1 parent c197941 commit 7f2542c
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 68 deletions.
2 changes: 1 addition & 1 deletion Classes/Domain/Model/Event.php
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ public function setProcessing(bool $processing): void
{
$queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable('tx_fourallportal_domain_model_event');
$query = $queryBuilder->update('tx_fourallportal_domain_model_event')
->set('processing', $processing, PDO::PARAM_INT)
->set('processing', $processing ? 1 : 0,PDO::PARAM_INT)
->where($queryBuilder->expr()->eq('uid', $this->uid));
$query->executeStatement();
$this->processing = $processing;
Expand Down
106 changes: 59 additions & 47 deletions Classes/Mapping/AbstractMapping.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@
use ReflectionClass;
use ReflectionException;
use ReflectionMethod;
use ReflectionProperty;
use RuntimeException;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Domain\Repository\PageRepository;
use TYPO3\CMS\Core\Resource\File;
use TYPO3\CMS\Core\Resource\FileInterface;
use TYPO3\CMS\Core\Resource\StorageRepository;
use TYPO3\CMS\Core\TypoScript\FrontendTypoScript;
Expand Down Expand Up @@ -62,11 +64,6 @@ public function injectPersistenceManager(PersistenceManager $persistenceManager)
$this->persistenceManager = $persistenceManager;
}

public function injectAccessiblePropertyMapper(AccessiblePropertyMapper $accessiblePropertyMapper)
{
$this->accessiblePropertyMapper = $accessiblePropertyMapper;
}

public function injectStorageRepository(StorageRepository $storageRepository)
{
$this->storageRepository = $storageRepository;
Expand Down Expand Up @@ -292,19 +289,18 @@ protected function removeObjectFromRepository(DomainObjectInterface $object): vo

/**
* @param array $data
* @param AbstractEntity|FileInterface $object
* @param AbstractEntity|File $object
* @param Module $module
* @param DimensionMapping|null $dimensionMapping
* @return bool
* @throws InvalidSourceException
* @throws ReflectionException
* @throws TypeConverterException
* @throws ApiException
*/
protected function mapPropertiesFromDataToObject(array $data, AbstractEntity|FileInterface $object, Module $module, DimensionMapping $dimensionMapping = null): bool
protected function mapPropertiesFromDataToObject(array $data, AbstractEntity|File $object, Module $module, DimensionMapping $dimensionMapping = null): bool
{
if (!$data['result']) {
return true;
}

$map = MappingRegister::resolvePropertyMapForMapper(static::class);
$properties = $data['result'][0]['properties'];
$responseValueReader = new ResponseDataFieldValueReader();
Expand All @@ -328,10 +324,7 @@ protected function mapPropertiesFromDataToObject(array $data, AbstractEntity|Fil
$propertyMappingProblemsOccurred = $this->mapPropertyValueToObject($targetPropertyName, $propertyValue, $object);
$mappingProblemsOccurred = $mappingProblemsOccurred ?: $propertyMappingProblemsOccurred;
}
} catch (PropertyNotAccessibleException $error) {
$message = 'Error mapping ' . $module->getModuleName() . ':' . $objectId . ':' . $importedName . ' - ' . $error->getMessage();
$this->loggingService->logObjectActivity($data['result'][0]['id'], $message, 3 /*GeneralUtility::SYSLOG_SEVERITY_WARNING*/);
} catch (DeferralException $error) {
} catch (PropertyNotAccessibleException|DeferralException|ReflectionException|InvalidSourceException|TypeConverterException $error) {
$message = 'Error mapping ' . $module->getModuleName() . ':' . $objectId . ':' . $importedName . ' - ' . $error->getMessage();
$this->loggingService->logObjectActivity($data['result'][0]['id'], $message, 3 /*GeneralUtility::SYSLOG_SEVERITY_WARNING*/);
}
Expand Down Expand Up @@ -373,10 +366,13 @@ protected function mapPropertyValueToObject(string $propertyName, mixed $propert
$objectId = $object->getRemoteId();
}

$array = (new ReflectionMethod(get_class($object), 'set' . ucfirst($propertyName)))->getParameters();
if ($propertyValue === null && reset($array)->allowsNull()) {
ObjectAccess::setProperty($object, $propertyName, null);
return false;
$setterName = 'set' . ucfirst($propertyName);
if (method_exists($objectId, $setterName)) {
$array = (new ReflectionMethod(get_class($object),))->getParameters();
if ($propertyValue === null && reset($array)->allowsNull()) {
ObjectAccess::setProperty($object, $propertyName, null);
return false;
}
}
$configuration = new PropertyMappingConfiguration();
$mappingProblemsOccurred = false;
Expand All @@ -388,7 +384,11 @@ protected function mapPropertyValueToObject(string $propertyName, mixed $propert

$propertyMapper = $this->getAccessiblePropertyMapper();
$targetType = $this->determineDataTypeForProperty($propertyName, $object);
$array1 = (new ReflectionMethod(get_class($object), 'set' . ucfirst($propertyName)))->getParameters();
if ($targetType === null) {
$classSchema = get_class($object);
$this->loggingService->logObjectActivity($objectId, "Type of property {$propertyName} on {$classSchema} could not be determined", 3);
return false;
}
if (strpos($targetType, '<')) {
$childType = substr($targetType, strpos($targetType, '<') + 1, -1);
$childType = trim($childType, '\\');
Expand Down Expand Up @@ -471,15 +471,22 @@ protected function mapPropertyValueToObject(string $propertyName, mixed $propert
}
}
}
} elseif ($propertyValue === null && !reset($array1)->allowsNull()) {
$message = sprintf(
'Property "%s" on object "%s->%s" does not allow NULL as value, but NULL was resolved. Please verify PIM response data consistency!',
$propertyName,
get_class($object),
method_exists($object, 'getRemoteId') ? $object->getRemoteId() : $object->getUid()
);
$this->loggingService->logObjectActivity($objectId, $message, 4 /*GeneralUtility::SYSLOG_SEVERITY_FATAL*/);
return false;
} elseif ($propertyValue === null) {
try {
$parameters = (new \ReflectionMethod(get_class($object), 'set' . ucfirst($propertyName)))->getParameters();
} catch (\ReflectionException $e) {
// ignore
}
if (!empty($parameters) && !$parameters[0]->allowsNull()) {
$message = sprintf(
'Property "%s" on object "%s->%s" does not allow NULL as value, but NULL was resolved. Please verify PIM response data consistency!',
$propertyName,
get_class($object),
method_exists($object, 'getRemoteId') ? $object->getRemoteId() : $object->getUid()
);
$this->loggingService->logObjectActivity($objectId, $message, 4 /*GeneralUtility::SYSLOG_SEVERITY_FATAL*/);
return false;
}
}

$setOnObject = $object;
Expand All @@ -506,33 +513,38 @@ protected function mapPropertyValueToObject(string $propertyName, mixed $propert
* @throws NoSuchPropertyException
* @throws UnknownClassException
*/
protected function determineDataTypeForProperty($propertyName, $object): bool|string
protected function determineDataTypeForProperty(string $propertyName, object $object): string|null
{
if (property_exists(get_class($object), $propertyName)) {
$property = GeneralUtility::makeInstance(ReflectionService::class);
$classSchema = $property->getClassSchema($object);
$varTags = $classSchema->getProperty('var');
if ($property->getPrimaryType()->isCollection()) {
return strpos($varTags[0], ' ') !== false ? substr($varTags[0], 0, strpos($varTags[0], ' ')) : $varTags[0];

if (property_exists($object, $propertyName)) {
$property = new ReflectionProperty($object, $propertyName);
$type = $property->getType();

if ($type !== null) {
return $type->getName();
}

$varTags = $property->getAttributes('var');
if (!empty($varTags)) {
return explode(' ', $varTags[0]->getArguments()[0])[0];
}
}

if (method_exists(get_class($object), 'set' . ucfirst($propertyName))) {
/** @see .build/vendor/typo3/cms-core/Documentation/Changelog/9.0/Breaking-57594-OptimizeReflectionServiceCacheHandling.rst */
$method = $classSchema->getMethod('set' . ucfirst($propertyName));
$setterMethod = 'set' . ucfirst($propertyName);
if (method_exists($object, $setterMethod)) {
$method = new ReflectionMethod($object, $setterMethod);
$parameters = $method->getParameters();
if ($parameters[0]->getType() !== null) {
return (string)$parameters[0]->getType();

if (!empty($parameters) && $parameters[0]->hasType()) {
return $parameters[0]->getType()->getName();
}

$varTags = $method->getParameter('param');
if (!empty($varTags)) {
$array = explode(' ', $varTags[0]);
return reset($array);
$paramTags = $method->getAttributes('param');
if (!empty($paramTags)) {
return explode(' ', $paramTags[0]->getArguments()[0])[0];
}
}

throw new RuntimeException('Type of property ' . $propertyName . ' on ' . get_class($object) . ' could not be determined');
return null;
}

/**
Expand All @@ -558,7 +570,7 @@ public function getEntityClassName(): string
*/
protected function getAccessiblePropertyMapper(): AccessiblePropertyMapper
{
return $this->accessiblePropertyMapper;
return GeneralUtility::makeInstance(AccessiblePropertyMapper::class);
}

/**
Expand Down
33 changes: 20 additions & 13 deletions Classes/Mapping/FalMapping.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@
use Crossmedia\Fourallportal\Domain\Model\Server;
use Crossmedia\Fourallportal\Error\ApiException;
use Crossmedia\Fourallportal\Service\ApiClient;
use Crossmedia\Fourallportal\Service\LoggingService;
use Crossmedia\Fourallportal\ValueReader\ResponseDataFieldValueReader;
use DateTime;
use Doctrine\DBAL\Exception;
use ReflectionException;
use RuntimeException;
use TYPO3\CMS\Core\Charset\CharsetConverter;
use TYPO3\CMS\Core\Core\Environment;
use TYPO3\CMS\Core\Database\ConnectionPool;
use TYPO3\CMS\Core\Resource\Driver\DriverInterface;
use TYPO3\CMS\Core\Resource\Driver\LocalDriver;
Expand All @@ -32,8 +33,7 @@
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Extbase\Domain\Model\FileReference;
use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
use TYPO3\CMS\Extbase\Property\Exception\InvalidSourceException;
use TYPO3\CMS\Extbase\Property\Exception\TypeConverterException;
use TYPO3\CMS\Extbase\Persistence\PersistenceManagerInterface;
use TYPO3\CMS\Extbase\Reflection\Exception\PropertyNotAccessibleException;
use TYPO3\CMS\Extbase\Reflection\ObjectAccess;

Expand All @@ -57,10 +57,7 @@ public function getEntityClassName(): string
* @throws InsufficientFolderReadPermissionsException
* @throws InsufficientFolderWritePermissionsException
* @throws InvalidFileNameException
* @throws InvalidSourceException
* @throws PropertyNotAccessibleException
* @throws ReflectionException
* @throws TypeConverterException
*/
public function import(array $data, Event $event): bool
{
Expand All @@ -77,6 +74,7 @@ public function import(array $data, Event $event): bool
->where($queryBuilder->expr()->eq('remote_id', $queryBuilder->quote($objectId)));

$deferAfterProcessing = false;
$logging = $this->loggingService = GeneralUtility::makeInstance(LoggingService::class);

switch ($event->getEventType()) {
case 'delete':
Expand All @@ -88,6 +86,7 @@ public function import(array $data, Event $event): bool
}
// handle multiple files in the system
foreach ($records as $record) {
/** @var File $object */
$object = $repository->findByUid($record['uid']);
if (!$object || !$record) {
// Object is already deleted, return false meaning no deferral after processing.
Expand All @@ -108,14 +107,24 @@ public function import(array $data, Event $event): bool
break;
case 'update':
case 'create':
$message = sprintf("start creating object with id %s", $objectId);
$logging->logEventActivity($event, $message);

/** @var File $object */
$object = $this->downloadFileAndGetFileObject($objectId, $data, $event);
$message = sprintf("object with id %s downloaded successfully", $objectId);
$logging->logEventActivity($event, $message);

$deferAfterProcessing = $this->mapPropertiesFromDataToObject($data, $object, $event->getModule());

$message = sprintf("object with id %s create successfully", $objectId);
$logging->logEventActivity($event, $message);
break;
default:
throw new RuntimeException('Unknown event type: ' . $event->getEventType());
}

$this->persistenceManager->persistAll();
GeneralUtility::makeInstance(PersistenceManagerInterface::class)->persistAll();

if ($object) {
$this->processRelationships($object, $data, $event);
Expand Down Expand Up @@ -221,16 +230,14 @@ protected function collectTablesAndRecordsWithRelationsToFileReferences(array $e

/**
* @param array $data
* @param AbstractEntity|FileInterface $object
* @param AbstractEntity|File $object
* @param Module $module
* @param DimensionMapping|null $dimensionMapping
* @return bool
* @throws ApiException
* @throws PropertyNotAccessibleException
* @throws ReflectionException
* @throws InvalidSourceException
* @throws TypeConverterException
*/
protected function mapPropertiesFromDataToObject(array $data, AbstractEntity|FileInterface $object, Module $module, DimensionMapping $dimensionMapping = null): bool
protected function mapPropertiesFromDataToObject(array $data, AbstractEntity|File $object, Module $module, DimensionMapping $dimensionMapping = null): bool
{
$deferAfterProcessing = parent::mapPropertiesFromDataToObject($data, $object, $module, $dimensionMapping);
$metadata = [];
Expand Down Expand Up @@ -512,7 +519,7 @@ public function check(ApiClient $client, Module $module, array $status): array
</p>
', $ids[0]);
} else {
$publicTempFile = 'typo3/typo3temp/assets/images/' . basename($temporaryFile);
$publicTempFile = Environment::getPublicPath() . '/typo3/typo3temp/assets/images/' . basename($temporaryFile);
rename($temporaryFile, $publicTempFile);
$temporaryFileRelativePath = substr($publicTempFile, strlen('typo3/') - 1);
$receivedBytes = filesize($publicTempFile);
Expand Down
2 changes: 1 addition & 1 deletion Classes/Service/ApiClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ public function saveDerivate(string $filename, string $objectId, string $usage =
curl_close($ch);
fclose($fp);

if ($expectedFileSize > 0 && $expectedFileSize != filesize($temporaryFilename)) {
if (!empty($expectedFileSize) && $expectedFileSize > 0 && $expectedFileSize != filesize($temporaryFilename)) {
unlink($temporaryFilename);
$message = 'The downloaded file does not match the expected filesize';
$this->loggingService->logFileTransferActivity($uri, $temporaryFilename . ': ' . $message, 4 /*GeneralUtility::SYSLOG_SEVERITY_ERROR*/);
Expand Down
10 changes: 9 additions & 1 deletion Classes/Service/EventExecutionService.php
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,11 @@ public function processEvent(Event $event, bool $updateEventId = true, ?SyncPara
);

$event->setProcessing(true);
try {
$this->persistenceManager->update($event);
} catch (UnknownObjectException $e) {
// ignore
}

if (method_exists($this->response, 'send')) {
$this->response->send();
Expand Down Expand Up @@ -603,14 +608,16 @@ public function processEvent(Event $event, bool $updateEventId = true, ?SyncPara
$event->setStatus('failed');
}
$this->loggingService->logEventActivity($event, 'Event was deferred', 2 /* GeneralUtility::SYSLOG_SEVERITY_WARNING */);
} catch (Exception $exception) {
} catch (\Exception | \ReflectionException $exception) {
$event->setStatus('failed');
$event->setRetries(0);
$event->setMessage($exception->getMessage() . ' (code: ' . $exception->getCode() . ')' . $exception->getFile() . ':' . $exception->getLine());
if ($updateEventId) {
$event->getModule()->setLastEventId(max($event->getEventId(), $event->getModule()->getLastEventId()));
}
$this->loggingService->logEventActivity($event, 'System error: ' . $exception->getMessage(), 2 /* GeneralUtility::SYSLOG_SEVERITY_WARNING */);
} finally {
$event->setProcessing(false);
}
// $responseMetadata = $client->getLastResponse();
// $event->setHeaders($responseMetadata['headers']);
Expand All @@ -620,6 +627,7 @@ public function processEvent(Event $event, bool $updateEventId = true, ?SyncPara
// $event->setProcessing(false);
// $this->eventRepository->update($event);
try {
$this->persistenceManager->update($event);
$this->persistenceManager->persistAll();
} catch (Exception $exception) {
$this->loggingService->logEventActivity($event, 'System error: ' . $exception->getMessage(), 2 /* GeneralUtility::SYSLOG_SEVERITY_WARNING */);
Expand Down
3 changes: 2 additions & 1 deletion Classes/Service/LoggingService.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Crossmedia\Fourallportal\Domain\Model\Event;
use Crossmedia\Fourallportal\Domain\Model\LogEntry;
use Crossmedia\Fourallportal\Utility\ConstantsUtility;
use TYPO3\CMS\Core\Core\Environment;
use TYPO3\CMS\Core\SingletonInterface;
use TYPO3\CMS\Core\Utility\GeneralUtility;

Expand Down Expand Up @@ -147,7 +148,7 @@ protected function writeEntry(string $logFile, string $message, int $severity):

protected function resolveLogFilePath(string $type, string $identity = null): string
{
$logFilePath = ConstantsUtility::LOG_BASEDIR . $type;
$logFilePath = Environment::getVarPath() . ConstantsUtility::LOG_BASEDIR . $type;
if ($identity) {
$logFilePath .= '/' . $identity . '.log';
} else {
Expand Down
2 changes: 1 addition & 1 deletion Classes/Utility/ConstantsUtility.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ class ConstantsUtility
public final const TEXT_SCHEMA = 'schema';
public final const TEXT_CONNECTION = 'connection';
public final const TEXT_ERRORS = 'error';
public final const LOG_BASEDIR = 'typo3temp/var/logs/fourallportal/';
public final const LOG_BASEDIR = 'logs/fourallportal/';
}
Loading

0 comments on commit 7f2542c

Please sign in to comment.