Laravel 6-7 我怎样才能 Override/Change 成为供应商 Class?

Laravel 6-7 How Can I Override/Change a Vendor Class?

我最近 运行 遇到一个问题,我需要更改 Laravel 的供应商文件之一以获得所需的结果。 该文件是 vendor/laravel/framework/Illuminate/Routing/CompileRouteCollection.php.

在该文件中,需要更改一个函数。

protected function requestWithoutTrailingSlash(Request $request)
{
    $trimmedRequest = Request::createFromBase($request);

    $parts = explode('?', $request->server->get('REQUEST_URI'), 2);

    $trimmedRequest->server->set(
        'REQUEST_URI', rtrim($parts[0], '/').(isset($parts[1]) ? '?'.$parts[1] : '')
    );

    return $trimmedRequest;
}

更具体地说,这部分:rtrim($parts[0], '/')。最后的那个 / 需要被删除,以便我的部分路线能够正常工作。

我尝试在里面创建自己的自定义 class:App\Helpers\CompiledRouteCollection.php。我在其中复制了上面列出的函数并进行了自己的更改。

App\Helpers\CompiledRouteCollection.php

namespace App\Helpers;

use Illuminate\Http\Request;

class CompiledRouteCollection extends \Illuminate\Routing\CompiledRouteCollection
{
    protected function requestWithoutTrailingSlash(Request $request)
    {
        $trimmedRequest = Request::createFromBase($request);

        $parts = explode('?', $request->server->get('REQUEST_URI'), 2);

        $trimmedRequest->server->set(
            'REQUEST_URI', rtrim($parts[0], '').(isset($parts[1]) ? '?'.$parts[1] : '')
        );

        return $trimmedRequest;
    }
}

然后我进入 App\Providers\AppServiceProvider 并且我 运行 在寄存器函数里面。

public function register()
{
    $loader = AliasLoader::getInstance();
    $loader->alias('App\Helpers\CompiledRouteCollection', 'Illuminate\Routing\CompiledRouteCollection');
}

但是没有任何反应。

更新 1

我将别名更改为:

$loader = AliasLoader::getInstance();
$loader->alias('Illuminate\Routing\CompiledRouteCollection', 'App\Helpers\CompiledRouteCollection');

但现在在我的助手 class 它 returns 尝试访问任何页面时出现此错误: Class 'Illuminate\Routing\CompiledRouteCollection' not found

非常感谢任何有兴趣帮助我的人。如果您需要更多信息,请告诉我!

如果您需要更多上下文,我在 laravel/framework 上提出了一个问题,其中包含完整的背景解释 here

在别名中,第一个参数必须是供应商 class,之后被覆盖 class

public function register()
{
    $loader = AliasLoader::getInstance();
    $loader->alias(CompileRouteCollection::class, CompiledRouteCollection::class);
}

public function register()
{
    $loader = AliasLoader::getInstance();
    $loader->alias('Illuminate/Routing/CompileRouteCollection', 'App\Helpers\CompiledRouteCollection');
}

如你所愿))

我改用 composer 来 ovveride 文件,因为我以前的方法不管用。这是我所做的。

首先,我在 composer.json 文件的自动加载部分添加了以下内容:

"exclude-from-classmap": [
    "vendor\laravel\framework\src\Illuminate\Routing\CompiledRouteCollection.php"
],
"psr-4": {
    "App\": "app/",
    "Illuminate\": "app/Overrides/"
},

接下来,我在应用程序文件夹中创建了 Ovverides 文件夹,然后我复制了 CompiledRouteCollection.php 文件并将其粘贴到 Ovverides 文件夹中。

尝试在 RouteServiceProvider 而不是 AppServiceProvider

中换掉它

只是猜测,因为它是路由系统的一部分。在到达 AppServiceProvider 之前,它可能已经作为原始 class 被调用。

我在 https://github.com/laravel/framework/issues/32082 上查看了您的问题,令我惊讶的是他们没有建议尝试。如果我没记错 Laravel 的请求生命周期,RouteServiceProvider 可能 是你的票。

我很钦佩你在寻找解决方法方面的足智多谋。

根据我的经验,你可以这样做:

  1. App\Providers\AppServiceProvider .
  2. 的register函数中添加以下内容
public function register()
{
    $loader = AliasLoader::getInstance();
    $loader->alias('Illuminate\Routing\CompileRouteCollection', 'App\Helpers\CompiledRouteCollection');
}
  1. 像这样编辑作曲家文件。
"psr-4": {
    "App\": "app/",
    "Illuminate\Routing\": "app\Helpers\"
},

然后请compose install和运行项目。

您可以在 composer

中覆盖供应商 classes

您需要编辑您的 composer.json 文件并在自动加载部分添加两行额外的行以替换实现。

"exclude-from-classmap": ["vendor/packagename/diraction/to/File.php"],
"files": ["app/Overrides/File.php"]

第一行将不加载原始 class,第二行 class 将指向原始 class,并为您的实现提供适当的命名空间。

然后您需要创建 app/Overrides 文件夹并将 File.php(您要覆盖的文件)复制到其中。

最后一步是 运行:

composer dump-autoload

一切顺利!