() translation by (you can also view the original English article)



Si se está preguntando, "¿Qué es Yii?" Echa un vistazo a mi tutorial anterior: Introducción a Yii Framework, que revisa los beneficios de Yii e incluye una visión general de lo que es nuevo en Yii 2.0, publicado en octubre de 2014.
En este capitulo de la serie Cómo programar con Yii2, estoy orientando a los lectores en el uso de Yii2 Framework para PHP. En este tutorial, te guiaré a través de los conceptos básicos de subir archivos e imágenes en Yii2.
Para estos ejemplos, seguiremos imaginando que estamos construyendo un framework para publicar actualizaciones de estado simples, por ejemplo nuestro propio mini-Twitter. La imagen de arriba demuestra escribir una actualización corta al subir una foto que tomé del Taj Mahal.
Sólo un recordatorio, yo participo en los comentarios. Estoy especialmente interesado si tiene diferentes enfoques, ideas adicionales o desea sugerir temas para futuros tutoriales. Si tiene alguna pregunta o sugerencia de tema, por favor, hazla. También puede contactarme directamente en Twitter @reifman.
Complementos de carga de archivos



Hay dos complementos de carga de archivos para Yii2 que parecen los más robustos:
- El Widget FileInput de Kartik Visweswaran (mostrado arriba)
- El 2Amigos BlueImp File Uploader (un envoltorio para el BlueImp JQuery File Uploader)
Para este tutorial, decidí continuar con el complemento de Kartik. Lo encontré más fácil de usar y mejor documentado que el complemento 2Amigos. Sin embargo, el BlueImp File Uploader tiene algunas características intrigantes de la experiencia del usuario que puede que desee explorar (se muestra a continuación):



Programando con el complemento FileInput
Comencemos por instalar y utilizar el cargador de archivos e integrarlo en nuestro applet de publicación de estados tipo-Twitter. Una vez más, usaremos el árbol de aplicaciones de Yii2 Hello que puedes descargar con el enlace del botón de GitHub del costado o debajo.
Instalación del complemento
Primero, podemos usar composer para agregar kartik-v/yii2-widget-fileinput
a su aplicación:
1 |
$ composer require kartik-v/yii2-widget-fileinput "*" |
2 |
./composer.json has been updated |
3 |
Loading composer repositories with package information |
4 |
Updating dependencies (including require-dev) |
5 |
- Updating kartik-v/yii2-widget-fileinput (dev-master 36f9f49 => v1.0.4) |
6 |
Checking out 36f9f493c2d814529f2a195422a8af2e020fc80c |
7 |
|
8 |
Writing lock file |
9 |
Generating autoload files |
Ampliando de la tabla estado
A continuación, debemos agregar campos para el archivo que subiremos a nuestra tabla estado. En este ejemplo, dejaremos que el usuario cargue una imagen para ir junto con su estado.
Los campos que agregaremos son para el nombre de archivo original de los archivos cargados, así como un nombre de archivo único que se almacenará en nuestro servidor para su visualización:
- image_src_filename
- image_web_filename
Cree una nueva migración para agregar estos campos a la tabla estado:
1 |
$ ./yii migrate/create extend_status_table_for_image |
2 |
Yii Migration Tool (based on Yii v2.0.6) |
3 |
|
4 |
Create new migration '/Users/Jeff/Sites/hello/migrations/m160316_201654_extend_status_table_for_image.php'? (yes|no) [no]:yes |
5 |
New migration created successfully. |
Esta es la migración personalizada para agregar los dos campos como cadena:
1 |
<?php
|
2 |
|
3 |
use yii\db\Schema; |
4 |
use yii\db\Migration; |
5 |
|
6 |
class m160316_201654_extend_status_table_for_image extends Migration |
7 |
{
|
8 |
public function up() |
9 |
{
|
10 |
$tableOptions = null; |
11 |
if ($this->db->driverName === 'mysql') { |
12 |
$tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB'; |
13 |
}
|
14 |
$this->addColumn('{{%status}}','image_src_filename',Schema::TYPE_STRING.' NOT NULL'); |
15 |
$this->addColumn('{{%status}}','image_web_filename',Schema::TYPE_STRING.' NOT NULL'); |
16 |
}
|
17 |
|
18 |
public function down() |
19 |
{
|
20 |
$this->dropColumn('{{%status}}','image_src_filename'); |
21 |
$this->dropColumn('{{%status}}','image_web_filename'); |
22 |
return false; |
23 |
}
|
24 |
|
25 |
}
|
A continuación, ejecute la migración:
1 |
$ ./yii migrate/up |
2 |
Yii Migration Tool (based on Yii v2.0.6) |
3 |
|
4 |
Total 1 new migration to be applied: |
5 |
m160316_201654_extend_status_table_for_image |
6 |
|
7 |
Apply the above migration? (yes|no) [no]:yes |
8 |
*** applying m160316_201654_extend_status_table_for_image |
9 |
> add column image_src_filename string NOT NULL to table {{%status}} ... done (time: 0.044s) |
10 |
> add column image_web_filename string NOT NULL to table {{%status}} ... done (time: 0.011s) |
11 |
*** applied m160316_201654_extend_status_table_for_image (time: 0.071s) |
12 |
|
13 |
|
14 |
Migrated up successfully. |
Dado que Yii2 está construido con una arquitectura Modelo Vista Controlador (MVC), hay tres otras áreas de programación que necesitamos implementar para el cargador de archivos:
- El Modelo Status
- La vista y el formulario Status
- El controlador Status
Mejora de la funcionalidad del Modelo
Ahora, haremos cambios en el archivo /models/Status.php
. Primero, necesitamos proporcionar atributos y reglas de validación para los nuevos campos de imagen, así como la variable de $image
temporal que el widget utilizará para cargar el archivo.
A continuación, agregamos comentarios para las dos nuevas variables $image_xxx_filename
y creamos una variable temporal pública llamada $image
:
1 |
/**
|
2 |
* This is the model class for table "status".
|
3 |
*
|
4 |
* @property integer $id
|
5 |
* @property string $message
|
6 |
* @property integer $permissions
|
7 |
* @property string $image_src_filename
|
8 |
* @property string $image_web_filename
|
9 |
* @property integer $created_at
|
10 |
* @property integer $updated_at
|
11 |
* @property integer $created_by
|
12 |
*
|
13 |
* @property User $createdBy
|
14 |
*/
|
15 |
class Status extends \yii\db\ActiveRecord |
16 |
{
|
17 |
const PERMISSIONS_PRIVATE = 10; |
18 |
const PERMISSIONS_PUBLIC = 20; |
19 |
public $image; |
A continuación, agregaremos validación para nuestra imagen, como el tipo de archivo y el tamaño máximo:
1 |
public function rules() |
2 |
{
|
3 |
return [ |
4 |
[['message'], 'required'], |
5 |
[['message'], 'string'], |
6 |
[['permissions', 'created_at', 'updated_at','created_by'], 'integer'], |
7 |
[['image'], 'safe'], |
8 |
[['image'], 'file', 'extensions'=>'jpg, gif, png'], |
9 |
[['image'], 'file', 'maxSize'=>'100000'], |
10 |
[['image_src_filename', 'image_web_filename'], 'string', 'max' => 255], ]; |
11 |
}
|
Y nuevas etiquetas de atributos para las vistas:
1 |
public function attributeLabels() |
2 |
{
|
3 |
return [ |
4 |
'id' => Yii::t('app', 'ID'), |
5 |
'message' => Yii::t('app', 'Message'), |
6 |
'permissions' => Yii::t('app', 'Permissions'), |
7 |
'image_src_filename' => Yii::t('app', 'Filename'), |
8 |
'image_web_filename' => Yii::t('app', 'Pathname'), |
9 |
'created_by' => Yii::t('app', 'Created By'), |
10 |
'created_at' => Yii::t('app', 'Created At'), |
11 |
'updated_at' => Yii::t('app', 'Updated At'), ]; |
12 |
}
|
Ahora podemos pasar a los cambios en View en el formulario ActiveModel.
Agregar nuestra vista y la funcionalidad del formulario
Integración de carga de imágenes en el formulario de publicación de estado



Para habilitar la integración del formulario de carga de imágenes en las actualizaciones de estado (mostradas arriba), necesitamos realizar cambios en el archivo /views/status/_form.php
.
Primero, incluimos el widget kartik\file\FileInput
cerca de la parte superior y actualizamos el formulario para que se convierta en multipart, lo que soporta la publicación de archivos:
1 |
<?php
|
2 |
|
3 |
use yii\helpers\Html; |
4 |
use yii\widgets\ActiveForm; |
5 |
use app\assets\StatusAsset; |
6 |
use kartik\file\FileInput; |
7 |
|
8 |
StatusAsset::register($this); |
9 |
|
10 |
/* @var $this yii\web\View */
|
11 |
/* @var $model app\models\Status */
|
12 |
/* @var $form yii\widgets\ActiveForm */
|
13 |
?>
|
14 |
|
15 |
<div class="status-form"> |
16 |
<?php
|
17 |
$form = ActiveForm::begin([ |
18 |
'options'=>['enctype'=>'multipart/form-data']]); // important |
19 |
?>
|
A continuación, entre el campo Permissions (Permisos) y los botones Submit (Enviar), agregamos el widget FileInput:
1 |
<?=
|
2 |
$form->field($model, 'permissions')->dropDownList($model->getPermissions(), |
3 |
['prompt'=>Yii::t('app','- Choose Your Permissions -')]) ?> |
4 |
</div>
|
5 |
</div>
|
6 |
<div class="row"> |
7 |
<?= $form->field($model, 'image')->widget(FileInput::classname(), [ |
8 |
'options' => ['accept' => 'image/*'], |
9 |
'pluginOptions'=>['allowedFileExtensions'=>['jpg','gif','png'],'showUpload' => false,], |
10 |
]); ?> |
11 |
</div>
|
12 |
<div class="row"> |
13 |
|
14 |
<div class="form-group"> |
15 |
<?= Html::submitButton($model->isNewRecord ? Yii::t('app', 'Create') : Yii::t('app', 'Update'), ['class' => $model->isNewRecord ? 'btn btn-success' : 'btn btn-primary']) ?> |
16 |
</div>
|
17 |
</div>
|
En la línea de pluginOptions
, restringimos los tipos de archivo a formatos de imagen comunes como jpg.
Cuando esté completo, se verá algo así, esperando que el usuario agregue una imagen:



Visualización de la imagen
También voy a agregar código para mostrar la imagen cargada para más tarde (después de que terminemos el soporte del controlador).
Primero, lo agregaré a la página de vista de estado (/views/status/view.php
), que es muy básica. Sin embargo, exhibiré la imagen debajo de los detalles del artículo:
1 |
<?= DetailView::widget([ |
2 |
'model' => $model, |
3 |
'attributes' => [ |
4 |
'id', |
5 |
'createdBy.email', |
6 |
'message:ntext', |
7 |
'permissions', |
8 |
'image_web_filename', |
9 |
'image_src_filename', |
10 |
'created_at', |
11 |
'updated_at', |
12 |
],
|
13 |
]) ?> |
14 |
|
15 |
<?php
|
16 |
if ($model->image_web_filename!='') { |
17 |
echo '<br /><p><img src="'.Yii::$app->homeUrl. '/uploads/status/'.$model->image_web_filename.'"></p>'; |
18 |
}
|
19 |
?>
|
Se verá algo como esto:



También agregamos una pequeña vista en miniatura a nuestra página de índice de estado (/views/status/index.php
). He añadido un atributo de columna personalizado al widget GridView de Yii2:
1 |
<?= GridView::widget([
|
2 |
'dataProvider' => $dataProvider,
|
3 |
'filterModel' => $searchModel,
|
4 |
'columns' => [
|
5 |
['class' => 'yii\grid\SerialColumn'],
|
6 |
'id',
|
7 |
'message:ntext',
|
8 |
'permissions',
|
9 |
'created_at',
|
10 |
[
|
11 |
'attribute' => 'Image',
|
12 |
'format' => 'raw',
|
13 |
'value' => function ($model) {
|
14 |
if ($model->image_web_filename!='')
|
15 |
return '<img src="'.Yii::$app->homeUrl. '/uploads/status/'.$model->image_web_filename.'" width="50px" height="auto">'; else return 'no image';
|
16 |
},
|
17 |
],
|
18 |
['class' => 'yii\grid\ActionColumn',
|
19 |
'template'=>'{view} {update} {delete}',
|
20 |
'buttons'=>[
|
21 |
'view' => function ($url, $model) {
|
22 |
return Html::a('<span class="glyphicon glyphicon-eye-open"></span>', 'status/'.$model->slug, ['title' => Yii::t('yii', 'View'),]);
|
23 |
}
|
24 |
],
|
25 |
],
|
26 |
],
|
27 |
]); ?>
|
En última instancia, se verá así:



Creando el soporte del controlador
Para que todo lo anterior sea posible, necesitamos terminar la integración del controlador.
En la parte superior de /controllers/StatusController.php
, tenemos que incluir yii\web\UploadedFile
:
1 |
<?php
|
2 |
namespace app\controllers; |
3 |
use Yii; |
4 |
use app\models\Status; |
5 |
use app\models\StatusSearch; |
6 |
use app\models\User; |
7 |
use app\components\AccessRule; |
8 |
use yii\web\Controller; |
9 |
use yii\web\NotFoundHttpException; |
10 |
use yii\filters\VerbFilter; |
11 |
use yii\filters\AccessControl; |
12 |
use yii\web\UploadedFile; |
Entonces tenemos que actualizar la función actionCreate
:
1 |
public function actionCreate() |
2 |
{
|
3 |
$model = new Status(); |
4 |
|
5 |
if ($model->load(Yii::$app->request->post())) { |
6 |
$image = UploadedFile::getInstance($model, 'image'); |
7 |
if (!is_null($image)) { |
8 |
$model->image_src_filename = $image->name; |
9 |
$ext = end((explode(".", $image->name))); |
10 |
// generate a unique file name to prevent duplicate filenames
|
11 |
$model->image_web_filename = Yii::$app->security->generateRandomString().".{$ext}"; |
12 |
// the path to save file, you can set an uploadPath
|
13 |
// in Yii::$app->params (as used in example below)
|
14 |
Yii::$app->params['uploadPath'] = Yii::$app->basePath . '/web/uploads/status/'; |
15 |
$path = Yii::$app->params['uploadPath'] . $model->image_web_filename; |
16 |
$image->saveAs($path); |
17 |
}
|
18 |
if ($model->save()) { |
19 |
return $this->redirect(['view', 'id' => $model->id]); |
20 |
} else { |
21 |
var_dump ($model->getErrors()); die(); |
22 |
}
|
23 |
}
|
24 |
return $this->render('create', [ |
25 |
'model' => $model, |
26 |
]);
|
27 |
}
|
Esencialmente, esto realiza las siguientes operaciones:
- Capturamos el nombre de archivo original de la información del formulario de archivo cargado (
image_src_filename
). - Generamos un nombre de archivo único para nuestro servidor (
image_web_filename
). - Guardamos el archivo en su directorio de carga (
/web/uploads/status/
). - Guardamos el modelo.
- Redireccionamos a la página de vista mejorada.
Usted puede ver los resultados finales con la imagen de arriba, que incluye una foto del Taj Mahal.
El File Input Widget de Kartik también ofrece configuraciones más avanzadas que documenta bastante bien, como Arrastrar y Soltar:



Mire más de estos y compruébelos en las siguientes páginas:
- FileInput Widget Demo
- Subir archivo en Yii 2 usando el widget FileInput
- Subida avanzada mediante el widget Yii2 FileInput
¿Que sigue?
Espero que esto le ayude con los fundamentos de la carga de archivos en su aplicación Yii2. Si desea ver otro paso a través similar de este tipo de funcionalidad, consulte Creando su startup con PHP: configuración de usuario, imágenes de perfil y detalles de contacto. Ese tutorial ofrece una integración ligeramente diferente de este tutorial, usando pestañas, actualizando perfiles de usuario y escalando las imágenes.



Vea los próximos tutoriales en mi Serie: Cómo programar con Yii2 mientras continúo sumando diferentes aspectos del framework. También puede comprobar mi serie Creando su Startup con PHP, que está utilizando la plantilla avanzada de Yii2 como construir una aplicación del mundo real.
Si quieres saber cuándo llega el próximo tutorial de Yii2, sígueme @reifman en Twitter o consulta mi página de instructor. Mi página de instructor incluirá todos los artículos de esta serie tan pronto como se publiquen.
Enlaces relacionados
Aquí hay una variedad de enlaces que he utilizado para investigar y escribir este tutorial:
- Yii2 Developer Exchange, mi sitio de recursos Yii2
- FileInput Widget Demo por - Kartik
- Subir archivo en Yii 2 usando el widget FileInput - Kartik
- Código para kartik-v/yii2-widget-fileinput (GitHub)
- BlueImp JQuery File Upload Demo
- Código para 2amigos/yii2-file-upload-widget: BlueImp File Upload Widget (Github)
- Subir archivos - La guía definitiva de Yii 2.0