Skip to content

Commit

Permalink
Merge 48ca916 into 88f4476
Browse files Browse the repository at this point in the history
  • Loading branch information
hrach committed May 30, 2020
2 parents 88f4476 + 48ca916 commit 31de17d
Show file tree
Hide file tree
Showing 16 changed files with 135 additions and 54 deletions.
20 changes: 20 additions & 0 deletions doc/relationships.texy
Expand Up @@ -269,3 +269,23 @@ foreach ($authors as $author) {
$sub = $author->books->toCollection()->limitBy(2);
}
\--

You may decide to expose only the relationship's collection in its property. Use `exposeCollection` modifier argument. Further modifications are still allowed through relationship object returned by `IEntity::getProperty()` method.

/--php
/**
* @property int|null $id
* @property Collection|Book[] $books {1:m Author::$books, exposeCollection=true}
*/
class Author
{
public function setBooks(Book ...$books): void
{
$this->getProperty('books')->set($books);
}
}

$author = new Author();
$author->books->findBy(...);
$author->setBooks(new Book());
\--
2 changes: 1 addition & 1 deletion src/Entity/AbstractEntity.php
Expand Up @@ -445,7 +445,7 @@ private function internalSetValue(PropertyMetadata $metadata, string $name, $val
return;
} elseif ($property instanceof IProperty) {
$class = get_class($this);
throw new LogicException("You cannot set property wrapper's value on $class::\$$name directly.");
throw new LogicException("You cannot set property wrapper's value in $class::\$$name directly.");
}

if ($metadata->hasSetter) {
Expand Down
2 changes: 1 addition & 1 deletion src/Entity/Embeddable/Embeddable.php
Expand Up @@ -176,7 +176,7 @@ private function setImmutableData(array $data): void
continue;
} elseif ($property instanceof IProperty) {
$class = get_class($this);
throw new LogicException("You cannot set property wrapper's value on $class::\$$name directly.");
throw new LogicException("You cannot set property wrapper's value in $class::\$$name directly.");
}

if ($metadata->hasSetter) {
Expand Down
15 changes: 15 additions & 0 deletions src/Entity/Reflection/MetadataParser.php
Expand Up @@ -12,6 +12,7 @@
use Nextras\Orm\InvalidModifierDefinitionException;
use Nextras\Orm\InvalidStateException;
use Nextras\Orm\NotSupportedException;
use Nextras\Orm\Relationships\HasMany;
use Nextras\Orm\Relationships\ManyHasMany;
use Nextras\Orm\Relationships\ManyHasOne;
use Nextras\Orm\Relationships\OneHasMany;
Expand Down Expand Up @@ -341,6 +342,7 @@ protected function parseOneHasManyModifier(PropertyMetadata $property, array &$a
$this->processRelationshipEntityProperty($property, $args);
$this->processRelationshipCascade($property, $args);
$this->processRelationshipOrder($property, $args);
$this->processRelationshipExposeCollection($property, $args);
}


Expand Down Expand Up @@ -370,6 +372,7 @@ protected function parseManyHasManyModifier(PropertyMetadata $property, array &$
$this->processRelationshipEntityProperty($property, $args);
$this->processRelationshipCascade($property, $args);
$this->processRelationshipOrder($property, $args);
$this->processRelationshipExposeCollection($property, $args);
}


Expand Down Expand Up @@ -583,6 +586,18 @@ protected function processRelationshipOrder(PropertyMetadata $property, array &$
}


/**
* @phpstan-param array<int|string, mixed> $args
*/
protected function processRelationshipExposeCollection(PropertyMetadata $property, array &$args): void
{
if (isset($args['exposeCollection']) && $args['exposeCollection']) {
$property->args[HasMany::class]['exposeCollection'] = true;
}
unset($args['exposeCollection']);
}


/**
* @phpstan-param array<int|string, mixed> $args
*/
Expand Down
29 changes: 29 additions & 0 deletions src/Relationships/HasMany.php
Expand Up @@ -11,6 +11,7 @@
use Nextras\Orm\Entity\Reflection\PropertyMetadata;
use Nextras\Orm\Entity\Reflection\PropertyRelationshipMetadata;
use Nextras\Orm\InvalidStateException;
use Nextras\Orm\LogicException;
use Nextras\Orm\Mapper\IRelationshipMapper;
use Nextras\Orm\Repository\IRepository;
use function assert;
Expand Down Expand Up @@ -60,12 +61,16 @@ abstract class HasMany implements IRelationshipCollection
/** @var IRelationshipMapper|null */
protected $relationshipMapper;

/** @var bool */
protected $exposeCollection;


public function __construct(PropertyMetadata $metadata)
{
assert($metadata->relationship !== null);
$this->metadata = $metadata;
$this->metadataRelationship = $metadata->relationship;
$this->exposeCollection = $this->metadata->args[HasMany::class]['exposeCollection'] ?? false;
}


Expand Down Expand Up @@ -112,6 +117,30 @@ public function getRawValue(): array
}


public function setInjectedValue($value): bool
{
$class = get_class($this->parent);
throw new LogicException("You cannot set relationship collection value in $class::\${$this->metadata->name} directly.");
}


public function &getInjectedValue()
{
if ($this->exposeCollection) {
$collection = $this->getIterator();
return $collection;
} else {
return $this;
}
}


public function hasInjectedValue(): bool
{
return true;
}


public function add($entity): ?IEntity
{
if ($this->updatingReverseRelationship) {
Expand Down
4 changes: 2 additions & 2 deletions src/Relationships/IRelationshipCollection.php
Expand Up @@ -8,13 +8,13 @@
use Nextras\Orm\Collection\ICollection;
use Nextras\Orm\Entity\IEntity;
use Nextras\Orm\Entity\IEntityAwareProperty;
use Nextras\Orm\Entity\IProperty;
use Nextras\Orm\Entity\IPropertyContainer;


/**
* @extends IteratorAggregate<int, IEntity>
*/
interface IRelationshipCollection extends IProperty, IEntityAwareProperty, IteratorAggregate, Countable
interface IRelationshipCollection extends IPropertyContainer, IEntityAwareProperty, IteratorAggregate, Countable
{
/**
* Adds entity.
Expand Down
13 changes: 10 additions & 3 deletions src/Relationships/ManyHasOne.php
Expand Up @@ -5,6 +5,7 @@

use Nextras\Orm\Collection\ICollection;
use Nextras\Orm\Entity\IEntity;
use function assert;


class ManyHasOne extends HasOne
Expand Down Expand Up @@ -32,11 +33,15 @@ protected function updateRelationship(?IEntity $oldEntity, ?IEntity $newEntity,

$this->updatingReverseRelationship = true;
if ($oldEntity) {
$oldEntity->getValue($key)->remove($this->parent);
$property = $oldEntity->getProperty($key);
assert($property instanceof OneHasMany);
$property->remove($this->parent);
}

if ($newEntity) {
$newEntity->getValue($key)->add($this->parent);
$property = $newEntity->getProperty($key);
assert($property instanceof OneHasMany);
$property->add($this->parent);
}
$this->updatingReverseRelationship = false;
}
Expand All @@ -50,7 +55,9 @@ protected function initReverseRelationship(?IEntity $entity)
}

$this->updatingReverseRelationship = true;
$entity->getValue($key)->trackEntity($this->parent);
$property = $entity->getProperty($key);
assert($property instanceof OneHasMany);
$property->trackEntity($this->parent);
$this->updatingReverseRelationship = false;
}
}
14 changes: 6 additions & 8 deletions src/Relationships/OneHasMany.php
Expand Up @@ -77,10 +77,9 @@ protected function updateRelationshipAdd(IEntity $entity): void
}

$this->updatingReverseRelationship = true;
$entity->setReadOnlyValue(
$this->metadataRelationship->property,
$this->parent
);
$property = $entity->getProperty($this->metadataRelationship->property);
assert($property instanceof ManyHasOne);
$property->set($this->parent);
$this->updatingReverseRelationship = false;
}

Expand All @@ -92,10 +91,9 @@ protected function updateRelationshipRemove(IEntity $entity): void
}

$this->updatingReverseRelationship = true;
$entity->setReadOnlyValue(
$this->metadataRelationship->property,
null
);
$property = $entity->getProperty($this->metadataRelationship->property);
assert($property instanceof ManyHasOne);
$property->set(null, true);
$this->updatingReverseRelationship = false;
}
}
4 changes: 2 additions & 2 deletions src/Relationships/OneHasOne.php
Expand Up @@ -12,8 +12,8 @@ class OneHasOne extends HasOne
{
protected function createCollection(): ICollection
{
$colection = $this->getTargetRepository()->getMapper()->createCollectionOneHasOne($this->metadata);
return $colection->setRelationshipParent($this->parent);
$collection = $this->getTargetRepository()->getMapper()->createCollectionOneHasOne($this->metadata);
return $collection->setRelationshipParent($this->parent);
}


Expand Down
19 changes: 10 additions & 9 deletions src/Repository/RemovalHelper.php
Expand Up @@ -107,7 +107,7 @@ public static function getRelationships(IEntity $entity): array

$property = $entity->getProperty($name);
if ($property instanceof IRelationshipContainer) {
$value = $entity->getValue($name);
$value = $property->getEntity();
if ($value) {
if ($propertyMeta->relationship->type === Relationship::ONE_HAS_ONE && !$propertyMeta->relationship->isMain) {
$return[0][$name] = $value;
Expand All @@ -116,7 +116,7 @@ public static function getRelationships(IEntity $entity): array
}
}
} elseif ($property instanceof IRelationshipCollection) {
$return[0][$name] = $entity->getValue($name);
$return[0][$name] = $property;
}
}

Expand Down Expand Up @@ -166,9 +166,9 @@ private static function setNulls(
} elseif ($type === Relationship::MANY_HAS_ONE || ($type === Relationship::ONE_HAS_ONE && $propertyMeta->relationship->isMain)) {
$property = $entity->getProperty($name);
assert($property instanceof HasOne);
if ($reverseProperty !== null && $entity->hasValue($name)) {
$reverseEntity = $entity->getValue($name);
if (isset($queueRemove[spl_object_hash($reverseEntity)])) {
if ($reverseProperty !== null) {
$reverseEntity = $property->getEntity();
if ($reverseEntity === null || isset($queueRemove[spl_object_hash($reverseEntity)])) {
// reverse side is also being removed, do not set null to this relationship
continue;
}
Expand All @@ -178,22 +178,23 @@ private static function setNulls(
} else {
// $type === Relationship::ONE_HAS_MANY or
// $type === Relationship::ONE_HAS_ONE && !$isMain

if (!$entity->hasValue($name) || $reverseProperty === null) {
continue;
}

if ($reverseProperty->isNullable) {
if ($type === Relationship::ONE_HAS_MANY) {
foreach ($entity->getValue($name) as $subValue) {
$pre[] = $subValue;
}
$property = $entity->getProperty($name);
assert($property instanceof IRelationshipCollection);
foreach ($property as $subValue) {
$pre[] = $subValue;
}
$property->set([]);
} else {
$pre[] = $entity->getValue($name);
$property = $entity->getProperty($name);
assert($property instanceof HasOne);
$pre[] = $property->getEntity();
$property->set(null, true);
}
} else {
Expand Down
6 changes: 3 additions & 3 deletions tests/cases/integration/Entity/entity.cloning.phpt
Expand Up @@ -47,9 +47,9 @@ class EntityCloning2Test extends DataTestCase
/** @var Book $book */
$author = $this->e(Author::class);
$book = $this->e(Book::class, ['author' => $author]);
$tag1 = $this->e(Tag::class);
$tag2 = $this->e(Tag::class);
$tag3 = $this->e(Tag::class);
$tag1 = $this->e(Tag::class, ['name' => 'Tag 1']);
$tag2 = $this->e(Tag::class, ['name' => 'Tag 2']);
$tag3 = $this->e(Tag::class, ['name' => 'Tag 3']);

$book->tags->set([$tag1, $tag2, $tag3]);
$this->orm->books->persistAndFlush($book);
Expand Down
Expand Up @@ -118,7 +118,7 @@ class EntityRelationshipsTest extends DataTestCase
Assert::exception(function () {
$author = new Author();
$author->books = [];
}, LogicException::class, 'You cannot set property wrapper\'s value on NextrasTests\Orm\Author::$books directly.');
}, LogicException::class, 'You cannot set relationship collection value in NextrasTests\Orm\Author::$books directly.');
}
}

Expand Down
Expand Up @@ -344,9 +344,9 @@ class RelationshipsManyHasManyCollectionTest extends DataTestCase
$book3 = $this->orm->books->getById(3); // SELECT

$tag = $this->orm->tags->getById(1); // SELECT
Assert::count(0, $tag->books->getEntitiesForPersistence());
$tag->books->set([$book2, $book3]); // SELECT JOIN + SELECT BOOK
Assert::count(3, $tag->books->getEntitiesForPersistence());
Assert::count(0, $tag->getProperty('books')->getEntitiesForPersistence());
$tag->setBooks($book2, $book3, $book2); // SELECT JOIN + SELECT BOOK
Assert::count(3, $tag->getProperty('books')->getEntitiesForPersistence());
});

if ($queries !== null) {
Expand All @@ -360,7 +360,7 @@ class RelationshipsManyHasManyCollectionTest extends DataTestCase
static $id = 0;

$tag = new Tag();
$tag->name = 'New Tag #' . (++$id);
$tag->setName('New Tag #' . (++$id));
return $tag;
}

Expand Down

0 comments on commit 31de17d

Please sign in to comment.