Первая задача:
Описание:
Имеются Новости, Статьи и т.д. - то есть, таблицы news, articles, ... . У новостей должно быть 3 изображения + alt.
Хранить собираюсь так:
/path/to/vasja.png;
/path/to/vasja-500x500.png;
/path/to/vasja-100x100.png;
alt = Вася МегоМозг;
Вопросы:
1) Создавать таблицу images с 4мя этими полями, а в таблицах news,articles хранить id изображения или есть инной разумный вариант?
2) Как правильно обрабатывать, сохранять и вообще работать с изображениями? В моделе, контроллере или писать что-то отдельное для этого дела? (вопрос общий)
Вторая задача:
Описание:
Тут все страшно.
Думаю тут есть люди которые сидят в ВК и загружали аватарку. Так вот, мне нужен функционал такого же загрузчика как в ВК.
То есть, по шагам:
1) грузим фотку
2) выделяем и сохраняем область фотки для аватарки, то есть метод обрезания (crop).
3) подгружаеться уже обрезанная фотка и так же, выделям и сохраням область фотки под миниатюру (так же метод crop).
Как это сейчас у меня выглядет.
Заходим в админку, нажимаем создать новость, среди всех полей есть поле изображение. Нажимаем, грузим изображение, после загрузки всплывает модальное окно и 2 раза делаеться обрезание. http://joxi.ru/buxrU_3JTJA5U5nG76I
Функционал такой:
Грузим фото, по событию изменения кнопки загрузки файла, js вызывает метод контроллера (отдельного для этого), который обрабатывает файл (проверяет, существует ли имя, создает папку, если нужна и т.д/сохраняет файл), этот метод возвращает js-ту имя изображения, после этого всплывает модальное окно в котором делаем обрезание, жмем сохранить - опять летит методу контроллера, который обрезает/сохраняет и возвращает путь обрезанного файла и так 2 раза с обрезанием.
И тут такие моменты:
1) Изображения уже загружены, а новость еще не сохранена, вдруг пользователь отменит создание.
2) Как сохранить после этих операций имена всех изображений в базу не представляю. По сабмиту будет читать value поля, в которое изначально попало оригинальное изображение. А у нас первый метод по загрузке может изменить имя этого файла, если такой уже существует.
Описал, теперь кодом.
FileController.php
Код: Выделить всё
namespace app\controllers;
use Yii;
use yii\web\Controller;
use yii\web\UploadedFile;
use yii\helpers\Inflector;
use yii\helpers\FileHelper;
use yii\imagine\Image;
use Imagine\Image\ImageInterface;
class FileController extends Controller
{
public $file;
public $fileName;
public $fileExt;
public $path = 'uploads/';
private function upload($path='images')
{
$this->path = FileHelper::normalizePath($this->path.$path).DIRECTORY_SEPARATOR;
if (!file_exists($this->path)) {
FileHelper::createDirectory($this->path);
}
$this->file = UploadedFile::getInstanceByName('file');
$this->fileName = Inflector::slug($this->file->basename);
$this->fileExt = $this->file->extension;
if(file_exists($this->path.$this->fileName . '.' . $this->fileExt)) {
$this->fileName .= '-' . rand(10000,99999);
}
return $this->fileName . '.' . $this->fileExt;
}
private function resize($width, $height)
{
Image::thumbnail(
$this->path . $this->fileName . '.' . $this->fileExt,
$width,
$height,
ImageInterface::THUMBNAIL_INSET
)->save(
$this->path . $this->fileName . '-' . $width . 'x' . $height . '.' . $this->fileExt,
['quality' => 100]
);
return $this->fileName . '-' . $width . 'x' . $height . '.' . $this->fileExt;
}
private function crop($file, $width, $height , $x, $y)
{
Image::crop(
$this->path . $file,
$width,
$height,
[$x, $y]
)->save(
$this->path . $this->fileName . '-' . $width . 'x' . $height . '.' . $this->fileExt,
['quality' => 100]
);
return $this->fileName . '-' . $width . 'x' . $height . '.' . $this->fileExt;
}
private function save()
{
$this->file->saveAs($this->path . $this->fileName . '.' . $this->fileExt);
}
public function actionAjaxUploadResize()
{
if(isset($_POST['path'])) {
$path = $_POST['path'];
} else {
$path = 'images';
}
$this->upload($path);
$this->save();
$responce = Yii::$app->get('response');
$responce->format = 'json';
$responce->data = ['url' => Yii::$app->request->hostInfo . DIRECTORY_SEPARATOR . $this->path, 'file' => $this->resize(570,500), 'filename' => $this->fileName . '.' . $this->fileExt];
$responce->send();
}
public function actionAjaxCrop()
{
if(isset($_POST)) {
$path = $_POST['path'];
$file = $_POST['file'];
$filename = $_POST['filename'];
$width = $_POST['width'];
$height = $_POST['height'];
$x = $_POST['x'];
$y = $_POST['y'];
}
$info = pathinfo($filename);
$this->fileName = $info['filename'];
$this->fileExt = $info['extension'];
$this->path = FileHelper::normalizePath($this->path.$path).DIRECTORY_SEPARATOR;
$responce = Yii::$app->get('response');
$responce->format = 'json';
$responce->data = ['url' => Yii::$app->request->hostInfo . DIRECTORY_SEPARATOR . $this->path, 'file' => $this->crop($file, $width, $height, $x, $y), 'filename' => $this->fileName . '.' . $this->fileExt];
$responce->send();
}
}
Код: Выделить всё
var input = $('#news-file, #article-file');
var modal = $('#modal-image');
var imagePath;
input.on('change', function(){
if(this.id == 'news-file') {
imagePath = 'images/news';
} else {
imagePath = 'images/articles';
}
var file = ajaxUpload(this,imagePath);
crop(file.filename, file.file, file.url + file.file, imagePath);
});
function ajaxUpload(input,imagePath)
{
var formData = new FormData();
var file = input.files[0];
if (!file.type.match('image.*')) {
return;
}
formData.append('file', file, file.name);
formData.append('path', imagePath);
return $.parseJSON($.ajax({
url: "/file/ajax-upload-resize",
type: "POST",
data: formData,
processData: false,
contentType: false,
async: false,
}).responseText);
}
function crop(filename, file, src, imagePath, mode=true)
{
var data = '';
var image = document.createElement('img');
image.id = 'image';
image.src = src;
modal.find('.modal-body').html(image);
if(mode==true) {
modal.modal('show');
}
$('#image').Jcrop({
bgColor: 'black',
bgOpacity: .4,
minSize: [145,82],
aspectRatio: 145/82,
onChange: function(coords){
data = coords;
}
});
$('#save-image').on('click', function(){
if(mode==false) {
modal.modal('hide');
}
return $.ajax({
url: '/file/ajax-crop',
method: 'POST',
data: {
'filename': filename,
'path': imagePath,
'file': file,
'x': data.x.toFixed(),
'y': data.y.toFixed(),
'width': data.w.toFixed(),
'height': data.h.toFixed(),
},
success: function(data) {
if(mode==true) {
crop(data.filename, data.file, data.url + data.file, imagePath, false);
}
}
});
});
}
Этот вопрос тесно связан с первым. Сначала надо бы разобраться как и где правильно обрабатывать загрузку файлов, а потом уже манипуляции вот такие проводить, но всеравно ответ на второй вопрос нужен. С нетерпением жду ответов. Заранее спасибо.