235 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			235 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| 
 | |
| /*
 | |
|  * This file is part of JSON-API.
 | |
|  *
 | |
|  * (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 Tobscure\JsonApi;
 | |
| 
 | |
| use JsonSerializable;
 | |
| 
 | |
| class Document implements JsonSerializable
 | |
| {
 | |
|     use LinksTrait;
 | |
|     use MetaTrait;
 | |
| 
 | |
|     const MEDIA_TYPE = 'application/vnd.api+json';
 | |
| 
 | |
|     /**
 | |
|      * The included array.
 | |
|      *
 | |
|      * @var array
 | |
|      */
 | |
|     protected $included = [];
 | |
| 
 | |
|     /**
 | |
|      * The errors array.
 | |
|      *
 | |
|      * @var array
 | |
|      */
 | |
|     protected $errors;
 | |
| 
 | |
|     /**
 | |
|      * The jsonapi array.
 | |
|      *
 | |
|      * @var array
 | |
|      */
 | |
|     protected $jsonapi;
 | |
| 
 | |
|     /**
 | |
|      * The data object.
 | |
|      *
 | |
|      * @var ElementInterface
 | |
|      */
 | |
|     protected $data;
 | |
| 
 | |
|     /**
 | |
|      * @param ElementInterface $data
 | |
|      */
 | |
|     public function __construct(ElementInterface $data = null)
 | |
|     {
 | |
|         $this->data = $data;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Get included resources.
 | |
|      *
 | |
|      * @param \Tobscure\JsonApi\ElementInterface $element
 | |
|      * @param bool $includeParent
 | |
|      *
 | |
|      * @return \Tobscure\JsonApi\Resource[]
 | |
|      */
 | |
|     protected function getIncluded(ElementInterface $element, $includeParent = false)
 | |
|     {
 | |
|         $included = [];
 | |
| 
 | |
|         foreach ($element->getResources() as $resource) {
 | |
|             if ($resource->isIdentifier()) {
 | |
|                 continue;
 | |
|             }
 | |
| 
 | |
|             if ($includeParent) {
 | |
|                 $included = $this->mergeResource($included, $resource);
 | |
|             } else {
 | |
|                 $type = $resource->getType();
 | |
|                 $id = $resource->getId();
 | |
|             }
 | |
| 
 | |
|             foreach ($resource->getUnfilteredRelationships() as $relationship) {
 | |
|                 $includedElement = $relationship->getData();
 | |
| 
 | |
|                 if (! $includedElement instanceof ElementInterface) {
 | |
|                     continue;
 | |
|                 }
 | |
| 
 | |
|                 foreach ($this->getIncluded($includedElement, true) as $child) {
 | |
|                     // If this resource is the same as the top-level "data"
 | |
|                     // resource, then we don't want it to show up again in the
 | |
|                     // "included" array.
 | |
|                     if (! $includeParent && $child->getType() === $type && $child->getId() === $id) {
 | |
|                         continue;
 | |
|                     }
 | |
| 
 | |
|                     $included = $this->mergeResource($included, $child);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         $flattened = [];
 | |
| 
 | |
|         array_walk_recursive($included, function ($a) use (&$flattened) {
 | |
|             $flattened[] = $a;
 | |
|         });
 | |
| 
 | |
|         return $flattened;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * @param \Tobscure\JsonApi\Resource[] $resources
 | |
|      * @param \Tobscure\JsonApi\Resource $newResource
 | |
|      *
 | |
|      * @return \Tobscure\JsonApi\Resource[]
 | |
|      */
 | |
|     protected function mergeResource(array $resources, Resource $newResource)
 | |
|     {
 | |
|         $type = $newResource->getType();
 | |
|         $id = $newResource->getId();
 | |
| 
 | |
|         if (isset($resources[$type][$id])) {
 | |
|             $resources[$type][$id]->merge($newResource);
 | |
|         } else {
 | |
|             $resources[$type][$id] = $newResource;
 | |
|         }
 | |
| 
 | |
|         return $resources;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Set the data object.
 | |
|      *
 | |
|      * @param \Tobscure\JsonApi\ElementInterface $element
 | |
|      *
 | |
|      * @return $this
 | |
|      */
 | |
|     public function setData(ElementInterface $element)
 | |
|     {
 | |
|         $this->data = $element;
 | |
| 
 | |
|         return $this;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Set the errors array.
 | |
|      *
 | |
|      * @param array $errors
 | |
|      *
 | |
|      * @return $this
 | |
|      */
 | |
|     public function setErrors($errors)
 | |
|     {
 | |
|         $this->errors = $errors;
 | |
| 
 | |
|         return $this;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Set the jsonapi array.
 | |
|      *
 | |
|      * @param array $jsonapi
 | |
|      *
 | |
|      * @return $this
 | |
|      */
 | |
|     public function setJsonapi($jsonapi)
 | |
|     {
 | |
|         $this->jsonapi = $jsonapi;
 | |
| 
 | |
|         return $this;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Map everything to arrays.
 | |
|      *
 | |
|      * @return array
 | |
|      */
 | |
|     public function toArray()
 | |
|     {
 | |
|         $document = [];
 | |
| 
 | |
|         if (! empty($this->links)) {
 | |
|             $document['links'] = $this->links;
 | |
|         }
 | |
| 
 | |
|         if (! empty($this->data)) {
 | |
|             $document['data'] = $this->data->toArray();
 | |
| 
 | |
|             $resources = $this->getIncluded($this->data);
 | |
| 
 | |
|             if (count($resources)) {
 | |
|                 $document['included'] = array_map(function (Resource $resource) {
 | |
|                     return $resource->toArray();
 | |
|                 }, $resources);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         if (! empty($this->meta)) {
 | |
|             $document['meta'] = $this->meta;
 | |
|         }
 | |
| 
 | |
|         if (! empty($this->errors)) {
 | |
|             $document['errors'] = $this->errors;
 | |
|         }
 | |
| 
 | |
|         if (! empty($this->jsonapi)) {
 | |
|             $document['jsonapi'] = $this->jsonapi;
 | |
|         }
 | |
| 
 | |
|         return $document;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Map to string.
 | |
|      *
 | |
|      * @return string
 | |
|      */
 | |
|     public function __toString()
 | |
|     {
 | |
|         return json_encode($this->toArray());
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Serialize for JSON usage.
 | |
|      *
 | |
|      * @return array
 | |
|      */
 | |
|     #[\ReturnTypeWillChange]
 | |
|     public function jsonSerialize()
 | |
|     {
 | |
|         return $this->toArray();
 | |
|     }
 | |
| }
 |