Задача: есть сущность специалист, специалист имеет квалификации. Для того, чтобы оценить квалификацию специалиста, к ней должна быть привязана дата её получения. В итоге, в одном поле должны храниться пары вида:
1С-Профессионал 15.01.2005 1С-Специалист 09.06.2011 и т.д.
На схеме данных это выглядит так:
Понятно, что хранить лишний инфоблок для такого пустяка избыточно, и был найден другой способ.
Некоторые типы свойств (строка, число, файл, дата, и т.д.) позволяют отдельно хранить поле для описания значения свойства. По умолчанию это просто текстовое поле, что не совсем подходит — вбивать руками дату пользователя не заставишь.
Задача свелась к следующему: создать такой тип свойства ИБ, который бы позволял в поле VALUE хранить ID элемента ИБ Квалификации, а в поле DESCRIPTION — дату её получения. При этом выводиться список Квалификаций должен в селекте, дату же будем выбирать с помощью стандартного bitrix:main.calendar.
К счастью, разработчики из Bitrix оставили некоторые указания на этот счёт[4].
Каждый тип свойства описывается набором методов:
Кроме того, в файле /bitrix/modules/main/classes/general/usertypestr.php достаточно комментариев, описывающих каждый метод.
Реализация
Создаём класс, в котором описываем тип свойства. Методы, которые понадобились мне:
Романов Александр, в данном примере дейтсвительно ее нет, но на деле, с помощью этих функции можно сохранять одно, а показывать другое.
Например у меня есть кастомное поле "Товар" типа E (привзяка к элементам), понятно, что для лучшего отображения и работы с ним нужно знать id элемента, но они достаточно часто меняются при выгрузке, а вот артикул остается всегда одинаковым (идет из 1С).
Поэтому я с помощью ConvertFromDB по артикулу ищу id, а при сохранении элемента id опять перевожу в артикул с помощью ConvertToDB. Т.е. в админке выводится ID, а в БД хранится артикул.
В приведенном примере ф-ия GetPropertyFieldHtml отдает вывод echo. Обязательно надо отдавать результат работы через return, иначе не будет работать добавление множественных свойств.
Всё бы хорошо, но DESCRIPTION не всегда рекомендуется к применению, если хотите работать с этим в публичке, так как в ряде методов пользовательских свойств инфоблоков он опущен, те же GetPublicViewHTML, GetSearchContent (хотя почему - не понятно). Ну или если нужен более универсальный с пользовательскими полями главного модуля код.
Не знаю причин, почему Битрикс выпустил функционал многодепартаментности настолько недоделанным, но задачу разделения портала на подпорталы нужно было решать имеющимися инструментами. Трудности начали возникать на самом старте:
В стандартном мастере нельзя указать произвольное название папки департамента, а по умолчанию генерируются имена вида: «site_» + рандомно сгенерированный двухсимвольный суффикс типа «xa», «mn» и т.д. Как нетрудно догадаться, менеджеры (как, впрочем, и все остальные сотрудники) не очень любят ничего не значащие названия, а хотят видеть нечто более говорящее, допустим, для филиала в Севастополе — «sevastopol».
Функционал департаментов сквозной, т.е. сотрудники подразделения имеют доступ к данным сотрудников подразделений верхнего уровня.
Настройки компонентов по умолчанию некорректны (выбираются дни рождения для всех пользователей, поиск работает по всем сотрудникам и т.п.).
Мобильное приложение не поддерживает многодепартаментность.
Что делать?
Ниже — небольшая инструкция по добавлению сайта-департамента, написанная для тех, кто хочет уменьшить головную боль, возникающую при настройке многофилиальности. Инструкция не полная, часть косяков в процессе отлова, гора тикетов — в техподдержке. Дополнения и замечания приветствуются.
В админ-панели нажимаем «Добавить подразделение».
Проходим мастер добавления, попутно меняем:
Название сайта (например, «Севастополь»).
Выбираем подразделение, сотрудники которого будут иметь доступ к разделу.
Сгенерируется папка с названием вида «site_xx». Переименовываем её в нужную нам (например, в «sevastopol»).
Переходим в админку — настройки продукта — сайты — список сайтов. Выбираем нужный. В поле «Папка сайта» указываем только что переименованную папку.
Идём в настройки модуля задач, на вкладке только что созданного сайта устанавливаем правильные пути («site_xx» -> «sevastopol»).
Открываем urlrewrite.php, заменяем все «site_xx» на «sevastopol».
Где-нибудь на сервере выполняем replaceInDirectory('site_xx’, 'sevastopol’, $_SERVER['DOCUMENT_ROOT'] . '/sevastopol', true). Это нужно для того, чтобы заменить во всех файлах упоминания «site_xx» на «sevastopol». Код здесь.
На странице поиска сотрудников (/sevastopol/company/index.php) нужно отображать сотрудников только текущего департамента: /sevastopol/company/.left.menu.php Array( "Поиск сотрудника", "/sevastopol/company/index.php", —> “/sevastopol/company/index.php?set_filter_company_search=Y&company_search_UF_DEPARTMENT=1234” Array(), Array(), "" ), На индексную поиска можно добавить Поиск по сотрудникам всей компании
На странице дней рождения (https://indigo.rarus.ru/kzn/company/bi...thdays.php) нужно показывать др сотрудников текущего департамента:/sevastopol/company/.left.menu.php Array( "Дни рождения", "/sevastopol/company/birthdays.php", —> /sevastopol/company/birthdays.php?department=1234 Array(), Array(), "" ),
Правим пути в резервировании переговорных. /sevastopol/services/index.php, добавляем, где надо «/sevastopol».
Navigation Timing API — средство для выявления источников тормозов на проекте.
Как это работает?
Время загрузки страницы складывается из 3-х составляющих:
1. Время запроса от клиента к серверу (проблемы со связью?) 2. Возврат результатов обработки клиенту (сервак тупит?) 3. Рендеринг страницы (слабый клиент или много плагинов и прочего js?)
Внятного механизма получения значений времени, которое тратится на каждый из шагов раньше не было. Navigation Timing API как раз даёт возможность без труда определить это время на клиенте. В действительности, оно позволяет узнать даже больше (подробные описания таймингов есть у авторитетныхпарней):
Получить тайминги (timestamps) из браузера можно, используя interface PerformanceTiming { readonly attribute unsigned long longnavigationStart; readonly attribute unsigned long longunloadEventStart; readonly attribute unsigned long longunloadEventEnd; readonly attribute unsigned long longredirectStart; readonly attribute unsigned long longredirectEnd; readonly attribute unsigned long longfetchStart; readonly attribute unsigned long longdomainLookupStart; readonly attribute unsigned long longdomainLookupEnd; readonly attribute unsigned long longconnectStart; readonly attribute unsigned long longconnectEnd; readonly attribute unsigned long longsecureConnectionStart; readonly attribute unsigned long longrequestStart; readonly attribute unsigned long longresponseStart; readonly attribute unsigned long longresponseEnd; readonly attribute unsigned long longdomLoading; readonly attribute unsigned long longdomInteractive; readonly attribute unsigned long longdomContentLoadedEventStart; readonly attribute unsigned long longdomContentLoadedEventEnd; readonly attribute unsigned long longdomComplete; readonly attribute unsigned long longloadEventStart; readonly attribute unsigned long longloadEventEnd; };
Зачем это нужно? Пример: пользователи стали жаловаться, что страницы грузятся долго. Добиться чего-то более внятного, чем просто “долго”, невозможно, поэтому появилось такое решение:
Добавляем в шапку код, который сдирает данные из структуры выше + добавляем к ним время, когда страница окончательно собрана.
По вкусу добавляем к структуре имя пользователя, браузер, имя проекта.
Пакуем всё это дело, шлём на сервер. Примерно так:
tempOnLoad = window.onload; //сохраним битриксовые обработчики window.onload = function(){ checkTimings(); if (tempOnLoad){ tempOnLoad(); //возвращаем битриксовые обработчики } } function checkTimings(){
var temp = new Object(); for (var o in performance.timing){ /*костыль из-за различий между FF,IE и Chrome в понимании того, что же есть performance.timing*/ if (o == 'msFirstPaint') { //исключим специфику IE continue; } temp[o] = performance.timing[o]; } temp['secureConnectionStart'] = (temp['secureConnectionStart']) ? temp['secureConnectionStart'] : 0; // фикс для FF
var target = 'http://targetfile.php?time='+encodeURIComponent(JSON.stringify(temp)); var request = createCORSRequest('POST', target); request.send(); }
Что делать там с данными — уж кто как хочет. Наш вариант — график зависимости время загрузки от времени, когда данные были сняты с возможностью детального просмотра таймингов по каждому событию.
Александр Сербул , вот так можно померять задержки на клиент-сайде. Если внедрите на Bitrix24, то уже никаких «а у нас тормозило вчера» от недовольных клиентов.
Navigation Timing API — средство для выявления источников тормозов на проекте.
Как это работает?
Время загрузки страницы складывается из 3-х составляющих:
1. Время запроса от клиента к серверу (проблемы со связью?) 2. Возврат результатов обработки клиенту (сервак тупит?) 3. Рендеринг страницы (слабый клиент или много плагинов и прочего js?)
Внятного механизма получения значений времени, которое тратится на каждый из шагов раньше не было. Navigation Timing API как раз даёт возможность без труда определить это время на клиенте. В действительности, оно позволяет узнать даже больше (подробные описания таймингов есть у авторитетныхпарней):
Получить тайминги (timestamps) из браузера можно, используя interface PerformanceTiming { readonly attribute unsigned long longnavigationStart; readonly attribute unsigned long longunloadEventStart; readonly attribute unsigned long longunloadEventEnd; readonly attribute unsigned long longredirectStart; readonly attribute unsigned long longredirectEnd; readonly attribute unsigned long longfetchStart; readonly attribute unsigned long longdomainLookupStart; readonly attribute unsigned long longdomainLookupEnd; readonly attribute unsigned long longconnectStart; readonly attribute unsigned long longconnectEnd; readonly attribute unsigned long longsecureConnectionStart; readonly attribute unsigned long longrequestStart; readonly attribute unsigned long longresponseStart; readonly attribute unsigned long longresponseEnd; readonly attribute unsigned long longdomLoading; readonly attribute unsigned long longdomInteractive; readonly attribute unsigned long longdomContentLoadedEventStart; readonly attribute unsigned long longdomContentLoadedEventEnd; readonly attribute unsigned long longdomComplete; readonly attribute unsigned long longloadEventStart; readonly attribute unsigned long longloadEventEnd; };
Зачем это нужно? Пример: пользователи стали жаловаться, что страницы грузятся долго. Добиться чего-то более внятного, чем просто “долго”, невозможно, поэтому появилось такое решение:
Добавляем в шапку код, который сдирает данные из структуры выше + добавляем к ним время, когда страница окончательно собрана.
По вкусу добавляем к структуре имя пользователя, браузер, имя проекта.
Пакуем всё это дело, шлём на сервер. Примерно так:
tempOnLoad = window.onload; //сохраним битриксовые обработчики window.onload = function(){ checkTimings(); if (tempOnLoad){ tempOnLoad(); //возвращаем битриксовые обработчики } } function checkTimings(){
var temp = new Object(); for (var o in performance.timing){ /*костыль из-за различий между FF,IE и Chrome в понимании того, что же есть performance.timing*/ if (o == 'msFirstPaint') { //исключим специфику IE continue; } temp[o] = performance.timing[o]; } temp['secureConnectionStart'] = (temp['secureConnectionStart']) ? temp['secureConnectionStart'] : 0; // фикс для FF
var target = 'http://targetfile.php?time='+encodeURIComponent(JSON.stringify(temp)); var request = createCORSRequest('POST', target); request.send(); }
Что делать там с данными — уж кто как хочет. Наш вариант — график зависимости время загрузки от времени, когда данные были сняты с возможностью детального просмотра таймингов по каждому событию.
Александр Сербул , вот так можно померять задержки на клиент-сайде. Если внедрите на Bitrix24, то уже никаких «а у нас тормозило вчера» от недовольных клиентов.
Navigation Timing API — средство для выявления источников тормозов на проекте.
Как это работает?
Время загрузки страницы складывается из 3-х составляющих:
1. Время запроса от клиента к серверу (проблемы со связью?) 2. Возврат результатов обработки клиенту (сервак тупит?) 3. Рендеринг страницы (слабый клиент или много плагинов и прочего js?)
Внятного механизма получения значений времени, которое тратится на каждый из шагов раньше не было. Navigation Timing API как раз даёт возможность без труда определить это время на клиенте. В действительности, оно позволяет узнать даже больше (подробные описания таймингов есть у авторитетныхпарней):
Получить тайминги (timestamps) из браузера можно, используя interface PerformanceTiming { readonly attribute unsigned long longnavigationStart; readonly attribute unsigned long longunloadEventStart; readonly attribute unsigned long longunloadEventEnd; readonly attribute unsigned long longredirectStart; readonly attribute unsigned long longredirectEnd; readonly attribute unsigned long longfetchStart; readonly attribute unsigned long longdomainLookupStart; readonly attribute unsigned long longdomainLookupEnd; readonly attribute unsigned long longconnectStart; readonly attribute unsigned long longconnectEnd; readonly attribute unsigned long longsecureConnectionStart; readonly attribute unsigned long longrequestStart; readonly attribute unsigned long longresponseStart; readonly attribute unsigned long longresponseEnd; readonly attribute unsigned long longdomLoading; readonly attribute unsigned long longdomInteractive; readonly attribute unsigned long longdomContentLoadedEventStart; readonly attribute unsigned long longdomContentLoadedEventEnd; readonly attribute unsigned long longdomComplete; readonly attribute unsigned long longloadEventStart; readonly attribute unsigned long longloadEventEnd; };
Зачем это нужно? Пример: пользователи стали жаловаться, что страницы грузятся долго. Добиться чего-то более внятного, чем просто “долго”, невозможно, поэтому появилось такое решение:
Добавляем в шапку код, который сдирает данные из структуры выше + добавляем к ним время, когда страница окончательно собрана.
По вкусу добавляем к структуре имя пользователя, браузер, имя проекта.
Пакуем всё это дело, шлём на сервер. Примерно так:
tempOnLoad = window.onload; //сохраним битриксовые обработчики window.onload = function(){ checkTimings(); if (tempOnLoad){ tempOnLoad(); //возвращаем битриксовые обработчики } } function checkTimings(){
var temp = new Object(); for (var o in performance.timing){ /*костыль из-за различий между FF,IE и Chrome в понимании того, что же есть performance.timing*/ if (o == 'msFirstPaint') { //исключим специфику IE continue; } temp[o] = performance.timing[o]; } temp['secureConnectionStart'] = (temp['secureConnectionStart']) ? temp['secureConnectionStart'] : 0; // фикс для FF
var target = 'http://targetfile.php?time='+encodeURIComponent(JSON.stringify(temp)); var request = createCORSRequest('POST', target); request.send(); }
Что делать там с данными — уж кто как хочет. Наш вариант — график зависимости время загрузки от времени, когда данные были сняты с возможностью детального просмотра таймингов по каждому событию.
Александр Сербул , вот так можно померять задержки на клиент-сайде. Если внедрите на Bitrix24, то уже никаких «а у нас тормозило вчера» от недовольных клиентов.
Задача: надо добавлять в ИБ “A” элементы, связанные с элементами ИБ “B”, причём иногда, на момент создания элемента ИБ “A”, элементы ИБ “B” ещё не существуют. Т.е. их надо добавлять по ходу создания элемента ИБ “A”.
Как-то так:
Тип свойства “Тип аутсорсинга”: привязка к элементу в виде списка. Да, можно было бы просто сделать 2 формы добавления элементов A и B, и скорее всего, я бы так и сделал, если бы элемент B содержал в себе кучу сложных свойств, но для моей предметной области, элемент B имел всего лишь 2 поля:
Название.
Описание.
Очевидно, с таким набором удобнее добавлять нужные элементы на ходу, чем заставлять пользователя прыгать с формы на форму.
Реализация: я буду тут всё подряд упрощать, покажу только основное. Итак, предполагаю, что шаблон iblock.element.add.form перенесён в свой шаблон сайта, чтобы изменения не перетёрлись при обновлении.
1. Открываем template.php. В кейсе ‘USER_TYPE’ первого свича нужно отсеять наше свойство. Я добавляю вывод формы для елемента “B” сразу после вывода самого свойства, т.е. :
//исходный код...
В развёрнутом виде это так:
2. Зашлём данные из полей аяксом.
Тут всё предельно просто: берём данные из формы, и по клику на “Добавить” шлём их на addiblockelements.php
3. addiblockelements.php
Тут всё тоже ясно: сбрасываем буфер, чтобы не возвращать всякую ненужную шелуху, декодируем данные , создаём новый “B”. Если не получилось (например, поля пустые), то возвращаем ошибку, кодируем данные обратно.
4. Данные получили, теперь надо их обработать на клиенте, чтобы можно было использовать только что созданный элемент в главной форме. На шаге 2 мы определили, какой обработчик будет работать с полученными после запроса данными — add_pricetype_result
Тут мы добавляем элемент в выпадающий список элементов “B” формы добавления “A”. В value заносим id только что созданного элемента “B”, и теперь его можно использовать.
Вот и всё, надеюсь, кому-нибудь пригодится. Код выкладывать смысла нет, он достаточно специфичен.
Задача: есть сущность специалист, специалист имеет квалификации. Для того, чтобы оценить квалификацию специалиста, к ней должна быть привязана дата её получения. В итоге, в одном поле должны храниться пары вида:
1С-Профессионал 15.01.2005 1С-Специалист 09.06.2011 и т.д.
На схеме данных это выглядит так:
Понятно, что хранить лишний инфоблок для такого пустяка избыточно, и был найден другой способ.
Некоторые типы свойств (строка, число, файл, дата, и т.д.) позволяют отдельно хранить поле для описания значения свойства. По умолчанию это просто текстовое поле, что не совсем подходит — вбивать руками дату пользователя не заставишь.
Задача свелась к следующему: создать такой тип свойства ИБ, который бы позволял в поле VALUE хранить ID элемента ИБ Квалификации, а в поле DESCRIPTION — дату её получения. При этом выводиться список Квалификаций должен в селекте, дату же будем выбирать с помощью стандартного bitrix:main.calendar.
К счастью, разработчики из Bitrix оставили некоторые указания на этот счёт[4].
Каждый тип свойства описывается набором методов:
Кроме того, в файле /bitrix/modules/main/classes/general/usertypestr.php достаточно комментариев, описывающих каждый метод.
Реализация
Создаём класс, в котором описываем тип свойства. Методы, которые понадобились мне:
Романов Александр, в данном примере дейтсвительно ее нет, но на деле, с помощью этих функции можно сохранять одно, а показывать другое.
Например у меня есть кастомное поле "Товар" типа E (привзяка к элементам), понятно, что для лучшего отображения и работы с ним нужно знать id элемента, но они достаточно часто меняются при выгрузке, а вот артикул остается всегда одинаковым (идет из 1С).
Поэтому я с помощью ConvertFromDB по артикулу ищу id, а при сохранении элемента id опять перевожу в артикул с помощью ConvertToDB. Т.е. в админке выводится ID, а в БД хранится артикул.
В приведенном примере ф-ия GetPropertyFieldHtml отдает вывод echo. Обязательно надо отдавать результат работы через return, иначе не будет работать добавление множественных свойств.
Всё бы хорошо, но DESCRIPTION не всегда рекомендуется к применению, если хотите работать с этим в публичке, так как в ряде методов пользовательских свойств инфоблоков он опущен, те же GetPublicViewHTML, GetSearchContent (хотя почему - не понятно). Ну или если нужен более универсальный с пользовательскими полями главного модуля код.
Задача: есть сущность специалист, специалист имеет квалификации. Для того, чтобы оценить квалификацию специалиста, к ней должна быть привязана дата её получения. В итоге, в одном поле должны храниться пары вида:
1С-Профессионал 15.01.2005 1С-Специалист 09.06.2011 и т.д.
На схеме данных это выглядит так:
Понятно, что хранить лишний инфоблок для такого пустяка избыточно, и был найден другой способ.
Некоторые типы свойств (строка, число, файл, дата, и т.д.) позволяют отдельно хранить поле для описания значения свойства. По умолчанию это просто текстовое поле, что не совсем подходит — вбивать руками дату пользователя не заставишь.
Задача свелась к следующему: создать такой тип свойства ИБ, который бы позволял в поле VALUE хранить ID элемента ИБ Квалификации, а в поле DESCRIPTION — дату её получения. При этом выводиться список Квалификаций должен в селекте, дату же будем выбирать с помощью стандартного bitrix:main.calendar.
К счастью, разработчики из Bitrix оставили некоторые указания на этот счёт[4].
Каждый тип свойства описывается набором методов:
Кроме того, в файле /bitrix/modules/main/classes/general/usertypestr.php достаточно комментариев, описывающих каждый метод.
Реализация
Создаём класс, в котором описываем тип свойства. Методы, которые понадобились мне:
Романов Александр, в данном примере дейтсвительно ее нет, но на деле, с помощью этих функции можно сохранять одно, а показывать другое.
Например у меня есть кастомное поле "Товар" типа E (привзяка к элементам), понятно, что для лучшего отображения и работы с ним нужно знать id элемента, но они достаточно часто меняются при выгрузке, а вот артикул остается всегда одинаковым (идет из 1С).
Поэтому я с помощью ConvertFromDB по артикулу ищу id, а при сохранении элемента id опять перевожу в артикул с помощью ConvertToDB. Т.е. в админке выводится ID, а в БД хранится артикул.
В приведенном примере ф-ия GetPropertyFieldHtml отдает вывод echo. Обязательно надо отдавать результат работы через return, иначе не будет работать добавление множественных свойств.
Всё бы хорошо, но DESCRIPTION не всегда рекомендуется к применению, если хотите работать с этим в публичке, так как в ряде методов пользовательских свойств инфоблоков он опущен, те же GetPublicViewHTML, GetSearchContent (хотя почему - не понятно). Ну или если нужен более универсальный с пользовательскими полями главного модуля код.
Задача: есть сущность специалист, специалист имеет квалификации. Для того, чтобы оценить квалификацию специалиста, к ней должна быть привязана дата её получения. В итоге, в одном поле должны храниться пары вида:
1С-Профессионал 15.01.2005 1С-Специалист 09.06.2011 и т.д.
На схеме данных это выглядит так:
Понятно, что хранить лишний инфоблок для такого пустяка избыточно, и был найден другой способ.
Некоторые типы свойств (строка, число, файл, дата, и т.д.) позволяют отдельно хранить поле для описания значения свойства. По умолчанию это просто текстовое поле, что не совсем подходит — вбивать руками дату пользователя не заставишь.
Задача свелась к следующему: создать такой тип свойства ИБ, который бы позволял в поле VALUE хранить ID элемента ИБ Квалификации, а в поле DESCRIPTION — дату её получения. При этом выводиться список Квалификаций должен в селекте, дату же будем выбирать с помощью стандартного bitrix:main.calendar.
К счастью, разработчики из Bitrix оставили некоторые указания на этот счёт[4].
Каждый тип свойства описывается набором методов:
Кроме того, в файле /bitrix/modules/main/classes/general/usertypestr.php достаточно комментариев, описывающих каждый метод.
Реализация
Создаём класс, в котором описываем тип свойства. Методы, которые понадобились мне:
Романов Александр, в данном примере дейтсвительно ее нет, но на деле, с помощью этих функции можно сохранять одно, а показывать другое.
Например у меня есть кастомное поле "Товар" типа E (привзяка к элементам), понятно, что для лучшего отображения и работы с ним нужно знать id элемента, но они достаточно часто меняются при выгрузке, а вот артикул остается всегда одинаковым (идет из 1С).
Поэтому я с помощью ConvertFromDB по артикулу ищу id, а при сохранении элемента id опять перевожу в артикул с помощью ConvertToDB. Т.е. в админке выводится ID, а в БД хранится артикул.
В приведенном примере ф-ия GetPropertyFieldHtml отдает вывод echo. Обязательно надо отдавать результат работы через return, иначе не будет работать добавление множественных свойств.
Всё бы хорошо, но DESCRIPTION не всегда рекомендуется к применению, если хотите работать с этим в публичке, так как в ряде методов пользовательских свойств инфоблоков он опущен, те же GetPublicViewHTML, GetSearchContent (хотя почему - не понятно). Ну или если нужен более универсальный с пользовательскими полями главного модуля код.
Группы на сайте создаются не только сотрудниками «1С-Битрикс», но и партнерами компании. Поэтому мнения участников групп могут не совпадать с позицией компании «1С-Битрикс».