Laravel improving readability with blade directives

Laravel's blade templating system comes with ability to define custom directives. These directives can be very handly to improve readability of the view files. Let's do a quick recap of directives :

Blade directives :

  • Generic directive :

These directive take an argument and simply return the actions done in callback.

Blade::directive('caps', function ($expression) {
    return "<?php echo ucwords($expression); ?>";
});

You can use above in blade templates directly :

<div>{{ @cap('john smith') }}</div>

It is little tricky to handle the $expresssion in the callback, as if you pass an array or multiple string arguments, those are passed as single string expressions. You can see that shortly in action in usage ideas section.

  • Conditional directive :

These directives take an argument and use it inside callback to return value. Now the callback's return value is then casted as boolean to consider if statements inside it will be showed or now. It is just like @if ... @endif directive, but more intuitive.

Blade::if('isadmin', function ($user) {
    return $user->role == 'admin';
});

You can use above in blade templates directly :

@isadmin($user)
    <div>
        <a href="{{ route('users.all') }}">See all users</a>
    </div>
@endisadmin

Above is similar to this if done in usual without the conditional directive :

@if($user->role == 'admin')
    <div>
        <a href="{{ route('users.all') }}">See all users</a>
    </div>
@endif

Some usage ideas :

These directive give a great advantage to simplify your blade views and make them more readable. See few examples below :

  1. Conditional role checks :
Blade::if('role', function ($role) {

    // Not logged in
    if(!auth()->check()){
        return false;
    }

    // Multiple roles passed in argument
    if(is_array($role)){
        return in_array(auth()->user()->role, $role);
    }

    // Single role passed in argument
    return auth()->user()->role == $role;
});

This makes the role conditional checks in blade much easier :

@role('admin')
   <!-- something only an admin can see-->
@elserole(['customer', 'seller'])
   <!-- something only a customer or a seller an see-->
@endrole

  1. Rendering form errors :
Blade::directive('validation', function ($expression) {

    // $expression is a string expression and 
    // hence will be a string maintaing start and end quotes
    // Trimming the quotes
    $expression = str_replace(['(', ')'], '', $expression);
    $fieldName  = trim(trim($expression, '"'), '\'');

    $errors = \Session::get('errors', new \Illuminate\Support\MessageBag);

    if($errors->has($fieldName)){
        return '<span role="alert"><strong>' . $errors->first($fieldName) . '</strong></span>';
    }

    return;
});

This makes the the validation errors from server end much easier in forms :

<form role="form" method="POST" action="{{ route('some.url') }}">
    @csrf
    <div class="form-group">
        <label>First Name *</label>
        <input class="form-control" placeholder="Enter your first name" name="first_name">
        @validation("first_name")
    </div>
    <div class="form-group">
        <label>Last Name *</label>
        <input class="form-control" placeholder="Enter your last name" name="last_name">
        @validation("last_name")
    </div>
    <button type="submit" class="btn btn-primary">Submit Ticket</button>
</form>

  1. Dumping values in views fo debugging :
Blade::directive('dd', function ($expression) {

    // $expression is a string expression and 
    // It can not be directly passed in dd($expression)
    // We can use with() helper which basically encapsulate the syntax
    // to render it properly in blade files
    return "<?php dd(with({$expression})); ?>";
});

Please note that above will not work for multiple arguments, can dd one argumenet only. Above can be then used :

@dd([1,2,3,4]);

  1. Assigning values to variables in a view :

Now this might be a very less possible requirement but if you want to assign a variable in a view, generally you do something like :

@php 
    $name = "John Doe";
@endphp

However, we can do this using blade directive :

Blade::directive('assign', function ($expression) {

    // The $expression passed in closure is a string in format '($name), value'
    // Hence we first remove the paranthesis and explode by comma
    list($name, $value) = explode(', ', str_replace(['(', ')'], '', $expression));
    return "<?php {$name} = {$value}; ?>";
});

And then simply use it as (Below example is very very simple but you can use as per your preference) :

@assign($name, 'John Doe')

<div> {{ $name }} </div>

  1. Frequent HTML elements :

If you are using 3rd party HTML libraries like glyphicon or font-awesome, you need to use those in lot of places. You can use blade directive like :

Blade::directive('icon', function ($expression) {

    // The $expression passed in closure is a string in format '($name), value'
    // Hence we first remove the paranthesis and explode by comma
    $classes = str_replace(['(', ')'], '', $expression);
    $classes = str_replace(['"', '\''], '', $expression);
    $classes = str_replace(',', ' ', $classes);

    return '<i class="fa ' . $classes . '" aria-hidden="false"></i>';
});

Then it is as easy as it can get to use :

<label> @icon('fa-user', 'fa-2x') User Name </label>

You can also extend this idea for input, select etc. I think once you set such directives in a project, your blade views become readble. Plus less code in a bladel file is always better.

 
 
By : Mihir Bhende Categories : laravel, php Tags : laravel, php, blade, directives