Reputation: 3324
I'm sure that question has been asked numerous times but I can't seem to find a good/satisfying answer so please bare with me.
Using PHP 7.4+, I tend to type everything I can. But I have some problems with Doctrine entities properties.
If I type everything correctly, I usually get a lot of errors like this one.
Typed property App\Entity\User::$createdAt must not be accessed before initialization
A code sample for that type of error would look something like this
/**
* @var DateTimeInterface
* @ORM\Column(type="datetime")
*/
protected DateTimeInterface $createdAt;
So, I used to make the property nullable even though the database field is not. So it would look something like this.
/**
* @var DateTimeInterface|null
* @ORM\Column(type="datetime")
*/
protected ?DateTimeInterface $createdAt = null;
But, now I have another problem. I decided to implement a static code analyzer in my project and now I'm using PHPStan. So now, when I scan my code I get errors like that one.
Line src/Entity/Trait/TimestampableEntityPropertiesTrait.php (in context of class App\Entity\Article)
16 Property App\Entity\Article::$createdAt type mapping mismatch: property can contain DateTimeInterface|null but database expects DateTimeInterface.
Sometimes, I don't want to/can't initialize the property in the constructor since I don't have the correct values just yet.
What would be the right way to handle this type of situation?
Upvotes: 5
Views: 2272
Reputation: 3324
I'm not sure if this is a bad practice, but it turned out I only had to remove that check from phpstan configuration.
# phpstan.neon
parameters:
doctrine:
allowNullablePropertyForRequiredField: true
After some digging, I realized I should be using a DTO which would allow a null value, and then transfer it to my entity once ready (and valid). This way, my entity is always valid, and I do not risk flushing some invalid data in the DB.
Upvotes: 3
Reputation: 76699
phpstan
probably isn't that wrong about the code smell ...
the actual Doctrine annotation would be nullable=true
:
/**
* @ORM\Column(type="datetime", nullable=true)
*/
Then the ORM would stop complaining about the unexpected NULL
value.
Without it, created_at
would have NOT NULL
set; therefore it's "required".
The point is, that when it's nullable=true
, then it's not required anymore.
And when it's not required anymore, phpstan
would also stop to complain.
While on the other hand, when letting phpstan
ignore these conflicts on the application level with allowNullablePropertyForRequiredField: true
, this has zero impact on the underlying database, which would reject the record, based upon the annotations used to generate the database table.
Upvotes: 1