From installation onward, modern PHP frameworks expect many interactions to take place on the command line. Laravel provides three primary tools for command-line interaction: Artisan, a suite of built-in command-line actions with the ability to add more; Tinker, a REPL or interactive shell for your application; and the installer, which we’ve already covered in Chapter 2.
If you’ve been reading through this book chapter by chapter, you’ve already learned how to use Artisan commands. They look something like this:
php artisan make:controller PostsController
If you look in the root folder of your application, you’ll see that artisan is actually just a PHP file. That’s why you’re starting your call with php artisan; you’re passing that file into PHP to be parsed. Everything after that is just passed into Artisan as arguments.
Artisan is actually a layer on top of the Symfony Console component, so if you’re familiar with writing Symfony Console commands you should feel right at home.
Since the list of Artisan commands for an application can be changed by a package or by the specific code of the application, it’s worth checking every new application you encounter to see what commands are available.
To get a list of all available Artisan commands, you can run php artisan list from the project root (although if you just run php artisan with no parameters, it will do the same thing).
There’s not enough space here to cover all of the Artisan commands, but we’ll cover many of them. Let’s get started with the basic commands:
clear-compiled removes Laravel’s compiled class file, which is like an internal Laravel cache; run this as a first resort when things are going wrong and you don’t know why.
down puts your application in “maintenance mode” in order for you to fix an error, run migrations, or whatever else; up restores an application from maintenance mode.
dump-server (5.7+) starts the dump server (“Laravel Dump Server”) to collect and output dumped variables.
env displays which environment Laravel is running at the moment; it’s the equivalent of echoing app()->environment() in-app.
help provides help for a command; e.g., php artisan help commandName.
migrate runs all database migrations.
optimize clears and refreshes the configuration and route files.
preset changes out the frontend scaffolding for another.
serve spins up a PHP server at localhost:8000 (you can customize the host and/or port with --host and --port).
tinker brings up the Tinker REPL, which we’ll cover later in this chapter.
The list of Artisan commands, and their names, has changed in small ways over the lifetime of Laravel. I’ll try to note any time they’ve changed, but everything here is listed out for Laravel 5.7. If you’re not working in 5.7, the best way to see what’s available to you is to run php artisan from your application.
Before we cover the rest of the Artisan commands, let’s look at a few notable options you can pass any time you run an Artisan command:
-q suppresses all output.
-v, -vv, and -vvv are the three levels of output verbosity (normal, verbose, and debug).
--no-interaction does not ask any interactive questions, so it won’t interrupt automated processes running it.
--env allows you to define which environment the Artisan command should operate in (e.g., local, production, etc.).
--version shows you which version of Laravel your application is running on.
You’ve probably guessed from looking at these options that Artisan commands are intended to be used much like basic shell commands: you might run them manually, but they can also function as a part of some automated process at some point.
For example, there are many automated deploy processes that might benefit from certain Artisan commands. You might want to run php artisan config:cache every time you deploy an application. Flags like -q and --no-interaction ensure that your deploy scripts, not attended by a human being, can keep running smoothly.
The rest of the commands available out of the box are grouped by context. We won’t cover them all here, but we’ll cover each context broadly:
appThis just contains app:name, which allows you to replace every instance of the default top-level App\ namespace with a namespace of your choosing. For example: php artisan app:name MyApplication. I recommend avoiding this feature and keeping your app’s root namespace as “App”.
authAll we have here is auth:clear-resets, which flushes all of the expired password reset tokens from the database.
cachecache:clear clears the caches, cache:forget removes an individual item from the cache, and cache:table creates a database migration if you plan to use the database cache driver.
configconfig:cache caches your configuration settings for faster lookup; to clear the cache, use config:clear.
dbdb:seed seeds your database, if you have configured database seeders.
eventevent:generate builds missing event and event listener files based on the definitions in EventServiceProvider. You’ll learn more about events in Chapter 16.
keykey:generate creates a random application encryption key in your .env file.
If you run php artisan key:generate more than once on your application, every currently-logged-in user will be logged out when you run it additional times. Additionally, any data you have manually encrypted will no longer be decrypt-able. To learn more, check out this article from fellow Tightenite Jake Bathman: APP_KEY and You.
makemake:auth scaffolds out the views and corresponding routes for a landing page, a user dashboard, and login and register pages.
All the rest of the make: actions create a single item, and have parameters that vary accordingly. To learn more about any individual command’s parameters, use help to read its documentation.
For example, you could run php artisan help make:migration and learn that you can pass --create=tableNameHere to create a migration that already has the create table syntax in the file, as shown here: php artisan make:migration create_posts_table --create=posts.
migrateYou saw a migrate command earlier to run our migrations, but here we can run all the other migration-related commands. Create the migrations table (to keep track of the migrations that are executed) with migrate:install, reset your migrations and start from scratch with migrate:reset, reset your migrations and run them all again with migrate:refresh, roll back just one migration with migrate:rollback, drop all tables and re-run all the migrations with migrate:fresh, or check the status of your migrations with migrate:status.
notificationsnotifications:table generates a migration that creates the table for database notifications.
packageIn Laravel prior to 5.5 including a new Laravel-specific package in your app requires registering it manually in config/app.php. However, in 5.5 it’s possible for Laravel to “auto-discover” those packages so you don’t have to manually register them. package:discover rebuilds Laravel’s “discovered” manifest of the service providers from your external packages.
queueWe’ll cover Laravel’s queues in Chapter 16, but the basic idea is that you can push jobs up into remote queues to be executed one after another by a worker. This command group provides all the tools you need to interact with your queues, like queue:listen to start listening to a queue, queue:table to create a migration for database-backed queues, and queue:flush to flush all failed queue jobs. There are quite a few more, which you’ll learn about in Chapter 16.
routeIf you run route:list, you’ll see the definitions of every route defined in the application, including each route’s verb(s), path, name, controller/closure action, and middleware. You can cache the route definitions for faster lookups with route:cache and clear your cache with route:clear.
scheduleWe’ll cover Laravel’s cron-like scheduler in Chapter 16, but in order for it to work, you need to set the system cron to run schedule:run once a minute:
* * * * * php /home/myapp.com/artisan schedule:run >> /dev/null 2>&1
As you can see, this Artisan command is intended to be run regularly in order to power a core Laravel service.
sessionsession:table creates a migration for applications using database-backed sessions.
storagestorage:link creates a symbolic link from public/storage to storage/app/public. This is a common convention in Laravel apps, to make it easy to put user uploads (or other files that commonly end up in storage/app) somewhere where they’ll be accessible at a public URL.
vendorSome Laravel-specific packages need to “publish” some of their assets, either so that they can be served from your public directory or so that you can modify them. Either way, these packages register these “publishable assets” with Laravel, and when you run vendor:publish, it publishes them to their specified locations.
viewLaravel’s view rendering engine automatically caches your views. It usually does a good job of handling its own cache invalidation, but if you ever notice it’s gotten stuck, run view:clear to clear the cache.
Now that we’ve covered the Artisan commands that come with Laravel out of the box, let’s talk about writing your own.
First, you should know: there’s an Artisan command for that! Running php artisan make:command YourCommandName generates a new Artisan command in app/Console/Commands /{YourCommandName}.php.
The command signature for make:command has changed a few times. It was originally command:make, but for a while in 5.2 it was console:make and then make:console.
Finally, in 5.3, it was settled: all of the generators are under the make: namespace, and the command to generate new Artisan commands is now make:command.
Your first argument should be the class name of the command, and you can optionally pass a --command parameter to define what the terminal command will be (e.g., appname:action).
So, let’s do it:
php artisan make:command WelcomeNewUsers --command=email:newusers
Take a look at Example 8-1 to see what you’ll get.
<?phpnamespaceApp\Console\Commands;useIlluminate\Console\Command;classWelcomeNewUsersextendsCommand{/*** The name and signature of the console command.** @var string*/protected$signature='email:newusers';/*** The console command description.** @var string*/protected$description='Command description';/*** Create a new command instance.** @return void*/publicfunction__construct(){parent::__construct();}/*** Execute the console command.** @return mixed*/publicfunctionhandle(){//}}
As you can see, it’s very easy to define the command signature, the help text it shows in command lists, and the command’s behavior on instantiation (__construct()) and on execution (handle()).
In projects running versions of Laravel prior to 5.5, commands had to be manually bound into app\Console\Kernel.php. If your app is running an older version of Laravel, just add the fully-qualified class name for your Command to the $commands array in that file and it’ll be registered:
protected$commands=[\App\Console\Commands\WelcomeNewUsers::class,];
We haven’t covered mail or Eloquent yet (see Chapter 15 for mail and Chapter 5 for Eloquent), but the sample handle() method in Example 8-2 should read pretty clearly.
...classWelcomeNewUsersextendsCommand{publicfunctionhandle(){User::signedUpThisWeek()->each(function($user){::to($user)->send(newWelcomeEmail);});}
Now every time you run php artisan email:newusers, this command will grab every user that signed up this week and send them the welcome email.
If you would prefer injecting your mail and user dependencies instead of using facades, you can typehint them in the command constructor, and Laravel’s container will inject them for you when the command is instantiated.
Take a look at Example 8-3 to see what Example 8-2 might look like using dependency injection and extracting its behavior out to a service class.
...classWelcomeNewUsersextendsCommand{publicfunction__construct(UserMailer$userMailer){parent::__construct();$this->userMailer=$userMailer}publicfunctionhandle(){$this->userMailer->welcomeNewUsers();}
The $signature property of the new command looks like it might just contain the command name. But this property is also where you’ll define any arguments and options for the command. There’s a specific, simple syntax you can use to add arguments and options to your Artisan commands.
Before we dig into that syntax, take a look at an example for some context:
protected$signature='password:reset {userId} {--sendEmail}';
To define a required argument, surround it with braces:
password:reset {userId}
To make the argument optional, add a question mark:
password:reset {userId?}
To make it optional and provide a default, use:
password:reset {userId=1}
Options are similar to arguments, but they’re prefixed with -- and can be used with no value. To add a basic option, surround it with braces:
password:reset {userId} {--sendEmail}
If your option requires a value, add an = to its signature:
password:reset {userId} {--password=}
And if you want to pass a default value, add it after the =:
password:reset {userId} {--queue=default}
Both for arguments and for options, if you want to accept an array as input, use the * character:
password:reset {userIds*}
password:reset {--ids=*}
Using array arguments and parameters looks a bit like Example 8-4.
// Argument php artisan password:reset 1 2 3 // Option php artisan password:reset --ids=1 --ids=2 --ids=3
Since an array argument captures every parameter after its definition and adds them as array items, an array argument has to be the last argument within an Artisan command’s signature.
Remember how the built-in Artisan commands can give us more information about their parameters if we use artisan help? We can provide that same information about our custom commands. Just add a colon and the description text within the curly braces, like in Example 8-5.
protected$signature='password:reset{userId : The ID of the user}{--sendEmail : Whether to send user an email}';
Now that we’ve prompted for this input, how do we use it in our command’s handle() method? We have two sets of methods for retrieving the values of arguments and options.
$this->arguments() returns an array of all arguments (the first array item will be the command name). $this->argument() called with no parameters returns the same response; the plural method, which I prefer, is just available for better readability, and is only available after Laravel 5.3.
To get just the value of a single argument, pass the argument name as a parameter to $this->argument():
// with definition "password:reset {userId}":phpartisanpassword:reset5// $this->arguments() returns this array["command":"password:reset","userId":"5",]// $this->argument('userId') returns this string"5"
$this->options() returns an array of all options, including some that will by default be false or null. $this->option() called with no parameters returns the same response; the plural method, which I prefer, is just available for better readability, and is only available after Laravel 5.3.
To get just the value of a single option, pass the argument name as a parameter to $this->option():
// with definition "password:reset {--userId=}":phpartisanpassword:reset--userId=5// $this->options() returns this array["userId"=>"5""help"=>false"quiet"=>false"verbose"=>false"version"=>false"ansi"=>false"no-ansi"=>false"no-interaction"=>false"env"=>null]// $this->option('userId') returns this string"5"
Example 8-6 shows an Artisan command using argument() and option() in its handle() method.
publicfunctionhandle(){// All arguments, including the command name$arguments=$this->arguments();// Just the 'userId' argument$userid=$this->argument('userId');// All options, including some defaults like 'no-interaction' and 'env'$options=$this->options();// Just the 'sendEmail' option$sendEmail=$this->option('sendEmail');}
There are a few more ways to get user input from within your handle() code, and they all involve prompting the user to enter information during the execution of your command:
ask()Prompts the user to enter freeform text:
=$this->ask('What is your email address?');
secret()Prompts the user to enter freeform text, but hides the typing with asterisks:
$password=$this->secret('What is the DB password?');
confirm()Prompts the user for a yes/no answer, and returns a boolean:
if($this->confirm('Do you want to truncate the tables?')){//}
All answers except y or Y will be treated as a “no.”
anticipate()Prompts the user to enter freeform text, and provides autocomplete suggestions. Still allows the user to type whatever she wants:
$album=$this->anticipate('What is the best album ever?',["The Joshua Tree","Pet Sounds","What's Going On"]);
choice()Prompts the user to choose one of the provided options. The last parameter is the default if the user doesn’t choose:
$winner=$this->choice('Who is the best football team?',['Gators','Wolverines'],0);
Note that the final parameter, the default, should be the array key. Since we passed a nonassociative array, the key for “Gators” is 0. You could also key your array, if you’d prefer:
$winner=$this->choice('Who is the best football team?',['gators'=>'Gators','wolverines'=>'Wolverines'],'gators');
During the execution of your command, you might want to write messages to the user. The most basic way to do this is to use $this->info() to output basic green text:
$this->info('Your command has run successfully.');
You also have available the comment() (orange), question() (highlighted teal), error() (highlighted red), and line() (uncolored) methods to echo to the command line.
Please note that the exact colors may vary from machine to machine, but they try to be in line with the local machine’s standards for communicating to the end user.
The table component makes it simple to create ASCII tables full of your data. Take a look at Example 8-7.
$headers=['Name','Email'];$data=[['Dhriti','dhriti@amrit.com'],['Moses','moses@gutierez.com'],];// Or, you could get similar data from the database:$data=App\User::all(['name','email'])->toArray();$this->table($headers,$data);
Note that Example 8-7 has two sets of data: the headers, and the data itself. Both contain two “cells” per “row”; the first cell in each row is the name, and the second is the email. That way the data from the Eloquent call (which is constrained to pull only name and email) matches up with the headers.
Take a look at Example 8-8 to see what the table output looks like.
+---------+--------------------+ | Name | Email | +---------+--------------------+ | Dhriti | dhriti@amrit.com | | Moses | moses@gutierez.com | +---------+--------------------+
If you’ve ever run npm install, you’ve seen a command-line progress bar before. Let’s build one in Example 8-9.
$totalUnits=10;$this->output->progressStart($totalUnits);for($i=0;$i<$totalUnits;$i++){sleep(1);$this->output->progressAdvance();}$this->output->progressFinish();
What did we do here? First, we informed the system how many “units” we needed to work through. Maybe a unit is a user, and you have 350 users. The bar will then divide the entire width it has available on your screen by 350, and increment it by 1/350th every time you run progressAdvance(). Once you’re done, run progressFinish() so it knows it’s done displaying the progress bar.
If you’d prefer to keep your command definition process simpler, you can write commands as closures instead of classes by defining them in routes/console.php. Everything we discuss in this chapter will apply the same way, but you will just define and register the commands in a single step in that file:
// routes/console.phpArtisan::command('password:reset {userId} {--sendEmail}',function($userId,$sendEmail){$userId=$this->argument('userId');// do something...});
While Artisan commands are designed to be run from the command line, you can also call them from other code.
The easiest way is to use the Artisan facade. You can either call a command using Artisan::call() (which will return the command’s exit code), or queue a command using Artisan::queue().
Both take two parameters: first, the terminal command (password:reset); and second, an array of parameters to pass it. Take a look at Example 8-10 to see how it works with arguments and options.
Route::get('test-artisan',function(){$exitCode=Artisan::call('password:reset',['userId'=>15,'--sendEmail'=>true]);});
As you can see, arguments are passed by keying to the argument name, and options with no value can be passed true or false.
You can also call Artisan commands from other commands, using $this->call, (which is the same as Artisan::call(), or $this->callSilent, which is the same but suppresses all output). See Example 8-11 for an example.
publicfunctionhandle(){$this->callSilent('password:reset',['userId'=>15,]);}
Finally, you can inject an instance of the Illuminate\Contracts\Console\Kernel contract, and use its call() method.
Tinker is a REPL, or read–eval–print loop. If you’ve ever used IRB in Ruby, you’ll be familiar with how a REPL works.
REPLs give you a prompt, similar to the command-line prompt, that mimics a “waiting” state of your application. You type your commands into the REPL, hit Return, and then expect what you typed to be evaluated and the response printed out.
Example 8-12 provides a quick sample to give you a sense of how it works and how it might be useful. We start the REPL with php artisan tinker and are then presented with a blank prompt (>>>); every response to our commands is printed on a line prefaced with =>.
php artisan tinker
>>> $user = new App\User;
=> App\User: {}
>>> $user->email = 'matt@mattstauffer.com';
=> "matt@mattstauffer.com"
>>> $user->password = bcrypt('superSecret');
=> "$2y$10$TWPGBC7e8d1bvJ1q5kv.VDUGfYDnE9gANl4mleuB3htIY2dxcQfQ5"
>>> $user->save();
=> trueAs you can see, we created a new user, set some data, and saved it to the database. And this is real. If this were a production application, we would’ve just created a brand new user in our system.
This makes Tinker a great tool for simple database interactions, for trying out new ideas, and for running snippets of code when it’d be a pain to find a place to put them in the application source files.
Tinker is powered by Psy Shell, so check that out to see what else you can do with Tinker.
One common method of debugging the state of your data during development is to use Laravel’s dump() helper, which runs a decorated var_dump() on anything you pass to it. This is fine, but it can often run into view issues.
In projects running Laravel 5.7 and later, you can now enable the Laravel Dump Server, which catches those dump() statements and displays them in your console instead of rendering them to the page.
To run the Dump server in your local console, navigate to your project’s root directory and run php artisan dump-server.
$php artisan dump-server Laravel Var DumpServer=======================[OK]Server listening on tcp://127.0.0.1:9912 // Quit the server with CONTROL-C.
Now, try using the dump() helper function in your code somewhere. To test it out, try this code in your routes/web.php file:
Route::get('/',function(){dump('Dumped Value');return'Hello World';});
Without the dump server, you’d see both the dump and your “Hello World”. But with the dump server running, you’ll only see “Hello World” in the browser. In your console, you’ll see that the dump server caught that dump() and you can inspect it there.
GET http://myapp.test/ -------------------- ------------ --------------------------------- date Tue,18Sep201822:43:10 +0000 controller"Closure"sourceweb.php on line 20 file routes/web.php ------------ ---------------------------------"Dumped Value"
Since you know how to call Artisan commands from code, it’s easy to do that in a test and ensure that whatever behavior you expected to be performed has been performed correctly, as in Example 8-13.
In our tests, we use $this->artisan() instead of Artisan::call() because it has the same syntax but adds a few testing-related assertions.
publicfunctiontest_empty_log_command_empties_logs_table(){DB::table('logs')->insert(['message'=>'Did something']);$this->assertCount(1,DB::table('logs')->get());$this->artisan('logs:empty');// Same as Artisan::call('logs:empty');$this->assertCount(0,DB::table('logs')->get());}
In projects running Laravel 5.7 and later, you can chain on a few new assertions to your $this->artisan() calls that make it even easier to test Artisan commands—not just the impact they have on the rest of your app, but also how they actually operate. Take a look at Example 8-14 to see an example of this syntax.
publicfunctiontestItCreatesANewUser(){$this->artisan('myapp:create-user')->expectsQuestion("What's the name of the new user?","Wilbur Powery")->expectsQuestion("What's the email of the new user?","wilbur@thisbook.co")->expectsQuestion("What's the password of the new user?","secret")->expectsOutput("User Wilbur Powery created!");$this->assertDatabaseHas('users',['email'=>'wilbur@thisbook.co']);}
Artisan commands are Laravel’s command-line tools. Laravel comes with quite a few out of the box, but it’s also easy to create your own Artisan commands and call them from the command line or your own code.
Tinker is a REPL that makes it simple to get into your application environment and interact with real code and real data, and the dump server lets you debug your code without stopping the code’s execution.