Yii расширяем CHtml для работы с текстовыми полями

в 10:39, , рубрики: yii, метки:

Всем привет. Сейчас занимаюсь написанием очередного проекта на Yii и хотел бы поделиться кое-какими наработками. В этой статье я хотел бы описать, каким образом можно расширять функциональность фреймворка с помощью наследования классов CHtml, CActiveForm. Тут нет ничего сложного и инновационного, я просто хотел бы поделиться этим. Моя задача состояла в том, чтобы создать 2 элемента:

  • Текст, который при нажатии превращается в input
  • Блок, имеющий определенную ширину, в который может не поместиться весь необходимый текст, но при наведении появляется подсказка

Вот пример результата работы следующего кода (код после хабраката):

image

<?php $form=$this->beginWidget('MActiveForm', array(
'id'=>'personal-form',
'enableAjaxValidation'=>false,
)); 
 
?>
<?php echo $form->errorSummary($model); ?>
 
    <div class="row">
<?php echo $form->labelEx($model,'gender'); ?>
<?php echo $form->labelField($model,'gender'); ?>
<?php echo $form->error($model,'gender'); ?>
</div>
 
    <div class="row">
<?php echo $form->labelEx($model,'firstname'); ?>
<?php echo $form->labelField($model,'firstname'); ?>
<?php echo $form->error($model,'firstname'); ?>
</div>
 
    <div class="row">
<?php echo $form->labelEx($model,'secondname'); ?>
<?php echo $form->labelField($model,'secondname'); ?>
<?php echo $form->error($model,'secondname'); ?>
</div>
 
    <div class="row">
<?php echo $form->labelEx($model,'lastname'); ?>
<?php echo $form->labelField($model,'lastname'); ?>
<?php echo $form->error($model,'lastname'); ?>
</div>           
<? $this->endWidget(); ?>
 

Когда я писал первую форму, я сообразил, что в yii использую стандартный виджет CActiveForm и было бы неплохо продолжать его использовать. В конце концов теперь я могу выводить поля формы таким образом (только виджет MActiveForm):

<?php echo $form->labelField($model,'secondname'); ?>

На деле CActiveForm является лишь зеркалом для методов типа activeTextField класса CHtml, поэтому пришлось расширить класс CHtml
и добавить в него функцию activeLabelField (назовем наш пользовательский элемент управления labelField)

<?php
 
class MHtml extends CHtml
{
    static $msPublished = false; // зерегистрированы ли необходимые файлы css и js
 
    protected static function registerMHtmlAsset()
    {
        if(!MHtml::$msPublished)
        {          
            $path = Yii::app()->getAssetManager()->publish(Yii::getPathOfAlias('application.components.assets.mhtml'), false, -1, true); // последний параметр рекомендуется поставить в false, потому что из-за этого наши файлы всё время заново копируются в папку asset (это удобно для отладки)
            Yii::app()->getClientScript()->registerScriptFile($path.'/mhtml.js', CClientScript::POS_END);
            Yii::app()->getClientScript()->registerCssFile($path.'/mhtml.css');
            MHtml::$msPublished = true;
        }
    }
    public static function addClass($class, $htmlOptions = array())
    {
        if(isset($htmlOptions["class"]))
            $htmlOptions["class"] .= " ".$class;
        else $htmlOptions["class"] = $class;
 
        return $htmlOptions;
    }
    public static function labelField($name, $value = '', $htmlOptions = array())
    {       
        MHtml::registerMHtmlAsset();
        return MHtml::textField($name, $value, MHtml::addClass("labelInput", $htmlOptions));
    }
 
    public static function activeLabelField($model,$attribute,$htmlOptions=array())
{
    MHtml::registerMHtmlAsset();
self::resolveNameID($model,$attribute,$htmlOptions);
self::clientChange('change',$htmlOptions);
return self::activeInputField('text',$model,$attribute, MHtml::addClass("labelInput", $htmlOptions));
}
 
    public static function textHint($text, $htmlOptions = array())
    {
        MHtml::registerMHtmlAsset();
 
        return MHtml::tag('div', MHtml::addClass("textHint_mh", $htmlOptions), $text);
    }
}
?>

Немного поясню. Для создания текста со всплывающей подсказкой мы просто создаем div с классом textHint_mh.

А для создания текста, который при клике превращается в текстовое поле, мы создаем input поле с классом labelInput, который после загрузки javascript кода будет спрятан и вместо него будет показан div с классом textHint_mh.

Вот такая вот запутанная ерунда. Теперь нам необходимо расширить класс CActiveForm:

<?php
 
class MActiveForm extends CActiveForm
{
    public function labelField($model,$attribute,$htmlOptions=array())
{
return MHtml::activeLabelField($model,$attribute,$htmlOptions);
}
}

Пару строк. И далее в дело вступают js и css. Все работает, все просто. Надеюсь, кому-то пригодиться

Исходный код тут

Автор: shedy

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js