assign $attributes in nested Laravel 7 blade components - php

With Laravel 7, I began to use View Components.
I am trying to pass the $attributes variable from one component to another like:
x-modal component:
<div {{ $attributes->merge(['class' => 'modal fade']) }}>
Something great...
</div>
x-modal-form component:
<x-modal {{ $attributes }}>
Something great too
</x-modal>
In this case, I have an id property in the x-modal component like:
<x-modal-form id="aRandomId" title="Test"></x-modal-form>
But in this case, the id aRandomId is not spread to the x-modal component. I have an error "syntax error, unexpected 'endif' (T_ENDIF), expecting end of file" because of {{ $attributes }}
Do you know how to do that?

This behavior has been fixed in Laravel 8: #32576
You can now pass the $attributes variable from one component to another

as per laravel documents :
All of the attributes that are not part of the component's constructor
will automatically be added to the component's "attribute bag". This
attribute bag is automatically made available to the component via the
$attributes variable. All of the attributes may be rendered within the
component by echoing this variable.
and in case of nested or use more than component in one view and want to use attribute bag so you put in this bag the common attribute and put manually unique attribute like so:
<x-modal {{ $attributes }}>
<x-modal-form {{ $attributes }} id="aRandomId" title="Test">
// code here
</x-modal-form>
</x-modal>
and of course, The id attribute specifies a unique id for an HTML element. The value of the id attribute must be unique within the HTML document.

Related

How can I use a twig variable as a form field name

I have a form template which has a repeated block for several similar form fields. It is used as follows:
{# form_template.html.twig #}
{{ include ('company-select.html.twig', {field: 'companiesInclude'})
{{ include ('company-select.html.twig', {field: 'companiesExclude'})
{{ include ('company-select.html.twig', {field: 'companiesLinked'})
Now I have a company select template, which looks as follows:
{# company-select.html.twig (simplified, the actual template is much more complex) #}
<div class="form form-field selector" id="{{ field }}">
{{ form_label(form.field) }}
{{ form_widget(form.field) }}
</div>
The way it is, the template fails, because 'field' is not a property of the FormView class.
How can I make the template interpolate the twig variable into the form_xxx function call as an actual field name?
A property of an object or an array element in twig can either be accessed via the dot notation (.) or via the square bracket one ([]).
If your property happens to be a twig variable, you will need to use the later form.
So in your case:
form_label(form[field])
form_widget(form[field])
Your code in company-select.html.twig ending up being:
<div class="form form-field selector" id="{{ field }}">
{{ form_label(form[field]) }}
{{ form_widget(form[field]) }}
</div>
This is, in a really simplified example, testable here.
Note that, in a more complex flavour, you can also use the attribute function
., []: Gets an attribute of a variable.
Source: https://twig.symfony.com/doc/3.x/templates.html#other-operators
Also worth reading on the same note: https://twig.symfony.com/doc/3.x/templates.html#variables

Use blade value inside a component

At the moment I can successfully display some generated content in my blade view by calling a variable with a key, like this:
<div>
{{ $data['key'] }}
</div>
What I would like to achieve, is to reuse the key for a class name for example. The reason for that is that I want to easily access this content with JavaScript by using a selector. Something that would look like this:
<div class='key'>
{{ $data['key'] }}
</div>
This code work, but as I have many fields, I would like to avoid duplicating the key. To achieve that, I thought of creating a blade components, and pass the key in the slot. So that I can reuse this key both in the class name, and in the placeholder for data.
But it seems that my variable {{ $data }} is not accessible from my component file, as it throws the error: $data is undefined.
Here is my code:
<!-- In main.blade.php -->
#component('my-component')
key
#endcomponent
<!-- In my-component.blade.php -->
<div class="{{ $slot }}">
{{ $data[$slot] }}
</div>
I am not familiar to Blade so I am open to another approach if necessary.
You should pass your data and key as arguments to your component, thereby being more explicit. You don't need to use a slot for this, as a slot is generally used for blocks of text or HTML, not for simple attributes.
Create your component like this,
<div class="{{ $key }}">
{{ $data[$key] }}
</div>
And then render it like this
#component('my-component', ['data' => $data, 'key' => 'key'])

Strange Symfony syntax

I've joined new project of website in Symfony3 framework and now I'm struggling an issue, trying to figure out this particular syntax in Twig:
<li>{{ 'site.template.menu.contact'|trans }}</li>
Arguments in path() twig function have name of route in my SiteController but i totally don't know what does code between <a/> tags, except 'trans' filter. I don't have any variables in my twig template file.
Have you seen something like this before? Where I should find information about this in docs or how to name syntax like this to find some information?
It is just the twig "internationalization" (often abbreviated i18n).
Docs for it are here.
The quotes around the object shouldn't be there. I'm assuming that an object called site is being passed to the view, so it should be {{ site.template.menu.contact|trans }}
To explain the dot notation in twig;
If your PHP array is something like;
$site['template']['menu']['contact'] = 'fubar';
If it is an object then it is just attributes of the object.

Is there any way to pass some variables through ResourceController to template in Sylius?

I need to override behavior of sylius_partial_product_latest route to have ability render template with additional parameter.
The simple example: at the different pages I need to show from 2 to 4 products at a time with carousel scrolling through 4-8 products. Now in the SyliusWebBundle:Frontend/Product:latest template I have:
{{ grid(products) }}
But I need in some cases:
{{ grid(products, 2) }}
In others:
{{ grid(products, 3) }}
{# or it can be 4 or any other number #}
Now in template I have only products var (it served by Resources mechanism), I can pass variables to the repository where I can add it to my products array, but it is not a good way. It can be accomplished by simple passing variables to the query:
{{ render(url('sylius_partial_product_latest', {'size': 3, 'limit': 2, 'template': 'SyliusWebBundle:Frontend/Product:latest.html.twig'})) }}
I need to have ability to pass variable size to template SyliusWebBundle:Frontend/Product:latest outside of products.
I tried override the ProductBundle and ResourceBundle... But overriding controllers with custom action (I do not want to override indexAction or showAction) led me nowhere. PHP doesn't hit my controller at all. Instead it hit showAction of ResourceBundle. And, yes, I overrode routing to point my controller.
If I override ProductController with new route and use it in my template it throws exception:
An exception has been thrown during the rendering of a template
("Controller "sylius.controller.product:partialAction" for URI
"/partial" is not callable.") in
SyliusWebBundle:Frontend/Product:show.html.twig at line 136.
When I change _controller to point my controller in standard Symfony manner I have next exception:
Catchable fatal error: Argument 1 passed to
Sylius\Bundle\ResourceBundle\Controller\ResourceController::__construct()
must be an instance of
Sylius\Bundle\ResourceBundle\Controller\Configuration, none given,
called in
/Users/mihail/Sites/magazin/vendor/symfony/symfony/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerResolver.php
on line 77 and defined in
/Users/mihail/Sites/magazin/vendor/sylius/sylius/src/Sylius/Bundle/ResourceBundle/Controller/ResourceController.php
on line 63
There are 2 ways that you could go with this..
Controller
You could extend the controller and pass the variable into your template the same way you could with any other controller.
Request
You could just pass the variable to your controller through the GET parameters as the request like your..
{{ render(url('sylius_partial_product_latest', {'size': 3, 'limit': 2, 'template': 'SyliusWebBundle:Frontend/Product:latest.html.twig'})) }}
.. and then get that in your template using the request object like..
{{ grid(product, app.request.get('size')) }} // with a default or null

Symfony2/Twig - Add classes to form elements

I've just started a new Symfony2 project where I've used the generate:doctrine:crud to quickly scale out a few views, forms, etc.
The generated form code is just:
{{ form(form) }} but includes a generic create or delete button. I was wondering how I could add a class to these generic buttons or modify them in any way since it's just encompassed in {{ form(form) }}?
For reference I'm using Twitter Bootstrap to quickly apply some styles so I don't want to change the css based on the submit button.
Thanks!
You can specify CSS classes in the form builder class to avoid filling your Twig template with html even for rendering the form individually.
When you call {{ form(form) }} you are using a helper to simplify your code so you don't have to call form_widget for each one of your fields, but doing so you can't control the exact display in the template. To do it you have to specify the class that will be applied to the field.
In the WhateverType.php file, inside the Forms folder, you have the form builder. There you should have something like:
$builder
->add('text')
->add('whatever')
There you have to add the classes:
$builder
->add('text', 'attr'=> array('class'=>'btn')
->add('whatever')
Then, when your form is displayed in the template, it will apply the classes that you specified in the builder.
After following dmnptr's answer (breaking form into parts), you can pass an array of arguments to each form / form_row / form_label etc by:
{{ form(form, { 'attr': { 'class': 'your-css-class-1 your-css-class-2' } } ) }}
The attr param sets attributes for the item, so the above would produce:
<form class="your-css-class-1 your-css-class-2" ...
You are going to have to render each filed by hand and add necessary classes to elements in your TWIG. Read on how to do it in the official docs - http://symfony.com/doc/current/book/forms.html#rendering-each-field-by-hand

Categories