GitHub

Blade Templating

TinyMVC provides a fast, lightweight laravel like Blade templating system with additional conveniences for layouts, components, and data sharing.

Basic Usage

Rendering Views

// In controllers
return view('welcome', ['name' => 'John']);

// with context
$user = User::findOrFail($id);
$posts = Post::where('user_id', $id)->get();
return view('welcome', compact('user', 'posts'));

Template Structure

views/
├── layouts/
│   └── app.blade.php      # Main layout
├── components/
│   └── alert.blade.php    # Reusable components
└── pages/
    ├── home.blade.php     # Page templates
    └── profile.blade.php

Spark CLI

Use the Spark CLI to generate views, and components.

php spark make:view welcome
php spark make:component alert

Template Features

Passing Data

// Controller
return view('profile', [
    'user' => $user,
    'title' => 'User Profile'
]);

// Template (profile.blade.php)
<h1>{{ $title }}</h1>
<p>Welcome, {{ $user->name }}></p>

Layouts

// Using layout
return view('pages.home');

// Page template (pages/home.blade.php)
@extends('layouts.app')

@section('content')
    <section>
        <h1>Home</h1>
        <p>Welcome to the home page!</p>
    <section/>
@endsection

// Layout template (layouts/app.blade.php)
<!DOCTYPE html>
<html>
<head>
    <title>My App</title>
</head>
<body>
    @yield('content')
</body>
</html>

Components

// In template
<x-alert type="success" message="Updated!" />

// Component (components/alert.blade.php)
<div class="alert alert-{{ $type }}">
    {{ $message }}
</div>

// Component with slot and dynamic parameters
<x-user-card :$user :profileUrl="route('profile', ['username' => $user->username])">
    // user html slot content
</x-user-card>

// Component (components/user-card.blade.php)
<div class="user-card">
    <a href="{{ $profileUrl }}">
        <h2>{{ $user->name }}</h2>
        {!! $slot !!}
    </a><
</div>

Automatic Context

These variables are always available in templates:

$app       // Application instance
$request   // Current Request object  
$session   // Session object
$errors    // Validation errors
$view      // Current View instance

View Methods

// Share a context variable
@share('user', $user)

// Check for data in other child template
@isset($user)

@endisset

// Include template partials
@include('partials.header')

Advanced Patterns

View Composers & Custom directives

// Share or Compose to View
class AppServiceProvider
{
    public function boot()
    {
        // Share context globally to view
        View::share([
            'categories' => Category::all(),
            'stats' => SiteStats::get()
        ]);

        // Set Composers to specific views
        View::composer('partials.nav', function ($view) {
            $view->share('friends', User::friends(auth()->id()));
        });

        // Add a custom directive
        view()->directive('datetime', function ($expression) {
            return "<?php echo carbon($expression)->diffForHumans(); ?>";
        });
    }
}

Error Handling

// Access all validation errors
@errors('email')
    <li>{{ $message }}</li>
@enderrors

// Access a specific validation error
@error('email')
    <div class="error">{{ $message }}</div>
@enderror

// Alternative, Access a specific validation error
@if ($errors->has('email'))
    <div class="error">{{ $errors->first('email') }}</div>
@endif

// Access validation errors
@if ($errors->hasAny())
    <div class="alert alert-danger">{{ $errors }}</div>
@endif

Full Example

// Controller
public function show($id)
{
    return view('products.show', [
        'product' => Product::find($id),
        'related' => Product::related($id)
    ]);
}

// Template (products/show.blade.php)
@extends('layouts.store')

@section('content')
    @include('partials.product-header')

    <div class="product-details">
        <h1>{{ $product->name }}</h1>
        <x-price :price="$product->price" />
    </div>
@endsection


@if (!empty($related))
    <h2>Related Products</h2>
    @include('partials.product-grid', ['products' => $related])
@endif

// Layout (layouts/store.blade.php)
<!DOCTYPE html>
<html>
<head>
    <title>{{ $title ?? 'Store' }}</title>
</head>
<body>
    @include('partials.nav')
    <main>
        @yield('content')
    </main>
    @include('partials.footer')
</body>
</html>

Available Blade Directives

This Blade-like template engine supports the following directives and syntax:

Directive Description Usage Example
{{ $var }} Echoes escaped content (HTML entities converted). {{ $name }}
{!! $var !!} Echoes unescaped content (raw HTML output). {!! $html !!}
@php ... @endphp Executes raw PHP code inside the template.
@php
    $count = 5;
@endphp
@json($var) Echo JSON-encoded content. const users = @json($users)
@extends('layout') Specifies a parent view to extend. @extends('layouts.main')
@section('name') / @endsection Defines a section for layout injection.
@section('title')
My Page
@endsection
@section('name', 'value') Defines a section inline. @section('title', 'My Page')
@yield('section') Outputs a section’s content. @yield('content')
@yield('section', 'default') Outputs section content with a default value. @yield('title', 'Default')
@show Ends section and outputs it immediately.
@section('sidebar')
Sidebar content
@show
@include('view') Includes another view file. @include('partials.header')
@includeIf('view') Includes view if it exists. @includeIf('optional.view')
@includeWhen(condition, 'view', [data]) Includes view only when condition is true. @includeWhen($user, 'profile', ['user' => $user])
@includeUnless(condition, 'view') Includes view unless condition is true. @includeUnless($user, 'guest')
@hasSection('view') Checks if a section exists.
@hasSection('sidebar')
    Sidebar content is available.
@else
    No sidebar content.
@endif
@sectionMissing('view') Checks if a section is missing.
@sectionMissing('sidebar')
    No sidebar content.
@endif
<x-name /> Self-closing component tag. <x-alert type="success" />
<x-name>...</x-name> Component with content slot.
<x-alert type="error">
Error message
</x-alert>
:attribute Passes a PHP variable or expression to a component attribute. <x-alert :message="$error" />
@if(condition) / @endif Conditional block.
@if($user)
Hello, {{ $user->name }}
@endif
@elseif(condition) Else-if condition in an @if block. @elseif($admin)
@else Else branch for conditionals. @else
@unless(condition) / @endunless Executes block unless condition is true.
@unless($loggedIn)
Please log in.
@endunless
@isset($var) / @endisset Executes block if variable is set.
@isset($records)
Records found!
@endisset
@empty($var) / @endempty Executes block if variable is empty.
@empty($records)
No records found.
@endempty
@for(...) / @endfor Classic for loop.
@for($i = 0; $i < 10; $i++)
{{ $i }}
@endfor
@foreach(...) / @endforeach Loops through each item.
@foreach($users as $user)
{{ $user->name }}
@endforeach
@while(condition) / @endwhile While loop.
@while($count < 10)
Count: {{ $count++ }}
@endwhile
@continue / @break Loop control statements.
@foreach($items as $item)
    @if($item->skip) @continue @endif
    {{ $item }}
@endforeach
@switch($var) / @endswitch Switch statement.
@switch($role)
@case('admin')
Admin panel
@break
@default
User panel
@endswitch
@case(value) Case within a switch. @case('admin')
@default Default case in a switch. @default
@verbatim ... @endverbatim Outputs uncompiled content (useful for showing Blade syntax).
@verbatim
{{ This will not be compiled }}
@endverbatim
@csrf Outputs a hidden CSRF token input. @csrf
@method('PUT') Specifies HTTP method for form spoofing. @method('PATCH')
@auth ... @endauth Shows content only if user is authenticated.
@auth
Welcome back!
@endauth
@guest ... @endguest Shows content only if user is a guest.
@guest
Please log in.
@endguest
@can($ability) / @endcan Checks if a user has a specific ability.
@can('edit-articles')
You can edit articles.
@endcan
@cannot($ability) / @endcannot Checks if a user does not have a specific ability.
@cannot('edit-articles')
You cannot edit articles.
@endcannot
@vite($args) Includes Vite assets.
@vite('app.jsx')
@errors('field') Displays validation errors for a specific field.
@errors('email')
    {{ $message }}
@enderrors

Best Practices

  • Keep templates focused on presentation only
  • Use components for reusable UI elements
  • Pass only necessary data to views
  • Store complex logic in view composers
  • Use layouts for consistent page structures