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:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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()
|
||||
{
|
||||
|
Reference in New Issue
Block a user