Overview of Zend_CodeGenerator

    As many people already know, Zend_CodeGenerator appeared in beta 1.8. Zend_Framework
    I wanted to be patient before the release of version 1.8, but I could not resist and decided to try it out.
    We will generate a form class based on the mysql table.
    It is really very convenient and saves us from sometimes chores.

    First you need to consider the classes that we will use.

    To create a php file, a class exists.
    Zend_CodeGenerator_Php_File();
    Its constructor takes an array in which the classes in this file are indicated. For example, you can do this:

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


    Where $ class is an instance of the
    Zend_CodeGenerator_Php_Class ()

    class. There may be several classes. In order to generate several classes, it is worth specifying them in an array.

    But the coding standards for Zend_Framework say:
    “Only one class is allowed inside a single PHP file.
    Placing additional code in a file with a class is allowed, but not welcome. In such files, two empty lines should separate the class and additional PHP code. ”

    This is a subjective matter and I would still generate one file for each class.
    So, the structure of the application is more clearly traced.

    So create a new class:
    $class = new Zend_CodeGenerator_Php_Class();


    the first method that we need is setName (), the input
    parameter for it will be a string with a class called.
    $class -> setName('MyClass')
    In order to indicate from which class the generated class will be inherited, we use the method

    $class ->setExtendedClass('Myclass2')


    Then we may need a dock block,

    $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.

    In the array, which is the
    input parameter, we indicate 'shortDescription' - a brief description of the class
    'longDescription' a full description of the class

    In the nested array of tags, we can specify the tags for the docblock
    'name' - the name of the tag
    'description' - the text next after it

    Then we need to declare the variables used in this class
    This is the setProperties () method the input of the day it is an array of variables, each new variable will be described in a new array
    in which to indicate the properties of the variable
    Or they can be described through the class Zend_CodeGenerator_Php_Parameter

    Suppose then we need 2 variables:

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



    Or
    $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 - this is the name of the variable
    Visibility - access modifier
    Default value - default values, if you do not specify this parameter, the variable will be null

    Now our class may look like this:
    $class = new Zend_CodeGenerator_Php_Class();
    $class -> setName('MyClass extends MyClass2') -> setProperties($vars) -> setDocblock($docblock);


    Of course, we need to describe the methods of this class.
    To install the method, the method
    setMethod()or the
    setMethods()
    Difference only in the number of methods that we want to set, setMethod()accepts either an instance of the Zend_CodeGenerator_Php_Method class or an array that describes the method, setMethods()accepts an array containing the objects of the method, or a set of arrays.

    If you chose the first path, it may look like this:
    $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);


    If the second one can be like this:

    $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',
              )),
            ),
          )),
        )


    here 'name' is the name of the method
    'parameters' is the incoming parameters each new parameter is described by a new array, here everything is exactly the same as for variables inside the class and you can also use the class Zend_CodeGenerator_Php_Parameter ()
    'body' is the body of the method where we put the code that will be executed inside the method in the bottom case this is, '$ var =' hello world ';'. "\ n". 'return $ var', it is worth noting here that the code is not automatically formatted, so you have to use "\ n" and "\ t"
    Doc blocks in methods are specified exactly the same as for classes.

    In the end, all that remains to be done is to generate the code and write it to a file
    $code = $file->generate();
    file_put_contents('file.php', $code);


    To do this, use the standard php function - file_put_contents and the generate () method;
    Which is present in all the classes I have described in Zend_CodeGenerator.
    If you prefer, you can generate each element in parts and separately write to a file.

    Below I will give a rather striking example - a class that generates forms.

    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.


    In general, there is something to go around for example, for example, if the data type in mysql is DATE, then you can bind this by issuing it as a decorator, or make different validators for each data type. Flight of fancy - not limited.

    In addition to forms, you can generate almost anything - controllers, models, thereby saving yourself from unnecessary work.
    Or use Zend_Tool + Zend_Application to generate the site structure and some of its classes from under the console of your operating system.
    Of course, the code generated in this way needs to be finalized with a file, but still it will take less time than writing it from the very beginning.
    We are looking forward to the release of version 1.8, but for now we are dealing with innovations. It seems to me that the developers of the Zend Framework in the release version will make FormGenerator and many more goodies.

    PS: Posted by Gibbzy .

    Also popular now: