Внедрение зависимостей Laravel с базовым классом

Я относительно новичок в Laravel, и я создал промежуточное программное обеспечение и политику для обработки объектов Eloquent, находящихся в собственности, в моем проекте.

Я сделал это, используя черту:

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:

class Thread extends Model
{
    use Ownable;
}

Однако, когда я пытаюсь запустить проект с этой структурой, инжектор зависимостей Laravel выдает ошибку:

Цель [App\Ownable] не может быть создана при сборке App\Http\Middleware\CheckRights

Есть ли способ сообщить инжектору зависимостей о создании экземпляра правильного класса (возможно, используя маршруты или что-то еще)?

Если нет, есть ли удобный способ сделать что-то еще без инжектора зависимостей, чтобы убедиться, что создан правильный класс?


person Joas    schedule 25.11.2017    source источник
comment
Черта не может быть создана по определению. Я не думаю, что вам нужна черта здесь, это больше о классе и расширениях   -  person Vincent Decaux    schedule 26.11.2017
comment
Я понимаю, что здесь я использую трейты из соображений полиморфности. Тема принадлежит, но также комментируется, однако ForumRule не принадлежит, но комментируется (например). Именно поэтому я выбрал для этого типа структуры. @VincentDecaux   -  person Joas    schedule 26.11.2017
comment
Результат использования Trait всегда может быть записан как действительный самостоятельный класс. Когда Laravel применяет автоматическое разрешение в этом трейте, он пытается инициализировать его, что не работает. Таким образом, ваш способ будет заключаться в том, чтобы переключиться на класс вместо использования здесь черты, если вы хотите перейти к нужной точке.   -  person Leo    schedule 26.11.2017
comment
как промежуточное программное обеспечение узнает, какие входные данные нужно проверить в запросе на проверку предполагаемой связанной модели? Не уверен, зачем вам что-то нужно в конструкторе этого промежуточного программного обеспечения, поскольку сам запрос будет иметь доступ к тому, что вам нужно проверить.   -  person lagbox    schedule 26.11.2017


Ответы (1)


Я решил эту проблему, используя метод app::bind в AppServiceProvider.

В методе регистрации поставщика услуг я привязал интерфейс 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;
        });
    }
}

Подробнее о привязке

Затем я объединил трейт Ownable с интерфейсом для корректной подсказки типов, как было предложено на форуме другого сайта:

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

Затем в моем конструкторе промежуточного программного обеспечения я сделал собственный параметр необязательным (для случаев, когда вызывается действие хранилища или создания, а объект не указан) и обрабатывал мой запрос на основе имени действия и если объект задан

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();
    }
}
person Joas    schedule 26.11.2017