Commit fb812424 authored by Guillaume Perréal's avatar Guillaume Perréal
Browse files

Rends explicite la création de types en deux étapes.

parent d3e24168
......@@ -29,7 +29,6 @@ use Irstea\NgModelGeneratorBundle\Metadata\ResourceMetadata;
use Irstea\NgModelGeneratorBundle\Models\ClassName;
use Irstea\NgModelGeneratorBundle\Models\Declaration;
use Irstea\NgModelGeneratorBundle\Models\PHPClass;
use Irstea\NgModelGeneratorBundle\Models\Types\Alias;
use Irstea\NgModelGeneratorBundle\Models\Types\BuiltinType;
use Irstea\NgModelGeneratorBundle\Models\Types\Objects\InterfaceType;
use Irstea\NgModelGeneratorBundle\Models\Types\Objects\Property;
......@@ -192,24 +191,11 @@ final class ModelGenerator
$factory = new TypeFactory();
foreach (['Array', 'boolean', 'number', 'null', 'string', 'any', 'never'] as $builtin) {
$factory->addBuiltin($builtin);
$factory->add($builtin, BuiltinType::get($builtin));
}
$factory->getOrCreate(
'DateTime',
function () {
return new Alias('DateTime', BuiltinType::get('string'));
}
);
$factory->getOrCreate('UUID', [UUID::class, 'get']);
$factory->getOrCreate(
'CommonFilters',
function (): Type {
return $this->createCommonFilters('CommonFilters');
}
);
$factory->add('UUID', UUID::get());
$factory->add('CommonFilters', $this->createCommonFilters('CommonFilters'));
foreach ([
PHPType::BUILTIN_TYPE_ARRAY => 'Array',
......@@ -219,10 +205,14 @@ final class ModelGenerator
PHPType::BUILTIN_TYPE_NULL => 'null',
PHPType::BUILTIN_TYPE_STRING => 'string',
'Ramsey\Uuid\UuidInterface' => 'UUID',
'DateTime' => 'string',
'DateTimeInterface' => 'DateTime',
'DateTimeImmutable' => 'DateTime',
] as $alias => $target) {
$factory->addAlias($alias, $target);
if ($target === $alias || $factory->has($alias)) {
continue;
}
$factory->add($alias, $factory->get($target));
}
return $factory;
......
<?php declare(strict_types=1);
/*
* irstea/ng-model-generator-bundle generates Typescript interfaces for Angular using api-platform metadata.
* Copyright (C) 2018 IRSTEA
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License and the GNU
* Lesser General Public License along with this program. If not, see
* <https://www.gnu.org/licenses/>.
*/
namespace Irstea\NgModelGeneratorBundle\Models\Types;
/**
* Interface Deferred.
*/
interface Deferred extends Type
{
/**
* @param callable $callback
*/
public function resolveWith(callable $callback): Type;
/**
* @param Type $result
*/
public function resolve(Type $result): Type;
}
......@@ -19,24 +19,33 @@
namespace Irstea\NgModelGeneratorBundle\Models\Types;
use Irstea\NgModelGeneratorBundle\Models\Declaration;
/**
* Class Ref.
*/
class Reference extends AbstractType
class Reference extends AbstractType implements Deferred
{
private const UNRESOLVED = 0;
private const RESOLVING = 1;
private const RESOLVED = 2;
/** @var Type */
private $target;
/** @var string */
private $name;
/** @var bool */
private $state = self::UNRESOLVED;
/**
* Reference constructor.
*
* @param Type|null $target
* @param string $name
*/
public function __construct(Type $target = null)
public function __construct(string $name = 'anonymous reference')
{
$this->target = $target ?: Unresolved::get();
$this->name = $name;
$this->target = Unresolved::get();
}
/**
......@@ -50,13 +59,33 @@ class Reference extends AbstractType
}
/**
* Set target.
*
* @param Type $target
* {@inheritdoc}
*/
public function resolveWith(callable $callback): Type
{
switch ($this->state) {
case self::UNRESOLVED:
$this->state = self::RESOLVING;
return $this->resolve($callback());
case self::RESOLVING:
return $this;
case self::RESOLVED:
return $this->target;
}
}
/**
* {@inheritdoc}
*/
public function setTarget(Type $target)
public function resolve(Type $result): Type
{
$this->target = $target;
if ($this->state !== self::RESOLVED) {
$this->state = self::RESOLVED;
$this->target = $result;
}
return $this->target;
}
/**
......@@ -104,11 +133,7 @@ class Reference extends AbstractType
*/
public function jsonSerialize()
{
if ($this->target instanceof Declaration) {
return $this->target->getName();
}
return $this->target;
return \spl_object_hash($this);
}
/**
......@@ -116,7 +141,7 @@ class Reference extends AbstractType
*/
public function __toString()
{
return '&' . $this->target;
return '&' . $this->name;
}
/**
......
......@@ -29,6 +29,7 @@ use Irstea\NgModelGeneratorBundle\Models\PHPClass;
use Irstea\NgModelGeneratorBundle\Models\Types\Alias;
use Irstea\NgModelGeneratorBundle\Models\Types\ArrayType;
use Irstea\NgModelGeneratorBundle\Models\Types\BuiltinType;
use Irstea\NgModelGeneratorBundle\Models\Types\Deferred;
use Irstea\NgModelGeneratorBundle\Models\Types\Objects\Property;
use Irstea\NgModelGeneratorBundle\Models\Types\Reference;
use Irstea\NgModelGeneratorBundle\Models\Types\Resources\IRI;
......@@ -83,49 +84,39 @@ final class SerializationMapper implements TypeFactoryInterface
/**
* {@inheritdoc}
*/
public function getOrCreate(string $name, callable $builder, ...$args): Type
public function add(string $name, Type $type): void
{
return $this->typeFactory->getOrCreate($name, $builder, ...$args);
$this->typeFactory->add($name, $type);
}
/**
* {@inheritdoc}
*/
public function get(string $name): Type
public function defer(string $name): Deferred
{
if (!class_exists($name)) {
return $this->typeFactory->get($name);
}
$class = PHPClass::get($name);
if ($this->serialization->hasRepresentationOf($class)) {
$repr = $this->serialization->getRepresentationOf($class);
return $this->getOrCreate(
$repr->getName(),
function () use ($repr) {
return $this->mapRepresentation($repr);
}
);
}
return $this->getOrCreate($name, [$this, 'get'], 'any');
return $this->typeFactory->defer($name);
}
/**
* {@inheritdoc}
*/
public function addBuiltin(string $name): void
public function get(string $name): Type
{
$this->typeFactory->addBuiltin($name);
}
if (class_exists($name)) {
$class = PHPClass::get($name);
if ($this->serialization->hasRepresentationOf($class)) {
$repr = $this->serialization->getRepresentationOf($class);
return $this->defer($repr->getName())
->resolveWith(
function () use ($repr) {
return $this->mapRepresentation($repr);
}
);
}
}
/**
* {@inheritdoc}
*/
public function addAlias(string $alias, string $target): void
{
$this->typeFactory->addAlias($alias, $target);
return $this->typeFactory->get($name);
}
/**
......
......@@ -21,9 +21,7 @@ namespace Irstea\NgModelGeneratorBundle;
use Irstea\NgModelGeneratorBundle\Exceptions\TypeAlreadyExistsException;
use Irstea\NgModelGeneratorBundle\Exceptions\TypeNotFoundException;
use Irstea\NgModelGeneratorBundle\Models\Types\BuiltinType;
use Irstea\NgModelGeneratorBundle\Models\Types\Generics\GenericDef;
use Irstea\NgModelGeneratorBundle\Models\Types\Generics\GenericRef;
use Irstea\NgModelGeneratorBundle\Models\Types\Deferred;
use Irstea\NgModelGeneratorBundle\Models\Types\Reference;
use Irstea\NgModelGeneratorBundle\Models\Types\Type;
......@@ -79,42 +77,27 @@ final class TypeFactory implements TypeFactoryInterface, \IteratorAggregate
/**
* {@inheritdoc}
*/
public function getOrCreate(string $name, callable $builder, ...$args): Type
public function add(string $name, Type $type): void
{
if (isset($this->types[$name])) {
return $this->types[$name];
throw new TypeAlreadyExistsException("type already exists: ${name}");
}
$this->types[$name] = $ref = new Reference();
$ref->setTarget($builder(...$args));
return $ref;
$this->types[$name] = $type;
}
/**
* {@inheritdoc}
*/
public function addBuiltin(string $name): void
public function defer(string $name): Deferred
{
if (isset($this->types[$name])) {
throw new TypeAlreadyExistsException("builtin type already exists: ${name}");
}
$this->types[$name] = BuiltinType::get($name);
}
/**
* {@inheritdoc}
*/
public function addAlias(string $alias, string $target): void
{
if (isset($this->types[$alias])) {
return;
}
if (!isset($this->types[$target])) {
throw new TypeNotFoundException("alias target does not exist: ${target}");
if (isset($this->types[$name]) && $this->types[$name] instanceof Deferred) {
/* @noinspection PhpIncompatibleReturnTypeInspection */
return $this->types[$name];
}
$ref = new Reference($name);
$this->add($name, $ref);
$this->types[$alias] = $this->types[$target];
return $ref;
}
}
......@@ -19,6 +19,7 @@
namespace Irstea\NgModelGeneratorBundle;
use Irstea\NgModelGeneratorBundle\Models\Types\Deferred;
use Irstea\NgModelGeneratorBundle\Models\Types\Type;
/**
......@@ -41,22 +42,15 @@ interface TypeFactoryInterface
public function get(string $name): Type;
/**
* @param string $name
* @param callable $builder
* @param mixed ...$args
* @param string $name
*
* @return Type
*/
public function getOrCreate(string $name, callable $builder, ...$args): Type;
public function defer(string $name): Deferred;
/**
* @param string $name
* @param Type $type
*/
public function addBuiltin(string $name): void;
/**
* @param string $alias
* @param string $target
*/
public function addAlias(string $alias, string $target): void;
public function add(string $name, Type $type): void;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment