balping/laravel-blade-function

This Laravel 5.1+ package lets you declare functions inside blade templates.

v0.4.3 2024-03-30 18:23 UTC

This package is auto-updated.

Last update: 2024-03-30 17:28:23 UTC


README

This Laravel package lets you declare functions inside blade templates. After installing it, you'll never need to use partials as functions.

This package is compatible with Laravel 5.1 – 5.8, 6 - 11

In Laravel 5.4 components were introduced. There is an overlap between the problems componenets and this package try to solve. So from 5.4 you might want to consider using componenets instead. They are different though and this package might still provide a cleaner and easier solution in some cases.

Installation

Run this from the terminal:

composer require balping/laravel-blade-function

If you are using Laravel >=5.5, this step is unnecessary, thanks to package auto-discovery.

Add this line to the providers array in config/app.php:

Balping\BladeFunction\BladeFunctionServiceProvider::class,

That's it.

How to use it

You can declare and use functions in views like so:

@extends('layouts.app')

@function(hello ($who))
    Hello {{$who}}!
@endfunction

@section('content')
    <p>
        @hello('World')
    </p>
@endsection

The @function directive accepts the function name and the argument list as parameter. If your function doesn't need arguments, you can omit the parentheses:

{{-- Both are correct: --}}

@function( printhello () )
    Hello
@endfunction

@function(printhello)
    Hello
@endfunction

In this case you can omit the parentheses when calling the function as well: @printhello() and @printhello are both correct.

You can use any other blade directives inside your functions:

@function(mylist ($items))
    <ul>
        @foreach($items as $item)
            <li>{{$item}}</li>
        @endforeach
    </ul>
@endfunction

@mylist([1, 2, 3]) {{-- Prints ∙1 ∙2 ∙3  --}}

There's also a @return directive, just in case. But you probably won't need this.

@function(theanswer())
	@return(42)
@endfunction

You can automatically pass variables as reference from parent scope by using the use keyword:

@function(hello ($who) use ($lang))
    {{$lang == 'de' ? 'Hallo' : 'Hello'}} {{$who}}!
@endfunction

<?php $lang = 'en'; ?>
@hello('World')

Gotchas and Things to Be Aware of

Unlike in PHP in general, blade functions must be declared before calling them! Just like in the good old C days. But while in C you can use header files for this reason, in this case functions must be declared in the same view file where you use them. However this shouldn't be a problem, please see the When (not) to use it section.

When you declare a function using the @function directive, the function will be a real PHP function and it will be in the global namespace. This means that you can't use PHP keywords and already declared functions as function name.

You can call functions you declared in the 'traditional' way, in plain PHP code. In this case however you need to pass the $__env variable manually. (This is used by blade for various things, ex. in foreach loops.)

{{-- These are the same --}}
@hello('world')
<?php hello('world', $__env); ?>

If you use the use keyword, you also need to pass the additional parameters manually:

@function(hello ($who) use ($lang))
    ...
@endfunction

<?php $lang = 'en'; ?>


{{-- These are the same --}}
@hello('World')
<?php hello('world', $lang, $__env); ?>

When (not) to use it

This package is meant to help presenting small things. But only where blade syntax comes handy.

I created this package because many times I found myself treating partials as functions. Which can be pretty ugly and convenient, especially when you pass some data as argument. So I'd say, when you want to extract some blade code, but you don't feel like putting it into a separate partial view, that's when you probably want to use a blade function. It might be also a good idea to wrap partial includes in functions (see example below).

Keep in mind, that in most cases it is a good idea to separate logic and presentation. So you shouldn't use this for parsing data or calculating factorial series (however you can, see the example). It's neither the best choice for helper functions where you format some data without html (ex.: you can create an app/Http/helpers.php file where you can add your custom date formatting functions, etc.)

Examples

Wrapping partials

This looks like a common situation:

@include('partials.modal', [
	'header' => 'Alert',
	'body'   => 'Something terrible happened.'
])

You can replace the above code with this:

@function(modal ($header, $body))
    @include('partials.modal', compact('header', 'body'))
@endfunction

...

@modal('Alert', 'Something terrible happened.')

{{-- Let's reuse it --}}

@modal('Success', 'You\'re great!')

Much cleaner, isn't it?

Factorials

You shouldn't do this. I mean you really shouldn't. This is not what blade is designed for. But yeah, now you can do recursion using bladish syntax :-P

@function(factorials ($n))
    @if($n <= 1)
        {{1}}
        @return(1)
    @endif


    {{$tmp = $n * factorials($n - 1, $__env)}}

    @return($tmp)
@endfunction

@factorials(5) {{-- prints 1 2 6 24 120 --}}

Contributions

Any contributions are welcome. Probably there is a much better way to do this, since there's a way to add extensions and custom compilers to blade. But it's undocumented and I'm not into Laravel that deep to understand what's going on in the blade parser. If you do know more, please help me to rewrite this. I really don't like that functions must be defined first, in the same file and it is also ugly that you have to pass $__env each time.