123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484 |
- <?php
- /**
- * CCodeModel class file.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @link http://www.yiiframework.com/
- * @copyright 2008-2013 Yii Software LLC
- * @license http://www.yiiframework.com/license/
- */
- /**
- * CCodeModel is the base class for model classes that are used to generate code.
- *
- * Each code generator should have at least one code model class that extends from this class.
- * The purpose of a code model is to represent user-supplied parameters and use them to
- * generate customized code.
- *
- * Derived classes should implement the {@link prepare} method whose main task is to
- * fill up the {@link files} property based on the user parameters.
- *
- * The {@link files} property should be filled with a set of {@link CCodeFile} instances,
- * each representing a single code file to be generated.
- *
- * CCodeModel implements the feature of "sticky attributes". A sticky attribute is an attribute
- * that can remember its last valid value, even if the user closes his browser window
- * and reopen it. To declare an attribute is sticky, simply list it in a validation rule with
- * the validator name being "sticky".
- *
- * @property array $templates A list of available code templates (name=>directory).
- * @property string $templatePath The directory that contains the template files.
- * @property string $stickyFile The file path that stores the sticky attribute values.
- *
- * @author Qiang Xue <qiang.xue@gmail.com>
- * @package system.gii
- * @since 1.1.2
- */
- abstract class CCodeModel extends CFormModel
- {
- const STATUS_NEW=1;
- const STATUS_PREVIEW=2;
- const STATUS_SUCCESS=3;
- const STATUS_ERROR=4;
- static $keywords=array(
- '__class__',
- '__dir__',
- '__file__',
- '__function__',
- '__line__',
- '__method__',
- '__namespace__',
- 'abstract',
- 'and',
- 'array',
- 'as',
- 'break',
- 'case',
- 'catch',
- 'cfunction',
- 'class',
- 'clone',
- 'const',
- 'continue',
- 'declare',
- 'default',
- 'die',
- 'do',
- 'echo',
- 'else',
- 'elseif',
- 'empty',
- 'enddeclare',
- 'endfor',
- 'endforeach',
- 'endif',
- 'endswitch',
- 'endwhile',
- 'eval',
- 'exception',
- 'exit',
- 'extends',
- 'final',
- 'final',
- 'for',
- 'foreach',
- 'function',
- 'global',
- 'goto',
- 'if',
- 'implements',
- 'include',
- 'include_once',
- 'instanceof',
- 'interface',
- 'isset',
- 'list',
- 'namespace',
- 'new',
- 'old_function',
- 'or',
- 'parent',
- 'php_user_filter',
- 'print',
- 'private',
- 'protected',
- 'public',
- 'require',
- 'require_once',
- 'return',
- 'static',
- 'switch',
- 'this',
- 'throw',
- 'try',
- 'unset',
- 'use',
- 'var',
- 'while',
- 'xor',
- );
- /**
- * @var array user confirmations on whether to overwrite existing code files with the newly generated ones.
- * The value of this property is internally managed by this class and {@link CCodeGenerator}.
- */
- public $answers;
- /**
- * @var string the name of the code template that the user has selected.
- * The value of this property is internally managed by this class and {@link CCodeGenerator}.
- */
- public $template;
- /**
- * @var array a list of {@link CCodeFile} objects that represent the code files to be generated.
- * The {@link prepare()} method is responsible to populate this property.
- */
- public $files=array();
- /**
- * @var integer the status of this model. T
- * The value of this property is internally managed by {@link CCodeGenerator}.
- */
- public $status=self::STATUS_NEW;
- private $_stickyAttributes=array();
- /**
- * Prepares the code files to be generated.
- * This is the main method that child classes should implement. It should contain the logic
- * that populates the {@link files} property with a list of code files to be generated.
- */
- abstract public function prepare();
- /**
- * Declares the model validation rules.
- * Child classes must override this method in the following format:
- * <pre>
- * return array_merge(parent::rules(), array(
- * ...rules for the child class...
- * ));
- * </pre>
- * @return array validation rules
- */
- public function rules()
- {
- return array(
- array('template', 'required'),
- array('template', 'validateTemplate', 'skipOnError'=>true),
- array('template', 'sticky'),
- );
- }
- /**
- * Validates the template selection.
- * This method validates whether the user selects an existing template
- * and the template contains all required template files as specified in {@link requiredTemplates}.
- * @param string $attribute the attribute to be validated
- * @param array $params validation parameters
- */
- public function validateTemplate($attribute,$params)
- {
- $templates=$this->templates;
- if(!isset($templates[$this->template]))
- $this->addError('template', 'Invalid template selection.');
- else
- {
- $templatePath=$this->templatePath;
- foreach($this->requiredTemplates() as $template)
- {
- if(!is_file($templatePath.'/'.$template))
- $this->addError('template', "Unable to find the required code template file '$template'.");
- }
- }
- }
- /**
- * Checks if the named class exists (in a case sensitive manner).
- * @param string $name class name to be checked
- * @return boolean whether the class exists
- */
- public function classExists($name)
- {
- return class_exists($name,false) && in_array($name, get_declared_classes());
- }
- /**
- * Declares the model attribute labels.
- * Child classes must override this method in the following format:
- * <pre>
- * return array_merge(parent::attributeLabels(), array(
- * ...labels for the child class attributes...
- * ));
- * </pre>
- * @return array the attribute labels
- */
- public function attributeLabels()
- {
- return array(
- 'template'=>'Code Template',
- );
- }
- /**
- * Returns a list of code templates that are required.
- * Derived classes usually should override this method.
- * @return array list of code templates that are required. They should be file paths
- * relative to {@link templatePath}.
- */
- public function requiredTemplates()
- {
- return array();
- }
- /**
- * Saves the generated code into files.
- */
- public function save()
- {
- $result=true;
- foreach($this->files as $file)
- {
- if($this->confirmed($file))
- $result=$file->save() && $result;
- }
- return $result;
- }
- /**
- * Returns the message to be displayed when the newly generated code is saved successfully.
- * Child classes should override this method if the message needs to be customized.
- * @return string the message to be displayed when the newly generated code is saved successfully.
- */
- public function successMessage()
- {
- return 'The code has been generated successfully.';
- }
- /**
- * Returns the message to be displayed when some error occurred during code file saving.
- * Child classes should override this method if the message needs to be customized.
- * @return string the message to be displayed when some error occurred during code file saving.
- */
- public function errorMessage()
- {
- return 'There was some error when generating the code. Please check the following messages.';
- }
- /**
- * Returns a list of available code templates (name=>directory).
- * This method simply returns the {@link CCodeGenerator::templates} property value.
- * @return array a list of available code templates (name=>directory).
- */
- public function getTemplates()
- {
- return Yii::app()->controller->templates;
- }
- /**
- * @return string the directory that contains the template files.
- * @throws CHttpException if {@link templates} is empty or template selection is invalid
- */
- public function getTemplatePath()
- {
- $templates=$this->getTemplates();
- if(isset($templates[$this->template]))
- return $templates[$this->template];
- elseif(empty($templates))
- throw new CHttpException(500,'No templates are available.');
- else
- throw new CHttpException(500,'Invalid template selection.');
- }
- /**
- * @param CCodeFile $file whether the code file should be saved
- * @return bool whether the confirmation is found in {@link answers} with appropriate {@link operation}
- */
- public function confirmed($file)
- {
- return $this->answers===null && $file->operation===CCodeFile::OP_NEW
- || is_array($this->answers) && isset($this->answers[md5($file->path)]);
- }
- /**
- * Generates the code using the specified code template file.
- * This method is manly used in {@link generate} to generate code.
- * @param string $templateFile the code template file path
- * @param array $_params_ a set of parameters to be extracted and made available in the code template
- * @throws CException is template file does not exist
- * @return string the generated code
- */
- public function render($templateFile,$_params_=null)
- {
- if(!is_file($templateFile))
- throw new CException("The template file '$templateFile' does not exist.");
- if(is_array($_params_))
- extract($_params_,EXTR_PREFIX_SAME,'params');
- else
- $params=$_params_;
- ob_start();
- ob_implicit_flush(false);
- require($templateFile);
- return ob_get_clean();
- }
- /**
- * @return string the code generation result log.
- */
- public function renderResults()
- {
- $output='Generating code using template "'.$this->templatePath."\"...\n";
- foreach($this->files as $file)
- {
- if($file->error!==null)
- $output.="<span class=\"error\">generating {$file->relativePath}<br/> {$file->error}</span>\n";
- elseif($file->operation===CCodeFile::OP_NEW && $this->confirmed($file))
- $output.=' generated '.$file->relativePath."\n";
- elseif($file->operation===CCodeFile::OP_OVERWRITE && $this->confirmed($file))
- $output.=' overwrote '.$file->relativePath."\n";
- else
- $output.=' skipped '.$file->relativePath."\n";
- }
- $output.="done!\n";
- return $output;
- }
- /**
- * The "sticky" validator.
- * This validator does not really validate the attributes.
- * It actually saves the attribute value in a file to make it sticky.
- * @param string $attribute the attribute to be validated
- * @param array $params the validation parameters
- */
- public function sticky($attribute,$params)
- {
- if(!$this->hasErrors())
- $this->_stickyAttributes[$attribute]=$this->$attribute;
- }
- /**
- * Loads sticky attributes from a file and populates them into the model.
- */
- public function loadStickyAttributes()
- {
- $this->_stickyAttributes=array();
- $path=$this->getStickyFile();
- if(is_file($path))
- {
- $result=@include($path);
- if(is_array($result))
- {
- $this->_stickyAttributes=$result;
- foreach($this->_stickyAttributes as $name=>$value)
- {
- if(property_exists($this,$name) || $this->canSetProperty($name))
- $this->$name=$value;
- }
- }
- }
- }
- /**
- * Saves sticky attributes into a file.
- */
- public function saveStickyAttributes()
- {
- $path=$this->getStickyFile();
- @mkdir(dirname($path),0755,true);
- file_put_contents($path,"<?php\nreturn ".var_export($this->_stickyAttributes,true).";\n");
- }
- /**
- * @return string the file path that stores the sticky attribute values.
- */
- public function getStickyFile()
- {
- return Yii::app()->runtimePath.'/gii-'.Yii::getVersion().'/'.get_class($this).'.php';
- }
- /**
- * Converts a word to its plural form.
- * Note that this is for English only!
- * For example, 'apple' will become 'apples', and 'child' will become 'children'.
- * @param string $name the word to be pluralized
- * @return string the pluralized word
- */
- public function pluralize($name)
- {
- $rules=array(
- '/(m)ove$/i' => '\1oves',
- '/(f)oot$/i' => '\1eet',
- '/(c)hild$/i' => '\1hildren',
- '/(h)uman$/i' => '\1umans',
- '/(m)an$/i' => '\1en',
- '/(s)taff$/i' => '\1taff',
- '/(t)ooth$/i' => '\1eeth',
- '/(p)erson$/i' => '\1eople',
- '/([m|l])ouse$/i' => '\1ice',
- '/(x|ch|ss|sh|us|as|is|os)$/i' => '\1es',
- '/([^aeiouy]|qu)y$/i' => '\1ies',
- '/(?:([^f])fe|([lr])f)$/i' => '\1\2ves',
- '/(shea|lea|loa|thie)f$/i' => '\1ves',
- '/([ti])um$/i' => '\1a',
- '/(tomat|potat|ech|her|vet)o$/i' => '\1oes',
- '/(bu)s$/i' => '\1ses',
- '/(ax|test)is$/i' => '\1es',
- '/s$/' => 's',
- );
- foreach($rules as $rule=>$replacement)
- {
- if(preg_match($rule,$name))
- return preg_replace($rule,$replacement,$name);
- }
- return $name.'s';
- }
- /**
- * Converts a class name into a HTML ID.
- * For example, 'PostTag' will be converted as 'post-tag'.
- * @param string $name the string to be converted
- * @return string the resulting ID
- */
- public function class2id($name)
- {
- return trim(strtolower(str_replace('_','-',preg_replace('/(?<![A-Z])[A-Z]/', '-\0', $name))),'-');
- }
- /**
- * Converts a class name into space-separated words.
- * For example, 'PostTag' will be converted as 'Post Tag'.
- * @param string $name the string to be converted
- * @param boolean $ucwords whether to capitalize the first letter in each word
- * @return string the resulting words
- */
- public function class2name($name,$ucwords=true)
- {
- $result=trim(strtolower(str_replace('_',' ',preg_replace('/(?<![A-Z])[A-Z]/', ' \0', $name))));
- return $ucwords ? ucwords($result) : $result;
- }
- /**
- * Converts a class name into a variable name with the first letter in lower case.
- * This method is provided because lcfirst() PHP function is only available for PHP 5.3+.
- * @param string $name the class name
- * @return string the variable name converted from the class name
- * @since 1.1.4
- */
- public function class2var($name)
- {
- $name[0]=strtolower($name[0]);
- return $name;
- }
- /**
- * Validates an attribute to make sure it is not taking a PHP reserved keyword.
- * @param string $attribute the attribute to be validated
- * @param array $params validation parameters
- */
- public function validateReservedWord($attribute,$params)
- {
- $value=$this->$attribute;
- if(in_array(strtolower($value),self::$keywords))
- $this->addError($attribute, $this->getAttributeLabel($attribute).' cannot take a reserved PHP keyword.');
- }
- }
|