Views & Blade Templates

Info: 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())

Welcome, Admin!

{{ "@" }}elseif($user->isModerator())

Welcome, Moderator!

{{ "@" }}else

Welcome, User!

{{ "@" }}endif

{{-- Unless (inverse if) --}}
{{ "@" }}unless($user->isBanned())

You can post comments

{{ "@" }}endunless

{{-- Isset check --}}
{{ "@" }}isset($user)

User: {{ $user->name }}

{{ "@" }}endisset

{{-- Empty check --}}
{{ "@" }}empty($posts)

No posts found

{{ "@" }}endempty

Loops

{{-- Foreach loop --}}
{{ "@" }}foreach($posts as $post)
<article>

## {{ $post->title }}

{{ $post->excerpt }}

</article>
{{ "@" }}endforeach

{{-- For loop --}}
{{ "@" }}for($i = 0; $i < 10; $i++)

Item {{ $i }}

{{ "@" }}endfor

{{-- While loop --}}
{{ "@" }}while($condition)

Processing...

{{ "@" }}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>
 - 
{{ "@" }}stack('styles')
</head>
<body>
<header>
<h1>{{ $title }}</h1>
<nav>
[Home](/)
[About](/about)

<main>
{{ "@" }}yield('content')
</main>

<footer>

&copy; 2025 Larafony

</footer>

{{ "@" }}stack('scripts')

Extending a Layout

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

{{ "@" }}section('content')
<article>

## {{ $post->title }}

By {{ $post->author }} on {{ $post->created_at }}

{!! $post->content !!}

{{ "@" }}if($post->tags)

{{ "@" }}foreach($post->tags as $tag)
{{ $tag }}
{{ "@" }}endforeach

{{ "@" }}endif
</article>
{{ "@" }}endsection

{{ "@" }}push('scripts')

{{ "@" }}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 --}}

{{ "@" }}if($dismissible)
<button type="button" class="close">&times;</button>
{{ "@" }}endif

{{ "@" }}if($title)

#### {{ $title }}

{{ "@" }}endif

{!! $slot !!}

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 --}}

{{ "@" }}isset($slots['header'])

{!! $slots['header'] !!}

{{ "@" }}endisset

{{ "@" }}if($title)

### {{ $title }}

{{ "@" }}endif

{!! $slot !!}

{{ "@" }}isset($slots['footer'])

{!! $slots['footer'] !!}

{{ "@" }}endisset

Using Named Slots

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

Name: {{ $user->name }}

Email: {{ $user->email }}

<x-slot:footer>
<button>Edit Profile
</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 --}}

{{ "@" }}isset($slots['header'])

{!! $slots['header'] !!}
<button class="close">&times;</button>

{{ "@" }}endisset

{!! $slot !!}

{{ "@" }}isset($slots['footer'])

{!! $slots['footer'] !!}

{{ "@" }}endisset

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

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-modal>

Asset Stacks

Pushing to Stacks

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

{{ "@" }}push('scripts')

<script>
initCharts();
</script>
{{ "@" }}endpush

Rendering Stacks

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

{{ "@" }}stack('scripts')
</body>

Best Practices

Do

  • Use `{{ }}` for displaying data (automatic escaping)

    Don't

    Security

    Danger: XSS Protection: Always use &lbrace;&lbrace; &rbrace;&rbrace; for user input. Only use &lbrace;!! !!&rbrace; for trusted content.

    {{-- SAFE - Automatically escaped --}}
    
    Welcome, {{ $user->name }}
    
    {{-- DANGEROUS - Use only for trusted HTML --}}
    
    {!! $trustedHtmlContent !!}
    
    {{-- WRONG - Vulnerable to XSS --}}
    
    {!! $userComment !!}
    
    {{-- CORRECT --}}
    
    {{ $userComment }}
    
    

    Next Steps

    Controllers

    Learn how to create controllers and return views with data.

    Read Guide

    Validation

    Validate user input with DTO validation.

    Read Guide