Hi!
I tried to do this with trait, but it looks very bad, so i decide to try request simple feature.
Idea of feature is to cast value from database to object after finding and do reverse when inserting.
Example:
I have column in DB status. This integer enum column (0,1,2).
Right now it returns 0,1,2 as value and i cast it to StatusEnum object thru StatusEnum::getByValue(int).
What if create method getAttributeCasting with return of array with name of attribute as key and class name as value and after each data selecting automatically cast this value to object?
This will not brake any backward compatibility.
I like the idea of fine grained type casting.
How do you want config for it to look like?
Isn't this rather about types? How about getAttributeTypes()? Would it make sense to allow for all kinds of casting, like:
public function getAttributeTypes()
{
return [
'age' => 'integer', // you know that this never exceeds int limit
'status' => [
'class' => 'Enum', // we could even have a generic enum class
'values' => [
0 => 'closed',
1 => 'pending',
2 => 'new',
],
],
'foo' => [
'class' => 'MyFooType',
'bar' => 'baz',
],
],
];
}
We could have an interface for those DB cast classes.
@mikehaertl yes, it's about types. Having generic Enum interface is OK. Probably abstract class as well.
It may complicate validation though. At least it's less clear what's going on. Like: Is it first casted back to DB type then validated? Or should it be validated before?
Should be validated before, I think.
@samdark for enum we can use https://github.com/Skinka/type-enum
@mikehaertl validation always before inserting. We validate object and cast it back vis getValue just for inserting query.
I wonder a bit, how this would be used in practice. E.g. how would assignments work? Or would they work at all?
// Say, status = 1 in DB
$model = Demo::findOne($id);
// What should this output? 1 or status label ?
echo $model->status;
// Should this work?
$model->status = 0;
@mikehaertl
// Say, status = 1 in DB
$model = Demo::findOne($id);
echo $model->status; // Status object with value = 1
$model->status = 0; // Well, this is subject to voting.
I consider this is a duplication of #9656
@klimov-paul this feature have some connection to #9656, but its little bit different and can be realized w/o #9656
If I tried to achieve your goal I would follow #9656 approach.
You are talking of the interference into the ActiveRecord schema. Which, by the way, is already possible via ColumnSchema::typecast().
Following your path, which should abandon automatic schema detection and let developer to specify it manually including type-casting.
I can see absolutely no problem in actual implementation of this issue or #9656. It is already possible via virtual ActiveRecord properties. All you need is using different names for virtual attributes:
class MyAr extends \yii\db\ActiveRecord
{
public function getStatusObject()
{
return new Status($this->status);
}
}
You alreay have all necessary tools for your goal.
Sorry, i will answer in russian, Much faster.
@klimov-paul ΠΈΠ΄Π΅Ρ Π² ΡΠΏΡΠΎΡΠ΅Π½ΠΈΠΈ ΠΏΡΠΎΡΠ΅Π΄ΡΡΡ ΠΊΠ°ΡΡΠΈΠ½Π³Π°. ΠΠ°, ΠΌΠΎΠΆΠ½ΠΎ ΡΠΎΠ·Π΄Π°ΡΡ ΠΊΡΡΡ Π³Π΅ΡΡΠ΅ΡΠΎΠ² ΠΈ ΠΎΡ Π½ΠΈΡ
ΠΎΡΡΠ°Π»ΠΊΠΈΠ²Π°ΡΡΡΡ, Π½ΠΎ ΡΡΠΎ ΠΌΡΠ³ΠΊΠΎ Π³ΠΎΠ²ΠΎΡΡ Π½Π΅ΡΠ΄ΠΎΠ±Π½ΠΎ.
ΠΠ΅ Π½Π°Π΄ΠΎ ΠΎΡΠΊΠ°Π·ΡΠ²Π°ΡΡΡΡ ΠΎΡ Π°Π²ΡΠΎΠΌΠ°ΡΠΈΡΠ΅ΡΠΊΠΎΠΉ Π΄Π΅ΡΠ΅ΠΊΡΠΈΠΈ Π² ΡΠ΅Π»ΠΎΠΌ. Π’ΠΎΠ»ΡΠΊΠΎ Π΄Π»Ρ ΠΏΠΎΠ»Π΅ΠΉ ΡΠΊΠ°Π·Π°Π½Π½ΡΡ
ΠΊΠ°ΠΊ ΠΊΠ°ΡΡΠΈΡΡΠ΅ΠΌΡΠ΅. Π’Π°ΠΊΠ°Ρ ΡΡΡΠΊΠ° Π΅ΡΡΡ Π² Java ORM ΠΏΠΎΠ΄ Π½Π°Π·Π²Π°Π½ΠΈΠ΅ΠΌ Ebean ΠΈ ΠΏΠΎΠΊΠ°Π·ΡΠ²Π°Π΅Ρ ΡΠ΅Π±Ρ ΠΎΡΠ΅Π½Ρ Π΄Π°ΠΆΠ΅ Π½Π΅ ΠΏΠ»ΠΎΡ
ΠΎ.
ΠΡ Π²ΡΠ΅ΡΠ°ΠΊΠΈ Π΄Π΅Π»Π°Π΅ΠΌ ΠΠ ΡΡΠ΅ΠΉΠΌΠ²ΠΎΡΠΊ ΠΈ ΡΠ°ΠΊΠΈΠ΅ ΠΏΠ»ΡΡΠΊΠΈ ΠΊΠ°ΠΊ ΠΊΠ°ΡΡΠΈΠ½Π³ Π½Π΅ ΠΌΠ΅ΡΠ°ΡΡ.
Sorry, i will answer in russian, Much faster.
:-1: Maybe faster - but locking out the rest of us.
Translation:
The idea is to simplify type-casting procedure. Of course you can create multiple getters and use them but it's not really convenient. We should not drop automated casting and instead add an ability to customize casting for specific fields. Alike feature is supported in Java ORM called Ebean and I can say it's good. We're creating object-oriented framework and such feature is very handy.
Overall I agree that using setters isn't really convenient since you have to name these differently from the fields which leads to weird naming often.
ΠΠ·Π²ΠΈΠ½ΠΈΡΠ΅ Π·Π° ΡΡΠ°Π½ΡΡΠ·ΡΠΊΠΈΠΉ, Π½ΠΎ ΠΏΠΎΡΠ΅ΠΌΡ Π±Ρ Π½Π΅ ΡΠ΄Π΅Π»Π°ΡΡ ΠΌΠ΅ΡΠΎΠ΄ ΠΏΠΎΠ΄ΠΎΠ±Π½ΡΠΉ ΡΡΠΎΠΌΡ http://www.yiiframework.com/doc-2.0/yii-db-baseactiverecord.html#fields()-detail ΠΊΠΎΡΠΎΡΡΠΉ Π±ΡΠ΄Π΅Ρ ΠΎΠΏΠΈΡΡΠ²Π°ΡΡ Π°Π½ΠΎΠ½ΠΈΠΌΠΊΠ°ΠΌΠΈ Π³Π΅ΡΠ΅Ρ ΠΈ ΡΠ΅ΡΠ΅Ρ Π΄Π»Ρ ΠΏΠΎΠ»Π΅ΠΉ. Π’.Π΅. ΠΏΡΠΈ ΠΎΠ±ΡΠ°ΡΠ΅Π½ΠΈΠΈ ΠΊ ΠΏΠΎΠ»Ρ ΠΊΠΎΡΠΎΡΠΎΠ΅ Π΅ΡΡΡ Π² Π±Π°Π·Π΅ ΠΠ Π±ΡΠ΄Π΅Ρ Π΅Π³ΠΎ ΠΎΠ±ΡΠ°Π±Π°ΡΡΠ²Π°ΡΡ ΡΡΠ»ΠΎΠ²ΠΈΡΠΌΠΈ ΠΈΠ· ΡΡΠΎΠ³ΠΎ ΠΌΠ΅ΡΠΎΠ΄Π°.
ΠΠ°ΠΊ ΠΏΠΎ ΠΌΠ½Π΅, ΡΠ°ΠΊΠΎΠ³ΠΎ ΠΌΠ΅ΡΠΎΠ΄Π° ΠΎΡΠ΅Π½Ρ Π½Π΅ Ρ
Π²Π°ΡΠ°Π΅Ρ. Π₯ΠΎΡΡ Π±Ρ Π΄Π»Ρ ΠΎΠΏΠΈΡΠ°Π½ΠΈΡ ΡΠ΅Ρ
ΠΆΠ΅ enum ΠΏΠΎΠ»Π΅ΠΉ.
ΠΠ·Π²ΠΈΠ½ΠΈΡΠ΅ Π·Π° ΡΡΠ°Π½ΡΡΠ·ΡΠΊΠΈΠΉ
6 ΡΠ΅Π»ΠΎΠ²Π΅ΠΊ ΠΏΡΠΎΡΠΈΠ². ΠΠ°Π²Π°ΠΉΡΠ΅ ΡΠΆΠ΅ Π½Π° Π°Π½Π³Π»ΠΈΠΉΡΠΊΠΎΠΌ.
Translation again:
Why can't we introduce a method like http://www.yiiframework.com/doc-2.0/yii-db-baseactiverecord.html#fields()-detail which will describe setter and getter for a field via anonymous function i.e. when field is accessed and it's in the DB it will be processed using config defined. I'd love to have such method. At least for enums.
Why can't we introduce a method like http://www.yiiframework.com/doc-2.0/yii-db-baseactiverecord.html#fields()-detail which will describe setter and getter for a field via anonymous function i.e.
Relates to #8316.
There too much possible use cases around ActiveRecord attributes. If we start from this one - where it will end?
If you dislike manual setter/getter so much you can compose your solution into a behavior.
I don't think Yii should provide anything in this field by default. It is better to be implemented as separated extension.
Yeah, it could easily go wrong so while I don't agree that it should not be in the core framework, we should be really careful with it.
Questions open are:
@klimov-paul
Oh well. but why not give the developer the ability to create a getter for example with the name of the field from the base. it will be on his conscience! for example: field in the database 'status' getter it is possible to make getStatus () instead getStatusTekst ()
but why not give the developer the ability to create a getter for example with the name of the field from the base
https://github.com/yiisoft/yii2/issues/9656#issuecomment-139241911
https://github.com/yiisoft/yii2/issues/2262#issuecomment-33880219
yii\behaviors\AttributeTypecastBehavior introduced at #12067 can be used as a solution.
See also https://github.com/yii2tech/filedb
Most helpful comment
:-1: Maybe faster - but locking out the rest of us.