Персональный фотоальбом на yii2

Сегодня рассмотрим создание сайта с нуля. Пусть это будет фотоальбом — с папками для снимков и, собственно, фотографиями.

В качестве платформы для хостинга используем Amazon Web Services.

Для разработки используем PHP-фреймворк Yii2. Выбор обоснован поддержкой MVC, высокой скоростью работы и минимальными потребностями в ресурсах.

Amazon Web Services

Подробности создания виртуального сервера на Amazon Web Services выходят за рамки статьи. Но основные шаги здесь перечислим:

  1. Создайте аккаунт.
  2. Создайте инстанс EC2 t2.micro — в течение года он будет доступен бесплатно, а ресурсов его будет достаточно для достаточно сложного сайта.
  3. По подсказкам создайте политику безопасности, получите приватный ключ и с помощью Putty или ssh подключитесь к созданному инстансу.
  4. Установите Apache 2.4, PHP 5.5 и MySQL (клиентскую и серверную часть).

Инсталляция Yii2

По умолчанию, Apache использует /var/www в качестве корневой папки сайта. Для простоты установим наше приложение в этой папке.

Рекомендуемым способом установки Yii2 является инсталляция через composer. В новом инстансе его нет, поэтому вначале установим:

curl -s http://getcomposer.org/installer | php
mv composer.phar /usr/local/bin/composer

Теперь перейдем в корень сайта и скачаем Yii:

cd /var/www
composer global require "fxp/composer-asset-plugin:1.0.0"
composer create-project --prefer-dist yiisoft/yii2-app-basic gallery

В результате появится папка /var/www/gallery со всем необходимым.

Откройте в броузере адрес http://<внешний-IP-адрес-вашего-инстанса>/gallery/web/index.php — откроется шаблонное приложение yii2 при соблюдении условий:

  • Apache запущен
  • В политике безопасности отрыт доступ к 80-му порту
  • Установка требуемых программных пакетов завершена успешно

2015-04-21_0056

Создание базы данных

Как говорилось выше, будем строить фотоальбом из снимков, объединяемых в папки.

Снимкам и папкам дадим название и описание.

Фотографии будем принимать в формате JPEG и хранить в одном каталоге. Для соблюдения уникальности названия файла, имена файлов будем менять на идентификатор записи о снимке.

Соответственно, для создания базы и таблиц используем команды:

CREATE DATABASE `gallery` /*!40100 DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci */;
USE `gallery`;
CREATE TABLE `folder` (
  `id` int NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `name` varchar(255) NOT NULL,
  `description` text NULL
) ENGINE='InnoDB' COLLATE 'utf8_unicode_ci';
CREATE TABLE `photo` (
  `id` int NOT NULL AUTO_INCREMENT PRIMARY KEY,
  `name` varchar(255) NOT NULL,
  `description` text NULL,
  `folder_id` int(11) NOT NULL,
  FOREIGN KEY (`folder_id`) REFERENCES `folder` (`id`)
) ENGINE='InnoDB' COLLATE 'utf8_unicode_ci';

Примечание: если работать с MySQL с командной строки неудобно и непривычно, скачайте в корневую папку сайта adminer (это потребует предпринять дополнительные меры по обеспечению безопасности — как минимум, установите в MySQL пароль для пользователя root). Для текущей на данный момент версии 4.2.1 установка будет такой:

cd /var/www
wget http://downloads.sourceforge.net/adminer/adminer-4.2.1.php

Для доступа к adminer в броузере введите http://<внешний-IP-адрес-вашего-инстанса>/adminer-4.2.1.php

Базу данных можно создать как командами, приведенными выше, так и при помощи интерфейса adminer. В результате должна получиться такая схема данных:

2015-04-21_0144

Создание моделей

Для начала настроим соединение с базой.

Откройте в текстовом редакторе файл /var/www/html/gallery/config/db.php и поменяйте название базы:

<?php

return [
    'class' => 'yii\db\Connection',
    'dsn' => 'mysql:host=localhost;dbname=gallery',
    'username' => 'root',
    'password' => '',
    'charset' => 'utf8',
];

Теперь создаем модель для папки:

cd /var/www/html/gallery
./yii gii/model --tableName=folder --modelClass=Folder

На запрос подтверждения нажмите «Ввод» — утилита выполнит необходимые действия:

# ./yii gii/model --tableName=folder --modelClass=Folder
Running 'Model Generator'...

The following files will be generated:
        [new] models/Folder.php

Ready to generate the selected files? (yes|no) [yes]:

Files were generated successfully!
Generating code using template "/var/www/html/gallery/vendor/yiisoft/yii2-gii/generators/model/default"...
 generated models/Folder.php
done!

Аналогичным образом создайте модель для фотографии:

./yii gii/model --tableName=photo --modelClass=Photo

CRUD

Сокращение от Create, Read, Update, Delete — это набор операций, которые обеспечат функционирование сайта — создание, чтение, обновление и удаление папок и фотографий.

Начнем с папок:

./yii gii/crud --modelClass=app\\models\\Folder --controllerClass=app\\controllers\\FolderController

Как и при создании моделей, подтвердите создание файлов:

# ./yii gii/crud --modelClass=app\\models\\Folder --controllerClass=app\\controllers\\FolderController
Running 'CRUD Generator'...

The following files will be generated:
        [new] controllers/FolderController.php
        [new] views/folder/_form.php
        [new] views/folder/create.php
        [new] views/folder/index.php
        [new] views/folder/update.php
        [new] views/folder/view.php

Ready to generate the selected files? (yes|no) [yes]:

Files were generated successfully!
Generating code using template "/var/www/html/gallery/vendor/yiisoft/yii2-gii/generators/crud/default"...
 generated controllers/FolderController.php
 generated views/folder/_form.php
 generated views/folder/create.php
 generated views/folder/index.php
 generated views/folder/update.php
 generated views/folder/view.php
done!

Для проверки правильности создания файлов, откройте в броузере http://<внешний-IP-адрес-вашего-инстанса>/gallery/web/index.php?r=folder

Screenshot from 2015-05-06 11:58:02_cropСоздайте несколько папок — позже мы используем их для загрузки фотографий:

Screenshot from 2015-05-06 12:14:55_crop

Расширение модели photo

Как видно из схемы базы данных, в таблице фотографий сохраняются только названия и описания. Соответственно, созданная автоматически модель пока не имеет поле для загрузки файла.

Для добавления поля воспользуемся модулем, находящимся на стадии разработки. Для этого нам потребуется внести изменение в файл /var/www/html/gallery/composer.json:

    "minimum-stability": "dev",

Теперь добавим модуль, отвечающий за поведение поля загрузки файла:

composer require --prefer-dist yii-dream-team/yii2-upload-behavior "*"

В качестве дополнения мы также получаем генератор миниатюр, что удобно при просмотре списка загруженных снимков.

Внесем следующие изменения в файл /var/www/html/gallery/models/Photo.php

<?php

namespace app\models;

use Yii;

/**
 * This is the model class for table "photo".
 *
 * @property integer $id
 * @property string $name
 * @property string $description
 * @property integer $folder_id
 *
 * @property Folder $folder
 */
class Photo extends \yii\db\ActiveRecord
{
    public $image;

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

    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            [['name', 'folder_id'], 'required'],
            [['description'], 'string'],
            [['folder_id'], 'integer'],
            [['name'], 'string', 'max' => 255],
            [['image'], 'safe'],
            [['image'], 'file', 'extensions' => 'jpeg, jpg'],
        ];
    }

    /**
     * @inheritdoc
     */
    public function attributeLabels()
    {
        return [
            'id' => 'ID',
            'name' => 'Name',
            'description' => 'Description',
            'folder_id' => 'Folder ID',
        ];
    }

    /**
     * @return \yii\db\ActiveQuery
     */
    public function getFolder()
    {
        return $this->hasOne(Folder::className(), ['id' => 'folder_id']);
    }

    public function behaviors()
    {
        return [
            [
                'class' => '\yiidreamteam\upload\ImageUploadBehavior',
                'attribute' => 'image',
                'thumbs' => [
                    'thumb' => ['width' => 200, 'height' => 150],
                ],
                'filePath' => '@webroot/images/[[pk]].jpg',
                'fileUrl' => '/images/[[pk]].jpg',
                'thumbPath' => '@webroot/thumbs/[[profile]]_[[pk]].jpg',
                'thumbUrl' => '/thumbs/[[profile]]_[[pk]].jpg',
            ],
        ];
    }
}

Добавим возможность создания, редактирования, просмотра и удаления фотографий:

./yii gii/crud --modelClass=app\\models\\Photo --controllerClass=app\\controllers\\PhotoController

Обновим форму загрузки/редактирования информации о фото в /var/www/html/gallery/views/photo/_form.php:

<?php

use yii\helpers\Html;
use yii\widgets\ActiveForm;
use yii\helpers\ArrayHelper;
use app\models\Folder;

/* @var $this yii\web\View */
/* @var $model app\models\Photo */
/* @var $form yii\widgets\ActiveForm */
?>

<div class="photo-form">

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

    <div class="form-group">
    <?=
       Html::ActiveLabel($model, 'folder_id')
    ?>
    <?=
       Html::activeDropDownList($model, 'folder_id',
          ArrayHelper::map(Folder::find()->all(), 'id', 'name'), ['class'=>'form-control'])
    ?>
    </div>

    <?= $form->field($model, 'image')->fileInput() ?>

    <?= $form->field($model, 'name')->textInput(['maxlength' => 255]) ?>

    <?= $form->field($model, 'description')->textarea(['rows' => 6]) ?>

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

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

</div>

Теперь — представление списка фотографий в /var/www/html/gallery/views/photo/index.php:

<?php

use yii\helpers\Html;
use yii\grid\GridView;

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

$this->title = 'Photos';
$this->params['breadcrumbs'][] = $this->title;
?>
<div class="photo-index">

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

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

    <?= GridView::widget([
        'dataProvider' => $dataProvider,
        'columns' => [
            ['class' => 'yii\grid\SerialColumn'],

            'id',
            'name',
            'description:ntext',
            'folder.name',
            array(
                'format' => 'image',
                'value' => function($data) { return 'thumbs/thumb_'.$data->id.'.jpg'; },
                'contentOptions' => ['class' => 'img-thumbnail'],
            ),

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

</div>

И просмотр отдельного фото в /var/www/html/gallery/views/photo/view.php:

<?php

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

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

$this->title = $model->name;
$this->params['breadcrumbs'][] = ['label' => 'Photos', 'url' => ['index']];
$this->params['breadcrumbs'][] = $this->title;
?>
<div class="photo-view">

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

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

    <?= DetailView::widget([
        'model' => $model,
        'attributes' => [
            'id',
            'name',
            'description:ntext',
            'folder.name',
        ],
    ]) ?>

    <?= Html::img('images/'.$model->id.'.jpg',[
        'class' => 'img-rounded',
    ]) ?>

</div>

Для проверки логики загрузки и отображения снимков откройте в броузере http://<внешний-IP-адрес-вашего-инстанса>/gallery/web/index.php?r=photo и добавьте несколько снимков в подготовленные ранее папки.

Screenshot from 2015-05-07 19:27:50_crop

Последние штрихи

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

Что получилось?

Полнофункциональный сайт фотогалереи. Сайт хорошо смотрится как на компьютерах, так и на мобильных устройствах.

Добавить комментарий