json-api-server/src/ResourceType.php

126 lines
3.8 KiB
PHP

<?php
/*
* This file is part of tobyz/json-api-server.
*
* (c) Toby Zerner <toby.zerner@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Tobyz\JsonApiServer;
use Tobyz\JsonApiServer\Adapter\AdapterInterface;
use Tobyz\JsonApiServer\Exception\BadRequestException;
use Tobyz\JsonApiServer\Schema\Attribute;
use Tobyz\JsonApiServer\Schema\HasMany;
use Tobyz\JsonApiServer\Schema\HasOne;
use Tobyz\JsonApiServer\Schema\Type;
final class ResourceType
{
private $type;
private $adapter;
private $buildSchema;
private $schema;
public function __construct(string $type, AdapterInterface $adapter, callable $buildSchema = null)
{
$this->type = $type;
$this->adapter = $adapter;
$this->buildSchema = $buildSchema;
}
public function getType(): string
{
return $this->type;
}
public function getAdapter(): AdapterInterface
{
return $this->adapter;
}
public function getSchema(): Type
{
if (! $this->schema) {
$this->schema = new Type;
if ($this->buildSchema) {
($this->buildSchema)($this->schema);
}
}
return $this->schema;
}
public function scope($query, Context $context)
{
run_callbacks($this->getSchema()->getListeners('scope'), [$query, $context]);
}
public function filter($query, $filter, Context $context)
{
if (! is_array($filter)) {
throw new BadRequestException('filter must be an array', 'filter');
}
$schema = $this->getSchema();
$adapter = $this->getAdapter();
$filters = $schema->getFilters();
$fields = $schema->getFields();
foreach ($filter as $name => $value) {
if ($name === 'id') {
$adapter->filterByIds($query, explode(',', $value));
continue;
}
if (isset($filters[$name]) && evaluate($filters[$name]->getVisible(), [$context])) {
$filters[$name]->getCallback()($query, $value, $context);
continue;
}
if (isset($fields[$name]) && evaluate($fields[$name]->getFilterable(), [$context])) {
if ($fields[$name] instanceof Attribute) {
$this->filterByAttribute($adapter, $query, $fields[$name], $value);
} elseif ($fields[$name] instanceof HasOne) {
$value = array_filter(explode(',', $value));
$adapter->filterByHasOne($query, $fields[$name], $value);
} elseif ($fields[$name] instanceof HasMany) {
$value = array_filter(explode(',', $value));
$adapter->filterByHasMany($query, $fields[$name], $value);
}
continue;
}
throw new BadRequestException("Invalid filter [$name]", "filter[$name]");
}
}
private function filterByAttribute(AdapterInterface $adapter, $query, Attribute $attribute, $value)
{
if (preg_match('/(.+)\.\.(.+)/', $value, $matches)) {
if ($matches[1] !== '*') {
$adapter->filterByAttribute($query, $attribute, $value, '>=');
}
if ($matches[2] !== '*') {
$adapter->filterByAttribute($query, $attribute, $value, '<=');
}
return;
}
foreach (['>=', '>', '<=', '<'] as $operator) {
if (strpos($value, $operator) === 0) {
$adapter->filterByAttribute($query, $attribute, substr($value, strlen($operator)), $operator);
return;
}
}
$adapter->filterByAttribute($query, $attribute, $value);
}
}