Pull to refresh

Обзор Zend_CodeGenerator

Reading time10 min
Views648
Как многим уже известно Zend_CodeGenerator появился в бете 1.8 Zend_Framework
Я хотел было потерпеть до релиза версии 1.8, но не удержался и решил всё таки попробавть «на зубок».
Мы будем генерировать класс формы на основе mysql таблицы.
Это действительно очень удобно и избавляет нас от порой рутинной работы.

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

Для создания php файла сущетвует класс
Zend_CodeGenerator_Php_File();
Его конструктор принимает массив в котором указываются классы находящиеся в этом файле. Например это можно сделать так:

$file = new Zend_CodeGenerator_Php_File(array('classes' => array($class)));


Где $class это экземпляр класса
Zend_CodeGenerator_Php_Class()

Классов может быть несколько для того чтобы сгенерировать несколько классов стоит указать их в массиве.

Но в стандартах кодирования для Zend_Framework сказано:
“Только один класс разрешен внутри одного PHP-файла.
Размещение дополнительно кода в файле с классом разрешено, но не приветствуется. В таких файлах, две пустые строки должны разделять класс и дополнительный PHP-код.”

Это дело субъективное и я бы всё таки сгенерировал по одному файлу на каждый класс,
Так более чётко прослеживается структура приложения.

Итак создадим новый класс:
$class = new Zend_CodeGenerator_Php_Class();


первый метод который нам понадобится это setName()
входящим параметром для него будет являться строка с наванием класса.
$class -> setName('MyClass')
Для того чтобы указать от какого класса будет наследоватся генерируемый класс используем метод

$class ->setExtendedClass('Myclass2')


Затем нам может понадобиться док блок,

$docblock = new Zend_CodeGenerator_Php_Docblock(array(
  'shortDescription' => 'Простой сгенерированный класс',
  'longDescription' => 'Этот класс сгенерирован Zend_CodeGenerator',
  'tags'       => array(
    array(
      'name' => 'version',
    );


* This source code was highlighted with Source Code Highlighter.

В массиве, который являеться входящим параметром мы указываем
‘shortDescription' – краткое описание класса
'longDescription' полное описание класса

Во вложенном массиве tags мы можем указать теги для докблока
‘name’ – название тега
‘description’ – текст следующий после него

Затем нам нужно объявить переменные использумые в этом классе
Это метод setProperties() входящий дня него параметр это массив переменных, каждая новая переменная будет описанна в новом массиве
в которм следуе указать свойства переменной
Или их можно описать через класс Zend_CodeGenerator_Php_Parameter

Предположим что нам нужны 2 переменные:

$vars =  array(
      array(
        'name'     => ‘name,  
        'visibility'  => 'public',
        'defaultValue' => ‘0’,
      )
      array(
        'name'     => ‘_table’,
        'visibility'  => 'protected',
        'defaultValue' => ‘1’,
      )
    );



Или
$var1 = Zend_CodeGenerator_Php_Parameter(
      array(
        'name'     => ‘var’,  
        'visibility'  => 'public',
        'defaultValue' => ‘0’,
      )
);
$var2 = Zend_CodeGenerator_Php_Parameter(
      array(
        'name'     => ‘var2’,  
        'visibility'  => 'protected',
        'defaultValue' => ‘1’,
      )
);
$vars =  array($var1, var2);



Name – это название переменной
Visibility – модификатор доступа
Default value – значние по умолчанию, если не указать этот параметр то переменная будет равна null

Теперь наш класс может выглядеть так:
$class = new Zend_CodeGenerator_Php_Class();
$class -> setName('MyClass extends MyClass2') -> setProperties($vars) -> setDocblock($docblock);



Конечно же нам понадобится описать методы этого класса
Для установки метода служит метод
setMethod() или
setMethods()
Отличие лишь в количестве методов которые мы хотим установить, setMethod() принимает или экзепляр класса Zend_CodeGenerator_Php_Method или массив который описывает метод, setMethods() принимает массив в котором содержатся объекты метода, или набор массивов.

Если вы выбрали первый путь то это может выглядеть это будет вот так:
$method = Zend_CodeGenerator_Php_Method(array(
      'name' => 'myMethod',
      'body'    => 'echo "hello CodeGenerator"',
      'docblock'  => new Zend_CodeGenerator_Php_Docblock(array(
        'shortDescription' => 'блок документации',
        'tags'       => array(
          new Zend_CodeGenerator_Php_Docblock_Tag_Return(array(
            'datatype' => 'string|null',
          )),
        ),
      )),
    )),
  ));

$class ->setMethod($method);



Если второй то можно и так:

$class -> setMethods(array(
    array(
      'name'    => 'myMethod',
      'parameters' => array(
        array('name' => 'myVar),
      ),
      '
body'    => '$var = 'hello world';' . "\n" . 'return $var',
      '
docblock'  => new Zend_CodeGenerator_Php_Docblock(array(
        '
shortDescription' => 'блок документации',
        '
tags'       => array(
          new Zend_CodeGenerator_Php_Docblock_Tag_Param(array(
            '
paramName' => 'bar',
            '
datatype' => 'string'
          )),
          new Zend_CodeGenerator_Php_Docblock_Tag_Return(array(
            '
datatype' => 'string',
          )),
        ),
      )),
    )



здесь 'name' — имя метода
‘parameters' — это входящие параметры каждый новый параметр описывается новым массивом, здесь всё точно так же как и для переменных внутри класса и вы так же можете использовать класс Zend_CodeGenerator_Php_Parameter()
‘body’ – это тело метода куда мы помещаем код который будет выполняться внутри метода в дном случае это, '$var = 'hello world';'. "\n". 'return $var', здесь стоит заметить что код автоматически не форматируется потому приходится использовать "\n" и "\t"
Докблоки в методах указываются точто так же как и для классов.

В конце всё что остаётся сделать это сгенерировать код и записать его в файл
$code = $file->generate();
file_put_contents('file.php', $code);



Для этого используем стандартную фукцию php — file_put_contents и метод generate();
Который присутсвует во всех вышеописанных мною классов в Zend_CodeGenerator
Если вам будет удобнее то можно сгенерировать каждый элемент частями и по отдельности записать в файл.

Далее я приведу довольно яркий пример — класс который генерирует формы.

<?php
class FormGenerator
{
  /**
   * Массив в котором ключ тип данных в mysql
   * значение - input type у формы
   * */
  protected $_values = array(
    'text'  => 'Textarea',
    'int'   => 'Text',
    'varchar' => 'Text',
    'tinyint' => 'CheckBox',
    'date'  => 'Text',
    'float'  => 'Text',
    'mediumint'  => 'Text',
  );
  /**
   * Метод генерирующий класс формы
   * входящий параметр - экземпляр класса Zend_Db_Table
   * */
   public function generateForm(Zend_Db_Table $table)
  {
    //получаем инфомрмацию о таблице
    $tableInfo = $table->info();
    
    //Получаем навание класса
    $className = 'Form_' . ucfirst($tableInfo['name']);
    
    //Дирректория где будут хранится классы форм
    $folder = $_SERVER['DOCUMENT_ROOT'] . '/application/models/Form/';
    
    //Объявляем новый класс устанавливаем его имя и от чего он должен наследоваться
    $formClass = new Zend_CodeGenerator_Php_Class();
    $formClass->setName($className);
    $formClass->setExtendedClass('Zend_Form');
    
    //Тело метода init
    $initMethodBody = 'parent::init();
              $helper = new Zend_View_Helper_Url();
              '
. "\n\t\t";
    
    // записываем в тело метода элементы используя метод generateElement()
    foreach ($tableInfo['metadata'] as $field){
      Zend_Debug::dump($field);
      $initMethodBody .= $this->generateElement($field['COLUMN_NAME'], $field['DATA_TYPE']);
    }
    
    // отдельно генерируем кнопку submit
    $initMethodBody .= $this->generateSumitElement($tableInfo['name']);
    $initMethod = new Zend_CodeGenerator_Php_Method(
      array(
        'name' => 'init',
        'body'    =>$initMethodBody
      ));
      
    // устанавливаем метод в класс 
    $formClass->setMethod($initMethod);
    
    // устанавливаем класс в файл
    $file = new Zend_CodeGenerator_Php_File(array(
      'classes' => array($formClass)
    ));
    
    //генерирум код
    $code = $file->generate();
    
    // если дирректории нет то создаём её
    if(!file_exists($folder)) {
      mkdir($folder);
    }
    // и записываем код в файл
    file_put_contents($folder.ucfirst($tableInfo['name']) . '.php', $code);
  }
  
  /**
   * Метод герирования элемента формы
   * входящие параметры - имя и тип поля в mysql
   * возвращает код элемента
   * */
  public function generateElement($name, $type)
  { 
    $element = '$' . $name . ' = new Zend_Form_Element_' . $this->_values[$type]. "(\n\t\t"
          . "'$name'," . " \n\t\t"
          . "array("
          . "'label' => '$name')); \n\t\t";
    // тут если тип числовой тогда применяем валидатор Digits
    if($type == 'int' || $type == 'tinyint' || $type == 'mediumint') {
      $element .= '$' . $name . '->addValidator("Digits", true);' . "\n\t\t";
    }
    
    // а если сроковой тогда фильтр StripTags
    if($this->_values[$type] == 'Textarea' || $this->_values[$type] == 'Text'){
      $element .= '$' . $name . '->addFilter("StripTags");' . "\n\t\t";
    }
    // в любом случае нам понадобится фильтр StringTrim
    $element .= '$' . $name . '->addFilter("StringTrim");' . "\n\t\t"
         . '$this->addElement($' . $name . ');' . "\n\n\t\t";
    return $element;
  }
  
  /**
   * генерация кнопки submit ничего сложного 
   */
  public function generateSumitElement($name)
  {
    $element = '$submit_' . $name . ' = new Zend_Form_Element_Submit('
          . "'submit_$name'" . "); \n\t\t"
          . '$this->addElement($submit_' . $name . ');';
    return $element;
  }
}

* This source code was highlighted with Source Code Highlighter.


Вообще здесь есть куда разгулятся, например если тип данных в mysql — DATE то можно привязать вот это, оформив как декоратор, или сделать различные валидаторы для каждого типа данных. Полёт фантазии — не ограничен.

По мимо форм можно сгерировать практически всё что угодно — контроллры, модели тем самым избавив себя от лишней работы.
Или использовать Zend_Tool + Zend_Application для генерации структуры сайта и некоторых его классов из под консоли вашей операционной системы.
Конечно, код сгенерированный подобным образом требует доработки напильником, но всё же это займёт меньше времени чем писать его с самого начала.
Усиленно ждём релиза 1.8 версии, а пока разбираемся с нововведениями. Мне кажется, что разработчики Zend Framework в релизной версии сделают FormGenerator и ещё много всяких вкусностей.

P.S: Автор статьи Gibbzy.
Tags:
Hubs:
Total votes 12: ↑11 and ↓1+10
Comments11

Articles