Как вы поступаете, когда вам нужно отобразить множественные записи, привязанные к одной сущности?
Например вы управляете правами пользователя. Вы открываете страницу пользователя, вам подгружается список доступных прав, ролей, объектов, вложений или ещё чего-то множественного. И отмечаются галочками, или списком существующие у данного пользователя роли. Вы меняете данные. Что-то добавляете, что-то убираете, нажимаете сохранить. И как это всё должно правильным образом быть сохранено в базе? Давайте разбираться
Какие есть варианты? Давайте я начну с самых плохих к самым хорошим по моему скромному мнению
- Вы можете сразу при простановке или отмене галочки - делать отдельный запрос, который добавит или уберет зависимость. Это решение достаточно простое с точки зрения фиксации изменений, но оно ломает логику подтверждений в конце формы. Получается что какие-то поля будут изменяться только при сохранении общей формы, а какие-то - сразу и без возможности отмены. Это же может при определенных обстоятельствах привести к нарушению логики, если между полями будет какая-то зависимость. Плюс ко всему - вы не сможете проставлять роли пока пользователь не будет создан. С точки зрения UI - это плохо, вам придется сперва завести пользователя, а потом отдельно его настроить
- Если зависимостей не много, они не большие и вам не нужно будет искать скажем пользователей по зависиостям. Допустим показать всех пользователей, у которых есть роль оптимальным образом, а также целостность данных вас не интересует - вы можете создать одну ячейку, например roles
Какую бы из вариаций вы не выбрали - использовать constraints вы не сможете. При удалении скажем роли - вам нужно будет бегать по всем полям и вычищать самостоятельно несуществующие значения- Если существует какой-то символ, который может не используется в наименованиях, например вы там будете писать ID, или список почтовых адресов - в этом случае можете записать в ячейку прям списком через запятую выбранные значения. При сохранении никаких проблем не будет. Для PHP - Используйте implode, explode. При поиске через mysql - используйте функцию find_in_set
- Для современных баз данных - храните данные в JSON формате. Если база JSON не поддерживает - вы не сможете быстро и точно выполнять поиск по значениям. Из плюсов - вы можете хранить в поле более сложные структуры чем список значений
- Полная чистка и создание записей по новой. Метод в целом не плох. Вам пришел полный список значений - значит вы можете вычистить все существующие и накатить заново все пришедшие данные. В этом случае перед удалением - нужно максимально проверить сохраняемые данные, чтобы в случае ошибки - не проводить изменения. Хорошо, если используете транзакции и сможете откатить всё в случае какой-то ошибки.
Метод в целом не плох. Недостатки не существенные: Если зависимая таблица содержит свои id с автоинкрементом - то со временем этот список будет сильно расти, особенно если вы массово синхронизируете эти роли. Каждый день - вы удаляете всё и накатываете заново. Это и создаст нагрузку и id улетят в небеса через время. Если вы также храните какую-то метаинформацию, например дата предоставления роли или автор, который данную роль предоставил - при полном удалении - вы удалите всё и у вас не останется мета информации. А также историю изменений вам будет тяжело вести, если вы такую ведёте - Записывать только дельту. Вы находите разницу в передаваемых данных и сохраненных в базе данных и оперируете только с разницей. Сперва удаляете лишние, а затем добавляете новые. Вы не напрягаете узкое место - базу данных лишний раз, а также позволяете сохранить все данные и ID не уйдут в небеса. Сплошные плюсы. В PHP проще всего всего вычислить разницу через функции
$oldRoles=[1,2,3]; // существующие на момент сохранения роли
$newRoles=[2,3,4]; // новые пришедшие роли
$addRoles=array_diff($newRoles,$oldRoles); // список ролей, которые нужно добавить
$removeRoles=array_diff($oldRoles,$newRoles); // список ролей, которые нужно убрать
foreach ($addRoles as $key){
...
}
foreach ($removeRoles as $key){
...
}
А как бы сделали вы?
Пользуйтесь