php 不同可能Eloquent模型的条件依赖注入控制器方法

tct7dpnv  于 2023-10-15  发布在  PHP
关注(0)|答案(1)|浏览(130)

在我的Laravel项目中,这意味着寻找建筑物租金,我使用了一个具有多态关系的Eloquent模型来存储用户和租金的资格。所以,我有三个相关的模型来解释这个问题:'User'、'Alquiler'(租金)和'Calificacion'(资格),具有在其中定义的多态关系。
在我的“Alquiler”模型中,我定义了:

public function getRouteKeyName()
    {
        return 'slug';
    }

所以当我有一个这样定义的路由时:

GET|HEAD    alquileres/{alquiler} .... alquileres.show › AlquilerController@show

在我的“AlquilerController”中,我可以做:

public function show(Alquiler $alquiler){
    return view('alquileres.show',compact('alquiler'));
}

要轻松获得与已发布租金对应的模型示例,在我的Blade视图中:
<a href="{{route('alquileres.show',$alquiler)}}">...</a>
因此,呈现的链接看起来像:'http://localhost:8000/alquileres/capital-federal-arcos-3130-7-a'
在我的“User”模型中,我没有定义“getRouteKeyName()”方法,所以这个方法只是默认的ID字段。
尽管我可以很容易地为'User'和'Alquiler'执行依赖注入,但当必须在控制器方法中接收的模型可以是'User'或'Alquiler'时,我无法实现类似的东西,这取决于我的路由中定义的第一个参数,所以我编写了以下代码:
web.php:

Route::get('/calificaciones/calificar/{modelo}/{instancia}',  [CalificacionesController::class,'calificar'])->name('calificaciones.calificar');

Route::post('/calificaciones/guardarCalificacion/{modelo}/{instancia}',  [CalificacionesController::class,'guardarCalificacion'])->name('calificaciones.guardarCalificacion');

CalificacionesController.php:

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\User;
use App\Models\Alquiler;
use App\Models\Calificacion;
class CalificacionesController extends Controller{
    ...

     public function calificar(Request $request, $modelo=null, $identificador=null) {
          $instancia=null;
          if($modelo=='usuario'){
               $instancia=User::find((int) $identificador);
          }
          else if($modelo=='alquiler'){
               $instancia=Alquiler::where('slug', $identificador)->firstOrFail();
          }
          return view('calificaciones.calificar',compact(['modelo','instancia']));
     }

     public function guardarCalificacion(Request $request, $modelo=null, $identificador=null) {
         $calificador=auth()->user();
         $instancia=null;
         if($modelo=='usuario'){
              $instancia=User::find((int) $identificador);
         }
         else if($modelo=='alquiler'){
              $instancia=Alquiler::where('slug', $identificador)->firstOrFail();
         }
         Calificacion::create([
               'calificacionable_id' => $instancia->id,
               'calificacionable_type' => get_class($instancia),
               'puntuacion' => $request->puntuacion,
               'comentario' => $request->comentario,
               'calificador_id' => $calificador->id
          ]);
         
         return redirect()->route('calificaciones.calificacionesRealizadas');
     }
    ...
}

所以我得到的一些可能的链接是:
http://localhost:8000/calificaciones/calificar/alquiler/buenos-aires--lomas-del-mirador-liniers-554-12
http://localhost:8000/calificaciones/calification/usuario/2
通过执行<a href="{{route('calificaciones.calificar',['alquiler',$alquiler])}}"<a href="{{route('calificaciones.calificar',['usuario',$alquiler->publicador])}}"
我在其他路由和控制器方法中也有类似的东西。
尽管这种方法有效,但我发现它是一种非常丑陋的方法,因为我无法通过执行依赖注入在方法中获得所需的模型示例,而是通过执行Eloquent查询手动获得。除此之外,如果我在我的“User”模型中定义了一个“getRouteKeyName()”方法,或者如果我在我的“Alquiler”模型中更改了它,那么这段代码将不再工作,所以我需要在所有使用相同方法的方法中编辑它。
我试图通过在我的RouteServiceProvider上做一个显式的路由模型绑定来解决这个问题,如Laravel官方文档和其他地方所示:
https://laravel.com/docs/10.x/routing#route-model-binding www.example.com
然而,我试过的这些方法都不起作用。
有没有人可以建议一个更好的方法来实现我想要的结果,通过能够根据每种情况下我需要的模型执行DI?(或者至少是为了改进我现在的代码)
如果有任何更多的信息需要,或没有正确理解的东西,请让我知道。
太感谢了!
Leandro
编辑:
我几乎找到了一种实现这一点的方法,通过上下文绑定:
我写了一个这样的合约(接口):
Calificable.php:

<?php
namespace App\Contracts;
interface Calificable {}

在我的模型定义中,我做了:

use App\Contracts\Calificable;
class Alquiler extends Model implements Calificable {...

还有:

use App\Contracts\Calificable;
class User extends Model implements Calificable {...

然后,在我的RouteServiceProvider.php中,我添加了:

....
public function boot() {
      ...

        Route::bind('modelo', function (string $value) {
          error_log("Entro al bind de modelo");
          if($value=='usuario'){
               
               $this->app->singleton(Calificable::class, User::class);
          }
          else if($value=='alquiler'){
               $this->app->singleton(Calificable::class, Alquiler::class);
          }
          return $value;
     });
....

最后,在我的控制器方法中,我有:

public function calificar(Request $request, string $modelo, Calificable $instancia){
     error_log(get_class($instancia));
     error_log(json_encode($instancia));
     return view('calificaciones.calificar',compact(['modelo','instancia']));
}

当查看'calife'的第一个'error_log'的结果时,我正确地得到:
应用\型号\用户
或者说:
应用程序\模型\Alquiler
在相应的案例中。
然而,在第二个'error_log'中,我看到了一个空的模型,而不是我应该得到的模型。当我在我的控制器方法上用“Alquiler”或“User”输入提示我的参数时,这不会发生,得到一个成功的结果。
有没有什么方法来完成我试图通过这种方式做什么,只是通过编辑一点点我目前在RouteServiceProvider.php?我想我差不多完成了。

5lwkijsr

5lwkijsr1#

1-静态方法,可维护性更好

考虑到你只有2个选择,实现你的目标的最简单和最干净的方法是像这样分割路线:
web.php

Route::get('/calificaciones/calificar/usuario/{user}',  [CalificacionesController::class,'userCalificar']);

Route::get('/calificaciones/calificar/alquiler/{alquiler}',  [CalificacionesController::class,'alquilerCalificar']);

CalificacionesController.php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\User;
use App\Models\Alquiler;
use App\Models\Calificacion;
class CalificacionesController extends Controller{
    ...

    public function userCalificar(Request $request, User $instancia) {
        return view('calificaciones.calificar',compact(['instancia']));
    }

    public function alquilerCalificar(Request $request, Alquiler $instancia) {
        return view('calificaciones.calificar',compact(['instancia']));
    }
    
    ...
}

没有魔法绑定会让你的代码非常干净,便于将来的开发。

2-动态方法

但如果你或其他人阅读这需要一个更动态的方法,你可以使用这个:
RouteServiceProvider.php

...

        Route::bind('instancia', function ($value, $route) {
            $model = $route->parameter('modelo');

            return match ($model) {
                'usuario' => User::where('id', $value)->firstOrFail(),
                'alquiler' => Alquiler::where('slug', $value)->firstOrFail(),
                default => throw new ModelNotFoundException(),
            };
        });

        ...

CalificacionesController.php

...

    public function userCalificar(Request $request, string modelo, Model $instancia) {
        return view('calificaciones.calificar',compact(['instancia']));
    }
    
    ...

相关问题