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 PostController
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
, up
Puts your application in “maintenance mode” in order for you to fix an error, run migrations, or whatever else and restore an application from maintenance mode, respectively
dump-server
(5.7+)Starts the dump server (see “Laravel Dump Server”) to collect and output dumped variables
env
Displays which environment Laravel is running in at the moment; it’s the equivalent of echoing app()->environment()
in-app
help
Provides help for a command; for example, php artisan help commandName
migrate
optimize
preset
serve
Pins 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 have changed in small ways over the lifetime of Laravel. I’ll try to note any time they’ve changed, but everything here is current for Laravel 5.8. If you’re not working in 5.8, 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 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
Specify the level of output verbosity (normal, verbose, and debug)
--no-interaction
Suppresses interactive questions, so the command won’t interrupt automated processes running it
--env
Allows you to define which environment the Artisan command should operate in (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:
app
This 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
.
auth
All we have here is auth:clear-resets
, which flushes all of the expired password reset tokens from the database.
cache
cache:clear
clears the cache, 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.
config
config:cache
caches your configuration settings for faster lookup; to clear the cache, use config:clear
.
db
db:seed
seeds your database, if you have configured database seeders.
event
event:list
lists all the events and listeners in your application, event:cache
caches that list, event:clear
clears that cache, and event:generate
builds missing event and event listener files based on the definitions in EventServiceProvider
. You’ll learn more about events in Chapter 16.
key
key: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. Additionally, any data you have manually encrypted will no longer be decryptable. To learn more, check out the article “APP_KEY and You” by fellow Tightenite Jake Bathman.
make
Each of the make:
actions create a single item from a stub, 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
.
migrate
The migrate
command used to run all migrations was mentioned earlier, but there are several other migration-related commands. You can 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 rerun all the migrations with migrate:fresh
, or check the status of your migrations with migrate:status
.
notifications
notifications:table
generates a migration that creates the table for database notifications.
package
In versions of 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 “autodiscover” 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.
queue
We’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.
route
If 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
.
schedule
We’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.
session
session:table
creates a migration for applications using database-backed sessions.
storage
storage: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.
vendor
Some 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.
view
Laravel’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.
<?
php
namespace
AppConsoleCommands
;
use
IlluminateConsoleCommand
;
class
WelcomeNewUsers
extends
Command
{
/**
* 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
*/
public
function
__construct
()
{
parent
::
__construct
();
}
/**
* Execute the console command
*
* @return mixed
*/
public
function
handle
()
{
//
}
}
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 appConsoleKernel.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
=
[
AppConsoleCommandsWelcomeNewUsers
::
class
,
];
We haven’t covered mail or Eloquent yet in this chapter (see Chapter 15 for mail and Chapter 5 for Eloquent), but the sample handle()
method in Example 8-2 should read pretty clearly.
...
class
WelcomeNewUsers
extends
Command
{
public
function
handle
()
{
User
::
signedUpThisWeek
()
->
each
(
function
(
$user
)
{
::
to
(
$user
)
->
send
(
new
WelcomeEmail
);
});
}
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.
...
class
WelcomeNewUsers
extends
Command
{
public
function
__construct
(
UserMailer
$userMailer
)
{
parent
::
__construct
();
$this
->
userMailer
=
$userMailer
}
public
function
handle
()
{
$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()
, as shown in Example 8-6.
// With definition "password:reset {userId}"
php
artisan
password
:
reset
5
// $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; again, 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()
, as shown in Example 8-7.
// With definition "password:reset {--userId=}"
php
artisan
password
:
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-8 shows an Artisan command using argument()
and option()
in its handle()
method.
public
function
handle
()
{
// 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 they want:
$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()
method makes it simple to create ASCII tables full of your data. Take a look at Example 8-9.
$headers
=
[
'Name'
,
'Email'
];
$data
=
[
[
'Dhriti'
,
'[email protected]'
],
[
'Moses'
,
'[email protected]'
],
];
// Or, you could get similar data from the database:
$data
=
AppUser
::
all
([
'name'
,
'email'
])
->
toArray
();
$this
->
table
(
$headers
,
$data
);
Note that Example 8-9 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-10 to see what the table output looks like.
+---------+--------------------+ | Name | Email | +---------+--------------------+ | Dhriti | [email protected] | | Moses | [email protected] | +---------+--------------------+
If you’ve ever run npm install
, you’ve seen a command-line progress bar before. Let’s build one in Example 8-11.
$totalUnits
=
350
;
$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 that 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 define and register the commands in a single step in that file, as shown in Example 8-12.
// routes/console.php
Artisan
::
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-13 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
.
In Laravel 5.8+, you can call Artisan commands much more naturally from your code. Just pass the same string you’d call from the command line into Artisan::call()
:
Artisan
::
call
(
'password:reset 15 --sendEmail'
)
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-14 for an example.
public
function
handle
()
{
$this
->
callSilent
(
'password:reset'
,
[
'userId'
=>
15
,
]);
}
Finally, you can inject an instance of the IlluminateContractsConsoleKernel
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-15 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 AppUser; => AppUser: {} >>> $user->email = '[email protected]'; => "[email protected]" >>> $user->password = bcrypt('superSecret'); => "$2y$10$TWPGBC7e8d1bvJ1q5kv.VDUGfYDnE9gANl4mleuB3htIY2dxcQfQ5" >>> $user->save(); => true
As you can see, we created a new user, set some data (hashing the password with bcrypt()
for security), 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 Dump Server ======================= [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, 18 Sep 2018 22:43:10 +0000 controller "Closure" source web.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-16. In our tests, we use $this->artisan()
instead of Artisan::call()
because it has the same syntax but adds a few testing-related assertions.
public
function
test_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-17 to see an example of this syntax.
public
function
testItCreatesANewUser
()
{
$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?"
,
"[email protected]"
)
->
expectsQuestion
(
"What's the password of the new user?"
,
"secret"
)
->
expectsOutput
(
"User Wilbur Powery created!"
);
$this
->
assertDatabaseHas
(
'users'
,
[
'email'
=>
'[email protected]'
]);
}
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.