Last active
May 6, 2020 14:36
-
-
Save WinterSilence/43ae6cc5b102ee0500de5c81d88dbf13 to your computer and use it in GitHub Desktop.
Kohana/Koseven/KO7 CRUD controller
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 | |
/** | |
* CRUD controller. | |
* | |
* @link https://en.wikipedia.org/wiki/Create,_read,_update_and_delete CRUD | |
* @link https://koseven.dev/documentation/kohana/tutorials/basic-controller Controller_Base | |
*/ | |
class Controller_CRUD extends Controller_Base | |
{ | |
/** | |
* @var string|ORM model name or ORM instance | |
*/ | |
protected $model; | |
/** | |
* Short-hand for create HTTP exception. | |
* | |
* @param int $code HTTP error code | |
* @param string|array $message Error or `[error, variables]` | |
* @param Throwable|null $previous Previous exception | |
* @return HTTP_Exception | |
*/ | |
protected function http_exception(int $code, $message, Throwable $previous = null): HTTP_Exception | |
{ | |
$variables = null; | |
if (is_array($message)) { | |
[$message, $variables] = $message; | |
} | |
return HTTP_Exception::factory($code, $message, $variables, $previous)->request($this->request); | |
} | |
/** | |
* Short-hand for create URI by route of current request. | |
* | |
* @param array $params Route parameters | |
* @return string | |
*/ | |
protected function uri(array $params = []): string | |
{ | |
$params += [ | |
'directory' => $this->request->directory(), | |
'controller' => $this->request->controller(), | |
'action' => $this->request->action(), | |
]; | |
return $this->request->route()->uri($params); | |
} | |
/** | |
* Create and optional load model by route `id` parameter. | |
*/ | |
protected function init_model() | |
{ | |
if ($this->model === null) { | |
// model name is controller name without prefix `Controller_` | |
$this->model = substr(get_class($this), 11); | |
} | |
if (is_string($this->model)) { | |
$id = $this->request->param('id'); | |
try { | |
$this->model = ORM::factory($this->model, $id); | |
} catch (Exception $e) { | |
if ($id) { | |
throw $this->http_exception( | |
404, | |
['Model :model: record :id not found', [':model' => $model->object_name(), ':id' => $id]], | |
$e | |
); | |
} else { | |
throw $this->http_exception( | |
400, | |
['Cannot create model :model' [':model' => $model->object_name()]], | |
$e | |
); | |
} | |
} | |
} | |
} | |
/** | |
* Auto create/load model and bind to action template. | |
*/ | |
public function before() | |
{ | |
// check auth | |
parent::before(); | |
// init model | |
$this->init_model(); | |
} | |
/** | |
* Common method for create and update actions. | |
*/ | |
protected function save_model() | |
{ | |
$errors = []; | |
if ($this->request->method() == Request::POST) { | |
$data = $this->request->post($this->model->object_name()); | |
// external validation for prevent CSRF attacks | |
$validation = new Validation($this->request->post()); | |
$validation->rule('csrf', ['Security', 'check'], [':value']); | |
try { | |
$this->model->values($data)->save($validation); | |
} catch (ORM_Validation_Exception $e) { | |
// Display validation errors in form | |
$errors = $e->errors('models'); | |
} catch (Exception $e) { | |
throw $this->http_exception( | |
400, | |
['Error at :action item', [':action' => $this->request->action()]] | |
); | |
} | |
if (! $errors) { | |
// redirect to `update` action, set 303 code to send as GET. | |
static::redirect($this->uri(['action' => 'update', 'id' => $this->model->pk()]), 303); | |
} | |
} | |
$this->action_template->set([ | |
'csrf' => Security::token(), | |
'errors' => $errors | |
]); | |
} | |
/** | |
* Add new item. | |
*/ | |
public function action_create() | |
{ | |
$this->save_model(); | |
} | |
/** | |
* Update item. | |
*/ | |
public function action_update() | |
{ | |
$this->save_model(); | |
} | |
/** | |
* Delete item. | |
*/ | |
public function action_delete() | |
{ | |
try { | |
$this->model->delete(); | |
} catch (Exception $e) { | |
throw $this->http_exception(400, ['Error at delete item', [':model' =>]], $e); | |
} | |
// redirect to `index` action | |
static::redirect($this->uri(['action' => 'index'])); | |
} | |
/** | |
* Read and display items per page and pagination. | |
*/ | |
public function action_index() | |
{ | |
// create pagination instance | |
$pagination = new Pagination( | |
['total_items' => $this->model->count_all(), 'page' => $this->request->param('page')], | |
$this->request | |
); | |
// attach pagination to page template | |
$this->action_template->pagination = $pagination; | |
// set items per page | |
$this->model->offset($pagination->offset) | |
->limit($pagination->items_per_page); | |
// sort items | |
if ($this->request->param('sort_column')) { | |
$this->model->order_by( | |
$this->request->param('sort_column'), | |
$this->request->param('sort_direction') == 'desc' ? 'DESC' : 'ASC' | |
); | |
} | |
// attach items to page template | |
$this->action_template->items = $this->model->find_all(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment