Controllers

New in version 0.9.4.

Controllers are - in a MVC model - in charge of make relation between an URL and Objects that does the job behind the scenes. Since Galette uses Slim Framework, we’ve used anonymous functions in routes; but that makes all that code not reusable; therefore there were plenty of code that was very similar in several places.

This includes two steps removal mechanisms, outputs, and so on.

With new controllers, is is now possible to add specific methods that ease the development, and makes it less dependent on the framework. Check the Slim documentation about container resolution to known more.

Note

Of course, plugins can inherit of existing controllers and benefit of existing automations!

Abstract controller

Galette provides an AbstractController class all controllers must inherit. It declares in its constructor all properties from dependency injection used:

  • $zdb database instance,
  • $login current logged in user instance,
  • $preferences Galette configuration instance,
  • $view Smarty instance,

All those properties are then accessible like $this->zdb inside controllers.

CRUD controllers

CRUD stands for Create, Read, Update, Delete. Galette provides a Galette\Controllers\CrudController abstract class all objects that suits CRUD should rely on. By extending this class, you must declare all abstract methods:

  • add for the add page,
  • doAdd that will handle the add code,
  • list for a list,
  • filter for list filtering,
  • edit for the edit page,
  • doEdit that will handle the edit code,

For most of the pages, add and edit as well as doAdd and doEdit may be very similar; then you can use another new method (say store) that does the real job (that was not possible with anonymous functions previousely used):

<?php

use Slim\Http\Request;
use Slim\Http\Response;

public function doAdd(Request $request, Response $response, array $args = []) :Response
{
    return $this->store($request, $Response, $args);
}

public function doEdit(Request $request, Response $response, array $args = []) :Response
{
    return $this->store($request, $Response, $args);
}

public function store(Request $request, Response $response, array $args = []) :Response
{
    //do the magic
    return $response;
}

Two steps removal (one for removal confirmation, and then real removal) is quite simple: most of the code is automatically handled from the CrudController; you will have to define a few methods, to set the confirmation page title, the form and redirection URLs, and the removal itself; without taking care of what will be output. As an example, for payment types removal, this looks like the following:

<?php

public function redirectUri(array $args = [])
{
    return $this->router->pathFor('paymentTypes');
}

public function formUri(array $args = [])
{

    return $this->router->pathFor(
        'doRemovePaymentType',
        ['id' => $args['id'] ?? null]
    );
}

public function confirmRemoveTitle(array $args = [])
{
    $ptype = new PaymentType($this->zdb, (int)$args['id']);
    return sprintf(
        _T('Remove payment type %1$s'),
        $ptype->getName()
    );
}

protected function doDelete(array $args, array $post)
{
    $ptype = new PaymentType($this->zdb, (int)$args['id']);
    return $ptype->remove();
}

As you can see, we remove only one payment type at once; but you can also handle batch removal, with a few adaptations from the example below, and redefinition of the getIdsToRemove method that rely per default on a id argument set in URL.

<?php

protected function getIdsToRemove($args)
{
    if (isset($args['id'])) {
        return $args['id'];
    } else {
        $filters =  $this->session->filter_members;
        return $filters->selected;
    }
}

PDF and CSV controllers

The PdfController and CsvController in Galette centralize all PDF/CSV outputs, but the most interesting point is the sendResponse method that set correct headers and contents for those specific outputs.

The PdfController::sendResponse method waits for a Slim\Http\Response and a Galette\IO\Pdf objects to work.

The CsvController::sendResponse method waits for a Slim\Http\Response, path to the file on disk, and file name for download.

Usage in routes

Instead of using anonymous function directly in routes, you will call controller’s methods. For example , for members it would look like:

<?php

//members list
$app->get(
    '/members[/{option:page|order}/{value:\d+}]',
    Crud\MembersController::class . ':list'
)->setName('members')->add($authenticate);

//members list filtering
$app->post(
    '/members/filter',
    Crud\MembersController::class . ':filter'
)->setName('filter-memberslist')->add($authenticate);

$app->get(
    '/member/remove/{id:\d+}',
    Crud\MembersController::class . ':confirmDelete'
)->setName('removeMember')->add($authenticate);

$app->get(
    '/members/remove',
    Crud\MembersController::class . ':confirmDelete'
)->setName('removeMembers')->add($authenticate);

$app->post(
    '/member/remove' . '[/{id:\d+}]',
    Crud\MembersController::class . ':delete'
)->setName('doRemoveMember')->add($authenticate);