Skip to content

Instantly share code, notes, and snippets.

@josecelano
Last active March 10, 2016 21:13
Show Gist options
  • Save josecelano/0f823445f3a6154397cb to your computer and use it in GitHub Desktop.
Save josecelano/0f823445f3a6154397cb to your computer and use it in GitHub Desktop.
<?php
final class GetProjectsController extends Controller
{
/**
* @var QueryObjectFactory
*/
private $queryObjectFactory;
/**
* @var ProjectFinder
*/
private $projectFinder;
/**
* GetProjectsController constructor.
* @param QueryObjectFactory $queryObjectFactory
* @param ProjectFinder $projectFinder
*/
public function __construct(
QueryObjectFactory $queryObjectFactory,
ProjectFinder $projectFinder
)
{
$this->queryObjectFactory = $queryObjectFactory;
$this->projectFinder = $projectFinder;
}
/**
* @param Request $request
* @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function __invoke(Request $request)
{
// Sample url: ...projects?filterByState=draft&orderById=desc&offset=1&limit=7
$projects = $this->projectFinder->execute($this->queryObjectFactory->fromArray($request->all()));
return view('crowdfunding::projects', ['projects' => $projects]);
}
}
class DBProjectFinder implements ProjectFinder
{
/**
* @var ProjectDtoAssembler
*/
private $projectDtoAssembler;
/**
* DBProjectFinder constructor.
* @param ProjectDtoAssembler $projectDtoAssembler
*/
public function __construct(ProjectDtoAssembler $projectDtoAssembler)
{
$this->projectDtoAssembler = $projectDtoAssembler;
}
/**
* @param QueryObject $queryObject
* @return ProjectDto[]
*/
public function execute(QueryObject $queryObject)
{
$projects = DB::table('projects');
foreach($queryObject->getCriteria() as $filter) {
$projects = $projects->where($filter->getFieldName(), $filter->getOperator(), $filter->getFieldValue());
}
foreach($queryObject->getOrders() as $order) {
$projects = $projects->orderBy($order->getFieldName(), $order->getType());
}
$projects = $projects->skip($queryObject->getOffset());
if ($queryObject->getLimit() != -1) {
$projects = $projects->take($queryObject->getLimit());
}
$projects = $projects->get();
return $this->projectDtoAssembler->toDtoArrayFromStdClass($projects);
}
}
class QueryObjectFactory
{
const FILTER_PARAM_PREFIX = 'filterBy';
const ORDER_PARAM_PREFIX = 'orderBy';
/**
* @param array $params
* @return QueryObject
*/
public function fromArray($params)
{
$query = new QueryObject();
foreach ($params as $field => $input) {
if ($this->inputFieldIsFilter($field)) {
$fieldName = $this->mapFieldNameFromInputFilter($field);
$query->addCriteria(Criteria::equalsTo($fieldName, $input));
continue;
}
if ($this->inputFieldIsOrder($field)) {
$fieldName = $this->mapFieldNameFromInputOrder($field);
$query->addOrder(Order::by($fieldName, $input));
continue;
}
}
$limit = isset($params['limit']) ? $params['limit'] : -1;
$offset = isset($params['offset']) ? $params['offset'] : 0;
$query->setLimitAndOffset($limit, $offset);
return $query;
}
/**
* @param $field
* @return bool
*/
private function inputFieldIsFilter($field)
{
return substr($field, 0, strlen(self::FILTER_PARAM_PREFIX)) == self::FILTER_PARAM_PREFIX;
}
/**
* @param $field
* @return bool
*/
private function inputFieldIsOrder($field)
{
return substr($field, 0, strlen(self::ORDER_PARAM_PREFIX)) == self::ORDER_PARAM_PREFIX;
}
/**
* @param $field
* @return string
*/
private function mapFieldNameFromInputFilter($field)
{
return strtolower(substr($field, strlen(self::FILTER_PARAM_PREFIX)));
}
/**
* @param $field
* @return string
*/
private function mapFieldNameFromInputOrder($field)
{
return strtolower(substr($field, strlen(self::ORDER_PARAM_PREFIX)));
}
}
class QueryObject
{
/**
* @var Criteria[]
*/
private $criteria;
/**
* @var Order[]
*/
private $orders;
/**
* @var int
*/
private $offset;
/**
* @var int
*/
private $limit;
/**
* QueryObject constructor.
*/
public function __construct()
{
$this->criteria = array();
$this->orders = array();
$this->offset = 0;
$this->limit = -1;
}
/**
* @param Criteria $criteria
* @return $this
*/
public function addCriteria(Criteria $criteria)
{
$this->criteria[] = $criteria;
return $this;
}
/**
* @param Order $order
* @return $this
*/
public function addOrder(Order $order)
{
$this->orders[] = $order;
return $this;
}
/**
* @param int $limit
* @param int $offset
* @return $this
* @throws \Exception
*/
public function setLimitAndOffset($limit, $offset)
{
Assertion::min($limit, -1);
Assertion::min($offset, 0);
if ($limit == -1 && $offset > 0) {
throw new \Exception('Offset requires limit > 0.');
}
$this->limit = $limit;
$this->offset = $offset;
return $this;
}
/**
* @return Criteria[]
*/
public function getCriteria()
{
return $this->criteria;
}
/**
* @return int
*/
public function getLimit()
{
return $this->limit;
}
/**
* @return int
*/
public function getOffset()
{
return $this->offset;
}
/**
* @return Order[]
*/
public function getOrders()
{
return $this->orders;
}
}
class Criteria
{
/**
* @var string
*/
private $fieldName;
/**
* @var string
*/
private $operator;
/**
* @var string
*/
private $fieldValue;
/**
* Filter constructor.
* @param string $fieldName
* @param string $operator
* @param string $fieldValue
*/
private function __construct($fieldName, $operator, $fieldValue)
{
$this->fieldName = $fieldName;
$this->operator = $operator;
$this->fieldValue = $fieldValue;
}
public static function equalsTo($fieldName, $filedValue)
{
return new self($fieldName, $filedValue, '=');
}
public static function greaterThan($fieldName, $filedValue)
{
return new self($fieldName, $filedValue, '>');
}
/**
* @return string
*/
public function getFieldName()
{
return $this->fieldName;
}
/**
* @return string
*/
public function getOperator()
{
return $this->operator;
}
/**
* @return string
*/
public function getFieldValue()
{
return $this->fieldValue;
}
}
class Order
{
const ASC = 'asc';
const DESC = 'desc';
/**
* @var string
*/
private $fieldName;
/**
* ASC|DESC
* @var string
*/
private $type;
/**
* Order constructor.
* @param string $fieldName
* @param string $type
*/
private function __construct($fieldName, $type)
{
// TODO: assert valid type;
$this->fieldName = $fieldName;
$this->type = $type;
}
public static function by($fieldName, $type)
{
return new self($fieldName, $type);
}
/**
* @return string
*/
public function getFieldName()
{
return $this->fieldName;
}
/**
* @return string
*/
public function getType()
{
return $this->type;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment