Yii framework разбор кода

от автора


Разбору кода приложения Yii Framework (исходник).

Из статьи можно вынести интересные куски кода на php, а так же тонкости и конструкции Yii Framework, расчитана она на поддержку php программистов и пользователей Yii Framework.

Поведения Behavior

Пример поведения для работы с изображениями(как мы знаем поведения прикрепляются к модели и становятся частью ее функционала):

class ImageBehavior extends CBehavior{     public $modelName = '';     const MAX_WIDTH   = 450;     const MAX_HEIGHT  = 450;      public function resize($path){          $mimeType = mime_content_type($path);          $type     = str_replace('image/','',$mimeType);          list($width, $height) = getimagesize($path);          list($newWidth, $newHeight) = $this->getNewSize($width,$height);          $thumb = imagecreatetruecolor($newWidth, $newHeight);          $createFunction = 'imagecreatefrom' . $type;         $source         = $createFunction($path);          imagecopyresized($thumb, $source, 0, 0, 0, 0, $newWidth, $newHeight, $width, $height);          $imageFunction = 'image' . $type;          ob_start();         header('Content-Type: ' . $mimeType);          $imageFunction($thumb,null,100);          $img = ob_get_contents();          @unlink($path);          @file_put_contents($path,$img);     }      public function getNewSize($width,$height){         $wK        = $width/$height;         $hK        = $height/$width;         $newWidth  = $width;         $newHeight = $height;         if($width > self::MAX_WIDTH && ($width > $height)){             $newWidth  = self::MAX_WIDTH;             $newHeight = $newWidth/$wK;         }         if($height > self::MAX_HEIGHT && ($height > $width)){             $newHeight = self::MAX_HEIGHT;             $newWidth  = $newHeight/$hK;         }         return array($newWidth,$newHeight);     }      public function columnExists($column){         $modelName   = $this->modelName;         $model       = $modelName::model();         $table       = Yii::app()->getDb()->getSchema()->getTable($model->tableName());         $columnNames = $table->getColumnNames();          return in_array($column,$columnNames);     }      protected function afterSave($event){         if(!is_null($this->image)){             if($this->columnExists('image_path')){                 $webroot   = Yii::getPathOfAlias('webroot');                 $modelName = $this->modelName;                 $dir       = strtolower('/upload/' . $modelName);                 $dirPath   = $webroot . $dir;                 $ext       = str_replace("image/","",$this->image->getType());                 $path      = $dir . '/' . $this->id . '_' . time().'.'.$ext;                  if(!file_exists($dirPath))                     mkdir($dirPath,0777);                  $this->image->saveAs($webroot . $path);                  if(!is_null($this->image_path))                     @unlink($webroot . $this->image_path);                  $this->image_path = $path;                  $this->resize($webroot . $path);                 $modelName::model()->updateByPk($this->id,array(                     'image_path' => $path                 ));             }         }     }      protected function beforeSave($event){          $this->image = CUploadedFile::getInstance($this,'image');     }      public function deleteImage(){         if($this->columnExists('image_path')){             $path     = $this->image_path;             $fullPath = Yii::getPathOfAlias('webroot') . $path;             if(file_exists($fullPath))                 @unlink($fullPath);         }     }      public function getModelName(){         return get_called_class();     }  

Давайте разберем поподробнее, в поведение вынесена часть функционала модели Yii + добавлены общие методы для работы с изображениями. У нас есть 5 моделей в которых используются изображения, для того что бы не дублировать код мы просто выносим функционал в поведение. Так же в поведении можно переопределить часть стандартных функций класса, в моем случае это beforeSave и afterSave.

Action действия

Для удобного повторго использования кода в Yii существуют Actions которые прикрепляются к контроллерам.
Во время генерации кода при помощи модуля gii. Создаются множетсво почти одинаковых контроллеров функционал которых можно вынести в отдельный класс Action.
В моем случае создается CRUDAction который наследуется от CAction, определены 2 атрибута название модели и страница редиректа на которую пользователь попадает после завершения действий CRUD(Create Read Update Delete), так же происходит загрузка модели:

<?php  class CRUDAction extends  CAction{     public $modelName;     public $redirectTo = ['index'];      public function loadModel($id){         $m = $this->modelName;         $model = $m::model()->findByPk($id);         if($model===null)             throw new CHttpException(404,'The requested page does not exist.');         return $model;     } } 

CreateAction — наследуется от CRUDAction, динамически создается модель и задается название сценария, в методе run описывается стандартные действия:

<?php Yii::import('application.components.actions.CRUDAction'); class CreateAction extends CRUDAction{      public function run(){         $model = new $this->modelName;         $model->scenario = 'create';          if(isset($_POST[$this->modelName])){             $model->attributes = $_POST[$this->modelName];             if($model->save())                 $this->getController()->redirect($this->redirectTo);         }          $renderPath = strtolower("create");         $this->getController()->render($renderPath,[             'model' => $model,         ]);     } } 

Виджет, большое количество одинакогового функционала — можно упаковать в виджет и вызывать где понадобится:

class Citywidget extends CWidget{     public $cols = 10;     public $name;     public $dialogId;     public $city_id;     public $defaultName = 'Город';      public function init(){         parent::init();     }      public function run(){          $this->render('citywidget',[             'name'        => $this->name,             'dialogId'    => $this->dialogId,             'city_id'     => $this->city_id,             'cols'        => $this->cols,             'defaultName' => $this->defaultName,         ]);     } } 

<?php     $this->beginWidget('zii.widgets.jui.CJuiDialog',array(         'id' => $dialogId,         // additional javascript options for the dialog plugin         'options'=> [             'title' => 'Города',             'autoOpen'=>false,             'width' => '800px'         ],         'htmlOptions' => [             'width' => '800px'         ]     )); ?>  <?php     $cities   = Cities::getCities();     $count    = count($cities);     $perCol   = round($count/$cols);      if($city_id == 0){         $city_id = CityChooser::$cityId;     }      $cityName = Cities::getCityNameByPk($city_id,$defaultName); ?>  <style type="text/css">     #<?=$dialogId?>{         display:none;     }     #<?=$dialogId?> ul {         float:left;         clear:right;         padding:5px;     }     #<?=$dialogId?> li {         float:left;         clear:left;     } </style> <script type="text/javascript">     function changeCity<?=$dialogId?>(id,cityName,dialogId,inName){         $("#href-"+dialogId+"").text(cityName);         $("input[name*='"+inName+"']").val(id);         $("#"+dialogId).dialog("close");          if(dialogId == 'chooserDialogId'){             $.get( "/api/setcity/id/"+id, function( data ) {              });         }         //$("#"+dialogId).dialog("close");     } </script>          <?='<ul>'?>         <?php $i=0; ?>         <?php foreach ($cities as $city):?>            <?php if($i>=$perCol):?>                 <?='</ul><ul>'?>                 <?php $i=0; ?>            <?php endif;?>                <li style="margin-top:4px;">                 <a href="#" style="margin:8px;color: #428bca;" onClick="changeCity<?=$dialogId?>('<?=$city->id?>','<?=$city->name?>','<?=$dialogId?>','<?=$name?>')">                     <?php if((int)$city->sort !== 0):?>                         <b><?=$city->name?></b>                     <?php else:?>                         <?=$city->name?>                     <?php endif;?>                 </a>               </li>              <?php if($i>=$perCol):?>                 <?='</ul>'?>             <?php endif;?>              <?php $i++; ?>         <?php endforeach;?>         <?='</ul>'?>  <?php $this->endWidget('zii.widgets.jui.CJuiDialog');?>  <input type="hidden" name="<?=$name?>" value="<?=$city_id?>">  <a href="#" id="href-<?=$dialogId?>" onclick='$("#<?=$dialogId?>").dialog("open"); return false;'><?= $cityName?></a>  

Как видите с такой смесью php и html работать неудобно, а вот так выглядит вызов виджета:

        <?php             $this->widget('Citywidget',[                 'name'        => 'Biztrade[city_id]',                 'city_id'     => $model->city_id,                 'dialogId'    => 'dialogId'             ]);         ?> 

Ис интересного наверное все, я приложил исходник — в нем вы сможете найти более стандартные вещи.Спасибо.

ссылка на оригинал статьи https://habrahabr.ru/post/280382/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *