Saltar al contenido

Mismo controlador de recursos de Laravel para múltiples rutas

Este grupo de expertos pasados muchos días de investigación y recopilar de datos, encontramos la solución, esperamos que te resulte útil para tu trabajo.

Solución:

Por lo tanto, desea evitar el código duplicado para los controladores de recursos de pedidos y cumplimiento y ser un poco SECO. Bueno.

Los rasgos no se pueden escribir

Como dijo Matthew, no puede escribir rasgos y esa es la razón por la que recibe el error de resolución de enlace. Aparte de eso, incluso si se puede escribir a máquina, el contenedor se confundiría sobre qué modelo debería instanciar, ya que hay dos Commentable modelos disponibles. Pero lo veremos más tarde.

Interfaces junto con rasgos

A menudo es una buena práctica tener una interfaz para acompañar un rasgo. Además del hecho de que las interfaces pueden ser mecanografiadas, se está adhiriendo al principio de Segregación de Interfaces que, “si es necesario”, es una buena práctica.

interface Commentable 

    public function comments();


class Order extends Model implements Commentable

    use Commentable;

    // ...

Ahora que se puede escribir a máquina. Vayamos al problema de la confusión del contenedor.

Enlace contextual

El contenedor de Laravel admite enlaces contextuales. Esa es la capacidad de decirle explícitamente cuándo y cómo resolver un resumen en un concreto.

El único factor distintivo que tiene para sus controladores es la ruta. Necesitamos construir sobre eso. Algo parecido a:

# AppServiceProvider::register()
$this->app
    ->when(CommentController::class)
    ->needs(Commentable::class)
    ->give(function ($container, $params) 
        // Since you're probably utilizing Laravel's route model binding, 
        // we need to resolve the model associated with the passed ID using
        // the `findOrFail`, instead of just newing up an empty instance.

        // Assuming this route pattern: "order);

Básicamente le estás diciendo al contenedor cuando el CommentController requiere un Commentable Por ejemplo, primero verifique la ruta y luego cree una instancia del modelo comentable correcto.

El enlace no contextual también funcionará:

# AppServiceProvider::register()
$this->app->bind(Commentable::class, function ($container, $params) 
    $id = (int) $this->app->request->segment(2);

    return $this->app->request->segment(1) === 'order'
        ? Order::findOrFail($id)
        : Fulfillment::findOrFail($id);
);

Herramienta incorrecta

Acabamos de eliminar el código de controlador duplicado al introducir una complejidad innecesaria que es peor que eso.

Aunque funciona, es complejo, no se puede mantener, no es genérico y, lo peor de todo, depende de la URL. Está usando la herramienta incorrecta para el trabajo y es simplemente incorrecto.

Herencia

La herramienta adecuada para eliminar estos problemas es simplemente la herencia. Introduzca una clase de controlador de comentarios base abstracta y amplíe dos superficiales a partir de ella.

# AppHttpControllersCommentController
abstract class CommentController extends Controller

    public function store(CreateCommentRequest $request, Commentable $commentable) 
        // ...
    

    // All other common methods here...


# AppHttpControllersOrderCommentController
class OrderCommentController extends CommentController

    public function store(CreateCommentRequest $request, Order $commentable) 
        return parent::store($commentable);
    


# AppHttpControllersFulfillmentCommentController
class FulfillmentCommentController extends CommentController

    public function store(CreateCommentRequest $request, Fulfillment $commentable) 
        return parent::store($commentable);
    


# Routes
Route::resource('order.comment', 'OrderCommentController');
Route::resource('fulfillments.comment', 'FulfillCommentController');

Simple, flexible y mantenible.

Arrrgh, idioma incorrecto

No tan rapido:

Declaración de OrderCommentController :: store (CreateCommentRequest $ request, Order $ commentable) debe ser compatible con CommentController :: store (CreateCommentRequest $ request, Commentable $ commentable).

Aunque anular los parámetros del método funciona bien en los constructores, ¡simplemente no lo hace con otros métodos! Los constructores son casos especiales.

Podríamos simplemente dejar las sugerencias tipográficas en las clases para padres e hijos y seguir con nuestras vidas con identificaciones simples. Pero en ese caso, como el enlace de modelo implícito de Laravel solo funciona con sugerencias tipográficas, no habrá ninguna carga de modelo automática para nuestros controladores.

Ok, quizás en un mundo mejor.

Actualización: consulte el soporte de PHP 7.4 para la variación de tipo

Enlace de modelo de ruta explícito

Entonces, ¿qué vamos a hacer?

Si le decimos explícitamente al enrutador cómo cargar nuestro Commentable modelos, podemos usar el solitario CommentController clase. El enlace de modelo explícito de Laravel funciona mapeando marcadores de posición de ruta (p. Ej. order) para modelar clases o lógicas de resolución personalizadas. Entonces, mientras usamos nuestro single CommentController podemos utilizar modelos separados o lógicas de resolución para pedidos y entregas en función de sus marcadores de posición de ruta. Entonces, dejamos caer la sugerencia tipográfica y confiamos en el marcador de posición.

Para los controladores de recursos, el nombre del marcador de posición depende del primer parámetro que pase al Route::resource método. Solo haz un artisan route:list descubrir.

Bien, hagámoslo:

# AppProvidersRouteServiceProvider::boot()
public function boot()

    // Map `order` route placeholder to the AppOrder model
    $this->app->router->model('order', AppOrder::class);

    // Map `fulfillment` to the AppFulfilment model
    $this->app->router->model('fulfillment', AppFulfilment::class);

    parent::boot();

Su código de controlador sería:

# AppHttpControllersCommentController
class CommentController extends Controller

    // Note that we have dropped the typehint here:
    public function store(CreateCommentRequest $request, $commentable) 
        // $commentable is either an AppOrder or a AppFulfillment
    

    // Drop the typehint from other methods as well.

Y las definiciones de ruta siguen siendo las mismas.

Es mejor que la primera solución, ya que no depende de los segmentos de URL que son propensos a cambiar al contrario de los marcadores de posición de ruta que rara vez cambian. También es genérico como todos orders se resolverá en AppOrder modelo y todo fulfillments para el AppFulfillment.

Podríamos modificar la primera solución para utilizar parámetros de ruta en lugar de segmentos de URL. Pero no hay razón para hacerlo manualmente cuando Laravel nos lo ha proporcionado.


Sí, lo sé, yo tampoco me siento bien.

Si sostienes algún cuestión o capacidad de ascender nuestro reseña eres capaz de realizar una nota y con deseo lo leeremos.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *