Pull to refresh

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

Reading time5 min
Views6.5K
Разбор кода приложения написанного на php c применением 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);
    }

    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 контроллеров в которых используются изображения, для того что бы не дублировать код, мы просто выносим функционал в поведение. Так же в поведении можно переопределить часть стандартных функций класса.

Action действия


Для удобного повторго использования кода в Yii существуют Actions которые прикрепляются к контроллерам.
Во время генерации кода при помощи модуля gii, cоздаются множетсво почти одинаковых контроллеров функционал которых можно вынести в отдельный класс 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'
            ]);
        ?>

Из интересного наверное все, я приложил исходник — в нем вы сможете найти более стандартные вещи.Спасибо.
Tags:
Hubs:
-1
Comments64

Articles