Tickets + UserFiles - загрузка с фронт-энда

Для чего:

— Если у вас реализовано добавление тикетов с фронт-энда пользователями и вам нужен удобный инструмент для отслеживания прикрепленных изображений
— Вам нужно несколько независимых друг от друга форм добавления изображений с уникальными параметрами
— Вы хотите иметь единую закладку с загруженными изображениями в тикетах


Нам потребуется:

Tickets, ms2form или любой другой модуль для добавления ресурсов с фронт-энда
UserFiles для загрузки самих изображений

Примечание: на момент реализации данного решения модуль ms2guploader еще не был в общем доступе. В теории, схожим способом можно прикрепить его для загрузки изображений в ms2gallery.

Шаг 1
Вызываем сниппет [[!ticketform]] в желаемом месте и указываем для него чанки tplFormCreate и tplFormUpdate.

В чанке tplFormCreate ДО открывающего или ПОСЛЕ закрывающего тега form совершаем обычный вызов сниппета UserForm:
[[!ufForm?
	&list=`ticket-upload`
	&anonym=`0`
	&dropzone=`{
		"maxFilesize":2,
		"maxFiles":3,
		"acceptedFiles":".jpg, .jpeg, .gif, .png",
		"template":"edit"
	}`
]]
Зачем: тег form не может содержать внутри себя другой тег form, а сниппет ufForm генерирует для себя отдельную форму.

Впрочем, это совершенно не означает, что визуально загрузочные области всегда должны располагаться до или после основной формы. Используя jQuery-плагины (например Magnific Popup или Fancybox) вы можете расположить в желаемых областях ticketform кнопки «загрузки», нажав на которые сниппет ufForm будет подгружаться во всплывающем окне.

В чанке tplFormUpdate мы реализуем аналогичный предыдущему вызов [[!ufForm]] плюс (так как редактируемый документ уже имеет свой id) дописываем параметр:

&parent=`[[#GET.tid]]`
//для ms2form - [[#GET.pid]]

Примечание: [[#GET.tid]] — плейсхолдер, получаемый от парсера pdoTools. Если pdoTools у вас не установлен, то вам необходимо получить вышеописанное значение get-параметра иным способом.

Шаг 2

Пишем плагин на событие OnDocFormSave, который будет перепривязывать изображения для свежесозданного ресурса (без него все изображения, загруженные с чанка tplFormCreate, привязаны к странице с формой).

<?php
	if ($modx->context->key == 'mgr') {return;}

	//Ограничиваем работу только для Ticket'ов (для ms2form необходимо указать msProduct)
	if (!$resource OR $resource->get('class_key') != 'Ticket') {
		return;
	}
	
	if ($mode == 'new') {
		//Подключаем UserFiles
		$corePath = $modx->getOption('userfiles_core_path', null, $modx->getOption('core_path', null, MODX_CORE_PATH) . 'components/userfiles/');
		$UserFiles = $modx->getService('UserFiles', 'UserFiles', $corePath . 'model/userfiles/', array('core_path' => $corePath));

		//Ищем в свежесозданном документе прикрепленные изображения
		$q = $modx->newQuery('UserFile');
		$q->where(array(
			'list'  => 'ticket-upload',	//Если у вас более одной формы ufForm с различными параметрами list - их необходимо перечислить 'list:IN'  => array('ticket-upload','msproducts-upload'), чтобы не "переписать" лишнего
			'parent'  => 39,			//Id ресурса с вызванной формой ticketform. Если у вас более одной страницы с формой для добавления тикетов - их необходимо перечислить 'parent:IN'  => array(39,40), чтобы не "переписать" лишнего
			'class' => 'modResource',
			'createdby' => $modx->user->id,
		));
		$q->select('id');
		$q->sortby('rank ASC, createdon', 'ASC');
		
		//Доступно с версии 2.1.7-beta (10.04.2016)
		if ($q->prepare() && $q->stmt->execute()) {
			$sql = '';
			$table = $modx->getTableName('UserFile');
			
			//Если изображения присутствуют - перепривязываем их к новому ресурсу, обновляем пути и перегенерируем превьюшки
			if ($ids = $q->stmt->fetchAll(PDO::FETCH_COLUMN)) {
				foreach ($ids as $k => $id) {
					$file = $modx->getObject('UserFile', $id);
					$file->set('parent', $resource->get('id'));
					$file->save();
					if ($children = $file->getMany('Children')) {
						foreach ($children as $child) {
							$child->remove();
						}
						
						$file->generateThumbnails();
					}
				}
				$modx->exec($sql);
			}
		}
	}

Важно: до версии 2.1.7-beta задачу можно было решить следующим способом (более быстрое решение, т.к. не переносит файлы физически, а только подменяет их родителя. Из минусов — все файлы валяются в одной директории):
//...
if ($q->prepare() && $q->stmt->execute()) {
	$sql = '';
	$table = $modx->getTableName('UserFile');

	if ($ids = $q->stmt->fetchAll(PDO::FETCH_COLUMN)) {
		foreach ($ids as $k => $id) {
			$sql .= "UPDATE {$table} SET `parent` = '{$resource->get('id')}' WHERE `id` = {$id};";
		}
		$modx->exec($sql);
	}
}

Совет: если вы используете это решение для создания альбомов (или любой другой задачи, где пользователю не нужен доступ ко всем превьюшкам) — вы можете создать отдельный источник файлов для загружаемых изображений (без превьюшек) и подменять его на основной в этом же плагине.

Шаг 3

Теперь осталось только запретить пользователю создавать документ до того момента, пока изображения не загружены до конца/превьюшки не успели сгенерироваться.

На текущий момент (сейчас пути скриптов нельзя изменять из системной настройки) для этого нам потребуется видоизменить дефолтный файл assets/components/userfiles/vendor/dropzone/dist/dropzone.js, а именно:

— Блокировать кнопку создания ресурса на событие:
myDropzone.on('addedfile', function(file) {

});
— Разблокировать обратно на событие 'complete'.

Вот вроде и все..)
Максим Кузнецов
12 апреля 2016, 05:05
modx.pro
16
4 401
+5

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

Jenya Filimonov
12 апреля 2016, 08:28
0
Спасибо: )
    Jenya Filimonov
    12 апреля 2016, 09:01
    0
    Один вопрос. А возможно, чтобы это работало немного в другую сторону? Типа — добавляешь изображение и к нему автоматом создается тикет. Типа у изображения появляется возможность комментирования (что есть у тикетов), голосовалка и прочие плюшки.
      Максим Кузнецов
      12 апреля 2016, 09:16
      0
      На мой взгляд, эту задачу нужно и реализовывать «в другую сторону»:
      — загружаем кучу изображений в «альбом» (ресурс)
      — при нажатии на превьюшку открывать изображение в полноценном всплывающем окне
      — подгружать в это окно (помимо самого изображения) комментарии TicketComments с уникальным &thread для данной картинки (не ресурса)
      — расширить таблицу UserFiles, добавив в нее столбец для хранения рейтинга
      — выводить рейтинг/кнопки для его изменения

      Впрочем, можно попробовать реализовать и через ticketform + ufForm:
      — создаете страницу «добавить фотографию»
      — через TicketForm выводите в ней формы для заполнения полей ресурса (заголовок, описание)
      — там же вызываете ufForm с параметром
      &dropzone=`{"maxFiles":1}`
      — навешиваете рейтинги/комментарии в шаблоне созданной страницы (как и для обычного ресурса)
      Николай Загумённов
      25 мая 2016, 20:46
      0
      Можно ли этот компонент использовать для прикрепления изображений к комментариям тикетс?
      Константин
      06 мая 2018, 15:23
      0
      Как добавить кнопку добавления файлов в TicketForm?
        Максим Кузнецов
        06 мая 2018, 15:43
        0
        Все зависит от того, что эта кнопка должна делать:
        — вы можете подключить любую библиотеку всплывающих окон, засунуть во всплывающее окно вызов ufForm, а на кнопку «добавить файлы» повесить открытие этого окна
        — вы можете скрыть форму ufForm с помощью css, а при нажатии на кнопку «добавить файлы» менять её отображающие классы или стили

        Если вопрос был в том, где необходимо дописать html кнопки: чанки tplFormCreate/tplFormUpdate.
          Константин
          06 мая 2018, 16:12
          0
          Функция той кнопки, которая находится под формой добавления файлов меня устраивает. Мне нужно ее просто перенести в форму Tickets, а форма с изображениями нужно, чтобы оставалась под формой Tickets
            Максим Кузнецов
            06 мая 2018, 16:38
            +1
            1. На кнопку «выберите файлы» в чанке сниппета ufForm навешиваете уникальный id
            id="my-button"

            2. Визуально скрываете эту же кнопку с помощью стилей или классов
            style="display: none;"

            3. На кнопку «добавить фотографию» вешаете событие, указав id из шага 1:
            onclick="$('#my-button').trigger('click');"
            (для примера из шага 3 требуется подключенный jQuery до кнопки «добавить фотографию»)
              Константин
              06 мая 2018, 17:57
              0
              Спасибо! Но не получилось по-вашему. Вот так сработало:
              $(document).ready(function () {
                  $( "#project-add-img-link" ).click(function() {
                      document.getElementById('my-button').click();
                  });
              });
        Константин
        06 мая 2018, 23:27
        0
        Максим, нужна Ваша помощь. Пару недель назад, следуя Вашей инструкции по загрузке файлов к тикетам, у меня все получилось сделать без проблем. Т.е. файлы прикреплялись к новому тикету. Единственное, я поменял в Вашем плагине часть:
        $q->where(array(
        'list'  => 'default', // здесь поменял на default, иначе в админке не видел файлов, прикрепленных к тикету
        'parent'  => $resource->get('id'), // здесь у меня нет привязки к конкретному разделу, где добавляется тикет
        'class' => 'modResource',
        'createdby' => $modx->user->id,
        ));

        В сниппетах ufForm указал
        &list=`default`

        Сегодня обнаружил, что загруженные файлы прикрепляются к родительской секции, а не к дочерним тикетам. Что только я не делал и хоть ты тресни, ничего не получается. За две недели много чего по сайту было сделано, может что напортачил. Хотя маловероятно, что что-то могло повлиять на работу плагина. Попробовал все делать с нуля по Вашей инструкции и все равно ничего не получается, как будто плагин не отрабатывает как нужно и не перезаписываются пути для вновь созданного ресурса. Может на что-то следует обратить внимание?
          Максим Кузнецов
          07 мая 2018, 01:25
          0
          Возможно, стоит попробовать указать
          'parent'  => $resource->get('parent')

          Дело в том, что при создании тикета, он физически формируется лишь при нажатии на кнопку «добавить», в то время как сами изображения в моем способе загружаются ДО создания ресурса, а в процессе его создания уже переназначаются новому ресурсу. Поэтому и необходим промежуточный родитель.
            Константин
            07 мая 2018, 10:53
            0
            Неа, не помогло. Не знаю, куда еще думать. С моими знаниями в MODX чувствую не скоро решу проблему.
              Максим Кузнецов
              07 мая 2018, 12:05
              0
              Боюсь и я вам помочь не в силах, если при возвращении к исходным параметрам работоспособность не восстановилась.
              Навскидку, тут одно из: или сторонний плагин или код, влияющий на функционал, или в новых версиях UserFiles что-то изменилось, или не все восстановили.
              Константин
              07 мая 2018, 14:59
              0
              Хорошо. Если я не смогу разобраться, будет у Вас возможность помочь? Не бесплатно, конечно же.
          Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
          18