PHPackages                             gzhegow/orm8 - 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. gzhegow/orm8

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

gzhegow/orm8
============

1.0.0-rc.1761867973+20251030(8mo ago)04MITPHPPHP ~8.0.0|~8.1.0|^8.2

Since Aug 27Pushed 1mo agoCompare

[ Source](https://github.com/gzhegow1991/orm8)[ Packagist](https://packagist.org/packages/gzhegow/orm8)[ RSS](/packages/gzhegow-orm8/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (2)Dependencies (2)Versions (2)Used By (0)

ORM
===

[](#orm)

Пакет на основе `illuminate/database` (Laravel Eloquent, в простонародье "ёлка"), доработанный с помощью функционала Persistence и некоторыми другими полезными функциями

```
PS. Использование `symfony/doctrine` это конечно хорошо. Но человека нужно ему учить, долго учить, потом он сам должен много учить, а потом эта штука будет работать медленнее, чем обычные запросы к PDO, поэтому лучше использовать "ёлку"
PS2. Можно использовать PDO и встроенный в PHP способ работы с базами данных. К сожалению, этот метод недостаточно прост в использовании, а также требует постоянной проверки на SQL-иньекции вручную либо подсчета биндов для запроса... Это можно (и, по-хорошему) нужно делать, но далеко не все специалисты на рынке имеют достаточно опыта, чтобы делать это без подготовки и набитых шишек. И потом, бизнес-задачи имеют свойство "наращиваться", а вот собирать из кусков SQL запрос это тот ещё ад, сильно проще использовать для этого ёлковский билдер

```

Рекомендации при работе с ORM:

- не создавать модели в коде используя `new ModelClass()`, использовать для этого `ModelClass::new()`. Это позволит работать проверкам в \_\_get()/\_\_set() на возможность проставления и получения данных.

```
Так, в ёлке метод __get() может выполнить запрос, если свойство является связью. Разумно включить блокировку ленивых запросов в классе модели.
Также добавлена возможность блокировки ленивого чтения, чтобы была возможность оперировать ровно теми данными, что получены из БД, без применения магических атрибутов, которые могут возвращать значение по-умоланию, если оно там было.

Так, в ёлке метод __set() может проставить свойства, которые являются ID, при клонировании существующей модели.
Также добавлена возможность блокировки ленивой записи, что позволяет работать с таблицами с историческими данными, которые не должны меняться вручную.

```

- добавлена возможность установить префикс для связей (по умолчанию символ `_`);

```
Это сильно упрощает чтение кода, разделяя связи и свойства, а также ускоряет проверку при считывании свойства на предмет "нужно ли интерпретировать свойство как связь"

Eloquent::setRelationPrefix('_');

/**
 * @property int            $id
 * @property string         $name
 *
 * @property int            $demo_foo_id
 * @property DemoFooModel   $_demoFoo
 */
abstract class AbstractModel extends \Gzhegow\Orm\Package\Illuminate\Database\Eloquent\EloquentModel
{
}

/**
 * @property int            $id
 * @property string         $name
 *
 * @property int            $demo_foo_id
 * @property DemoFooModel   $_demoFoo
 */
class MyModel extends AbstractModel
{
    protected static function relationClasses() : array
    {
        return [
            '_demoFoo'  => BelongsTo::class,
        ];
    }

    public function _demoFoo() : BelongsTo
    {
        return $this->relation()
            ->belongsTo(
                __FUNCTION__,
                DemoFooModel::class
            )
        ;
    }
}

```

- добавлена возможность задавать колонки для выборки по-умолчанию, включая связи

```
Это сделано для того, чтобы при выборке модели из БД не тянуть все колонки, включая те, что могут хранить большие JSON данные, это можно задать в модели в свойстве $columns

class MyModel extends AbstractModel
{
    protected $columns = [ '*' ]; // достает все колонки, как по-умолчанию в Eloquent, для development окружения
    // protected $columns = [ '#' ]; // только PrimaryKey (не во всех таблицах он есть)
    // protected $columns = [ '#', 'name' ]; // только PrimaryKey и колонка `name`
}

Инструмент отлично сочетается с $preventsLazyGet/$preventsLazySet - в этом случае отстутствующие колонки будут прерывать работу программы, позволяя исправить код.
При выборке по связям используя ->with()/->load() колонки так же не будут выбираться автоматически, и да, это может привести к неверной работе связей, поэтому используйте этот инструмент с умом и вручную добавляйте нужные колонки.

$query = MyModel::query();
$query->addColumn('name');
$models = $query->get();

```

- для пагинации и выборки большого числа записей пользуйтесь инструментом выборки по чанкам;

```
Это делается с помощью \Generator, распределяя по времени нагрузку на обмен данных между базой и приложением

$builder = MyModel::chunks();
$builder->chunksModelNativeForeach(
    $limitChunk = 25, $limit = null, $offset = null
);
foreach ( $builder->chunksForeach() as $chunk ) {
    _dump($chunk);
}

$builder = MyModel::chunks();
$builder
    // ->setTotalItems(100)
    // ->setTotalPages(8)
    // ->withSelectCountNative()
    // ->withSelectCountExplain()
    ->paginatePdoNativeForeach(
        $perPage = 13, $page = 7, $pagesDelta = 2,
        $offset = null
    )
;
$result = $builder->paginateResult();

```

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

```
$my = MyModel::new();
$my->name = 'any_data';
$my->persistForSaveRecursive();

\Gzhegow\Orm\Core\Orm::getEloquentPersistence()->flush();

```

- указывая связи для загрузки использовать инструмент `ModelClass::relationDot()` передавая туда callable (в этом случае, если вы переименуете метод связи - оно будет переименовано во всем коде, как callable)

```
// НЕ ВЕРНО:
$query->with([
    '_relationName._relationNameChild',
    '_relationName._relationNameChild',
    '_relationName._relationNameChild',
]);
$model->load([
    '_relationName._relationNameChild',
    '_relationName._relationNameChild',
    '_relationName._relationNameChild',
]);
$collection->load([
    '_relationName._relationNameChild',
    '_relationName._relationNameChild',
    '_relationName._relationNameChild',
]);

// ВЕРНО:
$query->with([
    Orm::relationDot()([ ModelClass::class, '_relationName' ])([ Model2Class::class, '_relationNameChild' ])(),
    Orm::relationDot()([ ModelClass::class, '_relationName' ])([ Model2Class::class, '_relationNameChild' ])(),
    Orm::relationDot()([ ModelClass::class, '_relationName' ])([ Model2Class::class, '_relationNameChild' ])(),
]);
$model->load([
    Orm::relationDot()([ ModelClass::class, '_relationName' ])([ Model2Class::class, '_relationNameChild' ])(),
    Orm::relationDot()([ ModelClass::class, '_relationName' ])([ Model2Class::class, '_relationNameChild' ])(),
    Orm::relationDot()([ ModelClass::class, '_relationName' ])([ Model2Class::class, '_relationNameChild' ])(),
]);
$collection->load([
    Orm::relationDot()([ ModelClass::class, '_relationName' ])([ Model2Class::class, '_relationNameChild' ])(),
    Orm::relationDot()([ ModelClass::class, '_relationName' ])([ Model2Class::class, '_relationNameChild' ])(),
    Orm::relationDot()([ ModelClass::class, '_relationName' ])([ Model2Class::class, '_relationNameChild' ])(),
]);

```

Установить
----------

[](#установить)

```
composer require gzhegow/orm

```

Запустить тесты
---------------

[](#запустить-тесты)

```
php test.php

```

Примеры и тесты
---------------

[](#примеры-и-тесты)

```
