Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Yii: model attribute's comments/hints

Tags:

yii

I need to have comments/hints for some fields in my Form. My idea is to describe it in model, just like attributeLabels. How can I do it?

And then it would be ideal, if the Gii Model (and Crud) generator would take it directly from mysql column's comment

like image 785
zuups Avatar asked Sep 07 '12 14:09

zuups


2 Answers

So I see two questions here:

  1. Describe hints in the model and display on the form.
  2. Get hints from mysql comment

Displaying Hints from Model

Here's a slightly modified version of the default login.php file generated by Yiic

<div class="form">
<?php $form=$this->beginWidget('CActiveForm', array(
    'id'=>'login-form',
    'enableClientValidation'=>true,
    'clientOptions'=>array(
        'validateOnSubmit'=>true,
    ),
)); ?>

    <p class="note">Fields with <span class="required">*</span> are required.</p>

    <div class="row">
        <?php echo $form->labelEx($model,'username'); ?>
        <?php echo $form->textField($model,'username'); ?>
        <?php echo $form->error($model,'username'); ?>
    </div>

    <div class="row">
        <?php echo $form->labelEx($model,'password'); ?>
        <?php echo $form->passwordField($model,'password'); ?>
        <?php echo $form->error($model,'password'); ?>
        <p class="hint">
            Hint: You may login with <kbd>demo</kbd>/<kbd>demo</kbd> or <kbd>admin</kbd>/<kbd>admin</kbd>.
        </p>
    </div>

    <div class="row rememberMe">
        <?php echo $form->checkBox($model,'rememberMe'); ?>
        <?php echo $form->label($model,'rememberMe'); ?>
        <?php echo $form->error($model,'rememberMe'); ?>
    </div>

    <div class="row buttons">
        <?php echo CHtml::submitButton('Login'); ?>
    </div>

<?php $this->endWidget(); ?>
</div><!-- form -->

Let's move that password hint into the model by adding a attributeHints() method and a getHint() method to the LoginForm.php model.

    /**
     * Declares attribute hints.
     */
    public function attributeHints()
    {
        return array(
                'password'=>'Hint: You may login with <kbd>demo</kbd>/<kbd>demo</kbd> or <kbd>admin</kbd>/<kbd>admin</kbd>.',
        );
    }

    /**
     * Return a hint
     */
    public function getHint( $attribute )
    {
        $hints = $this->attributeHints();

        return $hints[$attribute];
    }

As you can see, we;ve moved the hint text from the view into the model and added a way to access it.

Now, back in login.php, let's add the hint tag based on data from the model.

<div class="row">
    <?php echo $form->labelEx($model,'password'); ?>
    <?php echo $form->passwordField($model,'password'); ?>
    <?php echo $form->error($model,'password'); ?>
    <?php echo CHtml::tag('p', array('class'=>'hint'), $model->getHint('password')); ?>
</div>

So now we've changed the hardcoded hint into a generated element populated with data from the model.

Now, moving on to the second question.

Getting hints from mySQL comments

Unforunately, I am not fammiliar enough with Gii to know how to automatically generate the hints from mySQL comments. However, getting the mySQL comment data into the model is fairly easy.

To do this we can use the following mySQL query

SHOW FULL COLUMNS FROM `tbl_user`

So let's add the comment to the password field

ALTER TABLE  `tbl_user` 
CHANGE  `password`  `password` VARCHAR( 256 ) 
CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL 
COMMENT  'Hint: You may login with <kbd>demo</kbd>/<kbd>demo</kbd> or <kbd>admin</kbd>/<kbd>admin</kbd>.';

And let's add the code to fetch it into our attributeHints() method.

    /**
     * Declares attribute hints.
     */
    public function attributeHints()
    {
        $columns= Yii::app()->db->createCommand('SHOW FULL COLUMNS FROM `tbl_user`')->queryAll();

        $comments=array();
        foreach($columns as $column){
            if( isset( $column['Comment'] ) )
            {
                $comments[ $column['Field'] ] = $column['Comment'];
            }

        }

        //Add any hardcoded hints here
        $hints = array(
                'username'=>'Enter username above',
        );

        //Return merged array
        return array_merge( $comments, $hints );
    }

We now have two ways to set comments, through mySQL comments or through hard coded statements.

Let's update our login.php file quick to include hints of both types.

<div class="row">
    <?php echo $form->labelEx($model,'username'); ?>
    <?php echo $form->textField($model,'username'); ?>
    <?php echo $form->error($model,'username'); ?>
    <?php echo CHtml::tag('p', array('class'=>'hint'), $model->getHint('username')); ?>
</div>

<div class="row">
    <?php echo $form->labelEx($model,'password'); ?>
    <?php echo $form->passwordField($model,'password'); ?>
    <?php echo $form->error($model,'password'); ?>
    <?php echo CHtml::tag('p', array('class'=>'hint'), $model->getHint('password')); ?>
</div>

And that's it!

Login page

Now our login page will look like this, with a username hint from the model and a password hint from the mySQL comment.

like image 138
Ross Avatar answered Nov 25 '22 14:11

Ross


As of Yii-1.1.13, a new attribute, comment, has been added to CMysqlColumnSchema which is defined in parent CDbColumnSchema:

comment of this column. Default value is empty string which means that no comment has been set for the column. Null value means that RDBMS does not support column comments at all (SQLite) or comment retrieval for the active RDBMS is not yet supported by the framework.

So we can use it to access the comment. Somewhat like this:

$modelObject->tableSchema->columns['column_name']->comment

// or if you are doing this within your model use
$this->tableSchema->columns['column_name']->comment

Note that the tableSchema is already set when any CActiveRecord model is constructed or even if the static model is used, so there are no new queries executed when we access the property.


A sample implementation within your model:

class MyModel extends CActiveRecord {
    // hints array will store the hints
    public $hints=array();

    public function init() {
        parent::init();
        $this->hints=self::initHints($this);
    }

    public static function initHints($model) {
        $comments=array();
        foreach ($model->tableSchema->columns as $aColumn){
            if(!empty($aColumn->comment))
                $comments["$aColumn->name"]=$aColumn->comment; 
        }
        return $comments;
    }

    public static function model($className=__CLASS__) {
        $model=parent::model($className);
        $model->hints=self::initHints($model);
        return $model;
    }

}

Now you can access hints as:

$model = new MyModel;
$single_column_hint=$model->hints['column_name'];

$model = MyModel::model();
$single_column_hint=$model->hints['column_name'];

For doing this through gii templates, you just need to copy the above code to your custom model code template, read the guide to see how this can be done.

I would recommend having the code in a custom base class, from which you can derive your active records.

like image 45
bool.dev Avatar answered Nov 25 '22 13:11

bool.dev