• Как проще всего сделать выборку количества каждого типа?

    @AUser0
    Чем больше знаю, тем лучше понимаю, как мало знаю.
    Правда такой запрос вернёт 3 записи, с разными type_id.
    И общее кол-во нужно будет суммировать самостоятельно из этих 3-х записей.
    SELECT COUNT(*) AS cnt, type_id
    FROM example
    WHERE user_id = 53 AND status = 1
    GROUP BY type_id
    Ответ написан
    Комментировать
  • Почему не работает INTERVAL?

    dimonchik2013
    @dimonchik2013
    non progredi est regredi
    кавычки надо для когда интервал, а не всегда

    т.е. или

    1 hour
    или
    '1-3' hour / '1:3' hour
    Ответ написан
    1 комментарий
  • Какую БД выбрать для формата ключ-значение?

    Redis в первую очередь хранит данные в памяти, mongodb не обязательно в памяти
    В mongodb есть memory движок, но он вроде только в enterprise версии
    Ответ написан
    Комментировать
  • Atom.io - как настроить плагин PlantUML?

    @AVKor
    Ответ написан
    Комментировать
  • Почему не запускается функция при наступлении события?

    gromdron
    @gromdron Куратор тега Битрикс24
    Работаю с Bitrix24
    Да, вы почти все правильно сделали, но не так как нужно.
    Прежде чем копировать бездумно прочитайте до конца, я попытался развернуть мысль, чтобы не просто дать ответ на вопрос, но и пояснить некоторые действия.

    Давайте разберемся что у вас получлось правильно:
    - Вы решили использовать механизм событий
    - Вы правильно определили событие
    - Вы использовали local-папку для разработки
    - Вы попытались разделить ответственность между подпиской на событием и непосредственно ее обработчиком.

    Теперь что у вас НЕ получилось.

    Для начала это сама подписка на событие.
    - Вы не правильно поняли ее аргументы
    - Вы использовали устаревшую надстройку для подписки.

    Начнем с обратного порядка: AddEventHandler это лишь обертка над \Bitrix\Main\EventManager::addEventHandlerCompatible поэтому мы будем использовать его.

    Для начала перепишем ваш код дословно на "новый лад":

    $eventManager = \Bitrix\Main\EventManager::getInstance();
    $eventManager->addEventHandlerCompatible(
    	'main',
    	'OnAfterUserAdd',
    	[
    		'AddUserToGroupChatsClass',
    		'AddUserToGroupChats'
    	],
    	$_SERVER["DOCUMENT_ROOT"] . "/local/php_interface/event_handlers/add_user_to_group_chats_class.php"
    );


    Оно выглядит лучше но по-прежнему не работает.

    Порядок аргументов addEventHandlerCompatible и AddEventHandler одинаковый и состоит из:

    - FROM_MODULE_ID - на какой модуль подписываемся
    - MESSAGE_ID - на какое событие подписываемся
    - CALLBACK - callback обработчик (будет вызван для )
    - SORT - порядок выполнения относительно других событий
    - FULL_PATH - путь к файлу

    Т.е. получается что у тебя нарушен порядок аргументов. Корректнее было бы так:
    $eventManager = \Bitrix\Main\EventManager::getInstance();
    $eventManager->addEventHandlerCompatible(
    	'main',
    	'OnAfterUserAdd',
    	[
    		'AddUserToGroupChatsClass',
    		'AddUserToGroupChats'
    	],
    	100,
    	$_SERVER["DOCUMENT_ROOT"] . "/local/php_interface/event_handlers/add_user_to_group_chats_class.php"
    );


    Теперь разберемся с самой подписной моделью: вы хотите использовать свой класс и выделить его в отдельный файл для удобства.
    Не будем поднимать вопросы по поводу нейминга, но совершенно не обязательно подключать дополнительный файл для события. Рекомендую почитать про spl_autoload и composer.
    Давайте воспользуемся нашей готовой разработкой init.php и разместим в init.php маленький автолоадер.

    Предположим что за добавление будет отвечать ваш класс AddUserToGroupChatsClass

    Ваш init.php:
    /**
     * - /local/php_interface/classes/{Path|raw}/{*|raw}.php
     * - /local/php_interface/classes/{Path|ucfirst,lowercase}/{*|ucfirst,lowercase}.php
     */
    spl_autoload_register(function($sClassName)
    {
    	$sClassFile = __DIR__.'/classes';
    
    	if ( file_exists($sClassFile.'/'.str_replace('\\', '/', $sClassName).'.php') )
    	{
    		require_once($sClassFile.'/'.str_replace('\\', '/', $sClassName).'.php');
    		return;
    	}
    
    	$arClass = explode('\\', strtolower($sClassName));
    	foreach($arClass as $sPath )
    	{
    	    $sClassFile .= '/'.ucfirst($sPath);
    	}
    	$sClassFile .= '.php';
    	if (file_exists($sClassFile))
    	{
    		require_once($sClassFile);
    	}
    });
    
    $eventManager = \Bitrix\Main\EventManager::getInstance();
    $eventManager->addEventHandlerCompatible(
    
    	'main',
    	'OnAfterUserAdd',
    	[
    		'AddUserToGroupChatsClass',
    		'AddUserToGroupChats'
    	]
    );


    Теперь нужно разметить ваш класс в файле: /local/php_interface/classes/AddUserToGroupChatsClass.php
    Заметьте - мы удалили сортировку (вам не важем порядок) и подключение файла - за это теперь отвечает автолоадер.

    Теперь поработаем с содержимым этого файла.
    Произведем косметические изменения:
    - уберем лишние отступы
    - добавим phpdoc

    Произведем функциональные изменения:
    - приведем файл к виду opentag -> namespace -> use -> class
    - добавим описание метода необходимые для вызова его в call_user_func_array
    - Пропишем корректные праметры к Debug::writeToFile методу

    <?php
    
    use \Bitrix\Main\Diag;
    
    class AddUserToGroupChatsClass
    {
    	/**
    	 * Handle main::OnAfterUserAdd event
    	 *     after add user to groups
    	 * @param array &$arFields User data
    	 * @return void
    	 */
    	public static function AddUserToGroupChats( &$arFields )
    	{		 
    		Diag\Debug::writeToFile(
    			[
    				'text'   => "Событие наступило",
    				'fields' => $arFields
    			],
    			date('d.m.Y'),
    			"AddUserToGroupChatsClass.log"
    		); 
    	}
    }


    В результате проделанной работы будет создан файл `AddUserToGroupChatsClass.log` (у меня bitrix env и $_SERVER['DOCUMENT_ROOT'] указывает на /home/bitrix/www, соответственно файл располагается по пути: /home/bitrix/www/AddUserToGroupChatsClass.log)

    С примерно таким содержимым:

    28.09.2021:
    Array
    (
        [text] => Событие наступило
        [fields] => Array
            (
                [TITLE] => 
                [NAME] => test1
                [LAST_NAME] => test1
                [SECOND_NAME] => test1
                [EMAIL] => test1@test1.test1
                [LOGIN] => test1@test1.test1
                [PERSONAL_PROFESSION] => 
                [PERSONAL_WWW] => 
                [PERSONAL_ICQ] => 
                [PERSONAL_GENDER] => 
                [PERSONAL_BIRTHDAY] => 
                [PERSONAL_PHONE] => 
                [PERSONAL_FAX] => 
                [PERSONAL_MOBILE] => 
                [PERSONAL_PAGER] => 
                [PERSONAL_STREET] => 
                [PERSONAL_MAILBOX] => 
                [PERSONAL_CITY] => 
                [PERSONAL_STATE] => 
                [PERSONAL_ZIP] => 
                [PERSONAL_COUNTRY] => 0
                [PERSONAL_NOTES] => 
                [WORK_COMPANY] => 
                [WORK_DEPARTMENT] => 
                [WORK_POSITION] => 
                [WORK_WWW] => 
                [WORK_PHONE] => 
                [WORK_FAX] => 
                [WORK_PAGER] => 
                [WORK_STREET] => 
                [WORK_MAILBOX] => 
                [WORK_CITY] => 
                [WORK_STATE] => 
                [WORK_ZIP] => 
                [WORK_COUNTRY] => 0
                [WORK_PROFILE] => 
                [WORK_NOTES] => 
                [AUTO_TIME_ZONE] => 
                [XML_ID] => 
                [PHONE_NUMBER] => 
                [PASSWORD_EXPIRED] => N
                [TIME_ZONE] => 
                [LID] => s1
                [LANGUAGE_ID] => 
                [ACTIVE] => Y
                [BLOCKED] => N
                [GROUP_ID] => Array
                    (
                        [0] => Array
                            (
                                [GROUP_ID] => 3
                                [DATE_ACTIVE_FROM] => 
                                [DATE_ACTIVE_TO] => 
                            )
    
                        [1] => Array
                            (
                                [GROUP_ID] => 12
                                [DATE_ACTIVE_FROM] => 
                                [DATE_ACTIVE_TO] => 
                            )
    
                        [2] => Array
                            (
                                [GROUP_ID] => 4
                                [DATE_ACTIVE_FROM] => 
                                [DATE_ACTIVE_TO] => 
                            )
    
                    )
    
                [ADMIN_NOTES] => 
                [PASSWORD] => $5$hjIX0a5X2ps0X6kFG1h5xXAt4elIW.typcRgt23xwX97xU.GgGt0i3HG1a2hwZtcYXwIR3Whg6sXwV.
                [CONFIRM_PASSWORD] => test1@test1.test1
                [UF_DEPARTMENT] => Array
                    (
                        [0] => 2
                    )
    
                [UF_PHONE_INNER] => 
                [UF_USER_CRM_ENTITY] => 
                [UF_INN] => 
                [UF_DISTRICT] => 
                [UF_SKYPE] => 
                [UF_TWITTER] => 
                [UF_FACEBOOK] => 
                [UF_LINKEDIN] => 
                [UF_XING] => 
                [UF_WEB_SITES] => 
                [UF_SKILLS] => 
                [UF_INTERESTS] => 
                [UF_EMPLOYMENT_DATE] => 
                [UF_SKYPE_LINK] => 
                [UF_ZOOM] => 
                [UF_TIMEMAN] => 
                [UF_TM_MAX_START] => 00:00
                [UF_TM_MIN_FINISH] => 00:00
                [UF_TM_MIN_DURATION] => 00:00
                [UF_TM_REPORT_REQ] => 
                [UF_TM_REPORT_TPL] => Array
                    (
                        [0] => 
                    )
    
                [UF_TM_FREE] => 
                [UF_TM_TIME] => 
                [UF_TM_DAY] => 
                [UF_TM_REPORT_DATE] => 
                [UF_REPORT_PERIOD] => 
                [UF_DELAY_TIME] => 
                [UF_LAST_REPORT_DATE] => 
                [UF_SETTING_DATE] => 
                [UF_TM_ALLOWED_DELTA] => 
                [CHECKWORD] => 433ddaf3c8a14fe75431252a2709b8
                [~CHECKWORD_TIME] => now()
                [ID] => 5
                [RESULT] => 5
            )
    )


    Итого на выходе у нас:
    - Подписка на событие (работает)
    - Автолоадер, который позволит подключать классы по мере использования (без необходимости прописывать явно)
    - Разделение логики между подпиской и обработчиком.

    Хорошо было бы углубиться в:
    - php классы (namespace, static, public, protected, private)
    - composer

    Надеюсь помог.
    Ответ написан
    Комментировать
  • Как в SQL работает оператор UNNEST?

    @kalapanga
    Описание тут https://www.postgresql.org/docs/13/functions-array.html
    Ну и например здесь https://habr.com/ru/post/280912/ Пример 2 про неё
    Ответ написан
    Комментировать
  • Как правильно делать подзапросы на SQL?

    rozhnev
    @rozhnev Куратор тега MySQL
    Fullstack programmer, DBA, медленно, дорого
    Правильно проиндексировать таблицы и использовать JOIN вместо подзапросов:
    SELECT shop.id, shop.name, SUM(sales.amount) sales_amount
    FROM sales
    JOIN shops ON sales.shop_id = shops.id
    GROUP BY  sales.shop_id, shop.id, shop.name
    Ответ написан
    2 комментария
  • При установке "pip install pyinstaller" выдает ошибку. Что делать?

    defender_X
    @defender_X
    Здравствуй друг! Зарегистрировался ради того что бы помочь тебе и всем кто ищет помощи. Ниже я провел порядок команд которые надо прописать для инсталляции pyinstaller. Хочу предупредить что "$" писать не надо. Если помог, не поленись зарегистрироваться на сайте и поставить лайк. Мне будет приятно вдвойне.
    $ python -m pip install —upgrade pip (Обновляем pip)
    $ pip install wheel (инсталлируем wheel без него ни как)
    $ pip install pyinstaller (Ну и сам pyinstaller)


    Сообщение для модератора/администратора
    Здравствуйте, оставляю эту запись здесь на всякий случай если будут какие либо претензии по поводу моего текста. Если все же я что то нарушил из ваших правил, прошу отредактировать пост, либо удалить. И не забудьте уведомить меня что именно было нарушено.
    С уважением Defendr X!
    Ответ написан
    Комментировать
  • Как не кешировать статическую страницу на битриксе?

    udjin123
    @udjin123
    PHP, Golang, React
    Если именно вставки в html код то
    Самый простой вариант добавить в ссылку к js и css рандомную строку

    Пример

    <script src="test.js?random=<?php echo uniqid(); ?>"></script>


    Но это не правильный способ подключения скриптов и стилей в битриксе, подключать нужно вот так

    Пример

    use Bitrix\Main\Page\Asset;
    
    Asset::getInstance()->addJs(SITE_TEMPLATE_PATH . "/js/fix.js");
    Asset::getInstance()->addCss(SITE_TEMPLATE_PATH . "/styles/fix.css");
    Asset::getInstance()->addString("<link href='http://fonts.googleapis.com/css?family=PT+Sans:400&subset=cyrillic' rel='stylesheet' type='text/css'>");


    Тогда можно сбросить кеш в админке или на нужной странице на панели администрирования.
    Ответ написан
    Комментировать
  • Как сделать плавное обновление блока погружаемого Ajax'ом?

    wielski
    @wielski
    ✔ Совет: Вам помогли? Отметьте ответы решением.
    А чем не устраивает fadeIn / fadeOut?
    Ответ написан
    2 комментария
  • Как получить все сделки в Битрикс24?

    gromdron
    @gromdron Куратор тега Битрикс24
    Работаю с Bitrix24
    Если вас интересует выгрузка большого объема данных, то метод с start не самая лучшая идея.
    Битрикс описал в своей мануале как это лучше сделать (вместе с замерами производительности):
    https://dev.1c-bitrix.ru/rest_help/rest_sum/start.php
    Ответ написан
    Комментировать
  • Из за чего не подключаются стандартные скрипты и стили в админке Битрикс?

    yuraSco
    @yuraSco Автор вопроса
    В конфиге apache надо было убрать:
    <LocationMatch "/\.(?!well-known)">
        Require             all denied
    </LocationMatch>
    Ответ написан
    7 комментариев
  • Как сделать редирект с карточки товара на новый урл?

    shambler81
    @shambler81 Куратор тега htaccess
    RewriteCond %{QUERY_STRING} (?:^|&)id\=(.+)(?:$|&)
    RewriteRule ^catalog/category/sub\-cetegory/name\-goods/$ /catalog/category/sub\-cetegory/products/name\-goods/\?id=%1 [L,R=301]
    Ответ написан
    Комментировать
  • Структура шаблона Shopify - зачем в корне файлов в шаблоне везде добавляют расширение liquid?

    KEugene
    @KEugene
    Это язык разметки, который используется в системе Shopify. И у файлов соответствующее расширение.
    https://shopify.github.io/liquid/
    Ответ написан
    Комментировать
  • Как обработать большой текст на js что бы разбить его на переменные?

    0xD34F
    @0xD34F Куратор тега JavaScript
    for (const n of str.matchAll(/---([A-Z]+)---(.*?)(?=---|$)/g)) {
      console.log(n[1], n[2].trim());
    }
    Ответ написан
    Комментировать
  • Как обработать большой текст на js что бы разбить его на переменные?

    firedragon
    @firedragon
    Не джун-мидл-сеньор, а трус-балбес-бывалый.
    Делайте split по —- в массиве четные строки будут заголовки, а нечетные телом.
    Ответ написан
    Комментировать
  • CSS и SEO - что лучше стили в отдельном файле или в теле страницы?

    @sidni
    Php Developer
    По правилам гугла...
    Выделяется базовый набор стилей только самые основные,к примеру сетка, основные цвета сайта и может размер шрифтов, и вставляется это inline прямо в header.
    Все файлы css подключаются асинхронно в инете есть множество примеров js скриптов которые это делают.
    Ответ написан
    6 комментариев
  • Как изменить цифру 8 на 7 при автозаполнении контакта (iphone) в инпут с маской?

    GrinMorg
    @GrinMorg
    Если ответ помог, отметь решением
    $('.form-tel').mask('+0 (000) 000 00 00', { placeholder: "+7 (___) ___ __ __" });
    $('.form-tel').on('input', function() {
            let val = $(this).val();
            if (val[1] == 8) {
                $(this).val(7 + val.slice(2));
            }
    });

    Проверка работает так: если первый символ после + равен 8, то срезаем всё кроме 8 и ставим 7 впереди.
    Ответ написан
    Комментировать