Всем привет!
Внедряться в итоге все это будет на сайт Клуба.
Напомню, что чаты здесь реализованы с помощью компонента @prisma-cms/society и модуля @prisma-cms/society-module, а проекты и задачи с помощью @prisma-cms/cooperation и @prisma-cms/cooperation-module.
Для простоты эти парные модули будем назваться Society (блого-социальный модуль) и Cooperation (проекты, задачи, команды и т.п.).
В этих двух отдельных модулях сейчас нас более всего интересуют ChatRoom (Чат-комнаты) из Society и Task (Задачи) из Cooperation. Эти сущности сейчас никак между собой не связаны, то есть Чат-комнаты ничего не знают о Задачах http://joxi.ru/MAjz7eNc4VoNOA, а Задачи ничего не знают о Чат-комнатах http://joxi.ru/EA4KnbqcwdMl12. То есть создавая чаты и общаясь в них по каким-то задачам, мы не сможем сделать выборку только тех чатов, которые имеют непосредственное отношение к каким-либо задачам. В свою очередь мы не можем зайти в задачу и получить чат, относящийся непосредственно к ней. А очень бы хотелось... Таким образом перед нами стоит задача установить связи между этими сущностями и получить API-методы для создания чатов для задач и получать чаты в задачах.
Шаг 1. Добавляем связь в схему.
Вообще связь создавать можно как в @prisma-cms/society-module, добавив в зависимости @prisma-cms/cooperation-module, так и наоборот (я уже писал ранее об этом, и это на мой взгляд одна из сильнейших сторон @prisma-cms). Но я стараюсь всегда добавлять связь от малого к большему. В нашем случае большее - это @prisma-cms/society-module (так как общение - это очень сложный и объемный модуль, с проверками прав и т.п.), а @prisma-cms/cooperation-module хоть и тоже довольно объемный и сложный модуль, но все-таки в данной задаче на мой взгляд это меньший модуль. Логика такого решения в том, что @prisma-cms/society-module используется много где в других модулях, а @prisma-cms/cooperation-module нет, и не круто будет подключая один модуль тянуть за ним еще кучу всего.
Итак, в @prisma-cms/cooperation-module в package.json я дописываю в dependencies "@prisma-cms/society-module": "latest" и выполняю установку зависимостей yarn --ignore-engines
Внимание! Важно делать именно так, то есть прописывать в package.json зависимость с указанием версии "latest", а не устанавливать через команду yarn add @prisma-cms/society-module@latest. Дело в том, что хотя установка выполнится корректно, в package.json будет записано типа "@prisma-cms/society-module": "^1.3.8", то есть с указанием конкретной версии, а не latest. Такое часто приводит к коллизиям при установке взаимоиспользуемых модулей ( когда занимаешься разработкой модуля и еще не вылил в сеть свежую версию, всегда в каком-либо модуле будет более старая версия). Хотя это в основном справедливо для этапа разработки модуля, а не при использовании его сторонними разработчиками, но все же считаю это правило упускать не надо, просто на будущее.
Все, установили зависимость. Теперь пропишем ее для использования в модуле. Для этого мы прописываем его в вызов метода this.mergeModules.
Сохраняем и выполняем deploy.
Если вы еще не выполняли деплой и выполняете его в первый раз, то у вас будут созданы не только сущности, прилетевшие с @prisma-cms/society-module, но и вообще все, что сейчас содержится в @prisma-cms/cooperation-module. А я уже выполнял деплой ранее, поэтому у меня вот только вновь прибывшие:
Как видите, много всего прилетело с новым модулем, то есть добавили буквально две строчки, а сколько всего нового появилось... При чем это не просто программный код добавился, а выполнилось сразу несколько операций:
1. Сгенерировалась из всех модулей общая схема для деплоя в призма-сервер.
2. Выполнился деплой в паризму.
3. Посоздавались и обновились таблицы и взаимосвязи с ними в базу данных.
4. Скачалась новая API-схема.
5. Сгенерировались новые API-фрагменты для использования их в пользовательских API-запросах.
Теперь мы на выходе имеет не только обновленную и расширенную базу данных, но и API для работы с ней, обновленную графическую схему и обновленные фильтры. Вот так у нас схема выглядела: http://joxi.ru/Dr83W9lC4Vvg9A, а вот так она выглядит теперь: http://joxi.ru/YmEy1pOH0nq1Om. И хотя без масштабирования схемы теперь не видно названий сущностей, тем не менее очевидно, что их стало значительно больше. Но наша задача еще не решена, так как хотя в рамках одного модуля теперь существуют обе нужные нам сущности (ChatRoom и Task), и можно даже через API создавать/редактировать и те и другие, связей между ними по прежнему нет, это по прежнему обособленные сущности.
Что бы добавить связь между ними, делаем так:
Можно уже сейчас для наглядности опять выполнить деплой.
Обновляем схему и видим, что у нас появилась связь с ChatRoom: http://joxi.ru/MAjz7eNc4Vol4A
Теперь при создании или обновлении Задачи можно сразу указать создаваемую или подключаемую Чат-комнату, а при получении данных задачи можно и сразу ее Чат-комнату получить. Но пока еще нельзя создать Задачу из Чат-комнаты, потому что нет еще связи из нее на Задачу.
2. Создаем связь Чат-комната - Задача.
В папке src/modules/schema/database (можно создать подпапку и туда файл добавить) создаем файл chatRoom.graphql (название файла не важно, а вот расширение .graphql важно) и пишем в него:
Это вся запись. Хотя исходное описание сущности ChatRoom находится в подключаемом модуле @prisma-cms/society-module и мы не можем в нем ничего править, нам нет необходимости копировать ее хоть целиком, хоть полностью. Мы просто пишем свое дополнительное описание. При деплое все описания сущностей объединяются и деплоятся как единая схема. То есть можно даже в рамках одного модуля несколько раз описать одну и ту же сущность и задеплоить, и если конфликтов по полям не будет, то они объединятся. Рассмотрение конфликтов - это тема для отдельного топика, здесь мы ее не будем рассматривать, рассматриваемые нами здесь примеры конфликтов не имеют.
Итак, сохраняем и выполняем деплой.
Вот теперь у нас двусторонняя связь в обеих сущностях: http://joxi.ru/Vm6a53MtDBbl8r. Теперь можно написать запрос на создание Чат-комнаты с привязкой к конкретной задаче: http://joxi.ru/BA06nb7HJ0ZDlm.
Как вы могли заметить, в результате выполнения запроса на создание чат-комнаты в теле ответа мы прописали больше сущностей, получив в ответ сразу и ранее созданные таймеры по этой задаче. Это еще одна сильная сторона @prisma-cms (унаследованная от технологии GraphQL).
Кстати, обратите внимание, что мы запрос выполняли в рамках модуля Cooperation, хотя запрашиваемый метод createChatRoomProcessor прописан в Society. Дело в том, что при объединении модулей, мы получаем не только объединенную схему, но и обединенный набор методов (резолверов), и хотя их процесс объединения не такой мощный, как в случае со схемой (по сути просто замена одних другими в случае уже имеющихся), тем не менее это гораздо больше, чем ничего. И это еще одна сильная сторона @prisma-cms :)
Шаг 2. Дописываем интерфейсы.
Итак, схема у нас есть и методы уже работаю. Теперь нам осталось только дописать интерфейсы, чтобы на странице задачи появилась возможность создать чат и переписываться. Дописывать мы их будем уже в компоненте @prisma-cms/cooperation, потому что за интерфейсы отвечает именно он, а не модуль. В целом, это не особо сложно, сейчас все расскажу-покажу.
За основу можно взять то, как реализованы чаты на страницах пользователя на сайте Клуба. Если вы зайдете в профиль любого пользователя, то там выводят чаты с этим пользователем и есть возможность не сразу ему написать. Вот подключаемый класс ChatRoomsByUser, а вот здесь он вызывается.
1. Описанным выше способом устанавливаем в @prisma-cms/cooperation зависимость @prisma-cms/society@latest. С ним мы получим не только интерфейсы, но и уже готовые запросы для получения чатов, сообщений и т.п.
2. Так как в текущем варианте @prisma-cms/cooperation-module мы запускаем в отдельной директории самостоятельно (и крутится он у нас на порту 4000 по умолчанию), а @prisma-cms/cooperation мы запускаем отдельно в другой директории, то @prisma-cms/cooperation ничего не знает еще о том, что в @prisma-cms/cooperation-module у нас изменилась схема. Нам нужно подтянуть в @prisma-cms/cooperation новые API-фрагменты. Для этого выполняем:
Вообще этот шаг требует оптимизации, но я пока не придумал как сделать так, чтобы этот момент полностью автоматизировать, так что его приходится выполнять на конечном проекте вручную. Компоненты, подобные @prisma-cms/society часто несут в себе два класса контекстных (ContextProvider и SubscriptionProvider). ContextProvider нужен для того, чтобы на всех уровнях ниже были доступны передаваемые в контекст переменные (включая заготовки запросов, некоторые UI-компоненты и т.п.). Пример использования описан здесь. SubscriptionProvider используется для того, чтобы автоматически подписаться на те или иные обновления с сервера (обновления данных пользователей, топиков и т.п.).
Вот при подключении подобных компонентов на конечных проектах надо подключать эти провайдеры, чтобы все работало корректно. К примеру, вот так выглядит подключение подобных провайдеров на сайте Клуба.
В нашем случае @prisma-cms/cooperation использует @prisma-cms/society, поэтому, чтобы используемые Society-компоненты работали корректно, надо в DevRenderer прописать эти провайдеры. Имейте ввиду, что DevRenderer вызывается только в режиме разработки конкретного компонента и не экспортируется автоматически на конечный проект, так что повторюсь, на конечном проекте его надо подключать дополнительно.
4. Дописываем вывод Чата на странице Задачи.
После того, как мы получили обновленные API-фрагменты и подключили контекст-провайдеры, можно пробовать выводить Чаты на страницах Задач. Для этого, как я и писал выше, мы позаимствуем пример выполнения с сайта Клуба. Я скопировал ChatRooms и немного переписал его, чтобы на вход он получал не пользователя, а задачу, и в условии запроса заменил
на
Теперь он должен получать чаты не по признаку участия пользователя, а по привязке к задаче.
Блок нового сообщения в текущем виде я удалил, так как его суть отправка персонального сообщения указанному пользователю, а у нас задача писать в существующий Чат или создавать новый при его отсутствии.
После этого подключаю этот компонент на странице Задачи вот в таком виде:
ОК, сохраняю и обновляю страницу Задачи. Ха, есть список Чатов и созданный нами ранее Чат:) http://joxi.ru/Y2LepD7h93qapA
Уже неплохо. Но нам надо еще докрутить это под намеченную логику, ведь у нас привязка не один-ко-многим, а один-к-одному, то есть в Задаче должен сразу выводиться Чат, соответствующий этой Задаче, или кнопка "Создать чат". Поэтому компонент ChatRooms мы полностью перепишем. Вот его код. Я им мало доволен, но это не страшно, главное - работает.
Ну, можно сказать и все. Остается только подключить на сайт Клуба. Подключение не потребовало особо усилий, в основном все свелось к тому, что бы убрать лишний код в кастомной странице и подключить внешний компонент. Вот коммит. Теперь здесь можно зайти в любую задачу и создать чат, чтобы обсудить детали. Еще одна приятная мелочь: фильтры в задачах сразу же подхватили новую схему и теперь можно найти все задачи, в которых есть чаты: https://modxclub.ru/tasks?filters=%7B%22ChatRoom%22%3A%7B%7D%7D
Конечно же есть еще какие-то баги. К примеру я сейчас создал чат в задаче и по задумке сразу же должен был назначиться участником в чат автор задачи, но этого не произошло. Я знаю почему (потому что у меня тут несколько измененные запросы для чатов, а не базовые, и соответственно надо чуть подправить API-запросы), но это поправится. Так же не хватает логики в плане вывода информации: в задаче мы видим чат, но из чата мы не видим задачу, то есть если сейчас зайти напрямую в чат, то не будет понятно, что он в задаче находится. Но это ничего, поправлю. Главное было сейчас в целом описать процесс интеграции отдельных призма-модулей. Надеюсь вам было интересно.