Gacela
Documentation version: 2.2.0
Colour theme

Docs Core concepts

On this page

Facade

The Facade (opens in a new tab) is the entry point of your module. It exposes what the module can do through a clean, public API while hiding the internal classes, services, and wiring behind simple method calls.

Start from the caller

Write the call you want consumers to make before designing the implementation. The caller should know the Facade and nothing behind it.

app.phpphp
<?php

declare(strict_types=1);

use App\Comment\CommentFacade;
use Gacela\Framework\Gacela;

require __DIR__ . '/vendor/autoload.php';

Gacela::bootstrap(__DIR__);

$score = (new CommentFacade())->getSpamScore('Lorem ipsum!');

echo "Spam score: {$score}" . PHP_EOL;

View the complete entry point (opens in a new tab).

Define the boundary

Turn the caller's desired operation into a Facade method. Extend AbstractFacade and delegate the implementation through getFactory().

src/Comment/CommentFacade.phpphp
<?php

declare(strict_types=1);

namespace App\Comment;

use Gacela\Framework\AbstractFacade;

/**
 * @extends AbstractFacade<CommentFactory>
 */
final class CommentFacade extends AbstractFacade
{
    public function getSpamScore(string $comment): int
    {
        return $this->getFactory()
            ->createSpamChecker()
            ->getSpamScore($comment);
    }
}

View the complete Facade (opens in a new tab). Keep this API small: add a method because a real caller needs the capability, not because an internal service happens to expose it.

Accessing the Facade from controllers and commands

In your infrastructure layer (controllers, CLI commands, etc.) you often can't extend AbstractFacade. Use ServiceResolverAwareTrait together with the #[ServiceMap] attribute to let Gacela resolve the Facade lazily through the Locator singleton. No constructor injection needed.

<?php

use Gacela\Framework\ServiceResolver\ServiceMap;
use Gacela\Framework\ServiceResolverAwareTrait;

#[ServiceMap(method: 'getFacade', className: RunFacade::class)]
final class TestCommand extends Command
{
    use ServiceResolverAwareTrait;

    protected function execute(InputInterface $in, OutputInterface $out): int
    {
        // getDependencies() is a method on RunFacade
        $dependencies = $this->getFacade()->getDependencies($paths);
        // ...
    }
}

Construct a Facade directly when your code owns the entry point, as in the Quickstart. Use #[ServiceMap] when another framework creates the controller or command and constructor injection is not practical.

The full reference, including repeatable declarations, the @method DocBlock migration path, and resolution behavior, is Service Map.