Customizing the Index Page

Customizing Fields

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']);

Setting options for specific fields

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
    ]
]);

Removing Fields from output

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']);

Formatting with a Callable

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';
            },
        ],
    ],
]);

Formatting with an Element

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

Column sorting

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,
    ]
]);

Index Buttons

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',
    ]
]);

Customizing primaryKey position in the url

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']
    ]
]);

Blacklisting Index Buttons

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.

Action Groups

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']
        ],
    ]
]);

Bulk Actions

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'),
]);

Index Finder Scopes

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.

Example: Applying Finder Scopes

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;
    }
}

Index Filters

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'
                ]
            ]);
    }
}

Multiple Index Pages

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');

Available Viewblocks

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.

Available Elements

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

action-header

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.

form/buttons

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

  v: stable
Versions
latest
stable
docs
Downloads
pdf
html
epub
On Read the Docs
Project Home
Builds
Downloads
On GitHub
View
Edit

Free document hosting provided by Read the Docs.