Zend_Tool – пакет Zend Framework’a, который позволяет писать свои консольные мини-приложения.
Написать своё подобное приложение достаточно просто, для этого нам потребуется сделать следующее:
- Написать класс провайдера (в нем будет реализована логика приложения)
- Написать класс манифеста (информационный класс, необходим для организации вывода информации о провайдерах)
- “Рассказать” где они ZF’у
Пример реализации провайдера
Начнем с написания простого провайдера:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 | class My_Tool_Project_Provider_MyProvider extends Zend_Tool_Project_Provider_Abstract implements Zend_Tool_Framework_Provider_Pretendable { public function getName() { // кастомное имя провайдера return 'Myth' ; } public function say() { // будет выводить сие приветствие echo "Hello Russian!" ; } } |
И еще более простого манифеста:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 | class My_Tool_Project_Provider_Manifest implements Zend_Tool_Framework_Manifest_ProviderManifestable { /** * Возвращаю список всех доступных провайдеров * * @return array */ public function getProviders() { return array ( new My_Tool_Project_Provider_MyProvider ); } } |
Теперь перед нами стоит задача инициализации данного манифеста и провайдера, для этой цели нам необходимо прописать информацию о них в конфигурационном файле Zend_Tool – .zf.ini (не путать с application.ini):
Создаем новый, используя консоль (будет создан в вашей домашней директории):
1 | zf --setup config- file |
Вносим изменения:
1 2 | basicloader.classes.0 = "My_Tool_Project_Provider_MyProvider" basicloader.classes.1 = "My_Tool_Project_Provider_Manifest" |
Расположение файла zf.ini может быть следующим:
- Берется из переменной окружения ZF_CONFIG_FILE
- Загружается файл $homeDirectory/.zf.ini, если таковой имеется
- Загружается файл $storageDirectory/zf.ini, если таковой имеется
Так же необходимо, чтобы эти наши классы лежали в include_path, если это не приемлемо (ну мне уж точно не нравится) – то для этой цели лучше написать утилиту враппер и положить в директорию с zf.sh, вот мой файл zfc.sh:
01 02 03 04 05 06 07 08 09 10 11 | #!/bin/sh # указываю свой путь к конфигурационному файлу ZF_CONFIG_FILE= "./../.zf.ini" export ZF_CONFIG_FILE # добавляю директорию к опции include_path ZEND_TOOL_INCLUDE_PATH_PREPEND= "./../library" export ZEND_TOOL_INCLUDE_PATH_PREPEND # вызываю zf.sh с всеми входящими параметрами . /zf .sh $@ |
Файл zfc.bat для Windows (спасибо Hunter’у):
1 2 3 4 5 | @ECHO off SET ZF_CONFIG_FILE=./../.zf.ini SET ZEND_TOOL_INCLUDE_PATH_PREPEND=./.. /library . /zf .bat -- %* |
Теперь пробуем вызвать наш провайдер:
1 2 3 | cd project /bin . /zfc .sh say myth >> Hello Russian! |
В результате всех вышеописанных манипуляций у меня получилась следующая структура проекта:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 | project |-- application |-- bin | |-- zf.bat | |-- zf.sh | |-- zf.php | |-- zfс.bat | `-- zfс.sh |-- library | |-- My | | `-- Tool | | `-- Project | | `-- Provider | | |-- Manifest.php | | `-- MyProvider.php | `-- Zend |-- public `-- .zf.ini |
Провайдер для ZF проекта
Далее стоит привести пример написания провайдеров для интеграции в ZF проект. Начну пожалуй с изменений в структуре проекта:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 | project |-- application |-- bin |-- library | |-- My | | `-- Tool | | |-- Context | | | `-- My | | | |-- MythDirectory.php (My_Tool_Project_Context_My_MythDirectory) | | | `-- MythFile.php (My_Tool_Project_Context_My_MythFile) | | `-- Project | | `-- Provider | | |-- Abstract.php (My_Tool_Project_Provider_Abstract) | | |-- Manifest.php | | `-- MyProvider.php | `-- Zend |-- public `-- .zf.ini |
Теперь приведу листинг каждого файла с небольшими пояснениями. Начну с файла My_Tool_Project_Provider_Abstract – он необходим для регистрации собственных элементов:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 | require_once 'Zend/Tool/Project/Provider/Abstract.php' ; class My_Tool_Project_Provider_Abstract extends Zend_Tool_Project_Provider_Abstract { /** * constructor */ public function __construct() { parent::__construct(); // load My Context elements $contextRegistry = Zend_Tool_Project_Context_Repository::getInstance(); $contextRegistry ->addContextsFromDirectory( dirname(dirname( __FILE__ )) . '/Context/My/' , 'My_Tool_Project_Context_My_' ); } } |
Пишем свои элементы – свою директорию:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 | require_once 'Zend/Tool/Project/Context/Filesystem/Directory.php' ; class My_Tool_Project_Context_My_MythDirectory extends Zend_Tool_Project_Context_Filesystem_Directory { /** * @var string */ protected $_filesystemName = 'myth' ; public function getName() { return 'MythDirectory' ; } } |
И некие мифические классы:
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 | class My_Tool_Project_Context_My_MythFile extends Zend_Tool_Project_Context_Zf_AbstractClassFile { protected $_mythName = 'Base' ; protected $_filesystemName = 'mythName' ; public function init() { $this ->_mythName = $this ->_resource->getAttribute( 'mythName' ); $this ->_filesystemName = ucfirst( $this ->_mythName) . '.php' ; parent::init(); } public function getPersistentAttributes() { return array ( 'mythName' => $this ->getMythName() ); } public function getName() { return 'MythFile' ; } public function getMythName() { return $this ->_mythName; } public function getContents() { $className = 'Myth_' .ucfirst( strtolower ( $this ->_mythName)); $codeGenFile = new Zend_CodeGenerator_Php_File( array ( 'fileName' => $this ->getPath(), 'classes' => array ( new Zend_CodeGenerator_Php_Class( array ( 'name' => $className , 'methods' => array ( new Zend_CodeGenerator_Php_Method( array ( 'name' => '__construct' , 'body' => '/* Myth Here ... */' , )) ) )) ) )); return $codeGenFile ->generate(); } } |
Теперь надо бы научиться использовать эти элементы, для этого в файле MyProvider добавляем метод create:
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 | public function create( $name = "base" ) { // загружаем профайл проекта (это файл .zfproject.xml) $profile = $this ->_loadProfile(self::NO_PROFILE_THROW_EXCEPTION); // ищем директиву projectDirectory $profileSearchParams = array ( 'projectDirectory' ); $projectDirectory = $profile ->search( $profileSearchParams ); if (!( $projectDirectory instanceof Zend_Tool_Project_Profile_Resource)) { throw new Zend_Tool_Project_Provider_Exception( 'Не нашли - прерываем работу' ); } /* создаем мифическую директорию, и сохраняем данные о ней в профайле */ $mythDirectory = $projectDirectory ->search( array ( 'mythDirectory' )); if (!( $mythDirectory instanceof Zend_Tool_Project_Profile_Resource)) { $mythDirectory = $projectDirectory ->createResource( 'mythDirectory' , array ( 'filesystemName' => 'myth' )); $mythDirectory -> create(); } /* создаем мифический класс */ /*@var Zend_Tool_Project_Profile_Resource $newMyth*/ /* запись в профайле */ $newMyth = $mythDirectory ->createResource( 'mythFile' , array ( 'mythName' => $name ) ); /* файл в системе */ $newMyth ->create(); /* сохраняем профайл */ $this ->_storeProfile(); } |
Пробуем сие творение:
1 | . /zfc .sh create myth Bigfoot |
Результатом будем создание директории myth с классом Myth_Bigfoot:
1 2 3 4 5 6 7 | class Myth_Bigfoot { public function __construct() { /* Myth Here ... */ } } |
Скачать пример можно по ссылке: My_Tool
Очень круто!
Так можно сделать мега-генератор админки, например, и жить долго и счастливо
Спасибо за статью , нужно будет на досуге написать генератор CRUD так как это сделанно в руби на рельсах.
Хорошая статья!
Может и юнит тесты за одно сгенерировать?
У меня так и не хватило терпения найти причину по которой эта фича не работает “из коробки”.
Так и в чем она оказалась?
В этой статье Антона есть решение этой проблемы?
Проблема, насколько у меня хватило терпения, оказалась в том что Tool, не сканит директорию указанную в .xml как контейнер для провайдеров, возможно проблема в самом деле и не в этом, в багтрекере есть уже упоминание проблемы этой (http://framework.zend.com/issues/browse/ZF-7747 Created: 01/Sep/09 07:57 AM) возможно эта проблема снова платформозавимима, изначально Zend_Tool “из коробки” под виндой вообще не работал, но нет времени все детально проверить.
В статье Антона есть решение но не в том виде в котором мне бы хотелось: в виде .patch для Zend.
Привет!
Решил написать мало ли кому пригодится.
у кого ZF из портов FreeBSD развернут
zfc.sh может так быть
#!/bin/sh
PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/sbin:/usr/local/bin
тра-та-та
zf $@
естественно в бин каталоге только zfc.sh
а также используйте класс Zend_Tool_Framework_Client_Console_ResponseDecorator_Colorizer
$console
=
new
Zend_Tool_Framework_Client_Console_ResponseDecorator_Colorizer();
$color
=
'hiGreen'
;
echo
$console
->decorate(
'Hello Russian!'
,
$color
);
и маленькая приятная новость, если у функции say указать параметр ($text)
class
My_Tool_Project_Provider_MyProvider
extends
Zend_Tool_Project_Provider_Abstract
implements
Zend_Tool_Framework_Provider_Pretendable
{
public
function
getName()
{
return
'Myth'
;
}
public
function
say(
$text
)
{
echo
"Hello Russian!"
;
}
}
то при вызове провайдера
./zfc.sh say myth
появится приглашение к вводу параметра
Please provide a value for $text
zf>