# Controllers

<?php

    protected $moduleName = 'yourModuleName';

    /*
     * The static permalink base to your module. Defaults to /yourModuleName
     * Set to '' if your module's permalinks are directly off the root, like in a Pages module, for example 
     */
    protected $permalinkBase = 'yourModuleName';

    /*
     * Options of the index view
     */
    protected $indexOptions = [
        'create' => true,
        'edit' => true,
        'publish' => true,
        'bulkPublish' => true,
        'feature' => false,
        'bulkFeature' => false,
        'restore' => true,
        'bulkRestore' => true,
        'forceDelete' => true,
        'bulkForceDelete' => true,
        'delete' => true,
        'duplicate' => false,
        'bulkDelete' => true,
        'reorder' => false,
        'permalink' => true,
        'bulkEdit' => true,
        'editInModal' => false,
        'skipCreateModal' => false,
    ];

    /*
     * Key of the index column to use as title/name/anythingelse column
     * This will be the first column in the listing and will have a link to the form
     */
    protected $titleColumnKey = 'title';

    /*
     * Available columns of the index view
     */
    protected $indexColumns = [
        'image' => [
            'thumb' => true, // image column
            'variant' => [
                'role' => 'cover',
                'crop' => 'default',
            ],
        ],
        'title' => [ // field column
            'title' => 'Title',
            'field' => 'title',
        ],
        'subtitle' => [
            'title' => 'Subtitle',
            'field' => 'subtitle',
            'sort' => true, // column is sortable
            'visible' => false, // will be available from the columns settings dropdown
        ],
        'relationName' => [ // relation column
            // Take a look at the example in the next section fot the implementation of the sort
            'title' => 'Relation name',
            'sort' => true,
            'relationship' => 'relationName',
            'field' => 'relationFieldToDisplay'
        ],
        'presenterMethodField' => [ // presenter column
            'title' => 'Field title',
            'field' => 'presenterMethod',
            'present' => true,
        ],
        'relatedBrowserFieldName' => [ // related browser column
            'title' => 'Field title',
            'field' => 'relatedFieldToDisplay',
            'relatedBrowser' => 'browserName',
        ]
    ];

    /*
     * Columns of the browser view for this module when browsed from another module
     * using a browser form field
     */
    protected $browserColumns = [
        'title' => [
            'title' => 'Title',
            'field' => 'title',
        ],
    ];

    /*
     * Relations to eager load for the index view
     */
    protected $indexWith = [];

    /*
     * Relations to eager load for the form view
     * Add relationship used in multiselect and resource form fields
     */
    protected $formWith = [];

    /*
     * Relation count to eager load for the form view
     */
    protected $formWithCount = [];

    /*
     * Filters mapping ('filterName' => 'filterColumn')
     * You can associate items list to filters by having a filterNameList key in the indexData array
     * For example, 'category' => 'category_id' and 'categoryList' => app(CategoryRepository::class)->listAll()
     */
    protected $filters = [];

    /*
     * Add anything you would like to have available in your module's index view
     */
    protected function indexData($request)
    {
        return [];
    }

    /*
     * Add anything you would like to have available in your module's form view
     * For example, relationship lists for multiselect form fields
     */
    protected function formData($request)
    {
        return [];
    }

    // Optional, if the automatic way is not working for you (default is ucfirst(str_singular($moduleName)))
    protected $modelName = 'model';

    // Optional, to specify a different feature field name than the default 'featured'
    protected $featureField = 'featured';

    // Optional, specify number of items per page in the listing view (-1 to disable pagination)
    // If you are implementing Sortable, this parameter is ignored given reordering is not implemented
    // along with pagination.
    protected $perPage = 20;

    // Optional, specify the default listing order
    protected $defaultOrders = ['title' => 'asc'];

    // Optional, specify the default listing filters
    protected $defaultFilters = ['search' => 'title|search'];

You can also override all actions and internal functions, checkout the ModuleController source in A17\Twill\Http\Controllers\Admin\ModuleController.

# Example: sorting by a relationship field

Let's say we have a controller with certain fields displayed:

File: app/Http/Controllers/Admin/PlayController.php

    protected $indexColumns = [
        'image' => [
            'thumb' => true, // image column
            'variant' => [
                'role' => 'featured',
                'crop' => 'default',
            ],
        ],
        'title' => [ // field column
            'title' => 'Title',
            'field' => 'title',
        ],
        'festivals' => [ // relation column
            'title' => 'Festival',
            'sort' => true,
            'relationship' => 'festivals',
            'field' => 'title'
        ],
    ];

To order by the relationship we need to overwrite the order method in the module's repository.

File: app/Repositories/PlayRepository.php

  ...
  public function order($query, array $orders = []) {

      if (array_key_exists('festivalsTitle', $orders)){
          $sort_method = $orders['festivalsTitle'];
          // remove the unexisting column from the orders array
          unset($orders['festivalsTitle']);
          $query = $query->orderByFestival($sort_method);
      }
      // don't forget to call the parent order function
      return parent::order($query, $orders);
  }
  ...

Then, add a custom sort scope to your model, it could be something like this:

File: app/Models/Play.php

    public function scopeOrderByFestival($query, $sort_method = 'ASC') {
        return $query
            ->leftJoin('festivals', 'plays.section_id', '=', 'festivals.id')
            ->select('plays.*', 'festivals.id', 'festivals.title')
            ->orderBy('festivals.title', $sort_method);
    }

# Index Options

You can change the available actions within the listing view for any particular module by altering the $indexOptions array in the module's controller. The full list at the start of this chapter demonstrates the available options with their default settings. Should you wish to change one, include it in the controller's array with the desired overriding value.

For example, to disable the user's ability to permanently delete an article, you include the following:

File: app/Http/Controllers/Admin/ArticleController


	protected $indexOptions = [
		'forceDelete' => false // This is the opposite of the default
		];

With this, all index options apart from Destroy and the synonymous bulk action will be available on the listing view for articles.

# Additional table actions

You can override the additionalTableActions() method to add custom actions in your module's listing view:

File: app/Http/Controllers/Admin/NewsletterController.php

    public function additionalTableActions()
    {
        return [
            'exportAction' => [ // Action name.
                'name' => 'Export Newsletter List', // Button action title.
                'variant' => 'primary', // Button style variant. Available variants; primary, secondary, action, editor, validate, aslink, aslink-grey, warning, ghost, outline, tertiary
                'size' => 'small', // Button size. Available sizes; small
                'link' => route('newsletter.export'), // Button action link.
                'target' => '', // Leave it blank for self.
                'type' => 'a', // Leave it blank for "button".
            ]
        ];
    }

In a multilingual setup it might be interesting to define a localized permalink base.

We saw before that we can customize the permalink using $permalinkBase but if we want to localize this we can use the controller method getLocalizedPermalinkBase.

protected function getLocalizedPermalinkBase()
{
    return [
        'en' => 'page',
        'nl' => 'pagina',
    ];
}

If you need more control or want to change the full permalink you can use the formData method instead.

The example below is a simple one and could be done as well with customizing the permalink

protected function formData($request)
{
    return [
        'localizedCustomPermalink' => [
            'en' => route('page', ['id' => $request->route('page')]),
            'nl' => route('page', ['id' => $request->route('page')])
        ]
    ];
}

If needed you can customize the permalink displayed in the admin interface when editing a model. This is especially useful if you are using Laravel for displaying your front-end as you do not need to keep your permalink and routes in sync.

screenshot

This can be done by setting the customPermalink via the formData method in the model controller.

The example below will result in: /page-route/3 for page with id 3.

# Route definition
Route::get('page-route/{id}', function() {...})->name('page.detail');

# Method implementation
protected function formData($request)
{
    if ($request->route('page')) {
        return [
            'customPermalink' => route('page.detail', ['id' => $request->route('page')]),
        ];
    }
    return [];
}