Skip to content

Instantly share code, notes, and snippets.

@ABM-Dan
Forked from tarlepp/AuthorController.php
Last active September 22, 2016 18:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ABM-Dan/845054491eb0861dcfe53bb5889cd0b3 to your computer and use it in GitHub Desktop.
Save ABM-Dan/845054491eb0861dcfe53bb5889cd0b3 to your computer and use it in GitHub Desktop.
<?php
/**
* /src/App/Controller/AuthorController.php
*
* @author TLe, Tarmo Leppänen <tarmo.leppanen@protacon.com>
*/
namespace App\Controller;
use App\Services\Rest\Author;
use App\Services\Rest\Helper\Request;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Symfony\Component\HttpFoundation\Request as HttpFoundationRequest;
use Symfony\Component\HttpFoundation\Response as HttpFoundationResponse;
/**
* Class AuthorController
*
* @Route(service="app.controller.author", path="/author")
*
* @Security("is_granted('IS_AUTHENTICATED_FULLY')")
*
* @method Author getService()
*
* @package App\Controller
* @author TLe, Tarmo Leppänen <tarmo.leppanen@protacon.com>
*/
class AuthorController // no extension??
{
/**
* @var Author
*/
protected $resourceService;
public function __construct(Author $authorService)
{
$this->resourceService = $authorService;
}
/**
* Find method for Author resource.
*
* @Route("")
* @Route("/")
*
* @Method({"GET"})
*
* @Security("has_role('ROLE_USER')")
*
* @return HttpFoundationResponse
*/
public function find(HttpFoundationRequest $request)
{
// Determine used parameters
$criteria = Request::getCriteria($request);
$orderBy = Request::getOrderBy($request);
$limit = Request::getLimit($request);
$offset = Request::getOffset($request);
$search = Request::getSearchTerms($request);
if (method_exists($this, 'processCriteria')) {
$this->processCriteria($criteria);
}
// Fetch data from database
// where is this method??
$data = $this->getService()->find($criteria, $orderBy, $limit, $offset, $search);
return new HttpFoundationResponse('test');
}
/**
* Generic 'count' method for REST endpoints.
*
* @Route("/count")
*
* @Method({"GET"})
*
* @Security("has_role('ROLE_USER')")
*
* @return HttpFoundationResponse
*/
public function count(HttpFoundationRequest $request)
{
// Determine used parameters
$criteria = Request::getCriteria($request);
$search = Request::getSearchTerms($request);
if (method_exists($this, 'processCriteria')) {
$this->processCriteria($criteria);
}
$data = [
'count' => $this->resourceService->count($criteria, $search),
];
return new HttpFoundationResponse(json_encode($data));
}
}
<?php
namespace App\Services\Rest\Helper;
use App\Utils\JSON;
use Symfony\Component\HttpFoundation\Request as HttpFoundationRequest;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\HttpException;
abstract class Request
{
/**
* Method to get used criteria array for 'find' method.
*
* @param HttpFoundationRequest $request
*
* @return array
*/
public static function getCriteria(HttpFoundationRequest $request)
{
try {
$userInput = array_filter(JSON::decode($request->get('where', '{}'), true));
} catch (\LogicException $error) {
throw new HttpException(Response::HTTP_BAD_REQUEST, 'Current \'where\' parameter is not valid JSON.');
}
return $userInput;
}
/**
* Getter method for used order by option within 'find' method. Some examples below.
*
* @param HttpFoundationRequest $request
*
* Basic usage:
* ?order=column1 => ORDER BY column1 ASC
* ?order=-column1 => ORDER BY column2 DESC
*
* Array parameter usage:
* ?order[column1]=ASC => ORDER BY column1 ASC
* ?order[column1]=DESC => ORDER BY column1 DESC
* ?order[column1]=foobar => ORDER BY column1 ASC
* ?order[column1]=DESC&orderBy[column2]=DESC => ORDER BY column1 DESC, column2 DESC
*
* @return null|array
*/
public static function getOrderBy(HttpFoundationRequest $request)
{
// Normalize parameter value
$input = array_filter((array)$request->get('order', []));
// Initialize output
$output = [];
/**
* Lambda function to process user input for 'order' parameter and convert it to proper array that
* Doctrine repository find method can use.
*
* @param string $value
* @param integer|string $key
*/
$iterator = function (&$value, $key) use (&$output) {
$order = 'ASC';
if (is_string($key)) {
$column = $key;
$order = in_array(strtoupper($value), ['ASC', 'DESC']) ? strtoupper($value) : $order;
} else {
$column = $value;
}
if ($column[0] === '-') {
$column = substr($column, 1);
$order = 'DESC';
}
$output[$column] = $order;
};
// Process user input
array_walk($input, $iterator);
return count($output) > 0 ? $output : null;
}
/**
* Getter method for used limit option within 'find' method.
*
* @param HttpFoundationRequest $request
*
* @return null|integer
*/
public function getLimit(HttpFoundationRequest $request)
{
return $request->get('limit', null);
}
/**
* Getter method for used offset option within 'find' method.
*
* @return null|integer
*/
public function getOffset(HttpFoundationRequest $request)
{
return $request->get('offset', null);
}
/**
* Getter method for used search terms within 'find' method.
*
* @param HttpFoundationRequest $request
*
* @todo improve docs about different use cases.
*
* @see \App\Repository\Base::processSearchTerms
*
* @return null|string[]
*/
public function getSearchTerms(HttpFoundationRequest $request)
{
$search = $request->get('search', null);
if (!is_null($search)) {
try {
$input = JSON::decode($search, true);
if (!array_key_exists('and', $input) && !array_key_exists('or', $input)) {
throw new HttpException(
Response::HTTP_BAD_REQUEST,
'Given search parameter is not valid, within JSON provide \'and\' and/or \'or\' property.'
);
}
/**
* Lambda function to normalize JSON search terms.
*
* @param string|array $terms
*/
$iterator = function (&$terms) {
if (!is_array($terms)) {
$terms = explode(' ', (string)$terms);
}
$terms = array_unique(array_filter($terms));
};
// Normalize user input, note that this support array and string formats on value
array_walk($input, $iterator);
$search = $input;
} catch (\LogicException $error) {
// By default we want to use 'OR' operand with given search words.
$search = [
'or' => array_unique(array_filter(explode(' ', $search)))
];
}
}
return $search;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment