Last active
March 10, 2016 21:13
-
-
Save josecelano/0f823445f3a6154397cb to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?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