laravel / ideas

Issues board used for Laravel internals discussions.
938 stars 28 forks source link

Improve Typecasting #9

Closed AdenFraser closed 6 years ago

AdenFraser commented 8 years ago

This has been discussed before in different issues raised laravel/framework.

I think it would be rather handy if Eloquent's typecasting was extendable, so that as well as being able to automatically cast to the existing: integer, real, float, double, string, boolean, object, array, collection, date and datetime That we could also cast to custom cast types.

For instance when using value objects this would allow the automatic casting of a dec to a Money type object.

Thoughts?

tomschlick commented 8 years ago

Using toString() also removes your ability to debug if there are errors. Instead of the normal stack trace, you'll get "toString() must not throw an exception" and it mutes the actual exception from the error.

barryvdh commented 8 years ago

The money object could be a formatted amount as strong, but perhaps you would want to store the integer value in the database. Or you could store an uuid as 16 bytes, but still want the 36 string version displayed as string in the front end.

What this could also achieve perhaps, is using the casts for the where* clause. En ->where('amount', $moneyObject), same as the datetime conversions.

And yes, custom casts would be very similar to mutators, only easier to reuse.

sebastiandedeyne commented 7 years ago

What if we'd have the caster mutate the model instead of returning a serialized value? Another example implementation, similar to @barryvdh's:

class MyModel extends Model
{
    protected $casts = [
        'price' => 'money',
    ];
}
class CastsMoney
{
    public function get(Model $model)
    {
        return new Money($model->price_amount, $model->price_currency);
    }

    public function set(Model $model, Money $value)
    {
        $model->price_amount = $value->getAmount();
        $model->price_currency = $value->getCurrency();
    }
}

Casts::extend('price', CastsMoney::class);

Advanced: You could pass values as parameters, for example the field names, or a hard coded currency like in the previous example.

class MyModel extends Model
{
    protected $casts = [
        'total' => 'money:total_amount,total_currency',
        'shipping_costs' => 'money:shipping_costs_amount,shipping_costs_currency',
    ];
}
class CastsMoney
{
    public function get(Model $model, $amountField, $currencyField)
    {
        return new Money($model->$amountField, $model->$currencyField);
    }

    public function set(Model $model, Money $value, $amountField, $currencyField)
    {
        $model->$amountField = $value->getAmount();
        $model->$currencyField = $value->getCurrency();
    }
}

Casts::extend('price', CastsMoney::class);

I think this would cover everything we want:

tomschlick commented 7 years ago

FYI, a new PR has been opened by @tillkruss to further the work that was started on this.

https://github.com/laravel/framework/pull/18106

For now discussion it is locked as it is a work in progress.

tillkruss commented 7 years ago

That was actually a typo, hence the [WIP] in the title. I fixed it earlier today.

$user->token = 'larav3l-secr3t'; // does not work
$user->save();
robclancy commented 7 years ago

Why is it locked?

On Sun, 26 Feb 2017, 02:44 Till Krüss notifications@github.com wrote:

That was actually a typo. I fixed it earlier today.

$user->token = 'larav3l-secr3t'; // does not work$user->save();

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/laravel/internals/issues/9#issuecomment-282495743, or mute the thread https://github.com/notifications/unsubscribe-auth/AA0UF6oGUaBwLgBW07q_p-viPbLcmp9rks5rgFpogaJpZM4Hwgiw .

tillkruss commented 7 years ago

Because I don't want people to comment, yet. If you have valuable feedback, ping me in Slack.

robclancy commented 7 years ago

What a bizzare thing to do. Just don't PR until ready...

On Sun, 26 Feb 2017, 02:47 Till Krüss notifications@github.com wrote:

Because I don't want people to comment, yet. If you have valuable feedback, ping me in Slack.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/laravel/internals/issues/9#issuecomment-282495965, or mute the thread https://github.com/notifications/unsubscribe-auth/AA0UFyBtqnOluRkwBPU8Cdcy5nKqb9jVks5rgFsrgaJpZM4Hwgiw .

tillkruss commented 7 years ago

Valueless, off-topic, thread-hijacking comments like that. That why it's locked.

robclancy commented 7 years ago

Wow I see now. Because you're a disrespectful little snowflake.

On Sun, 26 Feb 2017, 03:29 Till Krüss notifications@github.com wrote:

Valueless, off-topic comments like that. That why it's locked.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/laravel/internals/issues/9#issuecomment-282498648, or mute the thread https://github.com/notifications/unsubscribe-auth/AA0UF0gCSZKB74uKD86eBioIezi3cIPTks5rgGTpgaJpZM4Hwgiw .

franzliedke commented 7 years ago

Ignoring Robbo's comments for a while, I too agree that it would be helpful to allow feedback directly on the PR, especially since it is work in progress. ;)

robclancy commented 7 years ago

That's actually agreeing with my comments. It's the entire point of a pull request. Locking it is just disrespectful to anyone following this feature request. It is saying to every one of them that they aren't good enough to comment on the super amazing PR.

Regardless they will just discuss here anyway. So not only is the reason for the lock stupid but it is ineffective.

On Sun, 26 Feb 2017, 04:09 Franz Liedke notifications@github.com wrote:

Ignoring Robbo's comments for a while, I too agree that it would be helpful to allow feedback directly on the PR, especially since it is work in progress. ;)

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/laravel/internals/issues/9#issuecomment-282501494, or mute the thread https://github.com/notifications/unsubscribe-auth/AA0UF-yihFvHihrdcUCDacZW4DvPkUgpks5rgG5pgaJpZM4Hwgiw .

franzliedke commented 7 years ago

Well, I don't agree with your tone.

robclancy commented 7 years ago

Yeah because his tone was so welcoming. He was hostile first and the reason for "valueless" discourse in the first place. Ironic really.

sisve commented 7 years ago

The current implementation in https://github.com/laravel/framework/pull/18106 has a large flaw; it requires ownership of the objects you cast to. That is often not the case; an example are people using https://github.com/nicolopignatelli/valueobjects which would require an intermediate casting layer. Something like a TokenConverter that has a convertToPHPValue($value) and convertToDatabaseValue($value)

sisve commented 7 years ago

Can someone explain why this issue is so secretive that I need to talk to @tillkruss in a hidden thread in #internals on Slack instead of commenting in the PR?

Additional things I've told @tillkruss in previously mentioned secretive thread;

  1. The intermediate casting object (hereby known as ConverterThingie) should have an interface, and all methods should be instance methods.
  2. The ConverterThingie should be instantiated using the container so it can have dependencies.
  3. The current implementation will not ask the ConverterThingie about null values. This sounds wrong, the ConverterThingie's sole purpose in life is to convert things, it should be asked how to convert null values.
barryvdh commented 7 years ago

I don't get it either. If you're not sure about the architecture, discuss that privately before creating a PR. If you're not ready for feedback, work on it locally before creating a PR.

If you do create a PR, accept feedback on it. These discussions are very valuable to read back later, to understand why something is done this way. Redirecting to Slack just means it's lost after a few days.

I really hope this isn't a trend.. IMHO locking should be reserved for out of control threads with just spam, not reasonable discussions..

lagbox commented 7 years ago

Can we please stop this secretive nonsense. The point of this repository is so that [expletive deleted] isn't just on slack which disappears. This creates paper trails so other people can actually see the conversations and IDK maybe not waste their [expletive deleted] time on things that have already been discussed that they couldn't possibly [expletive deleted] know because they weren't on slack. There has to be somewhere this information lives that is accessible. How many times does this obvious issue have to be pointed out?

@barryvdh agreed pre-emptive heavy-handed moderating is not good

tillkruss commented 7 years ago

Unlocked the thread and closed the PR. Will open new PR when it's ready.

sisve commented 7 years ago

For those that missed it; a new PR was opened.

Every single point I made was ignored.

  1. There is no "casting object" that can declare constructor dependencies needed for conversion.
  2. No interfaces for this new functionality to conform to, instead it's specially named methods that need to implemented in every model.
  3. Null values are still ignored by the casting layer.

A quick reminder from that hidden-in-history Slack thread.

image

Did any of that happen?

sisve commented 7 years ago

It's way early in the morning and I misread the PR. It's not yet merged, and I updated my previous comment to remove that part.

I know I am bitter and filled of hatred, but could there at least be some notes about the different suggested implementations that show why those were declined? It's almost a year since the most thumbed-up (which I think means some kind of approval) comment suggested a way to do this, why wasn't that implemented? https://github.com/laravel/internals/issues/9#issuecomment-196547408

robclancy commented 7 years ago

I mean... his first PR showed he doesn't care what other people think. Instead of closing he will just ignore everyone because he is better than them (unless one of the Laravel "inner circle twitter gods").