Как загрузить файл

Общие вопросы по использованию фреймворка. Если не знаете как что-то сделать и это про Yii, вам сюда.
Ответить
Аватара пользователя
des1roer
Сообщения: 391
Зарегистрирован: 2015.02.06, 17:03
Контактная информация:

Как загрузить файл

Сообщение des1roer »

взял за основу инструкцию с толстой моделью http://yiiframework.ru/doc/cookbook/ru/ ... .fat.model
но вот косяк - при обновлении другого поля (не с картинкой) ссыль на картинку удаляется. понятно что $_POST['Item']['document'] приходит пустой, но что из-за этого затирать существущее? как победить?

D:\open\OpenServer\domains\localhost\mining\protected\modules\product\models\Item.php

Код: Выделить всё

<?php

/**
 * This is the model class for table "tbl_item".
 *
 * The followings are the available columns in table 'tbl_item':
 * @property integer $id
 * @property string $title
 * @property string $document
 */
class Item extends CActiveRecord
    {

    /**
     * @return string the associated database table name
     */
    public function tableName()
    {
        return 'tbl_item';
    }

    /**
     * @return array validation rules for model attributes.
     */
    public function rules()
    {
        return array(
            array('title', 'required', 'on' => 'insert,update'),
            array('document', 'file', 'types' => 'doc,docx,xls,xlsx,odt,pdf',
                'allowEmpty' => true, 'on' => 'insert,update'),
           // array('document', 'unsafe'),
        );
    }

    /**
     * @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(
        );
    }

    /**
     * @return array customized attribute labels (name=>label)
     */
    public function attributeLabels()
    {
        return array(
            'id' => 'ID',
            'title' => 'Title',
            'document' => 'Document',
        );
    }

    /**
     * Retrieves a list of models based on the current search/filter conditions.
     *
     * Typical usecase:
     * - Initialize the model fields with values from filter form.
     * - Execute this method to get CActiveDataProvider instance which will filter
     * models according to data in model fields.
     * - Pass data provider to CGridView, CListView or any similar widget.
     *
     * @return CActiveDataProvider the data provider that can return the models
     * based on the search/filter conditions.
     */
    public function search()
    {
        // @todo Please modify the following code to remove attributes that should not be searched.

        $criteria = new CDbCriteria;

        $criteria->compare('id', $this->id);
        $criteria->compare('title', $this->title, true);
        $criteria->compare('document', $this->document, true);

        return new CActiveDataProvider($this, array(
            'criteria' => $criteria,
        ));
    }

    /**
     * Returns the static model of the specified AR class.
     * Please note that you should have this exact method in all your CActiveRecord descendants!
     * @param string $className active record class name.
     * @return Item the static model class
     */
    public static function model($className = __CLASS__)
    {
        return parent::model($className);
    }

    public function beforeSave()
    {
        if (!parent::beforeSave())
            return false;
     //   echo '<pre>';
      //  var_dump(CUploadedFile::getInstance($this, 'document'));
      //if (!is_null(CUploadedFile::getInstance($this, 'document') ))
    //   {
            if (($this->scenario == 'insert' || $this->scenario == 'update') &&
                    ($document = CUploadedFile::getInstance($this, 'document')))
            
            {
                $this->deleteDocument(); // старый документ удалим, потому что загружаем новый

                $this->document = $document;
                $this->document->saveAs(
                        Yii::getPathOfAlias('webroot.media') . DIRECTORY_SEPARATOR . $this->document);
        //    }
       }
        return true;
    }

    protected function beforeDelete()
    {
        if (!parent::beforeDelete())
            return false;
        $this->deleteDocument(); // удалили модель? удаляем и файл
        return true;
    }

    public function deleteDocument()
    {
        $documentPath = Yii::getPathOfAlias('webroot.media') . DIRECTORY_SEPARATOR .
                $this->document;
        if (is_file($documentPath))
            unlink($documentPath);
    }

    public function afterFind()
    {

        parent::afterFind();
    }

    public function defaultScope()
    {
        /*
          //Example Scope
          return array(
          'condition'=>"deleted IS NULL ",
          'order'=>'create_time DESC',
          'limit'=>5,
          );
         */
        $scope = array();


        return $scope;
    }

    } 

D:\open\OpenServer\domains\localhost\mining\protected\modules\product\controllers\ItemController.php

Код: Выделить всё

<?php

class ItemController 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';

    /**
     * @return array action filters
     */
    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', // allow all users to perform 'index' and 'view' actions
                'actions' => array('index', 'view', 'getfile'),
                'users' => array('*'),
            ),
            array('allow', // allow authenticated user to perform 'create' and 'update' actions
                'actions' => array('create', 'update'),
                'users' => array('@'),
            ),
            array('allow', // allow admin user to perform 'admin' and 'delete' actions
                'actions' => array('admin', 'delete', 'export', 'import', 'editable', 'toggle',),
                'users' => array('admin'),
            ),
            array('deny', // deny all users
                'users' => array('*'),
            ),
        );
    }

    /**
     * Displays a particular model.
     * @param integer $id the ID of the model to be displayed
     */
    public function actionView($id)
    {

        if (isset($_GET['asModal']))
        {
            $this->renderPartial('view', array(
                'model' => $this->loadModel($id),
            ));
        }
        else
        {

            $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 Item;

        // Uncomment the following line if AJAX validation is needed
        // $this->performAjaxValidation($model);

        if (isset($_POST['Item']))
        {
            $transaction = Yii::app()->db->beginTransaction();
            try
            {
                $messageType = 'warning';
                $message = "There are some errors ";
                $model->attributes = $_POST['Item'];

                //$uploadFile=CUploadedFile::getInstance($model,'filename');
                if ($model->save())
                {
                    $messageType = 'success';
                    $message = "<strong>Well done!</strong> You successfully create data ";
                    /*
                      $model2 = Item::model()->findByPk($model->id);
                      if(!empty($uploadFile)) {
                      $extUploadFile = substr($uploadFile, strrpos($uploadFile, '.')+1);
                      if(!empty($uploadFile)) {
                      if($uploadFile->saveAs(Yii::app()->basePath.DIRECTORY_SEPARATOR.'files'.DIRECTORY_SEPARATOR.'item'.DIRECTORY_SEPARATOR.$model2->id.DIRECTORY_SEPARATOR.$model2->id.'.'.$extUploadFile)){
                      $model2->filename=$model2->id.'.'.$extUploadFile;
                      $model2->save();
                      $message .= 'and file uploded';
                      }
                      else{
                      $messageType = 'warning';
                      $message .= 'but file not uploded';
                      }
                      }
                      }
                     */
                    $transaction->commit();
                    Yii::app()->user->setFlash($messageType, $message);
                    $this->redirect(array('view', 'id' => $model->id));
                }
            }
            catch (Exception $e)
            {
                $transaction->rollBack();
                Yii::app()->user->setFlash('error', "{$e->getMessage()}");
                //$this->refresh();
            }
        }

        $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['Item']))
          {
          $messageType='warning';
          $message = "There are some errors ";
          $transaction = Yii::app()->db->beginTransaction();
          try{
          $model->attributes=$_POST['Item'];
          $messageType = 'success';
          $message = "<strong>Well done!</strong> You successfully update data ";



          if($model->save()){
          $transaction->commit();
          Yii::app()->user->setFlash($messageType, $message);
          $this->redirect(array('view','id'=>$model->id));
          }
          }
          catch (Exception $e){
          $transaction->rollBack();
          Yii::app()->user->setFlash('error', "{$e->getMessage()}");
          // $this->refresh();
          }

          $model->attributes=$_POST['Item'];
          if($model->save())
          $this->redirect(array('view','id'=>$model->id));
          }

          $this->render('update',array(
          'model'=>$model,
          ));
         */
        // в зависимости от аргумента создаем модель или ищем уже существующую
        if ($id === null)
            $model = new Item();
        else if (!$model = Item::model()->findByPk($id))
            throw new CHttpException(404);

        if (isset($_POST['Item']))
        {
            //var_dump($_POST['Item']);
            
            $model->attributes = $_POST['Item'];
           // echo '<pre>';
           // var_dump($model);
           if (empty($_POST['Item']['document'])) $model->document = Item::model()->findByPk($id)->document; 
           //echo '<pre>';
           //var_dump(Item::model()->findByPk($id));
           
           if ($model->save())
            {
                // отображаем успешное сообщение, обновляем страницу
                // или перенаправляем куда-либо ещё
                // $this->refresh();
                $this->redirect(array('admin'));
            }
        }

        $this->render('update', array('model' => $model));
    }

    public function actionGetFile($id)
    {
        if ($id !== NULL) {
            // некоторая логика по обработке пути из url в путь до файла на сервере
            $currentFile = Yii::getPathOfAlias('webroot.media') . DIRECTORY_SEPARATOR.$id ;
            $str=strpos($id, "."); 
            $row=substr($row, 0, $str); 
            
            if (is_file($currentFile)) {
                header("Content-Type: application/octet-stream");
                header("Accept-Ranges: bytes");
                header("Content-Length: " . filesize($currentFile));
                header("Content-Disposition: attachment; filename=" . $row);
                readfile($currentFile);
            };
        } else {
            $this->redirect('admin');
        };
    }

    /**
     * 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)
    {
        if (Yii::app()->request->isPostRequest)
        {
            // we only allow deletion via POST request
            $this->loadModel($id)->deleteByPk($id);

            // 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'));
        }
        else
            throw new CHttpException(400, 'Invalid request. Please do not repeat this request again.');
    }

    /**
     * Lists all models.
     */
    public function actionIndex()
    {
        /*
          $dataProvider=new CActiveDataProvider('Item');
          $this->render('index',array(
          'dataProvider'=>$dataProvider,
          ));
         */

        $model = new Item('search');
        $model->unsetAttributes();  // clear any default values
        if (isset($_GET['Item']))
            $model->attributes = $_GET['Item'];

        $this->render('index', array(
            'model' => $model,
        ));
    }

    /**
     * Manages all models.
     */
    public function actionAdmin()
    {

        $model = new Item('search');
        $model->unsetAttributes();  // clear any default values
        if (isset($_GET['Item']))
            $model->attributes = $_GET['Item'];

        $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 $id the ID of the model to be loaded
     * @return Item the loaded model
     * @throws CHttpException
     */
    public function loadModel($id)
    {
        $model = Item::model()->findByPk($id);
        if ($model === null)
            throw new CHttpException(404, 'The requested page does not exist.');
        return $model;
    }

    /**
     * Performs the AJAX validation.
     * @param Item $model the model to be validated
     */
    protected function performAjaxValidation($model)
    {
        if (isset($_POST['ajax']) && $_POST['ajax'] === 'item-form')
        {
            echo CActiveForm::validate($model);
            Yii::app()->end();
        }
    }

    public function actionExport()
    {
        $model = new Item;
        $model->unsetAttributes();  // clear any default values
        if (isset($_POST['Item']))
            $model->attributes = $_POST['Item'];

        $exportType = $_POST['fileType'];
        $this->widget('ext.heart.export.EHeartExport', array(
            'title' => 'List of Item',
            'dataProvider' => $model->search(),
            'filter' => $model,
            'grid_mode' => 'export',
            'exportType' => $exportType,
            'columns' => array(
                'id',
                'title',
                'document',
            ),
        ));
    }

    /**
     * Creates a new model.
     * If creation is successful, the browser will be redirected to the 'view' page.
     */
    public function actionImport()
    {

        $model = new Item;
        // Uncomment the following line if AJAX validation is needed
        // $this->performAjaxValidation($model);

        if (isset($_POST['Item']))
        {
            if (!empty($_FILES))
            {
                $tempFile = $_FILES['Item']['tmp_name']['fileImport'];
                $fileTypes = array('xls', 'xlsx'); // File extensions
                $fileParts = pathinfo($_FILES['Item']['name']['fileImport']);
                if (in_array(@$fileParts['extension'], $fileTypes))
                {

                    Yii::import('ext.heart.excel.EHeartExcel', true);
                    EHeartExcel::init();
                    $inputFileType = PHPExcel_IOFactory::identify($tempFile);
                    $objReader = PHPExcel_IOFactory::createReader($inputFileType);
                    $objPHPExcel = $objReader->load($tempFile);
                    $sheetData = $objPHPExcel->getActiveSheet()->toArray(null, true, true, true);
                    $baseRow = 2;
                    $inserted = 0;
                    $read_status = false;
                    while (!empty($sheetData[$baseRow]['A']))
                    {
                        $read_status = true;
                        //$id=  $sheetData[$baseRow]['A'];
                        $title = $sheetData[$baseRow]['B'];
                        $document = $sheetData[$baseRow]['C'];

                        $model2 = new Item;
                        //$model2->id=  $id;
                        $model2->title = $title;
                        $model2->document = $document;

                        try
                        {
                            if ($model2->save())
                            {
                                $inserted++;
                            }
                        }
                        catch (Exception $e)
                        {
                            Yii::app()->user->setFlash('error', "{$e->getMessage()}");
                            //$this->refresh();
                        }
                        $baseRow++;
                    }
                    Yii::app()->user->setFlash('success', ($inserted) . ' row inserted');
                }
                else
                {
                    Yii::app()->user->setFlash('warning', 'Wrong file type (xlsx, xls, and ods only)');
                }
            }


            $this->render('admin', array(
                'model' => $model,
            ));
        }
        else
        {
            $this->render('admin', array(
                'model' => $model,
            ));
        }
    }

    public function actionEditable()
    {
        Yii::import('bootstrap.widgets.TbEditableSaver');
        $es = new TbEditableSaver('Item');
        $es->update();
    }

    public function actions()
    {
        return array(
            'toggle' => array(
                'class' => 'bootstrap.actions.TbToggleAction',
                'modelName' => 'Item',
            )
        );
    }

    } 
D:\open\OpenServer\domains\localhost\mining\protected\modules\product\views\item\_form.php

Код: Выделить всё

<?php $form=$this->beginWidget('CActiveForm',array(
    'htmlOptions'=>array('enctype'=>'multipart/form-data'),
)); ?>
    <?php /* текстовое поле названия элемента */ ?>
    <div class="field">
        <?php echo $form->labelEx($model,'title'); ?>
        <?php echo $form->textField($model,'title'); ?>
        <?php echo $form->error($model,'title'); ?>
    </div>
 
    <?php /* поле для загрузки файла */ ?>
    <div class="field">
        <?php if($model->document): ?>
            <p><?php echo CHtml::encode($model->document); ?></p>
        <?php endif; ?>
        <?php echo $form->labelEx($model,'document'); ?>
        <?php echo $form->fileField($model,'document'); ?>
        <?php echo $form->error($model,'document'); ?>
    </div>
 
    <?php /* кнопка отправки */ ?>
    <div class="button">
        <?php echo CHtml::submitButton($model->isNewRecord ? 'Создать' : 'Сохранить'); ?>
    </div>
<?php $this->endWidget(); ?>
Аватара пользователя
MiddleSky
Сообщения: 20
Зарегистрирован: 2014.09.17, 18:17
Откуда: Киев
Контактная информация:

Re: Как загрузить файл

Сообщение MiddleSky »

>>но вот косяк - при обновлении другого поля (не с картинкой) ссыль на картинку удаляется. понятно что $_POST['Item']['document'] приходит пустой, но что из-за этого затирать существущее? как победить?

вам что нада сделать конкретней?....а то написали непонятно....

как вы обновляете другое поле?
Lesiuk Alexey - Senior Full Stack Developer
Аватара пользователя
des1roer
Сообщения: 391
Зарегистрирован: 2015.02.06, 17:03
Контактная информация:

Re: Как загрузить файл

Сообщение des1roer »

толстая модель оказалась нeжизнеспособной
Последний раз редактировалось des1roer 2015.07.03, 16:51, всего редактировалось 1 раз.
Аватара пользователя
MiddleSky
Сообщения: 20
Зарегистрирован: 2014.09.17, 18:17
Откуда: Киев
Контактная информация:

Re: Как загрузить файл

Сообщение MiddleSky »

все жизнеспособно.....проверял...все работает....
Lesiuk Alexey - Senior Full Stack Developer
Аватара пользователя
des1roer
Сообщения: 391
Зарегистрирован: 2015.02.06, 17:03
Контактная информация:

Re: Как загрузить файл

Сообщение des1roer »

а вот не соглашусь. целый день угробил пытаясь разобраться. а другим способом на раз два
Аватара пользователя
MiddleSky
Сообщения: 20
Зарегистрирован: 2014.09.17, 18:17
Откуда: Киев
Контактная информация:

Re: Как загрузить файл

Сообщение MiddleSky »

ну вот это как раз и отличает хорошего программиста от плохого......хорошему нужно понять причину почему не работало..а плохому..все равно раз получилось другим методом )) почему не работало ему не интересно
Lesiuk Alexey - Senior Full Stack Developer
Аватара пользователя
des1roer
Сообщения: 391
Зарегистрирован: 2015.02.06, 17:03
Контактная информация:

Re: Как загрузить файл

Сообщение des1roer »

потому что рецепт написал какой то мизантроп, приходящий в восторг от мучений других. и поправить это мракобесие никак... ну ладно я буду гордо нести добро в своем бложике. кст можете заглянуть, пишите отзывы в коментах.
NikVolkov
Сообщения: 83
Зарегистрирован: 2015.03.24, 22:03

Re: Как загрузить файл

Сообщение NikVolkov »

Если правильно понял проблему, то решается так, например:
В модели

Код: Выделить всё

protected function beforeSave()
{ 
    if(($this->scenario=='insert' || $this->scenario=='update') && ($photo=CUploadedFile::getInstance($this,'photo')))
    {
        //если файл есть в $_POST, то делаем всё, что полагается с ним делать.
    }else{
        unset($this->photo);
    }
 }
оно?
Аватара пользователя
des1roer
Сообщения: 391
Зарегистрирован: 2015.02.06, 17:03
Контактная информация:

Re: Как загрузить файл

Сообщение des1roer »

не актуально. сделал по другому. но все равно спасибо.
на самом деле модель норм отрабатывает. удаляет когда нужно. мудрит экшн апдейт. он в любом случае затирает имя файла

Код: Выделить всё

   public function actionUpdate($id)
    {


        // в зависимости от аргумента создаем модель или ищем уже существующую
        if ($id === null)
            $model = new Item();
        else if (!$model = Item::model()->findByPk($id))
            throw new CHttpException(404);

        if (isset($_POST['Item']))
        {
            //var_dump($_POST['Item']);
            
            $model->attributes = $_POST['Item'];
           if (empty($_POST['Item']['document'])) $model->document = Item::model()->findByPk($id)->document; 
           
           if ($model->save())
            {
                // отображаем успешное сообщение, обновляем страницу
                // или перенаправляем куда-либо ещё
                // $this->refresh();
                $this->redirect(array('admin'));
            }
        }

        $this->render('update', array('model' => $model));
    } 
Onotole
Сообщения: 1808
Зарегистрирован: 2012.12.24, 12:49

Re: Как загрузить файл

Сообщение Onotole »

И этот человек в своем блоге учит людей работе с Yii...
Аватара пользователя
des1roer
Сообщения: 391
Зарегистрирован: 2015.02.06, 17:03
Контактная информация:

Re: Как загрузить файл

Сообщение des1roer »

дак и вы учите. я ж не мешаю
Ответить