http://www.yiiframework.ru/doc/cookbook ... .fat.model
Все раньше работало ок, добавил в бд 1 поле и поправил вюхи, контролери, модели под него.
После этого перестала работать загрузка файлов. Думал права на папку, но не так. Пока что вижу проблему
в том что не передает в пост запросе название файла и логи такие.
Позже вардампом проверил что не можна взять ($file=CUploadedFile::getInstance($this->owner,'image1')) там пустое значения, а раньше работало.
Как и было сказано в рецепте убрал валидацию на поле файла в моделе.
2013/03/29 13:00:38 [warning] [application] Не удалось присвоить небезопасный атрибут "image1" класса "Vips".
in /var/www/release/ukrburshtyn.com/protected/modules/admin/controllers/VipsController.php (102)
in /var/www/release/ukrburshtyn.com/index.php (16)
код модели:
Код: Выделить всё
<?php
/**
* This is the model class for table "vips".
*
* The followings are the available columns in table 'vips':
* @property string $index
* @property string $category
* @property string $name
* @property string $artno
* @property string $description
* @property string $url
* @property double $price
* @property string $image1
* @property string $image2
* @property string $image3
* @property string $image4
* @property string $image5
* @property string $new
* @property string $main
* @property integer $priority
* @property string $meta_title
* @property string $meta_keywords
* @property string $meta_description
* @property string $lider
* @property string $special
*/
class Vips extends CActiveRecord
{
/**
* Returns the static model of the specified AR class.
* @param string $className active record class name.
* @return Vips the static model class
*/
public $savePathAlias='webroot.media';
public $groupName='vips';
public $saveDir ='media';
public $originals ='originals';
public $sizes = array('thumb','big','tiny');
public static function model($className=__CLASS__)
{
return parent::model($className);
}
/**
* @return string the associated database table name
*/
public function tableName()
{
return 'vips';
}
/**
* @return array validation rules for model attributes.
*/
public function rules()
{
// NOTE: you should only define rules for those attributes that
// will receive user inputs.
return array(
array('price, meta_keywords, meta_description', 'required'),
array('priority', 'numerical', 'integerOnly'=>true),
array('price', 'numerical'),
array('category, new, main, lider, special', 'length', 'max'=>10),
array('meta_title, url,alt1', 'length', 'max'=>255),
array('name, artno, description, alt1', 'safe'),
// The following rule is used by search().
// Please remove those attributes that should not be searched.
array('index, category, name, artno, description, url, price, alt1, new, main, priority, meta_title, meta_keywords, meta_description, lider, special', 'safe', 'on'=>'search'),
);
}
/**
* @return array relational rules.
*/
public function relations()
{
// NOTE: you may need to adjust the relation name and the related
// class name for the relations automatically generated below.
return array(
'category' => array(self::BELONGS_TO, 'VipsCategories', 'index'),
);
}
/**
* @return array customized attribute labels (name=>label)
*/
public function attributeLabels()
{
return array(
'index' => 'Index',
'category' => 'Category',
'name' => 'Name',
'artno' => 'Artno',
'description' => 'Description',
'price' => 'Price',
'url' => 'Url',
'image1' => 'Image1',
'alt1' => 'alt1',
'image2' => 'Image2',
'image3' => 'Image3',
'image4' => 'Image4',
'image5' => 'Image5',
'new' => 'New',
'main' => 'Main',
'priority' => 'Priority',
'meta_title' => 'Meta Title',
'meta_keywords' => 'Meta Keywords',
'meta_description' => 'Meta Description',
'lider' => 'Lider',
'special' => 'Special',
);
}
/**
* Retrieves a list of models based on the current search/filter conditions.
* @return CActiveDataProvider the data provider that can return the models based on the search/filter conditions.
*/
public function search()
{
// Warning: Please modify the following code to remove attributes that
// should not be searched.
$criteria=new CDbCriteria;
$criteria->compare('index',$this->index,true);
$criteria->compare('category',$this->category,false);
$criteria->compare('name',$this->name,true);
$criteria->compare('artno',$this->artno,true);
$criteria->compare('description',$this->description,true);
$criteria->compare('price',$this->price);
$criteria->compare('url',$this->url);
$criteria->compare('image1',$this->image1,true);
$criteria->compare('alt1',$this->alt1,true);
$criteria->compare('image2',$this->image2,true);
$criteria->compare('image3',$this->image3,true);
$criteria->compare('image4',$this->image4,true);
$criteria->compare('image5',$this->image5,true);
$criteria->compare('new',$this->new,true);
$criteria->compare('main',$this->main,true);
$criteria->compare('priority',$this->priority);
$criteria->compare('meta_title',$this->meta_title,true);
$criteria->compare('meta_keywords',$this->meta_keywords,true);
$criteria->compare('meta_description',$this->meta_description,true);
$criteria->compare('lider',$this->lider,true);
$criteria->compare('special',$this->special,true);
return new CActiveDataProvider($this, array(
'criteria'=>$criteria,
));
}
public function behaviors(){
return array(
// наше поведение для работы с файлом
'uploadableFile'=>array(
'class'=>'application.modules.admin.components.UploadableFileBehavior',
'savePathAlias' => $this->savePathAlias,
'groupName' => $this->groupName,
'sizes' => $this->sizes,
'originals' => $this->originals,
// конфигурируем нужные свойства класса UploadableFileBehavior
// ...
),
);
}
}
Код: Выделить всё
<?php
class VipsController extends Controller
{
/**
* @var string the default layout for the views. Defaults to '//layouts/column2', meaning
* using two-column layout. See 'protected/views/layouts/column2.php'.
*/
public $layout='/layouts/column2';
public function filters()
{
return array(
'accessControl', // perform access control for CRUD operations
'postOnly + delete', // we only allow deletion via POST request
);
}
/**
* Specifies the access control rules.
* This method is used by the 'accessControl' filter.
* @return array access control rules
*/
public function accessRules()
{
return array(
array('allow',
'actions'=>array('*'),
'expression'=>'$user->getIsAdmin()',
),
);
}
/**
* Displays a particular model.
* @param integer $id the ID of the model to be displayed
*/
public function actionView($id)
{
$this->render('view',array(
'model'=>$this->loadModel($id),
));
}
/**
* Creates a new model.
* If creation is successful, the browser will be redirected to the 'view' page.
*/
public function actionCreate()
{
$model=new Vips;
// Uncomment the following line if AJAX validation is needed
// $this->performAjaxValidation($model);
if(isset($_POST['Vips']))
{
$model->attributes=$_POST['Vips'];
if($model->save())
$this->redirect(array('view','id'=>$model->index));
}
$this->render('create',array(
'model'=>$model,
));
}
/**
* Updates a particular model.
* If update is successful, the browser will be redirected to the 'view' page.
* @param integer $id the ID of the model to be updated
*/
public function actionUpdate($id)
{
$model=$this->loadModel($id);
// Uncomment the following line if AJAX validation is needed
// $this->performAjaxValidation($model);
if(isset($_POST['Vips']))
{
$model->attributes=$_POST['Vips'];
//var_dump($model->attributes);exit();
if($model->save())
$this->redirect(array('view','id'=>$model->index));
}
$this->render('update',array(
'model'=>$model,
));
}
/**
* Deletes a particular model.
* If deletion is successful, the browser will be redirected to the 'admin' page.
* @param integer $id the ID of the model to be deleted
*/
public function actionDelete($id)
{
$this->loadModel($id)->delete();
// if AJAX request (triggered by deletion via admin grid view), we should not redirect the browser
if(!isset($_GET['ajax']))
$this->redirect(isset($_POST['returnUrl']) ? $_POST['returnUrl'] : array('admin'));
}
/**
* Lists all models.
*/
public function actionIndex()
{
$dataProvider=new CActiveDataProvider('Vips');
$this->render('index',array(
'dataProvider'=>$dataProvider,
));
}
/**
* Manages all models.
*/
public function actionAdmin()
{
$model=new Vips('search');
$model->unsetAttributes(); // clear any default values
if(isset($_GET['Vips']))
$model->attributes=$_GET['Vips'];
$this->render('admin',array(
'model'=>$model,
));
}
/**
* Returns the data model based on the primary key given in the GET variable.
* If the data model is not found, an HTTP exception will be raised.
* @param integer the ID of the model to be loaded
*/
public function loadModel($id)
{
$model=Vips::model()->findByPk($id);
if($model===null)
throw new CHttpException(404,'The requested page does not exist.');
return $model;
}
/**
* Performs the AJAX validation.
* @param CModel the model to be validated
*/
protected function performAjaxValidation($model)
{
if(isset($_POST['ajax']) && $_POST['ajax']==='vips-form')
{
echo CActiveForm::validate($model);
Yii::app()->end();
}
}
}
Код: Выделить всё
<?php
/* @var $this VipsController */
/* @var $model Vips */
/* @var $form CActiveForm */
?>
<div class="form">
<?php $form=$this->beginWidget('CActiveForm', array(
'id'=>'vips-form',
'enableAjaxValidation'=>false,
)); ?>
<p class="note">Fields with <span class="required">*</span> are required.</p>
<?php echo $form->errorSummary($model); ?>
<div class="row">
<?php echo $form->labelEx($model,'category'); ?>
<?php // echo $form->textField($model,'category',array('size'=>10,'maxlength'=>10)); ?>
<?php echo $form->dropDownList($model,'category', CHtml::listData(VipsCategories::model()->findAll(array('order' => 'name')),'index','name'));?>
<?php echo $form->error($model,'category'); ?>
</div>
<div class="row">
<?php echo $form->labelEx($model,'price'); ?>
<?php echo $form->textField($model,'price'); ?>
<?php echo $form->error($model,'price'); ?>
</div>
<div class="row">
<?php echo $form->labelEx($model,'name'); ?>
<?php echo $form->textArea($model,'name',array('rows'=>6, 'cols'=>50)); ?>
<?php echo $form->error($model,'name'); ?>
</div>
<div class="row">
<?php echo $form->labelEx($model,'url'); ?>
<?php echo $form->textArea($model,'url',array('rows'=>6, 'cols'=>50)); ?>
<?php echo $form->error($model,'url'); ?>
</div>
<div class="row">
<?php echo $form->labelEx($model,'artno'); ?>
<?php echo $form->textArea($model,'artno',array('rows'=>6, 'cols'=>50)); ?>
<?php echo $form->error($model,'artno'); ?>
</div>
<div class="row">
<?php echo $form->labelEx($model,'priority'); ?>
<?php echo $form->textField($model,'priority'); ?>
<?php echo $form->error($model,'priority'); ?>
</div>
<div class="row">
<?php echo $form->labelEx($model,'meta_title'); ?>
<?php echo $form->textField($model,'meta_title',array('size'=>60,'maxlength'=>255)); ?>
<?php echo $form->error($model,'meta_title'); ?>
</div>
<div class="row">
<?php echo $form->labelEx($model,'meta_keywords'); ?>
<?php echo $form->textArea($model,'meta_keywords',array('rows'=>6, 'cols'=>50)); ?>
<?php echo $form->error($model,'meta_keywords'); ?>
</div>
<div class="row">
<?php echo $form->labelEx($model,'meta_description'); ?>
<?php echo $form->textArea($model,'meta_description',array('rows'=>6, 'cols'=>50)); ?>
<?php echo $form->error($model,'meta_description'); ?>
</div>
<div class="row">
<?php echo $form->labelEx($model,'new'); ?>
<?php echo $form->checkBox($model,'new', array('value'=>1, 'uncheckValue'=>0)); ?>
<?php echo $form->error($model,'new'); ?>
</div>
<div class="row">
<?php echo $form->labelEx($model,'main'); ?>
<?php echo $form->checkBox($model,'main', array('value'=>1, 'uncheckValue'=>0)); ?>
<?php echo $form->error($model,'main'); ?>
</div>
<div class="row">
<?php echo $form->labelEx($model,'lider'); ?>
<?php echo $form->checkBox($model,'lider', array('value'=>1, 'uncheckValue'=>0)); ?>
<?php echo $form->error($model,'lider'); ?>
</div>
<div class="row">
<?php echo $form->labelEx($model,'special'); ?>
<?php echo $form->checkBox($model,'special', array('value'=>1, 'uncheckValue'=>0)); ?>
<?php echo $form->error($model,'special'); ?>
</div>
<div class="row">
<?php echo $form->labelEx($model,'description'); ?>
<?php echo $form->textArea($model,'description',array('rows'=>6, 'cols'=>50,'class'=>'tinymce ')); ?>
<?php echo $form->error($model,'description'); ?>
</div>
<div class="field">
<?php if($model->image1): ?>
<?php endif; ?>
<?php echo $form->labelEx($model,'image1'); ?>
<?php echo $form->fileField($model,'image1'); ?>
<?php echo $form->error($model,'image1'); ?>
</div>
<div class="row">
<?php echo $form->labelEx($model,'alt1'); ?>
<?php echo $form->textField($model,'alt1',array('size'=>60,'maxlength'=>255)); ?>
<?php echo $form->error($model,'alt1'); ?>
</div>
<div class="field">
<?php if($model->image2): ?>
<?php endif; ?>
<?php echo $form->labelEx($model,'image2'); ?>
<?php echo $form->fileField($model,'image2'); ?>
<?php echo $form->error($model,'image2'); ?>
</div>
<div class="field">
<?php if($model->image3): ?>
<?php endif; ?>
<?php echo $form->labelEx($model,'image3'); ?>
<?php echo $form->fileField($model,'image3'); ?>
<?php echo $form->error($model,'image3'); ?>
</div>
<div class="field">
<?php if($model->image4): ?>
<?php endif; ?>
<?php echo $form->labelEx($model,'image4'); ?>
<?php echo $form->fileField($model,'image4'); ?>
<?php echo $form->error($model,'image4'); ?>
</div>
<div class="field">
<?php if($model->image5): ?>
<?php endif; ?>
<?php echo $form->labelEx($model,'image5'); ?>
<?php echo $form->fileField($model,'image5'); ?>
<?php echo $form->error($model,'image5'); ?>
</div>
<div class="form-actions">
<?php $this->widget('bootstrap.widgets.TbButton', array('buttonType'=>'submit', 'type'=>'primary', 'label'=>$model->isNewRecord ? 'Create' : 'Save')); ?>
<?php $this->widget('bootstrap.widgets.TbButton', array('buttonType'=>'reset', 'label'=>'Reset')); ?>
</div>
<?php $this->endWidget(); ?>
</div><!-- form -->
Код: Выделить всё
<?php
/**
* @property string $savePath путь к директории, в которой сохраняем файлы
*/
class UploadableFileBehavior extends CActiveRecordBehavior{
/**
* @var string название атрибута, хранящего в себе имя файла и файл
*/
public $attributesName=array('image1','image2','image3','image4','image5');
/**
* @var string алиас директории, куда будем сохранять файлы
*/
public $savePathAlias='webroot.media';
/**
* @var array сценарии валидации к которым будут добавлены правила валидации
* загрузки файлов
*/
public $scenarios=array('insert','update');
/**
* @var string типы файлов, которые можно загружать (нужно для валидации)
*/
public $fileTypes='png,gif,jpg,jpeg';
public $groupName='';
public $sizes = array('thumb');
public $originals='';
/**
* Шорткат для Yii::getPathOfAlias($this->savePathAlias).DIRECTORY_SEPARATOR.
* Возвращает путь к директории, в которой будут сохраняться файлы.
* @return string путь к директории, в которой сохраняем файлы
*/
public function getSavePath(){
return Yii::getPathOfAlias($this->savePathAlias).DIRECTORY_SEPARATOR;
}
public function attach($owner){
parent::attach($owner);
if(in_array($owner->scenario,$this->scenarios)){
// добавляем валидатор файла
foreach($this->attributesName as $key => $value){
$fileValidator=CValidator::createValidator('file',$owner,$value,
array('types'=>$this->fileTypes,'allowEmpty'=>true));
$owner->validatorList->add($fileValidator);
}
}
}
public function beforeSave($event){
foreach($this->attributesName as $key => $value){
if(in_array($this->owner->scenario,$this->scenarios) &&
($file=CUploadedFile::getInstance($this->owner,'image1'))){
$this->deleteFile(); // старый файл удалим, потому что загружаем новый
$this->owner->setAttribute($value,$file->name);
//var_dump($this->getSavePath().$this->groupName.DIRECTORY_SEPARATOR.$this->originals.DIRECTORY_SEPARATOR.$file->name);exit();
$file->saveAs($this->getSavePath().$this->groupName.DIRECTORY_SEPARATOR.$this->originals.DIRECTORY_SEPARATOR.$file->name);
}
}
return true;
}
public function beforeDelete($event){
$this->deleteFile(); // удалили модель? удаляем и файл, связанный с ней
}
public function deleteFile(){
foreach($this->attributesName as $key => $value){
$filePath=$this->savePath.$this->owner->getAttribute($value);
}
if(@is_file($filePath))
@unlink($filePath);
}
}