vendor/zircote/swagger-php/src/Annotations/OpenApi.php line 132

Open in your IDE?
  1. <?php declare(strict_types=1);
  2. /**
  3.  * @license Apache 2.0
  4.  */
  5. namespace OpenApi\Annotations;
  6. use OpenApi\Analysis;
  7. use OpenApi\Generator;
  8. use OpenApi\Util;
  9. /**
  10.  * This is the root document object for the API specification.
  11.  *
  12.  * @see [OAI OpenApi Object](https://github.com/OAI/OpenAPI-Specification/blob/OpenAPI.next/versions/3.0.md#openapi-object)
  13.  *
  14.  * @Annotation
  15.  */
  16. class OpenApi extends AbstractAnnotation
  17. {
  18.     public const VERSION_3_0_0 '3.0.0';
  19.     public const VERSION_3_1_0 '3.1.0';
  20.     public const DEFAULT_VERSION self::VERSION_3_0_0;
  21.     public const SUPPORTED_VERSIONS = [self::VERSION_3_0_0self::VERSION_3_1_0];
  22.     /**
  23.      * The semantic version number of the OpenAPI Specification version that the OpenAPI document uses.
  24.      *
  25.      * The openapi field should be used by tooling specifications and clients to interpret the OpenAPI document.
  26.      *
  27.      * A version specified via `Generator::setVersion()` will overwrite this value.
  28.      *
  29.      * This is not related to the API info::version string.
  30.      *
  31.      * @var string
  32.      */
  33.     public $openapi self::DEFAULT_VERSION;
  34.     /**
  35.      * Provides metadata about the API. The metadata may be used by tooling as required.
  36.      *
  37.      * @var Info
  38.      */
  39.     public $info Generator::UNDEFINED;
  40.     /**
  41.      * An array of <code>@Server</code> objects, which provide connectivity information to a target server.
  42.      *
  43.      * If not provided, or is an empty array, the default value would be a Server Object with an url value of <code>/</code>.
  44.      *
  45.      * @var Server[]
  46.      */
  47.     public $servers Generator::UNDEFINED;
  48.     /**
  49.      * The available paths and operations for the API.
  50.      *
  51.      * @var PathItem[]
  52.      */
  53.     public $paths Generator::UNDEFINED;
  54.     /**
  55.      * An element to hold various components for the specification.
  56.      *
  57.      * @var Components
  58.      */
  59.     public $components Generator::UNDEFINED;
  60.     /**
  61.      * A declaration of which security mechanisms can be used across the API.
  62.      *
  63.      * The list of values includes alternative security requirement objects that can be used.
  64.      * Only one of the security requirement objects need to be satisfied to authorize a request.
  65.      * Individual operations can override this definition.
  66.      * To make security optional, an empty security requirement `({})` can be included in the array.
  67.      *
  68.      * @var array
  69.      */
  70.     public $security Generator::UNDEFINED;
  71.     /**
  72.      * A list of tags used by the specification with additional metadata.
  73.      *
  74.      * The order of the tags can be used to reflect on their order by the parsing tools.
  75.      * Not all tags that are used by the Operation Object must be declared.
  76.      * The tags that are not declared may be organized randomly or based on the tools' logic.
  77.      * Each tag name in the list must be unique.
  78.      *
  79.      * @var Tag[]
  80.      */
  81.     public $tags Generator::UNDEFINED;
  82.     /**
  83.      * Additional external documentation.
  84.      *
  85.      * @var ExternalDocumentation
  86.      */
  87.     public $externalDocs Generator::UNDEFINED;
  88.     /**
  89.      * @var Analysis
  90.      */
  91.     public $_analysis Generator::UNDEFINED;
  92.     /**
  93.      * @inheritdoc
  94.      */
  95.     public static $_required = ['openapi''info''paths'];
  96.     /**
  97.      * @inheritdoc
  98.      */
  99.     public static $_nested = [
  100.         Info::class => 'info',
  101.         Server::class => ['servers'],
  102.         PathItem::class => ['paths''path'],
  103.         Components::class => 'components',
  104.         Tag::class => ['tags'],
  105.         ExternalDocumentation::class => 'externalDocs',
  106.         Attachable::class => ['attachables'],
  107.     ];
  108.     /**
  109.      * @inheritdoc
  110.      */
  111.     public static $_types = [];
  112.     /**
  113.      * @inheritdoc
  114.      */
  115.     public function validate(array $stack null, array $skip nullstring $ref ''$context null): bool
  116.     {
  117.         if ($stack !== null || $skip !== null || $ref !== '') {
  118.             $this->_context->logger->warning('Nested validation for ' $this->identity() . ' not allowed');
  119.             return false;
  120.         }
  121.         if (!in_array($this->openapiself::SUPPORTED_VERSIONS)) {
  122.             $this->_context->logger->warning('Unsupported OpenAPI version "' $this->openapi '". Allowed versions are: ' implode(', 'self::SUPPORTED_VERSIONS));
  123.             return false;
  124.         }
  125.         return parent::validate([], [], '#', new \stdClass());
  126.     }
  127.     /**
  128.      * Save the OpenAPI documentation to a file.
  129.      */
  130.     public function saveAs(string $filenamestring $format 'auto'): void
  131.     {
  132.         if ($format === 'auto') {
  133.             $format strtolower(substr($filename, -5)) === '.json' 'json' 'yaml';
  134.         }
  135.         if (strtolower($format) === 'json') {
  136.             $content $this->toJson();
  137.         } else {
  138.             $content $this->toYaml();
  139.         }
  140.         if (file_put_contents($filename$content) === false) {
  141.             throw new \Exception('Failed to saveAs("' $filename '", "' $format '")');
  142.         }
  143.     }
  144.     /**
  145.      * Look up an annotation with a $ref url.
  146.      *
  147.      * @param string $ref The $ref value, for example: "#/components/schemas/Product"
  148.      */
  149.     public function ref(string $ref)
  150.     {
  151.         if (substr($ref02) !== '#/') {
  152.             // @todo Add support for external (http) refs?
  153.             throw new \Exception('Unsupported $ref "' $ref '", it should start with "#/"');
  154.         }
  155.         return $this->resolveRef($ref'#/'$this, []);
  156.     }
  157.     /**
  158.      * Recursive helper for ref().
  159.      *
  160.      * @param array|AbstractAnnotation $container
  161.      */
  162.     private static function resolveRef(string $refstring $resolved$container, array $mapping)
  163.     {
  164.         if ($ref === $resolved) {
  165.             return $container;
  166.         }
  167.         $path substr($refstrlen($resolved));
  168.         $slash strpos($path'/');
  169.         $subpath $slash === false $path substr($path0$slash);
  170.         $property Util::refDecode($subpath);
  171.         $unresolved $slash === false $resolved $subpath $resolved $subpath '/';
  172.         if (is_object($container)) {
  173.             if (property_exists($container$property) === false) {
  174.                 throw new \Exception('$ref "' $ref '" not found');
  175.             }
  176.             if ($slash === false) {
  177.                 return $container->{$property};
  178.             }
  179.             $mapping = [];
  180.             if ($container instanceof AbstractAnnotation) {
  181.                 foreach ($container::$_nested as $nestedClass => $nested) {
  182.                     if (is_string($nested) === false && count($nested) === && $nested[0] === $property) {
  183.                         $mapping[$nestedClass] = $nested[1];
  184.                     }
  185.                 }
  186.             }
  187.             return self::resolveRef($ref$unresolved$container->{$property}, $mapping);
  188.         } elseif (is_array($container)) {
  189.             if (array_key_exists($property$container)) {
  190.                 return self::resolveRef($ref$unresolved$container[$property], []);
  191.             }
  192.             foreach ($mapping as $nestedClass => $keyField) {
  193.                 foreach ($container as $key => $item) {
  194.                     if (is_numeric($key) && is_object($item) && $item instanceof $nestedClass && (string) $item->{$keyField} === $property) {
  195.                         return self::resolveRef($ref$unresolved$item, []);
  196.                     }
  197.                 }
  198.             }
  199.         }
  200.         throw new \Exception('$ref "' $unresolved '" not found');
  201.     }
  202. }