Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Converting types #1096

Open
Zebradil opened this issue Nov 14, 2021 · 12 comments
Open

Converting types #1096

Zebradil opened this issue Nov 14, 2021 · 12 comments
Labels

Comments

@Zebradil
Copy link

I'm struggling to find a way to generate a date using dateTimeBetween and convert it to DateTimeImmutable.

Example configuration:

App\Entity\Activity:
    activity_{1..50}:
        createdAt: '<dateTimeBetween("-200 days", "now")>'

Using it leads to doctrine error:

Could not convert PHP value of type DateTime to type datetime_immutable. Expected one of the following types: null, DateTimeImmutable

I tried to use the following, bit it also didn't work:

App\Entity\Activity:
    activity_{1..50}:
        createdAt: '<(\DateTimeImmutable::createFromMutable(dateTimeBetween("-200 days", "now")))>'

Throws Call to undefined function dateTimeBetween() error.

How can I convert DateTime to DateTimeImmutable?

@theofidry
Copy link
Member

I think it should be:

'<(\DateTimeImmutable::createFromMutable(<dateTimeBetween("-200 days", "now")>))>'

But maybe you could make it both more reliable and elegant by registering a custom faker provider

@curry684
Copy link
Contributor

I'm running into the same issue with Doctrine being strict about this. However what surprises me is that the fixture dates are not generated as DateTimeImmutable to begin with? I would expect Doctrine to accept an immutable as a mutable, and reject it the other way around.

@curry684
Copy link
Contributor

Your suggestion doesn't work btw @theofidry:

Could not evaluate the expression "\DateTimeImmutable::createFromMutable(<dateTimeBetween("-200 days", "now")>)": syntax error, unexpected token "<"

I don't think it can be fixed right now.

@theofidry
Copy link
Member

I think your best shot then is register your own faker provider, either a new one or override the faker built-in one

@NicolasGuilloux
Copy link

NicolasGuilloux commented Jun 15, 2022

For Symfony, this leads to create this kind of service and adapt every function to support DateTimeImmutable. This should be a little harder since the DateTime provider check the instance of the input object against \DateTime rather than \DateTimeInterface.

<?php declare(strict_types=1);

namespace App\Tests\Resources\Services\Faker;

use Faker\Provider\DateTime;

final class DateTimeImmutableProvider extends DateTime
{
    public static function dateTimeImmutableBetween($startDate = '-30 years', $endDate = 'now', $timezone = null): \DateTimeImmutable
    {
        $startTimestamp = $startDate instanceof \DateTimeInterface ? $startDate->getTimestamp() : $startDate;
        $dateTime = parent::dateTimeBetween($startTimestamp, $endDate, $timezone);

        return \DateTimeImmutable::createFromMutable($dateTime);
    }
}

@theofidry
Copy link
Member

@NicolasGuilloux this could also be made easier by contributing to Faker in order to provide DateTimeImmutable objects instead of DateTime.

@theofidry theofidry added the Bug label Jul 1, 2022
@haxus01
Copy link

haxus01 commented Aug 4, 2022

Actually <(new DateTimeImmutable('now'))> works for me under "hautelook/alice-bundle": "^2.11", and Symfony 6.1.3

@damienfa
Copy link

Also, the Symfony console make:entity command will generate Entity where dates are DateTimeImmutable. It makes impossible to use Alice dateTimeBetween on that type of fields… 😕
Why don't you provide a dateTimeImmutableBetween as an alias of dateTimeBetween but which will return an DateTimeImmutable instead of the current DateTime.
🙏🏼

@theofidry
Copy link
Member

Why don't you provide a dateTimeImmutableBetween as an alias of dateTimeBetween but which will return an DateTimeImmutable instead of the current DateTime.

Can be done: be it here or Faker. PRs for it are welcomed

@curry684
Copy link
Contributor

curry684 commented Oct 3, 2022

Having alternative functions for it seems like a weak workaround placing the burden on the fixture developer.

Given that there already is a decorated property accessor I think it should be possible to use the proper converter functions transparently?

(one could argue that this should even be part of the underlying symfony/propertyaccessor library transparently)

@theofidry
Copy link
Member

Having alternative functions for it seems like a weak workaround placing the burden on the fixture developer.

It's a way to see it, but I also it as a missing piece from those functions. Faker is not meant to be used only in Alice, having functions to generate DateTimeImmutable classes instead of DateTime seems pretty basic.

(one could argue that this should even be part of the underlying symfony/propertyaccessor library transparently)

I really don't think it's the property accessor's job to convert a type to another. The only reason why it might be acceptable here is because you are in a very specific context.

@curry684
Copy link
Contributor

curry684 commented Oct 3, 2022

I don't fundamentally disagree with either of those things, it's a pragmatism vs idealism situation methinks.

Faker is not meant to be used only in Alice, having functions to generate DateTimeImmutable classes instead of DateTime seems pretty basic.

But when using Faker directly one can easily use \DateTimeImmutable::createFromDateTime. The fact that PropertyAccess doesn't support it while Alice depends on it is the reason we can't solve it here.

I really don't think it's the property accessor's job to convert a type to another.

It happily converts integers to floats, and booleans to integers. It supports every type of type coercion natively supported by PHP. It's a weakness of PHP that it doesn't support cast overloading like many other languages, otherwise it would be able to do this conversion itself on explicit assignment.

Whether the PR I made for PropertyAccess ends up behind an option or not (I'm impartial as to whether it should be default behavior), it solves this issue for Alice and many other cases like Symfony Forms which has similar issues when mapping Doctrine entities.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

6 participants