Начиная с версии 1.1 в symfony каждая команда представляет из себя отдельный класс, в отличие от предыдущих версий, где каждая команда была представлена двумя функциями (описание и сама команда). Команды разделены на пространства имен, что позволяет избегать конфликтов в именовании команд. Команды можно наследовать и переопределять. При совпадении названий внутри одного пространства имен, команды перекрываются, такми образом команды установленных плагинов переопределяют команды ядра симфони, а команды проекта переопределяют команды плагинов и ядра симфони.
Для создания своей команды, можно воспользоваться генерацией каркаса команды. Например создадим команду, которая выводит "Привет, Мир!" и назовем ее "hello". Определим ее в пространстве имен "example"
./symfony generate:task example:hello
Теперь для того чтобы убедиться, что каркас был создан введем команду:
./symfony list example
и если мы на выходе получим примерно следующее:
Available tasks for the "example" namespace:
:hello
значит каркас был успешно создан и в директории "lib/task" можно найти файл "exampleHelloTask.class.php".
В этом файле и создан класс-каркас нашей команды. В котором определены два необходимых метода "configure" и "execute", которые конфигурируют и запускают команду соответственно.
class exampleHelloTask extends sfBaseTask
{
protected function configure()
{
// ...
}
protected function execute($arguments = array(), $options = array())
{
// ...
}
}
По умолчанию, команда "generate:task" создаст каркас в директории "lib/task", но можно указать путь, где создать каркас, например при создании своей команды в плагине:
./symfony generate:task --dir=plugins/spExamplePlugin/lib/task example:hello
В классе команды должны быть определены два метода, метод описания и конфигурации команды - "configure" и метод в котором выполняются действия команды - "execute". Метод configure для нашей команды может выглядеть примерно так:
protected function configure()
{
$this->namespace = 'example'; // пространство имен
$this->name = 'hello'; // название команды
// короткое описание
// выводимое по команде ./symfony list
$this->briefDescription = '';
// подробное описание
// выводимое по команде help, в этом описании
// форматируя особым образом текст можно добиться
// необходимой подсветки.
// например [text|INFO] выведет text зеленым цветом, а
// [text|COMMENT] выведет text коричневым цветом
$this->detailedDescription = '
Команда [example:hello|INFO] просто привествует мир.
Запускайте ее так:
[./symfony example:hello|INFO]
';
$this->aliases = array(); // массив синонимов
}
Теперь можно выполнить команду:
./symfony help example:hello
и убедиться, что справочная информация выводится так как и было задумано.
Теперь добавим действий команде, дополнив код метода "execute":
protected function execute($arguments = array(), $options = array())
{
$this->logSection("example", "Привет, Мир!");
}
Метод "logSection" печатает отформатированное сообщение на стандартный вывод.
Запускаем:
./symfony example:hello
и получаем:
>>example Привет, Мир!
Зачастую команды должны быть конфигурируемы, например выполнять действия в указанном окружении, или для определенного приложения. А так же должны уметь принимать аргументы как имя автора в команде "configure:author" или название приложения в команде "generate:app".
Эти задачи реализуются за счет описания опций и аргументов в методе "configure".
В качестве примера добавим нашей команде способность привествовать не только мир, но и разработчика вызвавшего ее. Для этого добавим аргумент "name", в котором будем принимать имя разработчика и немного изменим подробное описание команды, продемонстрировав еще одну возможность расскраски выводимого текста:
protected function configure()
{
$this->namespace = 'example'; // пространство имен
$this->name = 'hello'; // название команды
// короткое описание
// выводимое по команде ./symfony list
$this->briefDescription = '';
// подробное описание
// выводимое по команде help, в этом описании
// форматируя особым образом текст можно добиться
// необходимой подсветки.
// например [text|INFO] выведет text зеленым цветом, а
// [text|COMMENT] выведет text коричневым цветом
$this->detailedDescription = '
Команда [example:hello|INFO] просто привествует мир.
Запускайте ее так:
[./symfony example:hello|INFO]
Команда может привествовать не только мир, но и вас лично,
для этого используйте аргумент [name|COMMENT]:
[./symfony example:hello name|INFO]
';
$this->aliases = array(); // массив синонимов
$this->addArgument
(
'name', // название аргумента
sfCommandArgument::OPTIONAL, // тип аргумента
'Ваше имя, о величайший создатель', // справка
'Мир' // значение по умолчанию
)
}
Если теперь выполнить команду:
./symfony help example:hello
то можно увидеть, что описание этого аргумента добавилось в вывод справки нашей команды.
Теперь изменим код команды:
protected function execute($arguments = array(), $options = array())
{
$this->logSection('example', 'Привет, '.$arguments['name'].'!');
}
и запустим в двух вариантах:
./symfony example:hello
>>example Привет, Мир!
./symfony example:hello Сергей
>>example Привет, Сергей!
Рассмотрим подробнее описание аргумента.
Для описания используется метод:
/**
* name - имя аргумента
* mode - свойства аргумента, возможные значения
* sfCommandArgument::OPTIONAL,
* sfCommandArgument::REQUIRED,
* sfCommandArgument::IS_ARRAY
* help - справка
* default - значение по умолчанию, нельзя указать при REQUIRED
*/
addArgument($name, $mode = null, $help = '', $default = null);
Предназначение параметров вроде понятно из их названий, а вот о "mode" немного дополню.sfCommandArgument::OPTIONAL - говорит о том, что аргумент является не обязательным
sfCommandArgument::REQUIRED - напртив, говорит о том, что аргумент является обязательным. При указании sfCommandArgument::REQUIRED нельзя задать значение по умолчанию для аргумента.
sfCommandArgument::IS_ARRAY - говорит о том, что аргумент является массивом. В этом случае в методе "execute" он будет доступен именно как массив и в значении по умолчанию его тоже надо задавать в виде массива. При вызове команды из консоли массивы передаются так:
./symfony example:hello {Сергей,Мир}
// преобразуется в массив array('Сергей', 'Мир');
./symfony example:hello Сергей Мир
// преобразуется в массив, если у аргумента указан IS_ARRAY
"mode" можно задать и так, объединив свойства аргумента:
$this->addArgument
(
'hello',
sfCommandArgument::OPTIONAL | sfCommandArgument::IS_ARRAY
);
Для добавления нескольких аргументов за раз, можно воспользоваться методом "addArguments":
$this->addArguments
(
new sfCommandArgument
(
'hello',
sfCommandArgument::OPTIONAL,
'help',
'default'
),
new sfCommandArgument
(
'bye',
sfCommandArgument::OPTIONAL,
'help',
'default'
)
//, ...
);
Опции команде можно добавить используя методы "addOption" или "addOptions".
/**
* Описывает принимаемую опцию
*
* name - имя опции
* shortname - короткое имя опции
* mode - свойства параметра опции
* help - справка
* default - значение по умолчанию
*/
addOption($name, $shortname = null, $mode = null, $help = '', $default = null);
Добавим нашей команде возможность указания способа привествия, для этого опишем опцию "greeting" в методе "configure":
protected function configure()
{
// ... пропускаю то, что сделали выше
// обязателен только первый параметр
$this->addOption
(
'greeting', // имя опции
'g', // короткое имя опции
sfCommandOption::PARAMETER_OPTIONAL, // mode
'Как попривествовать', // справка
'Привет', // значение по умолчанию
)
}
protected function execute($arguments = array(), $options = array())
{
$this->logSection('example', $options['greeting'].', '.$arguments['name'].'!');
}
И запускаем в двух вариантах:
./symfony example:hello -g Здравствуй
>> example Здравствуй, Мир!
./symfony example:hello --greeting=Здравствуй
>> example Здравствуй, Мир!
Предназначение параметров понятны из названия и комментариев."mode" может иметь следующие значения или их комбинации:
sfCommandOption::PARAMETER_NONE - если опция не нуждается в параметре, т.е. например:
./symfony task_name --debug
в метод "execute" в "$options['debug']" будет передано либо "true" если опция указана, либо "false" если опция не указана.sfCommandOption::PARAMETER_REQUIRED - параметр у опции обязателен
sfCommandOption::PARAMETER_OPTIONAL - параметр у опции не обязателен
sfCommandOption::IS_ARRAY - параметр у опции массив, можно указать несколько раз:
./symfony task_name --option='param1' --option='param2'
// преобразуется в array('param1', 'param2')
Ну и вариант для добавления нескольких опций за раз:
protected function configure()
{
$this->addOptions
(
new sfCommandOption
(
'greeting',
'g',
sfCommandOption::PARAMETER_REQUIRED,
'help',
'Привет'
),
new sfCommandOption
(
'env'
)
//, ...
);
}
Несколько полезных советов
Вызов команды внутри другой команды.
protected function execute($arguments = array(), $options = array())
{
$task = new myOtherTask($this->dispatcher, $this->formatter);
$task->run
(
$arguments = array
(
'foo' => 'bar'
),
$options = array
(
'bar' => 'foo'
)
);
}
Использование базы данных Если в команде используется подключение к базе данных, то необходимо в методе "configure" добавить аргумент "appliction" и опцию "--env" (опция не обязательна) для указания какие данные использовать для подключения к базе данных. После этого необходимо в методе "execute" выполнить инициализацию соединения с базой данных.
protected function configure()
{
$this->addArgument('application', sfCommandArgument::REQUIRED, 'Имя приложения');
$this->addOption('env', null, sfCommandOption::PARAMETER_REQUIRED, 'Окружение', 'dev');
$this->addOption('connection', null, sfCommandOption::PARAMETER_REQUIRED, 'Имя соединения', 'doctrine')
// ...
}
protected function execute($arguments = array(), $options = array())
{
$dbManager = new sfDatabaseManager($this->configuration);
$connection = Doctrine_Manager::connection();
// ...
}
Можно и при создании каркаса команды указать опцию "--use-database", но потом поправить некоторые значения если используется "Doctrine", а в частности:В методе "configure" при описании опции "connection" изменить имя по умолчанию.
В метод "execute":
// заменить
$connection = Propel::getConnection($options['connection'] ? $options['connection'] : '');
// на
$connection = Doctrine_Manager::connection();
Комментариев нет:
Отправить комментарий