Can't get variable passed to view from controller in Laravel - laravel

Trying to pass a data array to all views, but I keep getting the error Undefined variable: data. Not sure what the missing piece is.
All my page specifric controllers extend the following BaseController
BaseController
<?php
...
class BaseController extends Controller
{
public function theme_options() {
// Set number of columns
$footer_cols = DB::table('theme_settings')->where('id','=','200')->value('setting_value');
$widget_width = 12 / $footer_cols;
// Footer Settings
$data = array(
'widget_width' => $widget_width
);
return $data;
}
}
layouts/default.blade.php
<!doctype html>
<html class="no-js" lang="">
<head>
#include('blocks.head')
</head>
<body>
#include('blocks.header')
#yield('content')
#include('blocks.scripts')
#include('blocks.footer', ['data' => $data])
</body>
</html>

Occasionally, you may need to share a piece of data with all views that are rendered by your application. You may do so using the view facade's share method.
In your AppServiceProvider boot method add the following code
// Set number of columns
$footer_cols = DB::table('theme_settings')
->where('id', '=', '200')
->value('setting_value');
$widget_width = 12 / $footer_cols;
View::share('widget_width', $widget_width);
so that the variable widget_width is available to all your views.
Here is the Documentation
P.S: Make sure to do the necessary imports like
use Illuminate\Support\Facades\View;
use DB;

You need to return those variable to view (blade) file try the below code :
class BaseController extends Controller
{
public function theme_options() {
// Set number of columns
$footer_cols = DB::table('theme_settings')->where('id','=','200')->value('setting_value');
$widget_width = 12 / $footer_cols;
// Footer Settings
$data = array(
'widget_width' => $widget_width
);
return view('your_view_name')->with($data);
}
}

Create a new provider for data sharing with views
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class ViewComposerServiceProvider extends ServiceProvider
{
public function boot()
{
$footer_cols = DB::table('theme_settings')->where('id','=','200')->value('setting_value');
return view()->composer('*',function($view){
$view->with('pages',12 / $footer_cols);
});
}
public function register()
{
}
}
Don't forget to add ViewComposerServiceProvider to providers array in config/app.php file

Related

How to architect a project which has more number of dynamic pages in laravel

I have a project which has a large number of dynamic pages. Approximately 30+ pages. The content of each page is different. what I did is created 30 tables and 30 routes as well. And on the admin side, there are 30+ modules to edit the contents. Is it the right way to do this?. In database table, different columns has to be kept.
// Route definition...
Route::get('/page1', [Page1Controller::class, 'show']);
Route::get('/page2', [Page2Controller::class, 'show']);
Route::get('/page3', [Page3Controller::class, 'show']);
// Controller method definition...
public function index() {
return view('page1');
}
// Route definition...
// All other routes above this slug catch all. otherwise it will try and hit this controller all the time and fail.
Route::get('/{slug}', [PageController::class, 'show']);
// Controller method definition...
public function show($slug)
{
$contents = PageContents::where('slug', $slug)->firstOrFail();
if ($contents) {
return view('page')->with('contents', $contents);
}
return view('404');
}
This way you have a table with all the contents you need. e.g. title, body copy so on. but if each layout is different you could also return a different view. e.g.
public function show($slug)
{
$contents = PageContents::where('slug', $slug)->firstOrFail();
if ($contents) {
return view('page-'.$slug)->with('contents', $contents);
}
return view('404');
}
You can create only one controller and add a parameter in the route(web.php):
web.php
//---Route Definition
Route::get('page/{page_number}', [PageController::class, 'show'])->name('page.show');
PageController.php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Crypt;
class PageController extends Controller {
//---Show
public function show($page_number) {
return view('show.show', compact('page_number'));
}//---End of Function show
}
If you want to retrieve your data from a database just one table is enough, just create a page table and give a field by the name of page_number and retrieve your specific page data by the given field.
For example:
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Crypt;
class PageController extends Controller {
//---Show
public function show($page_number) {
$page = PageContent::where('page_number', $page_number)->first();
return view('show.show', compact('page'));
}//---End of Function show
}
**
Your Link to routes
<a href="{{ route('page.show', ['page_number' => 1])) }}" class="" title="Show">
Show
</a>

How to transfer data to parent template without code duplication,

I have main layout which contains a header, nav, footer and ofc many blade templates with
inherited from him. My problem: i have categories which i need to connect in my navbar, also in many children templates, maybe it can be done somehow globally without duplication code.
It's my 'HomeContoller' return index template, but if i return my categories with $categories my main layout can't see this variable
public function index()
{
$posts = Post::paginate(10);
$popularPosts = Post::orderByViews()->take(6)->get();
return view('front.index', ['posts' => $posts, 'popularPosts' => $popularPosts]);
}
Now i return to layout.blade my $categories by this method.
#php
$categories = App\Category::all();
#endphp
For this particular case I would suggest the View Composer - especially, if you scroll a bit down on that page you'll see Attaching A Composer To Multiple Views - you could use:
View::composer('*', function ($view) {
$view->with('categories', App\Category::all());
});
You can register it under any of the existing providers for instance AppServiceProvider under the boot method:
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function boot(): void
{
View::composer('*', function ($view) {
$view->with('categories', App\Category::all());
});
}
}

How to pass data to all views in Laravel 5.6?

I have two controllers. StudentController and TeacherController. I have a variable $chat which I want to pass in all the views of StudentController and TeacherController. The $chat will contain different data for both these controllers.
I searched and found ways, but I am getting empty data. I am doing it like this.
<?php
namespace App\Http\Controllers;
use View;
class StudentController extends Controller {
public function __construct()
{
$this->middleware('auth')->except(['home']);
$this->middleware('access')->except(['home']);
$chats = studentChat();
View::share('chats', $chats);
}
So, here I am printing and it is returning an empty array, but when I use the same in a function the array contains data. What is wrong here? Can anyone please help?
What I tried:
public function boot()
{
View::composer('*', function ($view) {
$chats = Cache::remember('chats', 60, function () {
if(Auth::user()->user_type() == config('constant.student'))
{
return studentChat();
}
else
{
return teacherChat();
}
});
$view->with('chats', $chats);
});
}
If you use View::share your share data to ALL your view, if you need to add data to few different views you may do this:
Create blade file(chat.blade.php for your case), and put your variables:
<? $chats = studentChat(); ?>
Include this file to the begining of your views where your need this 'global' varables:
//begin of your blade file
#include('chat')
//some code
{{ $chat->channel }}
Sharing Data With All Views
Occasionally, you may need to share a piece of data with all views that are rendered by your application. You may do so using the view facade's share method. Typically, you should place calls to share within a service provider's boot method. You are free to add them to the AppServiceProvider or generate a separate service provider to house them:
<?php
namespace App\Providers;
use Illuminate\Support\Facades\View;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
$chats = studentChat();
View::share('chats', $chats);
}
public function register()
{
//
}
}
So, what I did was in the AppServiceProvider class, in the boot function I added this.
View::composer('*', function ($view) {
if(!\Auth::check())
{
return;
}
$userType = \Auth::user()->user_type ;
if($userType == config('constant.student'))
{
$chats = studentChat();
}
else if($userType == config('constant.teacher'))
{
$chats = teacherChat();
}
$view->with('chats', $chats);
});
You can pass data to the view Like.
return View::make('demo')->with('posts', $posts);
For more details visit article : Introduction to Routing in Laravel
write your query in boot method in appServiceProvider like,
View::composer('*', function ($view) {
$share_query = Cache::remember('share_query', 60,function () {
return App\User::all();
});
$view->with('share_query', $share_query);
});
Your final solution is ok, but not the cleanest possible.
Here is what i would do.
Define a class with a single function that contains your logic and return $chats, that way you will encapsulate your logic properly and keep your service provider boot method clean.
Then you have 2 options:
Inject your class in the boot() method of the service provider you use, then call its function and uses View::share. Should looks like :
public function boot(ChatResolver $chatResolver)
{
$chats = $chatResolver->getChats();
View::share(compact('chats));
}
If you only use $chats variable in a signe view or partial (like a part of layout), you can also inject the class you defined directly in the view.
Here is a link to Laravel doc regarding that.
In some cases it might be the easiest solution.

Passing a variable to a master template in laravel

In laravel i have defined a route like this
Route::get('/', array(){
'as' => 'index',
'uses' => 'HomeController#index'
});
The function index() in the HomeController contains
public function index(){
$index = new ExampleModel;
$data = $index->getExampleList();
return View::make('public.index');
}
Now the problem is i have a master layout called happypath inside layouts folder in my views which yields this public.index content and i need to pass this $data to layouts.happypath. How do i do this ?
You can use a view composer for example:
namespace App\Providers;
use App\ExampleModel;
use Illuminate\Support\ServiceProvider;
class ComposerServiceProvider extends ServiceProvider
{
protected $exampleModel;
public function __construct(ExampleModel $exampleModel)
{
$this->exampleModel = $exampleModel;
}
public function boot()
{
view()->composer('layouts.happypath', function ($view) {
$view->with('publicIndex', $this->exampleModel->getExampleList());
});
}
public function register()
{
//
}
}
So, every time you use/render the layouts.happypath the $publicIndex variable will be attached within the layout. Also you need to add the ComposerServiceProvider class in your config/app.php file in the providers array. You may access/reference the data using $publicIndex variable in your layout. There are other ways like global shared $information using view()->share(...) method to share a peace of data all over the views but this may help you.
I could not figure out the ComposerServiceProvider View::composer thing. So i basically solved it like this in Laravel 4.2. Added this code to the BaseController.php
protected $menuList;
public function __construct() {
$response = API::pool([
['GET', API::url('level')],
]);
$index = new Index();
$index->setCourseList($response[0]->json()['Category']);
$result = $index->getCourseList();
View::share('result', $result); //This line shares the $result globally across all the views in laravel 4.2
}
This can be done with a Service Provider. You can either use an existing one or create a new one.
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use App\ExampleModel;
class ViewServiceProvider extends ServiceProvider
{
public function boot()
{
$index = new ExampleModel;
$data = $index->getExampleList();
view()->share('public.index', $data);
}
public function register()
{
}
}
Source: EasyLaravel.com

How put data in app.blade.php from controller in Laravel 5

I Need to put some dynamic data from controller to app.blade.php, but I can't find any controller. Where I sholud do this?
Thanks
To inject data into a layout view (a view that's #extended by others) you can use a view composer. How you do that is actually pretty well explained in the documentation
Create a service provider (inside app/Providers):
<?php namespace App\Providers;
use View;
use Illuminate\Support\ServiceProvider;
class ComposerServiceProvider extends ServiceProvider {
public function boot()
{
//
}
public function register()
{
//
}
}
Now inside the boot() method you register your view composer:
View::composer('app', function($view){
$view->with('foo', 'bar');
});
After that, don't forget to register the service provider in config/app.php by adding it to the providers array:
'providers' => [
// other providers
'App\Providers\ComposerServiceProvider'
]
Thanks to lukasgeiter's answer. But it needs some modifications to get it working with all the views rendered by Laravel.
You need to put '*' character as a wildcard, so you may attach a composer to all views
View::composer('*', function($view){
//any code to set $val variable
$val = 'bar';
$view->with('foo', $val);
});
so complete class of app\Providers\ComposerServiceProvider.php will be like,
<?php
namespace App\Providers;
use View;
use Illuminate\Support\ServiceProvider;
class ComposerServiceProvider extends ServiceProvider {
public function boot()
{
View::composer('*', function($view){
//any code to set $val variable
$val = 'bar';
$view->with('foo', $val);
});
}
public function register()
{
//
}
}
Also register service provider in config\app.php file as,
'providers' => [
// Other Service Providers...
App\Providers\ComposerServiceProvider::class,
],
Now you can use $foo variable in your resources\views\layouts\app.blade.php file as
<div>
{{$foo}}
</div>
this will render to client as
<div>
bar
</div>

Resources