Controllers

In an effort to minimize the work of controllers, for they are not here to do work for the application but to point the request in the right direction. In Lucid terms, to serve the intended feature to the user.

Eventually we will end up having one line within each controller method, achieving the thinnest form possible.

Lucid Controller

Responsibility: Serve the designated feature.

What you should do in a controller:

  • Serve a feature.
  • Prepare input as required by the feature that’s being served [does not include input validation]

Generate Controller Class

Use lucid CLI to generate a controller that extends Lucid’s Controller class by default, which allows us to serve features features using the built-in serve method.

Signature lucid make:controller <controller>

Example

lucid make:controller Article

Generated class will be at app/Http/Controllers/ArticleController.php

Signature lucid make:controller <controller> <service>

Example

lucid make:controller Article Publishing

Generated class will be at app/Services/Publishing/Http/Controllers/ArticleController.php

 For more details on this command see the help manual with lucid make:controller --help or visit make:controller

Serve Features

Lucid Controller serve Feature

To serve a Feature from controllers simply call the serve method provided by Lucid’s parent controller.

use Lucid\Units\Controller;
use App\Features\UpdateArticleFeature;

class ArticleController extends Controller
{
    public function articles()
    {
        return $this->serve(new ListArticlesFeature());
    }
}

Request Input

The served feature will be able to inject Request class to access request properties. This keeps our controllers clean and allows us to concentrate on what matters to the feature only.

class ListArticlesFeature
{
    public function handle(Request $request)
    {
        $input = $request->input();
        // or
        $title = $request->input('title');
    }
}

Feature Parameters

To pass parameters to a feature, we use the same syntax as dispatching a Laravel job:

use Lucid\Units\Controller;
use App\Features\UpdateArticleFeature;

class ArticleController extends Controller
{
    public function update($id)
    {
        return $this->serve(UpdateArticleFeature::class, ['id' => $id]);
        // OR
        return $this->serve(new UpdateArticleFeature(id: $id));
        // OR
        return $this->serve(new UpdateArticleFeature($id));
    }
}

The id key will be mapped to $id constructor param UpdateArticleFeature::constructor($id).

 Parameter and constructor variable names must match. And they’re case sensitive!

When using PHP < 8.0, associative arrays as properties has the advantage of disregarding the order in which the parameters are defined which helps maintain a healthy codebase when unit signatures evolve.

class UpdateArticleFeature extends Feature
{
    private $id;

    public function __construct(string $id)
    {
        $this->id = $id;
    }

    public function handle(Request $request)
    {
        $this->run(UpdateArticleDataJob::class, [
            'id' => $this->id,
            'title' => $request->input('title'),
            'content' => $request->input('content');
        ]);
    }
}

As of PHP 8.0 we use named parameters for better readability and IDE signature recognition:

class UpdateArticleFeature extends Feature
{
    public function __construct(private string $id) {}

    public function handle(Request $request)
    {
        $this->run(new UpdateArticleDataJob(
            id: $this->id,
            title: $request->input('title'),
            content: $request->input('content');
        ));
    }
}

For more on working with features see the Features section.