Twig's documentation for tag include looks very similar to that of function include.
Tag include:
{% include 'header.html' %}
Function include:
{{ include('template.html') }}
Can somebody point out in what circumstances, one is preferred over the other? Thanks!
{{ include() }} Was introduce in Symfony 2.2:
Using a function allows you to do whatever you want with the output (which is not possible with a tag), like a simple:
{{ set content = include('some_template') }}
But as Fabien Potentier (twig founder) said
the function and the tag does indeed the exact same thing
You can find the discution about it's introduction here: https://github.com/twigphp/Twig/pull/926
Twig 3.x documentation for the include tag now states:
It is recommended to use the include function instead as it provides the same features with a bit more flexibility:
The include function is semantically more “correct” (including a template outputs its rendered contents in the current scope; a tag should not display anything);
The include function is more “composable”:
The include function does not impose any specific order for arguments thanks to named arguments.
Related
Laravel 5.4 Blade introduced the concept of components & slots - but I can't see what they add over the traditional #include. As I understand, with component/slots, you do:
In template component-tpl.blade.php:
<div class='container'>
<h1>{{$slot1}}</h1>
<h2>{{$slot2}}</h2>
</div>
Using slots in page template, you do:
#component('component-tpl')
#slot('slot1')
The content of Slot 1
#endslot
#slot('slot2')
The content of Slot 2
#endslot
#endcomponent
What functionality does that provide over the older:
#include('component-tpl',['slot1'=>'The content of Slot 1',
'slot2'=>"The content of Slot 2"])
using the exact same 'component-tpl.blade.php' Blade template?
What am I missing? Thanks for any insights.
Chris
As stated, there's no functional difference I was incorrect - see benjaminhull's answer for details on variable scoping and passing blade syntax code. The following still holds for basic usage, though.
If a slot could contain HTML, then using a component will give a cleaner syntax in your blade files.
#component('test')
<strong>This text has html</strong>
#endcomponent
versus
#include('test', ['slot' => '<strong>This text has HTML</strong>'])
Equally, if a component has no slots, then an include may be preferred:
#include('test')
versus
#component('test')
#endcomponent
There are two key differences.
1. Variable scope
As described in #DavidHyogo's answer, a component only sees variables explicitly passed to it. So you have to give it all variables like so...
#component('my-component', ['foo' => 'bar', 'etc' => 'etc'])
Whereas an include will adopt all variables from the global/current scope by default - unless you define an explicit set of variables to pass it, which then becomes local scope again.
{{-- This include will see all variables from the global/current scope --}}
#include('my-component')
{{-- This include will only see the variables explicitly passed in --}}
#include('my-component', ['foo' => 'bar', 'etc' => 'etc'])
2. Component's {{ $slot }} vs include's {{ $var }}
When using a {{ $slot }} in a component, you can give it blade syntax code e.g...
{{-- alert.blade.php --}}
<div class="alert">{{ $slot }}</div>
#component('alert')
<div>Hello {{ $name }} #include('welcome-message')</div>
#endcomponent
Note how the slot will receive html AND blade syntax code and just deal with it.
This is not possible with includes because you can only pass variables into includes...
{{-- alert.blade.php --}}
<div class="alert">{{ $slot }}</div>
#include('alert', ['slot' => "I CAN'T PASS IN BLADE SYNTAX HERE!"])
It could be done in a more hacky way by grabbing a fresh view() helper and passing it some variables to compile the output we want to pass into the slot, but this is what components are for.
I think I've tracked down another crucial difference. For instance, from the documentation for 5.4:
Blade's #include directive allows you to include a Blade view from within another view. All variables that are available to the parent view will be made available to the included view:
As far as I can tell, components have a different scope from a containing view and so the variables available to the parent view are not available within the component. You need to pass a variable to a component like this:
#component('alert', ['foo' => 'bar'])
#endcomponent
This discussion is related to this problem:
Use variables inside the Markdown Mailables
As the documentation says:
Components and slots provide similar benefits to sections and
layouts; however, some may find the mental model of components and
slots easier to understand.
For me most important thing is component needs a class. So when I need just a simplest reusable part of html (blade) there is no need to create blade file + php file, just simple #include with subview is enough ;)
I was just going through one of the Twig files in the Bolt default theme template, and I came across the following line of code:
{{ __("Unfortunately, no content could be found. Try another page, or go to the homepage.", {'%paths_root%': paths.root} ) }}
Now I thought the way you echo something in Twig is as follows:
{{ 'hello there' }}
I googled double underline and found this, but I’m not sure that's the answer to my question.
So what exactly is the double underline in Twig or Bolt?
In the current stable Bolt version, __() is a Twig function to call our translation layer that sits on top of Symfony's.
The second parameter in that function is the value in the string that is variable, and the value you want inserted in its place for that specific translation string, at that point.
I’m not sure if I understand this correctly, but in the Symfony framework for translations of strings you should use the translator service.
Then you could use the trans and transchoice Twig tags.
Please see Symfony documentation for more details:
Symfony translations
I have <?php masterslider(1); ?> and I need that to render in a .twig file, can anyone let me know the formatting for timber to get this function to work.
With Timber you can call functions in your Twig files:
{{ function('function_to_call', 'param_1', 'param_2', '…' ) }}
The first argument will be the name of the function to call, the following arguments will be all the parameters you want/need to pass to that function.
You could translate your function <?php masterslider(1); ?> to {{ function('masterslider', 1) }} if you want to use it in a Twig file.
To learn more about calling functions in Twig when using Timber, refer to the the Timber documentation on functions.
I wish to use the following inside of a Twig Extension
$kernel = $container->getService('kernel');
$path = $kernel->locateResource('#AdmeDemoBundle/path/to/file/Foo.png');
but this involved passing in the Kernel, which is bad. Plus I could not get it to work anyway when trying this method.
How can I access a resources path within a Twig Extension?
The Extension is already a Service. I can use Assetic to give me the URL, but I really want the path.
I had a similar need: i needed to pass to the filter the url of an image to display it in a for loop and build a string.
I passed the URL directly to the filter in this way:
{% image '#AppBundle/Resources/public/images/my_asset.png' %}
{% set resolved_asset_url = asset_url %}
{% endimage %}
{{ my_var|filter_name(resolved_asset_url)|raw(html) }}
In this way the Twig template resolve the correct resource's URL, sets it as a variable, and then I pass it to the filter from inside the template itself, without having to deal with kernel or something else.
If you want just to serve a download, you should create a Route that accomplishes that task.
In this way, you'll call the locator inside the route, and a simple
{{ path('route_that_does_the_locator_thing') }}
will be fine.
If you need instead to include a file in your template (ex. CSS, JS..), you need to declare your file as an asset, maybe using Assetic.
Is it possible to yield to another view but then default with an include statement?
Example:
#yield('header', #include('partials.header'))
The intended action is that if the subview does not include the header, then the current template will include the partials.header view.
It is possible. But you can't use blade tags inside blade tags. What you can do however is use View::make() instead of #include. #include actually compiles to a make call on the view factory.
#yield('header', View::make('partials.header'))