Reputation: 3036
I am using Yii2 and I have the virtual attribute notes2
(that is used by the GUI functions instead of database attribute notes):
class Order extends \yii\db\ActiveRecord
{
public function getnotes2() {
return iconv('UTF-16LE', 'UTF-8', $this->notes);
}
public function setnotes2($value) {
$this->notes = iconv('UTF-8', 'UTF-16LE', $value);
}
}
In this case both the following codes $order->notes2
and $order->Notes2
calls the setter and returns the right value.
But I have to use $order->getAttributes()
function and default implementation of it does not include the virtual attributes. So I tried to override this function with:
public function attributes() {
$attributes = parent::attributes();
$attributes['notes2'] = 'notes2';
return $attributes;
}
And now json_encode($order->getAttributes())
includes empty notes2
field, but $order->notes2
(obviously - this causes the notes2
field to become empty) has no value, but $order->Notes2
has value!
Why such flip-flop of the register of the first character happens? How to declare correctly the virtual field that is available in getAttributes()
as well?
But the following code (instead of override of attributes()
)
public function getAttributes($names = null, $except = []) {
return array_merge(['notes2'], parent::getAttributes($names, $except));
}
behaves as nothing has been overrides - both $order->notes2
and $order->Notes2
are calculated and there is no notes2
(or Notes2
) inside the json_encode($order->getAttributes())
Upvotes: 1
Views: 682
Reputation: 22144
This case sensitivity problem is related to PHP limitation/feature - method names are case insensitive so virtual attributes provided by methods are also case insensitive - there is not difference if you define/call it as getnotes2()
or getNotes2()
, so there is no way to distinguish between $order->notes2
and $order->Notes2
.
This works differently for regular attributes (and properties) which does not use methods and they're not affected this case-insensitivity limitation. You didn't explain what you want to achieve, but regular attributes (defined by attributes()
) and virtual attributes (provided by getters and setters) are two separate things and you can't mix them up - if you define attribute in attributes()
it will be stored in internal array and getter/setter will be ignored (since regular attributes has precedence over virtual attributes).
In your case you defined the same attribute twice: once as regular attribute (in attributes()
) and second as virtual attribute (with getter and setter). If you use this attribute with correct case ($order->notes2
), regular attribute will be used. If case is incorrect ($order->Notes2
) regular attribute will not be used (since it is case sensitive and there is no Notes2
attribute) and virtual attribute will be used (since it will ignore case) as a fallback.
If the only thing you want to do is include notes2
in getAttributes()
try to override getAttributes()
in this way and do not touch attributes()
at all:
public function getAttributes($names = null, $except = []) {
return array_merge(
['notes2' => $this->getNotes2()],
parent::getAttributes($names, $except)
);
}
Not that this will ignore $names
and $except
arguments and always return notes2
attribute.
Upvotes: 1