Skip to content

Commit

Permalink
Merge 128f8c4 into e45cf63
Browse files Browse the repository at this point in the history
  • Loading branch information
hrach committed Apr 15, 2023
2 parents e45cf63 + 128f8c4 commit 63eae38
Show file tree
Hide file tree
Showing 20 changed files with 127 additions and 121 deletions.
2 changes: 0 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
"nette/di": "^3.1",
"nette/neon": "~3.0",
"nette/tester": "~2.5",
"marc-mabe/php-enum": "~4.6",
"mockery/mockery": ">=1.5.1",
"phpstan/extension-installer": "1.2.0",
"phpstan/phpstan": "1.10.9",
Expand All @@ -41,7 +40,6 @@
"phpstan/phpstan-strict-rules": "1.4.5",
"nextras/multi-query-parser": "~1.0",
"nextras/orm-phpstan": "~1.0@dev",
"marc-mabe/php-enum-phpstan": "dev-master",
"tracy/tracy": "~2.3"
},
"autoload": {
Expand Down
2 changes: 1 addition & 1 deletion src/Entity/AbstractEntity.php
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ public function getRawValues(bool $modifiedOnly = false): array
} else {
$out[$name] = $this->getProperty($name)->getRawValue();
if ($out[$name] === null && !$propertyMetadata->isNullable) {
throw new NullValueException($this, $propertyMetadata);
throw new NullValueException($propertyMetadata);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/Entity/Embeddable/Embeddable.php
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ private function createPropertyWrapper(PropertyMetadata $metadata): IProperty

if ($wrapper instanceof IEntityAwareProperty) {
if ($this->parentEntity === null) {
throw new InvalidStateException("");
throw new InvalidStateException("Embeddable cannot contain a property having IEntityAwareProperty wrapper because embeddable is instanced before setting/attaching to its entity.");
} else {
$wrapper->onEntityAttach($this->parentEntity);
}
Expand Down
2 changes: 1 addition & 1 deletion src/Entity/Embeddable/EmbeddableContainer.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ public function setInjectedValue($value): bool
if ($value !== null && !$value instanceof $this->instanceType) {
throw new InvalidArgumentException("Value has to be instance of {$this->instanceType}" . ($this->metadata->isNullable ? ' or a null.' : '.'));
} elseif ($value === null && !$this->metadata->isNullable) {
throw new NullValueException($this->entity, $this->metadata);
throw new NullValueException($this->metadata);
}

if ($value !== null) {
Expand Down
13 changes: 11 additions & 2 deletions src/Entity/Reflection/MetadataParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
namespace Nextras\Orm\Entity\Reflection;


use BackedEnum;
use DateTime;
use Nette\Utils\Reflection;
use Nextras\Orm\Collection\ICollection;
use Nextras\Orm\Entity\Embeddable\EmbeddableContainer;
use Nextras\Orm\Entity\Embeddable\IEmbeddable;
use Nextras\Orm\Entity\IEntity;
use Nextras\Orm\Entity\IProperty;
use Nextras\Orm\Entity\Wrapper\BackedEnumWrapper;
use Nextras\Orm\Exception\InvalidStateException;
use Nextras\Orm\Exception\NotSupportedException;
use Nextras\Orm\Relationships\HasMany;
Expand Down Expand Up @@ -174,7 +176,7 @@ protected function parseAnnotations(ReflectionClass $reflection, array $methods)
{
preg_match_all(
'~^[ \t*]* @property(|-read|-write)[ \t]+([^\s$]+)[ \t]+\$(\w+)(.*)$~um',
(string) $reflection->getDocComment(), $matches, PREG_SET_ORDER
(string) $reflection->getDocComment(), $matches, PREG_SET_ORDER,
);

$properties = [];
Expand All @@ -183,6 +185,7 @@ protected function parseAnnotations(ReflectionClass $reflection, array $methods)

$property = new PropertyMetadata();
$property->name = $variable;
$property->containerClassname = $reflection->getName();
$property->isReadonly = $isReadonly;

$this->parseAnnotationTypes($property, $type);
Expand Down Expand Up @@ -228,7 +231,7 @@ protected function parseAnnotationTypes(PropertyMetadata $property, string $type
$typeLower = substr($typeLower, 1);
$type = substr($type, 1);
}
if (strpos($type, '[') !== false) { // string[]
if (str_contains($type, '[')) { // string[]
$type = 'array';
} elseif (isset($types[$typeLower])) {
$type = $typeLower;
Expand All @@ -240,12 +243,18 @@ protected function parseAnnotationTypes(PropertyMetadata $property, string $type
if ($type === DateTime::class || is_subclass_of($type, DateTime::class)) {
throw new NotSupportedException("Type '{$type}' in {$this->currentReflection->name}::\${$property->name} property is not supported anymore. Use \DateTimeImmutable or \Nextras\Dbal\Utils\DateTimeImmutable type.");
}
if (is_subclass_of($type, BackedEnum::class)) {
$property->wrapper = BackedEnumWrapper::class;
}
}
$parsedTypes[$type] = true;
}

$property->isNullable = $isNullable || isset($parsedTypes['null']) || isset($parsedTypes['NULL']) || isset($parsedTypes['mixed']);
unset($parsedTypes['null'], $parsedTypes['NULL']);
if (count($parsedTypes) < 1) {
throw new NotSupportedException("Property {$this->currentReflection->name}::\${$property->name} without a type definition is not supported.");
}
$property->types = $parsedTypes;
}

Expand Down
55 changes: 22 additions & 33 deletions src/Entity/Reflection/PropertyMetadata.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,47 +24,35 @@ class PropertyMetadata
use SmartObject;


/** @var string property name */
public $name = '';
public string $name = '';
public string $containerClassname = '';
public ?string $wrapper = null;

/** @var string|null */
public $wrapper;
public ?string $hasGetter = null;
public ?string $hasSetter = null;

/** @var string|null */
public $hasGetter;
/** @var non-empty-array<string, bool> of allowed types defined as keys */
public array $types;

/** @var string|null */
public $hasSetter;

/** @var array<string, bool> of allowed types defined as keys */
public $types = [];

/** @var bool */
public $isPrimary = false;

/** @var bool */
public $isNullable = false;

/** @var bool */
public $isReadonly = false;

/** @var bool */
public $isVirtual = false;

/** @var mixed */
public $defaultValue;

/** @var PropertyRelationshipMetadata|null */
public $relationship;
public bool $isPrimary = false;
public bool $isNullable = false;
public bool $isReadonly = false;
public bool $isVirtual = false;
public mixed $defaultValue = null;
public ?PropertyRelationshipMetadata $relationship = null;

/** @var array<string, mixed>|null */
public $args;
public ?array $args = null;

/** @var array<mixed>|null array of allowed values */
public $enum;
public ?array $enum = null;

private ?IProperty $wrapperPrototype = null;


/** @var IProperty|null */
private $wrapperPrototype;
public function __construct()
{
}


public function getWrapperPrototype(): IProperty
Expand All @@ -85,6 +73,7 @@ public function __sleep()
// we skip wrapperPrototype which may not be serializable and is created lazily
return [
'name',
'containerClassname',
'wrapper',
'hasGetter',
'hasSetter',
Expand Down
50 changes: 50 additions & 0 deletions src/Entity/Wrapper/BackedEnumWrapper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php declare(strict_types = 1);

namespace Nextras\Orm\Entity\Wrapper;


use BackedEnum;
use Nextras\Orm\Entity\ImmutableValuePropertyWrapper;
use Nextras\Orm\Exception\NullValueException;
use function array_key_first;
use function assert;
use function is_int;
use function is_string;
use function is_subclass_of;


final class BackedEnumWrapper extends ImmutableValuePropertyWrapper
{
public function setInjectedValue($value): bool
{
if ($value === null && !$this->propertyMetadata->isNullable) {
throw new NullValueException($this->propertyMetadata);
}

return parent::setInjectedValue($value);
}


public function convertToRawValue(mixed $value): mixed
{
if ($value === null) return null;
$type = array_key_first($this->propertyMetadata->types);
assert($value instanceof $type);
assert($value instanceof BackedEnum);
return $value->value;
}


public function convertFromRawValue(mixed $value): ?BackedEnum
{
if ($value === null) {
if ($this->propertyMetadata->isNullable) return null;
throw new NullValueException($this->propertyMetadata);
}

assert(is_int($value) || is_string($value));
$type = array_key_first($this->propertyMetadata->types);
assert(is_subclass_of($type, BackedEnum::class));
return $type::from($value);
}
}
6 changes: 2 additions & 4 deletions src/Exception/NullValueException.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,13 @@
namespace Nextras\Orm\Exception;


use Nextras\Orm\Entity\IEntity;
use Nextras\Orm\Entity\Reflection\PropertyMetadata;


class NullValueException extends InvalidArgumentException
{
public function __construct(IEntity $entity, PropertyMetadata $propertyMetadata)
public function __construct(PropertyMetadata $propertyMetadata)
{
$class = get_class($entity);
parent::__construct("Property {$class}::\${$propertyMetadata->name} is not nullable.");
parent::__construct("Property {$propertyMetadata->containerClassname}::\${$propertyMetadata->name} is not nullable.");
}
}
4 changes: 2 additions & 2 deletions src/Relationships/HasOne.php
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ public function getEntity(): ?IEntity

if ($value === null && !$this->metadata->isNullable) {
assert($this->parent !== null);
throw new NullValueException($this->parent, $this->metadata);
throw new NullValueException($this->metadata);
}

return $value;
Expand Down Expand Up @@ -313,7 +313,7 @@ protected function createEntity($entity, bool $allowNull): ?IEntity

} elseif ($entity === null) {
if (!$this->metadata->isNullable && !$allowNull) {
throw new NullValueException($this->getParentEntity(), $this->metadata);
throw new NullValueException($this->metadata);
}
return null;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class CollectionEmbeddablesTest extends DataTestCase
Assert::same(0, $books1->countStored());

$book = $this->orm->books->getByIdChecked(1);
$book->price = new Money(1000, Currency::CZK());
$book->price = new Money(1000, Currency::CZK);
$this->orm->persistAndFlush($book);

$books2 = $this->orm->books->findBy(['price->cents>=' => 1000]);
Expand Down
8 changes: 4 additions & 4 deletions tests/cases/integration/Collection/collection.where.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -98,25 +98,25 @@ class CollectionWhereTest extends DataTestCase

public function testFilterByPropertyWrapper(): void
{
$ean8 = new Ean(EanType::EAN8());
$ean8 = new Ean(EanType::EAN8);
$ean8->code = '123';
$ean8->book = $this->orm->books->getByIdChecked(1);
$this->orm->persist($ean8);

$ean13 = new Ean(EanType::EAN13());
$ean13 = new Ean(EanType::EAN13);
$ean13->code = '456';
$ean13->book = $this->orm->books->getByIdChecked(2);
$this->orm->persistAndFlush($ean13);

Assert::count(2, $this->orm->eans->findAll());

$eans = $this->orm->eans->findBy(['type' => EanType::EAN8()]);
$eans = $this->orm->eans->findBy(['type' => EanType::EAN8]);
Assert::count(1, $eans);
$fetched = $eans->fetch();
Assert::notNull($fetched);
Assert::equal('123', $fetched->code);

$eans = $this->orm->eans->findBy(['type' => EanType::EAN13()]);
$eans = $this->orm->eans->findBy(['type' => EanType::EAN13]);
Assert::count(1, $eans);
$fetched = $eans->fetch();
Assert::notNull($fetched);
Expand Down
14 changes: 7 additions & 7 deletions tests/cases/integration/Entity/entity.embeddable.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ class EntityEmbeddableTest extends DataTestCase
public function testBasic(): void
{
$book = $this->orm->books->getByIdChecked(1);
$book->price = new Money(1000, Currency::CZK());
$book->price = new Money(1000, Currency::CZK);
Assert::same(1000, $book->price->cents);
Assert::same(Currency::CZK(), $book->price->currency);
Assert::same(Currency::CZK, $book->price->currency);

$this->orm->persistAndFlush($book);
$this->orm->clear();
Expand All @@ -36,7 +36,7 @@ class EntityEmbeddableTest extends DataTestCase

Assert::notNull($book->price);
Assert::same(1000, $book->price->cents);
Assert::same(Currency::CZK(), $book->price->currency);
Assert::same(Currency::CZK, $book->price->currency);

$book->price = null;
$this->orm->persistAndFlush($book);
Expand All @@ -50,8 +50,8 @@ class EntityEmbeddableTest extends DataTestCase
public function testMultiple(): void
{
$book = $this->orm->books->getByIdChecked(1);
$book->price = new Money(1000, Currency::CZK());
$book->origPrice = new Money(330, Currency::EUR());
$book->price = new Money(1000, Currency::CZK);
$book->origPrice = new Money(330, Currency::EUR);

$this->orm->persistAndFlush($book);
$this->orm->clear();
Expand All @@ -73,7 +73,7 @@ class EntityEmbeddableTest extends DataTestCase
Assert::throws(function (): void {
$book = new Book();
// @phpstan-ignore-next-line
$book->price = (object) ['price' => 100, 'currency' => Currency::CZK()];
$book->price = (object) ['price' => 100, 'currency' => Currency::CZK];
}, InvalidArgumentException::class);
}

Expand All @@ -82,7 +82,7 @@ class EntityEmbeddableTest extends DataTestCase
{
$book = $this->orm->books->getByIdChecked(1);

$book->price = new Money(1000, Currency::CZK());
$book->price = new Money(1000, Currency::CZK);
Assert::same(1000, $book->price->cents);

$book->price = null;
Expand Down
6 changes: 6 additions & 0 deletions tests/cases/integration/Entity/entity.nullValidation.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use Nextras\Orm\Exception\InvalidArgumentException;
use Nextras\Orm\Exception\InvalidStateException;
use Nextras\Orm\Exception\NullValueException;
use NextrasTests\Orm\Book;
use NextrasTests\Orm\Ean;
use NextrasTests\Orm\TestCase;
use Tester\Assert;

Expand All @@ -32,6 +33,11 @@ class EntityNullValidationTest extends TestCase
$book->author = null; // @phpstan-ignore-line
}, NullValueException::class, 'Property NextrasTests\Orm\Book::$author is not nullable.');

Assert::throws(function (): void {
$ean = new Ean();
$ean->type = null; // @phpstan-ignore-line
}, NullValueException::class, 'Property NextrasTests\Orm\Ean::$type is not nullable.');

$book = new Book();
$book->translator = null;
}
Expand Down
4 changes: 2 additions & 2 deletions tests/cases/unit/Collection/FetchPairsHelperTest.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -175,11 +175,11 @@ class FetchPairsHelperTest extends TestCase
$data = new ArrayIterator([
$this->e(
Book::class,
['price' => new Money(100, Currency::CZK())]
['price' => new Money(100, Currency::CZK)]
),
$this->e(
Book::class,
['price' => new Money(200, Currency::CZK())]
['price' => new Money(200, Currency::CZK)]
),
]);
Assert::same(
Expand Down
Loading

0 comments on commit 63eae38

Please sign in to comment.