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

Adding Progress Feedback0:00

If I run php artisan track, this is what we get. And generally, that's fine because the basic idea is it would run behind the scenes automatically every five minutes. However, if we do run it manually, it might be nice to provide a little more feedback about the results. So with that in mind, let me show you how to deal with progress bars and table-based output. Let's see. Let's write out what we need to do. Start a progress bar, and then track each product while ticking the progress bar.

Let's write out what we need to do. Start a progressBar, and then track each product while ticking the progressBar. So basically, after every product is tracked, we increment the progressBar. And then finally here, finish the progressBar to 100%, and then output the results as a table. All right, let's get started. We can initialize and start a progressBar like this, a couple ways. I could say this, output, and I could call createProgressBar. And if we take a look at that real quick, it'll set up the progressBar and then return it.

And if we take a look at that real quick, it'll set up the progress bar and then return it. And then at that point, basically, we do something like this. Create a progressBar and then start it. However, alternatively, we could do this all at once by saying this, output, and progressStart. There it is. And if we take a look at that, it's not going to return anything from the method, but it still calls createProgressBar and then start. All right, next, track each project while ticking the progressBar.

still calls createProgressBar and then start. All right, next, track each project while ticking the progress bar. Let's switch this over. For each product, like this. Then, yes, we're going to track it, but then also we want to tick the progress bar. So once again, I could say this, output, and then progress advance. Now how does it know how much to advance? So should it advance by 5% or 10%? It doesn't know. However, if we go to our initializer, we can specify the max number of increments.

It doesn't know. However, if we go to our initializer, we can specify the max number of increments. So what I could do here is say progressStart, and then we'll clean this up in a bit. Let's begin by getting all of our products. And then I could say, well, the number of increments will be the total number of products we have there. So I could do count or products->count() like this. Okay, then we could swap this out. For each product, track it, and then advance the progressBar. And because we set the number of items there, it will know the correct increment there.

For each product, track it, and then advance the progress bar. And because we set the number of items there, it will know the correct increment there, the correct percentage count. Okay, next, once we get past this point, we have tracked all of our products. So we can finish the progress bar by saying this, output, progress, finish, and then finally output the results as a table. So we'll get to that in just a minute, but real quick, let's try it out. php artisan track, and there you go. Now, of course, in this case, it's kind of superfluous. We only have one item there.

Rendering Results Table2:52

Now, of course, in this case, it's kind of superfluous. We only have one item there. But if we had many products, this could be useful. Okay, let's now output the results as a table. So Laravel offers a table method, and it can be a little confusing. You want to make sure you provide the headers as well as the rows. And the rows could even be a collection of Eloquent models. Let me give you an idea. I could say first, last, those are the headers. And then for the rows, well, each row will be its own array.

I could say first, last, those are the headers. And then for the rows, well, each row will be its own array. And we'll do $myself, and then one more. Okay, so now, if I give that a run, this is what we're going to populate. But yeah, of course, we want this to reflect the product, the price, the URL, the availability, things like that. So on that note, let's chart it out. What do I want here? When I render my table, I want to show the product name. And then I want to pull in the stock associated with that product.

When I render my table, I want to show the product name. And then I want to pull in the stock associated with that product. So that'll pull in the price, maybe the URL, the availability. Yeah, that seems appropriate. So let's do this. We can either create a new query or have a look. If I do products->toArray() and give it a run, you'll see here's each one. So it has the product as well as all of the stock items eager loaded. So I could work with this. We could use some collection mapping to build up the exact data we want.

So I could work with this. We could use some collection mapping to build up the exact data we want. But I think it might be easier and maybe even quicker just to do another quick query. I'll show you what I mean. Here's our stock table. So we have one product and just one stock. Let's duplicate that. And we'll just say maybe this one is available. And it's a different SKU. All right, so let's write some SQL.

Joining Stock Data4:42

And it's a different SKU. All right, so let's write some SQL. SELECT * FROM products. Give it a run. OK, but now I want to join in the stock, right? So LEFT JOIN stock ON stock.product_id. So this is the connecting tissue that joins them together. The product_id column on the stock table needs to match the id column on the products table. So now if we run it, we get two results, and this is what we want.

This is just a simple explanation with no code.

We'll give that a run. And this is what we get. So I think we're good here. I'm going to stick with that. So I'm just going to paste this in for your review, and then we'll convert it to Eloquent. I could say product left join the stock table on the condition that the stock.product_id. Actually, let me turn on hints so you can see the parameter names. On the condition that the product_id equals the products.ID. So we're just reproducing exactly what we had here.

On the condition that the productID equals the products.id. So we're just reproducing exactly what we had here. And then let's get all of the results, but limited to, for each row, the name, the price, the url, and whether or not it's in stock. OK. So now, if I die and dump the products, let's cast that to an array. If we now run it again, there we go. OK. So now that we have our data here, let's hide the hints, and don't worry, we're going to clean this up, I can then create a table, pass that data to it, and then just specify

So now that we have our data here, let's hide the hints, and don't worry, we're going to clean this up, I can then create a table, pass that data to it, and then just specify what the column names are. But notice that I'm repeating myself. Now it's not a big deal, but we'll remove that duplication in a bit. So let's run it again. php artisan track, and I'm on a low resolution, but you get the idea. Here's all of the stock for all of the products that we're currently tracking. And we can see, as of the most recent update, neither of them are in stock. All right, great.

Refactoring Command Flow7:31

I could inline this like so. So grab all the products, and then first, I don't want to remove the chaining, but call tap so I can access that products variable, and we will initialize it. Next, I can move on, and then just call each directly on that collection. This would allow me to remove the top two lines. Maybe less readable. It's up to you. I find people have different reactions based upon how comfortable they are with collections. Anyways, if we keep going, this section right down here, what is that doing? Well, it's showing the results.

Anyways, if we keep going, this section right down here, what is that doing? Well, it's showing the results. So why don't we extract a method called showResults? All right, keep running it. Still looks good. What else? Let's just remove this to make it easier to scan for the screencast, give it a reformat. If I'm showing the results, you know what we could do is just complete the progress bar within here, but yeah, now we get this. Next, notice right here, we are duplicating the attributes.

And then here, I could delegate as well. Now if we want to fetch a new attribute and update the headers for the table, I only have to do it in one place. Again, not a big problem, but something to consider. And now notice how each header isn't capitalized. So what we could do, let's just pass this to array_map, and we're going to pass each one to ucwords. Good enough. This won't be perfect, I don't think. Let's see.

This won't be perfect, I don't think. Let's see. Name, price, URL. Yeah, not perfect. Good enough for the screencast though. Now anything else? Maybe a little thing. Sometimes you end up writing Eloquent queries like this, and it always feels kind of weird, right? It looks like that, but it's too long, so you bring this down, but then it just feels

Running Tests and Fixes10:02

Anything else here? You know what? I think it looks perfectly fine. Fine. Yeah, good to me. So that works. Let's go ahead and run phpunit, make sure we didn't break anything. Ah, we have one thing, and that's because we expected output to be all done. Yeah, we talked about this when we added this assertion here. It's fine.

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