hindy/orm

0.9.9.6 2017-07-13 03:55 UTC

This package is not auto-updated.

Last update: 2024-09-14 18:36:48 UTC


README

Build Status Coverage Status Latest Stable Version Total Downloads

又一 个 Django ORM 在 PHP 上的实现。目前处于积极开发阶段,不建议在生产环境中使用直到版本 1.0

对于文档的不足之处,我们表示歉意。文档仍在开发中。

部分代码基于 yii2 框架,但由于内核的模块化,我们不得不将框架分割成单独的包。在 Mindy ORM 中,Query 从 yii2 得到积极的应用。

支持的数据库类型:sqlitemysqlpgsqlmssql(所有 yii2 query 能处理的)。理论上 ORM 能够与 NoSql 存储库一起工作,这是通过实现自己的管理器并重写 Lookup 实现的。

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 框架类似

// 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 方法

返回结果的方法

获取

选择一个对象。如果存在多个符合条件的结果,则抛出异常,否则返回对象。如果没有找到对象,则返回 null。

找到 pk == 5 的对象。

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

全部

返回 Model 类的模型数组或调用 asArray() 方法时的关联数组。

选择所有用户。将返回 User 类的模型数组。

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

选择所有用户。将返回关联数组。

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

计数

返回符合条件的结果的对象数

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

返回已修改 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

过滤

您可以使用以下代码找到所有属于名为 example 的组的用户

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

group 在此情况下是到 Group 模型的 m2m 关联

排除

您可以使用以下代码找到所有不属于名为 example 的组的用户

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

group 在此情况下是到 Group 模型的 m2m 关联

排序

查找所有用户并按姓名排序

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

查找所有用户并按姓名逆序排序

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

查找所有用户并随机排序

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

查找

使用查找(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

查找用于在数据库中搜索NULL值。应用示例

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

将选择所有在数据库中名字字段值为NULL的用户。

SELECT * FROM user WHERE name IS NULL

如果传递false作为值,SQL查询将如下所示

SELECT * FROM user WHERE name IS NOT NULL

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

lte生成的SQL

SELECT * FROM user WHERE price <= 100.00

gte, gt

用于搜索大于指定值(gt)和大于或等于指定值(gte)的查找。以下gt查找示例

Product::objects()->filter(['price__gt' => 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

用于搜索严格等于指定值的值。示例

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

将选择所有名字为'Max'的用户。**查找是默认查找,也就是说,在之前的例子中,我们可以简单地使用['name' => 'Max']**

contains

用于搜索包含指定值的值(类似于SQL LIKE)。大小写敏感搜索。对于不区分大小写的搜索,请使用查找icontains。示例

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

将选择所有名字中包含'ax'组合的用户。

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

icontains

完全重复contains查找,但执行不区分大小写搜索。

startswith

用于搜索以指定值开始的值:大小写敏感。对于不区分大小写的搜索,请使用查找istartswith。示例

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

将选择所有名字以'M'开始的用户。

SELECT * FROM user WHERE name LIKE 'M%'

istartswith

完全重复startswith查找,但执行不区分大小写的搜索。

endswith

用于搜索以指定值结束的值:大小写敏感。对于不区分大小写的搜索,请使用查找iendswith。示例

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

将选择所有名字以'on'结束的用户。

SELECT * FROM user WHERE name LIKE '%on'

iendswith

完全重复iendswith查找,但执行不区分大小写的搜索。

in

用于搜索在传递的值列表中的值:示例

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

将选择所有pk在列表[1, 2]中的用户。

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

查找可以接受QuerySet作为值

此查找不仅可以接受值数组,还可以接受QuerySet对象。在这种情况下,查询将添加子查询。

示例

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

将选择所有组名以'A'开头的用户。将只执行一次选择用户的查询。

range

此查找允许找到位于指定值之间的值。此查找接受两个元素的数组。

示例

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

将选择所有价格在10到20之间的产品。

SELECT * FROM product WHERE price BETWEEN 10 AND 20

year

此查找仅适用于类型为DateTimeFieldDateField的字段。允许找到位于指定年份的所有值。

示例

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

将选择所有在2014年添加的产品。

注意:SQL查询将因不同的数据库而异。

month

此查找仅适用于类型为DateTimeFieldDateField的字段。允许找到位于指定月份的所有值。

示例

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

将选择所有在十二月添加的产品。

注意:SQL查询将因不同的数据库而异。

day

该查找器仅与类型为 DateTimeFieldDateField 的字段一起使用。允许找到位于指定月份某一天的所有值。

示例

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

将选择所有在任何月份的25日添加的产品。

注意:SQL查询将因不同的数据库而异。

week_day

该查找器仅与类型为 DateTimeFieldDateField 的字段一起使用。允许找到位于指定星期某一天的所有值。

值: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

该查找器仅与类型为 DateTimeFieldTimeField 的字段一起使用。允许找到位于指定小时的所有值。示例

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

将选择所有在10小时添加的产品。

注意:SQL查询将因不同的数据库而异。

minute

该查找器仅与类型为 DateTimeFieldTimeField 的字段一起使用。允许找到位于指定分钟的所有值。示例

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

将选择所有在35分钟添加的产品。

注意:SQL查询将因不同的数据库而异。

second

该查找器仅与类型为 DateTimeFieldTimeField 的字段一起使用。允许找到位于指定秒的所有值。示例

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

将选择所有在45秒添加的产品。

注意:SQL查询将因不同的数据库而异。

search

** 未实现 **

regex

按正则表达式搜索。 大小写敏感。对于大小写不敏感,请使用查找器 iregex。示例

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

将选择所有符合正则表达式 [a-z] 的产品。

注意:SQL查询将因不同的数据库而异。

iregex

完全重复前面的查找器,但执行大小写不敏感的搜索。

注意:SQL查询将因不同的数据库而异。

Q-对象(查询对象)

Q-对象用于方便地形成选择条件。存在两个 Q-对象:OrQAndQ

Q-对象是这样形成的

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

然后可以将其传递给方法 filterexclude

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

该查询将选择所有状态为1的用户id为1的申请和状态为2的用户id为4的申请。