Skip to content

Commit

Permalink
relationships: implement generic HasMany & HasOne relationships
Browse files Browse the repository at this point in the history
Latest PHPStorm 2022.2 EAP supports proper enumation of generic
Traverable, so completely migrating to HasMany<E> syntax.
  • Loading branch information
hrach committed Jun 3, 2022
1 parent 9cb5ec6 commit 6f1c9d8
Show file tree
Hide file tree
Showing 32 changed files with 193 additions and 105 deletions.
2 changes: 2 additions & 0 deletions .idea/codeStyles/Project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions composer.json
Expand Up @@ -36,7 +36,7 @@
"marc-mabe/php-enum": "~3.0",
"mockery/mockery": "~1.2",
"phpstan/extension-installer": "1.1.0",
"phpstan/phpstan": "1.4.10",
"phpstan/phpstan": "1.7.10",
"phpstan/phpstan-deprecation-rules": "1.0.0",
"phpstan/phpstan-nette": "1.0.0",
"phpstan/phpstan-mockery": "1.0.0",
Expand All @@ -58,7 +58,7 @@
]
},
"scripts": {
"phpstan": "phpstan analyse -c .phpstan.neon",
"phpstan": "phpstan analyse -c .phpstan.neon --memory-limit 1G",
"tests": "tester -C --colors 1 --setup ./tests/inc/setup.php ./tests/cases"
},
"config": {
Expand Down
3 changes: 3 additions & 0 deletions src/Entity/Embeddable/EmbeddableContainer.php
Expand Up @@ -17,6 +17,9 @@
use function count;


/**
* @implements IEntityAwareProperty<IEntity>
*/
class EmbeddableContainer implements IPropertyContainer, IEntityAwareProperty
{
use SmartObject;
Expand Down
7 changes: 5 additions & 2 deletions src/Entity/IEntityAwareProperty.php
Expand Up @@ -5,17 +5,20 @@

/**
* @experimental This interface API is experimental and is subjected to change. It is ok to use its implementation.
* @template E of IEntity
*/
interface IEntityAwareProperty extends IProperty
{
/**
* this listener is ired when property is attached to entity.
* Executed when the IProperty is attached to an entity.
* @phpstan-param E $entity
*/
public function onEntityAttach(IEntity $entity): void;


/**
* This listener is fired when the entity is attached to repository.
* Executed when the entity is attached to the repository.
* @phpstan-param E $entity
*/
public function onEntityRepositoryAttach(IEntity $entity): void;
}
1 change: 1 addition & 0 deletions src/Entity/Reflection/MetadataParser.php
Expand Up @@ -525,6 +525,7 @@ protected function processRelationshipEntityProperty(PropertyMetadata $property,
}
} else {
$targetProperty = substr($class, $pos + 3); // skip ::$
assert($targetProperty !== false); // @phpstan-ignore-line
$class = substr($class, 0, $pos);

if (isset($args['oneSided'])) {
Expand Down
58 changes: 39 additions & 19 deletions src/Relationships/HasMany.php
Expand Up @@ -20,12 +20,19 @@
use function spl_object_hash;


/**
* @template E of IEntity
* @implements IRelationshipCollection<E>
*/
abstract class HasMany implements IRelationshipCollection
{
use SmartObject;


/** @var IEntity */
/**
* @var IEntity
* @phpstan-var E
*/
protected $parent;

/** @var PropertyMetadata */
Expand All @@ -36,25 +43,31 @@ abstract class HasMany implements IRelationshipCollection

/**
* @var ICollection|null
* @phpstan-var ICollection<IEntity>|null
* @phpstan-var ICollection<E>|null
*/
protected $collection;

/** @var IEntity[] */
/**
* @var IEntity[]
* @phpstan-var array<string, E>
*/
protected $toAdd = [];

/** @var IEntity[] */
/**
* @var IEntity[]
* @phpstan-var array<string,E>
*/
protected $toRemove = [];

/** @var IEntity[] */
protected $added = [];

/** @var IEntity[] */
/**
* @var IEntity[]
* @phpstan-var array<string, E>
*/
protected $tracked = [];

/**
* @var IRepository|null
* @phpstan-var IRepository<IEntity>|null
* @phpstan-var IRepository<E>|null
*/
protected $targetRepository;

Expand Down Expand Up @@ -262,7 +275,7 @@ public function toCollection(): ICollection

/**
* @deprecated Use toCollection() instead.
* @phpstan-return ICollection<IEntity>
* @phpstan-return ICollection<E>
*/
public function get(): ICollection
{
Expand All @@ -284,7 +297,7 @@ public function countStored(): int

/**
* @return ICollection|IEntity[]
* @phpstan-return ICollection<IEntity>
* @phpstan-return ICollection<E>
*/
public function getIterator(): ICollection
{
Expand Down Expand Up @@ -315,7 +328,7 @@ public function trackEntity(IEntity $entity): void


/**
* @phpstan-return ICollection<IEntity>
* @phpstan-return ICollection<E>
*/
protected function getCollection(bool $forceNew = false): ICollection
{
Expand All @@ -326,16 +339,18 @@ protected function getCollection(bool $forceNew = false): ICollection
if ($this->parent->isPersisted()) {
$collection = $this->createCollection();
} else {
/** @var ICollection<E> $collection */
$collection = new EmptyCollection();
}

if (count($this->toAdd) > 0 || count($this->toRemove) > 0) {
/** @phpstan-var callable():array{array<string, IEntity>, array<string, IEntity>} $diffCb */
/** @phpstan-var callable():array{array<string, E>, array<string, E>} $diffCb */
$diffCb = function (): array {
return [$this->toAdd, $this->toRemove];
};

$collection = $collection->resetOrderBy();
/** @var ICollection<E> $collection */
$collection = new HasManyCollection($this->getTargetRepository(), $collection, $diffCb);
$collection = $this->applyDefaultOrder($collection);
}
Expand All @@ -349,6 +364,8 @@ protected function getCollection(bool $forceNew = false): ICollection

/**
* @param IEntity|string|int $entity
* @phpstan-param E|string|int $entity
* @phpstan-return E|null
*/
protected function createEntity($entity, bool $need = true): ?IEntity
{
Expand Down Expand Up @@ -384,13 +401,15 @@ public function __clone()


/**
* @phpstan-return IRepository<IEntity>
* @phpstan-return IRepository<E>
*/
protected function getTargetRepository(): IRepository
{
if ($this->targetRepository === null) {
$this->targetRepository = $this->parent->getRepository()->getModel()
/** @var IRepository<E> $repository */
$repository = $this->parent->getRepository()->getModel()
->getRepository($this->metadataRelationship->repository);
$this->targetRepository = $repository;
}

return $this->targetRepository;
Expand All @@ -410,9 +429,8 @@ protected function getRelationshipMapper(): IRelationshipMapper


/**
* @template T of ICollection<IEntity>
* @phpstan-param T $collection
* @phpstan-return T
* @phpstan-param ICollection<E> $collection
* @phpstan-return ICollection<E>
*/
protected function applyDefaultOrder(ICollection $collection): ICollection
{
Expand All @@ -432,19 +450,21 @@ abstract protected function modify(): void;

/**
* Returns collection for has many relationship.
* @phpstan-return ICollection<IEntity>
* @phpstan-return ICollection<E>
*/
abstract protected function createCollection(): ICollection;


/**
* Updates relationship change for the $entity.
* @phpstan-param E $entity
*/
abstract protected function updateRelationshipAdd(IEntity $entity): void;


/**
* Updates relationship change for the $entity.
* @phpstan-param E $entity
*/
abstract protected function updateRelationshipRemove(IEntity $entity): void;
}
42 changes: 33 additions & 9 deletions src/Relationships/HasOne.php
Expand Up @@ -15,12 +15,19 @@
use function assert;


/**
* @template E of IEntity
* @implements IRelationshipContainer<E>
*/
abstract class HasOne implements IRelationshipContainer
{
use SmartObject;


/** @var IEntity */
/**
* @var IEntity
* @phpstan-var E
*/
protected $parent;

/** @var PropertyMetadata */
Expand All @@ -31,7 +38,7 @@ abstract class HasOne implements IRelationshipContainer

/**
* @var ICollection
* @phpstan-var ICollection<IEntity>
* @phpstan-var ICollection<E>
*/
protected $collection;

Expand All @@ -41,15 +48,21 @@ abstract class HasOne implements IRelationshipContainer
/** @var bool Is raw value loaded from storage and not converted yet? */
protected $isValueFromStorage = false;

/** @var IEntity|string|int|null */
/**
* @var IEntity|string|int|null
* @phpstan-var E|string|int|null
*/
protected $value;

/** @var IEntity[] */
/**
* @var IEntity[]
* @phpstan-var list<E>
*/
protected $tracked = [];

/**
* @var IRepository|null
* @phpstan-var IRepository<IEntity>|null
* @phpstan-var IRepository<E>|null
*/
protected $targetRepository;

Expand Down Expand Up @@ -138,6 +151,7 @@ public function isLoaded(): bool
* Sets the relationship value to passed entity.
* Returns true if the setter has modified property value.
* @param IEntity|int|string|null $value Accepts also a primary key value.
* @phpstan-param E|int|string|null $value Accepts also a primary key value.
*/
public function set($value, bool $allowNull = false): bool
{
Expand Down Expand Up @@ -212,6 +226,9 @@ protected function getPrimaryValue()
}


/**
* @phpstan-return E|null
*/
protected function getValue(bool $allowPreloadContainer = true): ?IEntity
{
if (!$this->isValueValidated && $this->value !== null) {
Expand Down Expand Up @@ -240,6 +257,9 @@ protected function initValue(bool $allowPreloadContainer = true): void
}


/**
* @phpstan-return E|null
*/
protected function fetchValue(): ?IEntity
{
$collection = $this->getCollection();
Expand All @@ -248,21 +268,23 @@ protected function fetchValue(): ?IEntity


/**
* @phpstan-return IRepository<IEntity>
* @phpstan-return IRepository<E>
*/
protected function getTargetRepository(): IRepository
{
if ($this->targetRepository === null) {
$this->targetRepository = $this->parent->getRepository()->getModel()
/** @var IRepository<E> $targetRepository */
$targetRepository = $this->parent->getRepository()->getModel()
->getRepository($this->metadataRelationship->repository);
$this->targetRepository = $targetRepository;
}

return $this->targetRepository;
}


/**
* @phpstan-return ICollection<IEntity>
* @phpstan-return ICollection<E>
*/
protected function getCollection(): ICollection
{
Expand All @@ -276,6 +298,8 @@ protected function getCollection(): ICollection

/**
* @param IEntity|string|int|null $entity
* @phpstan-param E|string|int|null $entity
* @phpstan-return E|null
*/
protected function createEntity($entity, bool $allowNull): ?IEntity
{
Expand Down Expand Up @@ -373,7 +397,7 @@ abstract protected function isImmediateEntityForPersistence(?IEntity $entity): b

/**
* Creates relationship collection.
* @phpstan-return ICollection<IEntity>
* @phpstan-return ICollection<E>
*/
abstract protected function createCollection(): ICollection;

Expand Down

0 comments on commit 6f1c9d8

Please sign in to comment.