Para subir archivos en Yii a modo de ejemplo creare una una tabla llamada “DashboardMedia”, por ejemplo en SQLite:

CREATE TABLE DashboardMedia (id_media integer primary key not null, filename varchar(100), id_autor integer, Fecha datetime, extencion varchar(10), FOREIGN KEY(id_autor) REFERENCES Users (id_user));

Modelo

En el Modelo al generarlo con GII, el campo de “rules” generado por defecto es el siguiente:

  /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['id_autor'], 'integer'],
            [['Fecha'], 'safe'],
            [['filename'], 'string', 'max' => 100],
            [['extencion'], 'string', 'max' => 10]
        ];
    }

Este campo en el ítem de “filename”, cambiaremos el tipo de datos de “String” a “File”

  /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['id_autor'], 'integer'],
            [['Fecha'], 'safe'],
            [['filename'], 'file'],
            [['extencion'], 'string', 'max' => 10]
        ];
    }

O si queremos definir algún formato de archivo en especial podríamos definir las exenciones a aceptar, por ejemplo si son imágenes podemos colocar que solo se aceptan jpg, png:

    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['id_autor'], 'integer'],
            [['Fecha'], 'safe'],
            [['filename'], 'file', 'skipOnEmpty' => false, 'extensions' => 'png, jpg'],
            [['extencion'], 'string', 'max' => 10]
        ];
    }

Ahora en el modelo también agregaremos una función que guardara el archivo subido en alguna carpeta. Por ejemplo he creado una carpeta llama “uploads” ubicada en “proyect/web/” para dejar los archivos que subo.

    public function upload(){
            if ($this->validate()) {
                $this->filename->saveAs('uploads/' . $this->filename->baseName . '.' . $this->filename->extension);
                return true;
            } else {
                return false;
            }
    }

Entonces nuestro Modelo quedaría de la siguiente forma:

<?php

namespace app\models;

use yii\base\Model;//new
use yii\web\UploadedFile; //NEW

use Yii;


/**
 * This is the model class for table "DashboardMedia".
 *
 * @property integer $id_media
 * @property string $filename
 * @property integer $id_autor
 * @property string $Fecha
 * @property string $extencion
 *
 * @property Users $idAutor
 */
class DashboardMedia extends \yii\db\ActiveRecord
{
  //public $filename_file;
  //public $filename;

    /**
     * @inheritdoc
     */
    public static function tableName()
    {
        return 'DashboardMedia';
    }

    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['id_autor'], 'integer'],
            [['Fecha'], 'safe'],
          //  [['filename'], 'string', 'max' => 100],
            //[['filename'], 'file', 'skipOnEmpty' => false, 'extensions' =&
gt; 'png, jpg'],
            [['filename'], 'file'],
            [['extencion'], 'string', 'max' => 10]
        ];
    }

    /**
     * @inheritdoc
     */
    public function attributeLabels()
    {
        return [
            'id_media' => 'Id Media',
            'filename' => 'Filename',
            'id_autor' => 'Id Autor',
            'Fecha' => 'Fecha',
            'extencion' => 'Extencion',
        ];
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getIdAutor()
    {
        return $this->hasOne(Users::className(), ['id_user' => 'id_autor']);
    }

    public function upload(){
            if ($this->validate()) {
                $this->filename->saveAs('uploads/' . $this->filename->baseName . '.' . $this->filename->extension);
                return true;
            } else {
                return false;
            }
    }
}

En este caso la función “getIdAutor”, hace referencia a la llave foránea entre la tabla “Dashboardfile” (creada para subir archivos) y la tabla “Users”.

Controlador:

En el controlador editaremos el Create y Update. Por ejemplo el Create quedaría de la siguiente forma:

    /**
     * Creates a new DashboardMedia model.
     * If creation is successful, the browser will be redirected to the 'view' page.
     * @return mixed
     */
    public function actionCreate()
    {
        $model = new DashboardMedia();

        if ($model->load(Yii::$app->request->post())){

            $model->filename=UploadedFile::getInstance($model, 'filename');
            $model->extencion=$model->filename->extension;
            $model->id_autor=Yii::$app->user->identity->id_user;
            $model->Fecha=date('Y-m-d H:i:s');
            if( $model->save()) {
              if($model->upload()){
                return $this->redirect(['view', 'id' => $model->id_media]);
              }
            }
            else {
              # code...
              return $this->render('create', [
                  'model' => $model,
              ]);
            }
        } else {
            return $this->render('create', [
                'model' => $model,
            ]);
        }
    }

En donde “UploadedFile::getInstance($model, ‘filename’);” lo uso solo en este caso para obtener la exención del archivo, según el nombre (filename)

El controlador quedaría de la siguiente forma:

<?php

namespace app\controllers;

use Yii;
use app\models\DashboardMedia;
use yii\data\ActiveDataProvider;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;

use yii\filters\AccessControl;

use yii\web\UploadedFile; //new
use app\models\UploadForm;//new
/**
 * DashboardMediaController implements the CRUD actions for DashboardMedia model.
 */
class DashboardMediaController extends Controller
{
  public function behaviors()
  {
      return [
          'access'=>[
              'class'=>AccessControl::className(),
              'rules'=>[
                  [
                      'actions'=>[
                          'index',
                          'create',
                          '
update',
                          'delete',
                          'view'
                      ],
                      'allow'=>true,
                      'roles' => ['@'],
                  ],
              ],
          ],
          'verbs' => [
              'class' => VerbFilter::className(),
              'actions' => [
                  'delete' => ['post'],
              ],
          ],
      ];
  }

    /**
     * Lists all DashboardMedia models.
     * @return mixed
     */
    public function actionIndex()
    {
        $dataProvider = new ActiveDataProvider([
            'query' => DashboardMedia::find(),
        ]);

        return $this->render('index', [
            'dataProvider' => $dataProvider,
        ]);
    }

    /**
     * Displays a single DashboardMedia model.
     * @param integer $id
     * @return mixed
     */
    public function actionView($id)
    {
        return $this->render('view', [
            'model' => $this->findModel($id),
        ]);
    }

    /**
     * Creates a new DashboardMedia model.
     * If creation is successful, the browser will be redirected to the 'view' page.
     * @return mixed
     */
    public function actionCreate()
    {
        $model = new DashboardMedia();

        if ($model->load(Yii::$app->request->post())){

            $model->filename=UploadedFile::getInstance($model, 'filename');
            $model->extencion=$model->filename->extension;
            $model->id_autor=Yii::$app->user->identity->id_user;
            $model->Fecha=date('Y-m-d H:i:s');
            if( $model->save()) {
              if($model->upload()){
                return $this->redirect(['view', 'id' => $model->id_media]);
              }
            }
            else {
              # code...
              return $this->render('create', [
                  'model' => $model,
              ]);
            }
        } else {
            return $this->render('create', [
                'model' => $model,
            ]);
        }
    }


    /**
     * Updates an existing DashboardMedia model.
     * If update is successful, the browser will be redirected to the 'view' page.
     * @param integer $id
     * @return mixed
     */
    public function actionUpdate($id)
    {
        $model = $this->findModel($id);

        if ($model->load(Yii::$app->request->post())){

            $model->filename=UploadedFile::getInstance($model, 'filename');
            $model->extencion=$model->filename->extension;
            $model->id_autor=Yii::$app->user->identity->id_user;
            $model->Fecha=date('Y-m-d H:i:s');
            if( $model->save()) {
              if($model->upload()){
                return $this->redirect(['view', 'id' => $model->id_media]);
              }
            }
            else {
              # code...
              return $this->render('update', [
                  'model' => $model,
              ]);
            }
        } else {
            return $this->render('update', [
                'model' => $model,
            ]);
        }
    }

    /**
     * Deletes an existing DashboardMedia model.
     * If deletion is successful, the browser will be redirected to the 'index' page.
     * @param integer $id

n     * @return mixed
     */
    public function actionDelete($id)
    {
        $this->findModel($id)->delete();

        return $this->redirect(['index']);
    }

    /**
     * Finds the DashboardMedia model based on its primary key value.
     * If the model is not found, a 404 HTTP exception will be thrown.
     * @param integer $id
     * @return DashboardMedia the loaded model
     * @throws NotFoundHttpException if the model cannot be found
     */
    protected function findModel($id)
    {
        if (($model = DashboardMedia::findOne($id)) !== null) {
            return $model;
        } else {
            throw new NotFoundHttpException('The requested page does not exist.');
        }
    }


}

 

Ahora procedemos a modifcar el formulario para el servicio de create y update. En “views/nombre_vista_crud/” en mi caso “views/dashboard-media/” se encuentran las vistas del CRUD, editaremos el “_form.php”,  “index.php” y “view.php”.

_form.php

Para el formulario utilizaramos un widget llamado FileInput, para esto lo instalaremos vía composer.

php composer.phar require kartik-v/yii2-widget-fileinput "@dev"

Ahora el formulario editado con el plugin queda de la siguiente forma:

<?php

use yii\helpers\Html;
use yii\widgets\ActiveForm;
use kartik\file\FileInput;

?>

<div class="dashboard-media-form">

    <?php  /*$form = ActiveForm::begin();*/ ?>


    <?php $form = ActiveForm::begin(['options' => ['enctype' => 'multipart/form-data']]) ?>

    <?php
        // Usage with ActiveForm and model
        echo $form->field($model, 'filename')->widget(FileInput::classname(), [
            'options' => ['accept' => 'upload/*'],
        ]);
        ?>

    <div class="form-group">
        <?= Html::submitButton($model->isNewRecord ? 'Create' : 'Update', ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?>
    </div>

    <?php ActiveForm::end(); ?>

</div>

1

Las modificaciones fueron, agregar la libreria de “FileInput” (use kartik\file\FileInput;) y agregar el widget, remplazando el campo de texto generado automacamente por GII.

    <?php
        echo $form->field($model, 'filename')->widget(FileInput::classname(), [
            'options' => ['accept' => 'upload/*'],
        ]);
        ?>

Recordar que los campos de fecha, extención se guardaron de forma “automatica” en la función create del en el Controlador, capturando la fecha del sistema vía php y la extención del archivo se extrae del nombre de este.

 

View.php

Ahora editaremos el View, para que muestre la imagen subida. Es este caso solo agregaremos al final del archivo las siguientes lineas para desplegar la imagen:

    <?php
    echo "<center><a href=\"uploads/$model->filename\"><img style=\"width:30%\" src=\"uploads/$model->filename\" class=\"img-responsive\"></a></center>";
     ?>

nQuedando de la siquiete forma:

<?php

use yii\helpers\Html;
use yii\widgets\DetailView;

/* @var $this yii\web\View */
/* @var $model app\models\DashboardMedia */

$this->title = $model->id_media;
$this->params['breadcrumbs'][] = ['label' => 'Dashboard Media', 'url' => ['index']];
$this->params['breadcrumbs'][] = $this->title;
?>
<div class="dashboard-media-view">

    <h1><?= Html::encode($this->title) ?></h1>

    <p>
        <?= Html::a('Update', ['update', 'id' => $model->id_media], ['class' => 'btn btn-primary']) ?>
        <?= Html::a('Delete', ['delete', 'id' => $model->id_media], [
            'class' => 'btn btn-danger',
            'data' => [
                'confirm' => 'Are you sure you want to delete this item?',
                'method' => 'post',
            ],
        ]) ?>
    </p>

    <?= DetailView::widget([
        'model' => $model,
        'attributes' => [
            //'id_media',
            'filename',
            'id_autor',
            'Fecha',
            'extencion',
        ],
    ]) ?>

    <?php
    echo "<center><a href=\"uploads/$model->filename\"><img style=\"width:30%\" src=\"uploads/$model->filename\" class=\"img-responsive\"></a></center>";
     ?>

</div>

2

Index

Ahora editaremos el index, para que en la lista de archivos subidos muestre la imagen de las fotos :).

Aca remplazamos el campo de la imagen por lo siguiente:

            [
              'attribute' => 'filename',
              'format' => 'html',
              'label' => 'ImageColumnLable',
              'value' => function ($data) {
                return Html::img('uploads/' . $data['filename'],
                ['width' => '100px']);
              },
            ],

Quedando de la siguiente forma:

<?php
namespace app\models;
use yii\helpers\Html;
use yii\grid\GridView;

/* @var $this yii\web\View */
/* @var $dataProvider yii\data\ActiveDataProvider */

$this->title = 'Dashboard Media';
$this->params['breadcrumbs'][] = $this->title;
?>
<div class="dashboard-media-index">

    <h1><?= Html::encode($this->title) ?></h1>

    <p>
        <?= Html::a('Create Dashboard Media', ['create'], ['class' => 'btn btn-success']) ?>
    </p>

    <?= GridView::widget([
        'dataProvider' => $dataProvider,
        'columns' => [
            ['class' => 'yii\grid\SerialColumn'],
            //IMAGEN DEL DOCUMENTO / IMAGEN
            [
              'attribute' => 'filename',
              'format' => 'html',
              'label' => 'ImageColumnLable',
              'value' =>
 function ($data) {
                return Html::img('uploads/' . $data['filename'],
                ['width' => '100px']);
              },
            ],

            //NOMBRE + URL DEL DOCUMENTO / IMAGEN
            [
              'label'=>'File',
              'format' => 'raw',
              'value'=>function ($data) {
                  $url="uploads/".$data->filename;
                  return Html::a($data->filename, $url);
              },
            ],
            //'id_autor',
            //'autor'=> Users::find()->select('username')->where(['id_user'=>'id_autor'])->one(),
            'Fecha',
            'extencion',

            ['class' => 'yii\grid\ActionColumn'],
        ],
    ]); ?>

</div>

3

Listo, allí ya tenemos un buen avance para subir archivos y visualizar nuestras fotos 🙂
Saludos