1
0
mirror of https://github.com/flarum/core.git synced 2025-08-07 00:47:00 +02:00

feat: allow adding endpoints before/after others (#4115)

This commit is contained in:
Sami Mazouz
2024-11-22 08:45:26 +01:00
committed by GitHub
parent 4feb4a3820
commit 5e7fbcb0e8
3 changed files with 130 additions and 0 deletions

View File

@@ -148,6 +148,10 @@ class Endpoint implements \Tobyz\JsonApiServer\Endpoint\Endpoint
return json_api_response($this->showResource($context, $data));
}
if (is_array($data)) {
return json_api_response($data);
}
return null;
}
}

View File

@@ -22,6 +22,8 @@ use Tobyz\JsonApiServer\Schema\Sort;
class ApiResource implements ExtenderInterface
{
private array $endpoints = [];
private array $endpointsBefore = [];
private array $endpointsAfter = [];
private array $removeEndpoints = [];
private array $endpoint = [];
private array $fields = [];
@@ -55,6 +57,44 @@ class ApiResource implements ExtenderInterface
return $this;
}
/**
* Add endpoints to the resource before a certain endpoint.
*
* @param string $before the name of the endpoint to add the new endpoints before.
* @param callable|class-string $endpoints must be a callable that returns an array of objects that implement \Flarum\Api\Endpoint\Endpoint.
*/
public function endpointsBefore(string $before, callable|string $endpoints): self
{
$this->endpointsBefore[] = [$before, $endpoints];
return $this;
}
/**
* Add endpoints to the resource after a certain endpoint.
*
* @param string $after the name of the endpoint to add the new endpoints after.
* @param callable|class-string $endpoints must be a callable that returns an array of objects that implement \Flarum\Api\Endpoint\Endpoint.
*/
public function endpointsAfter(string $after, callable|string $endpoints): self
{
$this->endpointsAfter[] = [$after, $endpoints];
return $this;
}
/**
* Add endpoints to the resource before all other endpoints.
*
* @param callable|class-string $endpoints must be a callable that returns an array of objects that implement \Flarum\Api\Endpoint\Endpoint.
*/
public function endpointsBeforeAll(callable|string $endpoints): self
{
$this->endpointsBefore[] = [0, $endpoints];
return $this;
}
/**
* Remove endpoints from the resource.
*
@@ -214,6 +254,31 @@ class ApiResource implements ExtenderInterface
$endpoints = array_merge($endpoints, $newEndpointsCallback());
}
foreach ($this->endpointsBefore as [$before, $newEndpointsCallback]) {
$newEndpointsCallback = ContainerUtil::wrapCallback($newEndpointsCallback, $container);
if ($before === 0) {
array_unshift($endpoints, ...$newEndpointsCallback());
} else {
$newEndpoints = $newEndpointsCallback();
$beforeIndex = array_search($before, array_column($endpoints, 'name'));
if ($beforeIndex !== false) {
array_splice($endpoints, $beforeIndex, 0, $newEndpoints);
}
}
}
foreach ($this->endpointsAfter as [$after, $newEndpointsCallback]) {
$newEndpointsCallback = ContainerUtil::wrapCallback($newEndpointsCallback, $container);
$newEndpoints = $newEndpointsCallback();
$afterIndex = array_search($after, array_column($endpoints, 'name'));
if ($afterIndex !== false) {
array_splice($endpoints, $afterIndex + 1, 0, $newEndpoints);
}
}
foreach ($this->removeEndpoints as $removeEndpointClass) {
[$endpointsToRemove, $condition] = $removeEndpointClass;

View File

@@ -11,6 +11,7 @@ namespace Flarum\Tests\integration\extenders;
use Carbon\Carbon;
use Flarum\Api\Context;
use Flarum\Api\Endpoint\Endpoint;
use Flarum\Api\Endpoint\Index;
use Flarum\Api\Endpoint\Show;
use Flarum\Api\Resource\AbstractDatabaseResource;
@@ -91,6 +92,66 @@ class ApiResourceTest extends TestCase
$this->assertEquals('dataSerializationPrepCustomTitle', $payload['data']['attributes']['title'], $body);
}
#[Test]
public function custom_endpoint_works_if_added()
{
$this->extend(
(new Extend\ApiResource(DiscussionResource::class))
->endpoints(fn () => [
Endpoint::make('custom')
->route('GET', '/{id}/custom')
->action(function (Context $context) {
$discussion = $context->model;
return [
'data' => [
'message' => 'custom endpoint '.$discussion->id,
],
];
}),
])
);
$response = $this->send(
$this->request('GET', '/api/discussions/1/custom', [
'authenticatedAs' => 1,
])
);
$payload = json_decode($body = $response->getBody()->getContents(), true);
$this->assertEquals('custom endpoint 1', $payload['data']['message'], $body);
}
#[Test]
public function custom_endpoint_works_if_added_before_all()
{
$this->extend(
(new Extend\ApiResource(DiscussionResource::class))
->endpointsBeforeAll(fn () => [
Endpoint::make('custom')
->route('GET', '/custom')
->action(function (Context $context) {
return [
'data' => [
'message' => 'custom endpoint',
],
];
}),
])
);
$response = $this->send(
$this->request('GET', '/api/discussions/custom', [
'authenticatedAs' => 1,
])
);
$payload = json_decode($body = $response->getBody()->getContents(), true);
$this->assertEquals('custom endpoint', $payload['data']['message'], $body);
}
#[Test]
public function after_endpoint_callback_works_with_invokable_classes()
{