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

Refactoring de Path.

Un Path est la concaténation de une ou plusieurs PathPart, dont certaines
sont des chaînes fixes et d'autres sont des paramètres.
Showing with 355 additions and 86 deletions
+355 -86
......@@ -19,63 +19,69 @@
namespace Irstea\NgModelGeneratorBundle\Models\Types\Operations;
use Irstea\NgModelGeneratorBundle\TypescriptHelper;
/**
* Class PlainPath.
* Class FixedPathPart.
*/
class PlainPath implements Path, \JsonSerializable
final class FixedPathPart implements PathPart
{
/** @var string */
private $path;
/**
* @var string
*/
private $part;
/**
* PlainPath constructor.
*
* @param string $path
* FixedPathPart constructor.
*/
public function __construct(string $path)
public function __construct(string $part)
{
$this->path = $path;
$this->part = $part;
}
/**
* {@inheritdoc}
*/
public function getUsage(): string
public function asTemplate(): string
{
return TypescriptHelper::quoteString($this->path);
return $this->part;
}
/**
* {@inheritdoc}
*/
public function getParameters(): array
public function asTestPattern(): string
{
return [];
return \preg_quote($this->part, '/');
}
/**
* {@inheritdoc}
*/
public function getPattern(): string
public function asCapturePattern(): string
{
return preg_quote($this->path, '/');
return $this->asTestPattern();
}
/**
* @return Parameter|null
* {@inheritdoc}
*/
public function getIdentifier(): ?Parameter
public function getParameter(): ?Parameter
{
return null;
}
/**
* @return mixed|string
* {@inheritdoc}
*/
public function isEqual(PathPart $other): bool
{
return $other instanceof self && $other->part === $this->part;
}
/**
* @return array
*/
public function jsonSerialize()
{
return $this->path;
return \get_object_vars($this);
}
}
......@@ -89,15 +89,29 @@ class Parameter implements \IteratorAggregate, \JsonSerializable
yield $this->type;
}
/**
* @param self $other
*
* @return bool
*/
public function isEqual(self $other): bool
{
/* @noinspection TypeUnsafeComparisonInspection */
return $other instanceof self &&
$other->name === $this->name &&
$other->optional === $this->optional &&
$other->type == $this->type;
}
/**
* @return array|mixed
*/
public function jsonSerialize()
{
return [
'name' => $this->name,
'type' => $this->type,
'required' => !$this->optional,
'name' => $this->name,
'type' => $this->type,
'required' => !$this->optional,
];
}
}
......@@ -19,87 +19,83 @@
namespace Irstea\NgModelGeneratorBundle\Models\Types\Operations;
use Irstea\NgModelGeneratorBundle\Exceptions\DomainException;
use Irstea\NgModelGeneratorBundle\TypescriptHelper;
/**
* Class PathTemplate.
* Class ParameterPathPart.
*/
class PathTemplate implements Path, \JsonSerializable
final class ParameterPathPart implements PathPart
{
/** @var string */
private $template;
/** @var string */
private $pattern;
/** @var Parameter[] */
private $parameters = [];
/**
* @var Parameter
*/
private $parameter;
/** @var string|null */
private $identifierName;
/**
* @var string
*/
private $requirement;
/**
* PathTemplate constructor.
* ParameterPathPart constructor.
*
* @param string $template
* @param string $pattern
* @param Parameter[] $parameters
* @param string|null $identifierName
* @param Parameter $parameter
* @param string $requirement
*/
public function __construct(string $template, string $pattern, array $parameters, ?string $identifierName)
public function __construct(Parameter $parameter, string $requirement = '[^/]+')
{
$this->template = $template;
$this->pattern = $pattern;
$this->identifierName = $identifierName;
$this->parameter = $parameter;
$this->requirement = $requirement;
}
foreach ($parameters as $parameter) {
$this->parameters[$parameter->getName()] = $parameter;
}
/**
* {@inheritdoc}
*/
public function asTemplate(): string
{
return sprintf('${%s}', $this->parameter->getName());
}
if ($identifierName && !isset($this->parameters[$identifierName])) {
throw new DomainException("L'identifiant $identifierName n'est pas dans la liste des paramètres");
}
/**
* {@inheritdoc}
*/
public function asTestPattern(): string
{
return $this->requirement;
}
/**
* Get template.
*
* @return string
* {@inheritdoc}
*/
public function getUsage(): string
public function asCapturePattern(): string
{
return TypescriptHelper::quoteString($this->template, '`');
return sprintf('(%s)', $this->requirement);
}
/**
* {@inheritdoc}
*/
public function getPattern(): string
public function getParameter(): ?Parameter
{
return $this->pattern;
return $this->parameter;
}
/**
* Get parameters.
*
* @return Parameter[]
* {@inheritdoc}
*/
public function getParameters(): array
public function isEqual(PathPart $other): bool
{
return $this->parameters;
return $other instanceof self && $other->parameter->isEqual($this->parameter);
}
/**
* @return Parameter|null
* @return \Generator
*/
public function getIdentifier(): ?Parameter
public function getIterator()
{
return $this->identifierName ? $this->parameters[$this->identifierName] : null;
yield $this->parameter;
}
/**
* @return mixed|array
* @return array
*/
public function jsonSerialize()
{
......
......@@ -19,28 +19,157 @@
namespace Irstea\NgModelGeneratorBundle\Models\Types\Operations;
use Irstea\NgModelGeneratorBundle\TypescriptHelper;
/**
* Interface Path.
* Class Path.
*/
interface Path
final class Path
{
/**
* @var PathPart[]
*/
private $parts;
/**
* Path constructor.
*
* @param PathPart[] $parts
*/
public function __construct(array $parts)
{
$this->parts = $parts;
}
/**
* @return string
*/
public function getUsage(): string
{
return TypescriptHelper::quoteString(
$this->getTemplate(),
$this->hasParameters() ? '`' : "'"
);
}
/**
* @return string
*/
public function getTemplate(): string
{
return implode(
'',
array_map(
function (PathPart $part): string {
return $part->asTemplate();
},
$this->parts
)
);
}
/**
* @return string
*/
public function getUsage(): string;
public function getTestPattern(): string
{
return implode(
'',
array_map(
function (PathPart $part): string {
return $part->asTestPattern();
},
$this->parts
)
);
}
/**
* @return string
*/
public function getPattern(): string;
public function getCapturePattern(): string
{
return implode(
'',
array_map(
function (PathPart $part): string {
return $part->asCapturePattern();
},
$this->parts
)
);
}
/**
* @return bool
*/
public function hasParameters(): bool
{
foreach ($this->parts as $part) {
if ($part->getParameter() !== null) {
return true;
}
}
return false;
}
/**
* @return Parameter[]
*/
public function getParameters(): array;
public function getParameters(): array
{
return \array_filter(
array_map(
function (PathPart $part): ?Parameter {
return $part->getParameter();
},
$this->parts
)
);
}
/**
* @param Path $other
* @param Parameter $otherParameter
*
* @return Path
*/
public function buildUsing(Path $other, Parameter $otherParameter): Path
{
if (\count($other->parts) > \count($this->parts)) {
return $this;
}
foreach ($other->parts as $index => $part) {
if (!$this->parts[$index]->isEqual($part)) {
return $this;
}
}
if (\count($other->parts) === \count($this->parts)) {
return $other;
}
return new Path(
\array_merge(
[new ParameterPathPart($otherParameter, $other->getTestPattern())],
\array_slice($this->parts, \count($other->parts))
)
);
}
/**
* @return \Generator
*/
public function getIterator()
{
yield from $this->parts;
}
/**
* @return Parameter|null
* @return array
*/
public function getIdentifier(): ?Parameter;
public function jsonSerialize()
{
return \get_object_vars($this);
}
}
<?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\Operations;
/**
* interface PathPart.
*/
interface PathPart
{
/**
* @return string
*/
public function asTemplate(): string;
/**
* @return string
*/
public function asTestPattern(): string;
/**
* @return string
*/
public function asCapturePattern(): string;
/**
* @return Parameter|null
*/
public function getParameter(): ?Parameter;
/**
* @param PathPart $other
*
* @return bool
*/
public function isEqual(PathPart $other): bool;
}
......@@ -19,15 +19,12 @@
namespace Irstea\NgModelGeneratorBundle;
use Irstea\NgModelGeneratorBundle\Models\ClassName;
use Irstea\NgModelGeneratorBundle\Models\Types\BuiltinType;
use Irstea\NgModelGeneratorBundle\Models\Types\Objects\Property;
use Irstea\NgModelGeneratorBundle\Models\Types\Operations\FixedPathPart;
use Irstea\NgModelGeneratorBundle\Models\Types\Operations\Parameter;
use Irstea\NgModelGeneratorBundle\Models\Types\Operations\ParameterPathPart;
use Irstea\NgModelGeneratorBundle\Models\Types\Operations\Path;
use Irstea\NgModelGeneratorBundle\Models\Types\Operations\PathTemplate;
use Irstea\NgModelGeneratorBundle\Models\Types\Operations\PlainPath;
use Irstea\NgModelGeneratorBundle\Models\Types\Resources\IRI;
use Irstea\NgModelGeneratorBundle\Models\Types\Union;
/**
* Class PathParser.
......@@ -37,19 +34,14 @@ final class PathParser implements PathParserInterface
/** @var Property[] */
private $properties;
/** @var ClassName */
private $resource;
/**
* PathParser constructor.
*
* @param ClassName $resource
* @param Property[] $properties
*/
public function __construct(ClassName $resource, array $properties)
public function __construct(array $properties)
{
$this->properties = $properties;
$this->resource = $resource;
}
/**
......@@ -57,65 +49,36 @@ final class PathParser implements PathParserInterface
*/
public function parse(string $path, array $requirements): Path
{
$parts = preg_split('/\{(\w+)\}/', $path, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
if (\count($parts) === 1) {
return new PlainPath($parts[0]);
}
$stringParts = preg_split('/\{(\w+)\}/', $path, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
return $this->parsePathTemplate($parts, $requirements);
}
$parts = [];
/**
* @param string[] $parts
*
* @return PathTemplate
*/
private function parsePathTemplate(array $parts, array $requirements): PathTemplate
{
$template = $pattern = $parameters = [];
$identifier = null;
$num = \count($parts);
for ($i = 0; $i < $num; $i += 2) {
$plain = $parts[$i];
$template[] = $plain;
$pattern[] = preg_quote($plain, '/');
$num = \count($stringParts);
for ($i = 0; $i < $num; ++$i) {
if ($stringParts[$i]) {
$parts[] = new FixedPathPart($stringParts[$i]);
}
++$i;
if (!isset($parts[$i + 1])) {
if ($i >= $num) {
break;
}
$name = $parts[$i + 1];
$name = $stringParts[$i];
if (isset($this->properties[$name])) {
$property = $this->properties[$name];
$isIdentifier = $property->isIdentifier();
$type = $property->getType();
} else {
$isIdentifier = $name === 'id';
$type = BuiltinType::get('string');
}
if ($isIdentifier) {
$identifier = $name;
//$type = Union::create([$type, new IRI([$this->resource])]);
}
$template[] = '${';
$template[] = $name;
$template[] = '}';
$pattern[] = $isIdentifier ? '(' : '(?:';
$pattern[] = isset($requirements[$name]) ? trim($requirements[$name], '^$') : '[^\\/]*';
$pattern[] = ')';
$parameter = new Parameter($name, $type);
$requirement = isset($requirements[$name]) ? trim($requirements[$name], '^$') : '[^\\/]*';
$parameters[$name] = new Parameter($name, $type);
$parts[] = new ParameterPathPart($parameter, $requirement);
}
return new PathTemplate(
implode('', $template),
implode('', $pattern),
$parameters,
$identifier
);
return new Path($parts);
}
}
Supports Markdown
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