skqr/hateoas

View on GitHub
JsonApi/Request/LinkBodyParser.php

Summary

Maintainability
A
2 hrs
Test Coverage
<?php
/**
 * @copyright 2014 Integ S.A.
 * @license http://opensource.org/licenses/MIT The MIT License (MIT)
 * @author Javier Lorenzana <javier.lorenzana@gointegro.com>
 */

namespace GoIntegro\Hateoas\JsonApi\Request;

// HTTP.
use Symfony\Component\HttpFoundation\Request;
// JSON.
use GoIntegro\Hateoas\Util;
// Collections.
use Doctrine\Common\Collections\Collection;

/**
 * @see http://jsonapi.org/format/#crud-updating
 */
class LinkBodyParser implements BodyParserInterface
{
    const LINKS = 'links';

    const ERROR_EMPTY_BODY = "The resource data was not found on the body.",
        ERROR_RELATIONSHIP_TYPE = "The type of the relationship Ids is unexpected",
        ERROR_RELATIONSHIP_EXISTS = "The relationships \"%s\" already exist.",
        ERROR_RELATIONSHIPS_NOT_FOUND = "The relationships \"%s\" were not found.",
        ERROR_RELATIONSHIP_NOT_FOUND = "The relationship was not found.";

    /**
     * @param Request $request
     * @param Params $params
     * @param array $body
     * @return array
     * @todo Sólo sirve para actualizar ahora.
     */
    public function parse(Request $request, Params $params, array $body)
    {
        $entity = $params->entities->primary->first();
        $ids = NULL;

        // @todo Encapsulate.
        $method = 'get' . Util\Inflector::camelize($params->relationship);
        $relation = $entity->$method();

        if ($relation instanceof Collection) {
            $relation = $relation->toArray();
        }

        if (in_array($params->action->name, [
            RequestAction::ACTION_CREATE, RequestAction::ACTION_UPDATE
        ])) {
            if (!is_array($body) || !isset($body[$params->relationship])) {
                throw new ParseException(self::ERROR_EMPTY_BODY);
            }

            $ids = $body[$params->relationship];

            if (RequestAction::ACTION_CREATE == $params->action->name) {
                $ids = $this->parseCreateAction($ids, $relation);
            }
        }

        $entityData = [
            (string) $entity->getId() => [
                self::LINKS => [
                    $params->relationship => $ids
                ]
            ]
        ];

        return $entityData;
    }

    /**
     * @param mixed $ids
     * @param array $relation
     * @return mixed
     * @throws ParseException
     * @throws ExistingRelationshipException
     */
    protected function parseCreateAction($ids, array $relation)
    {
        if (is_array($ids)) {
            if (!is_array($relation)) {
                throw new ParseException(
                    self::ERROR_RELATIONSHIP_TYPE
                );
            }

            $callback = function($entity) {
                return (string) $entity->getId();
            };
            $current = array_map($callback, $relation);
            $intersection = array_intersect($ids, $current);

            if (!empty($intersection)) {
                $existing = implode('", "', $intersection);
                $message = sprintf(self::ERROR_RELATIONSHIP_EXISTS, $existing);
                throw new ExistingRelationshipException($message);
            }

            $ids = array_merge($current, $ids);
        } elseif (is_string($ids) && !empty($relation)) {
            $message = sprintf(self::ERROR_RELATIONSHIP_EXISTS, $ids);
            throw new ExistingRelationshipException($message);
        } elseif (!is_string($ids)) {
            throw new ParseException(self::ERROR_RELATIONSHIP_TYPE);
        }

        return $ids;
    }
}