Статьи

Ваше универсальное руководство по командам Laravel

В наше время для разработчика вполне нормально иметь представление о консолях и о том, как выполнять основные команды. Но что, если вы могли бы написать свои собственные команды для улучшения рабочего процесса? Если мы вернемся к Laravel 3, вы, возможно, помните, что он предлагал задачи. Задачи были чрезвычайно полезны, но все еще не подходили для более сложных операций. К счастью, Laravel 4 содержит улучшенный Artisan, который сделает вашу жизнь разработчика намного проще!


Artisan — это утилита командной строки, выпущенная в Laravel 3.

Если вы не знакомы с Laravel, то можете не знать о Artisan. Artisan — это утилита командной строки, выпущенная в Laravel 3. Если вы использовали другие фреймворки, вы можете сравнить Artisan с Oil в FuelPHP, ZFTool в Zend или Console в Symfony 2.

Artisan предлагает много полезных команд, которые могут помочь вам выполнять различные задачи, такие как генерация миграций или публикация ресурсов пакета. В дополнение к встроенным командам вы можете расширить Artisan своими собственными командами.


Это где Artisan черпает свою силу.

В Laravel 3 Artisan был написан с нуля Тейлором Отвеллом (создателем Laravel), таким образом, он был довольно простым (хотя все еще потрясающим). Теперь, когда Laravel 4 основан на Composer, он может использовать существующие пакеты, разработанные другими замечательными разработчиками. В результате Laravel 4 теперь зависит от многочисленных пакетов из среды Symfony . Одним из таких пакетов является превосходный компонент консоли .

Если мы посмотрим на источник приложения Artisan по адресу Illuminate\Console\Application , то увидим, что сам класс расширяет Symfony\Component\Console\Application . Это где Artisan черпает свою силу. Хотя Artisan использует компонент консоли Symfony, многие из распространенных методов получили более быстрые псевдонимы, подобные Laravel. Так что не волнуйтесь, вы все равно будете чувствовать, что разрабатываете с Laravel!


Обычно возникает два вопроса при попытке разработать новую команду.

Когда вы устанавливаете копию Laravel, вы найдете предопределенный каталог в app/commands . Этот каталог также находится в classmap вашего composer.json по умолчанию. Это означает, что после того, как вы создали команду, вам нужно запустить composer dump-autoload чтобы сгенерировать обновленный файл автозагрузки. Если вы этого не сделаете, вы получите ошибки, жалуясь, что ваша команда не может быть найдена.

Если вы разрабатываете пакет, вам нужно создать каталог в вашем каталоге пакетов src/<vendor>/<package> для хранения ваших команд. В кодовой базе Laravel 4 этот каталог называется Console . Не забудьте убедиться, что каталог автоматически загружается в ваши пакеты composer.json .

Во всей кодовой базе Laravel 4 ко всем командам добавляется суффикс Command , и им присваивается имя выполняемой ими задачи. Допустим, например, что у вас есть команда, которая очищает ваш кеш. Вы можете назвать эту команду, CacheClearCommand .


Команда должна выполнить одну задачу. В оставшейся части этой статьи мы собираемся разработать команду генератора пользователей. Давайте рассмотрим основы команды.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// app/commands/UserGeneratorCommand.php
 
<?php
 
use Illuminate\Console\Command;
 
class UserGeneratorCommand extends Command {
 
    /**
     * The console command name.
     *
     * @var string
     */
    protected $name = ‘user:generate’;
 
    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = «Generate a new user»;
 
    /**
     * Execute the console command.
     *
     * @return void
     */
    public function fire()
    {
        $this->line(‘Welcome to the user generator.’);
    }
 
}

Laravel может сгенерировать этот шаблонный код для вас! Просто запустите:

1
$ php artisan command:make UserGeneratorCommand

Это создаст скелетную команду, которую вы можете изменить, однако для целей данного руководства мы пройдем процесс создания команды с нуля, чтобы мы могли изучить каждый фрагмент этого процесса.

Все команды должны предоставить имя. Это имя используется для запуска команды из консоли и должно описывать задачу, которую выполняет команда. Хотя не существует соглашения о том, как называется ваша команда, вы можете рассмотреть одно из следующих: namespace:group/command , namespace:command или просто command .

Все команды должны предоставить описание. Описание используется при получении списка доступных команд из Artisan и при просмотре справочных документов для команды. Описания должны кратко описывать задачу, которую выполняет команда.

Если бы мы открыли нашу консоль и получили список доступных команд, мы все равно не смогли бы увидеть нашу команду в списке.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
$ php artisan list
Laravel Framework version 4.0.0
 
Usage:
  [options] command [arguments]
 
Options:
  —help -h Display this help message.
  —quiet -q Do not output any message.
  —verbose -v Increase verbosity of messages.
  —version -V Display this application version.
  —ansi Force ANSI output.
  —no-ansi Disable ANSI output.
  —no-interaction -n Do not ask any interactive question.
  —env The environment the command should run under.
 
Available commands:
  help Displays help for a command
  list Lists commands
  migrate Run the database migrations
  serve Serve the application on the PHP development server
  tinker Interact with your application
  workbench Create a new package workbench
asset
  asset:publish Publish a package’s assets to the public directory
auth
  auth:reminders Create a migration for the password reminders table
command
  command:make Create a new Artisan command
config
  config:publish Publish a package’s configuration to the application
controller
  controller:make Create a new resourceful controller
db
  db:seed Seed the database with records
key
  key:generate Set the application key
migrate
  migrate:install Create the migration repository
  migrate:make Create a new migration file
  migrate:refresh Reset and re-run all migrations
  migrate:reset Rollback all database migrations
  migrate:rollback Rollback the last database migration
queue
  queue:listen Listen to a given queue
  queue:work Process the next job on a queue
session
  session:table Create a migration for the session database table

Чтобы зарегистрировать нашу новую команду, откройте app/start/artisan.php и быстро прочитайте блок комментариев по умолчанию, который там находится. Когда мы запускаем Artisan из консоли, этот файл включается; мы будем использовать его для начальной загрузки наших команд. В этом файле у нас есть доступ к переменной $artisan которая была объявлена ​​до включения файла. Помните класс приложения Artisan, который мы рассматривали ранее? Тот, который расширил компонент Symfony Console? Ну, $artisan является экземпляром этого класса.

Давайте добавим нашу команду, чтобы сделать ее доступной в консоли.

1
$artisan->add(new UserGeneratorCommand);

Или, если вы предпочитаете статический синтаксис:

1
Artisan::add(new UserGeneratorCommand);

Метод add принимает экземпляр команды. Как только наша команда была добавлена, мы можем получить к ней доступ из консоли.

1
2
$ php artisan user:generate
Welcome to the user generator.

Команда также должна быть указана в доступных командах, а также в справочной информации.

1
$ php artisan list
01
02
03
04
05
06
07
08
09
10
11
12
13
$ php artisan user:generate —help
Usage:
 user:generate
 
Options:
 —help (-h) Display this help message.
 —quiet (-q) Do not output any message.
 —verbose (-v) Increase verbosity of messages.
 —version (-V) Display this application version.
 —ansi Force ANSI output.
 —no-ansi Disable ANSI output.
 —no-interaction (-n) Do not ask any interactive question.
 —env The environment the command should run under.

Если вы получаете какие-либо ошибки, убедитесь, что вы запустили composer dump-autoload из корня приложения после создания команды.


Вывод цветного текста на консоль — непростая задача в Artisan. Существует четыре различных вспомогательных метода для вывода цветного вывода ANSI.

1
2
3
4
5
6
7
$this->info(«This is some information.»);
 
$this->comment(«This is a comment.»);
 
$this->question(«This is a question.»);
 
$this->error(«This is an error.»);

Увлекательной новой функцией Artisan является возможность предоставить команде параметры и аргументы.

Аргументы — это строки, которые вы отправляете команде. Они должны быть даны команде в том порядке, в котором они определены. Рассмотрим следующую команду:

1
$ php artisan user:generate [name] [email]

Аргумент name должен быть указан перед аргументом email .

Аргументы могут быть определены как необязательные.

Опции всегда являются необязательными и имеют префикс с двумя штрихами, если они предоставляются.

1
$ php artisan user:generate —admin

Помимо использования в качестве логических ключей, параметр может быть настроен на прием значения или массива значений.

1
2
$ php artisan user:generate —name=Jason
$ php artisan user:generate —role=user —role=editor

Прежде чем мы определим наши параметры и аргументы, лучше импортировать требуемые классы Symfony (они длинные и их будет сложно писать постоянно). Нам нужны два класса: Symfony\Component\Console\Input\InputOption и Symfony\Component\Console\Input\InputArgument .

Над объявлением нашего класса мы импортируем оба класса.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// app/commands/UserGenerateCommand.php
 
<?php
 
use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
 
class UserGeneratorCommand extends Command {
 
    /**
     * The console command name.
     *
     * @var string
     */
    protected $name = ‘user:generate’;
 
    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = «Generate a new user»;
 
    /**
     * Execute the console command.
     *
     * @return void
     */
    public function fire()
    {
        $this->line(‘Welcome to the user generator.’);
    }
 
}

Чтобы определить параметры и аргументы, вам нужно создать два новых метода: getArguments и getOptions . Оба эти метода возвращают массив аргументов или опций. Давайте заставим нашу команду принять аргумент name и параметр age .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
// app/commands/UserGenerateCommand.php
 
<?php
 
use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
 
class UserGeneratorCommand extends Command {
 
    /**
     * The console command name.
     *
     * @var string
     */
    protected $name = ‘user:generate’;
 
    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = «Generate a new user»;
 
    /**
     * Execute the console command.
     *
     * @return void
     */
    public function fire()
    {
        $this->line(‘Welcome to the user generator.’);
 
        // Get the name arguments and the age option from the input instance.
        $name = $this->argument(‘name’);
 
        $age = $this->option(‘age’);
 
        $this->line(«{$name} is {$age} years old.»);
    }
 
    /**
     * Get the console command arguments.
     *
     * @return array
     */
    protected function getArguments()
    {
        return array(
            array(‘name’, InputArgument::REQUIRED, ‘Name of the new user’),
        );
    }
 
    /**
     * Get the console command options.
     *
     * @return array
     */
    protected function getOptions()
    {
        return array(
            array(‘age’, null, InputOption::VALUE_REQUIRED, ‘Age of the new user’)
        );
    }
 
}

Помните: Laravel может сгенерировать весь этот стандартный код для вас. Мы просто делаем это вручную, чтобы просмотреть каждую строку в классе.

Теперь мы можем предоставить аргумент name и параметр age из нашей консоли.

1
2
$ php artisan user:generate Jason —age=22
Jason is 22 years old.

И аргументы, и опции определяются как многомерные массивы. Давайте подробнее рассмотрим определения для каждого из них.

Определение массива для аргумента принимает четыре ключа, причем требуется только первый (имя аргумента). Второй ключ — это режим аргументов, который должен быть либо InputArgument::OPTIONAL либо InputArgument::OPTIONAL InputArgument::REQUIRED . Третий — описание, а четвертый ключ — значение по умолчанию, если режим установлен на InputArgument::OPTIONAL .

Вот аргумент, использующий все ключи массива.

1
array(‘name’, InputArgument::OPTIONAL, ‘Name of the new user’, ‘Jason’)

Определение массива для опции принимает пять ключей, причем требуется только первый (имя опции). Второй ключ является ярлыком для опции (например, -a ). Третьим является режим параметров, который может принимать одно из следующих значений: InputOption::VALUE_NONE , InputOption::VALUE_REQUIRED , InputOption::VALUE_OPTIONAL или InputOption::VALUE_IS_ARRAY . Четвертый ключ является описанием параметров, а пятый ключ является значением по умолчанию, если режим не является InputOption::VALUE_NONE или InputOption::VALUE_REQUIRED .

Вот вариант, использующий все ключи массива.

1
array(‘age’, ‘a’, InputOption::VALUE_OPTIONAL, ‘Age of the new user’, 22)

Вы также можете комбинировать режим InputOption::VALUE_IS_ARRAY с InputOption::VALUE_REQUIRED или InputOption::VALUE_OPTIONAL .

1
array(‘role’, ‘r’, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, ‘Roles of the new user’, ‘user’)

Еще одна интересная новая функция Artisan — это возможность запрашивать подтверждение или даже задавать пользователю вопрос. Это делает разработку интерактивных команд максимально простой.

Используя confirm , мы можем задать пользователю вопрос и заставить его подтвердить либо «да», либо «нет». Давайте подтвердим, что пользователь правильно ввел свой возраст.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
// app/commands/UserGenerateCommand.php
 
<?php
 
use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
 
class UserGeneratorCommand extends Command {
 
    /**
     * The console command name.
     *
     * @var string
     */
    protected $name = ‘user:generate’;
 
    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = «Generate a new user»;
 
    /**
     * Execute the console command.
     *
     * @return void
     */
    public function fire()
    {
        $this->line(‘Welcome to the user generator.’);
 
        // Get the name arguments and the age option from the input instance.
        $name = $this->argument(‘name’);
 
        $age = $this->option(‘age’);
 
        if ( ! $this->confirm(«Are you really {$age} years old? [yes|no]», true))
        {
            $this->comment(‘Then why did you say you were!?’);
 
            return;
        }
 
        $this->comment(«{$name} is {$age} years old.»);
    }
 
    /**
     * Get the console command arguments.
     *
     * @return array
     */
    protected function getArguments()
    {
        return array(
            array(‘name’, InputArgument::REQUIRED, ‘Name of the new user’),
        );
    }
 
    /**
     * Get the console command options.
     *
     * @return array
     */
    protected function getOptions()
    {
        return array(
            array(‘age’, null, InputOption::VALUE_REQUIRED, ‘Age of the new user’, null)
        );
    }
 
}

Первый параметр — это вопрос, который вы хотите задать, а второй — значение по умолчанию, если пользователь нажимает ввод, ничего не печатая.

Используя ask , мы можем задать пользователю вопрос и ожидать от него ответа. Вместо того, чтобы убивать нашу команду, если пользователь указывает, что они ввели свой возраст неправильно, давайте вместо этого попросим его ввести его снова.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
// app/commands/UserGenerateCommand.php
 
<?php
 
use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
 
class UserGeneratorCommand extends Command {
 
    /**
     * The console command name.
     *
     * @var string
     */
    protected $name = ‘user:generate’;
 
    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = «Generate a new user»;
 
    /**
     * Execute the console command.
     *
     * @return void
     */
    public function fire()
    {
        $this->line(‘Welcome to the user generator.’);
 
        // Get the name arguments and the age option from the input instance.
        $name = $this->argument(‘name’);
 
        $age = $this->option(‘age’);
 
        // Confirm the user entered their age correctly and if they haven’t we’ll
        // ask them to enter it again.
        if ( ! $this->confirm(«Are you really {$age} years old? [yes|no]», true))
        {
            $age = $this->ask(‘So how old are you then?’);
        }
 
        $this->comment(«{$name} is {$age} years old.»);
    }
 
    /**
     * Get the console command arguments.
     *
     * @return array
     */
    protected function getArguments()
    {
        return array(
            array(‘name’, InputArgument::REQUIRED, ‘Name of the new user’),
        );
    }
 
    /**
     * Get the console command options.
     *
     * @return array
     */
    protected function getOptions()
    {
        return array(
            array(‘age’, null, InputOption::VALUE_REQUIRED, ‘Age of the new user’, null)
        );
    }
 
}

Внедрение зависимостей является важным шагом для обеспечения того, чтобы ваш код был тестируемым и перспективным. Давайте сделаем еще одну команду, внедрив экземпляр модели, чтобы мы могли сгенерировать пользователя. Мы начнем с создания пользовательского интерфейса и пользовательской модели.

1
2
3
4
5
6
7
// app/models/UserInterface.php
 
<?php
 
interface UserInterface {
 
}

Наш UserInterface самом деле не определяет какие-либо реализации методов, так как это всего лишь пример. Для реального приложения вы должны определить методы, которые ожидаете от своей модели.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
// app/models/User.php
 
<?php
 
class User extends Eloquent implements UserInterface {
 
    /**
     * The database table used by the model.
     *
     * @var string
     */
    protected $table = ‘users’;
 
}

Теперь, когда у нас есть User модель, реализующая наш пользовательский UserInterface , мы можем продолжить настройку нашей зависимости в нашей команде. Я собираюсь добавить немного больше в нашу команду создания и взаимодействовать с User моделью User .

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
// app/commands/UserGenerateCommand.php
 
<?php
 
use Illuminate\Console\Command;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Input\InputArgument;
 
class UserGeneratorCommand extends Command {
 
    /**
     * The console command name.
     *
     * @var string
     */
    protected $name = ‘user:generate’;
 
    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = «Generate a new user»;
 
    /**
     * User model instance.
     *
     * @var UserInterface
     */
    protected $user;
 
    /**
     * Create a new UserGeneratorCommand instance.
     *
     * @param UserInterface $user
     * @return void
     */
    public function __construct(UserInterface $user)
    {
        $this->user = $user;
    }
 
    /**
     * Execute the console command.
     *
     * @return void
     */
    public function fire()
    {
        $this->line(‘Welcome to the user generator.’);
 
        // Get the name arguments and the age option from the input instance.
        $this->user->name = $this->argument(‘name’);
 
        $this->user->age = $this->option(‘age’);
 
        // Confirm the user entered their age correctly and if they haven’t we’ll
        // ask them to enter it again.
        // sure they’ve entered the right age.
        $correctAge = false;
 
        while ( ! $correctAge)
        {
            if ( ! $this->confirm(«Are you really {$this->user->age} years old? [yes|no]», true))
            {
                $this->user->age = $this->ask(‘So how old are you then?’);
            }
            else
            {
                $correctAge = true;
            }
        }
 
        $this->user->framework = $this->ask(‘What is your favorite framework?’, ‘Laravel’);
 
        $this->user->website = $this->ask(‘What is your website address?’);
 
        // Save the user to the database.
        $this->user->save();
 
        // Report that the user has been saved.
        $this->info(«{$this->user->name} has been generated and saved.»);
    }
 
    /**
     * Get the console command arguments.
     *
     * @return array
     */
    protected function getArguments()
    {
        return array(
            array(‘name’, InputArgument::REQUIRED, ‘Name of the new user’),
        );
    }
 
    /**
     * Get the console command options.
     *
     * @return array
     */
    protected function getOptions()
    {
        return array(
            array(‘age’, null, InputOption::VALUE_REQUIRED, ‘Age of the new user’, null)
        );
    }
 
}

Первое, что вы должны заметить, это то, что команда теперь имеет конструктор. Этот конструктор принимает один параметр, и мы UserInterface тип UserInterface , поэтому мы знаем, что класс, который мы получаем, реализует методы, определенные в интерфейсе. Конструкторы команд также должны вызывать родительский конструктор.

В методе fire команды мы напрямую назначаем свойства экземпляру модели User . Мы также используем цикл, чтобы продолжать спрашивать пользователей, правильно ли они ввели свой возраст. Наконец, пользователь сохраняется в базе данных, и мы выводим на консоль информацию о том, что пользователь был сгенерирован и сохранен.

Но ждать! Прежде чем мы сможем использовать команду, нам нужно внедрить экземпляр нашей модели User .

1
2
3
4
5
// app/start/artisan.php
 
$user = new User;
 
$artisan->add(new UserGeneratorCommand($user));

Если у вас есть настроенная база данных и она настроена правильно, вы сможете запустить команду и сохранить нового пользователя в базе данных!


Если вы разрабатываете пакет в Laravel, вы можете включить команды. Регистрация команд из пакетов — это в основном тот же процесс, за исключением того, что вы не добавляете (или не можете) добавить команду в app/start/artisan.php . Вместо этого вы решаете их с помощью Artisan из провайдера услуг пакетов.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
// path/to/your/PackageServiceProvider.php
 
/**
 * Register the service provider.
 *
 * @return void
 */
public function register()
{
    $this->app[‘command.package.command’] = $this->app->share(function($app)
    {
        return new PackageCommand($app[‘dependency’]);
    });
 
    $this->commands(‘command.package.command’);
}

Метод commands может принимать любое количество аргументов и разрешает команду из контейнера приложения при запуске Artisan.


Когда вы сравните Artisan в Laravel 4 с его аналогом Laravel 3, вы быстро обнаружите, что улучшения являются монументальными. Команды теперь могут быть привязаны к контейнеру IoC и включают внедрение зависимостей, предоставляют цветной вывод ANSI, используют аргументы и параметры и запрашивают взаимодействие с пользователем.

Сила Artisan, благодаря компоненту Symfony Console, невероятна. Команды будут играть огромную роль, поскольку мы продвигаемся вперед — так что садитесь на доску рано!