ClassInfo.php 9.23 KiB
<?php declare(strict_types=1);
/*
 * This file is part of "irstea/ng-model-generator-bundle".
 * "irstea/ng-model-generator-bundle" generates Typescript interfaces for Angular using api-platform metadata.
 * Copyright (C) 2018-2019 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;
use Irstea\NgModelGeneratorBundle\Exceptions\DomainException;
use Irstea\NgModelGeneratorBundle\Metadata\PropertyMetadata;
/**
 * Class ClassInfo.
final class ClassInfo implements ClassName
    public const UNDEFINED = 'UNDEFINED';
    public const IRI = 'IRI';
    public const UNION = 'UNION';
    public const INTERFACE = 'INTERFACE';
    /** @var ClassName */
    private $class;
    /** @var self|false|null */
    private $parent = false;
    /** @var PropertyMetadata[] */
    private $virtualProperties = [];
    /** @var PropertyMetadata[] */
    private $concreteProperties = [];
    /** @var self[] */
    private $children = [];
    /** @var string */
    private $type = self::UNDEFINED;
    /** @var bool */
    private $abstract;
    /** @var bool */
    private $resource;
    /**
     * ClassInfo constructor.
     * @param ClassName          $class
     * @param PropertyMetadata[] $properties
     * @param bool               $abstract
     * @param bool               $resource
    public function __construct(ClassName $class, array $properties = [], bool $abstract = false, bool $resource = false)
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
$this->class = $class; $this->abstract = $abstract; foreach ($properties as $property) { $this->virtualProperties[$property->getName()] = $property; } $this->concreteProperties = $abstract ? [] : $this->virtualProperties; $this->resource = $resource; } /** * {@inheritdoc} */ public function getNamespace(): string { return $this->class->getNamespace(); } /** * {@inheritdoc} */ public function getBaseName(): string { return $this->class->getBaseName(); } /** * {@inheritdoc} */ public function getFullName(): string { return $this->class->getFullName(); } /** * Get properties. * * @return PropertyMetadata[] */ public function getVirtualProperties(): array { return $this->virtualProperties; } /** * Get properties. * * @return PropertyMetadata[] */ public function getConcreteProperties(): array { return $this->concreteProperties; } /** * Get abstract. * * @return bool */ public function isAbstract(): bool { return $this->abstract; } /** * Get resource. * * @return bool */ public function isResource(): bool
141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
{ return $this->resource; } /** * Get parent. * * @return ClassInfo|null */ public function getParent(): ?ClassInfo { return $this->parent ?: null; } /** * Set parent. * * @param ClassInfo|null $parent */ public function setParent(?ClassInfo $parent): void { if ($parent === $this->parent) { return; } if ($parent === $this) { throw new DomainException('A class cannot be its own parent'); } if ($this->parent !== false) { throw new DomainException('Can only set parent once'); } $this->parent = $parent; if ($parent) { $parent->addChild($this); } } /** * Get children. * * @return ClassInfo[] */ public function getChildren(): array { return $this->children; } /** * @param ClassInfo $child * * @SuppressWarnings(PHPMD.UnusedPrivateMethod) */ private function addChild(ClassInfo $child): void { if (\in_array($child, $this->children, true)) { return; } $this->children[] = $child; $child->setParent($this); } /** * Test type. * * @param string $type * * @return bool */ public function isType(string $type): bool { return $this->type === $type;
211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
} /** * @return bool */ public function isInterface(): bool { return $this->isType(self::INTERFACE); } /** * @return bool */ public function isUnion(): bool { return $this->isType(self::UNION); } /** * @return bool */ public function isUndefined(): bool { return $this->isType(self::UNDEFINED); } /** * @return bool */ public function isIRI(): bool { return $this->isType(self::IRI); } /** * {@inheritdoc} */ public function jsonSerialize() { return [ 'class' => $this->class->getFullName(), 'type' => $this->type, 'abstract' => $this->abstract, 'parent' => $this->parent ? $this->parent->getFullName() : null, 'children' => array_map( function (ClassInfo $ci) { return $ci->getFullName(); }, $this->children ), 'virtualProperties' => $this->virtualProperties, 'concreteProperties' => $this->concreteProperties, ]; } /** * @return self[]|\Generator */ public function iterateConcreteDescendants(): \Generator { if (!$this->abstract) { yield $this; } foreach ($this->children as $child) { yield from $child->iterateConcreteDescendants(); } } /** * @return self[]|\Generator
281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
*/ public function iterateInterfaceDescendants(): \Generator { if ($this->isInterface()) { yield $this; } foreach ($this->children as $child) { yield from $child->iterateInterfaceDescendants(); } } /** * @return string */ public function __toString() { return $this->getFullName(); } /** * Fait remonter les propriétés communes des sous-classes. */ public function rearrangeHiearchy(): void { if ($this->parent) { return; } $this->bubbleUpProperties(); $this->sinkDownProperties(); } private function bubbleUpProperties(): void { if (!$this->children) { return; } $classProperties = []; if (!$this->abstract) { $classProperties[] = $this->virtualProperties; } foreach ($this->children as $child) { $child->bubbleUpProperties(); $classProperties[] = $child->virtualProperties; } switch (\count($classProperties)) { case 0: return; case 1: $commonProperties = array_shift($classProperties); break; default: $commonProperties = array_intersect_key(...$classProperties); } if (!$commonProperties) { return; } $this->virtualProperties = array_replace($this->virtualProperties, $commonProperties); } /** * @return bool */ private function sinkDownProperties(): bool { if ($this->parent) { $this->virtualProperties = array_replace($this->parent->virtualProperties, $this->virtualProperties);