include nested views if exists in blade, laravel 5 - php

I am trying to include another view if it exists. I have a main page.blade.php which should render the content of the selected page. in the back-end of the application I get a flat array with all the content in it (id and name). So now if a template exists I want to render it but first I need to check if the template actually exists.
I got the following code right now:
#foreach($flattenPage as $page)
#if(file_exists('templates.'.strtolower($page['name'])))
#include('templates.'.strtolower($page["name"]))
#endif
#endforeach
The problem is that it won't get through the if statement.
I also tried:
#if(file_exists('../templates/'.strtolower($page['name']).'.blade.php'))
The current template is views/page/show.blade.php and I need to render views/templates/myContent.blade.php

If you need to determine if a view exists - you can use exists method (as described in the docs)
#if (view()->exists('templates.'.strtolower($page["name"])))
#include('templates.'.strtolower($page["name"]))
#endif

From Laravel 5.2 you can also do this:
#includeIf('view.name', ['some' => 'data'])
Your code will look like this:
#foreach($flattenPage as $page)
#includeIf('templates.'.strtolower($page["name"]))
#endforeach

Related

Laravel - how can make dynamic content with layout?

I'm wanting to create a website with laravel framework. I had made layout but now, have some zone i don't know how to set content for it. Ex: 2 zone of me are left-menu and cart (please view picture). My left-menu will get content from table: categories and cart will get content from package cart [Cart::content()].
It's on layout and of course, all page will have it. But i don't know how to give content of categories and cart() for it. Please help me
I think that you should to use View Composer.
https://laravel.com/docs/5.6/views#view-composers
Use Blade templates, as found here: https://laravel.com/docs/5.6/blade
Wherever in your page you want to print content, use the {{ $mycontent }} construct. You can also use confitionals and loop structures like #if and #foreach to loop through collections.
Then, in your controllers, you can just call the view and pass it content from your database or wherever you get it by doing something like:
return response()->view(“myView”, [“mycontent” => $content], $httpStatus);
You may opt for afterMiddleware if you want it on every page. Create a section on the master blade page (usually app.blade.php) and fill it in the middleware just like you would in any other controller. You can create a middleware by running php artisan create:middleware Cart. A file will be created at app/Http/Middleware/Cart.php.
Register the middleware in the app/Http/kernel.php file.
You may have to add a Auth::check() condition to avoid errors.

How to use dynamic link to run query with dynamic variable in Laravel / Eloquent

I am not sure where to look / what to look for as I am new to HTML / CSS and Laravel / PHP.
I have a function that is returning a collection (of just one item in this case, but I wanted to keep in the count it uses for use later), and I access the object I want in my view as such:
Top Vulnerability: #foreach ($tvuln as $object)
{{ $object->cve }}
#endforeach
I want to turn the CVE that is returning into a link and have that link, when pressed take me to another page that runs a query to pull up a list of all hosts with the given CVE.
I am trying to wrap my head around how to do this and could use some guidance in terms of what to search for or how to implement this with Laravel / Eloquent.
You could try something like:
#foreach ($tvuln as $object)
<a href="{{ route(routename..., parameters...) }}">
{{ $object->cve }}
</a>
#endforeach
For some more info about routes check here.

How to correct Laravel's Blade variable section scoping when yielding inside a loop?

When I include a blade template that extends a base blade, any variables within the section of the included blade show only the variables of the first iteration.
Reading around it seems the render order here is important, and views are rendered before variables, or vice versa.
Note
I have read this SO question/answer: Laravel Blade #yield variable scope
The below snippet is greatly reduced in complexity, so the example could be restructured to exclude sections/extends. However my real case can't be
Example
// index.blade.php
//
#foreach($jobs as $job)
{{ $job->id }} // <-- Correct output, 1,2,3,..N
#include('job-detail', ['id' => $job->id])
#endforeach
Then in the job detail blade
// job-detail.blade.php
//
#extends('job-base')
A: {{ $id }} // <-- Correct output, 1,2,3,..N
#section('content')
B: {{ $id }} // <-- Incorrect output, 1,1,1,..1 (or whatever the first index is)
#endsection // have also tried #stop
Then in the job base blade
// job-base.blade.php
//
#yield('content') // Have also tried #section('content') + #show
After wading through the source code, namely BladeCompiler and View/Factory I noticed the following snippet:
protected function compileOverwrite($expression)
{
return '<?php $__env->stopSection(true); ?>';
}
In the background Laravel appears to store rendered content (by including the file, and extract current variables in a ob_style fashion) in a keyed array, with the view name being the key.
When stopSection is not passed a boolean true, it creates a new key, and the view gets the data from the original key.
Long story short, it's now undocumented (for 5.1+) but can be found in the docs for 5.0:
https://laravel.com/docs/5.0/templates
However it doesn't really explain the "why". This page seems to explain it a little better:
http://laravel-recipes.com/recipes/244/stopping-injecting-content-into-a-section-and-overwriting

Laravel Blade - pass variable via an #include or #yield

I need to pass a variable to an included Blade file. I have attempted this two-ways; however, neither have been successful.
Pass a variable, title, to the included file:
#section('left')
#include('modal', ['title' => 'Hello'])
#stop
Use #yield and set the section:
#section('left')
#include('modal')
#section('title')
Hello
#stop
#stop
I am using Laravel 4.2. I am unaware if what I am trying to do is possible, but I imagine it is.
According to the documentation, the include-way should be the way to do it:
Including Sub-Views
#include('view.name')
You may also pass an array of data to the included view:
#include('view.name', array('some'=>'data'))
My hunch is that $title is conflicting with another variable in your nested templates. Just for troubleshooting, try temporarily calling it something else.
pass an array of data to the included view
#include('view.name', array('some'=>'data'))
then use this on view/name folder
{{ $some }}

Override section in a laravel blade template throwing undefined variable errors

I am using Laravel 4 and blade templates, and running into an issue when I try and extend a template.
In my layout I have
#yield('content')
and in my page I have
#section('content')
Welcome {{ $name }}
#stop
which works fine, I've created another page very similar to my first, and just want to change override the admin content section. The other sections in the template are fine.
so I extend my page, and do
#section('content')
Hello!
#stop
I get an undefined notice with the $name variable.
I tried
#section('content')
Hello!
#overwrite
and same deal, I get the notice error.
I checked my controller and it IS using the correct template. I am not calling #parent so I don't understand, how can I overwrite a section in a template with out notice errors?
Blade layouts work their way up the tree to the route or master view before rendering any of the children. Thus, nested views that extend others must always have their parent rendered before they are. As a result, parent views that contain sections will always be rendered prior to the child.
To overcome the problem you are experiencing it is a good idea to only ever nest pages that don't overwrite parents sections that contain variables, as the parents content will always be rendered before the child.
As the above ideal can't always be adhered to or a parents section content is still required, a good alternative method would be to use view composers. View composers give you an opportunity to declare variables for any specific view whenever they are rendered.
View::composer(array('pages.admin'), function($view)
{
$view->with('name', Auth::user()->username);
});
Another alternative would be to use a view creator. Creators are fired the moment a view is instantiated rather than rendered. This method allows you to overwrite the variable should you so wish prior to the view being rendered.
View::creator(array('pages.admin'), function($view)
{
$view->with('name', Auth::user()->username);
});
You can read up more about these methods in the documentation here. (Or here for the Laravel 5 documentation.)
I can't guarantee support for Laravel 4 but for those looking for a solution that works in Laravel 5.5 (and probably a fair bit further back – hard to check) is to define the variables you need when #extending.
E.g. in the example in the question:
#extend('my.parent.view', ['name' => ''])
This approach can be especially useful if the data needed is available to the child-view, but under a different name.
E.g. if a parent-view needed a $parent variable, but the child view only has a $child variable which has a property referencing the parent, you might do:
#extend('my.parent.view', ['parent' => $child->parent])
I am not sure if this is a bug or intentional, but it seems like Laravel renders the variables before interpreting blade instructions.
The workaround would be this:
views/layouts/testlayout.blade.php:
<html>
<body>
#yield('sidebar', 'This is the master sidebar. {{ $name }}' )
<div class="container">
#yield('content')
</div>
</body>
</html>
actual view: views/test.blade.php
#extends('layouts.testlayout')
#section('sidebar')
No variable in the child
#stop
#section('content')
This is a child content
#stop
This prevents the variable $name to get rendered if there is a section with that name in the actual view. It seems like this is the approach if the content in the layout file contains a variable
In your page try this :
#section('content')
#hasSection('content')
#yield('content')
#else
Welcome {{ $name }}
#endif
#stop
And read this post for more inspiration https://laracasts.com/discuss/channels/laravel/laravel-blade-layouts-inheritence-problem
I found an easy solution for this problem :)
Just add the # symbol before the variable/method you call in the parent view. If there is an error (notice/warning) PHP will ignore that and continue the execution.
It's not perfect, but save us to code view/composers.
Hope this help!

Categories