Composer + Yii + Imagine: небольшое приложение для загрузки картинок

Владимир | | PHP, Web разработка, Yii.

yii composer

Совсем недавно фреймворк Yii включили в репозиторий packagist.org. Новость очень хорошая, т.к. теперь можно использовать один менеджер зависимостей Composer для обновления и фреймворка, и дополнительных библиотек.

В этой статье мы рассмотрим пример создания несложного приложения на основе Yii, которое позволит загружать картинки и автоматически создавать их миниатюры. Задача тривиальная, но мне хотелось показать подключение дополнительных библиотек с помощью Composer, а в packagist как раз входит Imagine (очень удобная библиотека для работы с изображениями).

Код приложения с инструкцией по установке доступен на GitHub.

Source

Теперь перейдём непосредственно к созданию приложения.

Шаг 1. Устанавливаем Composer.

Тут всё предельно просто. Для Windows есть инсталлятор. Если вы работаете в Linux или MacOS нужно будет выполнить несколько команд из консоли. И инсталлятор, и команды можно взять на официальном сайте.

Шаг 2. Создаём папку для приложения.

В моём случае это yii-composer. Т.е. приложение доступно по адресу

http://localhost/yii-composer

Но, естественно, название и размещение может быть любым.

Шаг 3. Создаем composer.json

В этом файле содержатся названия компонентов, которые будет загружать Composer.

{
    "require": {
        "yiisoft/yii": "dev-master",
        "imagine/Imagine": "dev-master"
    }
}

Как видите, данные записаны в JSON формате. Здесь мы указываем менеджеру зависимостей, что нужно загрузить Yii фреймворк и библиотеку Imagine. Преимущество такого подхода заключается в том, что Composer сам отслеживает возможные зависимости. Т.е. когда разработчик библиотеки выкладывает её в репозиторий, он указывает необходимые условия для её работы (например, версию PHP), списки зависимостей и возможных конфликтов с другими библиотеками.

Шаг 4. Загружаем компоненты.

Для этого нужно выполнить команду:

composer install

или composer update (если install уже выполнялась, и вы изменяли composer.json).

В результате Composer загрузит указанные пакеты, и мы получим следующую структуру папок.

folder-structure

Как видите, Composer создал папку vendor и загрузил в неё библиотеку imagine и фреймворк.

Шаг 5. Создаем приложение.

Здесь мы используем стандартную утилиту yiic. Я решил, что приложение должно находиться в папке public_html, но вы можете использовать другую структуру папок.

В любом случае, алгоритм следующий.
Из папки /vendor/yiisoft/yii/framework
выполняем команду

yiic webapp ../../../../public_html

Вместо ../../../../public_html можно указать свою папку для приложения.

Yiic создаст нужные файлы, и мы увидим результат по адресу.
http://localhost/yii-composer/public_html

Шаг 6. База данных.

Данные о картинках будем хранить в базе данных в таблице images со следующими полями:
id – первичный ключ;
title – название картинки;
url – URL картинки.

После этого указываем параметры подключения в файлах protected/config/main.php и protected/config/console.php.

'db'=>array(
	'connectionString' => 'mysql:host=localhost;dbname=yii-composer',
	'emulatePrepare' => true,
	'username' => 'root',
	'password' => 'your_pass',
	'charset' => 'utf8',
),

Шаг 7. Создаём модель, представление и контроллер.

Для этого в файле protected/config/main.php раскомментируем модуль gii и указываем какой-нибудь пароль.

Заходим в админку gii
/public_html/index.php?r=gii/default/login

Создаем с помощью гененратора модель (Images), контроллер (для модели Images) и представления.

На данном этапе посмотреть результат можно на странице
/index.php?r=images

На этом этапе я подробно не останавливаюсь, т.к. процедура хорошо описана в документации Yii.

Шаг 8. Настраиваем представление.

Нам нужно добавить в форму поле для загрузки файла и убирать поле url (т.к. url картинки будет генерироваться автоматически).

Добавляем поле для загрузки файла (файл views/images/_form.php)

<?php $form=$this->beginWidget('CActiveForm', array(
	'id'=>'images-form',
	'enableAjaxValidation'=>false,
	'htmlOptions'=>array(
			'enctype'=>'multipart/form-data',
		),
)); ?>
...
<div class="row">
	<?php echo $form->labelEx($model,'image'); ?>
	<?php echo $form->fileField($model,'image'); ?>
	<?php echo $form->error($model,'image'); ?>
</div>

Шаг 9. Подключаем библиотеки, загруженные с помощью Composer

Composer автоматически создаёт загрузчик (файл vendor/autoload.php), который соответствует спецификации PSR-0. На практике это означает, что для того, чтобы использовать библиотеки, загруженные с помощью Composer, достаточно подключить загрузчик в файле index.php фреймворка.

Т.е. для данного примера добавляем в файл public_html/index.php строку:

require_once('../vendor/autoload.php');

Теперь можно использовать Imagine. Например,

$imagine = new Imagine\Gd\Imagine();

Как видите, при создании объекта необходимо путь к классу Imagine начиная от папки vendor/imagine/lib. Т.е. фактически вам без разницы, где именно Composer хранит библиотеки. Вы можете использовать примеры из документации к Imagine без какой-либо дополнительной настройки. Достигается это за счёт того, что Composer автоматически создаёт файл vendor/composer/autoload_namespaces.php, который возвращает реальное размещение библиотек. В данном случае:

return array(
    'Imagine' => $vendorDir . '/imagine/Imagine/lib/',
);

Шаг 10. Добавляем обработчик загрузки файла в модель.

Для этого добавляем свойство $image в класс Images (файл protected/models/images.php)

public $image;

Затем добавляем это поле в правила проверки данных модели

public function rules()
{
	return array(
		array('title', 'length', 'max'=>255),
		array('title, image', 'required'),
		array('image', 'file', 'types'=>'jpg, jpeg, gif, png'),
		// The following rule is used by search().
		// @todo Please remove those attributes that should not be searched.
		array('id, title, image', 'safe', 'on'=>'search'),
	);
}

В данном случае мы разрешаем загрузку файлов с расширениями jpg, jpeg, gif и png.

И добавляем следующие методы.

public function beforeSave() {
	$this->url = $this->image->getName();
	return parent::beforeSave();
}

Этот метод сохраняет имя загруженного файла в поле url.

Следующий метод создаёт миниатюру.

public function createThumbs() {
	$imagine = new Imagine\Gd\Imagine();

	$size = new Imagine\Image\Box(40, 40);
	$mode = Imagine\Image\ImageInterface::THUMBNAIL_INSET;

	$imagine->open(Yii::app()->params['uploadsDir'].$this->image->getName())
		->thumbnail($size, $mode)
		->save(Yii::app()->params['uploadsDir'].$this->getThumbnailName());
}

В данном случае мы создаём миниатюру размером в 40px по большей стороне и сохраняем её в папку public_html/uploads. Размещение папки указываем в параметрах (файл protected/config/main.php).

Последний метод в модели формирует имя файла миниатюры (добавляет суффикс _40x40 к имени полноразмерной картинки).

public function getThumbnailName() {
	$parts = explode('.', $this->url);
	$parts[count($parts) - 2] .= '_40x40';
	return implode('.', $parts);
}

Шаг 11. Добавляем поддержку загрузки файла в контроллере.

Для этого в файле protected/controllers/ImagesController.php изменяем метод actionCreate

$model->image=CUploadedFile::getInstance($model,'image');
if($model->save()){
	if ($model->image->saveAs(Yii::app()->params['uploadsDir'].$model->image->getName())) {
		$model->createThumbs();
	}
	$this->redirect(array('view','id'=>$model->id));
}

Здесь выполняется две проверки. Первая – при вызове save – проверяется заполнение полей модели. При второй проверке проверяется, успешно ли сохранён оригинальный файл, и после этого создаётся миниатюра.

Шаг 12. Показываем картинки.

Для этого в файл представления protected/views/view.php добавляем строки.

<?php
	echo CHtml::image(Yii::app()->baseUrl.'/uploads/'.$model->url, $model->title);
	echo CHtml::image(Yii::app()->baseUrl.'/uploads/'.$model->getThumbnailName(), $model->title);
?>

Естественно, на практике выводить миниатюру под картинкой, особого смысла нет. Но в этом примере дизайн странице не рассматриваем, поэтому я привёл только код, необходимый для отображения картинки.

Заключение.

Статья получилась довольно объёмной, но большая её часть – обычный код для работы с файлами. Подключение Composer сводится к подключению загрузчика. В результате у вас упрощается подключение дополнительных библиотек. Кроме того, в этом случае можно оставить в системе контроля версий только код приложения, т.к. любой разработчик всегда сможет получить нужные версии библиотек с помощью всего одной команды (composer install).

Ещё советую почитать статью Creating Yii applications with composer.

P.S. А для тех, кто интересуется разработкой с использованием Flash — FlashAdverts