所有控制器和视图的全局变量

Posted

技术标签:

【中文标题】所有控制器和视图的全局变量【英文标题】:global variable for all controller and views 【发布时间】:2014-10-01 02:28:06 【问题描述】:

在 Laravel 中,我有一个表设置,并且我从 BaseController 中的表中获取了完整的数据,如下所示

public function __construct() 

    // Fetch the Site Settings object
    $site_settings = Setting::all();
    View::share('site_settings', $site_settings);

现在我想访问 $site_settings。在所有其他控制器和视图中,这样我就不需要一次又一次地编写相同的代码,所以任何人请告诉我解决方案或任何其他方式,以便我可以从表中获取数据一次并在所有控制器中使用它和查看。

【问题讨论】:

你为什么不用configuration files? Laravel: Where to store global arrays data and constants? 可能重复使用 Config::set('foo.bar', 'test'); 【参考方案1】:

好的,我将完全忽略那些荒谬的过度工程和假设,其他答案充斥着其他答案,并选择简单的选项。

如果您可以在每个请求期间进行一次数据库调用,那么方法很简单,令人震惊的是:

class BaseController extends \Controller


    protected $site_settings;

    public function __construct() 
    
        // Fetch the Site Settings object
        $this->site_settings = Setting::all();
        View::share('site_settings', $this->site_settings);
    


现在,如果您的所有控制器都扩展了这个 BaseController,它们就可以做到$this->site_settings

如果您希望限制跨多个请求的查询数量,您可以使用之前提供的缓存解决方案,但根据您的问题,简单的答案是类属性。

【讨论】:

这是满足我需求的最佳解决方案。谢谢! 这不适用于从未碰到控制器的视图(即在您的站点过滤器中显示的视图) 在 App::error() 处理程序中显示视图时会发生什么? 是的,但如果不是呢?许多网站,例如 ***,至少会加载基本详细信息,例如当前登录用户的错误页面。您当然可以在每个处理程序中复制代码,但最好找到一个通用的解决方案。 您的回答对于 OPs 问题完全有效,这就是为什么我没有否决它(尽管我觉得 OP 已经知道如何使用成员变量)。但是,值得一提的是您的解决方案不起作用的常见情况。【参考方案2】:

首先,配置文件适用于此类事情,但您也可以使用另一种方法,如下所示(Laravel - 4):

// You can keep this in your filters.php file
App::before(function($request) 
    App::singleton('site_settings', function()
        return Setting::all();
    );

    // If you use this line of code then it'll be available in any view
    // as $site_settings but you may also use app('site_settings') as well
    View::share('site_settings', app('site_settings'));
);

要在您可能使用的任何控制器中获取相同的数据:

$site_settings = app('site_settings');

有很多方法,只使用一种或另一种,你喜欢哪一种,但我使用的是Container

【讨论】:

但是当我使用这种方法时,我会在控制器和视图中获取数据,但数据的形式类似于 Illuminate\Database\Eloquent\Collection Object ([items:protected] => Array ( [0] => Setting Object ( [table:protected] => settigs 和 multiplemarray in now 告诉我如何从这里访问数据 @ollieread,这并不意味着这是一种错误的方法,我已经在回答中提到了There are many ways, just use one or another, which one you prefer but I'm using the Container。在对任何答案投反对票之前,请三思。我的回答也是正确的。 +1 这是一个很好的答案,根本没有过度设计,比把它放在你的控制器中更简单更好 我认为这是最好的答案。使用这种方法,变量在应用程序范围内实际上是全局的。 这个答案很好,在 Laravel 中有一百万种方法可以实现某些东西,你可以花很长时间在堆栈中重构你的方式以寻求完美,在这种情况下是 Config 类,但在你的自己的风格完全没问题。【参考方案3】:

使用 Config 类:

Config::set('site_settings', $site_settings);

Config::get('site_settings');

http://laravel.com/docs/4.2/configuration

在运行时设置的配置值仅针对当前请求设置,不会延续到后续请求。

【讨论】:

IMO 这是更好的答案。 记得清除你的配置文件。 php artisan config:clear【参考方案4】:

在 Laravel 5+ 中,您可以在 config 文件夹中创建一个文件并在其中创建变量并在整个应用程序中使用它。 例如,我想根据站点存储一些信息。 我创建了一个名为site_vars.php 的文件, 看起来像这样

<?php
return [
    'supportEmail' => 'email@gmail.com',
    'adminEmail' => 'admin@sitename.com'
];

现在可以在routescontrollerviews 中使用

Config::get('site_vars.supportEmail')

如果我这样的话在意见中

 Config::get('site_vars.supportEmail') 

它会给 email@gmail.com

希望这会有所帮助。

编辑- 您还可以在.env 文件中定义变量并在此处使用它们。 我认为这是最好的方法,因为它可以让您灵活地在本地机器上使用所需的值。

所以,你可以在数组中这样做

'supportEmail' => env('SUPPORT_EMAIL', 'defaultmail@gmail.com')

重要 - 完成此操作后,不要忘记在生产环境中执行此操作

php artisan config:cache

万一还是有问题,那么你可以这样做(通常它永远不会发生,但如果它发生了,仍然会发生)

php artisan cache:clear
php artisan config:cache

在你的local env 中,添加它之后总是这样做

php artisan config:clear 

最好不要在本地缓存配置变量。万一它被缓存了,这将删除缓存并加载新的更改。

【讨论】:

BaseController 的答案很好,但是这个确实可以确保您的数据在 Controller 之外的任何地方都可用,所以我会选择这个。您还可以在“site_settings”中设置默认值,这样如果缺少某些值就不会出错【参考方案5】:

我明白了,5.4+ 仍然需要这个,我也遇到了同样的问题,但是没有一个答案是足够干净的,所以我尝试使用ServiceProviders 来实现可用性。这是我所做的:

    创建了提供者SettingsServiceProvider
php artisan make:provider SettingsServiceProvider
    创建了我需要的模型 (GlobalSettings)
php artisan make:model GlobalSettings
    \App\Providers\SettingsServiceProvider 中编辑了生成的register 方法。如您所见,我使用 Setting::all() 的 eloquent 模型检索我的设置。
 

    public function register()
    
        $this->app->singleton('App\GlobalSettings', function ($app) 
            return new GlobalSettings(Setting::all());
        );
    

 
    GlobalSettings中定义了一些有用的参数和方法(包括需要Collection参数的构造函数)
 

    class GlobalSettings extends Model
    
        protected $settings;
        protected $keyValuePair;

        public function __construct(Collection $settings)
        
            $this->settings = $settings;
            foreach ($settings as $setting)
                $this->keyValuePair[$setting->key] = $setting->value;
            
        

        public function has(string $key) /* check key exists */ 
        public function contains(string $key) /* check value exists */ 
        public function get(string $key) /* get by key */ 
    

 
    最后我在config/app.php注册了提供者
 

    'providers' => [
        // [...]

        App\Providers\SettingsServiceProvider::class
    ]

 
    使用php artisan config:cache 清除配置缓存后,您可以按如下方式使用您的单例。
 

    $foo = app(App\GlobalSettings::class);
    echo $foo->has("company") ? $foo->get("company") : "Stack Exchange Inc.";

 

您可以在 Laravel Docs > Service Container and Laravel Docs > Service Providers 中阅读更多关于服务容器和服务提供者的信息。

这是我的第一个答案,我没有太多时间写下来,所以格式有点冗长,但我希望你能得到一切。


我忘了包含SettingsServiceProviderboot 方法,以使设置变量在视图中全局可用,所以你去吧:

 

    public function boot(GlobalSettings $settinsInstance)
    
        View::share('globalsettings', $settinsInstance);
    

 

在调用启动方法之前,所有的提供者都已经注册好了,所以我们可以使用我们的GlobalSettings实例作为参数,这样它就可以被Laravel注入了。

在刀片模板中:

 

     $globalsettings->get("company") 

 

【讨论】:

【参考方案6】:

BaseController 最流行的答案在 Laravel 5.4 上对我不起作用,但他们在 5.3 上起作用。不知道为什么。

我找到了一种适用于 Laravel 5.4 的方法,甚至可以为跳过控制器的视图提供变量。当然,您可以从数据库中获取变量。

添加您的app/Providers/AppServiceProvider.php

class AppServiceProvider extends ServiceProvider

    public function boot()
    
        // Using view composer to set following variables globally
        view()->composer('*',function($view) 
            $view->with('user', Auth::user());
            $view->with('social', Social::all()); 
            // if you need to access in controller and views:
            Config::set('something', $something); 
        );
    

信用:http://laraveldaily.com/global-variables-in-base-controller/

【讨论】:

这是最新 Laravel 的答案(我的是 5.8)【参考方案7】:
View::share('site_settings', $site_settings);

添加到

app-&gt;Providers-&gt;AppServiceProvider文件启动方式

它是全局变量。

【讨论】:

【参考方案8】:

在 Laravel 5+ 中,只需设置一次变量并“全局”访问它,我发现将其作为属性添加到请求中最简单:

$request->attributes->add(['myVar' => $myVar]);

然后您可以使用以下任何控制器从任何控制器访问它:

$myVar = $request->get('myVar');

并从您的任何刀片使用:

 Request::get('myVar') 

【讨论】:

使用$request-&gt;merge(['myVar'=&gt;$myVar]);会更安全。【参考方案9】:

在 Laravel 5.1 中,我需要一个全局变量,其中填充了可在所有视图中访问的模型数据。

我对 ollieread 的回答采用了类似的方法,并且能够在任何视图中使用我的变量 ($notifications)。

我的控制器位置:/app/Http/Controllers/Controller.php

<?php

namespace App\Http\Controllers;

use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;

use App\Models\Main as MainModel;
use View;

abstract class Controller extends BaseController

    use AuthorizesRequests, DispatchesJobs, ValidatesRequests;

    public function __construct() 
        $oMainM = new MainModel;
        $notifications = $oMainM->get_notifications();
        View::share('notifications', $notifications);
    

我的模型位置:/app/Models/Main.php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use DB;

class Main extends Model

    public function get_notifications() ...

【讨论】:

【参考方案10】:

我找到了一种更好的方法,可以在 Laravel 5.5 上运行,并使变量可以被视图访问。您可以从数据库中检索数据,通过导入模型来执行您的逻辑,就像在控制器中一样。

“*”表示您引用了所有视图,如果您研究得更多,您可以选择要影响的视图。

添加你的 app/Providers/AppServiceProvider.php

<?php

    namespace App\Providers;

    use Illuminate\Contracts\View\View;

    use Illuminate\Support\ServiceProvider;
    use App\Setting;

class AppServiceProvider extends ServiceProvider

    /**
     * Bootstrap any application services.
     *
     * @return void
    */
    public function boot()
    
        // Fetch the Site Settings object
        view()->composer('*', function(View $view) 
            $site_settings = Setting::all();
            $view->with('site_settings', $site_settings);
        );
    

    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    

    

【讨论】:

我喜欢这种方法,但它又快又脏。不是 IMO 的长期解决方案。 问题是只能在那个视图中访问【参考方案11】:

如果您担心重复的数据库访问,请确保您在方法中内置了某种缓存,以便每个页面请求仅进行一次数据库调用。

类似(简化示例):

class Settings 

    static protected $all;

    static public function cachedAll() 
        if (empty(self::$all)) 
           self::$all = self::all();
        
        return self::$all;
    

然后您将访问Settings::cachedAll() 而不是all(),这只会对每个页面请求进行一次数据库调用。后续调用将使用缓存在类变量中的已检索内容。

上面的例子非常简单,并且使用了内存缓存,所以它只持续一个请求。如果你愿意,你可以使用 Laravel 的缓存(使用 Redis 或 Memcached)在多个请求中持久化你的设置。您可以在此处阅读有关非常简单的缓存选项的更多信息:

http://laravel.com/docs/cache

例如,您可以向 Settings 模型添加一个方法,如下所示:

static public function getSettings() 
    $settings = Cache::remember('settings', 60, function() 
        return Settings::all();
    );
    return $settings;

这只会每 60 分钟调用一次数据库,否则它会在您调用 Settings::getSettings() 时返回缓存值。

【讨论】:

但是如果设置发生变化而不是从缓存值中检索数据而不是新值的更新方式会发生什么 那么您还必须实现缓存清除逻辑。这更多地属于缓存管理策略,但在 Laravel 的情况下,最简单的方法是向模型的 saving() 事件添加一个侦听器,以清除缓存中的“设置”键(以确保它在下次访问时重新生成) )。 这是对一个简单问题的可怕过度设计方法。 @ollieread 关心扩大批评?他特别要求一种方法来避免每次他想检索他的数据库支持的设置时都进行数据库调用。我提供了两种方法,一种确保每次页面加载一个请求,另一种添加跨请求缓存(因为他的设置可能不会经常更改,甚至可能不需要每次页面加载一个请求)。两者都使用框架,并且与您的解决方案不同,可以在代码库中的任何地方使用,而不仅仅是在控制器和视图中。 我认为这个问题被误解了,他问他如何从他的所有视图和控制器中访问这些数据,而不必每次都调用数据库。简单地说,答案是 BaseController 中的一个类属性。您的缓存解决方案很好,但没有解决 OP 试图解决的核心问题。【参考方案12】:

你也可以使用我正在使用的 Laravel helper。 只需在 App 文件夹下创建 Helpers 文件夹 然后添加以下代码:

namespace App\Helpers;
Use SettingModel;
class SiteHelper

    public static function settings()
    
        if(null !== session('settings'))
          $settings = session('settings');
        else
          $settings = SettingModel::all();
          session(['settings' => $settings]);
        
        return $settings;
    

然后将其添加到您的配置中> app.php 下的别名

'aliases' => [
....
'Site' => App\Helpers\SiteHelper::class,
]

1。在控制器

中使用
use Site;
class SettingsController extends Controller

    public function index()
    
        $settings = Site::settings();
        return $settings;
    

2。在视图中使用:

Site::settings()

【讨论】:

【参考方案13】:

使用middlwares

1- 创建任何名称的中间件

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Support\Facades\View;

class GlobalData

    public function handle($request, Closure $next)
    
        // edit this section and share what do you want
        $site_settings = Setting::all();
        View::share('site_settings', $site_settings);
        return $next($request);
    

2- 在Kernal.php注册你的中间件

protected $routeMiddleware = [
 .
 ...
 'globaldata' => GlobalData::class,
 ]

3-现在使用 globaldata 中间件对您的路由进行分组

Route::group(['middleware' => ['globaldata']], function () 
//  add routes that need to site_settings

【讨论】:

【参考方案14】:

在控制器中使用的全局变量;您可以像这样在 AppServiceProvider 中设置:

public function boot()

    $company=DB::table('company')->where('id',1)->first();
    config(['yourconfig.company' => $company]);

用法

config('yourconfig.company');

【讨论】:

【参考方案15】:

在文件 - \vendor\autoload.php 中,如下定义你的 gobals 变量,应该在最上面一行。

$global_variable = "Some value";//the global variable

在任何地方访问该全局变量:-

$GLOBALS['global_variable'];

享受:)

【讨论】:

【参考方案16】:

有两种选择:

    在 app/libraries/YourClassFile.php 中创建一个 php 类文件

    一个。您在其中创建的任何功能都可以在所有视图和控制器中轻松访问。

    b.如果它是一个静态函数,您可以通过类名轻松访问它。

    c。确保在 Composer 文件的自动加载类映射中包含“app/libraries”。

    在 app/config/app.php 中创建一个变量,你可以使用它来引用它

    Config::get('variable_name');

希望这会有所帮助。

编辑 1:

我的第 1 点示例:

// app/libraries/DefaultFunctions.php

class DefaultFunctions

    public static function getSomeValue()
     // Fetch the Site Settings object
     $site_settings = Setting::all();
     return $site_settings; 
    


//composer.json

"autoload": 
        "classmap": [
..
..
..  
        "app/libraries" // add the libraries to access globaly.
        ]
    

 //YourController.php

   $default_functions  = new DefaultFunctions();
    $default_functions->getSomeValue();

【讨论】:

我在我的问题中添加了一个小示例代码。希望这会有所帮助。 但在应用程序文件夹中我没有​​库文件夹所以我在哪里创建类以及如何生成 jason 文件 如何生成composer.json文件请告诉我我也没有这个文件 @DeepakGoyal 我认为如果您不熟悉 Composer 或向项目添加文件夹,您可能需要更详细地了解基本的 Laravel 文档。这些是 Laravel 中非常基本但核心的概念,如果您对它们的工作方式不满意,您将遇到更多问题。 好吧,抛开更新不谈,这甚至还算不上 PHP。一方面,php 确实使用点作为对象表示法,其次,格式非常糟糕,第三,将功能移动到它自己的对象并不能解决问题,因为现在他必须在任何他想要的地方调用它。简单地说,答案是类属性。

以上是关于所有控制器和视图的全局变量的主要内容,如果未能解决你的问题,请参考以下文章

应用程序关闭后如何快速保存全局变量?

全局变量在不同视图控制器中使用时返回空值

如何在django视图函数中使用全局变量,对所有线程有效。

tp5 跨模块调用模板 所有的变量也要重新定义吗

如何使用 Express / Node.JS 创建可在所有视图中访问的全局变量?

在目标 c 中使用全局变量