Views & Blade Templates

Build dynamic views with Larafony's Blade-inspired template engine featuring components, layouts, and directives.

PSR-7 Integration: Views extend PSR-7 Response, making them directly returnable from controllers.

Overview

Larafony's template system provides:

Basic View Usage

Returning Views from Controllers

use Larafony\Framework\Web\Controller;
use Psr\Http\Message\ResponseInterface;

class HomeController extends Controller
{
    public function index(): ResponseInterface
    {
        // Renders resources/views/home.blade.php
        return $this->render('home', [
            'title' => 'Welcome',
            'user' => $user,
        ]);
    }
}

View File Structure

resources/
└── views/
    └── blade/
        ├── home.blade.php
        ├── layouts/
        │   └── app.blade.php
        ├── components/
        │   ├── alert.blade.php
        │   └── card.blade.php
        └── posts/
            ├── index.blade.php
            └── show.blade.php

Blade Syntax

Displaying Data

{{-- Escaped output (safe) --}}
{{ $name }}
{{ $user->email }}

{{-- Raw output (use with caution) --}}
{!! $htmlContent !!}

{{-- Comments (won't appear in HTML) --}}
{{-- This is a comment --}}

Control Structures

{{-- If statements --}}
@if($user->isAdmin())
    <p>Welcome, Admin!</p>
@elseif($user->isModerator())
    <p>Welcome, Moderator!</p>
@else
    <p>Welcome, User!</p>
@endif

{{-- Unless (inverse if) --}}
@unless($user->isBanned())
    <p>You can post comments</p>
@endunless

{{-- Isset check --}}
@isset($user)
    <p>User: {{ $user->name }}</p>
@endisset

{{-- Empty check --}}
@empty($posts)
    <p>No posts found</p>
@endempty

Loops

{{-- Foreach loop --}}
@foreach($posts as $post)
    <article>
        <h2>{{ $post->title }}</h2>
        <p>{{ $post->excerpt }}</p>
    </article>
@endforeach

{{-- For loop --}}
@for($i = 0; $i < 10; $i++)
    <p>Item {{ $i }}</p>
@endfor

{{-- While loop --}}
@while($condition)
    <p>Processing...</p>
@endwhile

Layouts & Sections

Defining a Layout

{{-- resources/views/layouts/app.blade.php --}}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{{ $title ?? 'Larafony' }}</title>
    <link rel="stylesheet" href="/css/app.css">
    @stack('styles')
</head>
<body>
    <header>
        <h1>{{ $title }}</h1>
        <nav>
            <a href="/">Home</a>
            <a href="/about">About</a>
        </nav>
    </header>

    <main>
        @yield('content')
    </main>

    <footer>
        <p>&copy; 2025 Larafony</p>
    </footer>

    @stack('scripts')
</body>
</html>

Extending a Layout

{{-- resources/views/posts/show.blade.php --}}
@extend('layouts.app')

@section('content')
    <article>
        <h2>{{ $post->title }}</h2>
        <p class="meta">By {{ $post->author }} on {{ $post->created_at }}</p>

        <div class="content">
            {!! $post->content !!}
        </div>

        @if($post->tags)
            <div class="tags">
                @foreach($post->tags as $tag)
                    <span class="tag">{{ $tag }}</span>
                @endforeach
            </div>
        @endif
    </article>
@endsection

@push('scripts')
    <script src="/js/post-interactions.js"></script>
@endpush

Components (The Power of Larafony)

Creating a Component Class

<?php
// app/View/Components/Alert.php

namespace App\View\Components;

use Larafony\Framework\View\Component;

class Alert extends Component
{
    public function __construct(
        public readonly string $type = 'info',
        public readonly bool $dismissible = false,
        public readonly ?string $title = null,
    ) {}

    protected function getView(): string
    {
        return 'components.alert';
    }
}

Component Template

{{-- resources/views/components/alert.blade.php --}}
<div class="alert alert-{{ $type }} {{ $dismissible ? 'alert-dismissible' : '' }}">
    @if($dismissible)
        <button type="button" class="close">&times;</button>
    @endif

    @if($title)
        <h4 class="alert-title">{{ $title }}</h4>
    @endif

    <div class="alert-content">
        {!! $slot !!}
    </div>
</div>

Using Components

{{-- Simple usage --}}
<x-alert type="success">
    Operation completed successfully!
</x-alert>

{{-- With attributes --}}
<x-alert type="warning" :dismissible="true" title="Warning">
    Please review your settings.
</x-alert>

{{-- Dynamic attributes --}}
<x-alert :type="$messageType" :title="$messageTitle">
    {{ $messageContent }}
</x-alert>

Component Slots

Named Slots

// app/View/Components/Card.php
class Card extends Component
{
    public function __construct(
        public readonly ?string $title = null,
    ) {}

    protected function getView(): string
    {
        return 'components.card';
    }
}
{{-- resources/views/components/card.blade.php --}}
<div class="card">
    @isset($slots['header'])
        <div class="card-header">
            {!! $slots['header'] !!}
        </div>
    @endisset

    <div class="card-body">
        @if($title)
            <h3 class="card-title">{{ $title }}</h3>
        @endif

        {!! $slot !!}
    </div>

    @isset($slots['footer'])
        <div class="card-footer">
            {!! $slots['footer'] !!}
        </div>
    @endisset
</div>

Using Named Slots

<x-card title="User Profile">
    <x-slot:header>
        <img src="{{ $user->avatar }}" alt="Avatar">
    </x-slot:header>

    <p>Name: {{ $user->name }}</p>
    <p>Email: {{ $user->email }}</p>

    <x-slot:footer>
        <button>Edit Profile</button>
    </x-slot:footer>
</x-card>

Advanced Component Examples

Example 1: Button Component

// app/View/Components/Button.php
class Button extends Component
{
    public function __construct(
        public readonly string $type = 'button',
        public readonly string $variant = 'primary',
        public readonly bool $disabled = false,
    ) {}

    protected function getView(): string
    {
        return 'components.button';
    }
}
{{-- resources/views/components/button.blade.php --}}
<button
    type="{{ $type }}"
    class="btn btn-{{ $variant }}"
    {{ $disabled ? 'disabled' : '' }}
>
    {!! $slot !!}
</button>

{{-- Usage --}}
<x-button type="submit" variant="success">
    Save Changes
</x-button>

<x-button variant="danger" :disabled="true">
    Delete
</x-button>

Example 2: Modal Component

// app/View/Components/Modal.php
class Modal extends Component
{
    public function __construct(
        public readonly string $id,
        public readonly string $size = 'md',
    ) {}

    protected function getView(): string
    {
        return 'components.modal';
    }
}
{{-- resources/views/components/modal.blade.php --}}
<div class="modal" id="{{ $id }}">
    <div class="modal-dialog modal-{{ $size }}">
        <div class="modal-content">
            @isset($slots['header'])
                <div class="modal-header">
                    {!! $slots['header'] !!}
                    <button class="close">&times;</button>
                </div>
            @endisset

            <div class="modal-body">
                {!! $slot !!}
            </div>

            @isset($slots['footer'])
                <div class="modal-footer">
                    {!! $slots['footer'] !!}
                </div>
            @endisset
        </div>
    </div>
</div>

{{-- Usage --}}
<x-modal id="confirmDelete" size="sm">
    <x-slot:header>
        <h5>Confirm Deletion</h5>
    </x-slot:header>

    Are you sure you want to delete this item?

    <x-slot:footer>
        <x-button variant="secondary">Cancel</x-button>
        <x-button variant="danger">Delete</x-button>
    </x-slot:footer>
</x-modal>

Asset Stacks

Pushing to Stacks

{{-- In any view --}}
@push('styles')
    <link rel="stylesheet" href="/css/custom.css">
@endpush

@push('scripts')
    <script src="/js/charts.js"></script>
    <script>
        initCharts();
    </script>
@endpush

Rendering Stacks

{{-- In layout --}}
<head>
    <link rel="stylesheet" href="/css/app.css">
    @stack('styles')
</head>
<body>
    {{-- Content --}}

    <script src="/js/app.js"></script>
    @stack('scripts')
</body>

Best Practices

Do

Don't

Security

XSS Protection: Always use {{ }} for user input. Only use {!! !!} for trusted content.
{{-- SAFE - Automatically escaped --}}
<p>Welcome, {{ $user->name }}</p>

{{-- DANGEROUS - Use only for trusted HTML --}}
<div>{!! $trustedHtmlContent !!}</div>

{{-- WRONG - Vulnerable to XSS --}}
<div>{!! $userComment !!}</div>

{{-- CORRECT --}}
<div>{{ $userComment }}</div>

Next Steps

Controllers

Learn how to create controllers and return views with data.

Read Guide

Validation

Validate user input with DTO validation.

Read Guide