Usando clases de entidad
Higgs apoya las clases de Entidad como ciudadano de primera clase, manteniendo su uso es completamente opcional. Se utilizan comúnmente como parte del patrón Repositorio, pero pueden ser usado directamente con el Modelo si eso se adapta mejor a sus necesidades.
Uso de entidad
En esencia, una clase Entidad es simplemente una clase que representa una única fila de la base de datos. Tiene propiedades de clase. para representar las columnas de la base de datos y proporciona métodos adicionales para implementar la lógica empresarial para esa fila.
Nota
For ease of understanding, the explanation here is based on the case of utilizando una base de datos. Sin embargo, Entidad también se puede utilizar para datos que no vienen de una base de datos.
La característica principal, sin embargo, es que no sabe nada sobre cómo persistir. Eso es responsabilidad del modelo o de la clase de repositorio. De esa manera, si algo cambia sobre cómo necesita guardar el objeto, no es necesario cambiar la forma en que se utiliza ese objeto en toda la aplicación.
Esto hace posible use archivos JSON o XML para almacenar los objetos durante una etapa de creación rápida de prototipos y luego cambie fácilmente a un base de datos cuando hayas demostrado que el concepto funciona.
Veamos una entidad de usuario muy simple y cómo trabajaríamos con ella para ayudar a aclarar las cosas.
Supongamos que tiene una tabla de base de datos llamada usuarios
que tiene el siguiente esquema:
identificación - número entero
nombre de usuario - cadena
correo electrónico - cadena
contraseña - cadena
creado_en - fecha y hora
Importante
attributes
is a reserved word for internal use. If you use it as a column name, the Entity does not work correctly.
Crear la clase de entidad
Ahora crea una nueva clase de entidad. Dado que no existe una ubicación predeterminada para almacenar estas clases y no encaja Con la estructura de directorios existente, cree un nuevo directorio en app/Entities. Crea el Entidad misma en app/Entities/User.php.
<?php
namespace App\Entities;
use Higgs\Entity\Entity;
class User extends Entity
{
// ...
}
En su forma más simple, esto es todo lo que necesita hacer, aunque lo haremos más útil en un minuto.
Crear el modelo
Primero crea el modelo en app/Models/UserModel.php para que podamos interactuar con él:
<?php
namespace App\Models;
use Higgs\Model;
class UserModel extends Model
{
protected $table = 'users';
protected $allowedFields = [
'username', 'email', 'password',
];
protected $returnType = \App\Entities\User::class;
protected $useTimestamps = true;
}
El modelo utiliza la tabla usuarios
en la base de datos para todas sus actividades. Hemos configurado la propiedad $allowedFields
para incluir todos los campos que queremos que cambien fuera de las clases. Los campos id
, created_at
y updated_at
son manejados automáticamente por la clase o la base de datos, por lo que no queremos cambiarlos. Finalmente, hemos configurado nuestra Entidad
clase como $returnType
. Esto garantiza que todos los métodos del modelo que devuelven filas de la base de datos devolverán
instancias de nuestra clase de entidad de usuario en lugar de un objeto o matriz como de costumbre.
Trabajar con la clase de entidad
Ahora que todas las piezas están en su lugar, trabajará con la clase Entidad como lo haría con cualquier otra clase:
<?php
$user = $userModel->find($id);
// Display
echo $user->username;
echo $user->email;
// Updating
unset($user->username);
if (! isset($user->username)) {
$user->username = 'something new';
}
$userModel->save($user);
// Create
$user = new \App\Entities\User();
$user->username = 'foo';
$user->email = 'foo@example.com';
$userModel->save($user);
Quizás hayas notado que la clase Usuario
no ha establecido ninguna propiedad para las columnas, pero aún puedes
acceder a ellos como si fueran bienes públicos. La clase base, Higgs\Entity\Entity
, se encarga de esto por usted, como
además de brindar la capacidad de verificar las propiedades con isset()
o unset()
la propiedad y realizar un seguimiento
de qué columnas han cambiado desde que se creó el objeto o se extrajo de la base de datos.
Nota
The Entity class stores the data in the class property $attributes
internally.
Cuando el usuario pasa al método save()
del modelo, automáticamente se encarga de leer las propiedades.
y guardar cualquier cambio en las columnas enumeradas en la propiedad $allowedFields
del modelo. También sabe si crear
una nueva fila o actualizar una existente.
Nota
When we are making a call to the insert()
all the values from Entity are passed to the method, but when we
llame a update()
, luego solo se pasan los valores que han cambiado.
Propiedades de relleno rápidamente
La clase Entity también proporciona un método, fill()
que le permite insertar una matriz de pares clave/valor en la clase.
y completar las propiedades de la clase. Cualquier propiedad de la matriz se establecerá en la Entidad. Sin embargo, al guardar mediante
el modelo, sólo los campos en $allowedFields
realmente se guardarán en la base de datos, para que pueda almacenar datos adicionales
en sus entidades sin preocuparse mucho de que los campos perdidos se guarden incorrectamente.
<?php
$data = $this->request->getPost();
$user = new \App\Entities\User();
$user->fill($data);
$userModel->save($user);
También puede pasar los datos en el constructor y los datos se pasarán a través del método fill()
durante la creación de instancias.
<?php
$data = $this->request->getPost();
$user = new \App\Entities\User($data);
$userModel->save($user);
Propiedades de acceso masivo
La clase Entity tiene dos métodos para extraer todas las propiedades disponibles en una matriz: toArray()
y toRawArray()
.
El uso de la versión sin formato evitará los métodos y lanzamientos mágicos de «captadores». Ambos métodos pueden tomar un primer parámetro booleano.
para especificar si los valores devueltos deben filtrarse por aquellos que han cambiado, y un parámetro final booleano para
haga que el método sea recursivo, en el caso de entidades anidadas.
Manejo de la lógica empresarial
Si bien los ejemplos anteriores son convenientes, no ayudan a aplicar ninguna lógica empresarial. La clase de entidad base implementa
algunos métodos inteligentes __get()
y __set()
que buscarán métodos especiales y los usarán en lugar de usar
los atributos directamente, lo que le permite aplicar cualquier lógica empresarial o conversión de datos que necesite.
Aquí hay una entidad de usuario actualizada para proporcionar algunos ejemplos de cómo podría usarse:
<?php
namespace App\Entities;
use Higgs\Entity\Entity;
use Higgs\I18n\Time;
class User extends Entity
{
public function setPassword(string $pass)
{
$this->attributes['password'] = password_hash($pass, PASSWORD_BCRYPT);
return $this;
}
public function setCreatedAt(string $dateString)
{
$this->attributes['created_at'] = new Time($dateString, 'UTC');
return $this;
}
public function getCreatedAt(string $format = 'Y-m-d H:i:s')
{
// Convert to Higgs\I18n\Time object
$this->attributes['created_at'] = $this->mutateDate($this->attributes['created_at']);
$timezone = $this->timezone ?? app_timezone();
$this->attributes['created_at']->setTimezone($timezone);
return $this->attributes['created_at']->format($format);
}
}
Lo primero que hay que notar es el nombre de los métodos que hemos agregado. Para cada uno, la clase espera el caso_serpiente.
nombre de la columna que se convertirá a PascalCase y con el prefijo set
o get
. Estos métodos luego
se llamará automáticamente cada vez que configure o recupere la propiedad de clase usando la sintaxis directa (es decir, $usuario->correo electrónico
).
No es necesario que los métodos sean públicos a menos que desee acceder a ellos desde otras clases. Por ejemplo, created_at
Se accederá a la propiedad de clase a través de los métodos setCreatedAt()
y getCreatedAt()
.
Nota
This only works when trying to access the properties from outside of the class. Any methods internal to the
La clase debe llamar a los métodos setX()
y getX()
directamente.
En el método setPassword()
nos aseguramos de que la contraseña siempre esté codificada.
En setCreatedAt()
convertimos la cadena que recibimos del modelo en un objeto DateTime, asegurando que nuestra zona horaria
es UTC para que podamos convertir fácilmente la zona horaria actual del espectador. En getCreatedAt()
, convierte la hora a
una cadena formateada en la zona horaria actual de la aplicación.
Si bien son bastante simples, estos ejemplos muestran que el uso de clases de entidad puede proporcionar una forma muy flexible de hacer cumplir lógica de negocios y crear objetos que sean agradables de usar.
<?php
// Auto-hash the password - both do the same thing
$user->password = 'my great password';
$user->setPassword('my great password');
Getter/Setter especial
Nuevo en la versión 4.4.0.
Por ejemplo, si la clase principal de su entidad ya tiene un método getParent()
definido, y su Entidad también tiene una columna llamada padre
, cuando intenta agregar
lógica de negocios al método getParent()
en su clase Entidad, el método es
Ya definido.
En tal caso, puede utilizar el captador/definidor especial. En lugar de getX()
/setX()
,
establezca _getX()
/_setX()
.
En el ejemplo anterior, si su entidad tiene el método _getParent()
, el método
se usará cuando obtenga $entity->parent
y el método _setParent()
se utilizará cuando establezca $entidad->padre
.
Mapeo de datos
En muchos puntos de tu carrera, te encontrarás con situaciones en las que el uso de una aplicación ha cambiado y la Los nombres de columnas originales en la base de datos ya no tienen sentido. O descubre que su estilo de codificación prefiere camelCase propiedades de clase, pero el esquema de su base de datos requería nombres de casos de serpientes. Estas situaciones se pueden manejar fácilmente con las funciones de mapeo de datos de la clase Entidad.
Como ejemplo, imagine que tiene la entidad de usuario simplificada que se utiliza en toda su aplicación:
<?php
namespace App\Entities;
use Higgs\Entity\Entity;
class User extends Entity
{
protected $attributes = [
'id' => null,
'name' => null, // Represents a username
'email' => null,
'password' => null,
'created_at' => null,
'updated_at' => null,
];
}
Tu jefe se acerca a ti y te dice que ya nadie usa nombres de usuario, por lo que estás cambiando para usar solo correos electrónicos para iniciar sesión.
Pero sí quieren personalizar un poco la aplicación, por lo que quieren que cambies el campo nombre
para representar el nombre de un usuario.
nombre completo ahora, no su nombre de usuario como lo hace actualmente. Para mantener las cosas ordenadas y garantizar que las cosas sigan teniendo sentido.
en la base de datos, organiza una migración para cambiar el nombre del campo nombre
a nombre_completo
para mayor claridad.
Haciendo caso omiso de lo artificial que es este ejemplo, ahora tenemos dos opciones sobre cómo arreglar la clase Usuario. Podríamos modificar la clase.
propiedad de $name
a $full_name
, pero eso requeriría cambios en toda la aplicación. En cambio, podemos
simplemente asigne la columna full_name
en la base de datos a la propiedad $name
y termine con los cambios de entidad:
<?php
namespace App\Entities;
use Higgs\Entity\Entity;
class User extends Entity
{
protected $attributes = [
'id' => null,
'full_name' => null, // In the $attributes, the key is the db column name
'email' => null,
'password' => null,
'created_at' => null,
'updated_at' => null,
];
protected $datamap = [
// property_name => db_column_name
'name' => 'full_name',
];
}
Al agregar el nuevo nombre de nuestra base de datos a la matriz $datamap
, podemos decirle a la clase qué propiedad de clase tiene la columna de la base de datos.
debe ser accesible a través de. La clave de la matriz es la propiedad de clase a la que asignarla, donde el valor de la matriz es el
nombre de la columna en la base de datos.
En este ejemplo, cuando el modelo establece el campo full_name
en la clase Usuario, en realidad asigna ese valor al
class” $name
, por lo que se puede configurar y recuperar a través de $user->name
. El valor seguirá siendo accesible.
a través del $user->full_name
original, también, ya que esto es necesario para que el modelo recupere los datos y los guarde.
a la base de datos. Sin embargo, unset()
y isset()
solo funcionan en la propiedad asignada, $user->name
, no en el nombre de la columna de la base de datos.
$usuario->nombre_completo
.
Nota
When you use Data Mapping, you must define set*()
and get*()
method
para el nombre de la columna de la base de datos. En este ejemplo, debe definir setFullName()
y
getFullName()
.
Mutadores
Mutadores de fecha
De forma predeterminada, la clase Entidad convertirá los campos denominados created_at, updated_at o deleted_at en Tiempo instancias cada vez que se configuran o recuperan. La clase Time proporciona una gran cantidad de métodos útiles de forma inmutable y localizada.
Puede definir qué propiedades se convierten automáticamente agregando el nombre a la propiedad $dates
:
<?php
namespace App\Entities;
use Higgs\Entity\Entity;
class User extends Entity
{
protected $dates = ['created_at', 'updated_at', 'deleted_at'];
}
Ahora, cuando se establezca cualquiera de esas propiedades, se convertirán en una instancia de tiempo, utilizando el comando de la aplicación. zona horaria actual, como se establece en app/Config/App.php:
<?php
$user = new \App\Entities\User();
// Converted to Time instance
$user->created_at = 'April 15, 2017 10:30:00';
// Can now use any Time methods:
echo $user->created_at->humanize();
echo $user->created_at->setTimezone('Europe/London')->toDateString();
Fundición de propiedad
Puede especificar que las propiedades de su entidad se deben convertir a tipos de datos comunes con la propiedad $casts
.
Esta opción debe ser una matriz donde la clave es el nombre de la propiedad de clase y el valor es el tipo de datos.
debe ser lanzado.
La conversión de propiedades afecta tanto a la lectura (obtener) como a la escritura (establecer), pero algunos tipos afectan solo leer (obtener).
Fundición tipo escalar
Las propiedades se pueden convertir a cualquiera de los siguientes tipos de datos:
entero, flotante, doble, cadena, booleano, objeto, matriz, fechahora, ** marca de tiempo**, uri y int-bool. Agregue un signo de interrogación al principio del tipo para marcar la propiedad como anulable, es decir, ?string, ?integer.
Nota
int-bool can be used since v7.3.0.
Por ejemplo, si tuviera una entidad de Usuario con una propiedad is_banned
, puede convertirla en booleana:
<?php
namespace App\Entities;
use Higgs\Entity\Entity;
class User extends Entity
{
protected $casts = [
'is_banned' => 'boolean',
'is_banned_nullable' => '?boolean',
];
}
Transmisión de matriz/Json
La conversión de matrices/Json es especialmente útil con campos que almacenan matrices serializadas o json en ellos. Cuando se emite como:
una matriz, se deserializarán automáticamente,
un json, se establecerán automáticamente como un valor de
json_decode($value, false)
,un json-array, se establecerán automáticamente como un valor de
json_decode($value, true)
,
cuando establece el valor de la propiedad. A diferencia del resto de los tipos de datos a los que puede convertir propiedades,:
array el tipo de conversión se serializará,
json y json-array cast usarán la función json_encode en
el valor cada vez que se establece la propiedad:
<?php
namespace App\Entities;
use Higgs\Entity\Entity;
class User extends Entity
{
protected $casts = [
'options' => 'array',
'options_object' => 'json',
'options_array' => 'json-array',
];
}
<?php
$user = $userModel->find(15);
$options = $user->options;
$options['foo'] = 'bar';
$user->options = $options;
$userModel->save($user);
Transmisión CSV
Si sabe que tiene una matriz plana de valores simples, codifíquelos como una cadena serializada o JSON. puede ser más complejo que la estructura original. La conversión como valores separados por comas (CSV) es una alternativa más simple dará como resultado una cadena que utiliza menos espacio y se lee más fácilmente por humanos:
<?php
namespace App\Entities;
use Higgs\Entity\Entity;
class Widget extends Entity
{
protected $casts = [
'colors' => 'csv',
];
}
Almacenado en la base de datos como «rojo, amarillo, verde»:
<?php
$widget->colors = ['red', 'yellow', 'green'];
Nota
Casting as CSV uses PHP’s internal implode
and explode
methods and assumes all values are string-safe and free of commas. For more complex data casts try array
or json
.
Fundición personalizada
Puede definir sus propios tipos de conversión para obtener y configurar datos.
Al principio necesitas crear una clase de controlador para tu tipo. Digamos que la clase estará ubicada en el directorio app/Entities/Cast:
<?php
namespace App\Entities\Cast;
use Higgs\Entity\Cast\BaseCast;
// The class must inherit the Higgs\Entity\Cast\BaseCast class
class CastBase64 extends BaseCast
{
public static function get($value, array $params = [])
{
return base64_decode($value, true);
}
public static function set($value, array $params = [])
{
return base64_encode($value);
}
}
Ahora necesitas registrarlo:
<?php
namespace App\Entities;
use Higgs\Entity\Entity;
class MyEntity extends Entity
{
// Specify the type for the field
protected $casts = [
'key' => 'base64',
];
// Bind the type to the handler
protected $castHandlers = [
'base64' => Cast\CastBase64::class,
];
}
// ...
$entity->key = 'test'; // dGVzdA==
echo $entity->key; // test
Si no necesita cambiar valores al obtener o establecer un valor. Entonces simplemente no implementes el método apropiado:
<?php
namespace App\Entities\Cast;
use Higgs\Entity\Cast\BaseCast;
class CastBase64 extends BaseCast
{
public static function get($value, array $params = [])
{
return base64_decode($value, true);
}
}
Parámetros
En algunos casos, un tipo no es suficiente. En esta situación, puede utilizar parámetros adicionales.
Los parámetros adicionales se indican entre corchetes y se enumeran con una coma.
como tipo[param1, param2]
.
<?php
namespace App\Entities;
use Higgs\Entity\Entity;
class MyEntity extends Entity
{
// Define a type with parameters
protected $casts = [
'some_attribute' => 'class[App\SomeClass, param2, param3]',
];
// Bind the type to the handler
protected $castHandlers = [
'class' => 'SomeHandler',
];
}
<?php
namespace App\Entities\Cast;
use Higgs\Entity\Cast\BaseCast;
class SomeHandler extends BaseCast
{
public static function get($value, array $params = [])
{
var_dump($params);
/*
* Output:
* array(3) {
* [0]=>
* string(13) "App\SomeClass"
* [1]=>
* string(6) "param2"
* [2]=>
* string(6) "param3"
* }
*/
}
}
Nota
If the casting type is marked as nullable like ?bool
and the passed value is not null, then the parameter with
el valor nullable
se pasará al controlador de tipo de conversión.
Si el tipo de conversión tiene parámetros predefinidos, se agregará «nullable» al final de la lista.
Comprobación de atributos modificados
Puede verificar si un atributo de Entidad ha cambiado desde que fue creado. El único parámetro es el nombre del atributo a comprobar:
<?php
$user = new \App\Entities\User();
$user->hasChanged('name'); // false
$user->name = 'Fred';
$user->hasChanged('name'); // true
O para verificar toda la entidad en busca de valores modificados, omita el parámetro:
<?php
$user->hasChanged(); // true