Сегодня рассмотрим создание сайта с нуля. Пусть это будет фотоальбом — с папками для снимков и, собственно, фотографиями.
В качестве платформы для хостинга используем Amazon Web Services.
Для разработки используем PHP-фреймворк Yii2. Выбор обоснован поддержкой MVC, высокой скоростью работы и минимальными потребностями в ресурсах.
Amazon Web Services
Подробности создания виртуального сервера на Amazon Web Services выходят за рамки статьи. Но основные шаги здесь перечислим:
- Создайте аккаунт.
- Создайте инстанс EC2 t2.micro — в течение года он будет доступен бесплатно, а ресурсов его будет достаточно для достаточно сложного сайта.
- По подсказкам создайте политику безопасности, получите приватный ключ и с помощью Putty или ssh подключитесь к созданному инстансу.
- Установите 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-му порту
- Установка требуемых программных пакетов завершена успешно
Создание базы данных
Как говорилось выше, будем строить фотоальбом из снимков, объединяемых в папки.
Снимкам и папкам дадим название и описание.
Фотографии будем принимать в формате 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. В результате должна получиться такая схема данных:
Создание моделей
Для начала настроим соединение с базой.
Откройте в текстовом редакторе файл /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
Создайте несколько папок — позже мы используем их для загрузки фотографий:
Расширение модели 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 и добавьте несколько снимков в подготовленные ранее папки.
Последние штрихи
Мы создали административную часть сайта. Теперь пришло время пользовательского интерфейса. Оставим эту работу нашим читателям — делитесь своими наработками. С удовольствием разместим ссылки на самые интересные репозитории и/или готовые сайты.
Что получилось?
Полнофункциональный сайт фотогалереи. Сайт хорошо смотрится как на компьютерах, так и на мобильных устройствах.



