|
<?php |
|
|
|
use Phalcon\Mvc\Controller; |
|
use Phalcon\Mvc\Dispatcher; |
|
use Phalcon\Mvc\DispatcherInterface; |
|
use Phalcon\Mvc\Model\CriteriaInterface; |
|
use Phalcon\Mvc\ModelInterface; |
|
use Phalcon\Mvc\View; |
|
|
|
abstract class RestController extends Controller |
|
{ |
|
/** |
|
* If the controller is in an error state |
|
* This should be set to true if an exception is uncaught by the called action |
|
* @var bool |
|
*/ |
|
private $isErrored = false; |
|
|
|
protected function initialize() |
|
{ |
|
// Use a custom handler for any exceptions thrown from this controller type |
|
$this->eventsManager->attach('dispatch:beforeException', $this); |
|
} |
|
|
|
/** |
|
* Get the search/query/filter from the request |
|
* @return string |
|
*/ |
|
public function getQuery() |
|
{ |
|
return $this->request->get('q', 'trim'); |
|
} |
|
|
|
/** |
|
* Get the offset to return from relative to the start of the result set |
|
* @return int |
|
*/ |
|
public function getOffset() |
|
{ |
|
return (int) $this->request->get('offset'); |
|
} |
|
|
|
/** |
|
* Get the maximum number of results the request should return |
|
* @return int |
|
*/ |
|
public function getLimit() |
|
{ |
|
return (int) $this->request->get('limit'); |
|
} |
|
|
|
/** |
|
* @param CriteriaInterface $query |
|
* @return \Phalcon\Mvc\Model\CriteriaInterface |
|
*/ |
|
protected function applyLimitsToQuery(CriteriaInterface $query) |
|
{ |
|
if ($this->getLimit()) { |
|
$query->limit($this->getLimit(), $this->getOffset()); |
|
} |
|
return $query; |
|
} |
|
|
|
/** |
|
* Wrap all results and send to client encoded as JSON |
|
* @param DispatcherInterface $dispatcher |
|
*/ |
|
public function afterExecuteRoute(DispatcherInterface $dispatcher) |
|
{ |
|
$result = $dispatcher->getReturnedValue(); |
|
|
|
// Don't attempt to transform the response as it wasn't completed |
|
if ($this->isErrored) { |
|
return; |
|
} |
|
|
|
// Expand query objects into arrays |
|
if ($result instanceof CriteriaInterface) { |
|
$result = $result->execute()->toArray(); |
|
} |
|
|
|
// Transform a model return value to an array of fields |
|
if ($result instanceof ModelInterface) { |
|
$result = $result->toArray(); |
|
} |
|
|
|
// Only accept arrays and scalars to send to the client |
|
if (!is_array($result) && !is_scalar($result) && !is_null($result)) { |
|
$this->sendException( |
|
new \RuntimeException(sprintf( |
|
'Expected array or scalar return type from controller. Got %s instead', |
|
is_object($result) ? get_class($result) : gettype($result) |
|
)) |
|
); |
|
} |
|
|
|
$output = [ |
|
'result' => $result |
|
]; |
|
|
|
$this->send($output); |
|
} |
|
|
|
public function beforeException(\Phalcon\Events\Event $event, Dispatcher $dispatcher, \Exception $exception) |
|
{ |
|
$this->isErrored = true; |
|
$this->sendException($exception); |
|
return false; |
|
} |
|
|
|
protected function sendAccessDenied() |
|
{ |
|
$this->isErrored = true; |
|
$this->response->setStatusCode(403, 'Access denied'); |
|
|
|
$this->send([ |
|
'error' => true, |
|
'message' => 'You don\'t have permission to access that resource.' |
|
]); |
|
} |
|
|
|
protected function sendNotFound() |
|
{ |
|
$this->isErrored = true; |
|
$this->response->setStatusCode(404, 'Resource not found'); |
|
|
|
$this->send([ |
|
'error' => true, |
|
'message' => 'No resource found' |
|
]); |
|
} |
|
|
|
protected function checkSecurityToken() |
|
{ |
|
$token = $this->request->getPost('token'); |
|
|
|
if ($token && $token === $this->security->getSessionToken()) { |
|
return true; |
|
} |
|
|
|
$this->isErrored = true; |
|
$this->response->setStatusCode(400, 'Invalid security token'); |
|
|
|
$this->send([ |
|
'error' => true, |
|
'code' => 'bad-token', |
|
'message' => 'Invalid security token' |
|
]); |
|
|
|
return false; |
|
} |
|
|
|
private function sendException(\Exception $exception) |
|
{ |
|
$this->response->setStatusCode(500, 'Server error'); |
|
|
|
if (DEV_MODE) { |
|
$this->send([ |
|
'error' => true, |
|
'message' => $exception->getMessage(), |
|
'trace' => $exception->getTraceAsString() |
|
]); |
|
} else { |
|
$this->send([ |
|
'error' => true, |
|
'message' => 'The server encountered a fatal error trying to process your request.' |
|
]); |
|
|
|
// Log the exception with your own logger here if needed |
|
} |
|
} |
|
|
|
|
|
/** |
|
* Put data in the response as JSON |
|
* @param mixed $output |
|
*/ |
|
private function send($output) |
|
{ |
|
$this->view->setRenderLevel(View::LEVEL_NO_RENDER); |
|
$this->response->setContentType('application/json'); |
|
|
|
$opts = DEV_MODE ? JSON_PRETTY_PRINT : 0; |
|
$json = json_encode($output, $opts); |
|
|
|
if (json_last_error() !== JSON_ERROR_NONE) { |
|
throw new \RuntimeException('Failed to convert server response to JSON: ' . json_last_error_msg()); |
|
} |
|
|
|
$this->response->setContent($json); |
|
$this->response->send(); |
|
} |
|
} |
Hi, I am new to phalcon, but need this kind of generic rest controller badly, because I really don't want to copy-paste code for every entity. Unfortunatelly I wasn't able to run your example: i just see a white screen. Can you please provide an example how to run it from index.php?