Controllers

Controllers manage application flow between models, views, and HTTP input/output. In a Piko application, a controller is a class that extends Piko\Controller.

A controller should be responsible for:

Controllers should not contain SQL queries or HTML markup directly.

Controllers expose one or more action methods. Each action is reachable through routing.

Example:

namespace app\modules\site\controllers;

class DefaultController extends \Piko\Controller
{
    /**
     * Route: site/default/hello
     */
    public function helloAction()
    {
        return "Hello world!";
    }
}

Controller class naming

Controller classes use CamelCase. The class name is based on the controller ID, suffixed by Controller.

Examples:

controller id class name
article ArticleController
article-manager ArticleManagerController

Action method naming

Action methods use camelCase and end with Action. The action ID maps to the method name.

Examples:

action id method name
export exportAction
export-article exportArticleAction

Dependency injection

When a controller is instantiated by a module, constructor arguments are resolved automatically from application components (configured in the app container).

namespace app\modules\products\controllers;

use PDO;
use Piko\User;

class ProduitsController extends \Piko\Controller
{
    public function __construct(private User $user, private PDO $db)
    {
    }
}

Creating objects from a controller

If you need to instantiate a model/service that also has dependencies, use the controller helper create() instead of new. This delegates to the module object factory and resolves constructor dependencies the same way as controllers.

public function deleteAction(int $id)
{
    /** @var \app\modules\products\models\Produit $model */
    $model = $this->create(\app\modules\products\models\Produit::class);
    $model->load($id);

    // ...
}

You can also override specific constructor arguments:

$service = $this->create(MyService::class, ['timeout' => 30]);

View rendering

The render method processes a view script. By default, view scripts are located in the views directory of the corresponding module. The views directory contains one subdirectory per controller.

Example module structure for site/default/users:

site
    controllers
        DefaultController.php
    views
        default
            userlist.php

DefaultController.php:

<?php
namespace app\modules\site\controllers;

class DefaultController extends \Piko\Controller
{
    public function usersAction()
    {
        $users = [
            ['firstname' => 'John', 'lastname' => 'Douglas'],
            ['firstname' => 'Robert', 'lastname' => 'Johnson']
        ];

        return $this->render('userlist', ['users' => $users]);
    }
}

userlist.php:

<ul>
<?php foreach ($users as $user): ?>
    <li>
        <?php echo $user['firstname']?>
        <?php echo $user['lastname']?>
    </li>
<?php endforeach ?>
</ul>

Forward and redirect

Useful helpers:

Use cases inside a controller:

public function saveAction()
{
    return $this->redirect($this->getUrl('site/default/user', ['username' => 'Bill']));
}

public function validateAction()
{
    return $this->forward('site/default/user', ['username' => 'Bill']);
}

Working with request parameters

Action parameters are mapped by name from route parameters and query parameters. Basic scalar conversion is applied for int, float, and bool.

public function showAction(int $id, bool $preview = false)
{
    // $id and $preview are mapped from request parameters
}

To access the full PSR-7 request, use $this->request:

public function userAction()
{
    if ($this->request->getMethod() === 'POST') {
        $post = $this->request->getParsedBody();
    }
}

Request object comes from the package httpsoft/http-message and implements the Psr\Http\Message\ServerRequestInterface

Interact with the response

In the same way as with the request, it’s possible to interact with the HTTP response:

public function rssAction()
{
    $this->response = $this->response->withHeader('Content-Type', 'text/xml');
    // ...
}

Response object comes from the package httpsoft/http-message and implements the Psr\Http\Message\ResponseInterface

AJAX

To work with AJAX requests/responses, Piko\Controller provides: isAjax, jsonResponse.

public function userSaveAction()
{
    if ($this->isAjax()) {
        $data = json_decode((string) $this->request->getBody(), true);
        return $this->jsonResponse($data);
    }

    return $this->jsonResponse(['error' => 'Bad request'])->withStatus(400);
}