Skip to content

Commit

Permalink
refactor and decompose builders, allow extending, add examples
Browse files Browse the repository at this point in the history
  • Loading branch information
klkvsk committed Feb 21, 2023
1 parent 3dcf48e commit b77bb1a
Show file tree
Hide file tree
Showing 34 changed files with 1,884 additions and 373 deletions.
12 changes: 12 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Path-based git attributes
# https://www.kernel.org/pub/software/scm/git/docs/gitattributes.html

# Ignore all test and documentation with "export-ignore".
/.gitattributes export-ignore
/.gitignore export-ignore
/.editorconfig export-ignore
/.php-cs-fixer.php export-ignore
/psalm.xml export-ignore
/phpunit.xml export-ignore
/tests export-ignore
/example export-ignore
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,10 @@ Closure of type `importer` is predefined for all types except `t\object`:
dto\field('file', t\external(SplFileInfo::class, fn ($x) => new SplFileInfo($x))
```

## Example

See [/example/](./example) dir for the example schema and generated classes
for different PHP versions.

## License
The MIT License (MIT). Please see [License File](LICENSE.md) for more information.
The MIT License (MIT). Please see [License File](./LICENSE) for more information.
13 changes: 13 additions & 0 deletions example/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
all: gen-php7.4 gen-php8.0 gen-php8.1

gen-php7.4: dto.schema.php
OUTPUT_DIR=php7.4 ../bin/dto-gen --target 7.4

gen-php8.0: dto.schema.php
OUTPUT_DIR=php8.0 ../bin/dto-gen --target 8.0

gen-php8.1: dto.schema.php
OUTPUT_DIR=php8.1 ../bin/dto-gen --target 8.1

clean:
rm -r php*
29 changes: 15 additions & 14 deletions example/dto.schema.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,26 @@
use Klkvsk\DtoGenerator\Schema as dto;
use Klkvsk\DtoGenerator\Schema\Types as t;

$outputDir = getenv('OUTPUT_DIR') ?: null;
if ($outputDir) {
$outputDir = __DIR__ . DIRECTORY_SEPARATOR . $outputDir;
}

return dto\schema(
namespace: 'Klkvsk\\DtoGenerator\\Example\\One',
outputDir: $outputDir,
objects: [
$genre = dto\enum(
dto\enum(
name: 'Genre',
cases: [
'romance',
'comedy',
'drama',
'non-fiction',
],
enumKeys: dto\EnumValues::CONST,
backedType: 'string'
'scientific-work'
]
),
$author = dto\object(
dto\object(
name: 'Author',
fields: [
dto\field('id', t\int(), required: true),
Expand All @@ -30,26 +35,22 @@ enumKeys: dto\EnumValues::CONST,
),
]
),
$book = dto\object(
dto\object(
name: 'Book',
fields: [
dto\field('id', t\int(), required: true),
dto\field('title', t\string(), required: true),
dto\field('released', t\date()),
dto\field('genre', t\enum($genre)),
dto\field('genres', t\list_(t\enum($genre))),
dto\field('author', t\object('Author'), required: true),
dto\field('references', t\list_(t\object('Book'))),
dto\field('rating', t\int(), default: 5),
dto\field('subDto', t\object('Foo\\SubDto')),
dto\field('genres', t\list_(t\enum('Genre'))),
]
),

dto\object(
name: 'Foo\SubDto',
name: 'ScienceBook',
extends: 'Book',
fields: [
dto\field('id', t\int(), required: true),
dto\field('author', t\object('Author'), required: true),
dto\field('references', t\list_(t\object('ScienceBook'))),
]
),
],
Expand Down
94 changes: 94 additions & 0 deletions example/php7.4/Author.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<?php
declare(strict_types=1);

namespace Klkvsk\DtoGenerator\Example\One;

/**
* This class is auto-generated with klkvsk/dto-generator
* Do not modify it, any changes might be overwritten!
*
* @see project://example/dto.schema.php (line 25)
*
* @link https://github.com/klkvsk/dto-generator
* @link https://packagist.org/klkvsk/dto-generator
*/
class Author
{
protected int $id;
protected string $firstName;
protected ?string $lastName;

public function __construct(int $id, string $firstName, ?string $lastName = null)
{
$this->id = $id;
$this->firstName = $firstName;
$this->lastName = $lastName;
}

public function getId(): int
{
return $this->id;
}

public function getFirstName(): string
{
return $this->firstName;
}

public function getLastName(): ?string
{
return $this->lastName;
}

protected static function required(): array
{
return ['id', 'firstName'];
}

protected static function processors(string $key): \Generator
{
switch ($key) {
case "id":
yield 'importer' => \Closure::fromCallable('intval');
break;

case "firstName":
yield 'filter' => fn ($x) => \trim($x);
yield 'filter' => \Closure::fromCallable('strval');
yield 'importer' => \Closure::fromCallable('strval');
break;

case "lastName":
yield 'filter' => fn ($x) => \trim($x);
yield 'importer' => \Closure::fromCallable('strval');
yield 'validator' => fn ($x) => \strlen($x) > 2;
break;
}
}

public static function create(array $data): self
{
// check required
if ($diff = array_diff(array_keys($data), self::required())) {
throw new \InvalidArgumentException("missing keys: " . implode(", ", $diff));
}

// process
foreach ($data as $key => &$value) {
foreach (self::processors($key) as $type => $processor) if ($value !== null) {
if ($type === "validator" && call_user_func($processor, $value) === false) {
throw new \InvalidArgumentException("invalid value at key: $key");
} else {
$value = call_user_func($processor, $value);
}
}
}

// create
return new self(
$data['id'],
$data['firstName'],
$data['lastName'],
);
}
}
146 changes: 146 additions & 0 deletions example/php7.4/Book.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
<?php
declare(strict_types=1);

namespace Klkvsk\DtoGenerator\Example\One;

/**
* This class is auto-generated with klkvsk/dto-generator
* Do not modify it, any changes might be overwritten!
*
* @see project://example/dto.schema.php (line 38)
*
* @link https://github.com/klkvsk/dto-generator
* @link https://packagist.org/klkvsk/dto-generator
*/
class Book
{
protected int $id;
protected string $title;
protected Author $author;
protected ?\DateTimeInterface $released;
protected ?int $rating;

/** @var list<Genre> $genres */
protected array $genres;

public function __construct(
int $id,
string $title,
Author $author,
?\DateTimeInterface $released = null,
?int $rating = 5,
array $genres = [],
) {
$this->id = $id;
$this->title = $title;
$this->author = $author;
$this->released = $released;
$this->rating = $rating;
(function(Genre ...$_) {})( ...$genres);
$this->genres = $genres;
}

public function getId(): int
{
return $this->id;
}

public function getTitle(): string
{
return $this->title;
}

public function getAuthor(): Author
{
return $this->author;
}

public function getReleased(): ?\DateTimeInterface
{
return $this->released;
}

public function getRating(): ?int
{
return $this->rating;
}

/**
* @return list<Genre>
*/
public function getGenres(): array
{
return $this->genres;
}

protected static function defaults(): array
{
return ['rating' => 5];
}

protected static function required(): array
{
return ['id', 'title', 'author'];
}

protected static function processors(string $key): \Generator
{
switch ($key) {
case "id":
case "rating":
yield 'importer' => \Closure::fromCallable('intval');
break;

case "title":
yield 'importer' => \Closure::fromCallable('strval');
break;

case "author":
yield 'importer' => fn (array $data) => call_user_func([ '\Klkvsk\DtoGenerator\Example\One\Author', 'create' ]);
break;

case "released":
yield 'importer' => static fn ($d) => new \DateTimeImmutable($d, null);
break;

case "genres":
yield 'importer' => fn ($array) => array_map(
fn (array $data) => call_user_func([ '\Klkvsk\DtoGenerator\Example\One\Genre', 'from' ]),
(array)$array
);
break;
}
}

public static function create(array $data): self
{
// defaults
$data += self::defaults();

// check required
if ($diff = array_diff(array_keys($data), self::required())) {
throw new \InvalidArgumentException("missing keys: " . implode(", ", $diff));
}

// process
foreach ($data as $key => &$value) {
foreach (self::processors($key) as $type => $processor) if ($value !== null) {
if ($type === "validator" && call_user_func($processor, $value) === false) {
throw new \InvalidArgumentException("invalid value at key: $key");
} else {
$value = call_user_func($processor, $value);
}
}
}

// create
return new self(
$data['id'],
$data['title'],
$data['author'],
$data['released'],
$data['rating'],
$data['genres'],
);
}
}
Loading

0 comments on commit b77bb1a

Please sign in to comment.