تماشای این درس نیاز به اشتراک حرفه‌ای دارد.

Sorting Achievements by Level0:00

Take a look, I'm going to boot up php artisan tinker, and we're going to fetch all of our achievements. And you know what, why don't we save that as a quick variable here. Okay, so here's all of the achievements in the system. But now imagine that we want to sort them according to the associated skill level. Like maybe in the forum, next to each User's name, we want to show their best achievements that they have acquired. So usually those will be their advanced level achievements. Well, how exactly do we do that? There's no default way for a collection to know the distinction between beginner, intermediate,

Well, how exactly do we do that? There's no default way for a Collection to know the distinction between beginner, intermediate, and advanced. So we have to write custom logic for that. Let me give you some ideas here. So we have, once again, we have that. And we could say sortBy. So I could say sortBy level. Now the sortBy method, of course, is available on the Illuminate\Support\Collection instance. Now, when you give it a string, well, it's just going to try to alphabetize that as best

Now the sortBy method, of course, is available on the Illuminate\Support\Collection instance. Now, when you give it a string, well, it's just going to try to alphabetize that as best as it can. So if we think advanced, beginner, intermediate, the letter I comes after A and B. A for advanced, B for beginner. So that comes at the end. And of course, at the top, A comes first. So by collection logic, those would show before all of the others. Now in addition to that, we could also say sortByDescending. That's just going to do the exact opposite.

Now in addition to that, we could also say sort by descending. That's just going to do the exact opposite. So now A will be at the end and I will be at the top. But still, not really useful to us at all. We're not alphabetizing it. We almost want to assign a value, a number value, to each skill level. And by the way, this is a good argument for why within our database table, rather than beginner, intermediate, and advanced, you might instead opt for a number-based skill. So you could have 1, 2, and 3. And then you could have within your php code a translation layer that translates 1 to beginner,

So you could have 1, 2, and 3. And then you could have within your php code a translation layer that translates 1 to beginner, 2 to intermediate, 3 to advanced. Pros and cons to both sides. In our case though, let's imagine you're not changing the database, you're stuck with this, and you need to figure out, well, how can we sort our achievements so that the beginner level ones come first, followed by the intermediate ones, followed by the advanced level achievements? And we do that by passing a function. You may not know that you can do this. So we're just going to write some custom logic here.

Using a Lookup Table2:22

You may not know that you can do this. So we're just going to write some custom logic here. Let's do it inline. Now to begin, we need a, we call this a lookup table. So we could say, well, beginner corresponds to level 1, intermediate corresponds to level 2, and advanced corresponds to level 3. Again, things like this we often refer to as a lookup table. So let's just give it the achievements level that we have stored within the database. Okay, so think about what's going to happen. Let's say for this record, the achievement level is beginner.

Okay, so think about what's going to happen. Let's say for this record, the achievementLevel is beginner. All right, well, we have our array here, and then we're just going to grab the value associated with beginner, which is 1. All right, so for that iteration, we return 1. For another one, it is advanced. So we have our lookupTable, we ask for the key, or I'm sorry, we ask for the value associated with advanced, and we get 3. And then the collection is just going to sort those, either in ascending order or descending order.

Writing a Sorting Test3:42

And then the advanced ones should be at the top. Great. So now where should something like this live? Well, seems to reason it should be on that customAchievements collection that we had before. So something like sortByLevel. Okay, great. Let's write a test for that. So AchievementsTest. We already have some to ensure that we do get a custom collection, and that we can filter.

So achievements test. We already have some to ensure that we do get a custom collection, and that we can filter it to a given User. Let's do another one, though. It can sort the achievements according to a skill level. Okay, so let's set up the world. Let's say we have one achievement here where the level is beginner. And yeah, let's do this. Let's do it one at a time. So one, another will be intermediate, and then finally a third one is advanced.

Let's do it one at a time. So one, another will be intermediate, and then finally a third one is advanced. Okay, so those now exist within the database. So if we now fetch all of the achievements, and then say sort by the skill level, then well, if we're doing ascending by default, why don't we switch these up just to make sure we don't look out into the proper order. Let's do that. Okay. Anyways, if we do that, well, let's just make sure they line up. Okay, so what we want is beginner, intermediate, advanced.

Anyways, if we do that, well, let's just make sure they line up. Okay, so what we want is beginner, intermediate, advanced. So I'm going to do this, this assertEquals that, and then we're going to compare it against this query, and then let's just pluck the level out of there. Or we could check the IDs, anything we want. Anyways, let's give that a run, and of course it's going to fail. We're calling a method that isn't available to us, or at least we've created it, but it's not returning anything. So let's get a true initial run there. All right, sortByLevel method does not exist.

Implementing sortByLevel5:28

So let's get a true initial run there. All right, method sortByLevel does not exist. So now we're just going to say this sortBy, and then provide our custom handler here. And this is exactly what we had earlier in the code. So let's have our lookup, beginner is 1, intermediate is 2, advanced is 3, and let's compare that against the achievements.level. And finally, of course, let's return that. All right, so if we give that a run, collection object does not match the expected type of array. Ah, yeah, of course.

array. Ah, yeah, of course. So in this case, when we call pluck, it's still going to return to us a Collection. In fact, let me show you this. So I'm used to that being an array, but if we give it a run, you're going to get a Collection there. So we could either wrap this up, I'm sorry, we could either wrap our array here up, or you can also call this all method on any Collection, and that will give you the underlying array. So that should now pass, and it does. Now let's do this real quick.

Adding Descending Sort6:29

So that should now pass, and it does. Now let's do this real quick. Let's grab all of the achievements, like so, and then let's do one more to see if we can say sort by level in descending order. So that should be the opposite. Advanced, intermediate, beginner. Okay, so now if we give that one a run, it's failing. For things like this, the traditional advice is one assertion per test method. So if you have multiple here, you would create a new test. Again, just kind of use your judgment.

Now of course, if we give that a run, it's going to fail, because we're not accounting for the reversed order. So two options here. We could say, do we want it in ascending order? Yes. And we could say method equals, if it's ascending, sort by, otherwise sort by descending. And then we just call this as a variableName, and then pass false here. So I think that should give a screen, and it does. Another option is, well, if we go to the sortBy method on the collection, descending is available as the third argument.

Another option is, well, if we go to the sortBy method on the collection, descending is available as the third argument. So that means I could bring this back to good old sortBy, but then down here, whether we want ascending or not can be specified. So let's invert that. By default, it's not going to descend, but if we call sortBy descending, then we should. All right, so we can get rid of that, give our test a run again, and we still get green. Now either or fine, this I don't love, so I'm just going to call it as a method. So we'll bring that back, give it a run, and we still get green.

So one more time, we will fetch all of our achievements, but now I can say sort by level, and we'll get advanced at the end, those are the highest level, and beginner at the beginning. Or we can say sort by level and descending, in which case beginner will be at the end and advanced will be at the top. Okay, so everything seems to be working, and we have tests to prove that. Now is there any other way we might allow for this lookup here? Well, one thing we might do is store it on achievement. Achievement can be responsible for knowing how to translate the string beginner to a level, that's the responsibility of achievement. Now we already know on any achievement we have a level property, right, and that just

Refactoring Level Conversion9:41

level, that's the responsibility of achievement. Now we already know on any Achievement we have a level property, right, and that just corresponds to what we have in the database table. So why don't we add another method here called levelAsNumber, something like that. So if we took that approach, this could be removed or extracted to here. Then we could just do basically what we had before. Here's our lookup, we're just going to take whatever exists within the database and translate it to a number. In my mind, this is a smarter and a better location for logic like this to live. Okay, so now if we come back, let's go to our sortByLevel method, and now rather than

In my mind, this is a smarter and a better location for logic like this to live. Okay, so now if we come back, let's go to our sortByLevel method, and now rather than doing something like this, we're just going to say return achievementLevel as number. Okay, let's give it another run and we still get green. And now if you think about it, because we're just calling a method directly off of achievement, we could use a higher order collection like this. Give it another run and we still get green. Pretty cool. So that's a little bonus we get from that refactor. Anyways, that'll do it.

So that's a little bonus we get from that refactor. Anyways, that'll do it.

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