Rudra FrameworkRudra Framework

Три слоя доступа к данным

В Rudra доступ к данным построен на трёх согласованных уровнях, которые позволяют начать с минимума и масштабироваться без переписывания кода.
Эта архитектура даёт полную гибкость, не навязывая ORM, наследование от монолитных моделей или жёсткие правила.

Вы всегда начинаете с одного класса — и добавляете слои только когда они нужны.Три слоя доступа к данным

В Rudra доступ к данным построен на трёх согласованных уровнях, которые позволяют начать с минимума и масштабироваться без переписывания кода.
Эта архитектура даёт полную гибкость, не навязывая ORM, наследование от монолитных моделей или жёсткие правила.

Вы всегда начинаете с одного класса — и добавляете слои только когда они нужны.

ℹ️Уровни архитектуры

Уровень

Назначение

Когда использовать

Entity

Точка входа. Лёгкий класс с именем таблицы.

Всегда — с него начинается работа.

Model

Бизнес-логика, статические методы, фабрики, валидация.

Когда нужна доменная логика поверх данных.

Repository

Запросы к БД, JOIN’ы, пагинация, кэширование.

Когда нужны сложные SQL-операции или оптимизация.

✅При вызове User::method() Rudra автоматически ищет реализацию в порядке:
Model → Repository → Базовый Repository.

Как это работает на практике

1. Начните с Entity — и получите CRUD «из коробки»

// App/Entity/User.php
namespace App\Entity;

use Rudra\Model\Entity;

class User extends Entity
{
    public static ?string $table = 'users';
}

Теперь вы можете:

$user = User::find(1);
$admins = User::findBy('role', 'admin');
User::create(['name' => 'Alice', 'email' => 'alice@example.com']);

→ Все методы делегируются Rudra\Model\Repository, так как Model и Repository ещё не созданы.

2. Добавьте Model — для бизнес-логики

// App/Model/User.php
namespace App\Model;

use Rudra\Model\Model;

class User extends Model
{
    public static function createAdmin(string $email, string $name): array
    {
        // Инкапсулируем доменную операцию
        return (new \App\Repository\UserRepository('users'))->create([
            'email' => $email,
            'name'  => $name,
            'role'  => 'admin',
            'active' => true
        ]);
    }

    // Можно даже переопределить базовый метод
    public static function find(int $id): array|false
    {
        $user = parent::find($id); // или вызов через репозиторий напрямую
        if ($user) {
            // Например, логируем, обогащаем данные и т.п.
        }
        return $user;
    }
}

Теперь:

User::createAdmin('boss@example.com', 'Admin'); // → вызывается Model
User::find(1);                                 // → тоже Model

Model имеет приоритет над Repository. Это позволяет переопределять поведение, не трогая инфраструктуру.


3. Добавьте Repository — для сложных запросов

// App/Repository/UserRepository.php
namespace App\Repository;

use Rudra\Model\Repository;
use Rudra\Pagination;

class UserRepository extends Repository
{
    public function getActiveWithProfile(Pagination $pagination)
    {
        return $this->qBuilder($this->qb()
            ->select('users.*, profiles.bio, roles.name as role_name')
            ->from($this->table)
            ->join('profiles')->on('users.id = profiles.user_id')
            ->join('roles')->on('users.role_id = roles.id')
            ->where('users.active = 1')
            ->orderBy('users.created_at DESC')
            ->limit($pagination->getPerPage())
            ->offset($pagination->getOffset())
            ->get()
        );
    }

    public function activate(int $id): void
    {
        $this->update(['id' => $id, 'active' => 1]);
        $this->clearCache('database', 'getActiveWithProfile');
    }
}

→ Этот метод автоматически становится доступен через User::getActiveWithProfile(...).

ℹ️Два стиля вызова — оба поддерживаются

// Статический стиль — лаконичный и выразительный
$admins = User::findBy('role', 'admin');

// Объектный стиль — удобен при DI (внедрении зависимости)
public function actionIndex(User $user): void
{
    $me = $user->find($this->auth->id());
}

Оба вызова проходят одну и ту же цепочку делегирования.


ℹ️ Преимущества подхода

  • Нет дублирования — логика в одном месте.
  • Постепенное усложнение — начните с Entity, добавьте Model или Repository позже.
  • Полный контроль — вы видите каждый слой, ничего не скрыто.
  • Тестируемость — каждый слой можно проверить отдельно.
  • Совместимость — работает со всеми СУБД (MySQL, PostgreSQL, SQLite).

ℹ️ Заключение

Три слоя — не обязанность, а возможность.
Вы не обязаны создавать Model и Repository, если не нужно.
Но когда проект растёт — архитектура уже готова к этому.

Это Rudra:
минимализм по умолчанию,
мощь по требованию,
контроль всегда.