Skip to content

Commit

Permalink
Merge pull request #1611 from ConductionNL/feature/PC108-13/fix-sourceId
Browse files Browse the repository at this point in the history
No longer use url for sourceId in notifications / syncs when not needed
  • Loading branch information
WilcoLouwerse authored Jan 23, 2024
2 parents 2af0136 + a1e183c commit 27d58c1
Showing 1 changed file with 69 additions and 42 deletions.
111 changes: 69 additions & 42 deletions api/src/Service/SynchronizationService.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use App\Exception\GatewayException;
use CommonGateway\CoreBundle\Service\CallService;
use CommonGateway\CoreBundle\Service\FileSystemHandleService;
use CommonGateway\CoreBundle\Service\GatewayResourceService;
use CommonGateway\CoreBundle\Service\MappingService;
use DateInterval;
use DateTime;
Expand All @@ -23,6 +24,7 @@
use Monolog\Logger;
use Psr\Cache\CacheException;
use Psr\Cache\InvalidArgumentException;
use Ramsey\Uuid\Uuid;
use Safe\Exceptions\UrlException;
use Symfony\Component\Console\Helper\TableSeparator;
use Symfony\Component\Console\Style\SymfonyStyle;
Expand Down Expand Up @@ -60,6 +62,7 @@ class SynchronizationService
private SymfonyStyle $io;
private Environment $twig;
private MappingService $mappingService;
private GatewayResourceService $resourceService;

private ActionEvent $event;
private EventDispatcherInterface $eventDispatcher;
Expand All @@ -83,6 +86,7 @@ class SynchronizationService
* @param EventDispatcherInterface $eventDispatcher
* @param MappingService $mappingService
* @param FileSystemHandleService $fileSystemService
* @param GatewayResourceService $resourceService
*/
public function __construct(
CallService $callService,
Expand All @@ -98,7 +102,8 @@ public function __construct(
Environment $twig,
EventDispatcherInterface $eventDispatcher,
MappingService $mappingService,
FileSystemHandleService $fileSystemService
FileSystemHandleService $fileSystemService,
GatewayResourceService $resourceService
) {
$this->callService = $callService;
$this->entityManager = $entityManager;
Expand All @@ -119,6 +124,7 @@ public function __construct(
$this->logger = new Logger('installation');
$this->mappingService = $mappingService;
$this->fileSystemService = $fileSystemService;
$this->resourceService = $resourceService;
}

/**
Expand Down Expand Up @@ -303,7 +309,7 @@ private function loopThroughCollectionResults(array $results, array $config): ar
array_key_exists('object', $this->configuration['apiSource']['location']) && $result = $dot->get($this->configuration['apiSource']['location']['object'], $result);

// Lets grab the sync object, if we don't find an existing one, this will create a new one:
$synchronization = $this->findSyncBySource($config['source'], $config['entity'], $id);
$synchronization = $this->findSyncBySource($config['source'], $config['entity'], $id, $this->configuration['location'] ?? null);
// todo: Another search function for sync object. If no sync object is found, look for matching properties...
// todo: ...in $result and an ObjectEntity in db. And then create sync for an ObjectEntity if we find one this way. (nice to have)
// Other option to find a sync object, currently not used:
Expand Down Expand Up @@ -670,13 +676,22 @@ public function getSingleFromSource(Synchronization $synchronization): ?array

$url = \Safe\parse_url($synchronization->getSource()->getLocation());

$endpoint = $synchronization->getEndpoint().'/'.$synchronization->getSourceId();
if (str_contains('http', $synchronization->getSourceId()) === true) {
$endpoint = $synchronization->getEndpoint();
}
if (isset($this->configuration['location']) === true) {
$endpoint = $this->configuration['location'];
$synchronization->setEndpoint($endpoint);
}

if ($url['scheme'] === 'http' || $url['scheme'] === 'https') {
// Get object form source with callservice
try {
$this->logger->info("getSingleFromSource with Synchronization->sourceId = {$synchronization->getSourceId()}");
$response = $this->callService->call(
$callServiceConfig['source'],
$synchronization->getEndpoint() ?? $callServiceConfig['endpoint'],
$endpoint,
$callServiceConfig['method'] ?? 'GET',
[
'body' => '',
Expand All @@ -694,7 +709,7 @@ public function getSingleFromSource(Synchronization $synchronization): ?array
$result = $this->callService->decodeResponse($callServiceConfig['source'], $response);
} elseif ($url['scheme'] === 'ftp') {
// This only works if a file data equals a single Object(Entity). Or if the mapping on the Source or Synchronization results in data for just a single Object.
$result = $this->fileSystemService->call($synchronization->getSource(), $synchronization->getEndpoint() ?? $callServiceConfig['endpoint']);
$result = $this->fileSystemService->call($synchronization->getSource(), isset($this->configuration['location']) === true ? $callServiceConfig['endpoint'] : $endpoint);
}
$dot = new Dot($result);
// The place where we can find the id field when looping through the list of objects, from $result root, by object (dot notation)
Expand All @@ -711,15 +726,20 @@ public function getSingleFromSource(Synchronization $synchronization): ?array
/**
* Finds a synchronization object if it exists for the current object in the source, or creates one if it doesn't exist.
*
* @param Source $source The source that is requested
* @param Entity $entity The entity that is requested
* @param string $sourceId The id of the object in the source
* @param Source $source The source that is requested
* @param Entity $entity The entity that is requested
* @param string $sourceId The id of the object in the source
* @param string|null $endpoint The endpoint of the synchronization.
*
* @return Synchronization|null A synchronization object related to the object in the source
*/
public function findSyncBySource(Source $source, Entity $entity, string $sourceId): ?Synchronization
public function findSyncBySource(Source $source, Entity $entity, string $sourceId, ?string $endpoint = null): ?Synchronization
{
$synchronization = $this->entityManager->getRepository('App:Synchronization')->findOneBy(['gateway' => $source, 'entity' => $entity, 'sourceId' => $sourceId]);
$criteria = ['gateway' => $source, 'entity' => $entity, 'sourceId' => $sourceId];
if (empty($endpoint) === false) {
$criteria['endpoint'] = $endpoint;
}
$synchronization = $this->entityManager->getRepository('App:Synchronization')->findOneBy($criteria);

if ($synchronization instanceof Synchronization) {
if (isset($this->io)) {
Expand All @@ -731,6 +751,7 @@ public function findSyncBySource(Source $source, Entity $entity, string $sourceI
}

$synchronization = new Synchronization($source, $entity);
$synchronization->setEndpoint($endpoint);
$synchronization->setSourceId($sourceId);
$this->entityManager->persist($synchronization);
// We flush later
Expand Down Expand Up @@ -1326,15 +1347,27 @@ private function syncToSource(Synchronization $synchronization, bool $existsInSo

// $objectArray = $this->objectEntityService->checkGetObjectExceptions($data, $object, [], ['all' => true], 'application/ld+json');
// todo: maybe move this to foreach in getAllFromSource() (nice to have)
$callServiceConfig = $this->getCallServiceConfig($synchronization->getSource(), null, $objectArray);
$callServiceConfig = $this->getCallServiceConfig($synchronization->getSource(), $existsInSource ? $synchronization->getSourceId() : null, $objectArray);
$objectArray = $this->mapOutput($objectArray);

$endpoint = $synchronization->getEndpoint();
if ($existsInSource === true) {
$endpoint = $endpoint.'/'.$synchronization->getSourceId();
}
if (str_contains('http', $synchronization->getSourceId()) === true) {
$endpoint = $synchronization->getEndpoint();
}
if (isset($this->configuration['location']) === true) {
$endpoint = $this->configuration['location'];
$synchronization->setEndpoint($endpoint);
}

$objectString = $this->getObjectString($objectArray);

try {
$result = $this->callService->call(
$callServiceConfig['source'],
$synchronization->getEndpoint() ?? $callServiceConfig['endpoint'],
$endpoint,
$callServiceConfig['method'] ?? ($existsInSource ? 'PUT' : 'POST'),
[
'body' => $objectString,
Expand Down Expand Up @@ -1469,41 +1502,35 @@ private function syncThroughComparing(Synchronization $synchronization): Synchro
*/
public function aquireObject(string $url, Entity $entity): ?ObjectEntity
{
// 1. Get the domain from the url
$parse = \Safe\parse_url($url);
$location = $parse['scheme'].'://'.$parse['host'];

// 2.c Try to establish a source for the domain
$source = $this->entityManager->getRepository('App:Gateway')->findOneBy(['location'=>$location]);

// 2.b The source might be on a path e.g. /v1 so if whe cant find a source let try to cycle
if ($source instanceof Source === false && isset($parse['path']) === true) {
foreach (explode('/', $parse['path']) as $pathPart) {
if ($pathPart !== '') {
$location = $location.'/'.$pathPart;
}
$source = $this->entityManager->getRepository('App:Gateway')->findOneBy(['location'=>$location]);
if ($source !== null) {
break;
}
}
}
if ($source instanceof Source === false) {
return null;
}
$source = $this->resourceService->findSourceForUrl($url, 'conduction-nl/commonground-gateway', $endpoint);
$sourceId = $this->getSourceId($endpoint, $url);

// 3 If we have a source we can establish an endpoint.
$endpoint = str_replace($location, '', $url);

// 4 Create sync
$synchronization = new Synchronization($source, $entity);
$synchronization->setSourceId($url);
$synchronization->setEndpoint($endpoint);

$this->entityManager->persist($synchronization);
$synchronization = $this->findSyncBySource($source, $entity, $sourceId, $endpoint);

$this->synchronize($synchronization);

return $synchronization->getObject();
}

/**
* A function best used after resourceService->findSourceForUrl and/or before $this->findSyncBySource.
* This function will get the uuid / int id from the end of an endpoint. This is the sourceId for a Synchronization.
*
* @param string $endpoint The endpoint to get the SourceId from.
* @param string|null $url The url used as back-up for SourceId if no proper SourceId can be found.
*
* @return string|null The sourceId, will be equal to $url if end part of the endpoint isn't an uuid or integer.
*/
public function getSourceId(string &$endpoint, ?string $url = null): ?string
{
$explodedEndpoint = explode('/', $endpoint);
$sourceId = end($explodedEndpoint);
if (Uuid::isValid($sourceId) === true || is_int((int) $sourceId) === true) {
$endpoint = str_replace("/$sourceId", '', $endpoint);
} else {
$sourceId = $url;
}

return $sourceId;
}
}

0 comments on commit 27d58c1

Please sign in to comment.