Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[8.x] Adds class handling for Blade echo statements #37478

Merged
merged 21 commits into from
May 28, 2021
Merged

[8.x] Adds class handling for Blade echo statements #37478

merged 21 commits into from
May 28, 2021

Conversation

lukeraymonddowning
Copy link
Contributor

@lukeraymonddowning lukeraymonddowning commented May 25, 2021

What is it?

When working in Blade, I'll often want to always output a class in the same manner. I'll use Brick/Money as the example here, but this can apply to pretty much any class you can think of.

Brick/Money is a final class, so I can't add a Stringable interface to it. Whenever I output {{ $moneyObject }}, I would want it to format as £100.00, for example. The same could be said for a Carbon instance.

This PR adds a new Blade::handle() method that can be placed in the boot method of a Service Provider and allows the user to add intercepting closures for any class. The returned value will be outputted in Blade.

Think of this as the Exception Handler, but for Blade.

Usage

// AppServiceProvider
Blade::handle(Money::class, fn($object) => $object->formatTo('en_GB'));
Blade::handle(Carbon::class, fn($object) => $object->format('d/m/Y')));
<dl>
    <dt>Total</dt>
    <dd>{{ $product->total }}</dd> <!-- This is a money object, but will be outputted as an en_GB formatted string -->
    <dt>Created at</dt>
    <dd>{{ $product->created_at }}</dd> <!-- This is a Carbon object, but will be outputted as English date format -->
</dl>

How does it work?

This works by wrapping a small piece of logic around php output at the parser level, which means that the object is evaluated just in time and can thus be treated as a standard object throughout the entire application; it is only transformed by the PHP script at the time of output.

Feel free to throw any questions back at me :-)

Thanks for all the hard work guys!

@lukeraymonddowning
Copy link
Contributor Author

This is a fixed version of #37477 which had broken unit tests. It also is faster than previously because it will completely skip the JIT check if no handlers have been specified.

@driesvints driesvints changed the title [8.x] Adds class handling for Blade echo statements [fixed unit tests] [8.x] Adds class handling for Blade echo statements May 25, 2021
@taylorotwell
Copy link
Member

taylorotwell commented May 26, 2021

Does putting line breaks in the compiled echo syntax cause any unwanted side effects in regards to rendered elements? For example:

Foo{{ $bar }}baz

And:

Foo: {{ $bar }}

Is the proper spacing always maintained when rendered?

@lukeraymonddowning
Copy link
Contributor Author

Will check this tomorrow and add unit tests to prove

@lukeraymonddowning
Copy link
Contributor Author

@taylorotwell from testing in a real application, the whitespaces made no difference, but it doesn't really make much sense to keep the whitespaces there anyway so I've removed them. Also added a test in similar vain to those in the BladeEchoTest file that check for the preservation of newlines after the output.

*
* @return void
*/
public function handle(string $className, callable $handler)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wondering if this should be addEchoHandler. handle is so generic and might be confused with a job's handle method. The former is a registration of a resolver while the later is an actual resolver.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. I've renamed.

@taylorotwell
Copy link
Member

taylorotwell commented May 27, 2021

Renamed method to stringable and added ReflectsClosures trait to Blade compiler so that it is now possible to omit the class name as the first argument and just provide a type-hinted callback:

Blade::stringable(fn (Money $money) => $money->formatTo('en_GB'));

Thoughts?

@lukeraymonddowning
Copy link
Contributor Author

Love it @taylorotwell. Stringable fits in perfectly with the interface, so makes complete sense and the ability to type hint instead is pure fire 😎

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants