Introducing Symfony Console0:00
Let's next move on to Symfony's console component, which is really great. And in fact, if you use Laravel and you use artisan commands, and if you've ever written one on your own, what you're going to find is Laravel just provides kind of a nice layer on top of the console component. However, if you are just building a command line application or something like that, a little executable, you're not pulling in Laravel, of course, you would want to pull in Symfony\Console. So let me show you how it works.
Project Setup with Composer0:25
you would want to pull in Symfony\Component\Console. So let me show you how it works. I'm going to make a directory called console_episode and cd in there. And next, let's create our composer.json file, and then do composer require, and then you can grab it right here. Symfony\Component\Console. Okay, so now we're going to need some kind of entry point. I'm just going to call ours demo. But when I run that, that should echo out all of the various options that I have. That should spit out sort of like a table of contents for all of the commands I can run,
But when I run that, that should echo out all of the various options that I have. That should spit out sort of like a table of contents for all of the commands I can run, all of the options they accept, stuff like that. Okay, so I'm going to call it demo, but you would name this whatever you want. For example, with Laravel, they might use homestead as the name, or with valet, I think it'll just be called valet. So let's go ahead and do that. I'm going to touch a file called demo, and I'm going to leave off the extension entirely. Okay, so let's open this up.
Creating a Command Class1:18
and I'm going to leave off the extension entirely. Okay, so let's open this up. Now, if I take a look at the vendor directory, you'll see that we have Symfony console command, and then here's the parent class that we're going to extend for every single console command you create. So why don't we create one together? I'll store these within maybe a source directory, and we'll call this SpeakCommand. So all it's going to do is when you trigger it, it's going to speak some bit of text that you provided.
So all it's going to do is when you trigger it, it's going to speak some bit of text that you provided. Good little example. All right, so we call this speak command. And like I said, we're going to have it extend Symfony\Command class. So let's import that using a little macro there. And actually, so many people ask me about this. If you use Sublime and you want to do that, you want to pull in the Sublime PHP companion package, and that'll do it for you.
you want to pull in the Sublime PHP companion package, and that'll do it for you. Anyways, we're going to want two methods here. A configure method, this is where you name the command, you set a description, you set the arguments, you set the options, all of the configuration parts. Next, you'll need another method called execute. And this obviously is where you put the logic to execute the command itself. Okay, so let's get started. So what is the name of our command?
Okay, so let's get started. So what is the name of our command? Let's set the name to serve. So this means when I say demo, I'm going to call a serve command on it. Or if you want to namespace it, yeah, you can still do stuff like this. And actually, this is exactly what I do with all of the Laracasts specific commands. For example, I have one that sends me a daily report, I have one that backs up a database, I have one that clears out old records and stuff like that. They are all nested under a Laracasts namespace.
I have one that clears out old records and stuff like that. They are all nested under a layer cast namespace, which means when I run php artisan, they will all be grouped together. Anyways, in our case, it's irrelevant. So we will stick with speak. Next, let's keep it simple to start. So I will only add a description here called speak a message. What does the command do? Okay, so next, when we execute this command, let's just say exec for now. So exec, say, hello world.
Okay, so next, when we execute this command, let's just say exec for now. So exec, say, hello world. And then we will iterate on that in a few minutes. All right, so that's the basic makeup of a command. I'll show you how to add arguments and options in a minute. But still, it's not that complicated. Create a command class, extend Symfony's Command class, configure it, and execute it. Now, one note on this, though, what you're going to find is it's probably going to squawk at how we named this, but we'll get to that and we'll see it in the output.
Wiring the Entry Script3:47
it's probably going to squawk at how we named this, but we'll get to that and we'll see it in the output. All right, so at this point, we have a command class, but we haven't triggered it at all. That's what our entry point is going to be for. So this is coming from Bash, but we want to use php as the environment. Okay, so yeah, this is where we pull in our autoloader, we create our console application, we add this SpeakCommand, and then we run the application. Very simple, like this. Because we're using Composer, we want to autoload our dependencies, right?
Very simple, like this. Because we're using Composer, we want to autoload our dependencies, right? Now, if you come from Laravel, once again, this is something that just sort of happens for you behind the scenes. But otherwise, if you're gluing things together yourself, you would need to add this line. So require vendor/autoload.php, and then we can also be explicit about the directory. So the current directory, then the vendor folder, and then autoload.php. And let me set the syntax here to PHP. Okay, next, we're going to new up our console application. So new Application.
Okay, next, we're going to new up our console application. So new application. And once again, I will import that Symfony\Component\Console\Application. Next, we're going to add a command to our application. So app add new SpeakCommand. Finally, we're all set to go. So I will run the application. Now, I know this isn't going to work just yet, but let's just see what the failure is. So we're running this with php.
Fixing Autoload and Signatures5:08
Now, I know this isn't going to work just yet, but let's just see what the failure is. So we're running this with php. So I will say demo. And we get uncaught error class SpeakCommands not found. And that's because the autoloader doesn't know where to look for it. So we have it in the source directory, but we didn't tell the autoloader that, so it didn't know. We'll go to composer.json, and then specify our autoloading. Per usual, we're going to use the PSR-4 standard. And yeah, if you want to set a default namespace here, like Laracasts or something like that, you could do it.
And yeah, if you want to set a default namespace here, like Laracasts or something like that, you could do it. Otherwise, for these little console applications, I don't see a huge benefit to it. So I often leave the namespace blank. And then I just point that route to the source directory. But naturally, yeah, if you had something a bit bigger, then you would set a namespace. Okay, so composer dump-autoload to refresh those changes. And now if I try it again, php demo. Okay, we're starting to get there, but we still have an error. So yeah, this is the other thing I was talking about.
Okay, we're starting to get there, but we still have an error. So yeah, this is the other thing I was talking about. So the declaration of the execute method should be compatible with the parent class's execute method. And you'll see that that accepts the input and the output. So basically, we have to honor that contract. Okay, fair enough. So we need the input as well as the output. Now, when we write to the console, we would call a method on the output object. So again, if you come from Laravel, you know, you can just do things like this info.
Now, when we write to the console, we would call a method on the output object. So again, if you come from Laravel, you know, you can just do things like this info. But behind the scenes, it's delegating to the output interface. Okay, so let's update this and import it. And then update this one as well. And once again, import it. Great. So let's try it again. And now we're getting somewhere. We're getting somewhere.
And now we're getting somewhere. We're getting somewhere. So we have our table of contents. And we can see that we have one command there called speak. But now do you notice up here, it just says console tool. And there's not even a description as to what this is. That's because right here, when we new up the application, we didn't provide one. So check this out. I'll say foobar and then a version number. And if we run it again, yeah, there's the name of our console application.
I'll say foobar and then a version number. And if we run it again, yeah, there's the name of our console application. And there's the version number. Okay, so we're just going to call this LaracastDemo. And it's at 1.0. Great. Next, let's try to call the speak command. So php demo speak. And you can hear that through the microphone. Pretty cool, right?
Adding Arguments and Output8:21
Is it a required argument? Or is it one that can have a sensible default? You then give it a description for the documentation. And then finally, if you do want to provide a default value, you can do that. Okay, so let's do this. The argument will be the message. I am going to require it. So I will say input argument required. Now I do have to import that though. So I will grab that right here.
Not enough arguments. So if I do that again, get your ass to Mars. Hello, world. It didn't work. Obviously not because I have to update it in the execute method. Damn it. Let's do it again. So I'm going to say and then concatenate the argument that the user passed in. And we do that very simply through the input interface. So the input is to fetch incoming data like the arguments you provide or the options you pass.
And we do that very simply through the input interface. So the input is to fetch incoming data like the arguments you provide or the options you pass. And the output interface is to output information back to the console. Okay, so let's get the argument and we called it message. Okay, now it should do the trick. Get your ass to Mars. Not as good as Arnold says it, but still fine. Okay, so what if we want to use a default instead? So if we go back, you can see that optional is an option. Okay, so let's update this.
So if we go back, you can see that optional is an option. Okay, so let's update this. optional. And now I'm going to set the fourth argument to the default of hello, world. So now I can override the default message or I can fall back to something if I don't provide one. So let's run it again with no argument. Great, but I can override it as well. Now there's actually a lot to cover here. So we're not going to go into, for example, you could add an option as well. And that would be if you say php demo speak and then you pass through some extra option.
So we're not going to go into, for example, you could add an option as well. And that would be if you say php demo speak and then you pass through some extra option. Maybe the voice. I don't know if there's a way to speak with like a female voice. But yeah, maybe if you want options like that, you would use this. And once again, just refer to the parameter list and it's the exact same setup. Then down here, you would say input.getOption. Now you can also do things like format the output. You can use tabular data to display information in a nice table structure. That works really well.
You can use tabular data to display information in a nice table structure. That works really well. Maybe we'll finish up with some outputs. So we're saying a message and then I'm going to let's give you some space here. We're going to write a line that says all done. Okay, so if we run it. And then we get a message here. But if you want colored output, for example, like an information message or an error message, you could do that. So I could use, for example, info and all of these will correspond to different colors.
you could do that. So I could use, for example, info and all of these will correspond to different colors. So let's try it speak. Hello world. And now it's a different color or error should be read. Hello world. You get the idea. Now, once again, if you use Laravel and artisan, you'll have helper functions for this. So you'll have like a method called info. And really all that's doing behind the scenes is just performing this.
So you'll have like a method called info. And really all that's doing behind the scenes is just performing this. So that would, in Laravel, grab the output, write a line, and then just nest it here. Something along those lines is what I imagine is taking place. But this is fine how we have it. And I'm going to bring that back to how about just general info. Now, there's even stuff like progress indicators. And that's good if you're really doing a bunch of steps. And then you want to keep the user posted on which item they're on. So we just completed the fifth item out of 20 operations we have to do.
And then you want to keep the user posted on which item they're on. So we just completed the fifth item out of 20 operations we have to do. You can see a little progress indicator to show you how that's working. Once again, just refer to the console documentation. Very easy to set up all this stuff. But now I want to move on to one other thing. Right now, I have to run it like this. But yeah, a lot of the console applications, you don't have to precede it with php. You just move this to your bin directory. And then you can say demo speak, right?
So if we run it, we get the same thing. And now you can move this folder to somewhere in your path and just reference it like this. Pretty cool, and just not that hard. Okay, so I think we'll call it a day with that one. Once again, the rules are you create a directory, you require symphony/console, and your composer.json file autoload your source directory. Give it a namespace if you want. There, you create a command class and you extend Symfony\Component\Console\Command\Command.
Give it a namespace if you want. There, you create a command class and you extend Symfony's Command class. You configure it to provide a name, description, argument, and options. And then you execute it however you need to. Maybe you need to get contents from a file. Maybe you need to write to another file. You can put all that junk here or, of course, delegate to another class to handle the work at that point. Finally, you create your entry point where you autoload your files, you new up the application, you add your command, and you run it.
Finally, you create your entry point where you autoload your files, you new up the application, you add your command, and you run it.
