Skip to content

Commit

Permalink
feat(laravel): provide a trait in addition to the annotation
Browse files Browse the repository at this point in the history
  • Loading branch information
dunglas committed Aug 23, 2024
1 parent ebc61d5 commit af68e82
Show file tree
Hide file tree
Showing 8 changed files with 391 additions and 215 deletions.
17 changes: 13 additions & 4 deletions src/Laravel/ApiPlatformProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@
use ApiPlatform\Laravel\Eloquent\State\PersistProcessor;
use ApiPlatform\Laravel\Eloquent\State\RemoveProcessor;
use ApiPlatform\Laravel\Exception\ErrorHandler;
use ApiPlatform\Laravel\Metadata\ConcernsResourceMetadataCollectionFactory;
use ApiPlatform\Laravel\Metadata\ConcernsResourceNameCollectionFactory;
use ApiPlatform\Laravel\Routing\IriConverter;
use ApiPlatform\Laravel\Routing\Router as UrlGeneratorRouter;
use ApiPlatform\Laravel\Routing\SkolemIriConverter;
Expand Down Expand Up @@ -205,7 +207,7 @@ public function register(): void
$refl = new \ReflectionClass(Error::class);
$paths[] = \dirname($refl->getFileName());

return new AttributesResourceNameCollectionFactory($paths);
return new ConcernsResourceNameCollectionFactory($paths, new AttributesResourceNameCollectionFactory($paths));
});

$this->app->bind(ResourceClassResolverInterface::class, ResourceClassResolver::class);
Expand Down Expand Up @@ -273,13 +275,20 @@ public function register(): void
$app->make(PathSegmentNameGeneratorInterface::class),
new NotExposedOperationResourceMetadataCollectionFactory(
$app->make(LinkFactoryInterface::class),
new AttributesResourceMetadataCollectionFactory(
null,
new ConcernsResourceMetadataCollectionFactory(
new AttributesResourceMetadataCollectionFactory(
null,
$app->make(LoggerInterface::class),
[
'routePrefix' => $config->get('api-platform.routes.prefix') ?? '/',
],
false,
),
$app->make(LoggerInterface::class),
[
'routePrefix' => $config->get('api-platform.routes.prefix') ?? '/',
],
false
false,
)
)
)
Expand Down
27 changes: 27 additions & 0 deletions src/Laravel/IsApiResource.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <dunglas@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace ApiPlatform\Laravel;

use ApiPlatform\Metadata\ApiResource;

/**
* @author Kévin Dunglas <kevin@dunglas.dev>
*/
trait IsApiResource
{
public static function apiResource(): ApiResource
{
return new ApiResource();
}
}
54 changes: 54 additions & 0 deletions src/Laravel/Metadata/ConcernsResourceMetadataCollectionFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <dunglas@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace ApiPlatform\Laravel\Metadata;

use ApiPlatform\Laravel\IsApiResource;
use ApiPlatform\Metadata\Resource\Factory\MetadataCollectionFactoryTrait;
use ApiPlatform\Metadata\Resource\Factory\ResourceMetadataCollectionFactoryInterface;
use ApiPlatform\Metadata\Resource\ResourceMetadataCollection;

/**
* Creates a resource metadata from {@see IsApiResource} concerns.
*
* @author Kévin Dunglas <kevin@dunglas.dev>
*/
final class ConcernsResourceMetadataCollectionFactory implements ResourceMetadataCollectionFactoryInterface
{
use MetadataCollectionFactoryTrait;

/**
* {@inheritdoc}
*/
public function create(string $resourceClass): ResourceMetadataCollection
{
$resourceMetadataCollection = $this->decorated?->create($resourceClass) ?? new ResourceMetadataCollection(
$resourceClass
);

if (!method_exists($resourceClass, 'apiResource')) {
return $resourceMetadataCollection;
}

$metadataCollection = $resourceClass::apiResource();
if (!\is_array($metadataCollection)) {
$metadataCollection = [$metadataCollection];
}

foreach ($this->buildResourceOperations($metadataCollection, $resourceClass) as $resource) {
$resourceMetadataCollection[] = $resource;
}

return $resourceMetadataCollection;
}
}
63 changes: 63 additions & 0 deletions src/Laravel/Metadata/ConcernsResourceNameCollectionFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <dunglas@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace ApiPlatform\Laravel\Metadata;

use ApiPlatform\Laravel\IsApiResource;
use ApiPlatform\Metadata\Resource\Factory\ResourceNameCollectionFactoryInterface;
use ApiPlatform\Metadata\Resource\ResourceNameCollection;
use ApiPlatform\Metadata\Util\ReflectionClassRecursiveIterator;

/**
* Creates a resource name collection from {@see IsApiResource} concerns.
*
* @author Kévin Dunglas <kevin@dunglas.dev>
*/
final class ConcernsResourceNameCollectionFactory implements ResourceNameCollectionFactoryInterface
{
/**
* @param string[] $paths
*/
public function __construct(
private readonly array $paths,
private readonly ?ResourceNameCollectionFactoryInterface $decorated = null,
) {
}

/**
* {@inheritdoc}
*/
public function create(): ResourceNameCollection
{
$classes = [];

if ($this->decorated) {
foreach ($this->decorated->create() as $resourceClass) {
$classes[$resourceClass] = true;
}
}

foreach (ReflectionClassRecursiveIterator::getReflectionClassesFromDirectories($this->paths) as $className => $reflectionClass) {
if (
$reflectionClass->hasMethod('apiResource')
&& ($m = $reflectionClass->getMethod('apiResource'))
&& $m->isPublic()
&& $m->isStatic()
) {
$classes[$className] = true;
}
}

return new ResourceNameCollection(array_keys($classes));
}
}
4 changes: 2 additions & 2 deletions src/Laravel/workbench/app/Models/Author.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@

namespace Workbench\App\Models;

use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Laravel\IsApiResource;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

#[ApiResource]
class Author extends Model
{
use HasFactory;
use IsApiResource;
}
2 changes: 1 addition & 1 deletion src/Metadata/ApiResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
*
* The API Resource attribute declares the behaviors attached to a Resource inside API Platform.
* This class is immutable, and if you set a value yourself, API Platform will not override the value.
* The API Resource helps sharing options with operations.
* The API Resource helps to share options with operations.
*
* Read more about how metadata works [here](/docs/in-depth/metadata).
*
Expand Down
Loading

0 comments on commit af68e82

Please sign in to comment.