На последних проектах я столкнулся с тем, что к контенту на сайте прилагается значительное количество изображений с различными размерами. Обойтись стандартными полями превью и детального изображения для элементов и разделов инфоблоков с их настройками уменьшения изображения не получилось. Поэтому мы с коллегами пошли по простому пути и стали использовать стандартные свойства типа “файл” как для элементов инфоблоков, так и для пользовательских свойств для разделов инфоблоков. Далее, конечно же, создали обработчики событий для того, чтобы обработать изображения в то состояние, которое требуется для отображения на сайте. Под обработкой изображения я подразумеваю пропорциональный ресайзинг или кроп (ресайзинг по одному размеру и дальнейшая обрезка лишнего), чего можно добиться стандартными средствами Битрикса (методы CFile::ResizeImage и др.). Сделали один проект таким образом… А потом второй, третий… Конечно, такой подход имеет право на жизнь, но он очень неудобен. [spoiler] К разработке своего модуля меня подтолкнул рассказ коллеги об удачном опыте создания кастомного свойства инфоблока. Вдохновившись его примером и документацией я приступил к разработке.
Суть создания кастомных свойств заключается в создании определенных обработчиков событий для событий OnIBlockPropertyBuildList для свойств элементов инфоблока. Пример такого обработчика:
OnUserTypeBuildList для пользовательских свойств. Пример такого обработчика:
public static function getPictureResizerUserTypeDescription()
{
return array(
'USER_TYPE_ID' => 'resize_file',
'CLASS_NAME' => 'CustomPropertiesModule\\CustomProperties\\PictureResizerUserTypeProperty',
'DESCRIPTION' => 'Картинки с ресайзом',
'BASE_TYPE' => 'file',
);
}
В этих обработчиках содержится описание кастомных свойств и стандартные методы, которые могут быть вызваны при работе со свойством. Например, html-представление настроек для свойства элемента инфоблока определяется реализацией метода GetSettingsHTML. Результаты работы этого метода можно увидеть на следующем скриншоте:
Для пользовательских свойств страница настройки выглядит так:
Что еще позволяют делать эти методы? Обрабатывать значения перед сохранением в БД, создавать html-представления в формах редактирования админки и публичной части, обрабатывать значения настроек свойств и др.
Расскажу о некоторых проблемах в разработке. При создании кастомного свойства указывается базовый тип свойства (строка, файл, список и др.). Метод CFileInput::Show позволяет создать стандартное html-представление контрола для загрузки изображений. Если указать базовый тип свойства “файл” для пользовательских типов свойств, то никаких проблем не возникает. Но для свойств элемента инфоблока это стало проблемой, т.к. используя стандартное html-представление крайне трудно без костылей удалить уже загруженное в свойство изображение. В связи с этим я отказался от использования базового типа “файл” и стал использовать “строку”, куда помещаю идентификатор файла в таблице, регистрирующей файлы в БД Битрикс.
Код модуля можно увидеть на GitHub. Помимо стандартной установки модуля доступна установка с использованием Composer, о которой я рассказывал в своем предыдущем посте.
Важно! В модуле используется API ядра D7, поэтому рекомендуется использовать его только для версий Битрикса от 14 и выше. Модуль находится в beta-версии и, если вы решите использовать его в своих проектах, о найденных багах сообщайте, пожалуйста, в Issues репозитория.
Хотелось бы подвести небольшой итог этого поста. На мой взгляд, создание собственных свойств открывает множество возможностей, потому что обработка изображений - это, конечно же, не единственное применение. Созданные командой Битрикса свойства такие как, например, привязка к карте Google Maps - отличный тому пример.
Тут я ошибся. Под каждый требуемый размер создаем отдельное свойство. Оригинал картинки храним в DETAIL_PICTURE, для каждого размера создаем отдельное свойство в инфоблоке. Свойство не множественное. Пишем обработчик событий OnAfterIBlockElementUpdate и OnAfterIBlockElementAdd Код примерно такой:
function OnAfterIBlockElementAddAndUpdateHandler(&$arFields)
{
if ($arFields["RESULT"] && isset($arFields["DETAIL_PICTURE_ID"])) {
$imageData = $arFields["DETAIL_PICTURE_ID"];
//далее из этого массива получаем картинку в нужном размере используя CFile::ResizeImageGet и сохраняем в нужное свойство
}
}
Т.е. из 2 свойств у Вас автоматически получаются 8? И если я захочу на главной поменять с 300х300 на 250х250, то мне надо создавать новое свойство и т.д.?
Да, из оригинала при создании/обновлении элемента инфоблока генерируются все нужны размеры. Если размер меняется, то нужно либо создать новое свойство , либо обновить существующее.
Овсянников Максим написал: Оригинал картинки храним в DETAIL_PICTURE,
А как же фотогалерея для товара, ммм?...
Овсянников Максим написал: для каждого размера создаем отдельное свойство в инфоблоке
...и захламляем интерфейс менеджера. А если еще вспомнить про печально известное ограничение количества свойств в инфоблоке, связанное с ограничением в MySQL ( row size too large ), то становится совсем грустно. Нужно экономить свойства.
Теперь про нагрузку на сервер. При ресайзе происходит кэширование созданной картинки, и никаких дополнительных ресайзов не будет.
Овсянников Максим написал: А если страниц, где в шаблоне ресайзится картинка, тысячи, то нагрузка на сервер будет очень большая.
Ну и? А скриптом на сервере вы разве не создаете такую же большую нагрузку? В случае со множеством страниц нагрузка на сервер хотя бы размазывается по времени. Если же вам всё же нравится вариант со скриптом, то почему бы просто в этом скрипте не вызвать функции ресайза картинок, с аналогичными шаблонам настройками, без сохранения их в отдельные свойства? После отработки скрипта создадутся закэшированные уменьшенные версии изображений и для их получении в шаблонах не потребуются ресурсы сервера.
1) Если нужна галерея, то такой подход не подойдет. Но при желании можно сделать так, чтобы фото из галереи хранились в другом инфоблоке (например Фото), а выводились и добавлялись на странице редактирования инфоблока товара. Делаем множественное кастомное свойство типа "привязка к элементам инфоблока" и пишем для него свою форму. В ней можно вывести любое число фотографий (из инфоблока Фото) привязанных к товару, а также добавить в инфоблок Фото любое число фотографий, причем эти фотографии будут привязаны к редактируемому товару. В этом посте как раз об этом и говорится. Если проще и быстрее ресайзить фото в шаблоне то ок. Но если есть время, то почему бы не сделать красивое решение которое можно будет потом переносить на другие проекты?
2) Ненужные поля легко скрываются в настройках форма редактирования элемента инфоблока. Менеджер не будет их видеть. Если на проекте есть этап анализа и сбора требований с последующим проектированием, то проблему нехватки свойств можно избежать. Если мы заранее знаем что свойств будет очень много, то придется использовать другой подход. Тут все зависит от проекта.
3) А вы уверены что если одновременно много раз вызвать функцию ресайза, то ресайз будет выполнен только один раз а для остальных картинка будет взята из кеша? Скрипт можно запустить в любое время, например ночью когда нагрузка на сайт минимально и не нагружать сервер.
Группы на сайте создаются не только сотрудниками «1С-Битрикс», но и партнерами компании. Поэтому мнения участников групп могут не совпадать с позицией компании «1С-Битрикс».