Twig calls Model's relation method when it wants its property
rudiedirkx opened this issue · 4 comments
TwigBridge 0.11.2 with Twig 2.12.2.
Twig has changed its twig_get_attribute()
. (I came from Twig 1.42.2) If a relationship returns NULL, Twig tries to call its method and gets the Relationship
object.
In twig:
{% if g_organization.is(g_user.organization) %}
The problem is the g_user.organization
accessor (by twig_get_attribute()
). It should pass this check:
// object property
if (isset($object->$item) || \array_key_exists((string) $item, (array) $object)) {
because it's a magic property, but it doesn't, because the result is null, so not isset()
. A few lines later, there's a
// object method
which it passes, because there's a method 'organization()', but it returns a BelongsTo
relationship, not an Organization
model.
Twig tries the property, (Laravel resolves the relationship: null), Twig tries the method, Laravel returns the BelongsTo
object.
In my case that crashes in Model::is()
, because that expects a Model
argument, not a relationship, but the real problem happens before, with Twig accessing Laravel properties. Laravel is too much magic for Twig =(
I wouldn't know how to fix decently. The property exists, but is not isset()
. Is the miscommunication Laravel's fault or Twig's? I fixed it for now by overriding __isset()
in my app's custom Model
:
public function __isset($key) {
$this->getAttribute($key);
return array_key_exists($key, $this->toArray());
}
If the attribute exists, even if it's NULL, isset()
is now true. Not great...
Ehm. Yea. That works. Everyone knew this issue? So my whole essay was unnecessary? =(
But upgrading rcrowe/twigbridge
doesn't upgrade the config file, so how does anyone find out? Should I compare Laravel config files after a package upgrade?
Yeah I don't know what exactly changed, but it was submitted as a fix so I'm not 100% about any side-effects. But it does seems to be necessary for new Laravel version, so I think we might need to just always add it in the core.
I agree. Twig counts on Symfony style entities and accessors. For Laravel, this custom getter is the way to go. No need to 'break' my Model::__isset()
. Very cool. I didn't even know this was a Twig thing.
I'm not sure about efficiency though. Compiled twig templates call lots of GetAttrNode::attribute()
now, which loads class GetAttrExpression
and more of the compiler. Runtime doesn't need all that compiler code. Maybe the attribute override function should be a separate function, not a static method in the compiler. Might be 1% more efficient.