<?php /** * GiixCrudCode class file. * * @author Rodrigo Coelho <rodrigo@giix.org> * @link http://giix.org/ * @copyright Copyright © 2010-2011 Rodrigo Coelho * @license http://giix.org/license/ New BSD License */ Yii::import('system.gii.generators.crud.CrudCode'); Yii::import('ext.giix-core.helpers.*'); /** * GiixCrudCode is the model for giix crud generator. * * @author Rodrigo Coelho <rodrigo@giix.org> */ class GiixCrudCode extends CrudCode { /** * @var string The type of authentication. */ public $authtype = 'auth_none'; /** * @var int Specifies if ajax validation is enabled. 0 represents false, 1 represents true. */ public $enable_ajax_validation = 0; /** * @var string The controller base class name. */ public $baseControllerClass = 'GxController'; /** * Adds the new model attributes (class properties) to the rules. * #MethodTracker * This method overrides {@link CrudCode::rules}, from version 1.1.7 (r3135). Changes: * <ul> * <li>Adds the rules for the new attributes in the code generation form: authtype; enable_ajax_validation.</li> * </ul> */ public function rules() { return array_merge(parent::rules(), array( array('authtype, enable_ajax_validation', 'required'), )); } /** * Sets the labels for the new model attributes (class properties). * #MethodTracker * This method overrides {@link CrudCode::attributeLabels}, from version 1.1.7 (r3135). Changes: * <ul> * <li>Adds the labels for the new attributes in the code generation form: authtype; enable_ajax_validation.</li> * </ul> */ public function attributeLabels() { return array_merge(parent::attributeLabels(), array( 'authtype' => 'Authentication type', 'enable_ajax_validation' => 'Enable ajax validation', )); } /** * Generates and returns the view source code line * to create the appropriate active input field based on * the model attribute field type on the database. * #MethodTracker * This method is based on {@link CrudCode::generateActiveField}, from version 1.1.7 (r3135). Changes: * <ul> * <li>All styling is removed.</li> * </ul> * @param string $modelClass The model class name. * @param CDbColumnSchema $column The column. * @return string The source code line for the active field. */ public function generateActiveField($modelClass, $column) { if ($column->isForeignKey) { $relation = $this->findRelation($modelClass, $column); $relatedModelClass = $relation[3]; return "echo \$form->dropDownList(\$model, '{$column->name}', GxHtml::listDataEx({$relatedModelClass}::model()->findAllAttributes(null, true)))"; } if (strtoupper($column->dbType) == 'TINYINT(1)' || strtoupper($column->dbType) == 'BIT' || strtoupper($column->dbType) == 'BOOL' || strtoupper($column->dbType) == 'BOOLEAN') { return "echo \$form->checkBox(\$model, '{$column->name}')"; } else if (strtoupper($column->dbType) == 'DATE') { return "\$form->widget('zii.widgets.jui.CJuiDatePicker', array( 'model' => \$model, 'attribute' => '{$column->name}', 'value' => \$model->{$column->name}, 'options' => array( 'showButtonPanel' => true, 'changeYear' => true, 'dateFormat' => 'yy-mm-dd', ), ));\n"; } else if (stripos($column->dbType, 'text') !== false) { // Start of CrudCode::generateActiveField code. return "echo \$form->textArea(\$model, '{$column->name}')"; } else { $passwordI18n = Yii::t('app', 'password'); $passwordI18n = (isset($passwordI18n) && $passwordI18n !== '') ? '|' . $passwordI18n : ''; $pattern = '/^(password|pass|passwd|passcode' . $passwordI18n . ')$/i'; if (preg_match($pattern, $column->name)) $inputField = 'passwordField'; else $inputField='textField'; if ($column->type !== 'string' || $column->size === null) return "echo \$form->{$inputField}(\$model, '{$column->name}')"; else return "echo \$form->{$inputField}(\$model, '{$column->name}', array('maxlength' => {$column->size}))"; } // End of CrudCode::generateActiveField code. } /** * Generates and returns the view source code line * to create the appropriate active input field based on * the model relation. * @param string $modelClass The model class name. * @param array $relation The relation details in the same format * used by {@link getRelations}. * @return string The source code line for the relation field. * @throws InvalidArgumentException If the relation type is not HAS_ONE, HAS_MANY or MANY_MANY. */ public function generateActiveRelationField($modelClass, $relation) { $relationName = $relation[0]; $relationType = $relation[1]; $relationField = $relation[2]; // The FK. $relationModel = $relation[3]; // The relation type must be HAS_ONE, HAS_MANY or MANY_MANY. // Other types (BELONGS_TO) should be generated by generateActiveField. if ($relationType != GxActiveRecord::HAS_ONE && $relationType != GxActiveRecord::HAS_MANY && $relationType != GxActiveRecord::MANY_MANY) throw new InvalidArgumentException(Yii::t('giix', 'The argument "relationName" must have a relation type of HAS_ONE, HAS_MANY or MANY_MANY.')); // Generate the field according to the relation type. switch ($relationType) { case GxActiveRecord::HAS_ONE: return "echo \$form->dropDownList(\$model, '{$relationName}', GxHtml::listDataEx({$relationModel}::model()->findAllAttributes(null, true)))"; break; case GxActiveRecord::HAS_MANY: case GxActiveRecord::MANY_MANY: return "echo \$form->checkBoxList(\$model, '{$relationName}', GxHtml::encodeEx(GxHtml::listDataEx({$relationModel}::model()->findAllAttributes(null, true)), false, true))"; break; } } public function generateInputField($modelClass, $column) { return 'echo ' . parent::generateInputField($modelClass, $column); } /** * Generates and returns the view source code line * to create the appropriate attribute configuration for a CDetailView. * @param string $modelClass The model class name. * @param CDbColumnSchema $column The column. * @return string The source code line for the attribute. */ public function generateDetailViewAttribute($modelClass, $column) { if (!$column->isForeignKey) { if (strtoupper($column->dbType) == 'TINYINT(1)' || strtoupper($column->dbType) == 'BIT' || strtoupper($column->dbType) == 'BOOL' || strtoupper($column->dbType) == 'BOOLEAN') { return "'{$column->name}:boolean'"; } else return "'{$column->name}'"; } else { // Find the relation name for this column. $relation = $this->findRelation($modelClass, $column); $relationName = $relation[0]; $relatedModelClass = $relation[3]; $relatedControllerName = strtolower($relatedModelClass[0]) . substr($relatedModelClass, 1); return "array( 'name' => '{$relationName}', 'type' => 'raw', 'value' => \$model->{$relationName} !== null ? GxHtml::link(GxHtml::encode(GxHtml::valueEx(\$model->{$relationName})), array('{$relatedControllerName}/view', 'id' => GxActiveRecord::extractPkValue(\$model->{$relationName}, true))) : null, )"; } } /** * Generates and returns the view source code line * to create the CGridView column definition. * @param string $modelClass The model class name. * @param CDbColumnSchema $column The column. * @return string The source code line for the column definition. */ public function generateGridViewColumn($modelClass, $column) { if (!$column->isForeignKey) { // Boolean or bit. if (strtoupper($column->dbType) == 'TINYINT(1)' || strtoupper($column->dbType) == 'BIT' || strtoupper($column->dbType) == 'BOOL' || strtoupper($column->dbType) == 'BOOLEAN') { return "array( 'name' => '{$column->name}', 'value' => '(\$data->{$column->name} === 0) ? Yii::t(\\'app\\', \\'No\\') : Yii::t(\\'app\\', \\'Yes\\')', 'filter' => array('0' => Yii::t('app', 'No'), '1' => Yii::t('app', 'Yes')), )"; } else // Common column. return "'{$column->name}'"; } else { // FK. // Find the related model for this column. $relation = $this->findRelation($modelClass, $column); $relationName = $relation[0]; $relatedModelClass = $relation[3]; return "array( 'name'=>'{$column->name}', 'value'=>'GxHtml::valueEx(\$data->{$relationName})', 'filter'=>GxHtml::listDataEx({$relatedModelClass}::model()->findAllAttributes(null, true)), )"; } } /** * Generates and returns the view source code line * to create the advanced search. * @param string $modelClass The model class name. * @param CDbColumnSchema $column The column. * @return string The source code line for the column definition. */ public function generateSearchField($modelClass, $column) { if (!$column->isForeignKey) { // Boolean or bit. if (strtoupper($column->dbType) == 'TINYINT(1)' || strtoupper($column->dbType) == 'BIT' || strtoupper($column->dbType) == 'BOOL' || strtoupper($column->dbType) == 'BOOLEAN') return "echo \$form->dropDownList(\$model, '{$column->name}', array('0' => Yii::t('app', 'No'), '1' => Yii::t('app', 'Yes')), array('prompt' => Yii::t('app', 'All')))"; else // Common column. generateActiveField method will add 'echo' when necessary. return $this->generateActiveField($this->modelClass, $column); } else { // FK. // Find the related model for this column. $relation = $this->findRelation($modelClass, $column); $relatedModelClass = $relation[3]; return "echo \$form->dropDownList(\$model, '{$column->name}', GxHtml::listDataEx({$relatedModelClass}::model()->findAllAttributes(null, true)), array('prompt' => Yii::t('app', 'All')))"; } } /** * Generates and returns the array (as a PHP source code string) * to collect the MANY_MANY related data from the POST. * @param string $modelClass The model class name. * @return string The source code to collect the MANY_MANY related * data from the POST. */ public function generateGetPostRelatedData($modelClass, $indent = 1) { $result = array(); $relations = $this->getRelations($modelClass); foreach ($relations as $relationData) { $relationName = $relationData[0]; $relationType = $relationData[1]; if ($relationType == GxActiveRecord::MANY_MANY) $result[$relationData[0]] = "php:\$_POST['{$modelClass}']['{$relationName}'] === '' ? null : \$_POST['{$modelClass}']['{$relationName}']"; } return GxCoreHelper::ArrayToPhpSource($result, $indent); } /** * Checks whether this AR has a MANY_MANY relation. * @param string $modelClass The model class name. * @return boolean Whether this AR has a MANY_MANY relation. */ public function hasManyManyRelation($modelClass) { $relations = $this->getRelations($modelClass); foreach ($relations as $relationData) { if ($relationData[1] == GxActiveRecord::MANY_MANY) { return true; } } return false; } /** * Finds the relation of the specified column. * Note: There's a similar method in the class GxActiveRecord. * @param string $modelClass The model class name. * @param CDbColumnSchema $column The column. * @return array The relation. The array will have 3 values: * 0: the relation name, * 1: the relation type (will always be GxActiveRecord::BELONGS_TO), * 2: the foreign key (will always be the specified column), * 3: the related active record class name. * Or null if no matching relation was found. */ public function findRelation($modelClass, $column) { if (!$column->isForeignKey) return null; $relations = GxActiveRecord::model($modelClass)->relations(); // Find the relation for this attribute. foreach ($relations as $relationName => $relation) { // For attributes on this model, relation must be BELONGS_TO. if ($relation[0] == GxActiveRecord::BELONGS_TO && $relation[2] == $column->name) { return array( $relationName, // the relation name $relation[0], // the relation type $relation[2], // the foreign key $relation[1] // the related active record class name ); } } // None found. return null; } /** * Returns all the relations of the specified model. * @param string $modelClass The model class name. * @return array The relations. Each array item is * a relation as an array, having 3 items: * 0: the relation name, * 1: the relation type, * 2: the foreign key, * 3: the related active record class name. * Or an empty array if no relations were found. */ public function getRelations($modelClass) { $relations = GxActiveRecord::model($modelClass)->relations(); $result = array(); foreach ($relations as $relationName => $relation) { $result[] = array( $relationName, // the relation name $relation[0], // the relation type $relation[2], // the foreign key $relation[1] // the related active record class name ); } return $result; } /** * Returns the message to be displayed when the newly generated code is saved successfully. * #MethodTracker * This method overrides {@link CrudCode::successMessage}, from version 1.1.7 (r3135). Changes: * <ul> * <li>Custom giix success message.</li> * </ul> * @return string The message to be displayed when the newly generated code is saved successfully. */ public function successMessage() { return <<<EOM <p><strong>Sweet!</strong></p> <ul style="list-style-type: none; padding-left: 0;"> <li><img src="http://giix.org/icons/love.png"> Show how you love giix on <a href="http://www.yiiframework.com/forum/index.php?/topic/13154-giix-%E2%80%94-gii-extended/">the forum</a> and on its <a href="http://www.yiiframework.com/extension/giix">extension page</a></li> <li><img src="http://giix.org/icons/vote.png"> Upvote <a href="http://www.yiiframework.com/extension/giix">giix</a></li> <li><img src="http://giix.org/icons/powered.png"> Show everybody that you are using giix in <a href="http://www.yiiframework.com/forum/index.php?/topic/19226-powered-by-giix/">Powered by giix</a></li> <li><img src="http://giix.org/icons/donate.png"> <a href="http://giix.org/">Donate</a></li> </ul> <p style="margin: 2px 0; position: relative; text-align: right; top: -15px; color: #668866;">icons by <a href="http://www.famfamfam.com/lab/icons/silk/" style="color: #668866;">famfamfam.com</a></p> EOM; } /** * #MethodTracker * This method overrides {@link CCodeModel::confirmed}, from version 1.1.13. Changes: * <ul> * <li>Support for {@link http://www.yiiframework.com/extension/giic/ giic} out-of-the-box.</li> * </ul> */ public function confirmed($file) { if (defined('GIIC_ALL_CONFIRMED') && (GIIC_ALL_CONFIRMED === true)) { return true; } else { return parent::confirmed($file); } } }