I'm using Laravel and I've a large amount of index.blade.php pages that extends a master.blade.php page, now the master need some data like the list of menu items.
When I want to see the list of Aircraft I've this route:
Route::get('aircrafts', 'AircraftsController#index');
and this is the method AircraftsController#index:
public function index(){
$aircrafts = Aircraft::all();
$menus = Menu::all();
return view('aircrafts.index', compact('menus', 'aircrafts'));
}
How you can see I must to pass $menus to each view in each controller, and if in some moment the master require some other data I'm forced to edit every single controller...
Is there some more smart way to pass data to the master?
I would like to avoid to retrieve the interested data directly inside the view...
in your AppServiceProvider add use View;
public function boot()
{
View::composer('*', function($view){
$view->with('aircrafts', Aircraft::all());
$view->with('menus', Menu::all());
});
}
after that usage is same. Like #foreach($menus as $foo)
If data requires in all views then you can try view()->share('menus', Menu::all()) in service provider, Otherwise View::composer() is right option for this.
Related
I am working on Laravel for the first time
i have to make a Front End Menu Dynamic in Header and Footer [ list of categories will come from database ]. which controller I have to use for this.?
any common controller available in this framework to send data to header and footer.
When I receive the data in HomeController index Action its available for the home page only.
class HomeController {
public function index()
{
$categories = Category::get();
return view('home', compact('categories'));
}
}
Thanks.
This is a perfect case for View Composers:
View composers are callbacks or class methods that are called when a view is rendered. If you have data that you want to be bound to a view each time that view is rendered, a view composer can help you organize that logic into a single location.
You may attach a view composer to multiple views at once by passing an array of views as the first argument to the composer method:
View::composer(['partials.header', 'partials.footer'], function ($view) {
$view->with('categories', [1, 2, 3]); // bind data to view
});
Now you could simply retrieve $categories within your view (blade template).
Tip: Common practice is to create a new service provider called ComposerServiceProvider and place the abovementioned composer logic in the boot() method.
I assume you are using the Header and Footer in a master layout file. In this case you need to send all header/footer info every request. Which would be silly so instead use View Composers:
Define them in your appServiceProvider in the boot() method
view()->composer('home', function($view) {
$view->with('categories', App\Category::all());
});
In my example i made 'home' the name of the view, since it is in your example. But i would make a master file called layout and include a header and footer partial. If you want categories inside your header you could make a view()->composer('layout.header') with only header data.
which controller I have to use for this.?
Any
any common controller available in this framework to send data to header and footer
No.
You control what is returned from the Controller to be the response. You can design layouts and break them up into sections and have views that extend them. If you setup a layout that has the header and footer and your views extend from it, you can use a View Composer to pass data to that layout when it is rendered so you don't have to do this every time you need to return a view yourself.
Laravel Docs 5.5 - Front End - Blade
Laravel Docs 5.5 - Views - View Composers
In case of this u can use components
https://laravel.com/docs/8.x/blade#components
php artisan make:component Header
View/Component.Header.php
public function render()
{
$category = [Waht you want];
return view('views.header', ['category'=>$category]);
}
Then include Header.php to your blade like this
views/front.blade.php
<html>
<body>
<x-header/> <!-- like this -->
#yield('content')
#include('footer')
<body>
Here is my situation. I have a layout.blade.php which most of my pages use. Within this file, I have some partial pieces that I include, like #include('partials.header'). I am trying to use a controller to send data to my header.blade.php file, but I'm confused as to exactly how this will work since it is included in every view that extends layout.blade.php.
What I am trying to do is retrieve a record in my database of any Game that has a date of today's date, if it exists, and display the details using blade within the header.
How can I make this work?
I think to define those Game as globally shared is way to go.
In your AppServiceProvider boot method
public function boot()
{
view()->composer('partials.header', function ($view) {
view()->share('todayGames', \App\Game::whereDay('created_at', date('d')->get());
});
// or event view()->composer('*', Closure) to share $todayGames accross whole blade
}
Render your blade as usual, partial.header blade
#foreach ($todayGames as $game)
// dostuffs
#endforeach
In Laravel you can create a service class method that acts like a controller and use #inject directive to access this in your partial view. This means you do not need to create global variables in boot(), or pass variables into every controller, or pass through the base view layout.blade.php.
resources/views/header.blade.php:
#inject('gamesToday', 'App\Services\GamesTodayService')
#foreach ($gamesToday->getTodayGames() as $game)
// display game details
#endforeach
While it's different value you retrieved belong of the game chosen, you can do something like that:
Controller
$data = Game::select('id', 'name', 'published_date')->first();
return view('game')->with(compact('data'));
layout.blade.php
<html><head></head><body>
{{ $date }}
</body></html>
game.blade.php
#extend('layout')
#section('date', $data->date)
#section('content')
#endsection
The better solution would be this
Under your app folder make a class named yourClassNameFacade. Your class would look like this.
class yourClassNameFacade extends Facade
{
protected static function getFacadeAccessor()
{
return 'keyNameYouDecide';
}
}
Then go to the file app/Providers/AppServiceProvider.php and add to the register function
public function register()
{
$this->app->bind('keyNameYouDecide', function (){
//below your logic, in my case a call to the eloquent database model to retrieve all items.
//but you can return whatever you want and its available in your whole application.
return \App\MyEloquentClassName::all();
});
}
Then in your view or any other place you want it in your application you do this to reference it.
view is the following code:
{{ resolve('keyNameYouDecide') }}
if you want to check what is in it do this:
{{ ddd(resolve('keyNameYouDecide')) }}
anywhere else in your code you can just do:
resolve('keyNameYouDecide'))
To build a sidebar that has a lot of dynamic data on it I learned about View composers in Laravel. The problem was that View Composers trigger when the view loads, overriding any data from the controller for variables with the same name. According to the Laravel 5.4 documentation though, I achieve what I want with view creators :
View creators are very similar to view composers; however, they are
executed immediately after the view is instantiated instead of waiting
until the view is about to render. To register a view creator, use the
creator method:
From what I understand, this means if I load variables with the same name in the controller and the creator, controller should override it. However this isn't happening with my code. The view composer:
public function boot()
{
view()->creator('*', function ($view) {
$userCompanies = auth()->user()->company()->get();
$currentCompany = auth()->user()->getCurrentCompany();
$view->with(compact('userCompanies', 'currentCompany'));
});
}
And here is one of the controllers, for example:
public function name()
{
$currentCompany = (object) ['name' => 'creating', 'id' => '0', 'account_balance' => 'N/A'];
return view('companies.name', compact('currentCompany'));
}
the $currentCompany variable in question, for example, always retains the value from the creator rather than being overridden by the one from the controller. Any idea what is wrong here?
After some research, I realized my initial assumption that the data from the view creator can be overwritten by the data from the controller was wrong. The creator still loads after the controller somehow. But I found a simple solution.
For those who want to use View composers/creators for default data that can get overwritten, do an array merge between the controller and composer/creator data at the end of the boot() method of the composer/creator, like so:
$with = array_merge(compact('userCompanies', 'currentCompany', 'currentUser'), $view->getData());
$view->with($with);
In my app, i divided the folders in my view by:
"posts"
"pages"
"partials"
layout.blade.php
In my folder partials i have blade files, like nav.blade.php and footer.blade.php. In my folder "pages", i have files like home.blade.php and some other internal pages.
But now i need to pass a viable from a controller to my footer, since is needed to be shared in all views.
How i pass the variable from my PagesController that manages blade files inside the folder "pages" in the footer?
Example routeS:
Route::get('/', 'PageController#getHome');
Route::get('/registar', 'AuthenticationController#getRegistration');
Route::post('/post/comment', 'CommentController#store');
Route::get('/login', 'AuthenticationController#getLogin');
If i understood correctly, you want to share some data every time particular view is called? If that so, you can do this:
/* App\Providers\AppServiceProvider.php
** Edit the boot function, (dont forget to include View facade) */
public function boot(){
View::composer('path_to_view', function($view)
{
$view->with('variable', $variable); // you can pass array here aswell
});
}
Other way to do this (if you are extending the footer layout from the view you are accessing), is to pass data when you extend the layout, like this:
#extends('footer', ['data' => $data])
If you need to share same variable in multipe view from providers. you can also try to this
public function boot()
{
//set view path in array
View::composer(['path_to_view1', 'path_to_view2'], function ($view) {
$view->with('variableName', $variableName);
});
}
I have 5 controllers and 5 models and they are all related to backend. I can easily output data in the backend but I need to that for the frontend as well. Not all of course but some of them.
For example I have controller called BooksController:
public function getBooks(Request $request)
{
$books = Books::all();
return view('backend.books.show', compact('images'));
}
So this will show it in backend without any problems but what I want is for example to loop through all the books and show their images in welcome.blade.php which doesn't have controller.
And also to pass other parameters to that same view from different controllers.
Is this is possible?
Thank you.
You are having an error because you did not declare the variable $image
public function getBooks(Request $request)
{
$books = Books::all();
$images = array_map(function($book) {
$book->image;
}, $books);
return view('backend.books.show', compact('images'));
}
It sounds like you are potentially caught up on some terminology. In this case, it sounds like backend is referring to your admin-facing interface, and frontend is referring to your user-facing interface.
You also seem to be locked on the idea of controllers. Unless the route is verrrrrry basic, create a controller for it.
Have a controller for your welcome view, for your admin view, basically (with some exceptions) a controller per resource or view is fine.
In this case, you would have one controller for your admin book view, and a seperate controller for your welcome view. Both of which would pull the books out of the db and render them in their own way