El Patrón de Repositorio en Laravel 5
() translation by (you can also view the original English article)
El patrón de repositorio fue presentado por primera vez por Eric Evans en su libro de diseño dirigido por el dominio. El repositorio es, de hecho, el punto de entrada para que la aplicación acceda a la capa de dominio.
Para decirlo simplemente, el repositorio permite que todo su código utilice objetos sin tener que saber cómo se persiste el objeto. 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.
La única manera de hacer que sus repositorios funcionen en Laravel (como un verdadero repositorio—Eric Evans Domain-Driven Design book) es cambiar el ORM predeterminado del active record al data mapper. El mejor sustituto es Doctrine.
La Doctrine ORM
Doctrine es un ORM (mapeo objeto-relacional) que implementa el patrón de data mapper y le permite hacer una separación clara de las reglas de negocio de la aplicación de la capa de persistencia de la base de datos. Doctrine utiliza DQL, en lugar de SQL. DQL le trae lenguaje de consulta de objeto, lo que significa que en lugar de un término de consulta relacional tradicional, tendría consultas en términos de objeto.
Le permite escribir las consultas a base de datos de una manera orientada a objetos y ayuda cuando necesita consultar la base de datos de una manera que no se puede lograr utilizando los métodos de repositorio predeterminados. En mi opinión, DQL es la manera más poderosa de mantenerse en contacto con su base de datos.
Doctrine vs. Eloquent
Las entidades de Doctrine son simplemente una clase sencilla de PHP y no añaden sobrecarga a ninguna herencia de ORM. Doctrine gestiona sus solicitudes de consulta múltiple con la misma herencia sin golpear la base de datos, lo que significa que el objeto entidad existe para toda la solicitud.
La otra característica interesante de Doctrine es que en lugar de migrar archivos para crear el esquema de la base de datos, la base de datos se crea automáticamente para reflejar los metadatos en las anotaciones de la entidad. Por otro lado, Eloquent es menos complicado y muy fácil de usar.
Una comparación completa entre estos dos requeriría un artículo separado. Como puede ver, un objeto Doctrine es más claro y más abstracto. Sin embargo, Doctrine sólo se ajustará a proyectos específicos, por lo que puede traer sobrecarga a veces. Creo que depende del programador para elegir el mejor ORM para la aplicación.
La aplicación Blog
Ahora es el momento de crear una aplicación de blog con Laravel. Primero, necesitamos configurar Doctrine. Hay un bridge para permitir la armonizar 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 el 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" |
Ahora terminamos aquí.
Las entidades son partes importantes de la aplicación App\Entities\Post.php
:
1 |
|
2 |
namespace App\Entity; |
3 |
|
4 |
use Doctrine\ORM\Mapping as ORM; |
5 |
|
6 |
/**
|
7 |
* @ORM\Entity
|
8 |
* @ORM\Table(name="posts")
|
9 |
* @ORM\HasLifecycleCallbacks()
|
10 |
*/
|
11 |
class Post |
12 |
{
|
13 |
/**
|
14 |
* @var integer $id
|
15 |
* @ORM\Column(name="id", type="integer", unique=true, nullable=false)
|
16 |
* @ORM\Id
|
17 |
* @ORM\GeneratedValue(strategy="AUTO")
|
18 |
*
|
19 |
*/
|
20 |
private $id; |
21 |
|
22 |
/**
|
23 |
* @ORM\Column(type="string")
|
24 |
*/
|
25 |
private $title; |
26 |
|
27 |
/**
|
28 |
* @ORM\Column(type="text")
|
29 |
*/
|
30 |
private $body; |
31 |
|
32 |
public function __construct($input) |
33 |
{
|
34 |
$this->setTitle($input['title']); |
35 |
$this->setBody($input['body']); |
36 |
}
|
37 |
|
38 |
public function setId($id) |
39 |
{
|
40 |
return $this->id=$id; |
41 |
}
|
42 |
|
43 |
public function getId() |
44 |
{
|
45 |
return $this->id; |
46 |
}
|
47 |
|
48 |
public function getTitle() |
49 |
{
|
50 |
return $this->title; |
51 |
}
|
52 |
|
53 |
public function setTitle($title) |
54 |
{
|
55 |
$this->title = $title; |
56 |
}
|
57 |
|
58 |
public function getBody() |
59 |
{
|
60 |
return $this->body; |
61 |
}
|
62 |
|
63 |
public function setBody($body) |
64 |
{
|
65 |
$this->body = $body; |
66 |
}
|
67 |
}
|
Ahora es el momento de crear el repositorio, que se describió anteriormente. App/Repositories/PostRepo.php
:
1 |
namespace App\Repository; |
2 |
|
3 |
use App\Entity\Post; |
4 |
use Doctrine\ORM\EntityManager; |
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 |
public function __construct(EntityManager $em) |
18 |
{
|
19 |
$this->em = $em; |
20 |
}
|
21 |
|
22 |
public function create(Post $post) |
23 |
{
|
24 |
$this->em->persist($post); |
25 |
$this->em->flush(); |
26 |
}
|
27 |
|
28 |
public function update(Post $post, $data) |
29 |
{
|
30 |
$post->setTitle($data['title']); |
31 |
$post->setBody($data['body']); |
32 |
$this->em->persist($post); |
33 |
$this->em->flush(); |
34 |
}
|
35 |
|
36 |
public function PostOfId($id) |
37 |
{
|
38 |
return $this->em->getRepository($this->class)->findOneBy([ |
39 |
'id' => $id |
40 |
]);
|
41 |
}
|
42 |
|
43 |
public function delete(Post $post) |
44 |
{
|
45 |
$this->em->remove($post); |
46 |
$this->em->flush(); |
47 |
}
|
48 |
|
49 |
/**
|
50 |
* create Post
|
51 |
* @return Post
|
52 |
*/
|
53 |
private function perpareData($data) |
54 |
{
|
55 |
return new Post($data); |
56 |
}
|
57 |
}
|
58 |
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.edit')->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 |
}
|
Como puedes ver, he usado el ayudante de Flash para administrar los mensajes (puedes usar el de Laravel). Con respecto al Validador, debo agregar que usted puede crear su propio (como yo) o usar el de Laravel por defecto, dependiendo de su preferencia.
Los archivos de View son los mismos de siempre. En este ejemplo, el archivo View se parece a resources/views/admin/edit.blade.php
:
1 |
<div class="panel-body"> |
2 |
<div class="row" > |
3 |
<div class="col-md-12"> |
4 |
@if (Session::has('flash_notification.message')) |
5 |
<div class="alert alert-{{ Session::get('flash_notification.level') }}"> |
6 |
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button> |
7 |
{!! Session::get('flash_notification.message') !!} |
8 |
</div>
|
9 |
@endif |
10 |
</div>
|
11 |
</div>
|
12 |
@if($errors->has()) |
13 |
<div class="alert alert-danger" role="danger" > |
14 |
@foreach ($errors->all() as $error) |
15 |
<ul>
|
16 |
<li>{!! $error !!}</li> |
17 |
</ul>
|
18 |
@endforeach |
19 |
|
20 |
</div>
|
21 |
@endif |
22 |
<form method="post" > |
23 |
<div class="row"> |
24 |
<div class="col-md-6"> |
25 |
<div class="input-group {!! $errors->first('title')?'has-error':'' !!}"> |
26 |
<div class="input-group-addon">{!! 'title' !!}</div> |
27 |
<input type="text" name="title" value="{!! is_object($ListData)?$ListData->getBody():'' !!}" class ='form-control' autocomplete= 'off' /> |
28 |
</div>
|
29 |
<span class="help-block"> </span> |
30 |
</div>
|
31 |
<div class="col-md-6"> |
32 |
<div class="input-group {!! $errors->first('body')?'has-error':'' !!}"> |
33 |
<div class="input-group-addon">{!! 'Body' !!}</div> |
34 |
<textarea name="body" class ='form-control' autocomplete= 'off' > {!! is_object($ListData)?$ListData->getTitle():'' !!} </textarea> |
35 |
|
36 |
</div>
|
37 |
<span class="help-block"> </span> |
38 |
</div>
|
39 |
</div>
|
40 |
|
41 |
<div class="row"> |
42 |
<br/>
|
43 |
<div class="col-md-6"> |
44 |
<div class="col-sm-5 submitWrap"> |
45 |
<button type="submit" class="btn btn-primary btn-md" > {!! 'save' !!}</button> |
46 |
</div>
|
47 |
</div>
|
48 |
</div>
|
49 |
</form>
|
50 |
</div>
|
51 |
</div>
|
52 |
</div>
|
El enrutamiento y otras operaciones serían como de costumbre.
Conclusion
Ahora puedes ver cómo puedes crear fácilmente un repositorio basado en Doctrine en Laravel 5.0, que resultará en muchos beneficios.
Para aquellos de ustedes que están apenas comenzando con Laravel o buscando ampliar su conocimiento, sitio o aplicación con extensiones, tenemos una variedad de cosas que pueden estudiar en Envato Market.