Use your helper methods without the boring namespace stuff

Posted 2 years ago by mercuryseries

Before using Laravel I was a big fan of Ruby on Rails and the feature that I loved the most about Ruby on Rails was the ability to be able to create a helper method (in a module) and being able to call it like a global method.

Module BooksHelper
  def format_price(book)
    if book.free?
      content_tag(:strong, 'Free!')
    else
      number_to_currency(book.price)
    end
   end
end
<p><%= format_price(book) %></p>

Pretty cool isn't it?

Now as you might guess I want to have the same thing in Laravel.

Oh I should have said I have the same thing now with Laravel :)

EDIT: I made a small package for it available here https://github.com/mercuryseries/laravel-helpers

Here are the steps if you also want it:

  • Create a Helpers directory in your app folder.
  • Add some classes with helpers methods (PS: with the current code all your helper methods need to be static, but you can easily change it if you want)
<?php

namespace App\Helpers;

use App\Book;

class BooksHelper
{
    public static function formatPrice(Book $book)
    {
        if($book->isFree()) {
            return '<strong>Free!</strong>';
        } else {
            return sprintf('$%f', number_format($book->price, 2, '.', ''));
        }
    }
}
<?php

namespace App\Helpers;

class PagesHelper
{
    public static function setActive($route)
    {
        // your code goes here
    }
}
  • Create a HelpersServiceProvider and register it in config/app.php
php artisan make:provider HelpersServiceProvider
<?php

namespace App\Providers;

use ReflectionClass;
use View;
use Illuminate\Support\ServiceProvider;

class HelpersServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap the application services.
     *
     * @return void
     */
    public function boot()
    {
        $this->loadHelpersFrom(app_path('Helpers'));
    }

    /**
     * Register the application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }

    public static function loadHelpersFrom($directory)
    {
        $helpers = static::findAllHelpersIn($directory);

        foreach ($helpers as $helper) {
            static::registerMethods($helper);
        }
    }

    public static function findAllHelpersIn($directory)
    {
        return array_diff(scandir($directory), array('..', '.'));
    }

    public static function registerMethods($helper)
    {
        $helperClassName = substr($helper, 0, -4);
        $reflector = new ReflectionClass('App\\Helpers\\' . $helperClassName);
        $methods = $reflector->getMethods();

        foreach ($methods as $method) {
            $methodHelper = function(...$params) use ($method) {
                return $method->class::{$method->name}(...$params);
            };

            View::share($method->name, $methodHelper);
        }
    }
}

In config/app.php, add:

App\Providers\HelpersServiceProvider::class,
  • Have fun now as me by using your helper methods
{{ $formatPrice($book) }}
{{ $setActive('home') }}

You can also call it with:

{{ App\Helpers\BooksHelper::formatPrice($book) }}

But that is exactly what I want to avoid.

PS: Of course you can create a folder with many files helpers. For example a books_helpers.php file containing all your helpers as global methods but I rather prefer to create a class and it's much more clear when testing. So everyone may not like it!

Cheers

Please sign in or create an account to participate in this conversation.

Reply to

Use Markdown with GitHub-flavored code blocks.