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

Introducing Laravel Scout0:00

All right, let's move on. So this is overdue, but it's time to check out Laravel Scout. So as you see here in the documentation, Scout provides a simple driver based solution for adding full text search to your Eloquent models. Okay, so by driver based, here's what that basically means. It offers a single API, but you can swap out the underlying search engine, which is really cool.

but you can swap out the underlying search engine, which is really cool. So maybe you're using the database driver, but then you wanna switch over to Typesense. You can still stick with that Scout API and just swap out the underlying config. It's really cool. It's sort of an implementation of the manager pattern, if you're familiar with that. Okay, so let's pull it in first, we need to require it through Composer and then publish the configuration file.

Installing and Configuring Scout0:36

Okay, so let's pull it in first, we need to require it through Composer and then publish the configuration file. Run that and I'll come back, copy the publish command, and now you'll see we have a new config/scout.php file. Let's have a look. Alright, so here's our project, and sure enough, we have a config/scout.php file. All right, so there's a lot to take a look at here. But to start, the two things I want you to be aware

All right, so there's a lot to take a look at here. But to start, the two things I want you to be aware of are the SCOUT_DRIVER environment variable, as well as SCOUT_QUEUE. So yeah, like I said, Scout is driver based. You gotta pick which service you want to use and here are the supported options, or you can even build your own if you want, but of course in our case, we care about Typesense. So that's the one I want. So here's what I'll do.

but of course in our case, we care about type sense. So that's the one I want. So here's what I'll do. I'm gonna copy this environment variable, switch over to my .env file, and I'm gonna be explicit that we are using type sense here. Okay, so now if I switch back, if I scroll down, we can specify whether or not we want to use a queue when we are syncing these operations and we're performing, um, um, adding a record and then having that sync with the type sense index.

operations and we're performing, um, um, adding a record and then having that sync with the typesense index or doing a bulk import. So just now maybe in production, you might wanna turn that on for local development, declare it and just set it to false as a reminder that for production, maybe I should set that to true. Alright, so this is looking good. So now think about it. We have installed Laravel Scout, we have configured it. Let's go ahead and whip up some dummy data so

Creating Course Dummy Data2:01

We have installed Laravel Scout, we have configured it. Let's go ahead and whip up some dummy data so that we can perform a query. So from the terminal, let's do this, let's create the concept of a Course. So I'm gonna make a model called Course and I'm gonna have it generate all of the companion files. Uh, really too many. We're not gonna use some of these requests, but yeah, we at least get the Eloquent model.

of these requests, but yeah, we at least get the Eloquent model. We get a factory, we get a migration, and we get a CDR if we need it. Alright, so let's start within our migration, create courses table. And like I said, very, very simple. We'll say a Course consists of a name, a Course consists of a description. And then also I wanna, I want something to be faceted.

of a description. And then also I wanna, I want something to be faceted. So maybe let's say a Course has a Category now, yeah, in real life Category would probably be its own table, right? You'd have a categories table and then a foreign key that points to the related, uh, Category. But I dunno, let's just keep it simple. We're gonna have a simple string field here.

But I dunno, let's just keep it simple. We're gonna have a simple string field here. And then finally, why don't we say a Course belongs to a User? So I could say a foreign ID for a User and yeah, that's good enough for me. So now let's go ahead and run our migration. php artisan migrate. There we go. Looking good. Okay, so now we need some dummy data, right? So what I can do is very quickly go into our CourseFactory.

Okay, so now we need some dummy data, right? So what I can do is very quickly go into our CourseFactory and yeah, very quickly, let's see if AI can do this for us. Yeah, let's see what it gave us. So name, let's make this a sentence. description is a sentence, there is no duration or price. Um, let's do user. So the courses user_id will be a UserFactory. And then finally a category. Let's just choose a random, uh, element.

And then finally a category. Let's just choose a random, uh, element. Yeah, something like this. A random element. And we, we will use programming courses like frameworks, tooling, uh, languages and techniques. So it'll pick one of those, um, categories. And that looks good to me. So now let's generate maybe 500 records in the database. That way I can boot up php artisan tinker and we can say app\Models, of course,

That way I can boot up php artisan tinker and we can say app/Models, of course, factory(500). Uh, great, all right. And now we have 500 records that we can play around with and notice that each of them is assigned its own, uh, unique category, which is great. Okay, so now as you can imagine, I want to import these into TypeSense. So here's how we do that.

Defining Typesense Schema4:40

to import these into typeSense. So here's how we do that. Let's return to config/scout.php because as you'll see, this is where we declare our schema, just like you learned at the beginning of this course. So I'm gonna scroll down and you'll see some um, uh, search engine specific configuration, like if you're using Algolia, um, or this option. But in our case, we're using typeSense. And notice this looks very familiar, right?

But in our case, we're using typeSense. And notice this looks very familiar, right? It's the same thing. Declare your API key, declare your nodes. We did all of this, right? But now if I scroll down, we have our model settings. And notice this is where we declare the schema for each of our Eloquent models, which is really cool. And they even give us something to get going. So let's uncomment this.

And they even give us something to get going. So let's uncommon to this. And when I usually do is, well first I reformat it, uh, but then I simply swap it out with my model. That way I have, I have somewhere to get started or I have a shortcut to get started. Alright? So for a course, the collection schema and I can declare all of our fields. Again, this is exactly what we were doing at the beginning of the course.

Again, this is exactly what we were doing at the beginning of the course. So if we were to do this, let's imagine what we want to sync up. Well, we wanna give it an ID and notice your ID must always be a string. So if you manually are specifying your searchable fields, which we will do later, uh, you wanna make sure you cast your primary key to a string. That's important. Alright?

you wanna make sure you cast your primaryKey to a string. That's important. Alright? Next, a Course has a name, which is a string. A Course has a description, which is a string, it has a timestamp, uh, again, for timestamps, stick with int64. And then finally we're gonna sync up, uh, the userID and the, uh, category. So I'll do userID here, but you could also, if you want, uh, if you wanted to facet.

So I'll do userId here, but you could also, if you want, uh, if you wanted to facet by usernames or something like that, then of course, keep in mind that your type and schema does not have to perfectly line up or sync up with your database structure, right? If you wanna dynamically calculate something and send that up to your type sense collection, you can totally do that, okay? So it's not a one-to-one link. All right?

you can totally do that, okay? So it's not a one-to-one link. All right? So user_id with that in mind is going to be, uh, N32 is fine. And then finally I'm gonna do the category itself. category is a string. And remember, it makes sense that we facet by category, right? Show me all courses that are in the frameworks category. So let's be explicit that we want to, um,

Making Model Searchable7:04

Show me all courses that are in the frameworks category. So let's be explicit that we want to, um, facet, okay? So this is a key thing to remember. For any Eloquent model that you want to be indexed or converted into a type sense collection, you have to declare a schema within your config/scout file. Okay? So now we're about ready. But one more thing, let's go into our Course model and I'm going to use searchable.

But one more thing, let's go into our Course model and I'm going to use searchable. So this is a specific trait that Laravel is going to use that allows you to of course make any, um, record or any collection of records searchable. And by searchable that just means synced up with, uh, typesense. Okay? Very cool. All right. And then finally, I'm gonna declare this method to searchableArray.

And then finally, I'm gonna declare this method to searchableArray. Think of this as our way of converting the Eloquent model into the necessary, uh, schema or the fields, uh, for our type sense collection. So again, let's see if AI can help us. Um, id not quite ai. Remember we want this to be a string. So I will cast it to a string. We have the name, we have the description, we have created_at, let's also say the user_id will be, um,

We have the name, we have the description, we have created_at, let's also say the user_id will be, um, and I'm just going to for now hard code the user_id. Let's clean that up. And then what else did we have? The category. So the category again is just that hard-coded string. Okay? So yeah, this is the way, this is our way of converting the Course Eloquent model into the necessary document that will be synchronized with TypeSense. We're all set to go. Hope I didn't make a mistake.

Importing and Testing Search8:41

document that will be synchronized with typesense. We're all set to go. Hope I didn't make a mistake. Let's give it a shot. Now, if I run php artisan, because we installed scout, you'll see that we have a handful of new artisan commands. But really scout:flush and scout:import are the main ones that you should memorize. scout:import of course, will receive an Eloquent model. It'll fetch all of the records and literally import them into your typesense.

It'll fetch all of the records and literally import them into your type sense collection scout flesh. Of course, we'll clear it out and you would reference this if, for example, you need to update your type sense schema. If you add some new records, if you change things, flush it out and reimport all of the records from scratch. Okay? So in our case, we wanna say php artisan scout:import.

Okay? So in our case, we wanna say php artisan scout:import. And I'm gonna give it our Eloquent model App\Models, of course. All right, we cross our fingers and of course it fails immediately. Let's have a look together. Alright, field created at must be, ah, yes, of course. I'm very sorry about this field created at must be an int64. But right now, uh,

I'm very sorry about this field created at must be an N 64. But right now, uh, I believe we gave it like a Carbon instance. So this is actually a, a good thing to run into together, right down here, whenever you are including a timestamp with your, um, type sense collection or document, make sure that you call timestamp on it. timestamp, okay? So now let's cross our fingers and I think it should work this time and it does.

So now let's cross our fingers and I think it should work this time and it does. So sure enough, we imported 500 records into type syns. It's working. Okay, so now let's wrap up this video by performing our first search. And then in the next video I'll show you how, uh, how all of this works, how to add records, remove records, uh, update records, all of that stuff. So let's go into our routes file and yeah, check this out course.

So let's go into our routes file and yeah, check this out course. And I'm gonna say search and let's just search for fubar and give me the results. It's as simple as that. And remember, you have access to this search methods specifically because we imported the Searchable trait, okay? So, and actually let's put this on its own line. All right? So let's run this in the browser and see what we get. So if I load the search endpoint, we get nothing probably.

So let's run this in the browser and see what we get. So if I load the search endpoint, we get nothing probably because yeah, we forgot to return it. We return the data that you wanna see in the browser. Alright? So in this case, we get nothing at all. So what does this mean? Well, it means there were no matches and because there's no matches, well we get an empty collection effectively. Alright, so let's do this instead. Let's open up table plus.

well we get an empty collection effectively. Alright, so let's do this instead. Let's open up TablePlus. All right, let's open up the courses table and I will grab some word that I do not know the name of because I'm dumb. Okay, so let's go back to PHPStorm. We will now search for that. And this time if I give it a refresh, we do have results. So sure enough, we can see every single record contains, uh, that word as you see here.

So sure enough, we can see every single record contains, uh, that word as you see here. Now you might be wondering, well, how did it know to search through the name? Well take a look at this. If I go back into config/scouts, you'll see that for our Course model settings right down here, the default query by is set to name. So in your case, if you wanted it to be description instead you could update this.

So in your case, if you wanted it to be description instead you could update this. And something to be aware of is this is the default. And of course, if you need to, you can override it. But in many situations, yeah, you will always have a default query buy. Here's the things I'm actually interested in searching. Uh, if you search for a course name, maybe you don't need to include the timestamp with that. Okay? So back to the browser.

to include the timestamp with that. Okay? So back to the browser. And now if I give it a refresh, we will get different results this time results where the description, uh, contains that word. Okay? So I think we're making pretty good progress here. There's a lot to talk about still. So I will see you in the next episode.

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