autoloader собственных классов и подключение событий работая одновременно с несколькими крупными проектами, в которых используется кастомизация бизнес-процессов, может возникнуть вопрос реализации удобной структуры собственных классов и событий в php_interface. У меня такой вопрос возник, и вот что получилось:
init.php создал в папке /bitrix/php_interface. Это сделано, чтобы учесть проекты с многосайтовостью и сохранить новую структуру как для папки /local, так и для /bitrix.
в данном решение обрабатываются 4 основных, но не обязательных файла: functions.php - записываем функции, которые будут везде использоваться, например для debug adminHandlers.php - добавляются события, которые будут отработаны в административной части сайта publicHandlers.php - добавляются события, которые будут отработаны только на публичной части сайта handlers.php - добавляются события, которые будут отрабатываться всегда
в данном примере подключается метод addJsLibrary из класса Custom\PublicSection\Jsinit. Класс подгружается по принципу autoloader'а. Т.е. в папке php_interface/classes/public создан файл jsinit.php:
<?php
namespace Custom\PublicSection;
class Jsinit
{
public function addJsLibrary()
{
$arJsConfig = array(
'owl_carousel' => array(
'js' => '/local/js/owl_carousel/owl.carousel.js',
'css' => '/local/js/owl_carousel/assets/owl.carousel.css',
'rel' => array('jquery'),
),
);
foreach ($arJsConfig as $ext => $arExt) {
\CJSCore::RegisterExt($ext, $arExt);
}
}
}
По такой же схеме можно создать любой файл с собственным классом, например: /local/php_interface/classes/handlers/test.php с namespace Custom\Handlers, где класс будет Test. Далее методы класса можно использовать как в событиях, добавляя их в handlers.php, так и в любом необходимом месте, например, собственном компоненте.
В итогемы получаем отдельные файлы классов, которые подключаются автоматически, и файлы со списками методов подключаемых в события. При этом используем встроенный функционал Bitrix'а.
Добрый день,такой вопрос,у меня есть универсальный список и он заполняется параметрами,по средствам бизнес-процесса, соответственно в нём не срабатывает бизнес-процесс на создание элементов,необходимо через код запускать бизнес-процесса на все новые элементы в этом списке,как это реализуемо,возможно уже есть готовые статьи? Я поискал в интернете примеры,но ничего достойного не нашёл,коробка если что.
Установил 28.07.2021 обновление, в том числе обновился и модуль календаря, сотрудники начали ругаться на неудобство, почему при планировании встречи убрали отображение отсутствий у участников встречи.
Сначала подумал что это новая фича, а потом решил проверить ))) Оказалось баг. В файле: /home/bitrix/www/bitrix/modules/calendar/classes/general/calendar_planner.php в строке 161, 162, 167 и 172 перепутаны имена ключей массива, и вместо DT_TO и DT_FROM, которые приходят из метода CCalendar::GetAccessibilityForUsers вписаны DATE_TO и DATE_FROM.
Решение
Нужно исправить имена ключей, или просто вставить в 160 строку перенос значений в нужные ключи:
Зачастую нужно реализовать следующий сценарий: - Контент-менеджер загружает файлы (картинки товара или раздела каталога) как есть. С кириллическим названием или пробелами. Как результат при валидации кода (если придет дотошный сеошник) могут вылезти куча ошибок связанных с разрывами в имени файла. Ниже публикую 2 скрипта, которые позволяют поправить эту ошибку перезаписав имена на корректные с точки зрения seo. !!! ВАЖНО !!! Перед выполнением скрипта в настройках главного модуля должны быть следующие настройки (см. скриншот). И не забывайте указать свой ID инфоблока.
1. Для разделов
$start = microtime(true);
// включение модуля
\Bitrix\Main\Loader::includeModule('iblock');
$arOrder = array('ID' => 'ASC');
$arFilter = array('IBLOCK_ID' => 60); // указать id инфоблока
$arSelect = array('ID', 'NAME', 'PICTURE');
$countSection = 0;
$countPicture = 0;
// достаем список разделов
$res = CIBlockSection::GetList($arOrder, $arFilter, false, $arSelect, false);
// цикл перебора разделов
while($arSection = $res->Fetch()){
$countSection += 1;
// получаем id файла в системе
$fileID = $arSection['PICTURE'];
// если id файла не получен, значит раздел без картинки
if(isset($fileID)){
$countPicture += 1;
// получим картинку как объект по id
$fileInfo = CFile::GetByID($fileID);
if($fileArr = $fileInfo->Fetch()){
// указываем расположение для временного хранения в склейке с именем файла
// !!! путь к папке задается от корня /upload/
$newFilePath = 'user_files/'.$fileArr['FILE_NAME'];
// копируем файл во временную папку
$fileCopy = CFile::CopyFile($fileID, true, $newFilePath);
}
// получаем информацию в массиве
$arrTmp = CFile::MakeFileArray($fileCopy);
// начинаем обновлять картинку
$bs = new CIBlockSection;
// определим данные для корректной записи массива 'PICTURE'
$picture = array(
'name' => $arrTmp['name'],
'type' => $arrTmp['type'],
'tmp_name' => $arrTmp['tmp_name'],
'error' => 0,
'size' => $arrTmp['size'],
'MODULE_ID' => 'iblock',
);
$arFields = array(
'PICTURE' => $picture,
);
// обновляем раздел
$bs->Update($arSection['ID'], $arFields, false, false, true);
unset($fileID);
}
}
$time = microtime(true) - $start;
echo 'Всего найдено ' . $countSection . ' разделов <br>';
echo 'Обновлено ' . $countPicture . ' картинок <br>';
echo 'Время выполнения ' . $time . ' секунд';
2. Для элементов
$start = microtime(true);
// включение модуля
\Bitrix\Main\Loader::includeModule('iblock');
$arOrder = array('ID' => 'ASC');
$arFilter = array('IBLOCK_ID' => 55); // указать id инфоблока
$arSelect = array('ID', 'NAME', 'PREVIEW_PICTURE', 'DETAIL_PICTURE');
$countElement = 0;
$countPicture = 0;
// достаем список элементов
$ar_res = CIBlockElement::GetList($arOrder, $arFilter, false, false, $arSelect);
// цикл перебора элементов
while($arElement = $ar_res->Fetch()){
$countElement += 1;
$res = CIBlockElement::GetByID($arElement['ID']);
if($arElement = $res->GetNext()){
/*КАРТИНКА АНОНСА*/
if(isset($arElement['PREVIEW_PICTURE'])){
$countPicture += 1;
// получим картинку как объект по id
$fileInfo = CFile::GetByID($arElement['PREVIEW_PICTURE']);
if($fileArr = $fileInfo->Fetch()){
// указываем расположение для временного хранения в склейке с именем файла
// !!! путь к папке задается от корня /upload/
$newFilePath = 'user_files/'.$fileArr['FILE_NAME'];
// копируем файл во временную папку
$fileCopy = CFile::CopyFile($arElement['PREVIEW_PICTURE'], true, $newFilePath);
}
// получаем информацию в массиве
$arrTmp = CFile::MakeFileArray($fileCopy);
// обновляем элемент
$el = new CIBlockElement;
// определим данные для корректной записи массива 'PICTURE'
$picture = array(
'name' => $arrTmp['name'],
'type' => $arrTmp['type'],
'tmp_name' => $arrTmp['tmp_name'],
'error' => 0,
'size' => $arrTmp['size'],
'MODULE_ID' => 'iblock',
);
$arFields = array(
'PREVIEW_PICTURE' => $picture,
);
$res = $el->Update($arElement['ID'], $arFields);
}
/*КАРТИНКА ДЕТАЛЬНАЯ*/
if(isset($arElement['DETAIL_PICTURE'])){
$countPicture += 1;
// получим картинку как объект по id
$fileInfo = CFile::GetByID($arElement['DETAIL_PICTURE']);
if($fileArr = $fileInfo->Fetch()){
// указываем расположение для временного хранения в склейке с именем файла
// !!! путь к папке задается от корня /upload/
$newFilePath = 'user_files/'.$fileArr['FILE_NAME'];
// копируем файл во временную папку
$fileCopy = CFile::CopyFile($arElement['DETAIL_PICTURE'], true, $newFilePath);
}
// получаем информацию в массиве
$arrTmp = CFile::MakeFileArray($fileCopy);
// обновляем элемент
$el = new CIBlockElement;
// определим данные для корректной записи массива 'PICTURE'
$picture = array(
'name' => $arrTmp['name'],
'type' => $arrTmp['type'],
'tmp_name' => $arrTmp['tmp_name'],
'error' => 0,
'size' => $arrTmp['size'],
'MODULE_ID' => 'iblock',
);
$arFields = array(
'DETAIL_PICTURE' => $picture,
);
$res = $el->Update($arElement['ID'], $arFields);
}
}
}
$time = microtime(true) - $start;
echo 'Всего найдено ' . $countElement . ' элементов <br>';
echo 'Обновлено ' . $countPicture . ' картинок <br>';
echo 'Время выполнения ' . $time . ' секунд';
Писалось на скорую руку, так что как есть)) Оставлю это тут на всякий случай.
Когда-то давно я наткнулся на статью "Класс для файла настроек модуля options.php" который помогал формировать страницы опций. С тех пор он прочно осел в проектах, значительно упрощая работу. В том числе файл встречался различных коммерческих модулях что показало актуальность его существования.
К сожалению, оригинальная статья датирована 2012 годом и код несколько устарел. Стали видны слабые момент в виду сложности добавления новых типов полей в классе, да и в плане внешнего вида UI Bitrix продвинулся вперёд.
С учетом этих проблем сделана более улучшенная версия, позволяющая легко добавлять новые типы полей, и испольщую библиотеку интерфейсов битрикс. Создан пакет для composer и, если кому-то зачем-то нужно - был опубликован модуль для маркетплейса. Проблема добавления новых типов полей закрыта, внешний вид значительно улчшился (по моему мнению).
Как это выглядит в админке:
Уже реализованы поля типов: строка, число, текст, чекбокс, выпадающий и множественный списки. Можно вешать различные модификаторы на поля, добавлять теги. В будущем планирую добавить добавление файлов, размещение кнопок на которые можно вешать свои скрипты.
Не буду описывать особенности установки и настройки - они детально описаны как на гитхабе, так и в маркетплейсе. Буду рад, если решение будет полезно, проект открыт для доработок как по самому коду, так и по добавлению новых типов полей.
Отдельное спасибо Андрею Новикову, за класс, служивший до этого долгие годы.
В коде происходит выборка 30 элементов, первыми из которых пойдут элементы у которых есть совпадения тегов "Personal" и "2020", далее хотя бы одного из этих двух Тегов, и в конце статьи, не имеющие совпадений.
По желанию можно добавить условие фильтра для выборки только тех элементов, которые содержат хоть один Тег. Например, условие по одному Тегу будет выглядеть так:
array(
"LOGIC" => "OR",
array(
'%TAGS' => " ".$sTagName."," // строка целиком в середине
),
array(
'TAGS' => $sTagName.",%" // строка целиком в начале
),
array(
'TAGS' => "% ".$sTagName // строка целиком в конце
),
array(
'TAGS' => $sTagName // единственная строка в тегах
)
)
Пример запроса SQL:
select ((case when LOCATE('Personal', TAGS)>0 then 1 else 0 end) + (case when LOCATE('2020', TAGS)>0 then 1 else 0 end)) as SORT,
TAGS, ID fr om b_iblock_element WHERE IBLOCK_ID=18 ORDER BY SORT DESC LIMIT 0, 30;
Представим, что нам надо отправлять сообщения в Битрикс24 на события из bitbucket, например Тимлиду ссылку на пулреквест для кодревью.
Bitbucket webhook Вебхуки bitbucket имеют события на пулреквесты, пуши и ишью. Полный перечень тут. Добавляется вебхука в настройках репозитория:
Укажите путь, куда будет отправлен запрос и выберите какие события вы хотите обрабатывать:
Обработка событий и отправка сообщения в чат Следующий скрипт, принимает запрос от bitbucket и отправляет ссылку на пулреквест Тимлиду на портал. Отправленное сообщение состоит из названия и ссылки на пулреквест.
Вот так просто. Логику поиска получателей или отправителей вы уже должны реализовать самостоятельно, в зависимости от ваших процессов и замысла. В нашем примере, для упрощения, ID пользователей прописаны явно.
Для обработки вебхуков bitbucket используется библиотека. Библиотека понимает большинство событий и комплектует объекты данными ответа в виде методов для получения ника автора, ссылки на пулреквест, комментарии коммитов и так далее.
Стандартное автоопределение клавиатуры почти всегда справляется, но некоторые русские слова всё-таки перекидывает на английскую раскладку (например: "шкаф" превращается в "irfa", а "кувшин" в "rediby", очень неприятно, если это ищут). Ну и специфические потребности никто не отменял.
Как ни странно, но отвечающий за эту радость класс CSearchLanguage поддерживает какую-никакую кастомизацию. Копируем всё из папки /bitrix/modules/search/tools/ru/ в папку /bitrix/php_interface/ru/search/ (и аналогично с en версией). Папка local не поддерживается.
По этому пути ищется кастомный класс для этой петрушки и теперь он есть, но требует небольшой доработки. Добавляем в ru версию в файл language.php функцию
function PreGuessLanguage($text, $lang=false)
{
$stop_list = array(
//сюда вписываем любые слова, которым не требуется автоопреление. Ключи важны, значения - любые, но мне так удобнее
"шкаф" => "irfa",
"шкафы" => "irfas",
);
//Indicates that there is no own guess
if(isset($stop_list[$text]))
return true;
else
return false;
//In subclasses you should return array("from" => lang, "to" => lang) to translate
//or return true when no translation nedded
//or parent::GuessLanguage for futher processing
}
Теперь слово "шкаф" не заменяется на "irfa". Класс.
А в en версию аналогичный, но чуть другой:
function PreGuessLanguage($text, $lang=false)
{
$stop_list = array(
"irfa" => "шкаф",
"irfas" => "шкафы",
);
//Indicates that there is no own guess
if(isset($stop_list[$text]))
return array("from" => "en", "to" => "ru");
else
return false;
//In subclasses you should return array("from" => lang, "to" => lang) to translate
//or return true when no translation nedded
//or parent::GuessLanguage for futher processing
}
Теперь и "irfa" вполне себе меняется на "шкаф".
Собственно вот и всё. Можно вписывать любые другие слова и наслаждаться жизнью.
(А ещё можно вынести словарь в отдельный файл и подтягивать значения из него, но ради пары слов я бы таким не занимался.)
Необходимо выполнить доработки по сайту на Битриксе. Было куплено шаблонное решение, сейчас наполняем сайт для сео, нужны доработки. Задачи по сайту будут постоянные в дальнейшем.
На данный момент есть задачи по ТЗ, посмотрите их, оцените объем, напишите ваши условия.
Хочу поделиться способом автоматической минификации стилей и скриптов. Решение было сделано на БУС, но подойдет для других CMS. Описанное решение может оказаться полезным тем, у кого стили распределены по компонентам и не настроены автоматические сборщики типа gulp или webpack и д.р.
Думаю все знают про настройки Оптимизации CSS и JS в главном модуле, а именно "Подключать минифицированные версии CSS и JS файлов". К сожалению в Битриксе не заложена функция создания минифицированных файлов (*.min.css и *.min.js), но зато заложена опция подключения таких файлов.
CSS
Давайте начнем с CSS. Решение базируется на модуле uglifycss Node.js (https://www.npmjs.com/package/uglifycss) . Устанавливаете uglifycss для использования в командной строке (For a command line usage), это очень важно! Заранее позаботьтесь о необходимых доступах к серверу. Выполните к консоле команду:
$ npm install uglifycss -g
После успешной установки узнайте путь нахождения установленного модуля, выполнив команду. К примеру у меня, на боевом сервере был свой путь, а на серверах разработки другой.
whereis uglifycss
В ответе будет строка с путём до uglifycss. В моём случае - /usr/local/bin/uglifycss. Далее мы этот путь будем использовать в классе.
Сам класс:
<?
/*
* Класс по минификации CSS-файлов. Использует NodeJS плагин uglifycss
*/
class CCssMinify
{
const DIRS_FOR_CSS_MINIFY = [
'/local/admin/css/',
'/local/components/',
'/local/templates/main/components/',
'/local/templates/main/theme/build/styles/'
];
const FILES_FOR_CSS_MINIFY = [
'/local/templates/main/styles.css',
'/local/templates/main/template_styles.css'
];
private static $bNeedCacheRefresh = false;
/**
* Агент по минификации стилей
*
* @return string
*/
public static function minifyAgent(): string
{
try {
self::minify();
} catch (Exception $obException) {
CEventLog::Add(array(
"SEVERITY" => "ERROR",
"AUDIT_TYPE_ID" => "MINIFY_CSS",
"MODULE_ID" => "main",
"ITEM_ID" => "",
"DESCRIPTION" => $obException->getMessage()
));
}
return __METHOD__.'();';
}
/**
* Минификация стилей, находящихся внутри директорий, обозначенных в константе \dh\CCssMinify::DIRS_FOR_CSS_MINIFY,
* и в файлах в константе \dh\Seo\CCssMinify::FILES_FOR_CSS_MINIFY
*/
public static function minify()
{
foreach (self::DIRS_FOR_CSS_MINIFY as $sDir) {
$arFilePaths = self::findCssFilesInDir($sDir);
if (!empty($arFilePaths)) {
foreach ($arFilePaths as $sFilePath) {
self::execUglifycss($sFilePath);
}
}
}
foreach (self::FILES_FOR_CSS_MINIFY as $sFilePath) {
self::execUglifycss($sFilePath, true);
}
if (self::$bNeedCacheRefresh && BXClearCache(true, "/css/")) {
CEventLog::Add(array(
"SEVERITY" => "INFO",
"AUDIT_TYPE_ID" => "MINIFY_CSS",
"MODULE_ID" => "main",
"ITEM_ID" => "",
"DESCRIPTION" => "Clear cache"
));
}
}
/**
* Получим путь до UglifyCss
* @return string
*/
private static function getUglifyCssPath(): string
{
return '/usr/local/bin/uglifycss';
}
/**
* Поиск Не минифицированных css файлов в Директории (и её поддиректориях)
*
* @param $sDirPath
* @return array
*/
public static function findCssFilesInDir($sDirPath): array
{
$arFilePaths = [];
$obDirectory = new RecursiveDirectoryIterator($_SERVER["DOCUMENT_ROOT"].$sDirPath);
$obIterator = new RecursiveIteratorIterator($obDirectory);
foreach ($obIterator as $obInfo) {
$file_formal = substr($obInfo->getfileName(), strrpos($obInfo->getfileName(), ".") + 1);
$name_search = array("css"); // Список форматов
foreach ($name_search as $key_name) {
if (
$file_formal == $key_name &&
!stristr($obInfo->getfileName(), '.min.css')
) {
$arFilePaths[] = $obInfo->getPathname();
}
}
}
return $arFilePaths;
}
/**
* Выполнить минификацию
*
* @param $sFilePath
* @param bool $bAddDocumentRoot
*/
private static function execUglifycss($sFilePath, bool $bAddDocumentRoot = false)
{
if ($bAddDocumentRoot) {
$sFilePath = $_SERVER["DOCUMENT_ROOT"].$sFilePath;
}
$sMinFilePath = str_replace('.css', '.min.css', $sFilePath);
if (
!file_exists($sMinFilePath) ||
(
file_exists($sMinFilePath) &&
filectime($sFilePath) > filectime($sMinFilePath)
)
) {
/*
* https://www.npmjs.com/package/uglifycss
--output f puts the result in f file
*/
shell_exec(self::getUglifyCssPath().' '.$sFilePath.' --output '.$sMinFilePath);
self::$bNeedCacheRefresh = true;
}
}
}
В приведенном выше классе есть метод \CCssMinify::getUglifyCssPath, в котором как раз мы возвращаем путь до uglifycss, полученный через whereis uglifycss. Мы не используем специфических настроек запуска uglifycss, только путь до минифицированной версии, которая будет находится рядом с основной.
Сам Агент реализован методом \CCssMinify::minifyAgent(); Как видно из кода, метод автоматически очищает CSS КЕШ сайта. Пересозданию минификаций подвержены только те файлы css, время изменения которых позже созданных для них минификаций. В Административном разделе агент имеет следующие настройки:
Среднее время выполнения агента на моём проекте: 7-8 секунд, для ПОЛНОГО пересоздания. В режиме обычно работы, при пересоздании только изменённых файлов, не превышает 0.1 секунды. Не берусь говорить точно об объёмах, но проект довольно крупный, так что не сильно беспокойтесь, что всё повиснет. Хотя перестраховаться не мешает.
Пример результата работы агента:
C CSS мы закончили. давай перейдем к JS.
JS
Решение базируется на модуле uglifyjs Node.js (https://www.npmjs.com/package/uglify-js). Устанавливаете uglifyjs для использования в командной строке (From NPM for use as a command line app), это очень важно! Заранее позаботьтесь о необходимых доступах к серверу. Выполните к консоле команду:
npm install uglify-js -g
После успешной установки узнайте путь нахождения установленного модуля, выполнив команду.
whereis uglifyjs
В ответе будет строка с путём до uglifyjs. В моём случае - /usr/local/bin/uglifyjs. Далее мы этот путь будем использовать в классе.
Сам класс:
<?
/*
* Класс по минификации JS-файлов. Использует NodeJS плагин uglifyjs
*/
class CJsMinify
{
const DIRS_FOR_JS_MINIFY = [
'/local/admin/js/',
'/local/templates/main/js/',
'/local/components/',
'/local/templates/main/components/'
];
/**
* Агент по минификации скриптов
*
* @return string
*/
public static function minifyAgent()
{
try {
self::minify();
} catch (Exception $obException) {
CEventLog::Add(array(
"SEVERITY" => "ERROR",
"AUDIT_TYPE_ID" => "MINIFY_JS",
"MODULE_ID" => "main",
"ITEM_ID" => "",
"DESCRIPTION" => $obException->getMessage()
));
}
return __METHOD__.'();';
}
/**
* Минификация скриптов, находящихся внутри директорий, обозначенных в константе \dh\CJsMinify::DIRS_FOR_JS_MINIFY
*/
public static function minify()
{
$bNeedCacheRefresh = false;
foreach (self::DIRS_FOR_JS_MINIFY as $sDir) {
$arFilePaths = self::findJsFilesInDir($sDir);
if (!empty($arFilePaths)) {
foreach ($arFilePaths as $sFilePath) {
$sMinFilePath = str_replace('.js', '.min.js', $sFilePath);
if (
!file_exists($sMinFilePath) ||
(
file_exists($sMinFilePath) &&
filectime($sFilePath) > filectime($sMinFilePath)
)
) {
/*
* https://www.npmjs.com/package/uglify-js
-c, --compress [options] Enable compressor/specify compressor options
-m, --mangle [options] Mangle names/specify mangler options
-o, --output <file> Output file path (default STDOUT)
*/
shell_exec(self::getUglifyJsPath().' '.$sFilePath.' -c -m -o '.$sMinFilePath);
$bNeedCacheRefresh = true;
}
}
}
}
if ($bNeedCacheRefresh && BXClearCache(true, "/js/")) {
CEventLog::Add(array(
"SEVERITY" => "INFO",
"AUDIT_TYPE_ID" => "MINIFY_JS",
"MODULE_ID" => "main",
"ITEM_ID" => "",
"DESCRIPTION" => "Clear cache"
));
}
}
/**
* Получим путь до UglifyJS
* @return string
*/
private static function getUglifyJsPath() {
return '/usr/local/bin/uglifyjs';
}
/**
* Поиск Не минифицированных js файлов в Директории (и её поддиректориях)
*
* @param $sDirPath
* @return array
*/
public static function findJsFilesInDir($sDirPath)
{
$arFilePaths = [];
$obDirectory = new RecursiveDirectoryIterator($_SERVER["DOCUMENT_ROOT"].$sDirPath);
$obIterator = new RecursiveIteratorIterator($obDirectory);
foreach ($obIterator as $obInfo) {
$file_formal = substr($obInfo->getfileName(), strrpos($obInfo->getfileName(), ".") + 1);
$name_search = array("js"); // Список форматов
foreach ($name_search as $key_name) {
if (
$file_formal == $key_name &&
!stristr($obInfo->getfileName(), '.min.js') &&
!stristr($obInfo->getfileName(), '.map.js')
) {
$arFilePaths[] = $obInfo->getPathname();
}
}
}
return $arFilePaths;
}
}
В приведенном выше классе есть метод CJsMinify::getUglifyJsPath, в котором как раз мы возвращаем путь до uglifyjs, полученный через whereis uglifyjs. В коде имеются пояснения выставленных опций, с которыми подробнее можете ознакомится на странице https://www.npmjs.com/package/uglify-js
Сам Агент реализован методом CJsMinify::minifyAgent(). Как видно из кода, метод автоматически очищает JS КЕШ сайта. Пересозданию минификаций подвержены только те файлы js, время изменения которых позже созданных для них минификаций. В Административном разделе агент имеет следующие настройки:
Среднее время выполнения агента на моём проекте: 30-32 секундs, для ПОЛНОГО пересоздания. В режиме обычной работы, при пересоздании только изменённых файлов, не превышает 0.1 секунды.
Пример результата работы:
Бонус:
В качестве бонуса поделюсь примером .gitignore, чтобы не засорять репозиторий минификациями:
Проблема: у нас, например, есть 10 отдельных кешируемых страниц, нам надо сбрасывать разом весь их кеш. Без тегированного кеша надо знать все ключи и перебирая их сбрасывать. Добавляя 11 страницу, нам надо не забыть добавить его ключ в сбрасыватель кеша, что легко забыть, или сайт начнет выдавать баги.
Тут нам помогает тегированный кеш. При генерации страниц, мы помечаем данные одним общим тегом и по нему сбрасываем кеш. Добавляя 11 страницу, мы добавляем на странице общий тег и эта страница начинает сбрасываться автоматически.
use \Bitrix\Main\Data\Cache;
use \Bitrix\Main\Application;
$cache = Cache::createInstance(); // Служба кеширования
$taggedCache = Application::getInstance()->getTaggedCache(); // Служба пометки кеша тегами
/*
* Чтобы тегированный кеш нашел что ему сбрасывать, необходим
* одинаковый путь в $cache->initCache() и $taggedCache->startTagCache()
* У нас путь указан в $cachePath
*/
$cachePath = 'mycachepath';
$cacheTtl = 3600;
$cacheKey = 'mycachekey';
if ($cache->initCache($cacheTtl, $cacheKey, $cachePath))
{
$vars = $cache->getVars();
/*
* Еще тут можно вывести данные в браузер, через $cache->output();
* Тогда получится замена классу CPageCache
*/
}
elseif ($cache->startDataCache())
{
// Начинаем записывать теги
$taggedCache->startTagCache($cachePath);
$vars = [
'date' => date('r'),
'rand' => rand(0, 9999), // Если данные закешированы - число не будет меняться
];
// Добавляем теги
// Кеш сбрасывать при изменении данных в инфоблоке с ID 1
$taggedCache->registerTag('iblock_id_1');
// Кеш сбрасывать при изменении данных в инфоблоке с ID 2
$taggedCache->registerTag('iblock_id_2');
// Если что-то пошло не так и решили кеш не записывать
$cacheInvalid = false;
if ($cacheInvalid)
{
$taggedCache->abortTagCache();
$cache->abortDataCache();
}
// Всё хорошо, записываем кеш
$taggedCache->endTagCache();
$cache->endDataCache($vars);
}
// Данные будут обновляться раз в час или при обновлении данных в инфоблоках 1 и 2
print_r($vars);
Когда необходимо сбросить кеш по тегу:
use \Bitrix\Main\Application;
$taggedCache = Application::getInstance()->getTaggedCache(); // Служба пометки кеша тегами
/*
* Где-то на отдельной странице чистим кеш по тегу
*/
$taggedCache->clearByTag('iblock_id_28');
Как сделать чтобы мой кеш сбрасывался автоматически, при изменении данных в инфоблоке? Использовать готовые теги: iblock_id_{ID} - это зарезервированные теги битрикса для инфоблоков, сброс кеша по этим тегам уже есть в классах работы с инфоблоками. iblock_id_new - по этому тегу кеш сбрасывается при создании инфоблоков. Списка используемых тегов в битрикс я не нашел.
Для себя вы можете придумать свои теги.
Везде пишут что, чтобы работало всё это чудо, надо добавить в dbconn.php строку: define("BX_COMP_MANAGED_CACHE", true); Но у меня и без нее всё работает
Сталкивались ли вы с тем, что клиенты используют обновления битрикс как манипулятивный рычаг давления, чтобы спихнуть ошибки предыдущих разработчиков на тех, кто произвел обновление ядра (ядро не модифицировалось предыдущим разработчиком)?
(доводы клиента: до обновления все работало и прочее, верните все как было)
или это классическая ментальная ошибка, когда произошедшие одновременно вещи считают связанными?
или все-таки есть риски и большие при обновлении ядра?
хотя обновления ядра объективно - это ресурс, причем платный.
Всё более актуальной становится проблема недоставки писем, отправляемых через phpmailer. Не доверяют почтовые сервисы таким сообщениям... Особенно их не любит iCloud. Тут даже SPF не помогает. Помогает только DKIM. А ещё круче, когда письма отсылает платный сервис. Например, SendPulse. Ну, надо же всем зарабатывать, ведь правда?
Короче, нам было необходимо обеспечить 100% доставку писем о результатах тестов на ковид. В итоге, вот что получилось.
1. Регистрируемся на Sendpulse 2. Скачиваем в php_interface Битрикса библиотеку (враппер) их API 3. Прописываем в init.php следующее:
Таким образом, мы сохранили отправку всех сообщений, на базе почтовых шаблонов Битрикса, с поддержкой прикрепленных файлов (в CEvent::Send теперь есть массивчик под них). Фишка в том, что мы аннулируем отправку стандартных писем Битрикса, добавив функцию custom_mail. При этом перехватываем её через обработчик события, и шлём нужные нам письма через Сендпульс.
Единственный момент - штука не поддерживает спецслова в шаблонах типа DEFAULT_EMAIL_FROM, SITE_NAME и т.д. Только поля почтового события. Ну, это ерунда. Главное, что теперь почта ходит лучше, чем DHL.
После отключения mbstring.func_overload для установки обновлений Битрикса, перестали работать строковые функции типа strtoupper(). Техподдержка поделилась секретной ссылкой, как заставить работать: https://helpdesk.bitrix24.ru/open/11473408
Добрый день. В файле init.php объявлен обработчик события OnProlog, в нем реализована логика добавления js-скрипта в хэдер сайта, но скрипт не добавляется. Функция addJs возвращает true. Скажите, пожалуйста, в чем может быть причина?
Добрый день! Подскажите, пожалуйста! Недавно начал работать с битрикс, достался готовый магазин. При уходе с сайта выскакивает всплывающие окно. Шаблон аспро стоит. перелопатил всю админку, готовых решений не установлено по всплывающим окнам. Можете подсказать в каком направлении искать? Нужно убрать это окно.
Не устанавливается значение свойства. А если перед выполнением в SALE было Y, то после выполнения удаляет значения свойства. То есть при выполнении просто происходит удаление значения свойства.
Здравствуёте, Хотел спрость на тему вот этого вопроса https://dev.1c-bitrix.ru/community/forums/messages/forum6/topic84573/message470217/#message470217. У меня похожая проблема, должно сначало приходить письмо оформлемления заказа, потом после подтвердение заказа магазином, приходит письмо с сылкой на оплату, после оплаты приходит письмо о успешной оплате, но вот проблема на этом моменте опять приходит письмо со ссылкой об оплате(ссылка уже не действующая). Я думаю мой слечай. Подскажите пожалуйста по подробей, в каком файле вставить \Bitrix\Sale\Notify::setNotifyDisable(true); перед вызовом DoSaveOrder.
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Если возникли проблемы с очисткой cookies в браузере и не получается авторизоваться, можно инициировать удаление лишней куки со стороны сервера:
1. Если не используется многосайтовость, а поле «Доменное имя» очищено, то надо удалить куку с точкой в начале. Для этого впишите в любую строку файла dbconn.php следующий код: setcookie("PHPSESSID", "", 777, '/', '.site.ru'); где site.ru - имя вашего домена.
2. Если используется многосайтовость или не очищено поле «Доменное имя», то впишите код: setcookie("PHPSESSID", "", 777, '/'); строго без имени домена.
Не добавляются платежные системы после переноса сайта. Раньше при добавлении платежной системы было выпадающее меню с различными типами платежных систем, а теперь их нет. Подскажите, где начинать искать решение этой проблемы.
Добрый день, друзья! На дворе 2021 год, а проблема до сих пор не решена со стороны разработчика. Вот и я столкнулся с этой проблемой. Предисловие: был перенос хостинга (c VPS на другую VPS). Перенос прошел почти гладко, но вот с почтой загвоздки. Итак, что сейчас сделано: настроена отправка почты через Postfix, агенты на кроне, все тесты проходят хорошо (все зелененькие галочки). В терминале почта нормально отправляется и доставляется через юзеров root и bitrix. Но при выполнении заказов, при регистрации пользователя и др. событий с сайта, почта отправляется, но не доходит до пользователя. Симлинк на /ets/msmtp сделан. В crontab от bitrix прописан PATH. Крон срабатывает нормально (через минуту после события на сайте появляется в логах msmtp). Лог msmtp
Mar 08 09:11:01 host=127.0.0.1 tls=on auth=off from=noreply@binpro.ru recipients=alex-00@mail.ru mailsize=3749 smtpstatus=250 smtpmsg='250 2.0.0 Ok: queued as A6E0723B4D' exitcode=EX_OK Mar 08 09:40:05 host=127.0.0.1 tls=on auth=off from=noreply@binpro.ru recipients=velobox@inbox.ru mailsize=36938 smtpstatus=250 smtpmsg='250 2.0.0 Ok: queued as 8FC7E23B4C' exitcode=EX_OK Mar 08 10:09:03 host=127.0.0.1 tls=on auth=off from=noreply@binpro.ru recipients=alex-00@mail.ru mailsize=3749 smtpstatus=250 smtpmsg='250 2.0.0 Ok: queued as D129E23B51' exitcode=EX_OK
Настройки msmtp
# smtp account configuration for default account default logfile /home/bitrix/msmtp_default.log host 127.0.0.1 port 25 from noreply@binpro.ru keepbcc off auth off tls on tls_certcheck off
echo "hello from mail.com.ru." | msmtp --debug -a site.ru test@site.ruгде site.ru - значение account в конфиге .msmtprc
пример конфига для яндекса
# smtp account configuration for site.ru account site.ru logfile /home/bitrix/msmtp_site.ru.log host smtp.yandex.ru port 587 from noreply@site.ru keepbcc on auth on user noreply@site.ru password *********** tls on tls_starttls on tls_certcheck off
Не помогают вариации настроек главного модуля для отправки почты и т.д.
Укажите тут /bitrix/admin/settings.php?lang=ru&mid=main&tabControl_active_tab=tab_mail&back_url_settings= "Дополнительный параметр для передачи функции mail:" -a site.ru (см. скрин)
Чтобы гуглю было проще искать: SUCCESS_EXEC='F' , b_event, не работает почта msmtprc