CRUD View is an Admin Generator for CakePHP built on top of the CRUD plugin. It is flexible enough that it can be used only for certain parts of your applications and aims to be flexible enough so it requires little configuration.
The core philosophy behind CRUD and CRUD view is that you only need to deal with aspects of your applications. This means that you should be able to listen for events in order to modify how it looks and how it behaves.
Another goal of CRUD View is that its parts should be replaceable where possible, but it should offer a sane, ready-to-use Admin interface by default only by providing the database it needs to work with.
When you need to implement an Admin interface that is generated from the Backend. If you want to create your interface using only javascript, please only use the CRUD plugin as it will help you creating the required API.
When you want to take care about the rules of your data processing and not too much how the interface is going to look like.
If you prefer tweaking, overriding and configuring instead of doing everything from scratch.
This plugin is still in early development status, things may change suddenly, but it can be used in real projects already.
Installing CRUD view requires only a few steps
CakePHP 4.x
The recommended installation method for this plugin is by using composer.
In your aplication forlder execute:
composer require friendsofcake/crud-view
It is highly recommended that you install the Search
plugin as well:
composer require friendsofcake/search
Execute the following lines from your application folder:
bin/cake plugin load Crud
bin/cake plugin load CrudView
bin/cake plugin load BootstrapUI
bin/cake plugin load Search
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.
If you haven’t configured the CRUD plugin already, add the following lines to your
src/Controller/AppController.php
file
<?php
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('RequestHandler');
$this->loadComponent('Flash');
$this->loadComponent('Crud.Crud', [
'actions' => [
'Crud.Index',
'Crud.View',
'Crud.Add',
'Crud.Edit',
'Crud.Delete',
'Crud.Lookup',
],
'listeners' => [
// New listeners that need to be added:
'CrudView.View',
'Crud.Redirect',
'Crud.RelatedModels',
// If you need searching. Generally it's better to load these
// only in the controller for which you need searching.
'Crud.Search',
'CrudView.ViewSearch',
]
]);
}
/**
* Before render callback.
*
* @param \Cake\Event\Event $event The beforeRender event.
* @return void
*/
public function beforeRender(\Cake\Event\EventInterface $event)
{
if ($this->viewBuilder()->getClassName() === null) {
$this->viewBuilder()->setClassName('CrudView\View\CrudView');
}
}
}
If you are familair with the CRUD plugin already, you will immediately understand that Crud view is simply a listener for the events generated by the plugin. If this is new to you, don’t worry, it will be explained in the following sections.
Any controller inheriting from AppController
will automatically implement
the specified actions loaded int the CRUD
component configuration.
Therefore, you can just leave your controller code empty!
<?php
namespace App\Controller;
class CategoriesController extends AppController
{
// No code here, but we have all actions available to use!
}
You can now access your categories list by pointing your browser to
http://example.com/categories
. Browse around your new Admin interface for
each of the controllers you have in your application.
Getting comfortable with CRUD View usually depends on getting grips of the CRUD plugin first. Since much of the features this plugin provides are implemented on top of the features exposed by the CRUD plugin, much of the documentation will just repeat what it is possible in it.
Rendering a list of the rows in a table is a matter of just adding the Crud.Index
action to the Crud
component and the CrudView.View
as a listener.
public function initialize(): void
{
$this->loadComponent('Crud.Crud', [
'actions' => [
'Crud.Index',
// ...
],
'listeners' => [
'CrudView.View',
// ...
]
]);
}
There is no need to have an `index()
function in your controller. But you
can implement it to customize both the behavior and looks of the index listing
page.
<?php
declare(strict_types=1);
namespace App\Controller;
class ArticlesController extends AppController
{
public function index()
{
// Your customization and configuration changes here
return $this->Crud->execute();
}
}
Most configuration changes need to be done by using the config()
function in
the action object. The config()
method can be used for both reading and
writing.
public function index()
{
$action = $this->Crud->action(); // Gets the IndexAction object
debug($action->getConfig()); // Show all configuration related to this action
return $this->Crud->execute();
}
Below is a list of the configuration values that can be used and how they affect the rendering of your view:
By default all belongsTo
and hasOne
associations are fetched in the
pagination query for the index view. If you wanted to blacklist
one of those
associations.
Fore example you may want to not fetch the Authors
association of the
Articles
as you don’t plan to show it in the index table:
public function index()
{
$action = $this->Crud->action();
$action->setConfig('scaffold.relations_blacklist', ['Authors', ...]);
return $this->Crud->execute();
}
If you want to be specific about which association need to be fetched, just use
the scaffold.relations
configuration key:
public function index()
{
$action = $this->Crud->action();
$action->setConfig('scaffold.relations', ['Categories', 'Tags']);
return $this->Crud->execute();
}
Alternatively, you can use the Crud
plugin’s beforePaginate
method to
alter the contain()
list for the pagination query:
public function index()
{
$this->Crud->on('beforePaginate', function ($event) {
$paginationQuery = $event->getSubject()->query;
$paginationQuery->contain([
'Categories',
'Authors' => ['fields' => ['id', 'name']]
]);
});
return $this->Crud->execute();
}
If you wish to control which fields should be displayed in the index table, use
the scaffold.fields
and scaffold.fields_blacklist
configuration keys. By
default, all fields from the table will be displayed
For example, let’s avoid the created
and modified
fields from being
displayed in the index table:
public function index()
{
$action = $this->Crud->action();
$action->setConfig('scaffold.fields_blacklist', ['created', 'modified']);
return $this->Crud->execute();
}
You can also be specific about the fields, and the order, in which they should appear in the index table:
public function index()
{
$action = $this->Crud->action();
$action->setConfig('scaffold.fields', ['title', 'body', 'category', 'published_time']);
return $this->Crud->execute();
}
At the end of each row in the index table, there will be a list of actions
links, such as View
, Edit
and Delete
. If you wish to control which
actions should be displayed or not, use the scaffold.actions
and
scaffold.actions_blacklist
configurations keys.
For example, imagine we wanted to remove the Delete
link from the index
table:
public function index()
{
$action = $this->Crud->action();
$action->setConfig('scaffold.actions_blacklist', ['delete']);
return $this->Crud->execute();
}
Likewise, you can instruct the CrudView plugin on which actions should be specifically displayed in the index view:
public function index()
{
$action = $this->Crud->action();
$action->setConfig('scaffold.actions', ['view', 'add', 'edit']);
return $this->Crud->execute();
}
If you have read this far, you know almost everything there is to know about configuring any type of action using CrudView, but being explicit about what is available in all of them will not hurt.
Implementing the Add
action is done by adding the Crud.View
action to
the Crud
component configuration:
public function initialize()
{
$this->loadComponent('Crud.Crud', [
'actions' => [
'Crud.Add',
// ...
],
'listeners' => [
'CrudView.View',
'Crud.Redirect'
'Crud.RelatedModels'
// ...
]
]);
}
For the Add
action it is recommended that you add the Crud.Redirect
and
Crud.RelatedModels
listeners. The former will help adding more redirection
options after saving the record and the latter will send the required
information to the view so that the select
widgets for associations get the
correct options.
Likewise, edit actions can be implemented by adding the right configuration to
the Crud
component. This is the recommended configuration:
public function initialize(): void
{
$this->loadComponent('Crud.Crud', [
'actions' => [
'Crud.Edit',
// ...
],
'listeners' => [
'CrudView.View',
'Crud.Redirect'
'Crud.RelatedModels'
// ...
]
]);
}
As with the Add
action, the Crud.Redirect
and
Crud.RelatedModels
listeners will help handling redirection after save and
help populate the select
widgets for associations.
When adding or editing a record, you probably want to avoid some of the fields from
being displayed as an input in the form. Use the scaffold.fields
and
scaffold.fields_blacklist
.
For example, let’s avoid having inputs for the created
and modified
fields in the form:
public function add()
{
$action = $this->Crud->action();
$action->setConfig('scaffold.fields_blacklist', ['created', 'modified']);
return $this->Crud->execute();
}
It is also possible to directly specify which fields should have an input in the
form by using the scaffold.fields
configuration key:
public function edit()
{
$action = $this->Crud->action();
$action->setConfig('scaffold.fields', ['title', 'body', 'category_id']);
return $this->Crud->execute();
}
You can pass attributes or change the form input type to specific fields when
using the scaffold.fields
configuration key. For example, you may want to
add the placeholder
property to the title
input:
public function add()
{
$action = $this->Crud->action();
$action->setConfig('scaffold.fields', [
'title' => ['placeholder' => 'Insert a title here'],
'body',
'category_id'
]);
return $this->Crud->execute();
}
The configuration can be used in both add
and edit
actions.
By default the RelatedModels
listener will populate the select boxes in the
form by looking up all the records from the associated tables. For example, when
creating an Article, if you have a Categories
association it will populate
the select box for the category_id
field.
For a full explanation on RelatedModels
please visit the CRUD Documentation
for the RelatedModelsListener.
If you want to alter the query that is used for an association in particular,
you can use the relatedModels
event:
public function add()
{
$this->Crud->on('relatedModel', function(\Cake\Event\Event $event) {
if ($event->getSubject()->association->name() === 'Categories') {
$event->getSubject()->query->limit(3);
$event->getSubject()->query->where(['is_active' => true]);
}
});
return $this->Crud->execute();
}
The callback can be used in both add
and edit
actions.
In order to pre-select the right association options in an edit
action, for
example pre-selecting the category_id
in the categories select box,
CrudView will automatically fetch all associations for the entity to be
modified.
This can be wasteful at times, especially if you only allow a few associations
to be saved. For this case, you may use the scaffold.relations
and
scaffold.relations_blacklist
to control what associations are added to
contain()
:
public function edit()
{
$action $this->Crud->action();
// Only fetch association info for Categories and Tags
$action->setConfig('scaffold.relations', ['Categories', 'Tags']);
return $this->Crud->execute();
}
If you choose to use scaffold.relations_blacklist
, then you need only
specify those association that should not be added to contain()
:
public function edit()
{
$action $this->Crud->action();
// Only fetch association info for Categories and Tags
$action->setConfig('scaffold.relations_blacklist', ['Authors']);
return $this->Crud->execute();
}
You may have noticed already that in the add
form there are multiple submit
buttons. If you wish to only keep the “Save” button, you set the
scaffold.form_submit_extra_buttons
configuration key to false
:
public function add()
{
$action = $this->Crud->action();
$action->setConfig('scaffold.form_submit_extra_buttons', false);
return $this->Crud->execute();
}
Implementing a View
action, for displaying the full information for
a record, including its associations is also achieved via configuring the
Crud
component:
public function initialize()
{
$this->loadComponent('Crud.Crud', [
'actions' => [
'Crud.View',
// ...
],
'listeners' => [
'CrudView.View',
// ...
]
]);
}
For this type of action there are no extra recommended listeners that you can apply, but there are some configuration options you can use to customize the information that is displayed.
If you wish to control which fields should be displayed in the view table, use
the scaffold.fields
and scaffold.fields_blacklist
configuration keys. By
default, all fields from the table will be displayed
For example, let’s avoid the created
and modified
fields from being
displayed in the view table:
public function view()
{
$action = $this->Crud->action();
$action->setConfig('scaffold.fields_blacklist', ['created', 'modified']);
return $this->Crud->execute();
}
You can also be specific about the fields, and the order, in which they should appear in the index table:
public function view()
{
$action = $this->Crud->action();
$action->setConfig('scaffold.fields', ['title', 'body', 'category', 'published_time']);
return $this->Crud->execute();
}
By default all associations are fetched so they can be displayed in the view action.
Similarly to the Index
action, you can use the scaffold.relations
and
the scaffold.relations_blacklist
Fore example you may want to not fetch the Authors
association of the
Articles
as it may be implicit by the currently logged-in user:
public function view()
{
$action = $this->Crud->action();
$action->setConfig('scaffold.relations_blacklist', ['Authors', ...]);
return $this->Crud->execute();
}
If you want to be specific about which association need to be fetched, just use
the scaffold.relations
configuration key:
public function view()
{
$action = $this->Crud->action();
$action->setConfig('scaffold.relations', ['Categories', 'Tags']);
return $this->Crud->execute();
}
Alternatively, you can use the Crud
plugin’s beforePaginate
method to
alter the contain()
list for the pagination query:
public function view()
{
$this->Crud->on('beforeFind', function ($event) {
$event->getSubject()->query->contain([
'Categories',
'Authors' => ['fields' => ['id', 'name']]
]);
});
return $this->Crud->execute();
}
The Crud plugin provides bulk actions which can be easily used with crud view.
To set up crud action in controller do something like this in initialize method.
$this->loadComponent('Crud.Crud', [
'actions' => [
'deleteAll' => [
'className' => 'Crud.Bulk/Delete',
],
]
]);
Once a bulk action has been mapped, the scaffold.bulk_actions
configuration
key can be specified. The scaffold.bulk_actions
configuration key takes an
array of key/value pairs, where the key is the url and the value is the title.
$action = $this->Crud->action();
$action->setConfig('scaffold.bulk_actions', [
Router::url(['action' => 'deleteAll']) => __('Delete records'),
]);
The following chapters will show you how to customize the output of each field, how to override parts of the templates and implementing search auto-completion.
Despite CrudView being quite smart at guessing how to display your data and having great defaults, it is very often that you need to customize the look and feel of your Admin application.
Fields may be specified via the scaffold.fields
configuration key. By
default, this will contain a list of all columns associated with the Table being
in scope. To limit the fields used, simply specify an array of fields.
$action = $this->Crud->action();
$action->setConfig('scaffold.fields', ['title', 'description']);
You may also specify an options array. For forms, CrudView makes use of the
FormHelper::inputs()
method and will pass your array values as options when
generating the output.
$action = $this->Crud->action();
$action->setConfig('scaffold.fields', [
'title',
'thread_id' => [
'type' => 'text'
],
'featured' => [
'checked' => 'checked'
]
]);
If you wish to use the default automatic field population functionality but want
to specify settings for a few of the fields, you can use the
scaffold.field_settings
configuration key:
$action = $this->Crud->action();
$action->setConfig('scaffold.field_settings', [
'title' => [
// options here
]
]);
You may also use the scaffold.fields_blacklist
configuration key to remove
fields from the output if you are using the default automatic field population
functionality:
$action = $this->Crud->action();
$action->setConfig('scaffold.fields_blacklist', ['created', 'modified']);
Note
This functionality currently only applies to index
and view
pages.
The most immediate way of formatting a field is by passing a callable function
or object to the formatter
option. Callable functions or objects will
receive 5 arguments:
$name
The name of the field to be displayed
$value
The value of the field that should be outputted
$entity
The entity object from which the field was extracted
$options
An array of options passed to the CrudView helper when the field is being processed
$View
The view object in use during formatting
For example, imagine that when displaying the published_time
property, we
wanted to also display who approved the article:
$action = $this->Crud->action();
$action->setConfig('scaffold.fields', [
'title',
'published_time' => [
'formatter' => function ($name, $value, $entity) {
return $value->nice() . sprintf(' (Approved by %s)', $entity->approver->name);
}
],
]);
You may also specify formatters using the scaffold.field_settings
configuration key. This is useful if you want to display all fields but wish to
only configure the settings for one or two.
$action = $this->Crud->action();
$action->setConfig('scaffold.field_settings', [
'published_time' => [
'formatter' => function ($name, Time $value, Entity $entity) {
return $value->nice() . sprintf(' (Approved by %s)', $entity->approver->name);
}
],
]);
In some cases, it may be useful to access a helper within the callable. For instance, you might want to create a link:
$action = $this->Crud->action();
$action->setConfig('scaffold.fields', [
'title',
'external_id' => [
'formatter' => function ($name, $value, $entity, $options, $View) {
return $View->Html->link($name, sprintf('https://example.com/view/%d', $value));
}
],
]);
You can also keep your code DRY by configuring the CrudViewHelper
to use
a callable formatter based on column type. For .e.g.
// In controller action or preferably in beforeRender()
$this->viewBuilder()->setHelpers([
'CrudView' => [
'className' => 'CrudView.CrudView',
'fieldFormatters' => [
// Key can be any valid column type of table schema.
'datetime' => function ($name, $value, $entity, $options, $View) {
return $View->Time->nice($value);
},
'boolean' => function ($name, $value, $entity, $options, $View) {
return $value ? 'Yes' : 'No';
},
],
],
]);
Note
This functionality currently only applies to index
and view
pages.
Sometimes you want to execute more complex formatting logic, that may involve
the use of view helpers or outputting HTML. Since building HTML outside of the
view layer is not ideal, you can use the element
formatter for any of your
fields.
For example, consider this example where we want to link the published_time
to the same index action by passing some search arguments:
$action = $this->Crud->action();
$action->setConfig('scaffold.fields', [
'published_time' => [
'formatter' => 'element',
'element' => 'search/published_time',
'action' => 'index'
]
]);
We have instructed the formatter to use search/published_time
element. Then,
it is just a matter of creating the element file with the right content:
// templates/element/search/published_time.ctp
echo $this->Html->link($value->timeAgoInWords(), [
'action' => $options['action'],
'published_time' => $value->format('Y-m-d')
]);
After this, when displaying the published_time
field, there will the will be
a link similar to this one:
<a href="/articles?published_time=2015-06-23">4 days ago</a>
Element files will have available at least the following variables:
$value
: The value of the field
$field
: The name of the field it is intended to be rendered
$context
: The entity from which the value came from
$options
: The array of options associated to the field as passed in scaffold.fields
CrudView infers the name of the field by splitting the field so that it can be read by a human. Sometimes this is just not enough, or you may wish to show an entirely different header in a table or label in a form.
In our add()
and edit()
actions, you can specify the input label for
title for any of the fields by using the scaffold.fields
configuration
$action = $this->Crud->action();
$action->setConfig('scaffold.fields', [
'author_id' => ['label' => 'Author Name'],
// The rest of the fields to display here
]);
It’s easy to add an action to a controller that makes use of another CrudView action.
This does use the template provided by the edit action:
public function account() {
$this->Crud->mapAction('account', [
'className' => 'Crud.Edit',
'view' => 'edit',
]);
return $this->Crud->execute(null, $this->Auth->user('id'));
}
By default, it can be overwritten by providing a custom register.ctp
:
public function register() {
$this->Crud->mapAction('register', [
'className' => 'Crud.Add',
]);
return $this->Crud->execute();
}
All the CrudView templates are built from several elements that can be
overridden by creating them in your own templates/element
folder. The
following sections will list all the elements that can be overridden for each
type of action.
In general, if you want to override a template, it is a good idea to copy the
original implementation from
vendor/friendsofcake/crud-view/templates/element
Note
This functionality is only available for CakePHP 3.3.6 and up.
You can indicate the current page’s location within a navigational hierarchy
called a breadcrumb. CrudView does not output breadcrumbs by default, but they
may be enabled via the scaffold.breadcrumbs
configuration key.
Warning
Setting this configuration key to anything other than an array will result in no breadcrumbs.
The scaffold.breadcrumbs
configuration key takes an array of
CrudView\Breadcrumb\Breadcrumb
objects:
use CrudView\Breadcrumb\Breadcrumb;
$this->Crud->action()->setConfig('scaffold.breadcrumbs', [
new BreadCrumb('Home'),
]);
By default, CrudView\Breadcrumb\Breadcrumb
objects will output plain-text
breadcrumb entries. However, they also take url
and options
arrays:
use CrudView\Breadcrumb\Breadcrumb;
$this->Crud->action()->setConfig('scaffold.breadcrumbs', [
new BreadCrumb('Home', ['controller' => 'Posts', 'action' => 'index'], ['class' => 'derp']),
]);
You may also set any given breadcrumb to “active” by either setting the
class
option to ‘active’ or using a
CrudView\Breadcrumb\ActiveBreadCrumb
object:
// Using the "class" option method:
use CrudView\Breadcrumb\Breadcrumb;
$this->Crud->action()->setConfig('scaffold.breadcrumbs', [
new BreadCrumb('Home', '#', ['class' => 'active']),
]);
// Using the ActiveBreadCrumb method:
use CrudView\Breadcrumb\ActiveBreadCrumb;
$this->Crud->action()->setConfig('scaffold.breadcrumbs', [
new ActiveBreadCrumb('Home', '#'),
]);
Breadcrumbs are output in the layout
portion of template rendering,
outside of action
template rendering. If you wish to change the layout but
reuse the breadcrumb template logic, use the CrudView.breadcrumbs
element
like so:
<?= $this->element('breadcrumbs') ?>
Every page has what’s called the site title on the left side of the menu bar. If you want, you can customize it.
You can use the scaffold.site_title
config variable to modify the title. If
not set, it will fallback to the following alternative:
Configure::read('CrudView.siteTitle')
$action = $this->Crud->action();
$action->setConfig('scaffold.site_title', 'My Admin Site');
You can use the scaffold.site_title_link
config variable to modify the title
link. If not set, the title will not be made into a link. Both urls and cakephp
route arrays are supported.
$action = $this->Crud->action();
$action->setConfig('scaffold.site_title_link', '/');
You can use the scaffold.site_title_image
config variable to modify the
title link. If set, it replaces scaffold.site_title
.
$action = $this->Crud->action();
// Use an image included in your codebase
$action->setConfig('scaffold.site_title_image', 'site_image.png');
// Use an exact url
$action->setConfig('scaffold.site_title_image', 'http://www.google.com/images/logos/google_logo_41.png');
The “dashboard” can be used to display a default landing page for CrudView-powered
admin sites. It is made of several \Cake\View\Cell
instances, and can be extended to display items other than what is shipped with CrudView.
To use the “Dashboard”, the custom DashboardAction
needs to be mapped:
public function initialize(): void
{
parent::initialize();
$this->Crud->mapAction('dashboard', 'CrudView.Dashboard');
}
Browsing to this mapped action will result in a blank page. To customize it, a
\CrudView\Dashboard\Dashboard
can be configured on the scaffold.dashboard
key:
public function dashboard()
{
$dashboard = new \CrudView\Dashboard\Dashboard();
$this->Crud->action()->setConfig('scaffold.dashboard', $dashboard);
return $this->Crud->execute();
}
The \CrudView\Dashboard\Dashboard
instance takes two arguments:
title
: The title for the dashboard view. Defaults to Dashboard
.
columns
A number of columns to display on the view. Defaults to 1
.
public function dashboard()
{
// setting both the title and the number of columns
$dashboard = new \CrudView\Dashboard\Dashboard(__('Site Administration'), 12);
$this->Crud->action()->setConfig('scaffold.dashboard', $dashboard);
return $this->Crud->execute();
}
Any number of cells may be added to the Dashboard. All cells must extend the
\Cake\View\Cell
class.
Cells can be added via the Dashboard::addToColumn()
method. It takes a cell
instance and a column number as arguments.
// assuming the `CellTrait` is in use, we can generate a cell via `$this->cell()`
$someCell = $this->cell('SomeCell');
$dashboard = new \CrudView\Dashboard\Dashboard(__('Site Administration'), 2);
// add to the first column
$dashboard->addToColumn($someCell);
// configure the column to add to
$dashboard->addToColumn($someCell, 2);
CrudView ships with the DashboardTable
cell by default.
This can be used to display links to items in your application or offiste.
public function dashboard()
{
// setting both the title and the number of columns
$dashboard = new \CrudView\Dashboard\Dashboard(__('Site Administration'), 1);
$dashboard->addToColumn($this->cell('CrudView.DashboardTable', [
'title' => 'Important Links'
]));
$this->Crud->action()->setConfig('scaffold.dashboard', $dashboard);
return $this->Crud->execute();
}
In the above example, only a title to the DashboardTable
, which will
show a single subheading for your Dashboard.
In addition to showing a title, it is also possible to show a list of links. This can
be done by adding a links
key with an array of LinkItem
objects as the value.
Links containing urls for external websites will open in a new window by default.
public function dashboard()
{
// setting both the title and the number of columns
$dashboard = new \CrudView\Dashboard\Dashboard(__('Site Administration'), 1);
$dashboard->addToColumn($this->cell('CrudView.DashboardTable', [
'title' => 'Important Links',
'links' => [
new LinkItem('Example', 'https://example.com', ['target' => '_blank']),
],
]));
$this->Crud->action()->setConfig('scaffold.dashboard', $dashboard);
return $this->Crud->execute();
}
There is also a special kind of LinkItem
called an ActionLinkItem
. This
has a fourth argument is an array of LinkItem
objects. It can be used to show
embedded action links on the same row.
public function dashboard()
{
$dashboard = new \CrudView\Dashboard\Dashboard(__('Site Administration'), 1);
$dashboard->addToColumn($this->cell('CrudView.DashboardTable', [
'title' => 'Important Links',
'links' => [
new ActionLinkItem('Posts', ['controller' => 'Posts'], [], [
new LinkItem('Add', ['controller' => 'Posts', 'action' => 'add']),
]),
],
]));
$this->Crud->action()->setConfig('scaffold.dashboard', $dashboard);
return $this->Crud->execute();
}
The following custom view blocks are available for use within forms:
dashboard.before
: Rendered before the entire dashboard is rendered.
dashboard.after
: Rendered after the entire dashboard is rendered.
All the CrudView templates are built from several elements that can be
overridden by creating them in your own templates/element
folder. The
following sections will list all the elements that can be overridden for each
type of action.
In general, if you want to override a template, it is a good idea to copy the
original implementation from
vendor/friendsofcake/crud-view/templates/element
Create templates/element/action-header.ctp
to have full control over
what is displayed at the top of the page. This is shared across all page
types.
Fields may be specified via the scaffold.fields
configuration key. By
default, this will contain a list of all columns associated with the Table being
in scope. To limit the fields used, simply specify an array of fields:
$action = $this->Crud->action();
$action->setConfig('scaffold.fields', ['title', 'description']);
If you wish to use the default automatic field population functionality but want
to specify settings for a few of the fields, you can use the
scaffold.field_settings
configuration key:
$action = $this->Crud->action();
$action->setConfig('scaffold.field_settings', [
'title' => [
// options here
]
]);
You may also use the scaffold.fields_blacklist
configuration key to remove
fields from the output if you are using the default automatic field population
functionality:
$action = $this->Crud->action();
$action->setConfig('scaffold.fields_blacklist', ['created', 'modified']);
Note
This functionality currently only applies to index
and view
pages.
The most immediate way of formatting a field is by passing a callable function
or object to the formatter
option. Callable functions or objects will
receive 5 arguments:
$name
The name of the field to be displayed
$value
The value of the field that should be outputted
$entity
The entity object from which the field was extracted
$options
An array of options passed to the CrudView helper when the field is being processed
$View
The view object in use during formatting
For example, imagine that when displaying the published_time
property, we
wanted to also display who approved the article:
$action = $this->Crud->action();
$action->setConfig('scaffold.fields', [
'title',
'published_time' => [
'formatter' => function ($name, $value, $entity) {
return $value->nice() . sprintf(' (Approved by %s)', $entity->approver->name);
}
],
]);
You may also specify formatters using the scaffold.field_settings
configuration key. This is useful if you want to display all fields but wish to
only configure the settings for one or two.
$action = $this->Crud->action();
$action->setConfig('scaffold.field_settings', [
'published_time' => [
'formatter' => function ($name, Time $value, Entity $entity) {
return $value->nice() . sprintf(' (Approved by %s)', $entity->approver->name);
}
],
]);
In some cases, it may be useful to access a helper within the callable. For instance, you might want to create a link:
$action = $this->Crud->action();
$action->setConfig('scaffold.fields', [
'title',
'external_id' => [
'formatter' => function ($name, $value, $entity, $options, $View) {
return $View->Html->link($name, sprintf('https://example.com/view/%d', $value));
}
],
]);
You can also keep your code DRY by configuring the CrudViewHelper
to use
a callable formatter based on column type. For .e.g.
// In controller action or preferably in beforeRender()
$this->viewBuilder()->setHelpers([
'CrudView' => [
'className' => 'CrudView.CrudView',
'fieldFormatters' => [
// Key can be any valid column type of table schema.
'datetime' => function ($name, $value, $entity, $options, $View) {
return $View->Time->nice($value);
},
'boolean' => function ($name, $value, $entity, $options, $View) {
return $value ? 'Yes' : 'No';
},
],
],
]);
Note
This functionality currently only applies to index
and view
pages.
Sometimes you want to execute more complex formatting logic, that may involve
the use of view helpers or outputting HTML. Since building HTML outside of the
view layer is not ideal, you can use the element
formatter for any of your
fields.
For example, consider this example where we want to link the published_time
to the same index action by passing some search arguments:
$action = $this->Crud->action();
$action->setConfig('scaffold.fields', [
'published_time' => [
'formatter' => 'element',
'element' => 'search/published_time',
'action' => 'index'
]
]);
We have instructed the formatter to use search/published_time
element. Then,
it is just a matter of creating the element file with the right content:
// templates/element/search/published_time.ctp
echo $this->Html->link($value->timeAgoInWords(), [
'action' => $options['action'],
'published_time' => $value->format('Y-m-d')
]);
After this, when displaying the published_time
field, there will the will be
a link similar to this one:
<a href="/articles?published_time=2015-06-23">4 days ago</a>
Element files will have available at least the following variables:
$value
: The value of the field
$field
: The name of the field it is intended to be rendered
$context
: The entity from which the value came from
$options
: The array of options associated to the field as passed in scaffold.fields
By default sorting links are generated for index page table’s column headers
using the PaginatorHelper
. You can disable the link generation by using
the disableSort
option:
$action = $this->Crud->action();
$action->setConfig('scaffold.fields', [
'title' => [
'disableSort' => true,
]
]);
By default, the included index buttons are generated based on the mapped Crud
actions. You can customize available buttons by using the scaffold.actions
key:
$action = $this->Crud->action();
// restrict to just the add button, which will show up globally
$action->setConfig('scaffold.actions', [
'add'
]);
// restrict to just the delete/edit/view actions, which are scoped to entities
$action->setConfig('scaffold.actions', [
'delete',
'edit',
'view',
]);
You can also specify configuration for actions, which will be used when generating action buttons.
$action = $this->Crud->action();
$action->setConfig('scaffold.actions', [
'duplicate' => [
// An alternative title for the action
'link_title' => 'Duplicate this record',
// A url that this action should point to
'url' => ['action' => 'jk-actually-this-action'],
// The HTTP method to use. Defaults to GET. All others result in
// a ``FormHelper::postLink``
'method' => 'POST',
// Whether to scope the action to a single entity or the entire table
// Options: ``entity``, ``table``
'scope' => 'entity',
// All other options are passed in as normal to the options array
'other' => 'options',
]
]);
For entity-scoped actions, we will append the primaryKey
of the record to
the link by default:
$action = $this->Crud->action();
// For the PostsController, will generate
// /posts/translate/english/1
$action->setConfig('scaffold.actions', [
'translate' => [
'url' => ['action' => 'translate', 'english']
]
]);
We can specify the token :primaryKey:
. Rather than appending the
primaryKey
, we will replace this token in the url as many times as
specified.
$action = $this->Crud->action();
// For the PostsController, will generate
// /posts/translate/1/english
$action->setConfig('scaffold.actions', [
'translate' => [
'url' => ['action' => 'translate', ':primaryKey:', 'english']
]
]);
If you wish to blacklist certain action buttons from showing up, you can use the
scaffold.actions_blacklist
configuration key. This can be useful when many
Crud action classes are mapped but should not all be shown on the main UI.
$action = $this->Crud->action();
$action->setConfig('scaffold.actions_blacklist', ['add', 'delete']);
By default, we blacklist the action which is mapped to Crud.LookupAction
.
As this action is meant to be used solely for autocompletion, it cannot be removed
from the scaffold.actions_blacklist
list.
You can group actions together using Action Groups. This will generate a
dropdown for the group, and can be controlled by the scaffold.action_groups
configuration key.
$action = $this->Crud->action();
$action->setConfig('scaffold.actions', ['view', 'edit', 'delete']);
$action->setConfig('scaffold.action_groups', [
'Actions' => [
'view',
'edit',
'delete',
],
]);
All actions specified in an action group must be included in the
scaffold.actions
key.
You can specify multiple action groups:
$action = $this->Crud->action();
$action->setConfig('scaffold.actions', ['view', 'edit', 'delete', 'disable', 'delete']);
$action->setConfig('scaffold.action_groups', [
'Actions' => [
'view',
'edit',
'delete',
],
'Destructive Actions' => [
'disable',
'delete',
]
]);
Finally, you can also set configuration for each entry in an action group:
$action = $this->Crud->action();
$action->setConfig('scaffold.actions', ['view', 'edit', 'delete', 'english', 'spanish']);
$action->setConfig('scaffold.action_groups', [
'Actions' => [
'view',
'edit',
'delete',
],
'Translate' => [
'english' => [
'url' => ['action' => 'translate', 'english']
],
'spanish' => [
'url' => ['action' => 'translate', 'spanish']
],
]
]);
The Crud plugin provides bulk actions which can be easily used with crud view.
To set up crud action in controller do something like this in initialize method.
$this->loadComponent('Crud.Crud', [
'actions' => [
'deleteAll' => [
'className' => 'Crud.Bulk/Delete',
],
]
]);
Once a bulk action has been mapped, the scaffold.bulk_actions
configuration
key can be specified. The scaffold.bulk_actions
configuration key takes an
array of key/value pairs, where the key is the url and the value is the title.
$action = $this->Crud->action();
$action->setConfig('scaffold.bulk_actions', [
Router::url(['action' => 'deleteAll']) => __('Delete records'),
]);
In some cases, it is helpful to show quick links to pre-filtered datasets.
Rather than force users to select all the filters, CrudView enables the ability
to display “Finder Scope” links via the scaffold.index_finder_scopes
configuration key. These are output below the action header, above the data that
is being paginated.
The scaffold.index_finder_scopes
option takes an array of finder scope data.
Each sub-array should contain title
and finder
parameters.
$this->Crud->action()->setConfig('scaffold.index_finder_scopes', [
[
'title' => __('All'),
'finder' => 'all',
],
[
'title' => __('Active'),
'finder' => 'active',
],
[
'title' => __('Inactive'),
'finder' => 'inactive',
],
]);
The all
finder scope is special. This scope will be displayed by default,
and should always be included in the scope list. It is not automatically
injected.
Selecting a finder scope will reset any other querystring arguments. Selecting
the all
finder scope will result in being redirected to a page without
querystring arguments.
Selecting a finder scope will not automatically apply the find to your paginated result-set. This must be done manually.
Note
This example assumes a simple blog application is being modified, with a
posts
database table containing the fields id
, active
,
title
, body
, and created
.
Once a finder scope is selected, it must still be applied to the paginated result-set. This can be done in the mapped action as follows:
public function index()
{
$this->Crud->action()->setConfig('scaffold.index_finder_scopes', [
[
'title' => __('All'),
'finder' => 'all',
],
[
'title' => __('Active'),
'finder' => 'active',
],
[
'title' => __('Inactive'),
'finder' => 'inactive',
],
]);
// We don't need to check for `all` as it is the default findMethod
if (in_array($this->request->getQuery('finder'), ['active', 'inactive'])) {
$this->Crud->action()->config('findMethod', $this->request->getQuery('finder'));
}
return $this->Crud->execute();
}
Now that the findMethod
can be mapped, the respective custom find methods
must be created in the PostsTable
class.
use Cake\ORM\Query;
use Cake\ORM\Table;
class PostsTable extends Table
{
public function findActive(Query $query, array $options)
{
$query->where([$this->aliasField('active') => true]);
return $query;
}
public function findInactive(Query $query, array $options)
{
$query->where([$this->aliasField('active') => false]);
return $query;
}
}
The ViewSearch
listener generates filter inputs for filtering records on your
index action. It requries friendsofcake/search <https://packagist.org/packages/friendsofcake/search>
to be installed and filters configured for your model using the search manager.
<?php
declare(strict_types=1);
namespace App\Controller;
use App\Controller\AppController;
class SamplesController extends AppController
{
public function initialize(): void
{
parent::initialize();
// Enable PrgComponent so search form submissions
// properly populate querystring parameters for the SearchListener
$this->loadComponent('Search.Prg', [
'actions' => [
'index',
],
]);
}
public function index()
{
// Enable the SearchListener
$this->Crud->addListener('search', 'Crud.Search', [
// The search behavior collection to use. Default "default".
'collection' => 'admin',
]);
// Enable the ViewSearch listener
$this->Crud->addListener('viewSearch', 'CrudView.ViewSearch', [
// Indicates whether is listener is enabled.
'enabled' => true,
// Whether to use auto complete for select fields. Default `true`.
// This requires you have `Crud.Lookup` action enabled for that
// related model's controller.
// http://crud.readthedocs.io/en/latest/actions/lookup.html
'autocomplete' => true,
// Whether to use selectize for select fields. Default `true`.
'selectize' => true,
// The search behavior collection to use. Default "default".
'collection' => 'default',
// Config for generating filter controls. If `null` the
// filter controls will be derived based on filter collection.
// You can use "form" key in filter config to specify control options.
// Default `null`.
'fields' => [
// Key should be the filter name.
'filter_1' => [
// Any option which you can use Form::control() options.
],
// Control options for other filters.
]
]);
return $this->Crud->execute();
}
}
Here’s an e.g. of how configure filter controls options through search manager itself:
<?php
declare(strict_types=1);
namespace App\Model\Table;
use Cake\ORM\Table;
class SamplesTable extends Table
{
public function initialize(array $config): void
{
parent::initialize($config);
$this->addBehavior('Search.Search');
$this->searchManager()
->useCollection('default')
->add('q', 'Search.Like', [
'field' => ['title', 'body'],
'form' => [
'data-foo' => 'bar'
]
])
->add('category_id', 'Search.Value', [
'form' => [
'type' => 'select',
'class' => 'no-selectize'
]
]);
}
}
Sometime you may want more than one index page for a resource to represent
different views to the user. If multiple index pages exist, CrudView will
automatically build links at the top of the index
page. Including multiple
views is simple and requires setting the index
view in your action.
$action = $this->Crud->action();
$action->view('index');
The scaffold.index_formats
configuration key can be used to customize
“Download Links”. These are alternative methods of displaying the current index
page, and can be used to expose the paginated data in JSON, XML, or other
formats. The output of each format can be customized to your specifications.
The scaffold.index_formats
option takes an array of download format data.
Each sub-array should contain title
and url
parameters.
use Cake\Routing\Router;
// link to the current page, except with extensions `json` or `xml`
// include the querystring argument as specified or you will lose any
// currently applied filters
$action = $this->Crud->action();
$action->setConfig('scaffold.index_formats', [
[
'title' => 'JSON',
'url' => ['_ext' => 'json', '?' => $this->request->getQueryParams()]
],
[
'title' => 'XML',
'url' => Router::url(['_ext' => 'xml', '?' => $this->request->getQueryParams()])
],
]);
Download links are displayed near the bottom-left of the index page and will open in a new window.
Note
This example assumes a simple blog application is being modified, with a
posts
database table containing the fields id
, active
,
title
, body
, and created
.
To implement a simple csv download link, the friendsofcake/cakephp-csvview
plugin should be installed. This plugin will handle the actual rendering of
csv files at the CakePHP view layer.
composer require friendsofcake/cakephp-csvview:~3.0
Next, the csv
extension must be connected so that it can be properly parsed.
This can be done by modifying the config/routes.php
file. Below is a
semi-complete example:
Router::scope('/', function (RouteBuilder $routes) {
$routes->extensions(['csv']);
// other routes go here
});
To complete the initial setup, the RequestHandler should be notified to use the
CsvView.View
class whenever an extension of csv
is detected. The
following can be added to the AppController::initialize()
to do
application-wide:
$this->loadComponent('RequestHandler', [
'viewClassMap' => ['csv' => 'CsvView.Csv']
]);
Once the initial setup of the CsvView plugin is complete, the index()
action
can be modified to add a CSV Download Link.
public function index()
{
// only show the id, title, and created fields for csv output
if ($this->request->getParam('_ext') === 'csv') {
$this->set('_serialize', ['posts']);
$this->set('_extract', ['id', 'active', 'title', 'created']);
}
$this->Crud->action()->setConfig('scaffold.index_formats', [
[
'title' => 'CSV',
'url' => ['_ext' => 'csv', '?' => $this->request->getQueryParams()]
],
]);
return $this->Crud->execute();
}
The following custom view blocks are available for use within forms:
form.sidebar
: Rendered on the side of a form. Will also change the form
width.
form.before_create
: Rendered before FormHelper::create()
is called.
form.after_create
: Rendered after FormHelper::create()
is called.
form.before_end
: Rendered before FormHelper::end()
is called.
form.after_end
: Rendered after FormHelper::end()
is called. Used by embedded Form::postLink()
calls.
All the CrudView templates are built from several elements that can be
overridden by creating them in your own templates/element
folder. The
following sections will list all the elements that can be overridden for each
type of action.
In general, if you want to override a template, it is a good idea to copy the
original implementation from
vendor/friendsofcake/crud-view/templates/element
Create templates/element/action-header.ctp
to have full control over
what is displayed at the top of the page. This is shared across all page
types.
Create templates/element/form/buttons.ctp
to change what is displayed
for form submission. You can expect the $formSubmitButtonText
and
$formSubmitExtraButtons
variables to be available
To use a custom index element, you can set the scaffold.index_type
config option.
$action = $this->Crud->action();
$action->setConfig('scaffold.index_type', 'an_element');
The following variables are available for use within the element:
fields: List of fields to show and their options
actions: A list of actions that can be displayed for the index page.
bulkActions: A list of bulk actions associated with this resource
primaryKey: The name of the record’s primary key field.
singularVar: The singular version of the resource name.
viewVar: Reference to the name of the variable holding all records.
plural of viewVar: The set of records.
Render your index page as a set of posts.
$action = $this->Crud->action();
$action->config('scaffold.index_type', 'blog');
The blog index type has two main options:
scaffold.index_title_field
: (default: displayField
for current table) Controls the field used for the blog title.
scaffold.index_body_field
: (default: body
) Controls the field used for the blog body.
$action = $this->Crud->action();
$action->setConfig('scaffold.index_title_field', 'name');
$action->setConfig('scaffold.index_body_field', 'content');
The following variables are available for use within the element:
indexTitleField: The field containing the post title
indexBodyField: The field containing the post body
fields: List of fields to show and their options
actions: A list of actions that can be displayed for the index page.
bulkActions: A list of bulk actions associated with this resource
primaryKey: The name of the record’s primary key field.
singularVar: The singular version of the resource name.
viewVar: Reference to the name of the variable holding all records.
plural of viewVar: The set of records.
Render your index page as a gallery.
$action = $this->Crud->action();
$action->setConfig('scaffold.index_type', 'gallery');
The gallery index type has several options:
scaffold.index_title_field
: (default: displayField
for current table)
Controls the field used for each gallery entry title.
scaffold.index_image_field
: (default: image
) Controls the field used
for each gallery entry image.
scaffold.index_body_field
: (default: body
) Controls the field used for
each gallery entry body.
scaffold.index_gallery_css_classes
: (default: col-sm-6 col-md-3
)
Controls the css classes applied to each gallery entry, useful for specifying
how many entries should go on a single page.
$action = $this->Crud->action();
$action->setConfig('scaffold.index_title_field', 'name');
$action->setConfig('scaffold.index_image_field', 'image');
$action->setConfig('scaffold.index_body_field', 'content');
$action->setConfig('scaffold.index_gallery_css_classes', 'col-sm-4 col-md-2');
For each field, we will also retrieve configuration from the scaffold.fields
configuration key for formatting each field:
$action = $this->Crud->action();
$action->setConfig('scaffold.fields', [
'image' => [
'width' => '240',
'height' => '240'
],
]);
If no image is retrieved, CrudView will default to the following transparent gif:
data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
The following variables are available for use within the element:
indexImageField: The field containing the gallery entry image
indexTitleField: The field containing the gallery entry title
indexBodyField: The field containing the gallery entry body
fields: List of fields to show and their options
actions: A list of actions that can be displayed for the index page.
bulkActions: A list of bulk actions associated with this resource
primaryKey: The name of the record’s primary key field.
singularVar: The singular version of the resource name.
viewVar: Reference to the name of the variable holding all records.
plural of viewVar: The set of records.
By default, the index page is a table with each of the models content columns and links to show, edit and delete the object. There are many ways to customize what gets displayed.
By default, all fields are displayed on the index
page. To display an
attribute or a method on a record, you can use the scaffold.fields
config option.
$action = $this->Crud->action();
$action->setConfig('scaffold.fields', ['id', 'title']);
To specify the title used in the pagination header, you need to set
scaffold.fields
to an associative array and use the title
parameter:
$action = $this->Crud->action();
$action->setConfig('scaffold.fields', [
'author_id' => ['title' => 'Author Name'],
]);
All the CrudView templates are built from several elements that can be
overridden by creating them in your own templates/element
folder. The
following sections will list all the elements that can be overridden for each
type of action.
In general, if you want to override a template, it is a good idea to copy the
original implementation from
vendor/friendsofcake/crud-view/templates/element
Create templates/element/search.ctp
for having full control over how
the search filters are displayed in your pagination table. You can expect the
$searchInputs
and $searchOptions
variables to be available
Create templates/element/index/table.ctp
To implement your own
table.
Create templates/element/index/pagination.ctp
To implement your own
pagination links and counter.
Create templates/element/index/bulk_actions/table.ctp
for changing how
the bulk action inputs for the whole table. You can expect the
$bulkActions
, $primaryKey
and $singularVar
variables to be
available.
Create templates/element/index/bulk_actions/record.ctp
for changing how
the bulk action inputs for each row are displayed. You can expect the
$bulkActions
, $primaryKey
and $singularVar
variables to be
available.
Create templates/element/index/bulk_actions/form_start.ctp
To customize
the Form create call for bulk actions
Create templates/element/index/bulk_actions/form_end.ctp
To customize
the Form end call for bulk actions
Fields may be specified via the scaffold.fields
configuration key. By
default, this will contain a list of all columns associated with the Table being
in scope. To limit the fields used, simply specify an array of fields.
$action = $this->Crud->action();
$action->setConfig('scaffold.fields', ['title', 'description']);
You may also specify an options array. For forms, CrudView makes use of the
FormHelper::inputs()
method and will pass your array values as options when
generating the output.
$action = $this->Crud->action();
$action->setConfig('scaffold.fields', [
'title',
'thread_id' => [
'type' => 'text'
],
'featured' => [
'checked' => 'checked'
]
]);
If you wish to use the default automatic field population functionality but want
to specify settings for a few of the fields, you can use the
scaffold.field_settings
configuration key:
$action = $this->Crud->action();
$action->setConfig('scaffold.field_settings', [
'title' => [
// options here
]
]);
You may also use the scaffold.fields_blacklist
configuration key to remove
fields from the output if you are using the default automatic field population
functionality:
$action = $this->Crud->action();
$action->setConfig('scaffold.fields_blacklist', ['created', 'modified']);
You can group the form fields in tabs using the scaffold.form_tab_groups
configuration key:
$action = $this->Crud->action();
$action->setConfig('scaffold.form_tab_groups', [
'First Tab Header' => ['field_1', 'field_2'],
'Second Tab Header' => ['field_3', 'field_4'],
]);
If there are fields which are not listed under any group they will be
automatically shown under 1st tab with header Primary
. You can customize
the primary group’s name using scaffold.form_primary_tab config.
$action = $this->Crud->action();
$action->setConfig('scaffold.form_primary_tab', 'Key Info');
By default, the Crud plugin will redirect all form submissions to the
controller’s index
action. This can be changed by setting the
_redirect_url
view variable:
$this->set('_redirect_url', ['action' => 'home']);
By default, closing the a form page in your browser will result in lost data.
However, you may force a user prompt by enabling dirty form checks using the
scaffold.form_enable_dirty_check
configuration key:
$action = $this->Crud->action();
$action->setConfig('scaffold.form_enable_dirty_check', true);
You can change the submit button text from it’s default using the
scaffold.form_submit_button_text
configuration key.
$action = $this->Crud->action();
$action->setConfig('scaffold.form_submit_button_text', _('Submit'));
By default, we should the following extra buttons for forms:
Save & continue editing: Results in a form submission
Save & create new: Results in a form submission
Back: A link to the index page
To use the defaults, you may either omit the configuration key or set it to true:
$action = $this->Crud->action();
$action->setConfig('scaffold.form_submit_extra_buttons', true);
You can also customize this by using the scaffold.form_submit_extra_buttons
configuration key as follows:
$action = $this->Crud->action();
$action->setConfig('scaffold.form_submit_extra_buttons', [
[
'title' => __d('crud', 'Save & continue editing'),
'options' => ['class' => 'btn btn-success btn-save-continue', 'name' => '_edit', 'value' => true],
'type' => 'button',
],
[
'title' => __d('crud', 'Save & create new'),
'options' => ['class' => 'btn btn-success', 'name' => '_add', 'value' => true],
'type' => 'button',
],
[
'title' => __d('crud', 'Back'),
'url' => ['action' => 'index'],
'options' => ['class' => 'btn btn-default', 'role' => 'button', 'value' => true],
'type' => 'link',
],
]);
Specified values will override the defaults, and will be output in the order specified.
By default, extra buttons appear on the right-hand side of forms. The left-hand side is managed separately, and will show the following by default
Delete: An embedded postLink for deleting the current entity. This only appears on the
pages that are rendered via EditAction
.
To use the defaults, you may either omit the configuration key or set it to true:
$action = $this->Crud->action();
$action->setConfig('scaffold.form_submit_extra_left_buttons', true);
You can also customize this by using the scaffold.form_submit_extra_left_buttons
configuration key as follows:
$action = $this->Crud->action();
$action->setConfig('scaffold.form_submit_extra_left_buttons', [
[
'title' => __d('crud', 'Save & continue editing'),
'options' => ['class' => 'btn btn-success btn-save-continue', 'name' => '_edit', 'value' => true],
'type' => 'button',
],
]);
Rather than modifying the default extra buttons, you can also disable them completely:
$action = $this->Crud->action();
$action->setConfig('scaffold.form_submit_extra_buttons', false);
Disabling the default left extra buttons can also be done in a similar fashion:
$action = $this->Crud->action();
$action->setConfig('scaffold.form_submit_extra_left_buttons', false);
The following custom view blocks are available for use within forms:
form.sidebar
: Rendered on the side of a form. Will also change the form
width.
form.before_create
: Rendered before FormHelper::create()
is called.
form.after_create
: Rendered after FormHelper::create()
is called.
form.before_end
: Rendered before FormHelper::end()
is called.
form.after_end
: Rendered after FormHelper::end()
is called. Used by embedded Form::postLink()
calls.
All the CrudView templates are built from several elements that can be
overridden by creating them in your own templates/element
folder. The
following sections will list all the elements that can be overridden for each
type of action.
In general, if you want to override a template, it is a good idea to copy the
original implementation from
vendor/friendsofcake/crud-view/templates/element
Create templates/element/action-header.ctp
to have full control over
what is displayed at the top of the page. This is shared across all page
types.
Create templates/element/form/buttons.ctp
to change what is displayed
for form submission. You can expect the $formSubmitButtonText
and
$formSubmitExtraButtons
variables to be available