-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make "length" filter and "empty" test consider __toString [Twig 1.x] #2420
Conversation
LGTM. Can you add some tests and a note in the CHANGELOG file? |
@fabpot done. Hope the tests look like what you expected, otherwise please guide me. Failing tests on PHP 7 only, seems unrelated. |
lib/Twig/Extension/Core.php
Outdated
return mb_strlen($thing, $env->getCharset()); | ||
} | ||
|
||
if (is_object($thing) && !$thing instanceof \Countable && is_callable(array($thing, '__toString'))) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would use method_exists()
here instead as __toString()
must be public and we don't want to return true
is a class implements __call()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
which means that another test with a class having __call()
but no __toString()
should be added as well.
doc/filters/length.rst
Outdated
If ``Countable`` is implemented as well, the return value of the ``count()`` method | ||
takes precedence. | ||
|
||
.. versionadded:: 1.33 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@fabpot Do you have tooling/policy/processes in place to make this read 2.3 when merged into the 2.x branch?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will do that manually I think
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This block should be moved to the top.
@fabpot Do you think this could make it into the next Twig release? |
Can you rebase to get rid of the merge commit? I will then review it and make any additional comment before merge and release. Thanks. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor comments, ready to be merged after fixes. Thanks.
CHANGELOG
Outdated
* 1.33.0 (2017-XX-XX) | ||
|
||
* "length" filter now returns string length when applied to an object that does not implement \Countable but provides __toString() | ||
* "empty" test will now consider the return value of the __toString() method for objects implementing __toString() but not \Countable |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you wrap each line like done for other items?
doc/filters/length.rst
Outdated
If ``Countable`` is implemented as well, the return value of the ``count()`` method | ||
takes precedence. | ||
|
||
.. versionadded:: 1.33 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will do that manually I think
doc/filters/length.rst
Outdated
length of the string being returned. | ||
|
||
If ``Countable`` is implemented as well, the return value of the ``count()`` method | ||
takes precedence. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find this confusing. I prefer the way you documented the other one. Can you change it to read the same as the other one?
doc/tests/empty.rst
Outdated
|
||
.. versionadded:: 1.33 | ||
|
||
Support for the ``__toString()`` magic method has been added in Twig 1.33. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This block should be moved to the top.
doc/filters/length.rst
Outdated
If ``Countable`` is implemented as well, the return value of the ``count()`` method | ||
takes precedence. | ||
|
||
.. versionadded:: 1.33 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This block should be moved to the top.
…t are not \Countable Use case: When you have variables in your views that are actually objects but implement `__toString`, they feel like strings: For example, `{{ something }}` will make use of that to-string-conversion. What does *not* work is `{{ something | length }}`, because that will only have a meaningful return value for objects implementing `\Countable`. This interface, however, may have a totally different semantic/purpose for the object in question. For template designers, this may be surprising if they don't actually care about the object-or-string difference, they just "use" the variable. This change tries to address this as it changes the behavior for such objects that have a `__toString` method and are *not* `\Countable`. *Yes*, it's a BC break in an edge case: Objects that implement a `__toString` but not `\Countable` would previously yield `1` for `{{ object | length }}`, and now would return the length of the string returned by `__toString`.
Both instanceof and method_exists() seem to handle non-object value just fine
60c21a8
to
9dbed98
Compare
@fabpot rebased, docs fixed as you suggested |
Thank you @mpdude. |
…ng [Twig 1.x] (mpdude) This PR was squashed before being merged into the 1.x branch (closes #2420). Discussion ---------- Make "length" filter and "empty" test consider __toString [Twig 1.x] Use case: When you have variables in your views that are actually objects but implement `__toString`, they feel like strings: For example, `{{ something }}` will make use of that to-string-conversion. What does *not* work is **a)** `{{ something | length }}`, because that will only have a meaningful return value for objects implementing `\Countable`. This interface, however, may have a totally different semantic/purpose for the object in question. **b)** `{% if something is empty %}`, because > empty checks if a variable is an empty string, an empty array, an empty hash, exactly false, or exactly null `[http://twig.sensiolabs.org/doc/2.x/tests/empty.html]` ... and obviously `something !== null` in this case. For template designers, this may be surprising if they don't actually care about the object-or-string difference, they just "use" the variable. This change tries to address this as it changes the behavior for such objects that have a `__toString` method and are *not* `\Countable`. *Yes*, it's a BC break in edge cases: For a), objects that implement a `__toString` but not `\Countable` would previously yield `1` for `{{ object | length }}`, and now would return the length of the string returned by `__toString`. For b), testing (defined) variables that are objects implementing `__toString` and that return `''`, the test now is `false`. Commits ------- f5193e9 Make "length" filter and "empty" test consider __toString [Twig 1.x]
Not sure if it is BC or we are misusing toString method, but after updating to twig 2.3.0 our application crashed on this code. let's say you have an entity with a __toString method that not always returns a string. When you do something like: Is this related to this PR? @fabpot @mpdude . If we downgrade to 2.2.0 it works.
Thanks for your time. |
The |
In PHP? |
@mpdude |
My question is, should I mean, if the object is not null, it is not empty, no need to check more things. That's why I asked, I wasn't sure if I am missing something there. |
What is your code supposed to do? If |
If |
I can make a PR to make the But consider I don't see how this could work "both" ways. |
We used |
Use case: When you have variables in your views that are actually objects but implement
__toString
, they feel like strings: For example,{{ something }}
will make use of that to-string-conversion.What does not work is
a)
{{ something | length }}
, because that will only have a meaningful return value for objects implementing\Countable
. This interface, however, may have a totally different semantic/purpose for the object in question.b)
{% if something is empty %}
, because... and obviously
something !== null
in this case.For template designers, this may be surprising if they don't actually care about the object-or-string difference, they just "use" the variable.
This change tries to address this as it changes the behavior for such objects that have a
__toString
method and are not\Countable
.Yes, it's a BC break in edge cases:
For a), objects that implement a
__toString
but not\Countable
would previously yield1
for{{ object | length }}
, and now would return the length of the string returned by__toString
.For b), testing (defined) variables that are objects implementing
__toString
and that return''
, the test now isfalse
.