Contents

Introduction

Crud was built to be scaffolding on steroids, and allow developers to have enough flexibility to use it for both rapid prototyping and production applications, even on the same code base saving you time, and your clients money.

Why Use Crud

  • Crud is very fast to install, a few minutes tops.
  • Crud is very flexible and has tons of configuration options (but very sane defaults, just like CakePHP).
  • Crud aims to stay out of your way, and if it happens to get in your way, you can change the undesired behavior very easily.
  • Crud relies heavily on CakePHP events making it possible to override, extend, or disable almost all of Crud’s functionality either globally or for one specific action.
  • Crud removes the boilerplate code from your controllers, which mean less code to maintain, and less code to spend time unit testing.
  • Crud will dynamically add the actions to your controller so you don’t have to re-implement them over and over again.
  • Crud allows you to hook into all stages of a request, only building the controller code needed specifically for your business logic, outsourcing all the heavy boiler-plating to Crud.
  • Crud allows you to use your own views, baked or hand-crafted, in addition to adding the code needed to fulfill your application logic, using events. It is by default compatible with CakePHP’s baked views.
  • Optionally there is the Crud-View plugin for automatic generation of your admin area templates.
  • Crud also provides built in features for JSON API for any action you have enabled through Crud, which eliminates maintaining both a HTML frontend and a JSON and/or XML interface for your applications – saving you tons of time and having a leaner code base.
  • Crud uses the truly open source MIT license, just like CakePHP.

Bugs

If you happen to stumble upon a bug, please feel free to create a pull request or submit an issue with a fix (optionally with a test), and a description of the bug and how it was resolved.

Features

If you have a good idea for a Crud feature, please join us in #friendsofcake channel on Slack and let’s discuss it. Opening a pull request is always more than welcome, and a great way to start a discussion. Please check our contribution guidelines.

Support / Questions

You can join us CakePHP’s #support channel on Slack for any support or questions.

Installation

Requirements

  • CakePHP 3.2+
  • PHP 5.5.9+

Using composer

The recommended installation method for this plugin is by using composer.

composer require friendsofcake/crud

You can also check Packagist.

Loading the plugin

Run the following command

bin/cake plugin load Crud

Depending on your CakePHP version your src/Application.php or config/bootstrap.php will be modified to load the plugin.

Configuring the controller

The Crud plugin provides a trait which will catch a MissingActionException and then step in to provide scaffold actions to the controllers.

To enable Crud across your whole application add the trait to your src/Controller/AppController.php

namespace App\Controller;

class AppController extends \Cake\Controller\Controller
{
    use \Crud\Controller\ControllerTrait;
}

Note

To have Crud just scaffold a single controller you can just add the ControllerTrait to that specific controller.

Adding the ControllerTrait itself do not enable anything Crud, but simply installs the code to handle the \Cake\Error\MissingActionException exception so you don’t have to implement an action in your controller for Crud to work.

The next step is to load the Crud component in your controller. A basic example is as follows, and will enable the Crud plugin to scaffold all your controllers index actions.

class AppController extends \Cake\Controller\Controller
{
    use \Crud\Controller\ControllerTrait;

    public function initialize(): void
    {
        parent::initialize();

        $this->loadComponent('Crud.Crud', [
            'actions' => [
                'Crud.Index'
            ]
        ]);

        // Other application wide controller setup
    }
}

Further configuration options are detailed on the configuration page.

Quick Start

You are busy, and you just want to “get things done™”, so let’s get going.

After installation, you are ready to CRUD-ify your app.

The application

So the application our pointy-haired boss has tasked us to create today is a Blog.

App Controller

Let’s setup CRUD to handle all index(), add(), edit(), view() and delete() actions automatically, we do this by enabling Crud in the AppController with the actions options configuration.

declare(strict_types=1);

namespace App\Controller;

class AppController extends \Cake\Controller\Controller
{
    use \Crud\Controller\ControllerTrait;

    public function initialize(): void
    {
        parent::initialize();

        $this->loadComponent('Crud.Crud', [
            'actions' => [
                'Crud.Index',
                'Crud.Add',
                'Crud.Edit',
                'Crud.View',
                'Crud.Delete'
            ]
        ]);
    }
}

There we go, that was easy.

Posts Controller

So, our new Blog needs a Posts controller to allow us to create, read, update and delete posts.

namespace App\Controller;

class PostsController extends AppController
{
}

This is all the code we need in the PostsController as Crud will scaffold the controller actions for us.

If you are not using Crud-View then you will have to bake your templates.

bin/cake bake template posts

Let’s check out our new application, go to /posts and behold, a nice paginated ìndex() template, all without any code in your controller.

You should now be able to navigate to /posts/add as well and create your first post, as well as being able to edit it.

Reference application

If you’d rather look through a completed application, José from the CakePHP core team has created an application using Crud. You can find it on Github.

Configuration

Configuration of Crud is done through the Crud component - either on the fly anywhere in you application, or by providing the configuration in the Controller::loadComponent() method.

Assuming you have followed the installation guide we will now begin the actual configuration of Crud.

class AppController extends \Cake\Controller\Controller
{

  public function initialize(): void
  {
      parent::initialize();

      $this->loadComponent('Crud.Crud');
  }
}

At this time, the Crud Component is loaded, but we need to tell Crud which actions we want it to handle for us.

Actions

The list of actions is provided either as Component configuration, or on the fly.

An example configuration for handling index actions looks like this.

class AppController extends \Cake\Controller\Controller
{

  use \Crud\Controller\ControllerTrait;

  public function initialize(): void
  {
      parent::initialize();

      $this->loadComponent('Crud.Crud', [
          'actions' => [
              'Crud.Index'
          ]
      ]);
  }
}

An example of on the fly enabling an Crud action:

class AppController extends \Cake\Controller\Controller
{

  public function beforeFilter(\Cake\Event\EventInterface $event)
  {
      $this->Crud->mapAction('myIndex', 'Crud.Index');
  }

  public function myIndex()
  {
      // intercept events here

      return $this->Crud->execute();
  }
}

The examples above are functionally identical, and instructs Crud to handle the index action in controllers using Crud.Index action class.

Note

If you do not wish for Crud to be enabled across all controllers, or even use all actions provided by Crud you can pick and chose which to use. Crud will not force take-over any application logic, and you can enable/disable them as you see fit.

Action configuration

Note

Each Crud Action can have a different set of configuration settings, please see their individual documentation pages for more information.

A more verbose example now, where we’ll change the view template that Crud will use for index actions to be my_index.php

class AppController extends \Cake\Controller\Controller
{

  use \Crud\Controller\ControllerTrait;

  public function initialize(): void
  {
      parent::initialize();

      $this->loadComponent('Crud.Crud', [
          'actions' => [
              'index' => [
                'className' => 'Crud.Index',
                'view' => 'my_index'
              ]
          ]
      ]);
  }
}

An example of on the fly enabling a Crud action with configuration

class AppController extends \Cake\Controller\Controller
{

  public function beforeFilter(\Cake\Event\EventInterface $event)
  {
      $this->Crud->mapAction('index', [
        'className' => 'Crud.Index',
        'view' => 'my_index'
      ]);
  }
}

Disabling loaded actions

If you’ve loaded an action in eg. your AppController - but don’t want it included in a specific controller, it can be disabled with the $this->Crud->disable(['action_name']).

Example of disabling a loaded action, first we show all actions being configured to be handled by Crud, then disabling a specific action in our PostsController.

class AppController extends \Cake\Controller\Controller
{

  use \Crud\Controller\ControllerTrait;

  public function initialize()
  {
      parent::initialize();

      $this->loadComponent('Crud.Crud', [
          'actions' => [
              'Crud.Index',
              'Crud.View',
              'Crud.Delete',
              'Crud.Edit'
          ]
      ]);
  }
}
class PostsController extends AppController
{

    public function beforeFilter(\Cake\Event\EventInterface $event)
    {
        parent::beforeFilter($event);

        $this->Crud->disable(['Edit', 'Delete']);
    }
}

Built-in actions

Crud provides the default create, read, update and delete actions out of the box.

Custom action classes

It’s possible to create your own custom action classes as well, or overwrite the built-in ones. Simply provide the className configuration key for an action, and Crud will use that one instead.

class AppController extends \Cake\Controller\Controller
{
    use \Crud\Controller\ControllerTrait;

    public function initialize()
    {
        parent::initialize();

        $this->loadComponent('Crud.Crud', [
            'actions' => [
                'index' => ['className' => '\App\Crud\Action\MyIndexAction'],
                'view' => ['className' => '\App\Crud\Action\MyViewAction']
            ]
        ]);
    }
}

Note

Ensure that you escape your namespace when loading your own action classes.

Learn more about custom action classes.

Listeners

The other way to customise the behavior of the Crud plugin is through it’s many listeners. These provide lots of additional functionality to your scaffolding, such as dealing with api’s and loading related data.

Check the Listeners documentation for more on Crud’s included listeners, and how to create your own.

Prefix routing

You might have a scenario where you’d like to use Crud, but only within a certain prefix, such as running your admin area on Crud under the admin prefix.

The easiest way to achieve this is to create an AppController for the prefix, and have your other prefixed controllers extend from that one. Then you can configure Crud in your prefixes AppController.

Let’s look at an example, using an api prefix. For this example, we’ll assume your prefix routing is already configured.

First step is to create your new ApiAppController which should be in src/Controller/Api/.

namespace App\Controller\Api;

class ApiAppController extends Controller
{
    public function initialize(): void
    {
        $this->loadComponent('Crud.Crud', [
            'actions' => [
                'Crud.Index',
                'Crud.View'
            ]
        ]);

        $this->Crud->addListener('Crud.Api');
        $this->Crud->addListener('Crud.ApiPagination');
    }
}

So now that we’ve created our new ApiAppController we can extend the other prefix controllers from this one, so that they inherit the Crud configuration without impacting other areas of our application.

namespace App\Controller\Api;

class ProductsController extends ApiAppController
{
}

Actions

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.

Crud Actions are the backbone of the plugin, this is where most of the logic happens.

What Is An Action?

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.

A nice added bonus is that if all your controllers share a generic controller action, you only have to unit test once, to test every controller in your application.

The Anatomy Of An Action

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
28
29
<?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);
    }

}

Class And Namespace

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.

Where you choose to put your custom Crud actions is up to you, but using src/Crud is a good place. Remember to namespace your action class accordingly.

 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
28
29
<?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);
    }

}

Request Methods

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
28
29
<?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.

Events & Subject

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
28
29
<?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);
    }

}

Boilerplate

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
28
29
<?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 easy because you don’t need to edit all your applications 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.

Crud’s default actions

Crud has many actions built-in which come with the plugin.

Index

The Index Crud Action paginates over the primary model in the controller.

On a high level it’s basically just calling Controller::paginate().

Configuration

Note

Before applying any configuration to an action it must be mapped first.

If the action has not been mapped an exception will be raised.

enabled

Test or modify if the Crud Action is enabled or not.

When a CrudAction is disabled, Crud will not handle any requests to the action, and CakePHP will raise the normal \Cake\Error\MissingActionException exception if you haven’t implemented the action in your controller.

Warning

If you have enabled Crud and you are still receiving a MissingActionException, ensure the action is enabled and that the controller has the \Crud\Controller\ControllerTrait implemented.

To test if an action is enabled, call the enabled method on the action.

$this->Crud->action()->enabled();

To disable an action, call the disable method on the action.

$this->Crud->action()->disable();

To enable an action, call the enable method on the action.

$this->Crud->action()->enable();

To disable or enable multiple actions at the same time, Crud Component provides helper methods.

The enable and disable method can take a string or an array, for easy mass-updating.

$this->Crud->enable('index');
$this->Crud->enable(['index', 'add']);

$this->Crud->disable('index');
$this->Crud->disable(['index', 'add']);

Note

These methods simply calls the enable and disable method in each Crud Action class, and do not provide any magic other than mass updating.

Warning

While it’s possible to update the enabled property directly on an action using the config methods, it’s not recommend, as important cleanup logic will not be applied if you use the setConfig() method directly.

findMethod

The 1st parameter to Table::find() - the default value is all.

To get the current configured findMethod keys call the findMethod method without any arguments.

$this->Crud->action()->findMethod();

To change the findMethod value pass a string argument to the method

$this->Crud->action()->findMethod('my_custom_finder');
view

Get or set the view file to render at the end of the request.

The view setting is passed directly and unmodified to Controller::render().

To get the current configured view call the view method without any arguments.

$this->Crud->action()->view();

To change the view to render, pass a string as first argument.

$this->Crud->action()->view('my_custom_view');

Note

If the first parameter is NULL - which is the default value - the normal CakePHP behavior will be used.

Warning

Due to the nature of this method, once a custom view has been set, it’s not possible to revert back to the default behavior by calling ->view(null) as it will return the current configuration.

viewVar

Note

This maps directly to the $key argument in Controller::set($key, $value)

Change the name of the variable which contains the result of a index or view action query result.

To get the current configured viewVar call the viewViar method without any arguments.

$this->Crud->action()->viewVar();

To change the viewVar, pass a string as first argument.

$this->Crud->action()->viewVar('items');

For Index Action the default is plural version of the controller name.

Having a controller named PostsController would mean that the viewVar would be posts by default.

For View Action the default is singular version of the controller name.

Having a controller named PostsController would mean that the viewVar would be post by default.

serialize

Note

This setting is only relevant if you use the API listener.

Note

The API listener will always enforce success and data to be part of the _serialize array.

This method is intended to allow you to add additional keys to your API responses with ease. An example of this is the API Query Log.

To get the current configured serialize keys call the serialize method without any arguments.

$this->Crud->action()->serialize();

To change the serialize keys, pass a string or an array as first argument.

If a string is passed, it will be cast to array automatically.

$this->Crud->action()->serialize(['my', 'extra', 'keys']);
Events

This is a list of events emitted from the Index Crud Action.

Please see the events documentation for a full list of generic properties and how to use the event system correctly.

Crud.startup

Called after the Controller::beforeFilter() and before the Crud action.

It’s emitted from CrudComponent::startup() and thus is fired in the same cycle as all Component::startup() events.

Crud.beforeFilter

Triggered when a CrudAction is going to handle a CakePHP request.

It’s emitted from CrudComponent::beforeFilter and thus is fired in the same cycle as all Controller::beforeFilter events.

Crud.beforePaginate

This event is emitted before Controller::paginate() is called.

Add Conditions
public function index()
{
    $this->Crud->on('beforePaginate', function(\Cake\Event\EventInterface $event) {
        $this->paginate['conditions']['is_active'] = true;
    });

    return $this->Crud->execute();
}
Crud.afterPaginate

This event is emitted right after the call to Controller::paginate().

The entities property of the event object contains all the database records found in the pagination call.

Modify the Result
public function index()
{
    $this->Crud->on('afterPaginate', function(\Cake\Event\EventInterface $event) {
        foreach ($event->getSubject()->entities as $entity) {
            // $entity is an entity
        }
    });

    return $this->Crud->execute();
}
Crud.beforeRender

Invoked right before the view will be rendered.

This is also before the controllers own beforeRender callback.

View

The View Crud Action will read a record from a data source based on the ID that is part of the request.

Configuration

Note

Before applying any configuration to an action it must be mapped first.

If the action has not been mapped an exception will be raised.

enabled

Test or modify if the Crud Action is enabled or not.

When a CrudAction is disabled, Crud will not handle any requests to the action, and CakePHP will raise the normal \Cake\Error\MissingActionException exception if you haven’t implemented the action in your controller.

Warning

If you have enabled Crud and you are still receiving a MissingActionException, ensure the action is enabled and that the controller has the \Crud\Controller\ControllerTrait implemented.

To test if an action is enabled, call the enabled method on the action.

$this->Crud->action()->enabled();

To disable an action, call the disable method on the action.

$this->Crud->action()->disable();

To enable an action, call the enable method on the action.

$this->Crud->action()->enable();

To disable or enable multiple actions at the same time, Crud Component provides helper methods.

The enable and disable method can take a string or an array, for easy mass-updating.

$this->Crud->enable('index');
$this->Crud->enable(['index', 'add']);

$this->Crud->disable('index');
$this->Crud->disable(['index', 'add']);

Note

These methods simply calls the enable and disable method in each Crud Action class, and do not provide any magic other than mass updating.

Warning

While it’s possible to update the enabled property directly on an action using the config methods, it’s not recommend, as important cleanup logic will not be applied if you use the setConfig() method directly.

findMethod

The 1st parameter to Table::find() - the default value is all.

To get the current configured findMethod keys call the findMethod method without any arguments.

$this->Crud->action()->findMethod();

To change the findMethod value pass a string argument to the method

$this->Crud->action()->findMethod('my_custom_finder');
view

Get or set the view file to render at the end of the request.

The view setting is passed directly and unmodified to Controller::render().

To get the current configured view call the view method without any arguments.

$this->Crud->action()->view();

To change the view to render, pass a string as first argument.

$this->Crud->action()->view('my_custom_view');

Note

If the first parameter is NULL - which is the default value - the normal CakePHP behavior will be used.

Warning

Due to the nature of this method, once a custom view has been set, it’s not possible to revert back to the default behavior by calling ->view(null) as it will return the current configuration.

viewVar

Note

This maps directly to the $key argument in Controller::set($key, $value)

Change the name of the variable which contains the result of a index or view action query result.

To get the current configured viewVar call the viewViar method without any arguments.

$this->Crud->action()->viewVar();

To change the viewVar, pass a string as first argument.

$this->Crud->action()->viewVar('items');

For Index Action the default is plural version of the controller name.

Having a controller named PostsController would mean that the viewVar would be posts by default.

For View Action the default is singular version of the controller name.

Having a controller named PostsController would mean that the viewVar would be post by default.

serialize

Note

This setting is only relevant if you use the API listener.

Note

The API listener will always enforce success and data to be part of the _serialize array.

This method is intended to allow you to add additional keys to your API responses with ease. An example of this is the API Query Log.

To get the current configured serialize keys call the serialize method without any arguments.

$this->Crud->action()->serialize();

To change the serialize keys, pass a string or an array as first argument.

If a string is passed, it will be cast to array automatically.

$this->Crud->action()->serialize(['my', 'extra', 'keys']);
Events

This is a list of events emitted from the View Crud Action.

Please see the events documentation for a full list of generic properties and how to use the event system correctly.

Crud.startup

Called after the Controller::beforeFilter() and before the Crud action.

It’s emitted from CrudComponent::startup() and thus is fired in the same cycle as all Component::startup() events.

Crud.beforeFilter

Triggered when a CrudAction is going to handle a CakePHP request.

It’s emitted from CrudComponent::beforeFilter and thus is fired in the same cycle as all Controller::beforeFilter events.

Crud.beforeFind

The event is emitted before calling the find method in the table.

The Crud Subject contains the following keys:

  • id The ID that was originally passed to the action and usually the primary key value of your table.
  • repository An instance of the Repository (Table) which the query will be executed against.
  • query A Query object from the Repository where $PrimaryKey => $IdFromRequest is already added to the conditions.

This is the last place you can modify the query before it’s executed against the database.

Note

An example

Given the URL: /posts/view/10 the repository object will be an instance of PostsTable and the query includes a WHERE condition with Posts.id = 10

After the event has emitted, the database query is executed with LIMIT 1.

If a record is found the Crud.afterFind event is emitted.

Warning

If no record is found in the database, the recordNotFound event is emitted instead of Crud.afterFind.

Add Conditions
public function delete($id)
{
    $this->Crud->on('beforeFind', function(\Cake\Event\EventInterface $event) {
        $event->getSubject()->query->where(['author' => $this->Auth->user('id')]);
    });

    return $this->Crud->execute();
}
Crud.afterFind

After the query has been executed, and a record has been found this event is emitted.

The Crud Subject contains two keys:

  • id The ID that was originally passed to the action and is usually the primary key of your model.
  • entity The record that was found in the database.

Note

If an entity is not found, the RecordNotFound event is emitted instead.

Logging the Found Item
public function delete($id)
{
    $this->Crud->on('afterFind', function(\Cake\Event\EventInterface $event) {
        $this->log("Found item: " . $event->getSubject()->entity->id . " in the database");
    });

    return $this->Crud->execute();
}
Crud.recordNotFound

Note

This event will throw an exception.

The default configuration will thrown an Cake\Error\NotFoundException which will yield a 404 response.

The event is triggered after a find did not find any records in the database.

You can modify the exception class thrown using CrudComponent::message method

Crud.beforeRender

Invoked right before the view will be rendered.

This is also before the controllers own beforeRender callback.

Add

The Add Crud Action will create a new record if the request is POST and the data validates - otherwise it will attempt to render a form to the end-user.

Configuration

Note

Before applying any configuration to an action it must be mapped first.

If the action has not been mapped an exception will be raised.

enabled

Test or modify if the Crud Action is enabled or not.

When a CrudAction is disabled, Crud will not handle any requests to the action, and CakePHP will raise the normal \Cake\Error\MissingActionException exception if you haven’t implemented the action in your controller.

Warning

If you have enabled Crud and you are still receiving a MissingActionException, ensure the action is enabled and that the controller has the \Crud\Controller\ControllerTrait implemented.

To test if an action is enabled, call the enabled method on the action.

$this->Crud->action()->enabled();

To disable an action, call the disable method on the action.

$this->Crud->action()->disable();

To enable an action, call the enable method on the action.

$this->Crud->action()->enable();

To disable or enable multiple actions at the same time, Crud Component provides helper methods.

The enable and disable method can take a string or an array, for easy mass-updating.

$this->Crud->enable('index');
$this->Crud->enable(['index', 'add']);

$this->Crud->disable('index');
$this->Crud->disable(['index', 'add']);

Note

These methods simply calls the enable and disable method in each Crud Action class, and do not provide any magic other than mass updating.

Warning

While it’s possible to update the enabled property directly on an action using the config methods, it’s not recommend, as important cleanup logic will not be applied if you use the setConfig() method directly.

view

Get or set the view file to render at the end of the request.

The view setting is passed directly and unmodified to Controller::render().

To get the current configured view call the view method without any arguments.

$this->Crud->action()->view();

To change the view to render, pass a string as first argument.

$this->Crud->action()->view('my_custom_view');

Note

If the first parameter is NULL - which is the default value - the normal CakePHP behavior will be used.

Warning

Due to the nature of this method, once a custom view has been set, it’s not possible to revert back to the default behavior by calling ->view(null) as it will return the current configuration.

saveMethod

The method to execute on Table:: when saving an entity - the default value is save.

To get the current configured saveMethod keys call the saveMethod method without any arguments.

$this->Crud->action()->saveMethod();

To change the saveMethod value pass an string argument to the method

$this->Crud->action()->saveMethod('my_custom_save_method');
saveOptions

The 2nd parameter to Table::save() - the default value is ['validate' => true, 'atomic' => true].

To get the current configured saveOptions keys call the saveOptions method without any arguments.

$this->Crud->action()->saveOptions();

To change the saveOptions value pass an array argument to the method

$this->Crud->action()->saveOptions(['atomic' => false]);

Sometimes you need to change the accessible fields before you update your entity.

$this->Crud->action()->saveOptions(['accessibleFields' => ['role_id' => true]]);
serialize

Note

This setting is only relevant if you use the API listener.

Note

The API listener will always enforce success and data to be part of the _serialize array.

This method is intended to allow you to add additional keys to your API responses with ease. An example of this is the API Query Log.

To get the current configured serialize keys call the serialize method without any arguments.

$this->Crud->action()->serialize();

To change the serialize keys, pass a string or an array as first argument.

If a string is passed, it will be cast to array automatically.

$this->Crud->action()->serialize(['my', 'extra', 'keys']);
relatedModels

Note

If you have the RelatedModels listener configured, you can have Crud automatically load related data.

<?php
$this->Crud->listener('relatedModels')->relatedModels(true);

Find out more about the RelatedModels listener in the Listeners chapter.

Events

This is a list of events emitted from the Add Crud Action.

Please see the events documentation for a full list of generic properties and how to use the event system correctly.

Crud.startup

Called after the Controller::beforeFilter() and before the Crud action.

It’s emitted from CrudComponent::startup() and thus is fired in the same cycle as all Component::startup() events.

Crud.beforeFilter

Triggered when a CrudAction is going to handle a CakePHP request.

It’s emitted from CrudComponent::beforeFilter and thus is fired in the same cycle as all Controller::beforeFilter events.

Crud.beforeSave

Note

Do not confuse this event with the beforeSave callback in the ORM layer

Called right before calling Table::save().

The Crud Subject contains the following keys:

  • entity An entity object marshaled with the HTTP POST data from the request.
  • saveMethod A string with the saveMethod.
  • saveOptions An array with the saveOptions.

All modifications to these keys will be passed into the Table::$saveMethod.

Warning

After this event has been emitted, changes done through the $action->saveMethod() or $action->saveOptions() methods will no longer affect the code, as the rest of the code uses the values from the Crud Subject

Crud.afterSave

Note

Do not confuse this event with the afterSave callback in the ORM layer.

This event is emitted right after the call to Table::save().

The Crud Subject contains the following keys:

  • success indicates whether or not the Table::save() call succeed or not.
  • created true if the record was created and false if the record was updated.
  • entity An entity object marshaled with the HTTP POST data from the request and the save() logic.
Check Created Status
public function edit($id)
{
    $this->Crud->on('afterSave', function(\Cake\Event\EventInterface $event) {
        if ($event->getSubject()->created) {
            $this->log("The entity was created");
        } else {
            $this->log("The entity was updated");
        }
    });

    return $this->Crud->execute();
}
Check Success Status
public function edit($id)
{
    $this->Crud->on('afterSave', function(\Cake\Event\EventInterface $event) {
        if ($event->getSubject()->success) {
            $this->log("The entity was saved successfully");
        } else {
            $this->log("The entity was NOT saved successfully");
        }
    });

    return $this->Crud->execute();
}
Get Entity ID
public function add()
{
    $this->Crud->on('afterSave', function(\Cake\Event\EventInterface $event) {
        if ($event->getSubject()->created) {
            $this->log("The entity was created with id: " . $event->getSubject()->entity->id);
        }
    });

    return $this->Crud->execute();
}
Crud.setFlash

Simple and event driven wrapper for SessionComponent::setFlash.

The Crud Subject contains the following keys:

  • text The 1st argument to SessionComponent::setFlash.
  • element The 2nd argument to SessionComponent::setFlash.
  • params The 3rd argument to SessionComponent::setFlash.
  • key The 4th argument to SessionComponent::setFlash.
  • entity (Optional) The Entity from the previously emitted event.

All keys can be modified as you see fit, at the end of the event cycle they will be passed directly to SessionComponent::setFlash.

Defaults are stored in the messages configuration array for each action.

If you do not want to use this feature, simply stop the event by calling its stopPropagation() method.

If you’d like to customise the flash messages that are used, perhaps you’re using friendsofcake/bootstrap-ui. It’s actually quite simple to do, and can be done as part of the component configuration or on the fly.

public function initialize()
{
      $this->loadComponent('Crud.Crud', [
          'actions' => [
              'edit' => [
                  'className' => 'Crud.Edit',
                  'messages' => [
                      'success' => [
                          'params' => ['class' => 'alert alert-success alert-dismissible']
                      ],
                      'error' => [
                          'params' => ['class' => 'alert alert-danger alert-dismissible']
                      ]
                  ],
              ]
          ]
      ]);
}

If you’d like to configure it on the fly you can use the eventManager to change the event subject as the event is emitted.

$this->eventManager()->on('Crud.setFlash', function (Event $event) {
    if ($event->getSubject()->success) {
        $event->getSubject()->params['class'] = ['alert', 'alert-success', 'alert-dismissible'];
    }
});
Crud.beforeRedirect

Simple and event driven wrapper for Controller::redirect().

The Crud Subject contains the following keys:

  • url The 1st argument to Controller::redirect().
  • status The 2nd argument to Controller::redirect().
  • exit The 3rd argument to Controller::redirect().
  • entity (Optional) The Entity from the previously emitted event.

All keys can be modified as you see fit, at the end of the event cycle they will be passed directly to Controller::redirect().

The redirect $url can be changed on the fly either by posting a redirect_url field from your form or by providing a redirect_url HTTP query key.

The default for most redirects are simply to return to the index() action.

Crud.beforeRender

Invoked right before the view will be rendered.

This is also before the controllers own beforeRender callback.

Edit

The Edit Crud Action will update an existing record if the request is POST or PUT and the data validates - otherwise it will attempt to render a form to the end-user.

Configuration

Note

Before applying any configuration to an action it must be mapped first.

If the action has not been mapped an exception will be raised.

enabled

Test or modify if the Crud Action is enabled or not.

When a CrudAction is disabled, Crud will not handle any requests to the action, and CakePHP will raise the normal \Cake\Error\MissingActionException exception if you haven’t implemented the action in your controller.

Warning

If you have enabled Crud and you are still receiving a MissingActionException, ensure the action is enabled and that the controller has the \Crud\Controller\ControllerTrait implemented.

To test if an action is enabled, call the enabled method on the action.

$this->Crud->action()->enabled();

To disable an action, call the disable method on the action.

$this->Crud->action()->disable();

To enable an action, call the enable method on the action.

$this->Crud->action()->enable();

To disable or enable multiple actions at the same time, Crud Component provides helper methods.

The enable and disable method can take a string or an array, for easy mass-updating.

$this->Crud->enable('index');
$this->Crud->enable(['index', 'add']);

$this->Crud->disable('index');
$this->Crud->disable(['index', 'add']);

Note

These methods simply calls the enable and disable method in each Crud Action class, and do not provide any magic other than mass updating.

Warning

While it’s possible to update the enabled property directly on an action using the config methods, it’s not recommend, as important cleanup logic will not be applied if you use the setConfig() method directly.

view

Get or set the view file to render at the end of the request.

The view setting is passed directly and unmodified to Controller::render().

To get the current configured view call the view method without any arguments.

$this->Crud->action()->view();

To change the view to render, pass a string as first argument.

$this->Crud->action()->view('my_custom_view');

Note

If the first parameter is NULL - which is the default value - the normal CakePHP behavior will be used.

Warning

Due to the nature of this method, once a custom view has been set, it’s not possible to revert back to the default behavior by calling ->view(null) as it will return the current configuration.

findMethod

The 1st parameter to Table::find() - the default value is all.

To get the current configured findMethod keys call the findMethod method without any arguments.

$this->Crud->action()->findMethod();

To change the findMethod value pass a string argument to the method

$this->Crud->action()->findMethod('my_custom_finder');
saveMethod

The method to execute on Table:: when saving an entity - the default value is save.

To get the current configured saveMethod keys call the saveMethod method without any arguments.

$this->Crud->action()->saveMethod();

To change the saveMethod value pass an string argument to the method

$this->Crud->action()->saveMethod('my_custom_save_method');
saveOptions

The 2nd parameter to Table::save() - the default value is ['validate' => true, 'atomic' => true].

To get the current configured saveOptions keys call the saveOptions method without any arguments.

$this->Crud->action()->saveOptions();

To change the saveOptions value pass an array argument to the method

$this->Crud->action()->saveOptions(['atomic' => false]);

Sometimes you need to change the accessible fields before you update your entity.

$this->Crud->action()->saveOptions(['accessibleFields' => ['role_id' => true]]);
serialize

Note

This setting is only relevant if you use the API listener.

Note

The API listener will always enforce success and data to be part of the _serialize array.

This method is intended to allow you to add additional keys to your API responses with ease. An example of this is the API Query Log.

To get the current configured serialize keys call the serialize method without any arguments.

$this->Crud->action()->serialize();

To change the serialize keys, pass a string or an array as first argument.

If a string is passed, it will be cast to array automatically.

$this->Crud->action()->serialize(['my', 'extra', 'keys']);
relatedModels

Note

If you have the RelatedModels listener configured, you can have Crud automatically load related data.

<?php
$this->Crud->listener('relatedModels')->relatedModels(true);

Find out more about the RelatedModels listener in the Listeners chapter.

Events

This is a list of events emitted from the Edit Crud Action.

Please see the events documentation for a full list of generic properties and how to use the event system correctly.

Crud.startup

Called after the Controller::beforeFilter() and before the Crud action.

It’s emitted from CrudComponent::startup() and thus is fired in the same cycle as all Component::startup() events.

Crud.beforeFilter

Triggered when a CrudAction is going to handle a CakePHP request.

It’s emitted from CrudComponent::beforeFilter and thus is fired in the same cycle as all Controller::beforeFilter events.

Crud.beforeFind

The event is emitted before calling the find method in the table.

The Crud Subject contains the following keys:

  • id The ID that was originally passed to the action and usually the primary key value of your table.
  • repository An instance of the Repository (Table) which the query will be executed against.
  • query A Query object from the Repository where $PrimaryKey => $IdFromRequest is already added to the conditions.

This is the last place you can modify the query before it’s executed against the database.

Note

An example

Given the URL: /posts/view/10 the repository object will be an instance of PostsTable and the query includes a WHERE condition with Posts.id = 10

After the event has emitted, the database query is executed with LIMIT 1.

If a record is found the Crud.afterFind event is emitted.

Warning

If no record is found in the database, the recordNotFound event is emitted instead of Crud.afterFind.

Add Conditions
public function delete($id)
{
    $this->Crud->on('beforeFind', function(\Cake\Event\EventInterface $event) {
        $event->getSubject()->query->where(['author' => $this->Auth->user('id')]);
    });

    return $this->Crud->execute();
}
Crud.afterFind

After the query has been executed, and a record has been found this event is emitted.

The Crud Subject contains two keys:

  • id The ID that was originally passed to the action and is usually the primary key of your model.
  • entity The record that was found in the database.

Note

If an entity is not found, the RecordNotFound event is emitted instead.

Logging the Found Item
public function delete($id)
{
    $this->Crud->on('afterFind', function(\Cake\Event\EventInterface $event) {
        $this->log("Found item: " . $event->getSubject()->entity->id . " in the database");
    });

    return $this->Crud->execute();
}
Crud.beforeSave

Note

Do not confuse this event with the beforeSave callback in the ORM layer

Called right before calling Table::save().

The Crud Subject contains the following keys:

  • entity An entity object marshaled with the HTTP POST data from the request.
  • saveMethod A string with the saveMethod.
  • saveOptions An array with the saveOptions.

All modifications to these keys will be passed into the Table::$saveMethod.

Warning

After this event has been emitted, changes done through the $action->saveMethod() or $action->saveOptions() methods will no longer affect the code, as the rest of the code uses the values from the Crud Subject

Crud.afterSave

Note

Do not confuse this event with the afterSave callback in the ORM layer.

This event is emitted right after the call to Table::save().

The Crud Subject contains the following keys:

  • success indicates whether or not the Table::save() call succeed or not.
  • created true if the record was created and false if the record was updated.
  • entity An entity object marshaled with the HTTP POST data from the request and the save() logic.
Check Created Status
public function edit($id)
{
    $this->Crud->on('afterSave', function(\Cake\Event\EventInterface $event) {
        if ($event->getSubject()->created) {
            $this->log("The entity was created");
        } else {
            $this->log("The entity was updated");
        }
    });

    return $this->Crud->execute();
}
Check Success Status
public function edit($id)
{
    $this->Crud->on('afterSave', function(\Cake\Event\EventInterface $event) {
        if ($event->getSubject()->success) {
            $this->log("The entity was saved successfully");
        } else {
            $this->log("The entity was NOT saved successfully");
        }
    });

    return $this->Crud->execute();
}
Get Entity ID
public function add()
{
    $this->Crud->on('afterSave', function(\Cake\Event\EventInterface $event) {
        if ($event->getSubject()->created) {
            $this->log("The entity was created with id: " . $event->getSubject()->entity->id);
        }
    });

    return $this->Crud->execute();
}
Crud.setFlash

Simple and event driven wrapper for SessionComponent::setFlash.

The Crud Subject contains the following keys:

  • text The 1st argument to SessionComponent::setFlash.
  • element The 2nd argument to SessionComponent::setFlash.
  • params The 3rd argument to SessionComponent::setFlash.
  • key The 4th argument to SessionComponent::setFlash.
  • entity (Optional) The Entity from the previously emitted event.

All keys can be modified as you see fit, at the end of the event cycle they will be passed directly to SessionComponent::setFlash.

Defaults are stored in the messages configuration array for each action.

If you do not want to use this feature, simply stop the event by calling its stopPropagation() method.

If you’d like to customise the flash messages that are used, perhaps you’re using friendsofcake/bootstrap-ui. It’s actually quite simple to do, and can be done as part of the component configuration or on the fly.

public function initialize()
{
      $this->loadComponent('Crud.Crud', [
          'actions' => [
              'edit' => [
                  'className' => 'Crud.Edit',
                  'messages' => [
                      'success' => [
                          'params' => ['class' => 'alert alert-success alert-dismissible']
                      ],
                      'error' => [
                          'params' => ['class' => 'alert alert-danger alert-dismissible']
                      ]
                  ],
              ]
          ]
      ]);
}

If you’d like to configure it on the fly you can use the eventManager to change the event subject as the event is emitted.

$this->eventManager()->on('Crud.setFlash', function (Event $event) {
    if ($event->getSubject()->success) {
        $event->getSubject()->params['class'] = ['alert', 'alert-success', 'alert-dismissible'];
    }
});
Crud.beforeRedirect

Simple and event driven wrapper for Controller::redirect().

The Crud Subject contains the following keys:

  • url The 1st argument to Controller::redirect().
  • status The 2nd argument to Controller::redirect().
  • exit The 3rd argument to Controller::redirect().
  • entity (Optional) The Entity from the previously emitted event.

All keys can be modified as you see fit, at the end of the event cycle they will be passed directly to Controller::redirect().

The redirect $url can be changed on the fly either by posting a redirect_url field from your form or by providing a redirect_url HTTP query key.

The default for most redirects are simply to return to the index() action.

Crud.beforeRender

Invoked right before the view will be rendered.

This is also before the controllers own beforeRender callback.

Delete

The Delete Crud Action will delete a record by the id provided in the URL.

Configuration

Note

Before applying any configuration to an action it must be mapped first.

If the action has not been mapped an exception will be raised.

enabled

Test or modify if the Crud Action is enabled or not.

When a CrudAction is disabled, Crud will not handle any requests to the action, and CakePHP will raise the normal \Cake\Error\MissingActionException exception if you haven’t implemented the action in your controller.

Warning

If you have enabled Crud and you are still receiving a MissingActionException, ensure the action is enabled and that the controller has the \Crud\Controller\ControllerTrait implemented.

To test if an action is enabled, call the enabled method on the action.

$this->Crud->action()->enabled();

To disable an action, call the disable method on the action.

$this->Crud->action()->disable();

To enable an action, call the enable method on the action.

$this->Crud->action()->enable();

To disable or enable multiple actions at the same time, Crud Component provides helper methods.

The enable and disable method can take a string or an array, for easy mass-updating.

$this->Crud->enable('index');
$this->Crud->enable(['index', 'add']);

$this->Crud->disable('index');
$this->Crud->disable(['index', 'add']);

Note

These methods simply calls the enable and disable method in each Crud Action class, and do not provide any magic other than mass updating.

Warning

While it’s possible to update the enabled property directly on an action using the config methods, it’s not recommend, as important cleanup logic will not be applied if you use the setConfig() method directly.

findMethod

The 1st parameter to Table::find() - the default value is all.

To get the current configured findMethod keys call the findMethod method without any arguments.

$this->Crud->action()->findMethod();

To change the findMethod value pass a string argument to the method

$this->Crud->action()->findMethod('my_custom_finder');
serialize

Note

This setting is only relevant if you use the API listener.

Note

The API listener will always enforce success and data to be part of the _serialize array.

This method is intended to allow you to add additional keys to your API responses with ease. An example of this is the API Query Log.

To get the current configured serialize keys call the serialize method without any arguments.

$this->Crud->action()->serialize();

To change the serialize keys, pass a string or an array as first argument.

If a string is passed, it will be cast to array automatically.

$this->Crud->action()->serialize(['my', 'extra', 'keys']);
Events

This is a list of events emitted from the Delete Crud Action.

Please see the events documentation for a full list of generic properties and how to use the event system correctly.

Crud.startup

Called after the Controller::beforeFilter() and before the Crud action.

It’s emitted from CrudComponent::startup() and thus is fired in the same cycle as all Component::startup() events.

Crud.beforeFilter

Triggered when a CrudAction is going to handle a CakePHP request.

It’s emitted from CrudComponent::beforeFilter and thus is fired in the same cycle as all Controller::beforeFilter events.

Crud.beforeFind

The event is emitted before calling the find method in the table.

The Crud Subject contains the following keys:

  • id The ID that was originally passed to the action and usually the primary key value of your table.
  • repository An instance of the Repository (Table) which the query will be executed against.
  • query A Query object from the Repository where $PrimaryKey => $IdFromRequest is already added to the conditions.

This is the last place you can modify the query before it’s executed against the database.

Note

An example

Given the URL: /posts/view/10 the repository object will be an instance of PostsTable and the query includes a WHERE condition with Posts.id = 10

After the event has emitted, the database query is executed with LIMIT 1.

If a record is found the Crud.afterFind event is emitted.

Warning

If no record is found in the database, the recordNotFound event is emitted instead of Crud.afterFind.

Add Conditions
public function delete($id)
{
    $this->Crud->on('beforeFind', function(\Cake\Event\EventInterface $event) {
        $event->getSubject()->query->where(['author' => $this->Auth->user('id')]);
    });

    return $this->Crud->execute();
}
Crud.afterFind

After the query has been executed, and a record has been found this event is emitted.

The Crud Subject contains two keys:

  • id The ID that was originally passed to the action and is usually the primary key of your model.
  • entity The record that was found in the database.

Note

If an entity is not found, the RecordNotFound event is emitted instead.

Logging the Found Item
public function delete($id)
{
    $this->Crud->on('afterFind', function(\Cake\Event\EventInterface $event) {
        $this->log("Found item: " . $event->getSubject()->entity->id . " in the database");
    });

    return $this->Crud->execute();
}
Crud.recordNotFound

Note

This event will throw an exception.

The default configuration will thrown an Cake\Error\NotFoundException which will yield a 404 response.

The event is triggered after a find did not find any records in the database.

You can modify the exception class thrown using CrudComponent::message method

Crud.beforeDelete

This event is emitted before calling Table::delete.

The Crud Subject contains the following keys:

  • id The ID of the entity, from the URL
  • item The Entity from the find() call.

To abort a delete() simply stop the event by calling $event->stopPropagation().

Stop Delete
public function delete($id)
{
    $this->Crud->on('beforeDelete', function(\Cake\Event\EventInterface $event) {
        // Stop the delete event, the entity will not be deleted
        if ($event->getSubject()->entity->author !== 'admin') {
            $event->stopPropagation();
        }
    });

    return $this->Crud->execute();
}
Crud.afterDelete

This event is emitted after Table::delete() has been called.

The Crud Subject contains two keys:

  • success if true the delete() call succeeded, false otherwise
  • id The ID that was originally passed to the action and is usually the primary key of your model.
  • item The record that was found in the database.
Check Success
public function delete($id)
{
    $this->Crud->on('afterDelete', function(\Cake\Event\EventInterface $event) {
        if (!$event->getSubject()->success) {
            $this->log("Delete failed for entity " . $event->getSubject()->id);
        }
    });

    return $this->Crud->execute();
}
Crud.beforeRedirect

Simple and event driven wrapper for Controller::redirect().

The Crud Subject contains the following keys:

  • url The 1st argument to Controller::redirect().
  • status The 2nd argument to Controller::redirect().
  • exit The 3rd argument to Controller::redirect().
  • entity (Optional) The Entity from the previously emitted event.

All keys can be modified as you see fit, at the end of the event cycle they will be passed directly to Controller::redirect().

The redirect $url can be changed on the fly either by posting a redirect_url field from your form or by providing a redirect_url HTTP query key.

The default for most redirects are simply to return to the index() action.

Lookup

The Lookup Crud Action will display a record from a data source for auto-complete purposes. Used mostly for Crud-View.

Configuration

Note

Before applying any configuration to an action it must be mapped first.

If the action has not been mapped an exception will be raised.

enabled

Test or modify if the Crud Action is enabled or not.

When a CrudAction is disabled, Crud will not handle any requests to the action, and CakePHP will raise the normal \Cake\Error\MissingActionException exception if you haven’t implemented the action in your controller.

Warning

If you have enabled Crud and you are still receiving a MissingActionException, ensure the action is enabled and that the controller has the \Crud\Controller\ControllerTrait implemented.

To test if an action is enabled, call the enabled method on the action.

$this->Crud->action()->enabled();

To disable an action, call the disable method on the action.

$this->Crud->action()->disable();

To enable an action, call the enable method on the action.

$this->Crud->action()->enable();

To disable or enable multiple actions at the same time, Crud Component provides helper methods.

The enable and disable method can take a string or an array, for easy mass-updating.

$this->Crud->enable('index');
$this->Crud->enable(['index', 'add']);

$this->Crud->disable('index');
$this->Crud->disable(['index', 'add']);

Note

These methods simply calls the enable and disable method in each Crud Action class, and do not provide any magic other than mass updating.

Warning

While it’s possible to update the enabled property directly on an action using the config methods, it’s not recommend, as important cleanup logic will not be applied if you use the setConfig() method directly.

view

Get or set the view file to render at the end of the request.

The view setting is passed directly and unmodified to Controller::render().

To get the current configured view call the view method without any arguments.

$this->Crud->action()->view();

To change the view to render, pass a string as first argument.

$this->Crud->action()->view('my_custom_view');

Note

If the first parameter is NULL - which is the default value - the normal CakePHP behavior will be used.

Warning

Due to the nature of this method, once a custom view has been set, it’s not possible to revert back to the default behavior by calling ->view(null) as it will return the current configuration.

viewVar

Note

This maps directly to the $key argument in Controller::set($key, $value)

Change the name of the variable which contains the result of a index or view action query result.

To get the current configured viewVar call the viewViar method without any arguments.

$this->Crud->action()->viewVar();

To change the viewVar, pass a string as first argument.

$this->Crud->action()->viewVar('items');

For Index Action the default is plural version of the controller name.

Having a controller named PostsController would mean that the viewVar would be posts by default.

For View Action the default is singular version of the controller name.

Having a controller named PostsController would mean that the viewVar would be post by default.

serialize

Note

This setting is only relevant if you use the API listener.

Note

The API listener will always enforce success and data to be part of the _serialize array.

This method is intended to allow you to add additional keys to your API responses with ease. An example of this is the API Query Log.

To get the current configured serialize keys call the serialize method without any arguments.

$this->Crud->action()->serialize();

To change the serialize keys, pass a string or an array as first argument.

If a string is passed, it will be cast to array automatically.

$this->Crud->action()->serialize(['my', 'extra', 'keys']);
Events

This is a list of events emitted from the Lookup Crud Action.

Please see the events documentation for a full list of generic properties and how to use the event system correctly.

Crud.startup

Called after the Controller::beforeFilter() and before the Crud action.

It’s emitted from CrudComponent::startup() and thus is fired in the same cycle as all Component::startup() events.

Crud.beforeFilter

Triggered when a CrudAction is going to handle a CakePHP request.

It’s emitted from CrudComponent::beforeFilter and thus is fired in the same cycle as all Controller::beforeFilter events.

Crud.beforeLookup

This event is emitted before Controller::paginate() is called inside the Lookup Action.

Add Conditions
public function lookup()
{
    $this->Crud->on('beforeLookup', function(\Cake\Event\EventInterface $event) {
        $this->paginate['conditions']['is_active'] = true;
    });

    return $this->Crud->execute();
}
Crud.afterLookup

This event is emitted right after the call to Controller::paginate() in the Lookup Action.

The entities property of the event object contains all the database records found in the pagination call.

Modify the Result
public function lookup()
{
    $this->Crud->on('afterLookup', function(\Cake\Event\EventInterface $event) {
        foreach ($event->getSubject()->entities as $entity) {
            // $entity is an entity
        }
    });

    return $this->Crud->execute();
}
Crud.recordNotFound

Note

This event will throw an exception.

The default configuration will thrown an Cake\Error\NotFoundException which will yield a 404 response.

The event is triggered after a find did not find any records in the database.

You can modify the exception class thrown using CrudComponent::message method

Crud.beforeRender

Invoked right before the view will be rendered.

This is also before the controllers own beforeRender callback.

Bulk

If you need to perform an action against a number of records, you can extend the abstract Bulk\BaseAction class to create your own.

Three BulkAction classes exist in the core:

  • Delete: Deletes a set of entities
  • SetValue: Sets a field to a value for a set of entities
  • Toggle: Toggles the value of a boolean field for a set of entities

To create your own BulkAction, simply create a new action class with a _bulk method. This method takes a CakePHP Query object as its first argument

<?php
namespace App\Crud\Action;

use Cake\ORM\Query;
use Crud\Action\Bulk\BaseAction;

class ApproveAction extends BaseAction
{
  /**
   * Set the value of the approved field to true
   * for a set of entities
   *
   * @param \Cake\ORM\Query $query The query to act upon
   * @return boolean
   */
  protected function _bulk(Query $query)
  {
    $query->update()->set(['approved' => true]);
    $statement = $query->execute();
    $statement->closeCursor();
    return $statement->rowCount();
  }
}
Configuration

Note

Before applying any configuration to an action it must be mapped first.

If the action has not been mapped an exception will be raised.

enabled

Test or modify if the Crud Action is enabled or not.

When a CrudAction is disabled, Crud will not handle any requests to the action, and CakePHP will raise the normal \Cake\Error\MissingActionException exception if you haven’t implemented the action in your controller.

Warning

If you have enabled Crud and you are still receiving a MissingActionException, ensure the action is enabled and that the controller has the \Crud\Controller\ControllerTrait implemented.

To test if an action is enabled, call the enabled method on the action.

$this->Crud->action()->enabled();

To disable an action, call the disable method on the action.

$this->Crud->action()->disable();

To enable an action, call the enable method on the action.

$this->Crud->action()->enable();

To disable or enable multiple actions at the same time, Crud Component provides helper methods.

The enable and disable method can take a string or an array, for easy mass-updating.

$this->Crud->enable('index');
$this->Crud->enable(['index', 'add']);

$this->Crud->disable('index');
$this->Crud->disable(['index', 'add']);

Note

These methods simply calls the enable and disable method in each Crud Action class, and do not provide any magic other than mass updating.

Warning

While it’s possible to update the enabled property directly on an action using the config methods, it’s not recommend, as important cleanup logic will not be applied if you use the setConfig() method directly.

findMethod

The 1st parameter to Table::find() - the default value is all.

To get the current configured findMethod keys call the findMethod method without any arguments.

$this->Crud->action()->findMethod();

To change the findMethod value pass a string argument to the method

$this->Crud->action()->findMethod('my_custom_finder');
Events

This is a list of events emitted from actions that extend Bulk\BaseAction.

Please see the events documentation for a full list of generic properties and how to use the event system correctly.

Crud.startup

Called after the Controller::beforeFilter() and before the Crud action.

It’s emitted from CrudComponent::startup() and thus is fired in the same cycle as all Component::startup() events.

Crud.beforeFilter

Triggered when a CrudAction is going to handle a CakePHP request.

It’s emitted from CrudComponent::beforeFilter and thus is fired in the same cycle as all Controller::beforeFilter events.

Crud.beforeBulk

This event is emitted before _bulk() is called on a Bulk Crud action.

The Crud Subject contains the following keys:

  • ids A list of ids of entities, from the request data
  • repository An instance of the Repository (Table) which the query will be executed against.
  • query A Query object from the Repository where $PrimaryKey => $IdFromRequest is already added to the conditions.

To abort a bulk action, simply stop the event by calling $event->stopPropagation().

Stop Bulk Action
public function bulk($id)
{
    $this->Crud->on('beforeBulk', function(\Cake\Event\EventInterface $event) {
        // Stop the bulk event, the action will not continue
        if ($event->getSubject()->item->author !== 'admin') {
            $event->stopPropagation();
        }
    });

    return $this->Crud->execute();
}
Crud.afterBulk

This event is emitted after calling _bulk() on a Bulk Crud action.

The Crud Subject contains two keys:

  • success if true the _bulk() call succeeded, false otherwise
  • ids A list of ids of entities, from the request data
  • repository An instance of the Repository (Table) which the query will be executed against.
  • query A Query object from the Repository where $PrimaryKey => $IdFromRequest is already added to the conditions.
Check Success
public function bulk($id)
{
    $this->Crud->on('afterBulk', function(\Cake\Event\EventInterface $event) {
        if (!$event->getSubject()->success) {
            $this->log("Bulk action failed");
        }
    });

    return $this->Crud->execute();
}
Crud.setFlash

Simple and event driven wrapper for SessionComponent::setFlash.

The Crud Subject contains the following keys:

  • text The 1st argument to SessionComponent::setFlash.
  • element The 2nd argument to SessionComponent::setFlash.
  • params The 3rd argument to SessionComponent::setFlash.
  • key The 4th argument to SessionComponent::setFlash.
  • entity (Optional) The Entity from the previously emitted event.

All keys can be modified as you see fit, at the end of the event cycle they will be passed directly to SessionComponent::setFlash.

Defaults are stored in the messages configuration array for each action.

If you do not want to use this feature, simply stop the event by calling its stopPropagation() method.

If you’d like to customise the flash messages that are used, perhaps you’re using friendsofcake/bootstrap-ui. It’s actually quite simple to do, and can be done as part of the component configuration or on the fly.

public function initialize()
{
      $this->loadComponent('Crud.Crud', [
          'actions' => [
              'edit' => [
                  'className' => 'Crud.Edit',
                  'messages' => [
                      'success' => [
                          'params' => ['class' => 'alert alert-success alert-dismissible']
                      ],
                      'error' => [
                          'params' => ['class' => 'alert alert-danger alert-dismissible']
                      ]
                  ],
              ]
          ]
      ]);
}

If you’d like to configure it on the fly you can use the eventManager to change the event subject as the event is emitted.

$this->eventManager()->on('Crud.setFlash', function (Event $event) {
    if ($event->getSubject()->success) {
        $event->getSubject()->params['class'] = ['alert', 'alert-success', 'alert-dismissible'];
    }
});
Crud.beforeRedirect

Simple and event driven wrapper for Controller::redirect().

The Crud Subject contains the following keys:

  • url The 1st argument to Controller::redirect().
  • status The 2nd argument to Controller::redirect().
  • exit The 3rd argument to Controller::redirect().
  • entity (Optional) The Entity from the previously emitted event.

All keys can be modified as you see fit, at the end of the event cycle they will be passed directly to Controller::redirect().

The redirect $url can be changed on the fly either by posting a redirect_url field from your form or by providing a redirect_url HTTP query key.

The default for most redirects are simply to return to the index() action.

Bulk Delete

You can use the Bulk\DeleteAction class to delete a group of database records.

<?php
namespace App\Controller;

class PostsController extends AppController
{
    public function initialize(): void
    {
        parent::initialize();
        $this->Crud->mapAction('deleteAll', 'Crud.Bulk/Delete');
    }
}
Configuration

Note

Before applying any configuration to an action it must be mapped first.

If the action has not been mapped an exception will be raised.

enabled

Test or modify if the Crud Action is enabled or not.

When a CrudAction is disabled, Crud will not handle any requests to the action, and CakePHP will raise the normal \Cake\Error\MissingActionException exception if you haven’t implemented the action in your controller.

Warning

If you have enabled Crud and you are still receiving a MissingActionException, ensure the action is enabled and that the controller has the \Crud\Controller\ControllerTrait implemented.

To test if an action is enabled, call the enabled method on the action.

$this->Crud->action()->enabled();

To disable an action, call the disable method on the action.

$this->Crud->action()->disable();

To enable an action, call the enable method on the action.

$this->Crud->action()->enable();

To disable or enable multiple actions at the same time, Crud Component provides helper methods.

The enable and disable method can take a string or an array, for easy mass-updating.

$this->Crud->enable('index');
$this->Crud->enable(['index', 'add']);

$this->Crud->disable('index');
$this->Crud->disable(['index', 'add']);

Note

These methods simply calls the enable and disable method in each Crud Action class, and do not provide any magic other than mass updating.

Warning

While it’s possible to update the enabled property directly on an action using the config methods, it’s not recommend, as important cleanup logic will not be applied if you use the setConfig() method directly.

findMethod

The 1st parameter to Table::find() - the default value is all.

To get the current configured findMethod keys call the findMethod method without any arguments.

$this->Crud->action()->findMethod();

To change the findMethod value pass a string argument to the method

$this->Crud->action()->findMethod('my_custom_finder');
Events

This is a list of events emitted from actions that extend Bulk\BaseAction.

Please see the events documentation for a full list of generic properties and how to use the event system correctly.

Crud.startup

Called after the Controller::beforeFilter() and before the Crud action.

It’s emitted from CrudComponent::startup() and thus is fired in the same cycle as all Component::startup() events.

Crud.beforeFilter

Triggered when a CrudAction is going to handle a CakePHP request.

It’s emitted from CrudComponent::beforeFilter and thus is fired in the same cycle as all Controller::beforeFilter events.

Crud.beforeBulk

This event is emitted before _bulk() is called on a Bulk Crud action.

The Crud Subject contains the following keys:

  • ids A list of ids of entities, from the request data
  • repository An instance of the Repository (Table) which the query will be executed against.
  • query A Query object from the Repository where $PrimaryKey => $IdFromRequest is already added to the conditions.

To abort a bulk action, simply stop the event by calling $event->stopPropagation().

Stop Bulk Action
public function bulk($id)
{
    $this->Crud->on('beforeBulk', function(\Cake\Event\EventInterface $event) {
        // Stop the bulk event, the action will not continue
        if ($event->getSubject()->item->author !== 'admin') {
            $event->stopPropagation();
        }
    });

    return $this->Crud->execute();
}
Crud.afterBulk

This event is emitted after calling _bulk() on a Bulk Crud action.

The Crud Subject contains two keys:

  • success if true the _bulk() call succeeded, false otherwise
  • ids A list of ids of entities, from the request data
  • repository An instance of the Repository (Table) which the query will be executed against.
  • query A Query object from the Repository where $PrimaryKey => $IdFromRequest is already added to the conditions.
Check Success
public function bulk($id)
{
    $this->Crud->on('afterBulk', function(\Cake\Event\EventInterface $event) {
        if (!$event->getSubject()->success) {
            $this->log("Bulk action failed");
        }
    });

    return $this->Crud->execute();
}
Crud.setFlash

Simple and event driven wrapper for SessionComponent::setFlash.

The Crud Subject contains the following keys:

  • text The 1st argument to SessionComponent::setFlash.
  • element The 2nd argument to SessionComponent::setFlash.
  • params The 3rd argument to SessionComponent::setFlash.
  • key The 4th argument to SessionComponent::setFlash.
  • entity (Optional) The Entity from the previously emitted event.

All keys can be modified as you see fit, at the end of the event cycle they will be passed directly to SessionComponent::setFlash.

Defaults are stored in the messages configuration array for each action.

If you do not want to use this feature, simply stop the event by calling its stopPropagation() method.

If you’d like to customise the flash messages that are used, perhaps you’re using friendsofcake/bootstrap-ui. It’s actually quite simple to do, and can be done as part of the component configuration or on the fly.

public function initialize()
{
      $this->loadComponent('Crud.Crud', [
          'actions' => [
              'edit' => [
                  'className' => 'Crud.Edit',
                  'messages' => [
                      'success' => [
                          'params' => ['class' => 'alert alert-success alert-dismissible']
                      ],
                      'error' => [
                          'params' => ['class' => 'alert alert-danger alert-dismissible']
                      ]
                  ],
              ]
          ]
      ]);
}

If you’d like to configure it on the fly you can use the eventManager to change the event subject as the event is emitted.

$this->eventManager()->on('Crud.setFlash', function (Event $event) {
    if ($event->getSubject()->success) {
        $event->getSubject()->params['class'] = ['alert', 'alert-success', 'alert-dismissible'];
    }
});
Crud.beforeRedirect

Simple and event driven wrapper for Controller::redirect().

The Crud Subject contains the following keys:

  • url The 1st argument to Controller::redirect().
  • status The 2nd argument to Controller::redirect().
  • exit The 3rd argument to Controller::redirect().
  • entity (Optional) The Entity from the previously emitted event.

All keys can be modified as you see fit, at the end of the event cycle they will be passed directly to Controller::redirect().

The redirect $url can be changed on the fly either by posting a redirect_url field from your form or by providing a redirect_url HTTP query key.

The default for most redirects are simply to return to the index() action.

Bulk Set Value

You can use the Bulk\SetValueAction class to specify the value of a given field for a group of database records.

<?php
namespace App\Controller;

class PostsController extends AppController
{
    public function initialize(): void
    {
        parent::initialize();
        $this->Crud->mapAction('publishAll', [
            'className' => 'Crud.Bulk/SetValue',
            'field' => 'status',
            'value' => 'publish'
        ]);
    }
}
Configuration

Note

Before applying any configuration to an action it must be mapped first.

If the action has not been mapped an exception will be raised.

enabled

Test or modify if the Crud Action is enabled or not.

When a CrudAction is disabled, Crud will not handle any requests to the action, and CakePHP will raise the normal \Cake\Error\MissingActionException exception if you haven’t implemented the action in your controller.

Warning

If you have enabled Crud and you are still receiving a MissingActionException, ensure the action is enabled and that the controller has the \Crud\Controller\ControllerTrait implemented.

To test if an action is enabled, call the enabled method on the action.

$this->Crud->action()->enabled();

To disable an action, call the disable method on the action.

$this->Crud->action()->disable();

To enable an action, call the enable method on the action.

$this->Crud->action()->enable();

To disable or enable multiple actions at the same time, Crud Component provides helper methods.

The enable and disable method can take a string or an array, for easy mass-updating.

$this->Crud->enable('index');
$this->Crud->enable(['index', 'add']);

$this->Crud->disable('index');
$this->Crud->disable(['index', 'add']);

Note

These methods simply calls the enable and disable method in each Crud Action class, and do not provide any magic other than mass updating.

Warning

While it’s possible to update the enabled property directly on an action using the config methods, it’s not recommend, as important cleanup logic will not be applied if you use the setConfig() method directly.

findMethod

The 1st parameter to Table::find() - the default value is all.

To get the current configured findMethod keys call the findMethod method without any arguments.

$this->Crud->action()->findMethod();

To change the findMethod value pass a string argument to the method

$this->Crud->action()->findMethod('my_custom_finder');
Events

This is a list of events emitted from actions that extend Bulk\BaseAction.

Please see the events documentation for a full list of generic properties and how to use the event system correctly.

Crud.startup

Called after the Controller::beforeFilter() and before the Crud action.

It’s emitted from CrudComponent::startup() and thus is fired in the same cycle as all Component::startup() events.

Crud.beforeFilter

Triggered when a CrudAction is going to handle a CakePHP request.

It’s emitted from CrudComponent::beforeFilter and thus is fired in the same cycle as all Controller::beforeFilter events.

Crud.beforeBulk

This event is emitted before _bulk() is called on a Bulk Crud action.

The Crud Subject contains the following keys:

  • ids A list of ids of entities, from the request data
  • repository An instance of the Repository (Table) which the query will be executed against.
  • query A Query object from the Repository where $PrimaryKey => $IdFromRequest is already added to the conditions.

To abort a bulk action, simply stop the event by calling $event->stopPropagation().

Stop Bulk Action
public function bulk($id)
{
    $this->Crud->on('beforeBulk', function(\Cake\Event\EventInterface $event) {
        // Stop the bulk event, the action will not continue
        if ($event->getSubject()->item->author !== 'admin') {
            $event->stopPropagation();
        }
    });

    return $this->Crud->execute();
}
Crud.afterBulk

This event is emitted after calling _bulk() on a Bulk Crud action.

The Crud Subject contains two keys:

  • success if true the _bulk() call succeeded, false otherwise
  • ids A list of ids of entities, from the request data
  • repository An instance of the Repository (Table) which the query will be executed against.
  • query A Query object from the Repository where $PrimaryKey => $IdFromRequest is already added to the conditions.
Check Success
public function bulk($id)
{
    $this->Crud->on('afterBulk', function(\Cake\Event\EventInterface $event) {
        if (!$event->getSubject()->success) {
            $this->log("Bulk action failed");
        }
    });

    return $this->Crud->execute();
}
Crud.setFlash

Simple and event driven wrapper for SessionComponent::setFlash.

The Crud Subject contains the following keys:

  • text The 1st argument to SessionComponent::setFlash.
  • element The 2nd argument to SessionComponent::setFlash.
  • params The 3rd argument to SessionComponent::setFlash.
  • key The 4th argument to SessionComponent::setFlash.
  • entity (Optional) The Entity from the previously emitted event.

All keys can be modified as you see fit, at the end of the event cycle they will be passed directly to SessionComponent::setFlash.

Defaults are stored in the messages configuration array for each action.

If you do not want to use this feature, simply stop the event by calling its stopPropagation() method.

If you’d like to customise the flash messages that are used, perhaps you’re using friendsofcake/bootstrap-ui. It’s actually quite simple to do, and can be done as part of the component configuration or on the fly.

public function initialize()
{
      $this->loadComponent('Crud.Crud', [
          'actions' => [
              'edit' => [
                  'className' => 'Crud.Edit',
                  'messages' => [
                      'success' => [
                          'params' => ['class' => 'alert alert-success alert-dismissible']
                      ],
                      'error' => [
                          'params' => ['class' => 'alert alert-danger alert-dismissible']
                      ]
                  ],
              ]
          ]
      ]);
}

If you’d like to configure it on the fly you can use the eventManager to change the event subject as the event is emitted.

$this->eventManager()->on('Crud.setFlash', function (Event $event) {
    if ($event->getSubject()->success) {
        $event->getSubject()->params['class'] = ['alert', 'alert-success', 'alert-dismissible'];
    }
});
Crud.beforeRedirect

Simple and event driven wrapper for Controller::redirect().

The Crud Subject contains the following keys:

  • url The 1st argument to Controller::redirect().
  • status The 2nd argument to Controller::redirect().
  • exit The 3rd argument to Controller::redirect().
  • entity (Optional) The Entity from the previously emitted event.

All keys can be modified as you see fit, at the end of the event cycle they will be passed directly to Controller::redirect().

The redirect $url can be changed on the fly either by posting a redirect_url field from your form or by providing a redirect_url HTTP query key.

The default for most redirects are simply to return to the index() action.

Bulk Toggle

You can use the Bulk\ToggleAction class to toggle the value of a boolean field for a group of database records.

<?php
namespace App\Controller;

class PostsController extends AppController
{
    public function initialize(): void
    {
        parent::initialize();
        $this->Crud->mapAction('toggleActive', [
            'className' => 'Crud.Bulk/Toggle',
            'field' => 'toggle',
        ]);
    }
}
Configuration

Note

Before applying any configuration to an action it must be mapped first.

If the action has not been mapped an exception will be raised.

enabled

Test or modify if the Crud Action is enabled or not.

When a CrudAction is disabled, Crud will not handle any requests to the action, and CakePHP will raise the normal \Cake\Error\MissingActionException exception if you haven’t implemented the action in your controller.

Warning

If you have enabled Crud and you are still receiving a MissingActionException, ensure the action is enabled and that the controller has the \Crud\Controller\ControllerTrait implemented.

To test if an action is enabled, call the enabled method on the action.

$this->Crud->action()->enabled();

To disable an action, call the disable method on the action.

$this->Crud->action()->disable();

To enable an action, call the enable method on the action.

$this->Crud->action()->enable();

To disable or enable multiple actions at the same time, Crud Component provides helper methods.

The enable and disable method can take a string or an array, for easy mass-updating.

$this->Crud->enable('index');
$this->Crud->enable(['index', 'add']);

$this->Crud->disable('index');
$this->Crud->disable(['index', 'add']);

Note

These methods simply calls the enable and disable method in each Crud Action class, and do not provide any magic other than mass updating.

Warning

While it’s possible to update the enabled property directly on an action using the config methods, it’s not recommend, as important cleanup logic will not be applied if you use the setConfig() method directly.

findMethod

The 1st parameter to Table::find() - the default value is all.

To get the current configured findMethod keys call the findMethod method without any arguments.

$this->Crud->action()->findMethod();

To change the findMethod value pass a string argument to the method

$this->Crud->action()->findMethod('my_custom_finder');
Events

This is a list of events emitted from actions that extend Bulk\BaseAction.

Please see the events documentation for a full list of generic properties and how to use the event system correctly.

Crud.startup

Called after the Controller::beforeFilter() and before the Crud action.

It’s emitted from CrudComponent::startup() and thus is fired in the same cycle as all Component::startup() events.

Crud.beforeFilter

Triggered when a CrudAction is going to handle a CakePHP request.

It’s emitted from CrudComponent::beforeFilter and thus is fired in the same cycle as all Controller::beforeFilter events.

Crud.beforeBulk

This event is emitted before _bulk() is called on a Bulk Crud action.

The Crud Subject contains the following keys:

  • ids A list of ids of entities, from the request data
  • repository An instance of the Repository (Table) which the query will be executed against.
  • query A Query object from the Repository where $PrimaryKey => $IdFromRequest is already added to the conditions.

To abort a bulk action, simply stop the event by calling $event->stopPropagation().

Stop Bulk Action
public function bulk($id)
{
    $this->Crud->on('beforeBulk', function(\Cake\Event\EventInterface $event) {
        // Stop the bulk event, the action will not continue
        if ($event->getSubject()->item->author !== 'admin') {
            $event->stopPropagation();
        }
    });

    return $this->Crud->execute();
}
Crud.afterBulk

This event is emitted after calling _bulk() on a Bulk Crud action.

The Crud Subject contains two keys:

  • success if true the _bulk() call succeeded, false otherwise
  • ids A list of ids of entities, from the request data
  • repository An instance of the Repository (Table) which the query will be executed against.
  • query A Query object from the Repository where $PrimaryKey => $IdFromRequest is already added to the conditions.
Check Success
public function bulk($id)
{
    $this->Crud->on('afterBulk', function(\Cake\Event\EventInterface $event) {
        if (!$event->getSubject()->success) {
            $this->log("Bulk action failed");
        }
    });

    return $this->Crud->execute();
}
Crud.setFlash

Simple and event driven wrapper for SessionComponent::setFlash.

The Crud Subject contains the following keys:

  • text The 1st argument to SessionComponent::setFlash.
  • element The 2nd argument to SessionComponent::setFlash.
  • params The 3rd argument to SessionComponent::setFlash.
  • key The 4th argument to SessionComponent::setFlash.
  • entity (Optional) The Entity from the previously emitted event.

All keys can be modified as you see fit, at the end of the event cycle they will be passed directly to SessionComponent::setFlash.

Defaults are stored in the messages configuration array for each action.

If you do not want to use this feature, simply stop the event by calling its stopPropagation() method.

If you’d like to customise the flash messages that are used, perhaps you’re using friendsofcake/bootstrap-ui. It’s actually quite simple to do, and can be done as part of the component configuration or on the fly.

public function initialize()
{
      $this->loadComponent('Crud.Crud', [
          'actions' => [
              'edit' => [
                  'className' => 'Crud.Edit',
                  'messages' => [
                      'success' => [
                          'params' => ['class' => 'alert alert-success alert-dismissible']
                      ],
                      'error' => [
                          'params' => ['class' => 'alert alert-danger alert-dismissible']
                      ]
                  ],
              ]
          ]
      ]);
}

If you’d like to configure it on the fly you can use the eventManager to change the event subject as the event is emitted.

$this->eventManager()->on('Crud.setFlash', function (Event $event) {
    if ($event->getSubject()->success) {
        $event->getSubject()->params['class'] = ['alert', 'alert-success', 'alert-dismissible'];
    }
});
Crud.beforeRedirect

Simple and event driven wrapper for Controller::redirect().

The Crud Subject contains the following keys:

  • url The 1st argument to Controller::redirect().
  • status The 2nd argument to Controller::redirect().
  • exit The 3rd argument to Controller::redirect().
  • entity (Optional) The Entity from the previously emitted event.

All keys can be modified as you see fit, at the end of the event cycle they will be passed directly to Controller::redirect().

The redirect $url can be changed on the fly either by posting a redirect_url field from your form or by providing a redirect_url HTTP query key.

The default for most redirects are simply to return to the index() action.

Custom Action Classes

If you need to customize an action for any reason, you can create your own custom Crud action class.

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.

A default custom index action might be as simple as the following:

<?php
declare(strict_types=1);

namespace App\Crud\Action;

class MyIndexAction extends \Crud\Action\BaseAction
{
    /**
     * Default settings
     *
     * @var array
     */
    protected $_defaultConfig = [
        'enabled' => true,
        'scope' => 'table',
        'findMethod' => 'all',
        'view' => null,
        'viewVar' => null,
        'serialize' => [],
        'api' => [
            'success' => [
                'code' => 200
            ],
            'error' => [
                'code' => 400
            ]
        ]
    ];

    /**
    * Generic handler for all HTTP verbs
    *
    * @return void
    */
    protected function _handle()
    {
        $query = $this->_table()->find($this->findMethod());
        $items = $this->_controller()->paginate($query);
    }
}

Note

In this basic example, we have removed all the events that are emitted.

Why

The most common use-cases for a custom action class is when you need to have specific code run on all your controllers for a certain action. For example reading from the session or adjusting the query to add dynamic complex conditions.

Remember that in the Configuration you can configure your action classes on a per-action basis, so you might just want a custom action for a single action across your controllers.

Using your custom action class

Once you have created your custom action class, you can configure Crud to use it for specific actions by changing the Crud component configuration.

class AppController extends \Cake\Controller\Controller
{
    use \Crud\Controller\ControllerTrait;

    public function initialize(): void
    {
        parent::initialize();

        $this->loadComponent('Crud.Crud', [
            'actions' => [
                'index' => ['className' => '\App\Crud\Action\MyIndexAction']
            ]
        ]);
    }
}

Note

Ensure that you escape your namespace when loading your own action classes.

Using custom named controller actions

When using non CRUD named controller actions, like UsersController::drinkbeer() you can use one of the provided Crud Actions or create your own custom Action. Just assign the wanted action to the controller function:

class UsersController extends \Cake\Controller\Controller
{
    use \Crud\Controller\ControllerTrait;

    public function initialize(): void
    {
        parent::initialize();

        $this->loadComponent('Crud.Crud', [
            'actions' => [
                'drinkbeer' => ['className' => '\App\Crud\Action\DrinkbeerAction']
            ]
        ]);
    }

    public function drinkbeer() {
      $this->Crud->execute();
    }
}

Events

Events are the backbone of Crud, and your primary gateway into customization of Crud and fitting it to your applications.

You can subscribe to events from almost everywhere, and in multiple ways.

Controller

implementedEvents

We override the implementedEvents() method in the controller, and bind the Crud.beforeFind event to the _beforeFind() method in the controller.

When using this technique, you need to prefix all the event names with Crud.

Most of the other ways to listen for events do not need this, as it’s done automatically.

namespace app\Controller;

class BlogsController extends AppController
{

    public function implementedEvents(): array
    {
        return parent::implementedEvents() + ['Crud.beforeFind' => '_beforeFind'];
    }

    public function _beforeFind(\Cake\Event\EventInterface $event)
    {

    }
}

Note

It’s important that the controller event method is public, since it’s called from the CakePHP event manager, outside of the Controller scope.

The added _ prefix is there only to prevent it being executed as an controller action.

Action

You can bind events directly in your controller actions, simply call the on() method in Crud and provide a callback. The example below uses a closure for the callback, but everything that is valid for call_user_func() can be used

public function view($id)
{
  $this->Crud->on('beforeFind', function(\Cake\Event\EventInterface $event) {
      // Will only execute for the view() action
  });

  return $this->Crud->execute();
}

Note

When implementing events in your controller actions, it’s important to include return $this->Crud->execute(); otherwise Crud will not process the action.

The benefit of the controller method is that you can easily share it between two actions, like below.

public function view($id)
{
    $this->Crud->on('beforeFind', [$this, '_beforeFind']);
    return $this->Crud->execute();
}

public function admin_view($id)
{
    $this->Crud->on('beforeFind', [$this, '_beforeFind']);
    return $this->Crud->execute();
}

public function _beforeFind(\Cake\Event\EventInterface $event)
{
    // Will execute for both view() and admin_view()
}

Core Crud Events

Different Crud actions will emit a different combination of events during their execution, with different Subject data. If you are looking for events specific to an action, check the specific Crud action documentation page.

Included actions

This is a full list of all events emitted from Crud.

Crud.beforeFilter

Triggered when a CrudAction is going to handle a CakePHP request.

It’s emitted from CrudComponent::beforeFilter and thus is fired in the same cycle as all Controller::beforeFilter events.

Crud.startup

Called after the Controller::beforeFilter() and before the Crud action.

It’s emitted from CrudComponent::startup() and thus is fired in the same cycle as all Component::startup() events.

Crud.beforeDelete

This event is emitted before calling Table::delete.

The Crud Subject contains the following keys:

  • id The ID of the entity, from the URL
  • item The Entity from the find() call.

To abort a delete() simply stop the event by calling $event->stopPropagation().

Stop Delete
public function delete($id)
{
    $this->Crud->on('beforeDelete', function(\Cake\Event\EventInterface $event) {
        // Stop the delete event, the entity will not be deleted
        if ($event->getSubject()->entity->author !== 'admin') {
            $event->stopPropagation();
        }
    });

    return $this->Crud->execute();
}
Crud.afterDelete

This event is emitted after Table::delete() has been called.

The Crud Subject contains two keys:

  • success if true the delete() call succeeded, false otherwise
  • id The ID that was originally passed to the action and is usually the primary key of your model.
  • item The record that was found in the database.
Check Success
public function delete($id)
{
    $this->Crud->on('afterDelete', function(\Cake\Event\EventInterface $event) {
        if (!$event->getSubject()->success) {
            $this->log("Delete failed for entity " . $event->getSubject()->id);
        }
    });

    return $this->Crud->execute();
}
Crud.beforeFind

The event is emitted before calling the find method in the table.

The Crud Subject contains the following keys:

  • id The ID that was originally passed to the action and usually the primary key value of your table.
  • repository An instance of the Repository (Table) which the query will be executed against.
  • query A Query object from the Repository where $PrimaryKey => $IdFromRequest is already added to the conditions.

This is the last place you can modify the query before it’s executed against the database.

Note

An example

Given the URL: /posts/view/10 the repository object will be an instance of PostsTable and the query includes a WHERE condition with Posts.id = 10

After the event has emitted, the database query is executed with LIMIT 1.

If a record is found the Crud.afterFind event is emitted.

Warning

If no record is found in the database, the recordNotFound event is emitted instead of Crud.afterFind.

Add Conditions
public function delete($id)
{
    $this->Crud->on('beforeFind', function(\Cake\Event\EventInterface $event) {
        $event->getSubject()->query->where(['author' => $this->Auth->user('id')]);
    });

    return $this->Crud->execute();
}
Crud.afterFind

After the query has been executed, and a record has been found this event is emitted.

The Crud Subject contains two keys:

  • id The ID that was originally passed to the action and is usually the primary key of your model.
  • entity The record that was found in the database.

Note

If an entity is not found, the RecordNotFound event is emitted instead.

Logging the Found Item
public function delete($id)
{
    $this->Crud->on('afterFind', function(\Cake\Event\EventInterface $event) {
        $this->log("Found item: " . $event->getSubject()->entity->id . " in the database");
    });

    return $this->Crud->execute();
}
Crud.beforeSave

Note

Do not confuse this event with the beforeSave callback in the ORM layer

Called right before calling Table::save().

The Crud Subject contains the following keys:

  • entity An entity object marshaled with the HTTP POST data from the request.
  • saveMethod A string with the saveMethod.
  • saveOptions An array with the saveOptions.

All modifications to these keys will be passed into the Table::$saveMethod.

Warning

After this event has been emitted, changes done through the $action->saveMethod() or $action->saveOptions() methods will no longer affect the code, as the rest of the code uses the values from the Crud Subject

Crud.afterSave

Note

Do not confuse this event with the afterSave callback in the ORM layer.

This event is emitted right after the call to Table::save().

The Crud Subject contains the following keys:

  • success indicates whether or not the Table::save() call succeed or not.
  • created true if the record was created and false if the record was updated.
  • entity An entity object marshaled with the HTTP POST data from the request and the save() logic.
Check Created Status
public function edit($id)
{
    $this->Crud->on('afterSave', function(\Cake\Event\EventInterface $event) {
        if ($event->getSubject()->created) {
            $this->log("The entity was created");
        } else {
            $this->log("The entity was updated");
        }
    });

    return $this->Crud->execute();
}
Check Success Status
public function edit($id)
{
    $this->Crud->on('afterSave', function(\Cake\Event\EventInterface $event) {
        if ($event->getSubject()->success) {
            $this->log("The entity was saved successfully");
        } else {
            $this->log("The entity was NOT saved successfully");
        }
    });

    return $this->Crud->execute();
}
Get Entity ID
public function add()
{
    $this->Crud->on('afterSave', function(\Cake\Event\EventInterface $event) {
        if ($event->getSubject()->created) {
            $this->log("The entity was created with id: " . $event->getSubject()->entity->id);
        }
    });

    return $this->Crud->execute();
}
Crud.beforePaginate

This event is emitted before Controller::paginate() is called.

Add Conditions
public function index()
{
    $this->Crud->on('beforePaginate', function(\Cake\Event\EventInterface $event) {
        $this->paginate['conditions']['is_active'] = true;
    });

    return $this->Crud->execute();
}
Crud.afterPaginate

This event is emitted right after the call to Controller::paginate().

The entities property of the event object contains all the database records found in the pagination call.

Modify the Result
public function index()
{
    $this->Crud->on('afterPaginate', function(\Cake\Event\EventInterface $event) {
        foreach ($event->getSubject()->entities as $entity) {
            // $entity is an entity
        }
    });

    return $this->Crud->execute();
}
Crud.beforeRedirect

Simple and event driven wrapper for Controller::redirect().

The Crud Subject contains the following keys:

  • url The 1st argument to Controller::redirect().
  • status The 2nd argument to Controller::redirect().
  • exit The 3rd argument to Controller::redirect().
  • entity (Optional) The Entity from the previously emitted event.

All keys can be modified as you see fit, at the end of the event cycle they will be passed directly to Controller::redirect().

The redirect $url can be changed on the fly either by posting a redirect_url field from your form or by providing a redirect_url HTTP query key.

The default for most redirects are simply to return to the index() action.

Crud.beforeRender

Invoked right before the view will be rendered.

This is also before the controllers own beforeRender callback.

Crud.recordNotFound

Note

This event will throw an exception.

The default configuration will thrown an Cake\Error\NotFoundException which will yield a 404 response.

The event is triggered after a find did not find any records in the database.

You can modify the exception class thrown using CrudComponent::message method

Crud.setFlash

Simple and event driven wrapper for SessionComponent::setFlash.

The Crud Subject contains the following keys:

  • text The 1st argument to SessionComponent::setFlash.
  • element The 2nd argument to SessionComponent::setFlash.
  • params The 3rd argument to SessionComponent::setFlash.
  • key The 4th argument to SessionComponent::setFlash.
  • entity (Optional) The Entity from the previously emitted event.

All keys can be modified as you see fit, at the end of the event cycle they will be passed directly to SessionComponent::setFlash.

Defaults are stored in the messages configuration array for each action.

If you do not want to use this feature, simply stop the event by calling its stopPropagation() method.

If you’d like to customise the flash messages that are used, perhaps you’re using friendsofcake/bootstrap-ui. It’s actually quite simple to do, and can be done as part of the component configuration or on the fly.

public function initialize()
{
      $this->loadComponent('Crud.Crud', [
          'actions' => [
              'edit' => [
                  'className' => 'Crud.Edit',
                  'messages' => [
                      'success' => [
                          'params' => ['class' => 'alert alert-success alert-dismissible']
                      ],
                      'error' => [
                          'params' => ['class' => 'alert alert-danger alert-dismissible']
                      ]
                  ],
              ]
          ]
      ]);
}

If you’d like to configure it on the fly you can use the eventManager to change the event subject as the event is emitted.

$this->eventManager()->on('Crud.setFlash', function (Event $event) {
    if ($event->getSubject()->success) {
        $event->getSubject()->params['class'] = ['alert', 'alert-success', 'alert-dismissible'];
    }
});

Crud Subject

The Crud Subject is the class which is passed as the subject of all the events that the Crud plugin emits during its execution. Depending on the action being scaffolded, and what it’s working on the contents of the subject can be different.

Core event subjects

You can find many of the subject contents are included as part of the Core Crud Events documentation. This is because the subject of the event is very specific to the event being emitted.

When dealing with listeners, you are able to manipulate the subject of the event in order to change Crud’s behavior. Such as changing pagination, or adding extra conditions to a query.

This is an example of the data passed in a beforeFind event subject.

<?php
public function view($id)
{
    $this->Crud->on('beforeFind', function (\Cake\Event\EventInterface $event) {
        $query = $event->getSubject()->query;
        $primaryKey = $event->getSubject()->id;
        $table = $event->getSubject()->repository;
    });
}

Find more examples in the Core Crud Events documentation, for the event you need.

Listeners

Tip

While CRUD provides many listeners, it’s recommended that you add your own reusable listeners for your application needs

Listeners are the foundation for the extreme flexibility Crud provides you as an application developer.

The event system allows you to hook into the most important part of the Crud actions flow and customize it to your unique application needs.

The Anatomy Of A Listener

The listener system is simply the Events System from CakePHP, and all the official documentation and usage also applies to Crud.

The Crud event system uses two methods trigger() and on() to interface the underlying CakePHP event system.

The only hard requirement for a Crud listener is that it needs to either implement the implementedEvents() method or extend \Crud\Listener\Base.

Below is the code for a simple Crud listener. 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.

Class And Namespace

All built-in listeners in Crud live in the Crud\Listener namespace.

All listeners in Crud, including yours, should inherit from the Crud\Listener\Base class. This class is abstract and provides numerous auxiliary methods which can be useful for you both as a developer and 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
28
29
30
31
<?php
namespace Crud\Listener;

class Example extends \Crud\Listener\BaseListener
{

    /**
     * Returns a list of all events that will fire in the lister during the Crud life-cycle.
     *
     * @return array
     */
    public function implementedEvents(): array
    {
        return [
            'Crud.beforeRender' => ['callable' => 'beforeRender']
        ];
    }

    /**
     * Executed when Crud.beforeRender is emitted.
     *
     * @param \Cake\Event\EventInterface $event Event instance
     *
     * @return void
     */
    public function beforeRender(\Cake\Event\EventInterface $event)
    {
        $this->_response()->header('X-Powered-By', 'CRUD 4.0');
    }

}

Implemented Events

As documented in the CakePHP Events System all listeners must contain a implementedEvents method.

In this example, we simply request that beforeRender in our class is executed every time a Crud.beforeRender event is emitted.

 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
28
29
30
31
<?php
namespace Crud\Listener;

class Example extends \Crud\Listener\BaseListener
{

    /**
     * Returns a list of all events that will fire in the lister during the Crud life-cycle.
     *
     * @return array
     */
    public function implementedEvents(): array
    {
        return [
            'Crud.beforeRender' => ['callable' => 'beforeRender']
        ];
    }

    /**
     * Executed when Crud.beforeRender is emitted.
     *
     * @param \Cake\Event\EventInterface $event Event instance
     *
     * @return void
     */
    public function beforeRender(\Cake\Event\EventInterface $event)
    {
        $this->_response()->header('X-Powered-By', 'CRUD 4.0');
    }

}

Note

The Crud.beforeRender event is similar to the Controller and View event of the same name, but Crud.beforeRender is called first, and can halt the entire rendering process

The Callback

This method gets executed every time a Crud.beforeRender event is emitted from within Crud or by you as a developer. When the event is emitted, we append a header to the client HTTP response named X-Powered-By with the value CRUD 4.0.

 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
28
29
30
31
<?php
namespace Crud\Listener;

class Example extends \Crud\Listener\BaseListener
{

    /**
     * Returns a list of all events that will fire in the lister during the Crud life-cycle.
     *
     * @return array
     */
    public function implementedEvents(): array
    {
        return [
            'Crud.beforeRender' => ['callable' => 'beforeRender']
        ];
    }

    /**
     * Executed when Crud.beforeRender is emitted.
     *
     * @param \Cake\Event\EventInterface $event Event instance
     *
     * @return void
     */
    public function beforeRender(\Cake\Event\EventInterface $event)
    {
        $this->_response()->header('X-Powered-By', 'CRUD 4.0');
    }

}

Included listeners

Crud comes with a selection of listeners covering the most common use-cases. These allow you to tap into the events within the plugin and change behavior to suit your application, or to provide extra functionality, such as an API.

API

This listener allows you to easily create a JSON or XML Api built on top of Crud.

Introduction

Note

The API listener depends on the RequestHandler to be loaded before Crud.

Please also see the CakePHP documentation on JSON and XML views

Setup
Routing

You need to tell the Router to parse extensions else it won’t be able toprocess and render json and xml URL extension.

// config/routes.php
Router::extensions(['json', 'xml']);

Ensure this statement is used before connecting any routes, and is in the routing global scope.

Controller

Attach it on the fly in your controllers beforeFilter, this is recommended if you want to attach it only to specific controllers and actions.

<?php
class SamplesController extends AppController {

  public function beforeFilter(\Cake\Event\EventInterface $event)
  {
    parent::beforeFilter($event);
    $this->Crud->addListener('Crud.Api');
  }
}

Attach it using components array, this is recommended if you want to attach it to all controllers, application wide.

<?php
class AppController extends Controller {

  public function initialize(): void
  {
      $this->loadComponent('RequestHandler');
      $this->loadComponent('Crud.Crud', [
        'actions' => [
          'Crud.Index',
          'Crud.View'
        ],
        'listeners' => ['Crud.Api']
      ]);
}
Request detectors

The Api Listener creates 3 new detectors in your Request object.

is(‘json’)

Checks if the extension of the request is .json or if the requester accepts json as part of the HTTP accepts header.

is(‘xml’)

Checks if the extension of the request is .xml or if the requester accepts XML as part of the HTTP accepts header.

is(‘api’)

Checking if the request is either is('json') or is('xml').

Default behavior

If the current request doesn’t evaluate is('api') to true, the listener won’t do anything at all.

All its callbacks will simply return NULL and don’t get in your way.

Exception handler

The Api listener overrides the Exception.renderer for api requests, so in case of an error, a standardized error will be returned, in either json or xml - according to the API request type.

Create a custom exception renderer by extending the Crud’s ExceptionRenderer class and enabling it with the exceptionRenderer configuration option.

<?php
class AppController extends Controller {

  public function initialize(): void
  {
    parent::initialize();
    $this->Crud->setConfig(['listeners.api.exceptionRenderer' => 'App\Error\ExceptionRenderer']);
  }
}

Note: However if you are using CakePHP 3.3+’s PSR7 middleware feature the exceptionRenderer config won’t be used and instead you will have to set the Error.exceptionRenderer config in config/app.php to 'Crud\Error\ExceptionRenderer' as following:

'Error' => [
    'errorLevel' => E_ALL,
    'exceptionRenderer' => 'Crud\Error\ExceptionRenderer',
    'skipLog' => [],
    'log' => true,
    'trace' => true,
],
Request type enforcing

The API listener will try to enforce some best practices on how an API should behave.

For a request to index and view the HTTP request type must be HTTP GET - else an MethodNotAllowed exception will be raised.

For a request to add the HTTP request type must be HTTP POST - else an MethodNotAllowed exception will be raised.

For a request to edit the HTTP request type must be HTTP PUT - else an MethodNotAllowed exception will be raised.

For a request to delete the HTTP request type must be HTTP DELETE - else an MethodNotAllowed exception will be raised.

You can find out more about RESTful on Wikipedia.

Response format

The default response format for both XML and JSON has two root keys, success and data. It’s possible to add your own root keys simply by using _serialize on the view var.

JSON response
{
  "success": true,
  "data": {

  }
}
XML response
<response>
  <success>1</success>
  <data></data>
</response>
Exception response format

The data.exception key is only returned if debug is > 0

JSON exception
{
  "success": false,
  "data": {
    "code": 500,
    "url": "/some/url.json",
    "name": "Some exception message",
    "exception": {
      "class": "CakeException",
      "code": 500,
      "message": "Some exception message",
      "trace": []
    }
  }
}
XML exception
<response>
  <success>0</success>
  <data>
    <code>500</code>
    <url>/some/url.json</url>
    <name>Some exception message</name>
    <exception>
      <class>CakeException</class>
      <code>500</code>
      <message>Some exception message</message>
      <trace></trace>
      <trace></trace>
    </exception>
    <queryLog/>
  </data>
</response>
HTTP POST (add)

success is based on the event->subject->success parameter from the Add action.

If success is false a HTTP response code of 422 will be returned, along with a list of validation errors from the model in the data property of the response body.

If success is true a HTTP response code of 201 will be returned, along with the id of the created record in the data property of the response body.

The success return data can be customized by setting the api.success.data.entity config for the action.

//In your Controller/Action
$this->Crud->action()->setConfig('api.success.data.entity', [
    'id', //Extract the `id` value from the entity and place it into the `id` key in the return data.
    'status' => 'status_value' //Extract the `status_value` value from the entity and place it into the `status` key in the return data.
]);
HTTP PUT (edit)

success is based on the event->subject->success parameter from the Edit action.

If success is false a HTTP response code of 422 will be returned, along with a list of validation errors from the model in the data property of the response body.

If success is true a HTTP response code of 200 will be returned (even when the resource has not been updated).

HTTP DELETE (delete)

success is based on the event->subject->success parameter from the Delete action.

If success is false a HTTP response code of 400 will be returned.

If success is true a HTTP response code of 200 will be returned, along with empty data property in the response body.

Not Found (view / edit / delete)

In case an id is provided to a crud action and the id does not exist in the database, a 404 NotFoundException` will be thrown.

Invalid id (view / edit / delete)

In case a ìd is provided to a crud action and the id is not valid according to the database type a 500 BadRequestException will be thrown

API Pagination

Warning

This feature requires the API listener to work.

This listener appends pagination information to the API responses that is contain pagination information.

Setup

Attach this listener to your AppController components array if you want to make it available for all your controllers, application wide.

<?php
class AppController extends \Cake\Controller\Controller {

    public function initialize(): void
    {
        $this->loadComponent('RequestHandler');
        $this->loadComponent('Crud.Crud', [
            'listeners' => [
                'Crud.Api', // Required
                'Crud.ApiPagination'
            ]
        ]);
    }
}

Attach it on the fly in your controller beforeFilter if you want to limit availability of the listener to specific controllers and actions.

<?php
class SamplesController extends AppController
{
    public function beforeFilter(\Cake\Event\EventInterface $event)
    {
        $this->Crud->addListener('Crud.Api'); // Required
        $this->Crud->addListener('Crud.ApiPagination');
    }
}
Output

Paginated results will include a new pagination element similar to the one below:

{
        "success": true,
        "data":[

        ],
        "pagination":{
                "page_count": 13,
                "current_page": 1,
                "count": 25,
                "has_prev_page": false,
                "has_next_page": true
        }
}
Configuration

Configure this listener by setting the CakePHP Pagination options directly to the query object.

public function index()
{
    $this->Crud->on('beforePaginate', function (\Cake\Event\EventInterface $event) {
        $event->getSubject()->query->contain([
            'Comments' => function ($q) {
                return $q
                    ->select(['id', 'name', 'description'])
                    ->where([
                        'Comments.approved' => true
                    ]);
            }
        ]);
    });
}

API Query Log

Warning

This feature requires the API listener to work.

This listener appends query log information to the API responses

Note

The listener will only append the queryLog key if debug is set to true.

Setup

Attach it on the fly in your controller beforeFilter, this is recommended if you want to attach it only to specific controllers and actions

<?php
class SamplesController extends AppController
{
    public function beforeFilter(\Cake\Event\EventInterface $event)
    {
        $this->Crud->addListener('Crud.Api'); // Required
        $this->Crud->addListener('Crud.ApiQueryLog');
    }
}

Attach it in AppController::initialize(), this is recommended if you want to attach it to all controllers, application wide

<?php
class AppController extends \Cake\Controller\Controller
{
    public function initialize(): void
    {
        $this->loadComponent('RequestHandler');
        $this->loadComponent('Crud.Crud', [
            'listeners' => [
                'Crud.Api', // Required
                'Crud.ApiQueryLog'
            ]
        ]);
    }
}
Output

Paginated results will include a

{
    "success": true,
    "data": [

    ],
    "queryLog": {
        "default": {
            "log": [
                {
                    "query": "SELECT SOMETHING FROM SOMEWHERE",
                    "took": 2,
                    "params": [

                    ],
                    "affected": 25,
                    "numRows": 25
                },
                {
                    "query": "SELECT SOMETHING FROM SOMEWHERE'",
                    "params": [

                    ],
                    "affected": 1,
                    "numRows": 1,
                    "took": 0
                }
            ]
        }
    }
}
Configuration

By default this listener will log all defined connections.

If you need to select specific connections to log, you can use the connections configuration:

$this->loadComponent('Crud.Crud', [
    'listeners' => [
        'Crud.Api',
        'ApiQueryLog' => [
            'className' => 'Crud.ApiQueryLog',
            'connections' => ['default', 'elastic']
        ]
    ]
]);

JSON API

The Crud JsonApi listener allows you to create APIs that produce JSON API compliant output.

Please note that using this listener requires adding it to your application by:

  1. composer installing the Crud addon friendsofcake/crud-json-api
  2. configuring the listener as described in the documentation

Redirect listener

Enable more complex redirect rules.

Setup

Attach it on the fly in your controller beforeFilter, this is recommended if you want to attach it only to specific controllers and actions:

<?php
class SamplesController extends AppController
{
    public function beforeFilter(\Cake\Event\EventInterface $event)
    {
        $this->Crud->addListener('Crud.Redirect');

        parent::beforeFilter($event);
    }
}

Attach it using components array, this is recommended if you want to attach it to all controllers, application wide:

<?php
class SamplesController extends AppController {

  public function initialize()
  {
      $this->loadComponent('Crud.Crud', [
          'actions' => [
              'index',
              'view'
          ],
          'listeners' => [
              'Crud.Redirect'
          ]
      ]);
  }
}
Configuration
Readers

A reader is a closure that can access a field in an object through different means.

Below is a list of the build-in readers you can use:

Name Pseudo code Description
request.key $this->request->{$field} Access a property directly on the Request object
request.data $this->request->data($field) Access a HTTP POST data field using Hash::get() compatible format
request.query $this->request->query($field) Access a HTTP query argument using Hash::get() compatible format
model.key $Model->{$field} Access a property directly on the Model instance
model.data $Model->data[$field] Access a model data key using Hash::get() compatible format
model.field $Model->field($field) Access a model key by going to the database and read the value
subject.key $CrudSubject->{$key} Access a property directly on the event subject
Adding your own reader

Adding or overriding a reader is very simple.

The closure takes two arguments:

  1. CrudSubject $subject
  2. $key = null
<?php
class SamplesController extends AppController
{
  public function beforeFilter(\Cake\Event\EventInterface $event)
  {
    $listener = $this->Crud->listener('Redirect');
    $listener->reader($name, Closure $closure);

    // Example on a reader using Configure
    $listener->reader('configure.key', function(CrudSubject $subject, $key) {
      return Configure::read($key);
    });

    parent::beforeFilter();
  }
}
?>
Action defaults

Below is the defaults provided by build-in Crud actions:

Add action

By default Add Crud Action always redirect to array('action' => 'index') on afterSave

Name Reader Key Result Description
post_add request.data _add array('action' => 'add') By providing _add as a post key, the user will be redirected back to the add action
post_edit request.data _edit array('action' => 'edit', $id) By providing _edit as a post key, the user will be redirected to the edit action with the newly created ID as parameter
Edit action

By default Edit Crud Action always redirect to array('action' => 'index') on afterSave

Name Reader Key Result Description
post_add request.data _add array('action' => 'add') By providing _add as a post key, the user will be redirected back to the add action
post_edit request.data _edit array('action' => 'edit', $id) By providing _edit as a post key, the user will be redirected to the edit action with the same ID as parameter as the current URL
Configuring your own redirect rules

It’s very simple to modify existing or add your own redirect rules:

<?php
class SamplesController extends AppController
{
  public function beforeFilter(\Cake\Event\EventInterface $event)
  {
    // Get all the redirect rules
    $rules = $this->Crud->action()->redirectConfig();

    // Get one named rule only
    $rule = $this->Crud->action()->redirectConfig('add');

    // Configure a redirect rule:
    //
    // if $_POST['_view'] is set then redirect to
    // 'view' action with the value of '$subject->id'
    $this->Crud->action()->redirectConfig('view',
        [
            'reader' => 'request.data',    // Any reader from the list above
            'key' => '_view',              // The key to check for, passed to the reader
            'url' => [                     // The url to redirect to
                'action' => 'view',        // The final url will be '/view/$id'
                ['subject.key', 'id']      // If an array is encountered, it will be expanded the same was as 'reader'+'key'
            ]
        ]
    );

    parent::beforeFilter($event);
  }
}

Custom

Any class can be used as a Crud Listener, even the controller.

Using a controller as a listener

We override the implementedEvents() method in the controller, and bind the Crud.beforeFind event to the _beforeFind() method in the controller.

<?php
namespace App\Controller;

class BlogsController extends AppController {

  public function implementedEvents(): array
  {
      return parent::implementedEvents() + [
          'Crud.beforeFind' => '_beforeFind'
      ];
  }

  public function _beforeFind(\Cake\Event\EventInterface $event, \Cake\ORM\Query $query)
  {

  }

}
Creating a listener class

Creating your own listener class is very similar to using a controller as a listener.

<?php
namespace App\Lib\Listeners;

use Cake\Event\Event;
use Crud\Listener\BaseListener;

class MyListener extends BaseListener
{
    public function implementedEvents(): array
    {
        return [
            'Crud.beforeFind' => '_beforeFind'
        ];
    }

    public function _beforeFind(Event $event)
    {
        Log::debug('Inside the listener!');
    }
}

Creating an API

Creating a REST API using Crud is very easy and just requires adding an API Listener to your application.

Bravo-Kernel of the CakePHP community has written a great blog post on implementing an API using Crud.

Implementing the API Listener

If you’d like to get started right away with the API Listener, please check the Listeners chapter.

Implementing the JSON API Listener

To get started with the JSON API Listener, please check the listener’s documentation.

Unit Testing

To ease with unit testing of Crud Listeners and Crud Actions, it’s recommended to use the proxy methods found in [CrudBaseObject]({{site.url}}/api/develop/class-CrudBaseObject.html).

These methods are much easier to mock than the full CrudComponent object.

They also allow you to just mock the methods you need for your specific test, rather than the big dependency nightmare the CrudComponent can be in some cases.

Proxy methods

These methods are available in all CrudAction and CrudListener objects.

_crud()

Get the CrudComponent instance

$this->_crud()

_action($name)

Get an CrudAction object by it’s action name

$this->_action()
$this->_action($name)

_trigger($eventName, $data = [])

Trigger a Crud Event

$this->_trigger('beforeSave')
$this->_trigger('beforeSave', ['data' => 'keys'])
$this->_trigger('beforeSave', $this->_subject(['data' => 'keys']))

_listener($name)

Get a Listener by its name

$this->_listener('Api')

_subject($additional = [])

Create a Crud Subject - used in $this->_trigger

$this->_subject()
$this->_subject(['data' => 'keys'])

_session()

Get the Session Component instance

$this->_session()

_controller()

Get the controller for the current request

$this->_controller()

_request()

Get the current Cake\Network\Request for this HTTP Request

$this->_request()

_response()

Get the current Cake\Network\Response for this HTTP Request

$this->_response()

_entity()

Get the entity instance that is created from Controller::$modelClass

$this->_entity()

_table()

Get the table instance that is created from Controller::$modelClass

$this->_table()