DAO

La clase DAO es responsable de las operaciones de carga y persistencia de los modelos :

Conexión a la base de datos

Compruebe que los parámetros de conexión a la base de datos se han introducido correctamente en el archivo de configuración:

Ubiquity config -f=database

Desde la versión 2.3.0

El inicio de la base de datos con DAO::startDatabase($config) en el archivo services.php es inútil, no es necesario iniciar la base de datos, la conexión se realiza automáticamente en la primera petición. Usa DAO::start() en el archivo app/config/services.php cuando uses varias bases de datos (con la característica multi db)

Carga de datos

Cargar una instancia

Cargando una instancia de la clase models\User con id 5.

use Ubiquity\orm\DAO;
use models\User;

$user=DAO::getById(User::class, 5);

Cargar una instancia utilizando una condición:

use Ubiquity\orm\DAO;
use models\User;

DAO::getOne(User::class, 'name= ?',false,['DOE']);

Carga de BelongsTo

Por defecto, los miembros definidos por una relación belongsTo se cargan automáticamente

Cada usuario pertenece a una sola categoría:

$user=DAO::getById(User::class,5);
echo $user->getCategory()->getName();

Es posible evitar esta carga por defecto; el tercer parámetro permite cargar o no los miembros belongsTo:

$user=DAO::getOne(User::class,5, false);
echo $user->getCategory();// NULL

Carga de HasMany

La carga de miembros hasMany debe ser siempre explícita; el tercer parámetro permite la carga explícita de miembros.

Cada usuario tiene muchos grupos:

$user=DAO::getOne(User::class,5,['groupes']);
foreach($user->getGroupes() as $groupe){
    echo $groupe->getName().'<br>';
}

Clave primaria compuesta

O bien el modelo ProductDetail correspondiente a un producto pedido en una orden y cuya clave primaria es compuesta:

app/models/ProductDetail.php
 1 namespace models;
 2
 3use Ubiquity\attributes\items\Id;
 4
 5 class ProductDetail{
 6
 7   #[Id]
 8   private $idProduct;
 9
10   #[Id]
11   private $idCommand;
12
13   ...
14 }

El segundo parámetro $keyValues puede ser un array si la clave primaria es compuesta:

$productDetail=DAO::getOne(ProductDetail::class,[18,'BF327']);
echo 'Command:'.$productDetail->getCommande().'<br>';
echo 'Product:'.$productDetail->getProduct().'<br>';

Carga multiple de objetos

Carga de instancias de la clase User:

$users=DAO::getAll(User::class);
foreach($users as $user){
    echo $user->getName()."<br>";
}

Consulta mediante condiciones

Consultas sencillas

El parámetro condition equivale a la parte WHERE de una sentencia SQL:

$users=DAO::getAll(User::class,'firstName like "bren%" and not suspended',false);

Para evitar inyecciones SQL y beneficiarse de la preparación de sentencias, es preferible realizar una consulta parametrizada:

$users=DAO::getAll(User::class,'firstName like ? and suspended= ?',false,['bren%',false]);

UQueries

El uso de U-queries permite establecer condiciones sobre los miembros asociados:

Selección de usuarios cuya organización tiene el dominio lecnam.net:

$users=DAO::uGetAll(User::class,'organization.domain= ?',false,['lecnam.net']);

Es posible ver la solicitud generada en los registros (si el registro está activado):

../_images/uquery-users-log.png

El resultado puede verificarse seleccionando a todos los usuarios de esta organización:

$organization=DAO::getOne(Organization::class,'domain= ?',['users'],['lecnam.net']);
$users=$organization->getUsers();

Los registros correspondientes:

../_images/uquery-users-orga-log.png

Contando

Pruebas de existencia

if(DAO::exists(User::class,'lastname like ?',['SMITH'])){
    //there's a Mr SMITH
}

Contando

Contar las instancias, lo que no hay que hacer, si los usuarios no están ya cargados:

$users=DAO::getAll(User::class);
echo "there are ". \count($users) ." users";

Lo que hay que hacer:

$count=DAO::count(User::class);
echo "there are $count users";

Con una condición:

$notSuspendedCount=DAO::count(User::class, 'suspended = ?', [false]);

con una condición sobre los objetos asociados:

Número de usuarios pertenecientes a la organización denominada OTAN.

$count=DAO::uCount(User::class,'organization.name= ?',['OTAN']);

Modificación de datos

Añadir una instancia

Añadir una organización:

$orga=new Organization();
$orga->setName('Foo');
$orga->setDomain('foo.net');
if(DAO::save($orga)){
  echo $orga.' added in database';
}

Añadir una instancia de Usuario, en una organización:

$orga=DAO::getById(Organization::class, 1);
$user=new User();
$user->setFirstname('DOE');
$user->setLastname('John');
$user->setEmail('doe@bar.net');
$user->setOrganization($orga);
if(DAO::save($user)){
  echo $user.' added in database in '.$orga;
}

Actualización de una instancia

En primer lugar, debe cargarse la instancia:

$orga=DAO::getOne(Organization::class,'domain= ?',false,['foo.net']);
$orga->setAliases('foo.org');
if(DAO::save($orga)){
  echo $orga.' updated in database';
}

Borrar una instancia

Si la instancia se carga desde la base de datos:

$orga=DAO::getById(Organization::class,5,false);
if(DAO::remove($orga)){
  echo $orga.' deleted from database';
}

Si la instancia no está cargada, es más apropiado utilizar el método delete:

if(DAO::delete(Organization::class,5)){
  echo 'Organization deleted from database';
}

Eliminar varias instancias

Eliminar varias instancias sin carga previa:

if($res=DAO::deleteAll(models\User::class, 'id in (?,?,?)',[1,2,3])){
    echo "$res elements deleted";
}

Consultas masivas

Las consultas masivas permiten realizar varias operaciones (inserción, modificación o supresión) en una sola consulta, lo que contribuye a mejorar el rendimiento.

Inserciones masivas

Ejemplo de inserciones:

$u = new User();
$u->setName('Martin1');
DAO::toInsert($u);
$u = new User();
$u->setName('Martin2');
DAO::toInsert($u);
//Perform inserts
DAO::flushInserts();

Actualizaciones masivas

Ejemplo de actualizaciones:

$users = DAO::getAll(User::class, 'name like ?', false, [
   'Martin%'
]);
foreach ($users as $user) {
   $user->setName(\strtoupper($user->getName()));
   DAO::toUpdate($user);
}
DAO::flushUpdates();

Borrado masivo

Ejemplo de eliminación

$users = DAO::getAll(User::class, 'name like ?', false, [
     'BULK%'
]);
DAO::toDeletes($users);
DAO::flushDeletes();

El método DAO::flush() puede ser llamado si hay inserciones, actualizaciones o borrados pendientes.

Transacciones

Transacciones explícitas

Todas las operaciones DAO se pueden insertar en una transacción, de forma que se pueda atomizar una serie de cambios:

try{
   DAO::beginTransaction();
   $orga=new Organization();
   $orga->setName('Foo');
   DAO::save($orga);

   $user=new User();
   $user->setFirstname('DOE');
   $user->setOrganization($orga);
   DAO::save($user);
   DAO::commit();
}catch (\Exception $e){
   DAO::rollBack();
}

En caso de múltiples bases de datos definidas en la configuración, los métodos relacionados con transacciones pueden tomar el offset de base de datos definido en parámetro.

DAO::beginTransaction('db-messagerie');
//some DAO operations on messagerie models
DAO::commit('db-messagerie');

Transacciones implícitas

Algunos métodos DAO utilizan implícitamente transacciones para agrupar operaciones de inserción, actualización o eliminación.

$users=DAO::getAll(User::class);
foreach ($users as $user){
    $user->setSuspended(true);
    DAO::toUpdate($user);
}
DAO::updateGroups();//Perform updates in a transaction

Clase SDAO

La clase SDAO acelera las operaciones CRUD para las clases de negocio sin relaciones.

En este caso, los modelos deben declarar únicamente los miembros públicos y no respetar la encapsulación habitual.

app/models/Product.php
 1 namespace models;
 2 class Product{
 3   /**
 4    * @id
 5    */
 6   public $id;
 7
 8   public $name;
 9
10   ...
11 }

La clase SDAO hereda de DAO y tiene los mismos métodos para realizar operaciones CRUD.

use Ubiquity\orm\DAO;

$product=DAO::getById(Product::class, 5);

Consultas DAO preparadas

La preparación de ciertas peticiones puede mejorar el rendimiento con los servidores Swoole, Workerman o Roadrunner.
Esta preparación inicializa los objetos que luego se utilizarán para ejecutar la consulta.
Esta inicialización se realiza al inicio del servidor, o al inicio de cada worker, si existe tal evento.

Ejemplo swoole

Preparación

app/config/swooleServices.php
$swooleServer->on('workerStart', function ($srv) use (&$config) {
   \Ubiquity\orm\DAO::startDatabase($config);
   \Ubiquity\orm\DAO::prepareGetById('user', User::class);
   \Ubiquity\orm\DAO::prepareGetAll('productsByName', Product::class,'name like ?');
});

Utilización

app/controllers/UsersController.php
public function displayUser($idUser){
   $user=DAO::executePrepared('user',[1]);
   echo $user->getName();
}

public function displayProducts($name){
   $products=DAO::executePrepared('productsByName',[$name]);
   ...
}