模型元数据¶
概览¶
当使用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 |  反向列映射(别名) | 
方法¶
返回表属性名(字段) 返回必须忽略的属性INSERTSQL 生成  返回必须忽略的属性UPDATESQL 生成  返回属性及其绑定数据类型   如果有的话返回列映射
返回具有默认值的属性及其默认值 返回属性及其数据类型 返回类型为数值的属性 返回允许空字符串的属性 如果存在,则返回标识字段的名称 返回不属于主键的字段数组 返回非空属性的数组 返回属于主键的字段数组 如果有的话返回反向列映射 返回获取元数据的策略 检查模型是否具有某个属性 检查内部元数据容器是否为空从适配器读取元数据
读取特定模型的有序/反向列映射 使用MODEL_*常量读取特定模型的列映射信息  读取特定模型的完整元数据  读取特定模型的元数据  重置内部元数据以便重新生成它  设置必须从 INSERT SQL 生成中忽略的属性  设置必须从 UPDATE SQL 生成中忽略的属性  设置允许空字符串值的属性  设置元数据提取策略 将元数据写入适配器 使用 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文件中,用于强制组件在存储元数据出错或目标目录不可写时抛出异常。
策略¶
获取模型元数据的默认策略是数据库内省(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;
}