Merge pull request #118 from goteo/fix/versioned-resources-state
[fix] Versioned resources state
This commit is contained in:
+10
-11
@@ -5,7 +5,6 @@ namespace App\ApiResource;
|
||||
use ApiPlatform\Metadata as API;
|
||||
use App\Filter\ResourceVersionResourceFilter;
|
||||
use App\Filter\ResourceVersionResourceIdFilter;
|
||||
use App\Service\ApiService;
|
||||
use App\State\ResourceVersionStateProvider;
|
||||
use Gedmo\Loggable\Entity\LogEntry;
|
||||
|
||||
@@ -23,7 +22,7 @@ class Version
|
||||
{
|
||||
public function __construct(
|
||||
private readonly LogEntry $log,
|
||||
private readonly object $entity,
|
||||
private readonly string $shortName,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -34,14 +33,6 @@ class Version
|
||||
return $this->log->getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* The ID of the version for this specific resource.
|
||||
*/
|
||||
public function getVersion(): ?int
|
||||
{
|
||||
return $this->log->getVersion();
|
||||
}
|
||||
|
||||
/**
|
||||
* The type of action that performed the recorded changes.
|
||||
*/
|
||||
@@ -55,7 +46,7 @@ class Version
|
||||
*/
|
||||
public function getResource(): string
|
||||
{
|
||||
return ApiService::toResource($this->log->getObjectClass());
|
||||
return $this->shortName;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -66,6 +57,14 @@ class Version
|
||||
return $this->log->getObjectId();
|
||||
}
|
||||
|
||||
/**
|
||||
* The version number for this specific resource.
|
||||
*/
|
||||
public function getResourceVersion(): ?int
|
||||
{
|
||||
return $this->log->getVersion();
|
||||
}
|
||||
|
||||
/**
|
||||
* The changed resource data, i.e the new values of the changed properties.
|
||||
*/
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
namespace App\DependencyInjection\Compiler;
|
||||
|
||||
use App\Service\ApiService;
|
||||
use ApiPlatform\Metadata\ApiResource;
|
||||
use App\Service\VersionedResourceService;
|
||||
use Gedmo\Mapping\Annotation as Gedmo;
|
||||
use Gedmo\Mapping\Annotation\Loggable;
|
||||
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
@@ -13,27 +13,48 @@ class VersionedResourcePass implements CompilerPassInterface
|
||||
public function process(ContainerBuilder $container): void
|
||||
{
|
||||
$allClasses = \get_declared_classes();
|
||||
$entityClasses = \array_filter($allClasses, function (string $className) {
|
||||
return \str_starts_with($className, 'App\\Entity\\');
|
||||
$resourceClasses = \array_filter($allClasses, function (string $className) {
|
||||
return \str_starts_with($className, 'App\\ApiResource\\');
|
||||
});
|
||||
|
||||
$versionedResourceNames = [];
|
||||
foreach ($entityClasses as $entityClass) {
|
||||
$reflectionClass = new \ReflectionClass($entityClass);
|
||||
$attributes = $reflectionClass->getAttributes(Gedmo\Loggable::class);
|
||||
$versionedResources = [];
|
||||
foreach ($resourceClasses as $resourceClass) {
|
||||
$resourceReflection = new \ReflectionClass($resourceClass);
|
||||
$resourceAttributes = $resourceReflection->getAttributes(ApiResource::class);
|
||||
|
||||
if (empty($attributes)) {
|
||||
if (empty($resourceAttributes)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$versionedResourceNames = [
|
||||
...$versionedResourceNames,
|
||||
ApiService::toResource($entityClass),
|
||||
$resourceAttribute = $resourceAttributes[0];
|
||||
$resourceAttributeArgs = $resourceAttribute->getArguments();
|
||||
|
||||
if (!\array_key_exists('stateOptions', $resourceAttributeArgs)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!\array_key_exists('shortName', $resourceAttributeArgs)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/** @var string */
|
||||
$resourceEntityClass = $resourceAttributeArgs['stateOptions']->getEntityClass();
|
||||
|
||||
$entityReflection = new \ReflectionClass($resourceEntityClass);
|
||||
$entityLoggable = $entityReflection->getAttributes(Loggable::class);
|
||||
|
||||
if (empty($entityLoggable)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$versionedResources = [
|
||||
...$versionedResources,
|
||||
$resourceAttributeArgs['shortName'] => $resourceEntityClass,
|
||||
];
|
||||
}
|
||||
|
||||
/** @var VersionedResourceService */
|
||||
$versionedResourceService = $container->get(VersionedResourceService::class);
|
||||
$versionedResourceService->compileNames($versionedResourceNames);
|
||||
$versionedResourceService->compileNames($versionedResources);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ final class ResourceVersionResourceFilter extends AbstractFilter
|
||||
'description' => 'The name of the resource.',
|
||||
'schema' => [
|
||||
'type' => Type::BUILTIN_TYPE_STRING,
|
||||
'enum' => $this->versionedResourceService->getNames(),
|
||||
'enum' => \array_keys($this->versionedResourceService->getNames()),
|
||||
],
|
||||
'openapi' => [
|
||||
'allowEmptyValue' => false,
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
class ApiService
|
||||
{
|
||||
/**
|
||||
* Converts an Entity class name into an API resource name.
|
||||
*/
|
||||
public static function toResource(string $className): string
|
||||
{
|
||||
$classPieces = explode('\\', $className);
|
||||
|
||||
return lcfirst(end($classPieces));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts to an Entity class name from an API resource name.
|
||||
*/
|
||||
public static function toEntity(string $resourceName): string
|
||||
{
|
||||
return sprintf('App\\Entity\\%s', ucfirst($resourceName));
|
||||
}
|
||||
}
|
||||
@@ -43,7 +43,7 @@ class VersionedResourceService
|
||||
/**
|
||||
* Stores the given names in lock file.
|
||||
*
|
||||
* @param string[] $names
|
||||
* @param array<string, string> $names
|
||||
*/
|
||||
public function compileNames(array $names)
|
||||
{
|
||||
@@ -51,17 +51,45 @@ class VersionedResourceService
|
||||
|
||||
\file_put_contents(
|
||||
self::getNamesLockFile(),
|
||||
implode(PHP_EOL, $names)
|
||||
json_encode($names)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string> List of the versioned resource names
|
||||
* @return array<string, string> List of the versioned resource names
|
||||
*
|
||||
* @see compileNames()
|
||||
*/
|
||||
public static function getNames(): array
|
||||
{
|
||||
return explode(PHP_EOL, \file_get_contents(self::getNamesLockFile()));
|
||||
return json_decode(\file_get_contents(self::getNamesLockFile()), true);
|
||||
}
|
||||
|
||||
public static function getEntityFromResource(string $resourceShortName): string
|
||||
{
|
||||
$names = self::getNames();
|
||||
|
||||
if (\array_key_exists($resourceShortName, $names)) {
|
||||
return $names[$resourceShortName];
|
||||
}
|
||||
|
||||
throw new \Exception(\sprintf(
|
||||
"The resource shortName '%s' does not match to a known versioned resource",
|
||||
$resourceShortName
|
||||
));
|
||||
}
|
||||
|
||||
public static function getResourceFromEntity(string $entityClass): string
|
||||
{
|
||||
foreach (self::getNames() as $shortName => $entityFqcl) {
|
||||
if ($entityFqcl === $entityClass) {
|
||||
return $shortName;
|
||||
}
|
||||
}
|
||||
|
||||
throw new \Exception(\sprintf(
|
||||
"The entity class name '%s' does not match to a known versioned resource",
|
||||
$entityClass
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ use ApiPlatform\Metadata as API;
|
||||
use ApiPlatform\Metadata\Operation;
|
||||
use ApiPlatform\State\ProviderInterface;
|
||||
use App\ApiResource\Version;
|
||||
use App\Service\ApiResourceNormalizer;
|
||||
use App\Service\VersionedResourceService;
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\Persistence\Mapping\MappingException;
|
||||
use Gedmo\Loggable\Entity\LogEntry;
|
||||
@@ -33,6 +33,8 @@ class ResourceVersionStateProvider implements ProviderInterface
|
||||
$context['request']->query->get('resource'),
|
||||
$context['request']->query->get('resourceId')
|
||||
);
|
||||
default:
|
||||
throw new \Exception('Operation not supported for Version resource', 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,8 +50,9 @@ class ResourceVersionStateProvider implements ProviderInterface
|
||||
}
|
||||
|
||||
$entity = $this->entityManager->find($log->getObjectClass(), $log->getObjectId());
|
||||
$resourceName = VersionedResourceService::getResourceFromEntity($entity::class);
|
||||
|
||||
return new Version($log, $entity);
|
||||
return new Version($log, $resourceName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,10 +60,10 @@ class ResourceVersionStateProvider implements ProviderInterface
|
||||
*/
|
||||
private function getVersions(string $resourceName, int $resourceId): array
|
||||
{
|
||||
$resourceClass = ApiResourceNormalizer::toEntity($resourceName);
|
||||
$entityClass = VersionedResourceService::getEntityFromResource($resourceName);
|
||||
|
||||
try {
|
||||
$entity = $this->entityManager->find($resourceClass, $resourceId);
|
||||
$entity = $this->entityManager->find($entityClass, $resourceId);
|
||||
} catch (MappingException $e) {
|
||||
throw new NotFoundHttpException(sprintf("Resource '%s' does not exist", $resourceName));
|
||||
}
|
||||
@@ -73,7 +76,7 @@ class ResourceVersionStateProvider implements ProviderInterface
|
||||
|
||||
$versions = [];
|
||||
foreach ($logs as $log) {
|
||||
$versions[] = new Version($log, $entity);
|
||||
$versions[] = new Version($log, $resourceName);
|
||||
}
|
||||
|
||||
return $versions;
|
||||
|
||||
Reference in New Issue
Block a user