¿Cuándo usar Repository vs Service vs Trait en Laravel? [closed]

6 minutos de lectura

Para evitar la duplicación de código en Laravel, quiero tener un método que sea utilizado por varios controladores, inserte algunas filas en la base de datos y también actualice algunos datos en otra tabla.

Pensé en usar Repository, pero leí en alguna parte que Repository se usa mejor para recuperar datos y no debería usarse para insertar.

Así que voy a usar Rasgos ahora. pero estoy un poco confundido…

¿Podría alguien explicar de manera sencilla cuál es el mejor uso para cada uno de estos (Repositorio/Servicio/Rasgo) y en qué se diferencian?

avatar de usuario de mrhn
mrhn

Rasgos

Son un enfoque alternativo a la herencia que resuelve algunas limitaciones de la herencia de clase única, que PHP usos. Esto se usa comúnmente para compartir una lógica similar entre modelos. Imaginemos que un par de modelos tienen una relación con la empresa.

trait HasCompany {
   public function company() {
       return $this->belongsTo(Company::class);
   }
}

Ahora el usuario puede compartir fácilmente el código del rasgo, por palabra clave using. Este es un ejemplo y, en la mayoría de los casos, se necesitaría un caso de uso más complejo para que tenga sentido.

class User {
   use HasCompany;
}

Repositorios

Los repositorios son un patrón de diseño para abstraer capas de datos de la aplicación. Su lógica no debería preocuparse por cómo almacena los datos, por lo que si quisiera cambiar de Mysql a Mongodbsolo cambiaría el repositorio y no tendría que cambiar la lógica empresarial.

Muy obstinado aquí, pero este no es un patrón de diseño apropiado para Laravel. Laravel tiene Eloquent y, por lo tanto, la capa de la base de datos ya está abstraída. A veces se utilizan repositorios para Laravel aplicaciones, sino más bien un valor atípico, que una vista común. Una de las razones principales de los repositorios es ser independiente de la implementación de datos, que ya existe y puede cambiar entre servidores SQL sin problemas. También Eloquents características como ::find(), scopes etc. se siente como un reemplazo para los Repositorios y es peculiar de usar al mismo tiempo.

Si usas Doctrine como el ORMque puedes en Laraveles el núcleo de su arquitectura y debe utilizarse.

Servicios

Se usa comúnmente como un lugar para almacenar la lógica comercial o los componentes básicos de sus acciones en su aplicación. En tradicional MVC diseño, los controladores solo deben manejar la entrada. Normalmente, colocaría su lógica en Modelos, pero se “engordan” muy rápidamente, cuando esto sucede, los servicios son un lugar común para colocar la lógica empresarial. A veces también se nombran acciones o comandos, que son enfoques similares pero un poco diferentes.

Una de las cosas principales que resuelve es hacer que su lógica comercial sea reutilizable. Imágenes que filtran a todos los usuarios por un indicador activo, cuando lo recupera en su controlador.

public function all() {
    return User::where('active', true)->get();
}

Ahora que tiene su lógica comercial, que exige que solo trabaje en usuarios activos, luego desea notificar a todos los usuarios activos con un correo electrónico, mediante notificaciones usando un comando.

class NotifyUsers extends Command {
    public function handle() {
        foreach (User::where('active', true)->get() as $user) {
            $user->notify();
        }
    }
}

Ahora debe mantener actualizada la lógica empresarial de forma manual. La próxima vez que agregue una segunda condición o cambie la lógica, debe cambiar el código en dos lugares. En una aplicación grande donde este bloque de código se usa con frecuencia, puede resultar bastante difícil mantener las condiciones sin olvidar uno de los lugares. Si crea un servicio con esta lógica, puede utilizar fácilmente la misma lógica comercial en toda la aplicación. Si bien uno tiene un lugar para cambiar el código, si esta lógica tuviera que cambiar.

class UserService {
    public function all() {
        return User::where('active', true)->get();
    }
}

Dondequiera que desee utilizar esta lógica empresarial para obtener usuarios activos, puede utilizar el servicio. Por lo tanto, solo tiene un lugar para mantener la lógica. Una llamada puede ser tan simple como resolve(UserService::class)->all(). Ejemplo de la lógica actualizada con servicios sería.

// controller
public function all(UserService $userService) {
    return $userService->all();
}

// command
class NotifyUsers extends Command {
    public function handle(UserService $userService) {
        $userService->all()->each->notify();
    }
}

Conclusión

El mundo no es blanco y negro, tienes que descubrir tu propio enfoque. Mi consejo es, no pierdas tiempo en Repositorios, Laravel tiene muchas características para manejar operaciones relacionadas con datos scopes, getters setters etc. que entra en conflicto con el patrón de diseño del Repositorio. Vea si un enfoque de diseño similar a un servicio le conviene y puede utilizarlo. Traits no es tanto un patrón de diseño arquitectónico, sino una alternativa de herencia de clase, simplemente para compartir lógica entre clases.

  • Eso fue perfecto, más como un artículo que como una respuesta en realidad, ¡muchas gracias!

    – J. Doe

    3 de febrero de 2020 a las 1:14

  • Me alegro de que te haya gustado, este es un tema muy esponjoso, la opinión y la religión importan más que los hechos 🙂

    – señor

    3 de febrero de 2020 a las 1:21

  • ¿Sería preferible la capa de servicio para la paginación y su lógica?

    – Shulz

    3 de noviembre de 2021 a las 10:40

  • Hmm… En general, no veo la correlación con la paginación y estos patrones de diseño. Como estos ya están hechos en Laravel en el generador de consultas, generalmente solo los uso y transformo la metainformación del generador de consultas en la respuesta.

    – señor

    3 de noviembre de 2021 a las 11:57

  • Amablemente agregaré a la discusión sobre Repositorios vs modelos Elocuentes. Los repositorios en Laravel son muy útiles en grandes proyectos con: 1) Abstracción de mecanismos complejos de almacenamiento en caché. 2) Componer conjuntos de datos complejos y dinámicos en función del usuario autenticado, el entorno, el estado de los datos, etc. 3) Abstracción de transacciones con lógica de inserción/actualización de datos complejos de varias tablas.

    – Umur Karagoz

    27 abr a las 20:33

¿Ha sido útil esta solución?