Open
Description
With the newly added feature, maybe, there is a new way how to write entities.
Consequently, this would utilize property types, annotations & property hooks as well.
So the original entity like:
/**
* @property int|null $id {primary}
* @property string $name
* @property DateTimeImmutable|null $born {default "2021-03-21 08:23:00"}
* @property string $web {default "http://www.example.com"}
* @property Author|null $favoriteAuthor {m:1 Author::$favoredBy}
* @property OneHasMany<Author> $favoredBy {1:m Author::$favoriteAuthor}
* @property OneHasMany<Book> $books {1:m Book::$author, orderBy=[id=DESC], cascade=[persist, remove]}
* @property OneHasMany<Book> $translatedBooks {1:m Book::$translator}
* @property OneHasMany<TagFollower> $tagFollowers {1:m TagFollower::$author, cascade=[persist, remove]}
* @property-read int $age {virtual}
*/
final class Author extends Entity
{
protected function getterAge(): int
{
if ($this->born === null) {
return 0;
}
return ((int) date('Y')) - ((int) $this->born->format('Y'));
}
}
would become
class Author extends Entity
{
#[Primary]
public int|null $id;
public string $name;
#[Default("2021-03-21 08:23:00")]
public DateTimeImmutable|null $born;
public string $web = "http://www.example.com";
#[ManyHasOne(Author::class, "favoredBy")]
public Author|null $favoriteAuthor;
#[OneHasMany(Author::class, "favoriteAuthor")]
public OneHasMany $favortedBy;
#[OneHasMany(Book::class, 'author', orderBy: ['id' => 'desc'], cascade: ['persist', 'remove'])
public OneHasMany $books;
#[OneHasMany(Book::class, 'translator')
public OneHasMany $translatedBooks;
#[OneHasMany(TagFollower::class, 'author', cascade: ['persist', 'remove'])
public OneHasMany $tagFollowers;
public int $age {
get {
if ($this->born === null) return 0;
return ((int) date('Y')) - ((int) $this->born->format('Y'));
}
}
// example of still public/open constructor
public __construct(string $name) {
parent::__construct();
$this->name = $name;
}
}
Implementation comments:
- *HasOne relationships's backing relationship instance would have to be stored somewhere else, i.e. property wrappers have to be separated into user-facing and backing field ones and the second has to be handled separately.
- There is still an open question of how "setting" a hasOne relationship could properly propagate to its backing field relationship; a required setter with sideffect? or utilize hooks to avoid hidden backing-fields?
- The whole mechanism could be implemented as another option and it would be up to the user when to migrate to this new way of entity definition.
- old getters/setters would be deprecated
HasOne options:
class Author {
#[ManyHasOne(Author::class, "favoredBy")]
private ManyHasOne $favoriteAuthorRel;
public Author|null $favoriteAuthor { get => $this->favoriteAuthorRel->getEntity(); }
}
or
class Author {
#[ManyHasOne(Author::class, "favoredBy")]
public Author|null $favoriteAuthor {
set {
$this->favoriteAuthor = $value;
$this->updateReverse('...', $value);
}
}