I have a test that I can use as follows:
{% if app.user is user_that_has_more_than_one_partner %}
This is verbose, and I was wondering if it might not make more sense to create a has keyword that triggers a test like is does. That way, we could use:
{% if app.user has more_than_one_partner %}
Since has typically returns a boolean response, I would consider this useful in many more instances.
I thought about adding support for has several times but never did. I think it makes sense, and I think it could even simplify some test names we have in Symfony (in the workflow component IIRC).
What others think?
in the workflow component IIRC
Exactly ;) :+1: for me
@lyrixx Can you paste here what we have in Symfony and what it would look like with the introduction of has?
current usage
{% if workflow_has_marked_place(aSubject, 'my_place_1') %}
The object is in place "my_place_1"
{% endif %}
new usage
{% if aSubject has workflow_place('my_place_1') %}
The object is in place "my_place_1"
{% endif %}
We had the discussion about whether workflow_has_marked_place() should become a test and only the fact that it would read weird with "is" led to the introduction of the function IIRC. So having support for "has" would help us there.
I'm against this change because in my mind has has a different meaning. has often relates to an inclusion check for collections. Using it as a substitute of is may confuse beginners.
@ooflorent, can you post an example of what you mean?
@imctomhv Sure. Let's rename the variables from the proposal:
{% if filters has title %}
What are we testing here? Let's make a guess without looking at the proposal.
filters contains title?filters equals title?I bet every newcomer will assume 1.
Tests triggered by has should be separated from tests triggered by is to avoid weird tests such as foo has divisible by (3).
This new keyword could be confusing in some circumstances:
1) Replacing in with has:
{# BEFORE #}
{% is username in user.friends %}
...
{% endif %}
{# AFTER - it looks OK but it won't work #}
{% is user.friends has username %}
...
{% endif %}
2) Replacing ?? or default() with has:
{# BEFORE #}
{{ user.email ?? user.name }}
{# AFTER - it looks OK but it won't work #}
{{ user has 'email' ? user.email : user.name }}
So, has is indeed not a synonym for is. What we could do is add support for has but only for specific tests. A test would basically be able to choose if it works with is or has, defaulting to is for BC reasons (and because it makes more sense most of the time).
But if you allow has in some circumstances, some people (i.e. non-developers) will think that it can be used everywhere. They'll do if user.friends has username and it won't work ... and they won't know why 馃槙
Is it possible to have situations where a test would make sense if it is used with is and with has?
@javiereguiluz Not sure I understand your concern as you have the same issue with all features then. You cannot use keywords at will.
@julienfalque I don't think so, but if we have some examples, I would like to see them.
@javiereguiluz Just to be clear, the docs are very clear about the syntax: it's is then a test name or has then a test name. Your examples do not follow this scheme.
Actually, even if it happens, I guess implementing the test for both keywords wouldn't be a big deal.
Maybe it's because of my usual frustration with is. I often use this code:
{% if section_name is 'index' %}
...
{% endif %}
... and get the Twig_Error_Syntax error ... although looking at the template, it looks like it should work like a charm.
Maybe it helps if the proposed working is pseudo coded out?
Like:
{{ a has b ?? 1}}
Twig tries:
not trying to be critical, just looking for proposed implementation
Keep in mind that we should keep one operator for each operation.
It's section_name == "index", not section_name is "index", or a.b is defined, not a has b.
So, in both cases, we already have a working notation that we should not replace.
Another discussion could be to deprecate == in favor of is (a is b which would be quite nice as we also have a is same as b). And the same goes for is defined. But that would be a huge BC break with tons of templates to update.
@fabpot this would even make the syntax ambiguous. Should a is b use the b test or compared a to the b variable ? If this depends on whether b is an existing test, it creates 2 issues:
b does not exist)b test, it breaks all existing templates using a b variable, as it changes the meaning of an existing expression.@SpacePossum your comment has nothing to do with the suggested feature. You are proposing a totally different has operator than the one suggested by @fabpot
@SpacePossum your comment has nothing to do with the suggested feature. You are proposing a totally different has operator than the one suggested by @fabpot
I'm not proposing anything, I'm asking what the proposed/suggested feature will do:
Maybe it helps if the proposed working is pseudo coded out?
@SpacePossum but your pseudo-code is not what was proposed at the beginning of the discussion. your pseudo-code is about a replacement for is defined, which is totally different.
@ooflorent I don't think we're proposing the same thing. I think you're proposing (or think I'm proposing) is a way to check whether a collection contains a particular element, which is a great idea, and the contains keyword is perfect.
What I am proposing is a more semantic way to trigger a Twig_SimpleTest.
Ideally, I would write:
{% if app.user.hasMoreThanOnePartner %}
However, I do not have an association User::$partners. The association is many-to-many unidirectional Partner::$user, therefore I have to use a repository and so I must use either a Twig_SimpleTest or a Twig_Function:
{% if app.user is user_that_has_more_than_one_partner %}
or
{% if has_more_than_one_partner(app.user) %}
Neither of these is semantically ideal. I would much prefer to be able to do the following:
{% if app.user has more_than_one_partner %}
oh maybe I wasn't clear, I don't propose anything, I would like someone to provide pseudo code about what is proposed.
So far example
{% if app.user has more_than_one_partner %}
will Twig compile to PHP code that checks if the function has_more_than_one_partner($app['user']) or the method $more_than_one_partner->has( $app.user) or $app['user']->has('more_than_one_partner') exists and run if so during runtime? Again, I'm not criticizing, just wondering, maybe I'm just out of my league about what is proposed.
@SpacePossum, take a look here: http://symfony.com/doc/current/templating/twig_extension.html
Twig tests are not about calling a method on the variable. They areabout callign a callable defined by the extension registering the test (similar to functions and filters)
I'm still a bit confused as well about whathas does in this case, if not checking for an item in a collection. Can you describe what has_more_than_one_partner equates to, that would clarify greatly I think.
IMO has can be used in broader contexts than just checking for the existence of an item in a collection (where the in operator would be more suitable). An example could be a booking system for conferences where you may want to check if there is some capacity available for a workshop. This could be a method in the Workshop class, but may not be the best option if the check requires some external system to be requested. Having a has operator would allow to write something like this:
{% if workshop has available_capacity(2) %}
requested seats are available
{% endif %}
Where available_capacity is a usual Twig test like this (whatever the $capacityChecker might be):
new TwigTest('available_capacity', function($numberOfRequestedSeats) use ($capacityChecker) {
return $capacityChecker->remainingCapacity() >= $numberOfRequestedSeats;
});
@mindfullsilence Does this example make it more clear to you?
Closing as the discussion went nowhere.
Most helpful comment
I'm against this change because in my mind
hashas a different meaning.hasoften relates to an inclusion check for collections. Using it as a substitute ofismay confuse beginners.