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:
- Blade Syntax - Familiar directives like @if, @foreach, @extends
- Component System - Reusable UI components with slots
- Template Inheritance - Layouts and sections
- Compiled Templates - Cached for performance
- PSR-7 Compatible - Return directly from controllers
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>© 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">×</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">×</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
- Use
{{ }}for displaying data (automatic escaping) - Create reusable components for repeated UI patterns
- Use named slots for complex component layouts
- Keep component logic in the component class
- Use layouts for consistent page structure
- Push scripts to stacks for proper loading order
Don't
- Don't use
{!! !!}for user input (XSS risk) - Don't put business logic in views
- Don't create deeply nested components (3+ levels)
- Don't forget to escape user-provided content
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>