در حال بارگذاری ...

Filament as UI framework0:00

I really like to describe Filament as a full-stack UI framework. The reason for that is because while internally we use HTML, CSS, JavaScript, the end developer who's building something with Filament only really has to touch PHP. Let's take this interface for example. Here's a table. The table has columns. Each of these columns is represented by a PHP object. Here's some filters on the table. Each of these filters is also represented by a PHP object. Each row in the table is clickable, and it opens a form.

Each of these filters is also represented by a PHP object. Each row in the table is clickable, and it opens a form. Each of these form fields is also represented by an object, and so is this button. And having all of these things in PHP allows the user to customize them without having to touch any frontend. Let's take this name text input for example. In our ProductResource, we can see the code we used to render this text input. We have a static make method, and what this does is it creates a new instance of the text input and then returns it. We then have these configuration methods here that are modifying that input that we returned.

Creating a TextInput class1:09

input and then returns it. We then have these configuration methods here that are modifying that input that we returned. Now I want to recreate this in an empty php class and show you exactly how it gets rendered in the interface. So let's create a new TextInput class in our project. So app/components is just a directory I've created. Name is going to be TextInput. This is just a basic php class. Now the first thing we're going to encounter is going to be our public static function that makes a new TextInput.

Now the first thing we're going to encounter is going to be our public static function that makes a new text input. So public static function make. This function returns an instance of the text input, so we can use self as a return type. Let's return a new self. Now in our example in the ProductResource, we were able to pass in the name of the text input here. Let's make a new parameter called name and pass that to the constructor of the object. In the construct method, we can accept the name and we can set a new property called name to the name that was passed in.

In the construct method, we can accept the name and we can set a new property called name to the name that was passed in. However, we could clean this up a little bit by using constructor property promotion and define the property right here. Now when the User uses this name, it gets passed through to the constructor here and then it gets saved into this protected property. Let's utilize this textInput. I've created a little route in web.php and we're going to save this to an input variable. So textInput, this is going to be our app components textInput, make. And for our textInput example, we're going to use an email address, so email.

Rendering via Blade view3:03

So text input, this is going to be our app components text input, make. And for our text input example, we're going to use an email address, so email. Now we have an input object. We want to actually render this in the view. So we can pass this through to the view like this. However, this input object doesn't actually have any HTML associated with it at the moment. So that's why we're going to create a view just for this text input and make sure the text input can render itself. So let's create a view in resources/views/components. Going to create a text input file, so text input.blade.php.

So let's create a view in resources/views/components. Going to create a text input file, so textInput.blade.php. Now in here we want to render an HTML input element. So input, probably type text, and we want to render this from the TextInput class. So we're going to make a new public function called render, public function render. And this is going to return an instance of the view. We can use the view contract from Laravel to do this. And this is going to return view helper method. And we're going to be passing in the components.textInput. This is how our component renders itself.

And we're going to be passing in the components.textInput. This is how our component renders itself. Let's go back into our root. As you can see, we're passing in the input object to this demo view, and we can output this using echo. So input, render, and this returns a view object. So then we have to call render on it again to actually get the string to render. Let's go into our view. As you can see, the HTML that's associated with this component is now output in the view. Now we can escape that HTML by switching out the tags that we're using.

Implementing HTMLable output4:58

As you can see, the HTML that's associated with this component is now output in the view. Now we can escape that HTML by switching out the tags that we're using. And now we have our input. However, calling render, render, and using these special tags for every single component I want to render is not exactly the best developer experience. Luckily, Laravel allows us to output any HTMLable object much easier in Blade just by using simple template strings like this. Now HTMLable is an interface from the Laravel core, and it contains one public function called toHTML. And this instructs Laravel how to extract the HTML out of the object.

called toHTML. And this instructs Laravel how to extract the HTML out of the object. So let's implement HTMLable on our object. Implements HTMLable. Now that toHTML method needs to be added to our class, and this is going to be returning a string. And we can call this render, render, just as we did in the view. Now since Laravel knows this is an HTMLable object, we don't need to escape it. So we can get rid of all of this. Now check our view again, and it just works.

Adding fluent label config6:13

So we can get rid of all of this. Now check our view again, and it just works. Now in our ProductResource, we had some configuration associated with this text input. It was required, it was lazy, it had an after state updated function, and some of these also have labels. So for example, this text input here has a custom label. So let's add this label function onto our text input. To do this, we need a public function, public function label, and it's going to return an instance of the current text input. This is to ensure that we can then chain these methods onto one another in any order, fluently.

instance of the current text input. This is to ensure that we can then chain these methods onto one another in any order, fluently. This method accepts a string of the label, and we can save it into a label property. Let's define that property. And now we can pass that label to our view. In our view, we can now access the label as the label variable. So let's make a label tag, we can make a span, holds the actual label, going to output the label, and we're going to output our field. Now in web.php, we can pass in our label here, so let's call it email address. And now we have our label rendering in the view.

Now in WebPHP, we can pass in our label here, so let's call it emailAddress. And now we have our label rendering in the view. However, let's go into WebPHP and remove the label. As you can see, we now have an error. This is because the label has not been initialized, and in this case, we want to actually auto generate a label for the user. So let's make a new function called getLabel, and we're going to wrap this get call here in a function that is able to handle the fact that a label might not be set. So we're going to generate a label from the name. It's going to return a string.

So we're going to generate a label from the name. It's going to return a string. We can use Laravel's string helper to do this, so this name here, and we can return the title of this name, and this is going to add capitalization, etc. Now when we pass in the label to the view, we can just use this getLabel now. Sure enough, we now have a default label, however, this also still works. Now you could do this for every single configuration method on your component, however, this could get very time consuming because you have to then add every single getter method to this long array. What I like to do instead is have a function that is able to extract all of these getter

Auto-passing methods with Reflection9:23

long array. What I like to do instead is have a function that is able to extract all of these getter methods into an array automatically. So let's create one called extractPublicMethods. It's going to return an array that we can pass directly to the view. php has an API called Reflection, and Reflection is able to get information about the code. So for example, I can create a new Reflection here. It can be a new ReflectionClass. I can pass in $this, and this is going to give me information about the textInput. So Reflection, getMethods, getName, getProperties, getMethod, getAttributes.

I can pass in this, and this is going to give me information about the text input. So Reflection, getMethods, getName, getProperties, getMethod, getAttributes. This case, we just want the methods, not just any method though, we want public methods. So we're going to pass in the ReflectionMethod isPublic constant, and that is able to filter down the methods to only the public ones. Now to construct our array, we need to foreach through these methods as method, and each time we want to add a new item to an array containing the name of the method as our key, and a callable version of the method as the value. So let's create a new temporary variable to hold those. So methods is going to be an array, we can return methods here, and for each method,

So let's create a new temporary $variable to hold those. So methods is going to be an array, we can return methods here, and for each method, we're going to save a new method into our array. The key is going to be the name of the method, so method > getName, and the value is going to be closure, from callable, and we can pass in a callable here, so that's anything that php can call as a function. So this method, getName, is the callable representation of calling this method on this object. And what closure from callable does is convert that into a function that the user can then run. Now, I know I went through the implementation of that method quite quickly, but hopefully

run. Now, I know I went through the implementation of that method quite quickly, but hopefully now you can understand that to be able to use configuration values from your component class in your view, you don't need to keep passing them into the view manually, Filament does that for you. This should save you loads of time if you're ever going to be building custom fields, custom form components, custom table columns, custom info list entries, any component in Filament. Now we have our extractPublicMethods method. We can replace this entire array with this, extractPublicMethods. Now in our textInput, we can replace this with just getLabel.

We can replace this entire array with this, extractPublicMethods. Now in our text input, we can replace this with just getLabel. And since we have our getLabel public method on our class, it should be passed in automatically. Now you can see how we can get directly from this PHP object into the view. And this is the concept that underpins the entirety of Filament.

The files that make up a component. Instantiating a component class with a static <code>make()</code> method. Using Laravel's <code>Htmlable</code> interface to render objects in Blade as HTML. Using getter and setter methods to access component properties. Automatically exposing component getter methods to the view.

دوست دارید گاهی خبرهای Laracasts را ایمیل کنیم؟