Как загрузить/обновить" изображение к тикету?

Приветствую!
Стояла задача: при создании тикета из фронтенда загружать главное изображение, которое будет использоваться в превью и отображаться на странице самого тикета в начале.

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

Кратко:
1. В форму создания тикета добавляем поле input type=«file»
2. Создаем плагин на событие сохранения формы с загрузкой и изменением размеров изображения.

Итак:
1. На всякий случай создаем копию чанка tpl.Tickets.form.create и редактируем его.
2. Форме создания тикета добавляем аттрибут enctype=«multipart/form-data», т.к. будем загружать файлы:
<form class="well create" method="post" action="" id="ticketForm" enctype="multipart/form-data">
3. Внутри самой формы добавляем поле для загрузки изображения. Я сделал так:
<div class="form-group">
     <label for="ticket-photo">Изображение</label>
     <input type="file" class="form-control" name="photo"/>
    <span class="error" id="error_ticketphoto"></span>
</div>
Сохраняем. Все, с редактированием чанка tpl.Tickets.form.create закончили.



4. Создаем текстовое ТВ-поле для хранения имени изображения. Назовем его srcImg. Не забываем указать доступы для шаблонов страниц создания и вывода тикета.

5. Создаем в корне сайта папку imgTickets, а в ней папки user_uploads и tmp.

6. Создаем новый плагин, назовем его ImgTicketsNew, который будет загружать изображение в папку imgTickets/tmp/, создавать копию изображения с новыми размерами в папке imgTickets/user_uploads/ и удалять оригинал изображения.
if ($modx->event->name == 'OnDocFormSave') {
	if($mode == 'new'){  
		if (!empty($_FILES)) {              
			$id = $resource->get('id');
 			$folder = 'imgTickets/user_uploads/';   //Папка с загруженными изображениями
			$path = MODX_BASE_PATH.$folder;         // Путь от корня до нужного места
			$tmp_path = MODX_BASE_PATH.'imgTickets/tmp/';
			$tv_name = 'srcImg';                    // имя текстовой тв для изображения 
             
			// все значения файла
			$nameFile = $_FILES['photo']['name'];
			$typeFile = $_FILES['photo']['type'];
			$tmpNameFile = $_FILES['photo']['tmp_name'];
			$sizeFile = $_FILES['photo']['size']; 
             
			$limit_size = 5*1024*1024; // 5 Mb - максимальный размер загружаемого файла
			$max_width = 800;
			$extensionFile = substr(strrchr($nameFile, '.'), 1); // получаем расширение файла
            
			// новое имя файла
			$NewNameFile = 'id_'.$id.'_'.date("m_d_y").'.'.$extensionFile;  
			$filename = $tmp_path.$NewNameFile;
            
			// проверяем зашёл ли файл и подходит ли его размер 
			if(is_uploaded_file($tmpNameFile) and $sizeFile <= $limit_size) {
                
				// тип содержимого
        			header('Content-Type: '.$typeFile);	
				// загружаем файл
				move_uploaded_file($tmpNameFile, $filename);
                	
				if ($typeFile == 'image/jpeg')
					$image = imagecreatefromjpeg($filename);
				elseif ($typeFile == 'image/png')
					$image = imagecreatefrompng($filename);
				elseif ($typeFile == 'image/gif')
					$image = imagecreatefromgif($filename);
				else
					return false;
        			
				list($width, $height) = getimagesize($filename);
                	
				if ($width > $max_width) {
					// получение новых размеров
					$ratio = $width/$max_width;
					$new_width = round($width/$ratio);
					$new_height = round($height/$ratio);
                
					// ресэмплирование
					$image_p = imagecreatetruecolor($new_width, $new_height);
					imagecopyresampled($image_p, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
                
					// сохраняем изображение в папку
					imagejpeg($image_p, $path.$NewNameFile, 100);
					// записываем в наш тв
					$resource->setTVValue($tv_name, $folder.$NewNameFile);
                		}
				// если картинку уменьшать не нужно
				else {
					// копируем изображение в папку
                			copy($tmp_path.$NewNameFile, $path.$NewNameFile);
                			// записываем в наш тв
                			$resource->setTVValue($tv_name, $folder.$NewNameFile);
            			}
                
    				// Очищаем память
    				imagedestroy($image);
    				// Удаляем временный файл (закомментируйте строку, если не хотите удалять оригиналы изображений)
   				unlink($tmp_path.$NewNameFile);
			}
		}
	} 
}
7. Не забываем в настройках плагина поставить галочку во вкладке Системные событияна OnDocFormSave. Сохраняем.

8. В шаблоне вывода тикета добавляем:
[[*srcImg:notempty=<img style="padding:15px; margin: 0 auto; max-width:100%" class="media-object" src="[[*srcImg]]" alt="[[*pagetitle]]" title="[[*pagetitle]]">`]]


Все работает, но есть небольшие проблемы:
{решено} 1. При загрузке изображения с расширением .png, прозрачный фон заменяется на черный.
2. При создании тикета и добавлении фото с телефона, фото получается перевернутым из-за вертикальной съемки, нужно ориентацию картинки как то отслеживать, либо организовывать редактирование фото перед загрузкой.
Василий Stepanov
19 мая 2017, 13:45
modx.pro
2
1 313
+2
Поблагодарить автора Отправить деньги

Комментарии: 4

Василий Stepanov
24 мая 2017, 12:10
1
+1
Проблема № 1 При загрузке изображения с расширением .png, прозрачный фон заменяется на черный. решена!
При ресемплировании выключаем режим сопряжения цветов и включаем сохранение альфаканала:
//Отключаем режим сопряжения цветов
imagealphablending($image_p, false);
//Включаем сохранение альфа канала
imagesavealpha($image_p, true);
И в зависимости от расширения исходного файла сохраняем изображение:
// сохраняем изображение в папку
if ($typeFile == 'image/jpeg')
imagejpeg($image_p, $path.$NewNameFile, 100);
elseif ($typeFile == 'image/png')
imagepng($image_p, $path.$NewNameFile);
else
return false;
Чтобы ввесь код сюда не копировать, замените условие if ($width > $max_width) {...} на следующее:
if ($width > $max_width) {
	// получение новых размеров
	$ratio = $width/$max_width;
	$new_width = round($width/$ratio);
	$new_height = round($height/$ratio);
                    
	// ресэмплирование
	$image_p = imagecreatetruecolor($new_width, $new_height);

	//Отключаем режим сопряжения цветов
	imagealphablending($image_p, false);
	//Включаем сохранение альфа канала
	imagesavealpha($image_p, true);
                    
	imagecopyresampled($image_p, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);
                    
	// сохраняем изображение в папку
	if ($typeFile == 'image/jpeg')
	imagejpeg($image_p, $path.$NewNameFile, 100);
	elseif ($typeFile == 'image/png')
	imagepng($image_p, $path.$NewNameFile);
	else
	return false;
                    
	// записываем в поле photo
	$profile->set('photo', $folder.$NewNameFile);
	$profile->save();
}
    Василий Stepanov
    28 мая 2017, 13:56
    0
    Нашел ошибку! Нужно
    // записываем в поле photo
    $profile->set('photo', $folder.$NewNameFile);
    $profile->save();
    Заменить на
    // записываем в наш тв
    $resource->setTVValue($tv_name, $folder.$NewNameFile);
    Alexey
    10 октября 2020, 09:24
    0
    А как плагин ведет себя при обновлении тикета?
      Alexey
      10 октября 2020, 09:42
      0
      Просто я заменил в Вашем плагине строку
      if($mode == 'new'){...
      на
      if($mode == 'new' || $mode == 'upd' && $resource->class_key == "Ticket"){...
      По идее, при обновлении тикета, если не изменяется изображение, то ни чего с ним и не должно происходить?
      Но в моем случае затирается ранее загруженное изображение…
      Не подскажете?
      Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
      4