Skip to content

Commit

Permalink
refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
Mohammad-Alavi committed Jan 31, 2025
1 parent 59a2505 commit 854df2a
Show file tree
Hide file tree
Showing 38 changed files with 724 additions and 904 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
"Apiato\\": "src/"
},
"files": [
"src/Support/helpers.php"
"src/Foundation/helpers.php"
]
},
"autoload-dev": {
Expand Down
151 changes: 149 additions & 2 deletions src/Abstract/Controllers/ApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,156 @@

namespace Apiato\Abstract\Controllers;

use Apiato\Foundation\Support\Traits\Response;
use Apiato\Abstract\Models\Model;
use Apiato\Abstract\Transformers\Transformer;
use Illuminate\Http\JsonResponse;
use Illuminate\Pagination\AbstractPaginator;
use Illuminate\Support\Collection;
use Spatie\Fractal\Facades\Fractal;

abstract class ApiController extends Controller
{
use Response;
protected array $metaData = [];

/**
* @param class-string<Transformer>|Transformer $transformerName
* @param string[] $includes
* @param string $resourceKey
*
* @return array|null
*/
public function transform(
$data,
$transformerName = null,
array $includes = [],
array $meta = [],
$resourceKey = null,
) {
$transformer = match (true) {
$transformerName instanceof Transformer => $transformerName,
default => new $transformerName(),
};

if (!$transformer instanceof Transformer) {
throw new \RuntimeException('Invalid transformer.');
}

// add specific meta information to the response message
$this->metaData = array_merge($this->metaData, [
'include' => $transformer->getAvailableIncludes(),
'custom' => $meta,
]);

// no resource key was set
if (!$resourceKey) {
// get the resource key from the model
$obj = null;
if ($data instanceof AbstractPaginator) {
$obj = $data->getCollection()->first();
} elseif ($data instanceof Collection) {
$obj = $data->first();
} elseif (is_array($data) && [] !== $data) {
$obj = $data[0];
} else {
$obj = $data;
}

// if we have an object, try to get its resourceKey
if ($obj) {
$resourceKey = $obj->getResourceKey();
}
}

$fractal = Fractal::create($data, $transformer)->withResourceName($resourceKey)->addMeta($this->metaData);

// read includes passed via query params in url
$requestIncludes = $this->parseRequestedIncludes();

// merge the requested includes with the one added by the transform() method itself
$requestIncludes = array_unique(array_merge($includes, $requestIncludes));

// and let fractal include everything
$fractal->parseIncludes($requestIncludes);

// apply request filters if available in the request
if ($requestFilters = request()?->input(config('apiato.requests.params.filter', 'filter'))) {
$result = $this->filterResponse($fractal->toArray(), explode(';', (string) $requestFilters));
} else {
$result = $fractal->toArray();
}

return $result;
}

protected function parseRequestedIncludes(): array
{
return explode(',', request()?->input('include') ?? '');
}

private function filterResponse(array $responseArray, array $filters): array
{
foreach ($responseArray as $k => $v) {
if (in_array($k, $filters, true)) {
// we have found our element - so continue with the next one
continue;
}

if (is_array($v)) {
// it is an array - so go one step deeper
$v = $this->filterResponse($v, $filters);
if (empty($v)) {
// it is an empty array - delete the key as well
unset($responseArray[$k]);
} else {
$responseArray[$k] = $v;
}
} elseif (!in_array($k, $filters)) {
// check if the array is not in our filter-list
unset($responseArray[$k]);
}
}

return $responseArray;
}

public function withMeta($data): self
{
$this->metaData = $data;

return $this;
}

public function json($data, $status = 200, array $headers = [], $options = 0): JsonResponse
{
return new JsonResponse($data, $status, $headers, $options);
}

public function created($data = null, $status = 201, array $headers = [], $options = 0): JsonResponse
{
return new JsonResponse($data, $status, $headers, $options);
}

public function deleted(Model|null $deletedModel = null): JsonResponse
{
if (!$deletedModel instanceof Model) {
return $this->accepted();
}

$id = $deletedModel->getHashedKey();
$className = (new \ReflectionClass($deletedModel))->getShortName();

return $this->accepted([
'message' => "$className ($id) Deleted Successfully.",
]);
}

public function accepted($data = null, $status = 202, array $headers = [], $options = 0): JsonResponse
{
return new JsonResponse($data, $status, $headers, $options);
}

public function noContent($status = 204): JsonResponse
{
return new JsonResponse(null, $status);
}
}
Loading

0 comments on commit 854df2a

Please sign in to comment.