Laravel 4 - understanding View::share() - laravel

From what I understand:
View::share('foo','bar');
Will make $foo available in all views.
However, is it correct to say View::share() can be used only in the __construct()?
Because from outside __construct() I can't make it to work.

View::share should be available anywhere within your application. A common place that it is used is in view composers, but it should be usable within a route or wherever you need it.

Yes, adding:
View::share('foo','bar');
in your routes.php file will make $foo (with a value of 'bar') available in all views. This is especially useful for something like Twitter Bootstrap's "active" navigation classes. For example, you could do:
View::share('navactive', '');
to make sure the navactive variable is set in all views (and thus won't throw errors) and then when you are making views (in your controller, for example), you could pass:
return View::make('one')->with('navactive', 'one');
and then in your view (preferably some bootstrappy blade template) you can do the following:
<ul class="nav">
#if ( Auth::user() )
<li #if ($navactive === 'one') class="active" #endif>One</li>
<li #if ($navactive === 'three') class="active" #endif>Three</li>
<li #if ($navactive === 'five') class="active" #endif>Five</li>
#endif
</ul>

Basically if you want to share the variables through all view, you might first want to create a base route(E.x.:internalController.php) as a parent class then extend other controllers as a child of it(E.x:childController.php).
And yeah you will most likely set the view::share('foo', $bar) in the __constructor() of the internalController.php, since it lunches whenever the class is initialized, this way the parent class will serve the variable values to the child classes.

Related

How to handle the if statement in a view called from multiple places when passing a variable to compact

I have the following function in the controller:
public function tasks(Client $client)
{
$tasks = $client->tasks;
$client_name = $client->name;
return view('task.index', compact('tasks','client_name'));
}
and as task_index is called from multiple places, I am handling h1 as shown below:
<div class="col-12 col-md-10 d-flex justify-content-center">
#if($client_name)
<h1>List of overall customer tasks {{$client_name}}</h1>
#else
<h1>List of tasks</h1>
#endif
</div>
only when I click on the button to show all the tasks I get the error
Undefined variable $client_name
so the if is not working.
Can anyone tell me how to do please?
Use the Blade #isset directive rather than #if:
#isset($client_name)
<h1>List of overall customer tasks {{$client_name}}</h1>
#else
<h1>List of tasks</h1>
#endisset
If You are using $client_name in different blade, Try to share your variable using View::share() in the AppServiceProvider it will act as component and you can use it across all the blade template
from AppServiceProvider class
$tasks = $client->tasks;
$client_name = $client->name;
ex: View::share(['client_name'=>$client_name] i already use it in my project
If you are using multiple blade files within each other, you must pass the variable you want to re-use in each subsequent blade file
eg.
<h1>List of overall customer tasks {{$client_name}}</h1>
#include('another.blade.php', ['client_name' => $client_name])

How to prevent loops in laravel global variable

I've created file GlobalVariable.php inside app\Composers
public function compose($view)
{
$categories = \App\Models\Category::all();
$view->with('globCategory', $categories);
}
then register to AppServiceProvider the code view()->composer('*', GlobalVariable::class);
I use global $globCategory for creating dynamic navbar
<ul class="nav nav-tabs border-0 flex-column flex-lg-row">
#foreach ($globCategory as $item)
<li class="nav-item">
{{$item->name}}
</li>
#endforeach
</ul>
the only problem here when I see laravel debuggar it show repetition of categories query.
here is the result
How to avoid this looping query? is there correct way?
The way you're registering your view composer (using '*' instead of a particular view name), it's going to call the compose method for every single rendered view + subview.
What you can do is instead of this:
view()->composer('*', GlobalVariable::class);
Have this:
\View::share('globCategory', \App\Models\Category::all());
This will globally share your categories (within views), and run the query only once.
View composers, as described from the laravel documentation, bind data to a view every time it is rendered. They clean our code by getting fetching data once and passing it to the view.
While it is possible to get the data in every controller method and pass it to the single view, this approach may be undesirable.
Replace the view name with an asterisk wildcard.

Laravel 4 view composers not working

I saw this question. I have a similar problem, but it ain't working. Laravel 4 public functions.
I have a view composer that includes some codes in base layout. Here's my composer:
View::composer(array('common.menu_addition','common.base_errors','common.view_special'), function($view)
{
if(Auth::check()) {
$roles = Auth::user()->type;
if ($roles == '5') {
$view->with('roles', $roles);
} else {
return Redirect::to('news/index');
}
}
});
When I'm not logged in, it works perfectly. But one of my files of view composer goes like this:
<div class="pull-right">
#if (Auth::check())
#if ($roles == 5)
<ul class="nav">
<li>
<a href="{{ URL::to('admin/dash') }}">
<i class="icon-eye-open">
</i>
<strong>
Admin Dashboard
</strong>
</a>
</li>
</ul>
#endif
#endif
</div>
When I login, it won't display any site. It just says Undefined variable: roles in that view composer file.
I don't think it's possible to return a redirect like that, in your view composer. And even if you could it's a bad place to put that logic. You should create a filter http://four.laravel.com/docs/routing and redirect away if the user doesn't have the proper authentication level.
It looks like you're not defining $roles beforehand and not passing $roles into your views.
When you're making checks against the $roles in views you need to make sure that variable actually exists. Other possibility is to change the check to something like
#if (isset($roles) && $roles == 5)
to ignore the error but that gets really messy in the long run.
So make sure to initialise view variables beforehand in the view composer and everywhere else. Laravel tries to be much more stricter about non-initialised variables than PHP in common.

Is there an easier way to write this html/razor code

<ul>
#{int i=0;}
#foreach (var entry in Model.PhoneNumberEntries)
{
<li>
<span>#entry.PhoneNumber<span>
#Html.TextBoxFor(m=>Model.PhoneNumberEntries[i].PhoneNumber)</li>
i++;
}
</ul>
This seems a little too verbose for me... is there way to get around creating the counter with having to resort to the standard for loop?
This seems a little too verbose for me... is there way to get around
creating the counter with having to resort to the standard for loop?
Yeah it seems too verbose to me as well. Even the loop seems too verbose as you don't need it if you use editor templates.
<ul>
#Html.EditorFor(x => x.PhoneNumberEntries)
</ul>
and then obviously you would define a custom editor template that will automatically be rendered for each element of the PhoneNumberEntries collection (~/Views/Shared/EditorTemplates/PhoneNumberEntry.cshtml):
#model PhoneNumberEntry
<li>
<span>#Model.PhoneNumber</span>
#Html.EditorFor(m => m.PhoneNumber)
</li>
You don't even need to write loops as templates work by convention.
Notice that the name and the location of the editor template is important. It should be located either inside ~/Views/Shared/EditorTemplates if you want to share this template between views belonging to different controllers in your application and it is the location where ASP.NET MVC will first look for it. Or you could also put it inside ~/Views/XXX/EditorTemplates where XXX is the name of the current controller. Then name of the editor template must be the name of the type used as agrument for the collection property.
So if you had no your main view model:
public IEnumerable<FooBarViewModel> FooBars { get; set; }
the name of the corresponding template would be FooBarViewModel.cshtml and obviously it will be strongly typed to FooBarViewModel.
Try this:
<ul>
#for (int i=0; i++; i < Model.PhoneNumberEntries.Count)
{
<li>#Html.TextBoxFor(m=>Model.PhoneNumberEntries[i].PhoneNumber)</li>
}
</ul>

How to implement a sidebar in Zend Framework

How do I implement a sidebar in Zend Framework?
I know that I can use a placeholder or something similar in Zend_layout, but how do I automatically generate the code for the sidebar in my controllers without having to call a sidebar class within every controller?
My setup is as follows
Application
- modules
- blog
- other modules
I only want the sidebar for my blog module.
I have found this http://www.zfforums.com/zend-framework-components-13/model-view-controller-mvc-21/how-layout-sidebar-etc-2677.html but I do not understand the last part "just inject your layout, register it with the front controller ..."
You could just have a action and view in one of your controllers which renders the sidebar.
from the layout for the blog module you just call:
<? echo $this->action('action','controller','module',array('optionalparams'=>1); ?>
on the position where you want to have it. So one call to one action.
Rather than use the action stack and the action() view helper, you could render a "partial view script" that includes your sidebar elements.
# in your layout.phtml
<div id="sidebar">
<?php echo $this->render('blog/_sidebar.phtml'); /*relative to your view scripts directory*/ ?>
</div>
# in blog/_sidebar.phtml
<div id="blog_categories">
<?php foreach ($this->categories as $category): ?>
<?php echo $category->name; ?>
<?php endforeach; ?>
</div>
The render() view helper is used to render the content of another view script. It has the same scope as all your other view scripts, so if there are any variable assigned to the view, they will be available to your partial. So in the example above, the categories variable was set in the controller.
There is another view helper called the partial() view helper. This function is a little more expensive since it creates its own variable scope. In other words, none of your current view variables will be available. You will have a clean slate to work with, which means you must pass in any variables you need:
# in your layout.phtml
<div id="sidebar">
<?php echo $this->partial('blog/_sidebar.phtml', array('categories2'=>$this->categories)); ?>
</div>
# in blog/_sidebar.phtml
<div id="blog_categories">
<?php foreach ($this->categories2 as $category): ?>
<?php echo $category->name; ?>
<?php endforeach; ?>
</div>
I don't find myself using partial() very often since it is more expensive, and I rarely need to create a separate context.
As far as setting up the variables for use in the sidebar partial ($this->categories in this example), I have used a number of different methods depending on the particular problem. If it's specific to a controller action, I will write the code and assign it in the view script:
# controller
public function somethingAction()
{
$this->view->categories = $this->_getCategoriesForThisParticularAction();
// other controller code
}
If my code is more generic to all the actions of the controller, I will utilize the controller's preDispatch() function. If it's more generic to multiple controllers, I will put the code in the init() of my base controller (a controller the most of my controllers extend).
Sometimes I do not even put the code in my controller. If it's simple enough, I just stick the code in the partial. If it's a little more complex, I will move it to a view helper. This may break the MVC pattern, but I think it really depends on the particular case in order to determine the best placement.
If you are using Zend_Layout, just add the sidebar with the Action viewhelper as Rufinus said.
in your layout script:
<div id="sidebar">
<?php echo $this->action('action', 'controller', 'module', array('optionalparams'=>1)); ?>
</div>
<div id="content">
<?php echo $this->layout()->content; ?>
</div>
This should meet the requirements posted in your question.

Resources