Defining global variable in laravel - php

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.

Related

Laravel, calling controller method from blade template file

Heey guys! I use Laravel 5.4, WAMP for localhost. I am struggling with the problem to call a Controller#methodName within my header.blade.php file, because I want to show in my header.blade.php file all notifications for the User. Normally I was getting all needed data with the help of routes in different pages. But for this case I need to call without using routes. Here is my code for my NotificationController:
class NotificationController extends Controller
{
public function getNotification(){
$notifications = Notification::where('user_id',Auth::user()->id)->get();
$unread=0;
foreach($notifications as $notify){
if($notify->seen==0)$unread++;
}
return ['notifications'=>$notifications, 'unread'=>$unread];
}
}
And I should receive all these data in my header file. I have used: {{App::make("NotificationController")->getNotification()}}
and {{NotificationController::getNotification() }} But it says Class NotificationController does not exist. Please heelp!
Instead of calling the controller method to get notifications, you can make a relationship method in your User model to retrieve all the notifications that belongs to the user and can use Auth::user()->notifications. For example:
// In User Model
public function notifications()
{
// Import Notification Model at the top, i.e:
// use App\Notification;
return $this->hasMany(Notification::class)
}
In your view you can now use something like this:
#foreach(auth()->user()->notifications as $notification)
// ...
#endforeach
Regarding your current problem, you need to use fully qualified namespace to make the controller instance, for example:
app(App\Http\Controllers\NotificationController::class)->getNotification()
Try using the full namespace:
For instance, App\Http\Controllers\NotificationController::getNotification
but of course, controllers aren't meant to be called the way you're using them. They're meant for routes. The better solution is to add a relationship in your user model like so:
public function notifications()
{
return $this->hasMany(Notification::class)
}
And then use this in your view like so:
#foreach(Auth::user()->notifications as $notification)

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 : " " }}'>

In Laravel Can I create a new Model Instance without new?

For example:
You can create a new model instance of User as:
new App\Model\User()
But when I use it in blade views, looks like:
new App\Model\User()->..->...
I think it is not a good way. It's not so elegant.
So I want to add some methods to achieve that I can use like below in blade views:
User::instance()->..->...
How can I achieve this? Thanks a lot!
Thanks for helping. I know it is not a good way to call model in blade views. But in some cases, sometimes I still have chance calling model in blade views for convenient.
For example, in create blade form, usually use like this:
{!!Form::model(new App\Model\User, ['url' => '/', 'class' => 'form' ])!!}
So there is chance to use model in blade views. So I want to find a elegant way to get an instance of Model instead of using new App\Model\ModelName...
Like
User::instance()
to get a new instance of \App\Model\User.
Can scopeQuery in model works?
First of all, if you understand the concept of MVC you should know the relationship between a model, view and controller.
The controller as a middle man should do the work of passing appropriate data to your view.
This is a better way to do it in Laravel.
Your controller:
use App\Model\User;
class AccountController extends Controller{
public function __construct (User $user){
$this->user = $user;
}
public function profile(){
return view('profile, ['user'=>$this->user]);
}
}
Then in your view, profile.blade.php
Welcome {{$user->name}}

Laravel - return View::make vs $layout

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.

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 :-)

Categories