'название поля'] */
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);
}
}