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

Creating Records via Eloquent0:00

All right, so check this out. This is pretty cool here. I have our courses table pulled up and sure enough, we have 501, uh, dummy records. Watch this. I'm gonna run php artisan tinker, and we'll say App\Models\Course::factory()->create(), and let's create one where the name is some course. Okay? So now if I come back to TablePlus and I give this a refresh, and yet we see our new record and we'd expect as much, right?

and I give this a refresh, and yet we see our new record and we'd expect as much, right? But now here's the cool part. If we come back to PHPStorm, and once again, let's say course, let's search for the word course and get the results, and I will return that as json. Now watch we get our results, and sure enough, I see some course. All right? So that's really cool, right?

Automatic Typesense Sync0:44

results, and sure enough, I see some course. All right? So that's really cool, right? Think about what's happening there. We ran an Eloquent query to insert a record into our database, but behind the scenes it just automatically figured out that, okay, you're inserting a record. You're saving a record. Let's make sure that we also synchronize it with, um, a corresponding document within your courses

Let's make sure that we also synchronize it with, um, a corresponding document within your courses type sense collection. Say that three times fast. It's really cool. It just happens for you for free. And again, it's happening because within our Course model, we used the searchable trait and yeah, it's basically going to register an observer. Let's see if we can find it real quick together.

and yeah, it's basically going to register an observer. Let's see if we can find it real quick together. Yeah, something like this. Uh, it's gonna listen for when a record is saved or created or updated, and it's gonna figure out, well, is this the sort of model that should be searchable? More on that in just a minute. If it's not, then let's make it unsearchable. Otherwise we're gonna call this searchable method, which ultimately synchronizes it with typesense.

Handling Manual DB Changes1:41

Otherwise we're gonna call this searchable method, which ultimately synchronizes it with typesense. Okay? So though, what if we don't handle this through Eloquent? Because if we don't do it through Eloquent, then we don't get an eloquent event. And if we don't have an eloquent event, then none of this logic is going to fire, right? So for example, imagine that we just duplicate this. Um, how do I do it? Copy paste. There we go.

So for example, imagine that we just duplicate this. Um, how do I do it? Copy paste. There we go. Uh, another SumCourse. Oh, what did I do wrong? Unique. Oh yeah, let's give it a new primary key. Okay, so now if we scroll back up, we have two Courses that include the keyword course, but of course now I created the record manually, right? So that means no event was dispatch, which means if I give this a refresh type sense, doesn't know anything about this.

which means if I give this a refresh type sense, doesn't know anything about this. So these are the sorts of things that you need to keep in mind, right? If you have some kind of system where you are manually inserting records, or they're getting imported from a SQL file or something like that, uh, you need to have logic that will manually, uh, import these records. So you do have some options here.

manually, uh, import these records. So you do have some options here. Of course, you can write your own script, um, you can run scout:import, but also here's something you could do if I run php artisan tinker. Yeah, if you have one off cases like this, here's something you could do. This course has an ID of 501. So let's say App\Models\Course::find(1)

This course has an ID of 501. So let's say app\Models\Course finds the one with an id of 501. Yep. And yeah, if we wanted to, we could just manually call that searchable method, and that's it. So that synchronizes it. So now if I give it a refresh, you will see that, oh, I'm, I'm sorry, that's not right. We want the one with an id of 502. You saw that and you're thinking, Jeff,

We want the one with an Idea of 5 0 2. You saw that and you're thinking, Jeff, this is not gonna work the way you think. Okay? Now, if we synchronize number 5 0 2, you'll see, okay? Now type sins is aware, uh, of that record, and um, that's what you want, that that's something you want to think about, okay? It's an easy trap to fall into. And yeah, the same thing's going to be true. Like sometimes, you know, if you're a solopreneur, if

And yeah, the same thing's going to be true. Like sometimes, you know, if you're a solopreneur, if that's a word, uh, sometimes TablesPlus is your, uh, your CMS, right? So maybe you update it here, some great amazing course. You just update it directly there. But then when a User searches, um, your website, they're gonna see the old version, right? So they're gonna see, um, oh, well, okay, I need to clarify something.

So they're gonna see, um, oh, well, okay, I need to clarify something. So yes, in this case it's going to work because once we found a matching result for course, then Scout is going to fetch the corresponding, uh, records from your actual database and display the results. So that is fair. However, if we look for, great, here's my point. Uh, let's go into peach storm back to our routes file, and if we instead search for, great,

Uh, let's go into routes file, and if we instead search for, great, now you're gonna see we don't get anything. So that's, that's what I was trying to demonstrate to you. We manually updated this record, and this just happens to be the only record that has the word great in it, but because we did it manually, it didn't get synchronized with TypeSense. So at no point did we update that document,

it didn't get synchronized with type sense. So at no point did we update that document, which means now if the user were to search for great, uh, as we're doing here, they're not gonna get any results, even though they should. That's my point, okay? So once again, you could track down the corresponding, uh, record. So in this case, find 501 and if we call searchable, um,

Sync on Delete/Update5:12

So in this case, find fiveOhOne and if we call searchable, um, that will do effectively the same thing as you can see there. Okay, good to know. Okay, next. So let's, let's imagine, well, this course did not pan out and we're just gonna delete it from our database entirely. So notice if I were to track down that record and I call delete once again, uh, through model events, um, scout's gonna pick up on that.

and I call delete once again, uh, through model events, um, Scout's gonna pick up on that. So now if I come back to TablePlus that record is gone, no 501, and also it's smart enough to know, okay, we need to remove this record from TypeSense. So if we search for great, once again, we're not gonna get any results, which is cool. And yeah, once again, I think you get the basic idea. Let's look for the record with a, with an Idea of 502 and we're gonna update it.

Let's look for the record with a, with an Idea of 5 0 2 and we're gonna update it. So we'll say, uh, let's clean this up, let's update the name to be blah, blah, blah. Alright, so we give this a run and Eloquent is gonna try to fight me, okay? Uh, what's happening here is it's protecting me against mass assignments, um, vulnerabilities, even though I don't need it. That's okay, we'll just do it manually, of course.

even though I don't need it. That's okay, we'll just do it manually, of course. Name equals blah, blah, blah, as my daughter says to me. Alright, so if I save it, that will of course update the record on our database in, but once again, through that model event, it will synchronize it. Uh, you already guessed this was gonna happen, so let's look for blah. Actually, this might pick up more than one thing it does.

Excluding Archived Records6:41

for blah. Actually, this might pick up more than one thing it does. Uh, but sure enough, among those, uh, search results is the, uh, the updated course, which is really cool. Alright, so now let's wrap up by discussing how we can effectively opt out of certain records being imported into type sense. So here's what we'll do. Uh, let's go into our database folder into migrations, into the migration for a courses table, and let's add a new one.

our database folder into migrations, into the migration for a courses table, and let's add a new one. Now, let's say table boolean, and this will determine whether or not the course has been archived and by default it has not been archived. Okay? So let's repopulate everything and then, uh, update our schema back to the terminal. I'm gonna run php artisan migrate:fresh. And then once again, if we open up php artisan tinker,

I'm gonna run a php artisan migrate:fresh. And then once again, if we open up php artisan tinker, I will say very quickly, give me, uh, 500 Course entries. Alright, that's done. So now let's go back into our schema. So config/scout, we have changed the schema for a Course. So this is a good review of how you would go about updating things and yeah, if I scroll down to type sends, here we go. We're gonna add a new field right down here.

and yeah, if I scroll down to type sends, here we go. We're gonna add a new field right down here. This one is going to be called archived, and it is of type Boolean. All right? And then finally, if I return to our Course model, let's just declare that we are now tracking the archived status, at least right now. So I can say $this->archived. Alright, that's done. So now let's run scout:flush.

So I can say this archived. Alright, that's done. So now let's run scout:flush. So I'm gonna clear out all of the records. Uh, so app/Models/Course, all right, and then I will import them. Okay, so now, yeah, if we once again open up our database, uh, sqlite file and I go into courses, let's say for this most recently created course here I'm gonna set it to archived. So yeah, if we do that, yeah, ideally when the User searches

recently created course here I'm gonna set it to archived. So yeah, if we do that, yeah, ideally when the User searches for any portion of this, it should not be included in the results set. It's effectively not searchable at that point. So once again, if you want, you could, you could have scheduled jobs or something like that where you say, uh, run a query, find all records where archived is set to true. And for each of those, uh, call, call unsearchable.

find all records where archived is set to true. And for each of those, uh, call, call unsearchable. So you do something like this, you'd say app\Models\Course where archived is true and you could say unsearchable. So yeah, if you wanted to set that up as a, uh, a console command or a scheduled job, you could do that. But another way is just say, look, if it's archived, it should never be imported in the first place. So here's what you can do back to php storm. Let's go into our Course model

Using shouldBeSearchable9:34

So here's what you can do back to php Storm. Let's go into our Course model and we're gonna add this method. Uh, let's do it right up here. Should be searchable. So yeah, if we just did something like this where we return false, what do you think is gonna happen? Well, let's give it a shot. In fact, let's say php artisan scout:flush. So we're gonna clear everything out at models/course.

In fact, let's say php artisan scout:flush. So we're gonna clear everything out at models course. Alright? Now, if I run import, let's see how many records get imported. The answer is zero. And that's specifically because, well for every single record it's calling this method. Is this something that we should, uh, make searchable? And remember whenever you see

Is this something that we should, uh, make searchable? And remember whenever you see that word searchable in the context of Scout, that means is it something that should be searchable with Typesense, right? And in this case, for every single record we returned, uh, no. So if I were to go to the routes file and say, just for a visual for you, let's look for everything.

and say, just for a visual for you, let's look for everything. Well, if we live this in the browser, we're gonna get nothing because there are no records, uh, to return. So that's something to be aware of. Alright? So you, in this case, here's what we could say. Well look, if this record is, uh, if this course is archived, or rather if it is not archived,

if this course is archived, or rather if it is not archived, then yes, it should be searchable. If it is archived on the other hand, then it should not be searchable. Okay? So once again, let's do this. Let's flush everything reimport from scratch and yeah, here's what we're gonna see. Let's come back to, um, arc and we're gonna get all

Let's come back to, um, arc and we're gonna get all of the records except the one that was archived. So if we were to search for archived equals 1, no, we're not gonna see anything at all, uh, because it wasn't included there. Alright? So very good work. Think about it. Now you've learned that when you use Eloquent to create or update or delete a record, well of course Eloquent model events will be dispatched.

or update or delete a record, well of course Eloquent model events will be dispatched and Scout hooks into those and that's how it's able to synchronize those changes with Typesense. And it happens automatically. You don't even have to think about it, which is really cool. However, you can also manually make records searchable. If you track down a model, you can call searchable or unsearchable

If you track down a model, you can call searchable or unsearchable or you could do it directly off of a collection, which is really cool as well. Um, scout uses these macros to hook into existing collections to basically, um, extend the API, which is kind of fun. And then finally, you learn that if you want to exclude certain, uh, records from being searchable, then you can override the shouldBeSearchable method on

to exclude certain, uh, records from being searchable, then you can override the shouldBeSearchable method on your Eloquent model. Okay, so in the next episode, let's just take a few minutes to talk about, uh, advanced customization and how you might go about doing that.

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