spatie / laravel-ray

Debug with Ray to fix problems faster in Laravel apps
https://myray.app
MIT License
291 stars 64 forks source link

@ray blade directive can break other custom directives #250

Closed dfox288 closed 2 years ago

dfox288 commented 2 years ago

Describe the bug Under certain circumstances, the @ray blade directive breaks other directives if they are loaded after the ray package

Versions Ray version 1.25+

PHP version: 8.0.19 Laravel version: 8+

To Reproduce

It's hard to reproduce but I will try to narrow the issue down in the next couple of days.

Fact is, that once I require the ray package in one of my clients laravel applications, it will break custom blade directives, which are properly registered in their respective Service Providers.

I guess due to some kind of race condition, the call to register a custom blade directive AFTER registering the custom blade directive for Ray will instantiate a new blade compiler instance, which will somehow not merge the previously registered blade directives.

Expected behavior

Blade directives registered after the @ray directive should wait for the blade compiler to be resolved before registering the directive.

Additional context

Here's an excerpt from my logging attempts - but it should showcase what's happening in my project. As you can see, the unique class hash (spl_object_hash($this)) changes after the ray directive has been registered.

string(55) "Unique class-hash: 00000000000000e50000000000000000 string(35) "Register directive: role string(35) "Registered directives: 1 string(55) "Unique class-hash: 00000000000000e50000000000000000 string(39) "Register directive: elserole string(35) "Registered directives: 2 string(55) "Unique class-hash: 00000000000000e50000000000000000 string(38) "Register directive: endrole string(35) "Registered directives: 3 string(55) "Unique class-hash: 00000000000000e50000000000000000 string(38) "Register directive: hasrole string(35) "Registered directives: 4 string(55) "Unique class-hash: 00000000000000e50000000000000000 string(41) "Register directive: endhasrole string(35) "Registered directives: 5 string(55) "Unique class-hash: 00000000000000e50000000000000000 string(41) "Register directive: hasanyrole string(35) "Registered directives: 6 string(55) "Unique class-hash: 00000000000000e50000000000000000 string(44) "Register directive: endhasanyrole string(35) "Registered directives: 7 string(55) "Unique class-hash: 00000000000000e50000000000000000 string(42) "Register directive: hasallroles string(35) "Registered directives: 8 string(55) "Unique class-hash: 00000000000000e50000000000000000 string(45) "Register directive: endhasallroles string(35) "Registered directives: 9 string(55) "Unique class-hash: 00000000000000e50000000000000000 string(41) "Register directive: unlessrole string(36) "Registered directives: 10 string(55) "Unique class-hash: 00000000000000e50000000000000000 string(44) "Register directive: endunlessrole string(36) "Registered directives: 11 string(55) "Unique class-hash: 00000000000000e50000000000000000 string(44) "Register directive: hasexactroles string(36) "Registered directives: 12 string(55) "Unique class-hash: 00000000000000e50000000000000000 string(47) "Register directive: endhasexactroles string(36) "Registered directives: 13 string(55) "Unique class-hash: 00000000000000e50000000000000000 string(34) "Register directive: ray string(36) "Registered directives: 14 string(55) "Unique class-hash: 000000000000003d0000000000000000 string(35) "Register directive: role string(35) "Registered directives: 1 string(55) "Unique class-hash: 000000000000003d0000000000000000 string(39) "Register directive: elserole string(35) "Registered directives: 2 string(55) "Unique class-hash: 000000000000003d0000000000000000 string(38) "Register directive: endrole string(35) "Registered directives: 3 string(55) "Unique class-hash: 000000000000003d0000000000000000 string(38) "Register directive: hasrole string(35) "Registered directives: 4 string(55) "Unique class-hash: 000000000000003d0000000000000000 string(41) "Register directive: endhasrole string(35) "Registered directives: 5 string(55) "Unique class-hash: 000000000000003d0000000000000000 string(41) "Register directive: hasanyrole string(35) "Registered directives: 6 string(55) "Unique class-hash: 000000000000003d0000000000000000 string(44) "Register directive: endhasanyrole string(35) "Registered directives: 7 string(55) "Unique class-hash: 000000000000003d0000000000000000 string(42) "Register directive: hasallroles string(35) "Registered directives: 8 string(55) "Unique class-hash: 000000000000003d0000000000000000 string(45) "Register directive: endhasallroles string(35) "Registered directives: 9 string(55) "Unique class-hash: 000000000000003d0000000000000000 string(41) "Register directive: unlessrole string(36) "Registered directives: 10 string(55) "Unique class-hash: 000000000000003d0000000000000000 string(44) "Register directive: endunlessrole string(36) "Registered directives: 11 string(55) "Unique class-hash: 000000000000003d0000000000000000 string(44) "Register directive: hasexactroles string(36) "Registered directives: 12 string(55) "Unique class-hash: 000000000000003d0000000000000000 string(47) "Register directive: endhasexactroles string(36) "Registered directives: 13 string(55) "Unique class-hash: 00000000000000e50000000000000000 string(39) "Register directive: lm_attrs string(36) "Registered directives: 15 string(55) "Unique class-hash: 00000000000000e50000000000000000 string(42) "Register directive: lm_endattrs string(36) "Registered directives: 16 string(55) "Unique class-hash: 00000000000000e50000000000000000 string(52) "Register directive: data_toggle_attribute string(36) "Registered directives: 17 string(55) "Unique class-hash: 00000000000000e50000000000000000 string(41) "Register directive: boxWrapper string(36) "Registered directives: 18 string(55) "Unique class-hash: 00000000000000e50000000000000000 string(40) "Register directive: boxHeader string(36) "Registered directives: 19 string(55) "Unique class-hash: 00000000000000e50000000000000000 string(38) "Register directive: boxBody string(36) "Registered directives: 20 string(55) "Unique class-hash: 00000000000000e50000000000000000 string(40) "Register directive: boxFooter string(36) "Registered directives: 21 string(55) "Unique class-hash: 00000000000000e50000000000000000 string(48) "Register directive: defaultButtonSize string(36) "Registered directives: 22 string(55) "Unique class-hash: 000000000000003d0000000000000000 string(37) "Register directive: routes string(36) "Registered directives: 14 string(55) "Unique class-hash: 00000000000000e50000000000000000 string(35) "Register directive: test string(36) "Registered directives: 23 string(55) "Unique class-hash: 00000000000000e50000000000000000 string(39) "Register directive: currency string(36) "Registered directives: 24 string(55) "Unique class-hash: 00000000000000e50000000000000000 string(41) "Register directive: boxWrapper string(36) "Registered directives: 24 string(55) "Unique class-hash: 00000000000000e50000000000000000 string(40) "Register directive: boxHeader string(36) "Registered directives: 24 string(55) "Unique class-hash: 00000000000000e50000000000000000 string(38) "Register directive: boxBody string(36) "Registered directives: 24 string(55) "Unique class-hash: 00000000000000e50000000000000000 string(40) "Register directive: boxFooter string(36) "Registered directives: 24 string(55) "Unique class-hash: 00000000000000e50000000000000000 string(48) "Register directive: defaultButtonSize string(36) "Registered directives: 24

Proposed solution

As it is done in other Spatie projects like spatie/laravel-permissions package, which also has custom directives, I propose wrapping the Blade::directive call in a closure that waits for the blade compiler to be resolved:

$this->callAfterResolving('blade.compiler', function (BladeCompiler $bladeCompiler) {
            $this->registerBladeExtensions($bladeCompiler);
        });

I can prepare a PR if you want