0

首先,我使用的是 Laravel 6 和 PHP 7.2。

好吧。我有各种模型,我可以在它们上执行相同的操作。对于 DRY,我想到了以下想法:

在每个模型上,我将实现一个接口,并将用于处理操作的实际实现放在一个可调用的控制器中。

问题是我不知道如何将工作模型路由绑定到这样的实现。

为了让我的问题更容易理解,这里有一些代码片段:

  • 楷模
class Post extends Model implements Actionable { /* attributes, relationships, etc. */ }
class Comment extends Model implements Actionable { /* attributes, relationships, etc. */ }
class User extends Model implements Actionable { /* attributes, relationships, etc. */ }
  • 控制器
class DoActionOnActionable extends Controller
{
    public function __invoke(Actionable $actionable, Request $request) {
        // implementation
    }
}

我知道 Laravel 要做模型路由绑定,它确实需要知道要绑定什么DoActionOnActionable模型

class DoActionOnUser extends DoActionOnActionable
{
    public function __invoke(User $user, Request $request) {
        parent::__invoke($user, $request);
    }
}
class DoActionOnPost extends DoActionOnActionable
{
    public function __invoke(Post $post, Request $request) {
        parent::__invoke($post, $request);
    }
}
class DoActionOnComment extends DoActionOnActionable
{
    public function __invoke(Comment $comment, Request $request) {
        parent::__invoke($comment, $request);
    }
}
  • 路线
Route::post('/users/{user}/actions', 'DoActionOnUser');
Route::post('/posts/{post}/comments/{comment}/actions', 'DoActionOnComment');
Route::post('/posts/{post}/actions', 'DoActionOnPost');

问题是当我向这些路由发送请求时,我需要尽可能多的时间来响应我取消请求。所以,我认为出了点问题,它没有按我预期的那样工作。

我很感激任何能帮助我理解我的实施问题或更好地解决我的问题(DRY)的东西。

4

1 回答 1

1

尝试了不同的方法 - 不完全使用隐式路由模型绑定,而是尝试使用共享控制器

资源管理器

<?php

namespace App;

use ReflectionClass;
use Illuminate\Support\Str;
use Symfony\Component\Finder\Finder;
use Illuminate\Database\Eloquent\Model;

class ResourceManager
{
    public static array $resources = [];

    /**
     * Register resources/models from the class files at given path;
     */
    public static function registerResourcesFrom(string $path): self
    {
        $namespace = rtrim(app()->getNamespace(), '\\');
        $resources = [];
        foreach ((new Finder)->in($path)->files() as $resource) {
            $resource =  $namespace . str_replace(
                ['/', '.php'],
                ['\\', ''],
                Str::after($resource->getPathname(), app_path())
            );

            $reflectionClass = new ReflectionClass($resource);

            if ($reflectionClass->isSubclassOf(Model::class) && !$reflectionClass->isTrait()) {
                $resources[] = $resource;
            }
        }

        static::registerResources($resources);

        return new static;
    }

    /**
     * Register the resources provided as array.
     */
    public static function registerResources(array $resources): self
    {
        static::$resources = array_unique(array_merge(static::$resources, $resources));

        return new static;
    }

    /**
     * Get all registered resources/models
     */
    public static function resources(): array
    {
        return static::$resources;
    }

    /**
     * Get the resource/model class for the given resource name
     */
    public static function resourceClass($resourceName): string
    {
        return collect(static::$resources)->first(
            fn ($resource) => Str::plural(Str::lower(class_basename($resource))) === preg_replace('/[^a-zA-Z0-9]/s', '', $resourceName)
        );
    }
}

在 AppServiceProvider 中


namespace App\Providers;

use App\ResourceManager;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        //Register all model classes from app/Models as resources.

        ResourceManager::registerResourcesFrom(app_path('Models'));
    }
}

控制器 - 显示方法

<?php

namespace App\Http\Controllers;

use App\ResourceManager;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;

class ResourceShowController extends Controller
{
    public function __invoke(Request $request)
    {
        $resource        = $request->route('resource');
        $resourceKey     = $request->route('resourceKey');
        $resourceClass   = ResourceManager::resourceClass($resource);
        $routeKeyName    = (new $resourceClass)->getRouteKeyName();

        $record          = $resourceClass::where($routeKeyName, $resourceKey)->first();
        $primaryKey      = (new $resourceClass)->getKeyName();

        return response()->json(['record' => $record, 'foo' => 'bar']);
    }
}

路线 (web.php)

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\ResourceShowController;


Route::get('/{resource}/{resourceKey}', ResourceShowController::class);

仍然需要扩展嵌套资源路由的概念——目前它只处理非嵌套路由

让我知道它是否有趣 - 如果没有,将删除答案

于 2020-12-04T09:35:29.257 回答