Repository: GuilhemN/swagger Branch: master Commit: bdd3b68d1f8d Files: 60 Total size: 120.5 KB Directory structure: gitextract_3xv09ez2/ ├── .gitattributes ├── .gitignore ├── .php_cs.dist ├── .travis.yml ├── LICENSE ├── README.md ├── composer.json ├── phpunit ├── phpunit.xml.dist ├── src/ │ ├── AbstractModel.php │ ├── Collections/ │ │ ├── Definitions.php │ │ ├── Headers.php │ │ ├── Parameters.php │ │ ├── Paths.php │ │ └── Responses.php │ ├── Contact.php │ ├── ExternalDocs.php │ ├── Header.php │ ├── Info.php │ ├── Items.php │ ├── License.php │ ├── Operation.php │ ├── Parameter.php │ ├── Parts/ │ │ ├── ConsumesPart.php │ │ ├── DescriptionPart.php │ │ ├── ExtensionPart.php │ │ ├── ExternalDocsPart.php │ │ ├── ItemsPart.php │ │ ├── ParametersPart.php │ │ ├── ProducesPart.php │ │ ├── RefPart.php │ │ ├── RequiredPart.php │ │ ├── ResponsesPart.php │ │ ├── SchemaPart.php │ │ ├── SchemesPart.php │ │ ├── SecurityPart.php │ │ ├── TagsPart.php │ │ ├── TypePart.php │ │ └── UrlPart.php │ ├── Path.php │ ├── Response.php │ ├── Schema.php │ ├── SecurityScheme.php │ ├── Swagger.php │ ├── Tag.php │ └── Util/ │ └── MergeHelper.php └── tests/ ├── BasicAuthTest.php ├── CollectionsTest.php ├── KeekoTest.php ├── PetstoreTest.php ├── SwaggerTest.php └── fixtures/ ├── basic-auth.json ├── keeko-user.json ├── petstore-dictionaries.json ├── petstore-expanded.json ├── petstore-minimal.json ├── petstore-parameter-refs.json ├── petstore-simple.json ├── petstore-with-external-docs.json └── petstore.json ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitattributes ================================================ .* export-ignore *.md export-ignore tests export-ignore ================================================ FILE: .gitignore ================================================ .buildpath .php_cs.cache composer.phar composer.lock phpunit.xml vendor/ coverage/ ================================================ FILE: .php_cs.dist ================================================ in(__DIR__) ->exclude('Tests/Functional/cache') ; return PhpCsFixer\Config::create() ->setRules([ '@Symfony' => true, 'ordered_imports' => true, 'phpdoc_order' => true, 'header_comment' => [ 'header' => <<
setFinder($finder) ; ================================================ FILE: .travis.yml ================================================ language: php php: - 7.0 - 7.1 - 7.2 - 7.3 - 7.4 sudo: false cache: directories: - $HOME/.composer/cache branches: only: - master - /^\d+\.\d+$/ matrix: fast_finish: true include: - php: 7.0 env: COMPOSER_FLAGS="--prefer-lowest" - php: 7.4 env: COMPOSER_FLAGS="--prefer-lowest" before_install: - composer self-update install: composer update $COMPOSER_FLAGS script: ./phpunit ================================================ FILE: LICENSE ================================================ The MIT License (MIT) Copyright (c) 2015 Thomas Gossmann Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # Swagger [![Build Status](https://travis-ci.org/GuilhemN/swagger.svg?branch=master)](https://travis-ci.org/GuilhemN/swagger) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/EXSyst/Swagger/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/EXSyst/Swagger) [![Code Coverage](https://scrutinizer-ci.com/g/EXSyst/Swagger/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/EXSyst/Swagger) A php library to manipulate [Swagger](http://Swagger.io)/[Open API](https://openapis.org) specifications. ## Installation ``` composer require EXSyst/Swagger ``` ## Usage Read an `api.json` file: ```php $swagger = Swagger::fromFile('api.json'); // or $swagger = new Swagger($array); ``` ### Collections There are two major collections: `Paths` and `Definitions`. The API is similar for both: ```php $paths = $swagger->getPaths(); $p = new Path('/user'); foreach ($paths as $path) { // adding $paths->add($a); // retrieving if ($paths->has('/user') || $paths->contains($p)) { $path = $paths->get('/user'); } // removing $paths->remove('/user'); } ``` ### Models There are a lot of models, e.g. the mentioned `Path` above. The API is well written, so it works with the auto-completion of your IDE. It is straight forward and uses the same naming scheme as the OpenAPI specification. ## Contributing Feel free to fork and submit a pull request (don't forget the tests) and I am happy to merge. ================================================ FILE: composer.json ================================================ { "name" : "exsyst/swagger", "description" : "A php library to manipulate Swagger specifications", "type" : "library", "license" : "MIT", "authors" : [ { "name" : "Guilhem Niot", "email" : "guilhem@gniot.fr" } ], "autoload" : { "psr-4" : { "EXSyst\\Component\\Swagger\\" : "src/" } }, "autoload-dev" : { "psr-4" : { "EXSyst\\Component\\Swagger\\tests\\" : "tests/" } }, "require" : { "php" : "^7.0|^8.0" }, "require-dev" : { "symfony/phpunit-bridge": "^4.1.8|^5.0" } } ================================================ FILE: phpunit ================================================ #!/usr/bin/env php tests . tests vendor ================================================ FILE: src/AbstractModel.php ================================================ doMerge($this->normalize($data), $overwrite); } public function toArray() { $return = []; foreach ($this->doExport() as $key => $value) { $value = $this->resolve($value); if (null === $value) { continue; } $return[$key] = $value; } if (method_exists($this, 'getExtensions')) { foreach ($this->getExtensions() as $name => $value) { $return['x-'.$name] = $value; } } if (is_array($return) && 0 === count($return) && !static::REQUIRED) { $return = null; } return $return; } abstract protected function doMerge($data, $overwrite = false); protected function normalize($data) { if ($data instanceof \stdClass || $data instanceof \ArrayAccess) { return (array) $data; } return $data; } private function resolve($value) { if (is_array($value)) { foreach ($value as &$v) { $v = $this->resolve($v); } } elseif ($value instanceof self) { $value = $value->toArray(); } return $value; } } ================================================ FILE: src/Collections/Definitions.php ================================================ merge($data); } protected function doMerge($data, $overwrite = false) { foreach ($data as $name => $schema) { $this->get($name)->merge($schema, $overwrite); } } protected function doExport(): array { return $this->definitions; } /** * Returns the schema for the given field. */ public function get(string $name): Schema { if (!$this->has($name)) { $this->set($name, new Schema()); } return $this->definitions[$name]; } /** * Sets the field. */ public function set(string $name, Schema $schema): self { $this->definitions[$name] = $schema; return $this; } /** * Removes the given field. */ public function remove(string $name): self { unset($this->definitions[$name]); return $this; } /** * Returns definitions has a schema with the given name. */ public function has(string $name): bool { return isset($this->definitions[$name]); } public function getIterator(): \ArrayIterator { return new \ArrayIterator($this->definitions); } } ================================================ FILE: src/Collections/Headers.php ================================================ merge($data); } protected function doMerge($data, $overwrite = false) { foreach ($data as $name => $header) { $this->get($name)->merge($header, $overwrite); } } protected function doExport(): array { return $this->headers; } /** * Returns whether a header with the given name exists. */ public function has(string $header): bool { return isset($this->headers[$header]); } /** * Returns the header info for the given code. */ public function get($header): Header { if (!$this->has($header)) { $this->set($header, new Header()); } return $this->headers[$header]; } /** * Sets the header. */ public function set(string $name, Header $header): self { $this->headers[$name] = $header; return $this; } /** * Removes the given header. */ public function remove(string $header): self { unset($this->headers[$header]); return $this; } public function getIterator(): \ArrayIterator { return new \ArrayIterator($this->headers); } } ================================================ FILE: src/Collections/Parameters.php ================================================ merge($data); } protected function doMerge($data, $overwrite = false) { $this->mergeRef($data, $overwrite); if (!$this->hasRef()) { foreach ($data as $parameter) { $this->add(new Parameter($parameter)); } } } protected function doExport(): array { if ($this->hasRef()) { return ['$ref' => $this->getRef()]; } return array_values($this->parameters); } /** * Searches whether a parameter with the given unique combination exists. */ public function has(string $name, string $in = null): bool { $id = $in ? $name.'/'.$in : $name; return isset($this->parameters[$id]); } public function get(string $name, string $in = null): Parameter { if (!$this->has($name, $in)) { $this->add( new Parameter(['name' => $name, 'in' => $in]) ); } $id = $in ? $name.'/'.$in : $name; return $this->parameters[$id]; } /** * Adds a parameter. */ public function add(Parameter $parameter): self { $this->parameters[$this->getIdentifier($parameter)] = $parameter; return $this; } /** * Removes a parameter. */ public function remove(Parameter $parameter): self { unset($this->parameters[$this->getIdentifier($parameter)]); return $this; } private function getIdentifier(Parameter $parameter) { if ($parameter->hasRef()) { return $parameter->getRef(); } return $parameter->getName().'/'.$parameter->getIn(); } public function getIterator(): \ArrayIterator { return new \ArrayIterator(array_values($this->parameters)); } } ================================================ FILE: src/Collections/Paths.php ================================================ merge($data); } protected function doMerge($data, $overwrite = false) { foreach ($data as $key => $path) { if (0 !== strpos($key, 'x-')) { $this->get($key)->merge($path, $overwrite); } } $this->mergeExtensions($data, $overwrite); } protected function doExport(): array { return $this->paths; } /** * Returns whether a path with the given name exists. */ public function has(string $path): bool { return isset($this->paths[$path]); } /** * Returns the path info for the given path. */ public function get(string $path): Path { if (!$this->has($path)) { $this->set($path, new Path()); } return $this->paths[$path]; } /** * Sets the path. */ public function set(string $path, Path $model): self { $this->paths[$path] = $model; return $this; } /** * Removes the given path. */ public function remove(string $path): self { unset($this->paths[$path]); return $this; } public function getIterator(): \ArrayIterator { return new \ArrayIterator($this->paths); } } ================================================ FILE: src/Collections/Responses.php ================================================ merge($data); } protected function doMerge($data, $overwrite = false) { $this->mergeExtensions($data, $overwrite); foreach ($data as $code => $response) { if (0 !== strpos($code, 'x-')) { $this->set($code, new Response($response)); } } } protected function doExport(): array { return $this->responses; } /** * Returns whether the given response exists. */ public function has($code): bool { return isset($this->responses[$code]); } /** * Returns the response info for the given code. */ public function get($code): Response { if (!$this->has($code)) { $this->set($code, new Response()); } return $this->responses[$code]; } /** * Sets the response. */ public function set($code, Response $response): self { $this->responses[$code] = $response; return $this; } /** * Removes the given response. */ public function remove($code): self { unset($this->responses[$code]); return $this; } public function getIterator(): \ArrayIterator { return new \ArrayIterator($this->responses); } } ================================================ FILE: src/Contact.php ================================================ merge($data); } protected function doMerge($data, $overwrite = false) { MergeHelper::mergeFields($this->name, $data['name'] ?? null, $overwrite); MergeHelper::mergeFields($this->url, $data['url'] ?? null, $overwrite); MergeHelper::mergeFields($this->email, $data['email'] ?? null, $overwrite); $this->mergeExtensions($data, $overwrite); } protected function doExport(): array { return [ 'name' => $this->name, 'url' => $this->url, 'email' => $this->email, ]; } /** * @return string */ public function getName() { return $this->name; } /** * @param string $name */ public function setName($name): self { $this->name = $name; return $this; } /** * @return string */ public function getUrl() { return $this->url; } /** * @param string $url */ public function setUrl($url): self { $this->url = $url; return $this; } /** * @return string */ public function getEmail() { return $this->email; } /** * @param string $email */ public function setEmail($email): self { $this->email = $email; return $this; } } ================================================ FILE: src/ExternalDocs.php ================================================ merge($data); } protected function doMerge($data, $overwrite = false) { $this->mergeDescription($data, $overwrite); $this->mergeExtensions($data, $overwrite); $this->mergeUrl($data, $overwrite); } protected function doExport(): array { return [ 'description' => $this->description, 'url' => $this->url, ]; } } ================================================ FILE: src/Header.php ================================================ merge($data); } protected function doMerge($data, $overwrite = false) { $this->mergeDescription($data, $overwrite); $this->mergeExtensions($data, $overwrite); $this->mergeItems($data, $overwrite); $this->mergeType($data, $overwrite); } public function doExport(): array { return array_merge( [ 'description' => $this->description, 'items' => $this->items, ], $this->doExportType() ); } } ================================================ FILE: src/Info.php ================================================ contact = new Contact(); $this->license = new License(); $this->merge($data); } protected function doMerge($data, $overwrite = false) { MergeHelper::mergeFields($this->title, $data['title'] ?? null, $overwrite); MergeHelper::mergeFields($this->termsOfService, $data['termsOfService'] ?? null, $overwrite); MergeHelper::mergeFields($this->version, $data['version'] ?? null, $overwrite); $this->contact->merge($data['contact'] ?? [], $overwrite); $this->license->merge($data['license'] ?? [], $overwrite); $this->mergeDescription($data, $overwrite); $this->mergeExtensions($data, $overwrite); } protected function doExport(): array { return [ 'title' => $this->title, 'description' => $this->description, 'termsOfService' => $this->termsOfService, 'contact' => $this->contact, 'license' => $this->license, 'version' => $this->version, ]; } /** * @return string|null */ public function getTitle() { return $this->title; } /** * @param string|null $title */ public function setTitle($title): self { $this->title = $title; return $this; } /** * @return string|null */ public function getTerms() { return $this->termsOfService; } /** * @param string|null $terms */ public function setTerms($terms): self { $this->termsOfService = $terms; return $this; } /** * @return Contact */ public function getContact() { return $this->contact; } /** * @return License */ public function getLicense() { return $this->license; } /** * @return string|null */ public function getVersion() { return $this->version; } /** * @param string|null $version * * @return Info */ public function setVersion($version): self { $this->version = $version; return $this; } } ================================================ FILE: src/Items.php ================================================ merge($data); } protected function doMerge($data, $overwrite = false) { MergeHelper::mergeFields($this->name, $data['name'] ?? null, $overwrite); $this->mergeExtensions($data, $overwrite); $this->mergeUrl($data, $overwrite); } protected function doExport(): array { return [ 'name' => $this->name, 'url' => $this->url, ]; } /** * @return string */ public function getName() { return $this->name; } /** * @param string $name */ public function setName($name): self { $this->name = $name; return $this; } } ================================================ FILE: src/Operation.php ================================================ merge($data); } protected function doMerge($data, $overwrite = false) { MergeHelper::mergeFields($this->summary, $data['summary'] ?? null, $overwrite); MergeHelper::mergeFields($this->description, $data['description'] ?? null, $overwrite); MergeHelper::mergeFields($this->operationId, $data['operationId'] ?? null, $overwrite); MergeHelper::mergeFields($this->deprecated, $data['deprecated'] ?? null, $overwrite); $this->mergeConsumes($data, $overwrite); $this->mergeExtensions($data, $overwrite); $this->mergeExternalDocs($data, $overwrite); $this->mergeParameters($data, $overwrite); $this->mergeProduces($data, $overwrite); $this->mergeResponses($data, $overwrite); $this->mergeSchemes($data, $overwrite); $this->mergeSecurity($data, $overwrite); $this->mergeTags($data, $overwrite); } protected function doExport(): array { return [ 'summary' => $this->getSummary(), 'description' => $this->getDescription(), 'operationId' => $this->getOperationId(), 'deprecated' => $this->getDeprecated(), 'consumes' => $this->getConsumes() ?: null, 'produces' => $this->getProduces() ?: null, 'parameters' => $this->getParameters(), 'responses' => $this->getResponses(), 'schemes' => $this->getSchemes() ?: null, 'tags' => $this->getTags() ?: null, 'externalDocs' => $this->getExternalDocs(), 'security' => $this->getSecurity(), ]; } /** * @return string */ public function getSummary() { return $this->summary; } /** * @param string $summary */ public function setSummary($summary): self { $this->summary = $summary; return $this; } /** * @return string */ public function getDescription() { return $this->description; } /** * @param string $description */ public function setDescription($description): self { $this->description = $description; return $this; } /** * @return string */ public function getOperationId() { return $this->operationId; } /** * @param string $operationId */ public function setOperationId($operationId): self { $this->operationId = $operationId; return $this; } /** * @return bool */ public function getDeprecated() { return $this->deprecated; } /** * @param bool $deprecated */ public function setDeprecated($deprecated): self { $this->deprecated = $deprecated; return $this; } } ================================================ FILE: src/Parameter.php ================================================ normalize($data); $this->merge($data); if (!$this->hasRef()) { if (!isset($data['name']) || !isset($data['in'])) { throw new \InvalidArgumentException('"in" and "name" are required for parameters'); } $this->name = $data['name']; $this->in = $data['in']; } } protected function doMerge($data, $overwrite = false) { MergeHelper::mergeFields($this->allowEmptyValue, $data['allowEmptyValue'] ?? null, $overwrite); $this->mergeDescription($data, $overwrite); $this->mergeExtensions($data, $overwrite); $this->mergeItems($data, $overwrite); $this->mergeRef($data, $overwrite); $this->mergeRequired($data, $overwrite); $this->mergeSchema($data, $overwrite); $this->mergeType($data, $overwrite); } protected function doExport(): array { if ($this->hasRef()) { return ['$ref' => $this->getRef()]; } return array_merge( [ 'name' => $this->name, 'in' => $this->in, 'allowEmptyValue' => $this->allowEmptyValue, 'required' => $this->required, 'description' => $this->description, 'schema' => $this->schema, 'items' => $this->items, ], $this->doExportType() ); } /** * @return string */ public function getName() { return $this->name; } /** * @return string */ public function getIn() { return $this->in; } /** * @return bool */ public function getAllowEmptyValue() { return $this->allowEmptyValue; } /** * Sets the ability to pass empty-valued parameters. This is valid only for either `query` or * `formData` parameters and allows you to send a parameter with a name only or an empty value. * Default value is `false`. * * @param bool $allowEmptyValue */ public function setAllowEmptyValue($allowEmptyValue): self { $this->allowEmptyValue = $allowEmptyValue; return $this; } } ================================================ FILE: src/Parts/ConsumesPart.php ================================================ consumes, $data['consumes'] ?? null, $overwrite); } /** * Return consumes. */ public function getConsumes() { return $this->consumes; } } ================================================ FILE: src/Parts/DescriptionPart.php ================================================ description, $data['description'] ?? null, $overwrite); } /** * @return string|null */ public function getDescription() { return $this->description; } /** * @param string $description * * @return $this */ public function setDescription(string $description = null): self { $this->description = $description; return $this; } } ================================================ FILE: src/Parts/ExtensionPart.php ================================================ $value) { if (0 === strpos($name, 'x-')) { $this->extensions[substr($name, 2)] = $value; } } } /** * Returns extensions. * * @return array */ public function getExtensions(): array { return $this->extensions; } } ================================================ FILE: src/Parts/ExternalDocsPart.php ================================================ getExternalDocs()->merge($data['externalDocs']); } } /** * @return ExternalDocs */ public function getExternalDocs(): ExternalDocs { if (null === $this->externalDocs) { $this->externalDocs = new ExternalDocs(); } return $this->externalDocs; } public function setExternalDocs(ExternalDocs $externalDocs): self { $this->externalDocs = $externalDocs; return $this; } } ================================================ FILE: src/Parts/ItemsPart.php ================================================ getItems()->merge($data['items'], $overwrite); } } /** * Returns the items. */ public function getItems(): Items { if (null === $this->items) { $this->items = new Items(); } return $this->items; } } ================================================ FILE: src/Parts/ParametersPart.php ================================================ getParameters()->merge($data['parameters'], $overwrite); } } /** * Return parameters. */ public function getParameters(): Parameters { if (null === $this->parameters) { $this->parameters = new Parameters(); } return $this->parameters; } } ================================================ FILE: src/Parts/ProducesPart.php ================================================ produces[$produce] = true; } } /** * Return produces. */ public function getProduces(): array { return array_keys($this->produces); } } ================================================ FILE: src/Parts/RefPart.php ================================================ ref = $data['$ref'] ?? null; } /** * @return string|null */ public function getRef() { return $this->ref; } /** * @param string|null $ref */ public function setRef(string $ref = null): self { $this->ref = $ref; return $this; } public function hasRef(): bool { return null !== $this->ref; } } ================================================ FILE: src/Parts/RequiredPart.php ================================================ required, $data['required'] ?? null, $overwrite); } /** * @return bool|null */ public function getRequired() { return $this->required; } /** * @param bool|null $required */ public function setRequired(bool $required = null): self { $this->required = $required; return $this; } } ================================================ FILE: src/Parts/ResponsesPart.php ================================================ getResponses()->merge($data['responses'], $overwrite); } } /** * Return responses. */ public function getResponses(): Responses { if (null === $this->responses) { $this->responses = new Responses(); } return $this->responses; } } ================================================ FILE: src/Parts/SchemaPart.php ================================================ getSchema()->merge($data['schema'], $overwrite); } } public function getSchema(): Schema { if (null === $this->schema) { $this->schema = new Schema(); } return $this->schema ?: new Schema(); } } ================================================ FILE: src/Parts/SchemesPart.php ================================================ schemes[$scheme] = true; } } /** * Return schemes. */ public function getSchemes(): array { return array_keys($this->schemes); } } ================================================ FILE: src/Parts/SecurityPart.php ================================================ security, $data['security'] ?? null, $overwrite); } /** * @return array|null */ public function getSecurity() { return $this->security; } public function setSecurity(array $security = null): self { $this->security = $security; return $this; } } ================================================ FILE: src/Parts/TagsPart.php ================================================ tags[$tag->getName()] = $tag; } } /** * Return tags. */ public function getTags(): array { return array_values($this->tags); } protected function exportTags(): array { $out = []; foreach ($this->tags as $tag) { $out[] = $tag->toArray(); } return $out; } } ================================================ FILE: src/Parts/TypePart.php ================================================ getTypeFields() as $field) { MergeHelper::mergeFields($this->{$field}, $data[$field] ?? null, $overwrite); } } protected function doExportType(): array { $return = []; foreach ($this->getTypeFields() as $field) { $return[$field] = $this->{$field}; } return $return; } private function getTypeFields(): array { return [ 'type', 'format', 'collectionFormat', 'default', 'maximum', 'exclusiveMaximum', 'minimum', 'exclusiveMinimum', 'maxLength', 'minLength', 'pattern', 'maxItems', 'minItems', 'uniqueItems', 'enum', 'multipleOf', ]; } /** * @return string|null */ public function getType() { return $this->type; } /** * @param string|null $type */ public function setType($type): self { $this->type = $type; return $this; } /** * @return string|null */ public function getFormat() { return $this->format; } /** * Sets the extending format for the type. * * @param string|null $format */ public function setFormat($format): self { $this->format = $format; return $this; } /** * @return string|null */ public function getCollectionFormat() { return $this->collectionFormat; } /** * Determines the format of the array if type array is used. Possible values are:. * * - `csv` - comma separated values `foo,bar`. * - `ssv` - space separated values `foo bar`. * - `tsv` - tab separated values `foo\tbar`. * - `pipes` - pipe separated values `foo|bar`. * - `multi` - corresponds to multiple parameter instances instead of multiple values for a * single instance `foo=bar&foo=baz`. This is valid only for parameters in "query" or "formData". * * Default value is `csv`. * * * @param string|null $collectionFormat */ public function setCollectionFormat($collectionFormat): self { $this->collectionFormat = $collectionFormat; return $this; } /** * @return mixed */ public function getDefault() { return $this->default; } /** * @param mixed|null $default */ public function setDefault($default): self { $this->default = $default; return $this; } /** * @return float|null */ public function getMaximum() { return $this->maximum; } /** * @param float|null $maximum */ public function setMaximum($maximum): self { $this->maximum = $maximum; return $this; } /** * @return bool|null */ public function isExclusiveMaximum() { return $this->exclusiveMaximum; } /** * @param bool|null $exclusiveMaximum */ public function setExclusiveMaximum($exclusiveMaximum): self { $this->exclusiveMaximum = $exclusiveMaximum; return $this; } /** * @return float|null */ public function getMinimum() { return $this->minimum; } /** * @param float|null $minimum */ public function setMinimum($minimum): self { $this->minimum = $minimum; return $this; } /** * @return bool|null */ public function isExclusiveMinimum() { return $this->exclusiveMinimum; } /** * @param bool|null $exclusiveMinimum * * @return $this */ public function setExclusiveMinimum($exclusiveMinimum) { $this->exclusiveMinimum = $exclusiveMinimum; return $this; } /** * @return int|null */ public function getMaxLength() { return $this->maxLength; } /** * @param int|null $maxLength */ public function setMaxLength($maxLength): self { $this->maxLength = $maxLength; return $this; } /** * @return int|null */ public function getMinLength() { return $this->minLength; } /** * @param int|null $minLength */ public function setMinLength($minLength): self { $this->minLength = $minLength; return $this; } /** * @return string|null */ public function getPattern() { return $this->pattern; } /** * @param string|null $pattern */ public function setPattern($pattern): self { $this->pattern = $pattern; return $this; } /** * @return int|null */ public function getMaxItems() { return $this->maxItems; } /** * @param int|null $maxItems */ public function setMaxItems($maxItems): self { $this->maxItems = $maxItems; return $this; } /** * @return int|null */ public function getMinItems() { return $this->minItems; } /** * @param int|null $minItems */ public function setMinItems($minItems): self { $this->minItems = $minItems; return $this; } /** * @return bool|null */ public function hasUniqueItems() { return $this->uniqueItems; } /** * @param bool|null $uniqueItems */ public function setUniqueItems($uniqueItems): self { $this->uniqueItems = $uniqueItems; return $this; } /** * @return mixed */ public function getEnum() { return $this->enum; } /** * @param mixed $enum */ public function setEnum($enum): self { $this->enum = $enum; return $this; } /** * @return float|null */ public function getMultipleOf() { return $this->multipleOf; } /** * @param float|null $multipleOf */ public function setMultipleOf($multipleOf): self { $this->multipleOf = $multipleOf; return $this; } } ================================================ FILE: src/Parts/UrlPart.php ================================================ url, $data['url'] ?? null, $overwrite); } /** * @return string|null */ public function getUrl() { return $this->url; } /** * @param string $url */ public function setUrl(string $url = null): self { $this->url = $url; return $this; } } ================================================ FILE: src/Path.php ================================================ merge($data); } protected function doMerge($data, $overwrite = false) { foreach (Swagger::$METHODS as $method) { if (isset($data[$method])) { $this->getOperation($method)->merge($data[$method]); } } $this->mergeExtensions($data, $overwrite); $this->mergeParameters($data, $overwrite); } protected function doExport(): array { return array_merge($this->operations, array('parameters' => $this->getParameters())); } public function getOperations(): array { return $this->operations; } /** * Gets the operation for the given method, creates one if none exists. */ public function getOperation(string $method): Operation { if (!$this->hasOperation($method)) { $this->setOperation($method, new Operation()); } return $this->operations[$method]; } /** * Sets the operation for a method. */ public function setOperation(string $method, Operation $operation): self { $this->operations[$method] = $operation; return $this; } public function hasOperation(string $method): bool { return isset($this->operations[$method]); } /** * Removes an operation for the given method. */ public function removeOperation(string $method): self { unset($this->operations[$method]); return $this; } /** * Returns all methods for this path. */ public function getMethods(): array { return array_keys($this->operations); } } ================================================ FILE: src/Response.php ================================================ headers = new Headers(); $this->merge($data); } protected function doMerge($data, $overwrite = false) { foreach ($data['examples'] ?? [] as $mimeType => $example) { $this->examples[$mimeType] = $this->examples[$mimeType] ?? null; MergeHelper::mergeFields($this->examples[$mimeType], $example, $overwrite); } $this->headers->merge($data['headers'] ?? [], $overwrite); $this->mergeDescription($data, $overwrite); $this->mergeExtensions($data, $overwrite); $this->mergeRef($data, $overwrite); $this->mergeSchema($data, $overwrite); } protected function doExport(): array { if ($this->hasRef()) { return ['$ref' => $this->getRef()]; } return [ 'description' => $this->description, 'schema' => $this->schema, 'headers' => $this->headers, 'examples' => $this->examples ?: null, ]; } public function getExamples(): array { return $this->examples; } /** * Returns headers for this response. */ public function getHeaders(): Headers { return $this->headers; } } ================================================ FILE: src/Schema.php ================================================ properties = new Definitions(); $this->merge($data); } protected function doMerge($data, $overwrite = false) { MergeHelper::mergeFields($this->required, $data['required'] ?? null, $overwrite); MergeHelper::mergeFields($this->title, $data['title'] ?? null, $overwrite); MergeHelper::mergeFields($this->discriminator, $data['discriminator'] ?? null, $overwrite); MergeHelper::mergeFields($this->readOnly, $data['readOnly'] ?? null, $overwrite); MergeHelper::mergeFields($this->example, $data['example'] ?? null, $overwrite); $this->properties->merge($data['properties'] ?? [], $overwrite); foreach ($data['allOf'] ?? [] as $schema) { $this->allOf[] = new self($schema); } if (isset($data['additionalProperties'])) { if (null === $this->additionalProperties) { $this->additionalProperties = new self(); } if (true === $data['additionalProperties']) { $data['additionalProperties'] = []; } $this->additionalProperties->merge($data['additionalProperties'], $overwrite); } $this->mergeDescription($data, $overwrite); $this->mergeExternalDocs($data, $overwrite); $this->mergeExtensions($data, $overwrite); $this->mergeItems($data, $overwrite); $this->mergeRef($data, $overwrite); $this->mergeType($data, $overwrite); } protected function doExport() { if ($this->hasRef()) { return ['$ref' => $this->getRef()]; } // if "additionalProperties" has no special types/refs, it must return `{}` or `true` // @see https://swagger.io/docs/specification/data-models/dictionaries/ $additionalProperties = ($this->additionalProperties instanceof self && [] === $this->additionalProperties->toArray()) ?: $this->additionalProperties; return array_merge([ 'title' => $this->title, 'discriminator' => $this->discriminator, 'description' => $this->description, 'readOnly' => $this->readOnly, 'example' => $this->example, 'externalDocs' => $this->externalDocs, 'items' => $this->items, 'required' => $this->required, 'properties' => $this->properties, 'additionalProperties' => $additionalProperties, 'allOf' => $this->allOf ?: null, ], $this->doExportType()); } /** * @return bool|array */ public function getRequired() { return $this->required; } /** * @param bool|array $required * * @return $this */ public function setRequired($required) { $this->required = $required; return $this; } /** * @return string|null */ public function getDiscriminator() { return $this->discriminator; } /** * @param string|null $discriminator * * @return Schema */ public function setDiscriminator($discriminator) { $this->discriminator = $discriminator; return $this; } /** * @return bool|null */ public function isReadOnly() { return $this->readOnly; } /** * @param bool|null $readOnly * * @return Schema */ public function setReadOnly($readOnly) { $this->readOnly = $readOnly; return $this; } /** * @return string|null */ public function getExample() { return $this->example; } /** * @param string|null $example * * @return Schema */ public function setExample($example) { $this->example = $example; return $this; } /** * @return string|null */ public function getTitle() { return $this->title; } /** * @param string|null $title * * @return $this */ public function setTitle($title) { $this->title = $title; return $this; } /** * @return Definitions */ public function getProperties() { return $this->properties; } /** * @return array */ public function getAllOf(): array { return $this->allOf; } /** * @return Schema|null */ public function getAdditionalProperties() { return $this->additionalProperties; } } ================================================ FILE: src/SecurityScheme.php ================================================ merge($data); } /** * Return the name of the header or query parameter to be used. * * @return string */ public function getName() { return $this->name; } /** * Sets the name of the header or query parameter to be used. * * @param string $name * * @return $this */ public function setName($name) { $this->name = $name; return $this; } /** * Returns the type of the security scheme. * * @return string */ public function getType() { return $this->type; } /** * Sets the type of the security scheme. * * @param string $type Valid values are "basic", "apiKey" or "oauth2" * * @return $this */ public function setType($type) { $this->type = $type; return $this; } /** * Returns the location of the API key. * * @return string */ public function getIn() { return $this->in; } /** * Sets the location of the API key. * * @param string $in Valid values are "query" or "header" * * @return $this */ public function setIn($in) { $this->in = $in; return $this; } /** * Retunrs the flow used by the OAuth2 security scheme. * * @return string */ public function getFlow() { return $this->flow; } /** * Sets the flow used by the OAuth2 security scheme. * * @param string $flow Valid values are "implicit", "password", "application" or "accessCode" * * @return $this */ public function setFlow($flow) { $this->flow = $flow; return $this; } /** * Returns the authorization URL to be used for this flow. * * @return string */ public function getAuthorizationUrl() { return $this->authorizationUrl; } /** * Sets the authorization URL to be used for this flow. * * @param string $authorizationUrl * * @return $this */ public function setAuthorizationUrl($authorizationUrl) { $this->authorizationUrl = $authorizationUrl; return $this; } /** * Returns the token URL to be used for this flow. * * @return string */ public function getTokenUrl() { return $this->tokenUrl; } /** * Sets the token URL to be used for this flow. * * @param string $tokenUrl * * @return $this */ public function setTokenUrl($tokenUrl) { $this->tokenUrl = $tokenUrl; return $this; } /** * Returns the scopes. * * @return array */ public function getScopes() { return $this->scopes; } /** * @return $this */ public function setScopes(array $scopes = null) { $this->scopes = $scopes; return $this; } protected function doMerge($data, $overwrite = false) { MergeHelper::mergeFields($this->name, $data['name'] ?? null, $overwrite); MergeHelper::mergeFields($this->type, $data['type'] ?? null, $overwrite); MergeHelper::mergeFields($this->in, $data['in'] ?? null, $overwrite); MergeHelper::mergeFields($this->flow, $data['flow'] ?? null, $overwrite); MergeHelper::mergeFields($this->authorizationUrl, $data['authorizationUrl'] ?? null, $overwrite); MergeHelper::mergeFields($this->tokenUrl, $data['tokenUrl'] ?? null, $overwrite); MergeHelper::mergeFields($this->scopes, $data['scopes'] ?? null, $overwrite); $this->mergeDescription($data, $overwrite); } protected function doExport() { return [ 'name' => $this->name, 'type' => $this->type, 'in' => $this->in, 'flow' => $this->flow, 'authorizationUrl' => $this->authorizationUrl, 'tokenUrl' => $this->tokenUrl, 'scopes' => $this->scopes, 'description' => $this->description, ]; } } ================================================ FILE: src/Swagger.php ================================================ info = new Info(); $this->definitions = new Definitions(); $this->paths = new Paths(); $this->merge($data); } protected function doMerge($data, $overwrite = false) { MergeHelper::mergeFields($this->host, $data['host'] ?? null, $overwrite); MergeHelper::mergeFields($this->basePath, $data['basePath'] ?? null, $overwrite); if (isset($data['info'])) { $this->info->merge($data['info'], $overwrite); } if (isset($data['definitions'])) { $this->getDefinitions()->merge($data['definitions'], $overwrite); } if (isset($data['paths'])) { $this->getPaths()->merge($data['paths'], $overwrite); } $this->mergeConsumes($data, $overwrite); $this->mergeExtensions($data, $overwrite); $this->mergeExternalDocs($data, $overwrite); $this->mergeProduces($data, $overwrite); $this->mergeResponses($data, $overwrite); $this->mergeSchemes($data, $overwrite); $this->mergeSecurity($data, $overwrite); $this->mergeTags($data, $overwrite); foreach ($data['parameters'] ?? [] as $name => $def) { $this->parameters[$name] = new Parameter($def); } foreach ($data['securityDefinitions'] ?? [] as $name => $def) { $this->securityDefinitions[$name] = new SecurityScheme($def); } } protected function doExport(): array { return [ 'swagger' => '2.0', 'info' => $this->info, 'host' => $this->host, 'basePath' => $this->basePath, 'schemes' => $this->getSchemes() ?: null, 'consumes' => $this->getConsumes() ?: null, 'produces' => $this->getProduces() ?: null, 'paths' => $this->paths, 'definitions' => $this->definitions, 'parameters' => $this->parameters ?: null, 'responses' => $this->responses, 'tags' => $this->getTags() ?: null, 'externalDocs' => $this->externalDocs, 'securityDefinitions' => $this->securityDefinitions ?: null, 'security' => $this->getSecurity(), ]; } /** * @return string */ public function getVersion(): string { return '2.0'; } /** * @return Info */ public function getInfo() { return $this->info; } /** * @return string */ public function getHost() { return $this->host; } /** * @param string $host */ public function setHost($host): self { $this->host = $host; return $this; } /** * @return string */ public function getBasePath() { return $this->basePath; } /** * @param string $basePath * * @return $this */ public function setBasePath($basePath) { $this->basePath = $basePath; return $this; } /** * @return Paths */ public function getPaths() { return $this->paths; } /** * @return Definitions */ public function getDefinitions() { return $this->definitions; } /** * @return array */ public function getSecurityDefinitions() { return $this->securityDefinitions; } /** * @return array */ public function getParameters() { return $this->parameters; } /** * @param array $parameters */ public function setParameters(array $parameters): self { $this->parameters = $parameters; return $this; } } ================================================ FILE: src/Tag.php ================================================ normalize($data); if (!isset($data['name'])) { throw new \InvalidArgumentException('A tag must have a name.'); } $this->name = $data['name']; $this->merge($data); } protected function doMerge($data, $overwrite = false) { $this->mergeDescription($data, $overwrite); $this->mergeExtensions($data, $overwrite); $this->mergeExternalDocs($data, $overwrite); } public function toArray() { $return = parent::toArray(); if (1 === count($return)) { return $return['name']; } return $return; } protected function doExport(): array { return [ 'name' => $this->name, 'description' => $this->description, 'externalDocs' => $this->externalDocs, ]; } /** * @return string */ public function getName(): string { return $this->name; } /** * @param string|array $data * * @return array */ protected function normalize($data): array { if (is_string($data)) { return [ 'name' => $data, ]; } return parent::normalize($data); } } ================================================ FILE: src/Util/MergeHelper.php ================================================ assertEquals($this->fileToArray($filename), $swagger->toArray()); } } ================================================ FILE: tests/CollectionsTest.php ================================================ getDefinitions(); $this->assertInstanceOf(Definitions::class, $definitions); $this->assertNull($definitions->toArray()); $this->assertFalse($definitions->has('User')); $user = new Schema(); $definitions->set('User', $user); $this->assertCount(1, $definitions->toArray()); $this->assertTrue($definitions->has('User')); $this->assertSame($user, $definitions->get('User')); $this->assertInternalType('array', $definitions->toArray()['User']); $definitions->remove('User'); $this->assertNull($definitions->toArray()); $this->assertFalse($definitions->has('User')); } public function testPaths() { $swagger = new Swagger(); $paths = $swagger->getPaths(); $this->assertInstanceOf(Paths::class, $paths); $this->assertNull($paths->toArray()); $this->assertFalse($paths->has('/pets')); $pets = new Path(); $paths->set('/pets', $pets); $this->assertCount(1, $paths->toArray()); $this->assertTrue($paths->has('/pets')); $this->assertSame($pets, $paths->get('/pets')); $this->assertInternalType('array', $paths->toArray()['/pets']); $paths->remove('/pets'); $this->assertNull($paths->toArray()); $this->assertFalse($paths->has('/pets')); } public function testParameters() { $path = new Path(); $parameters = $path->getOperation('get')->getParameters(); $this->assertInstanceOf(Parameters::class, $parameters); $this->assertNull($parameters->toArray()); $id = new Parameter([ 'name' => 'id', 'in' => 'path', ]); $parameters->add($id); $this->assertCount(1, $parameters->toArray()); $this->assertTrue($parameters->has('id', 'path')); $id2 = new Parameter([ 'name' => 'id', 'in' => 'body', ]); $parameters->add($id2); $this->assertCount(2, $parameters->toArray()); $this->assertTrue($parameters->has('id', 'body')); $this->assertSame($id, $parameters->get('id', 'path')); $this->assertSame($id2, $parameters->get('id', 'body')); $parameter = $parameters->get('bar', 'query'); $this->assertEquals('bar', $parameter->getName()); $this->assertEquals('query', $parameter->getIn()); $this->assertInternalType('array', $parameters->toArray()[0]); $this->assertInternalType('array', $parameters->toArray()[1]); $parameters->remove($id); $parameters->remove($id2); $parameters->remove($parameter); $this->assertNull($parameters->toArray()); // test $ref $parameters->setRef('#/definitions/id'); $this->assertEquals(['$ref' => '#/definitions/id'], $parameters->toArray()); } public function testResponses() { $operation = new Operation(); $responses = $operation->getResponses(); $this->assertInstanceOf(Responses::class, $responses); $this->assertCount(0, $responses->toArray()); $this->assertFalse($responses->has('200')); $ok = new Response(); $responses->set('200', $ok); $this->assertCount(1, $responses->toArray()); $this->assertTrue($responses->has('200')); $this->assertInstanceOf(Response::class, $responses->get('200')); $this->assertSame($ok, $responses->get('200')); $this->assertInternalType('array', $responses->toArray()['200']); $responses->remove('200'); $this->assertCount(0, $responses->toArray()); $this->assertFalse($responses->has('200')); } } ================================================ FILE: tests/KeekoTest.php ================================================ assertEquals($this->fileToArray($filename), $swagger->toArray()); } } ================================================ FILE: tests/PetstoreTest.php ================================================ assertEquals($this->fileToArray($filename), $swagger->toArray()); } public function testSimple() { $filename = __DIR__.'/fixtures/petstore-simple.json'; $swagger = Swagger::fromFile($filename); $this->assertEquals($this->fileToArray($filename), $swagger->toArray()); } public function testParameterRefs() { $filename = __DIR__.'/fixtures/petstore-parameter-refs.json'; $swagger = Swagger::fromFile($filename); $this->assertEquals($this->fileToArray($filename), $swagger->toArray()); } public function testPetstore() { $filename = __DIR__.'/fixtures/petstore.json'; $swagger = Swagger::fromFile($filename); $this->assertEquals($this->fileToArray($filename), $swagger->toArray()); $responses = $swagger->getPaths()->get('/pets')->getOperation('get')->getResponses(); $headers = $responses->get('200')->getHeaders(); $this->assertEquals(1, count($headers->toArray())); $this->assertTrue($headers->has('x-expires')); $expires = $headers->get('x-expires'); $this->assertEquals('string', $expires->getType()); $headers->remove('x-expires'); $this->assertNull($headers->toArray()); $this->assertFalse($headers->has('x-expires')); $headers->set('x-expires', $expires); $this->assertCount(1, $headers->toArray()); $this->assertTrue($headers->has('x-expires')); } public function testExpanded() { $filename = __DIR__.'/fixtures/petstore-expanded.json'; $swagger = Swagger::fromFile($filename); $this->assertEquals($this->fileToArray($filename), $swagger->toArray()); } public function testExternalDocs() { $filename = __DIR__.'/fixtures/petstore-with-external-docs.json'; $swagger = Swagger::fromFile($filename); $this->assertEquals($this->fileToArray($filename), $swagger->toArray()); $external = $swagger->getExternalDocs(); $this->assertEquals('find more info here', $external->getDescription()); $this->assertEquals('https://Swagger.io/about', $external->getUrl()); $info = $swagger->getInfo(); $this->assertEquals('1.0.0', $info->getVersion()); $this->assertEquals('Swagger Petstore', $info->getTitle()); $this->assertEquals('A sample API that uses a petstore as an example to demonstrate features in the Swagger-2.0 specification', $info->getDescription()); $this->assertEquals('http://Swagger.io/terms/', $info->getTerms()); $this->assertEquals('1.0.1', $info->setVersion('1.0.1')->getVersion()); $this->assertEquals('Pets', $info->setTitle('Pets')->getTitle()); $this->assertEquals('desc', $info->setDescription('desc')->getDescription()); $this->assertEquals('T-O-S', $info->setTerms('T-O-S')->getTerms()); $contact = $info->getContact(); $this->assertEquals('Swagger API Team', $contact->getName()); $this->assertEquals('apiteam@Swagger.io', $contact->getEmail()); $this->assertEquals('http://Swagger.io', $contact->getUrl()); $this->assertEquals('Swaggers', $contact->setName('Swaggers')->getName()); $this->assertEquals('team@Swagger.io', $contact->setEmail('team@Swagger.io')->getEmail()); $this->assertEquals('https://Swagger.io', $contact->setUrl('https://Swagger.io')->getUrl()); $license = $info->getLicense(); $this->assertEquals('MIT', $license->getName()); $this->assertEquals('http://github.com/gruntjs/grunt/blob/master/LICENSE-MIT', $license->getUrl()); $this->assertEquals('APL', $license->setName('APL')->getName()); $this->assertEquals('https://www.apache.org/licenses/LICENSE-2.0', $license->setUrl('https://www.apache.org/licenses/LICENSE-2.0')->getUrl()); } public function testDictionaries() { $filename = __DIR__.'/fixtures/petstore-dictionaries.json'; $swagger = Swagger::fromFile($filename); $swaggerAsArray = $swagger->toArray(); $this->assertEquals($this->fileToArray($filename), $swaggerAsArray); $this->assertInstanceOf(Schema::class, $swagger->getDefinitions()->get('Pet')->getProperties()->get('sub-object')->getAdditionalProperties()); $this->assertSame(true, $swaggerAsArray['definitions']['Pet']['properties']['sub-object']['additionalProperties']); $this->assertSame(null, $swagger->getDefinitions()->get('Pet')->getProperties()->get('sub-object')->getAdditionalProperties()->getType()); $this->assertSame(null, $swagger->getDefinitions()->get('Pet')->getProperties()->get('sub-object')->getAdditionalProperties()->getAdditionalProperties()); $this->assertSame('string', $swagger->getDefinitions()->get('Pet')->getProperties()->get('another-sub-object')->getAdditionalProperties()->getType()); $this->assertSame(null, $swagger->getDefinitions()->get('Pet')->getProperties()->get('another-sub-object')->getAdditionalProperties()->getAdditionalProperties()); $this->assertSame('object', $swagger->getDefinitions()->get('Pet')->getProperties()->get('nested-sub-objects')->getAdditionalProperties()->getType()); $this->assertInstanceOf(Schema::class, $swagger->getDefinitions()->get('Pet')->getProperties()->get('nested-sub-objects')->getAdditionalProperties()->getAdditionalProperties()); $this->assertSame('string', $swagger->getDefinitions()->get('Pet')->getProperties()->get('nested-sub-objects')->getAdditionalProperties()->getAdditionalProperties()->getType()); $this->assertSame('string', $swaggerAsArray['definitions']['Pet']['properties']['nested-sub-objects']['additionalProperties']['additionalProperties']['type']); $this->assertSame('array', $swagger->getDefinitions()->get('Pet')->getProperties()->get('children')->getType()); $this->assertSame('array', $swaggerAsArray['definitions']['Pet']['properties']['children']['type']); $this->assertInstanceOf(Schema::class, $swagger->getDefinitions()->get('Pet')->getProperties()->get('children')->getItems()); $this->assertSame('#/definitions/Pet', $swagger->getDefinitions()->get('Pet')->getProperties()->get('children')->getItems()->getRef()); $this->assertSame('#/definitions/Pet', $swaggerAsArray['definitions']['Pet']['properties']['children']['items']['$ref']); $this->assertSame('object', $swaggerAsArray['definitions']['Pet']['properties']['child-pet']['type']); $this->assertInstanceOf(Schema::class, $swagger->getDefinitions()->get('Pet')->getProperties()->get('child-pet')->getProperties()->get('name')); $this->assertSame('string', $swagger->getDefinitions()->get('Pet')->getProperties()->get('child-pet')->getAdditionalProperties()->getProperties()->get('name')->getType()); $this->assertSame('string', $swaggerAsArray['definitions']['Pet']['properties']['child-pet']['additionalProperties']['properties']['name']['type']); $this->assertSame('object', $swagger->getDefinitions()->get('Pet')->getProperties()->get('child-pet')->getAdditionalProperties()->getProperties()->get('child-pet-children')->getType()); $this->assertSame('string', $swagger->getDefinitions()->get('Pet')->getProperties()->get('child-pet')->getAdditionalProperties()->getProperties()->get('child-pet-children')->getAdditionalProperties()->getType()); $this->assertSame('object', $swagger->getDefinitions()->get('Pet')->getProperties()->get('child-pet')->getAdditionalProperties()->getProperties()->get('sub-object')->getType()); $this->assertSame(true, $swaggerAsArray['definitions']['Pet']['properties']['child-pet']['additionalProperties']['properties']['sub-object']['additionalProperties']); } } ================================================ FILE: tests/SwaggerTest.php ================================================ assertEquals('2.0', $swagger->getVersion()); } public function testBasics() { $swagger = new Swagger(); $swagger->setBasePath('/api'); $swagger->setHost('http://example.com'); $this->assertEquals('/api', $swagger->getBasePath()); $this->assertEquals('http://example.com', $swagger->getHost()); $this->assertEquals([ 'swagger' => '2.0', 'host' => 'http://example.com', 'basePath' => '/api', ], $swagger->toArray()); } } ================================================ FILE: tests/fixtures/basic-auth.json ================================================ { "swagger": "2.0", "info": { "version": "1.0.0", "title": "Basic Auth Example", "description": "An example for how to use Basic Auth with Swagger.\nServer code is available [here](https://github.com/mohsen1/basic-auth-server). It's running on Heroku.\n\n**User Name and Password**\n* User Name: `user`\n* Password: `pass`\n" }, "host": "basic-auth-server.herokuapp.com", "schemes": [ "http", "https" ], "securityDefinitions": { "basicAuth": { "type": "basic", "description": "HTTP Basic Authentication. Works over `HTTP` and `HTTPS`" } }, "paths": { "/": { "get": { "security": [ { "basicAuth": [] } ], "responses": { "200": { "description": "Will send `Authenticated` if authentication is succesful, otherwise it will send `Unauthorized`" } } } } } } ================================================ FILE: tests/fixtures/keeko-user.json ================================================ { "swagger": "2.0", "paths": { "/users": { "get": { "description": "List all users", "operationId": "user-list", "produces": [ "application/json" ], "responses": { "200": { "description": "Array of users", "schema": { "$ref": "#/definitions/PagedUsers" } } } }, "post": { "description": "Creates an user", "operationId": "user-create", "schemes": ["https", "wss"], "produces": [ "application/json" ], "parameters": [ { "name": "body", "in": "body", "required": true, "description": "The new user", "schema": { "$ref": "#/definitions/WritableUser" } } ], "responses": { "201": { "description": "user created" } } } }, "/users/{id}": { "get": { "description": "Reads an user", "operationId": "user-read", "produces": [ "application/json" ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The user id", "type": "integer" } ], "responses": { "200": { "description": "gets the user", "schema": { "$ref": "#/definitions/User" } }, "400": { "description": "Invalid ID supplied" }, "404": { "description": "No user found" } } }, "put": { "description": "Updates an user", "operationId": "user-update", "produces": [ "application/json" ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The user id", "type": "integer" } ], "responses": { "200": { "description": "user updated", "schema": { "$ref": "#/definitions/User" } }, "400": { "description": "Invalid ID supplied" }, "404": { "description": "No user found" } } }, "delete": { "description": "Deletes an user", "operationId": "user-delete", "produces": [ "application/json" ], "parameters": [ { "name": "id", "in": "path", "required": true, "description": "The user id", "type": "integer" } ], "responses": { "204": { "description": "user deleted" }, "400": { "description": "Invalid ID supplied" }, "404": { "description": "No user found" } } } } }, "definitions": { "Meta": { "properties": { "total": { "type": "integer" }, "first": { "type": "integer" }, "next": { "type": "integer" }, "previous": { "type": "integer" }, "last": { "type": "integer" } } }, "PagedUsers": { "properties": { "users": { "type": "array", "items": { "$ref": "#/definitions/User" } }, "meta": { "$ref": "#/definitions/Meta" } } }, "WritableUser": { "properties": { "id": { "type": "int" }, "login_name": { "type": "string" }, "password": { "type": "string" }, "given_name": { "type": "string" }, "family_name": { "type": "string" }, "display_name": { "type": "string" }, "email": { "type": "string" }, "birthday": { "type": "string" }, "sex": { "type": "int" }, "password_recover_code": { "type": "string" }, "password_recover_time": { "type": "string" } } }, "User": { "properties": { "id": { "type": "int" }, "login_name": { "type": "string" }, "password": { "type": "string" }, "given_name": { "type": "string" }, "family_name": { "type": "string" }, "display_name": { "type": "string" }, "email": { "type": "string" }, "birthday": { "type": "string" }, "sex": { "type": "int" }, "password_recover_code": { "type": "string" }, "password_recover_time": { "type": "string" }, "created_at": { "type": "string" }, "updated_at": { "type": "string" } } } } } ================================================ FILE: tests/fixtures/petstore-dictionaries.json ================================================ { "swagger": "2.0", "info": { "version": "1.0.0", "title": "Swagger Petstore", "contact": { "name": "Swagger API Team", "url": "http://Swagger.io" }, "license": { "name": "Creative Commons 4.0 International", "url": "http://creativecommons.org/licenses/by/4.0/" } }, "host": "petstore.Swagger.io", "basePath": "/api", "schemes": [ "http" ], "paths": { "/pets": { "get": { "description": "Returns all pets from the system that the user has access to", "produces": [ "application/json" ], "responses": { "200": { "description": "A list of pets.", "schema": { "type": "array", "items": { "$ref": "#/definitions/Pet" } } } } } } }, "definitions": { "Pet": { "type": "object", "properties": { "sub-object": { "type": "object", "additionalProperties": true }, "another-sub-object": { "type": "object", "additionalProperties": { "type": "string" } }, "nested-sub-objects": { "type": "object", "additionalProperties": { "type": "object", "additionalProperties": { "type": "string" } } }, "children": { "items": { "$ref": "#/definitions/Pet" }, "type": "array" }, "child-pet": { "type": "object", "additionalProperties": { "properties": { "name": { "type": "string" }, "child-pet-children": { "type": "object", "additionalProperties": { "type": "string" } }, "sub-object": { "type": "object", "additionalProperties": true } } } } } } } } ================================================ FILE: tests/fixtures/petstore-expanded.json ================================================ { "swagger": "2.0", "info": { "version": "1.0.0", "title": "Swagger Petstore", "description": "A sample API that uses a petstore as an example to demonstrate features in the Swagger-2.0 specification", "termsOfService": "http://Swagger.io/terms/", "contact": { "name": "Swagger API Team", "email": "foo@example.com", "url": "http://madskristensen.net" }, "license": { "name": "MIT", "url": "http://github.com/gruntjs/grunt/blob/master/LICENSE-MIT" } }, "host": "petstore.Swagger.io", "basePath": "/api", "schemes": [ "http" ], "consumes": [ "application/json" ], "produces": [ "application/json" ], "paths": { "/pets": { "get": { "description": "Returns all pets from the system that the user has access to\nNam sed condimentum est. Maecenas tempor sagittis sapien, nec rhoncus sem sagittis sit amet. Aenean at gravida augue, ac iaculis sem. Curabitur odio lorem, ornare eget elementum nec, cursus id lectus. Duis mi turpis, pulvinar ac eros ac, tincidunt varius justo. In hac habitasse platea dictumst. Integer at adipiscing ante, a sagittis ligula. Aenean pharetra tempor ante molestie imperdiet. Vivamus id aliquam diam. Cras quis velit non tortor eleifend sagittis. Praesent at enim pharetra urna volutpat venenatis eget eget mauris. In eleifend fermentum facilisis. Praesent enim enim, gravida ac sodales sed, placerat id erat. Suspendisse lacus dolor, consectetur non augue vel, vehicula interdum libero. Morbi euismod sagittis libero sed lacinia.\n\nSed tempus felis lobortis leo pulvinar rutrum. Nam mattis velit nisl, eu condimentum ligula luctus nec. Phasellus semper velit eget aliquet faucibus. In a mattis elit. Phasellus vel urna viverra, condimentum lorem id, rhoncus nibh. Ut pellentesque posuere elementum. Sed a varius odio. Morbi rhoncus ligula libero, vel eleifend nunc tristique vitae. Fusce et sem dui. Aenean nec scelerisque tortor. Fusce malesuada accumsan magna vel tempus. Quisque mollis felis eu dolor tristique, sit amet auctor felis gravida. Sed libero lorem, molestie sed nisl in, accumsan tempor nisi. Fusce sollicitudin massa ut lacinia mattis. Sed vel eleifend lorem. Pellentesque vitae felis pretium, pulvinar elit eu, euismod sapien.\n", "operationId": "findPets", "parameters": [ { "name": "tags", "in": "query", "description": "tags to filter by", "required": false, "type": "array", "collectionFormat": "csv", "items": { "type": "string" } }, { "name": "limit", "in": "query", "description": "maximum number of results to return", "required": false, "type": "integer", "format": "int32" } ], "responses": { "200": { "description": "pet response", "schema": { "type": "array", "items": { "$ref": "#/definitions/Pet" } } }, "default": { "description": "unexpected error", "schema": { "$ref": "#/definitions/Error" } } } }, "post": { "description": "Creates a new pet in the store. Duplicates are allowed", "operationId": "addPet", "parameters": [ { "name": "pet", "in": "body", "description": "Pet to add to the store", "required": true, "schema": { "$ref": "#/definitions/NewPet" } } ], "responses": { "200": { "description": "pet response", "schema": { "$ref": "#/definitions/Pet" } }, "default": { "description": "unexpected error", "schema": { "$ref": "#/definitions/Error" } } } } }, "/pets/{id}": { "get": { "description": "Returns a user based on a single ID, if the user does not have access to the pet", "operationId": "find pet by id", "parameters": [ { "name": "id", "in": "path", "description": "ID of pet to fetch", "required": true, "type": "integer", "format": "int64" } ], "responses": { "200": { "description": "pet response", "schema": { "$ref": "#/definitions/Pet" } }, "default": { "description": "unexpected error", "schema": { "$ref": "#/definitions/Error" } } } }, "delete": { "description": "deletes a single pet based on the ID supplied", "operationId": "deletePet", "parameters": [ { "name": "id", "in": "path", "description": "ID of pet to delete", "required": true, "type": "integer", "format": "int64" } ], "responses": { "204": { "description": "pet deleted" }, "default": { "description": "unexpected error", "schema": { "$ref": "#/definitions/Error" } } } } } }, "definitions": { "Pet": { "type": "object", "allOf": [ { "$ref": "#/definitions/NewPet" }, { "required": [ "id" ], "properties": { "id": { "type": "integer", "format": "int64" } } } ] }, "NewPet": { "type": "object", "required": [ "name" ], "properties": { "name": { "type": "string" }, "tag": { "type": "string" } } }, "Error": { "type": "object", "required": [ "code", "message" ], "properties": { "code": { "type": "integer", "format": "int32" }, "message": { "type": "string" } } } } } ================================================ FILE: tests/fixtures/petstore-minimal.json ================================================ { "swagger": "2.0", "info": { "version": "1.0.0", "title": "Swagger Petstore", "description": "A sample API that uses a petstore as an example to demonstrate features in the Swagger-2.0 specification", "termsOfService": "http://Swagger.io/terms/", "contact": { "name": "Swagger API Team" }, "license": { "name": "MIT" } }, "host": "petstore.Swagger.io", "basePath": "/api", "schemes": [ "http" ], "consumes": [ "application/json" ], "produces": [ "application/json" ], "paths": { "/pets": { "get": { "description": "Returns all pets from the system that the user has access to", "produces": [ "application/json" ], "responses": { "200": { "description": "A list of pets.", "schema": { "type": "array", "items": { "$ref": "#/definitions/Pet" } } } } } } }, "definitions": { "Pet": { "type": "object", "required": [ "id", "name" ], "properties": { "id": { "type": "integer", "format": "int64" }, "name": { "type": "string" }, "tag": { "type": "string" } } } } } ================================================ FILE: tests/fixtures/petstore-parameter-refs.json ================================================ { "swagger": "2.0", "info": { "version": "1.0.0", "title": "Swagger Petstore", "description": "A sample API that uses a petstore as an example to demonstrate features in the Swagger-2.0 specification", "termsOfService": "http://Swagger.io/terms/", "contact": { "name": "Swagger API Team" }, "license": { "name": "MIT" } }, "host": "petstore.Swagger.io", "basePath": "/api", "schemes": [ "http" ], "consumes": [ "application/json" ], "produces": [ "application/json" ], "paths": { "/pets": { "get": { "description": "Returns all pets from the system that the user has access to", "operationId": "findPets", "produces": [ "application/json", "application/xml", "text/xml", "text/html" ], "parameters": [ { "name": "tags", "in": "query", "description": "tags to filter by", "required": false, "type": "array", "items": { "type": "string" }, "collectionFormat": "csv" }, { "name": "limit", "in": "query", "description": "maximum number of results to return", "required": false, "type": "integer", "format": "int32" } ], "responses": { "200": { "description": "pet response", "schema": { "type": "array", "items": { "$ref": "#/definitions/Pet" } } }, "default": { "description": "unexpected error", "schema": { "$ref": "#/definitions/ErrorModel" } } } }, "post": { "description": "Creates a new pet in the store. Duplicates are allowed", "operationId": "addPet", "produces": [ "application/json" ], "parameters": [ { "name": "pet", "in": "body", "description": "Pet to add to the store", "required": true, "schema": { "$ref": "#/definitions/PetInput" } } ], "responses": { "200": { "description": "pet response", "schema": { "$ref": "#/definitions/Pet" } }, "default": { "description": "unexpected error", "schema": { "$ref": "#/definitions/ErrorModel" } } } } }, "/pets/{id}": { "get": { "description": "Returns a user based on a single ID, if the user does not have access to the pet", "operationId": "findPetById", "produces": [ "application/json", "application/xml", "text/xml", "text/html" ], "parameters": [ { "$ref": "#/parameters/petId" } ], "responses": { "200": { "description": "pet response", "schema": { "$ref": "#/definitions/Pet" } }, "default": { "description": "unexpected error", "schema": { "$ref": "#/definitions/ErrorModel" } } } }, "delete": { "description": "deletes a single pet based on the ID supplied", "operationId": "deletePet", "parameters": [ { "$ref": "#/parameters/petId" } ], "responses": { "204": { "description": "pet deleted" }, "default": { "description": "unexpected error", "schema": { "$ref": "#/definitions/ErrorModel" } } } } } }, "definitions": { "Pet": { "type": "object", "required": [ "id", "name" ], "properties": { "id": { "type": "integer", "format": "int64" }, "name": { "type": "string" }, "tag": { "type": "string" } } }, "PetInput": { "type": "object", "allOf": [ { "$ref": "#/definitions/Pet" }, { "required": [ "name" ], "properties": { "id": { "type": "integer", "format": "int64" } } } ] }, "ErrorModel": { "type": "object", "required": [ "code", "message" ], "properties": { "code": { "type": "integer", "format": "int32" }, "message": { "type": "string" } } } }, "parameters": { "petId": { "name": "id", "in": "path", "description": "Pet ID", "required": true, "type": "integer", "format": "int64" } } } ================================================ FILE: tests/fixtures/petstore-simple.json ================================================ { "swagger": "2.0", "info": { "version": "1.0.0", "title": "Swagger Petstore", "description": "A sample API that uses a petstore as an example to demonstrate features in the Swagger-2.0 specification", "termsOfService": "http://Swagger.io/terms/", "contact": { "name": "Swagger API Team" }, "license": { "name": "MIT" } }, "host": "petstore.Swagger.io", "basePath": "/api", "schemes": [ "http" ], "consumes": [ "application/json" ], "produces": [ "application/json" ], "paths": { "/pets": { "get": { "description": "Returns all pets from the system that the user has access to", "operationId": "findPets", "produces": [ "application/json", "application/xml", "text/xml", "text/html" ], "parameters": [ { "name": "tags", "in": "query", "description": "tags to filter by", "required": false, "type": "array", "items": { "type": "string" }, "collectionFormat": "csv" }, { "name": "limit", "in": "query", "description": "maximum number of results to return", "required": false, "type": "integer", "format": "int32" } ], "responses": { "200": { "description": "pet response", "schema": { "type": "array", "items": { "$ref": "#/definitions/Pet" } } }, "default": { "description": "unexpected error", "schema": { "$ref": "#/definitions/ErrorModel" } } } }, "post": { "description": "Creates a new pet in the store. Duplicates are allowed", "operationId": "addPet", "produces": [ "application/json" ], "parameters": [ { "name": "pet", "in": "body", "description": "Pet to add to the store", "required": true, "schema": { "$ref": "#/definitions/PetInput" } } ], "responses": { "200": { "description": "pet response", "schema": { "$ref": "#/definitions/Pet" } }, "default": { "description": "unexpected error", "schema": { "$ref": "#/definitions/ErrorModel" } } } } }, "/pets/{id}": { "get": { "description": "Returns a user based on a single ID, if the user does not have access to the pet", "operationId": "findPetById", "produces": [ "application/json", "application/xml", "text/xml", "text/html" ], "parameters": [ { "name": "id", "in": "path", "description": "ID of pet to fetch", "required": true, "type": "integer", "format": "int64" } ], "responses": { "200": { "description": "pet response", "schema": { "$ref": "#/definitions/Pet" } }, "default": { "description": "unexpected error", "schema": { "$ref": "#/definitions/ErrorModel" } } } }, "delete": { "description": "deletes a single pet based on the ID supplied", "operationId": "deletePet", "parameters": [ { "name": "id", "in": "path", "description": "ID of pet to delete", "required": true, "type": "integer", "format": "int64" } ], "responses": { "204": { "description": "pet deleted" }, "default": { "description": "unexpected error", "schema": { "$ref": "#/definitions/ErrorModel" } } } } } }, "definitions": { "Pet": { "type": "object", "required": [ "id", "name" ], "properties": { "id": { "type": "integer", "format": "int64" }, "name": { "type": "string" }, "tag": { "type": "string" } } }, "PetInput": { "type": "object", "allOf": [ { "$ref": "#/definitions/Pet" }, { "required": [ "name" ], "properties": { "id": { "type": "integer", "format": "int64" } } } ] }, "ErrorModel": { "type": "object", "required": [ "code", "message" ], "properties": { "code": { "type": "integer", "format": "int32" }, "message": { "type": "string" } } } } } ================================================ FILE: tests/fixtures/petstore-with-external-docs.json ================================================ { "swagger": "2.0", "info": { "version": "1.0.0", "title": "Swagger Petstore", "description": "A sample API that uses a petstore as an example to demonstrate features in the Swagger-2.0 specification", "termsOfService": "http://Swagger.io/terms/", "contact": { "name": "Swagger API Team", "email": "apiteam@Swagger.io", "url": "http://Swagger.io" }, "license": { "name": "MIT", "url": "http://github.com/gruntjs/grunt/blob/master/LICENSE-MIT" } }, "externalDocs": { "description": "find more info here", "url": "https://Swagger.io/about" }, "host": "petstore.Swagger.io", "basePath": "/api", "schemes": [ "http" ], "consumes": [ "application/json" ], "produces": [ "application/json" ], "paths": { "/pets": { "get": { "description": "Returns all pets from the system that the user has access to", "operationId": "findPets", "externalDocs": { "description": "find more info here", "url": "https://Swagger.io/about" }, "produces": [ "application/json", "application/xml", "text/xml", "text/html" ], "parameters": [ { "name": "tags", "in": "query", "description": "tags to filter by", "required": false, "type": "array", "items": { "type": "string" }, "collectionFormat": "csv" }, { "name": "limit", "in": "query", "description": "maximum number of results to return", "required": false, "type": "integer", "format": "int32" } ], "responses": { "200": { "description": "pet response", "schema": { "type": "array", "items": { "$ref": "#/definitions/Pet" } } }, "default": { "description": "unexpected error", "schema": { "$ref": "#/definitions/ErrorModel" } } } }, "post": { "description": "Creates a new pet in the store. Duplicates are allowed", "operationId": "addPet", "produces": [ "application/json" ], "parameters": [ { "name": "pet", "in": "body", "description": "Pet to add to the store", "required": true, "schema": { "$ref": "#/definitions/NewPet" } } ], "responses": { "200": { "description": "pet response", "schema": { "$ref": "#/definitions/Pet" } }, "default": { "description": "unexpected error", "schema": { "$ref": "#/definitions/ErrorModel" } } } } }, "/pets/{id}": { "get": { "description": "Returns a user based on a single ID, if the user does not have access to the pet", "operationId": "findPetById", "produces": [ "application/json", "application/xml", "text/xml", "text/html" ], "parameters": [ { "name": "id", "in": "path", "description": "ID of pet to fetch", "required": true, "type": "integer", "format": "int64" } ], "responses": { "200": { "description": "pet response", "schema": { "$ref": "#/definitions/Pet" } }, "default": { "description": "unexpected error", "schema": { "$ref": "#/definitions/ErrorModel" } } } }, "delete": { "description": "deletes a single pet based on the ID supplied", "operationId": "deletePet", "parameters": [ { "name": "id", "in": "path", "description": "ID of pet to delete", "required": true, "type": "integer", "format": "int64" } ], "responses": { "204": { "description": "pet deleted" }, "default": { "description": "unexpected error", "schema": { "$ref": "#/definitions/ErrorModel" } } } } } }, "definitions": { "Pet": { "type": "object", "required": [ "id", "name" ], "externalDocs": { "description": "find more info here", "url": "https://Swagger.io/about" }, "properties": { "id": { "type": "integer", "format": "int64" }, "name": { "type": "string" }, "tag": { "type": "string" } } }, "NewPet": { "type": "object", "allOf": [ { "$ref": "#/definitions/Pet" }, { "required": [ "name" ], "properties": { "id": { "type": "integer", "format": "int64" } } } ] }, "ErrorModel": { "type": "object", "required": [ "code", "message" ], "properties": { "code": { "type": "integer", "format": "int32" }, "message": { "type": "string" } } } } } ================================================ FILE: tests/fixtures/petstore.json ================================================ { "swagger": "2.0", "info": { "version": "1.0.0", "title": "Swagger Petstore", "contact": { "name": "Swagger API Team", "url": "http://Swagger.io" }, "license": { "name": "Creative Commons 4.0 International", "url": "http://creativecommons.org/licenses/by/4.0/" } }, "host": "petstore.Swagger.io", "basePath": "/api", "schemes": [ "http" ], "paths": { "/pets": { "get": { "tags": [ "Pet Operations" ], "summary": "finds pets in the system", "responses": { "200": { "description": "pet response", "schema": { "type": "array", "items": { "$ref": "#/definitions/Pet" } }, "headers": { "x-expires": { "type": "string" } } }, "default": { "description": "unexpected error", "schema": { "$ref": "#/definitions/Error" } } } } } }, "definitions": { "Pet": { "type": "object", "required": [ "id", "name" ], "properties": { "id": { "type": "integer", "format": "int64" }, "name": { "type": "string" }, "tag": { "type": "string" } } }, "Error": { "type": "object", "required": [ "code", "message" ], "properties": { "code": { "type": "integer", "format": "int32" }, "message": { "type": "string" } } } } }