orm icon indicating copy to clipboard operation
orm copied to clipboard

Property hooks from PHP 8.4

Open hrach opened this issue 1 year ago • 1 comments

As PHP 8.4 comes with property hooks we could remove virtual properties, as they would be completely modelled by a custom property with getter hook.

This:

/** ...
 * @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

/** ...
 */
final class Author extends Entity
{
	public int $age {
		get {
			if ($this->born === null) {
				return 0;
			}

			return ((int) date('Y')) - ((int) $this->born->format('Y'));
		}
	}
}

Please note, that this would not mean removing custom getters/setters support, as they're still needed for non-virtual properties.

hrach avatar Oct 25 '24 13:10 hrach

I have an use case where I fetch "extended" entity with properties that are not available in original table. Something like:

/**
 * ...
 * @property-read DateTimeImmutable $changedAt
 */
class JoinedEntity extends Entity {}

Where value for $changedAt comes from joined table:

SELECT
  pt.*,
  l.changed_at
FROM primary_table pt
LEFT JOIN (SELECT l.change_at FROM ... )

When given entity is being persisted, these extended properties are marked as virtual to avoid ORM attempting to persist them. After persisting they are reset.

    // Required for correct behavior on persisting values not present in mapper DB table
    public function onBeforeInsert(): void
    {
        parent::onBeforeInsert();
        $this->metadata->getProperty('changedAt')->isVirtual = true;
        $this->metadata->getProperty('changedBy')->isVirtual = true;
    }

    public function onAfterInsert(): void
    {
        parent::onAfterInsert();
        $this->metadata->getProperty('changedAt')->isVirtual = false;
        $this->metadata->getProperty('changedBy')->isVirtual = false;
    }

I don't remember exactly why it was implemented this way, but it was the only solution we came with.

mskocik avatar Oct 29 '24 15:10 mskocik