BMC IO DocsBMC IO Docs
IO v6
IO v7
Notes
Docs
IO v6
IO v7
Notes
Docs
  • IO Framework v7

    • О фреймворке
    • Что изменилось в 7 версии
    • IO7 Framework vs Laravel 13 — Сравнение
    • Структура
    • Варианты проектов
    • Доступ к участкам проекта
    • Разворачивание нового проекта
    • Установка проекта
    • Запуск локальной разработки
  • API

    • Обзор API
    • IOCore::call() и IOCore::callAction()
    • Создание API
  • CLI

    • Обзор CLI
    • iocli
    • Кастомные CLI команды
  • Работа с базами данных

    • Обзор работы с базами данных
    • Cron / Планировщик задач (Schedule)
    • Фабрики
    • Миграции
    • Сидеры
    • Query Builder
    • Подключение MinIO
    • Подключение MongoDB
    • Подключение MySQL
    • Подключение PostgreSQL
    • Подключение ProxySQL
    • Подключение RabbitMQ
    • Подключение Redis
  • Логирование

    • Обзор логирования
    • IOEvent - Логирование событий
    • Pinba (PinbaManager) - Профилировщик
  • Модели

    • Обзор моделей
    • CRUD операции
    • Связи моделей
  • Очереди

    • Обзор очередей
    • RabbitMQ
  • Маршруты

    • Обзор маршрутов
    • Определение маршрутов
    • Middleware
  • Сессии

    • Обзор сессий
    • Кроссдоменная SSO
    • JWT авторизация
    • Социальная авторизация
    • OAuth2
    • Keycloak
  • Twig

    • Обзор Twig
    • Формы (FormBuilder)
    • Twig функции
  • Тестирование

    • Обзор тестирования
    • Unit тесты
  • Backend

    • Настройки проекта Conf.php
    • Настройки модуля Module.php
    • Настройки composer
    • Функции фреймворка
    • Вспомогательные функции (Helpers)
    • Глобальные переменные
    • Константы фреймворка
    • Event класс
    • Core класс
    • Route и работа с ними
    • Request и работа с ними
    • Middleware и работа с ними
    • Class и работа с ними
    • Api model и работа с ними
    • Template и работа с ними
    • Мультиязычность и словарь фраз
    • Bin скрипты и работа с ними
    • Cron скрипты и работа с ними
    • $ioSession и работа с сессией
    • $ioHash и работа с кешем
    • $ioXCache и работа с кешем
    • $iodb и работа с базой данных
    • Миграции
  • Frontend

    • Twig шаблонизатор и работа с ним
    • Twig функции
    • Twig фильтры
    • Twig контекст
    • Настройка NPM
    • Сборка Frontend составляющей
    • Обращение к Api через JS
    • Хранилище (store)
    • Навигация в хосте
    • Навигация в микрофронтенде
    • Параметры микрофронтенда
    • Проверка полномочий
  • Tailux UI Компоненты

    • Базовый UI

      • AvatarDot
      • Avatar
      • Badge
      • Button
      • Card
      • ConfirmModal
      • Divider
      • Highlight
      • Tag
    • Загрузка

      • Circlebar
      • Progress
      • Skeleton
      • Spinner
    • Навигация

      • Accordion
      • AccordionButton
      • AccordionHeader
      • AccordionItem
      • AccordionPanel
      • AccordionProvider
      • Pagination
      • PaginationControl
      • PaginationItems
      • PaginationDots
      • PaginationFirst
      • PaginationLast
      • PaginationNext
      • PaginationPrevious
    • Отображение данных

      • Box
      • Collapse
      • ContextualHelp
      • ScrollShadow
      • Timeline
      • TimelineItem
    • Элементы таблиц

      • Table
      • CollapsibleSearch
      • ColumnFilter
      • CopyableCell
      • DateFilter
      • FacetedFilter
      • FilterSelector
      • PaginationSection
      • RadioFilter
      • RangeFilter
      • ResponsiveFilter
      • RoleFilter
      • SelectedRowsActions
      • TableColumnVisibility
      • TableSettings
      • TableSortIcon
    • Элементы форм

      • Checkbox
      • Combobox
      • DatePicker
      • Filepond
      • Input
      • Listbox
      • Radio
      • Range
      • Select
      • StyledSwitch
      • Swap
      • SwapOn
      • SwapOff
      • Switch
      • Textarea
      • TextEditor
      • Upload

Связи моделей IO7

Внимание

Данная статья документации написана нейросетью. Возможны некоторые расхождения и неточность информации!

  • Определение связей
    • hasMany()
    • belongsTo()
    • hasOne()
    • hasManyThrough()
    • belongsToMany()
  • Жадная загрузка (Eager Loading)
  • Фильтрация по связям
  • Пример: полная модель со связями
  • См. также

IO7 использует стандартные методы связей Eloquent, доступные через IO\SqlClass (который наследует Illuminate\Database\Eloquent\Model).


Определение связей

hasMany()

Один ко многим. Определяется в родительской модели.

public function hasMany(
    string $related,
    string $foreignKey = null,
    string $localKey = null
): \Illuminate\Database\Eloquent\Relations\HasMany

Параметры:

ПараметрТипЗначение по умолчаниюОбязателенОписание
$relatedstring—ДаКласс связанной модели
$foreignKeystring|nullnullНетВнешний ключ связанной таблицы
$localKeystring|nullnullНетЛокальный ключ текущей таблицы
namespace App\Models;

use IO\SqlClass;

class Department extends SqlClass
{
    protected $primaryKey = 'pkid';

    public static function tablename(): string
    {
        return 'departments';
    }

    public function employees()
    {
        return $this->hasMany(Employee::class, 'department_id', 'pkid');
    }
}
$department = Department::find(1);
$employees = $department->employees;          // коллекция
$count = $department->employees()->count();   // количество

belongsTo()

Многие к одному. Определяется в дочерней модели.

public function belongsTo(
    string $related,
    string $foreignKey = null,
    string $ownerKey = null,
    string $relation = null
): \Illuminate\Database\Eloquent\Relations\BelongsTo

Параметры:

ПараметрТипЗначение по умолчаниюОбязателенОписание
$relatedstring—ДаКласс родительской модели
$foreignKeystring|nullnullНетВнешний ключ текущей таблицы
$ownerKeystring|nullnullНетКлюч родительской таблицы
$relationstring|nullnullНетИмя связи
class Employee extends SqlClass
{
    protected $primaryKey = 'pkid';

    public static function tablename(): string
    {
        return 'employees';
    }

    public function department()
    {
        return $this->belongsTo(Department::class, 'department_id', 'pkid');
    }
}
$employee = Employee::find(1);
$department = $employee->department;           // объект Department
$departmentName = $employee->department->name; // имя отдела

hasOne()

Один к одному.

public function hasOne(
    string $related,
    string $foreignKey = null,
    string $localKey = null
): \Illuminate\Database\Eloquent\Relations\HasOne
class User extends SqlClass
{
    public static function tablename(): string
    {
        return 'users';
    }

    public function profile()
    {
        return $this->hasOne(Profile::class, 'user_id', 'pkid');
    }
}
$user = User::find(1);
$avatar = $user->profile->avatar_url;

hasManyThrough()

Один ко многим через промежуточную модель.

public function hasManyThrough(
    string $related,
    string $through,
    string $firstKey = null,
    string $secondKey = null,
    string $localKey = null,
    string $secondLocalKey = null
): \Illuminate\Database\Eloquent\Relations\HasManyThrough

Параметры:

ПараметрТипЗначение по умолчаниюОбязателенОписание
$relatedstring—ДаКласс целевой модели
$throughstring—ДаКласс промежуточной модели
$firstKeystring|nullnullНетВнешний ключ промежуточной модели
$secondKeystring|nullnullНетВнешний ключ целевой модели
$localKeystring|nullnullНетЛокальный ключ текущей модели
$secondLocalKeystring|nullnullНетЛокальный ключ промежуточной модели
class Country extends SqlClass
{
    public static function tablename(): string
    {
        return 'countries';
    }

    public function posts()
    {
        return $this->hasManyThrough(
            Post::class,
            User::class,
            'country_id',  // ForeignKey в users
            'user_id',     // ForeignKey в posts
            'pkid',        // LocalKey в countries
            'pkid'         // LocalKey в users
        );
    }
}

belongsToMany()

Многие ко многим (через промежуточную таблицу).

public function belongsToMany(
    string $related,
    string $table = null,
    string $foreignPivotKey = null,
    string $relatedPivotKey = null,
    string $relation = null
): \Illuminate\Database\Eloquent\Relations\BelongsToMany
class User extends SqlClass
{
    public function roles()
    {
        return $this->belongsToMany(
            Role::class,
            'user_roles',    // промежуточная таблица
            'user_id',       // ключ текущей модели
            'role_id'        // ключ связанной модели
        );
    }
}
$user = User::find(1);
$roles = $user->roles;              // коллекция Role
$hasAdmin = $user->roles->contains('name', 'admin');

Жадная загрузка (Eager Loading)

Для предотвращения N+1 проблемы используйте with():

// Загрузка связей вместе с основной моделью
$departments = Department::with('employees')->get();

// Вложенные связи
$users = User::with(['posts', 'profile', 'roles'])->get();

// Жадная загрузка в CrudApi через onSearchParams()
class EmployeeApi extends \IO\Api\CrudApi
{
    public function onSearchParams(array $params): array
    {
        $params['join'][] = 'LEFT JOIN departments ON employees.department_id = departments.pkid';
        return $params;
    }
}

Фильтрация по связям

// whereHas — модели, у которых есть связанные записи
$users = User::whereHas('posts', function ($query) {
    $query->where('status', 'published');
})->get();

// whereDoesntHave — модели без связанных записей
$users = User::whereDoesntHave('posts')->get();

// has — модели минимум с N связями
$users = User::has('posts', '>=', 3)->get();

Пример: полная модель со связями

namespace App\Models;

use IO\SqlClass;

class Order extends SqlClass
{
    protected $primaryKey = 'pkid';
    public $timestamps = false;

    public static function tablename(): string
    {
        return 'orders';
    }

    public function customer()
    {
        return $this->belongsTo(Customer::class, 'customer_id', 'pkid');
    }

    public function items()
    {
        return $this->hasMany(OrderItem::class, 'order_id', 'pkid');
    }

    public function status()
    {
        return $this->belongsTo(OrderStatus::class, 'status_id', 'pkid');
    }

    public static function rules(): array
    {
        return [
            'static' => ['*' => 1],
            'object' => ['*' => 1],
        ];
    }
}
// Использование
$order = Order::with(['customer', 'items', 'status'])->find(42);

echo $order->customer->name;
echo $order->status->label;

foreach ($order->items as $item) {
    echo $item->product_name . ': ' . $item->quantity;
}

См. также

  • Обзор моделей
  • CRUD операции
  • Создание API
Prev
CRUD операции