After some thinking and a bit of digging I found the following:
When we try to access the attribute, the __get($key)
method on our Illuminate\Database\Eloquent\Model
is called. This in turn calls the getAttribute($key)
method, which does the following:
public function getAttribute($key)
{
if (array_key_exists($key, $this->attributes) || $this->hasGetMutator($key)) {
return $this->getAttributeValue($key);
}
return $this->getRelationValue($key);
}
So in essence, what it does is it checks if our model either has the attribute set, in which case the model is hydrated, or if we have defined a mutator. Laravel assumes that we do not use mutators on our relation fields. Since I had defined a mutator to map my value to the namespaced class, it attempted to return $this->getRelationValue($key)
. But since I actually hadn't yet loaded the relationship, and the model hence was not hydrated, I got null.
Having attempted to fix this with
public function getSourceTypeAttribute($type)
{
// transform to lower case
$type = $this->getRelationValue('source_type');
$type = strtolower($type);
// to make sure this returns value from the array
return array_get($this->types, $type, $type);
// which is always safe, because new 'class'
// will work just the same as new 'Class'
}
I can also state that it does not yet work, but I'm one step closer.
Currently, there is a buildDictionary(Collection $models)
in Illuminate\Database\Eloquent\Relations\MorphTo
defined as
protected function buildDictionary(Collection $models)
{
foreach ($models as $model) {
if ($model->{$this->morphType}) {
$this->dictionary[$model->{$this->morphType}][$model->{$this->foreignKey}][] = $model;
}
}
}
In essence, what this does is take our model(s), and check if they have the attribute of $this->morphType
, and $this->morphType
is set in the constructor and is by default the caller method's name (in my case source
), appended with _type
. So, for me, it's source_type
. It will then check for $model->source_type
, so for me, that'd be $orderItem->source_type. It then takes this and adds to its dictionary, which results in an array like the one beneath, with the following values for demonstration purposes:
$this->morphType = 'source_type'
$model->{$this->morphType} = 'product'
$this->foreign_key = 'source_id'
$model->{$this->foreign_key} = 1
$model = OrderItem::find(1)
[
'product' => [
1 => [
OrderItem {attributes}
]
]
]
I'll probably fork the laravel core and add the functionality of custom mapping of type and class to resolve my issue.
Sign in to participate in this thread!
The Laravel portal for problem solving, knowledge sharing and community building.
The community