Давайте дадим нашим схемам баз данных больше свободы

MongoDB - отличный выбор для ряда приложений. В мире PHP мы также можем попробовать нечто большее, чем просто стек LAMP, и дать нашим схемам базы данных больше свободы. Одним из самых популярных объектно-реляционных сопоставителей (ORM) для PHP является Doctrine, который также имеет очень хорошую реализацию Object Document Mapping (ODM) для MongoDB. Мы не будем вдаваться в подробности о преимуществах или недостатках баз данных NoSql и SQL, но посмотрим, как мы можем создать очень простое приложение, если мы уже решили использовать Mongo.

Полный исходный код доступен в следующем репозитории:



Нам необходимо создать приложение корзины покупок с REST API, которое позволит нам:

  • добавить новый товар в каталог
  • обновить название продукта
  • создать новую корзину
  • добавлять и удалять товары из корзины покупок
  • записывать, когда товар был добавлен в корзину

Также у нас есть набор требований:

  • цена продукта должна быть положительной и указана валюта EUR, PLN или USD.
  • у нас может быть только один товар данного типа в корзине и не более 4 товаров одновременно

Мы будем использовать фреймворк Symfony, поскольку он прекрасно интегрируется с Doctrine ODM. Мы можем установить библиотеку и сгенерировать базовую конфигурацию, выполнив следующие команды:

composer config extra.symfony.allow-contrib true
composer require doctrine/mongodb-odm-bundle

Мы будем обращаться к базе данных таким же образом, как и с ORM в Doctrine. Мы используем аннотации в моделях, которые укажут, какие переменные класса следует сохранить. В нашем Product мы указываем имя, цену и валюту в качестве аргументов конструктора. Не требуется особой логики, поэтому класс очень простой.

По умолчанию коллекция имеет то же имя, что и модель, которая ее использует. Мы можем настроить это поведение, указав параметр collectionName в аннотации Document. Мы также можем хранить несколько разных моделей в одной коллекции, поскольку MongoDb очень гибок, когда дело касается схемы базы данных.

Product получает проверенные объекты значений, которые обеспечивают правильность данных. Мы не будем вдаваться в подробности их реализации, их можно найти на Github.

Doctrine ODM делает оптимистичную блокировку чрезвычайно простой. Этот механизм гарантирует, что никто не изменил модель одновременно с нами, сравнивая атрибут version. Все, что нам нужно было сделать, это поставить одну аннотацию @ODM\Version.

Модель корзины для покупок немного сложнее, поскольку мы должны обеспечить соблюдение всех правил, связанных с добавлением и удалением продуктов. Мы могли бы хранить ссылку на коллекцию продуктов в Mongo или использовать встроенные документы. У каждого подхода есть свои плюсы и минусы. Мы должны хранить метку времени добавления новых продуктов, чтобы встроенный документ нам больше подходил. Более того, так будет эффективнее.

Мы используем данные о продукте и создаем отдельный ShoppingCartItem встроенный документ.

Проблема, с которой мы можем столкнуться, - это синхронизация данных между коллекциями. Когда кто-то меняет название продукта, оно не будет автоматически распространяться, и мы увидим устаревшее название в корзине. Нам нужно будет создать собственный механизм для обеспечения согласованности данных.

Мы сохраняем модели с помощью Doctrine Document Manager. Мы можем использовать собственный репозиторий для каждой модели или использовать встроенный с базовыми функциями. Для простоты мы будем придерживаться последнего. Если нам потребуется дополнительная настройка, нам нужно будет добавить параметр repositoryClass в аннотацию @ODM\Document.

MongoDB зарекомендовал себя очень полезным во многих случаях использования и может отлично работать с PHP. Это определенно интересная альтернатива для наиболее распространенных движков баз данных в проектах PHP, таких как MySql или PostgreSQL.

Использованная литература: