diff --git "a/docs/00_\320\241_\321\207\320\265\320\263\320\276_\320\275\320\260\321\207\320\260\321\202\321\214.md" "b/docs/00_\320\241_\321\207\320\265\320\263\320\276_\320\275\320\260\321\207\320\260\321\202\321\214.md" index 7f1d141..b43e313 100644 --- "a/docs/00_\320\241_\321\207\320\265\320\263\320\276_\320\275\320\260\321\207\320\260\321\202\321\214.md" +++ "b/docs/00_\320\241_\321\207\320\265\320\263\320\276_\320\275\320\260\321\207\320\260\321\202\321\214.md" @@ -1,17 +1,17 @@ # Введение -Битрикс24 это сложный продукт с богатым наследием, окутанный мифами и тайнами. Можно любить Битрикс24, можно нендавидеть, но если вам приходиться разбираться с ним то это точно для вас. В этой книге мы будем рассматривать коробочную версию Битрикс24 и хотя некоторые аспекты будут симметричны для облачной версии, нашим фокусом будет именно на коробочной версии. Понимание процессов происходящих внутри продукта поможет сократить значительное время на исследование их самостоятельным путем. +Битрикс24 это сложный продукт с богатым наследием, окутанный мифами и тайнами. Можно любить Битрикс24, можно ненавидеть, но если вам приходиться разбираться с ним то это точно для вас. В этой книге мы будем рассматривать коробочную версию Битрикс24 и хотя некоторые аспекты будут симметричны для облачной версии, нашим фокусом будет именно коробочная версия. Понимание процессов происходящих внутри продукта поможет сократить значительное время на исследование их самостоятельным путем. -Работа над книгой мы держим в фокусе следующие цели: +Работа над книгой мы ставим перед собой следующие цели: * Систематизация знаний в области API Битрикс24. * Упрощение изучения платформы для новых разработчиков # С чего начать изучение Битрикс24? -Прежде всего рекомендуется начать пользоваться продуктом, потому что без знания продукта нельзя разрабатывать качественные решения под него. Продукт имеет свою философию и фокус-группу и понимание их в свою очередь дает хороший старт для последующих разработок - вы не просто будете понимать как вашу задачу решает продукт, но и как не следует ее решать, а обычно это узнать можно только на практике. +Прежде всего рекомендуется начать пользоваться продуктом, потому что без знания продукта нельзя разрабатывать качественные решения под него. Продукт имеет свою философию и ее понимание в свою очередь дает хороший старт для последующих разработок - вы не просто будете понимать как вашу задачу решает продукт, но и как не следует ее решать. -Прежде чем читать этот технический текст, настоятельно рекомендуется ознакомиться с следующими источниками: +Прежде чем читать этот технический текст, настоятельно рекомендуется ознакомиться со следующими источниками: * [Поддержка24](https://helpdesk.bitrix24.ru/) * [Администратор сервиса Битрикс24 (коробочная версия)](https://dev.1c-bitrix.ru/learning/course/index.php?COURSE_ID=48) @@ -20,10 +20,10 @@ Некоторые разделы данного руководства могут частично или полностью повторять уроки и/или статьи в перечисленных ранее источниках, это не воровство или присваивание чужого интеллектуального труда, а необходимая мера для систематизации знаний в одном месте. -Для понимания значительной части информации потребуются знания только языка программирования PHP, однако для понимания некоторых разделов потребуются дополнительные знания. Мы считаем что минимально ориентироваться стоит на следующе технологии: +Для понимания значительной части информации потребуются знания языка программирования PHP, однако для понимания некоторых разделов потребуются дополнительные знания. Мы считаем что минимально ориентироваться стоит на следующе технологии: -* Знать PHP 7.4, 8.0, 8.1 и их различия в части обратной совместимости +* Знать PHP 7.4, 8.0 - 8.2 и их различия в части обратной совместимости * JavaScript - в продукте используются разные технологии включая JS, ES6, TypeScript * SQL (основная субд - MySQL / Percona Server / MariaDB) -* Linux (базовое владение в том числе комманды cd, ls, chmod, chown, vi/vim/nano, cat, tail, grep, rm и др.) -* Общие знания по работе протоколов HTTP, DNS, SSL, SMTP, IMAP/POP3 \ No newline at end of file +* Linux (базовое владение, в том числе команды: `cd`, `ls`, `chmod`, `chown`, `vi`/`vim`/`nano`, `cat`, `tail`, `grep`, `rm` и др.) +* Общие знания по работе протоколов HTTP, DNS, SMTP, IMAP/POP3 \ No newline at end of file diff --git "a/docs/01_\320\224\320\276\320\272\321\203\320\274\320\265\320\275\321\202\320\260\321\206\320\270\321\217/00_\320\241\320\277\321\200\320\260\320\262\320\276\321\207\320\275\320\270\320\272.md" "b/docs/01_\320\224\320\276\320\272\321\203\320\274\320\265\320\275\321\202\320\260\321\206\320\270\321\217/00_\320\241\320\277\321\200\320\260\320\262\320\276\321\207\320\275\320\270\320\272.md" index a2fdc8e..fe35487 100644 --- "a/docs/01_\320\224\320\276\320\272\321\203\320\274\320\265\320\275\321\202\320\260\321\206\320\270\321\217/00_\320\241\320\277\321\200\320\260\320\262\320\276\321\207\320\275\320\270\320\272.md" +++ "b/docs/01_\320\224\320\276\320\272\321\203\320\274\320\265\320\275\321\202\320\260\321\206\320\270\321\217/00_\320\241\320\277\321\200\320\260\320\262\320\276\321\207\320\275\320\270\320\272.md" @@ -1,6 +1,6 @@ # Вступление -Перед тем как погружаться в изучение Битрикс24 необходимо иметь хотя бы поверхностные знания о продукте, а лучшее место где можно подчерпнуть эти знания является документация. +Перед тем как погружаться в изучение Битрикс24 необходимо иметь хотя бы поверхностные знания о продукте, а лучшее место где можно подчеркнуть эти знания является документация. На этой странице мы пытаемся собрать ссылки на информационные ресурсы, которые так или иначе связаны с продуктом. diff --git "a/docs/01_\320\224\320\276\320\272\321\203\320\274\320\265\320\275\321\202\320\260\321\206\320\270\321\217/01_\320\241\320\260\320\274_\321\201\320\265\320\261\320\265_\320\270\321\201\321\202\320\276\321\207\320\275\320\270\320\272.md" "b/docs/01_\320\224\320\276\320\272\321\203\320\274\320\265\320\275\321\202\320\260\321\206\320\270\321\217/01_\320\241\320\260\320\274_\321\201\320\265\320\261\320\265_\320\270\321\201\321\202\320\276\321\207\320\275\320\270\320\272.md" index 469d041..4dae522 100644 --- "a/docs/01_\320\224\320\276\320\272\321\203\320\274\320\265\320\275\321\202\320\260\321\206\320\270\321\217/01_\320\241\320\260\320\274_\321\201\320\265\320\261\320\265_\320\270\321\201\321\202\320\276\321\207\320\275\320\270\320\272.md" +++ "b/docs/01_\320\224\320\276\320\272\321\203\320\274\320\265\320\275\321\202\320\260\321\206\320\270\321\217/01_\320\241\320\260\320\274_\321\201\320\265\320\261\320\265_\320\270\321\201\321\202\320\276\321\207\320\275\320\270\320\272.md" @@ -8,9 +8,9 @@ >Если для искомого механизма существует REST метод, то его можно найти и посмотреть как он реализован. -Модуль REST является скорее техническим модулем нежели самостоятельным. Его архитектурная идея состоит в том, чтобы помочь другим модулям предоставив механизм для описания REST методов, а так же предоставить возможность использовать внешними системами это API. Таким образом найдя все подписки на этот модуль, можно найти все методы которые доступны через REST. +Модуль REST является скорее техническим модулем, нежели самостоятельным. Его архитектурная идея состоит в том, чтобы помочь другим модулям предоставив механизм для описания REST методов, а так же предоставить возможность использовать внешними системами это API. Таким образом найдя все подписки на этот модуль, можно найти все методы которые доступны через REST. -Интересующее нас событие onRestServiceBuildDescription модуля rest. Именно на него подписываются существующие модули или произвольный php-код и дополняют существующие методы (или переопределяют). Для того чтобы определить все классы которые предоставляют rest-методы можно выполнить фрагмент кода в Командной PHP-строке: +Интересующее нас событие onRestServiceBuildDescription модуля rest. Именно на него подписываются существующие модули или произвольный php-код и дополняют существующие методы (или переопределяют). Для того чтобы определить все классы, которые предоставляют rest-методы можно выполнить фрагмент кода в Командной PHP-строке: ```php var_dump(\GetModuleEvents('rest', 'onRestServiceBuildDescription')); @@ -26,10 +26,10 @@ var_dump(\GetModuleEvents('rest', 'onRestServiceBuildDescription')); Таким образом, в случае если для определенной сущности выбрано название, то оно будет фигурировать во всех связанных с ней областях. Так например, для сделки выбрано DEAL, тогда все классы так или иначе будут связаны со сделкой. Пример: -* Класс CCrmDeal -* Класс \Bitrix\Crm\DealTable -* Класс \Bitrix\Crm\Recycling\DealBinder -* Константа SONET_CRM_DEAL_ENTITY +* Класс `CCrmDeal` +* Класс `\Bitrix\Crm\DealTable` +* Класс `\Bitrix\Crm\Recycling\DealBinder` +* Константа `SONET_CRM_DEAL_ENTITY` Этой информации достаточно для начала поиска, в то время как именование классов будет рассмотрено отдельно в соответствующем разделе. @@ -37,15 +37,15 @@ var_dump(\GetModuleEvents('rest', 'onRestServiceBuildDescription')); Иногда может потребоваться найти вывод какого-нибудь специального фрагмента, например языковой фразы или css-класса и такой поиск может существенно затянуться, ведь они могут быть разбросаны по системе в сотнях огромных файлах. -Для этого на выручку приходят коммандные утилиты linux, такие как grep. Подробнее с коммандой можно разобраться по [доступным статьям в сети интернет](https://losst.ru/gerp-poisk-vnutri-fajlov-v-linux), мы же воспользуемся краткой выжимкой. +Для этого на выручку приходят командные утилиты linux, например `grep`. Подробнее с командой можно разобраться по [доступным статьям в сети интернет](https://losst.ru/gerp-poisk-vnutri-fajlov-v-linux), мы же воспользуемся краткой выжимкой. ```bash grep -ril 'something' ./some_path ``` -Комманда выполняет рекурсивный (``r``) регистронезависимый (``i``) поиск something в директории ``./some_path`` выводя исключительно файлы (``l``). +Команда выполняет рекурсивный (``r``) регистро-независимый (``i``) поиск something в директории ``./some_path`` выводя исключительно файлы (``l``). -Например, если выполнить нижеописанную комманду в директории ``/home/bitrix/www/bitrix/modules/crm/lib`` +Например, если выполнить нижеописанную команду в директории ``/home/bitrix/www/bitrix/modules/crm/lib`` ```bash grep -ril 'DEAL' ./ @@ -68,7 +68,7 @@ grep -ril 'DEAL' ./ ./tracking/analytics/dataprovider.php ``` -Иногда для исследования необходимо отследить не только конкретный фрагмент но и его окружение, тогда полезным будет другой модификатор комманды: ``n``. +Иногда для исследования необходимо отследить не только конкретный фрагмент, но и его окружение, тогда полезным будет другой модификатор команды: ``n``. Например, мы хотим найти то же слово, но нас так же интересует контекст (номер стройки и ее содержимое). Выполняем измененную команду в той же директории: ```bash @@ -95,14 +95,14 @@ grep -rin 'DEAL' ./ ./ads/adsaudience.php:79: $entityDb = \CCrmDeal::getListEx(array(), $subFilter); ``` -Помните, что рекурсивый вызов grep может занять достаточно продолжительное время, поэтому рекомендуется ограничивать область поиска локализуя его перед тем как выполнить комманду. +Помните, что рекурсивный вызов grep может занять достаточно продолжительное время, поэтому рекомендуется ограничивать область поиска локализуя его перед тем как выполнить команду. ## Исследование JS-событий Достаточно часто возникает ситуация когда нужно повлиять на текущую страницу, например убрать какие-либо элементы или изменить их поведение. -Зачастую неопытные разработчики пытаются применить timeout-механизм, который может сыграть с ним злую шутку и на пользовательском ПК не сработать.Наиболе правильным вариантов в данном случае будет использование событий страницы. +Зачастую неопытные разработчики пытаются применить timeout-механизм, который может сыграть с ним злую шутку и на пользовательском ПК не сработать. Наиболее правильным вариантом в данном случае будет использование событий страницы. -В отличии от php-событий системы события публичной части не описываются и приходится искать их по всей системе, а советы которые предлагают разработчики уже не работают (привет новому коду из ES6). Как же тогда искать все вызовы? +В отличие от php-событий системы события публичной части не описываются и приходится искать их по всей системе, а советы которые предлагают разработчики уже не работают (привет новому коду из ES6). Как же тогда искать все вызовы? Помощь приходит откуда не ждали: в браузере Mozilla Firefox присутствуют [механизмы отладки в браузере](https://developer.mozilla.org/en-US/docs/Tools/Debugger). Нас интересует логгирование в браузере [Set a logpoint](https://developer.mozilla.org/en-US/docs/Tools/Debugger/Set_a_logpoint). diff --git "a/docs/02_\320\236\320\261\321\211\320\270\320\265_\321\201\320\262\320\265\320\264\320\265\320\275\320\270\321\217/00_\320\236\320\261\321\200\320\260\320\261\320\276\321\202\320\272\320\260_uri.md" "b/docs/02_\320\236\320\261\321\211\320\270\320\265_\321\201\320\262\320\265\320\264\320\265\320\275\320\270\321\217/00_\320\236\320\261\321\200\320\260\320\261\320\276\321\202\320\272\320\260_uri.md" index 9f40512..929413e 100644 --- "a/docs/02_\320\236\320\261\321\211\320\270\320\265_\321\201\320\262\320\265\320\264\320\265\320\275\320\270\321\217/00_\320\236\320\261\321\200\320\260\320\261\320\276\321\202\320\272\320\260_uri.md" +++ "b/docs/02_\320\236\320\261\321\211\320\270\320\265_\321\201\320\262\320\265\320\264\320\265\320\275\320\270\321\217/00_\320\236\320\261\321\200\320\260\320\261\320\276\321\202\320\272\320\260_uri.md" @@ -4,17 +4,13 @@ # Жизненный цикл запроса -В отличии от многих современных MVC-фреймворков, продукт Битрикс24 не использует концепцию единой точки входа. Это дает преимущество в гибкости построения маршрутов и не накладывает искусственных ограничений на разработчика. +В отличие от многих современных MVC-фреймворков, продукт Битрикс24 не использует концепцию единой точки входа. Это дает преимущество в гибкости построения маршрутов и не накладывает искусственных ограничений на разработчика. ## Как выполняется запрос? -1. Проверяется физическое существование файла. - - если существует файл, он будет исполнен -2. Проверяется является ли директория символьной ссылкой. - - если искомая директория является символьной ссылкой то физически будет подключен ссылаемый на нее файл. -3. Проверяется физическое существование папки. - - если папку существует, будет подключен index.php -4. Происходит подключение файла с ЧПУ `/bitrix/urlrewrite.php` +1. Проверяется физическое существование файла (если в запросе указан файл), директории (если в запросе нет конкретного файла или он `index.php`) или существование символьной ссылки. Если они существуют - будут подключены и исполнены. +2. Происходит подключение файла с обработкой правил `/bitrix/urlrewrite.php`. Если найдено правило - подключается файл согласно правилу, если нет - шаг пропускается. +3. Подключается файл `404.php` >Исторически битрикс отрабатывает все правила переадресации через 404 ошибку, учитывайте это при разработке вашего программного обеспечения. @@ -23,13 +19,13 @@ На момент написания статьи платформа использует аналог `роутов` (маршрутов) - правила адресации. Все существующие в системе правила описываются в переменной `$arUrlRewrite` внутри `urlrewrite.php`. Каждое правило состоит из нескольких полей, описывающих его: -`CONDITION` - регулярное выражение для проверки `$_SERVER["REQUEST_URI"]` на соответствии правилу. -`RULE` - правила замены переменных для строки переменных. -`ID` - имя компонента добавившего правило. -`PATH` - физический файл, который будет подключен. -`SORT` - приоритет правила для сортировки. +- `CONDITION` - регулярное выражение для проверки `$_SERVER["REQUEST_URI"]` +- `RULE` - правила замены переменных для строки переменных +- `ID` - имя компонента добавившего правило +- `PATH` - физический файл, который будет подключен +- `SORT` - приоритет правила для сортировки ->Правила располагаются в файле в порядке приоритетов сортировки, однако при одинаковой сортировке правила будут отсортированы по длинне поля `CONDITION`. +>Правила располагаются в файле в порядке приоритетов сортировки, однако при одинаковой сортировке правила будут отсортированы по длине поля `CONDITION`. Необходимым минимумом для описания маршрута являются ключи `CONDITION` и `PATH`. @@ -54,22 +50,20 @@ $arUrlRewrite = [ ]; ``` -Давайте остановимся разберем эти правила подробнее. -Предположим мы хотим открыть страницу: `/pub/form/some_test/somesec/dome_file.php?qparam=qvalue` в федолтной структуре битрикса. +Давайте остановимся и разберем как это работает на примере запроса к несуществующей странице `/fake/page.php`: +1. Будет произведена проверка физического существования файла (`/fake/page.php`) - файла не существует. +2. Будет произведена проверка на существование директории `/fake` (для обработки `.htaccess`) - директории не существует. +3. В порядке очередности будет применяться каждое регулярное выражение для проверки на соответствие. Правило не найдено. +4. Подключается `404.php` -Полный алгоритм будет выглядеть так: -1. Проверяется физическое существование файла. - Физического файла `/pub/form/some_test/some_sec/dome_file.php` не сущестивует. Шаг пропущен. -2. Проверяется является ли директория символьной ссылкой. - Символьной ссылки тоже нет. Шаг пропущен -3. Проверяется физическое существование папки. - Происходит подключение папки, а не физ.файла. Шаг пропущен. -4. Происходит подключение файла с ЧПУ `/bitrix/urlrewrite.php` -5. В файле `urlrewrite.php` определены правила. Обработаем первое правило. -6. Правило подходит, подключим страницу /pub/form.php +Рассмотрим еще один пример - клиент запрашивает ссылку: `/pub/form/abc/123/test.php?key=value`: +1. Будет произведена проверка физического существования файла `/pub/form/abc/123/test.php` - файла не существует. +2. Будет произведена проверка на существование директории `/pub/form/abc/123/` - директории не существует. +3. В порядке очередности будет применяться каждое регулярное выражение для проверки на соответствие. Найдено правило: `'#^/pub/form/([0-9a-z_]+?)/([0-9a-z]+?)/.*#'`. -Давайте посмотрим внимательно, что реально мы получим на странице и зачем нужно правило `RULE`: при открытии страницы мы указали `QUERY_STRING = ?test=123`, однако если мы выведем значение `$_SERVER['QUERY_STRING]` на экран, мы не увидим нашего параметра, а увидим указанное в `PATH` ключе заполненное правило `form_code=some_test&sec=somesec`. Однако это вовсе не означает что оно не доступно теперь, если попробовать обратиться к `$_GET` или `$_POST` мы можем получить значения и `qparam` и `form_code` и `sec`. +В результате на запрос `/pub/form/abc/123/test.php?key=value` будет эквивалентен запросу `/pub/form.php?form_code=abc&sec=123`, но что же случилось с параметром `key` ? Битрикс активно использует подмену глобальных переменных и в случае если мы обратимся к `$_SERVER['QUERY_STRING]`, то мы не увидим нашего значения, однако оно будет по-прежнему доступно через глобальные переменные `$_GET`, `$_POST` и `$_REQUEST`, точно так же как и добавленные правилом `form_code` и `sec`. +>Помните что поля добавленные правилом имеют приоритет на стандартными, поэтому в данном конкретном случае мы не имеет возможности передавать `form_code` и `sec`. ### Как работает RULE-параметр @@ -79,10 +73,22 @@ $arUrlRewrite = [ Таким образом битрикс обработает наш запрос как если бы он сразу поступил на адрес `/pub/form.php?form_code=some_test&sec=somesec`. -### Перерасчет правил +### Пересоздания правил обработки адресов -Не стоит слепо полагаться на этот файл и порядок внутри него. Механизмы платформы зачастую изменяют этот файл при любом редактировании в публичной части и правила могут быть рассчитаны. +1С-Битрикс предоставляет стандартный инструмент пересоздания правил обработки адресов, который располагается в административной панели. **Авторы этого труда настоятельно не рекомендуют применять его при работе с Битрикс24**. + +Как работает этот инструмент? +После запуска инструмента обработчик проходится по всеми физическим файлам в рабочей директории, собирает вызовы компонентов (`$APPLICATION->IncludeComponent`), собирает оттуда правила обработки адресов (`SEF`) и генерирует новый список правил. + +Причины по которым не рекомендуется применение этого инструмента в разрезе продукт Битрикс24: +1. Модули "Диск", "REST", "Мобильное приложение" и другие добавляют собственные правила, которые не ссылаются на файлы с вызовом компонентов. Эти правила будут утеряны без возможности восстановления. +2. При использовании `require`/`include` функций не происходит корректной индексации файлов. # Роутинг -Не смотря на то, что правила маршрутизации закрывают основную потребность в обработке ссылок они не являются удобными для разработки в целом. На момент написания статьи комманда core-разработчиков платформы готовит введение механизма замещающего правила обработки, однако на данный момент она не реализована. \ No newline at end of file +Несмотря на наличие механизма правил ЧПУ, которые прекрасно выполняют свою работу, в современных условиях недостаточно. Поскольку на момент написания статьи механизм не является распространенным и не поставляется в продукт по-умолчанию (его необходимо сконфигурировать), мы не будем рассматривать этот момент и оставим его на самостоятельное изучение. + +# Полезные ссылки + +1. [Пересоздание правил обработки адресов](https://dev.1c-bitrix.ru/user_help/settings/settings/urlrewrite/urlrewrite_reindex.php) +2. [Роутинг](https://dev.1c-bitrix.ru/learning/course/index.php?COURSE_ID=43&CHAPTER_ID=013764&LESSON_PATH=3913.3516.5062.13764) \ No newline at end of file diff --git "a/docs/02_\320\236\320\261\321\211\320\270\320\265_\321\201\320\262\320\265\320\264\320\265\320\275\320\270\321\217/01_\320\257\320\264\321\200\320\276_\320\277\321\200\320\276\320\264\321\203\320\272\321\202\320\260.md" "b/docs/02_\320\236\320\261\321\211\320\270\320\265_\321\201\320\262\320\265\320\264\320\265\320\275\320\270\321\217/01_\320\257\320\264\321\200\320\276_\320\277\321\200\320\276\320\264\321\203\320\272\321\202\320\260.md" index 47dfe36..7efb262 100644 --- "a/docs/02_\320\236\320\261\321\211\320\270\320\265_\321\201\320\262\320\265\320\264\320\265\320\275\320\270\321\217/01_\320\257\320\264\321\200\320\276_\320\277\321\200\320\276\320\264\321\203\320\272\321\202\320\260.md" +++ "b/docs/02_\320\236\320\261\321\211\320\270\320\265_\321\201\320\262\320\265\320\264\320\265\320\275\320\270\321\217/01_\320\257\320\264\321\200\320\276_\320\277\321\200\320\276\320\264\321\203\320\272\321\202\320\260.md" @@ -1,10 +1,13 @@ +# Ядро продукта + +[TOC] + Когда мы говорим о любом коммерческом модульном продукте можно выделить 2 его технические составляющие: * Ядро * Пользовательская часть -[TOC] -Если смотреть на вещи функционально то для понимания можно использовать следующую семантику: ядро это системная часть, которая обеспечивает работу пользовательской части. +Если смотреть на вещи функционально, то для понимания можно использовать следующую семантику: ядро это системная часть, которая обеспечивает работу пользовательской части. В случае Битрикс24 под ядром мы чаще всего будем понимать системные файлы и каталоги, **в которые разработчик не имеет права вносить свои изменения**. @@ -43,10 +46,10 @@ Bitrix Framework организован таким образом, что про - `after_connect.php` - подключается сразу же после создания соединения с базой; - `dbconn_error.php` - подключается при ошибке в момент создания соединения с базой; - `dbquery_error.php` - подключается при ошибке в момент выполнения SQL запроса; - - `/ID сайта/init.php` - дополнительные параметры сайта; файл подключается сразу же после определения специальной константы c идентификатором сайта - SITE_ID; + - `/ID сайта/init.php` - дополнительные параметры сайта; файл подключается сразу же после определения специальной константы с идентификатором сайта - SITE_ID; * `/tools/` - при инсталляции в этот каталог копируются дополнительные страницы, которые могут быть непосредственно использованы на любых страницах сайта: помощь, календарь, показ изображения и т.п.; * `/updates/` - каталог, автоматически создаваемый системой обновлений; -* `.settings.php` - файл с настройками ядра продукта, в т.ч. доступ к базе, крипто ключ, настройки пуш соединение и сессий +* `.settings.php` - файл с настройками ядра продукта, в т.ч. доступ к базе, секретный ключ, настройки пуш соединение и сессий * `header.php` - стандартный файл, подключающий в свою очередь конкретный пролог текущего шаблона сайта; данный файл должен использоваться на всех страницах публичной части; * `footer.php` - стандартный файл, подключающий в свою очередь конкретный эпилог текущего шаблона сайта; данный файл должен использоваться на всех страницах публичной части; * `license_key.php` - файл с лицензионным ключом; @@ -60,9 +63,9 @@ Bitrix Framework организован таким образом, что про ## Особые файлы -В каталоге `/bitrix/` можно встретить и другие файлы и директории, которые будем рассматривать отдельно в следующих разделах, однако есть некоторые каталоги о которых следует знать: +В каталоге `/bitrix/` можно встретить и другие файлы и директории (мы будем рассматривать отдельно в следующих разделах), однако есть некоторые каталоги о которых следует знать: * `/stack_cache/` - еще одна папка для хранения кеша. В настоящий момент в данной папке находится кеш курсов валют, однако эта папка отмечена устаревшей и более не будет использоваться в продукте. * Директории: `activities`, `components`, `gadgets`, `js`, `templates` имеют особую структуру и зависят как от модулей битрикса, так и от сторонних разработчиков. Структуру этих папок мы будем рассматривать позже. Сейчас достаточно знать зачем они нужны. * Опциональный файл `.settings_extra.php` который дополняет конфигурацию основного файла, заменяя разрешенные ключи ->Иногда при разработке проекта удобнее считать что все что поставляется продуктом Битрикс24 является ядром и пользовательской частью, которую можно менять является содержимое каталога local, технический файл `/bitrix/.settings_extra.php` и файлы/директории которые разработчик добавил сам. Подобный подход наилучшим образом гарантирует договечность проекта \ No newline at end of file +>Иногда при разработке проекта удобнее считать что все, что находится в директории bitrix является ядром, а изменять можно только содержимое каталога local, технический файл `/bitrix/.settings_extra.php` и файлы/директории которые разработчик добавил сам. Подобный подход наилучшим образом гарантирует долговечность проекта \ No newline at end of file diff --git "a/docs/02_\320\236\320\261\321\211\320\270\320\265_\321\201\320\262\320\265\320\264\320\265\320\275\320\270\321\217/02_\320\241\321\202\321\200\320\260\320\275\320\270\321\206\320\260.md" "b/docs/02_\320\236\320\261\321\211\320\270\320\265_\321\201\320\262\320\265\320\264\320\265\320\275\320\270\321\217/02_\320\241\321\202\321\200\320\260\320\275\320\270\321\206\320\260.md" index d16424d..b95308a 100644 --- "a/docs/02_\320\236\320\261\321\211\320\270\320\265_\321\201\320\262\320\265\320\264\320\265\320\275\320\270\321\217/02_\320\241\321\202\321\200\320\260\320\275\320\270\321\206\320\260.md" +++ "b/docs/02_\320\236\320\261\321\211\320\270\320\265_\321\201\320\262\320\265\320\264\320\265\320\275\320\270\321\217/02_\320\241\321\202\321\200\320\260\320\275\320\270\321\206\320\260.md" @@ -2,157 +2,105 @@ [TOC] -Теперь когда мы знаем как именно [обрабатывается URI](Обработка_uri) и [где не нужно располагать свои публичные страницы](Ядро_продукта), мы можем поговорить о самой странице. +Теперь когда мы знаем как именно [обрабатывается URI](00_Обработка_uri) и [где не нужно располагать свои публичные страницы](01_Ядро_продукта), мы можем поговорить о самой странице. +## Состав страницы Под термином `Страница` в контексте данной статьи мы будем понимать физический исполняемый файл, а не контент отображаемый в браузере пользователя. И любая страница состоит из 3 составляющих: * Шапка (`header`) * Рабочая область (`workarea`) * Подвал (`footer`) -## Шапка (`header`) +### Пример кода страницы -Подключается **к каждой** странице фрагментом php-кода: +Пример минималистичного кода страницы: ```php - -## Подвал (`footer`) + -Подключается **к каждой** странице фрагментом php-кода: - -```php - ``` -Подвал включает в себя, как правило, статическую информацию (контактная информация, сведения об авторе и владельце сайта и так далее), нижнее горизонтальное меню и правое меню (если они есть в дизайне). Может включать в себя информационные материалы. - -# Визуализация +### Шапка (`header`) -Представить разделение для продукта `1С-Битрикс: Управление сайтом` можно при помощи изображения из официальной документации -![Разметка БУС](images/page_structure1.png) - -На данном скриншоте цифрой 1 (или красной областью) обозначена шапка, цифрой 2 - рабочая область, а цифрой 3 - подвал. - -Данная схема совершенно логично смотрится в `1С-Битрикс: Управление сайтом`, однако при рассмотрении `1С-Битрикс24` все становится немного сложнее. Например для главной страницы продукта будет актуальна следующая разметка: -![Размеченный Битрикс24](images/page_structure2_marked.png) - -Расшифровка цветовой индикации: -* Красный - шапка -* Желтый - подвал -* Зеленый - рабочая область -* Синий - дополнительные элементы - -**Откуда в этой схеме взялся дополнительный цвет?** - -Битрикс24 активно использует механизм [отложенных функций](../Разработка/Технологии/Отложенные функции), поэтому преставление на странице иногда бывает не очень наглядным. Для описания данного поведения мы не можем отнести его в ту или иную область, потому как их вызов осуществляется в одной части страницы, а фактическое отображение блока может быть в другом месте. - -На рассматриваемой главной странице к таким частям можно отнеси: -* Панель виджетов справа -* Панель Веб-мессенджера - -## Пример страницы - -На основании изложенной выше информации, типовая 'чистая' страница без заголовка будет выглядеть следующим образом: +Каждая физическая страница публичной части начинается с подключения технического файла: ```php - - -Тело страницы - - ``` -## Заглядываем за кулисы - -Термины `Шапка` и `Подвал` понятны и доступны всем техническим специалистам, однако на платформе за этими терминами кроются куда более интересные механизмы: `пролог` и `эпилог`. -На самом деле `шапка` это комбинация служебной части пролога и визуальной части пролога, а `подвал` это комбинация визуальной части эпилога и служебной части эпилога. Порядок скриптов очень важен! - -Таким образом, в некотором роде, страницу можно представить как комбинацию этих скриптов: - -```php - +### Рабочая область -Тело страницы +Или `Тело страницы` - это часть PHP/HTML кода он не является частью шаблона сайта и отображает индивидуальное содержимое публичной либо административной страницы. - ``` -Конечно, мы можем задаться вопросом *Зачем так сделано?*, однако наиболее правильной формулировкой станет *Что дает нам это разделение?*. - -Подобное разделение дает гибкость в формировании страницы. -Например: можно выполнить код до вызова публичной части, но после подключения ядра системы или можно вообще использовать облегченную версию без дизайна вообще. Это очень актуально для консольных и других специальных скриптов. - -# Порядок выполнения страницы - -Знать из чего состоит страница зачастую недостаточно чтобы решать определенный класс задач. Для понимания некоторых концепций и механизмов требуется понимать как именно исполняется страница. - -| Шаг | Описание | -| :------------- | -------------------- | -| - | Служебная часть пролога (`/bitrix/modules/main/include/prolog_before.php`) | -| 1 | Подключение `/bitrix/php_interface/dbconn.php`. Подключаемый файл должен содержать определения переменных для соединения с базой данных, констант для отладки и прав доступа. | -| 2 | Соединение с базой данных. В случае ошибки соединения будет подключен файл `/bitrix/php_interface/dbconn_error.php`. | -| 3 | Подключение `/bitrix/php_interface/after_connect.php` и `/bitrix/php_interface/after_connect_d7.php`. Подключаемые файлы могут содержать операции, необходимые для выполнения сразу после соединения с БД. | -| 4 | Определение текущего сайта `$APPLICATION`, `SITE_ID`, `SITE_DIR`, `SITE_SERVER_NAME`, `SITE_CHARSET`, `FORMAT_DATE`, `FORMAT_DATETIME`, `LANGUAGE_ID`. Определяются все классы и функции Главного модуля. Если к этому моменту определена константа с кодом сайта `SITE_ID`, то сайт не будет определяться по текущей папке и доменному имени, а все остальные константы будут определены для этого сайта. | -| 5 | Подключение `/local/php_interface/init.php` или `/bitrix/php_interface/init.php`. Может содержать в себе инициализацию обработчиков событий, подключение дополнительных функций - общие для всех сайтов. | -| 6 | Подключение `/bitrix/php_interface/ID сайта/init.php`. Может содержать параметры, определения функций для конкретного сайта. | -| 7 | Открытие сессии | -| 8 | Событие `OnPageStart` | -| 9 | Определение пользователя, авторизация пользователя, завершение сеанса, регистрация (в зависимости от параметров в запросе) | -| 10 | Определение текущего шаблона сайта `SITE_TEMPLATE_ID` | -| 11 | Событие `OnBeforeProlog` | -| 12 | Проверка прав доступа к физическому файлу. В случае если прав недостаточно, то выводится форма авторизации и страница завершает выполнение. | -| 13 | Начало буфферизации вывода | -| 14 | Событие OnProlog | -| -- | Визуальная часть пролога (`/bitrix/modules/main/include/prolog_after.php`) | -| 15 | Подключение `/bitrix/templates/ID шаблона сайта/header.php` | -| -- | Тело страницы | -| -- | Визуальная часть эпилога (`/bitrix/modules/main/include/epilog_before.php`) | -| 16 | Подключение `/bitrix/templates/ID шаблона сайта/footer.php` | -| 17 | Вызов функции `CMain::ShowSpreadCookieHTML`. Данная функция выводит набор невидимых IFRAME'ов используемых в Технология переноса посетителей | -| -- |Служебная часть эпилога (`/bitrix/modules/main/include/epilog_after.php`) | -| 18 | Событие `OnEpilog` | -| 20 | Завершение буферизации страницы и вывод в поток содержимое буффера | -| 21 | Событие `OnAfterEpilog` | -| 22 | Проверка агентов | -| 23 | Отправка E-Mail писем | -| 24 | Завершение соединения с базой данных | +Образно, внутри него выполняются все остальные подключения: +- Подключение визуальной части эпилога (`epilog_before.php`) +- Подключение служебной части эпилога (`epilog_after.php`) + +## Порядок выполнения + +Теперь когда мы знаем из чего состоит страница самое время посмотреть вглубь и понять как именно она исполняется - какие файлы подключаются и какие переменные доступы в момент тот или иной момент. + +| Шаг | Описание | +|:----|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| - | Служебная часть пролога (`/bitrix/modules/main/include/prolog_before.php`) | +| 1 | Подключение `/bitrix/php_interface/dbconn.php`. Файл содержит константы необходимые для корректной работы Битрикс24. Ранее в нем так же определялись глобальные переменные для соединения с базой данных. | +| 2 | Соединение с базой данных. В случае ошибки соединения будет подключен файл `/bitrix/php_interface/dbconn_error.php`. | +| 3 | Подключение `/bitrix/php_interface/after_connect.php` (при наличии) и `/bitrix/php_interface/after_connect_d7.php` (при наличии). Подключаемые файлы могут содержать операции, необходимые для выполнения сразу после соединения с БД. | +| 4 | Определение текущего сайта, переменных и констант: `$APPLICATION`, `SITE_ID`, `SITE_DIR`, `SITE_SERVER_NAME`, `SITE_CHARSET`, `FORMAT_DATE`, `FORMAT_DATETIME`, `LANGUAGE_ID`. Определяются все классы и функции Главного модуля. Если к этому моменту определена константа с кодом сайта `SITE_ID`, то сайт не будет определяться по текущей папке и доменному имени, а все остальные константы будут определены для этого сайта. | +| 5 | Подключение `/local/php_interface/init.php` или `/bitrix/php_interface/init.php`. Может содержать в себе инициализацию обработчиков событий, подключение дополнительных функций - общие для всех сайтов. | +| 6 | Подключение `/bitrix/php_interface//init.php`. Может содержать параметры, функции и классы для конкретного сайта. | +| 7 | Открытие сессии | +| 8 | Событие `OnPageStart` | +| 9 | Определение пользователя, авторизация пользователя, завершение сеанса, регистрация (в зависимости от параметров в запросе). Можно использовать `$USER`. | +| 10 | Определение текущего шаблона сайта `SITE_TEMPLATE_ID` | +| 11 | Событие `OnBeforeProlog` | +| 12 | Проверка прав доступа к физическому файлу. В случае если прав недостаточно, то выводится форма авторизации и страница завершает выполнение. | +| 13 | Начало буферизации вывода | +| 14 | Событие `OnProlog` | +| 15 | Визуальная часть пролога (`/bitrix/modules/main/include/prolog_after.php`) | +| 16 | Подключение `/bitrix/templates/ID шаблона сайта/header.php` | +| 17 | Тело страницы | +| 18 | Визуальная часть эпилога (`/bitrix/modules/main/include/epilog_before.php`) | +| 19 | Подключение `/bitrix/templates/ID шаблона сайта/footer.php` | +| 20 | Вызов функции `CMain::ShowSpreadCookieHTML`. Данная функция выводит набор невидимых IFRAME'ов используемых в Технология переноса посетителей | +| 21 | Служебная часть эпилога (`/bitrix/modules/main/include/epilog_after.php`) | +| 22 | Событие `OnEpilog` | +| 23 | Завершение буферизации страницы и вывод в поток содержимое буфера | +| 24 | Событие `OnAfterEpilog` | +| 25 | Выполнение фоновых работ. В том числе: проверка агентов и отправка E-Mail писем | +| 27 | Завершение соединения с базой данных | # Выполнение в фоновом режиме -Использование платформы не ограничивается обработкой HTTP запросов. Достаточно распространенным действием является выполнение операций в фоновом режиме, которые могут занять продолжительное время, поэтому выполнять их посредством HTTP запроса не рекомендуется. Обычно для таких операций используют фоновые задания или консольные скрипты которые в последствии устанавливаются в расписание планировщика задач `cron`. +Использование платформы не ограничивается простой обработкой HTTP запросов ведь достаточно распространенным действием является выполнение операций в фоновом режиме. Такие операции могут занять продолжительное время, поэтому выполнять их посредством HTTP запроса не рекомендуется. Для таких операций используют фоновые задания (`background job`) или консольные скрипты, которые в последствии устанавливаются в расписание планировщика задач `cron`. -В чем особенность работы скрипта в консоли? -Мы не будем рассматривать работу php скрипта в консоли, а лишь обратим внимание на ограничения связанные с платформой Битрикс, накладываемые на него: -* Нет авторизованного посетителя -* Нет сессий и cookie -* Нет серверных переменных +**В чем особенность работы скрипта в консоли?** -Что это все значит? -Это значит, что код который выполняется в браузере и код который будет выполнен в консоли не обязательно будет иметь один и тот же результат. Помните, что во всех методах явно или не явно контролируются права **текущего** пользователя, которого при консольном выполнении нет. +Неопытные разработчики часто отождествляют работу скрипта в консоли с работой страницы в браузере однако это не так - результат который моделируется в браузере или "php-консоли" разработчика может не совпадать. -Пример страницы выполняющийся в фоновом режиме (например на cron): +Так происходит потому что: +* В консольном скрипте нет авторизованного посетителя. Все действия выполняются от гостей +* Нет сессий и cookie, поэтому нельзя сохранить состояние между выполнениями. +* Нет серверных переменных - поэтому не следует опираться на `$_SERVER` переменные, например брать оттуда `SERVER_NAME`. + +Пример страницы выполняющийся в фоновом режиме (например на `cron`): ```php ``` -Рассмотрим данную страницу с точки зрения платформы. -Битрикс активно использует `$_SERVER` переменные, которых в консольном приложении нет. Наиболее распространенной переменной, которая тянется сквозь всю систему явялестя `$_SERVER['DOCUMENT_ROOT']`. Ее следует задавать абсолютным путем от корня веб-сервера к директории в которой находится папка `bitrix`. `$DOCUMENT_ROOT` это устаревшая глобальная переменна к `$_SERVER["DOCUMENT_ROOT"]`, ее следует устанавливать в случае если на платформе возможно использование устаревших модулей или компонентов. +Рассмотрим код данного файла страницу с точки зрения платформы. + +Битрикс активно использует значения глобальной переменной `$_SERVER`. Эта переменная заполняется веб-сервером - промежуточным звеном между клиентом и интерпретатором php-кода. Когда мы запускаем консольный скрипт выполняя команду `php -f script.php` она не заполняется и остается пустой. Наиболее распространенной переменной, которая тянется сквозь всю систему является `$_SERVER['DOCUMENT_ROOT']`. Ее следует задавать абсолютным путем от корня веб-сервера к директории в которой находится папка `bitrix`. +> `$DOCUMENT_ROOT` это устаревшая ссылка на глобальную переменную `$_SERVER["DOCUMENT_ROOT"]`, ее следует устанавливать на всякий случай, так как на платформе возможно использование устаревших модулей или компонентов. -Скрипт является консольным, поэтому до подключения служебной части пролога, рекомендуется произвести преднастройку среды: +Поскольку консольный скрипт является служебным, то до подключения служебной части пролога, рекомендуется произвести настройку среды: -* Выключить сбор и обработку статистики (для модуля 'Веб-аналитика': `NO_KEEP_STATISTIC`, `STOP_STATISTICS`, `NO_AGENT_STATISTIC`) -* Выключить проверку прав (`NOT_CHECK_PERMISSIONS`) -* Запретить сброс кеша акселератора (`BX_NO_ACCELERATOR_RESET`) +* Выключить сбор и обработку статистики для модуля 'Веб-аналитика' (константы: `NO_KEEP_STATISTIC`, `STOP_STATISTICS`, `NO_AGENT_STATISTIC`) +* Выключить проверку прав (константа `NOT_CHECK_PERMISSIONS`) +* Запретить сброс кеша акселератора (константа `BX_NO_ACCELERATOR_RESET`) * Не проверять агенты (`DisableEventsCheck`, `NO_AGENT_CHECK`) -Каждый скрипт использующий возможности платформы должен содержать как минимум подключение ее служебной части. +Следом происходит подключение технической части пролога, после чего для консольных скриптов рекомендуется дополнительно убрать лимит времени выполнения (`set_time_limit`) и отключить прерывание выполнения скрипта при отключении клиента (`ignore_user_abort`) поскольку эти параметры могут быть переопределены в `dbconn.php`. + +Подготовка закончена и теперь можно писать код, который будет делать что-то полезное. + +Завершающей частью скрипта является подключение технической части эпилога или специальной функций `\CMain::FinalActions();` - там выполняются технические скрипты для закрытия соединения с БД, обработка фоновых заданий (`background jobs`), отправка push уведомлений. -Затем для консольного выполнения необходио убрать лимит времени выполнения (`set_time_limit`) и отключить прерывание выполнения скрипта при отключений клиента (`ignore_user_abort`). +> Подключение технической части эпилога или завершающей функцией является необходимым для корректной работы консольного скрипта. -Подготовка закончена и теперь можно писать код, который будет делать что-то полезное. -В ранних версиях битрикса этого было достаточно, однако с версии `20.0` необходимо обязательно подключать подвал или по крайней мере его служебную часть. Однако вместо подключения этих тяжелых вещей мы можем воспользоваться легковестным статическим методом `\CMain::FinalActions();`. \ No newline at end of file diff --git "a/docs/02_\320\236\320\261\321\211\320\270\320\265_\321\201\320\262\320\265\320\264\320\265\320\275\320\270\321\217/03_\320\250\320\260\320\261\320\273\320\276\320\275.md" "b/docs/02_\320\236\320\261\321\211\320\270\320\265_\321\201\320\262\320\265\320\264\320\265\320\275\320\270\321\217/03_\320\250\320\260\320\261\320\273\320\276\320\275.md" new file mode 100644 index 0000000..c072361 --- /dev/null +++ "b/docs/02_\320\236\320\261\321\211\320\270\320\265_\321\201\320\262\320\265\320\264\320\265\320\275\320\270\321\217/03_\320\250\320\260\320\261\320\273\320\276\320\275.md" @@ -0,0 +1,36 @@ +# Шаблон дизайна Битрикс24 + +[TOC] + +В _1С-Битрикс:Управление сайтом_ шаблон является частью решения поставляемого разработчиком и может быть исправлен или доработан по решению разработчика в любой момент. + +>Шаблон дизайна - это внешний вид сайта, в котором определяется расположение различных элементов на сайте, художественный стиль и способ отображения страниц. Включает в себя программный html-код, графические элементы, таблицы стилей, дополнительные файлы для отображения контента. Может также включать в себя шаблоны компонентов, шаблоны готовых страниц и сниппеты. + +Битрикс24 поставляется вместе с единым системным шаблоном и он является частью решения и не подлежит изменению или копированию. + +> Строго говоря, изменять системный шаблон это один из последних подходов которые только можно использовать. Крайне не рекомендуется копировать его в директорию [`local`](/03_Разработка/20_Структура_папки_local/00_Основное) + +## Визуализация + +Из статьи о [страницах](/02_Общие_сведения/02_Страница.md) нам уже известно о наличии технических частей - шапки и подвала и вот как представляют разделение в документации по фреймворку: + +![Разметка БУС](images/page_structure1.png) + +На данном скриншоте цифрой 1 (или красной областью) обозначена шапка, цифрой 2 - рабочая область, а цифрой 3 - подвал. + +Данная схема совершенно логично смотрится в _1С-Битрикс: Управление сайтом_, однако при рассмотрении Битрикс24 все становится немного сложнее: например для главной страницы продукта будет актуальна следующая разметка: +![Размеченный Битрикс24](images/page_structure2_marked.png) + +Расшифровка цветовой индикации: +* Красный - шапка +* Желтый - подвал +* Зеленый - рабочая область +* Синий - дополнительные элементы + +**Откуда в этой схеме взялся дополнительный цвет?** + +Битрикс24 активно использует механизм [отложенных функций](../03_Разработка/100_Технологии/10_Отложенные_функции.md), поэтому преставление на странице иногда бывает не очень наглядным. Для описания данного поведения мы не можем отнести его в ту или иную область, потому что их вызов может быть в одной части страницы, а фактическое отображение блока может быть в другом месте. + +На рассматриваемой главной странице к таким частям можно отнеси: +* Панель виджетов (Онлайн, Пуль, Задачи, Мобильное приложение и др.) +* Панель Веб-мессенджера (Уведомления, Открытые линии, Поиск, Чаты, Звонки) \ No newline at end of file diff --git "a/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/00_\320\222\320\262\320\265\320\264\320\265\320\275\320\270\320\265.md" "b/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/00_\320\222\320\262\320\265\320\264\320\265\320\275\320\270\320\265.md" index 2c631e5..8ae7170 100644 --- "a/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/00_\320\222\320\262\320\265\320\264\320\265\320\275\320\270\320\265.md" +++ "b/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/00_\320\222\320\262\320\265\320\264\320\265\320\275\320\270\320\265.md" @@ -1,6 +1,8 @@ -[TOC] +# Введение в разработку -Работа с продуктом значительно осожняется возможностями которые он предоставляет и отсутствием накладываемых ограничений. Любой разработчик с абсолютно любой квалификацией может вносить изменения в абсолютно любые части продукта (не всегда без плачевных последствий). +[TOC] + +Работа с продуктом значительно осложняется возможностями которые он предоставляет и отсутствием накладываемых ограничений. Любой разработчик с абсолютно любой квалификацией может вносить изменения в абсолютно любые части продукта (не всегда без плачевных последствий). Чтобы не было мучительно больно при обслуживании коробки Битрикс24 следует осознать несколько простых правил, о которых мы поговорим далее. @@ -10,11 +12,11 @@ ## Вы должны знать что вы делаете -Перед тем как бросаться писать код необходимо подумать. Думать вообще полезно, но при работе с продуктом официальная документация по которому отстутствует и нет гарантии обратной совместимости на уровне кода думать нужно не только по тем сценариям что уже появились, но и то что еще может появиться. +Перед тем как бросаться писать код необходимо подумать. Думать вообще полезно, но при работе с продуктом официальная документация по которому отсутствует и нет гарантии обратной совместимости на уровне кода думать нужно не только по тем сценариям что уже появились, но и то что еще может появиться. Начните с формализации требований: опишите запрос клиента в терминологии Битрикс24. Возможно это уже существует в продукте и можно использовать готовые инструменты. -Потом найдите все используемые места использования данного механизма. Например для изменения лида это может быть: +Потом найдите все используемые места использования данного механизма. Например, для изменения лида это может быть: * Изменение в карточке лида * Изменение из списка лидов * Изменение из канбана @@ -24,7 +26,7 @@ Подумайте как ваша новая механика будет затрагивать существующие стандартные механики, как она будет влиять на внешние приложения (которые потом клиент поставит сам), как она будет работать в связке с уже написанными механиками. -Хорошо подумайте и ответьте на вопрос "Как еще можно добиться желаемого результата?". Здесь как и везде действует правило Паретто: 20% работы приносит 80% пользы. Старайтесь делать меньше и получать больше. +Хорошо подумайте и ответьте на вопрос "Как еще можно добиться желаемого результата?". Здесь, как и везде действует правило Паретто: 20% работы приносит 80% пользы. Старайтесь делать меньше и получать больше. Если вы не знаете как это работает, старайтесь не изменять стандартное поведение системы. Лучше потратить чуть больше времени на разработку своего, чем изменять имеющиеся. diff --git "a/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/100_\320\242\320\265\321\205\320\275\320\276\320\273\320\276\320\263\320\270\320\270/10_\320\236\321\202\320\273\320\276\320\266\320\265\320\275\320\275\321\213\320\265_\321\204\321\203\320\275\320\272\321\206\320\270\320\270.md" "b/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/100_\320\242\320\265\321\205\320\275\320\276\320\273\320\276\320\263\320\270\320\270/10_\320\236\321\202\320\273\320\276\320\266\320\265\320\275\320\275\321\213\320\265_\321\204\321\203\320\275\320\272\321\206\320\270\320\270.md" index 4255fb3..8004c39 100644 --- "a/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/100_\320\242\320\265\321\205\320\275\320\276\320\273\320\276\320\263\320\270\320\270/10_\320\236\321\202\320\273\320\276\320\266\320\265\320\275\320\275\321\213\320\265_\321\204\321\203\320\275\320\272\321\206\320\270\320\270.md" +++ "b/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/100_\320\242\320\265\321\205\320\275\320\276\320\273\320\276\320\263\320\270\320\270/10_\320\236\321\202\320\273\320\276\320\266\320\265\320\275\320\275\321\213\320\265_\321\204\321\203\320\275\320\272\321\206\320\270\320\270.md" @@ -32,7 +32,7 @@ Для рассмотрения таких особенностей, чтобы не вводить читателей в заблуждение мы искусственно введем свою терминологию и классифицируем их по месту применения как: -* Общиие (BufferContent) +* Общие (BufferContent) * Компонентные (ViewTarget) # Особенности работы @@ -80,7 +80,7 @@ CMain::AddBufferContent( ) ``` -Давайте релаизуем свою отложенную функцию по вывода meta-информации. В нашем примере мы используем класс с статической переменной для хранения последнего значения: +Давайте разработаем свою отложенную функцию по выводу meta-информации. В нашем примере мы используем класс со статической переменной для хранения последнего значения: ```php class LastValueDeferredBufferContent @@ -99,7 +99,7 @@ class LastValueDeferredBufferContent } ``` -Мы определили класс с статической переменной которая хранит последнее заданное значение. Зарегистрированная отложенная функция будет выглядеть следующим образом: +Мы определили класс со статической переменной которая хранит последнее заданное значение. Зарегистрированная отложенная функция будет выглядеть следующим образом: ```php function getLastValueFromDeferredBufferContent() @@ -128,15 +128,15 @@ for( $i = 0; $i<10, $i++) ``` -Как видите, не смотря на то, что приложение было предзаполнено заполнено `0`, пользователю в браузер вывелось `9`. +Как видите, несмотря на то, что приложение было предзаполнено `0`, пользователю в браузер вывелось `9`. # Разработка своей компонентной отложенной функции Компонентные отложенные функции работают иначе - они используют специальный глобальный буфер для запоминания содержимого и локальный буфер компонента, чтобы иметь возможность использовать результат отложенного содержимого даже в кеширующемся компоненте. -Важно отметить, что не смотря на наличие такой возможности, данные сохраняемые в буферах не являются динамическими. Что это значит? Это значит что локальный буфер компонента использует кеш компонента и контент который попадет в локальный буфер при первом выводе компонента с включенным кешированием будет отображаться в области до момента создания нового кеша. +Важно отметить, что несмотря на наличие такой возможности, данные, сохраняемые в буфере, не являются динамическими. Что это значит? Это значит что локальный буфер компонента использует кеш компонента и контент который попадет в локальный буфер при первом выводе компонента с включенным кешированием будет отображаться в области до момента создания нового кеша. -Давайте предположим, что у нас на странице есть некоторый компонент `bx24devbook:article.detail` и мы хотим вывести часть содержимого под загловок страницы в область `below_pagetitle` (существующие области мы рассмотрим позднее). +Давайте предположим, что у нас на странице есть некоторый компонент `bx24devbook:article.detail` и мы хотим вывести часть содержимого под заголовок страницы в область `below_pagetitle` (существующие области мы рассмотрим позднее). Для того чтобы это сделать, в используемом шаблоне компонента (`template.php` или любой другой подключаемый php-файл) мы должны вызвать следующие функции: @@ -147,14 +147,14 @@ $this->SetViewTarget('below_pagetitle'); $this->EndViewTarget(); ``` -Этого достаточно чтобы вывести содержимое в нужной нам области. +Этого достаточно для отображения содержимого в нужной нам области. **Можно ли использовать данный механизм вне компонента?** На этот вопрос можно ответить как положительно, так и отрицательно. Да, можно вывести произвольное содержимое в эти области из любого исполняемого кода в рамках страницы. Для этого необходимо воспользоваться нестатическим методом `CMain::AddViewContent`. -Например для приведенного выше фрагмента, аналогом может выступить: +Например, для приведенного выше фрагмента, аналогом может выступить: ```php global $APPLICATION; $APPLICATION->AddViewContent( @@ -189,7 +189,7 @@ $APPLICATION->ShowViewContent("some_location_name"); * `above_pagetitle` - перед строкой с заголовком * `below_pagetitle` - после строки заголовка, но до контентной области -Стоит отметить так же пару областей с особым применением, ввиду использования механизмка ui.toolbar: +Стоит отметить так же пару областей с особым применением, ввиду использования механизма ui.toolbar: * `pagetitle` - область справа от заголовка до кнопок. * `inside_pagetitle` - область кнопок справа от заголовка страницы. diff --git "a/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/100_\320\242\320\265\321\205\320\275\320\276\320\273\320\276\320\263\320\270\320\270/20_\320\220\320\263\320\265\320\275\321\202\321\213.md" "b/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/100_\320\242\320\265\321\205\320\275\320\276\320\273\320\276\320\263\320\270\320\270/20_\320\220\320\263\320\265\320\275\321\202\321\213.md" index 0698731..f8c550c 100644 --- "a/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/100_\320\242\320\265\321\205\320\275\320\276\320\273\320\276\320\263\320\270\320\270/20_\320\220\320\263\320\265\320\275\321\202\321\213.md" +++ "b/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/100_\320\242\320\265\321\205\320\275\320\276\320\273\320\276\320\263\320\270\320\270/20_\320\220\320\263\320\265\320\275\321\202\321\213.md" @@ -80,39 +80,29 @@ keywords: "agent, cagent, bitrix24, bitrix, 1c-bitrix, агенты, агент, ## Ограничения -Разработчик должен учитывать, что код который будет завернут в агент имееет достаточно много ограничений: - -1. Объекта пользователя (`$USER`) в агентах нет. - -Поэтому любой код, который запрашивает должен проверяться на наличие опций отключающих проверку прав. -Важно: В агентах нельзя проводить авторизацию методом `Authorize`, поскольку она может отправить cookie файлы авторизации случайному посетителю. - ->Примечание: даже наличие глобальной переменной `$USER` не является гарантией того, что в этой переменной находится объект класса `CUser` - -2. Отсутствует константа `SITE_ID` -Агент может выполнять не только на страницах конкретного сайта, но и на хитах в административной панели и даже в cli-режиме (например на cron) +Разработчик должен учитывать, что код, который будет завернут в агент имеет достаточно много ограничений: +1. Объекта пользователя (`$USER`) в агентах нет. Поэтому любой код, который запрашивает должен проверяться на наличие опций отключающих проверку прав. +2. Отсутствует константа `SITE_ID`. Агент может выполнять не только на страницах конкретного сайта, но и на хитах в административной панели и даже в cli-режиме (например на cron). 3. На многоязычных сайтах нельзя заранее узнать какой будет язык. - -4. Агенты выполняются в однопоточном режиме с блокировкой на MySQL на 10 минут. -Новый вызов агента возможен только после того, как отработает предыдущий вызов. -Блокировка БД может потеряться если закроется соединение с ней. 10 минут ожидания это - дополнительная защита от повторного запуска, агентов которые не корректно отработали. - +4. Агенты выполняются в однопоточном режиме с блокировкой на MySQL на 10 минут. Новый вызов агента возможен только после того, как отработает предыдущий вызов. Блокировка БД может потеряться если закроется соединение с ней. 10 минут ожидания это - дополнительная защита от повторного запуска, агентов которые не корректно отработали. 5. В случае выполнения агентов на хитах временная точность запуска агентов напрямую зависит от равномерности и плотности посещаемости сайта. Реальное время запуска агента обычно чуть-чуть позже, чем время, на которое назначен агент (при равномерной посещаемости). Момент запуска - это когда кто-то зашел на страницу сайта. Если вам необходимо организовать запуск каких-либо PHP функций в абсолютно точно заданное время, то необходимо воспользоваться стандартной утилитой cron, предоставляемой большинством хостингов. - 6. Кроме этого, не рекомендуется вешать на агенты ресурсоёмкие операции, для них существует фоновый запуск по cron'у. +> Важно: В агентах нельзя проводить авторизацию методом `Authorize`, поскольку она может отправить cookie файлы авторизации случайному посетителю. + +>Примечание: даже наличие глобальной переменной `$USER` не является гарантией того, что в этой переменной находится объект класса `CUser` ## Выбор между агентами и cron У опытных разработчиков обычно не возникает сомнений в выборе способа реализации той или иной бизнес-функции, однако есть общие рекомендации по выбору: -1. Ресурсоемкие оперции (выполняющиеся 5+ секунд или требующие значительного объема оперативной памяти) следует выполнять отдельными `cron`-скриптами +1. Ресурсоемкие операции (выполняющиеся 5+ секунд или требующие значительного объема оперативной памяти) следует выполнять отдельными `cron`-скриптами. 2. Если это будет использоваться в тиражируемом модуле, то выбор стоит отдать в пользу агентов. 3. Во всех остальных случаях предпочтение стоит отдать агентам. ->Да, последний пункт является "вкусовщиной" и нет единого мнения как стоит реализовывать тот или иной код. Лично я предпочитаю использовать cron-скрипты, вместо агентов и использую последних только в тиражируемых модулях или когда это выгоднее с точки зрения времени на написание. +>Да, последний пункт является "вкусовщиной" и нет единого мнения как стоит реализовывать тот или иной код. Я предпочитаю использовать cron-скрипты, вместо агентов и использую последних только в тиражируемых модулях или когда это выгоднее с точки зрения времени на написание. ## API @@ -228,26 +218,32 @@ CAgent::Add($arFields); Иногда возникает необходимость отладить какие-то сложные механизмы или алгоритмы и для этого существует debug-функция агентов. -1. Определяем в проекте произвольную функцию с следующей сигнатурой: +Шаг 1. +Определяем в проекте произвольную функцию со следующей сигнатурой: ```php function agentDebug($arAgent, $strEvent, $strEvalResult = null, $error = ""): void ``` -Пояснение к аргументами: +Пояснение к аргументам: - `$arAgent` - данные агента из таблицы `b_agent` - `$strEvent` - код события, поясняющего момент вызова (`start` - инициализация, `finish` - успешное завершение, `not_callable` - неопределенное поведение) - `$strEvalResult` - результат выполнения агента - `$error` - `Throwable`-наследник. -2. Определяем константу `BX_AGENTS_LOG_FUNCTION` с названием лог-функции +Шаг 2. +Определяем константу `BX_AGENTS_LOG_FUNCTION` с названием нашей лог-функции: + ```php define('BX_AGENTS_LOG_FUNCTION', 'agentDebug'); ``` -3. Любуемся результатом. + +Шаг 3. + +Ждем пока исполнятся агенты и любуемся результатом. >Важное примечание: в последних релизах (21 и 22) механизм отладки агентов - сломан. Если агент во время выполнения бросит исключение, то события с кодами `finish` и `not_callable` не будут вызваны! Вместо этого нужно смотреть Exception-лог из главного модуля. -Пример функции-логгирования для размещения в `legacy.php` (см. [структуру проекта](/Разработка/Структура_папки_local/Свой_код)) +Пример функции-логирования для размещения в `legacy.php` (см. [структуру проекта](/03_Разработка/20_Структура_папки_local/10_Свой_код.md)) ```php function agentDebug($arAgent, $strEvent, $strEvalResult = null, $error = "") { diff --git "a/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/100_\320\242\320\265\321\205\320\275\320\276\320\273\320\276\320\263\320\270\320\270/30_\320\241\320\276\320\261\321\213\321\202\320\270\321\217.md" "b/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/100_\320\242\320\265\321\205\320\275\320\276\320\273\320\276\320\263\320\270\320\270/30_\320\241\320\276\320\261\321\213\321\202\320\270\321\217.md" index 8cbc533..050ac22 100644 --- "a/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/100_\320\242\320\265\321\205\320\275\320\276\320\273\320\276\320\263\320\270\320\270/30_\320\241\320\276\320\261\321\213\321\202\320\270\321\217.md" +++ "b/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/100_\320\242\320\265\321\205\320\275\320\276\320\273\320\276\320\263\320\270\320\270/30_\320\241\320\276\320\261\321\213\321\202\320\270\321\217.md" @@ -3,7 +3,7 @@ keywords: "event, eventhandler, bitrix24, bitrix, 1c-bitrix, события, о --- # Введение -Иногда бывает необходимо повлиять на ход выполнения какого-нибудь процесса, а поскольку изменять [ядро продукта](/Общие_сведения/Ядро_продукта) запрещено в системе реализован механизм событий. В ходе выполнения некоторых API функций или частях системы, в определенных точках установлены вызовы определённых функций, так называемых обработчиков события. +Иногда бывает необходимо повлиять на ход выполнения какого-нибудь процесса, а поскольку изменять [ядро продукта](/02_Общие_сведения/01_Ядро_продукта.md) запрещено в системе реализован механизм событий. В ходе выполнения некоторых API функций или частях системы, в определенных точках установлены вызовы определённых функций, так называемых обработчиков события. >Событие - это сообщение программного обеспечения либо его части, которое указывает, что произошло. >Обработчик события - код который исполняется для обработки события @@ -13,7 +13,7 @@ keywords: "event, eventhandler, bitrix24, bitrix, 1c-bitrix, события, о - Название события - Параметры события (аргументы события) -Например событие OnPageStart модуля main не имеет параметров события, а просто оповещает что происходит начало выполнения пользовательского кода, а событие OnBeforeCrmDealAdd модуля crm передает параметр содержащий поля добавляемой сделки. +Например, событие OnPageStart модуля main не имеет параметров события, а просто оповещает что происходит начало выполнения пользовательского кода, а событие OnBeforeCrmDealAdd модуля crm передает параметр содержащий поля добавляемой сделки. >Не следует путать "Событие" как явление и "Событие" как объект описывающее это явление. Помимо глобального вещания в событие (как объект) можно передать конкретный фильтр модулей, обработчикам которых вы хотите его передать. @@ -22,7 +22,7 @@ keywords: "event, eventhandler, bitrix24, bitrix, 1c-bitrix, события, о ## Как это работает? В разрезе продукта существует глобальный singleton `\Bitrix\Main\EventManager`, который хранит все зарегистрированные обработчики событий. -Некоторый код инициирует отправку события события, `EventManager` выполняет поиск всех обработчиков удовлетворяющих условиям поиска и последовательно(!) в порядке приоритетов и добавления обработчиков передает его в обработчик события. +Некоторый код инициирует отправку события, `EventManager` выполняет поиск всех обработчиков удовлетворяющих условиям поиска и последовательно(!) в порядке приоритетов и добавления обработчиков передает его в функцию-обработчик события. Что может выступать обработчиком события? - Callback (php callable тип для которого будет выполнено `call_user_func_array`) @@ -36,7 +36,7 @@ keywords: "event, eventhandler, bitrix24, bitrix, 1c-bitrix, события, о Добавления обработчика событий - осуществляется в ходе выполнения программы и существует только в рамках исполняемого скрипта (закончили исполнение - забыли про событие). Помимо способов подписки на события существуют типы событий: старого ядра и нового ядра. -Обработчики событий старого ядра - принимают сколько угодно аргументов, передаваемых по значению или по ссылке и могут ожидать чего-угодно в результате своей работы. Например уже упомянутое событие OnBeforeCrmDealAdd модуля crm принимает массив полей добавляемого элемента по ссылке, а это значит что его можно изменить. Другой пример событие OnAfterCrmDealAdd, которое не обращает и не обрабатывает возвращаемый результат. +Обработчики событий старого ядра - принимают сколько угодно аргументов, передаваемых по значению или по ссылке и могут ожидать чего-угодно в результате своей работы. Например, уже упомянутое событие OnBeforeCrmDealAdd модуля crm принимает массив полей добавляемого элемента по ссылке, а это значит что его можно изменить. Другой пример событие OnAfterCrmDealAdd, которое не обращает и не обрабатывает возвращаемый результат. Обработчики событий нового ядра - принимают ровно один аргумент - наследник класса `\Bitrix\Main\Event` и ожидают возврата `\Bitrix\Main\EventResult` объекта (допустим null/void). @@ -69,7 +69,7 @@ $eventManager->addEventHandler( 2. Сигнатура метода добавления обработчика событий старого ядра отличается от нового ядра только названием метода: `addEventHandlerCompatible` -3. Сигнатура метода регистрации обработчка событий нового ядра: +3. Сигнатура метода регистрации обработчика событий нового ядра: ```php $registerEventHandler->registerEventHandler( $fromModuleId, @@ -110,9 +110,9 @@ $eventManager->addEventHandlerCompatible( ); ``` -Однако в соответствии с оговоренной ранее [структурой папки local](/Разработка/Структура_папки_local/Основное) размещать код обработчика вместе с кодом подписки не следует во избежании раздувания файла с подписками. Наиболее практичный вариант в данном случае: разделение кода-обработчика и кода подписчика. +Однако в соответствии с оговоренной ранее [структурой папки local](/03_Разработка/20_Структура_папки_local/00_Основное.md) размещать код обработчика вместе с кодом подписки не следует во избежании раздувания файла с подписками. Наиболее практичный вариант в данном случае: разделение кода-обработчика и кода подписчика. -Например для нашей [структуры папки local](/Разработка/Структура_папки_local/Основное) разделим указанный выше фрагмент. +Например, для нашей [структуры папки local](/03_Разработка/20_Структура_папки_local/00_Основное.md) разделим указанный выше фрагмент. В файле `local/php_interface/events.php`: ```php @@ -149,9 +149,8 @@ class DealCatcher Обратите внимание на следующие моменты: 1. Поскольку мы использовали callback-обработчик мы явно обозначили метод `handleAfterDealAdd` статическим. ->Если мы этого не сделаем, то на php 8+ мы получим фатальную ошибку `should not be called statically in ` 2. Мы добавили php-doc комментарий к методу обработчику: указали какое событие он обрабатывает и что он делает -3. Комментарий к аргументу `$fields` - `Some deal fields` - это именно некоторые поля которые было добавлены к сделке, а не все поля сделки. Событие не гарантирует что вам придет полный набор полей и вам всегда нужно проверять есть ли поле с кодом `...` в `$fields`. +3. Комментарий к аргументу `$fields` - `Some deal fields` - это поля, которые были указаны при добавлении сделки или были добавлены в процессе работы создания или других обработчиков событий, а не все поля сделки. Событие не гарантирует что вам придет полный набор полей и вам всегда нужно проверять есть ли поле с кодом `...` в `$fields`. 4. Мы явно указали типы аргументов которые мы ждем. ## Как отписаться от события? @@ -223,16 +222,16 @@ if ($event->getResults()) Несколько советов по созданию свои собственных событий: 1. К названию события подойдите максимально осознанно. Не следует создавать по событию на каждый чих - старайтесь группировать их по смыслу. -2. Обарабатывайте все результаты обработчиков. В приведенном примере, если несколько обработчиков будет установлено одному событию, то в массиве `$arMacros["PRODUCTS"]` будет результата последнего успешно завершенного обработчика. +2. Обрабатывайте все результаты обработчиков. В приведенном примере, если несколько обработчиков будет установлено одному событию, то в массиве `$arMacros["PRODUCTS"]` будет результата последнего успешно завершенного обработчика. 3. В параметрах события старайтесь передавать объекты. Все объекты в php передаются по ссылке, а значит каждый обработчик будет иметь доступ к последнему актуальному состоянию. Передача скалярных значений и массивов осуществляется по значению, т.е. изменить их в обработчиках будет нельзя. ### Отладка собственных событий Иногда возникает необходимость в отладке собственных событий, но не имеет смысла собирать информацию со всей системы. Именно для таких ситуаций в каждом объекте события присутствует 2 дополнительных свойства: -- `debugMode` - обозначающий что событие работает в режиме отладки +- `debugMode` - обозначающий, что событие работает в режиме отладки - `debugInfo` - массив произвольной информации, которой можно получить через метод `getDebugInfo` -Что нужно чтобы добавить отладку в свой код? +Что нужно, чтобы добавить отладку в свой код? 1. Перед отправкой события необходимо включить отладку: ``` @@ -250,7 +249,7 @@ $debugInfo = $event->getDebugInfo(); `$debugInfo` - будет содержать массив любой информации которую туда добавят обработчики. -3. В нужных местах обработчиков добавить дозапись полезной информации: +3. В нужных местах обработчиков добавить запись полезной информации: ``` $event->addDebugInfo( $ar ); @@ -266,7 +265,7 @@ $event->addDebugInfo( $ar ); ## Частные ситуации -Как и любой другой механизм события обладают определенными возможностями которые с одной стороны могут менять поведение системы, а с другой стороны существенно замедлить ее производительность и стать источником проблем. Рассматрим наиболее частые причины и способы их устранения. +Как и любой другой механизм события обладают определенными возможностями которые с одной стороны могут менять поведение системы, а с другой стороны существенно замедлить ее производительность и стать источником проблем. Рассмотрим наиболее частые причины и способы их устранения. ### Зациклирование обработчиков @@ -297,17 +296,16 @@ $eventManager->addEventHandlerCompatible( #### Изменение бизнес-логики -Поскольку рассмотрение данного примера это скорее творческая задача, а не техническая, то рассматривать ее в отрыве от реальной задачи не представляется возможным. -Какими трюками тут можно воспользоваться: -1. Не выполнять `update`. Поскольку в обработчик `onBeforeCrmDealUpdate` параметр `$arFields` приходит по ссылке, то мы можем дополнить его своими значениями и эта информация будет сохранена в сделку. -2. Использовать идемпотетный код. Т.е. перед тем как сделать изменения еще раз проверим что все требования выполнены, а действия раньше не было. Например: если бы нам необходимо было увеличить сумму сделки на 100 рублей если включен флаг "Доставка", то при изменении сделки мы бы могли проверять что стоимость товаров плюс 100 рублей не равна текущей стоимости сделки. +Иногда бывает полезно взглянуть на ситуацию под другим углом и изменить не техническую реализацию, а условие самой бизнес-логики. Например: +1. Не выполнять `update`. Поскольку в функции-обработчике `onBeforeCrmDealUpdate` параметр `$arFields` приходит по ссылке, то мы можем дополнить его своими значениями и эта информация будет сохранена в сделку. +2. Использовать идемпотентный код. Т.е. перед тем как сделать изменения еще раз проверим что все требования выполнены, а действия раньше не было. Например: если бы нам необходимо было увеличить сумму сделки на 100 рублей если включен флаг "Доставка", то при изменении сделки мы бы могли проверять что стоимость товаров плюс 100 рублей не равна текущей стоимости сделки. #### Установка lock-флагов В классе-обработчике создается статическая переменная-флаг. Когда флаг активен - обработчик быстро завершается. -При входе в обработчик - устанавливается флаг, а при выходе - снимается. +При входе в функцию-обработчик - устанавливается флаг, а при выходе - снимается. ```php namespace Vendor/Subsystem/Integration/Crm; @@ -371,7 +369,7 @@ class DealCatcher Кажется что в этом коде нет проблем - мы проверяем есть ли в наборе полей $fields на событии после изменения поле ASSIGNED_BY_ID и выполняем действия. Однако на самом деле - мы не знаем был ли изменен автор. Мы знаем что он есть в наборе полей $fields, но мы же туда могли отправить и того же самого автора и тогда код будет выполнен. Для исправления этой ситуации мы должны исправить кол: -1. Ставим дополнительную подписку на `onBefore`-событие. Если приходит ASSIGNED_BY_ID поле запрашиваем оригинальное значение. Если значение оригинального поля несовпадает со значением текущего поля - устанавливаем lock-флаг. +1. Ставим дополнительную подписку на `onBefore`-событие. Если приходит ASSIGNED_BY_ID поле запрашиваем оригинальное значение. Если значение оригинального поля не совпадает со значением текущего поля - устанавливаем lock-флаг. 2. На `onAfter`-событии проверяем установленный флаг, а не наличие поля diff --git "a/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/00_\320\222\320\262\320\265\320\264\320\265\320\275\320\270\320\265.md" "b/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/00_\320\222\320\262\320\265\320\264\320\265\320\275\320\270\320\265.md" index b8d70ce..02a1199 100644 --- "a/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/00_\320\222\320\262\320\265\320\264\320\265\320\275\320\270\320\265.md" +++ "b/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/00_\320\222\320\262\320\265\320\264\320\265\320\275\320\270\320\265.md" @@ -4,9 +4,9 @@ Изучение этих инстументов дает понимание работы продукта. В этом разделе собрано огромное количество информации, которое позволит создать вашу страницу быстрее и с большими возможностями: -- Настройте [тулбар](./Тулбар/Основное) для упрощенного вывода шапки страницы. Задавайте простыми движениями загловок, "избранное", фильтр и управляющие кнопки страницы. +- Настройте [тулбар](./Тулбар/Основное) для упрощенного вывода шапки страницы. Задавайте заголовок, "избранное", фильтр и управляющие кнопки страницы. - Используйте возможности [фильтра](./Фильтр/О_модуле) для обеспечения визуализации критериев поиска. -- Выводите информацию [в табличном виде](./Таблицы/Основное) для того чтобы обеспечить единообразие пользовательского опыта. -- Воспользуйтесь свойствами [кнопок](./Кнопки) чтобы добавить интерактива. +- Выводите информацию [в табличном виде](./Таблицы/Основное), для того чтобы обеспечить единообразие пользовательского опыта. +- Воспользуйтесь свойствами [кнопок](./Кнопки), чтобы добавить интерактива. Знание стандартных инструментов позволит экономить до 30% времени на разработку новых возможностей. \ No newline at end of file diff --git "a/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/10_\320\242\321\203\320\273\320\261\320\260\321\200/00_\320\236\321\201\320\275\320\276\320\262\320\275\320\276\320\265.md" "b/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/10_\320\242\321\203\320\273\320\261\320\260\321\200/00_\320\236\321\201\320\275\320\276\320\262\320\275\320\276\320\265.md" index 60d9bea..4a1f480 100644 --- "a/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/10_\320\242\321\203\320\273\320\261\320\260\321\200/00_\320\236\321\201\320\275\320\276\320\262\320\275\320\276\320\265.md" +++ "b/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/10_\320\242\321\203\320\273\320\261\320\260\321\200/00_\320\236\321\201\320\275\320\276\320\262\320\275\320\276\320\265.md" @@ -18,13 +18,13 @@ Тулбар применяется и отображается по-умолчанию для каждой страницы, если выполнены следующие условия: 1. Страница отображается в шаблоне Битрикс24 (в других шаблонах нужно вызывать компонент явно) 2. К странице не применяются устаревшие встройки. Т.е. следующие буферы, заполняемые из отложенных функций пусты: `pagetitle`, `inside_pagetitle`, `in_pagetitle`. -3. Буферизация страницы ведется, но еще не закончена (на момент отрисовки тулбара не вызваны методы прерывающие обработку). +3. Буферизация страницы уже ведется, но еще не закончена, поскольку на момент отрисовки тулбара не были вызваны методы прерывающие обработку. ->Если вы отрисовываете страницу через компонент `bitrix:ui.sidepanel.wrapper`, то для использования тулбара необходимо явно передавать параметр `"USE_UI_TOOLBAR" => "Y"` +>Если вы выводите страницу через компонент `bitrix:ui.sidepanel.wrapper`, то для использования тулбара необходимо явно передавать параметр `"USE_UI_TOOLBAR" => "Y"` ## Работа с содержимым тулбара -Работа с тулбаром осуществляестся через singleton-класс менеджера тулбаров: +Работа с тулбаром осуществляется через singleton-класс менеджера тулбаров: ```php use Bitrix\UI\Toolbar\Manager; @@ -54,7 +54,7 @@ $toolbar = $manager->createToolbar($id, $options); Поскольку технически страница может иметь несколько тулбаров (хотя на практике обычно не используется более 1), выполнять подобные действия каждый раз в своем компоненте является неудобным занятием: - Во-первых, компонент должен знать в какой тулбар добавить управляющий элемент -- Во-вторых, в каждом месте, которое добавляет элемент в тулбар, необходимо прописывать код, который обрабатывал бы ситуацию с тем, что тулбар не был инициализирован до этого. +- Во-вторых, при каждом добавлении элемента в тулбар, необходимо было бы прописывать код, который обрабатывал бы ситуацию с тем, что тулбар не был инициализирован до этого. Для облегчения этих действий, поскольку в дизайне Битрикс24 уже имеется компонент тулбара, был реализован класс-фасад, который обращается к дефолтному тулбару. Во всех примерах мы будем предполагать что в use-секцию вашего кода уже добавлено сокращение: @@ -67,7 +67,7 @@ use Bitrix\UI\Toolbar\Facade\Toolbar; ### Добавление фильтра -Поскольку подробнее работа фильтра рассмотрена в [другом разделе](/Разработка/UI/Фильтр/Обзор) мы не будем разбирать здесь его строение, а сконцентируемся лишь на использовании его в тулбаре. +Поскольку подробнее работа фильтра рассмотрена в [другом разделе](/Разработка/UI/Фильтр/Обзор) мы не будем разбирать здесь его строение, а сконцентрируемся лишь на использовании его в тулбаре. Для добавления фильтра на странице необходимо вызвать статический метод `addFilter`, чья сигнатура: @@ -122,7 +122,7 @@ Toolbar::deleteFavoriteStar(); ### Добавить пользовательский элемент -Операции добавления произвольного контента в области "до"/"после" заголовка страницы и блок пользовательского контента не явлются повсеместными (в отличии от других), поэтому фасада для таких операций не предусмотрено. +Операции добавления произвольного контента в области "до"/"после" заголовка страницы и блок пользовательского контента не являются повсеместными (в отличие от других), поэтому фасада для таких операций не предусмотрено. Алгоритм внесения изменений следующий: 1. Формирование контента 2. Получение инстанса тулбара @@ -171,10 +171,10 @@ $content = $toolbar->getRightCustomHtml(); // string or null ### Некоторые дополнительные возможности -Дополнительно к текущеми возможностям есть дополнительные обработчики на удаление ненужных кнопок и перемешивание. +Дополнительно к текущим возможностям есть дополнительные обработчики на удаление ненужных кнопок и перемешивание. Подобные операции не являются частыми, однако могут помочь "вырезать под корень лишнее". -Для удаления кнопки в тулбаре присутствует метод `deleteButtons(\Closure $closure)`, который принимает `Closure` объект и применяет его к кажой кнопки (вне зависимости от расположения). Если объект вернет `true` (строгое сравнение), то кнопка удаляется. +Для удаления кнопки в тулбаре присутствует метод `deleteButtons(\Closure $closure)`, который принимает `Closure` объект и применяет его к каждой кнопки (вне зависимости от расположения). Если объект вернет `true` (строгое сравнение), то кнопка удаляется. Например, мы хотим удалить все кнопки: @@ -190,7 +190,7 @@ $toolbar->deleteButtons(function($button){ Иногда возникает необходимость поменять кнопки местами в рамках определенной локации кнопок. Для этого существует нестатический метод `shuffleButtons(\Closure $closure, $buttonLocation)`, который позволяет изменить порядок. -Например поменяем первые 2 кнопки местами: +Например, поменяем первые 2 кнопки местами: ```php use \Bitrix\UI\Toolbar\ButtonLocation; $toolbar->shuffleButtons(function($buttonList){ diff --git "a/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/20_\320\244\320\270\320\273\321\214\321\202\321\200/00_\320\236_\320\274\320\276\320\264\321\203\320\273\320\265.md" "b/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/20_\320\244\320\270\320\273\321\214\321\202\321\200/00_\320\236_\320\274\320\276\320\264\321\203\320\273\320\265.md" index 0df5ba7..7a73956 100644 --- "a/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/20_\320\244\320\270\320\273\321\214\321\202\321\200/00_\320\236_\320\274\320\276\320\264\321\203\320\273\320\265.md" +++ "b/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/20_\320\244\320\270\320\273\321\214\321\202\321\200/00_\320\236_\320\274\320\276\320\264\321\203\320\273\320\265.md" @@ -4,7 +4,7 @@ Этот раздел показывает как применять стандартные технологии для обеспечения фильтрации в своих разработках. Для упрощения раздела мы будем рассматривать фильтрацию с разных сторон: -1. [Обзор компонента `bitrix:main.ui.filter`](./Обзор) -2. [Работа с фильтрами пользователя](./Фильтры_пользователя) -3. [Работа с компонентом в публичной части](./Публичная_часть) -4. [Свой объект фильтра и провайдер данных](./Свой_фильтр) +1. [Обзор компонента `bitrix:main.ui.filter`](./10_Обзор) +2. [Работа с фильтрами пользователя](./20_Фильтры_пользователя) +3. [Работа с компонентом в публичной части](./30_Публичная_часть) +4. [Свой объект фильтра и провайдер данных](./40_Свой_фильтр) diff --git "a/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/20_\320\244\320\270\320\273\321\214\321\202\321\200/10_\320\236\320\261\320\267\320\276\321\200.md" "b/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/20_\320\244\320\270\320\273\321\214\321\202\321\200/10_\320\236\320\261\320\267\320\276\321\200.md" index 2f31f24..e7043c5 100644 --- "a/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/20_\320\244\320\270\320\273\321\214\321\202\321\200/10_\320\236\320\261\320\267\320\276\321\200.md" +++ "b/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/20_\320\244\320\270\320\273\321\214\321\202\321\200/10_\320\236\320\261\320\267\320\276\321\200.md" @@ -13,34 +13,34 @@ ## Параметры компонента -| Параметр | Описание | -| :--- | --- | -| `FILTER_ID` (string) | - уникальный идентификатор фильтра, используемый для отделения его от других фильтров в продукте. Единственный обязательный параметр компонента. | -| `GRID_ID` (string) | - опциональный параметр идентификатор связанного грида. Если заполнен, то некоторые действия грида и фильтра будут связаны. Например при применении фильтра грид будет автоматически обновлен. | -| `FIELDS` (array) | - набор полей для фильтра. Подробнее в главе "Поля фильтра" | -| `RENDER_FILTER_INTO_VIEW` (string) | - код включаемой области для отрисовки фильтра | -| `RENDER_FILTER_INTO_VIEW_SORT` (int) | - приоритет для отрисовки в включаемой области (по-умолчанию 500) | -| `SETTINGS_URL` (string) | - относительный url к файлу, который управляет настройками фильтра. По-умолчанию ссылается на файл `settings.ajax.php` в папке компонента | -| `FILTER_ROWS` (array) | - набор идентификаторов полей фильтра находящихся на странице при первоначальной отрисовке (поля по-умолчанию или поля из последнего пресета) | -| `CURRENT_PRESET` (string) | - пресет из набора, переданного в параметрах `FILTER_PRESETS`, который выбран при открытии. | -| `ENABLE_LABEL` (bool) | - флаг, отвечающий за вывод названий полей в фильтре. | -| `DISABLE_SEARCH` (bool) | - в случае `true` будет доступен только фильтр без поиска. Семантически похож на `ENABLE_LIVE_SEARCH`, поэтому последний не рассматривается | -| `LIMITS` (array) | - ассоциативный массив описываюший предупреждение с лимитами. Подробнее в главе "Лимиты" | -| `RESET_TO_DEFAULT_MODE` (bool) | - флаг, отвечающий за поведение ворзвращения фильтра на закрепленный пресет. В случае когда пользователь имеет закрепленный пресет, затем выбирает другой фильтр и отменяет его, то в случае `true` (по-умолчанию) фильтр вернется в закрепленный пресен | -| `LAZY_LOAD` (array) | - массив ссылок, отвечающий за ленивую подгрузку данных. Подробнее в главе "Ленивая подгрузка данных" | -| `MESSAGES` (array) |- массив языковых фраз для переопределения. Подробнее в главе "Переопределение языковых фраз фильтра" | -|`FILTER` (array) | - набор конфигураций полей фильтра. | -| `FILTER_ROWS` (array) | - опциональный параметр показывающий какие поля из `FILTER` сейчас находятся на форме. Если не передан - будет вычислен из полей `FILTER` и пресета пользователя. По сути ассоциативный массив ` => `, где `k` - код поля, а `v` - bool-значение, `true` если отображается | -| `FILTER_PRESETS` (array) | - набор пресетов, отображающихся у пользователей как системные (их нельзя удалить). В фильтре всегда есть пресет с кодом `default_filter`, добавлять его самому не нужно, но и переопределять его не имеет смысла - он будет добавален автоматически компонентом. | -| `COMMON_PRESETS_ID` (string) | - пресет из списка `FILTER_PRESETS`, являющийся основным (т.е. по-умолчанию) при открытии страницы. | -| `CONFIG` (array) | - массив дополнительной приоритетной информации относительно конфигурации пользователя. Подробнее он разобран в "Поведение ключа `CONFIG`". | -| `VALUE_REQUIRED` (bool) | - нужно ли контролировать в фильтре обязательные параметры. В случае если параметр `true`, будет выполнен поиск обязательных полей и принудительный вывод на выбранный экран. Обязательные поля нельзя будет удалить из отображения фильтра. | -| `VALUE_REQUIRED_MODE` (bool) | Дополнительный флаг меняющий поведение фильтра без параметров. Дополняет стандартное поведение `VALUE_REQUIRED`. | -| `THEME` | - идентификатор темы применяемой для фильтра. Подробнее в главе "Темы для фильтра" | -| `ENABLE_ADDITIONAL_FILTERS` | `true` если в фильтре используются дополнительные опции (например "Значение отсутствует") | -| `ENABLE_FIELDS_SEARCH` | `true` если в фильтре разрешен поиск полей при добавлении нового поля на форму | -| `HEADERS_SECTIONS` | | -| Языковые параметры | Подробнее в главе "Переопределение языковых фраз фильтра" | +| Параметр | Описание | +|:-------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `FILTER_ID` (string) | - уникальный идентификатор фильтра, используемый для отделения его от других фильтров в продукте. Единственный обязательный параметр компонента. | +| `GRID_ID` (string) | - опциональный параметр идентификатор связанного грида. Если заполнен, то некоторые действия грида и фильтра будут связаны. Например при применении фильтра грид будет автоматически обновлен. | +| `FIELDS` (array) | - набор полей для фильтра. Подробнее в главе "Поля фильтра" | +| `RENDER_FILTER_INTO_VIEW` (string) | - код включаемой области для отрисовки фильтра | +| `RENDER_FILTER_INTO_VIEW_SORT` (int) | - приоритет для отрисовки в включаемой области (по-умолчанию 500) | +| `SETTINGS_URL` (string) | - относительный url к файлу, который управляет настройками фильтра. По-умолчанию ссылается на файл `settings.ajax.php` в папке компонента | +| `FILTER_ROWS` (array) | - набор идентификаторов полей фильтра находящихся на странице (поля по-умолчанию или поля из последнего пресета) | +| `CURRENT_PRESET` (string) | - пресет из набора, переданного в параметрах `FILTER_PRESETS`, который выбран при открытии. | +| `ENABLE_LABEL` (bool) | - флаг, отвечающий за вывод названий полей в фильтре. | +| `DISABLE_SEARCH` (bool) | - в случае `true` будет доступен только фильтр без поиска. Семантически похож на `ENABLE_LIVE_SEARCH`, поэтому последний не рассматривается | +| `LIMITS` (array) | - ассоциативный массив описывающий предупреждение с лимитами. Подробнее в главе "Лимиты" | +| `RESET_TO_DEFAULT_MODE` (bool) | - флаг, отвечающий за поведение фильтра возвращающего на закрепленный пресет. В случае когда пользователь имеет закрепленный пресет, затем выбирает другой фильтр и отменяет его, то в случае `true` (по-умолчанию) фильтр вернется в закрепленный пресен | +| `LAZY_LOAD` (array) | - массив ссылок, отвечающий за ленивую загрузку данных. Подробнее в главе "Ленивая загрузка данных" | +| `MESSAGES` (array) | - массив языковых фраз для переопределения. Подробнее в главе "Переопределение языковых фраз фильтра" | +| `FILTER` (array) | - набор конфигураций полей фильтра. | +| `FILTER_ROWS` (array) | - опциональный параметр показывающий какие поля из `FILTER` сейчас находятся на форме. Если не передан - будет вычислен из полей `FILTER` и пресета пользователя. По сути ассоциативный массив ` => `, где `k` - код поля, а `v` - bool-значение, `true` если отображается | +| `FILTER_PRESETS` (array) | - набор пресетов, отображающихся у пользователей как системные (их нельзя удалить). В фильтре всегда есть пресет с кодом `default_filter`, добавлять его самому не нужно, но и переопределять его не имеет смысла - он будет добавлен автоматически компонентом. | +| `COMMON_PRESETS_ID` (string) | - пресет из списка `FILTER_PRESETS`, являющийся основным (т.е. по-умолчанию) при открытии страницы. | +| `CONFIG` (array) | - массив дополнительной приоритетной информации относительно конфигурации пользователя. Подробнее он разобран в "Поведение ключа `CONFIG`". | +| `VALUE_REQUIRED` (bool) | - нужно ли контролировать в фильтре обязательные параметры. В случае если параметр `true`, будет выполнен поиск обязательных полей и принудительный вывод на выбранный экран. Обязательные поля нельзя будет удалить из отображения фильтра. | +| `VALUE_REQUIRED_MODE` (bool) | Дополнительный флаг меняющий поведение фильтра без параметров. Дополняет стандартное поведение `VALUE_REQUIRED`. | +| `THEME` | - идентификатор темы применяемой для фильтра. Подробнее в главе "Темы для фильтра" | +| `ENABLE_ADDITIONAL_FILTERS` | `true` если в фильтре используются дополнительные опции (например "Значение отсутствует") | +| `ENABLE_FIELDS_SEARCH` | `true` если в фильтре разрешен поиск полей при добавлении нового поля на форму | +| `HEADERS_SECTIONS` | | +| Языковые параметры | Подробнее в главе "Переопределение языковых фраз фильтра" | ### Отображаемый вид открытого фильтра @@ -65,10 +65,10 @@ Рассмотрим какие опции можно использовать: - `SEARCH` (bool) - дополнительный параметр, который учитывается в качестве условия "или" для возможности поиска. Поиск будет недоступен если `DISABLE_SEARCH = true` ИЛИ `SEARCH = false`. Если в `DISABLE_SEARCH = true`, параметр `SEARCH = false` не имеет силы. - `DEFAULT_PRESET` (bool) - разрешает или запрещает устанавливать перест по-умолчанию. Пресеты создавать можно, закреплять (т.е. делать по-умолчанию) нельзя. -- `FILTER_SHOW_DELAY` (int) - примерное количество милисекунд (1000 = 1 секунда) прежде чем нажатие по строке приведет к открытию фильтра -- `FILTER_CLOSE_DELAY` (int) - примерное количество милисекунд (1000 = 1 секунда) прежде чем фактическое закрытие фильтра приведет к исчезновению всплывающего окна с полями фильтрации +- `FILTER_SHOW_DELAY` (int) - примерное количество миллисекунд (1000 = 1 секунда) прежде чем нажатие по строке приведет к открытию фильтра +- `FILTER_CLOSE_DELAY` (int) - примерное количество миллисекунд (1000 = 1 секунда) прежде чем фактическое закрытие фильтра приведет к исчезновению всплывающего окна с полями фильтрации - `AUTOFOCUS` (bool) - если установлено (`true`), при открытии страницы фокус будет перемещен на фильтр -- `POPUP_BIND_ELEMENT_SELECTOR` (string) - css селектор, по которому будет производится поиск во всем DOM-дереве для позиционирования фильтра относительно этого элемента. +- `POPUP_BIND_ELEMENT_SELECTOR` (string) - css селектор, по которому производится поиск во всем DOM-дереве для позиционирования фильтра относительно этого элемента. - `POPUP_OFFSET_LEFT` (int) - смещение (в пикселях) влево относительно элемента для которого осуществляется позиционирование - `POPUP_OFFSET_TOP` (int) - смещение (в пикселях) вверх относительно элемента для которого осуществляется позиционирование @@ -78,19 +78,19 @@ ## Поля фильтра -Каждый фильтр состоит из набора полей (не ассоциативынй список), где каждое поле описывается некоторыми параметрами: - -| Поле | Тип | Описание | -| :-------------- | --------- | -------- | -| `id` | `string` | Код поля | -| `name` | `string` | Отображаемое название поля | -| `type` | `string` | См. допустимые типые полей под таблицей | -| `placeholder` | `string` | Текст в поле ввода. Допустим не для всех полей. | -| `params` | `array` | Набор дополнительных параметров поля | -| `required` | `bool` | Является ли поле обязательным | -| `valueRequired` | `bool` | Должно ли поле быть заполнено явно | +Каждый фильтр состоит из набора полей (не ассоциативный список), где каждое поле описывается некоторыми параметрами: + +| Поле | Тип | Описание | +|:----------------|-----------|--------------------------------------------------------------------------| +| `id` | `string` | Код поля | +| `name` | `string` | Отображаемое название поля | +| `type` | `string` | См. допустимые типы полей под таблицей | +| `placeholder` | `string` | Текст в поле ввода. Допустим не для всех полей. | +| `params` | `array` | Набор дополнительных параметров поля | +| `required` | `bool` | Является ли поле обязательным | +| `valueRequired` | `bool` | Должно ли поле быть заполнено явно | | `strict` | `bool` | Усиленная проверка полей (при включенном режиме дополнительных фильтров) | -| Типизированные | --------- | Зависят от выбранного типа. См. дополнительное описание полей | +| Типизированные | --------- | Зависят от выбранного типа. См. дополнительное описание полей | Актуальные допустимые типы поле в фильтре описаны константами в классе `Bitrix\Main\UI\Filter\FieldAdapter`. На момент написания статьи это типы (в скобках указано их значение): @@ -107,12 +107,12 @@ - `CHECKBOX` (`checkbox`) - Да/Нет В параметрах (`params`) полей могут передаваться дополнительные правила поведения полей. -Например для создания множественного поля, в параметрах нужно передать `multiple` со значением `true` (bool), либо `Y` (string). +Например, для создания множественного поля, в параметрах нужно передать `multiple` со значением `true` (bool), либо `Y` (string). ### Дополнительные возможности полей -Стандартное описание полей и параметров гибко зависят от типа поля. Некоторые типы полей требуют своих спецэффических настроек, а некоторые параметров. В этой главе мы будем рассматривать настройку таких полей. +Стандартное описание полей и параметров гибко зависят от типа поля. Некоторые типы полей требуют своих дополнительных настроек, а некоторые параметров. В этой главе мы будем рассматривать настройку таких полей. При рассмотрении предполагаем что в коде у нас прописаны следующие сокращения: ```php @@ -120,7 +120,7 @@ use Bitrix\Main\UI\Filter\FieldAdapter; ``` #### Поле типа Список (`FieldAdapter::LIST`). -В своем наборе полей ожидает получить дополнительный ключ `items`, который бы являлся ассоциативным массивом ключ=>значение, где ключ - реальное значение поля (которое будет использоваться в коде), а значение это отображаемый пользователю текст. +В своем наборе полей ожидает получить дополнительный ключ `items`, являющийся ассоциативным массивом ключ=>значение, где ключ - реальное значение поля (которое будет использоваться в коде), а значение это отображаемый пользователю текст. Пример описания поля типа список, не обязательного к заполнению с двумя вариантами. ```php @@ -136,7 +136,7 @@ use Bitrix\Main\UI\Filter\FieldAdapter; ] ``` -В случае использования не множественного необязательного поля в список `items` дополнительно будет добавлен технический элемент ключем которого выступит пустая строка, а значением - языковая фраза с кодом `MAIN_UI_FILTER__NOT_SET`. +В случае использования не множественного необязательного поля в список `items` дополнительно будет добавлен технический элемент ключом которого выступит пустая строка, а значением - языковая фраза с кодом `MAIN_UI_FILTER__NOT_SET`. #### Поле типа Число (`FieldAdapter::NUMBER`) @@ -146,13 +146,13 @@ use Bitrix\Main\UI\Filter\FieldAdapter; 1. `messages` - Ассоциативный массив `(string) => string` языковых фраз для приоритетного замещения стандартных. На момент написания статьи обрабатывает следующие языковые фразы: -| Код фразы | Значение на русском | -| :-------------------------------- | ------------------- | -| MAIN_UI_FILTER__NUMBER_SINGLE | Точно | -| MAIN_UI_FILTER__NUMBER_RANGE | Диапазон | -| MAIN_UI_FILTER__NUMBER_MORE | Больше чем | -| MAIN_UI_FILTER__NUMBER_LESS | Меньше чем | -| MAIN_UI_FILTER__NUMBER_BEFORE_N | Предыдущие N | +| Код фразы | Значение на русском | +|:--------------------------------|---------------------| +| MAIN_UI_FILTER__NUMBER_SINGLE | Точно | +| MAIN_UI_FILTER__NUMBER_RANGE | Диапазон | +| MAIN_UI_FILTER__NUMBER_MORE | Больше чем | +| MAIN_UI_FILTER__NUMBER_LESS | Меньше чем | +| MAIN_UI_FILTER__NUMBER_BEFORE_N | Предыдущие N | 2. `exclude` - перечисление стандартных подтипов поля, которые не нужно отображать. По-умолчанию все стандартные подтипы добавляются к полю и могут быть выбраны пользователем. @@ -171,7 +171,7 @@ use Bitrix\Main\UI\Filter\FieldAdapter; \Bitrix\Main\UI\Filter\AdditionalNumberType::BEFORE_N ``` -Пример как будет выглядеть описание обязательного поля типа Число, в возможнымии дополнительными значениями только "Предыдущие Н" (переименованным в "Рабочих дней назад": +Пример как будет выглядеть описание обязательного поля типа Число, в возможными дополнительными значениями только "Предыдущие Н" (переименованным в "Рабочих дней назад": ```php [ `id` => 'EXAMPLE_NUMBER', @@ -200,7 +200,7 @@ use Bitrix\Main\UI\Filter\FieldAdapter; На момент написания статьи обрабатывает следующие языковые фразы: | Код фразы | Значение на русском | -| :---------------------------------------------- | ------------------- | +|:------------------------------------------------|---------------------| | MAIN_UI_FILTER_FIELD_MONTH_1 | Январь | | MAIN_UI_FILTER_FIELD_MONTH_2 | Февраль | | MAIN_UI_FILTER_FIELD_MONTH_3 | Март | @@ -326,9 +326,9 @@ Bitrix\Main\UI\Filter\AdditionalDateType::AFTER_DAYS В своем наборе полей может принять дополнительно следующие поля: -1. `valueType` (string), которое описывает набор значений. В случае значения `numeric` (строгое сравнение) значения будут либо 1 либо 0, в случае если не `numberic`, то либо `Y` либо `N` соответственно. +1. `valueType` (string), которое описывает набор значений. В случае значения `numeric` (строгое сравнение) значения будут либо 1, либо 0, в случае если не `numberic`, то либо `Y` либо `N` соответственно. -Поле представляет из себя выпадающий список из 3 значений - Не выбрано (пустая строка), Да, Нет. +Поле представляет собой выпадающий список из 3 значений - Не выбрано (пустая строка), Да, Нет. Пример числового чек-бокса: ```php @@ -345,8 +345,8 @@ Bitrix\Main\UI\Filter\AdditionalDateType::AFTER_DAYS Не имеет дополнительных полей в наборе полей, однако имеет конфигурируемые параметры. В блоке параметров можно использовать следующие ключи: -- `multiple` (bool) - является ли выбор можественным -- `addEntityIdToResult` (bool) - true если нужно добавлять код типа сущности к значению. Например если у нас поиск из нескольких сущностей, то мы бы хотели получить набор вида `[, ]`, а не просто набор ID +- `multiple` (bool) - является ли выбор множественным +- `addEntityIdToResult` (bool) - true если нужно добавлять код типа сущности к значению. Например, если у нас поиск из нескольких сущностей, то мы бы хотели получить набор вида `[, ]`, а не просто набор ID - `showDialogOnEmptyInput` (bool) - true если нужно показывать диалог даже если - `dialogOptions` (array) - набор параметров entity-selector'а @@ -389,7 +389,7 @@ Bitrix\Main\UI\Filter\AdditionalDateType::AFTER_DAYS 1. `lightweight` (bool), в случае false (по-умолчанию) выполняет подключение на странице компонента `bitrix:main.ui.selector` с шаблоном `.default`, за счет чего и обеспечивается работа самого поля. В блоке параметров можно использовать следующие ключи: -- `multiple` (bool) - является ли выбор можественным +- `multiple` (bool) - является ли выбор множественным - `context` (string) - контекст выводимой информации (если не передан то `FILTER_`, где `` - код поля) - `enableUsers` (bool) - разрешать выбирать пользователей - `enableDepartments` (bool) - разрешать выбирать подразделения @@ -443,13 +443,13 @@ Bitrix\Main\UI\Filter\AdditionalDateType::AFTER_DAYS ``` Важные нюансы: -1. Пресеты индивидуальные. Новый пользователь может не иметь кастомных пресетов или иметьб другие +1. Пресеты индивидуальные. Новый пользователь может не иметь кастомных пресетов или иметь другие 2. Пресеты не обновляются. Т.е. все то что было сохранено в базу, то и останется. Это важно для полей с датами -3. Пресеты полносодержащие - т.е. они хранят не только значения (см `ASSIGNED_BY_ID`), но и отображаемые значения (`ASSIGNED_BY_ID_label`), включая технические поля (например `OPPORTUNITY_numsel` для поля типа Число). Это нужно формировать самостоятельно при работе с пресетами. +3. Пресеты тяжелые - т.е. они хранят не только значения (см `ASSIGNED_BY_ID`), но и отображаемые значения (`ASSIGNED_BY_ID_label`), включая технические поля (например `OPPORTUNITY_numsel` для поля типа Число). Это нужно формировать самостоятельно при работе с пресетами. ## Темы для фильтра -Компонент поддерживает возможность применения тем. Тема - это визуальный стил фильтра, который применяется поверх стандартного отображения. +Компонент поддерживает возможность применения тем. Тема - это визуальный стиль фильтра, который применяется поверх стандартного отображения. Набор тем ограничен стандартными темами. За работу тем отвечает класс `Bitrix\Main\UI\Filter\Theme`, который имеет константы тем и единственный метод `getList()` который возвращает список всех доступных тем (констант класса). @@ -458,7 +458,7 @@ Bitrix\Main\UI\Filter\AdditionalDateType::AFTER_DAYS - По-умолчанию (`Theme::DEFAULT_FILTER`) - Обрамленная (`Theme::BORDER`) - отличие от по-умолчанию в блоке фильтрации добавлена линии сверху и снизу от фильтра -- Округленная (`Theme::ROUNDED`) - левый и правый клая в блоке фильтрации сильно скруглены +- Округленная (`Theme::ROUNDED`) - левый и правый края в блоке фильтрации сильно скруглены - Легкая (`Theme::LIGHT`) - у фильтра белый фон заменен на полупрозрачный серый - Приглушенная (`Theme::MUTED`) - текст в фильтре не броский, становится более контрастным при наведении @@ -467,36 +467,36 @@ Bitrix\Main\UI\Filter\AdditionalDateType::AFTER_DAYS В компоненте предусмотрена принудительная замена языковых фраз через передачу параметров. Список поддерживаемых системных фраз: -| Параметр | Русское значение | -| :-------------------------------------------- | ---------------- | -| MAIN_UI_FILTER__AND | и | -| MAIN_UI_FILTER__MORE | ещё | -| MAIN_UI_FILTER__BEFORE | Раньше чем | -| MAIN_UI_FILTER__AFTER | Позже чем | -| MAIN_UI_FILTER__NUMBER_MORE | Больше чем | -| MAIN_UI_FILTER__NUMBER_LESS | Меньше чем | -| MAIN_UI_FILTER__PLACEHOLDER_DEFAULT | Фильтр + поиск | -| MAIN_UI_FILTER__PLACEHOLDER_WITH_FILTER | поиск | -| MAIN_UI_FILTER__PLACEHOLDER | Фильтр | -| MAIN_UI_FILTER__PLACEHOLDER_LIMITS_EXCEEDED | Достигнут лимит, подробнее | -| MAIN_UI_FILTER__QUARTER | Квартал | -| MAIN_UI_FILTER__IS_SET_AS_DEFAULT_PRESET | Назначен фильтром по умолчанию | -| MAIN_UI_FILTER__SET_AS_DEFAULT_PRESET | Назначить фильтром по умолчанию | -| MAIN_UI_FILTER__EDIT_PRESET_TITLE | Изменить название фильтра | -| MAIN_UI_FILTER__REMOVE_PRESET | Удалить фильтр | -| MAIN_UI_FILTER__DRAG_TITLE | Потяните, чтобы отсортировать список сохраненных фильтров | -| MAIN_UI_FILTER__DRAG_FIELD_TITLE | Потяните, чтобы отсортировать список полей | -| MAIN_UI_FILTER__REMOVE_FIELD | Скрыть поле | -| MAIN_UI_FILTER__CONFIRM_MESSAGE_FOR_ALL | Это действие сохранит настройки фильтра для всех пользователей.
Будут изменены сохраненные фильтры и набор полей. | -| MAIN_UI_FILTER__CONFIRM_APPLY_FOR_ALL | Сохранить для всех | -| MAIN_UI_FILTER__DATE_NEXT_DAYS_LABEL | Следующие #N# (дня/дней) | -| MAIN_UI_FILTER__DATE_PREV_DAYS_LABEL | Последние #N# (дня/дней) | -| MAIN_UI_FILTER__DATE_ERROR_TITLE | Фильтр по этому полю работать не будет. | -| MAIN_UI_FILTER__DATE_ERROR_LABEL | Укажите дату в формате | -| MAIN_UI_FILTER__VALUE_REQUIRED | Поле должно быть заполнено | - - -## Ленивая подгрузка данных +| Параметр | Русское значение | +|:--------------------------------------------|-----------------------------------------------------------------------------------------------------------------------| +| MAIN_UI_FILTER__AND | и | +| MAIN_UI_FILTER__MORE | ещё | +| MAIN_UI_FILTER__BEFORE | Раньше чем | +| MAIN_UI_FILTER__AFTER | Позже чем | +| MAIN_UI_FILTER__NUMBER_MORE | Больше чем | +| MAIN_UI_FILTER__NUMBER_LESS | Меньше чем | +| MAIN_UI_FILTER__PLACEHOLDER_DEFAULT | Фильтр + поиск | +| MAIN_UI_FILTER__PLACEHOLDER_WITH_FILTER | поиск | +| MAIN_UI_FILTER__PLACEHOLDER | Фильтр | +| MAIN_UI_FILTER__PLACEHOLDER_LIMITS_EXCEEDED | Достигнут лимит, подробнее | +| MAIN_UI_FILTER__QUARTER | Квартал | +| MAIN_UI_FILTER__IS_SET_AS_DEFAULT_PRESET | Назначен фильтром по умолчанию | +| MAIN_UI_FILTER__SET_AS_DEFAULT_PRESET | Назначить фильтром по умолчанию | +| MAIN_UI_FILTER__EDIT_PRESET_TITLE | Изменить название фильтра | +| MAIN_UI_FILTER__REMOVE_PRESET | Удалить фильтр | +| MAIN_UI_FILTER__DRAG_TITLE | Потяните, чтобы отсортировать список сохраненных фильтров | +| MAIN_UI_FILTER__DRAG_FIELD_TITLE | Потяните, чтобы отсортировать список полей | +| MAIN_UI_FILTER__REMOVE_FIELD | Скрыть поле | +| MAIN_UI_FILTER__CONFIRM_MESSAGE_FOR_ALL | Это действие сохранит настройки фильтра для всех пользователей.
Будут изменены сохраненные фильтры и набор полей. | +| MAIN_UI_FILTER__CONFIRM_APPLY_FOR_ALL | Сохранить для всех | +| MAIN_UI_FILTER__DATE_NEXT_DAYS_LABEL | Следующие #N# (дня/дней) | +| MAIN_UI_FILTER__DATE_PREV_DAYS_LABEL | Последние #N# (дня/дней) | +| MAIN_UI_FILTER__DATE_ERROR_TITLE | Фильтр по этому полю работать не будет. | +| MAIN_UI_FILTER__DATE_ERROR_LABEL | Укажите дату в формате | +| MAIN_UI_FILTER__VALUE_REQUIRED | Поле должно быть заполнено | + + +## Ленивая загрузка данных Извините - не готово. Предполагается описать структуру конфигурации ленивой погрузки. diff --git "a/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/20_\320\244\320\270\320\273\321\214\321\202\321\200/20_\320\244\320\270\320\273\321\214\321\202\321\200\321\213_\320\277\320\276\320\273\321\214\320\267\320\276\320\262\320\260\321\202\320\265\320\273\321\217.md" "b/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/20_\320\244\320\270\320\273\321\214\321\202\321\200/20_\320\244\320\270\320\273\321\214\321\202\321\200\321\213_\320\277\320\276\320\273\321\214\320\267\320\276\320\262\320\260\321\202\320\265\320\273\321\217.md" index e2f89ed..1814e00 100644 --- "a/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/20_\320\244\320\270\320\273\321\214\321\202\321\200/20_\320\244\320\270\320\273\321\214\321\202\321\200\321\213_\320\277\320\276\320\273\321\214\320\267\320\276\320\262\320\260\321\202\320\265\320\273\321\217.md" +++ "b/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/20_\320\244\320\270\320\273\321\214\321\202\321\200/20_\320\244\320\270\320\273\321\214\321\202\321\200\321\213_\320\277\320\276\320\273\321\214\320\267\320\276\320\262\320\260\321\202\320\265\320\273\321\217.md" @@ -1,10 +1,10 @@ # Работа с фильтрами сотрудника -Как мы уже обсудили, фильтр представляет собой сложную систему из полей, пресетов и выбранных значений, что на практике намного сложнее и неповоротливее чем нам бы хотелось. Если мы зайдем с технической стороны то фильтр состоит из пресетов и все это складывается в так называемую конфигурацию. Конфигурация индивидуальна. +Как мы уже обсудили, фильтр представляет собой сложную систему из полей, пресетов и выбранных значений, что на практике намного сложнее и неповоротливее чем нам бы хотелось. Если мы зайдем с технической стороны, то фильтр состоит из пресетов и все это складывается в так называемую конфигурацию. Конфигурация индивидуальна. ## Конфигурация -Как любая индивидуальная настройка конфигурация фильтра хранится в таблице `b_user_option` с следующими параметрами: +Как любая индивидуальная настройка конфигурация фильтра хранится в таблице `b_user_option` со следующими параметрами: - `CATEGORY = main.ui.filter` (категория всегда фиксирована) - `NAME = ` (`` - идентификатор фильтра) - `VALUE = ` (`` - строка, сериализованная php-методом `serialize` для хранения конфигурации). @@ -14,7 +14,7 @@ Структура состоящая из полей: - `filters` (array) - ассоциативный набор пресетов, - `filter` (string) - идентификатор текущего выбранного фильтра, -- `default` (string) - идентифиватор пресета назначенного по-умолчанию, +- `default` (string) - идентификатор пресета назначенного по-умолчанию, - `default_presets` (array) - ассоциативный набор пресетов по-умолчанию (доступных в системе), - `deleted_presets` (array) - ассоциативный набор ` => true` в котором содержатся перечни исключенных пресетов (из перечня стандартных тех что были удалены). - `use_pin_preset` (bool) - один из флагов отвечающий за закрепление фильтра. @@ -181,7 +181,7 @@ $uiFilter->pinPreset($presetId = "default_filter"); $usedFields = $uiFilter->getUsedFields(); ``` -3. Получить идентификатор/код фильтра по-умолчани или текущего выбранного +3. Получить идентификатор/код фильтра по-умолчанию или текущего выбранного ```php $defaultFilterId = $uiFilter->getDefaultFilterId(); @@ -190,9 +190,9 @@ $currentFilterId = $uiFilter->getCurrentFilterId(); ## Получение фильтра -Продемонстрированный в этой главе фильтр используется исключительно для демонстрационных целей или устаревщих систем. Настоятельно рекомендуется использовать механизм описанный в разделе [Свой фильтр](./Свой_фильтр). +Продемонстрированный в этой главе фильтр используется исключительно для демонстрационных целей или устаревших систем. Настоятельно рекомендуется использовать механизм описанный в разделе [Свой фильтр](./Свой_фильтр). -Поскольку фильтр в своем отображении использует и значения указанные в фильтрации в ui-объекте так же есть методы, которые позволяют преобразовать фильтр из запроса в orm-подобный фильтр. Именно для таких целей и существуют два полезных метода - `getFilter` (для получения фильтра указанных полей) и `getFilterLogic` (преобразование результата `getFilter` в логические значения подготовленные для использовании в `DataManager`). +Поскольку фильтр в своем отображении использует и значения указанные в фильтрации в ui-объекте так же есть методы, которые позволяют преобразовать фильтр из запроса в orm-подобный фильтр. Именно для таких целей и существуют два полезных метода - `getFilter` (для получения фильтра указанных полей) и `getFilterLogic` (преобразование результата `getFilter` в логические значения подготовленные для использования в `DataManager`). Предположим что у нас имеется набор полей фильтра (подробнее в главе "Поля фильтра" из статьи [Обзор](/Разработка/UI/Фильтр/Обзор)) и мы хотим из запроса (REQUEST) получить подготовленный набор. diff --git "a/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/20_\320\244\320\270\320\273\321\214\321\202\321\200/30_\320\237\321\203\320\261\320\273\320\270\321\207\320\275\320\260\321\217_\321\207\320\260\321\201\321\202\321\214.md" "b/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/20_\320\244\320\270\320\273\321\214\321\202\321\200/30_\320\237\321\203\320\261\320\273\320\270\321\207\320\275\320\260\321\217_\321\207\320\260\321\201\321\202\321\214.md" index c7e8fc5..cf736e4 100644 --- "a/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/20_\320\244\320\270\320\273\321\214\321\202\321\200/30_\320\237\321\203\320\261\320\273\320\270\321\207\320\275\320\260\321\217_\321\207\320\260\321\201\321\202\321\214.md" +++ "b/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/20_\320\244\320\270\320\273\321\214\321\202\321\200/30_\320\237\321\203\320\261\320\273\320\270\321\207\320\275\320\260\321\217_\321\207\320\260\321\201\321\202\321\214.md" @@ -10,7 +10,7 @@ ## Работа с фильтром Вся работа начинается с получения объекта фильтра, а поскольку на странице может быть много фильтров, то эта задача выделена объекту `BX.Main.filterManager`, который является объектом-хранилищем объектов фильтра. -Мы не будем расматривать его работу подробно, а остановимся лишь на некоторых его аспектах: +Мы не будем рассматривать его работу подробно, а остановимся лишь на некоторых его аспектах: 1. Получить все зарегистрированные (на момент выполнения кода) фильтры, можно через метод `getList` (`BX.Main.filterManager.getList()`) 2. Получить конкретный фильтр по его идентификатору можно через метод `getById` (`BX.Main.filterManager.getById( )`) @@ -22,7 +22,7 @@ В случае если текущее окно находится в фокусе, выполнение этого кода активирует часть фильтра отвечающего за Поиск и переместит курсор пользователя в него. `filterInstance.getParam( , );` - вернет значение параметра из объекта фильтра. Полный список параметров можно посмотреть в `params`-свойстве (`filterInstance.params`). -Например можно проверить является ли фильтр lazyload (`filterInstance.getParam('LAZY_LOAD')`) +Например, можно проверить является ли фильтр lazyload (`filterInstance.getParam('LAZY_LOAD')`) `filterInstance.resetFilter( );` - сбрасывает значения фильтра. Если ` = true`, поисковая строка (если она была задана) остается, в других случаях полная очистка фильтра. @@ -40,7 +40,7 @@ var namedField = filterInstance.getFieldByName( ); console.log(namedField); ``` -однако для lazyload придется исползовать promise: +однако для lazyload придется использовать promise: ```js filterInstance.getLazyLoadField( ) .then((namedField)=>{ @@ -49,7 +49,7 @@ filterInstance.getLazyLoadField( ) ``` Помните, что данный код является асинхронным, поэтому нужно учесть это в своих разработках. -Мы написали обобщенный асинхронный метод для получения мета-информации о поле и вы можете воспользоваться следующим помошником: +Мы написали обобщенный асинхронный метод для получения мета-информации о поле и вы можете воспользоваться следующим помощником: ```js BX.Main.Filter.prototype.getFieldDesc = function ( fieldName ) @@ -125,7 +125,7 @@ filterInstance.getFieldDesc('SOME_FIELD_NAME').then( В случае если вы знаете идентификатор пресета применить его можно через API методы. -Например для применения пресета `filter_my` можно воспользоваться кодом: +Например, для применения пресета `filter_my` можно воспользоваться кодом: ```js filterInstance.getApi().setFilter({preset_id:'filter_my'}); ```` @@ -143,7 +143,7 @@ filterInstance.getApi().apply(); ## События -Фильтр как и другие публичные элементы Битрикс24 подразумевает наличие полезных событий. На момент написания статьи сам фильтр имеет следующие события: +Фильтр, как и другие публичные элементы Битрикс24 подразумевает наличие полезных событий. На момент написания статьи сам фильтр имеет следующие события: - Показ полей фильтра (`show`) - в момент когда пользователь нажал на поисковую строку, после открытия области изменения фильтра. - Скрытие полей фильтра (`blur`) - в момент когда окно полей фильтра исчезает. - Событие применения фильтра (до применения `beforeApply` и в момент `apply`). @@ -159,7 +159,7 @@ BX.addCustomEvent('BX.Main.Filter:show', function(filterInstance) { }); ``` -Событие применения фильтра (`apply`) удобно использовать при отрисовке своих пользовательских интерфейсов, когда по нажатию нужно перерисовать область на экране: +Событие применения фильтра (`apply`) удобно использовать при разработке своих пользовательских интерфейсов, когда по нажатию нужно перерисовать область на экране: ```js BX.addCustomEvent('BX.Main.Filter:apply', function(filterId, action, filterInstance) { console.log('Submit filter', filterId); diff --git "a/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/20_\320\244\320\270\320\273\321\214\321\202\321\200/40_\320\241\320\262\320\276\320\271_\321\204\320\270\320\273\321\214\321\202\321\200.md" "b/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/20_\320\244\320\270\320\273\321\214\321\202\321\200/40_\320\241\320\262\320\276\320\271_\321\204\320\270\320\273\321\214\321\202\321\200.md" index 4dcbb53..ca0f08f 100644 --- "a/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/20_\320\244\320\270\320\273\321\214\321\202\321\200/40_\320\241\320\262\320\276\320\271_\321\204\320\270\320\273\321\214\321\202\321\200.md" +++ "b/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/20_\320\244\320\270\320\273\321\214\321\202\321\200/40_\320\241\320\262\320\276\320\271_\321\204\320\270\320\273\321\214\321\202\321\200.md" @@ -2,7 +2,7 @@ [TOC] -В разделе [Обзор](./Обзор) мы рассмотрели компонент `bitrix:main.ui.filter`, который отвечает за отрисовку фильтра. Мы обсудили что для работы фильтрации необходимо чтобы были заполнены `FIELDS` и `FILTER_ID` параметры и рассмотрели примеры их заполнения. До этого момента мы обсуждали какие механизмы работаю вокруг фильтра, но не затрагивали работу с самим фильтром. Мы будем использовать некоторые возможности [тулбара](../Тулбар/Основное), поэтому если вы не читали эту статью - самое время. +В разделе [Обзор](./Обзор) мы рассмотрели компонент `bitrix:main.ui.filter`, который отвечает за отображение и работу фильтра. Мы обсудили что для работы фильтрации необходимо чтобы были заполнены `FIELDS` и `FILTER_ID` параметры и рассмотрели примеры их заполнения. До этого момента мы обсуждали какие механизмы работаю вокруг фильтра, но не затрагивали работу с самим фильтром. Мы будем использовать некоторые возможности [тулбара](../Тулбар/Основное), поэтому если вы не читали эту статью - самое время. Представим абстрактную задачу: у нас есть некоторая страница на которой нам нужно нарисовать фильтр и обработать применение этого фильтра. Из полей доступных к фильтрации у нас имеется полный набор: @@ -15,7 +15,7 @@ ## Архитектура фильтра -Сам по себе фильтр это исключительно обретка над так называемыми провайдерами данных, который общаясь с входящими параметрами может доставать указанные в провайдерах данных поля и возвращать их в подготовленном виде. Теперь мы знаем что у нас есть сам объект фильтра и провайдеры данных, которые выполняют роль поставщиков полей. +Сам по себе фильтр это исключительно обертка над так называемыми провайдерами данных, который общаясь с входящими параметрами может доставать указанные в провайдерах данных поля и возвращать их в подготовленном виде. Теперь мы знаем что у нас есть сам объект фильтра и провайдеры данных, которые выполняют роль поставщиков полей. ## Объект фильтра @@ -47,7 +47,7 @@ $myFilter = new Filter( Рассмотрим создание фильтра с использованием фабрики. -Для создания фильтра в фабрике (`\Bitrix\Main\Filter\Factory`) существует статический метод `createEntityFilter` с сигнатурой: +Для создания фильтра у фабрики (`\Bitrix\Main\Filter\Factory`) существует статический метод `createEntityFilter` с сигнатурой: ```php \Bitrix\Main\Filter\Factory::createEntityFilter( $entityTypeName, @@ -128,7 +128,7 @@ class FactoryMain Несмотря на наличие возможности работать с `\Bitrix\Main\Filter\Filter` я рекомендую создавать наследника (пусть даже пустой), по некоторым причинам: 1. Вам проще будет контролировать аргументы ваших функций, когда вы будете зависеть от фильтра. -2. Вы сможете переопределять некоторые методы. Например метод `prepareFilterValue`, т.е. стандартный фильтр плохо работает с диапазонами значений. +2. Вы сможете переопределять некоторые методы. Например, метод `prepareFilterValue`, т.е. стандартный фильтр плохо работает с диапазонами значений. ### Работа с фильтром @@ -143,7 +143,7 @@ class FactoryMain $myFilterFromRequest = $myFilter->getValue(); ``` -После этого в `$myFilterFromRequest` будет находится подготовленный массив к использованию в качестве фильтра `DataManager`-а. +После этого в `$myFilterFromRequest` находится подготовленный массив к использованию в качестве фильтра `DataManager`-а. Помимо `REQUEST` мы так же можем передать массив для обработки явно, например так: diff --git "a/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/30_\320\232\320\275\320\276\320\277\320\272\320\270.md" "b/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/30_\320\232\320\275\320\276\320\277\320\272\320\270.md" index 1fb6c26..0168970 100644 --- "a/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/30_\320\232\320\275\320\276\320\277\320\272\320\270.md" +++ "b/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/30_\320\232\320\275\320\276\320\277\320\272\320\270.md" @@ -2,7 +2,7 @@ [TOC] -В разделе [Тулбар](./Тулбар/Основное) мы немного затрагивали тему работы с кнопками в тулбаре и эта статья должна раскрыть тему шире. Напомню, что мы рассматриваем кнопки в контекте использования их в тулбаре, другие применения UI остаются за рамками этой статьи. +В разделе [Тулбар](./Тулбар/Основное) мы немного затрагивали тему работы с кнопками в тулбаре и эта статья должна раскрыть тему шире. Напомню, что мы рассматриваем кнопки в контексте использования их в тулбаре, другие применения UI остаются за рамками этой статьи. Кнопки добавляются в тулбар статическим `addButton`, который принимает параметры: - `$button` - либо наследник `Bitrix\UI\Buttons\Button` либо массив описывающий кнопку @@ -48,7 +48,7 @@ $button = new Button([ ]); ``` -Более того, многие методы класса и ключи массива имеют схожие названия, поэтому указанные выше фрагменты кода эквивантны следующему: +Более того, многие методы класса и ключи массива имеют схожие названия, поэтому указанные выше фрагменты кода эквивалентны следующему: ```php use \Bitrix\UI\Buttons\Button; @@ -67,7 +67,7 @@ $button = (new Button()) Кнопки перехода имеют обязательный аттрибут `link` - ссылку для перехода. Мы уже использовали ее ранее для демонстрации стилей. -С скриптовыми кнопками гораздо интереснее: их поведение задачается через событие нажатия и в текущем виде можно реализовать несколькими способами (демонстрирую способы в порядке приоритета - каждый следующий перекрывает предыдущий): +Со скриптовыми кнопками гораздо интереснее: их поведение задается через событие нажатия и в текущем виде можно реализовать несколькими способами (демонстрирую способы в порядке приоритета - каждый следующий перекрывает предыдущий): ```php @@ -91,7 +91,7 @@ $button [ Все три примера эквивалентны, все допустимы к использованию, но использовать одновременно все 3 не имеет смысла. Теперь когда мы рассмотрели как навесить обработчик, поговорим о самом обработчике (значении `$myJsAction`). -В действительности обработчик на стороне backend (создание кнопки) представляет из себя объект класса (`\Bitrix\UI\Buttons\JsHandler`), который состоит из названии JS-функции обработчик и опционального контекста выполнения (строка). Вы можете не создавать объект сразу, ведь подобно классу `Button` вы можете передать строку и объект создадут за вас, но контекст обработчику можно присвоить только при самостоятельном создании. +В действительности обработчик на стороне backend (создание кнопки) представляет собой объект класса (`\Bitrix\UI\Buttons\JsHandler`), который состоит из названия JS-функции обработчик и опционального контекста выполнения (строка). Вы можете не создавать объект сразу, ведь подобно классу `Button` вы можете передать строку и объект создадут за вас, но контекст обработчику можно присвоить только при самостоятельном создании. >В данный момент контекст не обрабатывается. Контекст пробрасывается в data-аттрибут, но получить к нему доступ через методы нельзя. @@ -151,7 +151,7 @@ $button = [ ``` Передавая в ключе `icon` значение одной из константы класса `\Bitrix\UI\Buttons\Icon` вы можете установить иконку для своей кнопки. -Однако в классе перечислены не все доступные иконки и существует альтернативный способ задания иконки - вы можете передать css-класс инконки через `classList`: +Однако в классе перечислены не все доступные иконки и существует альтернативный способ задания иконки - вы можете передать css-класс иконки через `classList`: ```php $button = [ @@ -229,7 +229,7 @@ $button = [ ### Больше возможностей -Редко, но иногда при конструировании кнопки стандартных параметров нехватает и появляется необходимость завать дополнительные пользовательские аттрибуты, например `aria`. Сделать это можно получи коллекцию аттрибутов через метод `getAttributeCollection` объекта класса `Button`. Получить объект класса `Bitrix\UI\Buttons\ButtonAttributes` вы можете манипулировать его реальными значениями получить доступ ко всем необходимым вам свойствам. +Редко, но иногда при конструировании кнопки стандартных параметров нехватает и появляется необходимость задавать дополнительные пользовательские аттрибуты, например `aria`. Сделать это можно получи коллекцию аттрибутов через метод `getAttributeCollection` объекта класса `Button`. Получить объект класса `Bitrix\UI\Buttons\ButtonAttributes` вы можете манипулировать его реальными значениями получить доступ ко всем необходимым вам свойствам. ## Полезная литература diff --git "a/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/30_\320\242\320\260\320\261\320\273\320\270\321\206\321\213/00_\320\236\321\201\320\275\320\276\320\262\320\275\320\276\320\265.md" "b/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/30_\320\242\320\260\320\261\320\273\320\270\321\206\321\213/00_\320\236\321\201\320\275\320\276\320\262\320\275\320\276\320\265.md" index faf87bb..0391106 100644 --- "a/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/30_\320\242\320\260\320\261\320\273\320\270\321\206\321\213/00_\320\236\321\201\320\275\320\276\320\262\320\275\320\276\320\265.md" +++ "b/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/30_\320\242\320\260\320\261\320\273\320\270\321\206\321\213/00_\320\236\321\201\320\275\320\276\320\262\320\275\320\276\320\265.md" @@ -1,12 +1,12 @@ # Табличное представление -Подобно [фильтрам](./../Фильтр/О_модуле) в продукте существует возможность табличного вывода данных, такая возможность называется "табличный вывод", "грид", "grid". +Подобно [фильтрам](./../20_Фильтр/00_О_модуле) в продукте существует возможность табличного вывода данных, такая возможность называется "табличный вывод", "грид", "grid". Этот раздел показывает как применять стандартные технологии для обеспечения табличного вывода в своих разработках. Для упрощения раздела мы будем рассматривать эту возможность с разных сторон: -1. [Обзор компонента `bitrix:main.ui.grid`](./Обзор) -2. [Работа с гридом пользователя](./Персональные_настройки) -3. [Работа с компонентом в публичной части](./Публичная_часть) +1. [Обзор компонента `bitrix:main.ui.grid`](./10_Обзор) +2. [Работа с гридом пользователя](./20_Персональные_настройки) +3. [Работа с компонентом в публичной части](./30_Публичная_часть) ## Полезные ссылки diff --git "a/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/30_\320\242\320\260\320\261\320\273\320\270\321\206\321\213/10_\320\236\320\261\320\267\320\276\321\200.md" "b/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/30_\320\242\320\260\320\261\320\273\320\270\321\206\321\213/10_\320\236\320\261\320\267\320\276\321\200.md" index 4a91918..e0275df 100644 --- "a/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/30_\320\242\320\260\320\261\320\273\320\270\321\206\321\213/10_\320\236\320\261\320\267\320\276\321\200.md" +++ "b/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/30_\320\242\320\260\320\261\320\273\320\270\321\206\321\213/10_\320\236\320\261\320\267\320\276\321\200.md" @@ -14,61 +14,61 @@ Обязательные параметры компонента: -| Параметр | Описание | -| :------- | -------- | -| `GRID_ID` (string) | Идентификатор грида | +| Параметр | Описание | +|:------------------------------|-------------------------------------------------------------------| +| `GRID_ID` (string) | Идентификатор грида | | `HEADERS` / `COLUMNS` (array) | Набор мета-описаний столбцов. Подробнее в главе Описание столбцов | -| `ROWS` (array) | Набор данных для отображения строк. Подробнее в главе Строки | +| `ROWS` (array) | Набор данных для отображения строк. Подробнее в главе Строки | Другие параметры компонента: -| Параметр | Описание | -| :------- | -------- | -| `TOTAL_ROWS_COUNT` (int) | Число, которое используется для отображения общего количества записей. См. примечание для поля `FOOTER` | -| `AJAX_ID` (string) | Уникальный идентификатор грида. Обычно генерируется через код `\CAjax::GetComponentID('bitrix:main.ui.grid', '', '')` | -| `NAV_PARAM_NAME` (string) | Символьный код параметра, отвечающего за наличие в url номера страницы для постраничной навигации | -| `CURRENT_PAGE` (int) | Номер текущей страницы (используется для постраничной навигации) | -| `NAV_STRING` (string) | HTML фрагмент, отрисованной постраничной навигации. Один из параметров, который может быть передан в комплексном поле `FOOTER` (см. примечание этого поля) или вычислен на основании параметров навигации (см. параметры навигации) | -| `ACTIONS_LIST` (array) | Набор действий, доступных для отображения в гриде. Подробнее в [Панель действий](./Панель_действий) | -| `PAGE_SIZES` (array) | Набор значений, используемых для вывода допустимых размеров постраничной навигации. Состоит из структур вида: `['NAME' => "5", 'VALUE' => '5'],`| -| `DEFAULT_PAGE_SIZE` (int) | Количество строк, отображаемых на странице. По-умолчанию: 20 | -| `ALLOW_INLINE_EDIT` (bool) | Разрешить редактирование на странице. Алиас для значения `EDITABLE` | -| `SHOW_ROW_ACTIONS_MENU` (bool) | Отображать кнопку действия над строками. Алиас для значения `ROW_ACTIONS`| -| `SHOW_ROW_CHECKBOXES` (bool) | Отображать чек-боксы для строк | -| `SHOW_NAVIGATION_PANEL` (bool) | Отображать навигационную панель | -| `ALLOW_GROUP_ACTIONS` (bool) | Отображать панель групповых действий. Алиас для `ACTION_ALL_ROWS` | -| `SHOW_CHECK_ALL_CHECKBOXES` (bool) | Отображать чек-бокс для выбор всех элементов | -| `ALLOW_CONTEXT_MENU` (bool) | Включить поведение отображения контекстного меню для строки, по клику правой кнопкой мышки | -| `SHOW_GRID_SETTINGS_MENU` (bool) | Отображать шестеренку с возможностью конфигурировать грид | -| `SHOW_MORE_BUTTON` (bool) | Отображать кнопку "Загрузить еще" | -| `SHOW_PAGINATION` (bool) | Отображать постраничную навигацию | -| `SHOW_PAGESIZE` (bool) | Отображать переключатель количества строк на странице | -| `SHOW_SELECTED_COUNTER` (bool) | Отображать количество выделенных элементов на странице | -| `SHOW_TOTAL_COUNTER` (bool) | Отображать количество элементов на странице | -| `TOTAL_ROWS_COUNT_HTML` (string) | HTML для отображения количества элементов. Подробнее в главе "Количество строк" | -| `ALLOW_COLUMNS_SORT` (bool) | Разрешить менять столбцы местами | -| `ALLOW_ROWS_SORT` (bool) | Разрешить менять местами строки.| -| `ALLOW_ROWS_SORT_IN_EDIT_MODE` (bool) | Разрешить менять местами строки в режиме редактирования.| -| `ALLOW_ROWS_SORT_INSTANT_SAVE` (bool) | Немедленное сохранение при изменении порядка.| -| `ALLOW_HORIZONTAL_SCROLL` (bool) | Разрешить горизонтальную прокрутку таблицы | -| `ALLOW_PIN_HEADER` (bool) | Разрешает закреплять панель с заголовками вверху таблицы при вертикальной прокрутке | -| `ALLOW_SORT` (bool) | Разрешить пользователям изменять сортировку данных по тем столбцам, которые разрешены для изменения сортировки. Персональная настройка. | -| `ALLOW_COLUMNS_RESIZE` (bool) | Разрешить пользователям изменять ширину столбцов, для тех столбцов у которых резрешено растягивание. Персональная настройка. Алиас для `ALLOW_COLUMN_RESIZE`| -| `COLS_RESIZE_META` (array) | Структура описывающая ширину строк | -| `ENABLE_FIELDS_SEARCH` (char) | В случае если содержится значение `Y`, в списоке столбцов доступен поиск | -| `SHOW_ACTION_PANEL` (bool) | Нужно ли отображать панель действий | -| `ENABLE_COLLAPSIBLE_ROWS` (bool) | Разрешить сворачивание (схлопывание) строк. Подробнее в главе Сворачивание строк | -| `TOP_ACTION_PANEL_RENDER_TO` (string) | Идентификат DOM-элемента, куда будет осущствляться отрисовка панели действий | -| `TOP_ACTION_PANEL_PINNED_MODE` (bool) | В случае `true` прикрепляет панель действий к ноде | -| `TOP_ACTION_PANEL_CLASS` (string) | Дополнительный класс к панели действий | -| `ADVANCED_EDIT_MODE` (bool) | Один из флагов отвечающий за возможность редактировать строки. Либо должен быть установлен флаг, либо в списке должен присутствовать хотя бы одна строка с признаком редактируемой. | -| `ALLOW_EDIT_SELECTION` (bool) | Если установлен, добавляет чек-боксы к строкам и разрешает выбирать строки | -| `ALLOW_STICKED_COLUMNS` (bool) | Если установлен в `true`, разрешает "липучие" колонки - зафиксированные при горизонтальной прокрутке. | -| `SETTINGS_WINDOW_TITLE` (string) | Строка, отвечающая за название попапа формы настроек | -| `HIDE_TOP_BORDER_RADIUS` (bool) | Если установлен, скрывает округление верхней части таблицы| -| `HIDE_BOTTOM_BORDER_RADIUS` (bool) | Если установлен, скрывает округление нижней части таблицы | -| `ACTIONS` (array) | Набор действий, который на момент описания включает в себя структуру вида `["list" => ]`, где `` - содержимое `ACTIONS_LIST`| -| `FOOTER` (array) | Опциональный параметр, который используется для логической группировки параметров `TOTAL_ROWS_COUNT` и `NAV_STRING`. Это значит, что указанные параметры можно передавать как явно в параметрах компонента, так и через массив используя ключ `FOOTER` | +| Параметр | Описание | +|:--------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `TOTAL_ROWS_COUNT` (int) | Число, которое используется для отображения общего количества записей. См. примечание для поля `FOOTER` | +| `AJAX_ID` (string) | Уникальный идентификатор грида. Обычно генерируется через код `\CAjax::GetComponentID('bitrix:main.ui.grid', '', '')` | +| `NAV_PARAM_NAME` (string) | Символьный код параметра, отвечающего за наличие в url номера страницы для постраничной навигации | +| `CURRENT_PAGE` (int) | Номер текущей страницы (используется для постраничной навигации) | +| `NAV_STRING` (string) | HTML фрагмент постраничной навигации. Один из параметров, который может быть передан в комплексном поле `FOOTER` (см. примечание этого поля) или вычислен на основании параметров навигации (см. параметры навигации) | +| `ACTIONS_LIST` (array) | Набор действий, доступных для отображения в гриде. Подробнее в [Панель действий](./Панель_действий) | +| `PAGE_SIZES` (array) | Набор значений, используемых для вывода допустимых размеров постраничной навигации. Состоит из структур вида: `['NAME' => "5", 'VALUE' => '5'],` | +| `DEFAULT_PAGE_SIZE` (int) | Количество строк, отображаемых на странице. По-умолчанию: 20 | +| `ALLOW_INLINE_EDIT` (bool) | Разрешить редактирование на странице. Алиас для значения `EDITABLE` | +| `SHOW_ROW_ACTIONS_MENU` (bool) | Отображать кнопку действия над строками. Алиас для значения `ROW_ACTIONS` | +| `SHOW_ROW_CHECKBOXES` (bool) | Отображать чек-боксы для строк | +| `SHOW_NAVIGATION_PANEL` (bool) | Отображать навигационную панель | +| `ALLOW_GROUP_ACTIONS` (bool) | Отображать панель групповых действий. Алиас для `ACTION_ALL_ROWS` | +| `SHOW_CHECK_ALL_CHECKBOXES` (bool) | Отображать чек-бокс для выбор всех элементов | +| `ALLOW_CONTEXT_MENU` (bool) | Включить поведение отображения контекстного меню для строки, по клику правой кнопкой мышки | +| `SHOW_GRID_SETTINGS_MENU` (bool) | Отображать шестеренку с возможностью конфигурировать грид | +| `SHOW_MORE_BUTTON` (bool) | Отображать кнопку "Загрузить еще" | +| `SHOW_PAGINATION` (bool) | Отображать постраничную навигацию | +| `SHOW_PAGESIZE` (bool) | Отображать переключатель количества строк на странице | +| `SHOW_SELECTED_COUNTER` (bool) | Отображать количество выделенных элементов на странице | +| `SHOW_TOTAL_COUNTER` (bool) | Отображать количество элементов на странице | +| `TOTAL_ROWS_COUNT_HTML` (string) | HTML для отображения количества элементов. Подробнее в главе "Количество строк" | +| `ALLOW_COLUMNS_SORT` (bool) | Разрешить менять столбцы местами | +| `ALLOW_ROWS_SORT` (bool) | Разрешить менять местами строки. | +| `ALLOW_ROWS_SORT_IN_EDIT_MODE` (bool) | Разрешить менять местами строки в режиме редактирования. | +| `ALLOW_ROWS_SORT_INSTANT_SAVE` (bool) | Немедленное сохранение при изменении порядка. | +| `ALLOW_HORIZONTAL_SCROLL` (bool) | Разрешить горизонтальную прокрутку таблицы | +| `ALLOW_PIN_HEADER` (bool) | Разрешает закреплять панель с заголовками вверху таблицы при вертикальной прокрутке | +| `ALLOW_SORT` (bool) | Разрешить пользователям изменять сортировку данных по тем столбцам, которые разрешены для изменения сортировки. Персональная настройка. | +| `ALLOW_COLUMNS_RESIZE` (bool) | Разрешить пользователям изменять ширину столбцов, для тех столбцов у которых разрешено растягивание. Персональная настройка. Алиас для `ALLOW_COLUMN_RESIZE` | +| `COLS_RESIZE_META` (array) | Структура описывающая ширину строк | +| `ENABLE_FIELDS_SEARCH` (char) | В случае если содержится значение `Y`, в списке столбцов доступен поиск | +| `SHOW_ACTION_PANEL` (bool) | Нужно ли отображать панель действий | +| `ENABLE_COLLAPSIBLE_ROWS` (bool) | Разрешить сворачивание (схлопывание) строк. Подробнее в главе Сворачивание строк | +| `TOP_ACTION_PANEL_RENDER_TO` (string) | Идентификатор DOM-элемента, куда будет осуществляться отрисовка панели действий | +| `TOP_ACTION_PANEL_PINNED_MODE` (bool) | В случае `true` прикрепляет панель действий к указанной DOM Node | +| `TOP_ACTION_PANEL_CLASS` (string) | Дополнительный класс к панели действий | +| `ADVANCED_EDIT_MODE` (bool) | Один из флагов отвечающий за возможность редактировать строки. Либо должен быть установлен флаг, либо в списке должен присутствовать хотя бы одна строка с признаком редактируемой. | +| `ALLOW_EDIT_SELECTION` (bool) | Если установлен, добавляет чек-боксы к строкам и разрешает выбирать строки | +| `ALLOW_STICKED_COLUMNS` (bool) | Если установлен в `true`, разрешает "липучие" колонки - зафиксированные при горизонтальной прокрутке. | +| `SETTINGS_WINDOW_TITLE` (string) | Строка, отвечающая за название поп-апа формы настроек | +| `HIDE_TOP_BORDER_RADIUS` (bool) | Если установлен, скрывает округление верхней части таблицы | +| `HIDE_BOTTOM_BORDER_RADIUS` (bool) | Если установлен, скрывает округление нижней части таблицы | +| `ACTIONS` (array) | Набор действий, который на момент описания включает в себя структуру вида `["list" => ]`, где `` - содержимое `ACTIONS_LIST` | +| `FOOTER` (array) | Опциональный параметр, который используется для логической группировки параметров `TOTAL_ROWS_COUNT` и `NAV_STRING`. Это значит, что указанные параметры можно передавать как явно в параметрах компонента, так и через массив используя ключ `FOOTER` | >Не обязательно указывать все ключи, многие из них имеют поведения по-умолчанию или перекрываются другими комбинациями ключей @@ -96,46 +96,46 @@ $APPLICATION->IncludeComponent( Минимальный рекомендуемый набор полей для описания столбцов грида: -| Параметр | Описание | -| :------- | -------- | -| `id` (string) | Уникальный идентификатор строки | -| `name` (string) | Отображаемое название столбца | -| `sort` (string) | Идентификатор поля, по которому должна производиться сортировка | +| Параметр | Описание | +|:-------------------|------------------------------------------------------------------------------------------------------| +| `id` (string) | Уникальный идентификатор строки | +| `name` (string) | Отображаемое название столбца | +| `sort` (string) | Идентификатор поля, по которому должна производиться сортировка | | `default` (bool) | Определяет должна ли отображаться колонка по умолчанию в гриде. По умолчанию колонки не отображаются | Дополнительные параметры, которые так же могут быть полезны к использованию: -| Параметр | Описание | -| :------- | -------- | -| `first_order` (string) | Направление первой сортировки колонки. Возможные значения: `asc` или `desc` | -| `align` (string) | Выравнивание содержимого столбцов. Допустимы `center`, `left`, `right`, `justify` | -| `title` (string) | Текст подсказки, возникающей при наведении на заголовок столбца | -| `showname` (char) | В случае если значение `N` - название столбца не будет отображаться | -| `class` (string) | Строка с дополнительными css-классами | -| `width` (int) | Ширина столбца в пикселях | -| `editable` (bool) | Разрешено ли редактировать строчку на странице | -| `type` (string) | Тип данных, содержащихся в строке (доступные типы в `/modules/main/lib/grid/types.php`) | -| `prevent_default` (bool) | Отменяет выделение строки при клике на ячейку колонки. Может быть полезно, когда в ячейку выводится какой-то интерактивный контент. | -| `sticked` (bool) | Закрепляет колонку слева, при горизонтальной прокрутке. | -| `color` (sring) | В случае если значение начинается с `#`, `rgb` или `hsl` будет добавлено как css-свойство `background-color` к ячейке, в других случаях как часть класса | -| `iconUrl` (string) | URL-ссылка на иконку | -| `iconTitle` (string) | Текст, отображаемый при наведении на иконку | -| `section_id` (string) | Код раздела, для группировки полей в окне выбора отображаемых полей | -| `hint` (string) | Текст подсказки, возникающей при наведении на значок ? в заголовке столбца таблицы | -| `hintInteractivity` (bool) | если true, то с подсказкой можно взаимодействовать (выделять текст, нажимать кнопки) | -| `hintHtml` (bool) | Если `true`, то текст подсказки интерпретируется как html | +| Параметр | Описание | +|:---------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------| +| `first_order` (string) | Направление первой сортировки колонки. Возможные значения: `asc` или `desc` | +| `align` (string) | Выравнивание содержимого столбцов. Допустимы `center`, `left`, `right`, `justify` | +| `title` (string) | Текст подсказки, возникающей при наведении на заголовок столбца | +| `showname` (char) | В случае если значение `N` - название столбца не будет отображаться | +| `class` (string) | Строка с дополнительными css-классами | +| `width` (int) | Ширина столбца в пикселях | +| `editable` (bool) | Разрешено ли редактировать строчку на странице | +| `type` (string) | Тип данных, содержащихся в строке (доступные типы в `/modules/main/lib/grid/types.php`) | +| `prevent_default` (bool) | Отменяет выделение строки при клике на ячейку колонки. Может быть полезно, когда в ячейку выводится какой-то интерактивный контент. | +| `sticked` (bool) | Закрепляет колонку слева, при горизонтальной прокрутке. | +| `color` (string) | В случае если значение начинается с `#`, `rgb` или `hsl` будет добавлено как css-свойство `background-color` к ячейке, в других случаях как часть класса | +| `iconUrl` (string) | URL-ссылка на иконку | +| `iconTitle` (string) | Текст, отображаемый при наведении на иконку | +| `section_id` (string) | Код раздела, для группировки полей в окне выбора отображаемых полей | +| `hint` (string) | Текст подсказки, возникающей при наведении на значок ? в заголовке столбца таблицы | +| `hintInteractivity` (bool) | если true, то с подсказкой можно взаимодействовать (выделять текст, нажимать кнопки) | +| `hintHtml` (bool) | Если `true`, то текст подсказки интерпретируется как html | ### Описание строк Строки грида формируются как набор структур с параметрами: -| Параметр | Описание | -| :------- | -------- | -| `id` (string) | Уникальный идентификатор строки | -| `columns` (array) | Ассоциативный список Колонка => Отображаемое значение | -| `data` (array) | Данные для инлайн-редактирования. Например, если в columns мы можем передать данные для ячейки в том виде, в котором они должны отобразиться, то в data мы можем передать исходные данные которые нужны для редактирования. | -| `editableColumns` (array) | Определяет редактируемость ячеек колонки на уровне строки. Например, если колонка редактируемая, но для конкретной строки нужно запретить редактирование ячейки этой колонки, то в editableColumns можно указать идентификатор колонки со значением false. | -| `actions` (array) | Определяет действия над строкой. | +| Параметр | Описание | +|:--------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `id` (string) | Уникальный идентификатор строки | +| `columns` (array) | Ассоциативный список Колонка => Отображаемое значение | +| `data` (array) | Данные для инлайн-редактирования. Например, если в columns мы можем передать данные для ячейки в том виде, в котором они должны отобразиться, то в data мы можем передать исходные данные которые нужны для редактирования. | +| `editableColumns` (array) | Определяет возможности редактирования ячеек колонки на уровне строки. Например, если колонка редактируемая, но для конкретной строки нужно запретить редактирование ячейки этой колонки, то в editableColumns можно указать идентификатор колонки со значением false. | +| `actions` (array) | Определяет действия над строкой. | Пример описания строки: ```php @@ -167,19 +167,19 @@ $APPLICATION->IncludeComponent( ### Параметры навигации Существует несколько способов отобразить стандартную постраничную навигацию: -1. Передача строки с отрисованной постраничной навигацией через параметр компонента `NAV_STRING` +1. Передача строки с готовой версткой постраничной навигацией через параметр компонента `NAV_STRING` 2. Передача объекта `NAV_OBJECT` (наследника `\Bitrix\Main\UI\PageNavigation`) 3. Передача объекта `NAV_OBJECT` (наследника `CDBResult`). Навигация будет осуществляться через метод `GetPageNavStringEx` с учетом параметров компонента из `~NAV_PARAMS` -Дополнительно существует возможность использовать "ленивую подгрузку" - на страницу загружается лишь то количество элементов, которое нужно при первоначальной орисовки. -Затем, в случае наличия следующих страниц, отрисовывается кнопка для подгрузки следующих. Для работы необходимо передавать следующие параметры компонента: +Дополнительно существует возможность использовать "ленивую загрузку" - на страницу загружается лишь то количество элементов, которое нужно при первоначальной отрисовки. +Затем, в случае наличия следующих страниц, выводится кнопка для загрузки следующих. Для работы необходимо передавать следующие параметры компонента: -- `SHOW_MORE_BUTTON` (bool) - `true`, в случае, если хотите использовать кнопку ленивой подгрузки +- `SHOW_MORE_BUTTON` (bool) - `true`, в случае, если хотите использовать кнопку ленивой загрузки - `ENABLE_NEXT_PAGE` (bool) - `true`, в случае если присутствуют другие страницы - `NAV_PARAM_NAME` (string) - название параметра, используемого для хранения номера страницы - `CURRENT_PAGE` (int) - номер текущей страницы ->Ленивая подгрузка не отменяет действия постраничной навигации - их можно использовать одновременно +>Ленивая загрузка не отменяет действия постраничной навигации - их можно использовать одновременно ### Количество строк @@ -189,13 +189,13 @@ $APPLICATION->IncludeComponent( С одной стороны, можно указать параметр `TOTAL_ROWS_COUNT` - число, которое будет отображаться как количество записей. Но не всегда есть возможность посчитать количество элементов, доступных по фильтру и отобразить - иногда эта операция является трудозатратной. -Для рализации ленивой подгрузки данных, можно воспользоваться произвольным HTML-кодом, который бы в фоновом режиме опрашивал источник и подсчитывал значения или делал это по требованию пользователя. +Для реализации ленивой загрузки данных, можно воспользоваться произвольным HTML-кодом, который бы в фоновом режиме опрашивал источник и подсчитывал значения или делал это по требованию пользователя. Такой html можно установить через параметр компонента - `TOTAL_ROWS_COUNT_HTML`. ### Сворачивание строк -При наличии опции `ENABLE_COLLAPSIBLE_ROWS` компонент допускает сворачивание строк (вложнные строки), однако на практике работа с подобными строками вызывает большие сложности в постраничной навигации. Мы рекомендуем избегать этой возможности и использовать другие механизмы (например используя [aclips/bitrix-ui.ui-grid-collapse](https://github.com/aclips/bitrix-ui.ui-grid-collapse)), поэтому в данной главе мы будем рассматривать исключительно в ознакомительных целях. +При наличии опции `ENABLE_COLLAPSIBLE_ROWS` компонент допускает сворачивание строк (вложенные строки), однако на практике работа с подобными строками вызывает большие сложности в постраничной навигации. Мы рекомендуем избегать этой возможности и использовать другие механизмы (например используя [aclips/bitrix-ui.ui-grid-collapse](https://github.com/aclips/bitrix-ui.ui-grid-collapse)), поэтому в данной главе мы будем рассматривать исключительно в ознакомительных целях. Технически, строки таблицы являются набором (перечислением строк), не имеющим явной иерархии, поэтому выстраивать последовательность необходимо самостоятельно на основе порядка следования родительских разделов. Для этого к каждой родительской строке добавляются аттрибуты: @@ -205,7 +205,7 @@ $APPLICATION->IncludeComponent( К каждой дочерней строке добавляются параметры: - `shift` (bool) - наличие сдвига у строки -- `depth` (int) - глубина сдвига (в единицах). Величина сдвига будет расчитана как 20px умноженное на глубину сдвига +- `depth` (int) - глубина сдвига (в единицах). Величина сдвига будет рассчитана как 20px умноженное на глубину сдвига - `parent_id` (string) - идентификатор строки родителя ## Пример компонента diff --git "a/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/30_\320\242\320\260\320\261\320\273\320\270\321\206\321\213/17_\320\237\320\260\320\275\320\265\320\273\321\214_\320\264\320\265\320\271\321\201\321\202\320\262\320\270\320\271.md" "b/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/30_\320\242\320\260\320\261\320\273\320\270\321\206\321\213/17_\320\237\320\260\320\275\320\265\320\273\321\214_\320\264\320\265\320\271\321\201\321\202\320\262\320\270\320\271.md" index 4893f63..699edf1 100644 --- "a/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/30_\320\242\320\260\320\261\320\273\320\270\321\206\321\213/17_\320\237\320\260\320\275\320\265\320\273\321\214_\320\264\320\265\320\271\321\201\321\202\320\262\320\270\320\271.md" +++ "b/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/30_\320\242\320\260\320\261\320\273\320\270\321\206\321\213/17_\320\237\320\260\320\275\320\265\320\273\321\214_\320\264\320\265\320\271\321\201\321\202\320\262\320\270\320\271.md" @@ -1,6 +1,6 @@ # Панель действий -В настоящий момент продукт имеет 2 вида панели: первый (классический) - структура передаеваемая в ключе `ACTION_PANEL`, вторая - JS действия на основе расширения `ui.actionpanel` (можно увидеть в канбан представлении). В текущей статье мы будем рассматривать панель действий в классическом представлении. +В настоящий момент продукт имеет 2 вида панели: первый (классический) - структура передаваемая в ключе `ACTION_PANEL`, вторая - JS действия на основе расширения `ui.actionpanel` (можно увидеть в канбан представлении). В текущей статье мы будем рассматривать панель действий в классическом представлении. Панель действий инструмент для проведения групповых операций. @@ -17,7 +17,7 @@ ``` В свою очередь каждая группа это набор из двух параметров: -- `CLASS` (string) - строка которая добавляется `class`-аттрибут ячейки действия +- `CLASS` (string) - строка, которая добавляется `class`-аттрибут ячейки действия - `ITEMS` (array) - список элементов группы @@ -48,12 +48,12 @@ # Элемент группы -Мы уже обсудили, что каждя группа состоит набора элементов, а из чего состоит элемент? Технически элемент представляет из себя ассоциативный массив и каждый такой массив содержит набор обязательных полей (в числе которых - тип элемента) и набор уникальных полей для каждого типа элемента. +Мы уже обсудили, что каждая группа состоит набора элементов, а из чего состоит элемент? Технически элемент представляет собой ассоциативный массив и каждый такой массив содержит набор обязательных полей (в числе которых - тип элемента) и набор уникальных полей для каждого типа элемента. Обязательные поля: - `ID` (string) - уникальный идентификатор действия. По совместительству идентификатор dom node с управляющим элементом. - `TYPE` (enum) - тип поля (см. ниже допустимые типы полей) -- `VALUE` (mixed) - значение контрола +- `VALUE` (mixed) - значение Опциональные поля: - `DISABLED` (bool) - Состояние элемента (false по-умолчанию) @@ -175,24 +175,24 @@ Сами по себе элементы не представляют особого интереса - важную часть составляют именно обработчики действия изменения, которые оказывают влияние на всю панель выполняя определенные операции. -Строго говоря, название `ONCHANGE` немного вводит в заблуждение - в HTML есть событие `change` и одноименный html-аттрибут `onchange`, который имеет мало общего в представленным в панеле механизме. Рассматривая `ONCHANGE` ключ нужно помнить что это набор операций, выполняемых друг за другом. +Строго говоря, название `ONCHANGE` немного вводит в заблуждение - в HTML есть событие `change` и одноименный html-аттрибут `onchange`, который имеет мало общего в представленном механизме. Рассматривая `ONCHANGE` ключ нужно помнить что это набор операций, выполняемых друг за другом. Каждая операция состоит из двух обязательных параметров: -- `ACTION` (enum) - один из видов действия над панелью, указывающий что именно необходимо сделать. +- `ACTION` (enum) - один из видов действия над панелью описывающий поведение. - `DATA` (array) - дополнительная информация, которая зависит от действия >Существуют и другие, но об этом позже в `CALLBACK` Допустимые действия описаны константами класса `\Bitrix\Main\Grid\Panel\Actions`: -- Создание элементов (`CREATE`) - добавляет новые элементы в текующую группу. `DATА` - набор описаний элементовю +- Создание элементов (`CREATE`) - добавляет новые элементы в текущую группу. `DATА` - набор описаний элементов. - Активация (`ACTIVATE`) - делает элемент доступным для взаимодействия. `DATA` - идентификаторы элементов. - Показ и сокрытие (`SHOW` / `HIDE`) - скрывает/показывает элементы в группе. `DATA` - идентификаторы элементов. - Скрыть все, кроме (`HIDE_ALL_EXPECT`) - скрывает все элементы кроме перечисленных. `DATA` - идентификаторы элементов. - Показать все (`SHOW_ALL`) - показывает все элементы в группе - Удаление (`REMOVE`) - удаляет элементы в группе. `DATA` - идентификаторы элементов -- Колбек (`CALLBACK`) - выполняет произвольный javascript код +- Функция-обработчик (`CALLBACK`) - выполняет произвольный javascript код ### Комплексный пример @@ -294,13 +294,13 @@ - Удаляет элементы (себя и кнопку отменить, добавленные родительской кнопкой) ->Посмотрите класс со сниппетами чтобы найти больше интересных и разнообразных примеров. +>Посмотрите класс со сниппетами, чтобы найти больше интересных и разнообразных примеров. -### Колбек +### Функция-обработчик Самый большой интерес производит для нас выполнение собственного произвольного javascript кода, но тут все не так уж и однозначно. Во-первых, javascript код не исполняется сразу - в зависимости от настроек может быть отображен системный диалог подтверждения действия. -Во-вторых, по сути это не один скрипт, а последовательность скриптов, где падение одного прервет цепочку выполнения выполнения. +Во-вторых, по сути это не один скрипт, а последовательность скриптов, где падение одного прервет цепочку выполнения. В самой минимальной версии код выглядит так (пример взят из примера выше): ```php @@ -333,7 +333,7 @@ ## Сниппеты -Иногда, собирать вручную стандартные кнопки (Применить, Сохранить, Удалить, Отменить) и другие управляющие элементы (чек-бокс 'Для всех') становится довольно скучным и однообразным занятием. На такой случай в системе предусмотрен класс с сниппетами (`Bitrix\Main\Grid\Panel\Snippet`), который содержит уже реализованные типовые элементы. +Иногда, собирать вручную стандартные кнопки (Применить, Сохранить, Удалить, Отменить) и другие управляющие элементы (чек-бокс 'Для всех') становится довольно скучным и однообразным занятием. На такой случай в системе предусмотрен класс со сниппетами (`Bitrix\Main\Grid\Panel\Snippet`), который содержит уже реализованные типовые элементы. Пример получения типовых элементов: diff --git "a/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/30_\320\242\320\260\320\261\320\273\320\270\321\206\321\213/20_\320\237\320\265\321\200\321\201\320\276\320\275\320\260\320\273\321\214\320\275\321\213\320\265_\320\275\320\260\321\201\321\202\321\200\320\276\320\271\320\272\320\270.md" "b/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/30_\320\242\320\260\320\261\320\273\320\270\321\206\321\213/20_\320\237\320\265\321\200\321\201\320\276\320\275\320\260\320\273\321\214\320\275\321\213\320\265_\320\275\320\260\321\201\321\202\321\200\320\276\320\271\320\272\320\270.md" index 7f7a6cf..df9c4b6 100644 --- "a/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/30_\320\242\320\260\320\261\320\273\320\270\321\206\321\213/20_\320\237\320\265\321\200\321\201\320\276\320\275\320\260\320\273\321\214\320\275\321\213\320\265_\320\275\320\260\321\201\321\202\321\200\320\276\320\271\320\272\320\270.md" +++ "b/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/30_\320\242\320\260\320\261\320\273\320\270\321\206\321\213/20_\320\237\320\265\321\200\321\201\320\276\320\275\320\260\320\273\321\214\320\275\321\213\320\265_\320\275\320\260\321\201\321\202\321\200\320\276\320\271\320\272\320\270.md" @@ -2,7 +2,7 @@ Подобно фильтрам табличное отображение так же зависит от настроек пользователя и является индивидуальным. -Работа с гридами начинается с создания объекта настроек `Bitrix\Main\Grid\Options` (ранее `\CGridOptions`, сейчас новый класс его наследник), который в последних редакциях, для своей работы требует только идентификатор грида с которым будет осуществляться работа. +Работа с гридами начинается с создания объекта настроек `Bitrix\Main\Grid\Options` (ранее `\CGridOptions`), который требует только идентификатор грида с которым будет осуществляться работа. ```php use \Bitrix\Main\Grid\Options; @@ -24,10 +24,10 @@ $gridOptions = new Options('MY_UNIQUE_GRID_ID'); Для организации быстродействия, зачастую бывает полезно получать не всю информацию для отображения таблицы, а только ту, которую пользователь реально запросил. ->Случай 1: на одном проекте у нас была большая таблица с списком заявок, помимо полей самой заявки дополнительно фигурировали 2 столбца: Время реакции (вычисляемое поле между двумя значениями заявки) и Связанные заявки (перечень ссылок на заявки, доступные текущему пользователю). На вывод и вычисление этих столбцов требовалось огромное количество времени (до 60% от времени создания самого грида), однако вывод самих столбцов пользовался популярностью у малой группы сотрудников (меньше 1%). Просчет таких столбцов только для сотрудников, которым он был необходим дал значительный прирост производительности для остальных +>Случай 1: на одном проекте у нас была большая таблица со списком заявок, помимо полей самой заявки дополнительно фигурировали 2 столбца: Время реакции (вычисляемое поле между двумя значениями заявки) и Связанные заявки (перечень ссылок на заявки, доступные текущему пользователю). На вывод и вычисление этих столбцов требовалось огромное количество времени (до 60% от времени создания самого грида), однако вывод самих столбцов пользовался популярностью у малой группы сотрудников (меньше 1%). Просчет таких столбцов только для сотрудников, которым он был необходим, дал значительный прирост производительности для остальных ->Случай 2: В одном из проекте клиент запросил экспорта табличного представления идентичному табличному. Т.е. последовательность и наличие столбцов должна была быть такая же как пользователь видит на экране. +>Случай 2: В одном из проектов клиент запросил экспорта табличного представления идентичному табличному. Т.е. последовательность и наличие столбцов должна была быть такая же, как пользователь видит на экране. Такая возможность обеспечивается нестатическим методом `getUsedColumns( $defaultColumns = [] )` который вернет набор используемых столбцов (если у пользователя есть личный пресет), либо набор переданный аргументом в метод. @@ -47,9 +47,9 @@ $defaulColumns = $gridOptions->getUsedColumns([ ### Просчитать сортировку -Не смотря на то, что мы будем обсуждать метод `GetSorting($arParams=array())` (дословно - Получить сортировку), правильнее назвать это методом просчета сортировки, так как для получения результата будут учтены входящие праметры, параметры запроса, значения сессии и настройки пользователя. +Несмотря на то, что мы будем обсуждать метод `GetSorting($arParams=array())` (дословно - Получить сортировку), правильнее назвать это методом просчета сортировки, так как для получения результата будут учтены входящие параметры, параметры запроса, значения сессии и настройки пользователя. -Структура ответа метода совпадает с значением `arParams` (в коде `defaultParams`): +Структура ответа метода совпадает со значением `arParams` (в коде `defaultParams`): ```php $defaultParams = [ 'sort' => [] @@ -61,8 +61,8 @@ $defaultParams = [ ``` Сама сортировка состоит из 2 групп: Полей (`sort`) и Переменных (`vars`). -Поля представляют из себя ассоциативный массив где ключом выступает идентификатор поля, а значением одно из `ASC` / `DESC` варианта. -Переменные - состоят из 2 заранее определенных значний - `by` - название переменной в которой содержится код поля и `order` - название переменной в которой содержится значение сортировки. +Поля представляют собой ассоциативный массив где ключом выступает идентификатор поля, а значением одно из `ASC` / `DESC` варианта. +Переменные - состоят из 2 заранее определенных значений - `by` - название переменной в которой содержится код поля и `order` - название переменной в которой содержится значение сортировки. Почему именно такая структура, а не простой набор полей? Дело в том, что на странице параметры `by` и `order` могут быть зарезервированы под другие бизнес-значения, да и самих гридов на странице может быть несколько. В случае если у гридов не разделять указанные параметры, то может сложиться ситуация, когда второй грид будет отсортирован по несуществующему полю и это может привести к фатальной ошибке (если такая ситуация не будет предусмотрена вами). diff --git "a/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/30_\320\242\320\260\320\261\320\273\320\270\321\206\321\213/30_\320\237\321\203\320\261\320\273\320\270\321\207\320\275\320\260\321\217_\321\207\320\260\321\201\321\202\321\214.md" "b/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/30_\320\242\320\260\320\261\320\273\320\270\321\206\321\213/30_\320\237\321\203\320\261\320\273\320\270\321\207\320\275\320\260\321\217_\321\207\320\260\321\201\321\202\321\214.md" index a49f277..608e18b 100644 --- "a/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/30_\320\242\320\260\320\261\320\273\320\270\321\206\321\213/30_\320\237\321\203\320\261\320\273\320\270\321\207\320\275\320\260\321\217_\321\207\320\260\321\201\321\202\321\214.md" +++ "b/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/200_UI/30_\320\242\320\260\320\261\320\273\320\270\321\206\321\213/30_\320\237\321\203\320\261\320\273\320\270\321\207\320\275\320\260\321\217_\321\207\320\260\321\201\321\202\321\214.md" @@ -2,11 +2,11 @@ [TOC] -В отличии от фильтров, гриды представляют собой более сложную систему и классифицировать ее на несколько частей (как мы это делали в фильтрах) не представляется возможным. Охватить все возможные ситуации так же не представляется возможным, однако некоторые моменты все же стоит описать. +В отличие от фильтров, гриды представляют собой более сложную систему и классифицировать ее на несколько частей (как мы это делали в фильтрах) не представляется возможным. Охватить все возможные ситуации так же не представляется возможным, однако некоторые моменты все же стоит описать. ## Получение объекта грида -Поскольку на странице может быть несколько таблиц точкой входа в гриды является менеджер гридов (`BX.Main.gridManager`), который выполняет верхнеуровневую работу над самими гридами. При помощи менеджера можно получить текущие гриды, обновить грид или вовсе удалить. +Поскольку на странице может быть несколько таблиц точкой входа в гриды является менеджер гридов (`BX.Main.gridManager`), который выполняет верхне-уровневую работу над самими гридами. При помощи менеджера можно получить текущие гриды, обновить грид или вовсе удалить. Некоторые полезные методы: @@ -84,7 +84,7 @@ grid.getRows().getSelectedIds(); // [] grid.getRows().isAllSelected(); ``` -### Снять/Поставить выделение со строк +### Снять/поставить выделение со строк Для того чтобы снять выделение со строк, можно использовать метод `unselectAll` на строках ```js @@ -116,7 +116,7 @@ grid.adjustCheckAllCheckboxes(); Существует особое событие исполняемое перед выполнением запросов на сервер - `Grid::beforeRequest`. Событие позволяет получить доступ к 2 объектам - инстансу грида и объекту настроек запроса. -Объект настроек представляет из себя js-объект вида: +Объект настроек представляет собой js-объект вида: ```js { data: { diff --git "a/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/20_\320\241\321\202\321\200\321\203\320\272\321\202\321\203\321\200\320\260_\320\277\320\260\320\277\320\272\320\270_local/00_\320\236\321\201\320\275\320\276\320\262\320\275\320\276\320\265.md" "b/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/20_\320\241\321\202\321\200\321\203\320\272\321\202\321\203\321\200\320\260_\320\277\320\260\320\277\320\272\320\270_local/00_\320\236\321\201\320\275\320\276\320\262\320\275\320\276\320\265.md" index 352ed4b..9e16ec3 100644 --- "a/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/20_\320\241\321\202\321\200\321\203\320\272\321\202\321\203\321\200\320\260_\320\277\320\260\320\277\320\272\320\270_local/00_\320\236\321\201\320\275\320\276\320\262\320\275\320\276\320\265.md" +++ "b/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/20_\320\241\321\202\321\200\321\203\320\272\321\202\321\203\321\200\320\260_\320\277\320\260\320\277\320\272\320\270_local/00_\320\236\321\201\320\275\320\276\320\262\320\275\320\276\320\265.md" @@ -2,21 +2,21 @@ [TOC] -Ядро продукта эволюционировала многие года и как и любой другой инструмент со временем устаревает и изменяется. Для 2000-х годов использование разделенной логики монолитного приложения было нормой и это использовалось повсеместно, однако реальности 2010-х годов и массовое распространение систем контроля версий привели к тому, что жизнь разработчиков на платформе стала невыносимой. +Ядро продукта эволюционировало многие годы и как любой другой инструмент со временем устаревает и изменяется. Для 2000-х годов использование разделенной логики монолитного приложения было распространенной практикой и это использовалось повсеместно, однако реальности 2010-х годов и массовое распространение систем контроля версий привели к тому, что жизнь разработчиков на платформе стала невыносимой. -Для облегчения этой задачи вендор предоставил необходимый инструмент - папку `local`, которым сейчас является фактически стандартном в разработке. Благодаря новому ядру D7 с версии главного модуля 14.0.1 основные файлы проекта могут быть вынесены из папки `/bitrix` в папку `/local`. Это необходимо чтобы изолировать изменяющиеся файлы проекта от файлов продукта. +Для облегчения этой задачи вендор предоставил необходимый инструмент - папку `local`, которым сейчас является фактически стандартном в разработке. Благодаря новому ядру D7 с версии главного модуля 14.0.1 основные файлы проекта могут быть вынесены из директории `/bitrix` в директорию `/local`. Это необходимо для изоляции изменяющиеся файлы проекта от файлов продукта. -# Стандарт +## Стандарт -Мы строго рекомендуем использовать исключительно папку `/local` для своих разработок и никогда (без крайней необходимости) не использовать и не вносить изменения в любой файл находящийся в папке `/bitrix`. +Мы строго рекомендуем использовать исключительно директорию `/local` для своих разработок и никогда (без крайней необходимости) не использовать и не вносить изменения в любой файл находящийся в папке `/bitrix`. Исключением из этого правила могут быть лишь в двух случаях - реализация модуля и техническая невозможность альтернативного решения (так же как и высокая цена за корректное решение). -При обработке поддерживаемых папок приоритет всегда у папки `/local` перед `/bitrix`. +При обработке поддерживаемых директорий (см.далее) приоритет всегда у директории `/local` перед `/bitrix`. >Это означает, что если в /local/templates/ и /bitrix/templates/ будут находиться шаблоны сайта с одинаковым названием, то подключится шаблон из /local. -# Поддерживаемые папки +## Поддерживаемые директории -Список поддерживаемых папок и файлов внутри `/local` директории: +Список поддерживаемых директорий и файлов внутри `/local`: * `/activities` - действия бизнес-процесса; * `/blocks` - блоки для сайтов24; @@ -26,3 +26,5 @@ * `/modules` - модули; * `/php_interface` - внутренние классы; * `/templates` - шаблоны сайтов; + +> Мы настоятельно не рекомендуем размещать какие-либо другие директории в этом месте (за исключением директории `tools` с техническими устаревшими скриптами). Ни директория `vendor` ни файлы `composer.json` не должны находиться здесь - их место внутри `php_interface` \ No newline at end of file diff --git "a/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/20_\320\241\321\202\321\200\321\203\320\272\321\202\321\203\321\200\320\260_\320\277\320\260\320\277\320\272\320\270_local/10_\320\241\320\262\320\276\320\271_\320\272\320\276\320\264.md" "b/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/20_\320\241\321\202\321\200\321\203\320\272\321\202\321\203\321\200\320\260_\320\277\320\260\320\277\320\272\320\270_local/10_\320\241\320\262\320\276\320\271_\320\272\320\276\320\264.md" index 930c228..a493fca 100644 --- "a/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/20_\320\241\321\202\321\200\321\203\320\272\321\202\321\203\321\200\320\260_\320\277\320\260\320\277\320\272\320\270_local/10_\320\241\320\262\320\276\320\271_\320\272\320\276\320\264.md" +++ "b/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/20_\320\241\321\202\321\200\321\203\320\272\321\202\321\203\321\200\320\260_\320\277\320\260\320\277\320\272\320\270_local/10_\320\241\320\262\320\276\320\271_\320\272\320\276\320\264.md" @@ -1,19 +1,27 @@ -Папка `local` уже упрощает жизнь разработчику, но одно наличие этой папки не решает всех поставленных перед разработкой задач и проблем. Не смотря на то что компания 1С-Битрикс продвигает разработку через модульную подсистему это является актуальным только для продукта "Битрикс: Управление сайтом", продукт "Битрикс24" поставляется как монолитное приложение под конкретного клиента и подход который разработчики используют при работе с "Битрикс: Управление сайтом" обычно не подходит к "Битрикс24". +[TOC] -В данной статье мы рассмотрим практики компании "ИТ-Интегратор Фьюжн" для разработки энтерпрайз проектов. +Директория `local` уже упрощает жизнь разработчику, но одно ее наличие не решает всех поставленных перед разработкой задач и проблем. Компания 1С-Битрикс продвигает модульную разработку, однако это является актуальным только для продукта "Битрикс: Управление сайтом", продукт "Битрикс24" поставляется как монолитное приложение под конкретного клиента и подход который разработчики используют при работе с "Битрикс: Управление сайтом" обычно не подходит к "Битрикс24". ->Этот подход не претендует на истину в последней инстанции. Выбор любого технического решения должен быть обусловлен исключительно техническими показателями, однако этот подход проверен годами и является хорошей отправной точкой для начала разработки. +В данной статье мы рассмотрим практики компании "ИТ-Интегратор Фьюжн" для разработки проектов. -# Структура проекта +>Этот подход не претендует на истину в последней инстанции. Выбор любого технического решения должен быть обусловлен исключительно техническими показателями, однако этот подход проверен годами и является хорошей отправной точкой для начала разработки по Битрикс24 в целом. + +# Типовая структура проекта + +Мы уже рассмотрели содержимое директории [`local`](/03_Разработка/20_Структура_папки_local/00_Основное.md) которая продиктована разработчиками продукта, теперь рассмотрим содержимое директории `local/php_interface` которую "ИТ-Интегратор Фьюжн" использует в проектах: * `/local/php_interface` - `/classes/` - php-классы, подключаемые автолоадером; - - `/console/` - консольные утилиты и приложения; + - `/console/` - консольные скрипты и приложения; - `/install` - Инсталлеры/Миграторы; - `/init.php` - `/kernel.php` - core-модули (`env`-файл, `servicelocator`); - - `/events.php` - декларирование подписок на событий; + - `/events.php` - декларирование подписок на события; - `/legacy.php` - устаревшие механики; + - `/composer.json` + - `/vendors/` - директория для подключаемых `composer` пакетов; + +Рассмотрим содержимое каждого скрипта и директории в отдельности. ## init.php @@ -95,7 +103,7 @@ unset($filePath); ### Autoloader -Обычно Битрикс24 использует конкретный клиент под конкретные бизнес-задачи, поэтому оформление кода в модули является ресурсоемкой затеей, ведь проект по сути и есть один большой модуль. Для удобного подключения классов мы используем специальный код, который при вызове класса подключает php-файл с ним в код страницы. +Обычно Битрикс24 использует конкретный клиент под конкретные бизнес-задачи, поэтому оформление кода в модули является затратной по времени затеей, ведь проект по сути и есть один большой модуль. Для удобного подключения классов мы используем специальный код, который при вызове класса подключает php-файл с ним в код страницы. Например, при использовании класса `\Fusion\SomeClass\SomeOtherClass\SuperClass` будет произведена автоматическая попытка найти его в следующих файлах: @@ -104,13 +112,37 @@ unset($filePath); В случае если файл найден, он будет подключен `require_once` функцией к текущему выполнению страницы. +>В самом файле класса должен быть определен корректное пространство имен (`namespace`) иначе класс не будет подключен. + ## events.php -Наиболее частой причиной разрастания `init.php` файла является прописывание кода обработчика события непосредственно в подписке на событии. +Наиболее частой причиной разрастания файл `init.php` является наличие кода обработчика события непосредственно в подписке на событие. -В своей структуре мы решили избавиться от этой проблемы разделением ответственности между кодом обработчика события и кодом подписки на событие. +Плохой пример как это делать в `init.php`: +```php +$eventManager = \Bitrix\Main\EventManager::getInstance(); -1. Файл `events.php` соедржит перечень событий и классов-обработчиков подписанных на них. +// DO NOT DO THIS! Bad practice! Do not store code of your handler with code that subscribe to event +$eventManager->addEventHandlerCompatible( + 'crm', + 'OnBeforeCrmContactAdd', + function( &$arFields ) + { + // Very large code line 1 + // Very large code line 2 + // Very large code line 3 + + // Very large code line 199 + // Very large code line 200 + // Very large code line 201 + return true; + } +); +``` + +В своей структуре мы решили избавиться от этой проблемы путем разделения ответственности между кодом обработчика события и кодом подписки на событие. + +1. Файл `events.php` содержит перечень событий и классов-обработчиков подписанных на них. 2. Мы не пишем код обработчика, а указываем на статический метод класса который является обработчиком события Содержимое файла `/local/php_interface/events.php`: @@ -137,34 +169,76 @@ $eventManager = \Bitrix\Main\EventManager::getInstance(); unset($eventManager); ``` -Обращаю внимание, что не смотря на отсутствие явных технических отличий между `addEventHandler` и `addEventHandlerCompatible` (в одном случае входным аргументом будет `\Bitrix\Main\Event` или его наследник, а в другом параметрами) мы рекомендуем использовать разделение и для старых событий явно использовать `Compatible` метод. Это позволит не запутаться в тех случаях, когда обработчик модифицирует входящие аргументы. +Обращаю внимание, что несмотря на отсутствие явных технических отличий между `addEventHandler` и `addEventHandlerCompatible` (в одном случае входным аргументом будет `\Bitrix\Main\Event` или его наследник, а в другом случае параметрами запроса) мы рекомендуем использовать разделение и для старых событий явно использовать `Compatible` метод. Это позволит не запутаться в тех случаях, когда обработчик модифицирует входящие аргументы. + +Пример содержимого файла `events.php` (вместо строчки с "_Your event handlers here_"): + +```php +$eventManager->addEventHandlerCompatible( + 'crm', + 'OnBeforeCrmContactAdd', + [ + '\Fusion\Crm\Contact\CheckData', + 'handleBeforeCrmContactAdd' + ] +); +``` + +Файл `/local/php_interface/Fusion/Crm/Contact/CheckData.php`: + +```php +namespace Fusion\Crm\Contact; + +class CheckData +{ + /** + * Handle crm::OnBeforeCrmContactAdd event + * - Do some action + * @params &array $arFields - Changed contact fields + * @return bool + */ + public static function handleBeforeCrmContactAdd( &$arFields ) + { + // Very large code line 1 + // Very large code line 2 + // Very large code line 3 + + // Very large code line 199 + // Very large code line 200 + // Very large code line 201 + return true; + } +} +``` ## kernel.php -Стандартом при работе с большими проектами является наличие нескольких сред исполнения кода, например production север и developer сервер и если с переносом кода все более менее понятно, то с переменными окружения (адреса серверов, доступы для внешних сервисов) возникают вопросы. +Стандартом при работе с большими проектами является наличие нескольких сред исполнения кода, например production север и developer сервер и если с переносом кода все более менее понятно, то с переменными окружения (адреса серверов, доступы для внешних сервисов) не все так очевидно. -Для себя мы выделили два наиболее практичных и удобных подхода: +Для себя мы выделили два наиболее практичных и удобных подходов: - Использованием ini-файла (мы называем его `.env`) -- Использование механизма `options` (хранение в `b_options` таблице, редактирование в адм.панели) +- Использование механизма `options` (хранение в `b_options` таблице, редактирование в административной панели) + +Рассмотрим преимущества и недостатки каждого из методов: -Рассмотрим преимущества и недостатки каждого из методов. -| Рассматриваемый параметр | `.env` | адм. панель | -| :-- | :-: | :-: | -| Хранение переменных окружения | + | + | -| Редактирование пользователем | - | `+*` | -| Перенос через VCS | + | `-**` | +| Рассматриваемый параметр | `.env` | адм. панель | +|:-----------------------------------|:------:|:------------| +| Хранение переменных окружения | ✅ | ✅ | +| Редактирование пользователем | ❌ | ✅`*` | +| Перенос через VCS | ✅ | ❌`**` | +| Попадают в штатную резервную копию | ❌ | ✅ | Легенда таблицы: -`+` - наличие возможности +✅ - наличие возможности -`-` - отсутствие возможности +❌ - отсутствие возможности `*` - Под возможностью редактировать подразумевается как наличие в Битрикс24 средства по работе с таблицами, так и возможность разработать административный интерфейс. Редактирование env-файла в данном случае не рекомендуется. `**` - Существует возможность переноса изменений через код, однако при проведении обновления нет возможности определить какой из параметров является верным (тот что был введен или пришел при обновлении). -Мы рассмотрим работу с ini-файлом `.env`, так как создание страниц в публичной или административной панели не является достаточно заслуживающей внимания темой и хорошо изложена в курсах Bitrix Framework и Контент-менеджер. +Мы рассмотрим работу с ini-файлом `.env`, так как создание страниц в публичной или административной панели хорошо изложена в курсах Bitrix Framework и Контент-менеджер. Bitrix Framework имеет средства для работы с переменными окружения используемых в процессе выполнения страницы и не имеет штатных механик позволяющих загрузить какие-либо другие файлы, чтобы объединить их с реальными env-переменными. Мы будем использовать `.env`-файл располагаемый выше директории `DOCUMENT_ROOT` как хранилище конфигурационных данных зависящих от окружения среды. @@ -243,9 +317,9 @@ if ( class_exists('\Bitrix\Main\DI\ServiceLocator') ) ## legacy.php -Помимо событий и явных точек расширения в виде kernel-раздела в некоторых частях системы существуют и другие возможности, например определение функции custom_mail, определение констант и т.п. Чтобы придерживаться концепции тонких файлов ясной структуры необходимо иметь место для временного или определенного хранения данных механизмов - им выступает файл `legacy.php`. +Помимо событий и явных точек расширения в виде kernel-раздела в некоторых частях системы существуют и другие возможности, например определение функции `custom_mail`, определение констант и другое. Чтобы придерживаться концепции маленьких файлов и ясной структуры необходимо иметь место для хранения подобных механизмов - им выступает файл `legacy.php`. -В идеальной среде данный файл должен отсутствовать или не иметь содержимого в нем, однако в реальном мире этот файл является хорошим место для того чтобы перенести определение констант в проекте или устаревших функций, например `GetGlobalID()` поставляемой в некоторых установках. +В идеальной среде данный файл должен отсутствовать или не иметь содержимого в нем, однако в реальном мире этот файл является хорошим место для хранения определенных констант в проекте или устаревших функций, например `GetGlobalID()` поставляемой в некоторых установках. ```php /** @@ -265,13 +339,13 @@ if ( class_exists('\Bitrix\Main\DI\ServiceLocator') ) # Решение vs Модуль Для себя мы выделяем два подхода к разработке: "Разработка через модули" (далее модули) и "Разработка через решение". -В чем же отличие "Модуля" от "Решения", ведь каждый из этих подходов подразумевает какой-то код, структурированный особым образом и все это служит для достижения определенной цели?. +В чем же отличие "Модуля" от "Решения", ведь каждый из этих подходов подразумевает какой-то код, структурированный особым образом и все это служит для достижения определенной цели? -Модуль это переиспользуемое решение, т.е. общий случай, который можно дополнить или изменить не вмешиваясь в логику его работы. +Модуль это пере-используемое решение, т.е. общий случай, который можно дополнить или изменить не вмешиваясь в логику его работы. Если модуль не подходит к другим проектам или требуется его значительное переписывание из проекта в проект, то это не модуль. Однако это не единственный критерий - некоторые разработчики любят прятать решение - оформлять его как модуль, но при этом оно не в состоянии жить без "другого" кода. Как понять, что у вас "решение оформленное под модуль"? -1. Для переиспользования недостаточно копировать папку из `*/modules//` на другую установку. +1. Для пере-использования недостаточно копировать папку из `*/modules//` на другую установку. 2. Для обновления вашего модуля нужно выполнять действия руками (заменять файлы, выполнять код или создавать инфоблоки). -Зачастую многие веб-студии поставляют модули, а потом дополнительно поставляют модули чтобы обновлять их модули (например модуль миграции). Этот подход противоречит подходу "модульности" самого Битрикса, хоть и имеет право быть. \ No newline at end of file +Зачастую многие веб-студии поставляют модули, а потом дополнительно поставляют модули, чтобы обновлять их модули (например модуль миграции). Этот подход противоречит подходу "модульности" самого Битрикса, хоть и имеет право быть. \ No newline at end of file diff --git "a/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/20_\320\241\321\202\321\200\321\203\320\272\321\202\321\203\321\200\320\260_\320\277\320\260\320\277\320\272\320\270_local/20_\320\234\320\270\320\263\321\200\320\260\321\206\320\270\320\270.md" "b/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/20_\320\241\321\202\321\200\321\203\320\272\321\202\321\203\321\200\320\260_\320\277\320\260\320\277\320\272\320\270_local/20_\320\234\320\270\320\263\321\200\320\260\321\206\320\270\320\270.md" index 9e6bf86..b64b4ee 100644 --- "a/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/20_\320\241\321\202\321\200\321\203\320\272\321\202\321\203\321\200\320\260_\320\277\320\260\320\277\320\272\320\270_local/20_\320\234\320\270\320\263\321\200\320\260\321\206\320\270\320\270.md" +++ "b/docs/03_\320\240\320\260\320\267\321\200\320\260\320\261\320\276\321\202\320\272\320\260/20_\320\241\321\202\321\200\321\203\320\272\321\202\321\203\321\200\320\260_\320\277\320\260\320\277\320\272\320\270_local/20_\320\234\320\270\320\263\321\200\320\260\321\206\320\270\320\270.md" @@ -2,7 +2,7 @@ Миграции - механизм переноса изменений в базе данных между средами исполнения кода. Проще говоря это git для структуры базы данных. -К всеобщему сожалению разработчики продукта фокусируются на пользователях, а не на разработчиках, поэтому в платформе отсутствует встроенный механизм миграций. Однако это не должно останавливать разрабточиков от их использования. +К всеобщему сожалению разработчики продукта фокусируются на пользователях, а не на разработчиках, поэтому в платформе отсутствует встроенный механизм миграций. Однако это не должно останавливать разработчиков от их использования. # Для платформы @@ -17,7 +17,7 @@ # Альтернативная точка зрения -Расмотрим миграции не с точки зрения разработчиков, а сточки зрения конечного пользователя продукта. Битрикс24 нацелен на использование бизнес-пользователями и в отличии от других систем позволяет всем людям с необходимыми правами влиять на поведение системы. Например разрабатывтать бизнес-процессы, создавать дополнительные поля и делать все это без привлечения разработчиков. Но так ли важны дополнительные поля созданные на боевом сервере, если вся разработка базируется на других полях? Нет. Отсюда мы можем заключить что наличие разницы в пользовательских полях не является проблемой и нам необходимо лишь привести сервер к нужному нам состоянию: т.е. перенести поля которые нужны для кода, совершенное не изменяя поля которые уже были созданы клиентом. +Рассмотрим миграции не с точки зрения разработчиков, а сточки зрения конечного пользователя продукта. Битрикс24 нацелен на использование бизнес-пользователями и в отличие от других систем позволяет всем людям с необходимыми правами влиять на поведение системы. Например, разрабатывать бизнес-процессы, создавать дополнительные поля и делать все это без привлечения разработчиков. Но так ли важны дополнительные поля созданные на боевом сервере, если вся разработка базируется на других полях? Нет. Отсюда мы можем заключить что наличие разницы в пользовательских полях не является проблемой и нам необходимо лишь привести сервер к нужному нам состоянию: т.е. перенести поля необходимые для нашего кода и совершенно не затрагивающие поля которые были созданы клиентом. Отсюда и родилась идея "инсталлеров" - скриптов, чье выполнение должно изменить конфигурацию продукта таким образом, чтобы доставленный код через системы контроля версий делал свою работу. diff --git "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/00_\320\236_\320\274\320\276\320\264\321\203\320\273\320\265.md" "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/00_\320\236_\320\274\320\276\320\264\321\203\320\273\320\265.md" index 22cb8c8..579dba9 100644 --- "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/00_\320\236_\320\274\320\276\320\264\321\203\320\273\320\265.md" +++ "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/00_\320\236_\320\274\320\276\320\264\321\203\320\273\320\265.md" @@ -1,14 +1,14 @@ # Общая информация -CRM (Customer Relationship Management System - cистема управления взаимоотношениями с клиентами) – это система управления продажами, которая оптимизирует работу с клиентами и сопровождает их от первого контакта до финальной сделки. +CRM (Customer Relationship Management System - система управления взаимоотношениями с клиентами) – это система управления продажами, которая оптимизирует работу с клиентами и сопровождает их от первого контакта до финальной сделки. -Каждое холодное обращение, каждя зацепка с потенциальным клиентом это [Лид](/Лид/Описание), т.е. любая минимальная информация - будь то номер телефона, адрес электронной почты или сообщение из социальной сети. +Каждое холодное обращение, каждая зацепка с потенциальным клиентом это [Лид](./11_Лид/00_Описание), т.е. любая минимальная информация - будь то номер телефона, адрес электронной почты или сообщение из социальной сети. -После добавления лидов задачей менеджера является привлечь клиента, запланировать звонки, письма и встречи. Такая запланированная активность называется [Дело](/Дело/index.html). После успешной обработки менеджер может конвертировать лид в [контакт](/Контакт/Описание) или [компанию](/Компания/Описание), а в случае продажи - [в сделку](/Сделка/Описание). +После добавления лидов задачей менеджера является привлечь клиента, запланировать звонки, письма и встречи. Такая запланированная активность называется [Дело](./30_Дело/index). После успешной обработки менеджер может конвертировать лид в [контакт](./12_Контакт/00_Описание) или [компанию](./13_Компания/00_Описание), а в случае продажи - [в сделку](./14_Сделка/00_Описание). ![Условная схема взаимоотношений](convertation.png) -Помимо основных сущностей участвующих в процессах CRM существуют так же вспомогательные, зачастую не участвующие явно в процессе или обеспечивают собственную логику работу. К ним относятся: [Счета](/Счет), [Предложения](/Предложение), [Заказы](/Заказ/index.html). +Помимо основных сущностей участвующих в процессах CRM существуют так же вспомогательные, зачастую не участвующие явно в процессе или обеспечивают собственную логику работу. К ним относятся: [Счета](./22_Счет), [Предложения](./23_Предложение), [Заказы](./23_Заказ/index). # Перед использованием API @@ -25,4 +25,4 @@ if ( Main\Loader::IncludeModule('crm') ) # Изучение модуля -Модуль CRM не из простых. Каждая сущность не описывается лишь одной таблицей, а для некоторых сущностей используется более 5 связанных по определенным правилам таблиц. Мы рекомендуем начать изучение модуля с изучения [справочников](/Словари/Справочники), объяснения [типов полей и структур данных](/Словари/Структуры_данных) и их взаимоотношений. \ No newline at end of file +Модуль CRM не из простых. Каждая сущность не описывается лишь одной таблицей, а для некоторых сущностей используется более 5 связанных по определенным правилам таблиц. Мы рекомендуем начать изучение модуля с изучения [справочников](./01_Словари/10_Справочники), объяснения [типов полей и структур данных](./01_Словари/30_Структуры_данных) и их взаимоотношений. \ No newline at end of file diff --git "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/01_\320\235\320\276\320\262\320\276\320\265_API.md" "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/01_\320\235\320\276\320\262\320\276\320\265_API.md" index abd49fe..165f46a 100644 --- "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/01_\320\235\320\276\320\262\320\276\320\265_API.md" +++ "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/01_\320\235\320\276\320\262\320\276\320\265_API.md" @@ -1,7 +1,7 @@ # Новое API В настоящий момент модуль входит в новый виток своего развития: старые процедурные методы исторически имеют ряд ограничений, которые нельзя исправить. -В рамках реализации [Смарт-процессов](./Смарт_процессы/Описание) разработчики пошли дальше создания новой сущности и фактически ориентировались на удовлетворении следующих критериев: +В рамках реализации [Смарт-процессов](./15_Смарт_процессы/00_Описание) разработчики пошли дальше создания новой сущности и фактически ориентировались на удовлетворении следующих критериев: - Уменьшение дублирования кода. - Уменьшение связности классов. - Покрытие тестами. @@ -11,9 +11,9 @@ - Уменьшить количество ошибок - Ускорить процесса разработки и внедрения новых возможностей -Да, очевидно сложность в изучении модуля возросла многократно, однако это слихвой компенсируется единообразием. Планируется что изучив общий подход разработчик сможет по образу и подобию работать и с другими сущностями CRM. +Да, очевидно сложность в изучении модуля возросла многократно, однако это компенсируется единообразием. Планируется что изучив общий подход разработчик сможет по образу и подобию работать и с другими сущностями CRM. -Изучение нового API рекомендуется начать с изучения [Смарт-процессов](./Смарт_процессы/Описание), поскольку работа модуля для других сущностей будет аналогичной. Изучение классического API следует начать с [Лидов](./Лид/Описание), поскольку это фактически точка входа в CRM и хранение холодных зацепок. +Изучение нового API рекомендуется начать с изучения [Смарт-процессов](./15_Смарт_процессы/00_Описание), поскольку работа модуля для других сущностей будет аналогичной. Изучение классического API следует начать с [Лидов](./11_Лид/00_Описание), поскольку это фактически точка входа в CRM и хранение холодных зацепок. ## Полезные ссылки diff --git "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/01_\320\241\320\273\320\276\320\262\320\260\321\200\320\270/10_\320\241\320\277\321\200\320\260\320\262\320\276\321\207\320\275\320\270\320\272\320\270.md" "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/01_\320\241\320\273\320\276\320\262\320\260\321\200\320\270/10_\320\241\320\277\321\200\320\260\320\262\320\276\321\207\320\275\320\270\320\272\320\270.md" index 125cffe..b714e2e 100644 --- "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/01_\320\241\320\273\320\276\320\262\320\260\321\200\320\270/10_\320\241\320\277\321\200\320\260\320\262\320\276\321\207\320\275\320\270\320\272\320\270.md" +++ "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/01_\320\241\320\273\320\276\320\262\320\260\321\200\320\270/10_\320\241\320\277\321\200\320\260\320\262\320\276\321\207\320\275\320\270\320\272\320\270.md" @@ -1,6 +1,6 @@ [TOC] -Модуль CRM построен не только на базе сложных составных сущностей, в нем так же есть место перечислениям, которые назваются "Справочники CRM" (могут упоминаться так же "статусы crm", "crm_status", справочники). +Модуль CRM построен не только на базе сложных составных сущностей, в нем так же есть место перечислениям, которые называются "Справочники CRM" (могут упоминаться так же "статусы crm", "crm_status", справочники). С точки зрения модуля все справочные значения находятся в базе данных в виде одной таблицы содержащей все справочные значения. @@ -10,20 +10,20 @@ В модуле справочники хранятся в таблице b_crm_status с определенными ключами: -| Поле | Тип | Описание | -| :---------- | ------------ | --------------------------------------------- | -| ID | int(18) | Уникальный идентификатор | -| ENTITY_ID | varchar(50) | Симв. код справочника | -| STATUS_ID | varchar(50) | Симв. код хранимого значения | -| NAME | varchar(100) | Текущее название для хранимого значения | -| NAME_INIT | varchar(100) | Базовое название для хранимого значения | -| SORT | int(18) | Порядок отображения | -| SYSTEM | char(1) | Флаг системного свойства | -| CATEGORY_ID | int(18) | Идентификатор категории | -| COLOR | char(10) | Цветовой HEX-код (RBG) | -| SEMANTICS | char(1) | Семантика справочного значения | +| Поле | Тип | Описание | +|:------------|--------------|-----------------------------------------| +| ID | int(18) | Уникальный идентификатор | +| ENTITY_ID | varchar(50) | Симв. код справочника | +| STATUS_ID | varchar(50) | Симв. код хранимого значения | +| NAME | varchar(100) | Текущее название для хранимого значения | +| NAME_INIT | varchar(100) | Базовое название для хранимого значения | +| SORT | int(18) | Порядок отображения | +| SYSTEM | char(1) | Флаг системного свойства | +| CATEGORY_ID | int(18) | Идентификатор категории | +| COLOR | char(10) | Цветовой HEX-код (RBG) | +| SEMANTICS | char(1) | Семантика справочного значения | -При взгляде на эту таблицу, можно заметить что типы данных указаны не в используемой системе эквиваленте (string, int), а в виде mysql типов данных с размерностью. Это действие сделано осознанно чтобы показать читателю то что таблица является технической и реальный пользователь видит иную картину. +При взгляде на эту таблицу, можно заметить что типы данных указаны не в используемой системе эквиваленте (string, int), а в виде mysql типов данных с размерностью. Это сделано для того, чтобы показать читателю, что таблица является технической и реальный пользователь видит иную картину. ## Общая логика работы с полями @@ -41,7 +41,7 @@ Ранее мы говорили что справочники является простыми перечислениями, а после просмотра состава таблицы у читателя мог появиться вопрос о назначении других столбцов: `CATEGORY_ID`, `COLOR`, `SEMANTICS`. -Это 'костыль' который был добавлен в систему разработчиками, чтобы поддерживать механизм хранения статусов [Лидов](../Лид/Описание) и [Сделок](../Сделка/Описание), ведь по факту статусы этих сущностей являются справочниками. +Это 'костыль' который был добавлен в систему разработчиками, чтобы поддерживать механизм хранения статусов [Лидов](../11_Лид/00_Описание) и [Сделок](../14_Сделка/00_Описание), ведь по факту статусы этих сущностей являются справочниками. # API для работы со статусами @@ -121,7 +121,7 @@ array(12) { **Получить список всех значений для справочника** -Выполняет аналогичную работу что и `CCrmStatus::GetStatus( $status )`, с одним отличием: возвращает ассоциативный список вида `STATUS_ID` => `NAME` +Выполняет аналогичную работу, что и `CCrmStatus::GetStatus( $status )`, с одним отличием: возвращает ассоциативный список вида `STATUS_ID` => `NAME` ```php /** @@ -170,7 +170,7 @@ array(12) { **Получить первый элемент справочника** -По сути этот метод явеляется надстройкой над методом `\CCrmStatus::GetStatusList` и возвращает исключительно `STATUS_ID` первой найденной записи. +По сути этот метод является надстройкой над методом `\CCrmStatus::GetStatusList` и возвращает исключительно `STATUS_ID` первой найденной записи. ```php /** @@ -192,8 +192,8 @@ string(4) "CALL" ## Добавление -Существует только один метод на добавление значений в справочник: неастатический метод класс `CCrmStatus::Add(array $arFields, bool $bCheckStatusId = true)`, где `arFields` - ассоциативный массив описывающий добавляемое значение, а `bCheckStatusId` - флаг, указывающий что нужно проверять дубли. -Если вы не уверены что такого значения нет, рекомендуется всегда выставлять флаг `bCheckStatusId` в значение `true` (это его значение по-умолчанию) +Существует только один метод на добавление значений в справочник: нестатический метод класс `CCrmStatus::Add(array $arFields, bool $bCheckStatusId = true)`, где `arFields` - ассоциативный массив описывающий добавляемое значение, а `bCheckStatusId` - флаг, указывающий, что нужно проверять дубли. +Если вы не уверены, что такого значения нет, рекомендуется всегда выставлять флаг `bCheckStatusId` в значение `true` (это его значение по-умолчанию) Пример добавление нового системного значения в справочник "Источник информации" (`SOURCE`) ```php @@ -230,7 +230,7 @@ if ( !$addedStatusId ) **Добавление нескольких значений** -И хотя метод на добавление существует только один, есть синтаксическая прослойка позволяющая добавлять сразу много статусов. Преимуещством данного метода является удобство для первичного заполнения нового справочника, однако он никак не обрабатывает ошибки добавления самих статусов. Если что-то не сработало, вы об этом не узнаете. +И хотя метод на добавление существует только один, есть синтаксическая прослойка позволяющая добавлять сразу много статусов. Преимуществом данного метода является удобство для первичного заполнения нового справочника, однако он никак не обрабатывает ошибки добавления самих статусов. Если что-то не сработало, вы об этом не узнаете. ```php @@ -257,7 +257,7 @@ $items = [ ``` -Не смотря на наличие значительных ограничений, этот метод удобно использовать в паре с методом `CCrmStatus::Erase`, речь о котором пойдет далее. +Несмотря на наличие значительных ограничений, этот метод удобно использовать в паре с методом `CCrmStatus::Erase`, речь о котором пойдет далее. ## Редактирование @@ -267,7 +267,7 @@ $items = [ `arOptions` - дополнительные опции. -Не смотря на то что метод принимает массив параметром `arFields`, в реальности изменению подвержены только ключи: `SORT`, `NAME`, `SYSTEM`, `COLOR`, `SEMANTICS`. +Несмотря на то что метод принимает массив параметром `arFields`, в реальности изменению подвержены только ключи: `SORT`, `NAME`, `SYSTEM`, `COLOR`, `SEMANTICS`. При наличии в `arOptions` значений `ENABLE_STATUS_ID` и `ENABLE_NAME_INIT` можно дополнительно изменить `STATUS_ID` и `NAME_INIT` соответственно. @@ -322,7 +322,7 @@ if ( !$statusId ) **Удалить конкретное значение X для справочника Y** -Обратите внимание, что не смотря на то что в справочниках использутся связка по `STATUS_ID` (что реально сохраняется в таблицу) и `NAME` (что отображается пользователю), удаление происходит по primary key `ID`. Если вы попытаетесь удалить несуществующий в таблице идентификатор, может возникнуть фатальная ошибка. +Обратите внимание, что, несмотря на то что в справочниках используется связка по `STATUS_ID` (что реально сохраняется в таблицу) и `NAME` (что отображается пользователю), удаление происходит по primary key `ID`. Если вы попытаетесь удалить несуществующий в таблице идентификатор, может возникнуть фатальная ошибка. ```php @@ -346,7 +346,7 @@ if ( $statusEntity->Delete($statusId) ) } ``` -Интересный факт: не смотря на то что объект справочника иницализируется по симв. идентификатору справочника, в реальности при удалении значения не проверяется что удаляемый ID принадлежит этому справочнику. Сам же симв. идентификатор справочника используется чтобы очистить сохраненный кеш. +Интересный факт: несмотря на то что объект справочника инициализируется по симв. идентификатору справочника, в реальности при удалении значения не проверяется что удаляемый ID принадлежит этому справочнику. Сам же симв. идентификатор справочника используется, чтобы очистить сохраненный кеш. **Удалить все справочные значения определенного справочника** diff --git "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/01_\320\241\320\273\320\276\320\262\320\260\321\200\320\270/20_\320\242\320\270\320\277\321\213_\320\264\320\260\320\275\320\275\321\213\321\205.md" "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/01_\320\241\320\273\320\276\320\262\320\260\321\200\320\270/20_\320\242\320\270\320\277\321\213_\320\264\320\260\320\275\320\275\321\213\321\205.md" index 404f9d1..5bf4bc2 100644 --- "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/01_\320\241\320\273\320\276\320\262\320\260\321\200\320\270/20_\320\242\320\270\320\277\321\213_\320\264\320\260\320\275\320\275\321\213\321\205.md" +++ "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/01_\320\241\320\273\320\276\320\262\320\260\321\200\320\270/20_\320\242\320\270\320\277\321\213_\320\264\320\260\320\275\320\275\321\213\321\205.md" @@ -1,27 +1,27 @@ Для улучшения восприятия при описании модуля будут использованы следующие сокращения типов: -| Тип | Представление в БД | -| :------------- | -------------------- | -| crm_status | string | -| user | integer | -| crm_currency | string | -| crm_company | int | -| crm_contact | int | -| crm_deal | int | -| crm_lead | int | -| crm_order | int | -| crm_quote | int | -| crm_invoice | int | -| crm_multifield | - | +| Тип | Представление в БД | +|:---------------|--------------------| +| crm_status | string | +| user | integer | +| crm_currency | string | +| crm_company | int | +| crm_contact | int | +| crm_deal | int | +| crm_lead | int | +| crm_order | int | +| crm_quote | int | +| crm_invoice | int | +| crm_multifield | - | Теперь когда нам известны представление полей для типов в базе данных, мы можем перейти к рассмотрению физических значений и взаимосвязей в базе данных. -Тип `user` - связка по первичному ключу с списком пользователей из таблицы `b_user`, физическое представление - целочисленный идентификатор. +Тип `user` - связка по первичному ключу со списком пользователей из таблицы `b_user`, физическое представление - целочисленный идентификатор. -Тип `crm_status` - связка по символьному коду к таблице `b_crm_status`. Подробнее о символьном коде и механизме харнения можно рассмотреть в соответствующей [главе Справочники](Справочники). +Тип `crm_status` - связка по символьному коду к таблице `b_crm_status`. Подробнее о символьном коде и механизме хранения можно рассмотреть в соответствующей [главе Справочники](./10_Справочники). Тип `crm_currency` - строковый идентификатор валюты, согласно ISO 4217. -Тип `crm_company`, `crm_contact`, `crm_deal`, `crm_lead`, `crm_order`, `crm_quote`, `crm_invoice` - целочисленные идентификаторы CRM сущностей Компании, Контакта, Сделки, [Лида](../Лид/Описание), Заказа, Предложения, Счета. +Тип `crm_company`, `crm_contact`, `crm_deal`, `crm_lead`, `crm_order`, `crm_quote`, `crm_invoice` - целочисленные идентификаторы CRM сущностей Компании, Контакта, Сделки, [Лида](../11_Лид/00_Описание), Заказа, Предложения, Счета. -Тип `crm_multifield` является псевдотипом, т.е. не существующим в реальном жизни полем, собираемым в конкретный временной период. На чтение доступен как строка в режиме `as is`. \ No newline at end of file +Тип `crm_multifield` является псевдо-типом, т.е. не существующим в реальном жизни полем, собираемым в конкретный временной период. На чтение доступен как строка в режиме `as is`. \ No newline at end of file diff --git "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/01_\320\241\320\273\320\276\320\262\320\260\321\200\320\270/30_\320\241\321\202\321\200\321\203\320\272\321\202\321\203\321\200\321\213_\320\264\320\260\320\275\320\275\321\213\321\205.md" "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/01_\320\241\320\273\320\276\320\262\320\260\321\200\320\270/30_\320\241\321\202\321\200\321\203\320\272\321\202\321\203\321\200\321\213_\320\264\320\260\320\275\320\275\321\213\321\205.md" index d59af32..3de8408 100644 --- "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/01_\320\241\320\273\320\276\320\262\320\260\321\200\320\270/30_\320\241\321\202\321\200\321\203\320\272\321\202\321\203\321\200\321\213_\320\264\320\260\320\275\320\275\321\213\321\205.md" +++ "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/01_\320\241\320\273\320\276\320\262\320\260\321\200\320\270/30_\320\241\321\202\321\200\321\203\320\272\321\202\321\203\321\200\321\213_\320\264\320\260\320\275\320\275\321\213\321\205.md" @@ -1,4 +1,4 @@ -Не смотря на то что со стороны базы данных сущности описываются в разных таблицах, программистам удобнее работать с комплексными структурами наиболее качественно описывающими сущность. +Несмотря на то что со стороны базы данных сущности описываются в разных таблицах, программистам удобнее работать с комплексными структурами наиболее качественно описывающими сущность. Для упрощения работы программистов со стороны платформы часто предоставляются специальные структуры которые могут облегчить жизнь. @@ -6,7 +6,7 @@ Когда мы говорим об абстрактной сущности и ее полях мы можем использовать сколько угодно таблиц для ее описания, однако при наличии повторяющихся полей с одинаковой логикой не имеет никакого смысла дублировать эти таблицы. Для унификации этой ситуации битрикс создает комплексные таблицы и добавляет поля указывающие на тип сущности и ее идентификатор. -Обычно в таблицах они имеют ключи `OWNER_TYPE_ID` (для идентификатор типа) и `OWNER_ID` (для идентификатора элемента), иногда встречаются и такие поля как `ENTITY_ID` (мнемонический код типа) и `ELEMENT_ID` (идентификатора элемента). +Обычно в таблицах они имеют ключи `OWNER_TYPE_ID` (для идентификатора типа) и `OWNER_ID` (для идентификатора элемента), иногда встречаются и такие поля как `ENTITY_ID` (мнемонический код типа) и `ELEMENT_ID` (идентификатора элемента). В системе существует определенное количество системных сущностей и для каждой сущности закреплено мнемонический код, ее порядковый номер и комплексный префикс. @@ -150,15 +150,15 @@ array(2) { Исторически для описания таких полей как Телефон, Email, Сайт, IM используется структура `Коммуникационные поля` (`crm_multifield`). Все данные сохраняются в таблице `b_crm_field_multi` -| Поле | Тип данных | -| :------------- | -------------------- | -| ID | int(18) | -| ENTITY_ID | varchar(16) | -| ELEMENT_ID | int(18) | -| TYPE_ID | varchar(16) | -| VALUE_TYPE | varchar(50) | -| COMPLEX_ID | varchar(100) | -| VALUE | varchar(250) | +| Поле | Тип данных | +|:-----------|--------------| +| ID | int(18) | +| ENTITY_ID | varchar(16) | +| ELEMENT_ID | int(18) | +| TYPE_ID | varchar(16) | +| VALUE_TYPE | varchar(50) | +| COMPLEX_ID | varchar(100) | +| VALUE | varchar(250) | `ID` - уникальный идентификатор значения `ENTITY_ID` - мнемонический код сущности @@ -170,19 +170,19 @@ array(2) { Пример: сохраненная почта some@email как рабочая почта для лида ID:123 -| Поле | Значение | -| :------------- | ------------------ | -| ID | 12345 | -| ENTITY_ID | LEAD | -| ELEMENT_ID | 123 | -| TYPE_ID | EMAIL | -| VALUE_TYPE | HOME | -| COMPLEX_ID | EMAIL_HOME | -| VALUE | some@email | +| Поле | Значение | +|:-----------|------------| +| ID | 12345 | +| ENTITY_ID | LEAD | +| ELEMENT_ID | 123 | +| TYPE_ID | EMAIL | +| VALUE_TYPE | HOME | +| COMPLEX_ID | EMAIL_HOME | +| VALUE | some@email | За работу с множественными полями отвечает класс `CCrmFieldMulti`. -Список поддерживаемых на данный момент полей представлен в виде контант, аналогично с `\CCrmOwnerType`: `\CCrmFieldMulti::PHONE`, `\CCrmFieldMulti::EMAIL`, `\CCrmFieldMulti::WEB`, `\CCrmFieldMulti::IM` +Список поддерживаемых на данный момент полей представлен в виде констант, аналогично с `\CCrmOwnerType`: `\CCrmFieldMulti::PHONE`, `\CCrmFieldMulti::EMAIL`, `\CCrmFieldMulti::WEB`, `\CCrmFieldMulti::IM` ## API @@ -280,7 +280,7 @@ array(4) { **Получить тип значения по-умолчанию** -Для получения типа значения по-умолчанию используется статический метод `\CCrmFieldMulti::GetDefaultValueType($entityTypeID)`, который всегда возвращает тип значения по-умолчанию для указанонго типа. +Для получения типа значения по-умолчанию используется статический метод `\CCrmFieldMulti::GetDefaultValueType($entityTypeID)`, который всегда возвращает тип значения по-умолчанию для указанного типа. ```php echo \CCrmFieldMulti::GetDefaultValueType( \CCrmFieldMulti::PHONE ); // WORK @@ -292,7 +292,7 @@ echo \CCrmFieldMulti::GetDefaultValueType( \CCrmFieldMulti::PHONE ); // WORK `CCrmFieldMulti::GetListEx($arOrder = array(), $arFilter = array(), $arGroupBy = false, $arNavStartParams = false, $arSelectFields = array(), $arOptions = array())` ->Принципы фильтрации и общие методы работы изложены [в документации к методы CIblockElement::GetList](https://dev.1c-bitrix.ru/api_help/iblock/classes/ciblockelement/getlist.php). +>Принципы фильтрации и общие методы работы изложены [в документации к методу CIblockElement::GetList](https://dev.1c-bitrix.ru/api_help/iblock/classes/ciblockelement/getlist.php). ### Добавление @@ -432,7 +432,7 @@ else ### Пакетное сохранение -Не смотря на существование точечных методов на добавление, редактирование и удаление элементов для упрощения работы с ними можно использовать пакетный метод, который сам определить необходимые к изменению элементы. +Несмотря на существование точечных методов на добавление, редактирование и удаление элементов для упрощения работы с ними можно использовать пакетный метод, который сам определить необходимые к изменению элементы. За эту работу отвечает нестатический метод `SetFields($entityId, $elementId, $arFieldData, array $options = null)`. `$entityId` - мнемонический код изменяемой сущности. diff --git "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/11_\320\233\320\270\320\264/00_\320\236\320\277\320\270\321\201\320\260\320\275\320\270\320\265.md" "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/11_\320\233\320\270\320\264/00_\320\236\320\277\320\270\321\201\320\260\320\275\320\270\320\265.md" index f2d00c3..463ba9b 100644 --- "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/11_\320\233\320\270\320\264/00_\320\236\320\277\320\270\321\201\320\260\320\275\320\270\320\265.md" +++ "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/11_\320\233\320\270\320\264/00_\320\236\320\277\320\270\321\201\320\260\320\275\320\270\320\265.md" @@ -1,6 +1,6 @@ # Описание сущности -Лид - это любая минимальная информация о намерении получить услугу/товар. Заполнение формы обратной связи, входящий звонок, письпо полученное на почтовый ящик - это намерение купить товар/приобрести услугу. +Лид - это любая минимальная информация о намерении получить услугу/товар. Заполнение формы обратной связи, входящий звонок, письмо полученное на почтовый ящик - это намерение купить товар/приобрести услугу. >Перечень полей может изменяться и в зависимости от метода и способа вызова иметь различные аттрибуты. Конкретный перечень доступных полей необходимо смотреть в исходном коде метода который используется. @@ -9,53 +9,53 @@ В таблице указаны основные поля непосредственной сущности Лид. -| Поле | Тип | Описание | Примечание | -| :--- | --- | ----------------------------------------------- | ---------- | -| ID | int | Уникальный целочисленный идентификатор лида | ``AI``, ``RO`` | -| TITLE | string | Название лида | ``REQ`` | -| HONORIFIC | crm_status | Обращение | Код справочника: HONORIFIC | -| NAME | string | Имя || -| SECOND_NAME | string | Отчество || -| LAST_NAME | string | Фамилия || -| BIRTHDATE | date | Дата рождения || -| BIRTHDAY_SORT | integer | Универсальное число, получаемое из даты рождения для сортировки и поиска || -| COMPANY_TITLE | string | Название компании || -| SOURCE_ID | crm_status | Источник | Код справочника: SOURCE | -| SOURCE_DESCRIPTION | string | Дополнительно об источнике || -| STATUS_ID | crm_status | Статус | Код справочника: STATUS | -| STATUS_DESCRIPTION | string | Дополнительно о статусе || -| STATUS_SEMANTIC_ID | string | Состояние статуса (N (новый), P (в работе), F (закрыт)) | ``RO``| -| POST | string | Должность || -| CURRENCY_ID | crm_currency | Валюта || -| OPPORTUNITY | double | Сумма || -| OPENED | char | Доступен для всех | Y/N | -| COMMENTS | string | Комментарий || -| HAS_PHONE | char | Задан телефон, автоматически вычисляется при создании/обновлении | Y/N, ``RO`` | -| HAS_EMAIL | char | Задан e-mail, автоматически вычисляется при создании/обновлении | Y/N, ``RO`` | -| HAS_IMOL | char | Задана открытая линия, автоматически вычисляется при создании/обновлении | Y/N, ``RO`` | -| ASSIGNED_BY_ID | user | Ответственный || -| CREATED_BY_ID | user | Кем создан | ``RO`` | -| MODIFY_BY_ID | user | Кем изменен | ``RO`` | -| DATE_CREATE | datetime | Дата создания | ``RO`` | -| DATE_MODIFY | datetime | Дата изменения | ``RO`` | -| COMPANY_ID | crm_company | Компания || -| CONTACT_ID | crm_contact | Контакт | ``DEP`` | -| IS_RETURN_CUSTOMER | char | Повторный лид | Y/N, ``RO`` | -| DATE_CLOSED | datetime | Дата завершения | ``RO`` | -| ORIGINATOR_ID | string | Внешний источник || -| ORIGIN_ID | string | Идентификатор элемента во внешнем источнике || -| UTM_SOURCE | string | Рекламная система || -| UTM_MEDIUM | string | Тип трафика || -| UTM_CAMPAIGN | string | Обозначение рекламной кампании || -| UTM_CONTENT | string | Содержание кампании || -| UTM_TERM | string | Условие поиска кампании || -| PHONE | crm_multifield | Телефон | ``RO`` | -| EMAIL | crm_multifield | E-mail | ``RO`` | -| WEB | crm_multifield | Сайт | ``RO`` | -| IM | crm_multifield | Мессенджер | ``RO`` | +| Поле | Тип | Описание | Примечание | +|:-------------------|----------------|--------------------------------------------------------------------------|----------------------------| +| ID | int | Уникальный целочисленный идентификатор лида | ``AI``, ``RO`` | +| TITLE | string | Название лида | ``REQ`` | +| HONORIFIC | crm_status | Обращение | Код справочника: HONORIFIC | +| NAME | string | Имя | | +| SECOND_NAME | string | Отчество | | +| LAST_NAME | string | Фамилия | | +| BIRTHDATE | date | Дата рождения | | +| BIRTHDAY_SORT | integer | Универсальное число, получаемое из даты рождения для сортировки и поиска | | +| COMPANY_TITLE | string | Название компании | | +| SOURCE_ID | crm_status | Источник | Код справочника: SOURCE | +| SOURCE_DESCRIPTION | string | Дополнительно об источнике | | +| STATUS_ID | crm_status | Статус | Код справочника: STATUS | +| STATUS_DESCRIPTION | string | Дополнительно о статусе | | +| STATUS_SEMANTIC_ID | string | Состояние статуса (N (новый), P (в работе), F (закрыт)) | ``RO`` | +| POST | string | Должность | | +| CURRENCY_ID | crm_currency | Валюта | | +| OPPORTUNITY | double | Сумма | | +| OPENED | char | Доступен для всех | Y/N | +| COMMENTS | string | Комментарий | | +| HAS_PHONE | char | Задан телефон, автоматически вычисляется при создании/обновлении | Y/N, ``RO`` | +| HAS_EMAIL | char | Задан e-mail, автоматически вычисляется при создании/обновлении | Y/N, ``RO`` | +| HAS_IMOL | char | Задана открытая линия, автоматически вычисляется при создании/обновлении | Y/N, ``RO`` | +| ASSIGNED_BY_ID | user | Ответственный | | +| CREATED_BY_ID | user | Кем создан | ``RO`` | +| MODIFY_BY_ID | user | Кем изменен | ``RO`` | +| DATE_CREATE | datetime | Дата создания | ``RO`` | +| DATE_MODIFY | datetime | Дата изменения | ``RO`` | +| COMPANY_ID | crm_company | Компания | | +| CONTACT_ID | crm_contact | Контакт | ``DEP`` | +| IS_RETURN_CUSTOMER | char | Повторный лид | Y/N, ``RO`` | +| DATE_CLOSED | datetime | Дата завершения | ``RO`` | +| ORIGINATOR_ID | string | Внешний источник | | +| ORIGIN_ID | string | Идентификатор элемента во внешнем источнике | | +| UTM_SOURCE | string | Рекламная система | | +| UTM_MEDIUM | string | Тип трафика | | +| UTM_CAMPAIGN | string | Обозначение рекламной кампании | | +| UTM_CONTENT | string | Содержание кампании | | +| UTM_TERM | string | Условие поиска кампании | | +| PHONE | crm_multifield | Телефон | ``RO`` | +| EMAIL | crm_multifield | E-mail | ``RO`` | +| WEB | crm_multifield | Сайт | ``RO`` | +| IM | crm_multifield | Мессенджер | ``RO`` | Примечание к перечисленным полям: -1. Для расшифровки типов можно обратиться к [Типам данных](../Словари/Типы_данных). +1. Для расшифровки типов можно обратиться к [Типам данных](../01_Словари/20_Типы_данных). 2. Для обозначения специальных полей используются дополнительные флаги: * ``RO`` - read only (поле только для чтения) diff --git "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/11_\320\233\320\270\320\264/10_\320\234\320\265\321\202\320\276\320\264\321\213.md" "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/11_\320\233\320\270\320\264/10_\320\234\320\265\321\202\320\276\320\264\321\213.md" index a091166..91f9e54 100644 --- "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/11_\320\233\320\270\320\264/10_\320\234\320\265\321\202\320\276\320\264\321\213.md" +++ "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/11_\320\233\320\270\320\264/10_\320\234\320\265\321\202\320\276\320\264\321\213.md" @@ -50,18 +50,18 @@ if ( \Bitrix\Main\Loader::IncludeModule('crm') ) Существует несколько способов получить перечень лидов из системы: старое API и DataManager. Каждый способ имеет свои преимущества и не достатки, что в конечном счете использовать должен выбрать разработчик. -| Сравнение |Старое API|DataManager| -| :--------------------------------: | -------- | --------- | -| Возможность получить данные из БД | v | v | -| Учет прав при получении | v | x | -| Простая фильтрация данных | v | v | -| Использование подзапросов для сложной фильтрации | x | v | +| Сравнение | Старое API | DataManager | +|:--------------------------------------------------|------------|-------------| +| Возможность получить данные из БД | v | v | +| Учет прав при получении | v | x | +| Простая фильтрация данных | v | v | +| Использование под запросов для сложной фильтрации | x | v | Резюмируя, в случае DataManager как преимущество можно выделить скорость работы и гибкость за счет трансляции кода в SQL запрос, в то время как использование старого api дает возможность использовать проверку прав. ### Используя старое API -Для получение лидов используя старое API используется метод ```CCrmLead::GetListEx``. +Для получения лидов используя старое API используется метод `CCrmLead::GetListEx`. Сигнатура метода: ```php @@ -75,7 +75,7 @@ $leadResult = CCrmLead::GetListEx( ); ``` -Механизм получения данных аналогичен [выборке из инфоблоков](http://dev.1c-bitrix.ru/api_help/iblock/classes/ciblockelement/getlist.php). По-умолчанию при выборке проверяются права текущего пользователя, поэтому чтобы получить все значения без проверки прав необходимо передать в фильтре флаг ``CHECK_PERMISSIONS`` с значением ``N``. +Механизм получения данных аналогичен [выборке из инфоблоков](http://dev.1c-bitrix.ru/api_help/iblock/classes/ciblockelement/getlist.php). По-умолчанию при выборке проверяются права текущего пользователя, поэтому для получения всех значений без проверки прав необходимо передать в фильтре флаг ``CHECK_PERMISSIONS`` со значением ``N``. Пример: необходимо получить названия и ID лидов, которые созданные 1 января 2021 года без учета прав пользователя, отсортированные по источнику (убыванию) @@ -114,7 +114,7 @@ while( $lead = $leadResult->fetch() ) #### Прямое указание LIMIT и OFFSET -При помощи параметра `QUERY_OPTIONS` в `$arOptions` имеется возможность задания таких параметров. Это очень удобно для двухступенчатой постаничной навигации, когда сначала выбираются ID элементов, а потом уже данные для полученных ID. +При помощи параметра `QUERY_OPTIONS` в `$arOptions` имеется возможность задания таких параметров. Это очень удобно для двухступенчатой постраничной навигации, когда сначала выбираются ID элементов, а потом уже данные для полученных ID. Пример запроса: @@ -139,7 +139,7 @@ $leadResult = CCrmLead::GetListEx( #### Запросы с участием внешних таблиц в фильтре -Иногда бывает необходимость достать только те лиды, для которых есть запись в сторонней таблице. Для этого можно воспользоваться `__JOINS` ключем. +Иногда бывает необходимость достать только те лиды, для которых есть запись в сторонней таблице. Для этого можно воспользоваться `__JOINS` ключом. ```php @@ -383,7 +383,7 @@ if ( !$leadId ) } ``` ->Структура FM описывает коммуникационные поля. Если она вам незнакома, то рекомендуется изучить [соответствуюую статью](../Словари/Структуры_данных) +>Структура FM описывает коммуникационные поля. Если она вам незнакома, то рекомендуется изучить [соответствующую статью](../01_Словари/30_Структуры_данных) ## Обновление лида @@ -420,7 +420,7 @@ public function Update($ID, array &$arFields, $bCompare = true, $bUpdateSearch = 17. Обновление поискового индекса 18. Запись сообщения в ленту лида/чат 19. Вызов события OnAfterCrmLeadUpdate -20. Добавление наблюдетей в канбане +20. Добавление наблюдателей в канбане 21. Отправка данных в ML (при необходимости) Ниже представлен код иллюстрирующий изменение лида. @@ -474,6 +474,7 @@ $isUpdateSuccess = $leadEntity->Update( $leadId $leadFields, $bCompare = true, + $bUpdateSearch = true, $arOptions = [ /** * ID пользователя, от лица которого выполняется действие @@ -547,7 +548,7 @@ if ( !$isUpdateSuccess ) } ``` ->Структура FM описывает коммуникационные поля. Если она вам незнакома, то рекомендуется изучить [соответствуюую статью](../Словари/Структуры_данных) +>Структура FM описывает коммуникационные поля. Если она вам незнакома, то рекомендуется изучить [соответствующую статью](../01_Словари/30_Структуры_данных) ## Удаление лида diff --git "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/11_\320\233\320\270\320\264/20_C\320\276\320\261\321\213\321\202\320\270\321\217.md" "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/11_\320\233\320\270\320\264/20_C\320\276\320\261\321\213\321\202\320\270\321\217.md" index 99c54d5..6cb3767 100644 --- "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/11_\320\233\320\270\320\264/20_C\320\276\320\261\321\213\321\202\320\270\321\217.md" +++ "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/11_\320\233\320\270\320\264/20_C\320\276\320\261\321\213\321\202\320\270\321\217.md" @@ -1,18 +1,18 @@ -Как и у многих других сущностей платформы у Лидов есть события, позволяющие узнавать о каких либо событиях и даже влиять на их работу. +Как и у многих других сущностей платформы у лидов есть события, позволяющие узнавать о каких либо событиях и даже влиять на их работу. [TOC] ->Помните, что события не проверяются на цикличный вызов, поэтому если во время создания элемента на событии вы попыпаетесь создать элемент, то вы можете породить бесконечный цикл. +>Помните, что события не проверяются на цикличный вызов, поэтому если во время создания элемента на событии вы попытаетесь создать элемент, то вы можете породить бесконечный цикл. >Событие не всегда содержит полный набор полей, поэтому хорошим тоном является проверять фактическое наличие ключа в массиве параметров и в случае его отсутствия заполнение либо дефолтным значением, либо обращение в базу данных для предотвращения неопределенного поведения. # OnBeforeCrmLeadAdd -Событие вызываемое перед создание элемента методом `CCrmLead::Add`. +Событие вызываемое перед созданием элемента методом `CCrmLead::Add`. -| Параметр | Значение | -| :----------: | ---------------------- | -| &$arFields | Поля создаваемого лида | +| Параметр | Значение | +|:-----------|------------------------| +| &$arFields | Поля создаваемого лида | Возвращаемое значение: boolean. `true` успешное выполнение. @@ -53,9 +53,9 @@ $eventManager->addEventHandlerCompatible( Событие вызываемое после успешного создания элемента методом `CCrmLead::Add`. -| Параметр | Значение | -| :----------: | ---------------------- | -| &$arFields | Поля создаваемого лида | +| Параметр | Значение | +|:-----------|------------------------| +| &$arFields | Поля создаваемого лида | Возвращаемое значение не обрабатывается. @@ -81,9 +81,9 @@ $eventManager->addEventHandlerCompatible( Событие вызываемое перед обновлением элемента методом `CCrmLead::Update`. -| Параметр | Значение | -| :----------: | ---------------------- | -| &$arFields | Поля обновляемого лида | +| Параметр | Значение | +|:-----------|------------------------| +| &$arFields | Поля обновляемого лида | Возвращаемое значение: boolean. `true` успешное выполнение. @@ -124,9 +124,9 @@ $eventManager->addEventHandlerCompatible( Событие вызываемое после успешного обновления элемента методом `CCrmLead::Update`. -| Параметр | Значение | -| :----------: | ---------------------- | -| &$arFields | Поля обновляемого лида | +| Параметр | Значение | +|:-----------|------------------------| +| &$arFields | Поля обновляемого лида | Возвращаемое значение не обрабатывается. @@ -148,9 +148,9 @@ $eventManager->addEventHandlerCompatible( Событие вызываемое перед удалением элемента методом `CCrmLead::Delete` или перемещения в корзину. -| Параметр | Значение | -| :----------: | ------------------------------ | -| $id | Primary key удаляемой сущности | +| Параметр | Значение | +|:---------|--------------------------------| +| $id | Primary key удаляемой сущности | Возвращаемое значение: boolean. `true` успешное выполнение. @@ -191,9 +191,9 @@ $eventManager->addEventHandlerCompatible( Событие вызываемое после успешного удаления элемента методом `CCrmLead::Delete` или перемещения в корзину. -| Параметр | Значение | -| :----------: | ------------------------------ | -| $id | Primary key удаляемой сущности | +| Параметр | Значение | +|:---------|--------------------------------| +| $id | Primary key удаляемой сущности | Возвращаемое значение не обрабатывается. @@ -217,10 +217,10 @@ $eventManager->addEventHandlerCompatible( Событие вызываемое после успешного изменения состава товарных позиций элемента методом `CCrmLead::SaveProductRows`. -| Параметр | Значение | -| :----------: | ------------------------------ | -| $id | Primary key сущности | -| $arRows | Набор новых элементо | +| Параметр | Значение | +|:---------|-----------------------| +| $id | Primary key сущности | +| $arRows | Набор новых элементов | Возвращаемое значение не обрабатывается. diff --git "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/11_\320\233\320\270\320\264/30_\320\237\321\200\320\270\320\274\320\265\321\200\321\213.md" "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/11_\320\233\320\270\320\264/30_\320\237\321\200\320\270\320\274\320\265\321\200\321\213.md" index 8ebd6ab..7f25ee7 100644 --- "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/11_\320\233\320\270\320\264/30_\320\237\321\200\320\270\320\274\320\265\321\200\321\213.md" +++ "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/11_\320\233\320\270\320\264/30_\320\237\321\200\320\270\320\274\320\265\321\200\321\213.md" @@ -75,7 +75,7 @@ while( $lead = $leadResult->fetch() ) # Множественные поля -Мы уже описали что Битрикс24 хранит множственные поля отдельно и часто возникает вопрос как работать с такими полями. Наиболее удобным способом является работа от API множественных полей. +Мы уже описали что Битрикс24 хранит множественные поля отдельно и часто возникает вопрос как работать с такими полями. Наиболее удобным способом является работа от API множественных полей. ## Получение всех телефонов контакта @@ -188,15 +188,15 @@ foreach($dups as &$dup) } ``` ->Телефонный номер в таблице дубликатов хранится в виде строки состоящей из чисел, поэтому предавая ее на поиск в менеджер дубликатов предварительно нужно очистить ненужные символы. +>Телефонный номер в таблице дубликатов хранится в виде строки состоящей из чисел, поэтому предавая ее на поиск в менеджере дубликатов предварительно нужно очистить ненужные символы. # Дата рождения ## Найти лиды, день рождения которых сегодня -Иногда необходимо найти лиды чье день рождения выпадает на определенное число или месяц. Так как не все СУБД поддерживают частичный поиск по полям с типом дата, разработчики использовали иной подход к подсистеме хранения даты рождения. При изменения даты рождения исходное значение сохраняется в поле `BIRTHDATE`, в то время как на основании дня и месяца рождения вычисляется специальное число хранящееся в поле `BIRTHDAY_SORT`. +Иногда необходимо найти лиды чье день рождения выпадает на определенное число или месяц. Так как не все СУБД поддерживают частичный поиск по полям с типом дата, разработчики использовали иной подход к подсистеме хранения даты рождения. При изменении даты рождения исходное значение сохраняется в поле `BIRTHDATE`, в то время как на основании дня и месяца рождения вычисляется специальное число хранящееся в поле `BIRTHDAY_SORT`. -Таким образом чтобы найти пользователя у которого день рождения выпадает на определенно число нужно: +Таким образом, чтобы найти пользователя у которого день рождения выпадает на определенно число нужно: 1. Сгенерировать число для данной даты 2. Выполнить поиск числа по ключу `BIRTHDAY_SORT` @@ -266,7 +266,7 @@ while( $lead = $leadResult->fetch() ) * `$entityID` - тип сущности. Поддерживается `\CCrmOwnerType::Lead` и `\CCrmOwnerType::Contact` * `$currentDate` - текущая дата в формате сайта * `$startDate` - дата с которой нужно начинать поиск (в формате сайта) -* `$responsibleID` - ID ответветственного (если нужно), по-умолчанию - не учитывать +* `$responsibleID` - ID ответственного (если нужно), по-умолчанию - не учитывать * `$intervalInDays` - сколько дней от `$startDate` нужно вычислять * `$checkPermissions` - проверять права на просмотр * `$limit` - количество возвращаемых элементов diff --git "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/11_\320\233\320\270\320\264/40_\320\232\320\276\320\275\320\262\320\265\321\200\321\202\320\260\321\206\320\270\321\217.md" "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/11_\320\233\320\270\320\264/40_\320\232\320\276\320\275\320\262\320\265\321\200\321\202\320\260\321\206\320\270\321\217.md" index 9901308..5509e4f 100644 --- "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/11_\320\233\320\270\320\264/40_\320\232\320\276\320\275\320\262\320\265\321\200\321\202\320\260\321\206\320\270\321\217.md" +++ "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/11_\320\233\320\270\320\264/40_\320\232\320\276\320\275\320\262\320\265\321\200\321\202\320\260\321\206\320\270\321\217.md" @@ -18,9 +18,9 @@ Специализированный модификатор проверяет тип лида и в случае если конвертируемый лид является повторным то на его основании можно создать только сделку. -Модификатор генерируемый на основании ролевой карты собирает максимальные права данного пользователя на создание сущностей и разрешает конвертацию только в те сущности на которые у текущего пользователя есть права добавления. Так, например, если у пользователя нет прав на создания сделки, то Лид нельзя будет конвертировать в Сделку, но будет возможность конвертировать в Контакт / Компанию и их вариации. +Модификатор генерируемый на основании ролевой карты собирает максимальные права данного пользователя на создание сущностей и разрешает конвертацию только в те сущности на которые у текущего пользователя есть права добавления. Так, например, если у пользователя нет прав на создание сделки, то Лид нельзя будет конвертировать в Сделку, но будет возможность конвертировать в Контакт / Компанию и их вариации. -Если смотреть в суть вещей, то и процесс создания одного элемена на основании другого и процесс создания подобных связей без непосредственного создания новых сущностей является конвертацией, однако чтобы различать их рамках статьи мы будем рассматривать их как 2 независимых процесса: +Если смотреть в суть вещей, то и процесс создания одного элемента на основании другого и процесс создания подобных связей без непосредственного создания новых сущностей является конвертацией и чтобы различать их в рамках статьи мы будем рассматривать как 2 независимых процесса: - Конвертация - как создание результатов на основании конвертируемого элемента - Псевдоконвертация - как создание связей для уже существующих элементов. @@ -34,14 +34,14 @@ Конвертационная схема состоит из следующих полей (описание таблицы): -| Поле | Тип | Описание | Примечание | -| :--- | --- | -------- | ---------- | -| SRC_TYPE_ID | int(1) / tinyint(1) unsigned | Идентификатор типа конвертируемого элемента | см. `\CCrmOwnerType` | -| DST_TYPE_ID | int(1) / tinyint(1) unsigned | Идентификатор типа результата конвертации | см. `\CCrmOwnerType` | -| LAST_UPDATED | datetime | Дата последнего обновления конвертационной схемы | | -| DATA | longtext | Сериализованная конвертационная карта | | -| RELATION_TYPE | varchar(20) | Тип конвертации | По-умолчанию `CONVERSION` | -| IS_CHILDREN_LIST_ENABLED | char(1) | Доступность в списке связей | по-умолчанию `Y` | +| Поле | Тип | Описание | Примечание | +|:-------------------------|------------------------------|--------------------------------------------------|---------------------------| +| SRC_TYPE_ID | int(1) / tinyint(1) unsigned | Идентификатор типа конвертируемого элемента | см. `\CCrmOwnerType` | +| DST_TYPE_ID | int(1) / tinyint(1) unsigned | Идентификатор типа результата конвертации | см. `\CCrmOwnerType` | +| LAST_UPDATED | datetime | Дата последнего обновления конвертационной схемы | | +| DATA | longtext | Сериализованная конвертационная карта | | +| RELATION_TYPE | varchar(20) | Тип конвертации | По-умолчанию `CONVERSION` | +| IS_CHILDREN_LIST_ENABLED | char(1) | Доступность в списке связей | по-умолчанию `Y` | Отдельно стоит остановиться на нововведениях: механизм Смарт-процессов позволяет привязывать созданный Смарт-процесс к элементам. Для реализации этой возможности были добавлены столбцы `RELATION_TYPE` и `IS_CHILDREN_LIST_ENABLED`. `RELATION_TYPE` - тип связи конвертационной схемы. В настоящий момент допустимы только 2 значения: `\Bitrix\Crm\Relation\RelationType::CONVERSION` (конвертация) и `\Bitrix\Crm\Relation\RelationType::BINDING` (связь). @@ -66,7 +66,7 @@ >Не стоит обольщаться наличием флагов `isLocked` и `isRequired` их значения в конверсионной карте никак не обрабатываются, поэтому не имеет значения установите вы параметры в true или false, так как результат будет одинаковый. -При создании конвертационных схем битрикс использует автоматический мехазним, который состоит из двух частей: +При создании конвертационных схем битрикс использует автоматический механизм, который состоит из двух частей: 1. Строго определенной стандартной частью 2. Работой с пользовательскими полями @@ -216,7 +216,7 @@ if ($item) // Enable syncronization fields $item->enableSynchronization(true); - // Setup initial data. Accepted only `defaultName` + // Setup initial data. Accepted only 'defaultName' $item->setInitData([ 'defaultName' => 'Default contact name', ]); @@ -233,7 +233,7 @@ if ($item) // Enable syncronization fields $item->enableSynchronization(true); - // Setup initial data. Accepted only `categoryId` + // Setup initial data. Accepted only 'categoryId' $item->setInitData([ 'categoryId' => (int) $dealCategoryId, ]); @@ -303,7 +303,7 @@ if ( !$conversionWizard->execute($contextData) ) { /** * Caught some error. You can see error text (string) - * with `$conversionWizard->getErrorText()` + * with '$conversionWizard->getErrorText()' */ } else @@ -319,7 +319,7 @@ else Помимо выполнения конвертационного процесса существует и псевдоконцвертация, т.е. создание связей без создания элементов. В разных сущностях этот процесс характеризуется своими особенностями. ->Поле `LEAD_ID` является универсальным для Сделок, Контактов и Компаний, однако это соверешенно не значит что механизм его обработки одинаковый. Не пытайтесь заполнить этот поле в СУБД через SQL запрос! Используйте `старое` api для его заполнения. +>Поле `LEAD_ID` является универсальным для Сделок, Контактов и Компаний, однако это совершенно не значит что механизм его обработки одинаковый. Не пытайтесь заполнить этот поле в СУБД через SQL запрос! Используйте `старое` api для его заполнения. Если получилась такая ситуация, что поле `LEAD_ID` в какой-либо сущности было заполнено прямым SQL-запросом, то для данного лида необходимо пересчитать статистические данные методом: @@ -329,4 +329,4 @@ use \Bitrix\Crm\Statistics; Statistics\LeadConversionStatisticsEntry::processBindingsChange($leadID); ``` -Таким образом для того чтобы проставить связи между существующими Контактом, Компанией или Сделкой с лидом достаточно просто обновить данный соответствующей сущности добавив в поле `LEAD_ID` идентификатор лида. \ No newline at end of file +Таким образом, для того чтобы проставить связи между существующими Контактом, Компанией или Сделкой с лидом достаточно просто обновить данный соответствующей сущности добавив в поле `LEAD_ID` идентификатор лида. \ No newline at end of file diff --git "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/12_\320\232\320\276\320\275\321\202\320\260\320\272\321\202/00_\320\236\320\277\320\270\321\201\320\260\320\275\320\270\320\265.md" "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/12_\320\232\320\276\320\275\321\202\320\260\320\272\321\202/00_\320\236\320\277\320\270\321\201\320\260\320\275\320\270\320\265.md" index 821d996..ae5bc60 100644 --- "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/12_\320\232\320\276\320\275\321\202\320\260\320\272\321\202/00_\320\236\320\277\320\270\321\201\320\260\320\275\320\270\320\265.md" +++ "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/12_\320\232\320\276\320\275\321\202\320\260\320\272\321\202/00_\320\236\320\277\320\270\321\201\320\260\320\275\320\270\320\265.md" @@ -1,7 +1,7 @@ # Описание сущности Контакт - это физическое лицо с которым ведется взаимодействие. Например: покупатель интернет-магазина или сотрудник компании-партнера. -В Битриксе представлен в виде обособленного справочника, а это значит что контакт не является пользователем вашей системы или сотрудником вашей компании. +В системе представлен в виде обособленного справочника, а это значит что контакт не является пользователем вашей системы или сотрудником вашей компании. >Перечень полей может изменяться и в зависимости от метода и способа вызова иметь различные аттрибуты. Конкретный перечень доступных полей необходимо смотреть в исходном коде метода который используется. @@ -10,60 +10,60 @@ В таблице указаны основные поля непосредственной сущности. -| Поле | Тип | Описание | Примечание | -| :--- | --- | ----------------------------------------------- | ---------- | -| ID | int | Уникальный целочисленный идентификатор | ``AI``, ``RO`` | -| HONORIFIC | crm_status | Обращение | Код справочника: HONORIFIC | -| NAME | string | Имя |``REQ``*| -| SECOND_NAME | string | Отчество || -| LAST_NAME | string | Фамилия |``REQ``*| -| FULL_NAME | string | Полное имя |``HID``| -| PHOTO | integer | Фотография | идентификатор файла из таблицы b_file | -| BIRTHDATE | date | Дата рождения || -| BIRTHDAY_SORT | integer | Универсальное число, получаемое из даты рождения для сортировки и поиска |``HID``| -| TYPE_ID | crm_status | Тип контакта | Код справочника: CONTACT_TYPE | -| SOURCE_ID | crm_status | Источник | Код справочника: SOURCE | -| SOURCE_DESCRIPTION | string | Дополнительно об источнике || -| POST | string | Должность || -| ADDRESS | string | Адрес | ``DEP`` | -| ADDRESS_2 | string | Адрес (стр. 2) | ``DEP`` | -| ADDRESS_CITY | string | Город | ``DEP`` | -| ADDRESS_POSTAL_CODE | string | Почтовый индекс | ``DEP`` | -| ADDRESS_REGION | string | Район | ``DEP`` | -| ADDRESS_PROVINCE | string | Область | ``DEP`` | -| ADDRESS_COUNTRY | string | Страна | ``DEP`` | -| ADDRESS_COUNTRY_CODE | string | Код страны | ``DEP`` | -| ADDRESS_LOC_ADDR_ID | integer | Идентификатор адреса местоположения | | -| COMMENTS | string | Комментарий | ``DEP`` | -| OPENED | char | Доступен для всех | Y/N | -| EXPORT | char | Участвует в экспорте контактов | Y/N | -| HAS_PHONE | char | Задан телефон, автоматически вычисляется при создании/обновлении | Y/N, ``RO`` | -| HAS_EMAIL | char | Задан e-mail, автоматически вычисляется при создании/обновлении | Y/N, ``RO`` | -| HAS_IMOL | char | Задана открытая линия, автоматически вычисляется при создании/обновлении | Y/N, ``RO`` | -| ASSIGNED_BY_ID | user | Ответственный || -| CREATED_BY_ID | user | Кем создан | ``RO`` | -| MODIFY_BY_ID | user | Кем изменен | ``RO`` | -| DATE_CREATE | datetime | Дата создания | ``RO`` | -| DATE_MODIFY | datetime | Дата изменения | ``RO`` | -| COMPANY_ID | crm_company | Компания | ``DEP``| -| COMPANY_IDS | crm_company | Компания | ``MUL``| -| LEAD_ID | crm_lead | Лид | ``RO`` | -| ORIGINATOR_ID | string | Внешний источник || -| ORIGIN_ID | string | Идентификатор элемента во внешнем источнике || -| ORIGIN_VERSION | string | Версия оригинала || -| FACE_ID | integer | Привязка к лицам из модуля faceid || -| UTM_SOURCE | string | Рекламная система || -| UTM_MEDIUM | string | Тип трафика || -| UTM_CAMPAIGN | string | Обозначение рекламной кампании || -| UTM_CONTENT | string | Содержание кампании || -| UTM_TERM | string | Условие поиска кампании || -| PHONE | crm_multifield | Телефон | ``RO``, ``MUL`` | -| EMAIL | crm_multifield | E-mail | ``RO``, ``MUL`` | -| WEB | crm_multifield | Сайт | ``RO``, ``MUL`` | -| IM | crm_multifield | Мессенджер | ``RO``, ``MUL`` | +| Поле | Тип | Описание | Примечание | +|:---------------------|----------------|--------------------------------------------------------------------------|---------------------------------------| +| ID | int | Уникальный целочисленный идентификатор | ``AI``, ``RO`` | +| HONORIFIC | crm_status | Обращение | Код справочника: HONORIFIC | +| NAME | string | Имя | ``REQ``* | +| SECOND_NAME | string | Отчество | | +| LAST_NAME | string | Фамилия | ``REQ``* | +| FULL_NAME | string | Полное имя | ``HID`` | +| PHOTO | integer | Фотография | идентификатор файла из таблицы b_file | +| BIRTHDATE | date | Дата рождения | | +| BIRTHDAY_SORT | integer | Универсальное число, получаемое из даты рождения для сортировки и поиска | ``HID`` | +| TYPE_ID | crm_status | Тип контакта | Код справочника: CONTACT_TYPE | +| SOURCE_ID | crm_status | Источник | Код справочника: SOURCE | +| SOURCE_DESCRIPTION | string | Дополнительно об источнике | | +| POST | string | Должность | | +| ADDRESS | string | Адрес | ``DEP`` | +| ADDRESS_2 | string | Адрес (стр. 2) | ``DEP`` | +| ADDRESS_CITY | string | Город | ``DEP`` | +| ADDRESS_POSTAL_CODE | string | Почтовый индекс | ``DEP`` | +| ADDRESS_REGION | string | Район | ``DEP`` | +| ADDRESS_PROVINCE | string | Область | ``DEP`` | +| ADDRESS_COUNTRY | string | Страна | ``DEP`` | +| ADDRESS_COUNTRY_CODE | string | Код страны | ``DEP`` | +| ADDRESS_LOC_ADDR_ID | integer | Идентификатор адреса местоположения | | +| COMMENTS | string | Комментарий | ``DEP`` | +| OPENED | char | Доступен для всех | Y/N | +| EXPORT | char | Участвует в экспорте контактов | Y/N | +| HAS_PHONE | char | Задан телефон, автоматически вычисляется при создании/обновлении | Y/N, ``RO`` | +| HAS_EMAIL | char | Задан e-mail, автоматически вычисляется при создании/обновлении | Y/N, ``RO`` | +| HAS_IMOL | char | Задана открытая линия, автоматически вычисляется при создании/обновлении | Y/N, ``RO`` | +| ASSIGNED_BY_ID | user | Ответственный | | +| CREATED_BY_ID | user | Кем создан | ``RO`` | +| MODIFY_BY_ID | user | Кем изменен | ``RO`` | +| DATE_CREATE | datetime | Дата создания | ``RO`` | +| DATE_MODIFY | datetime | Дата изменения | ``RO`` | +| COMPANY_ID | crm_company | Компания | ``DEP`` | +| COMPANY_IDS | crm_company | Компания | ``MUL`` | +| LEAD_ID | crm_lead | Лид | ``RO`` | +| ORIGINATOR_ID | string | Внешний источник | | +| ORIGIN_ID | string | Идентификатор элемента во внешнем источнике | | +| ORIGIN_VERSION | string | Версия оригинала | | +| FACE_ID | integer | Привязка к лицам из модуля faceid | | +| UTM_SOURCE | string | Рекламная система | | +| UTM_MEDIUM | string | Тип трафика | | +| UTM_CAMPAIGN | string | Обозначение рекламной кампании | | +| UTM_CONTENT | string | Содержание кампании | | +| UTM_TERM | string | Условие поиска кампании | | +| PHONE | crm_multifield | Телефон | ``RO``, ``MUL`` | +| EMAIL | crm_multifield | E-mail | ``RO``, ``MUL`` | +| WEB | crm_multifield | Сайт | ``RO``, ``MUL`` | +| IM | crm_multifield | Мессенджер | ``RO``, ``MUL`` | Примечание к перечисленным полям: -1. Для расшифровки типов можно обратиться к [Типам данных](../Словари/Типы_данных). +1. Для расшифровки типов можно обратиться к [Типам данных](../01_Словари/20_Типы_данных). 2. Для обозначения специальных полей используются дополнительные флаги: * ``RO`` - read only (поле только для чтения) diff --git "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/12_\320\232\320\276\320\275\321\202\320\260\320\272\321\202/10_\320\234\320\265\321\202\320\276\320\264\321\213.md" "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/12_\320\232\320\276\320\275\321\202\320\260\320\272\321\202/10_\320\234\320\265\321\202\320\276\320\264\321\213.md" index 4f7ce6e..e597af2 100644 --- "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/12_\320\232\320\276\320\275\321\202\320\260\320\272\321\202/10_\320\234\320\265\321\202\320\276\320\264\321\213.md" +++ "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/12_\320\232\320\276\320\275\321\202\320\260\320\272\321\202/10_\320\234\320\265\321\202\320\276\320\264\321\213.md" @@ -50,18 +50,18 @@ if ( \Bitrix\Main\Loader::IncludeModule('crm') ) Существует несколько способов получить перечень контактов из системы: старое API и DataManager. Каждый способ имеет свои преимущества и не достатки, что в конечном счете использовать должен выбрать разработчик. -| Сравнение |Старое API|DataManager| -| :--------------------------------: | -------- | --------- | -| Возможность получить данные из БД | v | v | -| Учет прав при получении | v | x | -| Простая фильтрация данных | v | v | -| Использование подзапросов для сложной фильтрации | x | v | +| Сравнение | Старое API | DataManager | +|:--------------------------------------------------|:----------:|:-----------:| +| Возможность получить данные из БД | v | v | +| Учет прав при получении | v | x | +| Простая фильтрация данных | v | v | +| Использование под запросов для сложной фильтрации | x | v | Резюмируя, в случае DataManager как преимущество можно выделить скорость работы и гибкость за счет трансляции кода в SQL запрос, в то время как использование старого api дает возможность использовать проверку прав. ### Используя старое API -Для получение контактов используя старое API используется метод ```CCrmContact::GetListEx``. +Для получения контактов используя старое API используется метод `CCrmContact::GetListEx`. Сигнатура метода: ```php @@ -75,7 +75,7 @@ $contactResult = CCrmContact::GetListEx( ); ``` -Механизм получения данных аналогичен [выборке из инфоблоков](http://dev.1c-bitrix.ru/api_help/iblock/classes/ciblockelement/getlist.php). По-умолчанию при выборке проверяются права текущего пользователя, поэтому чтобы получить все значения без проверки прав необходимо передать в фильтре флаг ``CHECK_PERMISSIONS`` с значением ``N``. +Механизм получения данных аналогичен [выборке из инфоблоков](http://dev.1c-bitrix.ru/api_help/iblock/classes/ciblockelement/getlist.php). По-умолчанию при выборке проверяются права текущего пользователя, поэтому для получения всех значений без проверки прав необходимо передать в фильтре флаг ``CHECK_PERMISSIONS`` со значением ``N``. Пример: необходимо получить ФИО и ID контактов, которые созданные 1 января 2021 года без учета прав пользователя, отсортированные по источнику (убыванию) @@ -114,7 +114,7 @@ while( $contact = $contactResult->fetch() ) #### Прямое указание LIMIT и OFFSET -При помощи параметра `QUERY_OPTIONS` в `$arOptions` имеется возможность задания таких параметров. Это очень удобно для двухступенчатой постаничной навигации, когда сначала выбираются ID элементов, а потом уже данные для полученных ID. +При помощи параметра `QUERY_OPTIONS` в `$arOptions` имеется возможность задания таких параметров. Это очень удобно для двухступенчатой постраничной навигации, когда сначала выбираются ID элементов, а потом уже данные для полученных ID. Пример запроса: ```php @@ -138,7 +138,7 @@ $contactResult = CCrmContact::GetListEx( #### Запросы с участием внешних таблиц в фильтре -Иногда бывает необходимость достать только те контакты, для которых есть запись в сторонней таблице. Для этого можно воспользоваться `__JOINS` ключем. +Иногда бывает необходимость достать только те контакты, для которых есть запись в сторонней таблице. Для этого можно воспользоваться `__JOINS` ключом. ```php @@ -367,7 +367,7 @@ if ( !$contactId ) } ``` ->Структура FM описывает коммуникационные поля. Если она вам незнакома, то рекомендуется изучить [соответствуюую статью](../Словари/Структуры_данных) +>Структура FM описывает коммуникационные поля. Если она вам незнакома, то рекомендуется изучить [соответствующую статью](../01_Словари/30_Структуры_данных) ## Обновление контакта @@ -385,7 +385,7 @@ public function Update($ID, array &$arFields, $bCompare = true, $bUpdateSearch = `$options` - дополнительные опции при обновлении контакта. Общий процесс обновления контакта: -1. Получение текущих данных по контакта +1. Получение текущих данных по контакту 2. Проверка обязательных полей 3. Проверка прав на изменение 4. Вызов события OnBeforeCrmContactUpdate. @@ -473,7 +473,7 @@ $isUpdateSuccess = $contactEntity->Update( * Отмечать кеш менеджера дубликатов для этого контакта. * @var boolean */ - `ENABLE_DUP_INDEX_INVALIDATION` => true, + 'ENABLE_DUP_INDEX_INVALIDATION' => true, /** * В случае true, битрикс создаст сообщение в ленту о изменении @@ -493,7 +493,7 @@ $isUpdateSuccess = $contactEntity->Update( * В случае если флаг true, не будет проверки * обязательности заполнения пользовательских полей * - * Если флаг `DISABLE_USER_FIELD_CHECK` установлен в true, + * Если флаг 'DISABLE_USER_FIELD_CHECK' установлен в true, * данный флаг игнорируется - проверок не будет * * Флаг не отменяет необходимость корректного заполнения @@ -515,7 +515,7 @@ if ( !$isUpdateSuccess ) } ``` ->Структура FM описывает коммуникационные поля. Если она вам незнакома, то рекомендуется изучить [соответствуюую статью](../Словари/Структуры_данных) +>Структура FM описывает коммуникационные поля. Если она вам незнакома, то рекомендуется изучить [соответствующую статью](../01_Словари/30_Структуры_данных) ## Удаление контакта diff --git "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/12_\320\232\320\276\320\275\321\202\320\260\320\272\321\202/20_C\320\276\320\261\321\213\321\202\320\270\321\217.md" "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/12_\320\232\320\276\320\275\321\202\320\260\320\272\321\202/20_C\320\276\320\261\321\213\321\202\320\270\321\217.md" index 803b80b..9ec26b0 100644 --- "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/12_\320\232\320\276\320\275\321\202\320\260\320\272\321\202/20_C\320\276\320\261\321\213\321\202\320\270\321\217.md" +++ "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/12_\320\232\320\276\320\275\321\202\320\260\320\272\321\202/20_C\320\276\320\261\321\213\321\202\320\270\321\217.md" @@ -2,17 +2,17 @@ [TOC] ->Помните, что события не проверяются на цикличный вызов, поэтому если во время создания элемента на событии вы попыпаетесь создать элемент, то вы можете породить бесконечный цикл. +>Помните, что события не проверяются на цикличный вызов, поэтому если во время создания элемента на событии вы попытаетесь создать элемент, то вы можете породить бесконечный цикл. >Событие не всегда содержит полный набор полей, поэтому хорошим тоном является проверять фактическое наличие ключа в массиве параметров и в случае его отсутствия заполнение либо дефолтным значением, либо обращение в базу данных для предотвращения неопределенного поведения. # OnBeforeCrmContactAdd -Событие вызываемое перед создание элемента методом `CCrmContact::Add`. +Событие вызываемое перед созданием элемента методом `CCrmContact::Add`. -| Параметр | Значение | -| :----------: | ---------------------- | -| &$arFields | Поля создаваемого контакта | +| Параметр | Значение | +|:-----------|----------------------------| +| &$arFields | Поля создаваемого контакта | Возвращаемое значение: boolean. `true` успешное выполнение. @@ -53,9 +53,9 @@ $eventManager->addEventHandlerCompatible( Событие вызываемое после успешного создания элемента методом `CCrmContact::Add`. -| Параметр | Значение | -| :----------: | ---------------------- | -| &$arFields | Поля создаваемого контакта | +| Параметр | Значение | +|:-----------|----------------------------| +| &$arFields | Поля создаваемого контакта | Возвращаемое значение не обрабатывается. @@ -81,9 +81,9 @@ $eventManager->addEventHandlerCompatible( Событие вызываемое перед обновлением элемента методом `CCrmContact::Update`. -| Параметр | Значение | -| :----------: | ---------------------- | -| &$arFields | Поля обновляемого элемента | +| Параметр | Значение | +|:-----------|----------------------------| +| &$arFields | Поля обновляемого элемента | Возвращаемое значение: boolean. `true` успешное выполнение. @@ -124,9 +124,9 @@ $eventManager->addEventHandlerCompatible( Событие вызываемое после успешного обновления элемента методом `CCrmContact::Update`. -| Параметр | Значение | -| :----------: | ---------------------- | -| &$arFields | Поля обновляемого контакта | +| Параметр | Значение | +|:-----------|----------------------------| +| &$arFields | Поля обновляемого контакта | Возвращаемое значение не обрабатывается. @@ -148,9 +148,9 @@ $eventManager->addEventHandlerCompatible( Событие вызываемое перед удалением элемента методом `CCrmContact::Delete` или перемещения в корзину. -| Параметр | Значение | -| :----------: | ------------------------------ | -| $id | Primary key удаляемой сущности | +| Параметр | Значение | +|:---------|--------------------------------| +| $id | Primary key удаляемой сущности | Возвращаемое значение: boolean. `true` успешное выполнение. @@ -191,9 +191,9 @@ $eventManager->addEventHandlerCompatible( Событие вызываемое после успешного удаления элемента методом `CCrmContact::Delete` или перемещения в корзину. -| Параметр | Значение | -| :----------: | ------------------------------ | -| $id | Primary key удаляемой сущности | +| Параметр | Значение | +|:---------|--------------------------------| +| $id | Primary key удаляемой сущности | Возвращаемое значение не обрабатывается. diff --git "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/12_\320\232\320\276\320\275\321\202\320\260\320\272\321\202/30_\320\237\321\200\320\270\320\274\320\265\321\200\321\213.md" "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/12_\320\232\320\276\320\275\321\202\320\260\320\272\321\202/30_\320\237\321\200\320\270\320\274\320\265\321\200\321\213.md" index 58ea4ed..80e7a03 100644 --- "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/12_\320\232\320\276\320\275\321\202\320\260\320\272\321\202/30_\320\237\321\200\320\270\320\274\320\265\321\200\321\213.md" +++ "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/12_\320\232\320\276\320\275\321\202\320\260\320\272\321\202/30_\320\237\321\200\320\270\320\274\320\265\321\200\321\213.md" @@ -73,7 +73,7 @@ while( $contact = $contactResult->fetch() ) # Множественные поля -Мы уже описали что Битрикс24 хранит множственные поля отдельно и часто возникает вопрос как работать с такими полями. Наиболее удобным способом является работа от API множественных полей. +Мы уже описали что Битрикс24 хранит множественные поля отдельно и часто возникает вопрос как работать с такими полями. Наиболее удобным способом является работа от API множественных полей. ## Получение всех телефонов контакта @@ -186,15 +186,15 @@ foreach($dups as &$dup) } ``` ->Телефонный номер в таблице дубликатов хранится в виде строки состоящей из чисел, поэтому предавая ее на поиск в менеджер дубликатов предварительно нужно очистить ненужные символы. +>Телефонный номер в таблице дубликатов хранится в виде строки состоящей из чисел, поэтому предавая ее на поиск в менеджере дубликатов предварительно нужно очистить ненужные символы. # Дата рождения ## Найти контакты, день рождения которых сегодня -Иногда необходимо найти контакты чье день рождения выпадает на определенное число или месяц. Так как не все СУБД поддерживают частичный поиск по полям с типом дата, разработчики использовали иной подход к подсистеме хранения даты рождения. При изменения даты рождения исходное значение сохраняется в поле `BIRTHDATE`, в то время как на основании дня и месяца рождения вычисляется специальное число хранящееся в поле `BIRTHDAY_SORT`. +Иногда необходимо найти контакты чье день рождения выпадает на определенное число или месяц. Так как не все СУБД поддерживают частичный поиск по полям с типом дата, разработчики использовали иной подход к подсистеме хранения даты рождения. При изменении даты рождения исходное значение сохраняется в поле `BIRTHDATE`, в то время как на основании дня и месяца рождения вычисляется специальное число хранящееся в поле `BIRTHDAY_SORT`. -Таким образом чтобы найти пользователя у которого день рождения выпадает на определенно число нужно: +Таким образом, чтобы найти пользователя у которого день рождения выпадает на определенно число нужно: 1. Сгенерировать число для данной даты 2. Выполнить поиск числа по ключу `BIRTHDAY_SORT` @@ -264,7 +264,7 @@ while( $contact = $contactResult->fetch() ) * `$entityID` - тип сущности. Поддерживается `\CCrmOwnerType::Lead` и `\CCrmOwnerType::Contact` * `$currentDate` - текущая дата в формате сайта * `$startDate` - дата с которой нужно начинать поиск (в формате сайта) -* `$responsibleID` - ID ответветственного (если нужно), по-умолчанию - не учитывать +* `$responsibleID` - ID ответственного (если нужно), по-умолчанию - не учитывать * `$intervalInDays` - сколько дней от `$startDate` нужно вычислять * `$checkPermissions` - проверять права на просмотр * `$limit` - количество возвращаемых элементов diff --git "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/13_\320\232\320\276\320\274\320\277\320\260\320\275\320\270\321\217/00_\320\236\320\277\320\270\321\201\320\260\320\275\320\270\320\265.md" "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/13_\320\232\320\276\320\274\320\277\320\260\320\275\320\270\321\217/00_\320\236\320\277\320\270\321\201\320\260\320\275\320\270\320\265.md" index b7212a4..c48c505 100644 --- "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/13_\320\232\320\276\320\274\320\277\320\260\320\275\320\270\321\217/00_\320\236\320\277\320\270\321\201\320\260\320\275\320\270\320\265.md" +++ "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/13_\320\232\320\276\320\274\320\277\320\260\320\275\320\270\321\217/00_\320\236\320\277\320\270\321\201\320\260\320\275\320\270\320\265.md" @@ -1,71 +1,71 @@ # Описание сущности Компания - это юридическое лицо с которым ведется взаимодействие. -В Битриксе представлен в виде обособленного справочника, имеющего связи с другими подсистемами. +В системе представлен в виде обособленного справочника, имеющего связи с другими подсистемами. >Перечень полей может изменяться и в зависимости от метода и способа вызова иметь различные аттрибуты. Конкретный перечень доступных полей необходимо смотреть в исходном коде метода который используется. # Поля -| Поле | Тип | Описание | Примечание | -| :--- | --- | ----------------------------------------------- | ---------- | -| ID | int | Уникальный целочисленный идентификатор лида | ``AI``, ``RO`` | -| TITLE | string | Название компании |``REQ``*| -| COMPANY_TYPE | crm_status | Тип компании | Код справочника: COMPANY_TYPE | -| LOGO | file | Логотип | integet | -| ADDRESS | string | Фактический адрес | ``DEP`` | -| ADDRESS_2 | string | Адрес (стр. 2) | ``DEP`` | -| ADDRESS_CITY | string | Город | ``DEP`` | -| ADDRESS_POSTAL_CODE | string | Почтовый индекс | ``DEP`` | -| ADDRESS_REGION | string | Район | ``DEP`` | -| ADDRESS_PROVINCE | string | Область | ``DEP`` | -| ADDRESS_COUNTRY | string | Страна | ``DEP`` | -| ADDRESS_COUNTRY_CODE | string | Код страны | ``DEP`` | -| ADDRESS_LOC_ADDR_ID | integer | Идентификатор адреса местоположения | ``DEP`` -| ADDRESS_LEGAL | string | Юридический адрес | ``DEP`` | -| REG_ADDRESS | string | Юридический адрес | ``DEP`` | -| REG_ADDRESS_2 | string | Юридический адрес (стр. 2) | ``DEP`` | -| REG_ADDRESS_CITY | string | Юридический адрес город | ``DEP`` | -| REG_ADDRESS_POSTAL_CODE | string | Юридический адрес почтовый индекс | ``DEP`` | -| REG_ADDRESS_REGION | string | Юридический адрес район | ``DEP`` | -| REG_ADDRESS_PROVINCE | string | Юридический адрес область | ``DEP`` | -| REG_ADDRESS_COUNTRY | string | Юридический адрес страна | ``DEP`` | -| REG_ADDRESS_COUNTRY_CODE | string | Юридический адрес код страны | ``DEP`` | -| REG_ADDRESS_LOC_ADDR_ID | string | Юридический адрес идентификатор адреса местоположения | ``DEP`` | -| BANKING_DETAILS | string | Банковские реквизиты | | -| INDUSTRY | crm_status | Сфера деятельности | Код справочника: INDUSTRY | -| EMPLOYEES | crm_status | Кол-во сотрудников | Код справочника: EMPLOYEES | -| CURRENCY_ID | crm_currency | Валюта | | -| REVENUE | double | Годовой оборот | | -| OPENED | char | Доступна для всех | | -| COMMENTS | string | Комментарий | | -| HAS_PHONE | char | Задан телефон, автоматически вычисляется при создании/обновлении | Y/N, ``RO`` | -| HAS_EMAIL | char | Задан e-mail, автоматически вычисляется при создании/обновлении | Y/N, ``RO`` | -| HAS_IMOL | char | Задана открытая линия, автоматически вычисляется при создании/обновлении | Y/N, ``RO`` | -| IS_MY_COMPANY | char | Моя компания | Y/N, ``RO`` | -| ASSIGNED_BY_ID | user | Ответственный || -| CREATED_BY_ID | user | Кем создана | ``RO`` | -| MODIFY_BY_ID | user | Кем изменен | ``RO`` | -| DATE_CREATE | datetime | Дата создания | ``RO`` | -| DATE_MODIFY | datetime | Дата изменения | ``RO`` | -| CONTACT_ID | crm_contact | Контакт | ``MUL`` | -| LEAD_ID | crm_lead | Лид | ``RO`` | -| ORIGINATOR_ID | string | Внешний источник || -| ORIGIN_ID | string | Идентификатор элемента во внешнем источнике || -| ORIGIN_VERSION | string | Версия оригинала || -| UTM_SOURCE | string | Рекламная система || -| UTM_MEDIUM | string | Тип трафика || -| UTM_CAMPAIGN | string | Обозначение рекламной кампании || -| UTM_CONTENT | string | Содержание кампании || -| UTM_TERM | string | Условие поиска кампании || -| PHONE | crm_multifield | Телефон | ``MUL`` | -| EMAIL | crm_multifield | E-mail | ``MUL`` | -| WEB | crm_multifield | Сайт | ``MUL`` | -| IM | crm_multifield | Мессенджер | ``MUL`` | +| Поле | Тип | Описание | Примечание | +|:-------------------------|----------------|--------------------------------------------------------------------------|-------------------------------| +| ID | int | Уникальный целочисленный идентификатор лида | ``AI``, ``RO`` | +| TITLE | string | Название компании | ``REQ``* | +| COMPANY_TYPE | crm_status | Тип компании | Код справочника: COMPANY_TYPE | +| LOGO | file | Логотип | integer | +| ADDRESS | string | Фактический адрес | ``DEP`` | +| ADDRESS_2 | string | Адрес (стр. 2) | ``DEP`` | +| ADDRESS_CITY | string | Город | ``DEP`` | +| ADDRESS_POSTAL_CODE | string | Почтовый индекс | ``DEP`` | +| ADDRESS_REGION | string | Район | ``DEP`` | +| ADDRESS_PROVINCE | string | Область | ``DEP`` | +| ADDRESS_COUNTRY | string | Страна | ``DEP`` | +| ADDRESS_COUNTRY_CODE | string | Код страны | ``DEP`` | +| ADDRESS_LOC_ADDR_ID | integer | Идентификатор адреса местоположения | ``DEP`` | +| ADDRESS_LEGAL | string | Юридический адрес | ``DEP`` | +| REG_ADDRESS | string | Юридический адрес | ``DEP`` | +| REG_ADDRESS_2 | string | Юридический адрес (стр. 2) | ``DEP`` | +| REG_ADDRESS_CITY | string | Юридический адрес город | ``DEP`` | +| REG_ADDRESS_POSTAL_CODE | string | Юридический адрес почтовый индекс | ``DEP`` | +| REG_ADDRESS_REGION | string | Юридический адрес район | ``DEP`` | +| REG_ADDRESS_PROVINCE | string | Юридический адрес область | ``DEP`` | +| REG_ADDRESS_COUNTRY | string | Юридический адрес страна | ``DEP`` | +| REG_ADDRESS_COUNTRY_CODE | string | Юридический адрес код страны | ``DEP`` | +| REG_ADDRESS_LOC_ADDR_ID | string | Юридический адрес идентификатор адреса местоположения | ``DEP`` | +| BANKING_DETAILS | string | Банковские реквизиты | | +| INDUSTRY | crm_status | Сфера деятельности | Код справочника: INDUSTRY | +| EMPLOYEES | crm_status | Кол-во сотрудников | Код справочника: EMPLOYEES | +| CURRENCY_ID | crm_currency | Валюта | | +| REVENUE | double | Годовой оборот | | +| OPENED | char | Доступна для всех | | +| COMMENTS | string | Комментарий | | +| HAS_PHONE | char | Задан телефон, автоматически вычисляется при создании/обновлении | Y/N, ``RO`` | +| HAS_EMAIL | char | Задан e-mail, автоматически вычисляется при создании/обновлении | Y/N, ``RO`` | +| HAS_IMOL | char | Задана открытая линия, автоматически вычисляется при создании/обновлении | Y/N, ``RO`` | +| IS_MY_COMPANY | char | Моя компания | Y/N, ``RO`` | +| ASSIGNED_BY_ID | user | Ответственный | | +| CREATED_BY_ID | user | Кем создана | ``RO`` | +| MODIFY_BY_ID | user | Кем изменен | ``RO`` | +| DATE_CREATE | datetime | Дата создания | ``RO`` | +| DATE_MODIFY | datetime | Дата изменения | ``RO`` | +| CONTACT_ID | crm_contact | Контакт | ``MUL`` | +| LEAD_ID | crm_lead | Лид | ``RO`` | +| ORIGINATOR_ID | string | Внешний источник | | +| ORIGIN_ID | string | Идентификатор элемента во внешнем источнике | | +| ORIGIN_VERSION | string | Версия оригинала | | +| UTM_SOURCE | string | Рекламная система | | +| UTM_MEDIUM | string | Тип трафика | | +| UTM_CAMPAIGN | string | Обозначение рекламной кампании | | +| UTM_CONTENT | string | Содержание кампании | | +| UTM_TERM | string | Условие поиска кампании | | +| PHONE | crm_multifield | Телефон | ``MUL`` | +| EMAIL | crm_multifield | E-mail | ``MUL`` | +| WEB | crm_multifield | Сайт | ``MUL`` | +| IM | crm_multifield | Мессенджер | ``MUL`` | Примечание к перечисленным полям: -1. Для расшифровки типов можно обратиться к [Типам данных](../Словари/Типы_данных). +1. Для расшифровки типов можно обратиться к [Типам данных](../01_Словари/20_Типы_данных). 2. Для обозначения специальных полей используются дополнительные флаги: * ``RO`` - read only (поле только для чтения) @@ -76,4 +76,4 @@ 3. Не следует использовать поля `ORIGINATOR_ID`, `ORIGIN_ID` и `ORIGIN_VERSION` для хранения внешних ключей при синхронизации. Эти поля заполняются исключительно при создании из внешних систем и не должны изменяться при обновлении. -4. Не следует опираться на поля `ADDRESS`, `REG_ADDRESS`, `BANKING_DETAILS` так как не смотря на то что они работают и в некоторых подсистемах еще поддерживается обратная совместимость использование этих полей не рекомендуется. Лучше воспользоваться реквизитами и хранить необходимые данные там. \ No newline at end of file +4. Не следует опираться на поля `ADDRESS`, `REG_ADDRESS`, `BANKING_DETAILS` так как, несмотря на то что они работают и в некоторых подсистемах еще поддерживается обратная совместимость использование этих полей не рекомендуется. Лучше воспользоваться реквизитами и хранить необходимые данные там. \ No newline at end of file diff --git "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/13_\320\232\320\276\320\274\320\277\320\260\320\275\320\270\321\217/10_\320\234\320\265\321\202\320\276\320\264\321\213.md" "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/13_\320\232\320\276\320\274\320\277\320\260\320\275\320\270\321\217/10_\320\234\320\265\321\202\320\276\320\264\321\213.md" index f70c5bb..3457896 100644 --- "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/13_\320\232\320\276\320\274\320\277\320\260\320\275\320\270\321\217/10_\320\234\320\265\321\202\320\276\320\264\321\213.md" +++ "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/13_\320\232\320\276\320\274\320\277\320\260\320\275\320\270\321\217/10_\320\234\320\265\321\202\320\276\320\264\321\213.md" @@ -2,7 +2,7 @@ Компания это комплексная структура состоящая из нескольких составных частей: основные данные, множественные поля, пользовательские поля, реквизиты (как включая адреса, так и не включая). В рамках данной статьи мы будем рассматривать исключительно поля, т.е. поля непосредственно привязанные к компании: основные данные, множественные и пользовательские поля. -Во многих подсистемах (генерация документов, счетов) подразумевается что взаимодействие осуществляется между двумя юр.лицами (клиентом и владельцем Битрикс24), поэтому для удобства хранения разработчики решили использовать тот же механизм для хранения юридических лиц владельцев битрикса - "Моя компания". Технически они хранятся в тех же таблицах (с той лишь разницей что значение поля `IS_MY_COMPANY` = `Y`), но отображение этих компаний есть только на странице настроек CRM. +Во многих подсистемах (генерация документов, счетов) подразумевается что взаимодействие осуществляется между двумя юр.лицами (клиентом и владельцем Битрикс24), поэтому для удобства хранения разработчики решили использовать тот же механизм для хранения юридических лиц владельцев битрикса - "Моя компания". Технически они хранятся в тех же таблицах (с той лишь разницей, что значение поля `IS_MY_COMPANY` = `Y`), но отображение этих компаний есть только на странице настроек CRM. [TOC] @@ -51,18 +51,18 @@ if ( \Bitrix\Main\Loader::IncludeModule('crm') ) Существует несколько способов получить перечень компаний из системы: старое API и DataManager. Каждый способ имеет свои преимущества и не достатки, что в конечном счете использовать должен выбрать разработчик. -| Сравнение |Старое API|DataManager| -| :--------------------------------: | -------- | --------- | -| Возможность получить данные из БД | v | v | -| Учет прав при получении | v | x | -| Простая фильтрация данных | v | v | -| Использование подзапросов для сложной фильтрации | x | v | +| Сравнение | Старое API | DataManager | +|:--------------------------------------------------|------------|-------------| +| Возможность получить данные из БД | v | v | +| Учет прав при получении | v | x | +| Простая фильтрация данных | v | v | +| Использование под запросов для сложной фильтрации | x | v | Резюмируя, в случае DataManager как преимущество можно выделить скорость работы и гибкость за счет трансляции кода в SQL запрос, в то время как использование старого api дает возможность использовать проверку прав. ### Используя старое API -Для получение лидов используя старое API используется метод ```CCrmCompany::GetListEx``. +Для получения лидов используя старое API используется метод `CCrmCompany::GetListEx`. Сигнатура метода: ```php @@ -76,7 +76,7 @@ $entityResult = \CCrmCompany::GetListEx( ); ``` -Механизм получения данных аналогичен [выборке из инфоблоков](http://dev.1c-bitrix.ru/api_help/iblock/classes/ciblockelement/getlist.php). По-умолчанию при выборке проверяются права текущего пользователя, поэтому чтобы получить все значения без проверки прав необходимо передать в фильтре флаг ``CHECK_PERMISSIONS`` с значением ``N``. +Механизм получения данных аналогичен [выборке из инфоблоков](http://dev.1c-bitrix.ru/api_help/iblock/classes/ciblockelement/getlist.php). По-умолчанию при выборке проверяются права текущего пользователя, поэтому для получения всех значений без проверки прав необходимо передать в фильтре флаг ``CHECK_PERMISSIONS`` со значением ``N``. Пример: необходимо получить Название и ID компаний, которые созданы 1 января 2021 года без учета прав пользователя, отсортированные по источнику (убыванию) @@ -115,7 +115,7 @@ while( $entity = $entityResult->fetch() ) #### Прямое указание LIMIT и OFFSET -При помощи параметра `QUERY_OPTIONS` в `$arOptions` имеется возможность задания таких параметров. Это очень удобно для двухступенчатой постаничной навигации, когда сначала выбираются ID элементов, а потом уже данные для полученных ID. +При помощи параметра `QUERY_OPTIONS` в `$arOptions` имеется возможность задания таких параметров. Это очень удобно для двухступенчатой постраничной навигации, когда сначала выбираются ID элементов, а потом уже данные для полученных ID. Пример запроса: ```php @@ -139,7 +139,7 @@ $entityResult = \CCrmCompany::GetListEx( #### Запросы с участием внешних таблиц в фильтре -Иногда бывает необходимость достать только те элементы, для которых есть запись в сторонней таблице. Для этого можно воспользоваться `__JOINS` ключем. +Иногда бывает необходимость достать только те элементы, для которых есть запись в сторонней таблице. Для этого можно воспользоваться `__JOINS` ключом. ```php @@ -363,7 +363,7 @@ if ( !$entityId ) } ``` ->Структура FM описывает коммуникационные поля. Если она вам незнакома, то рекомендуется изучить [соответствуюую статью](../Словари/Структуры_данных) +>Структура FM описывает коммуникационные поля. Если она вам незнакома, то рекомендуется изучить [соответствующую статью](../01_Словари/30_Структуры_данных) ## Обновление компании @@ -447,6 +447,7 @@ $isUpdateSuccess = $entityObject->Update( $entityId, $entityFields, $bCompare = true, + $bUpdateSearch = true, $arOptions = [ /** * ID пользователя, от лица которого выполняется действие @@ -509,7 +510,7 @@ if ( !$isUpdateSuccess ) } ``` ->Структура FM описывает коммуникационные поля. Если она вам незнакома, то рекомендуется изучить [соответствуюую статью](../Словари/Структуры_данных) +>Структура FM описывает коммуникационные поля. Если она вам незнакома, то рекомендуется изучить [соответствующую статью](../01_Словари/30_Структуры_данных) ## Удаление компании diff --git "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/13_\320\232\320\276\320\274\320\277\320\260\320\275\320\270\321\217/20_C\320\276\320\261\321\213\321\202\320\270\321\217.md" "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/13_\320\232\320\276\320\274\320\277\320\260\320\275\320\270\321\217/20_C\320\276\320\261\321\213\321\202\320\270\321\217.md" index f1be704..f2d5d01 100644 --- "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/13_\320\232\320\276\320\274\320\277\320\260\320\275\320\270\321\217/20_C\320\276\320\261\321\213\321\202\320\270\321\217.md" +++ "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/13_\320\232\320\276\320\274\320\277\320\260\320\275\320\270\321\217/20_C\320\276\320\261\321\213\321\202\320\270\321\217.md" @@ -2,17 +2,17 @@ [TOC] ->Помните, что события не проверяются на цикличный вызов, поэтому если во время создания элемента на событии вы попыпаетесь создать элемент, то вы можете породить бесконечный цикл. +>Помните, что события не проверяются на цикличный вызов, поэтому если во время создания элемента на событии вы попытаетесь создать элемент, то вы можете породить бесконечный цикл. >Событие не всегда содержит полный набор полей, поэтому хорошим тоном является проверять фактическое наличие ключа в массиве параметров и в случае его отсутствия заполнение либо дефолтным значением, либо обращение в базу данных для предотвращения неопределенного поведения. # OnBeforeCrmCompanyAdd -Событие вызываемое перед создание элемента методом `CCrmCompany::Add`. +Событие вызываемое перед созданием элемента методом `CCrmCompany::Add`. -| Параметр | Значение | -| :----------: | ---------------------- | -| &$arFields | Поля создаваемого элемента | +| Параметр | Значение | +|:-----------|----------------------------| +| &$arFields | Поля создаваемого элемента | Возвращаемое значение: boolean. `true` успешное выполнение. @@ -53,9 +53,9 @@ $eventManager->addEventHandlerCompatible( Событие вызываемое после успешного создания элемента методом `CCrmCompany::Add`. -| Параметр | Значение | -| :----------: | ---------------------- | -| &$arFields | Поля создаваемого элемента | +| Параметр | Значение | +|:-----------|----------------------------| +| &$arFields | Поля создаваемого элемента | Возвращаемое значение не обрабатывается. @@ -81,9 +81,9 @@ $eventManager->addEventHandlerCompatible( Событие вызываемое перед обновлением элемента методом `CCrmCompany::Update`. -| Параметр | Значение | -| :----------: | ---------------------- | -| &$arFields | Поля обновляемой компании | +| Параметр | Значение | +|:-----------|---------------------------| +| &$arFields | Поля обновляемой компании | Возвращаемое значение: boolean. `true` успешное выполнение. @@ -124,9 +124,9 @@ $eventManager->addEventHandlerCompatible( Событие вызываемое после успешного обновления элемента методом `CCrmCompany::Update`. -| Параметр | Значение | -| :----------: | ---------------------- | -| &$arFields | Поля обновляемой компании | +| Параметр | Значение | +|:-----------|---------------------------| +| &$arFields | Поля обновляемой компании | Возвращаемое значение не обрабатывается. @@ -148,9 +148,9 @@ $eventManager->addEventHandlerCompatible( Событие вызываемое перед удалением элемента методом `CCrmCompany::Delete` или перемещения в корзину. -| Параметр | Значение | -| :----------: | ------------------------------ | -| $id | Primary key удаляемой сущности | +| Параметр | Значение | +|:---------|--------------------------------| +| $id | Primary key удаляемой сущности | Возвращаемое значение: boolean. `true` успешное выполнение. @@ -191,9 +191,9 @@ $eventManager->addEventHandlerCompatible( Событие вызываемое после успешного удаления элемента методом `CCrmCompany::Delete` или перемещения в корзину. -| Параметр | Значение | -| :----------: | ------------------------------ | -| $id | Primary key удаляемой сущности | +| Параметр | Значение | +|:---------|--------------------------------| +| $id | Primary key удаляемой сущности | Возвращаемое значение не обрабатывается. diff --git "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/13_\320\232\320\276\320\274\320\277\320\260\320\275\320\270\321\217/30_\320\237\321\200\320\270\320\274\320\265\321\200\321\213.md" "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/13_\320\232\320\276\320\274\320\277\320\260\320\275\320\270\321\217/30_\320\237\321\200\320\270\320\274\320\265\321\200\321\213.md" index d6b4271..4c71bb6 100644 --- "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/13_\320\232\320\276\320\274\320\277\320\260\320\275\320\270\321\217/30_\320\237\321\200\320\270\320\274\320\265\321\200\321\213.md" +++ "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/13_\320\232\320\276\320\274\320\277\320\260\320\275\320\270\321\217/30_\320\237\321\200\320\270\320\274\320\265\321\200\321\213.md" @@ -73,7 +73,7 @@ while( $entity = $entityResult->fetch() ) # Множественные поля -Мы уже описали что Битрикс24 хранит множственные поля отдельно и часто возникает вопрос как работать с такими полями. Наиболее удобным способом является работа от API множественных полей. +Мы уже описали что Битрикс24 хранит множественные поля отдельно и часто возникает вопрос как работать с такими полями. Наиболее удобным способом является работа от API множественных полей. ## Получение всех телефонов компании @@ -186,4 +186,4 @@ foreach($dups as &$dup) } ``` ->Телефонный номер в таблице дубликатов хранится в виде строки состоящей из чисел, поэтому предавая ее на поиск в менеджер дубликатов предварительно нужно очистить ненужные символы. \ No newline at end of file +>Телефонный номер в таблице дубликатов хранится в виде строки состоящей из чисел, поэтому предавая ее на поиск в менеджере дубликатов предварительно нужно очистить ненужные символы. \ No newline at end of file diff --git "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/14_\320\241\320\264\320\265\320\273\320\272\320\260/00_\320\236\320\277\320\270\321\201\320\260\320\275\320\270\320\265.md" "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/14_\320\241\320\264\320\265\320\273\320\272\320\260/00_\320\236\320\277\320\270\321\201\320\260\320\275\320\270\320\265.md" index 4d917cd..1c97876 100644 --- "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/14_\320\241\320\264\320\265\320\273\320\272\320\260/00_\320\236\320\277\320\270\321\201\320\260\320\275\320\270\320\265.md" +++ "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/14_\320\241\320\264\320\265\320\273\320\272\320\260/00_\320\236\320\277\320\270\321\201\320\260\320\275\320\270\320\265.md" @@ -6,57 +6,57 @@ # Поля -| Поле | Тип | Описание | Примечание | -| :--- | --- | ----------------------------------------------- | ---------- | -| ID | int | Уникальный целочисленный идентификатор | ``AI``, ``RO`` | -| TITLE | string | Название сделки |``REQ``| -| TYPE_ID | crm_status | Тип компании | Код справочника: `DEAL_TYPE` | -| CATEGORY_ID | crm_category | Направление сделки | | -| STAGE_ID | crm_status | Стадия | Код справочника: `DEAL_STAGE` | -| STAGE_SEMANTIC_ID | char | Семантическая стадия | ``RO`` | -| IS_NEW | char | Сделка только что создана | ``RO`` | -| IS_RECURRING | char | Флаг регулярности | Y/N | -| IS_RETURN_CUSTOMER | char | Сделка от существующего клиента | Y/N | -| IS_REPEATED_APPROACH | char | Сделка для повторного обращения | Y/N | -| PROBABILITY | int | Вероятность | | -| CURRENCY_ID | crm_currency | Валюта | | -| OPPORTUNITY | double | Сумма | | -| IS_MANUAL_OPPORTUNITY | char | Флаг, означающий что сумма сделки установлена вручную, а не рассчитана на основании товарных позиций | Y/N | -| TAX_VALUE | double | Ставка налога | | -| EXCH_RATE | double | Курс конвертации | ``RO`` | -| ACCOUNT_CURRENCY_ID | string | Валюта для отчетов | ``RO`` | -| OPPORTUNITY_ACCOUNT | double | Сумма для отчетов | ``RO`` | -| TAX_VALUE_ACCOUNT | double | Налог для отчетов | ``RO`` | -| COMPANY_ID | crm_company | Компания | | -| CONTACT_ID | crm_contact | Контакт | ``DEP``, используйте `CONTACT_IDS` | -| CONTACT_IDS | crm_contact | Контакты | ``MUL`` | -| QUOTE_ID | crm_quote | Ком.пред | ``RO`` | -| BEGINDATE | date | Дата начала | | -| CLOSEDATE | date | Дата окончания | | -| OPENED | char | Доступна для всех | Y/N | -| CLOSED | char | Сделка закрыта | Y/N | -| COMMENTS | string | Комментарий | | -| ASSIGNED_BY_ID | user | Ответственный | | -| CREATED_BY_ID | user | Кем создана | ``RO`` | -| MODIFY_BY_ID | user | Кем изменена | ``RO`` | -| DATE_CREATE | datetime | Дата создания | ``RO`` | -| DATE_MODIFY | datetime | Дата изменения | ``RO`` | -| SOURCE_ID | crm_status | Стадия | Код справочника: `SOURCE` | -| SOURCE_DESCRIPTION | string | Примечание к источнику | | -| LEAD_ID | crm_lead | Лид | ``RO`` | -| ADDITIONAL_INFO | string | Дополнительная информация | | -| LOCATION_ID | location | Местоположение | | -| ORIGINATOR_ID | string | Внешний источник | | -| ORIGIN_ID | string | Идентификатор элемента во внешнем источнике | | -| UTM_SOURCE | string | Рекламная система | | -| UTM_MEDIUM | string | Тип трафика | | -| UTM_CAMPAIGN | string | Обозначение рекламной кампании | | -| UTM_CONTENT | string | Содержание кампании | | -| UTM_TERM | string | Условие поиска кампании | | +| Поле | Тип | Описание | Примечание | +|:----------------------|--------------|------------------------------------------------------------------------------------------------------|------------------------------------| +| ID | int | Уникальный целочисленный идентификатор | ``AI``, ``RO`` | +| TITLE | string | Название сделки | ``REQ`` | +| TYPE_ID | crm_status | Тип компании | Код справочника: `DEAL_TYPE` | +| CATEGORY_ID | crm_category | Направление сделки | | +| STAGE_ID | crm_status | Стадия | Код справочника: `DEAL_STAGE` | +| STAGE_SEMANTIC_ID | char | Семантическая стадия | ``RO`` | +| IS_NEW | char | Сделка только что создана | ``RO`` | +| IS_RECURRING | char | Флаг регулярности | Y/N | +| IS_RETURN_CUSTOMER | char | Сделка от существующего клиента | Y/N | +| IS_REPEATED_APPROACH | char | Сделка для повторного обращения | Y/N | +| PROBABILITY | int | Вероятность | | +| CURRENCY_ID | crm_currency | Валюта | | +| OPPORTUNITY | double | Сумма | | +| IS_MANUAL_OPPORTUNITY | char | Флаг, означающий что сумма сделки установлена вручную, а не рассчитана на основании товарных позиций | Y/N | +| TAX_VALUE | double | Ставка налога | | +| EXCH_RATE | double | Курс конвертации | ``RO`` | +| ACCOUNT_CURRENCY_ID | string | Валюта для отчетов | ``RO`` | +| OPPORTUNITY_ACCOUNT | double | Сумма для отчетов | ``RO`` | +| TAX_VALUE_ACCOUNT | double | Налог для отчетов | ``RO`` | +| COMPANY_ID | crm_company | Компания | | +| CONTACT_ID | crm_contact | Контакт | ``DEP``, используйте `CONTACT_IDS` | +| CONTACT_IDS | crm_contact | Контакты | ``MUL`` | +| QUOTE_ID | crm_quote | Ком.пред | ``RO`` | +| BEGINDATE | date | Дата начала | | +| CLOSEDATE | date | Дата окончания | | +| OPENED | char | Доступна для всех | Y/N | +| CLOSED | char | Сделка закрыта | Y/N | +| COMMENTS | string | Комментарий | | +| ASSIGNED_BY_ID | user | Ответственный | | +| CREATED_BY_ID | user | Кем создана | ``RO`` | +| MODIFY_BY_ID | user | Кем изменена | ``RO`` | +| DATE_CREATE | datetime | Дата создания | ``RO`` | +| DATE_MODIFY | datetime | Дата изменения | ``RO`` | +| SOURCE_ID | crm_status | Стадия | Код справочника: `SOURCE` | +| SOURCE_DESCRIPTION | string | Примечание к источнику | | +| LEAD_ID | crm_lead | Лид | ``RO`` | +| ADDITIONAL_INFO | string | Дополнительная информация | | +| LOCATION_ID | location | Местоположение | | +| ORIGINATOR_ID | string | Внешний источник | | +| ORIGIN_ID | string | Идентификатор элемента во внешнем источнике | | +| UTM_SOURCE | string | Рекламная система | | +| UTM_MEDIUM | string | Тип трафика | | +| UTM_CAMPAIGN | string | Обозначение рекламной кампании | | +| UTM_CONTENT | string | Содержание кампании | | +| UTM_TERM | string | Условие поиска кампании | | Примечание к перечисленным полям: -1. Для расшифровки типов можно обратиться к [Типам данных](../Словари/Типы_данных). +1. Для расшифровки типов можно обратиться к [Типам данных](../01_Словари/20_Типы_данных). 2. Для обозначения специальных полей используются дополнительные флаги: * ``RO`` - read only (поле только для чтения) @@ -71,7 +71,7 @@ Только что созданная сделка (где не выполнялось никаких обновлений) будет помечена флагом `Y` в поле `IS_NEW`, после первого изменения он будет изменен на `N`. -Если сделка привязана к лиду от существующего клиента (т.е. лид помечен от повторного обращения) и при этом она не привязана к контакту или компании то она будет помечена флагом `Y` в поле `IS_REPEATED_APPROACH` что означает что сделка является повторным обращением. +Если сделка привязана к лиду от существующего клиента (т.е. лид помечен от повторного обращения) и при этом она не привязана к контакту или компании, то она будет помечена флагом `Y` в поле `IS_REPEATED_APPROACH` что означает что сделка является повторным обращением. Если к сделке привязан хоть один контакт или компания и при этом у них существует хоть одна успешная сделка, то сделка будет помечена как флагом `Y` в поле `IS_RETURN_CUSTOMER`, что означает повторная продажа. При этом флаги `IS_REPEATED_APPROACH` и `IS_RETURN_CUSTOMER` являются взаимоисключающими. -При этом при определении по уровню контакта и компании имеется строгий приоритет: Компания -> Контакт. Это означает что при проверке сделки если указана компания то определение сделок по контакту будут игнорироваться. Например: при создании сделки с контактом Х и компанией У проверка будет проводиться только по завершенным сделкам компании У, без проверки на завершенные сделки контакта Х. \ No newline at end of file +При этом при определении по уровню контакта и компании имеется строгий приоритет: Компания -> Контакт. Это означает что при проверке сделки если указана компания то определение сделок по контакту будут игнорироваться. Например: при создании сделки с контактом Х и компанией У проверки будет проводиться только по завершенным сделкам компании У, без проверки на завершенные сделки контакта Х. \ No newline at end of file diff --git "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/14_\320\241\320\264\320\265\320\273\320\272\320\260/10_\320\234\320\265\321\202\320\276\320\264\321\213.md" "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/14_\320\241\320\264\320\265\320\273\320\272\320\260/10_\320\234\320\265\321\202\320\276\320\264\321\213.md" index 511109f..ecfa8e9 100644 --- "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/14_\320\241\320\264\320\265\320\273\320\272\320\260/10_\320\234\320\265\321\202\320\276\320\264\321\213.md" +++ "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/14_\320\241\320\264\320\265\320\273\320\272\320\260/10_\320\234\320\265\321\202\320\276\320\264\321\213.md" @@ -2,7 +2,7 @@ Сделка это комплексная структура состоящая из нескольких составных частей: * основные данные, -* регурялность +* регулярность * пользовательские поля. [TOC] @@ -43,18 +43,18 @@ if ( \Bitrix\Main\Loader::IncludeModule('crm') ) Существует несколько способов получить перечень сделок из системы: старое API и DataManager. Каждый способ имеет свои преимущества и не достатки, что в конечном счете использовать должен выбрать разработчик. -| Сравнение |Старое API|DataManager| -| :--------------------------------: | -------- | --------- | -| Возможность получить данные из БД | v | v | -| Учет прав при получении | v | x | -| Простая фильтрация данных | v | v | -| Использование подзапросов для сложной фильтрации | x | v | +| Сравнение | Старое API | DataManager | +|:-------------------------------------------------:|------------|-------------| +| Возможность получить данные из БД | v | v | +| Учет прав при получении | v | x | +| Простая фильтрация данных | v | v | +| Использование под запросов для сложной фильтрации | x | v | Резюмируя, в случае DataManager как преимущество можно выделить скорость работы и гибкость за счет трансляции кода в SQL запрос, в то время как использование старого api дает возможность использовать проверку прав. ### Используя старое API -Для получения списка элементов используя старое API используется метод ```CCrmDeal::GetListEx``. +Для получения списка элементов используя старое API используется метод `CCrmDeal::GetListEx`. Сигнатура метода: ```php @@ -68,7 +68,7 @@ $entityResult = \CCrmDeal::GetListEx( ); ``` -Механизм получения данных аналогичен [выборке из инфоблоков](http://dev.1c-bitrix.ru/api_help/iblock/classes/ciblockelement/getlist.php). По-умолчанию при выборке проверяются права текущего пользователя, поэтому чтобы получить все значения без проверки прав необходимо передать в фильтре флаг ``CHECK_PERMISSIONS`` с значением ``N``. +Механизм получения данных аналогичен [выборке из инфоблоков](http://dev.1c-bitrix.ru/api_help/iblock/classes/ciblockelement/getlist.php). По-умолчанию при выборке данных проверяются права текущего пользователя, поэтому для получения всех значений без проверки прав необходимо передать в фильтре флаг ``CHECK_PERMISSIONS`` со значением ``N``. Пример: необходимо получить Название и ID сделок, которые созданы 1 января 2021 года без учета прав пользователя, отсортированные по источнику (убыванию) @@ -107,7 +107,7 @@ while( $entity = $entityResult->fetch() ) #### Прямое указание LIMIT и OFFSET -При помощи параметра `QUERY_OPTIONS` в `$arOptions` имеется возможность задания таких параметров. Это очень удобно для двухступенчатой постаничной навигации, когда сначала выбираются ID элементов, а потом уже данные для полученных ID. +При помощи параметра `QUERY_OPTIONS` в `$arOptions` имеется возможность задания таких параметров. Это очень удобно для двухступенчатой постраничной навигации, когда сначала выбираются ID элементов, а потом уже данные для полученных ID. Пример запроса: ```php @@ -131,7 +131,7 @@ $entityResult = \CCrmDeal::GetListEx( #### Запросы с участием внешних таблиц в фильтре -Иногда бывает необходимость достать только те элементы, для которых есть запись в сторонней таблице. Для этого можно воспользоваться `__JOINS` ключем. +Иногда бывает необходимость достать только те элементы, для которых есть запись в сторонней таблице. Для этого можно воспользоваться `__JOINS` ключом. ```php @@ -364,7 +364,7 @@ $entityId = $entityObject->Add( * В случае если флаг true, не будет проверки * обязательности заполнения пользовательских полей * - * Если флаг `DISABLE_USER_FIELD_CHECK` установлен в true, + * Если флаг 'DISABLE_USER_FIELD_CHECK' установлен в true, * данный флаг игнорируется - проверок не будет * * Флаг не отменяет необходимость корректного заполнения @@ -456,6 +456,7 @@ $isUpdateSuccess = $entityObject->Update( $entityId, $entityFields, $bCompare = true, + $bUpdateSearch = true, $arOptions = [ /** * ID пользователя, от лица которого выполняется действие diff --git "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/14_\320\241\320\264\320\265\320\273\320\272\320\260/20_C\320\276\320\261\321\213\321\202\320\270\321\217.md" "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/14_\320\241\320\264\320\265\320\273\320\272\320\260/20_C\320\276\320\261\321\213\321\202\320\270\321\217.md" index d305474..77f1f07 100644 --- "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/14_\320\241\320\264\320\265\320\273\320\272\320\260/20_C\320\276\320\261\321\213\321\202\320\270\321\217.md" +++ "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/14_\320\241\320\264\320\265\320\273\320\272\320\260/20_C\320\276\320\261\321\213\321\202\320\270\321\217.md" @@ -2,7 +2,7 @@ [TOC] ->Помните, что события не проверяются на цикличный вызов, поэтому если во время создания элемента на событии вы попыпаетесь создать элемент, то вы можете породить бесконечный цикл. +>Помните, что события не проверяются на цикличный вызов, поэтому если во время создания элемента на событии вы попытаетесь создать элемент, то вы можете породить бесконечный цикл. >Событие не всегда содержит полный набор полей, поэтому хорошим тоном является проверять фактическое наличие ключа в массиве параметров и в случае его отсутствия заполнение либо дефолтным значением, либо обращение в базу данных для предотвращения неопределенного поведения. @@ -10,9 +10,9 @@ Событие вызываемое перед созданием элемента методом `CCrmDeal::Add`. -| Параметр | Значение | -| :----------: | ---------------------- | -| &$arFields | Поля создаваемого элемента | +| Параметр | Значение | +|:-----------|----------------------------| +| &$arFields | Поля создаваемого элемента | Возвращаемое значение: boolean. `true` успешное выполнение. @@ -53,9 +53,9 @@ $eventManager->addEventHandlerCompatible( Событие вызываемое после успешного создания элемента методом `CCrmDeal::Add`. -| Параметр | Значение | -| :----------: | ---------------------- | -| &$arFields | Поля создаваемого элемента | +| Параметр | Значение | +|:-----------|----------------------------| +| &$arFields | Поля создаваемого элемента | Возвращаемое значение не обрабатывается. @@ -81,9 +81,9 @@ $eventManager->addEventHandlerCompatible( Событие вызываемое перед обновлением элемента методом `CCrmDeal::Update`. -| Параметр | Значение | -| :----------: | ---------------------- | -| &$arFields | Поля обновляемого элемента | +| Параметр | Значение | +|:-----------|----------------------------| +| &$arFields | Поля обновляемого элемента | Возвращаемое значение: boolean. `true` успешное выполнение. @@ -124,9 +124,9 @@ $eventManager->addEventHandlerCompatible( Событие вызываемое после успешного обновления элемента методом `CCrmDeal::Update`. -| Параметр | Значение | -| :----------: | ---------------------- | -| &$arFields | Поля обновляемого элемента | +| Параметр | Значение | +|:-----------|----------------------------| +| &$arFields | Поля обновляемого элемента | Возвращаемое значение не обрабатывается. @@ -148,9 +148,9 @@ $eventManager->addEventHandlerCompatible( Событие вызываемое перед удалением элемента методом `CCrmDeal::Delete` или перемещения в корзину. -| Параметр | Значение | -| :----------: | ------------------------------ | -| $id | Primary key удаляемого элемента | +| Параметр | Значение | +|:---------|---------------------------------| +| $id | Primary key удаляемого элемента | Возвращаемое значение: boolean. `true` успешное выполнение. @@ -191,9 +191,9 @@ $eventManager->addEventHandlerCompatible( Событие вызываемое после успешного удаления элемента методом `CCrmDeal::Delete` или перемещения в корзину. -| Параметр | Значение | -| :----------: | ------------------------------ | -| $id | Primary key удаляемого элемента | +| Параметр | Значение | +|:---------|---------------------------------| +| $id | Primary key удаляемого элемента | Возвращаемое значение не обрабатывается. @@ -218,7 +218,7 @@ $eventManager->addEventHandlerCompatible( Событие вызываемое после изменения товарных позиций из публичной части или методом `CCrmDeal::SaveProductRows`. Вернуть ошибку НЕЛЬЗЯ! Возвращаемые значения не обрабатываются. -| Параметр | Значение | -| :--------: | ------------------------------ | -| $id | Primary key сделки | -| $rows | Строки товарных позиций | \ No newline at end of file +| Параметр | Значение | +|:---------|-------------------------| +| $id | Primary key сделки | +| $rows | Строки товарных позиций | \ No newline at end of file diff --git "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/15_\320\241\320\274\320\260\321\200\321\202_\320\277\321\200\320\276\321\206\320\265\321\201\321\201\321\213/00_\320\236\320\277\320\270\321\201\320\260\320\275\320\270\320\265.md" "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/15_\320\241\320\274\320\260\321\200\321\202_\320\277\321\200\320\276\321\206\320\265\321\201\321\201\321\213/00_\320\236\320\277\320\270\321\201\320\260\320\275\320\270\320\265.md" index 924a9c4..4968fdd 100644 --- "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/15_\320\241\320\274\320\260\321\200\321\202_\320\277\321\200\320\276\321\206\320\265\321\201\321\201\321\213/00_\320\236\320\277\320\270\321\201\320\260\320\275\320\270\320\265.md" +++ "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/15_\320\241\320\274\320\260\321\200\321\202_\320\277\321\200\320\276\321\206\320\265\321\201\321\201\321\213/00_\320\236\320\277\320\270\321\201\320\260\320\275\320\270\320\265.md" @@ -2,7 +2,7 @@ Смарт-процессы (СП) это механизм позволяющий хранить и обрабатывать связанную с CRM информацию. -> Одна из основных функций CRM - отслеживание, хранение и удобное отображение коммуникаций. При этом не всегда коммуникации - это продажи. Это могут быть какие-то внутренние процессы, обработка обращений в техподдержку, закупки и т.д. В этом случае есть потребность хранить и обрабатывать информацию и коммуникации не внутри лидов/сделок, а отдельно. +> Одна из основных функций CRM - отслеживание, хранение и удобное отображение коммуникаций. При этом не всегда коммуникации - это продажи. Это могут быть какие-то внутренние процессы, обработка обращений в тех поддержку, закупки и т.д. В этом случае есть потребность хранить и обрабатывать информацию и коммуникации не внутри лидов/сделок, а отдельно. > Кроме того, часто в CRM хочется хранить много связанной информации, которая относится к продажам, но не является лидом/сделкой. Чтобы закрыть эту потребность в CRM с версии 20.700.0 появились смарт-процессы. Для лучшего понимания темы определимся с терминологией: @@ -10,7 +10,7 @@ - Смарт-процесс (СП, процесс) - универсальная или динамическая сущность, созданная с использованием механизма. - Элемент смарт-процесса (элемент СП) - это один элемент конкретной динамической сущности. -## Арихтектура хранения +## Архитектура хранения Концептуально смарт-процессы похожи на инфоблоки (универсальные списки), однако с точки зрения данных смарт-процессы похожи на rpa. Механизм хранения значений пользовательских полей такой же, как в rpa и highloadblock. diff --git "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/15_\320\241\320\274\320\260\321\200\321\202_\320\277\321\200\320\276\321\206\320\265\321\201\321\201\321\213/10_\320\237\321\200\320\276\321\206\320\265\321\201\321\201\321\213.md" "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/15_\320\241\320\274\320\260\321\200\321\202_\320\277\321\200\320\276\321\206\320\265\321\201\321\201\321\213/10_\320\237\321\200\320\276\321\206\320\265\321\201\321\201\321\213.md" index d43fecf..51f07db 100644 --- "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/15_\320\241\320\274\320\260\321\200\321\202_\320\277\321\200\320\276\321\206\320\265\321\201\321\201\321\213/10_\320\237\321\200\320\276\321\206\320\265\321\201\321\201\321\213.md" +++ "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/15_\320\241\320\274\320\260\321\200\321\202_\320\277\321\200\320\276\321\206\320\265\321\201\321\201\321\213/10_\320\237\321\200\320\276\321\206\320\265\321\201\321\201\321\213.md" @@ -2,8 +2,8 @@ [TOC] -Все взаимодействие с новым API CRM и смарт-процессами в частности осуществляется посредством взаимодейтсвия с сервисами из контейнера `\Bitrix\Crm\Service\Container`. Это означает что перед выполнением любой операции необходимо сначала получить контейнер, затем достать из него нужный сервис и уже после выполнить действие. ->Не смотря на то что в некоторых случаях можно обойтись без контейнеров, использование их строго рекомендовано чтобы обеспечивать возможность наследования и переопределения действий. +Все взаимодействие с новым API CRM и смарт-процессами в частности осуществляется посредством взаимодействия с сервисами из контейнера `\Bitrix\Crm\Service\Container`. Это означает что перед выполнением любой операции необходимо сначала получить контейнер, затем достать из него нужный сервис и уже после выполнить действие. +>Несмотря на то что в некоторых случаях можно обойтись без контейнеров, использование их строго рекомендовано, чтобы обеспечивать возможность наследования и переопределения действий. Пример получения контейнера для дальнейшей работы: @@ -18,7 +18,7 @@ $container = Service\Container::getInstance(); ## Получить зарегистрированные процессы -Для получения списка смарт-процессов необходимо сначала получить название таблета, с которым можно работать как и с любым другим DataManager объектом. +Для получения списка смарт-процессов необходимо сначала получить название таблета, с которым можно работать, как и с любым другим DataManager объектом. ```php use \Bitrix\Crm\Service; @@ -53,7 +53,7 @@ $listDynamicTypes = $typeDataClass::getList([ - Обновление связей - Обновление раздела (если выводится в собственном разделе) -Рассмотрим пример создания своего смарт-процесса: предположим нам необходимо создать типовой смарт-процесс для хранения NDA (соглашение о неразглашении) с стандартными полями (Название, Ответственный), привязкой к задачам. В данном примере мы не будем обновлять связи, не затрагиваем конверсионную карту и не будем обновлять отдельный раздел. +Рассмотрим пример создания своего смарт-процесса: предположим нам необходимо создать типовой смарт-процесс для хранения NDA (соглашение о неразглашении) со стандартными полями (Название, Ответственный), привязкой к задачам. В данном примере мы не будем обновлять связи, не затрагиваем конверсионную карту и не будем обновлять отдельный раздел. ```php use \Bitrix\Crm\Service, diff --git "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/15_\320\241\320\274\320\260\321\200\321\202_\320\277\321\200\320\276\321\206\320\265\321\201\321\201\321\213/20_\320\255\320\273\320\265\320\274\320\265\320\275\321\202\321\213.md" "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/15_\320\241\320\274\320\260\321\200\321\202_\320\277\321\200\320\276\321\206\320\265\321\201\321\201\321\213/20_\320\255\320\273\320\265\320\274\320\265\320\275\321\202\321\213.md" index f1be0c6..f956b4e 100644 --- "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/15_\320\241\320\274\320\260\321\200\321\202_\320\277\321\200\320\276\321\206\320\265\321\201\321\201\321\213/20_\320\255\320\273\320\265\320\274\320\265\320\275\321\202\321\213.md" +++ "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/15_\320\241\320\274\320\260\321\200\321\202_\320\277\321\200\320\276\321\206\320\265\321\201\321\201\321\213/20_\320\255\320\273\320\265\320\274\320\265\320\275\321\202\321\213.md" @@ -1,7 +1,7 @@ # Работа с элементами Взаимодействие с элементами смарт-процессов осуществляется через фабрики (`Bitrix\Crm\Service\Factory`), получать которые необходимо из контейнера `\Bitrix\Crm\Service\Container`. Это означает что перед выполнением любой операции необходимо сначала получить контейнер, затем получить необходимую фабрику и уже после выполнить действие. ->Не смотря на то что в некоторых случаях можно обойтись без контейнеров, использование их строго рекомендовано чтобы обеспечивать возможность наследования и переопределения действий. +>Несмотря на то что в некоторых случаях можно обойтись без контейнеров, использование их строго рекомендовано, чтобы обеспечивать возможность наследования и переопределения действий. [TOC] @@ -25,7 +25,7 @@ $factory = $container->getFactory( 184 ); ## Получение списка полей -Для получение списка полей смарт-процесса использутся метод `getFieldsCollection`, он возвращает экземпляр `Bitrix\Crm\Field\Collection` с описанием всех полей элемента смарт-процесса +Для получения списка полей смарт-процесса используется метод `getFieldsCollection`, он возвращает экземпляр `Bitrix\Crm\Field\Collection` с описанием всех полей элемента смарт-процесса ```php // ...$factory @@ -45,7 +45,7 @@ foreach ($fieldsCollection as $field) ## Поиск элементов -Для поиска элементов в каждой фабрике существуют методы `getItems` и `getItemsFilteredByPermissions`, которые отождествяют собой прямой доступ к элементам и доступ с учетом прав пользователя. +Для поиска элементов в каждой фабрике существуют методы `getItems` и `getItemsFilteredByPermissions`, которые отождествляют собой прямой доступ к элементам и доступ с учетом прав пользователя. ### Прямой поиск @@ -99,8 +99,8 @@ foreach ($elementsWithA as $element) ## Операции В этом разделе изложена справочная информация по низкоуровневым возможностям системы. -Если вам необходимо выполнить создание/обновление (сохранение), удаление или конвертацию элемента воспользуйтесь [операциями](./Операции). -Некоторый код расположенный ниже не удовляетворяет критериям: +Если вам необходимо выполнить создание/обновление (сохранение), удаление или конвертацию элемента воспользуйтесь [операциями](./30_Операции). +Некоторый код расположенный ниже не удовлетворяет критериям: - Прозрачности (вы не сможете отследить все места и доп.действия с элементом) - Расширяемости (вы не сможете быстро переопределить или дополнить доп.действиями) - Консистентности (код ниже не гарантирует корректную работу системы в некоторых частях (поиск, права, таймлайн и т.п.)) @@ -109,7 +109,7 @@ foreach ($elementsWithA as $element) *Прочитайте примечание к разделу 'Операция' прежде чем продолжить чтение.* -Оба совершаемых действия (созданию и обновлению) над элементом в объектном подходе обеспечивается методом `save`, который вызывается на объекте-наследнике `Bitrix\Crm\Item`, отсюда следует что каждое действие можно провести как минимум 2 путями помимо указанных выше [операций](./Операции). +Оба совершаемых действия (созданию и обновлению) над элементом в объектном подходе обеспечивается методом `save`, который вызывается на объекте-наследнике `Bitrix\Crm\Item`, отсюда следует что каждое действие можно провести как минимум 2 путями помимо указанных выше [операций](./30_Операции). Вариант с низкоуровневым созданием элемента смарт-процесса: @@ -144,7 +144,7 @@ else ``` _Почему данный вариант не подходит для использования разработчиком?_ -Это самое низкоуровненое сохранение элемента, в котором не происходит следующих действий: +Это самое низкоуровневое сохранение элемента, в котором не происходит следующих действий: 1. Установка значений по-умолчанию 2. Проверки прав 3. Установки связей @@ -189,7 +189,7 @@ else ``` _Почему данный вариант не подходит для использования разработчиком?_ -Это самое низкоуровненое сохранение элемента, в котором не происходит следующих действий: +Это самое низкоуровневое сохранение элемента, в котором не происходит следующих действий: 1. Установка значений по-умолчанию 2. Проверки прав 3. Установки связей @@ -201,7 +201,7 @@ _Почему данный вариант не подходит для испо 9. Формирования timeline -*Рекомендуемый* вариант с использованием [операций](./Операции): +*Рекомендуемый* вариант с использованием [операций](./30_Операции): ```php $initialFields = [ @@ -237,13 +237,13 @@ else Использование операций это рекомендуемый способ по сохранению элемента в полном объеме. Указанная операция создает элемент, для обновления элемента необходимо получить операцию редактирования (`getUpdateOperation`). -### Удалиение +### Удаление *Прочитайте примечание к разделу 'Операция' прежде чем продолжить чтение.* Существует несколько способов удаления элемента: низкоуровневый `delete` и операция по удалению элемента. -Вариант с прямым удалением элемена: +Вариант с прямым удалением элемент: ```php /** @@ -272,7 +272,7 @@ else ``` _Почему данный вариант не подходит для использования разработчиком?_ -Не смотря на то что элемент смарт-процесса фактически удаляется, соглсованность данных не обеспечивается, а это значит что не происходит следующих действий: +Несмотря на то что элемент смарт-процесса фактически удаляется, согласованность данных не обеспечивается, а это значит что не происходит следующих действий: 1. Очистки товарных позиций 2. Очистки записей о правах @@ -282,7 +282,7 @@ _Почему данный вариант не подходит для испо 6. Очистки счетчиков и т.д. -*Рекомендуемый* вариант с использованием [операций](./Операции): +*Рекомендуемый* вариант с использованием [операций](./30_Операции): ```php /** diff --git "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/15_\320\241\320\274\320\260\321\200\321\202_\320\277\321\200\320\276\321\206\320\265\321\201\321\201\321\213/30_\320\236\320\277\320\265\321\200\320\260\321\206\320\270\320\270.md" "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/15_\320\241\320\274\320\260\321\200\321\202_\320\277\321\200\320\276\321\206\320\265\321\201\321\201\321\213/30_\320\236\320\277\320\265\321\200\320\260\321\206\320\270\320\270.md" index 6fc4e1f..6b8587d 100644 --- "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/15_\320\241\320\274\320\260\321\200\321\202_\320\277\321\200\320\276\321\206\320\265\321\201\321\201\321\213/30_\320\236\320\277\320\265\321\200\320\260\321\206\320\270\320\270.md" +++ "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/15_\320\241\320\274\320\260\321\200\321\202_\320\277\321\200\320\276\321\206\320\265\321\201\321\201\321\213/30_\320\236\320\277\320\265\321\200\320\260\321\206\320\270\320\270.md" @@ -103,21 +103,21 @@ else `disableAllChecks` - выключает все проверки при выполнении операций. Аналогичен вызовам `disableCheckWorkflows`, `disableCheckAccess`, `disableCheckFields`, `disableCheckRequiredUserFields`. -| Действие | Включение | Выключение | Проверка | -| -------- | :-------- | :--------- | :------- | -| Проверка прав доступа к элементу | enableCheckAccess | disableCheckAccess | isCheckAccessEnabled | -| Проверка запущенных БП | enableCheckWorkflows | disableCheckWorkflows | isCheckWorkflowsEnabled | -| Обработка бизнес-логик полей (до и после) | enableFieldProcession | disableFieldProcession | isFieldProcessionEnabled | -| Проверка заполненных полей (на предмет обязательности) | enableCheckFields | disableCheckFields | isCheckFieldsEnabled | -| -- Валидация польз.полей | enableCheckRequiredUserFields | disableCheckRequiredUserFields | isCheckRequiredUserFields | -| Если элемент изменен, запуск Действий до сохранения | enableBeforeSaveActions | disableBeforeSaveActions | isBeforeSaveActionsEnabled | -| Сохранение записи в историю и timeline | enableSaveToHistory | disableSaveToHistory | isSaveToHistoryEnabled | -| Запуск Действий после сохранения | enableAfterSaveActions | disableAfterSaveActions | isAfterSaveActionsEnabled | -| Запуск бизнес-процессов | enableBizProc | disableBizProc | isBizProcEnabled | -| Запуск автоматизации | enableAutomation | disableAutomation | isAutomationEnabled | - - -Пример: повторим пример выше, но но с определенными настройками: выключим проверки бизнес-процессов и стандартных полей +| Действие | Включение | Выключение | Проверка | +|--------------------------------------------------------|:------------------------------|:-------------------------------|:---------------------------| +| Проверка прав доступа к элементу | enableCheckAccess | disableCheckAccess | isCheckAccessEnabled | +| Проверка запущенных БП | enableCheckWorkflows | disableCheckWorkflows | isCheckWorkflowsEnabled | +| Обработка бизнес-логик полей (до и после) | enableFieldProcession | disableFieldProcession | isFieldProcessionEnabled | +| Проверка заполненных полей (на предмет обязательности) | enableCheckFields | disableCheckFields | isCheckFieldsEnabled | +| -- Валидация польз.полей | enableCheckRequiredUserFields | disableCheckRequiredUserFields | isCheckRequiredUserFields | +| Если элемент изменен, запуск Действий до сохранения | enableBeforeSaveActions | disableBeforeSaveActions | isBeforeSaveActionsEnabled | +| Сохранение записи в историю и timeline | enableSaveToHistory | disableSaveToHistory | isSaveToHistoryEnabled | +| Запуск Действий после сохранения | enableAfterSaveActions | disableAfterSaveActions | isAfterSaveActionsEnabled | +| Запуск бизнес-процессов | enableBizProc | disableBizProc | isBizProcEnabled | +| Запуск автоматизации | enableAutomation | disableAutomation | isAutomationEnabled | + + +Пример: повторим пример выше, но с определенными настройками: выключим проверки бизнес-процессов и стандартных полей ```php use \Bitrix\Main, @@ -174,9 +174,9 @@ else `abstract public function process(\Bitrix\Crm\Item $item): \Bitrix\Main\Result;` Метод может как прекратить выполнение операции, так и изменить состояние объекта над которым выполняется операция. -Для действий выполняемых после сохранения, можно вызвать сохранние элемента (`$item->save()`) повторно. +Для действий выполняемых после сохранения, можно вызвать сохранение элемента (`$item->save()`) повторно. -Пример добавления дейтвий к полученной операции: +Пример добавления действий к полученной операции: ```php use \Bitrix\Main, diff --git "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/15_\320\241\320\274\320\260\321\200\321\202_\320\277\321\200\320\276\321\206\320\265\321\201\321\201\321\213/40_\320\232\320\260\321\201\321\202\320\276\320\274\320\270\320\267\320\260\321\206\320\270\321\217/00_\320\230\320\267\320\274\320\265\320\275\320\265\320\275\320\270\320\265_\320\273\320\276\320\263\320\270\320\272\320\270.md" "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/15_\320\241\320\274\320\260\321\200\321\202_\320\277\321\200\320\276\321\206\320\265\321\201\321\201\321\213/40_\320\232\320\260\321\201\321\202\320\276\320\274\320\270\320\267\320\260\321\206\320\270\321\217/00_\320\230\320\267\320\274\320\265\320\275\320\265\320\275\320\270\320\265_\320\273\320\276\320\263\320\270\320\272\320\270.md" index b646a10..1632550 100644 --- "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/15_\320\241\320\274\320\260\321\200\321\202_\320\277\321\200\320\276\321\206\320\265\321\201\321\201\321\213/40_\320\232\320\260\321\201\321\202\320\276\320\274\320\270\320\267\320\260\321\206\320\270\321\217/00_\320\230\320\267\320\274\320\265\320\275\320\265\320\275\320\270\320\265_\320\273\320\276\320\263\320\270\320\272\320\270.md" +++ "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/15_\320\241\320\274\320\260\321\200\321\202_\320\277\321\200\320\276\321\206\320\265\321\201\321\201\321\213/40_\320\232\320\260\321\201\321\202\320\276\320\274\320\270\320\267\320\260\321\206\320\270\321\217/00_\320\230\320\267\320\274\320\265\320\275\320\265\320\275\320\270\320\265_\320\273\320\276\320\263\320\270\320\272\320\270.md" @@ -2,23 +2,23 @@ [TOC] -Подход к реализации смарт-процессов сильно отличается от подхода используемого ранее: вместо привичных разработчку событий и методов по изменению предлагается новый подход с использованием [операций и действий](../Операции). Эта статья в каком-то роде переосмысление стандартной документации по [кастомизации crm](https://dev.1c-bitrix.ru/api_d7/bitrix/crm/customization/index.php), которая не точно раскрывает подходы. +Подход к реализации смарт-процессов сильно отличается от подхода используемого ранее: вместо простых и понятных разработчику событий и методов по изменению предлагается новый подход с использованием [операций и действий](../30_Операции). Эта статья в каком-то роде переосмысление стандартной документации по [кастомизации crm](https://dev.1c-bitrix.ru/api_d7/bitrix/crm/customization/index.php), которая не точно раскрывает подходы. Мы постараемся сделать все то же самое, но двигаясь поэтапно с подробными пояснениями. Для улучшения восприятия мы сделали ряд предположений: 1. `ENTITY_TYPE_ID` (идентификатор сущности смарт-процесса) известен заранее и для него существует некоторая константа `SUPER_ENTITY_TYPE_ID`. В реальном проекте у вас скорее всего будет другой механизм для получения такого идентификатора, но здесь мы будем использовать именно его -2. В оригинальной статье используется динамическое создание класса (`new class(...) extends`), но мы не будем использовать этот подход. Вместо этого мы будем разносить классы по разным файлам согласно нашей [структуре кода](../../../Разработка/Структура_папки_local/Свой_код) и `namespace` - `\Fusion\SomeSmartProcess`. +2. В оригинальной статье используется динамическое создание класса (`new class(...) extends`), но мы не будем использовать этот подход. Вместо этого мы будем разносить классы по разным файлам согласно нашей [структуре кода](../../../03_Разработка/20_Структура_папки_local/10_Свой_код) и `namespace` - `\Fusion\SomeSmartProcess`. 3. Мы предполагаем что работаем на "чистой" коробке, т.е. никаких модулей и кода модифицирующих сервисы не было. ->Открывающие php-теги в указанных фрагментах отстуствуют. Их нужно дописывать руками. +>Открывающие php-теги в указанных фрагментах отсутствуют. Их нужно дописывать руками. ## Шаг 1. Фабрика -Любая работа будь то операция создания или получение списка элементов с смарт-процессами или новым API начинается с получения фабрики этого типа. Если вы не знакомы с паттернами проектирования, то рекомендую сначала почитать про [фабрики](https://ru.wikipedia.org/wiki/%D0%90%D0%B1%D1%81%D1%82%D1%80%D0%B0%D0%BA%D1%82%D0%BD%D0%B0%D1%8F_%D1%84%D0%B0%D0%B1%D1%80%D0%B8%D0%BA%D0%B0_(%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD_%D0%BF%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F)#%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%80_%D0%BD%D0%B0_PHP5), а потом вернуться к изучению данного материала. +Любая работа будь то операция создания или получение списка элементов со смарт-процессами или новым API начинается с получения фабрики этого типа. Если вы не знакомы с паттернами проектирования, то рекомендую сначала почитать про [фабрики](https://ru.wikipedia.org/wiki/%D0%90%D0%B1%D1%81%D1%82%D1%80%D0%B0%D0%BA%D1%82%D0%BD%D0%B0%D1%8F_%D1%84%D0%B0%D0%B1%D1%80%D0%B8%D0%BA%D0%B0_(%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD_%D0%BF%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F)#%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%80_%D0%BD%D0%B0_PHP5), а потом вернуться к изучению данного материала. ### Подмена контейнера crm -Как вы знаете из [главы Процессы](../Процессы) все взаимодействие с смарт-процессами осуществляется через контейнер (`\Bitrix\Crm\Service\Container`), получить который можно следующим кодом: +Как вы знаете из [главы Процессы](../10_Процессы) все взаимодействие со смарт-процессами осуществляется через контейнер (`\Bitrix\Crm\Service\Container`), получить который можно следующим кодом: ```php use \Bitrix\Crm\Service; @@ -29,7 +29,7 @@ use \Bitrix\Crm\Service; $container = Service\Container::getInstance(); ``` -Однако, внутри себя `getInstance()` метод представляет ни что иное, как обращение к `DI\ServiceLocator` ([подробнее в документации](https://dev.1c-bitrix.ru/learning/course/index.php?COURSE_ID=43&LESSON_ID=14032)) и если мы заглянем внутрь этого метода, то увидим ни что иное как получение `crm.service.container` сервиса: +Однако, внутри себя `getInstance()` метод представляет не что иное, как обращение к `DI\ServiceLocator` ([подробнее в документации](https://dev.1c-bitrix.ru/learning/course/index.php?COURSE_ID=43&LESSON_ID=14032)) и если мы заглянем внутрь этого метода, то увидим не что иное, как получение `crm.service.container` сервиса: ```php public static function getInstance(): Container @@ -40,8 +40,8 @@ public static function getInstance(): Container Таким образом, воспользовавшись возможностями `DI\ServiceLocator` мы можем подменить возвращаемый результат на своего наследника. -Так как контейнер является общим объектом для CRM и для нашей кастомной сущности, выносить его подмену в наше пространство имен не является корректным шагом. ->Почему это не корректный шаг? Завтра может появится новый смарт-процесс со своей логикой работы и добавлять подмену фабрики для него в пространстве имен другой механике - плохая затея. +Так как контейнер является общим объектом для CRM и для нашей сущности, выносить его подмену в наше пространство имен не является корректным шагом. +>Почему это не корректный шаг? В будущем возможно появление нового смарт-процесса со своей логикой работы и добавлять подмену фабрики для него в пространстве имен другой механике - плохая затея. Так как контейнер общая часть для всех модулей CRM, целесообразно будет выделить его в соответсвующее пространство имен. Пусть это будет `Fusion\Crm\Container`. @@ -61,17 +61,17 @@ class Container extends Service\Container } ``` -Не буду пояснять что означает каждая строчка в данном файле, оставлюсь лишь на одном моменте: на 7 строчке мы добавили код +Не буду пояснять что означает каждая строчка в данном файле, остановлюсь лишь на одном моменте: на 7 строчке мы добавили код ```php Main\Loader::requireModule('crm'); ``` -Мы сделали это потому, что разработчик может явно обратиться к нашему коду и мы должны быть уверены что класс-родитель из модуля CRM подключен. +Мы сделали это потому, что разработчик может явно обратиться к нашему коду и мы должны быть уверены, что класс-родитель из модуля CRM подключен. -Теперь если мы попытаемся что-то сделать в CRM... ничего не произойдет. Мы создали класс-наследник но он ничего не делает и нигде не участвует. Даже если мы впишем ему какие-то методы модуль CRM не будет его использовать. +Теперь если мы попытаемся что-то сделать в CRM... ничего не произойдет. Мы создали класс-наследник, но он ничего не делает и нигде не участвует. Даже если мы впишем ему какие-то методы модуль CRM не будет его использовать. Следующий наш шаг - подмена сервиса. -Для этого, согласно нашей [структуре файлов](../../../Разработка/Структура_папки_local/Свой_код) в секцию смарт-процессов добавим следующий код: +Для этого, согласно нашей [структуре файлов](../../../03_Разработка/20_Структура_папки_local/10_Свой_код) в секцию смарт-процессов добавим следующий код: ```php $serviceLocator->addInstanceLazy('crm.service.container', [ @@ -80,7 +80,7 @@ $serviceLocator->addInstanceLazy('crm.service.container', [ ``` >Почему мы добавляем LazyInstance вместо Instance? Потому что не на каждом хите мы подключаем и используем контейнеры CRM. ->Иницилазиация нашего класса произойдет исключительно по требовани. +>Инициализация нашего класса произойдет исключительно по требованию. Теперь, мы можем открыть php-консоль в административном интерфейсе и выполнить код: @@ -98,7 +98,7 @@ else ``` Мы увидим вывод `It works!`. ->Если что-то пошло не так - проверьте еще раз. Возможно вы что-то упустили. Если вы уверены что все сделано правильно, свяжитесь с нами через github issue - мы исследуем вашу ситуацию +>Если что-то пошло не так - проверьте еще раз. Возможно вы что-то упустили. Уверены, что все сделано правильно? Свяжитесь с нами через github issue - мы исследуем вашу ситуацию. Теперь когда мы подменили контейнер, самое время подменить фабрику. Для начала создадим класс отвечающий за саму фабрику `/local/php_interface/classes/Fusion/SomeSmartProcess/Factory.php` с содержимым: @@ -126,7 +126,7 @@ class Factory extends Dynamic >Нижеследующий код ПРЕКРАТИТ работу CRM. Не выполнять на production в рабочие часы! -Для начала необходимо перекрыть код самого метода, для этого добавим класс контейненра в файл `Container.php` следующий код: +Для начала необходимо перекрыть код самого метода, для этого добавим класс контейнера в файл `Container.php` следующий код: ```php public function getFactory(int $entityTypeId): ?Service\Factory @@ -136,7 +136,7 @@ public function getFactory(int $entityTypeId): ?Service\Factory } ``` -Теперь когда мы выполнил нижеследующий код в консоли: +Теперь когда мы выполнили нижеследующий код в консоли: ```php \Bitrix\Main\Loader::IncludeModule('crm'); @@ -146,12 +146,12 @@ public function getFactory(int $entityTypeId): ?Service\Factory Мы увидим на экране надпись `Overridden`. -Если мы удалим `die`-функцию то CRM продолжит функционировать в обычном режиме, но с наследуюемыми классами. +Если мы удалим `die`-функцию то CRM продолжит функционировать в обычном режиме, но с наследуемыми классами. Реализовывать нужно по принципу "нашел - подменяем, нет - пропускаем", т.е. изменения должны влиять только на наш код. В перекрытом методе мы должны сделать следующие действия 1. Проверить что подменяем наш сервис (не наш подменять не нужно) 2. Проверить на наличие объекта (вдруг мы уже подменили и это повторное обращение?) -3. Создать объект фабрики, запомнить его и венруть +3. Создать объект фабрики, запомнить его и вернуть Полный текст метода `getFactory` с комментариями: @@ -217,10 +217,10 @@ else ### Подмена фабрики без подмены контейнера -Пытливый читатель может заметить, что при разработке модулей подход с подменой контейнера может не сработать. Если внимательно приглядеться к методу `getFactory` можно заметить что мы вызываем из контейнера (который по факту является серсивсом возвращаемым из `DI\ServiceLocator`) тот же `DI\ServiceLocator` для поиска существующих контейнеров. -А значит мы можем на любом событии (например `OnPageStart`) до вызова метода получения экземпляра фабрики подменить его сервис. +Пытливый читатель может заметить, что при разработке модулей подход с подменой контейнера может не сработать. Если внимательно приглядеться к методу `getFactory` можно заметить что мы вызываем из контейнера (который по факту является сервисом возвращаемым из `DI\ServiceLocator`) тот же `DI\ServiceLocator` для поиска существующих контейнеров. +А значит мы можем на любом событии (например `OnPageStart`) до момента его первого вызова подменить его сервис. -Для этого нам нужно получить подменяемое имя сервиса через метод `\Bitrix\Crm\Service\Container::getIdentifierByClassName` и реализовать налогичный lazy-сервис подмены. +Для этого нам нужно получить подменяемое имя сервиса через метод `\Bitrix\Crm\Service\Container::getIdentifierByClassName` и реализовать аналогичный lazy-сервис подмены. >Указанный способ - является способом "со звездочкой" поэтому в данном материале она пока не рассматривается. @@ -253,11 +253,11 @@ public function getUserFieldsInfo(): array ## Шаг 3. Подмена операции удаления -Обычные бизнес-требования могут подразумевать различные действия в системе в зависимости от выполняемых действий над элементом. В старом ядре механизм который обеспечивал подобные манипуляции основывался на событийной модели. При работе с смарт-процессами подобные влиянимя можно осуществить через действия - аналог событий. +Обычные бизнес-требования могут подразумевать различное поведение элементов в системе в зависимости от выполняемых действий над элементом. В старом ядре подобный механизм основывался на событийной модели. При работе со смарт-процессами подобные влияниям можно осуществить через действия - аналог событий. ->Напомню, что создание, изменение и удаление элементов происходят через [операции](../Операции), а действия - дополнительные обработчики которые выполняются до или после самой операции. +>Напомню, что создание, изменение и удаление элементов происходят через [операции](../30_Операции), а действия - дополнительные обработчики которые выполняются до или после самой операции. -Звучи сложно, давайте разбираться на конкретном примере. Предположим мы хотим логгировать удаление элементов для нашего смарт-процесса. +Звучи сложно, давайте разбираться на конкретном примере. Предположим мы хотим записывать удаление элементов для нашего смарт-процесса. Мы можем сделать это двумя путями: 1. Подменить операцию удаления, подобно тому как мы делали это с фабрикой. 2. Использовать механизм действий, чтобы дополнить стандартную операцию. @@ -265,7 +265,7 @@ public function getUserFieldsInfo(): array Мы выберем второй вариант, потому что подменять целые части системы для такой простой операции слишком затратно. Дополнить свое действие будет гораздо эффективнее. Из документации мы знаем, что любое действие является реализацией абстрактного класса `\Bitrix\Crm\Service\Operation\Action`. -Создаим свое действие-логгер: для этого создадим класс который будет реализовывать это действие и добавим его к операции удаления. +Создадим свое действие-логгер: для этого создадим класс, который будет реализовывать это действие и добавим его к операции удаления. Назовем его обработчик действия: `\Fusion\SomeSmartProcess\Operation\Action\Log`. >Почему мы делаем такую большую вложенность? Вы правы, такая большая вложенность в данном случае избыточна, но она открывает в будущем неограниченную возможность для кастомизации фабрики. Вы можете не ограничиваться стандартными операциями и добавить свои операции. Например `Operation\Sync` для синхронизации с внешней системой. И конечно же у вас может быть не одно действие для различных операций. @@ -352,9 +352,9 @@ class ChangeStageRestriction extends Operation\Action $userId === 222 // Если стадия меняется && $item->isChangedStageId() - // Если стадия на которую мы переходим `D150_3:CLIENT` + // Если стадия на которую мы переходим 'D150_3:CLIENT' && $item->getStageId() === 'D150_3:CLIENT' - // Если предыдущая стадия `D150_3:PREPARATIO` + // Если предыдущая стадия 'D150_3:PREPARATIO' && $item->remindActual(Item::FIELD_NAME_STAGE_ID) === 'D150_3:PREPARATION' ) { $result->addError( diff --git "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/22_\320\241\321\207\320\265\321\202.md" "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/22_\320\241\321\207\320\265\321\202.md" index fd0fb36..199f886 100644 --- "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/22_\320\241\321\207\320\265\321\202.md" +++ "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/22_\320\241\321\207\320\265\321\202.md" @@ -4,13 +4,13 @@ >В Битрикс24 счёт - финальный этап процесса продаж. Когда сделка заключена, мы создаём счет и выставляем его клиенту для оплаты. -В данный момент, в Б24 существуют только "Новые счета", основанные на механизме смарт-процессов, в то время как "старые счета" уже не используются и говорить о них нецелесообразно. С другой же стороны - рассуждать контектнонезависимо о новых счетах тоже не имеет смысла, поскольку они основаны на механизме [смарт-процессов](./Смарт_процессы/Элементы). Здесь мы поговорим о различиях в работе между смарт-процессами и счетами и посмотрим несколько примеров использования унифицированного api. +В данный момент, в Б24 существуют только "Новые счета", основанные на механизме смарт-процессов, в то время как "старые счета" уже не используются и говорить о них нецелесообразно. С другой же стороны - рассуждать контекстно-независимо о новых счетах тоже не имеет смысла, поскольку они основаны на механизме [смарт-процессов](./15_Смарт_процессы/20_Элементы). Здесь мы поговорим о различиях в работе между смарт-процессами и счетами и посмотрим несколько примеров использования унифицированного api. ## Основное -С технической точки зрения счета являются сущностью основанной на смарт-процессах, однако все же нельзя сказать что это одно и то же. Мы будем исходить из позиции что новые счета - это особый зафиксированный тип смарт-процесса со своими допущениями. +С технической точки зрения счета являются сущностью основанной на смарт-процессах, однако все же нельзя сказать что это одно и то же. Мы будем исходить из позиции, что новые счета - это особый зафиксированный тип смарт-процесса со своими допущениями. -В работе со смарт-процессами все начинается с фабрики, а для того чтобы получить фабрику необходимо знать идентификатор типа сущности с которой мы хотим продолжить работу. Для счетов это `\CCrmOwnerType::SmartInvoice` или `31` (цифровое значение). +В работе со [смарт-процессами](./15_Смарт_процессы/20_Элементы) все начинается с фабрики и чтобы получить фабрику, необходимо знать идентификатор типа сущности с которой мы хотим продолжить работу. Для счетов это `\CCrmOwnerType::SmartInvoice` или `31` (цифровое значение). >Важно отметить что если для каких-то разработок вы используете динамическое определение сущности, то `\CCrmOwnerType::isPossibleDynamicTypeId`, который говорит о предположительном смарт-процессе вернет вам `false`. Так что если вы не обработаете эту ситуацию сами вы будете неприятно удивлены. @@ -29,11 +29,11 @@ Счета являются особым типом смарт-процесса и должны реализовывать определенные заложенные в них поведения, а это значит что для счетов нельзя управлять настройками. Добавить или убрать какие-то опции как в своем смарт-процессе не получиться. -Что касается направлений, то они в данный момент не используют направления. Не смотря на то что технически направления существуют и поддерживаются механикой смарт-процессов использовать их не следует. При работе подразумевайте что счета это элементам смарт-процесса, у которого в интерфейсе отключены направления. +Что касается направлений, то они в данный момент не используют направления. Несмотря на то что технически направления существуют и поддерживаются механикой смарт-процессов использовать их не следует. При работе подразумевайте что счета это элементам смарт-процесса, у которого в интерфейсе отключены направления. Что касается стадий, то работа с ними ведется аналогично работе со смарт-процессами, за исключением того что счетов другой набор стадий при создании (это необходимо для поддержания обратной совместимости со старыми счетами). -Поскольку счета несут в себе бизнес-функцию и "наследуют" возможности старых счетов разработчики битрикса расшириликласс-наследник `DataManager` дополнительными полями (через `ORM`в `runtime`). +Поскольку счета несут в себе бизнес-функцию и "наследуют" возможности старых счетов разработчики битрикса расширили класс-наследник `DataManager` дополнительными полями (через `ORM`в `runtime`). При этом добавлены некоторые дополнительные поля: - `ACCOUNT_NUMBER` - номер счета @@ -41,7 +41,7 @@ ## Примеры -Небольшой пример работы со счетами: создадим счет с определенными паремтрами. +Небольшой пример работы со счетами: создадим счет с определенными параметрами. Плательщик: "ООО Ромашка" (ID:111), Наше юр.лицо: "ООО Фьюжн" (ID:400), по реквизитам юридического лица (ID:444) @@ -50,8 +50,8 @@ Сделка: "Продажа пестиков и тычинок в ООО Ромашка" (ID:555) Товары: -- "Пестик" (1шт, 100.0 руб./шт) (ID:222) -- "Тычинка" (2шт, 150.0 р/шт) (ID:333) +- "Пестик" (1шт, 100.0 руб./шт.) (ID:222) +- "Тычинка" (2шт, 150.0 р/шт.) (ID:333) Пример создания такого счета может выглядеть так: diff --git "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/21_\320\237\321\200\320\265\320\264\320\273\320\276\320\266\320\265\320\275\320\270\320\265.md" "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/23_\320\237\321\200\320\265\320\264\320\273\320\276\320\266\320\265\320\275\320\270\320\265.md" similarity index 61% rename from "docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/21_\320\237\321\200\320\265\320\264\320\273\320\276\320\266\320\265\320\275\320\270\320\265.md" rename to "docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/23_\320\237\321\200\320\265\320\264\320\273\320\276\320\266\320\265\320\275\320\270\320\265.md" index 243a8cd..3ba0a0e 100644 --- "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/21_\320\237\321\200\320\265\320\264\320\273\320\276\320\266\320\265\320\275\320\270\320\265.md" +++ "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/23_\320\237\321\200\320\265\320\264\320\273\320\276\320\266\320\265\320\275\320\270\320\265.md" @@ -4,9 +4,9 @@ >С точки зрения системы коммерческое предложение - это элемент CRM с информацией о компании, товарах и услугах, а также предложением сотрудничества. Это следующая стадия работы с клиентом после создания сделки. -Подобно [счетам](./Счет) предложение является уницифированной сущностью, но не основанной на механике смарт-процессов. Можно сказать что предложения реализуют те же интерфейсы и наследуются от тех же абстрактных классов что и другие сущности, но по большей части перекрывают их поведение. +Подобно [счетам](./22_Счет) предложение является уницифированной сущностью, но не основанной на механике смарт-процессов. Можно сказать что предложения реализуют те же интерфейсы и наследуются от тех же абстрактных классов что и другие сущности, но по большей части перекрывают их поведение. -Так как их поведение подчиняется тем же правилам работы с фабриками что и другие сущности (например [Смарт-процессы](./Смарт_процессы/Описание)) описывать методы и механики не имеет смысла. Единственный заслуживающий внимания частоиспользуемый случай - создание предложения на основании сделки. +Так как их поведение подчиняется тем же правилам работы с фабриками, описывать методы и механики не имеет смысла. Единственный заслуживающий внимания часто-используемый случай - создание предложения на основании сделки. ## Создание на основании сделки diff --git "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/30_\320\224\320\265\320\273\320\276/00_\320\236\320\261\321\211\320\265\320\265_API.md" "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/30_\320\224\320\265\320\273\320\276/00_\320\236\320\261\321\211\320\265\320\265_API.md" index f8c1172..7512987 100644 --- "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/30_\320\224\320\265\320\273\320\276/00_\320\236\320\261\321\211\320\265\320\265_API.md" +++ "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/30_\320\224\320\265\320\273\320\276/00_\320\236\320\261\321\211\320\265\320\265_API.md" @@ -1,6 +1,6 @@ # Общее апи -Здесь будет описано общее апи по работе с делами в том числе устаревшими. +Здесь будет описано общее апи по работе с делами, в том числе устаревшими. ## Удаление дела @@ -24,8 +24,8 @@ - `SKIP_COMMUNICATIONS` (bool) - флаг, отключающий удаление привязанных к делу коммуникационных каналов. - `SKIP_FILES` (bool) - флаг, отключающий удаление привязанных к делу файлов. Если `MOVED_TO_RECYCLE_BIN` = `true`, автоматически `true`. - `SKIP_USER_ACTIVITY_SYNC` (bool) - флаг отключающий синхронизацию активности (не будет перерасчета ближайших дел) -- `SKIP_STATISTICS` (bool) - флаг, отключащий перерасчет статистики сделки/лида -- `SKIP_ASSOCIATED_ENTITY` (bool) - флаг, отключащий удаление связанной сущности (связанную сущность определяет провайдер дела) +- `SKIP_STATISTICS` (bool) - флаг, отключающий перерасчет статистики сделки/лида +- `SKIP_ASSOCIATED_ENTITY` (bool) - флаг, отключающий удаление связанной сущности (связанную сущность определяет провайдер дела) - `SKIP_CALENDAR_EVENT` (bool) - флаг, отключающий удаление события календаря связанного с этим делом (если такое существует) Пример простого удаления дела с ID:123 @@ -51,9 +51,9 @@ else Событие вызываемое перед удалением (или перемещением в корзину) элемента методом `CCrmActivity::Delete`. -| Параметр | Значение | -| :----------: | ----------------------------- | -| $id | Идентификатор удаляемого дела | +| Параметр | Значение | +|:--------:|-------------------------------| +| $id | Идентификатор удаляемого дела | Если вернет `false` (строгая проверка) может прекратить удаление дела. @@ -77,9 +77,9 @@ $eventManager->addEventHandlerCompatible( Событие вызываемое после успешного удаления (или перемещения в корзину) элемента методом `CCrmActivity::Delete`. -| Параметр | Значение | -| :----------: | ----------------------------- | -| $id | Идентификатор удаленного дела | +| Параметр | Значение | +|:--------:|-------------------------------| +| $id | Идентификатор удаленного дела | Возвращаемое значение не обрабатывается. diff --git "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/30_\320\224\320\265\320\273\320\276/10_\320\243\320\275\320\270\320\262\320\265\321\200\321\201\320\260\320\273\321\214\320\275\320\276\320\265_\320\264\320\265\320\273\320\276.md" "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/30_\320\224\320\265\320\273\320\276/10_\320\243\320\275\320\270\320\262\320\265\321\200\321\201\320\260\320\273\321\214\320\275\320\276\320\265_\320\264\320\265\320\273\320\276.md" index aa0fb10..6884550 100644 --- "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/30_\320\224\320\265\320\273\320\276/10_\320\243\320\275\320\270\320\262\320\265\321\200\321\201\320\260\320\273\321\214\320\275\320\276\320\265_\320\264\320\265\320\273\320\276.md" +++ "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/30_\320\224\320\265\320\273\320\276/10_\320\243\320\275\320\270\320\262\320\265\321\200\321\201\320\260\320\273\321\214\320\275\320\276\320\265_\320\264\320\265\320\273\320\276.md" @@ -18,7 +18,7 @@ use \CCrmOwnerType, ; ``` 3. В переменной `$entityItemIdentifier` находится объект класса `\Bitrix\Crm\ItemIdentifier` для которого мы выполняем работу. -В рамках примеров, мы предположим что работам с сделкой (`\CCrmOwnerType::Deal`) под ID:16. +В рамках примеров, мы предположим что работам со сделкой (`\CCrmOwnerType::Deal`) под ID:16. ```php $entityItemIdentifier = new ItemIdentifier(CCrmOwnerType::Deal, 16); ``` @@ -93,13 +93,13 @@ $saveResult = $todo->save(); ### Удаление дела -Отдельного метода на удаления дела нет, воспользуйтесь [общим api по удалению дел](/Общее_API#udalenie-dela). +Отдельного метода на удаления дела нет, воспользуйтесь [общим api по удалению дел](./00_Общее_API#udalenie-dela). ### Получение дела по его ID ```php /** - * Suggested `todo` activity id + * Suggested 'todo' activity id * @var integer */ $activityId = 123; @@ -113,4 +113,4 @@ $todoEntity = ToDo::load($entityItemIdentifier, $activityId); ### Поиск дела Отдельного api на поиск и получения всех дел нет. -Воспользуйтесь [общим api](/Общее_API). \ No newline at end of file +Воспользуйтесь [общим api](./00_Общее_API). \ No newline at end of file diff --git "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/30_\320\224\320\265\320\273\320\276/index.md" "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/30_\320\224\320\265\320\273\320\276/index.md" index 8d4474d..ca044b4 100644 --- "a/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/30_\320\224\320\265\320\273\320\276/index.md" +++ "b/docs/04_\320\234\320\276\320\264\321\203\320\273\321\214_CRM/30_\320\224\320\265\320\273\320\276/index.md" @@ -1,7 +1,7 @@ # Введение Любая активность связанная с клиентом в CRM является элементом сущности "Дело" (дела, crm activity, activity). -Структурно дела деляться на 3 больших раздела: +Структурно дела делятся на 3 больших раздела: 1. "Реальные дела" - это то что существует исключительно в карточке CRM и без модуля `CRM` не имеет никакого смысла 2. "Прокси дела" - это динамические связки с другими модулями (события календаря, задачи, звонки) 3. "Специальные дела" - специальные дела, которые нельзя отнести к предыдущим видам (например "ожидания", "rest" и т.п.) @@ -12,4 +12,4 @@ Поскольку это достаточно быстроизменяющийся раздел, в данной книге мы будем рассматривать исключительно то что мы имеем в последних обновлениях: -- [Универсальное дело (ToDo)](./Универсальное_дело) \ No newline at end of file +- [Универсальное дело (ToDo)](./10_Универсальное_дело) \ No newline at end of file diff --git "a/docs/05_\320\234\320\276\320\264\321\203\320\273\321\214_\320\230\320\275\321\202\321\200\320\260\320\275\320\265\321\202/00_\320\236_\320\274\320\276\320\264\321\203\320\273\320\265.md" "b/docs/05_\320\234\320\276\320\264\321\203\320\273\321\214_\320\230\320\275\321\202\321\200\320\260\320\275\320\265\321\202/00_\320\236_\320\274\320\276\320\264\321\203\320\273\320\265.md" index f0a70bf..fd706f4 100644 --- "a/docs/05_\320\234\320\276\320\264\321\203\320\273\321\214_\320\230\320\275\321\202\321\200\320\260\320\275\320\265\321\202/00_\320\236_\320\274\320\276\320\264\321\203\320\273\320\265.md" +++ "b/docs/05_\320\234\320\276\320\264\321\203\320\273\321\214_\320\230\320\275\321\202\321\200\320\260\320\275\320\265\321\202/00_\320\236_\320\274\320\276\320\264\321\203\320\273\320\265.md" @@ -4,7 +4,7 @@ # Перед использованием API -Рассматривая работу модуля с точки зрения его api необходимо знать что так как модуль является основополагающим, то в подавляющем большинстве случаев модуль будет всегда подключен в контексте страницы, однако мы все же рекомендуем и это является хорошим тоном все же учитывать в своих методах зависящих от этого модуля факт его подключения. +Поскольку модуль "Интранет" является неотъемлемой частью Битрикс24 (его нельзя удалить), он всегда подключен к публичной части портала. Однако никогда не лишним убедиться что он подключен. ```php use \Bitrix\Main; diff --git "a/docs/05_\320\234\320\276\320\264\321\203\320\273\321\214_\320\230\320\275\321\202\321\200\320\260\320\275\320\265\321\202/05_\320\236\321\200\320\263\321\201\321\202\321\200\321\203\320\272\321\202\321\203\321\200\320\260.md" "b/docs/05_\320\234\320\276\320\264\321\203\320\273\321\214_\320\230\320\275\321\202\321\200\320\260\320\275\320\265\321\202/05_\320\236\321\200\320\263\321\201\321\202\321\200\321\203\320\272\321\202\321\203\321\200\320\260.md" index 934dbd8..fd60091 100644 --- "a/docs/05_\320\234\320\276\320\264\321\203\320\273\321\214_\320\230\320\275\321\202\321\200\320\260\320\275\320\265\321\202/05_\320\236\321\200\320\263\321\201\321\202\321\200\321\203\320\272\321\202\321\203\321\200\320\260.md" +++ "b/docs/05_\320\234\320\276\320\264\321\203\320\273\321\214_\320\230\320\275\321\202\321\200\320\260\320\275\320\265\321\202/05_\320\236\321\200\320\263\321\201\321\202\321\200\321\203\320\272\321\202\321\203\321\200\320\260.md" @@ -8,9 +8,9 @@ ## Архитектура -Подразделения представляю собой древовидный классификатор построенный на базе разделов информационного блока "Оргструктура". На одном портале может быть только одно корневое подразделение. В отличии от [Отсутствий](./Отсутствия) информационный блок для Оргструктуры единый для всего портала. +Подразделения представляю собой древовидный классификатор построенный на базе разделов информационного блока "Оргструктура". На одном портале может быть только одно корневое подразделение. В отличие от [Отсутствий](./30_Отсутствия) информационный блок для Оргструктуры единый для всего портала. -Каждое подразделение характерируется следующими свойствами: +Каждое подразделение характеризуется следующими свойствами: - Активность (Да/Нет) - Название подразделения (строка) - Руководитель (привязка к сотруднику) @@ -29,7 +29,7 @@ ## API -Поскольку организационная структура построена на базе разделов информационного блока "Оргструктура", API для CRUD-действий аналогичный работе с инфоблоками. +Поскольку организационная структура построена на базе разделов информационного блока "Оргструктура", API для CRUD-действий аналогичной работе с инфоблоками. Перед началом работы с API инфоблоков нужно получить идентификатор инфоблока для конкретного сайта. Они хранятся в настройках (`b_options`, `b_option_site`) с кодом модуля `intranet` и названием `iblock_structure` ```php @@ -45,7 +45,7 @@ $siteCo1StructureId = Option::get('intranet', 'iblock_structure', '-1', 'co1'); $iblockId = \COption::GetOptionInt('intranet', 'iblock_structure', -1); ``` ->Обратите внимание на трюк с значением по-умолчанию `-1`. Дело в том что при работе с инфоблоками пустое значение (равное нулю) в getList будет проигнорировано. Этот трюк позволяет не беспокоиться в случае технической ошибки и снизить ущерб. +>Обратите внимание на трюк со значением по-умолчанию `-1`. Дело в том что при работе с инфоблоками пустое значение (равное нулю) в getList будет проигнорировано. Этот трюк позволяет не беспокоиться в случае технической ошибки и снизить ущерб. >Обратите внимание: в Битрикс24 модуль `intranet` автоматически подключен к порталу, поэтому методы интранета можно вызывать без подключения модуля @@ -53,7 +53,7 @@ $iblockId = \COption::GetOptionInt('intranet', 'iblock_structure', -1); ### Получение дерева -Не смотря на то что архитектурно дерево подразделений устроено на базе информационных блоков, работать с чтением напрямую из инфоблока не рекомендуется и нет такой необходимости. Существует метод для получения объемного и полного дерева подразделений - `CIntranetUtils::GetStructure()`. +Несмотря на то что архитектурно дерево подразделений устроено на базе информационных блоков, работать с чтением напрямую из инфоблока не рекомендуется и нет такой необходимости. Существует метод для получения объемного и полного дерева подразделений - `CIntranetUtils::GetStructure()`. Пример возвращаемой структуры: ```php @@ -112,8 +112,8 @@ $structure = [ ``` `CIntranetUtils::GetStructure()` всегда возвращает структуру из двух элементов: -- Ключ `THREE` - содержит ассоциативный массив где ключи это ID родительского подразделения, а значения это массив из ID вложенных подразделений -- Ключ `DATA` - содержит ассоциативный массив где ключи это идентификаторы подразделений, а значения это структура опсиывающая подразделение +- Ключ `THREE` - содержит ассоциативный массив, где ключи это ID родительского подразделения, а значения это массив из ID вложенных подразделений +- Ключ `DATA` - содержит ассоциативный массив, где ключи это идентификаторы подразделений, а значения это структура описывающая подразделение Разберем структуру ключа `DATA`: - `ID` (string) - строковое представление идентификатора подразделения @@ -180,14 +180,14 @@ $result = ["2", "4", "3"]; ### Сотрудники подразделения Для получения списка сотрудников подразделения можно воспользоваться методом: `\Bitrix\Intranet\Util::getDepartmentEmployees( $params )`. -Структура `$params` представляет из себя ассоциативный массив, который состоит из следующих ключей: +Структура `$params` представляет собой ассоциативный массив, который состоит из следующих ключей: - `DEPARTMENTS` (`array`) - список идентификаторов подразделений, для которых выполняется поиск - `RECURSIVE` (`string`) - `Y` / `N` (по-умолчанию `N`) - нужно ли вычислять сотрудников вложенных подразделений - `ACTIVE` (`string`) - `Y` / `N` включать в список только действующих сотрудников (флаг активности = да) - `SKIP` (`int`) - идентификатор сотрудника, которого не нужно включать в список. - `SELECT` (`array`) - набор полей, которые нужно запросить из базы данных -Результатом работы метода будет наследник `CDBResult`, который можно проитерировать. +Результатом работы метода будет наследник `CDBResult`, который можно итерировать. Пример: ```php diff --git "a/docs/05_\320\234\320\276\320\264\321\203\320\273\321\214_\320\230\320\275\321\202\321\200\320\260\320\275\320\265\321\202/10_\320\242\320\265\320\274\321\213/00_\320\236\321\201\320\275\320\276\320\262\320\275\320\276\320\265.md" "b/docs/05_\320\234\320\276\320\264\321\203\320\273\321\214_\320\230\320\275\321\202\321\200\320\260\320\275\320\265\321\202/10_\320\242\320\265\320\274\321\213/00_\320\236\321\201\320\275\320\276\320\262\320\275\320\276\320\265.md" index 379f2be..5efa26c 100644 --- "a/docs/05_\320\234\320\276\320\264\321\203\320\273\321\214_\320\230\320\275\321\202\321\200\320\260\320\275\320\265\321\202/10_\320\242\320\265\320\274\321\213/00_\320\236\321\201\320\275\320\276\320\262\320\275\320\276\320\265.md" +++ "b/docs/05_\320\234\320\276\320\264\321\203\320\273\321\214_\320\230\320\275\321\202\321\200\320\260\320\275\320\265\321\202/10_\320\242\320\265\320\274\321\213/00_\320\236\321\201\320\275\320\276\320\262\320\275\320\276\320\265.md" @@ -10,32 +10,32 @@ - Системные (доступные изначально) - Пользовательские (созданные пользователем) -Пользовательские темы имеют значительные ограничения в кастомизации: допустипо выбрать только базовый цвет текста (светлый/темный), цвет фона и подложку, если необходимо. +Пользовательские темы имеют значительные ограничения в кастомизации: допустимо выбрать только базовый цвет текста (светлый/темный), цвет фона и подложку, если необходимо. >Для подложки используйте изображения (jpg, png) и гифки (gif) размером не более 20 Мб и разрешением не больше 5000х5000. Если вы загружаете картинку с пониженной прозрачностью, то также укажите и Цвет фона, который будет видно за загружаемым изображением. Помимо классификацией по типам существует классификация по месту применения: есть персонализированные темы для конкретных сотрудников, а есть для рабочих групп. У каждого места применения свои особенности: персонализированная тема для сотрудника открывается у любого пользователя который открывает его профиль, а тема для рабочих групп открывается лишь при просмотре группы в слайдере. -Помните что темы являются сайтозависыми, поэтому работа с ними осуществляется двумя путями: +Помните что темы зависят от сайта, поэтому работа с ними осуществляется двумя путями: * Для работы с конфигурацией через объект класса `ThemePicker`. Например, для получения списка тем определенного сайта. * Для работы с текущим сайтом через singleton-класса `ThemePicker`. Класс из пространства имен `\Bitrix\Intranet\Integration\Templates\Bitrix24\`. Выполняя примеры мы будем предполагать что вы выполнили следующие условия: -1. Убедились что подключили модуль Интранет (`intranet`). +1. Убедились, что подключили модуль Интранет (`intranet`). 2. Получили объект класса любым из перечисленным методом. 3. Добавили в use-раздел namespace: ```php use \Bitrix\Intranet\Integration\Templates\Bitrix24; ``` -В шаблоне `bitrix24` (шаблон по-умолчанию для корп. портала) механизм тем представляет из себя слоеный пирог, состоящий из: +В шаблоне `bitrix24` (шаблон по-умолчанию) механизм тем представляет собой слоеный пирог, состоящий из: 1. Базовой группы (`baseTheme`) 2. Тема (`subTheme`) В стандартной поставке существует 3 базовых группы: `default`, `light`, `black`. Однако `default` является группой с одной темой, так как является базовой для всего шаблона. Все остальные темы могут быть либо `light` либо `black`, которые различаются цветом шрифта и иконок. В `light` цвет будет белым. ->В данный момент существует техническое ограничене на количество пользовательских тем - 40. В это число не входят темы которые поставляются вендором в стандартной поставке, а только создаваемые пользователями. В будущем число может измениться. Актуальное для вашей версии число можно проверить в константе `MAX_CUSTOM_THEMES` класса темы. +>В данный момент существует техническое ограничение на количество пользовательских тем - 40. В это число не входят темы которые, поставляются вендором в стандартной поставке, а только создаваемые пользователями. В будущем число может измениться. Актуальное для вашей версии число можно проверить в константе `MAX_CUSTOM_THEMES` класса темы. # API Reference @@ -65,14 +65,14 @@ $themePicker = Bitrix24\ThemePicker::getInstance($themeType); Параметры: -| Параметр | Значение | -| :------------ | ------------------------------------------- | -| `$templateId` | идентификатор шаблона сайта. По-умолчанию в Битрикс24 используется шаблон `bitrix24` | -| `$siteId` | идентификатор сайта. По-умолчанию используется из константы `SITE_ID` | -| `$userId` | идентификатор пользователя чьи настройки используем | +| Параметр | Значение | +|:--------------|-------------------------------------------------------------------------------------------------------------------------------------------| +| `$templateId` | идентификатор шаблона сайта. По-умолчанию в Битрикс24 используется шаблон `bitrix24` | +| `$siteId` | идентификатор сайта. По-умолчанию используется из константы `SITE_ID` | +| `$userId` | идентификатор пользователя чьи настройки используем | | `$entityType` | тип сущности, над которой выполняется работа `Bitrix24\ThemePicker::ENTITY_TYPE_USER` или `Bitrix24\ThemePicker::ENTITY_TYPE_SONET_GROUP` | -| `$entityId` | идентификатор изменяемого элемента (применимо только к группе) | -| `$params` | дополнительные параметры | +| `$entityId` | идентификатор изменяемого элемента (применимо только к группе) | +| `$params` | дополнительные параметры | Пример альтернативного варианта получения объекта темы через конструктор: ```php @@ -104,9 +104,9 @@ $themes = $themePicker->getList(); Для установки темы используется нестатический метод `setCurrentThemeId($themeId, $currentUserId = 0): bool`, который в случае с пользователем меняет его тему, а в случае с группой производит изменение темы (не путать с тематикой) группы (без проверки прав). -| Параметр | Значение | -| :--------------- | ------------------------------------------- | -| `$themeId` | идентификатор устанавливаемой темы | +| Параметр | Значение | +|:-----------------|-------------------------------------------------------------------------------------------------------| +| `$themeId` | идентификатор устанавливаемой темы | | `$currentUserId` | если ThemePicker создан для сотрудника записывает его как установившего тему, для группы игнорируется | Например, если мы заходим для пользователя ID:`3` в шаблоне `bitrix24` сайта `s1` установить тему `light:tulips`, то мы можем использовать следующий код: @@ -192,7 +192,7 @@ array(9) { ``` -Обратите внимание что в ключе `css` массива описывающего темы можно уведеть несколько путей к css-файлам. +Обратите внимание, что в ключе `css` массива описывающего темы можно увидеть несколько путей к css-файлам. Часть файлов (`light/main.css`, `light/menu.css`) относятся к базовой группе, а часть (`light/tulips/style.css`) к самой теме. Получить идентификаторы базовой группы и темы установленных в данный момент можно через нестатические методы `getCurrentBaseThemeId()` и `getCurrentSubThemeId()` соответственно diff --git "a/docs/05_\320\234\320\276\320\264\321\203\320\273\321\214_\320\230\320\275\321\202\321\200\320\260\320\275\320\265\321\202/10_\320\242\320\265\320\274\321\213/01_\320\237\320\265\321\200\320\265\320\272\321\200\321\213\321\202\320\270\320\265.md" "b/docs/05_\320\234\320\276\320\264\321\203\320\273\321\214_\320\230\320\275\321\202\321\200\320\260\320\275\320\265\321\202/10_\320\242\320\265\320\274\321\213/01_\320\237\320\265\321\200\320\265\320\272\321\200\321\213\321\202\320\270\320\265.md" index a88aa5c..a422b46 100644 --- "a/docs/05_\320\234\320\276\320\264\321\203\320\273\321\214_\320\230\320\275\321\202\321\200\320\260\320\275\320\265\321\202/10_\320\242\320\265\320\274\321\213/01_\320\237\320\265\321\200\320\265\320\272\321\200\321\213\321\202\320\270\320\265.md" +++ "b/docs/05_\320\234\320\276\320\264\321\203\320\273\321\214_\320\230\320\275\321\202\321\200\320\260\320\275\320\265\321\202/10_\320\242\320\265\320\274\321\213/01_\320\237\320\265\321\200\320\265\320\272\321\200\321\213\321\202\320\270\320\265.md" @@ -1,4 +1,4 @@ -Не смотря на наличие тем для шаблона bitrix24 разработчики не предусмотрели никаких механик позволяющий влиять на это поведение, таким образом для изменения состава тем так или иначе приходится явно использовать папку `/bitrix/templates/bitrix24/themes` и сохранять эти изменения в системе контроля версий. +Несмотря на наличие тем для шаблона bitrix24 разработчики не предусмотрели никаких механик позволяющий влиять на это поведение, таким образом для изменения состава тем так или иначе приходится явно использовать папку `/bitrix/templates/bitrix24/themes` и сохранять эти изменения в системе контроля версий. Однако подобный вариант является достаточно варварским изменением системных файлов, что не является приемлемым в разработке коробочных версий. Существует не очень красивый способ, которым можно переопределить стандартные шаблоны не затрагивая стандартные механики. diff --git "a/docs/05_\320\234\320\276\320\264\321\203\320\273\321\214_\320\230\320\275\321\202\321\200\320\260\320\275\320\265\321\202/30_\320\236\321\202\321\201\321\203\321\202\321\201\321\202\320\262\320\270\321\217.md" "b/docs/05_\320\234\320\276\320\264\321\203\320\273\321\214_\320\230\320\275\321\202\321\200\320\260\320\275\320\265\321\202/30_\320\236\321\202\321\201\321\203\321\202\321\201\321\202\320\262\320\270\321\217.md" index 239bf60..93715df 100644 --- "a/docs/05_\320\234\320\276\320\264\321\203\320\273\321\214_\320\230\320\275\321\202\321\200\320\260\320\275\320\265\321\202/30_\320\236\321\202\321\201\321\203\321\202\321\201\321\202\320\262\320\270\321\217.md" +++ "b/docs/05_\320\234\320\276\320\264\321\203\320\273\321\214_\320\230\320\275\321\202\321\200\320\260\320\275\320\265\321\202/30_\320\236\321\202\321\201\321\203\321\202\321\201\321\202\320\262\320\270\321\217.md" @@ -2,7 +2,7 @@ [TOC] -В интранет модуле имеется сущность "Отсутствие" необходимое для контроля состояния сотрудника во времени (в отпуске, на больничном и т.п.). С точки зрения технического воплощения "Отсутствие" разбито на 2 части - одна обеспечивается модулем "Интранет" и представлена через инструмент "График отсутствий", а вторая является подсистемой модуля "Календарь". В этой статье мы рассмотрим "Отстутствие" с точки зрения "Графика отсутствий". +В интранет модуле имеется сущность "Отсутствие" необходимое для контроля состояния сотрудника во времени (в отпуске, на больничном и т.п.). С точки зрения технического воплощения "Отсутствие" разбито на 2 части - одна обеспечивается модулем "Интранет" и представлена через инструмент "График отсутствий", а вторая является подсистемой модуля "Календарь". В этой статье мы рассмотрим "Отсутствие" с точки зрения "Графика отсутствий". >График отсутствий — это инструмент, который помогает организовать рабочий процесс и следить за отсутствием сотрудников на рабочем месте. Он полезен для планирования проектов и распределения задач: всегда видно, когда сотрудники недоступны по различным причинам — отпуск, больничный или командировка. @@ -10,7 +10,7 @@ С точки зрения архитектуры "Отсутствие" - это элемент инфоблока "График отсутствий". По-умолчанию располагается в типе инфоблоков "Оргструктура". ->Инфоблок "График отсутствий" - может быть сконфигурирован в настройках модуля Интранет. Что это значит? Это значит что вы можете взять любой инфоблок, создать необходимые свойства и в настройках модуля Интранет указать что он является "хранителем" отсутствий. +>Инфоблок "График отсутствий" - может быть сконфигурирован в настройках модуля Интранет. Что это значит? Вы можете взять любой инфоблок, создать необходимые свойства и в настройках модуля Интранет указать что он является "хранителем" отсутствий. Отсутствие характеризуется следующими полями: - Отсутствующий сотрудник (Код свойства: `USER`, привязка к пользователю) @@ -18,7 +18,7 @@ - Причина отсутствия (Поле `NAME` - название инфоблока, строка) - Период отсутствия: Начало и Окончание (Поля `ACTIVE_FROM` и `ACTIVE_TO` - дата) ->Примечание к справочнику "Тип отсутствия": не смотря на то что в инфоблоке есть список который омжно дополнять и редактировать, нужно помнить что не все подсистемы модуля Интранет воспринимают новые поля. Может оказаться так что новый добавленный тип не будет учитываться как отсутствие без уважительной причины, отпуск или другое. Дополнять список можно, но не рекомендуется. +>Примечание к справочнику "Тип отсутствия": несмотря на то что в инфоблоке есть список который можно дополнять и редактировать, нужно помнить что не все подсистемы модуля Интранет воспринимают новые поля. Может оказаться так что новый добавленный тип не будет учитываться как отсутствие без уважительной причины, отпуск или другое. Дополнять список можно, но не рекомендуется. ## API @@ -34,7 +34,7 @@ $iblockId = Option::get('intranet', 'iblock_absence', '-1'); $siteCo1AbsenceId = Option::get('intranet', 'iblock_absence', '-1', 'co1'); ``` ->Обратите внимание на трюк с значением по-умолчанию `-1`. Дело в том что при запросе в CIBlockElement::getList пустое значение (равное нулю) будет проигнорировано. Этот трюк позволяет не беспокоиться в случае технической ошибки и снизить ущерб. +>Обратите внимание на трюк со значением по-умолчанию `-1`. Дело в том что при запросе в CIBlockElement::getList пустое значение (равное нулю) будет проигнорировано. Этот трюк позволяет не беспокоиться в случае технической ошибки и снизить ущерб. Альтернативный способ получения общего идентификатора графика отсутствий: @@ -86,7 +86,7 @@ $vacationTypes = [ ### Отсутствия текущего месяца -Помимо методов информационных блоков для получения информации есть кешируемый метод который позволяет получить отсутствия в текущем месяце. +Помимо методов инфоблоков для получения информации есть кешируемый метод, который позволяет получить отсутствия в текущем месяце. За счет кеширования выборка данных на текущем месяце будет быстрее. ```php @@ -116,7 +116,7 @@ $currentMonthAbsences = [ ``` Описание структуры: -- `ID` (`int`) - Идентификатор отсутствия (элмента инфоблока) +- `ID` (`int`) - Идентификатор отсутствия (элемента инфоблока) - `USER_ID` (`int`) - Идентификатор сотрудника - `ENTRY_TYPE` (`string`) - Симв.код типа отсутствия - `ENTRY_TYPE_ID` (`int`) - Идентификатор типа отсутствия @@ -144,7 +144,7 @@ $isUserAbsence = \CIntranetUtils::IsUserAbsent($userId); ``` -И его более сложный аналог - проверка отсутствия в определнный момент `\CIntranetUtils::GetAbsenceData($arParams = array(), $MODE = BX_INTRANET_ABSENCE_ALL)`. +И его более сложный аналог - проверка отсутствия в определенный момент `\CIntranetUtils::GetAbsenceData($arParams = array(), $MODE = BX_INTRANET_ABSENCE_ALL)`. Метод принимает на вход 2 аргумента: - `$arParams` (`array`) - параметры конфигурирующие запрос - `$mode` (`int`) - режим запроса @@ -179,13 +179,13 @@ $absenceList = \CIntranetUtils::GetAbsenceData([ Подсистема выбрасывает события начала (`OnStartAbsence`) и окончания отпуска (`OnEndAbsence`). -| Параметр | Значение | -| :----------: | --------------------------- | -| USER_ID | ID сотрудника (число) | -| ABSENCE_TYPE | Тип отпуска (число) | -| START | Дата начала (строка) | -| END | Дата окончания (строка) | -| DURATION | Длительность (число, сек.) | +| Параметр | Значение | +|:------------:|----------------------------| +| USER_ID | ID сотрудника (число) | +| ABSENCE_TYPE | Тип отпуска (число) | +| START | Дата начала (строка) | +| END | Дата окончания (строка) | +| DURATION | Длительность (число, сек.) | Возвращаемые значения не обрабатываются. diff --git "a/docs/06_\320\234\320\276\320\264\321\203\320\273\321\214_\320\221\320\270\320\267\320\275\320\265\321\201-\320\277\321\200\320\276\321\206\320\265\321\201\321\201\321\213/00_\320\236_\320\274\320\276\320\264\321\203\320\273\320\265.md" "b/docs/06_\320\234\320\276\320\264\321\203\320\273\321\214_\320\221\320\270\320\267\320\275\320\265\321\201-\320\277\321\200\320\276\321\206\320\265\321\201\321\201\321\213/00_\320\236_\320\274\320\276\320\264\321\203\320\273\320\265.md" index 75a9da0..980e4e3 100644 --- "a/docs/06_\320\234\320\276\320\264\321\203\320\273\321\214_\320\221\320\270\320\267\320\275\320\265\321\201-\320\277\321\200\320\276\321\206\320\265\321\201\321\201\321\213/00_\320\236_\320\274\320\276\320\264\321\203\320\273\320\265.md" +++ "b/docs/06_\320\234\320\276\320\264\321\203\320\273\321\214_\320\221\320\270\320\267\320\275\320\265\321\201-\320\277\321\200\320\276\321\206\320\265\321\201\321\201\321\213/00_\320\236_\320\274\320\276\320\264\321\203\320\273\320\265.md" @@ -7,15 +7,15 @@ Под *бизнес-процессом* мы будем понимать последовательность действий (алгоритм) с помощью которого можно достичь определенной цели. Например "Процесс продажи/выполнения проекта", "Процесс оформления заявки на отпуск" являются бизнес-процессами. -*Шаблон бизнес-процесса* - это последовательность конкретных шагов, описанных в дизанере бизнес-процессов битрикса, которые необходимо выполнить для достижения цели *над определенным объектом*. +*Шаблон бизнес-процесса* - это последовательность конкретных шагов, описанных в дизайнере бизнес-процессов битрикса, которые необходимо выполнить для достижения цели *над определенным объектом*. Например: последовательность действий "Запрос доп. информации", "Уведомления" и др. которые позволяют автоматизировать бизнес-процесс. >Важное примечание: бизнес-процесс можно запустить только на объекте, который поддерживает соответствующую механику. Не все объекты частично (например задачи) или даже полностью (старые счета, события календаря) поддерживают работу данной механики. -Шаблон бизнес-процесса состоиз из конкретных шагов - *действий бизнес-процесса*. Чаще для сокращения их называют *действиями*, *заданиями*, *шагами* или *активити*. Активити - это одна атомарная операция или 'визуальный кубик' в дизайнере бизнес-процессов. В дальнейшем мы будем различать действия по их поведениям: *простое действие* - шаг которое выполняется сразу (например изменение переменных, изменение документа и т.п.) и *задание* - нечто ожидающее решения пользователя (запрос доп.информации, утверждения документа и т.п.). +Шаблон бизнес-процесса состоит из из конкретных шагов - *действий бизнес-процесса*. Чаще для сокращения их называют *действиями*, *заданиями*, *шагами* или *активити*. Активити - это одна атомарная операция или 'визуальный кубик' в дизайнере бизнес-процессов. В дальнейшем мы будем различать действия по их поведениям: *простое действие* - шаг которое выполняется сразу (например изменение переменных, изменение документа и т.п.) и *задание* - нечто ожидающее решения пользователя (запрос доп. информации, утверждения документа и т.п.). Теперь когда мы определились что такое шаблон и бизнес-процесс, перейдем к рассмотрению самого выполнения процесса. -Предположим обьектом нашей автоматизации служит "Процесс оплаты поставщикам". +Предположим объектом нашей автоматизации служит "Процесс оплаты поставщикам". Мы составили процесс таким образом, что он состоит из простых шагов: 1. Задача на оплату бухгалтеру 2. Запрос скана оплаченного документа бухгалтеру @@ -29,7 +29,7 @@ # Модуль Бизнес-процессы и Модуль Дизайнер бизнес-процессов -Не смотря на схожесть названий модулей модуль "Дизайнер бизнес-процессов" предоставляет лишь визуальный дизайнер и больше ничего. +Несмотря на схожесть названий модулей модуль "Дизайнер бизнес-процессов" предоставляет лишь визуальный дизайнер и больше ничего. Мы всегда будем предполагать что имеется и подключено оба модуля. diff --git "a/docs/06_\320\234\320\276\320\264\321\203\320\273\321\214_\320\221\320\270\320\267\320\275\320\265\321\201-\320\277\321\200\320\276\321\206\320\265\321\201\321\201\321\213/10_\320\224\320\265\320\271\321\201\321\202\320\262\320\270\321\217/10_PHP_\320\272\320\276\320\264.md" "b/docs/06_\320\234\320\276\320\264\321\203\320\273\321\214_\320\221\320\270\320\267\320\275\320\265\321\201-\320\277\321\200\320\276\321\206\320\265\321\201\321\201\321\213/10_\320\224\320\265\320\271\321\201\321\202\320\262\320\270\321\217/10_PHP_\320\272\320\276\320\264.md" index 75530c0..cb78c5f 100644 --- "a/docs/06_\320\234\320\276\320\264\321\203\320\273\321\214_\320\221\320\270\320\267\320\275\320\265\321\201-\320\277\321\200\320\276\321\206\320\265\321\201\321\201\321\213/10_\320\224\320\265\320\271\321\201\321\202\320\262\320\270\321\217/10_PHP_\320\272\320\276\320\264.md" +++ "b/docs/06_\320\234\320\276\320\264\321\203\320\273\321\214_\320\221\320\270\320\267\320\275\320\265\321\201-\320\277\321\200\320\276\321\206\320\265\321\201\321\201\321\213/10_\320\224\320\265\320\271\321\201\321\202\320\262\320\270\321\217/10_PHP_\320\272\320\276\320\264.md" @@ -4,7 +4,7 @@ Иногда возникает необходимость расширить стандартные возможности бизнес-процессов, а для этого в коробке есть большой набор инструментов, одним из которых является действие "PHP код". ->Мы настоятельно не рекомендуем использовать это активити в релизах, поскольку данное действиее помимо своих сильных сторон имеет очевидные слабые стороны. +>Мы настоятельно не рекомендуем использовать это активити в релизах, поскольку данное действие помимо своих сильных сторон имеет очевидные слабые стороны. Преимущества: - Позволяет расширять возможности бизнес-процессов @@ -21,9 +21,9 @@ В случае если вы решили писать активити старайтесь следовать правилам: 1. Чем меньше кода тем проще его отладить. Старайтесь использовать код который можно отладить и без активити. -2. Оборачивайте код в [try-catch](https://www.php.net/manual/ru/language.exceptions.php) блок ожидая [Throwable](https://www.php.net/manual/ru/class.throwable.php). Таким образом вы предотвратите неожиданные и необьяснимые падения. +2. Оборачивайте код в [try-catch](https://www.php.net/manual/ru/language.exceptions.php) блок ожидая [Throwable](https://www.php.net/manual/ru/class.throwable.php). Таким образом вы предотвратите неожиданные и необъяснимые падения. 3. Записывайте все что может быть важно. Успешное выполнение, ошибка или неожиданное поведение. -4. Не используйте автозаменяемый битриксом код (Код `{ID}` автоматически заменяемый) +4. Не используйте код, который интерпретируется парсером битрикса (например `{ID}` автоматически заменяемый) 5. Не опирайтесь на глобальные переменные. Код может выполнять как на странице, так и на cron - переменная с текущим пользователем может быть пуста или заполнена не тем сотрудником. Идентификатора сайта может не быть. ## Журналирование @@ -108,7 +108,7 @@ $this->WriteToTrackingService($testMessage); В чем проблема? Представим грубо, что любая заменя это просто набор `str_replace`, т.е. переменные будут заменены как есть. Что произойдет если в заменяемой фразе будет кавычка? Например: в названии компании указано значение `ООО "Супер сила"` -Таким образом код будет выглядит следующим образом: +Таким образом код выглядит следующим образом: ```php $testMessage = "Entity id: ООО "Супер сила""; @@ -120,7 +120,7 @@ $this->WriteToTrackingService($testMessage) ### Парсинг -Мы уже знаем, что есть парсер который выполняет автозамену, но так же мы знаем что есть и калькулятор выражений, который умеет парсить и обрабатывать значения. +Из курса по бизнес-процессам нам известно о существование таких элементов как парсер (выполняет автозамену) и калькулятор выражений (парсит и вычисляет значения). За парсинг значений отвечает метод `\CBPActivity::parseValue($value, $convertToType = null)`, тогда у нас есть возможность использовать ее для своих нужд. ```php @@ -137,7 +137,7 @@ $testMessage = "Entity id: ".$this->ParseValue('{'.'=Document:TITLE}'); $this->WriteToTrackingService($testMessage); ``` ->Почему мы не написали `ParseValue('{=Document:TITLE}')` ? Дело в том, что с таком случае сработала бы автозамена и мы получили такую же ошибку как и ранее, поэтому мы сознательно разделили нашу запись чтобы автозамена значений битрикса не сработала. +>Почему мы не написали `ParseValue('{=Document:TITLE}')` ? Дело в том, что в таком случае сработала бы автозамена и мы получили такую же ошибку, как и ранее, поэтому мы сознательно разделили нашу запись чтобы автозамена значений битрикса не сработала. ## Полезные ссылки diff --git "a/docs/06_\320\234\320\276\320\264\321\203\320\273\321\214_\320\221\320\270\320\267\320\275\320\265\321\201-\320\277\321\200\320\276\321\206\320\265\321\201\321\201\321\213/10_\320\224\320\265\320\271\321\201\321\202\320\262\320\270\321\217/20_\320\224\320\265\320\271\321\201\321\202\320\262\320\270\321\217.md" "b/docs/06_\320\234\320\276\320\264\321\203\320\273\321\214_\320\221\320\270\320\267\320\275\320\265\321\201-\320\277\321\200\320\276\321\206\320\265\321\201\321\201\321\213/10_\320\224\320\265\320\271\321\201\321\202\320\262\320\270\321\217/20_\320\224\320\265\320\271\321\201\321\202\320\262\320\270\321\217.md" index 3442c00..7bbd098 100644 --- "a/docs/06_\320\234\320\276\320\264\321\203\320\273\321\214_\320\221\320\270\320\267\320\275\320\265\321\201-\320\277\321\200\320\276\321\206\320\265\321\201\321\201\321\213/10_\320\224\320\265\320\271\321\201\321\202\320\262\320\270\321\217/20_\320\224\320\265\320\271\321\201\321\202\320\262\320\270\321\217.md" +++ "b/docs/06_\320\234\320\276\320\264\321\203\320\273\321\214_\320\221\320\270\320\267\320\275\320\265\321\201-\320\277\321\200\320\276\321\206\320\265\321\201\321\201\321\213/10_\320\224\320\265\320\271\321\201\321\202\320\262\320\270\321\217/20_\320\224\320\265\320\271\321\201\321\202\320\262\320\270\321\217.md" @@ -2,7 +2,7 @@ [TOC] -Все, что исполняется в бизнес-процессе является действем (по-другому `активити`), а сам бизнес-процесс представляет собой набор вложенных действий. Каждое такое действие в рамках шаблона бизнес-процесса имеет уникальное имя. +Все, что исполняется в бизнес-процессе, является действием (по-другому `активити`), а сам бизнес-процесс представляет собой набор вложенных действий. Каждое такое действие в рамках шаблона бизнес-процесса имеет уникальное имя. С точки зрения кода действие — это php-класс, который наследуется от абстрактного класса `CBPActivity` или его потомков. Его название класса должно начинаться с подстроки `CBP` и может состоять из латинских букв и цифр. @@ -30,12 +30,12 @@ class CBPMyActivity1 - `CBPListenActivity` - Реализует ожидание одного из нескольких возможных событий. Когда одно из событий происходит, остальные перестают ожидать событий и отменяются. - `CBPParallelActivity` - Параллельно запускает набор дочерних действий. -Не смотря на наличие большого количества поставляемых по-умолчанию действий иногда возникает потребность в создании собственных. +Несмотря на наличие большого количества поставляемых по-умолчанию действий иногда возникает потребность в создании собственных. ## Классификация действий С точки зрения выполнения бизнес-процесса каждое действие можно классифицировать на простые и комплексные. -Комплексные (композитные) могут состоять из нескольких постых действий. +Комплексные (композитные) могут состоять из нескольких простых действий. Дополнительно действия можно разделить по характеру выполнения на немедленные, задания и событийные. - Немедленные - выполняются в рамках бизнес-процесса, не блокируют процесс выполнения в нормальном режиме работы. @@ -44,7 +44,7 @@ class CBPMyActivity1 По-умолчанию любое действие является немедленным. Для того чтобы сделать действие событийным, оно должно реализовывать интерфейсы `IBPEventActivity` и `IBPActivityExternalEventListener`, о событийных действиях мы поговорим позже. -Задания в свою очередь можно рассматривать как событийное действие с дополнительными возможностями - нужно наследоваться от `CBPCompositeActivity`, содержать дополнительные методы и реализовывать те же интерфейсы что и событийная модель. +Задания в свою очередь можно рассматривать как событийное действие с дополнительными возможностями - нужно наследоваться от `CBPCompositeActivity`, содержать дополнительные методы и реализовывать те же интерфейсы, что и событийная модель. ## Создание своего действия @@ -57,7 +57,7 @@ class CBPMyActivity1 Каждое действие располагается в отдельной директории и ее название должно совпадать с именем класса действия, но без первых символов `CBP`. Кроме того имя директории должно быть записано строчными буквами (в нижнем регистре). -В директории действия могут располагаться и другие необходимые действию файлы: файл с описанием, локалзиация, изображения или ресурсы. Рассмотрим содержимое директории действия. +В директории действия могут располагаться и другие необходимые действию файлы: файл с описанием, локализация, изображения или ресурсы. Рассмотрим содержимое директории действия. ### `.description.php` @@ -81,8 +81,8 @@ $arActivityDescription = array( ``` Рассмотрим все возможные ключи массива `$arActivityDescription`: -- `NAME` (string) - Локализованное название действия - отображается в списке действий, а так же в заголовке попапа настроек -- `DESCRIPTION` (string) - Локализованное описание действия - отображается в попапе настроек +- `NAME` (string) - Локализованное название действия - отображается в списке действий, а так же в заголовке всплывающего окна настроек +- `DESCRIPTION` (string) - Локализованное описание действия - отображается во всплывающем окне настроек - `TYPE` (string or array)- Тип действия. В случае условия может принимать только `condition`, в случае действия может быть либо `activiy`, либо `robot_activity` либо массивом из этих же элементов - `CLASS` (string) - название php-класса обработчика действия. Должен совпадать с названием директории - `JSCLASS` (string) - название js-класса обработчика действия. По-умолчанию `BizProcActivity`. @@ -105,9 +105,9 @@ $arActivityDescription = array( Это является минимально необходимым описанием для размещения действия в панели редактора шаблона бизнес-процесса. -Однако иногда бывает полезным создать собственный раздел. Для этого в категории необходимо указать еще несколько ключей: `OWN_ID` (string) - симв.код нового раздела и `OWN_NAME` (string) - отображаемое название раздела +Однако иногда бывает полезным создать собственный раздел. Для этого в категории необходимо указать еще несколько ключей: `OWN_ID` (string) - симв. код нового раздела и `OWN_NAME` (string) - отображаемое название раздела -Например так: +Например, так: ```php 'CATEGORY' => [ 'ID' => 'own_super_group', @@ -118,7 +118,7 @@ $arActivityDescription = array( #### `ROBOT_SETTINGS` -Аналогично структуре `CATEGORY` есть структура описывающая расположение карточки робота в интерфейсе выбора работов: +Аналогично структуре `CATEGORY` есть структура описывающая расположение карточки робота в интерфейсе выбора роботов: ```php 'ROBOT_SETTINGS' => [ @@ -181,7 +181,7 @@ $arActivityDescription = array( ], ``` -Доступыне типы (`TYPE`) возвращаемых значений описаны константами в классе `Bitrix\Bizproc\FieldType`. +Доступные типы (`TYPE`) возвращаемых значений описаны константами в классе `Bitrix\Bizproc\FieldType`. Например: - `FieldType::BOOL` (`bool`) - `FieldType::DATE` (`date`) @@ -196,15 +196,15 @@ $arActivityDescription = array( - `FieldType::USER` (`user`) - `FieldType::TIME` (`time`) ->Значения возвращаемые в `RESULT` без перечисления в `ADDITIONAL_RESULT` недоступны для использовании в других действиях бизнес-процессов. +>Значения возвращаемые в `RESULT` без перечисления в `ADDITIONAL_RESULT` недоступны для использования в других действиях бизнес-процессов. #### `ADDITIONAL_RESULT` Возвращаемые значения действия (`RESULT`) имеют ряд недостатков: -- Они должны быть обьявлены явно, т.е. нет возможности динамически определять их состав +- Они должны быть объявлены явно, т.е. нет возможности динамически определять их состав - Их нельзя использовать при настройке других действий бизнес-процессов -Для того чтобы избежать этой ситуации разработчики добавили специальный ключ `ADDITIONAL_RESULT`, который содержит перечисление свойств действия, которые будут транслированы в дизайнер бизнес-процессов и могут быть использованы для вставки в параметры других действий через инструмент "Вставка значения". +Чтобы избежать этой ситуации, разработчики добавили специальный ключ `ADDITIONAL_RESULT`, содержащий перечисление кодов свойств действия, которые будут транслированы в дизайнер бизнес-процессов и могут быть использованы для вставки в параметры других действий через инструмент "Вставка значения". Пример использования в мета-файле: ``` @@ -449,7 +449,7 @@ public static function GetPropertiesDialogValues( } ``` -Осталось тольк описать метод который будет срабатывать во время выполнения действия: +Осталось только описать метод, который будет срабатывать во время выполнения действия: ```php public function Execute() diff --git "a/docs/06_\320\234\320\276\320\264\321\203\320\273\321\214_\320\221\320\270\320\267\320\275\320\265\321\201-\320\277\321\200\320\276\321\206\320\265\321\201\321\201\321\213/10_\320\224\320\265\320\271\321\201\321\202\320\262\320\270\321\217/30_\320\236\320\272\321\200\321\203\320\266\320\265\320\275\320\270\320\265.md" "b/docs/06_\320\234\320\276\320\264\321\203\320\273\321\214_\320\221\320\270\320\267\320\275\320\265\321\201-\320\277\321\200\320\276\321\206\320\265\321\201\321\201\321\213/10_\320\224\320\265\320\271\321\201\321\202\320\262\320\270\321\217/30_\320\236\320\272\321\200\321\203\320\266\320\265\320\275\320\270\320\265.md" index 2c25c16..fa887dd 100644 --- "a/docs/06_\320\234\320\276\320\264\321\203\320\273\321\214_\320\221\320\270\320\267\320\275\320\265\321\201-\320\277\321\200\320\276\321\206\320\265\321\201\321\201\321\213/10_\320\224\320\265\320\271\321\201\321\202\320\262\320\270\321\217/30_\320\236\320\272\321\200\321\203\320\266\320\265\320\275\320\270\320\265.md" +++ "b/docs/06_\320\234\320\276\320\264\321\203\320\273\321\214_\320\221\320\270\320\267\320\275\320\265\321\201-\320\277\321\200\320\276\321\206\320\265\321\201\321\201\321\213/10_\320\224\320\265\320\271\321\201\321\202\320\262\320\270\321\217/30_\320\236\320\272\321\200\321\203\320\266\320\265\320\275\320\270\320\265.md" @@ -2,13 +2,11 @@ [TOC] -Любые действия бизнес-процесса для выполнения своих функций должны работать со своим окружением - иметь доступ к чтению параметров, чтению/записи переменных, уметь работать с константами и глобальными значениями. Задача этой главы показать как взаимодействовать с ними. В главе [PHP код](./PHP_код) мы обсуждали, что использование механизма автоподстановки значений с точки зрения кода является очень плохим, хоть и работающим подходом и чем можно его заменить. +Любые действия бизнес-процесса для выполнения своих функций должны работать со своим окружением - иметь доступ к чтению параметров, чтению/записи переменных, уметь работать с константами и глобальными значениями. Задача этой главы показать как взаимодействовать с ними. В главе [PHP код](./10_PHP_код) мы обсуждали, что использование механизма авто-подстановки значений с точки зрения кода является очень плохим, хоть и работающим подходом и чем можно его заменить. -## Универсальные методы +## Использование парсера -### Парсер - -Самый простой способ взаимодействия на чтение с выражением является использование механизма парсинга. Суть данного способа заключается в том, что разбить техническое выражение на части, а затем конкатенировать его при передаче в парсер. Звучит достаточно сложно, но на деле все просто. +Самый простой способ взаимодействия на чтение с выражением является использование встроенного парсера. Суть данного способа заключается в том, что разбить техническое выражение на части, а затем конкатенировать его при передаче в парсер. Звучит достаточно сложно, но на деле все просто. Представьте себе что у нас есть БП на сущности компания и нам нужно получить его значение, а значит нам достаточно использовать выражение: ```php $companyTitle = $this->ParseValue('{'.'=Document:TITLE}'); @@ -25,7 +23,7 @@ $companyTitle = $this->ParseValue('{'.'=Document:TITLE}'); - `$value` (string) - выражение для парсинга - `$convertToType` (null|string) - код типа, в случае если необходима конвертация. -Очень важно чтобы при использовании указанного кода вы не использовали значения, которые могут попать под автозамену, а это значит что **код ниже является ошибочным**: +Очень важно чтобы при использовании указанного кода вы не использовали значения, которые могут быть истолкованы как маркеры и попасть под автозамену, а это значит что **код ниже является ошибочным**: ```php $companyTitle = $this->ParseValue('{=Document:TITLE}'); ``` @@ -46,7 +44,7 @@ $companyTitle = $this->ParseValue('{=Document:TITLE}'); - `$field` (`string`) - название поля - `$ownerActivity` (`CBPActivity`) - исходное действие. -Метод возвращает неименованый массив из двух элементов: Описания свойства (`array`) и Реального значения (`mixed`) +Метод возвращает массив из двух элементов: Описания свойства (`array`) и Реального значения (`mixed`) Рассмотрим выполнение этого метода как для примера из парсера: мы будем запускать бизнес процесс на сущности компания. @@ -60,7 +58,7 @@ list($property, $companyTitle) = $this->getRuntimeProperty( ); ``` -Если вы залоггируем изменения то в наших переменных будут: +Если вы установите логгирование изменений, то в наших переменных будут: ```php $property = [ @@ -88,15 +86,9 @@ $companyTitle = "Веб-сервис"; ## Параметры -Параметры бизнес-процесса, это значения которые указываются при запуске, таким образом они остаются постоянными в ходе работы с бизнес процессом. -Для того чтобы обратиться к параметру необходимо явно знать его код. - -Например, мы создали в бизнес-процессе параметр с кодом `Parameter1` (значением кода по-умолчанию для первого создаваемого параметра), то для того чтобы получить его на чтение необходимо: -1. Получить объект корневого действия (т.е. действия являющегося верхнеуровневым для бизнес-процесса) -2. Обратиться к его свойству с названием параметра - -Таким образом код будет выглядеть следующимим образом: +Параметры бизнес-процесса - это значения, которые указываются при запуске бизнес-процесса. Таким образом они остаются постоянными в ходе его работы. +Пример кода как можно обратиться к параметру `Parameter1`: ```php $rootActivity = $this->getRootActivity(); @@ -105,7 +97,7 @@ $ourValue = $rootActivity->Parameter1; ## Переменные -В отличии от параметров переменные могут изменяться в ходе всего бизнес-процесса, поэтому у действия (`CBPActivity`) есть методы как на чтение `getVariable`, так и на запись `setVariable`. +В отличие от параметров переменные могут изменяться в ходе всего бизнес-процесса, поэтому у действия (`CBPActivity`) есть методы как на чтение `getVariable`, так и на запись `setVariable`. Сигнатуры нестатических методов: ```php @@ -140,7 +132,7 @@ $users = $this->getVariable('ApprovedByUsers'); ## Константы -Константы это неизменяемые значения для запущенного шаблона бизнес-процесса. Их поведение похоже на параметры, однако задать их можно только в дизайнере бизнес процесса при редактировании шаблона. Метода на изменение констант не существует. +Константы это неизменяемые значения для запущенного бизнес-процесса. Их поведение похоже на параметры, однако задать их можно только в дизайнере бизнес процесса при редактировании шаблона. Метода на изменение констант не существует. Для получения константы существует нестатический метод: ```php @@ -158,13 +150,11 @@ $ourHrUser = $this->getConstant('hr_user'); ## Сущность -Очень часто для получения сущности используются один из двух способов: либо прямое получение данных (посдтановка, парсинг, геттер), либо получение ID текущей сущности и дополнительные запросы в базу данных. В случае с парсингом и геттером это является допустимым, однако в остальных случаях это не самый эффективный способ. Мы уже знаем что бизнес процесс запускается по шаблону на определенной сущности, а значит к полям этой сущности у нас есть довольно простой доступ - работа через сервис документов. +Очень часто для получения сущности используются один из двух способов: либо прямое получение данных (подстановка, парсинг, геттер), либо получение ID текущей сущности и дополнительные запросы в базу данных. В случае с парсингом и геттером это является допустимым, однако в остальных случаях это не самый эффективный способ. Мы уже знаем что бизнес процесс запускается по шаблону на определенной сущности, а значит к полям этой сущности у нас есть довольно простой доступ - работа через сервис документов. Пример работы: ```php -$documentId = $this->getDocumentId(); - /** * @var CBPDocumentService */ @@ -173,15 +163,15 @@ $documentService = $this->workflow->getService('DocumentService'); /** * @var Bitrix\Bizproc\Document\ValueCollection */ -$document = $documentService->getDocument($documentId); +$document = $documentService->getDocument( $this->getDocumentId() ); -echo $document['TITLE']; +// Example: $document['TITLE']; ``` Преимущество работы с использованием данного способа: -1. `DocumentService` имеет локальное кеширование. Повторный вызов метода не вызовет запрос на получение данных, а значит все активити которые будут работать с данным сервисом не будут иметь накладных расходов в виде запросов в базу данных. Он так же является Lazy-load, а значит простой вызов кода не сделает запросов в базу даннхы. +1. `DocumentService` имеет локальное кеширование. Повторный вызов метода не вызовет запрос на получение данных, а значит все активити которые будут работать с данным сервисом не будут иметь накладных расходов в виде запросов в базу данных. Он так же является Lazy-load, а значит простой вызов кода не сделает запросов в базу данных. 2. Универсален. Не важно с какой сущностью вы работаете - сервис получит необходимые данные, а удобство работы с [ArrayAccess](https://www.php.net/manual/en/class.arrayaccess.php) позволит быстро к нему обратиться -3. Выполняется без проверки прав. Вы всегда получите сущность и ее поля даже если забудете дописать `CHECK_PERMISSION => N`. +3. Выполняется без проверки прав. Вы больше не забудете прописать `CHECK_PERMISSION => N` в своем коде. ## Глобальные хранилища diff --git "a/docs/06_\320\234\320\276\320\264\321\203\320\273\321\214_\320\221\320\270\320\267\320\275\320\265\321\201-\320\277\321\200\320\276\321\206\320\265\321\201\321\201\321\213/10_\320\224\320\265\320\271\321\201\321\202\320\262\320\270\321\217/40_\320\241\320\262\320\276\320\270_\321\203\321\201\320\273\320\276\320\262\320\270\321\217.md" "b/docs/06_\320\234\320\276\320\264\321\203\320\273\321\214_\320\221\320\270\320\267\320\275\320\265\321\201-\320\277\321\200\320\276\321\206\320\265\321\201\321\201\321\213/10_\320\224\320\265\320\271\321\201\321\202\320\262\320\270\321\217/40_\320\241\320\262\320\276\320\270_\321\203\321\201\320\273\320\276\320\262\320\270\321\217.md" index c5864ef..7a041aa 100644 --- "a/docs/06_\320\234\320\276\320\264\321\203\320\273\321\214_\320\221\320\270\320\267\320\275\320\265\321\201-\320\277\321\200\320\276\321\206\320\265\321\201\321\201\321\213/10_\320\224\320\265\320\271\321\201\321\202\320\262\320\270\321\217/40_\320\241\320\262\320\276\320\270_\321\203\321\201\320\273\320\276\320\262\320\270\321\217.md" +++ "b/docs/06_\320\234\320\276\320\264\321\203\320\273\321\214_\320\221\320\270\320\267\320\275\320\265\321\201-\320\277\321\200\320\276\321\206\320\265\321\201\321\201\321\213/10_\320\224\320\265\320\271\321\201\321\202\320\262\320\270\321\217/40_\320\241\320\262\320\276\320\270_\321\203\321\201\320\273\320\276\320\262\320\270\321\217.md" @@ -2,11 +2,11 @@ [TOC] -В рамках шаблона бизнес процессов помимо действия (активити, блока) есть еще и условия (кондишен). Условия это особый подвид активити, который может быть использован в блоках "Условие" и "Цикл", наряду с "Полем документа", "PHP код", "Смешанное" и "Истина". +В рамках шаблона бизнес процессов помимо действия (активити, `activity`) есть еще и условия (`condition`). Условия это особый подвид активити, который может быть использован в блоках "Условие" и "Цикл", наряду с "Полем документа", "PHP код", "Смешанное" и "Истина". >Для нетерпеливых, есть [оформленный пример кода на github](https://github.com/gromdron/bitrix-activity-dicecondition) ->Мы будем рассматривать условие на примере игральной кости (`dice`). Попадая в условие мы будем выбрасывать случайное число от 1 до 6 и в случае если это число то, которое запросил пользователь будем решать выполняется условие или нет. Для этого с параметрах условия будем запрашивать какое число мы ожидаем. +>Мы будем рассматривать условие на примере игральной кости (`dice`). Попадая в условие мы будем выбрасывать случайное число от 1 до 6 и в случае если это число то, которое запросил пользователь будем решать выполняется условие или нет. Для этого с параметрами условия будем запрашивать какое число мы ожидаем. ## Расположение @@ -49,13 +49,13 @@ Основная задача файла - установить переменную `$arActivityDescription` как массив описывающий условие. -| Ключ | Тип | Описание | -| :---------- | ------ | ------------------------------------------------------ | -| `NAME` | string | Отображаемое название условия | -| `TYPE` | enum | Тип активити. В случае условия - **condition** | -| `FILTER` | array | Структура описывающя ограничения для условия | +| Ключ | Тип | Описание | +|:---------|--------|------------------------------------------------| +| `NAME` | string | Отображаемое название условия | +| `TYPE` | enum | Тип активити. В случае условия - **condition** | +| `FILTER` | array | Структура содержащая ограничения для условия | -Немного о ключе `FILTER`: для активити (и для условия) можно задавать ограничения видимости - включать (`INCLUDE`) или выключать (`EXCLUDE`) для определенного типа. Например можно указать чтобы условие было доступно только в сделках: +Немного о ключе `FILTER`: для активити (и для условия) можно задавать ограничения видимости - включать (`INCLUDE`) или выключать (`EXCLUDE`) для определенного типа. Например, можно указать чтобы условие было доступно только в сделках: ```php 'FILTER' => [ 'INCLUDE' => [ @@ -93,7 +93,7 @@ $MESS['DICE_DESCR_NAME'] = "Игральная кость"; ### Файл `properties_dialog.php` -Задача файла - отрисовывать дополнительный html на страницах, где используется условия. +Содержимое файла является php-кодом, чья задача вывести дополнительный html на страницах, где используется условия. Для условий можно оставить файл пустым, но наше условие содержит один изменяемый параметр - ожидаемое значение кубика. Важно помнить что данная страница открывается в рамках существующей страницы с версткой, а значит мы должны адаптировать свое отображение. @@ -115,7 +115,7 @@ $MESS['DICE_DESCR_NAME'] = "Игральная кость"; ``` -Кроме того, в рамках страницы нам доступны различиные переменные, которые зависят от основного файла. +Кроме того, в рамках страницы нам доступны различные переменные, которые зависят от основного файла. Обычно в списке переменных находится `$arCurrentValues` - ассоциативный массив текущих значений. Поэтому содержимое нашего файла будет вида: @@ -140,7 +140,7 @@ $MESS['DICE_FIELD_NUMBER'] = "Ожидаемое значение"; ### Файл `dicecondition.php` -В данном файле содержится класс который является сердцем условия. В нем выполняется основная логика работы всего активити. +Файл содержащий php-класс, который описывает условие. Название класса формируется специальным образом: `CBP` + код активити (название директории, регистр значения не имеет) и он должен быть наследником `CBPActivityCondition`. Таким образом, для нашего условия он будет называться `CBPDiceCondition`. @@ -149,8 +149,7 @@ $MESS['DICE_FIELD_NUMBER'] = "Ожидаемое значение"; За основное действие (бизнес смысл) отвечает метод `Evaluate(CBPActivity $ownerActivity): bool`, который примет один аргумент - активити использующее условие (либо "Условие" либо "Цикл"). Вернуть он должен булево значение (в случае если условие выполнено - `true`). -Поскольку наше условие подразумевает наличие параметров, то нам необходимо так же реализовать статические методы `GetPropertiesDialog`, `ValidateProperties`, `GetPropertiesDialogValues` отвечающие за возврат отрисованных параметров (`properties_dialog.php`), валидацию введенных значений и парсинг введенных данных из отрисованных параметров в данные активити. - +Поскольку наше условие подразумевает наличие параметров, то нам необходимо так же реализовать статические методы `GetPropertiesDialog`, `ValidateProperties`, `GetPropertiesDialogValues` отвечающие за возврат html-верстки параметров (`properties_dialog.php`), валидацию введенных значений и парсинг введенных данных из http-запроса в данные активити. ```php Для нетерпеливых, есть [оформленный пример кода на github](https://github.com/gromdron/bitrix-activity-helloworldactivity) ->Мы будем рассматривать создание своего действия на примере 'Пример мир!' (`helloworld`): это будет простой шаг бизнес процеса, задачей которого будет вывести сообщение шаблонного вида "Привет, <обращение>! <текст сообщения>". Параметрами будет строка (обязательная, по-умолчанию "мир") и многострочный текст (обязательное поле). Мы так же усовершенствуем наше действие чтобы оно возвращало сгенерированное сообщение в качестве дополнительного результата. +>Мы будем рассматривать создание своего действия на примере 'Пример мир!' (`helloworld`): это будет простое действие бизнес-процесса, задачей которого будет вывести сообщение шаблонного вида "Привет, <обращение>! <текст сообщения>". Параметрами будет строка (обязательная, по-умолчанию "мир") и многострочный текст (обязательное поле). Мы так же усовершенствуем наше действие чтобы оно возвращало сгенерированное сообщение в качестве дополнительного результата. ## Расположение @@ -23,7 +23,7 @@ keywords: "activity, cbpactivity, baseactivity, bitrix, 1c-bitrix, активи Порядок поиска является приоритетным, т.е. директории будут перебираться последовательно пока не будет найдена директория с действием. `BX_ROOT` - это константа содержащая путь к директории битрикса. По-умолчанию равна `/bitrix`. -Например в стандартном BitrixEnv окружении класс нашего действия будут искать по следующим путям: +Например, в стандартном окружении BitrixEnv класс нашего действия Битрикс будет искать по следующим путям: - `/home/bitrix/www/local/activities/helloworldactivity/helloworldactivity.php` - `/home/bitrix/www/local/activities/custom/helloworldactivity/helloworldactivity.php` - `/home/bitrix/www/bitrix/activities/custom/helloworldactivity/helloworldactivity.php` @@ -143,11 +143,11 @@ class CBPHelloWorldActivity extends BaseActivity } ``` -Этого достаточно чтобы увидеть в редакторе бизнес процесса в блоке "Прочее" наше действие "Привет мир!". Его можно разместить в шаблоне процесса, сохранить и даже запустить бизнес-процесс. Ничего конечно же не произойдет, так как мы не придали нашему коду никакой бизнес логики - он запуститься, проверит условия и завершится. +После этого можно увидеть в редакторе бизнес процесса в блоке "Прочее" наше действие "Привет мир!". Его можно разместить в шаблоне процесса, сохранить и даже запустить бизнес-процесс. Ничего конечно же не произойдет, так как мы не придали нашему коду никакой бизнес логики - он запуститься, проверит условия и завершится. За выполнение действия отвечает метод `internalExecute` - он не имеет аргументов на входе, но в результате своей работы обязан вернуть объект с коллекцией ошибок (`Bitrix\Main\ErrorCollection`, но не пугайтесь это просто объект - коллекция может быть пуста). Абстрактный класс `Bitrix\Bizproc\Activity\BaseActivity` имеет несколько методов синтаксического сахара для записи в журнал бизнес процесса. -Воспользуемся методами-абстрациями над `$this->WriteToTrackingService` чтобы записать в журнал сообщения. +Воспользуемся методами-абстракциями над `$this->WriteToTrackingService` чтобы записать в журнал сообщения. Добавим к нашему классу метод: ```php @@ -194,13 +194,13 @@ protected function internalExecute(): ErrorCollection Теперь мы можем выполнить активити и даже использовать возвращаемое значение в других действиях, например в блоке "Запись в отчет". -По условию задачи мы должны генерировать текст вида "Привет, <обращение>! <текст сообщения>", и указанные маркет должны быть настраиваемыми параметрами. -Для того чтобы описать параметры активити нам необходимо переопределить метод `getPropertiesDialogMap` полученный от нашего родительского `BaseActivity`. +По условию задачи мы должны генерировать текст вида "Привет, <обращение>! <текст сообщения>", и указанные маркеры должны быть настраиваемыми параметрами. +Чтобы описать параметры действия, необходимо переопределить метод `getPropertiesDialogMap` полученный от нашего родительского `BaseActivity`. Напомню, что для конфигурации нам необходимо 2 поля ввода: строка и многострочный текст. Что мы сделаем? 1. Определим в конструкторе 2 новых ключа в arParams 2. Переопределим метод `getPropertiesDialogMap` класса `BaseActivity` -3. Вынесем языкозависимые переменные в языковой файл. +3. Вынесем языко-зависимые переменные в языковой файл. Таким образом наш код на данный момент выглядит следующим образом: @@ -312,7 +312,7 @@ $MESS['HELLOWORLD_ACTIVITY_TEXT'] = 'Привет, #SUBJECT#! #COMMENT#'; ## Подключение модулей -Наше действие может зависеть от установленных модулей в системе. Для того чтобы потребовать установку модуля не обязательно вносить изменения в конструктор или `internalExecute`, для этого в базовом класса есть свойство `$requiredModules` содержащее список модулей которые нам потребуются. +Наше действие может зависеть от установленных модулей в системе. Для того чтобы потребовать установку модуля не обязательно вносить изменения в конструктор или `internalExecute`, для этого в базовом классе есть свойство `$requiredModules` содержащее список модулей которые нам потребуются. Давайте подключим требование по наличию модуля к нашему активити: ```php @@ -330,7 +330,7 @@ class CBPHelloWorldActivity extends BaseActivity Как нам известно, любое активити должно быть наследником абстрактного класса `CBPActivity` и реализовывать метод `execute()`, но абстрактный класс `BaseActivity` поставляемый Битриксом является его наследником и перекрывает этот метод. -Таким образом, за нас уже написали примерно следующуий код: +Таким образом, за нас уже написали примерно следующий код: ```php public function execute() @@ -398,11 +398,11 @@ protected function checkProperties(): ErrorCollection } ``` -В этом методе вы можете достучаться до свойства `$preparedProperties`, которое хранит значения всех параметров переданных в действие при настройки. +В этом методе вы можете достучаться до свойства `$preparedProperties`, которое хранит значения всех параметров переданных в действие при настройке. ## Своя отрисовка -Что делать если вам нужна более сложная отрисовка чем предлагает стандартный механизм? Например вам нужны зависимые поля или какой-то ввод по маске? +Что делать если вам нужна более сложная отрисовка чем предлагает стандартный механизм? Например, вам нужны зависимые поля или какой-то ввод по маске? В таком случае, для отрисовки вы можете использовать более классический механизм предлагаемый файлом `properties_dialog.php` со всеми его преимуществами. Давайте представим, что мы бы захотели сделать точно такое же отображение настроек как в базовом варианте, только используя файл `properties_dialog.php`. @@ -431,7 +431,7 @@ foreach ($dialog->getMap() as $field) } ``` -Как видите, мы используем цикл по возвращаемым значениям из `$dialog->getMap()`, однако мы так же можем явно отрисовать наши параметры, используюя следующий примем: +Как видите, мы используем цикл по возвращаемым значениям из `$dialog->getMap()`, однако мы так же можем явно отрисовать наши параметры, используя следующий прием: ```php getMap()['Subject'];?> @@ -455,19 +455,19 @@ foreach ($dialog->getMap() as $field) ## Поля диалога -В нашем действии мы использовали типы полей Строка и Текст (в `getPropertiesDialogMap`, однако мы ими не ограничены и возможности `PropertiesDialog` намного шире чем эти два типа. +В нашем действии мы использовали типы полей Строка и Текст (в `getPropertiesDialogMap`), однако мы ими не ограничены и возможности `PropertiesDialog` намного шире чем эти два типа. Давайте разберем структуру одного поля (`Bitrix\Bizproc\FieldType`): -| Параметр | Тип | Описание | -| :--------------| -------------- | -------- | -| `Type` | `string` | Мнемонический код типа поля | -| `Name` | `string` | Отображаемое название поля | -| `Description` | `string` | Примечание к полю (нужно выводить вручную) | -| `Required` | `bool` | Флаг обязательного поля | -| `Multiple` | `bool` | Флаг множественного поля | -| `Options` | `string|array` | Строка либо массив с дополнительными параметрами (в зависимости от типа поля) | -| `Settings` | `array` | Массив с дополнительными параметрами (в зависимости от типа поля) | -| `Default` | `mixed` | Значение по-умолчанию (в зависимости от типа поля) | +| Параметр | Тип | Описание | +|:--------------|----------------|-------------------------------------------------------------------------------| +| `Type` | `string` | Мнемонический код типа поля | +| `Name` | `string` | Отображаемое название поля | +| `Description` | `string` | Примечание к полю (нужно выводить вручную) | +| `Required` | `bool` | Флаг обязательного поля | +| `Multiple` | `bool` | Флаг множественного поля | +| `Options` | `string/array` | Строка либо массив с дополнительными параметрами (в зависимости от типа поля) | +| `Settings` | `array` | Массив с дополнительными параметрами (в зависимости от типа поля) | +| `Default` | `mixed` | Значение по-умолчанию (в зависимости от типа поля) | Немного о параметре `Type`: на момент написания статьи типы могут быть как базовыми, так и пользовательскими. Пользовательские типы определяются документом над которым запущен бизнес процесс и могут меняться в зависимости от документа. Базовые типы для всех документов одинаковы. Список базовых типов: