Doctrine ORM y Laravel 5
Spanish (Español) translation by Elías Nicolás (you can also view the original English article)
Como desarrollador de PHP, es posible que haya encontrado el término ORM. ORM es una forma de trabajar con bases de datos de la misma manera que trabaja con clases y objetos. Si profundizas en cómo se diseñan y construyen las aplicaciones web, después de hacer un poco de exploración en su ORM encontrarías dos patrones bien conocidos: Active Record y Data Mapper.
Active Record se refiere a asignar un objeto a una fila de base de datos. De hecho, cada fila de la base de datos está vinculada a un objeto. Cuando recupera una fila de la base de datos puede actualizar, eliminar o guardar utilizando el propio objeto. Así es como trabajan Eloquent y Paris, y asi es cómo se hace en Ruby on Rails.
Por otra parte, Data Mapper es una capa de software que separa los objetos en memoria desde la base de datos. Con Data Mapper los objetos en memoria no necesitan saber que hay siquiera una base de datos presente. No necesitan código de interfaz SQL o conocimiento del esquema de la base de datos. Una de esas soluciones es Doctrine.

¿Qué es Doctrine?
Doctrine es una ORM que implementa el patrón de asignación de datos y le permite hacer una separación clara de las reglas de la aplicación de la capa de persistencia de la base de datos.
Algunas de las ventajas que descubrí al usar Doctrine con Laravel son:
- Más rápido y fácil de usar.
- Las entidades son simples objetos PHP.
- Doctrine utiliza un enfoque de "código primero", por lo que puede crear entidades primero, y luego generar una base de datos para ellos automáticamente. El caso inverso también es posible, pero no lo recomiendo.
- Soporta anotaciones, XML y YAML para el esquema.
- DQL (un reemplazo para SQL) abstrae sus tablas.
- Los eventos Doctrine le permiten conectarse fácilmente a eventos específicos de la base de datos y realizar ciertas acciones.
- Los repositorios son más fieles al patrón del repositorio.
- La
metodología
transaccional write-behindpermite que Doctrine tenga menos interacción con la Base de Datos hasta que se llame al métodoflush().
Por supuesto, Doctrine tiene desventajas también, pero es para el programador el elegir el correcto ORM.
Doctrine DQL
DQL significa Doctrine Query Language. DQL le trae lenguaje de consulta de objeto, lo que significa que en lugar de una consulta relacional tradicional, tiene consultas en forma de objeto.
DQL le permite escribir consultas de base de datos de una manera orientada a objetos, lo cual es útil cuando necesita consultar la base de datos de una manera que no se puede lograr (o es muy difícil) utilizando los métodos de repositorio predeterminados.
Muestra Yaueri TÍTULO:
1 |
SELECT b.id as ItemId, b.title as ItemTitle , b.url as ItemUrl |
2 |
FROM Alireza\Domain\Identity\Entities\Menu u |
3 |
WHERE u.id =:id |
Filtros Doctrine
Doctrine le permite limitar los resultados de la consulta con Filtros. Por ejemplo, puede que desee editar sólo la información del usuario conectado o asegurarse de que los datos del cliente actual se devolvieron de la base de datos. Un filtro es una solución automática para recordar condiciones específicas para todas sus consultas.
Doctrine proporciona limitaciones de nivel SQL, por lo que no es necesario mantener la cláusula en varios repositorios de su proyecto. Esto mejora la seguridad y hace que su código sea más fácil de leer.
Veamos un ejemplo:
1 |
/**
|
2 |
* @ManyToOne(targetEntity="User")
|
3 |
* @JoinColumn(name="user_id", referencedColumnName="id")
|
4 |
**/
|
5 |
private $user; |
Como
se puede ver en la entidad User, el resultado de JoinColumn está
limitado a sólo elementos con la condición de WHERE user_id = :user_id.
Configurando Doctrine 2
Para configurar Doctrine, hay un puente para permitir que coincida con la configuración existente de Laravel 5. Para instalar Doctrine 2 dentro de nuestro proyecto Laravel, ejecutamos el siguiente comando:
1 |
composer require laravel-doctrine/orm |
Como de costumbre, el paquete se debe agregar a la app/config.php, como proveedor de servicios:
1 |
LaravelDoctrine\ORM\DoctrineServiceProvider::class, |
El alias también debe configurarse:
1 |
'EntityManager' => LaravelDoctrine\ORM\Facades\EntityManager::class |
Finalmente, publicamos la configuración del paquete con:
1 |
php artisan vendor:publish --tag="config" |
Doctrine
no necesita ninguna configuración de base de datos y utiliza la
configuración actual de Laravel, pero si desea anularla, debe cambiar el
archivo de configuración de Doctrine en Config/doctrine.php:
1 |
'managers' => [ |
2 |
'default' => [ |
3 |
'dev' => env('APP_DEBUG'), |
4 |
'meta' => env('DOCTRINE_METADATA', 'annotations'), |
5 |
'connection' => env('DB_CONNECTION', 'mysql'), |
6 |
'namespaces' => [ |
7 |
'App'
|
8 |
],
|
9 |
Eso es todo sobre eso.
¿Qué es una Entidad?
"Entidad" se refiere a un objeto que tiene una identidad distinta. Una entidad debe tener un identificador específico que sea único en todo el sistema, como un cliente o un estudiante. Habría otros objetos, como direcciones de correo electrónico, que no son entidades, sino valor de objetos .
Vamos a crear una entidad Post App/Entity/Post.php:
1 |
namespace App\Entity; |
2 |
|
3 |
use Doctrine\ORM\Mapping as ORM; |
4 |
|
5 |
/**
|
6 |
* @ORM\Entity
|
7 |
* @ORM\Table(name="posts")
|
8 |
* @ORM\HasLifecycleCallbacks()
|
9 |
*/
|
10 |
class Post |
11 |
{
|
12 |
/**
|
13 |
* @var integer $id
|
14 |
* @ORM\Column(name="id", type="integer", unique=true, nullable=false)
|
15 |
* @ORM\Id
|
16 |
* @ORM\GeneratedValue(strategy="AUTO")
|
17 |
*
|
18 |
*/
|
19 |
private $id; |
20 |
|
21 |
/**
|
22 |
* @ORM\Column(type="string")
|
23 |
*/
|
24 |
private $title; |
25 |
|
26 |
/**
|
27 |
* @ORM\Column(type="text")
|
28 |
*/
|
29 |
private $body; |
30 |
|
31 |
public function __construct($input) |
32 |
{
|
33 |
$this->setTitle($input['title']); |
34 |
$this->setBody($input['body']); |
35 |
}
|
36 |
|
37 |
public function getId() |
38 |
{
|
39 |
return $this->id; |
40 |
}
|
41 |
|
42 |
public function getTitle() |
43 |
{
|
44 |
return $this->title; |
45 |
}
|
46 |
|
47 |
public function setTitle($title) |
48 |
{
|
49 |
$this->title = $title; |
50 |
}
|
51 |
|
52 |
public function getBody() |
53 |
{
|
54 |
return $this->body; |
55 |
}
|
56 |
|
57 |
public function setBody($body) |
58 |
{
|
59 |
$this->body = $body; |
60 |
}
|
61 |
}
|
Las
propiedades de la clase deben ser las mismas que las de la tabla de la
base de datos, o puede definirse con la anotación @Colum ("name"="myfield").
¿Qué es un repositorio?
El repositorio permite que todo su código utilice objetos sin necesidad de saber cómo se persistirán los objetos. El repositorio contiene todo el conocimiento de la persistencia, incluida la asignación de tablas a objetos. Esto proporciona una vista más orientada a objetos de la capa de persistencia y hace que el código de asignación sea más encapsulado.
Ahora es el momento de crear el repositorio en App/Repository/PostRepo.php:
1 |
namespace App\Repository; |
2 |
use App\Entity\Post; |
3 |
use Doctrine\ORM\EntityManager; |
4 |
|
5 |
class PostRepo |
6 |
{
|
7 |
|
8 |
/**
|
9 |
* @var string
|
10 |
*/
|
11 |
private $class = 'App\Entity\Post'; |
12 |
/**
|
13 |
* @var EntityManager
|
14 |
*/
|
15 |
private $em; |
16 |
|
17 |
|
18 |
public function __construct(EntityManager $em) |
19 |
{
|
20 |
$this->em = $em; |
21 |
}
|
22 |
|
23 |
|
24 |
public function create(Post $post) |
25 |
{
|
26 |
$this->em->persist($post); |
27 |
$this->em->flush(); |
28 |
}
|
29 |
|
30 |
public function update(Post $post, $data) |
31 |
{
|
32 |
$post->setTitle($data['title']); |
33 |
$post->setBody($data['body']); |
34 |
$this->em->persist($post); |
35 |
$this->em->flush(); |
36 |
}
|
37 |
|
38 |
public function PostOfId($id) |
39 |
{
|
40 |
return $this->em->getRepository($this->class)->findOneBy([ |
41 |
'id' => $id |
42 |
]);
|
43 |
}
|
44 |
|
45 |
public function delete(Post $post) |
46 |
{
|
47 |
$this->em->remove($post); |
48 |
$this->em->flush(); |
49 |
}
|
50 |
|
51 |
/**
|
52 |
* create Post
|
53 |
* @return Post
|
54 |
*/
|
55 |
private function prepareData($data) |
56 |
{
|
57 |
return new Post($data); |
58 |
}
|
59 |
}
|
60 |
El Doctrine EntityManager funciona como el punto de acceso para la gestión completa de sus entidades. A continuación, cree el controlador App/Http/Controllers/PostController.php:
1 |
namespace App\Http\Controllers; |
2 |
use App\Repository\PostRepo as repo; |
3 |
use App\Validation\PostValidator; |
4 |
|
5 |
class PostController extends Controller |
6 |
{
|
7 |
private $repo; |
8 |
|
9 |
public function __construct(repo $repo) |
10 |
{
|
11 |
$this->repo = $repo; |
12 |
}
|
13 |
|
14 |
public function edit($id=NULL) |
15 |
{
|
16 |
return View('admin.index')->with(['data' => $this->repo->postOfId($id)]); |
17 |
}
|
18 |
|
19 |
public function editPost() |
20 |
{
|
21 |
$all = Input::all(); |
22 |
$validate = PostValidator::validate($all); |
23 |
if (!$validate->passes()) { |
24 |
return redirect()->back()->withInput()->withErrors($validate); |
25 |
}
|
26 |
$Id = $this->repo->postOfId($all['id']); |
27 |
if (!is_null($Id)) { |
28 |
$this->repo->update($Id, $all); |
29 |
Session::flash('msg', 'edit success'); |
30 |
} else { |
31 |
$this->repo->create($this->repo->perpare_data($all)); |
32 |
Session::flash('msg', 'add success'); |
33 |
}
|
34 |
return redirect()->back(); |
35 |
}
|
36 |
|
37 |
public function retrieve() |
38 |
{
|
39 |
return View('admin.index')->with(['Data' => $this->repo->retrieve()]); |
40 |
}
|
41 |
|
42 |
public function delete() |
43 |
{
|
44 |
$id = Input::get('id'); |
45 |
$data = $this->repo->postOfId($id); |
46 |
if (!is_null($data)) { |
47 |
$this->repo->delete($data); |
48 |
Session::flash('msg', 'operation Success'); |
49 |
return redirect()->back(); |
50 |
} else { |
51 |
return redirect()->back()->withErrors('operationFails'); |
52 |
}
|
53 |
}
|
54 |
}
|
La vista y el enrutamiento son los mismos de siempre.
Yo prefiero crear mi propio Validador basado en la clase Validator de Laravel. Aquí está el Validador App\Validation\PostValidator.php:
1 |
namespace App\Validation; |
2 |
use Validator; |
3 |
|
4 |
class PostValidator |
5 |
{
|
6 |
public static function validate($input) |
7 |
{
|
8 |
$rules = [ |
9 |
'title' => 'Required|Min:4|Max:80|alpha_spaces', |
10 |
'body' => 'Required', |
11 |
];
|
12 |
return Validator::make($input, $rules); |
13 |
}
|
14 |
}
|
Conclusion
Si usted no ha trabajado previamente con Doctrine 2, espero que este artículo haya sido interesante e informativo. Laravel 5 no usa Doctrine, pero como puede ver, hay algunos paquetes que nos permiten usarlo fácilmente en Laravel. He creado una aplicación blog simple con Laravel 5 y Doctrine ORM, y espero que esto le ayude a crear la aplicación deseada. Agradezco sus comentarios.



