【问题标题】:Laravel - Using Values Returned from Middleware Group for Global VariablesLaravel - 使用从中间件组返回的值作为全局变量
【发布时间】:2019-08-04 20:12:12
【问题描述】:

背景:我想为多个模板网站使用相同的代码。我希望代码能够识别正在访问的域,然后能够设置要在整个应用程序中使用的全局变量。

起初,我创建了 \config\global.php 并让其中的逻辑按预期工作:

$webUrl = url()->current();

/**************************************************
 * Set Conference name based on URL
 **************************************************/
$confId = 0;
$confName = '';
$confAbbrev = '';
if(strpos($webUrl, 'webdomain1') > 0) {
    $confName = 'Domain 1 Full Name';
    $confAbbrev = 'Dom1';
    $confId = 25;
}
elseif(strpos($webUrl, 'webdomain2') >0) {
    $confName = 'Domain 2 Full Name';
    $confAbbrev = 'Dom2';
    $confId = 35;
}

但是,我最终发现“url()”导致了错误,导致我无法在整个应用程序中使用“php artisan”命令。在咨询了我的专业 Web 开发人员同事后,他说对全局变量使用“全局”配置文件并不是最佳实践,而是推荐使用中间件。他控制了我的笔记本电脑并且速度非常快......

在\app\Http\Kernel.php 中,他在$middlewareGroups 末尾添加了SetDomainVariables 行:

    protected $middlewareGroups = [
    'web' => [
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        // \Illuminate\Session\Middleware\AuthenticateSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\VerifyCsrfToken::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
        \App\Http\Middleware\SetDomainVariables::class,
    ],

    'api' => [
        'throttle:60,1',
        'bindings',
    ],
];

然后他创建了一个新文件:\app\Http\Middleware\SetDomainVariables.php

<?php

namespace App\Http\Middleware;

use Closure;

class SetDomainVariables
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        dd($request->getHttpHost());
        return $next($request);
    }
}

“$request->getHttpHost()”的结果是我需要的……它返回 www.foo.com 的“foo”。但是,我不知道如何将此值分配给一个变量并通过“$next”返回它,然后我如何在它周围放置逻辑来设置我可以在 Blade 部分中引用的全局变量等。

谢谢!

编辑:如果使用 \config\global.php 确实是完成我想要的事情的正确方法,我可以在我想要执行“php artisan”命令时注释掉“url()”行吗?

【问题讨论】:

    标签: laravel global-variables middleware


    【解决方案1】:

    有几种不同的方法可以解决这个问题,最简单的方法是使用config——它允许您动态获取和设置配置值。

    1. 创建一个名为 config/sites.php 的新文件,其中包含每个站点的数组,确保每个域都以 www 开头,并将域中的任何 . 替换为 -(因为配置中的 .键将不起作用,因为 Laravel 使用句点来访问子值)。
    return [
        'default' => [
            'id' => 15,
            'name' => 'Default Full Name',
            'abbreviation' => 'Def',
        ],
        'www-webdomain1-com' => [
            'id' => 25,
            'name' => 'Domain 1 Full Name',
            'abbreviation' => 'Web1',
        ],
        'www-webdomain2-com' => [
            'id' => 35,
            'name' => 'Domain 2 Full Name',
            'abbreviation' => 'Web2',
        ],
    ];
    

    您现在可以在应用程序的任何位置访问每个站点的配置值,例如:config('sites.www-webdomain1-com.name')

    1. 将以下内容添加到您的中间件:
    public function handle($request, Closure $next)
    {
        $host = str_slug(starts_with('www.', $request->getHttpHost()));
    
        $configuration = config("sites.{$host}") ?: config('sites.default');
    
        config(['site' => $configuration]);
    
        return $next($request);
    }
    

    您现在已将键 site 的配置值设置为您在 config/sites.php 中为请求域设置的站点配置的内容。

    1. 在您需要访问活动站点的配置选项的任何地方使用config('site.property'),例如:
    Hello, welcome to {{ config('site.name') }}
    

    有更好的方法来解决这个问题,我个人会创建一个Site 模型,然后使用Route Model Binding 但是我在这里概述的方式对于初学者来说很容易设置并且应该满足您的需求。

    【讨论】:

    • 谢谢。如果我走这条路,我能在 config/sites.php 中连接到我的数据库吗?我上面给出的示例(每个客户端网站的硬编码 ID、名称和缩写)更多地只是为了确保我有数据可以测试。但是我的数据库中有一个表,我可以在其中传递域名并动态带回 ID、名称、缩写,以用于正确的会议。现在我有 2 个客户,但如果我有 10 个以上的客户,我觉得单个数据库调用(传递域名)会更具可扩展性。
    • 如果你正在做这个数据库驱动,那么Route Model Binding 是正确的方法,这很容易。您创建一个子域路由组(路由文档中的“子域路由”),并为您在域路由中使用的密钥创建显式路由模型绑定,例如:Route::domain('{conference}.example.com)` 然后Route::bind('conference', ...) --所有这些都包含在文档中。如果您需要更多指导,请告诉我。
    • 为了将来参考,当您提出这样的问题时,最好先概述您想要实现的目标,例如:“我的数据库中有会议,我希望每个会议都有通过模型上的domain 属性确定的唯一子域可访问的页面,例如:conference.example.com 是会议id 1",而不是概述您的解决方案是什么/您认为的解决方案是什么。这为人们提供了帮助您实现目标最必要的信息:)
    • 感谢您的意见。我将在接下来的几天内尝试实施您建议的更改。澄清一点...这些将是单独的域,而不是同一网站的子域。我的第一个客户网站是 www.pac7sports.org ...我的第二个客户将是一个单独的会议。但由于内容的性质(体育比分等),它们将共享同一个数据库,但它们是完全独立的域,我计划在这些域中部署相同的确切代码以最大限度地减少维护。
    • 你不需要多次部署相同的代码库,你可以将多个域指向同一个 Laravel 安装,然后使用域(无论是子域还是完整域)来确定加载哪些数据。
    猜你喜欢
    • 2019-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-20
    • 2014-10-17
    相关资源
    最近更新 更多