PHPackages                             visavi/motor-orm - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. visavi/motor-orm

ActiveLibrary[Database &amp; ORM](/categories/database)

visavi/motor-orm
================

v4.2.2(2y ago)12661MITPHPPHP ^8.0

Since Feb 5Pushed 2y ago1 watchersCompare

[ Source](https://github.com/visavi/motor-orm)[ Packagist](https://packagist.org/packages/visavi/motor-orm)[ Docs](https://github.com/visavi/motor-orm)[ RSS](/packages/visavi-motor-orm/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (10)Dependencies (1)Versions (35)Used By (1)

Motor ORM
=========

[](#motor-orm)

Данный скрипт предоставляет ООП подход для работы текстовыми данными сохраненными в файловой системе

Структура данных CSV совместима, но с некоторыми изменения для более быстрой работы

Возможности
-----------

[](#возможности)

### Builder

[](#builder)

- Поиск по уникальному ключу
- Поиск по любым заданным условиям
- Возврат структуры файла
- Возврат количества записей в файле
- Возврат информации о существовании записи
- Сортировка строк
- Запись строки в файл с генерацией автоинкрементного ключа
- Обновление записей по любым условиям
- Удаление записей по любым условиям
- Приведение типов (Casts)
- Scope
- Очистка файла
- Жадная загрузка
- Связь один к одному
- Связь один ко многим
- Связь многие ко многим

### Collection

[](#collection)

- Преобразование коллекции в массив
- Получение первой записи
- Получение последней записи
- Получение количества записей в коллекции
- Добавление записи в коллекцию
- Удаление записи из коллекции
- Установка значения в коллекции
- Проверка коллекции на пустоту
- Очистка коллекции
- Срез коллекции
- Обход с получением ключа и значения из коллекции

### Collection Paginate

[](#collection-paginate)

- Расширяет класс Collection
- Получение текущей странице
- Получение количества страниц
- Получение массива со страницами

### Migration

[](#migration)

- [Создание таблицы](#%D0%A1%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5-%D1%82%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D1%8B)
- [Удаление таблицы](#%D0%A3%D0%B4%D0%B0%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5-%D1%82%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D1%8B)
- [Создание колонок](#%D0%A1%D0%BE%D0%B7%D0%B4%D0%B0%D0%BD%D0%B8%D0%B5-%D0%BA%D0%BE%D0%BB%D0%BE%D0%BD%D0%BE%D0%BA)
- [Переименовывание колонок](#%D0%9F%D0%B5%D1%80%D0%B5%D0%B8%D0%BC%D0%B5%D0%BD%D0%BE%D0%B2%D1%8B%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-%D0%BA%D0%BE%D0%BB%D0%BE%D0%BD%D0%BE%D0%BA)
- [Удаление колонок](#%D0%A3%D0%B4%D0%B0%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5-%D0%BA%D0%BE%D0%BB%D0%BE%D0%BD%D0%BE%D0%BA)
- [Проверка существования](#%D0%9F%D1%80%D0%BE%D0%B2%D0%B5%D1%80%D0%BA%D0%B0-%D1%81%D1%83%D1%89%D0%B5%D1%81%D1%82%D0%B2%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F-%D1%82%D0%B0%D0%B1%D0%BB%D0%B8%D1%86%D1%8B%D0%BA%D0%BE%D0%BB%D0%BE%D0%BD%D0%BA%D0%B8)

Работы с изменениями в файле, в том числе и вставка выполняется с блокировкой файла для защиты от случайного удаления данных в случае если несколько пользователей одновременно пишут в файл

Первых столбец в файле считается уникальным

Может быть строковым и числовым

Если столбец строковой, то все вставки должны быть с уже заданным уникальным ключом

Если столбец числовой, то уникальный ключ будет генерироваться автоматически

Запросы
-------

[](#запросы)

Все запросы проводятся через модели в котором должен быть указан путь к файлу с данными В самих моделях могут быть реализованы дополнительные методы

Примеры
-------

[](#примеры)

```
# Create class
use MotorORM\Builder;

class TestModel extends Builder
{
    public string $table = __DIR__ . '/test.csv';
}

# Find by primary key
TestModel::query()->find(1);

# Find by name limit 1
TestModel::query()->where('name', 'Миша')->limit(1)->get();

# Find by name and first 1
TestModel::query()->where('name', 'Миша')->first();

# Find by name and title
TestModel::query()->where('name', 'Миша')->where('title', 'Заголовок10')->get();

# Get from condition
TestModel::query()->where('time', '>=', 1231231235)->get();

# Get by condition in
TestModel::query()->whereIn('id', [1, 3, 4, 7])->get();

# Get by condition not in
TestModel::query()->whereNotIn('id', [1, 2, 3, 4, 5, 6, 7, 8, 9, 10])->get();

# Get records by multiple conditions and pagination
TestModel::query()
    ->where(function(Builder $builder) {
        $builder->where('name', 'Миша');
        $builder->orWhere(function(Builder $builder) {
            $builder->where('name', 'Петя');
            $builder->where('title', '', '');
        });
    })
    ->paginate(10);

# Get count
TestModel::query()->where('time', '>', 1231231234)->count();

# Get lines 1 - 10
$lines = TestModel::query()->offset(0)->limit(10)->get();

# Get last 10 records
$lines = TestModel::query()->orderByDesc('created_at')->offset(0)->limit(10)->get();

# Get headers
TestModel::query()->headers();

# Get first line
TestModel::query()->first();

# Get first 3 lines
TestModel::query()->limit(3)->get();

# Get last 3 lines
TestModel::query()->orderByDesc('created_at')->limit(3)->get();

# Find by name and double sort (time desc, id asc)
Test::query()
    ->where('name', 'Миша')
    ->orderByDesc('time')
    ->orderBy('id')
    ->limit(3)
    ->get();

# Create string
TestModel::query()->create(['name' => 'Миша']);

# Update strings
TestModel::query()->where('name', 'Миша')->update(['text' => 'Новый текст']);

# Update string
$test = TestModel::query()->where('name', 'Миша')->first();
$test->text = 'Новый текст';
$test->save();

# Update strings
$testModel = TestModel::query()->find(17);
$affectedLines = $testModel->update(['text' => 'Новый текст']);

# Delete records
TestModel::query()->where('name', 'Миша')->delete();

# Delete records
$records = TestModel::query()->get();
foreach($records as $record) {
    $record->delete();
}

# Truncate file
TestModel::query()->truncate();
```

### Частичный поиск (Like)

[](#частичный-поиск-like)

Поиск по частичному совпадению

```
// Строки начинающиеся на hi
$test = TestModel::query()->where('tag', 'like', 'hi%')->get();

// Строки заканчивающиеся на hi
$test = TestModel::query()->where('tag', 'like', '%hi')->get();

// Строки содержащие hi
$test = TestModel::query()->where('tag', 'like', '%hi%')->get();

// Этот запрос эквивалентен запросу выше
$test = TestModel::query()->where('tag', 'like', 'hi')->get();
```

### Нестрогий поиск (Lax)

[](#нестрогий-поиск-lax)

Поиск по нестрогому совпадению

При поиске orm использует строгое сравнение, чтобы задействовать нестрогий режим, можно использовать lax

```
// Будут найдено первое совпадение NAME, name, namE, Name итд
$user = User::query()->where('login', 'lax', 'name')->first();
```

### Приведение типов (Casts)

[](#приведение-типов-casts)

По умолчанию все поля полученные из файла строковые

За некоторыми исключениями

- Поле primary key - int
- Поля заканчивающиеся на \_id и \_at - int
- Пустые поля - null

Для переопределения используйте свойство casts

```
class Story extends Model
{
    protected array $casts = [
        'rating' => 'int',
        'reads'  => 'int',
        'locked' => 'bool',
    ];
}
```

Поддерживаются следующие типы

- 'int', 'integer' =&gt; int
- 'real', 'float', 'double' =&gt; float
- 'string' =&gt; string
- 'bool', 'boolean' =&gt; bool
- 'object' =&gt; json\_decode($value, false),
- 'array' =&gt; json\_decode($value, true),

### Условия запросов (Scope)

[](#условия-запросов-scope)

Каждый scope — это обычный метод, который начинается с префикса scope. Именно по префиксу ORM понимает, что это scope. Внутрь scope передаётся запрос, на который можно навешивать дополнительные условия.

```
class Story extends Model
{
    public function scopeActive(Builder $query): Builder
    {
        return $query->where('active', true);
    }
}
```

Использование:

```
Story::query()
    ->active()
    ->paginate($perPage);
```

#### Динамические условия

[](#динамические-условия)

Некоторые scope зависят от параметров, передающихся в процессе составления запроса. Для этого достаточно описать эти параметры внутри scope после параметра $query:

```
class Story extends Model
{
    public function scopeOfType(Builder $query, string $type): Builder
    {
        return $query->where('type', $type);
    }
}
```

Использование:

```
Story::query()
    ->ofType('new')
    ->paginate($perPage);
```

### Условные выражения (Conditional clauses)

[](#условные-выражения-conditional-clauses)

Иногда вам может понадобиться, чтобы определенный запроса выполнялся на основе другого условия. Например, вы можете захотеть применить where оператор только в том случае, если заданное входное значение присутствует во входящем HTTP-запросе. Вы можете сделать это, используя when метод:

```
$active = true;

$stories = Story::query()
    ->when($active, function (Story $query, $active) {
        $query->where('active', $active);
    })
    ->get();
```

Метод when выполняет данное замыкание только тогда, когда первый аргумент равен true. Если первый аргумент равен false, замыкание не будет выполнено.

Вы можете передать другое замыкание в качестве третьего аргумента when метода. Это замыкание будет выполняться только в том случае, если первый аргумент оценивается как false. Чтобы проиллюстрировать, как можно использовать эту функцию, мы будем использовать ее для настройки порядка запросов по умолчанию:

```
$sortByVotes = 'sort_by_votes';

$users = Story::query()
    ->when($sortByVotes, function ($query, $sortByVotes) {
        $query->orderBy('votes');
    }, function ($query) {
        $query->orderBy('name');
    })
    ->get();
```

### Связи (Relations)

[](#связи-relations)

В данный момент поддерживается 3 вида связей

- hasOne - один к одному
- hasMany - один ко многим
- hasManyThrough - многие ко многим

#### Один к одному (hasOne)

[](#один-к-одному-hasone)

3 параметра, имя класса, внешний и внутренний ключ

Внешний и внутренний ключ определяются автоматически, за исключением когда имена полей не совпадают с именем класса или если связь обратная belongsTo (Возможно в будущем это будет реализовано)

```
// Прямая связь
class User extends Model
{
    public function story(): Builder
    {
        return $this->hasOne(Story::class);
    }
}

// Обратная связь
class Story extends Model
{

    public function user(): Builder
    {
        return $this->hasOne(User::class, 'id', 'user_id');
    }
}
```

#### Один ко многим (hasMany)

[](#один-ко-многим-hasmany)

3 параметра, имя класса, внешний и внутренний ключ

Внешний и внутренний ключ определяются автоматически, за исключением когда имена полей не совпадают с именем класса

```
class Story extends Model
{
    public function comments(): Builder
    {
        return $this->hasMany(Comment::class);
    }
}
```

#### Многие ко многим (hasManyThrough)

[](#многие-ко-многим-hasmanythrough)

5 параметров, имя конечного класса, имя промежуточного класса, внешние и внутренние ключи

Внешние и внутренние ключи определяются автоматически, за исключением когда имена полей не совпадают с именами классов

```
class Story extends Model
{
    public function tags(): Builder
    {
        return $this->hasManyThrough(Tag::class, TagStory::class);
    }
}
```

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

[](#жадная-загрузка-eager-load)

По умолчанию все связи с ленивой загрузкой (lazy load)

Связь не будет загружена до тех пор, пока явно не будет вызвана

Для того чтобы жадно загрузить данные необходимо вызвать метод with и передать имена связей, которые требуется жадно загрузить

```
class StoryRepository implements RepositoryInterface

    public function getStories(int $perPage): CollectionPaginate
    {
        return Story::query()
            ->orderByDesc('locked')
            ->orderByDesc('created_at')
            ->with(['user', 'comments'])
            ->paginate($perPage);
    }
}
```

Жадная загрузка извлекает данные используя всего несколько запросов. Это позволяет избежать проблемы N + 1.

Представьте, что у вас есть этот код, который находит 10 сообщений, а затем отображает имя автора каждого сообщения.

```
foreach ($storyRepository->getStories(10) as $story) {
    echo $story->user->login;
}
```

Без ленивой загрузки при каждой итерации цикла было бы обращение в файловую систему для получения данных, то есть 1 запрос на получение списка постов и 10 на получение пользователей

Жадная загрузка избавляет от этой проблемы, 1 запрос на получение списка постов и 1 на получение пользователей этих постов

### Миграции

[](#миграции)

Для вызова класса миграции необходимо в конструктор передать нужную нам модель

```
$migration = new Migration(new Test());
```

#### Создание таблицы

[](#создание-таблицы)

Создание таблицы, пример создания файла test.csv с пятью полями

```
$migration->createTable(function (Migration $table) {
    $table->create('id');
    $table->create('title');
    $table->create('text');
    $table->create('user_id');
    $table->create('created_at');
});
```

#### Удаление таблицы

[](#удаление-таблицы)

```
$migration->deleteTable();
```

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

[](#создание-колонок)

```
$migration->changeTable(function (Migration $table) {
    // Создаст колонку text c текстом по умолчанию "Текст" после колонки title
    $table->create('text')->default('Текст')->after('title');

    // Создаст колонку test перед колонкой id
    $table->create('test')->before('id');
});
```

#### Переименовывание колонок

[](#переименовывание-колонок)

```
$migration->changeTable(function (Migration $table) {
    // Переименует user_id в author_id
    $table->rename('user_id', 'author_id');
});
```

#### Удаление колонок

[](#удаление-колонок)

```
$migration->changeTable(function (Migration $table) {
    // Удалит колонку title
    $table->delete('title');
});
```

#### Проверка существования таблицы/колонки

[](#проверка-существования-таблицыколонки)

```
// Проверит существование таблицы
$migration->hasTable();

// Проверит существование колонки
$migration->hasColumn('field');
```

###  Health Score

30

—

LowBetter than 64% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity13

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity65

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~20 days

Recently: every ~45 days

Total

34

Last Release

901d ago

Major Versions

v1.0.0 → v2.0.02022-02-12

v2.5.0 → v3.0.02022-07-30

v3.5.2 → v4.0.02023-05-31

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/826831?v=4)[Alexander Grigorev](/maintainers/visavi)[@visavi](https://github.com/visavi)

---

Top Contributors

[![visavi](https://avatars.githubusercontent.com/u/826831?v=4)](https://github.com/visavi "visavi (57 commits)")

---

Tags

ormcsvtext orm

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/visavi-motor-orm/health.svg)

```
[![Health](https://phpackages.com/badges/visavi-motor-orm/health.svg)](https://phpackages.com/packages/visavi-motor-orm)
```

###  Alternatives

[doctrine/orm

Object-Relational-Mapper for PHP

10.2k285.3M6.2k](/packages/doctrine-orm)[doctrine/doctrine-bundle

Symfony DoctrineBundle

4.8k241.3M3.3k](/packages/doctrine-doctrine-bundle)[doctrine/persistence

The Doctrine Persistence project is a set of shared interfaces and functionality that the different Doctrine object mappers share.

4.1k286.5M762](/packages/doctrine-persistence)[gedmo/doctrine-extensions

Doctrine behavioral extensions

4.1k118.8M366](/packages/gedmo-doctrine-extensions)[illuminate/database

The Illuminate Database package.

2.8k52.4M9.4k](/packages/illuminate-database)[beberlei/doctrineextensions

A set of extensions to Doctrine 2 that add support for additional query functions available in MySQL, Oracle, PostgreSQL and SQLite.

2.1k75.1M146](/packages/beberlei-doctrineextensions)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
