Twig check elements of array are in another array - twig

I'm trying to check in twig if any element of one array are set in other array.
Example:
I have user.roles with ['ROLE_ADMIN','ROLE_MANAGER'] and I have the product.roles with ['ROLE_ADMIN','ROLE_USER'].
I want to check (in Twig) if any user.roles are in product.roles, like:
{{ user.roles[0] is product.roles|keys }}
But with each element of user.roles in the same function.
Does anyone know how?

You could use the filter filter to do this, but guessing it would be better to move this to PHP / TwigExtension
{% if user.roles |filter((role) => role in product.roles) | length > 0 %}
Can do something with the post
{% else %}
Access denied
{% endif %}
demo

Use a for loop:
{% for role in user.roles %}
{% if role in product.roles|keys %}
do something...
{% endif %}
{% endfor %}

Related

How to add entity extension in Shopware 6 App?

I want to query the categories of the product in the product listing of a Shopware app, so that I can query the customFields of all categories. Is this even possible with an app?
I have already tried via a navigation-page-loaded. And when I override the box-standard.html.twig and access the product, I can't access the categories there.
For each product i want the categories extensions
As the categories association is not loaded for products in the listing you have to fetch the categories using an app script.
As already noted, add the script to the navigation-page-loaded hook, i.e. in Resources/scripts/navigation-page-loaded/category-loader.twig:
{% set products = [] %}
{% if hook.page.cmsPage.type === 'product_list' %}
{% foreach hook.page.cmsPage.sections as section %}
{% foreach section.blocks as sectionBlock %}
{% if sectionBlock.type !== 'product-listing' %}
{% continue %}
{% endif %}
{% foreach sectionBlock.slots as slot %}
{% if slot.type !== 'product-listing' %}
{% continue %}
{% endif %}
{% foreach slot.data.listing.entities as product %}
{% set products = products|merge([product]) %}
{% endforeach %}
{% endforeach %}
{% endforeach %}
{% endforeach %}
{% endif %}
{% set categoryIds = products|reduce((carry, v) => carry|merge(v.categoryIds), []) %}
{% if categoryIds %}
{% set categories = services.repository.search('category', {'ids': categoryIds}) %}
{% foreach products as product %}
{% do product.addArrayExtension('myCategories', {
'categories': categories.entities.getList(product.categoryIds),
}) %}
{% endforeach %}
{% endif %}
Where we first extract all the products, than load the categories of all products at once, and than assign the categories back to the products.
Note that for reading the category entity you need the correct permission, i.e. in the manifest.xml add:
<permissions>
<read>category</read>
<read>category_translation</read>
</permissions>
Now you should be able to access in the box-standard.html.twig template the categories using product.extensions.myCategories.categories.
If I understand your issue correctly, you are trying to access a product's category's custom fields in some piece of storefront logic (like a Twig template).
The way I see it, you would have to add a script that would enable you to query the repository for the categories and their custom fields. The issue is, a SalesChannelProductEntity will not contain the information about all its categories (only the SeoCategory), so you might need to first query the product_category repository.
Generally, it is going to be complicated but it should be doable.

How can I check whether the provided URLs is youtube or vimeo?

I have this two URLs:
https://youtu.be/erwZDijlFAA
https://vimeo.com/262998843
Now i want to check it by Twig. How can i check ?
{% if url %} <p>youtube</p> {% else %} <p>vimeo</p> {% endif %}
Or have any way to check whether the provided URLs is youtube or vimeo ?
You can use a simply version that use starts with operator like:
{% if url starts with 'https://youtu.be/' %}
YouTube.com
{% endif %}
Or for more complex criteria you can use Regular expression thru matches like:
{% if url matches '%(?:youtube(?:-nocookie)?\.com/(?:[^/]+/.+/|(?:v|e(?:mbed)?)/|.*[?&]v=)|youtu\.be/)([^"&?/ ]{11})%i' %}
YouTube.com
{% endif %}
RegEx credits: https://gist.github.com/ghalusa/6c7f3a00fd2383e5ef33
More info in the doc about comparison operator here
Hope this help
You can use the below code to segregate the videos in twig.
{% set link_type = view.field.body.original_value %} // Fetching value from the body field
{% if ('youtube' in link_type|render|render) %}
youtube url
{% else if ('vimeo' in link_typr|render|render ) %}
vimeo Url
{% endif %}

Symfony & Twig: how to get vars in twig by DB data?

One question please.
{{ dump(app.user.slugName) }}
If I do the above snippet in Twig, I get the slugName of the user loged ("my-user-2", i.e.) in the app (SlugName is an atribute of the entity user). Ok & Correct. But... I want to order this action from a var (var from BD data)
I have a variable named option which is set like this:
{% set option = 'app.user.slugName' %}
But when I'm trying output this variable with {{ dump(option)}} it returns app.user.slugName as literal. It does not return my-user-2.
Is there are any way in twig to solve this? It's a function to generate a menu, but some links needs some parameters.
I see what you mean, but Twig can't evaluate expression like that.
To achieve something like that you would need a snippet like this,
{% set value_methods = 'app.user.slugname' %}
{% set option_value = _context %}
{% for method in (value_methods|split('.')) if method != '' %}
{% set option_value = attribute(option_value, (method|replace({'()': '', }))) %}
{% endfor %}
{{ option_value }}
twigfiddle
(edit)
Remember you can create a macro to achieve some reusability for this snippet,
{% import _self as macros %}
{{ macros.evaluate(_context, 'app.user.slugname') }}
{% macro evaluate(context, value_methods) %}
{% set option_value = context %}
{% for method in (value_methods|split('.')) if method != '' %}
{% set option_value = attribute(option_value, (method|replace({'()': '', }))) %}
{% endfor %}
{{ option_value }}
{% endmacro %}

Twig get object names ending with numbers dynamically

I have some objects like address1, address2, address3 ... address10. All these objects have lat and long values.
I know we can get it from the attribute() function of Twig, but what I want in my twig template is to get the main objects
{% for i in 1..10 %}
{% set address = address~i %}
{{ address.lat }}
// or like
{{ attribute(address, 'lat') }}
{% endfor %}
Just simply use :
{% for i in 1..10 %}
{{ attribute(attribute(_context, 'address'~i), 'lat') }}
{% endfor %}

Check if variable is string or array in Twig

Is it possible to check if given variable is string in Twig ?
Expected solution:
messages.en.yml:
hello:
stranger: Hello stranger !
known: Hello %name% !
Twig template:
{% set title='hello.stranger' %}
{% set title=['hello.known',{'%name%' : 'hsz'}] %}
{% if title is string %}
{{ title|trans }}
{% else %}
{{ title[0]|trans(title[1]) }}
{% endif %}
Is it possible to do it this way ? Or maybe you have better solution ?
Can be done with the test iterable, added in twig1.7, as Wouter J stated in the comment :
{# evaluates to true if the users variable is iterable #}
{% if users is iterable %}
{% for user in users %}
Hello {{ user }}!
{% endfor %}
{% else %}
{# users is probably a string #}
Hello {{ users }}!
{% endif %}
Reference : iterable
Ok, I did it with:
{% if title[0] is not defined %}
{{ title|trans }}
{% else %}
{{ title[0]|trans(title[1]) }}
{% endif %}
Ugly, but works.
I found iterable to not be good enough since other objects can also be iterable, and are clearly different than an array.
Therefore adding a new Twig_SimpleTest to check if an item is_array is much more explicit. You can add this to your app configuration / after twig is bootstrapped.
$isArray= new Twig_SimpleTest('array', function ($value) {
return is_array($value);
});
$twig->addTest($isArray);
Usage becomes very clean:
{% if value is array %}
<!-- handle array -->
{% else %}
<!-- handle non-array -->
{% endif % }
There is no way to check it correctly using code from the box.
It's better to create custom TwigExtension and add custom check (or use code from OptionResolver).
So, as the result, for Twig 3, it will be smth like this
class CoreExtension extends AbstractExtension
{
public function getTests(): array
{
return [
new TwigTest('instanceof', [$this, 'instanceof']),
];
}
public function instanceof($value, string $type): bool
{
return ('null' === $type && null === $value)
|| (\function_exists($func = 'is_'.$type) && $func($value))
|| $value instanceof $type;
}
}
Assuming you know for a fact that a value is always either a string or an array:
{% if value is iterable and value is not string %}
...
{% else %}
...
{% endif %}
This worked good enough for me in a project I was working on. I realize you may need another solution.

Resources