'название поля'] */ protected $cacheUrl = []; /** @var string индекс размера для предпросмотра */ protected $iS = 's'; /** @var string индекс размера для просмотра (оригинальный) */ protected $iO = 'o'; /** @var array атрибуты тега img в thumbnail */ public $imgAttr = ['style' => 'width: 100px;height: 100px;']; /** * Инициализация поля * @return bool */ public function init() { if (! parent::init()) { return false; } $this->ajaxAction = 'images_action'; $this->setTemplateName('images'); $this->isUnionAllowed = true; if (empty($this->sizes)) { $o = $this->iO; $this->sizes = [$o => ['o' => true] ]; } $s = $this->iS; if (! isset($this->sizes[$s])) { $this->sizes[$s] = ['width' => 100, 'height' => 100]; } return true; } /** * Установить поле внутрь объединения полей * @param Union $union */ public function setUnion($union) { # для групового поля, данные о загруженных файлах хранятся вместе с данными других полей parent::setUnion($union); if ($this->group) { $union->activateSavedKey(); } } /** * Генерация основного контента поля * @param array $data @ref данные * @return string HTML */ public function view(array &$data = []) { $union = $this->unionID(); if ($union) { $union = 'Union'.$union; } $jsName = $this->form->jsObjectName($union.'images'.$this->id()); $data['jsName'] = $jsName; $data['noJsRender'] = 1; $data['value'] = $this->value(); $data['uploader'] = $this->uploader(); $data['recordID'] = $this->form->recordID(); $data['iS'] = $this->iS; $data['iO'] = $this->iO; $this->viewPrepare($data); $html = $this->render($data); $this->form->initionsJavascript($jsName, $this->jsRender()); return $html; } protected function viewPrepare(& $data) { } /** * Инициализация загрузчика * @return ImagesUploaderField */ public function uploader() { if (! $this->uploader) { $this->uploader = new ImagesUploaderField($this); } return $this->uploader; } /** * Обработка ajax запросов * @return array|bool данные для ajax ответа */ public function ajax() { # загрузка нового изображения $this->ajaxHandler('upload', function () { $deleted = $this->input->get('deleted', TYPE_ARRAY_STR); if (! empty($deleted)) { $this->uploaderDeleteImages($deleted); } $result = $this->uploaderUploadQQ(); $response = array('success' => ($result !== false && $this->errors->no())); if ($result !== false) { $response = array_merge($response, $result); $sizes = [$this->iO, $this->iS]; $response = array_merge($response, $this->uploaderGetURL($result, $sizes, $this->uploaderIsTmp())); } $response['errors'] = $this->errors->get(); return $this->ajaxResponse($response, true); }); # удаление временного файла, если recordID = 0 $this->ajaxHandler('delete-tmp', function () { $filename = $this->input->post('filename', TYPE_STR); $this->uploaderSetRecordID(0); $this->uploaderDeleteTmpFile($filename); return []; }); return parent::ajax(); } /** * Установка значения поля при загрузке данных из БД * @param mixed $data * @return void */ public function setValue($data) { $value = $this->uploaderGetData(); # построим URL для скачивания разммеров foreach ($value as &$v) { foreach ($this->sizes as $s => $vv) { $v['url_' . $s] = $this->uploaderGetURL($v, $s); } } unset($v); if ($this->unionID() && $this->group) { # если внутри групового поля - порядок файлов записан в груповом поле $result = []; foreach ($data as $v) { foreach ($value as $vv) { if ($v == $vv['filename']) { $result[] = $vv; continue 2; } } } $value = $result; } parent::setValue($value); } /** * Проверка значения поля * @param array $data ['value' => &$value], 'value' - ссылка на значение поля * @return bool true - значение корректно, false - значение некорректно, пропустить (не сохраняется в БД) */ public function validate($data) { if ($this->unionID()) { if ($this->group || ! $this->form->recordID()) { if (empty($data['value'])) { $data['value'] = []; } return true; } } return false; } /** * Выполнение действий после сохранения (точно есть recordID) * @param bool $isInserted - была добавленна новая запись false - редактирование существующей * @param array $params ['saved' => &$saved], 'saved' - сохраненные данные * @return void */ public function validateAfter($isInserted, $params) { $name = $this->name(); $union = $this->unionID(); if ($union) { $groupName = $this->union->name(); if ($isInserted) { $groupKey = $this->union->savedKey; if ($groupKey && isset($params['saved'][$groupName][$groupKey])) { $saved = $params['saved'][$groupName][$groupKey]; } elseif (isset($params['saved'][$groupName][$name])) { $saved = $params['saved'][$groupName][$name]; } if (! empty($saved)) { $data = []; # получим данные о загруженных изображениях из сохраненных данных групового поля foreach ($saved as $v) { if ($groupKey && ! empty($v[$name])) { $data = array_merge($data, $v[$name]); } elseif (is_scalar($v)) { $data[] = $v; } } if (! empty($data)) { # переместим файлы из временного каталога в постоянный $this->uploaderSaveTmp($data); } } } else { $deleted = $this->input->post($this->deleteName(), TYPE_ARRAY); if (! empty($deleted)) { # удалим удаленные $this->uploaderDeleteImages($deleted); } } } else { $data = $this->input->post($name, TYPE_ARRAY); if ($isInserted) { if (! empty($data)) { # переместим файлы из временного каталога в постоянный $this->uploaderSaveTmp($data); } } else { if (! empty($data)) { # сохраним порядок $this->uploaderSaveOrder($data); } $deleted = $this->input->post($this->deleteName(), TYPE_ARRAY); if (! empty($deleted)) { # удалим удаленные $this->uploaderDeleteImages($deleted); } } } } /** * Действия после завершения отрисовки группы * @return string HTML */ public function afterGroupRender() { # могут быть файлы, которые загрузили, но не сохранили в данных о группе # отправим такие файлы на удаление if (! $this->unionID()) { return ''; } # список файлов внутри группы $exist = []; $name = $this->name(); $value = $this->union->value(); foreach ($value as $v) { if (empty($v[$name])) continue; foreach ($v[$name] as $vv) { $exist[] = is_array($vv) ? $vv['filename'] : $vv; } } $exist = array_unique($exist); # список загруженных файлов $data = $this->uploaderGetData(); foreach ($data as $k => $v) { if (in_array($v['filename'], $exist)) { unset($data[$k]); } } # список файлов для удаления $result = []; if (! empty($data)) { foreach ($data as $v) { $result[] = ''; } } return join('', $result); } /** * Генерация имени содержащих данные об удаляемых изображениях * @return string */ public function deleteName() { return 'delete_image_' . $this->id() . ($this->unionID() ? '_' . $this->unionID() : ''); } /** * Обработка события удаления записи формой * @param int $recordID ID записи * @return void */ public function recordDelete($recordID) { $this->uploaderDeleteAllImages(); } /** * Получение данных о номере записи из формы * @return int */ public function recordID() { return $this->form->recordID(); } /** * Получить папку для хранения загруженных файлов из формы * @return string */ public function folder() { return $this->form->folder(); } /** * Загрузка данных для аплоадера * @return array */ public function loadRecordData() { $union = $this->unionID(); $saved = $this->form->_ajaxData($union ? $union : $this->id(), []); if (! is_array($saved)) { $saved = []; } if ($union) { $name = $this->name(); if (isset($saved[$name])) { $saved = $saved[$name]; } else { $saved = []; } } return $saved; } /** * Сохранение данных аплоадером * @param array $data * @return void */ public function saveRecordData(array $data) { foreach ($data as $k => &$v) { if (! is_array($v)) { continue; } $v['url'] = []; $v['path'] = []; foreach ($this->sizes as $s => $vv) { $url = $this->uploaderGetURL($v, $s); $url = str_replace(SITEURL_STATIC, '//{sitehost}', $url); $v['url'][$s] = $url; $path = $this->uploaderGetPath($v, $s); $path = str_replace(PATH_BASE, '{path_base}', $path); $v['path'][$s] = $path; } } unset($v); $union = $this->unionID(); if ($union) { $name = $this->name(); $saved = $this->form->_ajaxData($union, []); if (! is_array($saved)) { $saved = []; } $saved[$name] = $data; $this->form->_ajaxSave($union, $saved); } else { $this->form->_ajaxSave($this->id(), $data); } if (! empty($this->cacheUrl)) { if ($this->form->recordID()) { $save = []; $url = reset($data); if (isset($url['url'])) { $url = $url['url']; foreach ($this->cacheUrl as $k => $v) { if (! isset($url[$k])) { continue; } $save[$v] = $url[$k]; } } if (! empty($save)) { $this->form->save($save); } } } } /** * Установить параметры размера * @param string $key ключ размера * @param array $data данные * @return void */ public function imageSize($key, $data) { $this->sizes[$key] = $data; } /** * Получение значения необходимости раскладывать файлы по папкам * @param bool|null $folderByID * @return bool */ public function folderByID($folderByID = null) { if (! is_null($folderByID)) { $this->folderByID = (bool)$folderByID; } return $this->folderByID; } /** * Загрузка файла из существующего файла * @param string $file путь к файлу * @return void */ public function uploadFromFile($file) { $this->uploaderSetRecordID($this->form->recordID()); $this->uploaderUploadFromFile($file); } /** * Получение значения максимального количества файлов * @return int */ public function limit() { return $this->limit; } /** * Установить значение максимального количества файлов * @param $limit */ public function setLimit($limit) { $this->limit = (int)$limit; } /** * Получение массива размеров * @return array */ public function sizes() { return $this->sizes; } /** * Получение значения максимального размера изображения * @return int */ public function maxSize() { return $this->maxSize; } /** * Получение списка разрешенных расширений файлов * @return array */ public function extensionsAllowed() { return $this->extensionsAllowed; } /** * Кеширование в БД url первого изображения * @param array $data даные в формате ['индекс размера' => 'название поля'] * @return static */ public function cacheUrl($data) { foreach ($data as $k => $v) { if (! isset($this->sizes[$k])) { unset($data[$k]); } } $this->cacheUrl = $data; return $this; } /** * Получение данных о изображениях * @return array */ public function uploaderGetData() { return $this->uploader()->getData(); } /** * Удаление изображений * @param array $images данные об изображениях array(filename, ...) * @return int кол-во удаленных изображений */ public function uploaderDeleteImages($images) { return $this->uploader()->deleteImages($images); } /** * Удаление всех изображений связанных с записью * @param bool $updateQuery актуализировать ли данные о изображениях записи (после их удаления) * @return bool */ public function uploaderDeleteAllImages($updateQuery = false) { return $this->uploader()->deleteAllImages($updateQuery); } /** * Загрузка(сохранение/обновление) изображения при помощи QQ-загрузчика * @return array информация об успешно загруженном файле изображения (@see save) или FALSE в случае ошибки */ public function uploaderUploadQQ() { return $this->uploader()->uploadQQ(); } /** * Установить ID записи * @param $id */ public function uploaderSetRecordID($id) { $this->uploader()->setRecordID($id); } /** * Формирование URL изображения * @param array $image : filename - название файла gen(N).ext, dir - # папки, srv - ID сервера * @param string|array $size префикс размера или массив префиксов размеров * @param bool $tmp tmp-изображение * @return string|array URL */ public function uploaderGetURL($image, $size, $tmp = false) { return $this->uploader()->getURL($image, $size, $tmp); } /** * Формирование пути к изображению * @param array $image : filename - название файла gen(N).ext, dir - # папки, srv - ID сервера * @param string $size префикс размера * @param bool $tmp tmp-изображение * @return string Путь */ public function uploaderGetPath($image, $size, $tmp = false) { return $this->uploader()->getPath($image, $size, $tmp = false); } /** * Временный файл или нет * @return bool */ public function uploaderIsTmp() { return $this->uploader()->isTmp(); } /** * Удаление tmp изображения(-й) * @param string|array $filename имя файла (нескольких файлов) * @return bool */ public function uploaderDeleteTmpFile($filename) { return $this->uploader()->deleteTmpFile($filename); } /** * Переносим tmp-изображения в постоянную папку * @param string|array $fieldName ключ в массиве $_POST, тип TYPE_ARRAY_STR или filename-массив * @param bool $edit используем при редактировании записи * @return mixed */ public function uploaderSaveTmp($fieldName = 'img', $edit = false) { return $this->uploader()->saveTmp($fieldName, $edit); } /** * Сохранение порядка изображений * @param array $images данные об изображениях array(filename, ...) * @return bool */ public function uploaderSaveOrder($images) { return $this->uploader()->saveOrder($images); } /** * Загрузка(сохранение/обновление) изображения на основе пути к уже загруженному файлу * @param string $filePath путь к файлу * @param bool $saveOriginalFile сохранять оригинальный файл * @return array информация об успешно загруженном файле изображения (@see save) или FALSE в случае ошибки */ public function uploaderUploadFromFile($filePath, $saveOriginalFile = true) { return $this->uploader()->uploadFromFile($filePath, $saveOriginalFile); } }