Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
"require": {
"php" : "^7.4|^8.0|^8.1",
"illuminate/support": "^7.0|^8.0|^9.0",
"illuminate/http": "^7.0|^8.0|^9.0"
"illuminate/http": "^7.0|^8.0|^9.0",
"ext-json": "*"
},
"require-dev": {
"phpunit/phpunit": "^9.5",
Expand Down
11 changes: 11 additions & 0 deletions publishable/config/api.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,15 @@

// 'route_prefix' => 'app'

/*
|--------------------------------------------------------------------------
| Routing manifest file
|--------------------------------------------------------------------------
|
| Here is the path for the routing manifest that will cache the resolution
| strategy for each Resource in every version.
*/

'routing_cache_path' => app()->bootstrapPath('cache/api-resources-cache.php'),

];
70 changes: 22 additions & 48 deletions src/APIResourceManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
namespace Juampi92\APIResources;

use Exception;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Http\Resources\Json\ResourceCollection;
use Illuminate\Support\Str;
use Juampi92\APIResources\Exceptions\ResourceNotFoundException;
use Juampi92\APIResources\Resolvers\ResolverFactory;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Http\Resources\Json\ResourceCollection;
use Juampi92\APIResources\Support\Version;

class APIResourceManager
Expand Down Expand Up @@ -158,50 +159,9 @@ public function getBasePath(): string
return $this->path;
}

/**
* Returns the classname of the versioned resource,
* or it's latest version if it doesn't exist.
*
* Throws an exception if it cannot find it.
*
* @param string $classname
*
* @return class-string<JsonResource>
* @throws ResourceNotFoundException
*/
public function resolveClassname(string $classname)
{
$versions = $this->getVersionsBetween($this->current, $this->latest);

foreach ($versions as $version) {
$path = $this->parseClassname($classname, $version);

// Check if the resource was found
if (class_exists($path)) {
return $path;
}
}

throw new Exceptions\ResourceNotFoundException($classname, $this->latest);
}

/**
* Returns the classname with the version considering.
*
* @return class-string<JsonResource>
*/
protected function parseClassname(string $classname, string $version): string
public function getResourcesPath(): ?string
{
if (! empty($this->resources)) {
$path = $this->resources . "\\v{$version}\\" . Str::after($classname, $this->resources . "\\");
} else {
$path = "v{$version}\\" . $classname;
}

$path = "\\{$this->path}\\{$path}";

/** @phpstan-ignore-next-line */
return $path;
return $this->resources;
}

/**
Expand All @@ -216,9 +176,15 @@ protected function parseClassname(string $classname, string $version): string
*/
public function resolve(string $classname): APIResource
{
return new APIResource(
$this->resolveClassname($classname)
);
return new APIResource(ResolverFactory::make($classname)->run());
}

/**
* @throws ResourceNotFoundException
*/
public function resolveClassname(string $classname): string
{
return ResolverFactory::make($classname)->run();
}

/**
Expand Down Expand Up @@ -247,6 +213,14 @@ public function collection($classname, ...$args)
return $resource->collection(...$args);
}

/**
* @return array<string>
*/
public function getVersionsBetweenCurrentAndLatest(): array
{
return $this->getVersionsBetween($this->current, $this->latest);
}

/**
* @return array<string>
*/
Expand Down
6 changes: 6 additions & 0 deletions src/Facades/APIResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,19 @@
/**
* @method static \Juampi92\APIResources\APIResourceManager setVersion(string $version, string $apiName = null)
* @method static string getVersion()
* @method static string getLatestVersion()
* @method static bool isLatest(string $c = null)
* @method static string resolveClassname(string $classname, bool $forceLatest = null) Returns formatted classname using current version
* @method static \Juampi92\APIResources\APIResource resolve(string $classname)
* @method static \Illuminate\Http\Resources\Json\Resource make(string $classname, ...$args) Resolves the classname and instantiates the resource
* @method static \Illuminate\Http\Resources\Json\Resource collection(string $classname, ...$args) Resolves the classname and instantiates the resource as a collection
* @method static string getRoute(string $name, array $parameters, bool $absolute)
* @method static string getRouteName(string $name)
* @method static string getBasePath()
* @method static ?string getResourcesPath()
* @method static array<string> getVersionsBetweenCurrentAndLatest()
*
* @see \Juampi92\APIResources\APIResourceManager
*/
class APIResource extends Facade
{
Expand Down
35 changes: 35 additions & 0 deletions src/Resolvers/CacheResolver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

namespace Juampi92\APIResources\Resolvers;

use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Http\Resources\Json\ResourceCollection;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Juampi92\APIResources\Exceptions\ResourceNotFoundException;
use Juampi92\APIResources\Facades\APIResource;

class CacheResolver extends Resolver
{
public function run(): string
{
$routingManifest = include Storage::path(config('api.routing_cache_path'));

foreach (APIResource::getVersionsBetweenCurrentAndLatest() as $version) {
$version = Str::start($version, 'v');

/** @var ?class-string<JsonResource|ResourceCollection> $path */
$path = $routingManifest[$this->classname][$version] ?? null;

if (! $path) {
continue;
}

if (class_exists($path)) {
return $path;
}
}

throw new ResourceNotFoundException($this->classname, APIResource::getLatestVersion());
}
}
56 changes: 56 additions & 0 deletions src/Resolvers/PathResolver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

namespace Juampi92\APIResources\Resolvers;

use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Http\Resources\Json\ResourceCollection;
use Illuminate\Support\Str;
use Juampi92\APIResources\Exceptions\ResourceNotFoundException;
use Juampi92\APIResources\Facades\APIResource;

class PathResolver extends Resolver
{
public function run(): string
{
foreach (APIResource::getVersionsBetweenCurrentAndLatest() as $version) {
$version = Str::start($version, 'v');

$path = $this->getPath($version);

// Check if the resource was found
if (class_exists($path)) {
return $path;
}
}

throw new ResourceNotFoundException($this->classname, APIResource::getLatestVersion());
}

private function guessResourcePath(string $version): string
{
$resourcesPath = APIResource::getResourcesPath();

if (empty($resourcesPath)) {
return "{$version}\\{$this->classname}";
}

return sprintf(
"%s\\%s\\%s",
$resourcesPath,
$version,
Str::after($this->classname, $resourcesPath . "\\")
);
}

/**
* @return class-string<JsonResource|ResourceCollection>
*/
protected function getPath($version): string
{
$basePath = APIResource::getBasePath();

$resourcePath = $this->guessResourcePath($version);

return "\\{$basePath}\\{$resourcePath}";
}
}
23 changes: 23 additions & 0 deletions src/Resolvers/Resolver.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace Juampi92\APIResources\Resolvers;

use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Http\Resources\Json\ResourceCollection;
use Juampi92\APIResources\Exceptions\ResourceNotFoundException;

abstract class Resolver
{
protected string $classname;

public function __construct(string $classname)
{
$this->classname = $classname;
}

/**
* @return class-string<JsonResource|ResourceCollection>
* @throws ResourceNotFoundException
*/
abstract public function run(): string;
}
19 changes: 19 additions & 0 deletions src/Resolvers/ResolverFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace Juampi92\APIResources\Resolvers;

use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;
use Juampi92\APIResources\Facades\APIResource;

class ResolverFactory
{
public static function make(string $classname): Resolver
{
if (Storage::exists(config('api.routing_cache_path'))) {
return new CacheResolver($classname);
}

return new PathResolver($classname);
}
}
Loading