Relaciones de modelos

Resumen
La normalización de base de datos es un proceso donde los datos se dividen en diferentes tablas y se crean enlaces entre esas tablas, para incrementar la flexibilidad, reducir la redundancia de datos y mejorar la integridad de los datos. Las relaciones se definen en el método initialize
de cada modelo.
The following types of relationships are available:
hasOne(
string|array $fields,
string $referenceModel,
string|array $referencedFields,
array $options = null
)
hasOneThrough(
string|array $fields,
string $intermediateModel,
string|array $intermediateFields,
string|array $intermediateReferencedFields,
string $referenceModel,
string|array $referencedFields,
array $options = null
)
hasMany(
string|array $fields,
string $referenceModel,
string|array $referencedFields,
array options = null
)
belongsTo(
string|array $fields,
string $referenceModel,
string|array $referencedFields,
array options = null
)
hasManyToMany(
string|array $fields,
string $intermediateModel,
string|array $intermediateFields,
string|array $intermediateReferencedFields,
string $referenceModel,
string|array $referencedFields,
array $options = null
)
Relationships can be unidirectional or bidirectional, and each can be simple (a one-to-one model) or more complex (a combination of models). El gestor de modelos gestiona restricciones de clave ajena para estas relaciones, la definición de estas ayuda a la integridad referencial así como al acceso fácil y rápido de registros relacionados al modelo. A través de la implementación de relaciones, es fácil acceder a datos en modelos relacionados desde el modelo fuente de una forma fácil y uniforme.
<?php
namespace MyApp\Models;
use Phalcon\Mvc\Model;
class Invoices extends Model
{
public function initialize()
{
$this->hasOne(
'inv_cst_id',
Customers::class,
'cst_id',
[
'alias' => 'customers',
'reusable' => true,
]
);
}
}
Unidireccional
Las relaciones unidireccionales son aquellas que son generadas en relación de uno con otro, pero no viceversa.
Bidireccional
Las relaciones bidireccionales construyen relaciones en ambos modelos y cada modelo define la relación inversa del otro.
Configuración
En Phalcon, las relaciones se deben definir en el método initialize()
de un modelo. Los métodos belongsTo()
, hasMany()
, hasManyToMany()
, hasOne()
y hasOneThrough()
, definen la relación entre uno o más campos del modelo actual con los campos de otro modelo. Cada uno de estos métodos requiere 3 parámetros:
- campos locales
- modelo referenciado
- campos referenciados
Método |
Descripción |
belongsTo |
Define una relación n-1 |
hasMany |
Define una relación 1-n |
hasManyToMany |
Define una relación n-n |
hasOne |
Define una relación 1-1 |
hasOneThrough |
Define una relación 1-1 |
El siguiente esquema muestra 3 tablas cuyas relaciones nos servirán como ejemplo en cuanto a relaciones:
create table co_invoices
(
inv_id int(10) auto_increment primary key,
inv_cst_id int(10) null,
inv_status_flag tinyint(1) null,
inv_title varchar(100) null,
inv_total float(10, 2) null,
inv_created_at datetime null
);
create table co_invoices_x_products
(
ixp_inv_id int(10),
inv_prd_id int(10)
);
create table co_products
(
prd_id int(10) auto_increment primary key,
prd_title varchar(100) null,
prd_price float(10, 2) null
);
- El modelo
Invoices
tiene muchos InvoicesProducts
.
- El modelo
Products
tiene muchos InvoicesProducts
.
- El modelo
InvoicesProducts
pertenece a ambos modelos Invoices
y Products
como una relación muchos-a-uno.
- El modelo
Invoices
tiene una relación muchos-a-muchos con Products
a través de InvoicesProducts
.

El modelo con sus relaciones se puede implementar como sigue:
<?php
namespace MyApp\Models;
use Phalcon\Mvc\Model;
class Invoices extends Model
{
public $inv_id;
public $inv_cst_id;
public $inv_status_flag;
public $inv_title;
public $inv_total;
public $inv_created_at;
public function initialize()
{
$this->hasManyToMany(
'inv_id',
InvoicesProducts::class,
'ixp_inv_id',
'ixp_prd_id',
Products::class,
'prd_id',
[
'reusable' => true,
'alias' => 'products',
]
);
$this->hasMany(
'inv_id',
InvoicesProducts::class,
'ixp_inv_id',
[
'reusable' => true,
'alias' => 'invoicesProducts'
]
);
}
}
<?php
namespace MyApp\Models;
use Phalcon\Mvc\Model;
class InvoicesProducts extends Model
{
public $ixp_inv_id;
public $ixp_prd_id;
public function initialize()
{
$this->belongsTo(
'ixp_inv_id',
Invoices::class,
'inv_id',
[
'reusable' => true,
'alias' => 'invoice'
]
);
$this->belongsTo(
'ixp_prd_id',
Products::class,
'prd_id',
[
'reusable' => true,
'alias' => 'product'
]
);
}
}
<?php
namespace MyApp\Models;
use Phalcon\Mvc\Model;
class Products extends Model
{
public $prd_id;
public $prd_title;
public $prd_price;
public $prd_created_at;
public function initialize()
{
$this->hasMany(
'prd_id',
InvoicesProducts::class,
'ixp_prd_id'
);
// Many to many -> Invoices
$this->hasManyToMany(
'prd_id',
InvoicesProducts::class,
'ixp_prd_id',
'ixp_inv_id',
Invoices::class,
'inv_id',
[
'reusable' => true,
'alias' => 'invoices',
]
);
}
}
El primer parámetro indica el campo del modelo local usado en la relación; el segundo indica el nombre del modelo referenciado, y el tercero el nombre del campo en el modelo referenciado. También podría usar vectores para definir múltiples campos en la relación.
Many-to-many relationships require 3 models and define the attributes involved in the relationship:
<?php
namespace MyApp\Models;
use Phalcon\Mvc\Model;
class Invoices extends Model
{
public $inv_id;
public $inv_cst_id;
public $inv_status_flag;
public $inv_title;
public $inv_total;
public $inv_created_at;
public function initialize()
{
$this->hasManyToMany(
'inv_id',
InvoicesProducts::class,
'ixp_inv_id',
'ixp_prd_id',
Products::class,
'prd_id',
[
'reusable' => true,
'alias' => 'products',
]
);
}
}
Parámetros
Dependiendo de las necesidades de nuestra aplicación podríamos querer almacenar datos en una tabla, que describa distintos comportamientos. For instance, you might want to only have a table called co_customers
which has a field cst_status_flag
describing the status of the customer (e.g. active, inactive, etc.).
Usando las relaciones, puede obtener únicamente aquellos Customers
relacionados con nuestras Invoices
que tienen un cst_status_flag
determinado. Definir esa restricción en la relación le permite dejar que el modelo haga todo el trabajo.
También acepta una clausura, que es evaluada cada vez antes de acceder a registros relacionados. Esto permite que las condiciones se actualicen automáticamente entre las consultas.
<?php
namespace MyApp\Models;
use Phalcon\Mvc\Model;
class Invoices extends Model
{
public $inv_id;
public $inv_cst_id;
public $inv_status_flag;
public $inv_title;
public $inv_total;
public $inv_created_at;
public function initialize()
{
$this->hasMany(
'inv_cst_id',
Customers::class,
'cst_id',
[
'reusable' => true,
'alias' => 'customersActive',
'params' => [
'conditions' => 'cst_status_flag = :status:',
'bind' => [
'status' => 1,
]
]
]
);
$container = $this->getDI();
$this->hasMany(
'inv_cst_id',
Customers::class,
'cst_id',
[
'reusable' => true,
'alias' => 'customersNearby',
'params' => function() use ($container) {
return [
'conditions' => 'cst_location = :location:',
'bind' => [
'location' => $container->getShared('myLocationService')->myLocation,
]
];
}
]
);
}
}
Múltiples Campos
Hay veces, donde las relaciones necesitan ser definidas sobre una combinación de campos y no solo uno. Considere el ejemplo siguiente:
<?php
namespace MyApp\Models;
use Phalcon\Mvc\Model;
class Products extends Model
{
public $prd_id;
public $prd_type_flag;
public $prd_name;
}
and
<?php
namespace MyApp\Models;
use Phalcon\Mvc\Model;
class Parts extends Model
{
public $par_id;
public $par_prd_id;
public $par_par_id;
public $par_type_flag;
public $par_name;
}
Arriba tenemos un modelo Products
que tiene los campos prd_id
, prd_type_flag
y prd_name
. El modelo Parts
contiene par_id
, par_prd_id
, par_type_flag
y par_name
. La relación existe basada sobre el id único de producto así como sobre el tipo.
Usando las opciones de relación, vistas anteriormente, vinculando un campo entre los dos modelos no devolverá los resultados que necesitamos. Podemos usar un vector con los campos necesarios para definir la relación.
<?php
namespace MyApp\Models;
use Phalcon\Mvc\Model;
class Products extends Model
{
public $prd_id;
public $prd_type_flag;
public $prd_name;
public function initialize()
{
$this->hasOne(
[
'prd_id',
'prd_type_flag'
],
Parts::class,
[
'par_prd_id',
'par_type_flag'
],
[
'reusable' => true, // cache
'alias' => 'parts',
]
);
}
}
NOTE The field mappings in the relationship are one for one i.e. the first field of the source model array matches the first field of the target array etc. El número de campos debe ser idéntico en ambos modelos fuente y destino.
Acceso
Hay varias formas de acceder a las relaciones de un modelo.
- Métodos mágicos
__get
, __set
- Métodos mágicos
get*
getRelated
__get()
Podemos usar el método mágico para acceder a la relación. Asignar un alias
a la relación simplifica el acceso a los datos relacionados. El nombre de la propiedad es el mismo que el definido en el alias
.
<?php
$customer = Customers::findFirst(
[
'conditions' => 'cst_id = :customerId:',
'bind' => [
'customerId' => 1,
],
]
);
foreach ($customer->invoices as $invoice) {
echo $invoice->inv_title;
}
or for a many-to-many relationship (see models above):
<?php
$invoice = Invoices::findFirst(
[
'conditions' => 'inv_cst_id = :customerId:',
'bind' => [
'customerId' => 1,
],
]
);
foreach ($invoice->invoicesProducts as $product) {
echo $invoice->product->prd_name;
}
foreach ($invoice->products as $product) {
echo $invoice->prd_name;
}
Usar el método mágico __get
le permite acceder a la relación directamente pero no ofrece funcionalidad adicional como filtrado u ordenación sobre la relación.
get*()
You can access the same relationship by using a getter method, starting with get and using the name of the relationship.
<?php
$customer = Customers::findFirst(
[
'conditions' => 'cst_id = :customerId:',
'bind' => [
'customerId' => 1,
],
]
);
foreach ($customer->getInvoices() as $invoice) {
echo $invoice->inv_title;
}
or for a many-to-many relationship (see models above):
<?php
$invoice = Invoices::findFirst(
[
'conditions' => 'inv_cst_id = :customerId:',
'bind' => [
'customerId' => 1,
],
]
);
foreach ($invoice->getInvoiceProducts() as $product) {
echo $invoice->product->prd_name;
}
foreach ($invoice->getProducts() as $product) {
echo $invoice->prd_name;
}
Este getter mágico también nos permite ejecutar ciertas operaciones cuando se accede a la relación como ordenar la relación:
<?php
$invoice = Invoices::findFirst(
[
'conditions' => 'inv_cst_id = :customerId:',
'bind' => [
'customerId' => 1,
],
]
);
$products = $invoice->getProducts(
[
'order' => 'prd_name',
]
);
foreach ($products as $product) {
echo $invoice->prd_name;
}
También puede añadir condicionales adicionales en la relación:
<?php
$invoice = Invoices::findFirst(
[
'conditions' => 'inv_cst_id = :customerId:',
'bind' => [
'customerId' => 1,
],
]
);
$products = $invoice->getProducts(
[
'prd_created_at = :date:',
'bind' => [
'date' => '2019-12-25',
],
]
);
foreach ($products as $product) {
echo $invoice->prd_name;
}
Para obtener los mismos registros manualmente:
<?php
$invoice = Invoices::findFirst(
[
'conditions' => 'inv_cst_id = :customerId:',
'bind' => [
'customerId' => 1,
],
]
);
$invoicesProducts = InvoicesProducts::find(
[
'conditions' => 'ixp_inv_id = :invoiceId:',
'bind' => [
'invoiceId' => $invoice->inv_id,
],
]
);
$productIds = [];
foreach ($invoicesProducts as $intermediate) {
$productIds[] = $intermediate->ixp_prd_id;
}
$products = Products::find(
[
'conditions' => 'prd_id IN ({array:productIds})',
'bind' => [
'productIds' => $productIds,,
],
]
);
foreach ($products as $product) {
echo $invoice->prd_name;
}
El prefijo get
se usa para los registros relacionados de find()
/findFirst()
.
Tipo |
Método Implícito |
Devuelve |
Belongs-To |
findFirst |
Instancia de modelo del registro relacionado directamente |
Has-One |
findFirst |
Instancia de modelo del registro relacionado directamente |
Has-One-Through |
findFirst |
Instancia de modelo del registro relacionado directamente |
Has-Many |
find |
Colección de instancias de modelo del modelo referenciado |
Has-Many-to-Many |
(consulta compleja) |
Colección de instancias de modelo del modelo referenciado (inner join ) |
También puede usar el prefijo count
para devolver un entero que denota el recuento de registros relacionados:
<?php
$invoice = Invoices::findFirst(
[
'conditions' => 'inv_cst_id = :customerId:',
'bind' => [
'customerId' => 1,
],
]
);
echo $invoice->countProducts();
Puede acceder a la misma relación usando getRelated()
y definir qué relación quiere obtener.
<?php
$customer = Customers::findFirst(
[
'conditions' => 'cst_id = :customerId:',
'bind' => [
'customerId' => 1,
],
]
);
foreach ($customer->getRelated('invoices') as $invoice) {
echo $invoice->inv_title;
}
or for a many-to-many relationship (see models above):
<?php
$invoice = Invoices::findFirst(
[
'conditions' => 'inv_cst_id = :customerId:',
'bind' => [
'customerId' => 1,
],
]
);
foreach ($invoice->getRelated('products') as $product) {
echo $invoice->prd_name;
}
El segundo parámetro de getRelated()
es un vector que ofrece opciones adicionales a configurar, como filtrar u ordenar.
<?php
$invoice = Invoices::findFirst(
[
'conditions' => 'inv_cst_id = :customerId:',
'bind' => [
'customerId' => 1,
],
]
);
$products = $invoice->getRelated(
'products',
[
'prd_created_at = :date:',
'bind' => [
'date' => '2019-12-25',
],
]
);
foreach ($products as $product) {
echo $invoice->prd_name;
}
Alias
Acceder a una relación se puede conseguir usando el nombre de la tabla remota. Debido a la convención de nombres, esto podría no ser tan fácil y podría prestar a confusión. Como se ha visto anteriormente, puede definir un alias
a la relación.
<?php
namespace MyApp\Models;
use Phalcon\Mvc\Model;
class Invoices extends Model
{
public $inv_id;
public $inv_cst_id;
public $inv_status_flag;
public $inv_title;
public $inv_total;
public $inv_created_at;
public function initialize()
{
$this->hasManyToMany(
'inv_id',
InvoicesProducts::class,
'ixp_inv_id',
'ixp_prd_id',
Products::class,
'prd_id'
);
}
}
Con un alias:
<?php
namespace MyApp\Models;
use Phalcon\Mvc\Model;
class Invoices extends Model
{
public $inv_id;
public $inv_cst_id;
public $inv_status_flag;
public $inv_title;
public $inv_total;
public $inv_created_at;
public function initialize()
{
$this->hasManyToMany(
'inv_id',
InvoicesProducts::class,
'ixp_inv_id',
'ixp_prd_id',
Products::class,
'prd_id',
[
'reusable' => true,
'alias' => 'products',
]
);
}
}
Si su estructura de tablas tiene self joins, no puede acceder a esas relaciones sin alias porque usa el mismo modelo.
<?php
namespace MyApp\Models;
use Phalcon\Mvc\Model;
class Parts extends Model
{
public $par_id;
public $par_prd_id;
public $par_par_id;
public $par_type_flag;
public $par_name;
public function initialize()
{
$this->hasMany(
'par_id',
Invoices::class,
'par_par_id',
[
'reusable' => true,
'alias' => 'children',
]
);
$this->belongsTo(
'par_par_id',
Invoices::class,
'par_id',
[
'reusable' => true,
'alias' => 'parent',
]
);
}
}
En el ejemplo anterior, tenemos Part
que tiene una relación con uno o más objetos Part
. Cada Part
puede consistir de otras partes que lo componen. Como resultado terminamos con una relación self join. Para un Part
de teléfono tenemos los siguientes hijos:
<?php
$phone = Parts::findFirst(....);
echo $phone->getChildren();
// --- Cover
// --- Battery
// --- Charger
y cada una de esas partes tiene al teléfono como padre:
<?php
$charger = Parts::findFirst(....);
echo $phone->getParent();
// Phone
Caché
Acceder a datos relacionados puede suponer un incremento del número de consultas en su base de datos. Puede reducir esta carga tanto como sea posible, usando la opción reusable
en su relación. Estableciendo esta opción a true
indicará a Phalcon que almacene en caché los resultados de la relación la primera vez que se accede, para que las siguientes llamadas a la misma relación puedan usar el conjunto de resultados cacheado y no solicite los datos de nuevo a la base de datos. Este caché está activo durante la misma petición.
NOTE: You are encouraged to use the reusable
option as often as possible in your relationships
<?php
namespace MyApp\Models;
use Phalcon\Mvc\Model;
class Invoices extends Model
{
public function initialize()
{
$this->hasOne(
'inv_cst_id',
Customers::class,
'cst_id',
[
'alias' => 'customers',
'reusable' => true,
]
);
}
}
Autocompletado
La mayoría de IDEs y editores con capacidades de autocompletado puede que no detecten los tipos correctos cuando se usan getters mágicos (tanto métodos como propiedades). Para abordar este problema, podemos usar la clase docblock que especifica qué acciones mágicas están disponibles, ayudando al IDE a producir un mejor autocompletado:
<?php
namespace MyApp\Models;
use Phalcon\Mvc\Model;
/**
* Invoices model
*
* @property Simple|Products[] $products
* @method Simple|Products[] getProducts($parameters = null)
* @method integer countProducts()
*/
class Invoices extends Model
{
public $inv_id;
public $inv_cst_id;
public $inv_status_flag;
public $inv_title;
public $inv_total;
public $inv_created_at;
public function initialize()
{
$this->hasManyToMany(
'inv_id',
InvoicesProducts::class,
'ixp_inv_id',
'ixp_prd_id',
Products::class,
'prd_id',
[
'reusable' => true,
'alias' => 'products',
]
);
}
}
Condicionales
También puede crear relaciones basadas en condicionales. Cuando consulta basándose en la relación, la condición se añadirá automáticamente a la consulta:
<?php
namespace MyApp\Models;
use Phalcon\Mvc\Model;
class Invoices extends Model
{
public $inv_id;
public $inv_cst_id;
public $inv_status_flag;
public $inv_title;
public $inv_total;
public $inv_created_at;
public function initialize()
{
$this->hasManyToMany(
'inv_id',
InvoicesProducts::class,
'ixp_inv_id',
'ixp_prd_id',
Products::class,
'prd_id',
[
'reusable' => true,
'alias' => 'products',
]
);
}
}
class Companies extends Model
{
public function initialize()
{
$this->hasMany(
'id',
Invoices::class,
'inv_id',
[
'alias' => 'Invoices',
]
);
$this->hasMany(
'id',
Invoices::class,
'inv_id',
[
'alias' => 'InvoicesPaid',
'params' => [
'conditions' => "inv_status = 'paid'",
],
]
);
$this->hasMany(
'id',
Invoices::class,
'inv_id',
[
'alias' => 'InvoicesUnpaid',
'params' => [
'conditions' => "inv_status <> :status:",
'bind' => [
'status' => 'unpaid',
],
],
]
);
}
}
Adicionalmente, puede usar los parámetros de getInvoices()
o getRelated()
en el modelo, para filtrar u ordenar aún más su relación:
<?php
$company = Companies::findFirst(
[
'conditions' => 'id = :id:',
'bind' => [
'id' => 1,
],
]
);
*
$unpaidInvoices = $company->InvoicesUnpaid;
$unpaidInvoices = $company->getInvoicesUnpaid();
$unpaidInvoices = $company->getRelated('InvoicesUnpaid');
$unpaidInvoices = $company->getRelated(
'Invoices',
[
'conditions' => "inv_status = 'paid'",
]
);
$unpaidInvoices = $company->getRelated(
'Invoices',
[
'conditions' => "inv_status = 'paid'",
'order' => 'inv_created_date ASC',
]
);
Claves Ajenas Virtuales
Por defecto, las relaciones no tienen ninguna restricción adjunta a ellas, para comprobar datos relacionados cuando se añaden, actualizan o borran registros. Sin embargo, puede adjuntar validaciones a sus relaciones, para asegurar la integridad de los datos. Esto se puede hacer con el último parámetro del método relacionado con la relación.
La tabla de cruce InvoicesProducts
se puede cambiar ligeramente para demostrar esta funcionalidad:
<?php
namespace MyApp\Models;
use Phalcon\Mvc\Model;
class InvoicesProducts extends Model
{
public $ixp_inv_id;
public $ixp_prd_id;
public function initialize()
{
$this->belongsTo(
'ixp_inv_id',
Invoices::class,
'inv_id',
[
'alias' => 'invoice',
'foreignKey' => true,
'reusable' => true,
]
);
$this->belongsTo(
'ixp_prd_id',
Products::class,
'prd_id',
[
'alias' => 'product',
'foreignKey' => [
'message' => 'The prd_id does not exist ' .
'in the Products model',
],
'reusable' => true,
]
);
}
}
Si altera una relación belongsTo()
para actuar como clave ajena, validará que los valores insertados/actualizados en esos campos tengan identificadores de referencia válidos en los respectivos modelos. De forma similar, si un hasMany()
/hasOne()
se cambia para definir la foreignKey
, validará que registros pueden o no si el registro tiene datos relacionados.
<?php
namespace MyApp\Models;
use Phalcon\Mvc\Model;
class Products extends Model
{
public $prd_id;
public $prd_title;
public $prd_price;
public $prd_created_at;
public function initialize()
{
$this->hasMany(
'prd_id',
Products::class,
'ixp_prd_id',
[
'foreignKey' => [
'message' => 'The product cannot be deleted ' .
'because there are invoices ' .
'attached to it',
],
]
);
}
}
Una clave ajena virtual se puede configurar para permitir valores nulos de la siguiente manera:
<?php
namespace MyApp\Models;
use Phalcon\Mvc\Model;
class InvoicesProducts extends Model
{
public $ixp_inv_id;
public $ixp_prd_id;
public function initialize()
{
$this->belongsTo(
'ixp_inv_id',
Invoices::class,
'inv_id',
[
'alias' => 'invoice',
'foreignKey' => true,
'reusable' => true,
]
);
$this->belongsTo(
'ixp_prd_id',
Products::class,
'prd_id',
[
'alias' => 'product',
'foreignKey' => [
'allowNulls' => true,
'message' => 'The prd_id does not exist ' .
'in the Products model',
],
'reusable' => true,
]
);
}
}
Cascada/Restringir
Las relaciones que actúan como claves ajenas virtuales por defecto restringen la creación/actualización/borrado de registros para mantener la integridad de los datos. Puede definir estas restricciones que imitan la funcionalidad del RDBMS para CASCADE
y RESTRICT
usando la opción action
en foreignKey
. The Phalcon\Mvc\Model\Relation underlying object offers two constants:
Relation::ACTION_CASCADE
Relation::ACTION_RESTRICT
<?php
namespace MyApp\Models;
use Phalcon\Mvc\Model;
use Phalcon\Mvc\Model\Relation;
class Products extends Model
{
public $prd_id;
public $prd_title;
public $prd_price;
public $prd_created_at;
public function initialize()
{
$this->hasMany(
'prd_id',
Products::class,
'ixp_prd_id',
[
'foreignKey' => [
'action' => Relation::ACTION_CASCADE,
],
]
);
}
}
El código anterior le permite eliminar todos los registros relacionados si el registro primario se elimina (eliminación en cascada).
Operaciones
Puede ejecutar operaciones usando relaciones, si un conjunto de resultados devuelve objetos completos.
Guardar
Se pueden usar las propiedades mágicas para almacenar un registro y sus propiedades relacionadas:
<?php
$artist = new Artists();
$artist->name = 'Shinichi Osawa';
$artist->country = 'Japan';
$album = new Albums();
$album->name = 'The One';
$album->artist = $artist;
$album->year = 2008;
$album->save();
Guardando un registro y sus registros relacionados en una relación has-many:
<?php
$customer = Customers::findFirst(
[
'conditions' => 'cst_id = :customerId:',
'bind' => [
'customerId' => 1,
]
]
);
$invoice1 = new Invoices();
$invoice1-> inv_status_flag = 0;
$invoice1-> inv_title = 'Invoice for ACME Inc. #1';
$invoice1-> inv_total = 100;
$invoice1-> inv_created_at = time();
$invoice2 = new Invoices();
$invoice2-> inv_status_flag = 0;
$invoice2-> inv_title = 'Invoice for ACME Inc. #2';
$invoice2-> inv_total = 200;
$invoice2-> inv_created_at = time();
$customer->invoices = [
$invoice1,
$invoice2
];
$customer->save();
El código anterior obtiene un cliente de nuestra base de datos. Se crean dos facturas y se asignan a la relación invoices
del cliente como un vector. Se guarda entonces el registro de cliente, lo que también guarda las dos facturas en la base de datos y las enlaza al cliente.
Aunque la sintaxis anterior es muy útil, no siempre es ideal para usar, especialmente cuando actualiza registros relacionados. Phalcon does not know which records need to be added or removed using an update, and as a result it will perform a replacement. In update situations, it is better to control the data yourself vs. leaving it to the framework to do that.
Guardar los datos con la sintaxis anterior implícitamente creará una transacción y la confirmará si todo va bien. Los mensajes generados durante el proceso de guardado de toda la transacción se devolverán al usuario para más información.
NOTE: Adding related entities by overloading the following methods/events is not possible:
Phalcon\Mvc\Model::beforeSave()
Phalcon\Mvc\Model::beforeCreate()
Phalcon\Mvc\Model::beforeUpdate()
Necesita sobrecargar Phalcon\Mvc\Model::save()
para que esto funcione desde dentro de un modelo.
Actualizar
En lugar de hacer esto:
<?php
$invoices = $customer->getInvoices();
foreach ($invoices as $invoice) {
$invoice->inv_total = 100;
$invoice->inv_updated_at = time();
if (false === $invoice->update()) {
$messages = $invoice->getMessages();
foreach ($messages as $message) {
echo $message;
}
break;
}
}
puede hacer esto:
<?php
$customer->getInvoices()->update(
[
'inv_total' => 100,
'inv_updated_at' => time(),
]
);
update
también acepta una función anónima para filtrar los registros que se deben actualizar:
<?php
$data = [
'inv_total' => 100,
'inv_updated_at' => time(),
];
$customer->getInvoices()->update(
$data,
function ($invoice) {
return ($invoice->inv_cst_id !== 1);
}
);
Eliminar
En lugar de hacer esto:
<?php
$invoices = $customer->getInvoices();
foreach ($invoices as $invoice) {
if (false === $invoice->delete()) {
$messages = $invoice->getMessages();
foreach ($messages as $message) {
echo $message;
}
break;
}
}
puede hacer esto:
<?php
$customer->getInvoices()->delete();
delete()
también acepta una función anónima para filtrar los registros que se deben eliminar:
<?php
$customer->getInvoices()->delete(
function ($invoice) {
return ($invoice->inv_total >= 0);
}
);