【问题标题】:Laravel dependency injection with base class带有基类的 Laravel 依赖注入
【发布时间】:2017-11-26 21:31:01
【问题描述】:

我对 Laravel 比较陌生,我已经创建了一个中间件和策略来处理我的项目中的“Ownable”Eloquent 对象。

我使用 trait 做到了这一点:

trait Ownable
{

    public function user(){
        return $this->belongsTo(User::class, 'created_by');
    }
}

在我的政策中,我只是这样做:

class RightPolicy
{
    use HandlesAuthorization;

    public function update(User $user, Ownable $ownable)
    {
        return $ownable->created_by == $user->id;
    }
}

还有我的中间件,分配给我的控制器中的正确操作:

class CheckRights
{
    public function __construct(Route $route, Ownable $object) {
        $this->route = $route;
        $this->object = $object;
    }

    public function handle($request, Closure $next)
    {
         // @TODO handle request
    }
}

然后我使用 Ownable trait 创建了一个类:

class Thread extends Model
{
    use Ownable;
}

但是,当我尝试使用这种结构运行项目时,Laravel 的依赖注入器会报错:

在构建 App\Http\Middleware\CheckRights 时目标 [App\Ownable] 不可实例化

有没有办法让依赖注入器知道实例化正确的类(可能使用路由或其他方式)?

如果没有,是否有一种方便的方法可以在没有依赖注入器的情况下执行其他操作以确保实例化正确的类?

【问题讨论】:

  • 根据定义,特征不可实例化。我认为您在这里不需要 trait,更多的是关于 Class 和 Extends
  • 我明白,我在这里使用特征是出于多态的原因。线程是可拥有的,但也是可评论的,但是,论坛规则不是可拥有的,而是可评论的(例如)。这就是我选择这种结构的原因。 @VincentDecaux
  • 使用 Trait 的结果总是可以写成一个有效的类。当 Laravel 在该特征中应用自动解析时,它会尝试初始化不起作用。所以如果你想达到你想要的程度,你的方法是切换到一个类而不是在这里使用一个特征。
  • 中间件如何知道要检查假设绑定模型的请求时要检查的输入?不确定为什么您需要该中间件的构造函数中的任何内容,因为请求本身可以访问您需要检查的内容。

标签: php laravel dependency-injection eloquent laravel-5.5


【解决方案1】:

我通过使用 AppServiceProvider 中的 app::bind 方法解决了这个问题。

在服务提供者的注册方法中,我将一个 App\Ownable 接口绑定到一个函数,该函数循环遍历传递给路由器的所有注入的 Eloquent 对象。

namespace App\Providers;

use App\Ownable;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Schema;

class AppServiceProvider extends ServiceProvider
{
    public function boot()
    {
        Schema::defaultStringLength(191);
    }

    public function register()
    {
        // Binding ownable trait/interface for correctly handling policy
        $this->app->bind('App\Ownable', function() {
            // Get all parameters passed to the current route
            $array = Route::getCurrentRoute()->parameters;

            $return = NULL;
            foreach ($array as $object){
                if ($object instanceof Ownable){
                    // Fetch the last ownable instance found passed to the route
                    $return = $object;
                }
            }

            // return it
            return $return;
        });
    }
}

阅读更多:Binding

然后我将 Ownable 特征与用于正确类型提示的界面结合起来,正如其他网站上的论坛所建议的那样:

class Thread extends Model implements \App\Interfaces\Ownable
{
    use Ownable;
}

然后在我的中间件构造函数中,我将 ownable 参数设为可选(用于调用 store 或 create 操作且未给出对象时)并根据操作名称以及是否给出对象来处理我的请求

class CheckRights
{
    public function __construct(Route $route, Ownable $object = null) {
        $this->route = $route;
        $this->object = $object;
    }

    public function handle($request, Closure $next)
    {
        // Get the controller's action name
        $action = $this->route->getActionName();
        $action = substr($action, strpos($action, '@') + 1);

        // Check if an object is given in the request
        if ($action != 'store' && $action != 'create' && isset($this->object)){
            // Check if gate allows user to update/delete object
            if ($request->user()->can($action, $this->object)){
                return $next($request);
            }
        }elseif($action == 'store' || $action == 'create'){
            // Check if gate allows user to create object
            if ($request->user()->can($action, Ownable::class)){
                return $next($request);
            }
        }

        return back();
    }
}

【讨论】:

    猜你喜欢
    • 2015-09-03
    • 1970-01-01
    • 2014-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-10
    相关资源
    最近更新 更多