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

Feature/json api output #24

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ Homestead.json
/.vagrant
.phpunit.result.cache
coverage/
.php_cs.cache
.php_cs.cache
39 changes: 39 additions & 0 deletions src/Apitizer/JsonApi/Document.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

namespace Apitizer\JsonApi;

class Document
{
// /** @var ResourceObject[] */
// protected $includedResources = [];

/** @var ResourceObject[] */
protected $resources = [];

/** @var array */
protected $includes = [];

/**
* add a resource to the collection
* adds included resources if found inside the resource's relationships, unless $options['includeContainedResources'] is set to false.
*
* @param string $type
* @param string $id
* @param array $attributes optional, if given a ResourceObject is added, otherwise a ResourceIdentifierObject is added
*/
public function addResource(string $type, string $id, array $attributes = []): void
{
$object = ResourceObject::factory($attributes, $type, $id);

$this->resources[] = $object;
}

public function toArray(): array
{
$resources = collect($this->resources);

return $resources->count() == 1
? ['data' => $resources->first()->toArray()]
: ['data' => $resources->toArray()];
}
}
231 changes: 231 additions & 0 deletions src/Apitizer/JsonApi/ResourceObject.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
<?php

namespace Apitizer\JsonApi;

use Illuminate\Contracts\Support\Arrayable;

class ResourceObject implements Arrayable
{

/** @var array */
protected $attributes = [];

/** @var array */
protected $relationships;

/** @var string */
protected $type;

/** @var string */
protected $id;

public function __construct(string $type, string $id)
{
$this->type = $type;
$this->id = $id;
}

/**
* @param array $attributes
* @param string $type
* @param string $id
* @return ResourceObject
*/
public static function factory(array $attributes, string $type, string $id)
{
$resourceObject = new self($type, $id);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the contstructor? Or factory(ResourceObject::class)->create($attributes);

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

je can use the factory pattern also just for initing your object if you have some specific create logic you dont always want inside your constructor. I remember we had this discussion before ;)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We didn't finish that discussion

$resourceObject->attributes = $attributes;

return $resourceObject;
}

public function toArray(): array
{
$array = [];
$array['type'] = $this->type;
$array['id'] = $this->id;
if (! empty($this->attributes)) {
$array['attributes'] = $this->attributes;
}

// if ($this->meta !== null && $this->meta->isEmpty() === false) {
// $array['meta'] = $this->meta->toArray();
// }
// if ($this->relationships !== null && $this->relationships->isEmpty() === false) {
// $array['relationships'] = $this->relationships->toArray();
// }
// if ($this->links !== null && $this->links->isEmpty() === false) {
// $array['links'] = $this->links->toArray();
// }

return $array;
}


// /**
// * @param object $attributes
// * @param string $type optional
// * @param string|int $id optional
// * @param array $options optional {@see ResourceObject::$defaults}
// * @return ResourceObject
// */
// public static function fromObject($attributes, $type=null, $id=null, array $options=[]) {
// $array = Converter::objectToArray($attributes);

// return self::fromArray($array, $type, $id, $options);
// }

// /**
// * add key-value pairs to attributes
// *
// * @param string $key
// * @param mixed $value
// * @param array $options optional {@see ResourceObject::$defaults}
// */
// public function add($key, $value, array $options=[]) {
// $options = array_merge(self::$defaults, $options);

// if ($this->attributes === null) {
// $this->attributes = new AttributesObject();
// }

// $this->validator->claimUsedFields([$key], Validator::OBJECT_CONTAINER_ATTRIBUTES, $options);

// $this->attributes->add($key, $value);
// }

// /**
// * @param string $key
// * @param mixed $relation ResourceInterface | ResourceInterface[] | CollectionDocument
// * @param array $links optional
// * @param array $meta optional
// * @param array $options optional {@see ResourceObject::$defaults}
// * @return RelationshipObject
// */
// public function addRelationship($key, $relation, array $links=[], array $meta=[], array $options=[]) {
// $relationshipObject = RelationshipObject::fromAnything($relation, $links, $meta);

// $this->addRelationshipObject($key, $relationshipObject, $options);

// return $relationshipObject;
// }

// /**
// * @param string $href
// * @param array $meta optional, if given a LinkObject is added, otherwise a link string is added
// */
// public function setSelfLink($href, array $meta=[]) {
// $this->addLink('self', $href, $meta);
// }


// /**
// * @param string $key
// * @param RelationshipObject $relationshipObject
// * @param array $options optional {@see ResourceObject::$defaults}
// *
// * @throws DuplicateException if the resource is contained as a resource in the relationship
// */
// public function addRelationshipObject($key, RelationshipObject $relationshipObject, array $options=[]) {
// if ($relationshipObject->hasResource($this)) {
// throw new DuplicateException('can not add relation to self');
// }

// if ($this->relationships === null) {
// $this->setRelationshipsObject(new RelationshipsObject());
// }

// $this->validator->claimUsedFields([$key], Validator::OBJECT_CONTAINER_RELATIONSHIPS, $options);

// $this->relationships->addRelationshipObject($key, $relationshipObject);
// }

// /**
// * @param RelationshipsObject $relationshipsObject
// */
// public function setRelationshipsObject(RelationshipsObject $relationshipsObject) {
// $newKeys = $relationshipsObject->getKeys();
// $this->validator->clearUsedFields(Validator::OBJECT_CONTAINER_RELATIONSHIPS);
// $this->validator->claimUsedFields($newKeys, Validator::OBJECT_CONTAINER_RELATIONSHIPS);

// $this->relationships = $relationshipsObject;
// }

// /**
// * internal api
// */

// /**
// * whether the ResourceObject is empty except for the ResourceIdentifierObject
// *
// * this can be used to determine if a Relationship's resource could be added as included resource
// *
// * @internal
// *
// * @return boolean
// */
// public function hasIdentifierPropertiesOnly() {
// if ($this->attributes !== null && $this->attributes->isEmpty() === false) {
// return false;
// }
// if ($this->relationships !== null && $this->relationships->isEmpty() === false) {
// return false;
// }
// if ($this->links !== null && $this->links->isEmpty() === false) {
// return false;
// }

// return true;
// }

// /**
// * ResourceInterface
// */

// /**
// * @inheritDoc
// */
// public function getResource($identifierOnly=false) {
// if ($identifierOnly) {
// return ResourceIdentifierObject::fromResourceObject($this);
// }

// return $this;
// }

// /**
// * ObjectInterface
// */

// /**
// * @inheritDoc
// */
// public function isEmpty() {
// if (parent::isEmpty() === false) {
// return false;
// }
// if ($this->attributes !== null && $this->attributes->isEmpty() === false) {
// return false;
// }
// if ($this->relationships !== null && $this->relationships->isEmpty() === false) {
// return false;
// }
// if ($this->links !== null && $this->links->isEmpty() === false) {
// return false;
// }

// return true;
// }


// /**
// * @inheritDoc
// */
// public function getNestedContainedResourceObjects() {
// if ($this->relationships === null) {
// return [];
// }

// return $this->relationships->getNestedContainedResourceObjects();
// }
}
38 changes: 38 additions & 0 deletions src/Apitizer/Rendering/AbstractRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,51 @@

namespace Apitizer\Rendering;

use Apitizer\Exceptions\InvalidOutputException;
use Apitizer\Policies\PolicyFailed;
use Apitizer\QueryBuilder;
use Apitizer\Types\AbstractField;
use Apitizer\Types\Association;
use Apitizer\Types\Concerns\FetchesValueFromRow;
use Apitizer\Types\FetchSpec;
use Illuminate\Support\Arr;

abstract class AbstractRenderer
{
use FetchesValueFromRow;

/**
* @param QueryBuilder $queryBuilder
* @param mixed $data
* @param FetchSpec $fetchSpec
* @return array
*/
abstract public function render(QueryBuilder $queryBuilder, $data, FetchSpec $fetchSpec): array;

/**
* @param mixed $row
* @param AbstractField $field
* @param array<string, mixed> $renderedData
*
* @throws InvalidOutputException if the value does not adhere to the
* requirements set by the field. For example, if the field is not
* nullable but the value is null, this will throw an error. Enum
* field may also throw an error if the value is not in the enum.
*/
protected function addRenderedField(
$row,
AbstractField $field,
array &$renderedData
): void {
$value = $field->render($row);

if ($value instanceof PolicyFailed) {
return;
}

$renderedData[$field->getName()] = $value;
}

/**
* Check if we're dealing with a single row of data or a collection of rows.
*
Expand Down
Loading