Note
CRUD already provides the basic Index
, View
, Add
, Edit
and
Delete
actions, so you do not need to implement these on your own.
You can find the documentation for these actions in the menu to the left.
Actions are the backbone of CRUD - this is where most of the logic happens.
A Crud Action
contains more or less the exact same code as a normal
controller action.
The main difference between your normal Controller actions and a CRUD Action is that the CRUD Action is highly generic and flexible.
A CRUD action roughly translates to a normal Controller action.
The primary difference is that CRUD actions are made to be as generic and secure out of the box as possible.
You can consider a CRUD action as a more flexible PHP trait that fits nicely within the CakePHP ecosystem.
Below is the code for the Index Crud Action
In the next few sections we will walk through the code and explain how it works, and what every single line of code does.
For each section, the relevant lines of code will be highlighted.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | <?php
namespace Crud\Action;
class Index extends BaseAction {
/**
* Generic handler for all HTTP verbs
*
* @return void
*/
protected function _handle() {
$subject = $this->_subject();
$subject->set(['success' => true, 'viewVar' => $this->viewVar()]);
$this->_trigger('beforePaginate', $subject);
$controller = $this->_controller();
$items = $controller->paginate();
$subject->set(['items' => $items]);
$this->_trigger('afterPaginate', $subject);
$controller->set(['success' => $subject->success, $subject->viewVar => $subject->items]);
$this->_trigger('beforeRender', $subject);
}
}
|
All build-in actions in Crud live in the Crud\Action
namespace.
All actions in Crud, even your own, should inherit from the
Crud\Action\Base
class.
This class is abstract
and provides numerous auxiliary methods which can be
useful for you both as a developer as an action creator.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | <?php
namespace Crud\Action;
class Index extends BaseAction {
/**
* Generic handler for all HTTP verbs
*
* @return void
*/
protected function _handle() {
$subject = $this->_subject();
$subject->set(['success' => true, 'viewVar' => $this->viewVar()]);
$this->_trigger('beforePaginate', $subject);
$controller = $this->_controller();
$items = $controller->paginate();
$subject->set(['items' => $items]);
$this->_trigger('afterPaginate', $subject);
$controller->set(['success' => $subject->success, $subject->viewVar => $subject->items]);
$this->_trigger('beforeRender', $subject);
}
}
|
Next is the method _handle
. A Crud Action can respond to any HTTP verb
(GET
, POST
, PUT
, DELETE
).
Each HTTP verb can be implemented as method, e.g. _get()
for HTTP GET,
_post()
for HTTP POST and _put()
for HTTP PUT.
If no HTTP verb specific method is found in the class, _handle()
will be
executed.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | <?php
namespace Crud\Action;
class Index extends BaseAction {
/**
* Generic handler for all HTTP verbs
*
* @return void
*/
protected function _handle() {
$subject = $this->_subject();
$subject->set(['success' => true, 'viewVar' => $this->viewVar()]);
$this->_trigger('beforePaginate', $subject);
$controller = $this->_controller();
$items = $controller->paginate();
$subject->set(['items' => $items]);
$this->_trigger('afterPaginate', $subject);
$controller->set(['success' => $subject->success, $subject->viewVar => $subject->items]);
$this->_trigger('beforeRender', $subject);
}
}
|
You can treat the _handle()
method as a catch-all, if your crud action
wants to process all possible HTTP verbs.
An advantage of this setup is that you can separate the logic on a request type level instead of mixing all of the logic into one big block of code.
For example the Edit Crud Action implements _get()
,
_post()
and _put()
methods. The _get()
method simply reads the entity
from the database and passes it to the form, while _put()
handles validation
and saving the entity back to the database.
All Crud actions emit a range of events, and all of these events always contain a
Crud Subject`. The Crud Subject`
can change its state between emitted events. This object is a simple StdClass
which contains the current state of the Crud request.
The real beauty of Crud is the events and the flexibility they provide.
All calls to _trigger()
emit an event, that you as a developer can listen to
and inject your own application logic. These events are in no way magical, they
are simply normal CakePHP events, dispatched like all other events in CakePHP.
You can for example listen for the beforePaginate
event and add conditions
to your pagination query, just with a few lines of code. Those few lines
of code is what makes your application unique. The rest of the code you would
normally have is simply repeated boiler plate code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | <?php
namespace Crud\Action;
class Index extends BaseAction {
/**
* Generic handler for all HTTP verbs
*
* @return void
*/
protected function _handle() {
$subject = $this->_subject();
$subject->set(['success' => true, 'viewVar' => $this->viewVar()]);
$this->_trigger('beforePaginate', $subject);
$controller = $this->_controller();
$items = $controller->paginate();
$subject->set(['items' => $items]);
$this->_trigger('afterPaginate', $subject);
$controller->set(['success' => $subject->success, $subject->viewVar => $subject->items]);
$this->_trigger('beforeRender', $subject);
}
}
|
Only the code that you would normally have in your controller is left now.
While these 3 lines seem simple, and the whole Crud implementation a bit overkill at first, the true power of this setup will be clear when your application grows and the requirements increase.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | <?php
namespace Crud\Action;
class Index extends BaseAction {
/**
* Generic handler for all HTTP verbs
*
* @return void
*/
protected function _handle() {
$subject = $this->_subject();
$subject->set(['success' => true, 'viewVar' => $this->viewVar()]);
$this->_trigger('beforePaginate', $subject);
$controller = $this->_controller();
$items = $controller->paginate();
$subject->set(['items' => $items]);
$this->_trigger('afterPaginate', $subject);
$controller->set(['success' => $subject->success, $subject->viewVar => $subject->items]);
$this->_trigger('beforeRender', $subject);
}
}
|
For example adding an API layer to your application later in time will be non-trivial and time consuming if you do not use crud - especially if you have many controllers.
Using Crud, it would be as simple as loading the API listener and everything would be taken care of. All validation, exceptions, success and error responses would work immediately, and with just a few lines of code.
This is because the powerful event system can hook into the request and hijack the rendering easily and effortlessly – something baked controllers do not offer.