81

In Laravel I have a table settings and i have fetched complete data from the table in the BaseController, as following

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

Now i want to access $site_settings. in all other controllers and views so that i don't need to write the same code again and again, so anybody please tell me the solution or any other way so i can fetch the data from the table once and use it in all controllers and view.

Fatih Akgun
  • 479
  • 1
  • 6
  • 18
Deepak Goyal
  • 1,186
  • 2
  • 13
  • 26
  • 2
    Why don't you use the [configuration files](http://laravel.com/docs/configuration)? – Ben Aug 07 '14 at 18:39
  • possible duplicate of [Laravel: Where to store global arrays data and constants?](http://stackoverflow.com/questions/26854030/laravel-where-to-store-global-arrays-data-and-constants) Use Config::set('foo.bar', 'test'); – malhal Jul 09 '15 at 22:33

17 Answers17

67

Okay, I'm going to completely ignore the ridiculous amount of over engineering and assumptions that the other answers are rife with, and go with the simple option.

If you're okay for there to be a single database call during each request, then the method is simple, alarmingly so:

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);
    }

}

Now providing that all of your controllers extend this BaseController, they can just do $this->site_settings.

If you wish to limit the amount of queries across multiple requests, you could use a caching solution as previously provided, but based on your question, the simple answer is a class property.

ChrisF
  • 134,786
  • 31
  • 255
  • 325
ollieread
  • 6,018
  • 1
  • 20
  • 36
  • 4
    This was the best solution for my needs. Thanks! – Pepper Jan 01 '15 at 16:54
  • 3
    This won't work for views that never hit a controller (i.e a view presented in one of your site filters) – Hayley Jan 10 '15 at 17:20
  • @asdasd That's a none issue, views should always come from a controller. The very few cases where you could do it without a controller, wouldn't matter. – ollieread Jan 10 '15 at 17:22
  • 1
    What happens when you present a view in your App::error() handler? – Hayley Jan 10 '15 at 17:34
  • @asdasd I'd imagine that'd be a basic view. – ollieread Jan 10 '15 at 17:36
  • 2
    Yes, but what if it isn't? Many sites, StackOverflow for example, at the very least load basic details such as the current logged in user for error pages. You could of course duplicate the code in each of your handlers, but it would be better to find a universal solution. – Hayley Jan 10 '15 at 17:40
  • The problem here is that you're trying to find a solution to a problem that may or may not exist. OP requested that he be given a method to make that available to all views and controllers, with no stipulation as to extra views outside of controllers. I constantly see people on SO fall down the trap of over engineering, fixing problems that aren't there. – ollieread Jan 10 '15 at 17:44
  • 3
    Your answer is perfectly valid for OPs question, which is why I didn't downvote it (though I feel OP would already know how to use member variables). However, it's worth mentioning common situations where your solution will not work. – Hayley Jan 10 '15 at 18:02
  • 1
    This should be the best answer when you only need to access a Model from whatever view or controller you want. For example a SEO Database where you need to call a $seo_options variable in your layouts (which is extended in the views). – Jorge Peña Oct 31 '17 at 20:09
  • 1
    Note that routed middlewares are not yet run before the controller constructor, so you won't have access to e.g. the sessions (so you don't have Auth, for example). – Csongor Fagyal Sep 11 '22 at 01:07
58

At first, a config file is appropriate for this kind of things but you may also use another approach, which is as given below (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'));
});

To get the same data in any controller you may use:

$site_settings = app('site_settings');

There are many ways, just use one or another, which one you prefer but I'm using the Container.

cweiske
  • 30,033
  • 14
  • 133
  • 194
The Alpha
  • 143,660
  • 29
  • 287
  • 307
  • 1
    but when i use this approach than i get the data in controller and view but the fomet of data is something like this Illuminate\Database\Eloquent\Collection Object ( [items:protected] => Array ( [0] => Setting Object ( [table:protected] => settigs and multiplemarray in now tell me how to access the data from this – Deepak Goyal Aug 07 '14 at 19:59
  • You may access it using `$site_settings = app('site_settings')->first();` – The Alpha Aug 07 '14 at 22:22
  • This approach is far too over engineered for what is needed. – ollieread Aug 08 '14 at 00:23
  • 3
    @ollieread, it doesn't mean that it's a wrong approach and I already mentioned `There are many ways, just use one or another, which one you prefer but I'm using the Container` in my answer. Think before you down vote on any answer. My answer is also correct. – The Alpha Aug 08 '14 at 00:28
  • It is though, the approach is very very wrong. "...and use it in all controllers and view.". If OP wanted to use it every class within the system, sure, that'd work. This is just an example of completely over engineering something so simple as a class property. – ollieread Aug 08 '14 at 00:30
  • 2
    +1 this is a great answer, not over-engineered at all, simpler and better than putting it in your controller – Leon Aug 11 '15 at 14:59
  • @Leon TOTALLY disagree. Over engineered AF. This is how you do it: http://stackoverflow.com/questions/29715813/laravel-5-global-blade-view-variable-available-in-all-templates – Kevin Compton Feb 18 '16 at 21:23
  • 2
    I think this is the best answer. With this approach the variable is really global at application scope. – Ricardo Vigatti Aug 25 '16 at 16:15
  • Thanks @RicardoVigatti, It's for v-4x tho, Now v-5.3 is out :-) – The Alpha Aug 25 '16 at 17:00
  • 3
    This answer is fine, in Laravel there are a million ways to implement something and you can spend ages refactoring your way through the stack in seek of perfection which in this case is the Config class but reimplementing in your own style it is totally fine. – malhal Sep 27 '16 at 17:22
  • Do you have any example for *config* file? (since you suggested a config file in the beginning of your answer) – stack Dec 13 '16 at 11:02
45

Use the Config class:

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

Config::get('site_settings');

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

Configuration values that are set at run-time are only set for the current request, and will not be carried over to subsequent requests.

malhal
  • 26,330
  • 7
  • 115
  • 133
24

In Laravel, 5+ you can create a file in the config folder and create variables in that and use that across the app. For instance, I want to store some information based on the site. I create a file called site_vars.php, which looks like this

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

Now in the routes, controller, views you can access it using

Config::get('site_vars.supportEmail')

In the views if I this

{{ Config::get('site_vars.supportEmail') }}

It will give email@gmail.com

Hope this helps.

EDiT- You can also define vars in .env file and use them here. That is the best way in my opinion as it gives you the flexibility to use values that you want on your local machine.

So, you can do something this in the array

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

Important - After you do this, don't forget to do this on production env

php artisan config:cache

In case, there's still some problem, then you can do this (usually it would never happen but still if it ever happens)

php artisan cache:clear
php artisan config:cache

In your local env, always do this after this adding it

php artisan config:clear 

It's always a good practice not to cache config vars in local. in case, it was cached, this would remove the cache and would load the new changes.

Koushik Das
  • 9,678
  • 3
  • 51
  • 50
  • 3
    The answer with the BaseController is nice, but this one really ensures your data will be available everywhere other than Controller so I'd go with this one. You can also set default values in the "site_settings" so you won't get an error if some values are missing – NaturalBornCamper Jun 11 '19 at 13:45
18

I see, that this is still needed for 5.4+ and I just had the same problem, but none of the answers were clean enough, so I tried to accomplish the availability with ServiceProviders. Here is what i did:

  1. Created the Provider SettingsServiceProvider
    php artisan make:provider SettingsServiceProvider
  1. Created the Model i needed (GlobalSettings)
    php artisan make:model GlobalSettings
  1. Edited the generated register method in \App\Providers\SettingsServiceProvider. As you can see, I retrieve my settings using the eloquent model for it with Setting::all().
 

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

 
  1. Defined some useful parameters and methods (including the constructor with the needed Collection parameter) in GlobalSettings
 

    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 */ }
    }

 
  1. At last I registered the provider in config/app.php
 

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

        App\Providers\SettingsServiceProvider::class
    ]

 
  1. After clearing the config cache with php artisan config:cache you can use your singleton as follows.
 

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

 

You can read more about service containers and service providers in Laravel Docs > Service Container and Laravel Docs > Service Providers.

This is my first answer and I had not much time to write it down, so the formatting ist a bit spacey, but I hope you get everything.


I forgot to include the boot method of SettingsServiceProvider, to make the settings variable global available in views, so here you go:

 

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

 

Before the boot methods are called all providers have been registered, so we can just use our GlobalSettings instance as parameter, so it can be injected by Laravel.

In blade template:

 

    {{ $globalsettings->get("company") }}

 
nbsp
  • 326
  • 4
  • 12
10
View::share('site_settings', $site_settings);

Add to

app->Providers->AppServiceProvider file boot method

it's global variable.

Yasin Patel
  • 5,624
  • 8
  • 31
  • 53
Raci
  • 150
  • 2
  • 5
10

Most popular answers here with BaseController didn't worked for me on Laravel 5.4, but they have worked on 5.3. No idea why.

I have found a way which works on Laravel 5.4 and gives variables even for views which are skipping controllers. And, of course, you can get variables from the database.

add in your 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); 
        });
    }
}

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

Gediminas Šukys
  • 7,101
  • 7
  • 46
  • 59
8

In Laravel 5+, to set a variable just once and access it 'globally', I find it easiest to just add it as an attribute to the Request:

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

Then you can access it from any of your controllers using:

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

and from any of your blades using:

{{ Request::get('myVar') }}
supernifty
  • 4,171
  • 2
  • 32
  • 24
6

In Laravel 5.1 I needed a global variable populated with model data accessible in all views.

I followed a similar approach to ollieread's answer and was able to use my variable ($notifications) in any view.

My controller location: /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);
    }
}

My model location: /app/Models/Main.php

namespace App\Models;

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

class Main extends Model
{
    public function get_notifications() {...
Martin Carstens
  • 716
  • 8
  • 10
6

I have found a better way which works on Laravel 5.5 and makes variables accessible by views. And you can retrieve data from the database, do your logic by importing your Model just as you would in your controller.

The "*" means you are referencing all views, if you research more you can choose views to affect.

add in your 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()
    {

    }
}
Etimbuk
  • 89
  • 1
  • 7
5

If you are worried about repeated database access, make sure that you have some kind of caching built into your method so that database calls are only made once per page request.

Something like (simplified example):

class Settings {

    static protected $all;

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

Then you would access Settings::cachedAll() instead of all() and this would only make one database call per page request. Subsequent calls will use the already-retrieved contents cached in the class variable.

The above example is super simple, and uses an in-memory cache so it only lasts for the single request. If you wanted to, you could use Laravel's caching (using Redis or Memcached) to persist your settings across multiple requests. You can read more about the very simple caching options here:

http://laravel.com/docs/cache

For example you could add a method to your Settings model that looks like:

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

This would only make a database call every 60 minutes otherwise it would return the cached value whenever you call Settings::getSettings().

Seb Barre
  • 1,597
  • 1
  • 12
  • 17
  • But what happen if settings change than it retrive the data from the cached value than how the new value will updated – Deepak Goyal Aug 07 '14 at 18:58
  • 2
    Then you'd have to implement cache busting logic as well. That falls more under cache management strategy, but in the Laravel case, the easiest would be to add a listener to your model's `saving()` event that clears the "settings" key in the cache (to ensure that it re-generates on next access). – Seb Barre Aug 07 '14 at 22:42
  • 2
    This is a horrendously over engineered approach to a simple question. – ollieread Aug 08 '14 at 00:22
  • @ollieread care to expand on that criticism? He specifically asked for a way to avoid making database calls every time he wants to retrieve his database-backed settings. I provided 2 approaches, one that ensures one request per page load, and another that adds cross-request caching (since his settings may not change very often, one request for every page load is probably not even necessary). Both make use of the framework, and unlike your solution, can be used anywhere in the codebase, not just in controllers and views. – Seb Barre Aug 08 '14 at 11:05
  • I think the question was misunderstood, he asked how he would go about accessing this data from all of his views and controllers without having to call the database each and every time. Simply put, the answer is a class property within BaseController. Your caching solution is nice, but doesn't solve the core problem that OP was trying to solve. – ollieread Aug 08 '14 at 13:52
  • @ollieread My solutions very much *do* solve his core problem (no repeated DB requests), and it uses Laravel's built-in functionality to do so. Your suggestion of using View::share() is certainly valid, but that's core Laravel functionality straight out of the docs, and we should assume OP knows how to assign view variables. OP's "core" problem was avoiding repeated DB requests ("fetch the data from the table once"), not assigning view variables. What if he needs to access the settings from a Filter class or some other part of his application? Then your solution no longer works. – Seb Barre Aug 08 '14 at 14:43
5

You can also use Laravel helper which I'm using. Just create Helpers folder under App folder then add the following code:

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;
    }
}

then add it on you config > app.php under alliases

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

1. To Use in Controller

use Site;
class SettingsController extends Controller
{
    public function index()
    {
        $settings = Site::settings();
        return $settings;
    }
}

2. To Use in View:

Site::settings()
5

A global variable for using in controllers; you can set in AppServiceProvider like this :

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

usage

config('yourconfig.company');
Zahra Badri
  • 1,656
  • 1
  • 17
  • 28
3

using middlwares

1- create middlware with any name

<?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- register your middleware in Kernal.php

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

3-now group your routes with globaldata middleware

Route::group(['middleware' => ['globaldata']], function () {
//  add routes that need to site_settings
}
Mortada Jafar
  • 3,529
  • 1
  • 18
  • 33
  • so how would you access those $site_settings from this middleware in the controllers? (you got the views covered) – Valentino Nov 04 '22 at 21:28
1

In file - \vendor\autoload.php, define your gobals variable as follows, should be in the topmost line.

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

Access that global variable anywhere as :-

$GLOBALS['global_variable'];

Enjoy :)

Tom
  • 184
  • 2
  • 7
0

I know I am super late to the party, but this was the easiest way I found. In app/Providers/AppServiceProvider.php, add your variables in the boot method. Here I am retrieving all countries from the DB:

public function boot()
{
    // Global variables
    view()->composer('*',function($view) {
        $view->with('countries', Country::all());
    });
}
SEYED BABAK ASHRAFI
  • 4,093
  • 4
  • 22
  • 32
TheDeon
  • 1
  • 1
  • 1
-3

There are two options:

  1. Create a php class file inside app/libraries/YourClassFile.php

    a. Any function you create in it would be easily accessible in all the views and controllers.

    b. If it is a static function you can easily access it by the class name.

    c. Make sure you inclued "app/libraries" in autoload classmap in composer file.

  2. In app/config/app.php create a variable and you can reference the same using

    Config::get('variable_name');

Hope this helps.

Edit 1:

Example for my 1st point:

// 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();
Chintan Parekh
  • 1,101
  • 1
  • 12
  • 31
  • I have added a small sample code to my question. Hope this helps. – Chintan Parekh Aug 07 '14 at 19:00
  • but in the app folder i have not library folder so where i create the class and how to generate the jason file – Deepak Goyal Aug 07 '14 at 19:19
  • how to generate composer.json file please tell me i have not also this file – Deepak Goyal Aug 07 '14 at 19:31
  • Dude, do you have a Laravel Project? If yes, then you always have a composer.json in your project root directory... – Chintan Parekh Aug 07 '14 at 19:36
  • $myFunctions = new DefaultFunctions(); $site_settings = $myFunctions.getSomeValue(); echo "
    ";
      print_r($site_settings);die;
      die("i m here");
    
    i have put this code in my controller now but it show error
    – Deepak Goyal Aug 07 '14 at 20:07
  • 3
    @DeepakGoyal I think maybe you need to work your way through the basic Laravel documentation in a bit more detail if you're not familiar with Composer or with adding folders to your project. These are very basic but core concepts in Laravel, and you will run into many more issues if you aren't comfortable with how they work. – Seb Barre Aug 07 '14 at 22:45
  • This is a horrendously over engineered approach to a simple question. – ollieread Aug 08 '14 at 00:22
  • I had an answer with merely 6 lines and no code. .If u see it is added later since the guy hardly knew anything. .I don't understand the negative rating..since the answer is definitely right and the reason for that is already mentioned in comment. . – Chintan Parekh Aug 08 '14 at 04:34
  • 1
    Okay, so updates aside, that's barely even PHP. For one, php does use dots for object notation, secondly, the formatting is horrendously, and thirdly, moving the functionality to its own object does not solve the problem, as now he has to call this everywhere he wants it. Simply put, the answer is a class property. – ollieread Aug 08 '14 at 13:50
  • Yes, putting a dot was just by mistake. I was working on some other language and mixed it up, however,no excuses, I accept it, its corrected, thanks for pointing it out. About your second point, the code I added was purely to show how things work and not how it should look (still I will work on it), and lastly, there are many ways as you might have seen, some as you say are too long and pointless, I agree, but, they are not WRONG..I like your approach.I would infact go the way you recommend,but this answers popped up when I read the question and they are still not wrong. So, go easy if possi. – Chintan Parekh Aug 08 '14 at 16:27
  • Yeah, don't misunderstand me, I'm not saying that your answer is bad, I'm just saying that it perhaps doesn't belong here. It's not 'wrong' as you say but it's not correct/appropriate and you must admit, it does complicate something quite simple. – ollieread Aug 08 '14 at 18:14
  • I would rather say that your answer simplifies the thing..definitely. .and more appropriate in this context. .but in a broader perspective your answer is a mess..it would be a better approach to use libraries and separate your code based on use and not put everything under BaseController. .it is not an optimal solution.. – Chintan Parekh Aug 08 '14 at 18:41