跳转到内容

模型元数据


概览

当使用Phalcon\Mvc\Model类,这些类对应数据库中的实际表,Phalcon 需要知道有关这些表的基本信息,例如字段、数据类型、主键和外键以及关系。Phalcon\Mvc\Model\MetaData对象提供此功能,透明地查询数据库并从数据库模式生成必要的数据。然后可以将数据存储在数据存储(如 Redis、APCu 等)中,以确保每次执行查询时不会查询数据库的模式。

注意

在部署到生产环境时,请确保始终使 metaData 缓存失效,以便在部署期间传播的数据库更改可在应用程序中使用。metaData 缓存将重建所有必要的更改。

<?php

use MyApp\Models\Invoices;
use Phalcon\Mvc\Model\MetaData;

$invoice = new Invoices();

/** @var MetaData $metadata */
$metadata = $invoice->getModelsMetaData();

$attributes = $metadata->getAttributes($invoice);
print_r($attributes);

$dataTypes = $metadata->getDataTypes($invoice);
print_r($dataTypes);

上面的代码将打印字段名称以及字段到字段类型的数组。我们使用attributes作为fields.

[
    [0] => inv_id
    [1] => inv_cst_id
    [2] => inv_status_flag
    [3] => inv_title
    [4] => inv_total
    [5] => inv_created_at
    [6] => inv_created_by
    [7] => inv_updated_at
    [8] => inv_updated_by
]

[
    [inv_id]          => 0,
    [inv_cst_id]      => 0,
    [inv_status_flag] => 0,
    [inv_title]       => 2,
    [inv_total]       => 0,
    [inv_created_at]  => 4,
    [inv_created_by]  => 0,
    [inv_updated_at]  => 4,
    [inv_updated_by]  => 0,
]

常量

Phalcon\Mvc\Model\MetaData暴露了许多常量,可用于从内部集合中检索属性。

名称 描述
MODELS_ATTRIBUTES 映射表中的每个列
MODELS_AUTOMATIC_DEFAULT_INSERT 必须忽略的字段INSERTSQL 语句
MODELS_AUTOMATIC_DEFAULT_UPDATE 必须忽略的字段UPDATESQL 语句
MODELS_COLUMN_MAP 列映射(别名)
MODELS_DATA_TYPES 每个列及其数据类型
MODELS_DATA_TYPES_BIND 每个列必须如何绑定/转换
MODELS_DATA_TYPES_NUMERIC 具有数值数据类型的列
MODELS_DEFAULT_VALUES 列的默认值
MODELS_EMPTY_STRING_VALUES 允许空字符串的列
MODELS_IDENTITY_COLUMN 标识列。false如果模型没有标识列
MODELS_NON_PRIMARY_KEY 不属于主键的每个列
MODELS_NOT_NULL 不允许的每个列null
MODELS_PRIMARY_KEY 属于主键的每个列
MODELS_REVERSE_COLUMN_MAP 反向列映射(别名)

方法

public function getAttributes(ModelInterface $model): array
返回表属性名(字段)

print_r(
    $metaData->getAttributes(
        new Invoices()
    )
);

public function getAutomaticCreateAttributes(
    ModelInterface $model
): array
返回必须忽略的属性INSERTSQL 生成

print_r(
    $metaData->getAutomaticCreateAttributes(
        new Invoices()
    )
);

public function getAutomaticUpdateAttributes(
    ModelInterface $model
): array
返回必须忽略的属性UPDATESQL 生成

print_r(
    $metaData->getAutomaticUpdateAttributes(
        new Invoices()
    )
);

public function getBindTypes(ModelInterface $model): array
返回属性及其绑定数据类型

print_r(
    $metaData->getBindTypes(
        new Invoices()
    )
);
public function getColumnMap(ModelInterface $model): array

如果有的话返回列映射

print_r(
    $metaData->getColumnMap(
        new Invoices()
    )
);

public function getDefaultValues(ModelInterface $model): array
返回具有默认值的属性及其默认值

 print_r(
     $metaData->getDefaultValues(
         new Invoices()
     )
 );

public function getDataTypes(ModelInterface $model): array
返回属性及其数据类型

print_r(
    $metaData->getDataTypes(
        new Invoices()
    )
);

public function getDataTypesNumeric(ModelInterface $model): array
返回类型为数值的属性

print_r(
    $metaData->getDataTypesNumeric(
        new Invoices()
    )
);

public function getEmptyStringAttributes(
    ModelInterface $model
): array
返回允许空字符串的属性

print_r(
    $metaData->getEmptyStringAttributes(
        new Invoices()
    )
);

public function getIdentityField(ModelInterface $model): string
如果存在,则返回标识字段的名称

print_r(
    $metaData->getIdentityField(
        new Invoices()
    )
);

public function getNonPrimaryKeyAttributes(
    ModelInterface $model
): array
返回不属于主键的字段数组

print_r(
    $metaData->getNonPrimaryKeyAttributes(
        new Invoices()
    )
);

public function getNotNullAttributes(ModelInterface $model): array
返回非空属性的数组

print_r(
    $metaData->getNotNullAttributes(
        new Invoices()
    )
);

public function getPrimaryKeyAttributes(
    ModelInterface $model
): array
返回属于主键的字段数组

print_r(
    $metaData->getPrimaryKeyAttributes(
        new Invoices()
    )
);

public function getReverseColumnMap(
    ModelInterface $model
): array
如果有的话返回反向列映射

print_r(
    $metaData->getReverseColumnMap(
        new Invoices()
    )
);

public function getStrategy(): StrategyInterface
返回获取元数据的策略

public function hasAttribute(
    ModelInterface $model, 
    string $attribute
): bool
检查模型是否具有某个属性

print_r(
    $metaData->hasAttribute(
        new Invoices(),
        "inv_title"
    )
);

public function isEmpty(): bool
检查内部元数据容器是否为空

print_r(
    $metaData->isEmpty()
);
public function read(string $key): array | null

从适配器读取元数据

final public function readColumnMap(
    ModelInterface $model
): array | null
读取特定模型的有序/反向列映射

print_r(
    $metaData->readColumnMap(
        new Invoices()
    )
);

final public function readColumnMapIndex(
    ModelInterface $model, 
    int $index
)
使用MODEL_*常量读取特定模型的列映射信息

print_r(
    $metaData->readColumnMapIndex(
        new Invoices(),
        MetaData::MODELS_REVERSE_COLUMN_MAP
    )
);

final public function readMetaData(ModelInterface $model): array
读取特定模型的完整元数据

print_r(
    $metaData->readMetaData(
        new Invoices()
    )
);

final public function readMetaDataIndex(
    ModelInterface $model, 
    int $index
)
读取特定模型的元数据

print_r(
    $metaData->readMetaDataIndex(
        new Invoices(),
        0
    )
);

public function reset(): void
重置内部元数据以便重新生成它

 $metaData->reset();

public function setAutomaticCreateAttributes(
    ModelInterface $model, 
    array $attributes
): void
设置必须从 INSERT SQL 生成中忽略的属性

$metaData->setAutomaticCreateAttributes(
    new Invoices(),
    [
        "inv_created_at" => true,
    ]
);

public function setAutomaticUpdateAttributes(
    ModelInterface $model, 
    array $attributes
): void
设置必须从 UPDATE SQL 生成中忽略的属性

$metaData->setAutomaticUpdateAttributes(
    new Invoices(),
    [
        "inv_updated_at" => true,
    ]
);

public function setEmptyStringAttributes(
    ModelInterface $model, 
    array $attributes
): void
设置允许空字符串值的属性

$metaData->setEmptyStringAttributes(
    new Invoices(),
    [
        "inv_title" => true,
    ]
);

public function setStrategy(StrategyInterface $strategy): void
设置元数据提取策略

public function write(string $key, array $data): void
将元数据写入适配器

final public function writeMetaDataIndex(
    ModelInterface $model, 
    int $index, 
    mixed $data
): void
使用 MODEL_* 常量为特定模型写入元数据

print_r(
    $metaData->writeColumnMapIndex(
        new Invoices(),
        MetaData::MODELS_REVERSE_COLUMN_MAP,
        [
            "title" => "inv_title",
        ]
    )
);

final protected function initialize(
    ModelInterface $model, 
    mixed $key, 
    mixed $table, 
    mixed $schema
)
获取元数据是一项代价昂贵的数据库操作,我们当然不想在每次运行查询时都执行它。但是我们可以使用许多可用的适配器之一来缓存元数据。

适配器

对于本地开发,

注意

For local development, the Phalcon\Mvc\Models\MetaData\Memory推荐使用适配器,以便对数据库的任何更改都可以立即反映出来。

适配器 描述
Phalcon\Mvc\Models\MetaData\Apcu 该适配器使用另选 PHP 缓存 (APC)存储表元数据。(生产环境)
Phalcon\Mvc\Models\MetaData\Libmemcached 该适配器使用Memcached 服务器存储表元数据。(生产环境)
Phalcon\Mvc\Models\MetaData\Memory 此适配器使用内存。元数据仅在请求期间缓存。(开发)
Phalcon\Mvc\Models\MetaData\Redis 此适配器使用Redis存储表元数据。(生产环境)
Phalcon\Mvc\Models\MetaData\Stream 此适配器使用普通文件存储元数据。(不适用于生产环境)

APCu

该适配器使用另选 PHP 缓存 (APC)存储表元数据。为了使该元数据缓存工作,您的系统中必须存在扩展。如果服务器重启,数据将丢失。此适配器适合生产应用程序。

适配器接收一个Phalcon\Cache\AdapterFactory类以实例化相关的缓存对象。你也可以传递一个包含缓存操作额外选项的数组。

默认前缀是ph-mm-apcu-生命周期是172,000(48小时)。

<?php

use Phalcon\Cache\AdapterFactory;
use Phalcon\Di\FactoryDefault;
use Phalcon\Mvc\Model\MetaData\Apcu;
use Phalcon\Storage\SerializerFactory;

$container = new FactoryDefault();
$container->set(
    'modelsMetadata',
    function () {
        $serializerFactory = new SerializerFactory();
        $adapterFactory    = new AdapterFactory($serializerFactory);
        $options = [
            'lifetime' => 86400,
            'prefix'   => 'my-prefix',
        ];

        return new Apcu($adapterFactory, $options);
    }
);

Libmemcached

该适配器使用Memcached 服务器来存储表元数据。你的系统中必须包含此扩展,元数据缓存才能正常工作。该适配器适用于生产环境应用。

适配器接收一个Phalcon\Cache\AdapterFactory类以实例化相关的缓存对象。你也可以传递一个包含缓存操作额外选项的数组。

默认前缀是ph-mm-memc-生命周期是172,000(48小时)。persistenId预设为php-mm-mcid-.

<?php

use Phalcon\Cache\AdapterFactory;
use Phalcon\Di\FactoryDefault;
use Phalcon\Mvc\Model\MetaData\Libmemcached;
use Phalcon\Storage\SerializerFactory;

$container = new FactoryDefault();
$container->set(
    'modelsMetadata',
    function () {
        $serializerFactory = new SerializerFactory();
        $adapterFactory    = new AdapterFactory($serializerFactory);
        $options = [
            'servers' => [
                0 => [
                    'host'   => '127.0.0.1',
                    'port'   => 11211,
                    'weight' => 1
                ],   
            ],
            'lifetime' => 86400,
            'prefix'   => 'my-prefix',
        ];

        return new Libmemcached($adapterFactory, $options);
    }
);

内存

此适配器使用服务器内存存储元数据缓存。缓存只在请求期间有效,之后缓存将丢失。此缓存更适合开发环境,因为它适应了开发期间数据库的频繁更改。

<?php

use Phalcon\Di\FactoryDefault;
use Phalcon\Mvc\Model\MetaData\Memory;

$container = new FactoryDefault();
$container->set(
    'modelsMetadata',
    function () {
        return new Memory();
    }
);

Redis

该适配器使用Redis来存储表元数据。你的系统中必须包含此扩展,元数据缓存才能正常工作。该适配器适用于生产环境应用。

适配器接收一个Phalcon\Cache\AdapterFactory类以实例化相关的缓存对象。你也可以传递一个包含缓存操作额外选项的数组。

默认前缀是ph-mm-reds-生命周期是172,000(48小时)。

<?php

use Phalcon\Cache\AdapterFactory;
use Phalcon\Di\FactoryDefault;
use Phalcon\Mvc\Model\MetaData\Redis;
use Phalcon\Storage\SerializerFactory;

$container = new FactoryDefault();
$container->set(
    'modelsMetadata',
    function () {
        $serializerFactory = new SerializerFactory();
        $adapterFactory    = new AdapterFactory($serializerFactory);
        $options = [
            'host'     => '127.0.0.1',
            'port'     => 6379,
            'index'    => 1,
            'lifetime' => 86400,
            'prefix'   => 'my-prefix',
        ];

        return new Redis($adapterFactory, $options);
    }
);

该适配器使用文件系统来存储表元数据。该适配器适用于生产环境应用,但不推荐使用,因为它会增加I/O负载。

适配器可以接受一个metaDadaDir选项,用于指定存放元数据的目录。默认目录为当前目录。

<?php

use Phalcon\Di\FactoryDefault;
use Phalcon\Mvc\Model\MetaData\Stream;

$container = new FactoryDefault();
$container->set(
    'modelsMetadata',
    function () {
        $options = [
            'metaDataDir' => '/app/storage/cache/metaData',
        ];

        return new Stream($options);
    }
);

您可以使用orm.exception_on_failed_metadata_save选项在你的php.ini文件中,用于强制组件在存储元数据出错或目标目录不可写时抛出异常。

orm.exception_on_failed_metadata_save = true

策略

获取模型元数据的默认策略是数据库内省(introspection)。使用该策略时,通过信息模式(information schema)来识别表中的字段、主键、可为空的字段、数据类型等。

<?php

use Phalcon\Cache\AdapterFactory;
use Phalcon\Di\FactoryDefault;
use Phalcon\Mvc\Model\MetaData\Apcu;
use Phalcon\Mvc\Model\MetaData\Strategy\Introspection;
use Phalcon\Storage\SerializerFactory;

$container = new FactoryDefault();
$container->set(
    'modelsMetadata',
    function () {
        $serializerFactory = new SerializerFactory();
        $adapterFactory    = new AdapterFactory($serializerFactory);
        $options = [
            'lifetime' => 86400,
            'prefix'   => 'my-prefix',
        ];

        $metadata = new Apcu($adapterFactory, $options);
        $metadata->setStrategy(new Introspection());

        return $metadata;
    }
);

内省

该策略不需要任何自定义,并且被所有元数据适配器隐式使用。

注解

该策略使用注解来描述模型中的列。

<?php

use Phalcon\Mvc\Model;

class Invoices extends Model
{
    /**
     * @Primary
     * @Identity
     * @Column(type='integer', nullable=false)
     */
    public $inv_id;

    /**
     * @Column(type='integer', nullable=false)
     */
    public $inv_cst_id;

    /**
     * @Column(type='string', length=70, nullable=false)
     */
    public $inv_title;

    /**
     * @Column(type='double', nullable=false)
     */
    public $inv_total;
}

注解必须放置在映射到源表列的属性上。没有@Column注解的属性将被视为普通的类属性。

支持以下注解:

名称 描述
@Primary 将字段标记为表主键的一部分
@Identity 该字段是自增(auto_increment)或序列(serial)列
@Column 将属性标记为映射列

注解@Column支持以下参数:

名称 描述
column 实际列名
type 列的类型:char, biginteger, blob, boolean, date, datetime, decimal, integer, float, json, longblob, mediumblob, timestamp, tinyblob, text, varchar/string(默认)
length 列的长度(如存在)
nullable 设置列是否允许null
skip_on_insert 在插入时跳过此列
skip_on_update 在更新时跳过此列
allow_empty_string 列允许空字符串
default 默认值

注解策略可以如下设置:

<?php

use Phalcon\Cache\AdapterFactory;
use Phalcon\Di\FactoryDefault;
use Phalcon\Mvc\Model\MetaData\Apcu;
use Phalcon\Mvc\Model\MetaData\Strategy\Annotations;
use Phalcon\Storage\SerializerFactory;

$container = new FactoryDefault();
$container->set(
    'modelsMetadata',
    function () {
        $serializerFactory = new SerializerFactory();
        $adapterFactory    = new AdapterFactory($serializerFactory);
        $options = [
            'lifetime' => 86400,
            'prefix'   => 'my-prefix',
        ];

        $metadata = new Apcu($adapterFactory, $options);
        $metadata->setStrategy(new Annotations());

        return $metadata;
    }
);

手动

使用上述介绍的内省策略,Phalcon 可以为每个模型自动获取元数据。但是,你可以选择手动定义元数据。该策略会覆盖元数据管理器中设置的任何其他策略。映射表中添加、修改或删除的列必须在模型中手动更新,一切才能正常运行。

要设置元数据,我们在模型中使用metaData方法:

<?php

use Phalcon\Mvc\Model;
use Phalcon\Db\Column;
use Phalcon\Mvc\Model\MetaData;

class Invoices extends Model
{
    public function metaData()
    {
        return array(
            MetaData::MODELS_ATTRIBUTES => [
                'inv_id',
                'inv_cst_id',
                'inv_status_flag',
                'inv_title',
                'inv_total',
                'inv_created_at',
                'inv_created_by',
                'inv_updated_at',
                'inv_updated_by',
            ],

            MetaData::MODELS_PRIMARY_KEY => [
                'inv_id',
            ],

            MetaData::MODELS_NON_PRIMARY_KEY => [
                'inv_cst_id',
                'inv_status_flag',
                'inv_title',
                'inv_total',
                'inv_created_at',
                'inv_created_by',
                'inv_updated_at',
                'inv_updated_by',
            ],

            MetaData::MODELS_NOT_NULL => [
                'inv_id',
                'inv_cst_id',
                'inv_status_flag',
                'inv_title',
                'inv_total',
                'inv_created_at',
                'inv_created_by',
                'inv_updated_at',
                'inv_updated_by',

            MetaData::MODELS_DATA_TYPES => [
                'inv_id'          => Column::TYPE_INTEGER,
                'inv_cst_id'      => Column::TYPE_INTEGER,
                'inv_status_flag' => Column::TYPE_INTEGER,
                'inv_title'       => Column::TYPE_VARCHAR,
                'inv_total'       => Column::TYPE_FLOAT,
                'inv_created_at'  => Column::TYPE_DATETIME,
                'inv_created_by'  => Column::TYPE_INTEGER,
                'inv_updated_at'  => Column::TYPE_DATETIME,
                'inv_updated_by'  => Column::TYPE_INTEGER,
            ],

            MetaData::MODELS_DATA_TYPES_NUMERIC => [
                'inv_id'          => true,
                'inv_cst_id'      => true,
                'inv_status_flag' => true,
                'inv_total'       => true,
                'inv_created_by'  => true,
                'inv_updated_by'  => true,
            ],

            MetaData::MODELS_IDENTITY_COLUMN => 'inv_id',

            MetaData::MODELS_DATA_TYPES_BIND => [
                'inv_id'          => Column::BIND_PARAM_INT,
                'inv_cst_id'      => Column::BIND_PARAM_INT,
                'inv_status_flag' => Column::BIND_PARAM_INT,
                'inv_title'       => Column::BIND_PARAM_INT,
                'inv_total'       => Column::BIND_PARAM_DECIMAL,
                'inv_created_at'  => Column::BIND_PARAM_STR,
                'inv_created_by'  => Column::BIND_PARAM_INT,
                'inv_updated_at'  => Column::BIND_PARAM_STR,
                'inv_updated_by'  => Column::BIND_PARAM_INT,
            ],

            MetaData::MODELS_AUTOMATIC_DEFAULT_INSERT => [
                'inv_created_at' => true,
                'inv_created_by' => true,
                'inv_updated_at' => true,
                'inv_updated_by' => true,
            ],

            MetaData::MODELS_AUTOMATIC_DEFAULT_UPDATE => [
                'inv_created_at' => true,
                'inv_created_by' => true,
                'inv_updated_at' => true,
                'inv_updated_by' => true,
            ],

            MetaData::MODELS_DEFAULT_VALUES => [
                'inv_status_flag' => 0,
            ],

            MetaData::MODELS_EMPTY_STRING_VALUES => [
                'inv_created_at' => true,
                'inv_updated_at' => true,
            ],
        );
    }
}

自定义

Phalcon 提供了Phalcon\Mvc\Model\MetaData\Strategy\StrategyInterface接口,允许你创建自己的策略类。

<?php

namespace MyApp\Components\Strategy;

use Phalcon\Mvc\ModelInterface;
use Phalcon\Di\DiInterface;

class MyStrategy StrategyInterface
{
    public function getColumnMaps(
        ModelInterface $model, 
        DiInterface $container
    ): array;

    public function getMetaData(
        ModelInterface $model, 
        DiInterface $container
    ): array;
}
无噪 Logo
无噪文档
25 年 6 月翻译
版本号 5.9
文档源↗