Skip to content

Commit

Permalink
Moving the ActionParser.
Browse files Browse the repository at this point in the history
  • Loading branch information
Javier Lorenzana committed Nov 22, 2014
1 parent 65dd370 commit f6983f9
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 49 deletions.
81 changes: 56 additions & 25 deletions JsonApi/Request/ActionParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,15 @@
// Recursos.
use GoIntegro\Bundle\HateoasBundle\JsonApi\DocumentPagination;
// JSON.
use GoIntegro\Bundle\HateoasBundle\Util\JsonCoder;
use GoIntegro\Bundle\HateoasBundle\Util;

/**
* @see http://jsonapi.org/format/#introduction
*/
class ActionParser
{
const ERROR_REQUEST_SCOPE_UNKNOWN = "Could not calculate request scope; whether it affects one or many resources.";
const ERROR_REQUEST_SCOPE_UNKNOWN = "Could not calculate request scope; whether it affects one or many resources.",
ERROR_RESOURCE_CONTENT_MISSING = "The primary resource data is missing from the body.";

/**
* @var array This mapping is defined by JSON-API, not HTTP nor REST.
Expand All @@ -32,6 +33,19 @@ class ActionParser
Parser::HTTP_DELETE => RequestAction::ACTION_DELETE
];

/**
* @var Util\JsonCoder
*/
protected $jsonCoder;

/**
* @param Util\JsonCoder $jsonCoder
*/
public function __construct(Util\JsonCoder $jsonCoder)
{
$this->jsonCoder = $jsonCoder;
}

/**
* @param Request $request
* @param Params $params
Expand All @@ -42,7 +56,7 @@ public function parse(Request $request, Params $params)
$action = new RequestAction;

$action->name = self::$methodToAction[$request->getMethod()];
$action->type = $this->isMultipleAction($params, $action)
$action->type = $this->isMultipleAction($request, $params, $action)
? RequestAction::TYPE_MULTIPLE
: RequestAction::TYPE_SINGLE;
$action->target = !empty($params->relationship)
Expand All @@ -53,15 +67,18 @@ public function parse(Request $request, Params $params)
}

/**
* @param Request $request
* @param Params $params
* @param RequestAction $action
* @return boolean
* @throws ParseException
*/
private function isMultipleAction(Params $params, RequestAction $action)
private function isMultipleAction(
Request $request, Params $params, RequestAction $action)
{
return $this->isFilteredFetch($params, $action)
|| 1 < count($this->getCountable($params, $action));
|| $this->isIdParamAList($params, $action)
|| $this->isPrimaryResourceAList($request, $params, $action);
}

/**
Expand All @@ -78,35 +95,49 @@ private function isFilteredFetch(Params $params, RequestAction $action)
/**
* @param Params $params
* @param RequestAction $action
* @return array
* @throws ParseException
* @return boolean
*/
private function getCountable(Params $params, RequestAction $action)
private function isIdParamAList(Params $params, RequestAction $action)
{
if (
in_array(
return in_array(
$action->name,
[
RequestAction::ACTION_FETCH,
RequestAction::ACTION_UPDATE,
RequestAction::ACTION_DELETE
]
)
&& !empty($params->primaryIds)
) {
return $params->primaryIds;
} elseif (
RequestAction::ACTION_CREATE === $action->name
&& !empty($params->resources)
) {
return $params->resources;
} elseif (
RequestAction::ACTION_UPDATE === $action->name
&& !empty($params->entities)
) {
return $params->entities;
} else {
throw new ParseException(self::ERROR_REQUEST_SCOPE_UNKNOWN);
&& 1 < count($params->primaryIds);
}

/**
* @param Request $request
* @param Params $params
* @param RequestAction $action
* @return boolean
* @throws ParseException
*/
private function isPrimaryResourceAList(
Request $request, Params $params, RequestAction $action
)
{
$json = $request->getContent();

if (in_array($action->name, [
RequestAction::ACTION_CREATE, RequestAction::ACTION_UPDATE
])) {
$data = $this->jsonCoder->decode($json);

if (!is_array($data) || !isset($data[$params->primaryType])) {
throw new ParseException(self::ERROR_RESOURCE_CONTENT_MISSING);
}

return !Util\ArrayHelper::isAssociative(
$data[$params->primaryType]
);
}


return FALSE;
}
}
25 changes: 8 additions & 17 deletions JsonApi/Request/CreateBodyParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@

// HTTP.
use Symfony\Component\HttpFoundation\Request;
// JSON.
use GoIntegro\Bundle\HateoasBundle\Util\JsonCoder;
// Utils.
use GoIntegro\Bundle\HateoasBundle\Util;

/**
* @see http://jsonapi.org/format/#crud-creating-resources
Expand All @@ -21,14 +21,14 @@ class CreateBodyParser
const ERROR_ID_NOT_SUPPORTED = "Providing an Id on creation is not supported magically yet.";

/**
* @var JsonCoder
* @var Util\JsonCoder
*/
protected $jsonCoder;

/**
* @param JsonCoder $jsonCoder
* @param Util\JsonCoder $jsonCoder
*/
public function __construct(JsonCoder $jsonCoder)
public function __construct(Util\JsonCoder $jsonCoder)
{
$this->jsonCoder = $jsonCoder;
}
Expand All @@ -46,7 +46,9 @@ public function parse(Request $request, Params $params)

if (empty($data[$params->primaryType])) {
throw new ParseException(static::ERROR_PRIMARY_TYPE_KEY);
} elseif ($this->isAssociative($data[$params->primaryType])) {
} elseif (
Util\ArrayHelper::isAssociative($data[$params->primaryType])
) {
if (isset($data[$params->primaryType]['id'])) {
throw new ParseException(static::ERROR_ID_NOT_SUPPORTED);
} else {
Expand All @@ -64,15 +66,4 @@ public function parse(Request $request, Params $params)

return $entityData;
}

/**
* @param array $array
* @return boolean
* @todo Move to helper in utils.
* @see http://stackoverflow.com/a/173479
*/
private function isAssociative(array $array)
{
return array_keys($array) !== range(0, count($array) - 1);
}
}
5 changes: 2 additions & 3 deletions JsonApi/Request/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -155,15 +155,14 @@ public function parse(Request $request)
}

$params->filters = $this->filterParser->parse($request, $params);
$params->action = $this->actionParser->parse($request, $params);
$content = $request->getContent();

if (!empty($content)) {
// Needs the params from the ActionParser.
$params->resources = $this->bodyParser->parse($request, $params);
}

// Needs the params from the BodyParser.
$params->action = $this->actionParser->parse($request, $params);

if (!empty($params->primaryIds)) {
// Needs the params from the ActionParser.
$params->entities = $this->entityFinder->find($params);
Expand Down
2 changes: 2 additions & 0 deletions Resources/config/services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ services:
hateoas.request_parser.action:
class: GoIntegro\Bundle\HateoasBundle\JsonApi\Request\ActionParser
public: false
arguments:
- @hateoas.json_coder

hateoas.request_parser.entities:
class: GoIntegro\Bundle\HateoasBundle\JsonApi\Request\ParamEntityFinder
Expand Down
9 changes: 5 additions & 4 deletions Tests/JsonApi/Request/ActionParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,9 @@ public function testParsingSingleUpdateActionRequest()
$queryOverrides = [
'getContent' => function() { return self::UPDATE_BODY; }
];
$entity = Stub::makeEmpty(
'GoIntegro\\Bundle\\HateoasBundle\\JsonApi\\ResourceEntityInterface'
$jsonCoder = Stub::makeEmpty(
'GoIntegro\\Bundle\\HateoasBundle\\Util\\JsonCoder',
['decode' => json_decode(self::HTTP_PUT_BODY, TRUE)]
);
$request = self::createRequest(
'/api/v1/users',
Expand All @@ -49,10 +50,10 @@ public function testParsingSingleUpdateActionRequest()
'GoIntegro\\Bundle\\HateoasBundle\\JsonApi\\Request\\Params',
[
'primaryIds' => ['27'],
'entities' => [$entity]
'primaryType' => 'users'
]
);
$parser = new ActionParser;
$parser = new ActionParser($jsonCoder);
// When...
$action = $parser->parse($request, $params);
// Then...
Expand Down
22 changes: 22 additions & 0 deletions Util/ArrayHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php
/**
* @copyright 2014 Integ S.A.
* @license http://opensource.org/licenses/MIT The MIT License (MIT)
* @author Javier Lorenzana <[email protected]>
*/

namespace GoIntegro\Bundle\HateoasBundle\Util;

class ArrayHelper
{
/**
* @param array $array
* @return boolean
* @todo Move to helper in utils.
* @see http://stackoverflow.com/a/173479
*/
public function isAssociative(array $array)
{
return array_keys($array) !== range(0, count($array) - 1);
}
}

0 comments on commit f6983f9

Please sign in to comment.