verificar validar saber relaciones registro hasone hasmany existe example ejemplos datos oop laravel laravel-4 repository-pattern eloquent

oop - validar - Manejando las relaciones en Laravel, siguiendo el patrón de repositorio



validar si un registro existe en la base de datos laravel (4)

Al crear una aplicación en Laravel 4 después de leer el libro de T. Otwell sobre buenos patrones de diseño en Laravel, me encontré creando repositorios para cada tabla de la aplicación.

Terminé con la siguiente estructura de tabla:

  • Estudiantes: id, nombre
  • Cursos: id, name, teacher_id
  • Maestros: id, nombre
  • Asignaciones: id, name, course_id
  • Puntuaciones (actúa como un pivote entre los alumnos y las tareas): student_id, assignment_id, scores

Tengo clases de repositorio con métodos de búsqueda, creación, actualización y eliminación para todas estas tablas. Cada repositorio tiene un modelo Eloquent que interactúa con la base de datos. Las relaciones se definen en el modelo según la documentación de Laravel: http://laravel.com/docs/eloquent#relationships .

Al crear un nuevo curso, todo lo que hago es llamar al método create en el Repositorio del curso. Ese curso tiene asignaciones, por lo que al crear uno, también quiero crear una entrada en la tabla de puntajes para cada alumno del curso. Lo hago a través del Repositorio de Asignaciones. Esto implica que el repositorio de asignaciones se comunica con dos modelos Eloquent, con el modelo Asignación y Estudiante.

Mi pregunta es: como esta aplicación probablemente crecerá en tamaño y se introducirán más relaciones, ¿es una buena práctica comunicarse con diferentes modelos de Eloquent en repositorios o debería hacerse usando otros repositorios (me refiero a llamar a otros repositorios desde el repositorio de Asignación? ) o debería hacerse en los modelos Eloquent todos juntos?

Además, ¿es una buena práctica usar la tabla de puntajes como un pivote entre las tareas y los estudiantes o debería hacerse en otro lugar?


Estoy terminando un proyecto grande usando Laravel 4 y tuve que responder todas las preguntas que me estás haciendo en este momento. Después de leer todos los libros Laravel disponibles en Leanpub, y toneladas de Google, se me ocurrió la siguiente estructura.

  1. Una clase Eloquent Model por tabla de datos
  2. Una clase de repositorio por modelo elocuente
  3. Una clase de servicio que puede comunicarse entre múltiples clases de repositorio.

Entonces digamos que estoy construyendo una base de datos de películas. Tendría al menos las siguientes clases de Eloquent Model:

  • Película
  • Estudio
  • Director
  • Actor
  • revisión

Una clase de repositorio encapsularía cada clase Eloquent Model y sería responsable de las operaciones CRUD en la base de datos. Las clases de repositorio pueden verse así:

  • MovieRepository
  • StudioRepository
  • DirectorRepository
  • ActorRepositorio
  • ReviewRepository

Cada clase de repositorio extendería una clase BaseRepository que implementa la siguiente interfaz:

interface BaseRepositoryInterface { public function errors(); public function all(array $related = null); public function get($id, array $related = null); public function getWhere($column, $value, array $related = null); public function getRecent($limit, array $related = null); public function create(array $data); public function update(array $data); public function delete($id); public function deleteWhere($column, $value); }

Una clase de servicio se utiliza para unir múltiples repositorios y contiene la "lógica comercial" real de la aplicación. Los controladores solo se comunican con clases de servicio para crear, actualizar y eliminar acciones.

Entonces, cuando quiero crear un nuevo registro de Película en la base de datos, mi clase MovieController puede tener los siguientes métodos:

public function __construct(MovieRepositoryInterface $movieRepository, MovieServiceInterface $movieService) { $this->movieRepository = $movieRepository; $this->movieService = $movieService; } public function postCreate() { if( ! $this->movieService->create(Input::all())) { return Redirect::back()->withErrors($this->movieService->errors())->withInput(); } // New movie was saved successfully. Do whatever you need to do here. }

Depende de usted determinar cómo se envían los datos a sus controladores, pero digamos que los datos devueltos por Input :: all () en el método postCreate () se parecen a esto:

$data = array( ''movie'' => array( ''title'' => ''Iron Eagle'', ''year'' => ''1986'', ''synopsis'' => ''When Doug/'s father, an Air Force Pilot, is shot down by MiGs belonging to a radical Middle Eastern state, no one seems able to get him out. Doug finds Chappy, an Air Force Colonel who is intrigued by the idea of sending in two fighters piloted by himself and Doug to rescue Doug/'s father after bombing the MiG base.'' ), ''actors'' => array( 0 => ''Louis Gossett Jr.'', 1 => ''Jason Gedrick'', 2 => ''Larry B. Scott'' ), ''director'' => ''Sidney J. Furie'', ''studio'' => ''TriStar Pictures'' )

Como MovieRepository no debería saber cómo crear registros de Actor, Director o Studio en la base de datos, usaremos nuestra clase MovieService, que podría verse más o menos así:

public function __construct(MovieRepositoryInterface $movieRepository, ActorRepositoryInterface $actorRepository, DirectorRepositoryInterface $directorRepository, StudioRepositoryInterface $studioRepository) { $this->movieRepository = $movieRepository; $this->actorRepository = $actorRepository; $this->directorRepository = $directorRepository; $this->studioRepository = $studioRepository; } public function create(array $input) { $movieData = $input[''movie'']; $actorsData = $input[''actors'']; $directorData = $input[''director'']; $studioData = $input[''studio'']; // In a more complete example you would probably want to implement database transactions and perform input validation using the Laravel Validator class here. // Create the new movie record $movie = $this->movieRepository->create($movieData); // Create the new actor records and associate them with the movie record foreach($actors as $actor) { $actorModel = $this->actorRepository->create($actor); $movie->actors()->save($actorModel); } // Create the director record and associate it with the movie record $director = $this->directorRepository->create($directorData); $director->movies()->associate($movie); // Create the studio record and associate it with the movie record $studio = $this->studioRepository->create($studioData); $studio->movies()->associate($movie); // Assume everything worked. In the real world you''ll need to implement checks. return true; }

Entonces, lo que nos queda es una agradable y sensata separación de preocupaciones. Los repositorios solo conocen el modelo Eloquent que insertan y recuperan de la base de datos. Los controladores no se preocupan por los repositorios, solo entregan los datos que recopilan del usuario y los pasan al servicio apropiado. Al servicio no le importa cómo se guardan los datos que recibe en la base de datos, simplemente entrega los datos relevantes que le dio el controlador a los repositorios apropiados.


Me gusta pensarlo en términos de lo que mi código está haciendo y de lo que es responsable, en lugar de "lo correcto o incorrecto". Así es como rompo mis responsabilidades:

  • Los controladores son la capa HTTP y las solicitudes de ruta hasta la API subyacente (es decir, controla el flujo)
  • Los modelos representan el esquema de la base de datos, y le dicen a la aplicación cómo son los datos, qué relaciones puede tener, así como cualquier atributo global que pueda ser necesario (como un método de nombre para devolver un nombre y apellido concatenados)
  • Los repositorios representan las consultas e interacciones más complejas con los modelos (no realizo ninguna consulta sobre los métodos del modelo).
  • Motores de búsqueda: clases que me ayudan a crear consultas de búsqueda complejas.

Teniendo esto en cuenta, tiene sentido utilizar un repositorio cada vez (si crea interfaces.etc. Es un tema completamente distinto). Me gusta este enfoque, porque significa que sé exactamente dónde ir cuando necesito hacer cierto trabajo.

También tiendo a construir un repositorio base, generalmente una clase abstracta que define los valores predeterminados principales, básicamente operaciones CRUD, y luego cada niño puede simplemente extender y agregar métodos según sea necesario o sobrecargar los valores predeterminados. Inyectar su modelo también ayuda a que este patrón sea bastante robusto.


Piense en los repositorios como un archivador consistente de sus datos (no solo sus ORM). La idea es que quieras obtener datos en una API consistente y fácil de usar.

Si te encuentras simplemente haciendo Model :: all (), Model :: find (), Model :: create () probablemente no te beneficie demasiado al abstraer un repositorio. Por otro lado, si desea hacer un poco más de lógica de negocios para sus consultas o acciones, es posible que desee crear un repositorio para hacer una API más fácil de usar para manejar los datos.

Creo que estabas preguntando si un repositorio sería la mejor manera de lidiar con la sintaxis más detallada necesaria para conectar modelos relacionados. Dependiendo de la situación, hay algunas cosas que puedo hacer:

  1. Al colgar un nuevo modelo secundario de un modelo principal (one-one o one-many), agregaría un método al repositorio secundario algo así como createWithParent($attributes, $parentModelInstance) y esto solo agregaría el $parentModelInstance->id en el campo parent_id de los atributos y crear llamada.

  2. Al adjuntar una relación de muchos y muchos, realmente creo funciones en los modelos para poder ejecutar $ instance-> attachChild ($ childInstance). Tenga en cuenta que esto requiere elementos existentes en ambos lados.

  3. Al crear modelos relacionados en una sola ejecución, creo algo que llamo una Puerta de enlace (puede estar un poco fuera de las definiciones de Fowler). De manera que puedo llamar $ gateway-> createParentAndChild ($ parentAttributes, $ childAttributes) en lugar de un montón de lógica que puede cambiar o que complicaría la lógica que tengo en un controlador o comando.


Tenga en cuenta que está pidiendo opiniones: D

Aquí está el mío:

TL; DR: Sí, está bien.

¡Lo estás haciendo bien!

Hago exactamente lo que estás haciendo a menudo y encuentro que funciona muy bien.

A menudo, sin embargo, organizo repositorios en torno a la lógica empresarial en lugar de tener un repositorio por mesa. Esto es útil ya que es un punto de vista centrado en cómo su aplicación debería resolver su "problema comercial".

Un Curso es una "entidad", con atributos (título, identificación, etc.) e incluso otras entidades (Asignaciones, que tienen sus propios atributos y posiblemente entidades).

Su repositorio "Curso" debe poder devolver un Curso y los atributos / Asignaciones de los Cursos (incluida la Asignación).

Puedes lograr eso con Eloquent, afortunadamente.

(A menudo termino con un repositorio por tabla, pero algunos repositorios se usan mucho más que otros, y así tienen muchos más métodos. Su repositorio de "cursos" puede tener muchas más funciones que su repositorio de Asignaciones, por ejemplo, si la solicitud se centra más en los Cursos y menos en la colección de Asignaciones de los Cursos).

La parte difícil

A menudo uso repositorios dentro de mis repositorios para realizar algunas acciones en la base de datos.

Cualquier repositorio que implemente Eloquent para manejar datos probablemente devolverá modelos Eloquent. Desde ese punto de vista, está bien si su modelo de Curso utiliza relaciones integradas para recuperar o guardar Asignaciones (o cualquier otro caso de uso). Nuestra "implementación" se basa en Eloquent.

Desde un punto de vista práctico, esto tiene sentido. Es poco probable que cambiemos las fuentes de datos a algo que Eloquent no puede manejar (a una fuente de datos que no sea sql).

ORMS

La parte más difícil de esta configuración, al menos para mí, es determinar si Eloquent realmente nos está ayudando o perjudicando. Los ORM son un tema complicado, porque si bien nos ayudan mucho desde un punto de vista práctico, también acoplan el código de "entidades de lógica de negocios" con el código que realiza la recuperación de datos.

Este tipo de confusión confunde si la responsabilidad de su repositorio es en realidad para manejar datos o manejar la recuperación / actualización de entidades (entidades de dominio comercial).

Además, actúan como los mismos objetos que pasas a tus puntos de vista. Si luego tiene que evitar el uso de modelos de Eloquent en un repositorio, deberá asegurarse de que las variables pasadas a sus vistas se comporten de la misma manera o tengan los mismos métodos disponibles; de lo contrario, cambiar las fuentes de datos se convertirá en cambiar su puntos de vista, y (en parte) perdió el propósito de abstraer su lógica a los repositorios en primer lugar - la mantenibilidad de su proyecto se reduce a.

De todos modos, estos son pensamientos algo incompletos. Son, como se dijo, simplemente mi opinión, que resulta ser el resultado de leer Domain Driven Design y ver videos como el discurso principal de "uncle bob" en Ruby Midwest durante el último año.