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

Lazy instantioning from PHP 8.4 #683

Open
hrach opened this issue Oct 25, 2024 · 3 comments
Open

Lazy instantioning from PHP 8.4 #683

hrach opened this issue Oct 25, 2024 · 3 comments

Comments

@hrach
Copy link
Member

hrach commented Oct 25, 2024

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);
       }
}
@mabar
Copy link
Contributor

mabar commented Oct 25, 2024

This is technically possible even without PHP 8.4. It needs a few hacks, but I managed to create quite clear implementation in orisai/object-mapper. I can help with backporting it if it's welcome. My current project will be stuck on PHP 7.4 for a while, so I can't test new cool stuff...

Btw, there should be a way to distinguish between mapped property and regular property - for dependencies and memory cache.

@hrach
Copy link
Member Author

hrach commented Oct 25, 2024

Just from the first sight, it seems that the definition is more verbose. Hard to see this is the way.

@mskocik
Copy link

mskocik commented Oct 29, 2024

Just from the first sight, it seems that the definition is more verbose. Hard to see this is the way.

I agree. More verbose and harder to read. That's beauty of current implementation, easy to read and write.

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

No branches or pull requests

3 participants