Laravel - return View::make vs $layout - php

Usually I have managed my layouts in Laravel like this:
views/index.blade.php
<html>
<body>
#yield('content')
</body>
</html>
views/main/root.blade.php
#extends('index')
#section('content')
<p>whatever</p>
#stop
controllers/MainController.php
class MainController extends \BaseController {
public function root(){
return View::Make('main.root');
}
}
Now I am reading about the $layout variable. The documentation says:
Your application probably uses a common layout across most of its
pages. Manually creating this layout within every controller action
can be a pain. Specifying a controller layout will make your
development much more enjoyable
But I do not see how this makes it more enjoyable.
This is the same code, but using the $layout variable:
controllers/MainController.php
class MainController extends \BaseController {
public $layout = "index";
public function root(){
$this->layout->nest('content', 'main.root');
}
}
Now, how is this easier? It seems like more code to me. Besides I have already stated that rootblade extends index so it seems like there is duplication here.
I probably am getting something wrong about this technique. Can someone help me to make sense of it to me?

If you set up your BaseController: (Laravel calls setupLayout() automatically if it exists)
class BaseController extends Controller {
protected $layout = 'layouts.master';
protected function setupLayout()
{
$this->layout = View::make($this->layout);
}
}
You can just specify the #section() name as a property, not have to #extend() your views. and / or override the layout inherited form BaseController.
class MainController extends \BaseController {
public function index(){
$this->layout->content = View::make('main.index');
}
}
In your view:
#section('content')
<div class="row-fluid">
Test
</div>
#stop
In the master layout:
#yield('content')

The point is
not having to specify #extends in every single view
The possibility to render the content section of a template individually, for example for an AJAX template or to re-use the content section in more than one layouts.
Whether or not it is actually good practice or if it saves you any pain is definitely arguable, but that's the idea behind it.

I have been asking on IRC and it seems like this is actually coming from Laravel 3, and now #extends is the new way of doing things. So it appears setupLayout is sort of legacy code. So I guess I can safely ignore it.

Related

Putting data into master blade - Laravel

I have seen a few similar questions to mine, with the common answer being to use a view composer. I have a HomeController that shows articles from a database by passing query data to an associated view, which works see this image link
As you can see there is a nav bar, which is generated by the master layout, layout.master.
For each title in the navigation I am trying to show each article for that section via a for loop which generates the links.
My code is this.
public function index()
{
$loans_articles = Article::byDepartment('Loans')->get();
$digital_articles = Article::byDepartment('Digital')->get();
$consulting_articles = Article::byDepartment('Consulting')->get();
return view('welcome',
[
'loans_articles' => $loans_articles,
'digital_articles' => $digital_articles,
'consulting_articles' => $consulting_articles,
]);
}
As you can see I'm returning this data to the welcome blade.
In my nav bar I tried
#if(count($loans_articles) > 0)
#foreach($loans_articles as $ls)
<!--for each loop which grabs the articles with department Loans-->
<li>{{ $ls->title }}</li>
#endforeach
#endif
But as soon as you navigate away from the home page the nav bar doesn't know what $loans_article is.
Is there a clean way to pass this data to the master blade navigation without sending the same data to every subview?
The way I tend to achieve this is by making a variable available to every view in this way:
All of your controller should extend a base controller, which is usually located in app/Http/Controllers/Controller.php. Inside this controller you can put some code that will be used by all extending controllers.
In this base controller you can make a variable available to all views, like this...
class Controller extends BaseController
{
public function __construct()
{
// Load your objects
$loans_articles = Article::byDepartment('Loans')->get();
// Make it available to all views by sharing it
view()->share('loans_articles', $loans_articles);
}
}
All of your controllers must extend this controller for this to work.
If any of your controllers have their own constructors, you must also make sure to call parent::__construct() to ensure the above code is run. If your controllers don't have their own constructors, you can omit calling parent::__construct().
public class HomeController extends Controller
{
public function __construct()
{
parent::__construct();
// Your constructor code here..
}
}
This way you should be able to use $loans_articles in all of your views.
You must use View Composer to achieve what you are trying to do :
https://laravel.com/docs/5.2/views
if you would like to share data with all of your blade templates, a simple way is trough
appServiceProvider.php and boot method.
you can find this file in app/Providers/AppServideProvider.php and do the changes like bellow:
namespace App\Providers;
use Illuminate\Support\Facades\View;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* #return void
*/
public function register()
{
//
}
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
View::share('key', 'value');
}
}
after that you can access to the value in all blade files using {{ $key }}
note: do not forget to use Illuminate\Support\Facades\View in top of the class
<?php $contact = DB:table('tbl_contact')->get(); ?>
Use this code in master.blade.php in top section
And
Use such as
<a href='{{ $contact[0]->fbLink ? $contact[0]->fbLink : " " }}'>

Defining global variable in laravel

Model: Comment.php
class Comment extends Eloquent {
protected $table = 'comments';
public $timestamps = true;
}
Controller: PageController.php
class PageController extends BaseController {
$top_comments = Comment::take(3)->get();
return View::make('page', array('top_comments' => $top_comments));
}
View: page.blade.php
#foreach ($top_comments as $comment)
user #{{ $comment->user_id }}:<br />
{{ $comment->comment}}
#endforeach
This works perfect with the page.blade.php view which I can define as a route (/page). However, I can't seem to figure out how to achieve this globally.
Example: I want to be able to use the #foreach containing $top_comments in my master.blade.php file. Right now if I was to use the above, it works great on /page but not on /, /about, /tos
You can use View::share('top_comments', Comment::take(3)->get()); to make it available everywhere. Of course, you'll have to place it some place where it gets loaded no matter what page you load if you want it in every possible view. (One such place would be in the __construct() method of your BaseController, but I doubt that could be considered a best practice. Not sure where I'd put it myself.)
Another way would be to leverage view composers, like this:
View::composer('master', function($view)
{
$view->with('top_comments', Comment::take(3)->get());
});
This works if you meant that you want it in your master.blade.php no matter from where it is loaded, because it's bound to that view. If you choose this option, I recommend for instance creating a file composers.php and including that in app/start/global.php.
That said, I assume your controller sample above left something out, because it looks like it's missing a method declaration.

Make things available in any view file Laravel

I have a question about making some elements available in any view file
Lets say im building a webshop and on every page i will be having my sidebar, shoppingcart, user greeting in the top.
How can i make these things available in all my view files?
I could make a class, lets say class Frontend
I could do something like this:
class Frontend {
static $me;
public function get(){
if(!self::$me){
self::$me = new self();
}
return self::$me;
}
private function getShoppingCart(){
// do things
}
public function getData(){
return array(
'Username' => User::find(1)->UserName,
'Cart' => $this->getShoppingCart()
);
}
}
Now in my controller i could pass this Frontend object into the view
View::make('file.view')->with(array('data' => Frontend::get()->getData()));
But this way i will end up with a god class containing way too much stuff and in every controller method i would have to pass these data, which is not relevant to the controller method
Is there a way in Laravel that makes specific data available across all view files?
Thanks!
Use share:
View::share('name', 'Steve');
as per http://laravel.com/docs/responses#views
To keep everything clean, every part of the page should be its own *.blade.php file which would be put together using a master template of sorts.
master.blade.php
#yield('includes.sidebar')
#yield('users.greeting')
#yield('store.shoppingcart')
Then you can use view composers so that each time these views are loaded, the data you want is injected into them. I would probably either create a new file which would get autoloaded, or if you have service providers for the separate portions of your app that these views would use, it would also go great in there.
View::composer('users.greeting', function($view)
{
$view->with('user', Auth::user());
});
In this case, it would make the user model available inside your view. This makes it very easy to manage which data gets injected into your views.
You are close with your 'god class' idea.
Setting a $data variable in a basecontroller has helped me with similar issues
class BaseController extends Controller {
protected $data;
public function __construct() {
$this->data['Username'] = User::find(1)->UserName
$this->data['Cart'] = $this->getShoppingCart()
}
}
class Frontend extends BaseController {
function someMethod(){
View::make('file.view', $this->data)
}
}

Layouts Throwing "Attempt to assign property of non-object" In Laravel 4

In the Layouts folder, I have a layout called signup.blade.php
In my controller, I'm assigning a layout to it like so:
protected $layout = 'layouts.signup';
In a separate folder, named "signup" I have a file called "signup1.blade.php" It contains your typical blade template stuff. It's a section called "content". Before the code I have
#section('content')
and it's got #stop at the end.
My controller looks like this:
public function SignUp()
{
$this->layout->content = View::make('signup.signup1');
}
The frustrating part is that this is working with another layout and controller. I've double checked they're the same, and this one does not work. Any suggestions would be greatly appreciated. Thank you.
So, assuming this controller extends BaseController (it must for $layout to work), the code execution sets $this->layout to View::make($this->layout).
Your error seems to show that $this->layout is not getting set to a View object correctly.
Try to run this and see if $this->layout is an object/class, and if so, what class it is.
public function SignUp()
{
echo gettype($this->layout);
echo get_class($this->layout);
}
Knowing what $this->layout does not get changed into a View object means that the setupLayout() method is either not called or, more likely, not the result of View::make($this->layout) is not a proper view (perhaps it's silently failing for some reason).
The above steps hopefully give you a clue into whats happening there. Perhaps layouts.signup isn't a layout the app is finding?
What do your routes look like?
Change
class UsersController extends Controller
to
class UsersController extends BaseController
Hopefully the author of Confide fixes this :-)

Laravel how to include a partial in the base controller

In my laravel application I am using a Base_Controller class and then extend this class in other controller.
In my app there is a variable which I need to use in all my controller and templates.
This is why I tried to use in my base controller.
$this->layout->myVar = 'stuff'
But when I try use $myVar in my view I am getting an error:
Creating default object from empty value
My base class constructor is something like this:
public function __constructor()
{
parent::__construct();
$this->layout->menu = 'stuff';
}
Does anyone have any idea on what is the best way to approach this?
You must have $this->layout defined in your controller class or else $this->layout must be assigned an instance of View::make().
$this->layout->menu may also require having the #section('menu') #endsection in it.

Categories