form_widget with dynamic form name - php

In my Twig template I have a FOR LOOP that creates a multiple number of forms like so:
{% for thing in things %}
{% set form_id = 'myform_' ~ thing.Id %}
{% set form_name = attribute(form, 'myform_' ~ thing.Id) %}
{{ form_widget(form_id) }}
{{ form_widget(form_name) }}
{% endfor %}
I would like this to generate the following:
{{ form_widget(myform_1) }}
{{ form_widget(myform_2) }}
.... and so on.
I left my 2 failed attempts in there, (form_id and form_name), to save anyone from suggesting those as possible solutions.
To summarize; I need to insert the dynamically created value (myform_1, myform_2) inside of {{ form_widget() }}

You can render dynamic fields form with dynamic name in Twig with special function of Twig :
{{ attribute(object, method) }}
{{ attribute(object, method, arguments) }}
{{ attribute(array, item) }}
With this function you can easily generate dynamic string name for your field dynamic into your form like this
{{ form_widget(attribute(form, 'myfielddynamicname' ~ var ~ ' lastchar')) }}
With this variable "var" (array or others type) you can render lot of dynamic form name like :
myfielddynamicnamefoolastchar
myfielddynamicnamebarlastchar
myfielddynamicnameneolastchar
For more understanding you can read this official twig documentation function
here : attribute twig function documentation

The things myform_1 and myform_2 simply are variables with FormView object as you define in your controller.
I don't know if Twig allows on dynamic variables call, although you can collect these form objects in array in controller before passing to view. After this step, you can just iterate thought this array It will manage the problem you are facing with.

Don't create a loop in your Twig: the layout should only render a single form. Then you can build the forms in your controller and render each one of them.
See this documentation on the Symfony book on how to get the result of a rendered template. You can concatenate the single render results and return a response with the full content.

Related

I am unable to get values in twig template in drupal 9

I have mapped the fields of a content type (a webform) to node using Webform content creator in drupal 9 now the issue is that i am not getting those mapped fields in my twig template. All I am getting are previously mapped values. I have double checked the fields in content type and mapping in webform content creator.
You can use Drupal module Devel (https://www.drupal.org/project/devel) to find the right key to display.
Or debug in twig some of these:
{{ content.field_name.0 }}
{{ node.field_name.0.target_id }}
get keys you need:
{{ dump(content|keys) }}
dump like this for small fields:
{% for k,v in content.field_name %}
- {{ k }}: {{ dump(v.value) }}<br>
{% endfor %}
the variable content.field_name can be changed if you found the right field from your dump before

Twig iterate/read and get value - Octobercms

Hi guys its rather a very basic question, had chance to look several questions on stackoverflow but all in vain.
so i have this twig variable called "WordoftheDayfromDB ", to which i am passing from some data after querying DB in my controller via laravel pluck method. The controller exsits in plugin of octobercms. the content of the variable is shown below
{% set WordoftheDayfromDB = __SELF__.words %}
{{WordoftheDayfromDB}} # this output below object
["{\"id\":4,\"word_tr\":\"parazit\",\"slug_tr\":\"parazit\",\"word_gr\":\"\\u03c0\\u03b1\\u03c1\\u03ac\\u03c3\\u03b9\\u03c4\\u03bf\",\"slug_gr\":\"parasito\",\"pubordraft\":1,\"created_at\":\"2017-06-07 13:04:57\",\"updated_at\":\"2017-06-07 13:04:57\",\"deleted_at\":null,\"word_image\":\"\\\/cropped-images\\\/image2.jpg\",\"typeswb_id\":0}"]
can someone tell me a way to extract keys and values from the about twig variable.
what i already tried is following:
<pre> {{WordoftheDayfromDB.id}}</pre>
or
{% for item in WordoftheDayfromDB %}
{{item.word_tr}}
{% endfor %}
also some combination using {% if WordoftheDayfromDB is iterable %}.
I will appreciate your answer very much!
thank you for reading my question.
You can use the for loop so that the keys and values are both accessible like this:
{% for key, value in WordoftheDayfromDB %}
<li>{{ key }}: {{ value }}</li>
{% endfor %}
So the answer is rather complex then even i anticipated! i had to do a lot of digging with frustration to really get at the bottom of this matter.
First thing first, i was doing a cron job where i saved the data from a model in text type field. That is why if you see above result i.e
{% set WordoftheDayfromDB = __SELF__.words %}
{{WordoftheDayfromDB}} # this output below object
["{\"id\":4,\"word_tr\":\"parazit\",\"slug_tr\":\"parazit\",\"word_gr\":\"\\u03c0\\u03b1\\u03c1\\u03ac\\u03c3\\u03b9\\u03c4\\u03bf\",\"slug_gr\":\"parasito\",\"pubordraft\":1,\"created_at\":\"2017-06-07 13:04:57\",\"updated_at\":\"2017-06-07 13:04:57\",\"deleted_at\":null,\"word_image\":\"\\\/cropped-images\\\/image2.jpg\",\"typeswb_id\":0}"]
it outputs a JSON String, too bad can't iterate or do something with it.
To solve this,
Create json_decode filter in twig.
Apply the filter to value part of array.
Access Individual values of array with variable[keyname] method.
I created a twig filter json_decode
for creating filter see this Link
while in October, the creation to new twig extension is rather easy which is just give registerMarkupTags method in Plugin.php with filter array poiting to name and function name. See this link for extending twig in octobercms here
Now, the part we were waiting for, how to get the values and show them in twig template. Here it is going to be, by using above same example. This is what i did
{% set wordoftheday = __SELF__.words %}
{% for key, value in wordoftheday %}
{% set decoded = value|json_decode %}
# to get the indvisual values
{{ decoded['id'] }}
{{ decoded['created_at'] }}
{% endfor %}

How to deal with missing values in the array in twig

Some of the values that I'm requesting may or maynot be returning a value as the api takes someones profile and they have left out fields in registration etc.
If I request something which isn't there in my twig template I get the error
throw new Twig_Error_Runtime(sprintf('Key "%s" in object (with ArrayAccess) of type "%s" does not exist', $arrayItem, get_class($object)), -1, $this->getTemplateName());
I could solve this by doing this code on each value but it's messy and not clever is there a way of not getting the error, like in other php frameworks, it will just leave a blank
{% if profile.aboutMe %}
{{ profile.aboutMe }}
controller
return $this->render('LoginLogBundle:Default:userprofile.html.twig',array('profile'=>$user)));
You can use the default() filter to display some text when a object or a value is not defined:
{{ profile.aboutMe|default('No profile') }}
{# or #}
{{ profile.aboutMe|default('-') }}
{# or #}
{{ profile.aboutMe|default('') }}
{# etc. #}

How To append parameters to KNP paginator url

I am using the KNP Paginator bundle for pagination. Does anyone know how to append parameters to the generated url?
Here is my set up:
{{ knp_pagination_sortable(supplierProducts, 'Product Sku', 'p.name') }}
I want to add &section=supplier to the end of the URL, I just have no clue how to do it. I looked through the docs but did not find any info.
Please help if you can.
Thanks.
According to the KnpPaginator documentation, you can append query parameters as follows:
$paginator = $this->get('knp_paginator');
...
$pagination->setParam('section', 'supplier');
You could extend the kn_pagination_sortable template. When you run "knp_pagination_sortable" behind the scenes, it will basically generate an HTML according to your specifications. However, you can extend that. Instead of using the bundle's generated HTML for that element, you can write your own template for that pagination_sortable. This is a snippet from the project I'm working on. This is at my pagination_sortable.html.twig:
<a id="table_sorteable_{{ options['title']|lower }}" {% for attr, value in options %} {{ attr }}="{{ value }}"{% endfor %}>
{{ title }}
<b class="caret {{ options['class'] }}"></b>
</a>
Get it? You can have a template like that and change it according to your needs.
You can find more information on the link below.
Overriding default pagination template
As of 2020, and KnpPaginatorBundle v5.3, the solution proposed by #likeitlikeit doesn't work because the setParam method doesn't exist any more.
But you can append parameters to the sort and pagination links directly in the knp helpers in twig:
{# 4th parameter for sortable helper #}
{{ knp_pagination_sortable(results, column.title, column.alias, {}, params) }}
{# 3rd parameter for pagination helper #}
{{ knp_pagination_render(results, '', params) }}
For example, if you want to include the query parameters in the sort and pagination links, you can do:
{# Sort - pass all query parameters except sort column and direction #}
{% set params=app.request.query.all | filter((v, k) => (k != 'direction' and k != 'sort'))%}
{% for column in ... %}
{{ knp_pagination_sortable(results, column.title, column.alias, {}, params) }}
{% endfor %}
{# Pagination #}
{{ knp_pagination_render(results, '', app.request.query.all) }}
To add parameters in the url, I proceeded like this:
in Front:
{{ knp_pagination_render(clients, ('annuaire/my_pagination.html.twig'), {"type": type ? type : '' ,"city": city ? city : ''}) }}

twig: pass variables from view to controller

Setup:
Twig 1.13.1
PHP 5.4.3
Problem:
I have 10,000 articles in my DB. I need a way to only allow X amount of stories to display on the page. I know I can limit the number in the controller before i call the template but that number will be different depending on the template that is used. I will have one controller to handles all the articles. I need a way to pass the number from the template to the controller to limit the array. I don't want to pull down all 10,000 articles then use twig "slice" filter/func.
I know in django you can use the below. That will only load the top 3 stories.
{% get_latest_stories 3 sports as story_list %}
{% for story in story_list %}
{{ story.title }}
{% endfor %}
Here is my current files.
Controller
<?php
$stories = news_stories::getStories("sports",5); //getStories(section,limit);
?>
<?=$twig->render("storyList.html", array('stories' => $stories))?>
View/Template
{% for story in story_list %}
{{ story.title }}
{% endfor %}
Summary
I would like a way to pass a number from the template to the controller so that i can limit the about of rows returned from the DB
Logically speaking, it would be impossible for the view to pass something to controller since the view is being processed at the end of the stack, after everything else.
You can however, pass a function into the view. You would want to create some sort of getViewStories function that you can access from your twig template. Since you have this already in your controller:
<?php
$stories = news_stories::getStories("sports",5); //getStories(section,limit);
?>
<?=$twig->render("storyList.html", array('stories' => $stories))?>
All you would need to do is change it around a bit, like this:
<?php
$function = new Twig_SimpleFunction('getViewStories', function (section, limit) {
return news_stories::getStories(section,limit);
});
$twig->addFunction($function);
?>
<?=$twig->render("storyList.html")?>
Now, from inside your template, you can call this function, like so:
{% set story_list = getViewStories('sports',5) %}
{% for story in story_list %}
{{ story.title }}
{% endfor %}
And change the getViewStories parameters around in each template.
And while you can use the slice filter, I would recommend against it in your case, as it makes for unnecessarily long database calls. This is the most optimized method (that I'm aware of).
You want to use the slice filter I think this should work for you
http://twig.sensiolabs.org/doc/filters/slice.html
{% for story in story_list|slice(1,5) %}
{{ story.title }}
{% endfor %}
should only return the elements 1 - > 5 of the loop then break loop. You can also do it like this
{% for story in story_list|[start:5] %}
{{ story.title }}
{% endfor %}
Disclaimer: I've never actually used twig though this was just a quick browse through its docs
You can embedded controllers ( or render other urls ) from inside a twig template. This means you could have a main layout template for your site, and keep your storyList.html template very plain - just to iterate over the stories and any markup they might need.
In your main layout you would render the action for the news stories:
<div id="stories">
{% render url('...') with { section: 'sports', limit: 5}, {'standalone': 'js'} %}
</div>
This way requires hindclude.js included on your page. Check these docs. If you are also using symfony ( you mention MVC but not the framework ) - even better. Scroll up a bit and look at Embedded controllers.
Otherwise, I believe this way essentially uses ajax.

Categories