I am trying to access an Eloquent attribute with Twig in Slim, and getting an error.
I have a Field and a Type object, and the relationship is as follows
class Field extends \Illuminate\Database\Eloquent\Model {
protected $table = 'fields';
public function type()
{
return $this->belongsTo('models\Type');
}
When doing {{ f }}
(being f a field), the output is this:
{"field_id":"1","field_name":"Your name","form_id":"2","type_id":"1","placeholder":"Please give us your name"}
And when doing {{ f.type }}
, the result is:
Message: An exception has been thrown during the rendering of a template ("Object of class Illuminate\Database\Eloquent\Relations\BelongsTo could not be converted to string") in "pages/editform.html" at line 97.
If I try to do {{ f.type.name }}
, doesn't throw up an exception but doesn't print anything either.
If I do it in PHP
$fields = $form->fields;
var_dump($fields[0]->type->name);
The value gets output correctly.
Any ideas?, Thanks
If you don't want to do an eager load, you can override the magic __isset
method in your Field
class to return true
for the type
relationship property:
public function __isset($name)
{
if (in_array($name, [
'type'
])) {
return true;
} else {
return parent::__isset($name);
}
}
Explanation
The problem is in the interaction between how Eloquent implements the "dynamic property" for a relation (in your case, f.type
), and the rules that Twig uses for accessing "attributes" of a variable.
From the Twig documentation:
For convenience's sake
foo.bar
does the following things on the PHP layer:
- check if
foo
is an array andbar
a valid element;- if not, and if
foo
is an object, check thatbar
is a valid property;- if not, and if
foo
is an object, check thatbar
is a valid method (even ifbar
is the constructor - use__construct()
instead);- if not, and if
foo
is an object, check thatgetBar
is a valid method;- if not, and if
foo
is an object, check thatisBar
is a valid method;- if not, return a null value.
foo['bar']
on the other hand only works with PHP arrays:
- check if
foo
is an array andbar
a valid element;- if not, return a null value.
The key here is the part where it says "check that bar is a valid property". This means that on the level of PHP, Twig is calling isset
on $f->type
. Eloquent implements the magic __isset
method in Model
, so you might think that this wouldn't be a problem.
However, take a look at how it actually implements __isset
for model relations:
/**
* Determine if an attribute exists on the model.
*
* @param string $key
* @return bool
*/
public function __isset($key)
{
return (isset($this->attributes[$key]) || isset($this->relations[$key])) ||
($this->hasGetMutator($key) && ! is_null($this->getAttributeValue($key)));
}
It determines whether a relation is "set" by looking in its array of loaded relationships (isset($this->relations[$key])
). The problem is that if type
hasn't been loaded yet, Eloquent will say that it is not "set".
Thus when Twig looks at $f->type
, it will think that type
is not a valid property, and move on to the next rule:
...if
foo
is an object, check thatbar
is a valid method
So now it will look for the method type()
, which it finds. The only problem? type()
(the method) returns a Relation
(specifically, a BelongsTo
), rather than a Type
object. And BelongsTo
objects aren't models.
If you want Twig to know that the property $f->type
does indeed exist, you have two choices:
Type
object along with your Field
, as suggested by @roger-collins, or;__isset
magic method in Field
:
public function __isset($name)
{
if (in_array($name, [
'type'
])) {
return true;
} else {
return parent::__isset($name);
}
}
This will force Twig to recognize that type
is a valid property for Field
, even before the related model has actually been loaded.
I had the same issue and stumbled upon this question. After solving it myself, I thought I'd try to help you out.
Try doing a Eager Load on the model:
Field::with('type')->get()
This should allow you to do the following with no other issues.
{{ f.type }}
See more info here: http://laravel.com/docs/4.2/eloquent#eager-loading
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With