I have setup a general layout for all my views - all fine.
Now, I would like to get some information from database to put in the header, which is part of the layout.
At the moment, the only way I can find out is something like:
// OneControler.php
static public function hello()
{
$data['hey'] = 'heeey';
return View::make('layouts.partial.nav', $data);
}
And from inside the layout:
// master.blade.php
...
{{ OneController::hello() }}
...
This works fine but... I think there must be another way? I don't think loading a controller from inside the view/layout is the best way to do this?
You can use View Composers to help you with this:
View::composer(array('your.first.view','your.second.view'), function($view)
{
$view->with('count', User::count());
});
Then in your view your.first.view or your.second.view, or even your layout you can just:
{{ $count }}
In the array of views, you put the name of the view:
View::composer(array('layouts.partial.nav') ...
or you can just set it to all views:
View::composer(array('*') ...
If you want to define a variable for all views you can also use share:
View::share('name', 'Steve');
In your view or layout:
{{ $name }}
Related
I'm making a presonification menu on my navbar so that i can access from any page i don't want to use the getRepository inside a controller and pass to the frontend.
Is there a way on symfony 4 that I can get all the users from my database and call it to front? like the app.session.user (to get info on the logged user) for example?
Thanks!
As Cerad mentioned, you can embed a Controller in your templates : https://symfony.com/doc/current/templates.html#embedding-controllers
Instead of doing {% include 'base/navbar.html.twig' %} you will do
In your template :
{{ render(controller('App\\Controller\\BaseController::renderNavbar')) }}
In BaseController
public function renderNavbar(UserRepository $userRepository) {
return $this->render('base/navbar.html.twig', [
'activeUsers' => $userRepository->findActiveUsers(),
]);
}
It's not a route, it's simply a function that renders html, so you don't need to add annotations.
in Symfony 5, i want to display entities Categories in my navbar for each page of my website. Actually i return the same data in each function in my controller like
return $this->render('post/index.html.twig', ['Categories' => $Categories]);
I want to know if there is a better way to return always my categories instead of always retrieve data in each function and return the same data ?
If your navbar is the same on all pages, instead of including the navbar template like {% include 'base/navbar.html.twig' %}, you can include a Controller that will pull the Categories from the database and render the template. It's explained here : https://symfony.com/doc/current/templates.html#embedding-controllers.
In your template :
{{ render(controller('App\\Controller\\BaseController::navbar')) }}
In BaseController
public function navbar(CategoriesRepository $categoriesRepository) {
return $this->render('base/navbar.html.twig', [
'categories' => $categoriesRepository->findAll(),
]);
}
You don't need to add annotations, because there's no route. It's simply a function that returns html.
You need to use global variables. For example in config/packages/twig.yaml:
twig:
globals:
varKey: varValue
or to create own Twig Extension
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'))
I can access cookie in controller then pass it to view
//HomeController.php
public function index(Request $request)
{
$name = Cookie::get('name');
return view('index', ['name'=> $name]);
}
But I want to write a small control (widget) that can fetch data from cookie without concern of parent controller. For example, header, footer widgets could fetch its own data without main page controller knowing which data is needed.
I can query the data from database by using View Composer. But, how can I access data from view in the request cookie ?
Using static function with defining namespace and etc is a not safe.
Cuz maybe in next versions of framework this namespace can change.
It's better to use helper functions.
{{ request()->cookie('laravel_session') }}
or
{{ cookie('laravel_session') }}
Tested on working app with Laravel 5.2
You can use {{ Cookie::get('laravel_session') }} to print out the cookie inside your view.
You can use
{{\Illuminate\Support\Facades\Cookie::get('laravel_session')}}
in a blade template
You can use:
$response = new \Illuminate\Http\Response(view('your_view'));
$response->withCookie(cookie('cookieName' , 'cookieValue' , expire));
return $response;
or
\Cookie::queue('cookieName', 'cookieValue', expire);
return view('your_view');
I've used both of them.
As an admin I can create pages (don't think I have to paste my adminpagescontroller here, because you understand the logic). What I'm getting stuck on, is selecting, but especially using the layout that will be used for the page.
i.e. I have three layouts:
page with left sidebar
page with right sidebar
page with full-width (no sidebars)
And i.e. I want to create a salespage or so, which uses the layouts "page with full-width". How can I call this in my view?
Now all my views begin with #extends('layouts.path.file') <--- I need that to be filled in by the database, if you know what I mean.
One way of doing it is to use a view composer to define the current layout to be used. View composers set variables that can be used by all your views ('*') or just some ('users.profile', 'admin.profile'), so this is an example of using a user specific layout:
View::composer('*', function($view)
{
$view->with('userLayout', Auth::check() ? Auth::user()->layout : 'main');
});
And in your view you just have to:
#extends('layouts.'.$userLayout);
If you just need to select a page on your controller, you can pass a layout to it:
return View::make('myview')->with('layout', 'front.main');
And use it in your view:
#extends('layouts.'.$layout);
And if you have it on a table, you can just pass it on:
$layout = Pages::first()->layout;
return View::make('myview')->with('layout', $layout);
Or do the same in your composer
View::composer('*', function($view)
{
$layout = Pages::first()->layout;
$view->with('layout', $layout);
});
A lot of people like to set the layout in controller too, so you could in your controller do:
public function showProfile()
{
$this->layout = Pages::first()->layout;
$this->layout->content = View::make('user.profile');
}
And your views doesn't have to #extend a layout anymore, because you are already telling them which layout to use.