Skip to content

Commit

Permalink
Merge pull request #27 from sunrise-php/release/v3.1.0
Browse files Browse the repository at this point in the history
v3.1.0
  • Loading branch information
fenric authored Sep 29, 2023
2 parents e480915 + cf6be1f commit 6c9276d
Show file tree
Hide file tree
Showing 41 changed files with 2,135 additions and 709 deletions.
54 changes: 51 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ composer require sunrise/hydrator
* * [String](#string)
* * [Array](#array)
* * [Timestamp](#timestamp)
* * [Timezone](#timezone)
* * [UID](#uid)
* * [Enumeration](#enumeration)
* * [Relationship](#relationship)
* [Ignored property](#ignored-property)
Expand Down Expand Up @@ -68,7 +70,7 @@ final class Product
public function __construct(
public readonly string $name,
public readonly Category $category,
#[\Sunrise\Hydrator\Annotation\Relationship(Tag::class, limit: 100)]
#[\Sunrise\Hydrator\Annotation\Subtype(Tag::class, limit: 100)]
public readonly array $tags,
public readonly Status $status = Status::DISABLED,
#[\Sunrise\Hydrator\Annotation\Format(\DATE_RFC3339)]
Expand Down Expand Up @@ -207,17 +209,41 @@ public readonly array $value;
By default, this property accepts an array with any data. However, it can also be used to store relationships by using a special annotation, as shown in the example below:

```php
#[\Sunrise\Hydrator\Annotation\Relationship(SomeDto::class)]
#[\Sunrise\Hydrator\Annotation\Subtype(SomeDto::class)]
public readonly array $value;
```

Having an unlimited number of relationships in an array is a potentially bad idea as it can lead to memory leaks. To avoid this, it is recommended to limit such an array, as shown in the example below:

```php
#[\Sunrise\Hydrator\Annotation\Relationship(SomeDto::class, limit: 100)]
#[\Sunrise\Hydrator\Annotation\Subtype(SomeDto::class, limit: 100)]
public readonly array $value;
```

In addition to arrays, you can use collections, i.e. objects implementing the [ArrayAccess](http://php.net/ArrayAccess) interface, for example:

```php
final class TagCollection implements ArrayAccess
{
// some code...
}
```

```php
final class CreateProductDto
{
public readonly TagCollection $tags;
}
```

Additionally, you can type the elements of such an array or collection, like this:

```php
#[\Sunrise\Hydrator\Annotation\Subtype(DateTimeImmutable::class, limit: 100)]
#[\Sunrise\Hydrator\Annotation\Format('Y-m-d H:i:s')]
public readonly array $tags;
```

This property has no any additional behavior and only accepts arrays.

### Timestamp
Expand All @@ -238,6 +264,28 @@ public readonly DateTimeImmutable $value;

Also, please note that if a value in a dataset for this property is represented as an empty string or a string consisting only of whitespace, then the value will be handled as [null](#null).

### Timezone

Only the DateTimeZone type is supported.

```php
public readonly DateTimeZone $value;
```

Also, please note that if a value in a dataset for this property is represented as an empty string or a string consisting only of whitespace, then the value will be handled as [null](#null).

### UID

```bash
composer require symfony/uid
```

```php
public readonly \Symfony\Component\Uid\UuidV4 $value;
```

Also, please note that if a value in a dataset for this property is represented as an empty string or a string consisting only of whitespace, then the value will be handled as [null](#null).

### Enumeration

```php
Expand Down
5 changes: 3 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,11 @@
"require-dev": {
"sunrise/coding-standard": "~1.0.0",
"phpunit/phpunit": "^9.6",
"vimeo/psalm": "^5.12",
"vimeo/psalm": "^5.15",
"phpstan/phpstan": "^1.10",
"doctrine/annotations": "^2.0",
"symfony/validator": "^5.4"
"symfony/validator": "^5.4",
"symfony/uid": "^5.4"
},
"autoload": {
"psr-4": {
Expand Down
1 change: 1 addition & 0 deletions psalm.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
phpVersion="8.2"
>
<projectFiles>
<directory name="src" />
Expand Down
2 changes: 2 additions & 0 deletions src/Annotation/Alias.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ final class Alias
* The attribute value
*
* @var non-empty-string
*
* @readonly
*/
public string $value;

Expand Down
2 changes: 2 additions & 0 deletions src/Annotation/Format.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ final class Format
* The attribute value
*
* @var non-empty-string
*
* @readonly
*/
public string $value;

Expand Down
30 changes: 6 additions & 24 deletions src/Annotation/Relationship.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,35 +21,17 @@
* @NamedArgumentConstructor
*
* @Attributes({
* @Attribute("target", type="string", required=true),
* @Attribute("name", type="string", required=true),
* @Attribute("limit", type="integer", required=false),
* })
*
* @since 3.0.0
*
* @deprecated 3.1.0 Use the {@see Subtype} annotation.
*
* @psalm-suppress InvalidExtendClass
*/
#[Attribute(Attribute::TARGET_PROPERTY)]
final class Relationship
final class Relationship extends Subtype
{

/**
* @var class-string
*/
public string $target;

/**
* @var int<1, max>|null
*/
public ?int $limit;

/**
* Constructor of the class
*
* @param class-string $target
* @param int<1, max>|null $limit
*/
public function __construct(string $target, ?int $limit = null)
{
$this->target = $target;
$this->limit = $limit;
}
}
61 changes: 61 additions & 0 deletions src/Annotation/Subtype.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

/**
* It's free open-source software released under the MIT License.
*
* @author Anatoly Nekhay <[email protected]>
* @copyright Copyright (c) 2021, Anatoly Nekhay
* @license https://github.com/sunrise-php/hydrator/blob/master/LICENSE
* @link https://github.com/sunrise-php/hydrator
*/

declare(strict_types=1);

namespace Sunrise\Hydrator\Annotation;

use Attribute;

/**
* @Annotation
* @Target({"PROPERTY"})
* @NamedArgumentConstructor
*
* @Attributes({
* @Attribute("name", type="string", required=true),
* @Attribute("limit", type="integer", required=false),
* })
*
* @final See the {@see Relationship} class.
*
* @since 3.1.0
*/
#[Attribute(Attribute::TARGET_PROPERTY)]
class Subtype
{

/**
* @var non-empty-string
*
* @readonly
*/
public string $name;

/**
* @var int<0, max>|null
*
* @readonly
*/
public ?int $limit;

/**
* Constructor of the class
*
* @param non-empty-string $name
* @param int<0, max>|null $limit
*/
public function __construct(string $name, ?int $limit = null)
{
$this->name = $name;
$this->limit = $limit;
}
}
60 changes: 60 additions & 0 deletions src/AnnotationReader.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

/**
* It's free open-source software released under the MIT License.
*
* @author Anatoly Nekhay <[email protected]>
* @copyright Copyright (c) 2021, Anatoly Nekhay
* @license https://github.com/sunrise-php/hydrator/blob/master/LICENSE
* @link https://github.com/sunrise-php/hydrator
*/

declare(strict_types=1);

namespace Sunrise\Hydrator;

use Generator;
use LogicException;
use ReflectionAttribute;
use ReflectionProperty;

use function sprintf;

use const PHP_MAJOR_VERSION;

/**
* @since 3.1.0
*/
final class AnnotationReader implements AnnotationReaderInterface
{

/**
* Constructor of the class
*
* @throws LogicException If PHP version less than 8.0.
*/
public function __construct()
{
if (PHP_MAJOR_VERSION < 8) {
throw new LogicException(sprintf(
'The annotation reader {%s} requires PHP version greater than or equal to 8.0.',
__CLASS__,
));
}
}

/**
* @inheritDoc
*/
public function getAnnotations(ReflectionProperty $target, string $name): Generator
{
if (PHP_MAJOR_VERSION < 8) {
return;
}

$attributes = $target->getAttributes($name, ReflectionAttribute::IS_INSTANCEOF);
foreach ($attributes as $attribute) {
yield $attribute->newInstance();
}
}
}
30 changes: 30 additions & 0 deletions src/AnnotationReaderAwareInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

/**
* It's free open-source software released under the MIT License.
*
* @author Anatoly Nekhay <[email protected]>
* @copyright Copyright (c) 2021, Anatoly Nekhay
* @license https://github.com/sunrise-php/hydrator/blob/master/LICENSE
* @link https://github.com/sunrise-php/hydrator
*/

declare(strict_types=1);

namespace Sunrise\Hydrator;

/**
* @since 3.1.0
*/
interface AnnotationReaderAwareInterface
{

/**
* Sets the given annotation reader
*
* @param AnnotationReaderInterface $annotationReader
*
* @return void
*/
public function setAnnotationReader(AnnotationReaderInterface $annotationReader): void;
}
36 changes: 36 additions & 0 deletions src/AnnotationReaderInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

/**
* It's free open-source software released under the MIT License.
*
* @author Anatoly Nekhay <[email protected]>
* @copyright Copyright (c) 2021, Anatoly Nekhay
* @license https://github.com/sunrise-php/hydrator/blob/master/LICENSE
* @link https://github.com/sunrise-php/hydrator
*/

declare(strict_types=1);

namespace Sunrise\Hydrator;

use Generator;
use ReflectionProperty;

/**
* @since 3.1.0
*/
interface AnnotationReaderInterface
{

/**
* Gets annotations from the given target by the given annotation name
*
* @param ReflectionProperty $target
* @param class-string<T> $name
*
* @return Generator<mixed, T>
*
* @template T of object
*/
public function getAnnotations(ReflectionProperty $target, string $name): Generator;
}
28 changes: 28 additions & 0 deletions src/Dictionary/BuiltinType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

/**
* It's free open-source software released under the MIT License.
*
* @author Anatoly Nekhay <[email protected]>
* @copyright Copyright (c) 2021, Anatoly Nekhay
* @license https://github.com/sunrise-php/hydrator/blob/master/LICENSE
* @link https://github.com/sunrise-php/hydrator
*/

declare(strict_types=1);

namespace Sunrise\Hydrator\Dictionary;

/**
* Built-in types
*
* @since 3.1.0
*/
final class BuiltinType
{
public const BOOL = 'bool';
public const INT = 'int';
public const FLOAT = 'float';
public const STRING = 'string';
public const ARRAY = 'array';
}
Loading

0 comments on commit 6c9276d

Please sign in to comment.