Finding Composer Packages0:00
Alright, so now that we have Composer on our machine and ready to go, of course, the next step is to then install a package, and I will pull in two. Alright, so we can research which package we need in a couple of ways. First step, you can visit Packagist.org and search for what you want. So I'd like to talk to you about collections, and here's what pops up, and notice that they are ordered according to downloads. So yeah, generally the top five or six, often the top one or two will be the one that you most care about, or at least they are most reliable because they have been downloaded the most number of times. So yeah, I'm a big fan of Laravel, so I'd like to pull in this package right here, Illuminate
the most number of times. So yeah, I'm a big fan of Laravel, so I'd like to pull in this package right here, Illuminate Collections. And yeah, if you're not familiar with a collection, think of it almost like an array, but on steroids. It gives us a way to wrap an array and then call any number of methods to filter that array or customize it or iterate over it and everything in between. Okay, so yeah, this is the package that I want, but I also want to show you a different way that you can research. Instead, you can do it from the command line. I can say composer search, and then provide your keyword here, in this case, collections,
Requiring a Package1:13
Instead, you can do it from the command line. I can say composer search, and then provide your keyword here, in this case, collections, and here's what pops up. Notice, of course, the output is going to be very, very similar, and here's the one that I want. All right, let's pull it in. composer require, and then let's grab the name right here, the full name, and give that a go. All right, and you can see all this stuff being pulled in. All right, very cool.
All right, and you can see all this stuff being pulled in. All right, very cool. Now if I return to phpStorm and open composer.json, there we go. We have pulled in that package. All right, let's use it. And yeah, usually at this point, you will want to visit the documentation for that package. So I'll show you a little tip. If I click on here, often the name will correspond to a GitHub repository. So notice right here, the link, if we open this up in a new tab, is github.com, and then here's our full repository name.
So notice right here, the link, if we open this up in a new tab, is github.com, and then here's our full repository name. Okay, so in this particular case, because it is extracted from the Laravel framework, I don't immediately see documentation here, but I will note most of the time, the documentation for a repository will be available right on the GitHub, usually at the bottom within a README. Yeah, but in this case, it's not, and that's okay. Instead, we'll go to laravel.com, and don't worry, we're not yet learning about Laravel. But yeah, if I look for collections, we can see a quick bird's eye view of how it works. So notice I can call collect, I accept some items, and then I can work on those items.
Using Collections in PHP2:41
But yeah, if I look for collections, we can see a quick bird's eye view of how it works. So notice I can call collect, I accept some items, and then I can work on those items. I can map over them, I can filter them, I can split them into two, I can manipulate them, anything you want to do, really. All right, so let's give it a shot. Let's create a new file, and we'll call it playground.php, and yeah, this is going to be temporary. And now, as we learned in the last episode, the first thing we should do is require the autoload file. Okay, so now let's instantiate a collection, and yeah, because we pulled in this package,
autoload file. Okay, so now let's instantiate a Collection, and yeah, because we pulled in this package, we now have a new Collection class that we can work with. All right, and that gets imported at the top. So let's feed it an array of items, like one, two, three, four, or it can be anything you want. It could be numbers, it could be arrays themselves, whatever you need. So for example, if I want a collection of all numbers going up to 10, then we can do something like this. Okay, so why don't we call it numbers, and then just as a sanity check, let's die and
something like this. Okay, so why don't we call it numbers, and then just as a sanity check, let's die and var_dump the numbers, and then view this from the console, php public playground. All right, and yeah, if I scroll up, notice I don't have an array anymore. I have a Collection instance. It is a wrapper around that array that gives me all of these different methods that I can trigger. So if I want to grab the first item within the array, if I want to flip the array, if I want to, I don't know, figure out if the Collection contains a particular item, we can call this contains method.
I want to, I don't know, figure out if the Collection contains a particular item, we can call this contains method. And notice I can see we have to give it a key, and then optionally, an operator and a value. All right, so let's just try this out. Let's say if numbers contains, and how about 10, then we will die and say it contains 10. We're just playing around for a minute. And if I give that a run, it works. If it contains 100, well, in this case, we don't do anything. So we don't see any output at all.
If it contains 100, well, in this case, we don't do anything. So we don't see any output at all. But it's working. I could say, I don't know, numbers, map over them. So notice this ultimately is going to be running php's array_map function that you learned about. And if I call numbers filter, well, then that's going to be ultimately deferring to array_filter. Have a look. And I show you this just so you have a basic understanding of what's going on here.
Have a look. And I show you this just so you have a basic understanding of what's going on here. Yeah, ultimately, it defers to php's array_filter function. So yeah, if you wanted to, you could even construct your own Collection class, and that would be fine. And this is where it all comes back to, other than for learning purposes, is it a good use of your time to build up your own Collection class? Or would it instead be better to leverage something that has been literally pulled in millions of times, and has been debugged hundreds and hundreds of times, and improved hundreds and hundreds of times, and you get that all for free.
the collection or filtered out. So yeah, in this case, why don't we just say like return, is the number less than or equal to five? If it is, then it remains. If it's not, it's filtered out. So I will say, excuse me, less than or equal to five. Bit of a long variable name there, but it's fine. And then once again, let's var_dump that variable and view the output. All right, and sure enough, we have a new collection of only the numbers that are five or less.
Installing Pest Testing6:41
All right, and sure enough, we have a new collection of only the numbers that are five or less. All right, you get the basic idea. Let's pull in another package. And this time, I'm going to use Composer search. So I want something to help us out when it comes to testing. Up until this point, we are manually testing every piece of the puzzle, so to speak. But as you can imagine, in real life, when you're building larger projects, you need some level of assurance that the changes you just made didn't break the application. And this is where automated testing comes into play.
some level of assurance that the changes you just made didn't break the application. And this is where automated testing comes into play. Now, the tool that I really like is either PHPUnit or PestPHP. And as it turns out, PestPHP is actually itself a wrapper around PHPUnit. Okay, so let's pull in Pest in the same way. composer require PestPHP. All right, so now we can see a little help from Composer. It's saying, hey, a package like this probably belongs in your require-dev section. So now we can distinguish between packages that we will use in production and then packages that are only useful during the local or development phase, such as automated testing.
So now we can distinguish between packages that we will use in production and then packages that are only useful during the local or development phase, such as automated testing. So do we want to do that? Yes. All right. So now if I switch back and return to composer.json, give it a reload, yeah, now you can see we have two blocks. We have an object for require and then another one for require-dev. And yeah, again, require-dev is for local or development only. It will not be included as part of your production vendor assets or repositories.
And yeah, again, require-dev is for local or development only. It will not be included as part of your production vendor assets or repositories. Okay, cool. All right, so let's have a look. We will go to get started, installation, and yeah, we've already done the first step. The next step is to run composer require-dev then vendor/bin/pest init. All right, and we can see what this does. It'll create a configuration file named pest at the root level of your test suite. All right, let's paste this in. Oh, and I'm sorry, we have one quick issue.
All right, let's paste this in. Oh, and I'm sorry, we have one quick issue. Do you trust pest plugin to execute code? Yes, I do. Sorry about that. And now we're ready to get started. So I will paste that in. All right, and yeah, here are all of the files that were created. All right, let's have a look in the editor. All right, and sure enough, I do see a test directory, and it looks like we have folders.
Running and Failing Tests9:05
All right, let's have a look in the editor. All right, and sure enough, I do see a test directory, and it looks like we have folders for feature and unit tests. All right, so we're going to dedicate maybe one or two episodes to testing. Of course, at Laracasts, we cover it in significant detail, but yeah, I just want to stay on task. We don't want to get too far from the original goal of a php for beginners series, but it is important that you understand the basics of testing. All right, so why don't we open unit, and we have an example test here. And yeah, this is the syntax. We call test, we give it a name, and then we have a callback here or a closure where
And yeah, this is the syntax. We call test, we give it a name, and then we have a callback here or a closure where we can perform our expectation. And yeah, an expectation is exactly what you think. It is an assertion that I expect this to be that, to equal that, to be more than that, to have this, to contain, to be an array with this number of items. Whatever it is you need to test, you can do or perform as an expectation. Okay, so how do I run this little example test? Well, I can do vendor, then test. All right, and sure enough, our feature test and our unit test passes.
Well, I can do vendor, then test. All right, and sure enough, our feature test and our unit test passes. Why don't we get the test to fail? I'm going to change this to false. Expect false to be true. Well, that's instantly not right, and it should tell us when I run our test suite, and it does. Failed asserting that false is true, right here, and then I can fix the problem. All right, so again, in the next episode, we will talk quite a bit about testing. But for now, why don't we wrap up by giving you just some kind of real-world example of a test? How about let's go into container, and yeah, maybe we can test binding something into the container,
Writing a Container Test10:42
But for now, why don't we wrap up by giving you just some kind of real-world example of a test? How about let's go into container, and yeah, maybe we can test binding something into the container, and then resolving it out. All right, so let's go into tests, unit, and I will update this, and we will call it ContainerTest. And by the way, notice the convention of ending a test file with the suffix test. So why don't we test it can resolve something out of the container. All right, so typically, when you're writing a test, there will be a series of steps. You will need to arrange the world, and often that's instantiating a class, building up a dependency, whatever you need to do. We'll call it arrange.
building up a dependency, whatever you need to do. We'll call it arrange. The next step is act. So perform your action. Do whatever it is that you're trying to test. And then at the very end, assert or expect. And this is where you confirm whether or not it actually worked. And that's where we would write our expectation. All right, so arrange the world. Well, this would be working with the container.
All right, so arrange the world. Well, this would be working with the container. So maybe I can instantiate this Container class. All right, let's do that now. New Container. And then I should also bind something into the container. So why don't we just call bind, and then I will pass a closure that returns foo. Or don't forget, there is a shorthand, a single line arrow function that I will often reach for. Okay, so now I'm ready to act. Well, let's say container resolve foo, and this will give me the result.
Okay, so now I'm ready to act. Well, let's say container resolve foo, and this will give me the result. The final step is to perform our expectation. What do I expect result to be? Well, I expect result to be, and you know what, why don't we call it bar instead? I expect it to be bar. So expect result to be, or equal is fine in this case, bar. All right, let's give it a run. And there we go. It does work.
And you're right. But because I have written it down here and I've automated it, that means I can run this test hundreds and hundreds and hundreds of times for free, and I never have to manually confirm that this piece of functionality works. And trust me, as you maintain a project over a span of potentially years, these things will build up and continuously prove their usefulness. And then further, it helps us with confidence. And here's what I mean by that. If six months from now, I'd like to refactor the Container class, I can do so with confidence, because I immediately know if I make a mistake, the test will instantly inform me.
If six months from now, I'd like to refactor the Container class, I can do so with confidence, because I immediately know if I make a mistake, the test will instantly inform me. Whereas if I didn't have those automated tests, yeah, I could perform these refactors. But trust me, it can get tricky. And I'd have to do a lot of manual testing to see, well, did this work exactly the way it did before? Or have I changed it? And did I break code that was using this Container class over here? It gets very, very risky, very, very fast. So what ends up happening is that for the projects that don't have these automated tests
It gets very, very risky, very, very fast. So what ends up happening is that for the projects that don't have these automated tests backing them up, people just don't refactor in so many cases. They'll have a confusing piece of code that nobody touches because it's simply too risky to play with. But yeah, tests absolutely fix that, which allows us to write cleaner and better code. All right. So yeah, let's say maybe when we resolve, and maybe right here, we don't call the function, we just return the resolver. And we think that works.
we just return the resolver. And we think that works. But if I run the test, it fails. So again, we're working with the container class, we made a change, we thought that change would be fine. But our test instantly reveals, no, something you did just broke this code. So maybe you should revert and then try again. And now it works. All right. So why don't we take one more lesson?
