11

I want information about the system locale to be available in every view, so I could highlight whatever language is currently selected by a user. After some googling around, I've found the value-sharing issue addressed in the official documentation. However, after putting the code into boot() like this:

class AppServiceProvider extends ServiceProvider{
    public function boot(){
        view()->share('locale', \Lang::getLocale());
    }
}

the $locale variable, when accessed in views, always holds the default system locale, not the currently selected one. Why?

Alex Lomia
  • 6,705
  • 12
  • 53
  • 87
  • 1
    I don't know about Laravel, but why don't you store it in a session variable? – Niki van Stein Jan 27 '16 at 15:04
  • I want to stick to the Laravel best-practices as much as possible. I don't think that would be a Laravel-way of doing things. Also, the mechanism that I describe above is designed to address such very issues, hence there has to be some way to solve this problem 'in the right way'. Thanks for the idea anyway :) – Alex Lomia Jan 27 '16 at 15:06
  • Ah ok, it was just a suggestion :) – Niki van Stein Jan 27 '16 at 15:08
  • You are not showing how you set the locale. Agree that @panagiotis answer seems over engineered although still awesome (or poli kala) . Your solution should work though – Mike Miller Jan 31 '16 at 10:13

2 Answers2

20

I usually use View Composers so it's more clear and readable.

For example If I want to share a variable with the main navbar to all of my views I follow the below rules:

1. Create new service provider

You can create a service provider with artisan cli:

php artisan make:provider ViewComposerServiceProvider

In the ViewComposerServiceProvider file create composeNavigation method in which has the blade template main.nav-menu that represents the navmenu with shared variables.

The ViewComposerServiceProvider looks like:

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class ViewComposerServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap the application services.
     *
     * @return void
     */
    public function boot()
    {
        $this->composeNavigation();
    }

    /**
     * Register the application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }

    private function composeNavigation()
    {
        view()->composer('main.nav-menu', 'App\Http\ViewComposers\NavComposer');
    }
}

2. Create Composer

As you saw in the file above we have App\Http\ViewComposers\NavComposer.php so let's create that file. Create the folder ViewComposers in the App\Http and then inside create NavComposer.php file.

The NavComposer.php file:

<?php

namespace App\Http\ViewComposers;

use App\Repositories\NavMenuRepository;
use Illuminate\View\View;

class NavComposer
{
    protected $menu;

    public function __construct(NavMenuRepository $menu)
    {
        $this->menu = $menu;
    }

    public function compose(View $view)
    {
        $thing= $this->menu->thing();
        $somethingElse = $this->menu->somethingElseForMyDatabase();

        $view->with(compact('thing', 'somethingElse'));
    }
}

3. Create repository

As you saw above in the NavComposer.php file we have repository. Usually, I create a repository in the App directory, so create Repositories directory in the App and then, create inside NavMenuRepository.php file.

This file is the heart of that design pattern. In that file we have to take the value of our variables that we want to share with all of our views.

Take a look at the file bellow:

<?php

namespace App\Repositories;

use App\Thing;
use DB;

class NavMenuRepository
{

    public function thing()
    {
        $getVarForShareWithAllViews = Thing::where('name','something')->firstOrFail();
        return $getVarForShareWithAllViews;
    }

    public function somethingElseForMyDatabase()
    {
        $getSomethingToMyViews = DB::table('table')->select('name', 'something')->get();

        return $getSomethingToMyViews;
    }

}
Panagiotis Koursaris
  • 3,794
  • 4
  • 23
  • 46
  • 1
    Could you please elaborate on pros/cons of this approach? Sorry for being a newbie, but It's not quite clear to me. Is it not an overkill to write so much code for my exact situation? – Alex Lomia Jan 28 '16 at 09:23
  • 2
    If your project it will be big it's better to follow this because it's help to make the code reusable and readable. It's up to you... – Panagiotis Koursaris Jan 28 '16 at 10:13
  • 1
    @Panagiotis I guess you just forgot to mention adding this provider into array of providers of your app `App\Providers\ViewComposerServiceProvider::class,` – Mohamed Mo Kawsara Mar 03 '16 at 09:22
2

For people with small project:

Firstly, The accepted answer is awesome!

For Laravel 5.2 users:

Just use the new blade directive @inject within your views like this

@inject('shared','App\Utilities\SharedWithView')

then you can use it: {{ $shared->functionName() }}

And SharedWithView is a simple class like this one:

namespace App\Utilities;

use App\Repositories\SomeRepositoryLikeArticlesRepository;

class SharedWithView {

    public function functionName() {
        $properNameHere = new SomeRepositoryLikeArticlesRepository();

        return $properNameHere->forEaxmpleGetMostViewedArticles( 10 );
    }

}
Mohamed Mo Kawsara
  • 4,400
  • 2
  • 27
  • 43