Если вы спрашиваете: «Что такое Yii?» Посмотрите мой предыдущий учебник: Введение в Yii Framework , который рассматривает преимущества Yii и включает обзор того, что нового в Yii 2.0, выпущенном в октябре 2014 года.
В этой серии «Как программировать с Yii2» я расскажу читателям, как использовать Yii2 Framework для PHP. В этом уроке я познакомлю вас с основами загрузки файлов и изображений в Yii2.
Для этих примеров мы продолжим предполагать, что мы создаем структуру для публикации простых обновлений статуса, например, наш собственный мини-Twitter. Изображение выше демонстрирует написание короткого обновления при загрузке фотографии Тадж Махала, которую я сделал.
Просто напоминание, я участвую в комментариях ниже. Мне особенно интересно, если у вас есть другие подходы, дополнительные идеи или вы хотите предложить темы для будущих уроков. Если у вас есть вопрос или предложение по теме, пожалуйста, напишите ниже. Вы также можете связаться со мной через Twitter @reifman напрямую.
Плагины для загрузки файлов
Есть два плагина для загрузки файлов для Yii2, которые кажутся наиболее надежными:
- Виджет FileInput от Kartik Visweswaran (показан выше)
- 2Amigos BlueImp File Uploader (оболочка для BlueImp JQuery File Uploader )
Для этого урока я решил продолжить с плагина Kartik. Я обнаружил, что его легче использовать и лучше документировать, чем плагин 2Amigos. Тем не менее, BlueImp File Uploader имеет некоторые интригующие функции взаимодействия с пользователем, которые вы можете захотеть изучить (показано ниже):
Работа с плагином FileInput
Давайте начнем устанавливать и использовать загрузчик файлов и интегрировать его в наш Twitter-подобный апплет создания статуса. Опять же, мы будем использовать дерево приложений Yii2 Hello, которое вы можете загрузить с помощью ссылки кнопки GitHub рядом или ниже.
Установка плагина
Во-первых, мы можем использовать composer для добавления kartik-v/yii2-widget-fileinput
в наше приложение:
1
2
3
4
5
6
7
8
9
|
$ composer require kartik-v/yii2-widget-fileinput «*»
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
— Updating kartik-v/yii2-widget-fileinput (dev-master 36f9f49 => v1.0.4)
Checking out 36f9f493c2d814529f2a195422a8af2e020fc80c
Writing lock file
Generating autoload files
|
Расширение таблицы состояния
Далее нам нужно добавить поля для файла, который мы собираемся загрузить в нашу таблицу состояния. В этом примере мы дадим пользователю возможность загрузить изображение для обновления своего статуса.
Поля, которые мы добавим, предназначены для исходного имени загруженного файла, а также для уникального имени файла, которое будет храниться на нашем сервере для отображения:
- image_src_filename
- image_web_filename
Создайте новую миграцию для добавления этих полей в таблицу Status:
1
2
3
4
5
|
$ ./yii migrate/create extend_status_table_for_image
Yii Migration Tool (based on Yii v2.0.6)
Create new migration ‘/Users/Jeff/Sites/hello/migrations/m160316_201654_extend_status_table_for_image.php’?
New migration created successfully.
|
Вот настроенная миграция для добавления двух полей в виде строк:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
<?php
use yii\db\Schema;
use yii\db\Migration;
class m160316_201654_extend_status_table_for_image extends Migration
{
public function up()
{
$tableOptions = null;
if ($this->db->driverName === ‘mysql’) {
$tableOptions = ‘CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB’;
}
$this->addColumn(‘{{%status}}’,’image_src_filename’,Schema::TYPE_STRING.’ NOT NULL’);
$this->addColumn(‘{{%status}}’,’image_web_filename’,Schema::TYPE_STRING.’ NOT NULL’);
}
public function down()
{
$this->dropColumn(‘{{%status}}’,’image_src_filename’);
$this->dropColumn(‘{{%status}}’,’image_web_filename’);
return false;
}
}
|
Затем запустите миграцию:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
$ ./yii migrate/up
Yii Migration Tool (based on Yii v2.0.6)
Total 1 new migration to be applied:
m160316_201654_extend_status_table_for_image
Apply the above migration?
*** applying m160316_201654_extend_status_table_for_image
> add column image_src_filename string NOT NULL to table {{%status}} … done (time: 0.044s)
> add column image_web_filename string NOT NULL to table {{%status}} … done (time: 0.011s)
*** applied m160316_201654_extend_status_table_for_image (time: 0.071s)
Migrated up successfully.
|
Поскольку Yii2 построен с архитектурой Model View Controller (MVC), есть три других области кодирования, которые нам нужно реализовать для загрузчика файлов:
- Модель состояния
- Статус просмотра и формы
- Контроллер статуса
Улучшение функциональности модели
Теперь мы /models/Status.php
изменения в файл /models/Status.php
. Прежде всего, нам необходимо предоставить атрибуты и правила проверки для новых полей изображения, а также временную переменную $image
виджет будет использовать для загрузки файла.
Ниже мы добавляем комментарии для двух новых переменных $image_xxx_filename
и создаем общедоступную временную переменную с именем $image
:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
/**
* This is the model class for table «status».
*
* @property integer $id
* @property string $message
* @property integer $permissions
* @property string $image_src_filename
* @property string $image_web_filename
* @property integer $created_at
* @property integer $updated_at
* @property integer $created_by
*
* @property User $createdBy
*/
class Status extends \yii\db\ActiveRecord
{
const PERMISSIONS_PRIVATE = 10;
const PERMISSIONS_PUBLIC = 20;
public $image;
|
Далее мы добавим правила проверки для нашего изображения, такие как тип файла и максимальный размер:
01
02
03
04
05
06
07
08
09
10
11
|
public function rules()
{
return [
[[‘message’], ‘required’],
[[‘message’], ‘string’],
[[‘permissions’, ‘created_at’, ‘updated_at’,’created_by’], ‘integer’],
[[‘image’], ‘safe’],
[[‘image’], ‘file’, ‘extensions’=>’jpg, gif, png’],
[[‘image’], ‘file’, ‘maxSize’=>’100000’],
[[‘image_src_filename’, ‘image_web_filename’], ‘string’, ‘max’ => 255], ];
}
|
И новые атрибуты ярлыков для представлений:
01
02
03
04
05
06
07
08
09
10
11
12
|
public function attributeLabels()
{
return [
‘id’ => Yii::t(‘app’, ‘ID’),
‘message’ => Yii::t(‘app’, ‘Message’),
‘permissions’ => Yii::t(‘app’, ‘Permissions’),
‘image_src_filename’ => Yii::t(‘app’, ‘Filename’),
‘image_web_filename’ => Yii::t(‘app’, ‘Pathname’),
‘created_by’ => Yii::t(‘app’, ‘Created By’),
‘created_at’ => Yii::t(‘app’, ‘Created At’),
‘updated_at’ => Yii::t(‘app’, ‘Updated At’), ];
}
|
Теперь мы можем перейти к просмотру изменений в форме ActiveModel.
Добавление нашего взгляда и функциональности формы
Интеграция загрузки изображений в форму создания статуса
Чтобы включить интеграцию формы загрузки изображений в обновления статуса (показано выше), нам нужно внести изменения в файл /views/status/_form.php
.
Во-первых, мы kartik\file\FileInput
виджет kartik\file\FileInput
вверху и обновляем форму, чтобы она стала составной, которая поддерживает размещение файлов:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
use app\assets\StatusAsset;
use kartik\file\FileInput;
StatusAsset::register($this);
/* @var $this yii\web\View */
/* @var $model app\models\Status */
/* @var $form yii\widgets\ActiveForm */
?>
<div class=»status-form»>
<?php
$form = ActiveForm::begin([
‘options’=>[‘enctype’=>’multipart/form-data’]]);
?>
|
Затем между полем Permissions и кнопками Submit мы добавляем виджет FileInput:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
<?=
$form->field($model, ‘permissions’)->dropDownList($model->getPermissions(),
[‘prompt’=>Yii::t(‘app’,’- Choose Your Permissions -‘)]) ?>
</div>
</div>
<div class=»row»>
<?= $form->field($model, ‘image’)->widget(FileInput::classname(), [
‘options’ => [‘accept’ => ‘image/*’],
‘pluginOptions’=>[‘allowedFileExtensions’=>[‘jpg’,’gif’,’png’],’showUpload’ => false,],
]);
</div>
<div class=»row»>
<div class=»form-group»>
<?= Html::submitButton($model->isNewRecord ? Yii::t(‘app’, ‘Create’) : Yii::t(‘app’, ‘Update’), [‘class’ => $model->isNewRecord ? ‘btn btn-success’ : ‘btn btn-primary’]) ?>
</div>
</div>
|
В строке pluginOptions
мы ограничиваем типы файлов общими форматами изображений, такими как jpg.
По завершении оно будет выглядеть примерно так, ожидая, когда пользователь добавит изображение:
Отображение изображения
Я также собираюсь добавить код для отображения загруженного изображения на потом (после того, как мы закончим поддержку контроллера).
Сначала я добавлю его на страницу просмотра статуса ( /views/status/view.php
), которая очень /views/status/view.php
. Тем не менее, я покажу изображение под деталями элемента:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
<?= DetailView::widget([
‘model’ => $model,
‘attributes’ => [
‘id’,
‘createdBy.email’,
‘message:ntext’,
‘permissions’,
‘image_web_filename’,
‘image_src_filename’,
‘created_at’,
‘updated_at’,
],
]) ?>
<?php
if ($model->image_web_filename!=») {
echo ‘<br /><p><img src=»‘.Yii::$app->homeUrl. ‘/uploads/status/’.$model->image_web_filename.’»></p>’;
}
?>
|
Это будет выглядеть примерно так:
Мы также добавим небольшой миниатюрный вид на нашу страницу индекса состояния ( /views/status/index.php
). Я добавил пользовательский атрибут столбца в виджет GridView в Yii2:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
<?= GridView::widget([
‘dataProvider’ => $dataProvider,
‘filterModel’ => $searchModel,
‘columns’ => [
[‘class’ => ‘yii\grid\SerialColumn’],
‘id’,
‘message:ntext’,
‘permissions’,
‘created_at’,
[
‘attribute’ => ‘Image’,
‘format’ => ‘raw’,
‘value’ => function ($model) {
if ($model->image_web_filename!=»)
return ‘<img src=»‘.Yii::$app->homeUrl. ‘/uploads/status/’.$model->image_web_filename.’» width=»50px» height=»auto»>’;
},
],
[‘class’ => ‘yii\grid\ActionColumn’,
‘template’=>'{view} {update} {delete}’,
‘buttons’=>[
‘view’ => function ($url, $model) {
return Html::a(‘<span class=»glyphicon glyphicon-eye-open»>
}
],
],
],
]);
|
В конечном итоге это будет выглядеть так:
Построение поддержки контроллера
Чтобы сделать все вышеперечисленное возможным, нам нужно завершить интеграцию контроллера.
В верхней части /controllers/StatusController.php
мы должны включить yii\web\UploadedFile
:
01
02
03
04
05
06
07
08
09
10
11
12
|
<?php
namespace app\controllers;
use Yii;
use app\models\Status;
use app\models\StatusSearch;
use app\models\User;
use app\components\AccessRule;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
use yii\filters\VerbFilter;
use yii\filters\AccessControl;
use yii\web\UploadedFile;
|
Затем мы должны обновить функцию actionCreate
:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
public function actionCreate()
{
$model = new Status();
if ($model->load(Yii::$app->request->post())) {
$image = UploadedFile::getInstance($model, ‘image’);
if (!is_null($image)) {
$model->image_src_filename = $image->name;
$ext = end((explode(«.», $image->name)));
// generate a unique file name to prevent duplicate filenames
$model->image_web_filename = Yii::$app->security->generateRandomString().».{$ext}»;
// the path to save file, you can set an uploadPath
// in Yii::$app->params (as used in example below)
Yii::$app->params[‘uploadPath’] = Yii::$app->basePath .
$path = Yii::$app->params[‘uploadPath’] .
$image->saveAs($path);
}
if ($model->save()) {
return $this->redirect([‘view’, ‘id’ => $model->id]);
} else {
var_dump ($model->getErrors());
}
}
return $this->render(‘create’, [
‘model’ => $model,
]);
}
|
По сути, это выполняет следующие операции:
- Мы
image_src_filename
исходное имя файла из информации формы загруженного файла (image_src_filename
). - Мы генерируем уникальное имя файла для нашего сервера (
image_web_filename
). - Мы сохраняем файл в нашем каталоге загрузки (
/web/uploads/status/
). - Мы сохраняем модель.
- Мы перенаправляем на страницу расширенного просмотра.
Вы можете увидеть окончательные результаты с изображением выше, которое включает в себя изображение Тадж-Махала.
Виджет ввода файла от Kartik также предлагает более сложные конфигурации, которые он довольно хорошо документирует, такие как Drag and Drop:
Проверьте больше из них на следующих страницах:
- FileInput Widget Demo
- Загрузить файл в Yii 2 с помощью виджета FileInput
- Расширенная загрузка с использованием виджета Yii2 FileInput
Что дальше?
Я надеюсь, что это поможет вам с основами загрузки файлов в ваше приложение Yii2. Если вы хотите увидеть еще один аналогичный обзор функций такого рода, ознакомьтесь с разделом Создание стартапа с помощью PHP: настройки пользователя, изображения профиля и контактные данные . Этот учебник предлагает несколько иную интеграцию, чем этот учебник, с использованием вкладок, обновлением профилей пользователей и масштабированием изображений.
Следите за будущими уроками из серии «Как программировать с Yii2», поскольку я продолжаю изучать различные аспекты фреймворка. Вы также можете проверить мою серию «Построение стартапа с помощью PHP» , в которой используется расширенный шаблон Yii2, когда я создаю реальное приложение.
Если вы хотите узнать, когда появится следующий учебник по Yii2, следуйте за мной @reifman в Твиттере или зайдите на страницу моего инструктора . Моя страница инструктора будет включать все статьи из этой серии, как только они будут опубликованы.
Ссылки по теме
Вот множество ссылок, которые я использовал для исследования и написания этого урока:
- Yii2 Developer Exchange , мой ресурсный сайт Yii2
- FileInput Widget Демо — Картик
- Загрузить файл в Yii 2, используя виджет FileInput — Kartik
- Код для ввода kartik-v / yii2-widget-file (GitHub)
- Демонстрация загрузки файла в BlueImp JQuery
- Код для 2 amigos/yii2-file-upload-widget: Виджет загрузки файлов BlueImp (Github)
- Загрузка файлов — полное руководство по Yii 2.0