PHPackages                             hindy/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. hindy/orm

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

hindy/orm
=========

0.9.9.6(8y ago)01092MITPHP

Since Mar 7Pushed 8y ago1 watchersCompare

[ Source](https://github.com/hashstudio/Mindy_Orm)[ Packagist](https://packagist.org/packages/hindy/orm)[ Docs](https://github.com/hashstudio/Mindy_Orm)[ RSS](/packages/hindy-orm/feed)WikiDiscussions master Synced 4w ago

READMEChangelogDependencies (8)Versions (6)Used By (2)

Mindy ORM (Django like ORM)
===========================

[](#mindy-orm-django-like-orm)

[![Build Status](https://camo.githubusercontent.com/e0b356659a033a23641b0c71e2fb41b8366cfc7df93593c2ce30ed39a9986dce/68747470733a2f2f7472617669732d63692e6f72672f73747564696f3130372f4d696e64795f4f726d2e737667)](https://travis-ci.org/studio107/Mindy_Orm)[![Coverage Status](https://camo.githubusercontent.com/e0d2edf72626934b80ea6669094e4cafc2223f79ddd8ade73bbc8eb375f8b918/68747470733a2f2f696d672e736869656c64732e696f2f636f766572616c6c732f73747564696f3130372f4d696e64795f4f726d2e737667)](https://coveralls.io/r/studio107/Mindy_Orm)[![Latest Stable Version](https://camo.githubusercontent.com/a67632d4eb44a828ad5d01ffe92079b16e592d21d8f59ee8338fd020745e075f/68747470733a2f2f706f7365722e707567782e6f72672f6d696e64792f6f726d2f762f737461626c652e737667)](https://packagist.org/packages/mindy/orm)[![Total Downloads](https://camo.githubusercontent.com/0b93fd6f2a6371b4e0a171d44667078d1f9a8d28d5ab98bae6d32b99fd63875f/68747470733a2f2f706f7365722e707567782e6f72672f6d696e64792f6f726d2f646f776e6c6f6164732e737667)](https://packagist.org/packages/mindy/orm)

***Еще одна*** реализация Django ORM на PHP. На текущий момент находится в стадии активной доработки и не рекомендуется к использованию в `production` до версии ***1.0***.

Приносим извинения за неполноту документации. Документация находится разработке.

Часть кода основана на yii2 фреймворке, но ввиду монолитности ядра мы были вынуждены "распилить" фреймворк по отдельным пакетам. В `Mindy ORM` активно используется Query из yii2.

Поддерживаемые типы субд: `sqlite`, `mysql`, `pgsql`, `mssql` (все то, что умеет yii2 query). Теоретически ORM способна работать с `NoSql` хранилищами за счет реализации собственного менеджера с переопределением `Lookup`'ов.

Краткий пример возможностей ORM
-------------------------------

[](#краткий-пример-возможностей-orm)

Опишем подключение к бд:

```
Model::setConnection([
    'sqlite::memory'
]);
```

Опишем модель:

```
class MyModel extends Model
{
    public function getFields()
    {
        return [
            // Ключ - название поля при обращении к модели
            'name' => [
                // Тип поля
                'class' => CharField::className(),
                // Длинна поля
                'length' => 100,
                // NULL|NOT NULL
                'null' => false,
                // "Читабельное" имя модели. Используется в Mindy\Form\ModelForm
                // для построения форм автоматически.
                'verboseName' => 'Продукция',
                // Пример валидаторов
                'validators' => [
                    function ($value) {
                        if (mb_strlen($value, 'UTF-8') < 3) {
                            return "Minimal length < 3";
                        }

                        return true;
                    },
                    new UniqueValidator
                ]
            ],
            'price' => [
                'class' => CharField::className(),
                // Значение по умолчанию
                'default' => 0
            ],
            'description' => [
                'class' => TextField::className(),
                'default' => ''
            ],
            'category' => [
                'class' => ForeignField::className(),
                'modelClass' => Category::className(),
                'null' => true
            ],
            'lists' => [
                'class' => ManyToManyField::className(),
                'modelClass' => ProductList::className()
            ]
        ];
    }
}
```

Описание модели завершено. Валидация происходит на основе валидации полей модели. Модель описана, теперь необходимо создать ее в субд. Для этого выполним следующий код:

```
$sync = new Sync([
    new MyModel()
]);
$sync->create();
```

В бд создатутся таблицы всех переданных моделей а так же индексы и связи если это возможно.

Создадим несколько записей:

```
// Если модель с идентичными полями найдется, то ORM вернет ее, иначе создаст.
$model = MyModel::objects()->getOrCreate(['name' => 'Поросенок петр', 'price' => 1]);

$modelTwo = new MyModel;
// Массовое присвоение аттрибутов
$modelTwo->setData([
    'name' => 'Рубаха',
    'price' => 2
]);
// Валидация и сохранение
if($modelTwo->isValid() && $modelTwo->save()) {
    echo 'Модель сохранена';
}

$modelThree = new MyModel;
$modelThree->name = 'Джинсы';
$modelThree->price = 3;
// Валидация и сохранение
if($modelThree->isValid() && $modelThree->save()) {
    echo 'Модель сохранена';
}
```

Выборки реализованы по аналогии с Django Framework:

```
// SELECT * FROM my_model WHERE price >= 2
$models = MyModel::objects()->filter(['price__gte' => 2])->all();

// SELECT * FROM my_model WHERE name = 'Рубаха'
$models = MyModel::objects()->filter(['name' => 'Рубаха'])->all();

// SELECT * FROM my_model WHERE id IN (1, 2, 3)
$models = MyModel::objects()->filter(['pk__in' => [1, 2, 3]])->all();
```

И так далее. Более подробную информацию смотрите в разделе ***Lookups***

Очистим базу данных:

```
$sync = new Sync([
    new MyModel()
]);
$sync->delete();
```

Менеджеры
---------

[](#менеджеры)

Менеджер это интерфейс проксирующий до класса `QuerySet`, который занимается обработкой наших `Lookup`'ов и выполнением запросов. Каждая модель по умолчанию имеет менеджер `objects()`.

```
User::objects()
```

Менеджер обрабатывает QuerySet. Основным методом менеджера является `getQuerySet()`. Это возвращает объект, который впоследствии обрабатывается менеджером. Если вы хотите изменить логику менеджера по умолчанию, вы можете создать свой собственный менеджер. Например, `activeUsersManager()`:

```
class ActiveUsersManager extends Manager
{
    public function getQuerySet()
    {
        $qs = parent::getQuerySet();
        return $qs->filter(['status' => User::STATUS_ACTIVE]);
    }
}
```

Модель с собственным менеджером:

```
class User extends Model
{
    public function getFields()
    {
        'name' => [
            'class' => CharField::className(),
        ],
        'status' => [
            'class' => BooleanField::className(),
            'default' => false
        ]
    }

    public static function activeUsersManager($instance = null)
    {
        $className = get_called_class();
        return new ActiveUsersManager($instance ? $instance : new $className);
    }
}
```

Теперь вы можете использовать `ActiveUsersManager()` с помощью `User::activeUsers()`. И все запросы будут выполняться в соответствии с вашей логикой обработки только активных пользователей. Например, этот код поможет выбрать активных пользователей имя которых начинается с 'A':

```
User::activeUsers()->filter(['name__startswith' => 'A'])->all();
```

Manager/QuerySet методы
-----------------------

[](#managerqueryset-методы)

### Methods returning a result

[](#methods-returning-a-result)

#### Get

[](#get)

Выборка одного объекта. В случае если объектов соответствующих условию больше 1, выбрасываем исключение, иначе возвращаем объект. Если объектов не найдено, то возвращаем null.

Найдем объект где `pk == 5`.

```
$model = User::objects()->filter(['pk' => 5])->get();
```

#### All

[](#all)

Возвращает массив моделей класса `Model` или ассоциативный массив в случае если вызван метод `asArray()`.

Выборка всех пользователей. Вернется массив моделей класса `User`.

```
User::objects()->all();
```

Выборка всех пользователей. Вернется ассоциативный массив.

```
User::objects()->asArray()->all();
```

#### Count

[](#count)

Возвращает число объектов подходящих под условия выборки

```
User::objects()->count();
```

Методы, возвращающие измененный QuerySet
----------------------------------------

[](#методы-возвращающие-измененный-queryset)

Вы можете вызывать эти методы последовательно:

```
User::objects()->filter(['name' => 'Max'])->exclude(['address' => 'New York'])->order(['-address'])->all();
```

Данный код возвращает всех пользователей с именем `Max` живущих не в `New York` с сортировкой по адресу в обратном порядке.

```
SELECT * FROM user WHERE name='Max' AND address != 'New York' ORDER BY address DESC
```

#### Filter

[](#filter)

Вы можете найти всех пользователей состоящих в группе с именем `example`, используя следующий код:

```
User::objects()->filter(['group__name' => 'example'])->all();
```

`group` в данном случае связь `m2m` до модели `Group`

#### Exclude

[](#exclude)

Вы можете найти всех пользователей которые не состоят в группе с названием `example`, используя следующий код:

```
User::objects()->exclude(['group__name' => 'users'])->all();
```

`group` в данном случае связь `m2m` до модели `Group`

#### Order

[](#order)

Поиск всех пользователей и сортировка по имени:

```
User::objects()->order(['name'])->all();
```

Поиск всех пользователей и сортировка по имени в обратном порядке:

```
User::objects()->order(['-name'])->all();
```

Поиск всех пользователей и сортировка в случайном порядке

```
User::objects()->order(['?'])->all();
```

Lookups
-------

[](#lookups)

С помощью лукапов(lookups) вы можете фильтровать QuerySet. Лукапы применяются в методах менеджера `exclude()` и `filter()` и передаются в них массивом, где ключом массива являются поля (с лукапами), а значением - значение, по которому и производится фильтрация. Пример лукапа:

```
'name__exact'
```

Данный лукап указывает на то, что поле `name` должно быть равно указанному значению. Пример применения:

```
User::objects()->filter(['name__exact' => 'Max'])->all();
```

Выбираем всех пользователей имя которых равно 'Max'. *На самом деле, лукап `exact` является лукапом "по умолчанию". То есть, в данном примере можно было было обойтись условием `filter(['name' => 'Max'])`.*

```
SELECT * FROM user WHERE name = 'Max'
```

### isnull

[](#isnull)

Лукап, применяющийся для поиска значений `NULL` в базе данных. Пример применения:

```
User::objects()->filter(['name__isnull' => true])->all();
```

Произойдет выбор всех пользователей cо значением имени в БД `NULL`.

```
SELECT * FROM user WHERE name IS NULL
```

Если передать `false` в качестве значения то sql запрос будет выглядеть слудющим образом:

```
SELECT * FROM user WHERE name IS NOT NULL
```

### lte, lt

[](#lte-lt)

Лукапы, применяющиеся для поиска значений меньше заданного (`lt`), и меньших либо равных заданному (`lte`) Пример `lt` лукапа:

```
Product::objects()->filter(['price__lt' => 100.00])->all();
```

Произойдет выбор всех продуктов с ценой строго меньшей `100.00`.

Пример `lte` лукапа:

```
Product::objects()->filter(['price__lte' => 100.00])->all();
```

```
$dateTime = new DateTime();
$dateTime->setTimestamp(strtotime('+15 days'))
Product::objects()->filter(['created_at__lte' => $dateTime])->all();
```

Произойдет выбор всех продуктов с ценой меньшей, либо равной `100.00`.

`lt` формирует слудющий sql:

```
SELECT * FROM user WHERE price  100.00])->all();
```

Произойдет выбор всех продуктов с ценой строго большей `100.00`.

Пример `gte` лукапа:

```
Product::objects()->filter(['price__gte' => 100.00])->all();
```

Произойдет выбор всех продуктов с ценой большей, либо равной `100.00`.

`gt` формирует слудющий sql:

```
SELECT * FROM user WHERE price > 100.00
```

`gte` формирует слудющий sql:

```
SELECT * FROM user WHERE price >= 100.00
```

### exact

[](#exact)

Применяется для поиска значний строго равных заданному. Пример:

```
User::objects()->filter(['name__exact' => 'Max'])->all();
```

Произойдет выбор всех пользователей с именем 'Max'. \*\* Лукап является лукапом по умолчанию, то есть в предыдущем примере можно указать просто `['name' => 'Max']` \*\*

### contains

[](#contains)

Применяется для поиска значений в которых присутствует заданноу значение (аналог - SQL LIKE). ***Регистрозависимый*** поиск. Для регистронезависимого используйте lookup `icontains`. Пример:

```
User::objects()->filter(['name__contains' => 'ax'])->all();
```

Произойдет выбор всех пользователей, в имени которых есть сочетание 'ax'.

```
SELECT * FROM user WHERE name LIKE '%ax%'
```

### icontains

[](#icontains)

Полностью повторяет lookup `contains`, но осуществляет ***регистронезависимый*** поиск.

### startswith

[](#startswith)

Применяется для поиска значений, начинающихся с заданного значения: Регистрозависимый. Для регистронезависимого используйте lookup `istartswith`. Пример:

```
User::objects()->filter(['name__startswith' => 'M'])->all();
```

Произойдет выбор всех пользователей, имя которых начинается с 'M'.

```
SELECT * FROM user WHERE name LIKE 'M%'
```

### istartswith

[](#istartswith)

Полностью повторяет lookup `startswith`, но осуществляет регистронезависимый поиск.

### endswith

[](#endswith)

Применяется для поиска значний, заканчивающихся заданным значением: Регистрозависимый. Для регистронезависимого используйте lookup `iendswith`. Пример:

```
User::objects()->filter(['name__endswith' => 'on'])->all();
```

Произойдет выбор всех пользователей, имя которых начинается с 'on'.

```
SELECT * FROM user WHERE name LIKE '%on'
```

### iendswith

[](#iendswith)

Полностью повторяет lookup `iendswith`, но осуществляет регистронезависимый поиск.

### in

[](#in)

Применяется для поиска значений, попадающих в список переданных значений: Пример:

```
User::objects()->filter(['pk__in' => [1, 2]])->all();
```

Произойдет выбор всех пользователей, pk которых попадают в список `[1, 2]`.

```
SELECT * FROM user WHERE id IN (1, 2)
```

***Lookup может принимать QuerySet в качестве значения***

Данный лукап позволяет принимать не только массив значений, но и объект QuerySet. В этом случае в запрос будет добавлен подзапрос.

Пример:

```
$group_qs = Group::objects()->filter(['name__startswith' => 'A']);
$users = User::objects()->filter(['groups__pk__in' => $group_qs->select('id') ])->all();

```

Произойдет выбор всех пользователей, имена групп которых начинаются с 'A'. Будет выполнен всего один запрос на выбор пользователей.

### range

[](#range)

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

Пример:

```
Product::objects()->filter(['price__range' => [10, 20]])
```

Произойдет выбор всех продуктов с ценой от 10 до 20.

```
SELECT * FROM product WHERE price BETWEEN 10 AND 20
```

### year

[](#year)

Данный лукап работает только с полями типа `DateTimeField`, `DateField`. Позволяет найти все значения, расположенные в заданном году.

Пример:

```
Product::objects()->filter(['date_added__year' => 2014])
```

Произойдет выбор всех продуктов, добавленных в 2014 году.

***Внимание:*** sql запрос будет отличаться для разных субд.

### month

[](#month)

Данный лукап работает только с полями типа `DateTimeField`, `DateField`. Позволяет найти все значения, расположенные в заданном месяце.

Пример:

```
Product::objects()->filter(['date_added__year' => 12])
```

Произойдет выбор всех продуктов, добавленных в декабре.

***Внимание:*** sql запрос будет отличаться для разных субд.

### day

[](#day)

Данный лукап работает только с полями типа `DateTimeField`, `DateField`. Позволяет найти все значения, расположенные в заданном дне месяца.

Пример:

```
Product::objects()->filter(['date_added__day' => 25])
```

Произойдет выбор всех продуктов, добавленных 25 числа любого месяца.

***Внимание:*** sql запрос будет отличаться для разных субд.

### week\_day

[](#week_day)

Данный лукап работает только с полями типа `DateTimeField`, `DateField`. Позволяет найти все значения, расположенные в заданном дне недели.

Значения: 1 - Воскресенье, 2 - Понедельник, ..., 7 - Суббота. Порядок дней определяет ORM и подстраивает под текущую субд по следующей причине:

```
Method                              Range
------                              -----
PYTHON
    datetime_object.weekday()       0-6    Sunday=6
    datetime_object.isoweekday()    1-7    Sunday=7
    dt_object.isoweekday() % 7      0-6    Sunday=0 # Can easily add 1 for a 1-7 week where Sunday=1

MYSQL
    DAYOFWEEK(timestamp)            1-7    Sunday=1
    WEEKDAY(timestamp)              0-6    Monday=0

POSTGRES
    EXTRACT('dow' FROM timestamp)   0-6    Sunday=0
    TO_CHAR(timestamp, 'D')         1-7    Sunday=1

ORACLE
    TO_CHAR(timestamp, 'D')         1-7    Sunday=1 (US), Sunday=6 (UK)

```

Пример:

```
Product::objects()->filter(['date_added__week_day' => 2])
```

Произойдет выбор всех продуктов, добавленных в понедельник.

***Внимание:*** sql запрос будет отличаться для разных субд.

### hour

[](#hour)

Данный лукап работает только с полями типа `DateTimeField`, `TimeField`. Позволяет найти все значения, расположенные в заданном часе. Пример:

```
Product::objects()->filter(['date_added__hour' => 10])
```

Произойдет выбор всех продуктов, добавленных в 10 часов.

***Внимание:*** sql запрос будет отличаться для разных субд.

### minute

[](#minute)

Данный лукап работает только с полями типа `DateTimeField`, `TimeField`. Позволяет найти все значения, расположенные в заданной минуте. Пример:

```
Product::objects()->filter(['date_added__minute' => 35])
```

Произойдет выбор всех продуктов, добавленных в 35 минут.

***Внимание:*** sql запрос будет отличаться для разных субд.

### second

[](#second)

Данный лукап работает только с полями типа `DateTimeField`, `TimeField`. Позволяет найти все значения, расположенные в заданной секунде. Пример:

```
Product::objects()->filter(['date_added__minute' => 45])
```

Произойдет выбор всех продуктов, добавленных в 45 секунд.

***Внимание:*** sql запрос будет отличаться для разных субд.

### search

[](#search)

\*\* Не реализовано \*\*

### regex

[](#regex)

Поиск по регулярному выражению. ***Регистрозависимый***. Для регистронезависимого используйте lookup `iregex`. Пример:

```
Product::objects()->filter(['name__regex' => '[a-z]'])
```

Произойдет выбор всех продуктов, соответствующих регулярному выражению `[a-z]`

***Внимание:*** sql запрос будет отличаться для разных субд.

### iregex

[](#iregex)

Полностью повторяет предыдущий lookup, но осуществляет регистронезависимый поиск.

***Внимание:*** sql запрос будет отличаться для разных субд.

Q-объекты (Query-объекты)
-------------------------

[](#q-объекты-query-объекты)

Q-объекты необходимы для удобного формирования условий выборки. Существует 2 Q-объекта: **OrQ** и **AndQ**.

Q-объект формируется следующим образом:

```
new OrQ([['status' => 1, 'user_id' => 1],['status' => 2, 'user_id' => 4]]);
```

И затем его можно передать в методы **filter** или **exclude**:

```
Requests::objects()->filter([new OrQ([['status' => 1, 'user_id' => 1],['status' => 2, 'user_id' => 4]])])->all()
```

Данный запрос выберет нам все заявки со статусом 1 от пользователя с **id** равным 1 и заявки со статусом 2 от пользователя с **id** равным 4.

###  Health Score

27

—

LowBetter than 47% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity9

Limited adoption so far

Community13

Small or concentrated contributor base

Maturity57

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 50% 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 ~123 days

Total

5

Last Release

3276d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/17700234?v=4)[hashstudio](/maintainers/hashstudio)[@hashstudio](https://github.com/hashstudio)

---

Top Contributors

[![hashstudio](https://avatars.githubusercontent.com/u/17700234?v=4)](https://github.com/hashstudio "hashstudio (4 commits)")[![qantus](https://avatars.githubusercontent.com/u/3940487?v=4)](https://github.com/qantus "qantus (4 commits)")

### Embed Badge

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

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

###  Alternatives

[sulu/sulu

Core framework that implements the functionality of the Sulu content management system

1.3k1.4M198](/packages/sulu-sulu)[mostafaznv/larupload

Larupload is a ORM based file uploader for laravel to upload image, video, audio and other known files.

75462.1k6](/packages/mostafaznv-larupload)[codesleeve/stapler

Elegant and simple ORM-based file upload package for php.

536367.2k5](/packages/codesleeve-stapler)[contao/core-bundle

Contao Open Source CMS

1231.6M2.7k](/packages/contao-core-bundle)[elgg/elgg

Elgg is an award-winning social networking engine, delivering the building blocks that enable businesses, schools, universities and associations to create their own fully-featured social networks and applications.

1.7k16.2k55](/packages/elgg-elgg)[neos/neos-development-collection

Neos packages in a joined repository for pull requests.

267103.9k1](/packages/neos-neos-development-collection)

PHPackages © 2026

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