Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

haztakki's avatar

Custom blade directives

Hi all, I was wondering if someone could provide some help... I'm trying to setup a Blade directive but been stuck on it for some time now... Here's what I have so far:

Blade::directive('hasPermission', function ($expression) {
            list($user, $permission) = explode(', ', $expression);

            $permissions = "<?= with{$user}->permissions ?>";
            $hasPermission = in_array($permission, $permissions) ? 'true' : 'false';

            return "<?php if ($hasPermission): ?>";
        });

I am expanding functionality upon this: https://github.com/laracasts/roles-and-abilities

Watched tutorial: https://laracasts.com/series/intermediate-laravel/episodes/12

$user and $permission are still being treated as strings.

0 likes
32 replies
Snapey's avatar

You need to put all the logic in the output code because the view is built in advance of variable data.

So your evaluation of the user permission needs to be expressed in code that you echo into the view.

1 like
haztakki's avatar

I'm not sure if I'm on the right lines or not but something like this:

		Blade::directive('hasPermission', function ($expression) {
			list($user, $permission) = explode(', ', $expression);

			return "<?php if(in_array({$user->permissions}, {$permission})): ?>";
		});

This is what I have in my Blade view:

        @hasPermission(Auth::user(), 'view_bookings')
            <p>User has permission to view bookings</p>
        @else
            <p>User doesn't have permission to view bookings</p>
        @endif

I get the following error:

 Trying to get property 'permissions' of non-object
piljac1's avatar

If you dd(Auth::user()) in your Blade view, does it output a User instance or null ? Because if it outputs null, then that would explain your error.

haztakki's avatar

It outputs:

"Auth::user()"

I guess I am still having the original issue... $user and $permission are still being treated as strings.

piljac1's avatar

What if you assign Auth::user() to a $user variable in your controller and compact it in your view, then interpolate the variable in your Blade directive (since it's treated as a string).

Would this work ? (since the expression is treated as a string)

@hasPermission({$user}, 'view_bookings')

or

@hasPermission("{$user}", 'view_bookings')

or

@hasPermission("{$user}, view_bookings")

I have a feeling that the third one should work, but then again the string might be messed up by the User model.

haztakki's avatar

Unfortunately no dice.

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

			return "<?php if(in_array(auth()->user()->permissions, {$expression})): ?>";
		});

This doesn't work either. Same error message as above.

piljac1's avatar

Weird... even if your hardcode everything it doesn't work ?

Blade::directive('hasPermission', function ($expression) {
    return "<?php if(in_array(auth()->user()->permissions, 'whatever_permission_youre_trying_to_test')): ?>";
});
piljac1's avatar

Also, in the doc they're wrapping the variables that need chaining with parentheses.

So in your case :

@hasPermission(Auth::user(), 'view_bookings')

Blade::directive('hasPermission', function ($expression) {
    list($user, $permission) = explode(', ', $expression);

    return "<?php if(in_array(($user)->permissions, {$permission})): ?>";
});

or with Laravel <= 5.2, use with{$expression}

@hasPermission(Auth::user(), 'view_bookings')

Blade::directive('hasPermission', function ($expression) {
    list($user, $permission) = explode(', ', $expression);

    return "<?php if(in_array(with{$user}->permissions, {$permission})): ?>";
});
haztakki's avatar

I think the solution is close, I hope! New error:

syntax error, unexpected ':' 

I believe some of my previous message statements were false as I don't think I was logged in (oops, it's late here aha). I have also made sure that the permissions belongsToMany class works standalone.

{{ dd(auth()->user()->permissions()) }}

Returns:

Illuminate\Support\Collection {#539 ▼
  #items: array:1 [▼
    0 => "view_bookings"
  ]
}
        @hasPermission(Auth::user(), 'view_bookings')
            <p>User has permission to view bookings</p>
        @else
            <p>User doesn't have permission to view bookings</p>
        @endif

Blade directive:

		Blade::directive('hasPermission', function ($expression) {
			list($user, $permission) = explode(', ', $expression);

			return "<?php if(in_array( ($user)->permissions(), ($permission) ): ?>";
		});

I think you had some typos in your example above, however I have tried both () and {}, separate and together.

piljac1's avatar

Does your syntax error go away if you hardcode your permission name ?

Blade::directive('hasPermission', function ($expression) {
    list($user, $permission) = explode(', ', $expression);

    return "<?php if(in_array(($user)->permissions, 'view_bookings')): ?>";
});
piljac1's avatar

And try both to see if the error isn't related to the user variable

@hasPermission(Auth::user(), 'view_bookings')

@hasPermission(auth()->user(), 'view_bookings')
haztakki's avatar

Hi,

Blade::directive('hasPermission', function ($expression) {
    list($user, $permission) = explode(', ', $expression);

    return "<?php if(in_array(($user)->permissions, 'view_bookings')): ?>";
});

This gives an error:

Call to a member function permissions() on null

Hmm.

Snapey's avatar

where would $user come from in your view?

You cannot evaluate it when the blade is processed, you need to merge the string 'Auth::user()' into the output so that it can be evaluated in the view

Blade::directive('hasPermission', function ($expression) {
    list($user, $permission) = explode(', ', $expression);

    return "<?php if(in_array((" . $user .  ")->permissions, 'view_bookings')): ?>";
});
Snapey's avatar

same for permission

Blade::directive('hasPermission', function ($expression) {
    list($user, $permission) = explode(', ', $expression);

    return "<?php if(in_array((" . $user .  ")->permissions, " . $permission . ")): ?>";
});
1 like
haztakki's avatar

It will be passed from the controller to the view. In this test instance, I just pass it directly using Auth::user() however I have also tried defining it inside Blade @php tags. Like so:

@php
	$user = Auth::user();
@endphp
{{ dd($user) }}

dd returns the expected output.

Snapey's avatar

If it helps you get your head around it, look at the generated view file

haztakki's avatar

Yeah, I have already tried that, however the generated view never gets created due to the error.

 Trying to get property 'permissions' of non-object 
		Blade::directive('hasPermission', function ($expression) {
			list($user, $permission) = explode(', ', $expression);

			return "<?php if(in_array($permission, $user->permissions())): ?>";
		});

If I manually break it, the generated view is as followed:

        <?php if(in_array("view_bookings", auth()->user()->permissions()): ?>
            <p>User has permission to view bookings</p>
        <?php else: ?>
            <p>User doesn't have permission to view bookings</p>
        <?php endif; ?>

Adding {} around to break it:

return "<?php if(in_array($permission, {$user}->permissions()): ?>";
Snapey's avatar

but you are totally ignoring the examples I gave you and are reverting to trying to process the permissions in the blade component.

So, you want to create this string in the view

<?php if(in_array("view_bookings", auth()->user()->permissions()): ?>

and you want to pass to blade like;

@hasPermission(Auth::user(), 'view_bookings')

so you are passing 2 parameters, call them $user and $perm

You want to return the string

return "<?php if(in_array(" . $perm . "," .  $user . "->permissions()): ?>";

So the full directive would be

Blade::directive('hasPermission', function ($expression) {
    list($user, $perm) = explode(', ', $expression);

return "<?php if(in_array(" . $perm . "," .  $user . "->permissions()): ?>";

});

1 like
haztakki's avatar

I did try your previous suggestions. I couldn't get them to work. I have just directly copied your latest suggestion which gives this error:

syntax error, unexpected ':'
		Blade::directive('hasPermission', function ($expression) {
			list($user, $perm) = explode(', ', $expression);

			return "<?php if(in_array(" . $perm . "," .  $user . "->permissions()): ?>";

		});

Generated view:

        <?php if(in_array('view_bookings',Auth::user()->permissions()): ?>
            <p>User has permission to view bookings</p>
        <?php else: ?>
            <p>User doesn't have permission to view bookings</p>
        <?php endif; ?>
Snapey's avatar
		Blade::directive('hasPermission', function ($expression) {
			list($user, $perm) = explode(', ', $expression);

			return "<?php if(in_array(" . $perm . "," .  $user . "->permissions()); ?>";

		});

semicolon at the end of the generated string

Snapey's avatar

or you could just write a method in your User model. This would do the same thing.

public function hasPermission($permission)
{
    return in_array($permission, $this->permissions());
}

and then use it in your blade file like

@if(Auth::user()->hasPermission('view_bookings')
haztakki's avatar

Yeah I know. Trying to make use of Blade directives though.

Snapey's avatar

so, did changing : to ; fix your issue. (its a simple typo by me writing in this forum with no syntax check)

haztakki's avatar

I will give it a test later. I am away from the computer currently.

piljac1's avatar

@snapey correct me if I'm wrong, but it shouldn't it be : and not ; because the alternative control structure syntax is used ?

1 like
Snapey's avatar

@piljac1 Sorry, yes, of course you are right. The actual error is missing quotes around the permission string

Blade::directive('hasPermission', function ($expression) {
    list($user, $perm) = explode(', ', $expression);

    return "<?php if(in_array('" . $perm . "'," .  $user . "->permissions()): ?>";

});

really hard to see here, but the strings either side of the $perm have single quotes inserted

Writing Blade components is such a time sink, I almost always prefer to find alternate solutions, despite writing several posts on the subject

http://novate.co.uk/laravel-blade-to-deal-with-null-dates/

1 like
piljac1's avatar
piljac1
Best Answer
Level 28

I started a new project to try and get your Blade directive to work, and this seems to work perfectly.

// In view

// It also works with Auth::user()
@hasPermission(auth()->user(), 'view_bookings')
    Yes !
@endif
// In AppServiceProvider.php

Blade::directive('hasPermission', function ($expression) {
    list($user, $permission) = explode(', ', $expression);

    return "<?php if (in_array($permission, ($user)->permissions ?? [])): ?>";
});

Two things :

  • I added a null coalescing operator so an empty array will be used if the user is null
  • IMPORTANT : Do not forget to run php artisan view:clear after changing your Blade directive's code

You could also add a little touch to be less restrictive regarding the exact formatting of your parameters. With the current code, you will receive an error if there's no space or more than 1 space between your comma and your second parameter. To resolve the issue, you could explode the comma only and use trim to remove the excess spaces.

Blade::directive('hasPermission', function ($expression) {
    list($user, $permission) = explode(',', $expression);
    $user = trim($user);
    $permission = trim($permission);

    return "<?php if (in_array($permission, ($user)->permissions ?? [])): ?>";
});
1 like
piljac1's avatar

@snapey Doh ! Thank you for noticing. Edited my answer (tested and working).

1 like
haztakki's avatar

Sadly still no dice. I first tried without logging in and the correct message was shown. When I logged in, I get an error:

App\User::permissions must return a relationship instance
	public function permissions()
	{
		return $this->roles
			->map->permissions
			->flatten()->pluck('name')->unique();
	}

Changing permissions to permissions() gives a new error:

in_array() expects parameter 2 to be array, object given
Next

Please or to participate in this conversation.