Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API structures #2999

Merged
merged 8 commits into from Dec 21, 2020
3 changes: 3 additions & 0 deletions routes/api.php
Expand Up @@ -11,4 +11,7 @@
Route::name('assets.index')->get('assets/{asset_container}', 'AssetsController@index');
Route::name('assets.show')->get('assets/{asset_container}/{asset}', 'AssetsController@show')->where('asset', '.*');

Route::get('collections/{collection}/tree', 'CollectionTreeController@show');
Route::get('navigation/{navigation}', 'NavigationController@show');

Route::get('{path?}', 'NotFoundController')->where('path', '.*');
26 changes: 26 additions & 0 deletions src/Http/Controllers/API/CollectionTreeController.php
@@ -0,0 +1,26 @@
<?php

namespace Statamic\Http\Controllers\API;

use Statamic\Exceptions\NotFoundHttpException;
use Statamic\Facades\Site;
use Statamic\Http\Resources\API\TreeResource;

class CollectionTreeController extends ApiController
{
public function show($collection)
{
$site = request('site', Site::default()->handle());

$tree = $collection->structure()->in($site);
jesseleite marked this conversation as resolved.
Show resolved Hide resolved

throw_unless($tree, new NotFoundHttpException("Collection [{$collection->handle()}] not found in [{$site}] site"));

$fields = explode(',', request('fields', '*'));
$maxDepth = request('max_depth');

return app(TreeResource::class)::make($tree)
->fields($fields)
->maxDepth($maxDepth);
}
}
31 changes: 31 additions & 0 deletions src/Http/Controllers/API/NavigationController.php
@@ -0,0 +1,31 @@
<?php

namespace Statamic\Http\Controllers\API;

use Statamic\Exceptions\NotFoundHttpException;
use Statamic\Facades\Nav;
use Statamic\Facades\Site;
use Statamic\Http\Resources\API\TreeResource;

class NavigationController extends ApiController
{
public function show($navHandle)
{
$nav = Nav::find($navHandle);

throw_unless($nav, new NotFoundHttpException("Navigation [{$navHandle}] not found"));

$site = request('site', Site::default()->handle());

$tree = $nav->in($site);

throw_unless($tree, new NotFoundHttpException("Navigation [{$navHandle}] not found in [{$site}] site"));

$fields = explode(',', request('fields', '*'));
$maxDepth = request('max_depth');

return app(TreeResource::class)::make($tree)
->fields($fields)
->maxDepth($maxDepth);
}
}
1 change: 1 addition & 0 deletions src/Http/Resources/API/Resource.php
Expand Up @@ -18,6 +18,7 @@ class Resource
GlobalSetResource::class,
TermResource::class,
UserResource::class,
TreeResource::class,
];

/**
Expand Down
56 changes: 56 additions & 0 deletions src/Http/Resources/API/TreeResource.php
@@ -0,0 +1,56 @@
<?php

namespace Statamic\Http\Resources\API;

use Illuminate\Http\Resources\Json\JsonResource;
use Statamic\Facades\Site;
use Statamic\Structures\TreeBuilder;

class TreeResource extends JsonResource
{
protected $fields;
protected $depth;

/**
* Set selected fields.
*
* @param array|null $fields
* @return $this
*/
public function fields($fields = null)
{
$this->fields = $fields;

return $this;
}

/**
* Set max depth.
*
* @param int|null $depth
* @return $this
*/
public function maxDepth($depth = null)
{
$this->maxDepth = $depth;

return $this;
}

/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request
* @return array
*/
public function toArray($request)
{
return (new TreeBuilder)->build([
'structure' => $this->resource->structure()->handle(),
'include_home' => true,
'site' => Site::default()->handle(),
'fields' => $this->fields,
'max_depth' => $this->maxDepth,
]);
}
}
20 changes: 16 additions & 4 deletions src/Structures/AugmentedPage.php
Expand Up @@ -3,6 +3,7 @@
namespace Statamic\Structures;

use Statamic\Entries\AugmentedEntry;
use Statamic\Statamic;

class AugmentedPage extends AugmentedEntry
{
Expand All @@ -20,11 +21,22 @@ public function __construct($page)

public function keys()
{
if ($this->hasEntry) {
return parent::keys();
}
$keys = $this->hasEntry
? parent::keys()
: ['title', 'url', 'uri', 'permalink'];

return Statamic::isApiRoute()
? $this->apiKeys($keys)
: $keys;
}

return ['title', 'url', 'uri', 'permalink'];
private function apiKeys($keys)
{
return collect($keys)
->reject(function ($key) {
return in_array($key, ['parent']);
})
->all();
}

protected function getFromData($key)
Expand Down
11 changes: 9 additions & 2 deletions src/Structures/Page.php
Expand Up @@ -4,19 +4,21 @@

use Illuminate\Contracts\Support\Responsable;
use Illuminate\Support\Traits\ForwardsCalls;
use JsonSerializable;
use Statamic\Contracts\Auth\Protect\Protectable;
use Statamic\Contracts\Data\Augmentable;
use Statamic\Contracts\Entries\Entry;
use Statamic\Contracts\Routing\UrlBuilder;
use Statamic\Data\HasAugmentedInstance;
use Statamic\Data\TracksQueriedColumns;
use Statamic\Facades\Blink;
use Statamic\Facades\Collection;
use Statamic\Facades\Site;
use Statamic\Facades\URL;

class Page implements Entry, Augmentable, Responsable, Protectable
class Page implements Entry, Augmentable, Responsable, Protectable, JsonSerializable
{
use HasAugmentedInstance, ForwardsCalls;
use HasAugmentedInstance, ForwardsCalls, TracksQueriedColumns;

protected $tree;
protected $reference;
Expand Down Expand Up @@ -329,4 +331,9 @@ public function __call($method, $args)
{
return $this->forwardCallTo($this->entry(), $method, $args);
}

public function jsonSerialize()
{
return $this->toAugmentedCollection($this->selectedQueryColumns);
}
}
16 changes: 11 additions & 5 deletions src/Structures/TreeBuilder.php
Expand Up @@ -17,6 +17,8 @@ public function build($params)
}

$from = $params['from'] ?? null;
$maxDepth = $params['max_depth'] ?? null;
$fields = $params['fields'] ?? null;

if ($from && $structure instanceof Nav) {
throw new \Exception('Cannot get a nested starting position on a navigation structure.');
Expand All @@ -37,20 +39,24 @@ public function build($params)
->all();
}

return $this->toTree($pages, 1);
return $this->toTree($pages, 1, $maxDepth, $fields);
}

protected function toTree($pages, $depth)
protected function toTree($pages, $depth, $maxDepth, $fields)
{
return $pages->map(function ($page) use ($depth) {
if ($maxDepth && $depth > $maxDepth) {
return [];
}

return $pages->map(function ($page) use ($depth, $maxDepth, $fields) {
if ($page->reference() && ! $page->referenceExists()) {
return null;
}

return [
'page' => $page,
'page' => $page->selectedQueryColumns($fields),
'depth' => $depth,
'children' => $this->toTree($page->pages()->all(), $depth + 1),
'children' => $this->toTree($page->pages()->all(), $depth + 1, $maxDepth, $fields),
];
})->filter()->values()->all();
}
Expand Down