
Resumen
When using Phalcon\Mvc\Model classes, which correspond to actual tables in the database, Phalcon needs to know essential information regarding those tables, such as fields, data types, primary and foreign keys as well as relationships. The Phalcon\Mvc\Model\MetaData object is offering this functionality, transparently querying the database and generating the necessary data from the database schema. Los datos se pueden almacenar en un almacén de datos (tipo Redis, APCu, etc.) para asegurar que la base de datos no se consulta por el esquema cada vez que se ejecuta una consulta.
NOTE: During deployments to production, please ensure that you always invalidate the metaData cache so that database changes that propagated during your deployment are available in your application. El caché metaData se reconstruirá con todos los cambios necesarios.
<?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);
El código anterior imprimirá los nombres de los campos y también los campos al vector de tipos de campo. Usamos attributes
como un alias de 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,
]
Constantes
Phalcon\Mvc\Model\MetaData exposes a number of constants that can be used to retrieve attributes from the internal collection.
Nombre |
Descripción |
MODELS_ATTRIBUTES |
Cada columna en la tabla mapeada |
MODELS_AUTOMATIC_DEFAULT_INSERT |
Campos que se deben ignorar de las sentencias SQL INSERT |
MODELS_AUTOMATIC_DEFAULT_UPDATE |
Campos que se deben ignorar de las sentencias SQL UPDATE |
MODELS_COLUMN_MAP |
Mapa de columna (alias) |
MODELS_DATA_TYPES |
Cada columna y su tipo de datos |
MODELS_DATA_TYPES_BIND |
Como se debe vincular/convertir cada columna |
MODELS_DATA_TYPES_NUMERIC |
Las columnas que tienen tipos de datos numéricos |
MODELS_DEFAULT_VALUES |
Valores por defecto para las columnas |
MODELS_EMPTY_STRING_VALUES |
Columnas que permiten cadenas vacías |
MODELS_IDENTITY_COLUMN |
La columna identidad. false si el modelo no tiene ninguna columna identidad |
MODELS_NON_PRIMARY_KEY |
Cada columna que no sea parte de la clave primaria |
MODELS_NOT_NULL |
Cada columna que no permita valores null |
MODELS_PRIMARY_KEY |
Cada columna que sea parte de la clave primaria |
MODELS_REVERSE_COLUMN_MAP |
Mapa de columna inverso (alias) |
Métodos
public function getAttributes(ModelInterface $model): array
Devuelve los nombres de los atributos de la tabla (campos)
print_r(
$metaData->getAttributes(
new Invoices()
)
);
public function getAutomaticCreateAttributes(
ModelInterface $model
): array
Return attributes that must be ignored from the INSERT
SQL generation
print_r(
$metaData->getAutomaticCreateAttributes(
new Invoices()
)
);
public function getAutomaticUpdateAttributes(
ModelInterface $model
): array
Return attributes that must be ignored from the UPDATE
SQL generation
print_r(
$metaData->getAutomaticUpdateAttributes(
new Invoices()
)
);
public function getBindTypes(ModelInterface $model): array
Return attributes and their bind data types
print_r(
$metaData->getBindTypes(
new Invoices()
)
);
public function getColumnMap(ModelInterface $model): array
Devuelve el mapa de columnas si lo hay
print_r(
$metaData->getColumnMap(
new Invoices()
)
);
public function getDefaultValues(ModelInterface $model): array
Return attributes (which have default values) and their default values
print_r(
$metaData->getDefaultValues(
new Invoices()
)
);
public function getDataTypes(ModelInterface $model): array
Return attributes and their data types
print_r(
$metaData->getDataTypes(
new Invoices()
)
);
public function getDataTypesNumeric(ModelInterface $model): array
Return attributes which types are numerical
print_r(
$metaData->getDataTypesNumeric(
new Invoices()
)
);
public function getEmptyStringAttributes(
ModelInterface $model
): array
Return attributes allow empty strings
print_r(
$metaData->getEmptyStringAttributes(
new Invoices()
)
);
public function getIdentityField(ModelInterface $model): string
Devuelve el nombre del campo identidad (si hay uno presente)
print_r(
$metaData->getIdentityField(
new Invoices()
)
);
public function getNonPrimaryKeyAttributes(
ModelInterface $model
): array
Devuelve un vector de campos que no forman parte de la clave primaria
print_r(
$metaData->getNonPrimaryKeyAttributes(
new Invoices()
)
);
public function getNotNullAttributes(ModelInterface $model): array
Devuelve un vector de atributos no nulos
print_r(
$metaData->getNotNullAttributes(
new Invoices()
)
);
public function getPrimaryKeyAttributes(
ModelInterface $model
): array
Devuelve un vector de campos que forman parte de la clave primaria
print_r(
$metaData->getPrimaryKeyAttributes(
new Invoices()
)
);
public function getReverseColumnMap(
ModelInterface $model
): array
Devuelve el mapa de columnas inverso si existe
print_r(
$metaData->getReverseColumnMap(
new Invoices()
)
);
public function getStrategy(): StrategyInterface
Devuelve la estrategia para obtener los metadatos
public function hasAttribute(
ModelInterface $model,
string $attribute
): bool
Comprueba si un modelo tiene cierto atributo
print_r(
$metaData->hasAttribute(
new Invoices(),
"inv_title"
)
);
public function isEmpty(): bool
Comprueba si el contenedor de metadatos interno está vacío
print_r(
$metaData->isEmpty()
);
public function read(string $key): array | null
Lee los metadatos del adaptador
final public function readColumnMap(
ModelInterface $model
): array | null
Lee el mapa de columnas ordenado/inverso para cierto modelo
print_r(
$metaData->readColumnMap(
new Invoices()
)
);
final public function readColumnMapIndex(
ModelInterface $model,
int $index
)
Lee información del mapa de columnas para cierto modelo usando la constante MODEL_*
print_r(
$metaData->readColumnMapIndex(
new Invoices(),
MetaData::MODELS_REVERSE_COLUMN_MAP
)
);
final public function readMetaData(ModelInterface $model): array
Lee los metadatos completos para cierto modelo
print_r(
$metaData->readMetaData(
new Invoices()
)
);
final public function readMetaDataIndex(
ModelInterface $model,
int $index
)
Lee los metadatos para cierto modelo
print_r(
$metaData->readMetaDataIndex(
new Invoices(),
0
)
);
public function reset(): void
Resetea los metadatos internos para regenerarlos
public function setAutomaticCreateAttributes(
ModelInterface $model,
array $attributes
): void
Establece los atributos que se deben ignorar en la generación SQL del INSERT
$metaData->setAutomaticCreateAttributes(
new Invoices(),
[
"inv_created_at" => true,
]
);
public function setAutomaticUpdateAttributes(
ModelInterface $model,
array $attributes
): void
Establece los atributos que se deben ignorar en la generación SQL del UPDATE
$metaData->setAutomaticUpdateAttributes(
new Invoices(),
[
"inv_updated_at" => true,
]
);
public function setEmptyStringAttributes(
ModelInterface $model,
array $attributes
): void
Establece los atributos que permiten valores de cadena vacía
$metaData->setEmptyStringAttributes(
new Invoices(),
[
"inv_title" => true,
]
);
public function setStrategy(StrategyInterface $strategy): void
Establece la estrategia de extracción de metadatos
public function write(string $key, array $data): void
Escribe los metadatos al adaptador
final public function writeMetaDataIndex(
ModelInterface $model,
int $index,
mixed $data
): void
Escribe metadatos para cierto modelo usando una constante 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
)
Inicializa los metadatos para cierta tabla
Adaptadores
Retrieving the metadata is an expensive database operation, and we certainly do not want to perform it every time we run a query. Sin embargo, podemos usar uno de los muchos adaptadores disponibles para almacenar en caché los metadatos.
NOTE: For local development, the Phalcon\Mvc\Models\MetaData\Memory adapter is recommended so that any changes to the database can be reflected immediately.
APCu
This adapter uses the Alternative PHP Cache (APC) to store the table metadata. La extensión debe estar presente en su sistema para que funcione este caché de metadatos. Si el servidor se reinicia, los datos se perderán. Este adaptador es apropiado para aplicaciones en producción.
The adapter receives a Phalcon\Cache\AdapterFactory class in order to instantiate the relevant cache object. También puede pasar un vector con opciones adicionales para que el caché opere.
El prefijo predeterminado es ph-mm-apcu-
y el tiempo de vida es 172.000
(48 horas).
<?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
This adapter uses the Memcached Server to store the table metadata. La extensión debe estar presente en su sistema para que funcione este caché de metadatos. Este adaptador es apropiado para aplicaciones en producción.
The adapter receives a Phalcon\Cache\AdapterFactory class in order to instantiate the relevant cache object. También puede pasar un vector con opciones adicionales para que el caché opere.
El prefijo predeterminado es ph-mm-memc-
y el tiempo de vida es 172.000
(48 horas). persistenId
está preconfigurado a 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);
}
);
Memory
Este adaptador usa la memoria del servidor para almacenar el caché de metadatos. El cache está disponible sólo durante la petición, y después el caché se pierde. Este caché es más apropiado para desarrollo, ya que se adapta a los cambios frecuentes en la base de datos durante el desarrollo.
<?php
use Phalcon\Di\FactoryDefault;
use Phalcon\Mvc\Model\MetaData\Memory;
$container = new FactoryDefault();
$container->set(
'modelsMetadata',
function () {
return new Memory();
}
);
Redis
This adapter uses the Redis to store the table metadata. La extensión debe estar presente en su sistema para que funcione este caché de metadatos. Este adaptador es apropiado para aplicaciones en producción.
The adapter receives a Phalcon\Cache\AdapterFactory class in order to instantiate the relevant cache object. También puede pasar un vector con opciones adicionales para que el caché opere.
El prefijo predeterminado es ph-mm-reds-
y el tiempo de vida es 172.000
(48 horas).
<?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);
}
);
Flujo (Stream)
Este adaptador usa el sistema de ficheros para almacenar los metadatos de la tabla. Este adaptador es apropiado para aplicaciones de producción pero no es recomendable ya que introduce un aumento de E/S.
El adaptador puede aceptar una opción metaDataDir
con un directorio donde almacenar los metadatos. El directorio por defecto es el directorio actual.
<?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);
}
);
Puede usar la opción orm.exception_on_failed_metadata_save
en su fichero php.ini
para forzar que el componente lance una excepción si hay algún error almacenando los metadatos o si el directorio destino no es escribible.
orm.exception_on_failed_metadata_save = true
Estrategias
La estrategia por defecto para obtener los metadatos del modelo es la introspección de la base de datos. Utilizando esta estrategia, el esquema de información se usa para identificar los campos de una tabla, su clave primaria, campos nulos, tipos de datos, etc.
<?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;
}
);
Introspección
Esta estrategia no necesita ninguna personalización y se usa implícitamente por todos los adaptadores de metadatos.
Anotaciones
Esta estrategia hace uso de anotaciones para describir las columnas de un modelo.
<?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;
}
Las anotaciones deben colocarse en propiedades que se asignan a columnas en la fuente mapeada. Las propiedades sin la anotación @Column
se gestionan como atributos de clase simples.
Se soportan las siguientes anotaciones:
Nombre |
Descripción |
@Primary |
Marca el campo como parte de la clave primaria de la tabla |
@Identity |
El campo es una columna auto_increment/serial |
@Column |
Esto marca un atributo como una columna mapeada |
La anotación @Column
soporta los siguientes parámetros:
Nombre |
Descripción |
column |
Nombre de la columna real |
type |
El tipo de la columna: char , biginteger , blob , boolean , date , datetime , decimal , integer , float , json , longblob , mediumblob , timestamp , tinyblob , text , varchar /string (predeterminado) |
length |
El tamaño de la columna si hay |
nullable |
Establece si la columna acepta valores null o no |
skip_on_insert |
Omite esta columna al insertar |
skip_on_update |
Omite esta columna al actualizar |
allow_empty_string |
La columna permite cadenas vacías |
default |
Valor por defecto |
La estrategia de anotaciones se podría configurar de la siguiente manera:
<?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;
}
);
Manual
Usando las estrategias de introspección presentadas anteriormente, Phalcon puede obtener los metadatos de cada modelo automáticamente. Sin embargo, tiene la opción de definir los metadatos manualmente. Esta estrategia anula cualquier estrategia que se haya configurado en el gestor de metadatos. Las columnas añadidas, modificadas o eliminadas de la tabla mapeada se deben actualizar manualmente en el modelo para que todo funcione correctamente.
Para configurar los metadatos, usamos el método metaData
en un modelo:
<?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,
],
);
}
}
Personalizado
Phalcon offers the Phalcon\Mvc\Model\MetaData\Strategy\StrategyInterface interface, allowing you to create your own Strategy class.
<?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;
}