Skip to content
MiniShop3
MiniShop3
Современный компонент интернет-магазина для MODX 3
  1. Компоненты
  2. MiniShop3
  3. Разработка
  4. Модели и схема БД

Модели и схема базы данных

MiniShop3 использует xPDO ORM для работы с базой данных. Все модели находятся в namespace MiniShop3\Model.

xPDO модели

Основные классы

php
use MiniShop3\Model\msProduct;
use MiniShop3\Model\msProductData;
use MiniShop3\Model\msOrder;
use MiniShop3\Model\msCustomer;

// Получение товара
$product = $modx->getObject(msProduct::class, $id);

// Получение данных товара
$data = $product->getOne('Data');

// Получение заказа с адресом
$order = $modx->getObject(msOrder::class, $id);
$address = $order->getOne('Address');

// Получение клиента
$customer = $modx->getObject(msCustomer::class, ['email' => $email]);

Связи между моделями

php
// Товар → Данные товара (1:1)
$product->getOne('Data');

// Товар → Опции (1:N)
$product->getMany('Options');

// Товар → Файлы галереи (1:N)
$data->getMany('Files');

// Заказ → Товары в заказе (1:N)
$order->getMany('Products');

// Заказ → Клиент (N:1)
$order->getOne('msCustomer');

// Клиент → Адреса (1:N)
$customer->getMany('Addresses');

Schema-файл

Схема базы данных определена в XML-файле:

core/components/minishop3/schema/minishop3.mysql.schema.xml

Основные атрибуты схемы:

  • package: MiniShop3\Model
  • baseClass: xPDO\Om\xPDOObject
  • platform: mysql
  • version: 3.0

Таблицы базы данных

Товары

МодельТаблицаОписание
msProductsite_contentТовар (расширяет modResource)
msProductDatams3_productsДанные товара (цена, артикул, вес)
msProductFilems3_product_filesФайлы галереи товара
msProductOptionms3_product_optionsЗначения опций товара
msLinkms3_linksТипы связей товаров
msProductLinkms3_product_linksСвязи между товарами

msProductData — основные поля

ПолеТипОписание
idintID (совпадает с ID ресурса)
articlevarchar(50)Артикул
pricedecimal(12,2)Цена
old_pricedecimal(12,2)Старая цена
stockdecimal(13,3)Остаток на складе
weightdecimal(13,3)Вес
imagevarchar(255)Основное изображение
thumbvarchar(255)Превью изображения
vendor_idintID производителя
made_invarchar(100)Страна производства
newtinyint(1)Флаг «Новинка»
populartinyint(1)Флаг «Популярный»
favoritetinyint(1)Флаг «Избранное»
tagsjsonТеги
colorjsonЦвета
sizejsonРазмеры

Категории

МодельТаблицаОписание
msCategorysite_contentКатегория (расширяет modResource)
msCategoryMemberms3_product_categoriesСвязь товар-категория
msCategoryOptionms3_category_optionsОпции категории

Заказы

МодельТаблицаОписание
msOrderms3_ordersЗаказ
msOrderAddressms3_order_addressesАдрес доставки заказа
msOrderProductms3_order_productsТовары в заказе
msOrderLogms3_order_logsИстория изменений заказа
msOrderStatusms3_order_statusesСтатусы заказов

msOrder — основные поля

ПолеТипОписание
idintID заказа
user_idintID пользователя MODX
customer_idintID клиента msCustomer
tokenvarchar(128)Токен сессии
uuidchar(36)UUID заказа
numvarchar(20)Номер заказа
costdecimal(12,2)Общая стоимость
cart_costdecimal(12,2)Стоимость товаров
delivery_costdecimal(12,2)Стоимость доставки
weightdecimal(13,3)Общий вес
status_idintID статуса
delivery_idintID способа доставки
payment_idintID способа оплаты
contextvarchar(100)Контекст MODX
order_commenttextКомментарий к заказу
createdondatetimeДата создания
updatedondatetimeДата обновления

Клиенты (NEW в MiniShop3)

МодельТаблицаОписание
msCustomerms3_customersКлиент магазина
msCustomerAddressms3_customer_addressesСохранённые адреса клиента
msCustomerTokenms3_customer_tokensТокены авторизации

msCustomer — основные поля

ПолеТипОписание
idintID клиента
user_idintID связанного modUser (опционально)
first_namevarchar(191)Имя
last_namevarchar(191)Фамилия
phonevarchar(50)Телефон
emailvarchar(191)Email
passwordvarchar(255)Хэш пароля
is_activetinyint(1)Активен
is_blockedtinyint(1)Заблокирован
email_verified_atdatetimeДата подтверждения email
orders_countintКоличество заказов
total_spentdecimal(12,2)Сумма всех заказов
last_order_atdatetimeДата последнего заказа
privacy_accepted_atdatetimeДата принятия политики

Отличие от miniShop2

В miniShop2 клиент = modUser. В MiniShop3 клиент — отдельная сущность msCustomer, которая может быть связана с modUser опционально.

Доставка и оплата

МодельТаблицаОписание
msDeliveryms3_deliveriesСпособы доставки
msPaymentms3_paymentsСпособы оплаты
msDeliveryMemberms3_delivery_paymentsСвязь доставка-оплата

Производители

МодельТаблицаОписание
msVendorms3_vendorsПроизводители товаров

Опции

МодельТаблицаОписание
msOptionms3_optionsСправочник опций

Конфигурация полей (NEW в MiniShop3)

МодельТаблицаОписание
msModelFieldms3_model_fieldsНастройки полей моделей
msModelFieldSectionms3_model_field_sectionsСекции полей
msProductFieldms3_product_fieldsПоля товара (legacy)
msPageSectionms3_page_sectionsСекции страниц (legacy)
msExtraFieldms3_extra_fieldsДополнительные поля

Уведомления

МодельТаблицаОписание
msNotificationConfigms3_notification_configsКонфигурация уведомлений

Примеры работы с моделями

Создание заказа

php
use MiniShop3\Model\msOrder;
use MiniShop3\Model\msOrderProduct;
use MiniShop3\Model\msOrderAddress;

// Создание заказа
$order = $modx->newObject(msOrder::class);
$order->fromArray([
    'customer_id' => $customerId,
    'user_id' => $modx->user->get('id') ?: 0,
    'status_id' => $modx->getOption('ms3_status_new'),
    'delivery_id' => $deliveryId,
    'payment_id' => $paymentId,
    'context' => $modx->context->key,
]);
$order->save();

// Добавление товара в заказ
$orderProduct = $modx->newObject(msOrderProduct::class);
$orderProduct->fromArray([
    'order_id' => $order->get('id'),
    'product_id' => $productId,
    'name' => $productName,
    'price' => $price,
    'count' => $count,
    'cost' => $price * $count,
    'options' => json_encode($options),
]);
$orderProduct->save();

Работа с клиентом

php
use MiniShop3\Model\msCustomer;
use MiniShop3\Model\msCustomerAddress;

// Поиск или создание клиента
$customer = $modx->getObject(msCustomer::class, ['email' => $email]);
if (!$customer) {
    $customer = $modx->newObject(msCustomer::class);
    $customer->fromArray([
        'email' => $email,
        'first_name' => $firstName,
        'phone' => $phone,
    ]);
    $customer->save();
}

// Добавление адреса
$address = $modx->newObject(msCustomerAddress::class);
$address->fromArray([
    'customer_id' => $customer->get('id'),
    'city' => $city,
    'street' => $street,
    'building' => $building,
]);
$address->save();

// Получение всех адресов клиента
$addresses = $customer->getMany('Addresses');

Итерация по записям

php
use MiniShop3\Model\msOrder;

// Правильно: getIterator() — lazy loading
foreach ($modx->getIterator(msOrder::class, ['status_id' => 2]) as $order) {
    // Обработка заказа
}

// Неправильно: getCollection() загружает всё в память
// $orders = $modx->getCollection(msOrder::class, $criteria);

Архитектура моделей

Отличие от miniShop2

В miniShop2 использовались «толстые модели» (Fat Models) — классы моделей содержали большое количество бизнес-логики: валидацию, расчёты, отправку уведомлений и т.д.

В MiniShop3 бизнес-логика вынесена в сервисный слой (src/Services/, src/Controllers/):

miniShop2:
┌─────────────────────────────────┐
│           msOrder               │
│  - валидация                    │
│  - расчёт стоимости             │
│  - смена статуса                │
│  - отправка уведомлений         │
│  - работа с БД                  │
└─────────────────────────────────┘

MiniShop3:
┌─────────────────┐     ┌─────────────────────┐
│    msOrder      │◄────│  OrderController    │
│  - работа с БД  │     │  - бизнес-логика    │
│  - связи        │     └─────────────────────┘
│  - вызов        │     ┌─────────────────────┐
│    сервисов     │◄────│  NotificationManager│
└─────────────────┘     │  - уведомления      │
                        └─────────────────────┘

Прагматичный подход

Компромисс с архитектурой MODX

В современных концепциях (Clean Architecture, DDD) модели должны отвечать только за работу с базой данных и не знать о сервисном слое, репозиториях и контроллерах.

Однако архитектура MODX повсеместно использует бизнес-логику в моделях (modResource, modUser и др.). Поскольку некоторые модели MiniShop3 расширяют классы MODX (msProduct extends modResource, msCategory extends modResource), они обязаны следовать аналогичным паттернам.

Поэтому модели MiniShop3 содержат ссылки на сервисы для вызова методов бизнес-логики — это прагматичный компромисс для совместимости с экосистемой MODX.

Пример: вызов сервиса из модели

php
// src/Model/msProductData.php
class msProductData extends xPDOSimpleObject
{
    public function getPrice(array $data = []): float
    {
        // Делегирование в сервис форматирования
        $ms3 = $this->xpdo->services->get('ms3');
        return $ms3->format->price($this->get('price'));
    }
}

Регенерация моделей

Модели создаются вручную

В MiniShop3 модели НЕ генерируются автоматически из XML-схемы через buildModel(). Они создаются и поддерживаются вручную в директории src/Model/.

Это позволяет:

  • Добавлять кастомные методы в модели
  • Использовать полную типизацию PHP 8
  • Иметь полный контроль над кодом моделей

Важно: Не запускайте buildModel() — это перезапишет кастомные методы моделей.

Структура файлов модели

src/Model/
├── msProduct.php           # Основной класс модели
├── mysql/
│   └── msProduct.php       # MySQL-специфичный маппинг

Пример модели

php
<?php
namespace MiniShop3\Model;

use MODX\Revolution\modResource;

class msProduct extends modResource
{
    // Кастомные методы модели
    public function getPrice(): float
    {
        $data = $this->getOne('Data');
        return $data ? (float)$data->get('price') : 0.0;
    }
}

Пример маппинга

php
<?php
namespace MiniShop3\Model\mysql;

class msProduct extends \MiniShop3\Model\msProduct
{
    public static $metaMap = [
        'package' => 'MiniShop3\\Model\\',
        'version' => '3.0',
        'extends' => 'MODX\\Revolution\\modResource',
        'fields' => [
            'class_key' => 'MiniShop3\\Model\\msProduct',
        ],
        // ... остальные метаданные
    ];
}

Миграции Phinx

Изменения схемы БД выполняются через миграции Phinx:

core/components/minishop3/migrations/
├── 20240101000000_create_customers_table.php
├── 20240102000000_add_customer_fields.php
└── ...

Запуск миграций

bash
cd /path/to/modx
php vendor/bin/phinx migrate -c core/components/minishop3/phinx.php

Пример миграции

php
<?php
use Phinx\Migration\AbstractMigration;

class CreateCustomersTable extends AbstractMigration
{
    public function change()
    {
        $table = $this->table('ms3_customers', [
            'engine' => 'InnoDB',
            'collation' => 'utf8mb4_unicode_ci',
        ]);

        $table
            ->addColumn('email', 'string', ['limit' => 191])
            ->addColumn('first_name', 'string', ['limit' => 191, 'null' => true])
            ->addColumn('phone', 'string', ['limit' => 50, 'null' => true])
            ->addIndex(['email'], ['unique' => true])
            ->create();
    }
}

Диаграмма связей

┌─────────────┐       ┌─────────────────┐
│  msProduct  │──1:1──│  msProductData  │
│ (modResource)│       │  (ms3_products) │
└──────┬──────┘       └────────┬────────┘
       │                       │
       │ 1:N                   │ 1:N
       ▼                       ▼
┌──────────────┐       ┌────────────────┐
│msProductOption│       │ msProductFile  │
└──────────────┘       └────────────────┘

┌─────────────┐       ┌─────────────────┐
│   msOrder   │──1:1──│ msOrderAddress  │
└──────┬──────┘       └─────────────────┘

       ├──1:N──▶ msOrderProduct

       ├──N:1──▶ msCustomer ──1:N──▶ msCustomerAddress

       ├──N:1──▶ msDelivery

       └──N:1──▶ msPayment