Skip to content

Controllers ​

Basic Controller ​

php
use Nexphant\Get;
use Nexphant\Post;
use Nexphant\Put;
use Nexphant\Delete;
use Nexphant\Request;

class UserController
{
    #[Get('/users')]
    public function index()
    {
        return ['users' => []];
    }

    #[Get('/users/{id}')]
    public function show(Request $request, int $id)
    {
        return ['user_id' => $id];
    }

    #[Post('/users')]
    public function store(Request $request)
    {
        $data = $request->json();
        return ['created' => true, 'data' => $data];
    }

    #[Put('/users/{id}')]
    public function update(Request $request, int $id)
    {
        return ['updated' => $id];
    }

    #[Delete('/users/{id}')]
    public function destroy(int $id)
    {
        return ['deleted' => $id];
    }
}

Register Controller ​

php
$app->annotations(UserController::class);

Dependency Injection ​

Controller method parameters are resolved from the DI container automatically. Type-hint any registered service to have it injected.

php
class OrderController
{
    #[Post('/orders')]
    public function store(Request $request, OrderService $orders, Mailer $mailer)
    {
        $order = $orders->create($request->json());
        $mailer->sendConfirmation($order);
        return ['order_id' => $order->id];
    }
}

Services must be bound in the container before the controller is registered:

php
$app->bind(OrderService::class, fn () => new OrderService());
$app->bind(Mailer::class, fn () => new Mailer(env('MAIL_DSN')));

$app->annotations(OrderController::class);

Data Object Validation ​

Type-hint a Data subclass to get automatic validation before the method is called:

php
use Nexphant\Support\Data;
use Nexphant\Validation\Rules\{Required, Length, Email};

class CreateUserData extends Data
{
    #[Required, Email]
    public string $email;

    #[Required, Length(min: 2, max: 100)]
    public string $name;
}

class UserController
{
    #[Post('/users')]
    public function store(CreateUserData $data)
    {
        // $data is already validated
        return ['email' => $data->email, 'name' => $data->name];
    }
}

If validation fails, a 422 Unprocessable Entity response is returned automatically with the error details.

Middleware Per Route ​

Apply middleware to specific controller methods using the #[Middleware] attribute:

php
use Nexphant\Middleware;

class UserController
{
    #[Get('/users')]
    #[Middleware(AuthMiddleware::class)]
    public function index()
    {
        return ['users' => []];
    }

    #[Post('/users')]
    #[Middleware(AuthMiddleware::class, AdminMiddleware::class)]
    public function store(Request $request)
    {
        return ['created' => true];
    }
}

Route Parameters ​

Route parameters are injected by name. Type-casted automatically to int, float, or string.

php
class PostController
{
    #[Get('/posts/{postId}/comments/{commentId}')]
    public function showComment(int $postId, int $commentId)
    {
        return ['post' => $postId, 'comment' => $commentId];
    }
}

Constructor Injection ​

The controller itself is resolved from the DI container, so constructor injection works too:

php
class ProductController
{
    public function __construct(
        private readonly ProductRepository $products,
        private readonly CacheInterface $cache,
    ) {}

    #[Get('/products')]
    public function index()
    {
        return $this->cache->remember('products', fn () => $this->products->all());
    }
}

Next Steps ​

Released under the MIT License.