Разбор кода приложения написанного на 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'
]);
?>
Из интересного наверное все, я приложил исходник — в нем вы сможете найти более стандартные вещи.Спасибо.