From 9845eae45132b3cd6cc24232dc96a841d02a61e9 Mon Sep 17 00:00:00 2001 From: Jon Ursenbach Date: Sat, 24 Mar 2018 00:06:52 -0400 Subject: [PATCH 01/53] Renaming `@api-throws` to `@api-error`. https://github.com/vimeo/mill/issues/141 --- docs/_layouts/default.html | 2 +- docs/configuration.md | 8 +- docs/getting-started.md | 2 +- docs/reference.md | 2 +- docs/reference/actions.md | 2 +- .../reference/{api-throws.md => api-error.md} | 22 +- docs/reference/api-minversion.md | 2 +- docs/reference/api-return.md | 2 +- docs/reference/api-scope.md | 2 +- docs/reference/deprecation.md | 2 +- docs/reference/versioning.md | 2 +- docs/reference/visibility.md | 6 +- .../examples/Showtimes/Controllers/Movie.php | 22 +- .../examples/Showtimes/Controllers/Movies.php | 7 +- .../Showtimes/Controllers/Theater.php | 14 +- .../Showtimes/Controllers/Theaters.php | 5 +- .../changelog-public-only-all-capabilities.md | 4 +- ...c-only-matched-with-delete-capabilities.md | 4 +- ...d-with-tickets-and-feature-capabilities.md | 4 +- .../Showtimes/blueprints/changelog.md | 6 +- ...issingRepresentationErrorCodeException.php | 2 +- .../UncallableErrorCodeException.php | 2 +- .../UnknownErrorRepresentationException.php | 2 +- src/Generator/Blueprint.php | 10 +- src/Generator/Changelog.php | 14 +- .../{ActionThrows.php => ActionError.php} | 8 +- src/Generator/Changelog/Formats/Json.php | 4 +- src/Generator/ErrorMap.php | 6 +- ...rowsAnnotation.php => ErrorAnnotation.php} | 24 +-- src/Parser/Resource/Action/Documentation.php | 8 +- .../Generator/Changelog/Formats/JsonTest.php | 6 +- tests/Generator/ChangelogTest.php | 73 ++++--- tests/GeneratorTest.php | 22 +- ...tationTest.php => ErrorAnnotationTest.php} | 36 ++-- .../Resource/Action/DocumentationTest.php | 198 +++++++++--------- tests/ParserTest.php | 24 +-- 36 files changed, 275 insertions(+), 284 deletions(-) rename docs/reference/{api-throws.md => api-error.md} (72%) rename src/Generator/Changelog/Changesets/{ActionThrows.php => ActionError.php} (89%) rename src/Parser/Annotations/{ThrowsAnnotation.php => ErrorAnnotation.php} (90%) rename tests/Parser/Annotations/{ThrowsAnnotationTest.php => ErrorAnnotationTest.php} (93%) diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html index 448a15f..2c57201 100644 --- a/docs/_layouts/default.html +++ b/docs/_layouts/default.html @@ -38,12 +38,12 @@ diff --git a/docs/configuration.md b/docs/configuration.md index 4f37f7a..9fb2939 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -81,7 +81,7 @@ controllers return), live. #### Errors The representation `` setting lets you tell Mill where your error representations are (the content that is -returned from [`@api-throws`]({{ site.github.url }}/reference/api-throws) annotations. Here you can specify a `` +returned from [`@api-error`]({{ site.github.url }}/reference/api-error) annotations. Here you can specify a `` with a fully-qualified class name. Required attributes for the `` element are: @@ -95,8 +95,8 @@ Required attributes for the `` element are: /** * … * - * @api-throws:public {403} \ErrorRepresentation (\AppError::USER_NOT_ALLOWED) - * If the user isn't allowed to do something. + * @api-error:public {403} \ErrorRepresentation (\AppError::USER_NOT_ALLOWED) If + * the user isn't allowed to do something. */ public function PATCH() { @@ -120,7 +120,7 @@ specific users, you should use this to document that. You can find usage details for capabilities in the [`@api-capability`]({{ site.github.url }}/reference/api-capability), [`@api-param`]({{ site.github.url }}/reference/api-param), [`@api-return`]({{ site.github.url }}/reference/api-return), -and [`@api-throws`]({{ site.github.url }}/reference/api-throws) documentation. +and [`@api-error`]({{ site.github.url }}/reference/api-error) documentation. ### Scopes If your API has an authentication system that requires a specific scope(s) for using an API endpoint, use this to diff --git a/docs/getting-started.md b/docs/getting-started.md index 5bbef74..5450a6b 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -90,7 +90,7 @@ class UsersController extends \MyApplication\Controller * * @api-return:public {collection} \MyApplication\Representation\User * - * @api-throws:public {503} \MyApplication\Representation\Error If search + * @api-error:public {503} \MyApplication\Representation\Error If search * is disabled. */ public function GET() diff --git a/docs/reference.md b/docs/reference.md index 0604800..8a160cb 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -22,12 +22,12 @@ title: "Reference" | :--- | :--- | | [`@api-capability`]({{ site.github.url }}/reference/api-capability) | Denotes a required API capability for the action. | | [`@api-contenttype`]({{ site.github.url }}/reference/api-contenttype) | Denotes the `Content-Type` returned. | +| [`@api-error`]({{ site.github.url }}/reference/api-error) | An exception or error that may be thrown in the action. | | [`@api-label`]({{ site.github.url }}/reference/api-label) | Short description of what the resource action handles. | | [`@api-minversion`]({{ site.github.url }}/reference/api-minversion) | Minimum version required for this action. | | [`@api-param`]({{ site.github.url }}/reference/api-param) | A request parameter for this action. | | [`@api-return`]({{ site.github.url }}/reference/api-return) | A representation that is returned in a request. | | [`@api-scope`]({{ site.github.url }}/reference/api-scope) | Required authentication token scope necessary for the action. | -| [`@api-throws`]({{ site.github.url }}/reference/api-throws) | An exception or error that may be thrown in the action. | | [`@api-uri`]({{ site.github.url }}/reference/api-uri) | Denotes a URI that this action services. | | [`@api-urisegment`]({{ site.github.url }}/reference/api-urisegment) | Describes parameters for the URI. | diff --git a/docs/reference/actions.md b/docs/reference/actions.md index 0cb14ed..45d6fc9 100644 --- a/docs/reference/actions.md +++ b/docs/reference/actions.md @@ -11,11 +11,11 @@ permalink: /reference/resource-actions | :--- | :--- | | [`@api-capability`]({{ site.github.url }}/reference/api-capability) | Denotes a required API capability for the action. | | [`@api-contenttype`]({{ site.github.url }}/reference/api-contenttype) | Denotes the `Content-Type` returned. | +| [`@api-error`]({{ site.github.url }}/reference/api-error) | An exception or error that may be thrown in the action. | | [`@api-label`]({{ site.github.url }}/reference/api-label) | Short description of what the resource action handles. | | [`@api-minversion`]({{ site.github.url }}/reference/api-minversion) | Minimum version required for this action. | | [`@api-param`]({{ site.github.url }}/reference/api-param) | A request parameter for this action. | | [`@api-return`]({{ site.github.url }}/reference/api-return) | A representation that is returned in a request. | | [`@api-scope`]({{ site.github.url }}/reference/api-scope) | Required authentication token scope necessary for the action. | -| [`@api-throws`]({{ site.github.url }}/reference/api-throws) | An exception or error that may be thrown in the action. | | [`@api-uri`]({{ site.github.url }}/reference/api-uri) | Denotes a URI that this action services. | | [`@api-urisegment`]({{ site.github.url }}/reference/api-urisegment) | Describes parameters for the URI. | diff --git a/docs/reference/api-throws.md b/docs/reference/api-error.md similarity index 72% rename from docs/reference/api-throws.md rename to docs/reference/api-error.md index f6df350..52796f1 100644 --- a/docs/reference/api-throws.md +++ b/docs/reference/api-error.md @@ -1,17 +1,17 @@ --- layout: default -title: "@api-throws" -permalink: /reference/api-throws +title: "@api-error" +permalink: /reference/api-error --- -# @api-throws +# @api-error --- This represents an exception that may be thrown inside of a resource action. ## Syntax ```php -@api-throws:visibility {http code} \Representation (error code) +capability+ description +@api-error:visibility {http code} \Representation (error code) +capability+ description ``` ## Requirements @@ -31,11 +31,11 @@ This represents an exception that may be thrown inside of a resource action. | `description` | ✓ | A short description describing why, or what, this error is. | ## Types and subtypes -In addition to supporting straight descriptions, the [`@api-throws`]({{ site.github.url }}/reference/api-throws) annotation also supports +In addition to supporting straight descriptions, the [`@api-error`]({{ site.github.url }}/reference/api-error) annotation also supports the concept of "types" and "subtypes". For example: ```php -@api-throws:public {404} \ErrorRepresentation {user} +@api-error:public {404} \ErrorRepresentation {user} ``` In this case, this exception will be thrown when the `{user}` passed into the route (usually via the URI) is not found. @@ -44,7 +44,7 @@ The generated error message for this becomes: "If the user cannot be found." There also exist the concept of a subtype, represented as: ```php -@api-throws:public {404} \ErrorRepresentation {user,group} +@api-error:public {404} \ErrorRepresentation {user,group} ``` This means that if the supplied group could not be found for the supplied user, an exception will be thrown. The @@ -57,7 +57,7 @@ Usage with a capability and description type: /** * … * - * @api-throws:public {404} \ErrorRepresentation +SomeCapability+ {user} + * @api-error:public {404} \ErrorRepresentation +SomeCapability+ {user} */ public function PATCH() { @@ -71,8 +71,8 @@ With an error code: /** * … * - * @api-throws:public {403} \ErrorRepresentation (\AppError::USER_NOT_ALLOWED) - * If the user isn't allowed to do something. + * @api-error:public {403} \ErrorRepresentation (\AppError::USER_NOT_ALLOWED) If + * the user isn't allowed to do something. */ public function PATCH() { @@ -86,7 +86,7 @@ Standard usage: /** * … * - * @api-throws:public {404} \ErrorRepresentation If the user isn't allowed to do + * @api-error:public {404} \ErrorRepresentation If the user isn't allowed to do * something. */ public function PATCH() diff --git a/docs/reference/api-minversion.md b/docs/reference/api-minversion.md index 8a75edd..50ad71d 100644 --- a/docs/reference/api-minversion.md +++ b/docs/reference/api-minversion.md @@ -34,7 +34,7 @@ This allows you to denote the minimum API version required for a resource action * * @api-minversion 3.2 * - * @api-throws:private {403} \Some\ErrorErrorRepresentation If the user isn't + * @api-error:private {403} \Some\ErrorErrorRepresentation If the user isn't * allowed to do something. */ public function PATCH() diff --git a/docs/reference/api-return.md b/docs/reference/api-return.md index b86e1f8..f5bbb7f 100644 --- a/docs/reference/api-return.md +++ b/docs/reference/api-return.md @@ -56,7 +56,7 @@ application. | 304 Not Modified | notmodified | > **Note:** `@api-return` does not support returning 400 or 500 error codes. If you need those, use -> [`@api-throws`]({{ site.github.url }}/reference/api-throws) instead. +> [`@api-error`]({{ site.github.url }}/reference/api-error) instead. ## Examples ```php diff --git a/docs/reference/api-scope.md b/docs/reference/api-scope.md index d69f934..0c2877d 100644 --- a/docs/reference/api-scope.md +++ b/docs/reference/api-scope.md @@ -36,7 +36,7 @@ required for a resource action, or a representation data point. * * @api-scope edit * - * @api-throws:private {403} \Some\ErrorErrorRepresentation If the user isn't + * @api-error:private {403} \Some\ErrorErrorRepresentation If the user isn't * allowed to do something. */ public function PATCH() diff --git a/docs/reference/deprecation.md b/docs/reference/deprecation.md index a3fe39d..f6bf5a4 100644 --- a/docs/reference/deprecation.md +++ b/docs/reference/deprecation.md @@ -31,7 +31,7 @@ You might have instances where you need to deprecate a resource action request p * * @api-return:public {object} \MyApplication\Representations\Movie * - * @api-throws:public {404} \MyApplicationRepresentations\Error If the movie + * @api-error:public {404} \MyApplicationRepresentations\Error If the movie * could not be found. */ public function GET() diff --git a/docs/reference/versioning.md b/docs/reference/versioning.md index 5388b53..2c3a1ab 100644 --- a/docs/reference/versioning.md +++ b/docs/reference/versioning.md @@ -35,7 +35,7 @@ example: treated as being available across all versions. Versioning is currently only supported on [`@api-param`]({{ site.github.url }}/reference/api-param), -[`@api-return`]({{ site.github.url }}/reference/api-return), and [`@api-throws`]({{ site.github.url }}/reference/api-throws). +[`@api-return`]({{ site.github.url }}/reference/api-return), and [`@api-error`]({{ site.github.url }}/reference/api-error). ### Representations In representations, the [`@api-version`]({{ site.github.url }}/reference/api-version) annotation works as any other annotation. diff --git a/docs/reference/visibility.md b/docs/reference/visibility.md index 1574879..f53edb1 100644 --- a/docs/reference/visibility.md +++ b/docs/reference/visibility.md @@ -24,7 +24,7 @@ To choose what visibility your annotation should have, suffix your annotation wi * @api-uri:private {Films} /films/+id * @api-urisegment {/films/+id} id (integer) - Film ID * - * @api-throws:private {403} \Some\ErrorErrorRepresentation If the user isn't + * @api-error:private {403} \Some\ErrorErrorRepresentation If the user isn't * allowed to do something. */ public function PATCH() @@ -34,5 +34,5 @@ public function PATCH() ``` Visibility decorators are required on [`@api-param`]({{ site.github.url }}/reference/api-param), -[`@api-return`]({{ site.github.url }}/reference/api-return), -[`@api-throws`]({{ site.github.url }}/reference/api-throws), and [`@api-uri`]({{ site.github.url }}/reference/api-uri). +[`@api-return`]({{ site.github.url }}/reference/api-return), [`@api-error`]({{ site.github.url }}/reference/api-error), +and [`@api-uri`]({{ site.github.url }}/reference/api-uri). diff --git a/resources/examples/Showtimes/Controllers/Movie.php b/resources/examples/Showtimes/Controllers/Movie.php index 1a417e5..33a751b 100644 --- a/resources/examples/Showtimes/Controllers/Movie.php +++ b/resources/examples/Showtimes/Controllers/Movie.php @@ -35,7 +35,7 @@ class Movie * @api-return:public {object} \Mill\Examples\Showtimes\Representations\Movie * @api-return:public {notmodified} If no content has been modified since the supplied Last-Modified header. * - * @api-throws:public {404} \Mill\Examples\Showtimes\Representations\Error If the movie could not be found. + * @api-error:public {404} \Mill\Examples\Showtimes\Representations\Error If the movie could not be found. * * @api-version >=1.1.2 * @api-contentType application/mill.example.movie @@ -44,8 +44,8 @@ class Movie * @api-contentType application/json * * @api-version >=1.1.3 - * @api-throws:public {404} \Mill\Examples\Showtimes\Representations\Error For no reason. - * @api-throws:public {404} \Mill\Examples\Showtimes\Representations\Error For some other reason. + * @api-error:public {404} \Mill\Examples\Showtimes\Representations\Error For no reason. + * @api-error:public {404} \Mill\Examples\Showtimes\Representations\Error For some other reason. */ public function GET() { @@ -85,10 +85,9 @@ public function GET() * * @api-return:public {object} \Mill\Examples\Showtimes\Representations\Movie * - * @api-throws:public {400} \Mill\Examples\Showtimes\Representations\Error If there is a problem with the - * request. - * @api-throws:public {400} \Mill\Examples\Showtimes\Representations\Error If the IMDB URL could not be validated. - * @api-throws:public {404} \Mill\Examples\Showtimes\Representations\Error If the movie could not be found. + * @api-error:public {400} \Mill\Examples\Showtimes\Representations\Error If there is a problem with the request. + * @api-error:public {400} \Mill\Examples\Showtimes\Representations\Error If the IMDB URL could not be validated. + * @api-error:public {404} \Mill\Examples\Showtimes\Representations\Error If the movie could not be found. * * @api-version >=1.1.2 * @api-contentType application/mill.example.movie @@ -101,10 +100,9 @@ public function GET() * * @api-version >=1.1.3 * @api-return:public {accepted} \Mill\Examples\Showtimes\Representations\Movie - * @api-throws:public {404} \Mill\Examples\Showtimes\Representations\Error If the trailer URL could not be - * validated. - * @api-throws:private {403} \Mill\Examples\Showtimes\Representations\CodedError (1337) If something cool happened. - * @api-throws:public {403} \Mill\Examples\Showtimes\Representations\CodedError + * @api-error:public {404} \Mill\Examples\Showtimes\Representations\Error If the trailer URL could not be validated. + * @api-error:private {403} \Mill\Examples\Showtimes\Representations\CodedError (1337) If something cool happened. + * @api-error:public {403} \Mill\Examples\Showtimes\Representations\CodedError * (Mill\Examples\Showtimes\Representations\CodedError::DISALLOWED) If the user is not allowed to edit that * movie. */ @@ -128,7 +126,7 @@ public function PATCH() * * @api-return:private {deleted} * - * @api-throws:private {404} \Mill\Examples\Showtimes\Representations\Error If the movie could not be found. + * @api-error:private {404} \Mill\Examples\Showtimes\Representations\Error If the movie could not be found. */ public function DELETE() { diff --git a/resources/examples/Showtimes/Controllers/Movies.php b/resources/examples/Showtimes/Controllers/Movies.php index c99c3bd..4c6c70e 100644 --- a/resources/examples/Showtimes/Controllers/Movies.php +++ b/resources/examples/Showtimes/Controllers/Movies.php @@ -17,7 +17,7 @@ class Movies * * @api-return:public {collection} \Mill\Examples\Showtimes\Representations\Movie * - * @api-throws:public {400} \Mill\Examples\Showtimes\Representations\Error If the location is invalid. + * @api-error:public {400} \Mill\Examples\Showtimes\Representations\Error If the location is invalid. * * @api-version >=1.1.2 * @api-contentType application/mill.example.movie @@ -63,9 +63,8 @@ public function GET() * * @api-return:public {object} \Mill\Examples\Showtimes\Representations\Movie * - * @api-throws:public {400} \Mill\Examples\Showtimes\Representations\Error If there is a problem with the - * request. - * @api-throws:public {400} \Mill\Examples\Showtimes\Representations\Error If the IMDB URL could not be validated. + * @api-error:public {400} \Mill\Examples\Showtimes\Representations\Error If there is a problem with the request. + * @api-error:public {400} \Mill\Examples\Showtimes\Representations\Error If the IMDB URL could not be validated. * * @api-version >=1.1.2 * @api-contentType application/mill.example.movie diff --git a/resources/examples/Showtimes/Controllers/Theater.php b/resources/examples/Showtimes/Controllers/Theater.php index 00dd96a..74f4cd9 100644 --- a/resources/examples/Showtimes/Controllers/Theater.php +++ b/resources/examples/Showtimes/Controllers/Theater.php @@ -21,8 +21,7 @@ class Theater * @api-return:public {object} \Mill\Examples\Showtimes\Representations\Theater * @api-return:public {notmodified} If no content has been modified since the supplied Last-Modified header. * - * @api-throws:public {404} \Mill\Examples\Showtimes\Representations\Error If the movie theater could not be - * found. + * @api-error:public {404} \Mill\Examples\Showtimes\Representations\Error If the movie theater could not be found. * * @api-version >=1.1.2 * @api-contentType application/mill.example.theater @@ -51,17 +50,15 @@ public function GET() * * @api-return:public {object} \Mill\Examples\Showtimes\Representations\Theater * - * @api-throws:public {400} \Mill\Examples\Showtimes\Representations\Error If there is a problem with the - * request. - * @api-throws:public {404} \Mill\Examples\Showtimes\Representations\Error If the movie movie could not be - * found. + * @api-error:public {400} \Mill\Examples\Showtimes\Representations\Error If there is a problem with the request. + * @api-error:public {404} \Mill\Examples\Showtimes\Representations\Error If the movie movie could not be found. * * @api-version >=1.1.2 * @api-contentType application/mill.example.theater * * @api-version <1.1.2 * @api-contentType application/json - * @api-throws:public {403} \Mill\Examples\Showtimes\Representations\CodedError (1337) If something cool happened. + * @api-error:public {403} \Mill\Examples\Showtimes\Representations\CodedError (1337) If something cool happened. */ public function PATCH() { @@ -81,8 +78,7 @@ public function PATCH() * * @api-return:private {deleted} * - * @api-throws:private {404} \Mill\Examples\Showtimes\Representations\Error If the movie theater could not be - * found. + * @api-error:private {404} \Mill\Examples\Showtimes\Representations\Error If the movie theater could not be found. */ public function DELETE() { diff --git a/resources/examples/Showtimes/Controllers/Theaters.php b/resources/examples/Showtimes/Controllers/Theaters.php index 20bbf3a..b03befa 100644 --- a/resources/examples/Showtimes/Controllers/Theaters.php +++ b/resources/examples/Showtimes/Controllers/Theaters.php @@ -17,7 +17,7 @@ class Theaters * * @api-return:public {collection} \Mill\Examples\Showtimes\Representations\Theater * - * @api-throws:public {400} \Mill\Examples\Showtimes\Representations\Error If the location is invalid. + * @api-error:public {400} \Mill\Examples\Showtimes\Representations\Error If the location is invalid. * * @api-version >=1.1.2 * @api-contentType application/mill.example.theater @@ -45,8 +45,7 @@ public function GET() * * @api-return:public {object} \Mill\Examples\Showtimes\Representations\Theater * - * @api-throws:public {400} \Mill\Examples\Showtimes\Representations\Error If there is a problem with the - * request. + * @api-error:public {400} \Mill\Examples\Showtimes\Representations\Error If there is a problem with the request. * * @api-version >=1.1.2 * @api-contentType application/mill.example.theater diff --git a/resources/examples/Showtimes/blueprints/changelog-public-only-all-capabilities.md b/resources/examples/Showtimes/blueprints/changelog-public-only-all-capabilities.md index e255c58..e953c5a 100644 --- a/resources/examples/Showtimes/blueprints/changelog-public-only-all-capabilities.md +++ b/resources/examples/Showtimes/blueprints/changelog-public-only-all-capabilities.md @@ -7,10 +7,10 @@ Changed up the responses for `/movie/{id}`, `/movies/{id}` and `/movies`. #### Added ##### Resources - The following Movies resources have added: - - `/movies/{id}` now throws the following errors on `GET` requests: + - `/movies/{id}` now returns the following errors on `GET` requests: - `404 Not Found` with a `Error` representation: For no reason. - `404 Not Found` with a `Error` representation: For some other reason. - - `/movies/{id}` now throws the following errors on `PATCH` requests: + - `/movies/{id}` now returns the following errors on `PATCH` requests: - `404 Not Found` with a `Error` representation: If the trailer URL could not be validated. - `403 Forbidden` with a `Coded error` representation: If the user is not allowed to edit that movie. - On `/movies/{id}`, `PATCH` requests now return a `202 Accepted` with a `Movie` representation. diff --git a/resources/examples/Showtimes/blueprints/changelog-public-only-matched-with-delete-capabilities.md b/resources/examples/Showtimes/blueprints/changelog-public-only-matched-with-delete-capabilities.md index 4ff66c6..5282a2e 100644 --- a/resources/examples/Showtimes/blueprints/changelog-public-only-matched-with-delete-capabilities.md +++ b/resources/examples/Showtimes/blueprints/changelog-public-only-matched-with-delete-capabilities.md @@ -7,10 +7,10 @@ Changed up the responses for `/movie/{id}`, `/movies/{id}` and `/movies`. #### Added ##### Resources - The following Movies resources have added: - - `/movies/{id}` now throws the following errors on `GET` requests: + - `/movies/{id}` now returns the following errors on `GET` requests: - `404 Not Found` with a `Error` representation: For no reason. - `404 Not Found` with a `Error` representation: For some other reason. - - `/movies/{id}` now throws the following errors on `PATCH` requests: + - `/movies/{id}` now returns the following errors on `PATCH` requests: - `404 Not Found` with a `Error` representation: If the trailer URL could not be validated. - `403 Forbidden` with a `Coded error` representation: If the user is not allowed to edit that movie. - On `/movies/{id}`, `PATCH` requests now return a `202 Accepted` with a `Movie` representation. diff --git a/resources/examples/Showtimes/blueprints/changelog-public-only-matched-with-tickets-and-feature-capabilities.md b/resources/examples/Showtimes/blueprints/changelog-public-only-matched-with-tickets-and-feature-capabilities.md index e255c58..e953c5a 100644 --- a/resources/examples/Showtimes/blueprints/changelog-public-only-matched-with-tickets-and-feature-capabilities.md +++ b/resources/examples/Showtimes/blueprints/changelog-public-only-matched-with-tickets-and-feature-capabilities.md @@ -7,10 +7,10 @@ Changed up the responses for `/movie/{id}`, `/movies/{id}` and `/movies`. #### Added ##### Resources - The following Movies resources have added: - - `/movies/{id}` now throws the following errors on `GET` requests: + - `/movies/{id}` now returns the following errors on `GET` requests: - `404 Not Found` with a `Error` representation: For no reason. - `404 Not Found` with a `Error` representation: For some other reason. - - `/movies/{id}` now throws the following errors on `PATCH` requests: + - `/movies/{id}` now returns the following errors on `PATCH` requests: - `404 Not Found` with a `Error` representation: If the trailer URL could not be validated. - `403 Forbidden` with a `Coded error` representation: If the user is not allowed to edit that movie. - On `/movies/{id}`, `PATCH` requests now return a `202 Accepted` with a `Movie` representation. diff --git a/resources/examples/Showtimes/blueprints/changelog.md b/resources/examples/Showtimes/blueprints/changelog.md index 8604bf7..a30e175 100644 --- a/resources/examples/Showtimes/blueprints/changelog.md +++ b/resources/examples/Showtimes/blueprints/changelog.md @@ -7,13 +7,13 @@ Changed up the responses for `/movie/{id}`, `/movies/{id}` and `/movies`. #### Added ##### Resources - The following Movies resources have added: - - `/movie/{id}` now throws the following errors on `GET` requests: + - `/movie/{id}` now returns the following errors on `GET` requests: - `404 Not Found` with a `Error` representation: For no reason. - `404 Not Found` with a `Error` representation: For some other reason. - - `/movies/{id}` now throws the following errors on `GET` requests: + - `/movies/{id}` now returns the following errors on `GET` requests: - `404 Not Found` with a `Error` representation: For no reason. - `404 Not Found` with a `Error` representation: For some other reason. - - `/movies/{id}` now throws the following errors on `PATCH` requests: + - `/movies/{id}` now returns the following errors on `PATCH` requests: - `404 Not Found` with a `Error` representation: If the trailer URL could not be validated. - `403 Forbidden` with a `Coded error` representation: If something cool happened. - `403 Forbidden` with a `Coded error` representation: If the user is not allowed to edit that movie. diff --git a/src/Exceptions/Annotations/MissingRepresentationErrorCodeException.php b/src/Exceptions/Annotations/MissingRepresentationErrorCodeException.php index de11215..c2a5839 100644 --- a/src/Exceptions/Annotations/MissingRepresentationErrorCodeException.php +++ b/src/Exceptions/Annotations/MissingRepresentationErrorCodeException.php @@ -13,7 +13,7 @@ public static function create( string $method ): MissingRepresentationErrorCodeException { $message = sprintf( - 'The `%s` error representation on `@api-throws %s` in %s::%s is missing an error code, but is required ' . + 'The `%s` error representation on `@api-error %s` in %s::%s is missing an error code, but is required ' . 'to have one in your config file.', $representation, $representation, diff --git a/src/Exceptions/Annotations/UncallableErrorCodeException.php b/src/Exceptions/Annotations/UncallableErrorCodeException.php index ff6c4d5..8b71eba 100644 --- a/src/Exceptions/Annotations/UncallableErrorCodeException.php +++ b/src/Exceptions/Annotations/UncallableErrorCodeException.php @@ -10,7 +10,7 @@ class UncallableErrorCodeException extends BaseException public static function create(string $docblock, string $class, string $method): UncallableErrorCodeException { $message = sprintf( - 'The `@api-throws %s` in %s::%s has an uncallable error code.', + 'The `@api-error %s` in %s::%s has an uncallable error code.', $docblock, $class, $method diff --git a/src/Exceptions/Annotations/UnknownErrorRepresentationException.php b/src/Exceptions/Annotations/UnknownErrorRepresentationException.php index d644362..4e9ffde 100644 --- a/src/Exceptions/Annotations/UnknownErrorRepresentationException.php +++ b/src/Exceptions/Annotations/UnknownErrorRepresentationException.php @@ -13,7 +13,7 @@ public static function create( string $method ): UnknownErrorRepresentationException { $message = sprintf( - 'The `@api-throws %s` in %s::%s has an unknown representation. Is it present in your config file?', + 'The `@api-error %s` in %s::%s has an unknown representation. Is it present in your config file?', $representation, $class, $method diff --git a/src/Generator/Blueprint.php b/src/Generator/Blueprint.php index 7fd8a4a..fae0447 100644 --- a/src/Generator/Blueprint.php +++ b/src/Generator/Blueprint.php @@ -3,10 +3,10 @@ use Mill\Exceptions\Resource\NoAnnotationsException; use Mill\Generator; +use Mill\Parser\Annotations\ErrorAnnotation; use Mill\Parser\Annotations\ParamAnnotation; use Mill\Parser\Annotations\ReturnAnnotation; use Mill\Parser\Annotations\ScopeAnnotation; -use Mill\Parser\Annotations\ThrowsAnnotation; use Mill\Parser\Annotations\UriSegmentAnnotation; use Mill\Parser\Representation\Documentation; use Mill\Parser\Resource\Action; @@ -82,7 +82,7 @@ public function generate(): array $action_contents .= $this->processRequest($action); $coded_responses = []; - /** @var ReturnAnnotation|ThrowsAnnotation $response */ + /** @var ReturnAnnotation|ErrorAnnotation $response */ foreach ($action->getResponses() as $response) { $coded_responses[$response->getHttpCode()][] = $response; } @@ -339,13 +339,13 @@ protected function processResponses(Action\Documentation $action, string $http_c $blueprint .= sprintf('There are %s ways that this status code can be encountered:', $response_count); $blueprint .= $this->line(); - /** @var ReturnAnnotation|ThrowsAnnotation $response */ + /** @var ReturnAnnotation|ErrorAnnotation $response */ foreach ($responses as $response) { $description = $response->getDescription(); $description = (!empty($description)) ? $description : 'Standard request.'; $blueprint .= $this->tab(2); $blueprint .= sprintf(' * %s', $description); - if ($response instanceof ThrowsAnnotation) { + if ($response instanceof ErrorAnnotation) { $error_code = $response->getErrorCode(); if ($error_code) { $blueprint .= sprintf(' Unique error code: %s', $error_code); @@ -357,7 +357,7 @@ protected function processResponses(Action\Documentation $action, string $http_c } } - /** @var ReturnAnnotation|ThrowsAnnotation $response */ + /** @var ReturnAnnotation|ErrorAnnotation $response */ $response = array_shift($responses); $representation = $response->getRepresentation(); $representations = $this->getRepresentations($this->version); diff --git a/src/Generator/Changelog.php b/src/Generator/Changelog.php index 39d6f06..c3b2020 100644 --- a/src/Generator/Changelog.php +++ b/src/Generator/Changelog.php @@ -7,18 +7,18 @@ use Mill\Generator\Changelog\Formats\Markdown; use Mill\Parser\Annotation; use Mill\Parser\Annotations\ContentTypeAnnotation; +use Mill\Parser\Annotations\ErrorAnnotation; use Mill\Parser\Annotations\ParamAnnotation; use Mill\Parser\Annotations\ReturnAnnotation; -use Mill\Parser\Annotations\ThrowsAnnotation; use Mill\Parser\Representation\Documentation; use Mill\Parser\Resource\Action; class Changelog extends Generator { const CHANGESET_TYPE_ACTION = 'action'; + const CHANGESET_TYPE_ACTION_ERROR = 'action_error'; const CHANGESET_TYPE_ACTION_PARAM = 'action_param'; const CHANGESET_TYPE_ACTION_RETURN = 'action_return'; - const CHANGESET_TYPE_ACTION_THROWS = 'action_throws'; const CHANGESET_TYPE_CONTENT_TYPE = 'content_type'; const CHANGESET_TYPE_REPRESENTATION_DATA = 'representation_data'; @@ -203,7 +203,7 @@ private function buildResourceChangelog(array $resources = []): void } } - // Diff action `param`, `return` and `throws` annotations. + // Diff action `param`, `return` and `error` annotations. foreach ($action->getAnnotations() as $annotation_name => $annotations) { /** @var Annotation $annotation */ foreach ($annotations as $annotation) { @@ -244,13 +244,13 @@ private function buildResourceChangelog(array $resources = []): void } else { $data['representation'] = false; } - } elseif ($annotation instanceof ThrowsAnnotation) { - $change_type = self::CHANGESET_TYPE_ACTION_THROWS; + } elseif ($annotation instanceof ErrorAnnotation) { + $change_type = self::CHANGESET_TYPE_ACTION_ERROR; /** @var Documentation $representation */ $representation = $this->parsed['representations'][$annotation->getRepresentation()]; - /** @var ThrowsAnnotation $annotation */ + /** @var ErrorAnnotation $annotation */ $data['http_code'] = $annotation->getHttpCode(); $data['representation'] = $representation->getLabel(); $data['description'] = $annotation->getDescription(); @@ -422,7 +422,7 @@ private function hashChangeset(string $change_type, array $data): string $hash_data['uri'] = $data['uri']; break; - case self::CHANGESET_TYPE_ACTION_THROWS: + case self::CHANGESET_TYPE_ACTION_ERROR: $hash_data['method'] = $data['method']; $hash_data['uri'] = $data['uri']; break; diff --git a/src/Generator/Changelog/Changesets/ActionThrows.php b/src/Generator/Changelog/Changesets/ActionError.php similarity index 89% rename from src/Generator/Changelog/Changesets/ActionThrows.php rename to src/Generator/Changelog/Changesets/ActionError.php index 6b89e0e..52ef0c2 100644 --- a/src/Generator/Changelog/Changesets/ActionThrows.php +++ b/src/Generator/Changelog/Changesets/ActionError.php @@ -4,7 +4,7 @@ use Mill\Generator\Changelog; use Mill\Generator\Changelog\Changeset; -class ActionThrows extends Changeset +class ActionError extends Changeset { /** * {@inheritDoc} @@ -13,8 +13,8 @@ public function getTemplates(): array { return [ 'plural' => [ - Changelog::DEFINITION_ADDED => '{uri} now throws the following errors on {method} requests:', - Changelog::DEFINITION_REMOVED => '{uri} no longer throws the following errors on {method} requests:' + Changelog::DEFINITION_ADDED => '{uri} now returns the following errors on {method} requests:', + Changelog::DEFINITION_REMOVED => '{uri} no longer returns the following errors on {method} requests:' ], 'singular' => [ Changelog::DEFINITION_ADDED => 'On {method} requests to {uri}, a {http_code} with a {representation} ' . @@ -81,6 +81,6 @@ public function compileAddedOrRemovedChangeset(string $definition, array $change */ public function compileChangedChangeset(string $definition, array $changes = []) { - throw new \Exception($definition . ' action throws changes are not yet supported.'); + throw new \Exception($definition . ' action error changes are not yet supported.'); } } diff --git a/src/Generator/Changelog/Formats/Json.php b/src/Generator/Changelog/Formats/Json.php index 1f55880..b2a58c4 100644 --- a/src/Generator/Changelog/Formats/Json.php +++ b/src/Generator/Changelog/Formats/Json.php @@ -166,8 +166,8 @@ private function getAddedOrRemovedChangesetFactory(string $definition, string $c $changeset = new Changelog\Changesets\ActionReturn; break; - case Changelog::CHANGESET_TYPE_ACTION_THROWS: - $changeset = new Changelog\Changesets\ActionThrows; + case Changelog::CHANGESET_TYPE_ACTION_ERROR: + $changeset = new Changelog\Changesets\ActionError; break; case Changelog::CHANGESET_TYPE_REPRESENTATION_DATA: diff --git a/src/Generator/ErrorMap.php b/src/Generator/ErrorMap.php index e9f5fcf..3fffa5c 100644 --- a/src/Generator/ErrorMap.php +++ b/src/Generator/ErrorMap.php @@ -3,8 +3,8 @@ use Mill\Generator; use Mill\Generator\ErrorMap\Formats\Markdown; +use Mill\Parser\Annotations\ErrorAnnotation; use Mill\Parser\Annotations\ReturnAnnotation; -use Mill\Parser\Annotations\ThrowsAnnotation; use Mill\Parser\Resource\Action; class ErrorMap extends Generator @@ -39,9 +39,9 @@ public function generate(): array foreach ($data['resources'] as $resource_name => $resource) { /** @var Action\Documentation $action */ foreach ($resource['actions'] as $identifier => $action) { - /** @var ReturnAnnotation|ThrowsAnnotation $response */ + /** @var ReturnAnnotation|ErrorAnnotation $response */ foreach ($action->getResponses() as $response) { - if (!$response instanceof ThrowsAnnotation) { + if (!$response instanceof ErrorAnnotation) { continue; } diff --git a/src/Parser/Annotations/ThrowsAnnotation.php b/src/Parser/Annotations/ErrorAnnotation.php similarity index 90% rename from src/Parser/Annotations/ThrowsAnnotation.php rename to src/Parser/Annotations/ErrorAnnotation.php index 27737fb..bea5f34 100644 --- a/src/Parser/Annotations/ThrowsAnnotation.php +++ b/src/Parser/Annotations/ErrorAnnotation.php @@ -12,10 +12,10 @@ use Mill\Parser\Version; /** - * Handler for the `@api-throws` annotation. + * Handler for the `@api-error` annotation. * */ -class ThrowsAnnotation extends Annotation +class ErrorAnnotation extends Annotation { use HasHttpCodeResponseTrait; @@ -23,9 +23,9 @@ class ThrowsAnnotation extends Annotation const SUPPORTS_VERSIONING = true; const REGEX_ERROR_CODE = '/^(\(.*\))/'; - const REGEX_THROW_HTTP_CODE = '/{([\d]+)}/'; - const REGEX_THROW_TYPE = '/{([\w\s]+)}/'; - const REGEX_THROW_SUB_TYPE = '/{([\w\s]+),([\w\s]+)}/'; + const REGEX_ERROR_HTTP_CODE = '/{([\d]+)}/'; + const REGEX_ERROR_TYPE = '/{([\w\s]+)}/'; + const REGEX_ERROR_SUB_TYPE = '/{([\w\s]+),([\w\s]+)}/'; /** * Optional unique error code for the error that this exception handles. @@ -35,7 +35,7 @@ class ThrowsAnnotation extends Annotation protected $error_code = null; /** - * Description for why this exception can be thrown. + * Description for why this exception can be triggered. * * @var string */ @@ -74,15 +74,15 @@ protected function parser(): array $content = trim($this->docblock); // HTTP code is surrounded by +plusses+. - if (preg_match(self::REGEX_THROW_HTTP_CODE, $content, $matches)) { + if (preg_match(self::REGEX_ERROR_HTTP_CODE, $content, $matches)) { $parsed['http_code'] = $matches[1]; if (!$this->isValidHttpCode($parsed['http_code'])) { - throw UnknownReturnCodeException::create('throws', $this->docblock, $this->class, $method); + throw UnknownReturnCodeException::create('error', $this->docblock, $this->class, $method); } $parsed['http_code'] .= ' ' . $this->getHttpCodeMessage($parsed['http_code']); - $content = trim(preg_replace(self::REGEX_THROW_HTTP_CODE, '', $content)); + $content = trim(preg_replace(self::REGEX_ERROR_HTTP_CODE, '', $content)); } $parts = explode(' ', $content); @@ -132,9 +132,9 @@ protected function parser(): array $description = trim($content); if (!empty($description)) { - if (preg_match(self::REGEX_THROW_SUB_TYPE, $description, $matches)) { + if (preg_match(self::REGEX_ERROR_SUB_TYPE, $description, $matches)) { $description = sprintf('If %s was not found in the %s.', $matches[1], $matches[2]); - } elseif (preg_match(self::REGEX_THROW_TYPE, $description, $matches)) { + } elseif (preg_match(self::REGEX_ERROR_TYPE, $description, $matches)) { $description = sprintf('If %s was not found.', $matches[1]); } @@ -182,7 +182,7 @@ protected function interpreter(): void */ public static function hydrate(array $data = [], Version $version = null) { - /** @var ThrowsAnnotation $annotation */ + /** @var ErrorAnnotation $annotation */ $annotation = parent::hydrate($data, $version); $annotation->setDescription($data['description']); $annotation->setErrorCode($data['error_code']); diff --git a/src/Parser/Resource/Action/Documentation.php b/src/Parser/Resource/Action/Documentation.php index 6f4de06..2ae05e8 100644 --- a/src/Parser/Resource/Action/Documentation.php +++ b/src/Parser/Resource/Action/Documentation.php @@ -75,11 +75,11 @@ class Documentation */ protected static $ACCEPTED_ANNOTATIONS = [ 'capability', + 'error', 'param', 'minVersion', 'return', 'scope', - 'throws', 'uri', 'uriSegment' ]; @@ -464,16 +464,16 @@ public function getParameters(): array /** * Get back any responses that this action can throw. This will include both returns (`@api-return`) and exceptions - * (`@api-throws`). + * (`@api-error`). * * @return array */ public function getResponses(): array { $return = (isset($this->annotations['return'])) ? $this->annotations['return'] : []; - $throws = (isset($this->annotations['throws'])) ? $this->annotations['throws'] : []; + $error = (isset($this->annotations['error'])) ? $this->annotations['error'] : []; - return array_merge($return, $throws); + return array_merge($return, $error); } /** diff --git a/tests/Generator/Changelog/Formats/JsonTest.php b/tests/Generator/Changelog/Formats/JsonTest.php index 3b8fd0b..d8da1ba 100644 --- a/tests/Generator/Changelog/Formats/JsonTest.php +++ b/tests/Generator/Changelog/Formats/JsonTest.php @@ -37,7 +37,7 @@ public function testGenerate(): void [ '/movie/{id} now ' . - 'throws the following errors on GET requests:', [ @@ -61,7 +61,7 @@ public function testGenerate(): void [ '/movies/{id} now ' . - 'throws the following errors on GET requests:', [ @@ -85,7 +85,7 @@ public function testGenerate(): void [ '/movies/{id} now ' . - 'throws the following errors on PATCH requests:', [ diff --git a/tests/Generator/ChangelogTest.php b/tests/Generator/ChangelogTest.php index 6c7fd46..8517cdb 100644 --- a/tests/Generator/ChangelogTest.php +++ b/tests/Generator/ChangelogTest.php @@ -61,7 +61,7 @@ public function providerTestGeneration(): array $actions = [ '1.1.3' => [ '/movie/{id}' => [ - 'throws' => [ + 'error' => [ '2e302f7f79' => [ [ 'resource_namespace' => 'Movies', @@ -96,18 +96,7 @@ public function providerTestGeneration(): array ] ], '/movies/{id}' => [ - 'return' => [ - '162944fa14' => [ - [ - 'resource_namespace' => 'Movies', - 'method' => 'PATCH', - 'uri' => '/movies/{id}', - 'http_code' => '202 Accepted', - 'representation' => 'Movie' - ] - ] - ], - 'throws' => [ + 'error' => [ 'e7dc298139' => [ [ 'resource_namespace' => 'Movies', @@ -144,6 +133,17 @@ public function providerTestGeneration(): array 'description' => 'If the user is not allowed to edit that movie.' ] ] + ], + 'return' => [ + '162944fa14' => [ + [ + 'resource_namespace' => 'Movies', + 'method' => 'PATCH', + 'uri' => '/movies/{id}', + 'http_code' => '202 Accepted', + 'representation' => 'Movie' + ] + ] ] ] ], @@ -221,7 +221,7 @@ public function providerTestGeneration(): array ] ], '/theaters/{id}' => [ - 'action_throws' => [ + 'action_error' => [ 'b3a16c4d74' => [ [ 'resource_namespace' => 'Theaters', @@ -375,17 +375,16 @@ public function providerTestGeneration(): array 'resources' => [ 'Movies' => [ '/movie/{id}' => [ - Changelog::CHANGESET_TYPE_ACTION_THROWS => [ - '2e302f7f79' => $actions['1.1.3']['/movie/{id}']['throws']['2e302f7f79'] + Changelog::CHANGESET_TYPE_ACTION_ERROR => [ + '2e302f7f79' => $actions['1.1.3']['/movie/{id}']['error']['2e302f7f79'] ] ], '/movies/{id}' => [ - Changelog::CHANGESET_TYPE_ACTION_THROWS => [ - 'e7dc298139' => $actions['1.1.3']['/movies/{id}']['throws']['e7dc298139'], + Changelog::CHANGESET_TYPE_ACTION_ERROR => [ + 'e7dc298139' => $actions['1.1.3']['/movies/{id}']['error']['e7dc298139'], '162944fa14' => call_user_func( function () use ($actions): array { - $actions = - $actions['1.1.3']['/movies/{id}']['throws']['162944fa14']; + $actions = $actions['1.1.3']['/movies/{id}']['error']['162944fa14']; // Add in the "If something cool happened." exception. It's the // only private/capability-free exception we're testing, and it @@ -477,9 +476,9 @@ function () use ($actions): array { 'resources' => [ 'Theaters' => [ '/theaters/{id}' => [ - Changelog::CHANGESET_TYPE_ACTION_THROWS => [ + Changelog::CHANGESET_TYPE_ACTION_ERROR => [ 'b3a16c4d74' => - $actions['1.1.2']['/theaters/{id}']['action_throws']['b3a16c4d74'] + $actions['1.1.2']['/theaters/{id}']['action_error']['b3a16c4d74'] ] ] ] @@ -562,9 +561,9 @@ function () use ($actions): array { 'resources' => [ 'Movies' => [ '/movies/{id}' => [ - Changelog::CHANGESET_TYPE_ACTION_THROWS => [ - 'e7dc298139' => $actions['1.1.3']['/movies/{id}']['throws']['e7dc298139'], - '162944fa14' => $actions['1.1.3']['/movies/{id}']['throws']['162944fa14'] + Changelog::CHANGESET_TYPE_ACTION_ERROR => [ + 'e7dc298139' => $actions['1.1.3']['/movies/{id}']['error']['e7dc298139'], + '162944fa14' => $actions['1.1.3']['/movies/{id}']['error']['162944fa14'] ], Changelog::CHANGESET_TYPE_ACTION_RETURN => [ '162944fa14' => $actions['1.1.3']['/movies/{id}']['return']['162944fa14'] @@ -634,9 +633,9 @@ function () use ($actions): array { 'resources' => [ 'Theaters' => [ '/theaters/{id}' => [ - Changelog::CHANGESET_TYPE_ACTION_THROWS => [ + Changelog::CHANGESET_TYPE_ACTION_ERROR => [ 'b3a16c4d74' => - $actions['1.1.2']['/theaters/{id}']['action_throws']['b3a16c4d74'] + $actions['1.1.2']['/theaters/{id}']['action_error']['b3a16c4d74'] ] ] ] @@ -717,9 +716,9 @@ function () use ($actions): array { 'resources' => [ 'Movies' => [ '/movies/{id}' => [ - Changelog::CHANGESET_TYPE_ACTION_THROWS => [ - 'e7dc298139' => $actions['1.1.3']['/movies/{id}']['throws']['e7dc298139'], - '162944fa14' => $actions['1.1.3']['/movies/{id}']['throws']['162944fa14'] + Changelog::CHANGESET_TYPE_ACTION_ERROR => [ + 'e7dc298139' => $actions['1.1.3']['/movies/{id}']['error']['e7dc298139'], + '162944fa14' => $actions['1.1.3']['/movies/{id}']['error']['162944fa14'] ], Changelog::CHANGESET_TYPE_ACTION_RETURN => [ '162944fa14' => $actions['1.1.3']['/movies/{id}']['return']['162944fa14'] @@ -791,9 +790,9 @@ function () use ($actions): array { 'resources' => [ 'Theaters' => [ '/theaters/{id}' => [ - Changelog::CHANGESET_TYPE_ACTION_THROWS => [ + Changelog::CHANGESET_TYPE_ACTION_ERROR => [ 'b3a16c4d74' => - $actions['1.1.2']['/theaters/{id}']['action_throws']['b3a16c4d74'] + $actions['1.1.2']['/theaters/{id}']['action_error']['b3a16c4d74'] ] ] ] @@ -880,9 +879,9 @@ function () use ($actions): array { 'resources' => [ 'Movies' => [ '/movies/{id}' => [ - Changelog::CHANGESET_TYPE_ACTION_THROWS => [ - 'e7dc298139' => $actions['1.1.3']['/movies/{id}']['throws']['e7dc298139'], - '162944fa14' => $actions['1.1.3']['/movies/{id}']['throws']['162944fa14'] + Changelog::CHANGESET_TYPE_ACTION_ERROR => [ + 'e7dc298139' => $actions['1.1.3']['/movies/{id}']['error']['e7dc298139'], + '162944fa14' => $actions['1.1.3']['/movies/{id}']['error']['162944fa14'] ], Changelog::CHANGESET_TYPE_ACTION_RETURN => [ '162944fa14' => $actions['1.1.3']['/movies/{id}']['return']['162944fa14'] @@ -943,9 +942,9 @@ function () use ($actions): array { 'resources' => [ 'Theaters' => [ '/theaters/{id}' => [ - Changelog::CHANGESET_TYPE_ACTION_THROWS => [ + Changelog::CHANGESET_TYPE_ACTION_ERROR => [ 'b3a16c4d74' => - $actions['1.1.2']['/theaters/{id}']['action_throws']['b3a16c4d74'] + $actions['1.1.2']['/theaters/{id}']['action_error']['b3a16c4d74'] ] ] ] diff --git a/tests/GeneratorTest.php b/tests/GeneratorTest.php index 7302638..d5fbe7f 100644 --- a/tests/GeneratorTest.php +++ b/tests/GeneratorTest.php @@ -196,8 +196,8 @@ public function providerGeneratorWithVersion(): array 'uri.visible' => false, 'params.keys' => [], 'annotations.sum' => [ + 'error' => 1, 'return' => 2, - 'throws' => 1, 'uri' => 1, 'uriSegment' => 1 ] @@ -211,9 +211,9 @@ public function providerGeneratorWithVersion(): array 'location' ], 'annotations.sum' => [ + 'error' => 1, 'param' => 1, 'return' => 1, - 'throws' => 1, 'uri' => 1 ] ], @@ -234,10 +234,10 @@ public function providerGeneratorWithVersion(): array 'runtime' ], 'annotations.sum' => [ + 'error' => 2, 'param' => 9, 'return' => 1, 'scope' => 1, - 'throws' => 2, 'uri' => 1 ] ], @@ -256,8 +256,8 @@ public function providerGeneratorWithVersion(): array 'uri.visible' => true, 'params.keys' => [], 'annotations.sum' => [ + 'error' => 1, 'return' => 2, - 'throws' => 1, 'uri' => 1, 'uriSegment' => 1 ] @@ -288,11 +288,11 @@ public function providerGeneratorWithVersion(): array 'trailer' ], 'annotations.sum' => [ + 'error' => 3, 'minVersion' => 1, 'param' => 10, 'return' => 1, 'scope' => 1, - 'throws' => 3, 'uri' => 1, 'uriSegment' => 1 ] @@ -313,10 +313,10 @@ public function providerGeneratorWithVersion(): array 'params.keys' => [], 'annotations.sum' => [ 'capability' => 1, + 'error' => 1, 'minVersion' => 1, 'return' => 1, 'scope' => 1, - 'throws' => 1, 'uri' => 1, 'uriSegment' => 1 ] @@ -330,9 +330,9 @@ public function providerGeneratorWithVersion(): array 'location' ], 'annotations.sum' => [ + 'error' => 1, 'param' => 1, 'return' => 1, - 'throws' => 1, 'uri' => 1 ] ], @@ -347,10 +347,10 @@ public function providerGeneratorWithVersion(): array 'phone_number' ], 'annotations.sum' => [ + 'error' => 1, 'param' => 3, 'return' => 1, 'scope' => 1, - 'throws' => 1, 'uri' => 1 ] ], @@ -369,8 +369,8 @@ public function providerGeneratorWithVersion(): array 'uri.visible' => true, 'params.keys' => [], 'annotations.sum' => [ + 'error' => 1, 'return' => 2, - 'throws' => 1, 'uri' => 1, 'uriSegment' => 1 ] @@ -394,10 +394,10 @@ public function providerGeneratorWithVersion(): array 'phone_number' ], 'annotations.sum' => [ + 'error' => 3, 'param' => 3, 'return' => 1, 'scope' => 1, - 'throws' => 3, 'uri' => 1, 'uriSegment' => 1 ] @@ -417,9 +417,9 @@ public function providerGeneratorWithVersion(): array 'uri.visible' => false, 'params.keys' => [], 'annotations.sum' => [ + 'error' => 1, 'return' => 1, 'scope' => 1, - 'throws' => 1, 'uri' => 1, 'uriSegment' => 1 ] diff --git a/tests/Parser/Annotations/ThrowsAnnotationTest.php b/tests/Parser/Annotations/ErrorAnnotationTest.php similarity index 93% rename from tests/Parser/Annotations/ThrowsAnnotationTest.php rename to tests/Parser/Annotations/ErrorAnnotationTest.php index 53f8c5b..e86699c 100644 --- a/tests/Parser/Annotations/ThrowsAnnotationTest.php +++ b/tests/Parser/Annotations/ErrorAnnotationTest.php @@ -7,10 +7,10 @@ use Mill\Exceptions\Annotations\UnknownErrorRepresentationException; use Mill\Exceptions\Annotations\UnknownReturnCodeException; use Mill\Parser\Annotations\CapabilityAnnotation; -use Mill\Parser\Annotations\ThrowsAnnotation; +use Mill\Parser\Annotations\ErrorAnnotation; use Mill\Parser\Version; -class ThrowsAnnotationTest extends AnnotationTest +class ErrorAnnotationTest extends AnnotationTest { /** * @dataProvider providerAnnotation @@ -21,7 +21,7 @@ class ThrowsAnnotationTest extends AnnotationTest */ public function testAnnotation(string $content, $version, bool $visible, array $expected): void { - $annotation = new ThrowsAnnotation($content, __CLASS__, __METHOD__, $version); + $annotation = new ErrorAnnotation($content, __CLASS__, __METHOD__, $version); $annotation->process(); $annotation->setVisibility($visible); @@ -37,8 +37,8 @@ public function testAnnotation(string $content, $version, bool $visible, array $ */ public function testHydrate(string $content, $version, bool $visible, array $expected): void { - /** @var ThrowsAnnotation $annotation */ - $annotation = ThrowsAnnotation::hydrate(array_merge( + /** @var ErrorAnnotation $annotation */ + $annotation = ErrorAnnotation::hydrate(array_merge( $expected, [ 'class' => __CLASS__, @@ -49,7 +49,7 @@ public function testHydrate(string $content, $version, bool $visible, array $exp $this->assertAnnotation($annotation, $expected); } - private function assertAnnotation(ThrowsAnnotation $annotation, array $expected): void + private function assertAnnotation(ErrorAnnotation $annotation, array $expected): void { $this->assertTrue($annotation->requiresVisibilityDecorator()); $this->assertTrue($annotation->supportsVersioning()); @@ -138,7 +138,7 @@ public function providerAnnotation(): array 'visible' => true ] ], - 'description.throw_type' => [ + 'description.error_type' => [ 'content' => '{404} \Mill\Examples\Showtimes\Representations\Error {movie}', 'version' => null, 'visible' => true, @@ -152,7 +152,7 @@ public function providerAnnotation(): array 'visible' => true ] ], - 'description.throw_type.subthrow_type' => [ + 'description.error_type.suberror_type' => [ 'content' => '{404} \Mill\Examples\Showtimes\Representations\Error {movie,theater}', 'version' => null, 'visible' => true, @@ -278,40 +278,40 @@ public function providerAnnotationFailsOnInvalidContent(): array { return [ 'missing-http-code' => [ - 'annotation' => ThrowsAnnotation::class, + 'annotation' => ErrorAnnotation::class, 'content' => '', 'expected.exception' => MissingRequiredFieldException::class, 'expected.exception.asserts' => [ 'getRequiredField' => 'http_code', - 'getAnnotation' => 'throws', + 'getAnnotation' => 'error', 'getDocblock' => '', 'getValues' => [] ] ], 'missing-representation' => [ - 'annotation' => ThrowsAnnotation::class, + 'annotation' => ErrorAnnotation::class, 'content' => '{404} \Mill\Examples\Showtimes\Representations\Error', 'expected.exception' => MissingRequiredFieldException::class, 'expected.exception.asserts' => [ 'getRequiredField' => 'description', - 'getAnnotation' => 'throws', + 'getAnnotation' => 'error', 'getDocblock' => '{404} \Mill\Examples\Showtimes\Representations\Error', 'getValues' => [] ] ], 'missing-description' => [ - 'annotation' => ThrowsAnnotation::class, + 'annotation' => ErrorAnnotation::class, 'content' => '{404}', 'expected.exception' => MissingRequiredFieldException::class, 'expected.exception.asserts' => [ 'getRequiredField' => 'representation', - 'getAnnotation' => 'throws', + 'getAnnotation' => 'error', 'getDocblock' => '{404}', 'getValues' => [] ] ], 'representation-is-unknown' => [ - 'annotation' => ThrowsAnnotation::class, + 'annotation' => ErrorAnnotation::class, 'content' => '{404} \UnknownRepresentation', 'expected.exception' => UnknownErrorRepresentationException::class, 'expected.exception.asserts' => [ @@ -322,7 +322,7 @@ public function providerAnnotationFailsOnInvalidContent(): array ] ], 'error-code-is-uncallable' => [ - 'annotation' => ThrowsAnnotation::class, + 'annotation' => ErrorAnnotation::class, 'content' => '{404} \Mill\Examples\Showtimes\Representations\CodedError (\Uncallable::CONSTANT)', 'expected.exception' => UncallableErrorCodeException::class, 'expected.exception.asserts' => [ @@ -334,7 +334,7 @@ public function providerAnnotationFailsOnInvalidContent(): array ] ], 'error-code-is-required-but-missing' => [ - 'annotation' => ThrowsAnnotation::class, + 'annotation' => ErrorAnnotation::class, 'content' => '{403} \Mill\Examples\Showtimes\Representations\CodedError', 'expected.exception' => MissingRepresentationErrorCodeException::class, 'expected.exception.asserts' => [ @@ -345,7 +345,7 @@ public function providerAnnotationFailsOnInvalidContent(): array ] ], 'http-code-is-invalid' => [ - 'annotation' => ThrowsAnnotation::class, + 'annotation' => ErrorAnnotation::class, 'content' => '{440} \Mill\Examples\Showtimes\Representations\Error', 'expected.exception' => UnknownReturnCodeException::class, 'expected.exception.asserts' => [ diff --git a/tests/Parser/Resource/Action/DocumentationTest.php b/tests/Parser/Resource/Action/DocumentationTest.php index 8f0b77c..0ea92fc 100644 --- a/tests/Parser/Resource/Action/DocumentationTest.php +++ b/tests/Parser/Resource/Action/DocumentationTest.php @@ -210,6 +210,35 @@ public function providerParseMethodDocumentation(): array 'minimum_version' => false, 'responses.length' => 5, 'annotations' => [ + 'error' => [ + [ + 'capability' => false, + 'description' => 'If the movie could not be found.', + 'error_code' => false, + 'http_code' => '404 Not Found', + 'representation' => '\Mill\Examples\Showtimes\Representations\Error', + 'version' => false, + 'visible' => true + ], + [ + 'capability' => false, + 'description' => 'For no reason.', + 'error_code' => false, + 'http_code' => '404 Not Found', + 'representation' => '\Mill\Examples\Showtimes\Representations\Error', + 'version' => '>=1.1.3', + 'visible' => true + ], + [ + 'capability' => false, + 'description' => 'For some other reason.', + 'error_code' => false, + 'http_code' => '404 Not Found', + 'representation' => '\Mill\Examples\Showtimes\Representations\Error', + 'version' => '>=1.1.3', + 'visible' => true + ] + ], 'uri' => [ [ 'aliased' => true, @@ -271,35 +300,6 @@ public function providerParseMethodDocumentation(): array 'version' => false, 'visible' => true ] - ], - 'throws' => [ - [ - 'capability' => false, - 'description' => 'If the movie could not be found.', - 'error_code' => false, - 'http_code' => '404 Not Found', - 'representation' => '\Mill\Examples\Showtimes\Representations\Error', - 'version' => false, - 'visible' => true - ], - [ - 'capability' => false, - 'description' => 'For no reason.', - 'error_code' => false, - 'http_code' => '404 Not Found', - 'representation' => '\Mill\Examples\Showtimes\Representations\Error', - 'version' => '>=1.1.3', - 'visible' => true - ], - [ - 'capability' => false, - 'description' => 'For some other reason.', - 'error_code' => false, - 'http_code' => '404 Not Found', - 'representation' => '\Mill\Examples\Showtimes\Representations\Error', - 'version' => '>=1.1.3', - 'visible' => true - ] ] ] ] @@ -325,6 +325,62 @@ public function providerParseMethodDocumentation(): array 'responses.length' => 8, 'uri.aliases' => [], 'annotations' => [ + 'error' => [ + [ + 'capability' => false, + 'description' => 'If there is a problem with the request.', + 'error_code' => false, + 'http_code' => '400 Bad Request', + 'representation' => '\Mill\Examples\Showtimes\Representations\Error', + 'version' => false, + 'visible' => true + ], + [ + 'capability' => false, + 'description' => 'If the IMDB URL could not be validated.', + 'error_code' => false, + 'http_code' => '400 Bad Request', + 'representation' => '\Mill\Examples\Showtimes\Representations\Error', + 'version' => false, + 'visible' => true + ], + [ + 'capability' => false, + 'description' => 'If the movie could not be found.', + 'error_code' => false, + 'http_code' => '404 Not Found', + 'representation' => '\Mill\Examples\Showtimes\Representations\Error', + 'version' => false, + 'visible' => true + ], + [ + 'capability' => false, + 'description' => 'If the trailer URL could not be validated.', + 'error_code' => false, + 'http_code' => '404 Not Found', + 'representation' => '\Mill\Examples\Showtimes\Representations\Error', + 'version' => '>=1.1.3', + 'visible' => true + ], + [ + 'capability' => false, + 'description' => 'If something cool happened.', + 'error_code' => '1337', + 'http_code' => '403 Forbidden', + 'representation' => '\Mill\Examples\Showtimes\Representations\CodedError', + 'version' => '>=1.1.3', + 'visible' => false + ], + [ + 'capability' => false, + 'description' => 'If the user is not allowed to edit that movie.', + 'error_code' => '666', + 'http_code' => '403 Forbidden', + 'representation' => '\Mill\Examples\Showtimes\Representations\CodedError', + 'version' => '>=1.1.3', + 'visible' => true + ] + ], 'uri' => [ [ 'aliased' => false, @@ -526,62 +582,6 @@ public function providerParseMethodDocumentation(): array 'description' => false, 'scope' => 'edit' ] - ], - 'throws' => [ - [ - 'capability' => false, - 'description' => 'If there is a problem with the request.', - 'error_code' => false, - 'http_code' => '400 Bad Request', - 'representation' => '\Mill\Examples\Showtimes\Representations\Error', - 'version' => false, - 'visible' => true - ], - [ - 'capability' => false, - 'description' => 'If the IMDB URL could not be validated.', - 'error_code' => false, - 'http_code' => '400 Bad Request', - 'representation' => '\Mill\Examples\Showtimes\Representations\Error', - 'version' => false, - 'visible' => true - ], - [ - 'capability' => false, - 'description' => 'If the movie could not be found.', - 'error_code' => false, - 'http_code' => '404 Not Found', - 'representation' => '\Mill\Examples\Showtimes\Representations\Error', - 'version' => false, - 'visible' => true - ], - [ - 'capability' => false, - 'description' => 'If the trailer URL could not be validated.', - 'error_code' => false, - 'http_code' => '404 Not Found', - 'representation' => '\Mill\Examples\Showtimes\Representations\Error', - 'version' => '>=1.1.3', - 'visible' => true - ], - [ - 'capability' => false, - 'description' => 'If something cool happened.', - 'error_code' => '1337', - 'http_code' => '403 Forbidden', - 'representation' => '\Mill\Examples\Showtimes\Representations\CodedError', - 'version' => '>=1.1.3', - 'visible' => false - ], - [ - 'capability' => false, - 'description' => 'If the user is not allowed to edit that movie.', - 'error_code' => '666', - 'http_code' => '403 Forbidden', - 'representation' => '\Mill\Examples\Showtimes\Representations\CodedError', - 'version' => '>=1.1.3', - 'visible' => true - ] ] ] ] @@ -608,6 +608,17 @@ public function providerParseMethodDocumentation(): array 'capability' => 'DELETE_CONTENT' ] ], + 'error' => [ + [ + 'capability' => false, + 'description' => 'If the movie could not be found.', + 'error_code' => false, + 'http_code' => '404 Not Found', + 'representation' => '\Mill\Examples\Showtimes\Representations\Error', + 'version' => false, + 'visible' => false + ] + ], 'uri' => [ [ 'aliased' => false, @@ -647,17 +658,6 @@ public function providerParseMethodDocumentation(): array 'description' => false, 'scope' => 'delete' ] - ], - 'throws' => [ - [ - 'capability' => false, - 'description' => 'If the movie could not be found.', - 'error_code' => false, - 'http_code' => '404 Not Found', - 'representation' => '\Mill\Examples\Showtimes\Representations\Error', - 'version' => false, - 'visible' => false - ] ] ] ] @@ -872,13 +872,13 @@ public function providerMethodsThatWillFailParsing(): array * @api-contentType application/json * @api-scope public * @api-return:private {collection} \Mill\Examples\Showtimes\Representations\Representation - * @api-throws:public {403} \Mill\Examples\Showtimes\Representations\CodedError + * @api-error:public {403} \Mill\Examples\Showtimes\Representations\CodedError * (Mill\Examples\Showtimes\Representations\CodedError::DISALLOWED) If the user isn\'t allowed to * do something. */', 'expected.exception' => '\Mill\Exceptions\Resource\PublicDecoratorOnPrivateActionException', 'expected.exception.asserts' => [ - 'getAnnotation' => 'throws' + 'getAnnotation' => 'error' ] ], 'too-many-aliases' => [ @@ -891,7 +891,7 @@ public function providerMethodsThatWillFailParsing(): array * @api-contentType application/json * @api-scope public * @api-return:private {collection} \Mill\Examples\Showtimes\Representations\Representation - * @api-throws:public {403} \Mill\Examples\Showtimes\Representations\CodedError + * @api-error:public {403} \Mill\Examples\Showtimes\Representations\CodedError * (Mill\Examples\Showtimes\Representations\CodedError::DISALLOWED) If the user isn\'t allowed to * do something. */', diff --git a/tests/ParserTest.php b/tests/ParserTest.php index b8deb45..a2c12a5 100644 --- a/tests/ParserTest.php +++ b/tests/ParserTest.php @@ -101,6 +101,10 @@ public function providerParseAnnotationsOnClassMethod(): array 'class' => Parser\Annotations\DescriptionAnnotation::class, 'count' => 1 ], + 'error' => [ + 'class' => Parser\Annotations\ErrorAnnotation::class, + 'count' => 3 + ], 'label' => [ 'class' => Parser\Annotations\LabelAnnotation::class, 'count' => 1 @@ -113,10 +117,6 @@ public function providerParseAnnotationsOnClassMethod(): array 'class' => Parser\Annotations\ReturnAnnotation::class, 'count' => 2 ], - 'throws' => [ - 'class' => Parser\Annotations\ThrowsAnnotation::class, - 'count' => 3 - ], 'uri' => [ 'class' => Parser\Annotations\UriAnnotation::class, 'count' => 2 @@ -138,6 +138,10 @@ public function providerParseAnnotationsOnClassMethod(): array 'class' => Parser\Annotations\DescriptionAnnotation::class, 'count' => 1 ], + 'error' => [ + 'class' => Parser\Annotations\ErrorAnnotation::class, + 'count' => 6 + ], 'label' => [ 'class' => Parser\Annotations\LabelAnnotation::class, 'count' => 1 @@ -158,10 +162,6 @@ public function providerParseAnnotationsOnClassMethod(): array 'class' => Parser\Annotations\ScopeAnnotation::class, 'count' => 1 ], - 'throws' => [ - 'class' => Parser\Annotations\ThrowsAnnotation::class, - 'count' => 6 - ], 'uri' => [ 'class' => Parser\Annotations\UriAnnotation::class, 'count' => 1 @@ -187,6 +187,10 @@ public function providerParseAnnotationsOnClassMethod(): array 'class' => Parser\Annotations\DescriptionAnnotation::class, 'count' => 1 ], + 'error' => [ + 'class' => Parser\Annotations\ErrorAnnotation::class, + 'count' => 1 + ], 'label' => [ 'class' => Parser\Annotations\LabelAnnotation::class, 'count' => 1 @@ -203,10 +207,6 @@ public function providerParseAnnotationsOnClassMethod(): array 'class' => Parser\Annotations\ScopeAnnotation::class, 'count' => 1 ], - 'throws' => [ - 'class' => Parser\Annotations\ThrowsAnnotation::class, - 'count' => 1 - ], 'uri' => [ 'class' => Parser\Annotations\UriAnnotation::class, 'count' => 1 From b35e4cef5cfc8ddee9f7d347b53f11522c1835fc Mon Sep 17 00:00:00 2001 From: Jon Ursenbach Date: Wed, 28 Mar 2018 15:46:25 -0400 Subject: [PATCH 02/53] Moving `@api-error` over to a MSON-like syntax. --- docs/configuration.md | 4 +- docs/reference/api-error.md | 20 ++-- docs/reference/api-minversion.md | 2 +- docs/reference/api-scope.md | 2 +- docs/reference/deprecation.md | 2 +- docs/reference/visibility.md | 2 +- .../examples/Showtimes/Controllers/Movie.php | 24 ++--- .../examples/Showtimes/Controllers/Movies.php | 6 +- .../Showtimes/Controllers/Theater.php | 11 ++- .../Showtimes/Controllers/Theaters.php | 4 +- .../UncallableErrorCodeException.php | 26 ----- src/Parser/Annotations/ErrorAnnotation.php | 92 ++++++------------ src/Parser/MSON.php | 36 ++++++- .../Annotations/ErrorAnnotationTest.php | 94 +++++-------------- .../Annotations/ParamAnnotationTest.php | 10 -- .../Resource/Action/DocumentationTest.php | 10 +- 16 files changed, 127 insertions(+), 218 deletions(-) delete mode 100644 src/Exceptions/Annotations/UncallableErrorCodeException.php diff --git a/docs/configuration.md b/docs/configuration.md index 9fb2939..8985879 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -95,8 +95,8 @@ Required attributes for the `` element are: /** * … * - * @api-error:public {403} \ErrorRepresentation (\AppError::USER_NOT_ALLOWED) If - * the user isn't allowed to do something. + * @api-error:public 403 (\ErrorRepresentation<7701>) - If the user isn't + * allowed to do something. */ public function PATCH() { diff --git a/docs/reference/api-error.md b/docs/reference/api-error.md index 52796f1..e829f93 100644 --- a/docs/reference/api-error.md +++ b/docs/reference/api-error.md @@ -11,7 +11,7 @@ This represents an exception that may be thrown inside of a resource action. ## Syntax ```php -@api-error:visibility {http code} \Representation (error code) +capability+ description +@api-error:visibility httpCode (\Representation, capability) - description ``` ## Requirements @@ -25,9 +25,9 @@ This represents an exception that may be thrown inside of a resource action. | Tag | Optional | Description | | :--- | :--- | :--- | | `:visibility` | ✓ | [Visibility decorator]({{ site.github.url }}/reference/visibility) | -| `{http code}` | × | The HTTP code that will be returned. Example: `{404}`, `{403}`, etc. | +| `httpCode` | × | The HTTP code that will be returned. Example: `404`, `403`, etc. | | `\Representation` | × | The fully qualified class name for a representation that will be returned. | -| `(error code)` | ✓ | An optional error code, if your application supports unique error codes, that this error returns. This can either be a numerical code (ex. `(1234)`), or a fully qualified static accessor (ex. (`\Some\Exception::NOT_ALLOWED`). | +| `error code` | ✓ | An optional error code, if your application supports unique error codes, that this error returns. This can either be a numerical code (ex. `(1234)`), or a fully qualified static accessor (ex. (`\Some\Exception::NOT_ALLOWED`). | | `description` | ✓ | A short description describing why, or what, this error is. | ## Types and subtypes @@ -35,7 +35,7 @@ In addition to supporting straight descriptions, the [`@api-error`]({{ site.gith the concept of "types" and "subtypes". For example: ```php -@api-error:public {404} \ErrorRepresentation {user} +@api-error:public 404 (\ErrorRepresentation) - {user} ``` In this case, this exception will be thrown when the `{user}` passed into the route (usually via the URI) is not found. @@ -44,7 +44,7 @@ The generated error message for this becomes: "If the user cannot be found." There also exist the concept of a subtype, represented as: ```php -@api-error:public {404} \ErrorRepresentation {user,group} +@api-error:public 404 (\ErrorRepresentation) - {user,group} ``` This means that if the supplied group could not be found for the supplied user, an exception will be thrown. The @@ -57,7 +57,7 @@ Usage with a capability and description type: /** * … * - * @api-error:public {404} \ErrorRepresentation +SomeCapability+ {user} + * @api-error:public 404 (\ErrorRepresentation, SomeCapability) - {user} */ public function PATCH() { @@ -71,8 +71,8 @@ With an error code: /** * … * - * @api-error:public {403} \ErrorRepresentation (\AppError::USER_NOT_ALLOWED) If - * the user isn't allowed to do something. + * @api-error:public 403 (\ErrorRepresentation<7701>) If the user isn't + * allowed to do something. */ public function PATCH() { @@ -86,8 +86,8 @@ Standard usage: /** * … * - * @api-error:public {404} \ErrorRepresentation If the user isn't allowed to do - * something. + * @api-error:public 404 (\ErrorRepresentation) - If the user isn't allowed + * to do something. */ public function PATCH() { diff --git a/docs/reference/api-minversion.md b/docs/reference/api-minversion.md index 50ad71d..0dd7827 100644 --- a/docs/reference/api-minversion.md +++ b/docs/reference/api-minversion.md @@ -34,7 +34,7 @@ This allows you to denote the minimum API version required for a resource action * * @api-minversion 3.2 * - * @api-error:private {403} \Some\ErrorErrorRepresentation If the user isn't + * @api-error:private 403 (\Some\ErrorErrorRepresentation) - If the user isn't * allowed to do something. */ public function PATCH() diff --git a/docs/reference/api-scope.md b/docs/reference/api-scope.md index 0c2877d..a4f0182 100644 --- a/docs/reference/api-scope.md +++ b/docs/reference/api-scope.md @@ -36,7 +36,7 @@ required for a resource action, or a representation data point. * * @api-scope edit * - * @api-error:private {403} \Some\ErrorErrorRepresentation If the user isn't + * @api-error:private 403 (\Some\ErrorErrorRepresentation) - If the user isn't * allowed to do something. */ public function PATCH() diff --git a/docs/reference/deprecation.md b/docs/reference/deprecation.md index f6bf5a4..3c45611 100644 --- a/docs/reference/deprecation.md +++ b/docs/reference/deprecation.md @@ -31,7 +31,7 @@ You might have instances where you need to deprecate a resource action request p * * @api-return:public {object} \MyApplication\Representations\Movie * - * @api-error:public {404} \MyApplicationRepresentations\Error If the movie + * @api-error:public 404 (\MyApplicationRepresentations\Error) - If the movie * could not be found. */ public function GET() diff --git a/docs/reference/visibility.md b/docs/reference/visibility.md index f53edb1..d060a6f 100644 --- a/docs/reference/visibility.md +++ b/docs/reference/visibility.md @@ -24,7 +24,7 @@ To choose what visibility your annotation should have, suffix your annotation wi * @api-uri:private {Films} /films/+id * @api-urisegment {/films/+id} id (integer) - Film ID * - * @api-error:private {403} \Some\ErrorErrorRepresentation If the user isn't + * @api-error:private 403 (\Some\ErrorErrorRepresentation) - If the user isn't * allowed to do something. */ public function PATCH() diff --git a/resources/examples/Showtimes/Controllers/Movie.php b/resources/examples/Showtimes/Controllers/Movie.php index 33a751b..c0e20b0 100644 --- a/resources/examples/Showtimes/Controllers/Movie.php +++ b/resources/examples/Showtimes/Controllers/Movie.php @@ -35,7 +35,7 @@ class Movie * @api-return:public {object} \Mill\Examples\Showtimes\Representations\Movie * @api-return:public {notmodified} If no content has been modified since the supplied Last-Modified header. * - * @api-error:public {404} \Mill\Examples\Showtimes\Representations\Error If the movie could not be found. + * @api-error:public 404 (\Mill\Examples\Showtimes\Representations\Error) - If the movie could not be found. * * @api-version >=1.1.2 * @api-contentType application/mill.example.movie @@ -44,8 +44,8 @@ class Movie * @api-contentType application/json * * @api-version >=1.1.3 - * @api-error:public {404} \Mill\Examples\Showtimes\Representations\Error For no reason. - * @api-error:public {404} \Mill\Examples\Showtimes\Representations\Error For some other reason. + * @api-error:public 404 (\Mill\Examples\Showtimes\Representations\Error) - For no reason. + * @api-error:public 404 (\Mill\Examples\Showtimes\Representations\Error) - For some other reason. */ public function GET() { @@ -85,9 +85,9 @@ public function GET() * * @api-return:public {object} \Mill\Examples\Showtimes\Representations\Movie * - * @api-error:public {400} \Mill\Examples\Showtimes\Representations\Error If there is a problem with the request. - * @api-error:public {400} \Mill\Examples\Showtimes\Representations\Error If the IMDB URL could not be validated. - * @api-error:public {404} \Mill\Examples\Showtimes\Representations\Error If the movie could not be found. + * @api-error:public 400 (\Mill\Examples\Showtimes\Representations\Error) - If there is a problem with the request. + * @api-error:public 400 (\Mill\Examples\Showtimes\Representations\Error) - If the IMDB URL could not be validated. + * @api-error:public 404 (\Mill\Examples\Showtimes\Representations\Error) - If the movie could not be found. * * @api-version >=1.1.2 * @api-contentType application/mill.example.movie @@ -100,11 +100,11 @@ public function GET() * * @api-version >=1.1.3 * @api-return:public {accepted} \Mill\Examples\Showtimes\Representations\Movie - * @api-error:public {404} \Mill\Examples\Showtimes\Representations\Error If the trailer URL could not be validated. - * @api-error:private {403} \Mill\Examples\Showtimes\Representations\CodedError (1337) If something cool happened. - * @api-error:public {403} \Mill\Examples\Showtimes\Representations\CodedError - * (Mill\Examples\Showtimes\Representations\CodedError::DISALLOWED) If the user is not allowed to edit that - * movie. + * @api-error:public 404 (\Mill\Examples\Showtimes\Representations\Error) - If the trailer URL could not be + * validated. + * @api-error:private 403 (\Mill\Examples\Showtimes\Representations\CodedError<1337>) - If something cool happened. + * @api-error:public 403 (\Mill\Examples\Showtimes\Representations\CodedError<666>) - If the user is not allowed to + * edit that movie. */ public function PATCH() { @@ -126,7 +126,7 @@ public function PATCH() * * @api-return:private {deleted} * - * @api-error:private {404} \Mill\Examples\Showtimes\Representations\Error If the movie could not be found. + * @api-error:private 404 (\Mill\Examples\Showtimes\Representations\Error) - If the movie could not be found. */ public function DELETE() { diff --git a/resources/examples/Showtimes/Controllers/Movies.php b/resources/examples/Showtimes/Controllers/Movies.php index 4c6c70e..b70ede9 100644 --- a/resources/examples/Showtimes/Controllers/Movies.php +++ b/resources/examples/Showtimes/Controllers/Movies.php @@ -17,7 +17,7 @@ class Movies * * @api-return:public {collection} \Mill\Examples\Showtimes\Representations\Movie * - * @api-error:public {400} \Mill\Examples\Showtimes\Representations\Error If the location is invalid. + * @api-error:public 400 (\Mill\Examples\Showtimes\Representations\Error) - If the location is invalid. * * @api-version >=1.1.2 * @api-contentType application/mill.example.movie @@ -63,8 +63,8 @@ public function GET() * * @api-return:public {object} \Mill\Examples\Showtimes\Representations\Movie * - * @api-error:public {400} \Mill\Examples\Showtimes\Representations\Error If there is a problem with the request. - * @api-error:public {400} \Mill\Examples\Showtimes\Representations\Error If the IMDB URL could not be validated. + * @api-error:public 400 (\Mill\Examples\Showtimes\Representations\Error) - If there is a problem with the request. + * @api-error:public 400 (\Mill\Examples\Showtimes\Representations\Error) - If the IMDB URL could not be validated. * * @api-version >=1.1.2 * @api-contentType application/mill.example.movie diff --git a/resources/examples/Showtimes/Controllers/Theater.php b/resources/examples/Showtimes/Controllers/Theater.php index 74f4cd9..0c7807f 100644 --- a/resources/examples/Showtimes/Controllers/Theater.php +++ b/resources/examples/Showtimes/Controllers/Theater.php @@ -21,7 +21,7 @@ class Theater * @api-return:public {object} \Mill\Examples\Showtimes\Representations\Theater * @api-return:public {notmodified} If no content has been modified since the supplied Last-Modified header. * - * @api-error:public {404} \Mill\Examples\Showtimes\Representations\Error If the movie theater could not be found. + * @api-error:public 404 (\Mill\Examples\Showtimes\Representations\Error) - If the movie theater could not be found. * * @api-version >=1.1.2 * @api-contentType application/mill.example.theater @@ -50,15 +50,15 @@ public function GET() * * @api-return:public {object} \Mill\Examples\Showtimes\Representations\Theater * - * @api-error:public {400} \Mill\Examples\Showtimes\Representations\Error If there is a problem with the request. - * @api-error:public {404} \Mill\Examples\Showtimes\Representations\Error If the movie movie could not be found. + * @api-error:public 400 (\Mill\Examples\Showtimes\Representations\Error) - If there is a problem with the request. + * @api-error:public 404 (\Mill\Examples\Showtimes\Representations\Error) - If the movie movie could not be found. * * @api-version >=1.1.2 * @api-contentType application/mill.example.theater * * @api-version <1.1.2 * @api-contentType application/json - * @api-error:public {403} \Mill\Examples\Showtimes\Representations\CodedError (1337) If something cool happened. + * @api-error:public 403 (\Mill\Examples\Showtimes\Representations\CodedError<1337>) - If something cool happened. */ public function PATCH() { @@ -78,7 +78,8 @@ public function PATCH() * * @api-return:private {deleted} * - * @api-error:private {404} \Mill\Examples\Showtimes\Representations\Error If the movie theater could not be found. + * @api-error:private 404 (\Mill\Examples\Showtimes\Representations\Error) - If the movie theater could not be + * found. */ public function DELETE() { diff --git a/resources/examples/Showtimes/Controllers/Theaters.php b/resources/examples/Showtimes/Controllers/Theaters.php index b03befa..1340024 100644 --- a/resources/examples/Showtimes/Controllers/Theaters.php +++ b/resources/examples/Showtimes/Controllers/Theaters.php @@ -17,7 +17,7 @@ class Theaters * * @api-return:public {collection} \Mill\Examples\Showtimes\Representations\Theater * - * @api-error:public {400} \Mill\Examples\Showtimes\Representations\Error If the location is invalid. + * @api-error:public 400 (\Mill\Examples\Showtimes\Representations\Error) - If the location is invalid. * * @api-version >=1.1.2 * @api-contentType application/mill.example.theater @@ -45,7 +45,7 @@ public function GET() * * @api-return:public {object} \Mill\Examples\Showtimes\Representations\Theater * - * @api-error:public {400} \Mill\Examples\Showtimes\Representations\Error If there is a problem with the request. + * @api-error:public 400 (\Mill\Examples\Showtimes\Representations\Error) - If there is a problem with the request. * * @api-version >=1.1.2 * @api-contentType application/mill.example.theater diff --git a/src/Exceptions/Annotations/UncallableErrorCodeException.php b/src/Exceptions/Annotations/UncallableErrorCodeException.php deleted file mode 100644 index 8b71eba..0000000 --- a/src/Exceptions/Annotations/UncallableErrorCodeException.php +++ /dev/null @@ -1,26 +0,0 @@ -docblock = $docblock; - $exception->class = $class; - $exception->method = $method; - - return $exception; - } -} diff --git a/src/Parser/Annotations/ErrorAnnotation.php b/src/Parser/Annotations/ErrorAnnotation.php index bea5f34..646f57b 100644 --- a/src/Parser/Annotations/ErrorAnnotation.php +++ b/src/Parser/Annotations/ErrorAnnotation.php @@ -3,12 +3,12 @@ use Mill\Container; use Mill\Exceptions\Annotations\MissingRepresentationErrorCodeException; -use Mill\Exceptions\Annotations\UncallableErrorCodeException; use Mill\Exceptions\Annotations\UnknownErrorRepresentationException; use Mill\Exceptions\Annotations\UnknownReturnCodeException; use Mill\Exceptions\Config\UnconfiguredErrorRepresentationException; use Mill\Parser\Annotation; use Mill\Parser\Annotations\Traits\HasHttpCodeResponseTrait; +use Mill\Parser\MSON; use Mill\Parser\Version; /** @@ -57,7 +57,6 @@ class ErrorAnnotation extends Annotation /** * {@inheritdoc} * @throws UnknownReturnCodeException If a supplied HTTP code is invalid. - * @throws UncallableErrorCodeException If a supplied error code is uncallable. * @throws UnknownErrorRepresentationException If a supplied representation has not been configured as allowing * errors. * @throws MissingRepresentationErrorCodeException If a supplied representation has been configured as requiring @@ -66,91 +65,54 @@ class ErrorAnnotation extends Annotation protected function parser(): array { $config = Container::getConfig(); + $content = trim($this->docblock); /** @var string $method */ $method = $this->method; - - $parsed = []; - $content = trim($this->docblock); - - // HTTP code is surrounded by +plusses+. - if (preg_match(self::REGEX_ERROR_HTTP_CODE, $content, $matches)) { - $parsed['http_code'] = $matches[1]; - + $mson = (new MSON($this->class, $method))->allowAllSubtypes()->parse($content); + $parsed = [ + 'http_code' => $mson->getField(), + 'representation' => $mson->getType(), + 'error_code' => $mson->getSubtype(), + 'capability' => $mson->getCapability(), + 'description' => $mson->getDescription() + ]; + + if (!empty($parsed['http_code'])) { if (!$this->isValidHttpCode($parsed['http_code'])) { throw UnknownReturnCodeException::create('error', $this->docblock, $this->class, $method); } $parsed['http_code'] .= ' ' . $this->getHttpCodeMessage($parsed['http_code']); - $content = trim(preg_replace(self::REGEX_ERROR_HTTP_CODE, '', $content)); - } - - $parts = explode(' ', $content); - $parsed['representation'] = array_shift($parts); - - // Representation is by itself, so put the pieces back together so we can do some more regex. - $content = implode(' ', $parts); - - if (!empty($parsed['representation'])) { - $representation = $parsed['representation']; - - // Verify that the supplied representation class exists. If it's being excluded, we can just go ahead and - // set it here anyways, as we'll be looking further up the stack to determine if we should actually parse it - // for documentation. - // - // If the class doesn't exist, this method call will throw an exception back out. - try { - $config->doesErrorRepresentationExist($representation); - } catch (UnconfiguredErrorRepresentationException $e) { - throw UnknownErrorRepresentationException::create($representation, $this->class, $method); - } - } - - // Error codes are marked with `(\SomeError\Class::CASE)` or `(1337)` parens. - if (preg_match(self::REGEX_ERROR_CODE, $content, $matches)) { - $error_code = substr($matches[1], 1, -1); - if (is_numeric($error_code)) { - $parsed['error_code'] = $error_code; - } else { - if (!defined($error_code)) { - throw UncallableErrorCodeException::create($this->docblock, $this->class, $method); - } - - $parsed['error_code'] = constant($error_code); - } - - $content = trim(preg_replace(self::REGEX_ERROR_CODE, '', $content)); } // Capability is surrounded by +plusses+. - if (preg_match(self::REGEX_CAPABILITY, $content, $matches)) { - $capability = substr($matches[1], 1, -1); - $parsed['capability'] = (new CapabilityAnnotation($capability, $this->class, $method))->process(); - - $content = trim(preg_replace(self::REGEX_CAPABILITY, '', $content)); + if (!empty($parsed['capability'])) { + $parsed['capability'] = (new CapabilityAnnotation( + $parsed['capability'], + $this->class, + $method + ))->process(); } - $description = trim($content); - if (!empty($description)) { - if (preg_match(self::REGEX_ERROR_SUB_TYPE, $description, $matches)) { - $description = sprintf('If %s was not found in the %s.', $matches[1], $matches[2]); - } elseif (preg_match(self::REGEX_ERROR_TYPE, $description, $matches)) { - $description = sprintf('If %s was not found.', $matches[1]); + if (!empty($parsed['description'])) { + if (preg_match(self::REGEX_ERROR_SUB_TYPE, $parsed['description'], $matches)) { + $parsed['description'] = sprintf('If %s was not found in the %s.', $matches[1], $matches[2]); + } elseif (preg_match(self::REGEX_ERROR_TYPE, $parsed['description'], $matches)) { + $parsed['description'] = sprintf('If %s was not found.', $matches[1]); } - - $parsed['description'] = $description; } // Now that we've parsed out both the representation and error code, make sure that a representation that // requires an error code, actually has one. if (!empty($parsed['representation'])) { - $representation = $parsed['representation']; - // If this representation requires an error code (as defined in the config file), but we don't have one, // throw an error. - if ($config->doesErrorRepresentationNeedAnErrorCode($representation) && !isset($parsed['error_code'])) { + if ($config->doesErrorRepresentationNeedAnErrorCode($parsed['representation']) && + empty($parsed['error_code']) + ) { throw MissingRepresentationErrorCodeException::create( - $representation, + $parsed['representation'], $this->class, $method ); diff --git a/src/Parser/MSON.php b/src/Parser/MSON.php index 8a4789a..92e124e 100644 --- a/src/Parser/MSON.php +++ b/src/Parser/MSON.php @@ -2,7 +2,9 @@ namespace Mill\Parser; use Mill\Container; +use Mill\Exceptions\Annotations\UnknownErrorRepresentationException; use Mill\Exceptions\Annotations\UnsupportedTypeException; +use Mill\Exceptions\Config\UnconfiguredErrorRepresentationException; use Mill\Exceptions\Config\UnconfiguredRepresentationException; use Mill\Exceptions\MSON\MissingOptionsException; @@ -120,6 +122,13 @@ class MSON */ protected $values = []; + /** + * Allow all kind of subtypes. Used for `@api-error` annotations to allow error codes. + * + * @var bool + */ + protected $allow_all_subtypes = false; + /** * Supported MSON field types. * @@ -211,10 +220,18 @@ public function parse(string $content): self if (!in_array(strtolower($this->type), $this->supported_types)) { try { - // If this isn't a valid representation, then it's an invalid type. - $config->doesRepresentationExist($this->type); + // If we're allowing all subtypes, then we're dealing with error states and the `@api-error` + // annotation, so we should look at error representations instead here. + if ($this->allow_all_subtypes) { + $config->doesErrorRepresentationExist($this->type); + } else { + // If this isn't a valid representation, then it's an invalid type. + $config->doesRepresentationExist($this->type); + } } catch (UnconfiguredRepresentationException $e) { throw UnsupportedTypeException::create($content, $this->class, $this->method); + } catch (UnconfiguredErrorRepresentationException $e) { + throw UnknownErrorRepresentationException::create($content, $this->class, $this->method); } } @@ -232,6 +249,10 @@ public function parse(string $content): self break; default: + if ($this->allow_all_subtypes) { + break; + } + throw UnsupportedTypeException::create($content, $this->class, $this->method); } } @@ -373,6 +394,17 @@ public function getValues(): array return $this->values; } + /** + * Allow all kind of subtypes. Used for `@api-error` annotations to allow error codes. + * + * @return MSON + */ + public function allowAllSubtypes(): self + { + $this->allow_all_subtypes = true; + return $this; + } + /** * Get parsed MSON content in an array. * diff --git a/tests/Parser/Annotations/ErrorAnnotationTest.php b/tests/Parser/Annotations/ErrorAnnotationTest.php index e86699c..482bb1a 100644 --- a/tests/Parser/Annotations/ErrorAnnotationTest.php +++ b/tests/Parser/Annotations/ErrorAnnotationTest.php @@ -1,9 +1,9 @@ [ - 'content' => '{404} \Mill\Examples\Showtimes\Representations\Error If the movie could not be found.', + 'content' => '404 (\Mill\Examples\Showtimes\Representations\Error) - If the movie could not be found.', 'version' => null, 'visible' => true, 'expected' => [ @@ -95,8 +95,8 @@ public function providerAnnotation(): array ] ], 'capability' => [ - 'content' => '{404} \Mill\Examples\Showtimes\Representations\Error +BUY_TICKETS+ If the movie could ' . - 'not be found.', + 'content' => '404 (\Mill\Examples\Showtimes\Representations\Error, BUY_TICKETS) - If the movie ' . + 'could not be found.', 'version' => null, 'visible' => true, 'expected' => [ @@ -110,7 +110,7 @@ public function providerAnnotation(): array ] ], 'description' => [ - 'content' => '{400} \Mill\Examples\Showtimes\Representations\Error If an unknown error occurred.', + 'content' => '400 (\Mill\Examples\Showtimes\Representations\Error) - If an unknown error occurred.', 'version' => null, 'visible' => true, 'expected' => [ @@ -124,7 +124,7 @@ public function providerAnnotation(): array ] ], 'description.has_parenthesis' => [ - 'content' => '{403} \Mill\Examples\Showtimes\Representations\Error This is a description with a ' . + 'content' => '403 (\Mill\Examples\Showtimes\Representations\Error) - This is a description with a ' . '(parenthesis of something).', 'version' => null, 'visible' => true, @@ -139,7 +139,7 @@ public function providerAnnotation(): array ] ], 'description.error_type' => [ - 'content' => '{404} \Mill\Examples\Showtimes\Representations\Error {movie}', + 'content' => '404 (\Mill\Examples\Showtimes\Representations\Error) - {movie}', 'version' => null, 'visible' => true, 'expected' => [ @@ -153,7 +153,7 @@ public function providerAnnotation(): array ] ], 'description.error_type.suberror_type' => [ - 'content' => '{404} \Mill\Examples\Showtimes\Representations\Error {movie,theater}', + 'content' => '404 (\Mill\Examples\Showtimes\Representations\Error) - {movie,theater}', 'version' => null, 'visible' => true, 'expected' => [ @@ -167,9 +167,8 @@ public function providerAnnotation(): array ] ], 'error_code' => [ - 'content' => '{403} \Mill\Examples\Showtimes\Representations\CodedError ' . - '(Mill\Examples\Showtimes\Representations\CodedError::DISALLOWED) If the user is not allowed to ' . - 'edit that movie.', + 'content' => '403 (\Mill\Examples\Showtimes\Representations\CodedError<666>) - If the user is not ' . + 'allowed to edit that movie.', 'version' => null, 'visible' => true, 'expected' => [ @@ -183,7 +182,7 @@ public function providerAnnotation(): array ] ], 'error_code.numerical' => [ - 'content' => '{403} \Mill\Examples\Showtimes\Representations\CodedError (1337) If something cool ' . + 'content' => '403 (\Mill\Examples\Showtimes\Representations\CodedError<1337>) - If something cool ' . 'happened.', 'version' => null, 'visible' => true, @@ -198,7 +197,7 @@ public function providerAnnotation(): array ] ], 'private' => [ - 'content' => '{404} \Mill\Examples\Showtimes\Representations\Error {movie}', + 'content' => '404 (\Mill\Examples\Showtimes\Representations\Error) - {movie}', 'version' => null, 'visible' => false, 'expected' => [ @@ -212,7 +211,7 @@ public function providerAnnotation(): array ] ], 'versioned' => [ - 'content' => '{404} \Mill\Examples\Showtimes\Representations\Error {movie}', + 'content' => '404 (\Mill\Examples\Showtimes\Representations\Error) - {movie}', 'version' => new Version('1.1 - 1.2', __CLASS__, __METHOD__), 'visible' => false, 'expected' => [ @@ -226,8 +225,8 @@ public function providerAnnotation(): array ] ], '_complete.description' => [ - 'content' => '{404} \Mill\Examples\Showtimes\Representations\Error +BUY_TICKETS+ ' . - 'If the tickets URL does not exist.', + 'content' => '404 (\Mill\Examples\Showtimes\Representations\Error, BUY_TICKETS) - If the tickets ' . + 'URL does not exist.', 'version' => null, 'visible' => true, 'expected' => [ @@ -241,8 +240,7 @@ public function providerAnnotation(): array ] ], '_complete.error_code' => [ - 'content' => '{404} \Mill\Examples\Showtimes\Representations\CodedError ' . - '(\Mill\Examples\Showtimes\Representations\CodedError::DISALLOWED) +BUY_TICKETS+ ' . + 'content' => '404 (\Mill\Examples\Showtimes\Representations\CodedError<666>, BUY_TICKETS) - ' . '{movie,theater}', 'version' => null, 'visible' => true, @@ -257,8 +255,7 @@ public function providerAnnotation(): array ] ], '_complete.type_subtype' => [ - 'content' => '{404} \Mill\Examples\Showtimes\Representations\Error +BUY_TICKETS+ ' . - '{movie,theater}', + 'content' => '404 (\Mill\Examples\Showtimes\Representations\Error, BUY_TICKETS) - {movie,theater}', 'version' => null, 'visible' => true, 'expected' => [ @@ -277,65 +274,20 @@ public function providerAnnotation(): array public function providerAnnotationFailsOnInvalidContent(): array { return [ - 'missing-http-code' => [ - 'annotation' => ErrorAnnotation::class, - 'content' => '', - 'expected.exception' => MissingRequiredFieldException::class, - 'expected.exception.asserts' => [ - 'getRequiredField' => 'http_code', - 'getAnnotation' => 'error', - 'getDocblock' => '', - 'getValues' => [] - ] - ], - 'missing-representation' => [ - 'annotation' => ErrorAnnotation::class, - 'content' => '{404} \Mill\Examples\Showtimes\Representations\Error', - 'expected.exception' => MissingRequiredFieldException::class, - 'expected.exception.asserts' => [ - 'getRequiredField' => 'description', - 'getAnnotation' => 'error', - 'getDocblock' => '{404} \Mill\Examples\Showtimes\Representations\Error', - 'getValues' => [] - ] - ], - 'missing-description' => [ - 'annotation' => ErrorAnnotation::class, - 'content' => '{404}', - 'expected.exception' => MissingRequiredFieldException::class, - 'expected.exception.asserts' => [ - 'getRequiredField' => 'representation', - 'getAnnotation' => 'error', - 'getDocblock' => '{404}', - 'getValues' => [] - ] - ], 'representation-is-unknown' => [ 'annotation' => ErrorAnnotation::class, - 'content' => '{404} \UnknownRepresentation', + 'content' => '404 (\UnknownRepresentation) - For some reason.', 'expected.exception' => UnknownErrorRepresentationException::class, 'expected.exception.asserts' => [ 'getRequiredField' => null, 'getAnnotation' => null, - 'getDocblock' => '\UnknownRepresentation', - 'getValues' => [] - ] - ], - 'error-code-is-uncallable' => [ - 'annotation' => ErrorAnnotation::class, - 'content' => '{404} \Mill\Examples\Showtimes\Representations\CodedError (\Uncallable::CONSTANT)', - 'expected.exception' => UncallableErrorCodeException::class, - 'expected.exception.asserts' => [ - 'getRequiredField' => null, - 'getAnnotation' => null, - 'getDocblock' => '{404} \Mill\Examples\Showtimes\Representations\CodedError ' . - '(\Uncallable::CONSTANT)', + 'getDocblock' => '404 (\UnknownRepresentation) - For some reason.', 'getValues' => [] ] ], 'error-code-is-required-but-missing' => [ 'annotation' => ErrorAnnotation::class, - 'content' => '{403} \Mill\Examples\Showtimes\Representations\CodedError', + 'content' => '403 (\Mill\Examples\Showtimes\Representations\CodedError) - For some reason.', 'expected.exception' => MissingRepresentationErrorCodeException::class, 'expected.exception.asserts' => [ 'getRequiredField' => null, @@ -346,12 +298,12 @@ public function providerAnnotationFailsOnInvalidContent(): array ], 'http-code-is-invalid' => [ 'annotation' => ErrorAnnotation::class, - 'content' => '{440} \Mill\Examples\Showtimes\Representations\Error', + 'content' => '440 (\Mill\Examples\Showtimes\Representations\Error) - For some reason.', 'expected.exception' => UnknownReturnCodeException::class, 'expected.exception.asserts' => [ 'getRequiredField' => null, 'getAnnotation' => null, - 'getDocblock' => '{440} \Mill\Examples\Showtimes\Representations\Error', + 'getDocblock' => '440 (\Mill\Examples\Showtimes\Representations\Error) - For some reason.', 'getValues' => [] ] ] diff --git a/tests/Parser/Annotations/ParamAnnotationTest.php b/tests/Parser/Annotations/ParamAnnotationTest.php index b8cfdbe..31e6ff1 100644 --- a/tests/Parser/Annotations/ParamAnnotationTest.php +++ b/tests/Parser/Annotations/ParamAnnotationTest.php @@ -432,16 +432,6 @@ public function providerAnnotation(): array public function providerAnnotationFailsOnInvalidContent(): array { return [ - 'invalid-mson' => [ - 'annotation' => ParamAnnotation::class, - 'content' => '', - 'expected.exception' => InvalidMSONSyntaxException::class, - 'expected.exception.asserts' => [ - 'getAnnotation' => 'param', - 'getDocblock' => '', - 'getValues' => [] - ] - ], 'unsupported-type' => [ 'annotation' => ParamAnnotation::class, 'content' => 'content_rating `G` (str) - MPAA rating', diff --git a/tests/Parser/Resource/Action/DocumentationTest.php b/tests/Parser/Resource/Action/DocumentationTest.php index 0ea92fc..869cb6e 100644 --- a/tests/Parser/Resource/Action/DocumentationTest.php +++ b/tests/Parser/Resource/Action/DocumentationTest.php @@ -872,9 +872,8 @@ public function providerMethodsThatWillFailParsing(): array * @api-contentType application/json * @api-scope public * @api-return:private {collection} \Mill\Examples\Showtimes\Representations\Representation - * @api-error:public {403} \Mill\Examples\Showtimes\Representations\CodedError - * (Mill\Examples\Showtimes\Representations\CodedError::DISALLOWED) If the user isn\'t allowed to - * do something. + * @api-error:public 403 (\Mill\Examples\Showtimes\Representations\CodedError<666>) - If the user + * isn\'t allowed to do something. */', 'expected.exception' => '\Mill\Exceptions\Resource\PublicDecoratorOnPrivateActionException', 'expected.exception.asserts' => [ @@ -891,9 +890,8 @@ public function providerMethodsThatWillFailParsing(): array * @api-contentType application/json * @api-scope public * @api-return:private {collection} \Mill\Examples\Showtimes\Representations\Representation - * @api-error:public {403} \Mill\Examples\Showtimes\Representations\CodedError - * (Mill\Examples\Showtimes\Representations\CodedError::DISALLOWED) If the user isn\'t allowed to - * do something. + * @api-error:public 403 (\Mill\Examples\Showtimes\Representations\CodedError<666>) - If the user + * isn\'t allowed to do something. */', 'expected.exception' => '\Mill\Exceptions\Resource\TooManyAliasedUrisException', 'expected.exception.asserts' => [] From 56cf4d5def67d252faafae7ce4f0fd52721bb01f Mon Sep 17 00:00:00 2001 From: Jon Ursenbach Date: Thu, 29 Mar 2018 15:09:30 -0400 Subject: [PATCH 03/53] Replacing `@api-capability` with a new generalized `@api-vendorTag`. https://github.com/vimeo/mill/issues/148 --- README.md | 2 +- composer.json | 40 ++-- config.xsd | 22 +- docs/_layouts/default.html | 2 +- docs/configuration.md | 104 ++++----- docs/generate/changelogs.md | 9 +- docs/generate/documentation.md | 9 +- docs/getting-started.md | 30 +-- docs/index.html | 2 +- docs/reference.md | 2 +- docs/reference/actions.md | 2 +- docs/reference/api-capability.md | 59 ----- docs/reference/api-data.md | 22 +- docs/reference/api-error.md | 22 +- docs/reference/api-minversion.md | 3 +- docs/reference/api-param.md | 11 +- docs/reference/api-return.md | 22 +- docs/reference/api-scope.md | 5 +- docs/reference/api-see.md | 6 +- docs/reference/api-vendortag.md | 65 ++++++ docs/reference/deprecation.md | 14 +- docs/reference/uri-segment.md | 3 +- docs/reference/versioning.md | 41 ++-- docs/reference/visibility.md | 21 +- .../examples/Showtimes/Controllers/Movie.php | 2 +- .../Showtimes/Representations/Movie.php | 2 +- ... => errors-public-only-all-vendor-tags.md} | 0 ...errors-public-only-matched-vendor-tags.md} | 0 ...rors-public-only-unmatched-vendor-tags.md} | 0 ... => errors-public-only-all-vendor-tags.md} | 0 ...errors-public-only-matched-vendor-tags.md} | 0 ...rors-public-only-unmatched-vendor-tags.md} | 0 ... => errors-public-only-all-vendor-tags.md} | 0 ...errors-public-only-matched-vendor-tags.md} | 0 ...rors-public-only-unmatched-vendor-tags.md} | 0 ... => errors-public-only-all-vendor-tags.md} | 0 ...errors-public-only-matched-vendor-tags.md} | 0 ...rors-public-only-unmatched-vendor-tags.md} | 0 ... changelog-public-only-all-vendor-tags.md} | 0 ...c-only-matched-with-delete-vendor-tags.md} | 0 ...d-with-tickets-and-feature-vendor-tags.md} | 0 resources/examples/mill.xml | 12 +- src/Command/Changelog.php | 10 +- src/Command/ErrorMap.php | 10 +- src/Config.php | 38 ++-- .../InvalidCapabilitySuppliedException.php | 44 ---- .../InvalidVendorTagSuppliedException.php | 42 ++++ src/Generator.php | 46 ++-- src/Parser.php | 4 + src/Parser/Annotation.php | 105 +++++---- .../Annotations/CapabilityAnnotation.php | 64 ------ src/Parser/Annotations/DataAnnotation.php | 25 ++- src/Parser/Annotations/ErrorAnnotation.php | 26 ++- src/Parser/Annotations/ParamAnnotation.php | 25 ++- .../Annotations/VendorTagAnnotation.php | 90 ++++++++ src/Parser/MSON.php | 44 ++-- src/Parser/Representation/Documentation.php | 43 ++-- .../Representation/RepresentationParser.php | 14 +- src/Parser/Resource/Action/Documentation.php | 48 ++-- tests/Command/ChangelogTest.php | 40 ++-- tests/Command/ErrorMapTest.php | 38 ++-- tests/ConfigTest.php | 10 +- tests/Generator/ChangelogTest.php | 38 ++-- tests/Generator/ErrorMapTest.php | 44 ++-- tests/GeneratorTest.php | 64 +++--- .../Annotations/ContentTypeAnnotationTest.php | 9 +- .../Parser/Annotations/DataAnnotationTest.php | 158 +++++++------- .../Annotations/DescriptionAnnotationTest.php | 9 +- .../Annotations/ErrorAnnotationTest.php | 91 ++++---- .../Annotations/LabelAnnotationTest.php | 9 +- .../Annotations/MinVersionAnnotationTest.php | 9 +- .../Annotations/ParamAnnotationTest.php | 128 ++++++----- .../Annotations/ReturnAnnotationTest.php | 9 +- .../Annotations/ScopeAnnotationTest.php | 9 +- .../Parser/Annotations/UriAnnotationTest.php | 9 +- .../Annotations/UriSegmentAnnotationTest.php | 11 +- ...onTest.php => VendorTagAnnotationTest.php} | 43 ++-- tests/Parser/MSONTest.php | 69 +++--- .../Representation/DocumentationTest.php | 144 ++++++------ .../RepresentationParserTest.php | 82 +++---- .../Resource/Action/DocumentationTest.php | 206 +++++++++--------- tests/ParserTest.php | 8 +- ...ithVersioningAcrossMultipleAnnotations.php | 4 +- tests/_fixtures/mill.test.xml | 12 +- 84 files changed, 1320 insertions(+), 1145 deletions(-) delete mode 100644 docs/reference/api-capability.md create mode 100644 docs/reference/api-vendortag.md rename resources/examples/Showtimes/blueprints/1.0/{errors-public-only-all-capabilities.md => errors-public-only-all-vendor-tags.md} (100%) rename resources/examples/Showtimes/blueprints/1.0/{errors-public-only-matched-capabilities.md => errors-public-only-matched-vendor-tags.md} (100%) rename resources/examples/Showtimes/blueprints/1.0/{errors-public-only-unmatched-capabilities.md => errors-public-only-unmatched-vendor-tags.md} (100%) rename resources/examples/Showtimes/blueprints/1.1.1/{errors-public-only-all-capabilities.md => errors-public-only-all-vendor-tags.md} (100%) rename resources/examples/Showtimes/blueprints/1.1.1/{errors-public-only-matched-capabilities.md => errors-public-only-matched-vendor-tags.md} (100%) rename resources/examples/Showtimes/blueprints/1.1.1/{errors-public-only-unmatched-capabilities.md => errors-public-only-unmatched-vendor-tags.md} (100%) rename resources/examples/Showtimes/blueprints/1.1.3/{errors-public-only-all-capabilities.md => errors-public-only-all-vendor-tags.md} (100%) rename resources/examples/Showtimes/blueprints/1.1.3/{errors-public-only-matched-capabilities.md => errors-public-only-matched-vendor-tags.md} (100%) rename resources/examples/Showtimes/blueprints/1.1.3/{errors-public-only-unmatched-capabilities.md => errors-public-only-unmatched-vendor-tags.md} (100%) rename resources/examples/Showtimes/blueprints/1.1/{errors-public-only-all-capabilities.md => errors-public-only-all-vendor-tags.md} (100%) rename resources/examples/Showtimes/blueprints/1.1/{errors-public-only-matched-capabilities.md => errors-public-only-matched-vendor-tags.md} (100%) rename resources/examples/Showtimes/blueprints/1.1/{errors-public-only-unmatched-capabilities.md => errors-public-only-unmatched-vendor-tags.md} (100%) rename resources/examples/Showtimes/blueprints/{changelog-public-only-all-capabilities.md => changelog-public-only-all-vendor-tags.md} (100%) rename resources/examples/Showtimes/blueprints/{changelog-public-only-matched-with-delete-capabilities.md => changelog-public-only-matched-with-delete-vendor-tags.md} (100%) rename resources/examples/Showtimes/blueprints/{changelog-public-only-matched-with-tickets-and-feature-capabilities.md => changelog-public-only-matched-with-tickets-and-feature-vendor-tags.md} (100%) delete mode 100644 src/Exceptions/Annotations/InvalidCapabilitySuppliedException.php create mode 100644 src/Exceptions/Annotations/InvalidVendorTagSuppliedException.php delete mode 100644 src/Parser/Annotations/CapabilityAnnotation.php create mode 100644 src/Parser/Annotations/VendorTagAnnotation.php rename tests/Parser/Annotations/{CapabilityAnnotationTest.php => VendorTagAnnotationTest.php} (62%) diff --git a/README.md b/README.md index 5bfe350..7e9a4f1 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ [![Packagist](https://img.shields.io/packagist/v/vimeo/mill.svg)](https://packagist.org/packages/vimeo/mill) [![Travis CI](http://img.shields.io/travis/vimeo/mill.svg?style=flat)](https://travis-ci.org/vimeo/mill) -Mill is a PHP library for documenting a REST API with a small annotation DSL. +Mill is an annotation-based DSL for documenting a REST API. It was built for automatically generating the [Vimeo API](https://developer.vimeo.com/api/endpoints) documentation microsite, and can be compiled down into [API Blueprint](https://apiblueprint.org/) files. diff --git a/composer.json b/composer.json index 9562046..5d3cbc5 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "vimeo/mill", - "description": "A PHP library for documenting a REST API with a small annotation DSL.", + "description": "☴ An annotation-based DSL for documenting a REST API.", "license": "MIT", "authors": [ { @@ -58,34 +58,34 @@ ], "build-changelogs": [ "./bin/mill changelog --config=resources/examples/mill.xml --private=false resources/examples/Showtimes/blueprints/", - "mv resources/examples/Showtimes/blueprints/changelog.md resources/examples/Showtimes/blueprints/changelog-public-only-all-capabilities.md", + "mv resources/examples/Showtimes/blueprints/changelog.md resources/examples/Showtimes/blueprints/changelog-public-only-all-vendor-tags.md", - "./bin/mill changelog --config=resources/examples/mill.xml --private=false --capability=BUY_TICKETS --capability=FEATURE_FLAG resources/examples/Showtimes/blueprints/", - "mv resources/examples/Showtimes/blueprints/changelog.md resources/examples/Showtimes/blueprints/changelog-public-only-matched-with-tickets-and-feature-capabilities.md", + "./bin/mill changelog --config=resources/examples/mill.xml --private=false --vendor_tag='tag:BUY_TICKETS' --vendor_tag='tag:FEATURE_FLAG' resources/examples/Showtimes/blueprints/", + "mv resources/examples/Showtimes/blueprints/changelog.md resources/examples/Showtimes/blueprints/changelog-public-only-matched-with-tickets-and-feature-vendor-tags.md", - "./bin/mill changelog --config=resources/examples/mill.xml --private=false --capability=DELETE_CONTENT resources/examples/Showtimes/blueprints/", - "mv resources/examples/Showtimes/blueprints/changelog.md resources/examples/Showtimes/blueprints/changelog-public-only-matched-with-delete-capabilities.md", + "./bin/mill changelog --config=resources/examples/mill.xml --private=false --vendor_tag='tag:DELETE_CONTENT' resources/examples/Showtimes/blueprints/", + "mv resources/examples/Showtimes/blueprints/changelog.md resources/examples/Showtimes/blueprints/changelog-public-only-matched-with-delete-vendor-tags.md", "./bin/mill changelog --config=resources/examples/mill.xml resources/examples/Showtimes/blueprints/" ], "build-errors": [ "./bin/mill errors --config=resources/examples/mill.xml --private=false resources/examples/Showtimes/blueprints/", - "mv resources/examples/Showtimes/blueprints/1.0/errors.md resources/examples/Showtimes/blueprints/1.0/errors-public-only-all-capabilities.md", - "mv resources/examples/Showtimes/blueprints/1.1/errors.md resources/examples/Showtimes/blueprints/1.1/errors-public-only-all-capabilities.md", - "mv resources/examples/Showtimes/blueprints/1.1.1/errors.md resources/examples/Showtimes/blueprints/1.1.1/errors-public-only-all-capabilities.md", - "mv resources/examples/Showtimes/blueprints/1.1.3/errors.md resources/examples/Showtimes/blueprints/1.1.3/errors-public-only-all-capabilities.md", + "mv resources/examples/Showtimes/blueprints/1.0/errors.md resources/examples/Showtimes/blueprints/1.0/errors-public-only-all-vendor-tags.md", + "mv resources/examples/Showtimes/blueprints/1.1/errors.md resources/examples/Showtimes/blueprints/1.1/errors-public-only-all-vendor-tags.md", + "mv resources/examples/Showtimes/blueprints/1.1.1/errors.md resources/examples/Showtimes/blueprints/1.1.1/errors-public-only-all-vendor-tags.md", + "mv resources/examples/Showtimes/blueprints/1.1.3/errors.md resources/examples/Showtimes/blueprints/1.1.3/errors-public-only-all-vendor-tags.md", - "./bin/mill errors --config=resources/examples/mill.xml --private=false --capability=BUY_TICKETS --capability=FEATURE_FLAG resources/examples/Showtimes/blueprints/", - "mv resources/examples/Showtimes/blueprints/1.0/errors.md resources/examples/Showtimes/blueprints/1.0/errors-public-only-unmatched-capabilities.md", - "mv resources/examples/Showtimes/blueprints/1.1/errors.md resources/examples/Showtimes/blueprints/1.1/errors-public-only-unmatched-capabilities.md", - "mv resources/examples/Showtimes/blueprints/1.1.1/errors.md resources/examples/Showtimes/blueprints/1.1.1/errors-public-only-unmatched-capabilities.md", - "mv resources/examples/Showtimes/blueprints/1.1.3/errors.md resources/examples/Showtimes/blueprints/1.1.3/errors-public-only-unmatched-capabilities.md", + "./bin/mill errors --config=resources/examples/mill.xml --private=false --vendor_tag='tag:BUY_TICKETS' --vendor_tag='tag:FEATURE_FLAG' resources/examples/Showtimes/blueprints/", + "mv resources/examples/Showtimes/blueprints/1.0/errors.md resources/examples/Showtimes/blueprints/1.0/errors-public-only-unmatched-vendor-tags.md", + "mv resources/examples/Showtimes/blueprints/1.1/errors.md resources/examples/Showtimes/blueprints/1.1/errors-public-only-unmatched-vendor-tags.md", + "mv resources/examples/Showtimes/blueprints/1.1.1/errors.md resources/examples/Showtimes/blueprints/1.1.1/errors-public-only-unmatched-vendor-tags.md", + "mv resources/examples/Showtimes/blueprints/1.1.3/errors.md resources/examples/Showtimes/blueprints/1.1.3/errors-public-only-unmatched-vendor-tags.md", - "./bin/mill errors --config=resources/examples/mill.xml --private=false --capability=DELETE_CONTENT resources/examples/Showtimes/blueprints/", - "mv resources/examples/Showtimes/blueprints/1.0/errors.md resources/examples/Showtimes/blueprints/1.0/errors-public-only-matched-capabilities.md", - "mv resources/examples/Showtimes/blueprints/1.1/errors.md resources/examples/Showtimes/blueprints/1.1/errors-public-only-matched-capabilities.md", - "mv resources/examples/Showtimes/blueprints/1.1.1/errors.md resources/examples/Showtimes/blueprints/1.1.1/errors-public-only-matched-capabilities.md", - "mv resources/examples/Showtimes/blueprints/1.1.3/errors.md resources/examples/Showtimes/blueprints/1.1.3/errors-public-only-matched-capabilities.md", + "./bin/mill errors --config=resources/examples/mill.xml --private=false --vendor_tag='tag:DELETE_CONTENT' resources/examples/Showtimes/blueprints/", + "mv resources/examples/Showtimes/blueprints/1.0/errors.md resources/examples/Showtimes/blueprints/1.0/errors-public-only-matched-vendor-tags.md", + "mv resources/examples/Showtimes/blueprints/1.1/errors.md resources/examples/Showtimes/blueprints/1.1/errors-public-only-matched-vendor-tags.md", + "mv resources/examples/Showtimes/blueprints/1.1.1/errors.md resources/examples/Showtimes/blueprints/1.1.1/errors-public-only-matched-vendor-tags.md", + "mv resources/examples/Showtimes/blueprints/1.1.3/errors.md resources/examples/Showtimes/blueprints/1.1.3/errors-public-only-matched-vendor-tags.md", "./bin/mill errors --config=resources/examples/mill.xml resources/examples/Showtimes/blueprints/" ], diff --git a/config.xsd b/config.xsd index bc11302..9e13858 100644 --- a/config.xsd +++ b/config.xsd @@ -20,10 +20,10 @@ - + @@ -127,16 +127,6 @@ - - - - - - - - - - @@ -178,6 +168,16 @@ + + + + + + + + + + diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html index 2c57201..344c32d 100644 --- a/docs/_layouts/default.html +++ b/docs/_layouts/default.html @@ -36,7 +36,6 @@
  • · Resource Actions
  • diff --git a/docs/configuration.md b/docs/configuration.md index 8985879..04f423f 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -7,8 +7,9 @@ permalink: /configuration # Configuration --- -In order to instruct Mill on where to look for documentation, and any constraints you may have, Mill requires the use -of an XML configuration file (`mill.xml`). +In order to instruct Mill on where to look for documentation, and any +constraints you may have, Mill requires the use of an XML configuration file +(`mill.xml`). ```xml @@ -56,14 +57,16 @@ of an XML configuration file (`mill.xml`). ## Settings ### Versions -The `` setting lets you inform Mill on the various version of your API that exist. From here, Mill will then -know what versions to compile documentation for. +The `` setting lets you inform Mill on the various version of your API +that exist. From here, Mill will then know what versions to compile +documentation for. -To set a "default" API version, use the `default="true"` attribute. You **must** have a default version set, and there -can only be one. +To set a "default" API version, use the `default="true"` attribute. You +**must** have a default version set, and there can only be one. ### Controllers -The `` setting lets you inform Mill on where your API controllers live. +The `` setting lets you inform Mill on where your API controllers +live. * Use `` elements to specify a directory name (and `suffix`). * Specify a `` element for a specific, fully-qualified class name. @@ -80,16 +83,15 @@ controllers return), live. * Add in an `` block, with `` elements for excluding specific controllers from being parsed. #### Errors -The representation `` setting lets you tell Mill where your error representations are (the content that is -returned from [`@api-error`]({{ site.github.url }}/reference/api-error) annotations. Here you can specify a `` -with a fully-qualified class name. +The representation `` setting lets you tell Mill where your error +representations are (the content that is returned from +[`@api-error`]({{ site.github.url }}/reference/api-error) annotations. Here you +can specify a `` with a fully-qualified class name. Required attributes for the `` element are: -* `method`: Same in the way that representations in your `` declaration have method attributes to - tell Mill where your documentation lives, error representations require the same. -* `needsErrorCode`: Informs Mill if your error representation handles, and returns, a unique error code. The way that - looks in your documentation is: +* `method`: Same in the way that representations in your `` declaration have method attributes to tell Mill where your documentation lives, error representations require the same. +* `needsErrorCode`: Informs Mill if your error representation handles, and returns, a unique error code. The way that looks in your documentation is: ```php /** @@ -106,25 +108,9 @@ public function PATCH() Here, `\ErrorRepresentation` would have `needsErrorCode="true"`. -### Ccapabilities -If your API has a capability-backed permission system for granting certain endpoints, or data in representations, to -specific users, you should use this to document that. - -```xml - - - - - -``` - -You can find usage details for capabilities in the [`@api-capability`]({{ site.github.url }}/reference/api-capability), -[`@api-param`]({{ site.github.url }}/reference/api-param), [`@api-return`]({{ site.github.url }}/reference/api-return), -and [`@api-error`]({{ site.github.url }}/reference/api-error) documentation. - ### Scopes -If your API has an authentication system that requires a specific scope(s) for using an API endpoint, use this to -document those. +If your API has an authentication system that requires a specific scope(s) for +using an API endpoint, use this to document those. Example: @@ -137,11 +123,13 @@ Example: ``` -You can find usage details for scopes in the [`@api-scope`]({{ site.github.url }}/reference/api-scope) documentation. +You can find usage details for scopes in the +[`@api-scope`]({{ site.github.url }}/reference/api-scope) documentation. ### Parameter Tokens -Parameter tokens allow you to create a [`@api-param`]({{ site.github.url }}/reference/api-param) shortcode to save time -for common elements in your API (like paging or sorting). +Parameter tokens allow you to create a +[`@api-param`]({{ site.github.url }}/reference/api-param) shortcode to save +time for common elements in your API (like paging or sorting). Example: @@ -153,15 +141,16 @@ Example: ``` -You can find usage details for parameter tokens in the [`@api-param`]({{ site.github.url }}/reference/api-param#tokens) -documentation. +You can find usage details for parameter tokens in the +[`@api-param`]({{ site.github.url }}/reference/api-param#tokens) documentation. -### `` -#### `` -The URI segment translations section allows you to set up translation elements for -[`@api-uriSegment`]({{ site.github.url }}/reference/api-urisegment) annotations. Say, in your code, the route for a -video is at `/videos/+video_id`, but in your documentation, you want it to just say `/videos/+id`, this is the place to -do that. +### URI Segments +#### Translations +The URI segment translations section allows you to set up translation elements +for [`@api-uriSegment`]({{ site.github.url }}/reference/api-urisegment) +annotations. Say, in your code, the route for a video is at `/videos/+video_id`, +but in your documentation, you want it to just say `/videos/+id`, this is the +place to do that. Example: @@ -173,14 +162,32 @@ Example: ``` +### Vendor tags +If you'd like to add additional metadata (that you can eventually filter your +documentation against), you should use vendor tags to document those. + +```xml + + + + + +``` + +You can find usage details for vendor tags in the +[`@api-vendortag`]({{ site.github.url }}/reference/api-vendortag), +[`@api-param`]({{ site.github.url }}/reference/api-param), +[`@api-return`]({{ site.github.url }}/reference/api-return), and +[`@api-error`]({{ site.github.url }}/reference/api-error) documentation. + ### Generators -These settings let you control the documentation generators that Mill supports from the `./bin/mill generate` command. +These settings let you control the documentation generators that Mill supports +from the `./bin/mill generate` command. #### API Blueprint ##### Excludes -* Use `` elements to specify a resource namespace that should be excluded from API Blueprint generation and - compilation. - * Make sure to add a `namespace` attribute so Mill knows what namespace you're excluding.. +* Use `` elements to specify a resource namespace that should be excluded from API Blueprint generation and compilation. + * Make sure to add a `namespace` attribute so Mill knows what namespace you're excluding. Example: @@ -197,8 +204,7 @@ Example: ## Notes * **All directory paths should be relative to the location of your `mill.xml` configuration file.** -* If you specify a controller, representation, capability, or scope in your documentation that hasn't been configured - here, API documentation generation will fail with errors. +* If you specify a controller, representation, vendor tag, or scope in your documentation that hasn't been configured here, API documentation generation will fail with errors. ## XSD If you wish to use it for a reference, Mill has an included diff --git a/docs/generate/changelogs.md b/docs/generate/changelogs.md index 3de0399..dc24ef9 100644 --- a/docs/generate/changelogs.md +++ b/docs/generate/changelogs.md @@ -7,8 +7,9 @@ permalink: /generate/changelogs # Generate changelogs --- -Mill includes a `mill` command line application for doing various tasks on your API, including compiling your -documentation into a Markdown-representation changelog. +Mill includes a `mill` command line application for doing various tasks on your +API, including compiling your documentation into a Markdown-representation +changelog. ```bash $ ./bin/mill changelog --help @@ -83,8 +84,8 @@ $changelog = $generator->generateJson(); var_dump($changelog); ``` -Mill wraps important pieces of content in the JSON-encoded changelog that can then be styled according to however you -want to render it: +Mill wraps important pieces of content in the JSON-encoded changelog that can +then be styled according to however you want to render it: | Changeset | HTML class | data-* attribute | | :--- | :--- | :--- | diff --git a/docs/generate/documentation.md b/docs/generate/documentation.md index 83b4eef..5a432a7 100644 --- a/docs/generate/documentation.md +++ b/docs/generate/documentation.md @@ -7,8 +7,7 @@ permalink: /generate/documentation # Generate documentation --- -Mill includes a `mill` command line application for doing various tasks on your API, including compiling it down into -versioned [API Blueprint](https://apiblueprint.org/) files. +Mill includes a `mill` command line application for doing various tasks on your API, including compiling it down into versioned [API Blueprint](https://apiblueprint.org/) files. ```bash $ ./vendor/bin/mill generate --help @@ -55,8 +54,7 @@ Done! This will compile the configured documentation for my API (versions 1.0 through 1.1.1) into the `blueprints/` directory. -If we look at one of the versioned directories that it created, `blueprints/1.1`, we can see that we've got API -Blueprint files! +If we look at one of the versioned directories that it created, `blueprints/1.1`, we can see that we've got API Blueprint files! ```bash $ ls blueprints/1.1 @@ -84,8 +82,7 @@ Information on a specific movie. … ``` -Mill also generates individual parts of your documentation for you. This is helpful if you have people working on API -design work, but just want to work on the API Blueprint files (and have someone else do the backend work). +Mill also generates individual parts of your documentation for you. This is helpful if you have people working on API design work, but just want to work on the API Blueprint files (and have someone else do the backend work). ```bash $ cat blueprints/1.1/resources/Movies.apib diff --git a/docs/getting-started.md b/docs/getting-started.md index 5450a6b..b89f9a3 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -13,8 +13,8 @@ permalink: /getting-started ## Documenting your API ### Resources -Resources are a collection of actions (endpoints). These can generally be referred to as a "controller" in a standard -MVC application structure. +Resources are a collection of actions (endpoints). These can generally be +referred to as a "controller" in a standard MVC application structure. Documenting a resource is easy: @@ -32,11 +32,13 @@ class UsersController extends \MyApplication\Controller ``` -Here, you can see that we're using the [`@api-label`]({{ site.github.url }}/reference/api-label) annotation to denote +Here, you can see that we're using the +[`@api-label`]({{ site.github.url }}/reference/api-label) annotation to denote that this controller primarily handles "Search" actions. -If you'd also like to include a full Markdown representation (or anything else, really) description along with this -resource for your compiled documentation, you can do so by adding that content into the docblock: +If you'd also like to include a full Markdown representation (or anything else, +really) description along with this resource for your compiled documentation, +you can do so by adding that content into the docblock: ```php ☴ Mill
    -

    Mill is a PHP library for documenting a REST API with a small annotation DSL.

    +

    Mill is an annotation-based DSL for documenting a REST API.

    It was built for automatically generating the Vimeo API diff --git a/docs/reference.md b/docs/reference.md index 8a160cb..5fad35d 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -20,7 +20,6 @@ title: "Reference" | @annotation | Description | | :--- | :--- | -| [`@api-capability`]({{ site.github.url }}/reference/api-capability) | Denotes a required API capability for the action. | | [`@api-contenttype`]({{ site.github.url }}/reference/api-contenttype) | Denotes the `Content-Type` returned. | | [`@api-error`]({{ site.github.url }}/reference/api-error) | An exception or error that may be thrown in the action. | | [`@api-label`]({{ site.github.url }}/reference/api-label) | Short description of what the resource action handles. | @@ -30,6 +29,7 @@ title: "Reference" | [`@api-scope`]({{ site.github.url }}/reference/api-scope) | Required authentication token scope necessary for the action. | | [`@api-uri`]({{ site.github.url }}/reference/api-uri) | Denotes a URI that this action services. | | [`@api-urisegment`]({{ site.github.url }}/reference/api-urisegment) | Describes parameters for the URI. | +| [`@api-vendortag`]({{ site.github.url }}/reference/api-vendortag) | Denotes a documented vendor tag for the action. | ## Representations diff --git a/docs/reference/actions.md b/docs/reference/actions.md index 45d6fc9..d96fb9f 100644 --- a/docs/reference/actions.md +++ b/docs/reference/actions.md @@ -9,7 +9,6 @@ permalink: /reference/resource-actions | @annotation | Description | | :--- | :--- | -| [`@api-capability`]({{ site.github.url }}/reference/api-capability) | Denotes a required API capability for the action. | | [`@api-contenttype`]({{ site.github.url }}/reference/api-contenttype) | Denotes the `Content-Type` returned. | | [`@api-error`]({{ site.github.url }}/reference/api-error) | An exception or error that may be thrown in the action. | | [`@api-label`]({{ site.github.url }}/reference/api-label) | Short description of what the resource action handles. | @@ -19,3 +18,4 @@ permalink: /reference/resource-actions | [`@api-scope`]({{ site.github.url }}/reference/api-scope) | Required authentication token scope necessary for the action. | | [`@api-uri`]({{ site.github.url }}/reference/api-uri) | Denotes a URI that this action services. | | [`@api-urisegment`]({{ site.github.url }}/reference/api-urisegment) | Describes parameters for the URI. | +| [`@api-vendortag`]({{ site.github.url }}/reference/api-vendortag) | Denotes a documented vendor tag for the action. | diff --git a/docs/reference/api-capability.md b/docs/reference/api-capability.md deleted file mode 100644 index 6e4cad7..0000000 --- a/docs/reference/api-capability.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -layout: default -title: "@api-capability" -permalink: /reference/api-capability ---- - -# @api-capability ---- - -This defines a required capability in your API that the developer's application needs to possess in order to execute -the resource action, or get the representation field in the endpoint response. - -## Syntax -```php -@api-capability capability -``` - -## Requirements - -| Required? | Needs a visibility | Supports versioning | Supports deprecation | -| :--- | :--- | :--- | :--- | -| × | × | × | × | - -## Breakdown - -| Tag | Optional | Description | -| :--- | :--- | :--- | -| `capability` | × | Required capability that an API application must posses. | - -## Examples -On a resource action: - -```php -/** - * … - * @api-capability SomeApplicationCapability - * … - */ -public function PATCH() -{ - … -} -``` - -On a representation field: - -```php -$representation = [ - … - - /** - * @api-data download (boolean, SomeApplicationCapability) - Download permission setting - */ - 'download' => true, - - … -]; -``` - diff --git a/docs/reference/api-data.md b/docs/reference/api-data.md index 99dff17..36bcabe 100644 --- a/docs/reference/api-data.md +++ b/docs/reference/api-data.md @@ -7,11 +7,12 @@ permalink: /reference/api-data # @api-data --- -This describes a piece of data within a representation that a resource action can return. +This describes a piece of data within a representation that a resource action +can return. ## Syntax ```php -@api-data fieldName `sampleData` (type, required|optional, nullable, capabilityName) - Description +@api-data fieldName `sampleData` (type, required|optional, nullable, vendor:tagName) - Description + Members - `option` - Option description ``` @@ -31,7 +32,7 @@ This describes a piece of data within a representation that a resource action ca | `type` | × | This describes the type of data that a representation data field contains. | | `required|optional` | ✓ | A flag that indicates that the data is, well, optional. If nothing is supplied, it defaults to being `optional`. | | `nullable` | ✓ | A flag that indicates that the data is nullable. If nothing is supplied, it defaults to being non-nullable. | -| `capabilityName` | ✓ | Defined capability that the developers application should possess. | +| `vendor:tagName` | ✓ | Defined vendor tag. See the [`@api-vendortag`]({{ site.github.url }}/reference/api-vendortag) documentation for more information. There is no limit to the amount of vendor tags you can specify on a parameter. | | `Description` | × | A description for that this data is. | | Members | ✓ | If this data has acceptable values (like in the case of an `enum` type), you can document those values here along with a description for what the value is, or means. | @@ -53,8 +54,8 @@ This describes a piece of data within a representation that a resource action ca | uri | string | #### Representations -If your dataset is a Mill representation, you can document that by setting the type to the FQN of the representation in -question. +If your dataset is a Mill representation, you can document that by setting the +type to the FQN of the representation in question. ```php /** @@ -64,12 +65,13 @@ question. ``` #### Subtypes -Mill allows you, if necessary, to define a single subtype for a dataset. For example, if you have an array that contains -objects, you can set the `type` as `array`. Alternatively, if you have an array of representations, you can do -the same with `array<\RepresentationFQN>`. +Mill allows you, if necessary, to define a single subtype for a dataset. For +example, if you have an array that contains objects, you can set the `type` as +`array`. Alternatively, if you have an array of representations, you +can do the same with `array<\RepresentationFQN>`. -Currently, only `array` types are allowed to contain subtypes. To define subtypes of objects, use a `@api-data` -annotation for each property. +Currently, only `array` types are allowed to contain subtypes. To define +subtypes of objects, use a `@api-data` annotation for each property. ## Examples Common uses: diff --git a/docs/reference/api-error.md b/docs/reference/api-error.md index e829f93..b535cd5 100644 --- a/docs/reference/api-error.md +++ b/docs/reference/api-error.md @@ -11,7 +11,7 @@ This represents an exception that may be thrown inside of a resource action. ## Syntax ```php -@api-error:visibility httpCode (\Representation, capability) - description +@api-error:visibility httpCode (\Representation, vendor:tagName) - description ``` ## Requirements @@ -28,18 +28,21 @@ This represents an exception that may be thrown inside of a resource action. | `httpCode` | × | The HTTP code that will be returned. Example: `404`, `403`, etc. | | `\Representation` | × | The fully qualified class name for a representation that will be returned. | | `error code` | ✓ | An optional error code, if your application supports unique error codes, that this error returns. This can either be a numerical code (ex. `(1234)`), or a fully qualified static accessor (ex. (`\Some\Exception::NOT_ALLOWED`). | +| `vendor:tagName` | ✓ | Defined vendor tag. See the [`@api-vendortag`]({{ site.github.url }}/reference/api-vendortag) documentation for more information. There is no limit to the amount of vendor tags you can specify on a parameter. | | `description` | ✓ | A short description describing why, or what, this error is. | ## Types and subtypes -In addition to supporting straight descriptions, the [`@api-error`]({{ site.github.url }}/reference/api-error) annotation also supports -the concept of "types" and "subtypes". For example: +In addition to supporting straight descriptions, the +[`@api-error`]({{ site.github.url }}/reference/api-error) annotation also +supports the concept of "types" and "subtypes". For example: ```php @api-error:public 404 (\ErrorRepresentation) - {user} ``` -In this case, this exception will be thrown when the `{user}` passed into the route (usually via the URI) is not found. -The generated error message for this becomes: "If the user cannot be found." +In this case, this exception will be thrown when the `{user}` passed into the +route (usually via the URI) is not found. The generated error message for this +becomes: "If the user cannot be found." There also exist the concept of a subtype, represented as: @@ -47,17 +50,18 @@ There also exist the concept of a subtype, represented as: @api-error:public 404 (\ErrorRepresentation) - {user,group} ``` -This means that if the supplied group could not be found for the supplied user, an exception will be thrown. The -generated error message for this is: "If the user cannot be found in the group." +This means that if the supplied group could not be found for the supplied user, +an exception will be thrown. The generated error message for this is: "If the +user cannot be found in the group." ## Examples -Usage with a capability and description type: +Usage with a vendor tag and description type: ```php /** * … * - * @api-error:public 404 (\ErrorRepresentation, SomeCapability) - {user} + * @api-error:public 404 (\ErrorRepresentation, needs:SomeApplicationFeature) - {user} */ public function PATCH() { diff --git a/docs/reference/api-minversion.md b/docs/reference/api-minversion.md index 0dd7827..64036a8 100644 --- a/docs/reference/api-minversion.md +++ b/docs/reference/api-minversion.md @@ -7,7 +7,8 @@ permalink: /reference/api-minversion # @api-minversion --- -This allows you to denote the minimum API version required for a resource action. +This allows you to denote the minimum API version required for a resource +action. ## Syntax ```php diff --git a/docs/reference/api-param.md b/docs/reference/api-param.md index baea328..a6cc23b 100644 --- a/docs/reference/api-param.md +++ b/docs/reference/api-param.md @@ -11,7 +11,7 @@ A request parameter that can be supplied to a resource action. ## Syntax ```php -@api-param:visibility fieldName `sampleData` (type, required|optional, nullable, capabilityName) - Description +@api-param:visibility fieldName `sampleData` (type, required|optional, nullable, vendor:tagName) - Description + Members - `option` - Option description ``` @@ -32,7 +32,7 @@ A request parameter that can be supplied to a resource action. | `type` | × | This can be a reference to the type of variable that is being passed in (string, boolean, array, etc.), or can be one of the [tokens](#tokens) that are configured for your API. | | `required|optional` | ✓ | A flag that indicates that the parameter is, well, optional. If nothing is supplied, it defaults to being `optional`. | | `nullable` | ✓ | A flag that indicates that the parameter is nullable. If nothing is supplied, it defaults to being non-nullable. | -| `capabilityName` | ✓ | Defined capability that the developers application should possess. | +| `vendor:tagName` | ✓ | Defined vendor tag. See the [`@api-vendortag`]({{ site.github.url }}/reference/api-vendortag) documentation for more information. There is no limit to the amount of vendor tags you can specify on a parameter. | | `Description` | × | Description for what the parameter is for. | | Members | ✓ | If this parameter has acceptable values (like in the case of an `enum` type), you can document those values here along with a description for what the value is, or means. | @@ -54,8 +54,7 @@ A request parameter that can be supplied to a resource action. | uri | string | ## Tokens -Because writing out the same parameter for a large number of endpoints can get tiring, we have a system in place that -allows you to configure tokens, which act as kind of a short-code for a parameter: +Because writing out the same parameter for a large number of endpoints can get tiring, we have a system in place that allows you to configure tokens, which act as kind of a short-code for a parameter: In your [`mill.xml`]({{ site.github.url }}/configuration) file: @@ -98,10 +97,10 @@ Using a token with available values: `playable` ``` -With a capability: +With a vendor tag: ```php -@api-param:public locked_down (string, AnotherRequiredCapability) - This is a cool thing. +@api-param:public locked_down (string, needs:SomeApplicationFeature) - This is a cool thing. ``` Normal usage with acceptable values: diff --git a/docs/reference/api-return.md b/docs/reference/api-return.md index f5bbb7f..b5c3a89 100644 --- a/docs/reference/api-return.md +++ b/docs/reference/api-return.md @@ -8,16 +8,18 @@ permalink: /reference/api-return --- Like a standard [PHPDoc](https://phpdoc.org/) -[`@return`](https://phpdoc.org/docs/latest/references/phpdoc/tags/return.html) annotation, this defines the response, -and representation that a resource action returns. The difference here, however, is that this is made up of two parts: +[`@return`](https://phpdoc.org/docs/latest/references/phpdoc/tags/return.html) +annotation, this defines the response, and representation that a resource action +returns. The difference here, however, is that this is made up of two parts: * `{return type}` * `\Representation` -The `{return type}` should be indicative of the HTTP code that will be delivered (ex. "collection", "object", "created", -etc.), and the `\Representation` should be representative of the type of response and data that this action deals with. -Say if this is a user data action, it might return a `\UserRepresentation`, or however that is set up in your -application. +The `{return type}` should be indicative of the HTTP code that will be delivered +(ex. "collection", "object", "created", etc.), and the `\Representation` should +be representative of the type of response and data that this action deals with. +Say if this is a user data action, it might return a `\UserRepresentation`, or +however that is set up in your application. ## Syntax ```php @@ -55,8 +57,9 @@ application. | | updated | | 304 Not Modified | notmodified | -> **Note:** `@api-return` does not support returning 400 or 500 error codes. If you need those, use -> [`@api-error`]({{ site.github.url }}/reference/api-error) instead. +> **Note:** `@api-return` does not support returning 400 or 500 error codes. If +> you need those, use [`@api-error`]({{ site.github.url }}/reference/api-error) +> instead. ## Examples ```php @@ -75,7 +78,8 @@ public function PATCH() /** * … * - * @api-public {notmodified} If no content has changed since the last modified date. + * @api-public {notmodified} If no content has changed since the last modified + * date. */ public function GET() { diff --git a/docs/reference/api-scope.md b/docs/reference/api-scope.md index a4f0182..4dd7a9c 100644 --- a/docs/reference/api-scope.md +++ b/docs/reference/api-scope.md @@ -7,8 +7,9 @@ permalink: /reference/api-scope # @api-scope --- -This corresponds to an available user authentication token scope (ex. "create", "edit", "interact`, etc.) that is -required for a resource action, or a representation data point. +This corresponds to an available user authentication token scope (ex. "create", +"edit", "interact`, etc.) that is required for a resource action, or a +representation data point. ## Syntax ```php diff --git a/docs/reference/api-see.md b/docs/reference/api-see.md index 1a00fb4..8d9826b 100644 --- a/docs/reference/api-see.md +++ b/docs/reference/api-see.md @@ -7,7 +7,8 @@ permalink: /reference/api-see # @api-see --- -This is a reference pointer that allows you to pull in related documentation into a representation. +This is a reference pointer that allows you to pull in related documentation +into a representation. ## Syntax ```php @@ -54,4 +55,5 @@ private function getPrivacy($object, $request) } ``` -From here, `download` will be imported into the representation documentation as `privacy.download`. +From here, `download` will be imported into the representation documentation as +`privacy.download`. diff --git a/docs/reference/api-vendortag.md b/docs/reference/api-vendortag.md new file mode 100644 index 0000000..f244ad0 --- /dev/null +++ b/docs/reference/api-vendortag.md @@ -0,0 +1,65 @@ +--- +layout: default +title: "@api-vendortag" +permalink: /reference/api-vendortag +--- + +# @api-vendortag +--- + +This defines a vendor tag in your API. With these, you can specify additional +metadata (requirements specific to your API, notes like "requiresAUser", or +anything else you can think of) on your resource actions or representation +fields. + +With Mill's generator commands, you can also later filter down your +documentation to only those that have specific vendor tags. + +## Syntax +```php +@api-vendortag vendorTagName +``` + +## Requirements + +| Required? | Needs a visibility | Supports versioning | Supports deprecation | +| :--- | :--- | :--- | :--- | +| × | × | × | × | + +## Breakdown + +| Tag | Optional | Description | +| :--- | :--- | :--- | +| `vendortag` | × | Name of the vendor tag | + +## Examples +On a resource action: + +```php +/** + * … + * @api-vendortag needs:SomeApplicationFeature + * … + */ +public function PATCH() +{ + … +} +``` + +On a representation field: + +```php +$representation = [ + … + + /** + * @api-data download (boolean, needs:SomeApplicationFeature) - Download + * permission setting + */ + 'download' => true, + + … +]; +``` + diff --git a/docs/reference/deprecation.md b/docs/reference/deprecation.md index 3c45611..35cc2c7 100644 --- a/docs/reference/deprecation.md +++ b/docs/reference/deprecation.md @@ -7,12 +7,13 @@ permalink: /reference/deprecation # Deprecation --- -> **Note:** Deprecated status is not currently being used when generating documentation, however, there are plans to -> hook it up to the internal generator system to make it available in your compiled API Blueprints and manual Mill API -> usages. +> **Note:** Deprecated status is not currently being used when generating +> documentation, however, there are plans to hook it up to the internal +> generator system to make it available in your compiled API Blueprints and +> manual Mill API usages. -You might have instances where you need to deprecate a resource action request parameter or URI, you can use the -`:deprecated` "decorator". +You might have instances where you need to deprecate a resource action request +parameter or URI, you can use the `:deprecated` "decorator". ```php /** @@ -40,5 +41,6 @@ public function GET() } ``` -Deprecated decorators are only available on [`@api-param`]({{ site.github.url }}/reference/api-param) and +Deprecated decorators are only available on +[`@api-param`]({{ site.github.url }}/reference/api-param) and [`@api-uri`]({{ site.github.url }}/reference/api-uri). diff --git a/docs/reference/uri-segment.md b/docs/reference/uri-segment.md index d5a36bd..e8f62c9 100644 --- a/docs/reference/uri-segment.md +++ b/docs/reference/uri-segment.md @@ -7,7 +7,8 @@ permalink: /reference/api-urisegment # @api-urisegment --- -This allows you to describe the segments, or parameters, of a particular resource action URI. +This allows you to describe the segments, or parameters, of a particular +resource action URI. ## Syntax ```php diff --git a/docs/reference/versioning.md b/docs/reference/versioning.md index 2c3a1ab..dbc5ebb 100644 --- a/docs/reference/versioning.md +++ b/docs/reference/versioning.md @@ -7,15 +7,18 @@ permalink: /reference/versioning # API Versioning --- -As is the case with all API endpoints, there comes a time where you need to version specific endpoints, parameters, -responses, exceptions, or representations. You can handle these types of changes in Mill by using the -[`@api-version`]({{ site.github.url }}/reference/api-version) annotation on resource actions or representations. +As is the case with all API endpoints, there comes a time where you need to +version specific endpoints, parameters, responses, exceptions, or +representations. You can handle these types of changes in Mill by using the +[`@api-version`]({{ site.github.url }}/reference/api-version) annotation on +resource actions or representations. ## Usage ### Actions -On resource actions, [`@api-version`]({{ site.github.url }}/reference/api/version) is a block-level annotation. This -means that it allows you to classify any parameter following it as belonging to that defined version constraint. For -example: +On resource actions, +[`@api-version`]({{ site.github.url }}/reference/api/version) is a block-level +annotation. This means that it allows you to classify any parameter following it +as belonging to that defined version constraint. For example: ```php @api-param:public {on_all_version requests} @@ -31,25 +34,31 @@ example: * Anything below `@api-version >3.2` will be parsed with `version = >3.2` on it. * Anything below `@api-version >=3.4` will have `version = >=3.4`. -* And anything that doesn't follow a [`@api-version`]({{ site.github.url }}/reference/api-version) annotation will be -treated as being available across all versions. +* And anything that doesn't follow a [`@api-version`]({{ site.github.url }}/reference/api-version) annotation will be treated as being available across all versions. -Versioning is currently only supported on [`@api-param`]({{ site.github.url }}/reference/api-param), -[`@api-return`]({{ site.github.url }}/reference/api-return), and [`@api-error`]({{ site.github.url }}/reference/api-error). +Versioning is currently only supported on +[`@api-param`]({{ site.github.url }}/reference/api-param), +[`@api-return`]({{ site.github.url }}/reference/api-return), and +[`@api-error`]({{ site.github.url }}/reference/api-error). ### Representations -In representations, the [`@api-version`]({{ site.github.url }}/reference/api-version) annotation works as any other annotation. +In representations, the +[`@api-version`]({{ site.github.url }}/reference/api-version) annotation works +as any other annotation. ```php /** - * @api-data pictures (\MyApplication\Representations\Picture) - The users' pictures + * @api-data pictures (\MyApplication\Representations\Picture) - The users' + * pictures * @api-version >=3.2 */ ``` -This response field will be then constrained to being available on anything above, or equal to, version `3.2`. +This response field will be then constrained to being available on anything +above, or equal to, version `3.2`. ## Supported constraint schemas -The backend for the Mill versioning system uses the core [composer/semver](https://github.com/composer/semver) package -from Composer, so standard [Semver](http://semver.org/) constraints will work, but you can see their versions -documentation for more proper information: +The backend for the Mill versioning system uses the core +[composer/semver](https://github.com/composer/semver) package from Composer, so +standard [Semver](http://semver.org/) constraints will work, but you can see +their versions documentation for more proper information: diff --git a/docs/reference/visibility.md b/docs/reference/visibility.md index d060a6f..f20b096 100644 --- a/docs/reference/visibility.md +++ b/docs/reference/visibility.md @@ -7,14 +7,17 @@ permalink: /reference/visibility # Visibility --- -> **Note:** Visibility status is not currently being used when generating API Blueprint files, however there are -> future plans to hook it up to that generator. +> **Note:** Visibility status is not currently being used when generating API +> Blueprint files, however there are future plans to hook it up to that +> generator. -We have the concept of an annotation visibility "decorator" that allows you to set certain annotations as private, or -explicitly public. With this additional metadata, you can do cool things like only show certain endpoints or parameters +We have the concept of an annotation visibility "decorator" that allows you to +set certain annotations as private, or explicitly public. With this additional +metadata, you can do cool things like only show certain endpoints or parameters to privileged developers in your documentation. -To choose what visibility your annotation should have, suffix your annotation with either `:public` or `:private`. +To choose what visibility your annotation should have, suffix your annotation +with either `:public` or `:private`. ```php /** @@ -33,6 +36,8 @@ public function PATCH() } ``` -Visibility decorators are required on [`@api-param`]({{ site.github.url }}/reference/api-param), -[`@api-return`]({{ site.github.url }}/reference/api-return), [`@api-error`]({{ site.github.url }}/reference/api-error), -and [`@api-uri`]({{ site.github.url }}/reference/api-uri). +Visibility decorators are required on +[`@api-param`]({{ site.github.url }}/reference/api-param), +[`@api-return`]({{ site.github.url }}/reference/api-return), +[`@api-error`]({{ site.github.url }}/reference/api-error), and +[`@api-uri`]({{ site.github.url }}/reference/api-uri). diff --git a/resources/examples/Showtimes/Controllers/Movie.php b/resources/examples/Showtimes/Controllers/Movie.php index c0e20b0..e0ce14a 100644 --- a/resources/examples/Showtimes/Controllers/Movie.php +++ b/resources/examples/Showtimes/Controllers/Movie.php @@ -120,7 +120,7 @@ public function PATCH() * @api-uriSegment {/movies/+id} id (integer) - Movie ID * * @api-contentType application/json - * @api-capability DELETE_CONTENT + * @api-vendorTag tag:DELETE_CONTENT * @api-scope delete * @api-minVersion 1.1 * diff --git a/resources/examples/Showtimes/Representations/Movie.php b/resources/examples/Showtimes/Representations/Movie.php index df2f803..c7179bf 100644 --- a/resources/examples/Showtimes/Representations/Movie.php +++ b/resources/examples/Showtimes/Representations/Movie.php @@ -123,7 +123,7 @@ private function getExternalUrls() 'trailer' => $this->movie->trailer, /** - * @api-data tickets (string, BUY_TICKETS) - Tickets URL + * @api-data tickets (string, tag:BUY_TICKETS) - Tickets URL * @api-version <1.1.3 */ 'tickets' => $this->movie->tickets_url diff --git a/resources/examples/Showtimes/blueprints/1.0/errors-public-only-all-capabilities.md b/resources/examples/Showtimes/blueprints/1.0/errors-public-only-all-vendor-tags.md similarity index 100% rename from resources/examples/Showtimes/blueprints/1.0/errors-public-only-all-capabilities.md rename to resources/examples/Showtimes/blueprints/1.0/errors-public-only-all-vendor-tags.md diff --git a/resources/examples/Showtimes/blueprints/1.0/errors-public-only-matched-capabilities.md b/resources/examples/Showtimes/blueprints/1.0/errors-public-only-matched-vendor-tags.md similarity index 100% rename from resources/examples/Showtimes/blueprints/1.0/errors-public-only-matched-capabilities.md rename to resources/examples/Showtimes/blueprints/1.0/errors-public-only-matched-vendor-tags.md diff --git a/resources/examples/Showtimes/blueprints/1.0/errors-public-only-unmatched-capabilities.md b/resources/examples/Showtimes/blueprints/1.0/errors-public-only-unmatched-vendor-tags.md similarity index 100% rename from resources/examples/Showtimes/blueprints/1.0/errors-public-only-unmatched-capabilities.md rename to resources/examples/Showtimes/blueprints/1.0/errors-public-only-unmatched-vendor-tags.md diff --git a/resources/examples/Showtimes/blueprints/1.1.1/errors-public-only-all-capabilities.md b/resources/examples/Showtimes/blueprints/1.1.1/errors-public-only-all-vendor-tags.md similarity index 100% rename from resources/examples/Showtimes/blueprints/1.1.1/errors-public-only-all-capabilities.md rename to resources/examples/Showtimes/blueprints/1.1.1/errors-public-only-all-vendor-tags.md diff --git a/resources/examples/Showtimes/blueprints/1.1.1/errors-public-only-matched-capabilities.md b/resources/examples/Showtimes/blueprints/1.1.1/errors-public-only-matched-vendor-tags.md similarity index 100% rename from resources/examples/Showtimes/blueprints/1.1.1/errors-public-only-matched-capabilities.md rename to resources/examples/Showtimes/blueprints/1.1.1/errors-public-only-matched-vendor-tags.md diff --git a/resources/examples/Showtimes/blueprints/1.1.1/errors-public-only-unmatched-capabilities.md b/resources/examples/Showtimes/blueprints/1.1.1/errors-public-only-unmatched-vendor-tags.md similarity index 100% rename from resources/examples/Showtimes/blueprints/1.1.1/errors-public-only-unmatched-capabilities.md rename to resources/examples/Showtimes/blueprints/1.1.1/errors-public-only-unmatched-vendor-tags.md diff --git a/resources/examples/Showtimes/blueprints/1.1.3/errors-public-only-all-capabilities.md b/resources/examples/Showtimes/blueprints/1.1.3/errors-public-only-all-vendor-tags.md similarity index 100% rename from resources/examples/Showtimes/blueprints/1.1.3/errors-public-only-all-capabilities.md rename to resources/examples/Showtimes/blueprints/1.1.3/errors-public-only-all-vendor-tags.md diff --git a/resources/examples/Showtimes/blueprints/1.1.3/errors-public-only-matched-capabilities.md b/resources/examples/Showtimes/blueprints/1.1.3/errors-public-only-matched-vendor-tags.md similarity index 100% rename from resources/examples/Showtimes/blueprints/1.1.3/errors-public-only-matched-capabilities.md rename to resources/examples/Showtimes/blueprints/1.1.3/errors-public-only-matched-vendor-tags.md diff --git a/resources/examples/Showtimes/blueprints/1.1.3/errors-public-only-unmatched-capabilities.md b/resources/examples/Showtimes/blueprints/1.1.3/errors-public-only-unmatched-vendor-tags.md similarity index 100% rename from resources/examples/Showtimes/blueprints/1.1.3/errors-public-only-unmatched-capabilities.md rename to resources/examples/Showtimes/blueprints/1.1.3/errors-public-only-unmatched-vendor-tags.md diff --git a/resources/examples/Showtimes/blueprints/1.1/errors-public-only-all-capabilities.md b/resources/examples/Showtimes/blueprints/1.1/errors-public-only-all-vendor-tags.md similarity index 100% rename from resources/examples/Showtimes/blueprints/1.1/errors-public-only-all-capabilities.md rename to resources/examples/Showtimes/blueprints/1.1/errors-public-only-all-vendor-tags.md diff --git a/resources/examples/Showtimes/blueprints/1.1/errors-public-only-matched-capabilities.md b/resources/examples/Showtimes/blueprints/1.1/errors-public-only-matched-vendor-tags.md similarity index 100% rename from resources/examples/Showtimes/blueprints/1.1/errors-public-only-matched-capabilities.md rename to resources/examples/Showtimes/blueprints/1.1/errors-public-only-matched-vendor-tags.md diff --git a/resources/examples/Showtimes/blueprints/1.1/errors-public-only-unmatched-capabilities.md b/resources/examples/Showtimes/blueprints/1.1/errors-public-only-unmatched-vendor-tags.md similarity index 100% rename from resources/examples/Showtimes/blueprints/1.1/errors-public-only-unmatched-capabilities.md rename to resources/examples/Showtimes/blueprints/1.1/errors-public-only-unmatched-vendor-tags.md diff --git a/resources/examples/Showtimes/blueprints/changelog-public-only-all-capabilities.md b/resources/examples/Showtimes/blueprints/changelog-public-only-all-vendor-tags.md similarity index 100% rename from resources/examples/Showtimes/blueprints/changelog-public-only-all-capabilities.md rename to resources/examples/Showtimes/blueprints/changelog-public-only-all-vendor-tags.md diff --git a/resources/examples/Showtimes/blueprints/changelog-public-only-matched-with-delete-capabilities.md b/resources/examples/Showtimes/blueprints/changelog-public-only-matched-with-delete-vendor-tags.md similarity index 100% rename from resources/examples/Showtimes/blueprints/changelog-public-only-matched-with-delete-capabilities.md rename to resources/examples/Showtimes/blueprints/changelog-public-only-matched-with-delete-vendor-tags.md diff --git a/resources/examples/Showtimes/blueprints/changelog-public-only-matched-with-tickets-and-feature-capabilities.md b/resources/examples/Showtimes/blueprints/changelog-public-only-matched-with-tickets-and-feature-vendor-tags.md similarity index 100% rename from resources/examples/Showtimes/blueprints/changelog-public-only-matched-with-tickets-and-feature-capabilities.md rename to resources/examples/Showtimes/blueprints/changelog-public-only-matched-with-tickets-and-feature-vendor-tags.md diff --git a/resources/examples/mill.xml b/resources/examples/mill.xml index cd5019c..0bfa000 100644 --- a/resources/examples/mill.xml +++ b/resources/examples/mill.xml @@ -43,10 +43,10 @@ - - - - - - + + + + + + diff --git a/src/Command/Changelog.php b/src/Command/Changelog.php index 4698fc8..cc642fb 100644 --- a/src/Command/Changelog.php +++ b/src/Command/Changelog.php @@ -32,10 +32,10 @@ protected function configure() true ) ->addOption( - 'capability', + 'vendor_tag', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, - 'The name of a capability if you want to generate a changelog that includes capability-locked ' . + 'The name of a vendor tag if you want to generate a changelog that includes vendor tag-bound ' . 'documentation.' ) ->addArgument( @@ -55,11 +55,11 @@ protected function execute(InputInterface $input, OutputInterface $output) parent::execute($input, $output); $private_docs = $input->getOption('private'); - $capabilities = $input->getOption('capability'); + $vendor_tags = $input->getOption('vendor_tag'); $output_dir = realpath($input->getArgument('output')); $private_docs = ($private_docs === true || strtolower($private_docs) == 'true') ? true : false; - $capabilities = (!empty($capabilities)) ? $capabilities : null; + $vendor_tags = (!empty($vendor_tags)) ? $vendor_tags : null; /** @var Config $config */ $config = $this->container['config']; @@ -71,7 +71,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $changelog = new Generator\Changelog($config); $changelog->setLoadPrivateDocs($private_docs); - $changelog->setLoadCapabilityDocs($capabilities); + $changelog->setLoadVendorTagDocs($vendor_tags); $markdown = $changelog->generateMarkdown(); $filesystem->put( diff --git a/src/Command/ErrorMap.php b/src/Command/ErrorMap.php index aaa1c5a..6e01deb 100644 --- a/src/Command/ErrorMap.php +++ b/src/Command/ErrorMap.php @@ -56,10 +56,10 @@ protected function configure() true ) ->addOption( - 'capability', + 'vendor_tag', null, InputOption::VALUE_OPTIONAL | InputOption::VALUE_IS_ARRAY, - 'The name of a capability if you want to generate an error map that includes capability-locked error' . + 'The name of a vendor tag if you want to generate an error map that includes vendor tag-bound error' . 'documentation.' ) ->addArgument( @@ -79,13 +79,13 @@ protected function execute(InputInterface $input, OutputInterface $output) parent::execute($input, $output); $private_docs = $input->getOption('private'); - $capabilities = $input->getOption('capability'); + $vendor_tags = $input->getOption('vendor_tag'); $output_dir = realpath($input->getArgument('output')); $version = $input->getOption('constraint'); $dry_run = $input->getOption('dry-run'); $private_docs = ($private_docs === true || strtolower($private_docs) == 'true') ? true : false; - $capabilities = (!empty($capabilities)) ? $capabilities : null; + $vendor_tags = (!empty($vendor_tags)) ? $vendor_tags : null; // Generate! if ($dry_run) { @@ -116,7 +116,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $error_map = new Generator\ErrorMap($config, $version); $error_map->setLoadPrivateDocs($private_docs); - $error_map->setLoadCapabilityDocs($capabilities); + $error_map->setLoadVendorTagDocs($vendor_tags); $markdown = $error_map->generateMarkdown(); foreach ($markdown as $version => $content) { diff --git a/src/Config.php b/src/Config.php index 310bb90..7d9c20c 100644 --- a/src/Config.php +++ b/src/Config.php @@ -63,11 +63,11 @@ class Config protected $api_versions = []; /** - * Allowable list of valid application capabilities. + * Allowable list of valid application vendor tags. * * @var array */ - protected $capabilities = []; + protected $vendor_tags = []; /** * Allowable list of valid application authentication scopes. @@ -185,9 +185,9 @@ public static function loadFromXML(Filesystem $filesystem, string $config_file, require_once $config->base_dir . $xml['bootstrap']; } - if (isset($xml->capabilities)) { - $config->capabilities = []; - $config->loadCapabilities($xml->capabilities->capability); + if (isset($xml->vendorTags)) { + $config->vendor_tags = []; + $config->loadVendorTags($xml->vendorTags->vendorTag); } if (isset($xml->scopes)) { @@ -225,29 +225,29 @@ public static function loadFromXML(Filesystem $filesystem, string $config_file, } /** - * Load an array of application capabilities into the configuration system. + * Load an array of application vendor tags into the configuration system. * - * @param SimpleXMLElement $capabilities + * @param SimpleXMLElement $vendor_tags */ - protected function loadCapabilities(SimpleXMLElement $capabilities): void + protected function loadVendorTags(SimpleXMLElement $vendor_tags): void { - /** @var SimpleXMLElement $capability */ - foreach ($capabilities as $capability) { - $this->addCapability((string) $capability['name']); + /** @var SimpleXMLElement $vendor_tag */ + foreach ($vendor_tags as $vendor_tag) { + $this->addVendorTag((string) $vendor_tag['name']); } // Keep things tidy. - $this->capabilities = array_unique($this->capabilities); + $this->vendor_tags = array_unique($this->vendor_tags); } /** - * Add a new application capability into the instance config. + * Add a new application vendor tag into the instance config. * - * @param string $capability + * @param string $vendor_tag */ - public function addCapability(string $capability): void + public function addVendorTag(string $vendor_tag): void { - $this->capabilities[] = $capability; + $this->vendor_tags[] = $vendor_tag; } /** @@ -744,13 +744,13 @@ public function getApiVersion(string $version): array } /** - * Get the array of configured application capabilities. + * Get the array of configured application vendor tags. * * @return array */ - public function getCapabilities(): array + public function getVendorTags(): array { - return $this->capabilities; + return $this->vendor_tags; } /** diff --git a/src/Exceptions/Annotations/InvalidCapabilitySuppliedException.php b/src/Exceptions/Annotations/InvalidCapabilitySuppliedException.php deleted file mode 100644 index 853ccb9..0000000 --- a/src/Exceptions/Annotations/InvalidCapabilitySuppliedException.php +++ /dev/null @@ -1,44 +0,0 @@ -capability = $capability; - $exception->class = $class; - $exception->method = $method; - - return $exception; - } - - /** - * Get the capability that this exception occurred with. - * - * @return string - */ - public function getCapability(): string - { - return $this->capability; - } -} diff --git a/src/Exceptions/Annotations/InvalidVendorTagSuppliedException.php b/src/Exceptions/Annotations/InvalidVendorTagSuppliedException.php new file mode 100644 index 0000000..0666a54 --- /dev/null +++ b/src/Exceptions/Annotations/InvalidVendorTagSuppliedException.php @@ -0,0 +1,42 @@ +vendor_tag = $vendor_tag; + $exception->class = $class; + $exception->method = $method; + + return $exception; + } + + /** + * Get the vendor tag that this exception occurred with. + * + * @return string + */ + public function getVendorTag(): string + { + return $this->vendor_tag; + } +} diff --git a/src/Generator.php b/src/Generator.php index c29b713..7119d8f 100644 --- a/src/Generator.php +++ b/src/Generator.php @@ -1,8 +1,8 @@ setUri($uri); $action->setUriSegments($segments); - $action->filterAnnotationsForVisibility($this->load_private_docs, $this->load_capability_docs); + $action->filterAnnotationsForVisibility($this->load_private_docs, $this->load_vendor_tag_docs); // Hash the action so we don't happen to double up and end up with dupes. $identifier = $action->getUri()->getPath() . '::' . $action->getMethod(); @@ -242,7 +242,7 @@ protected function parseRepresentations(): array } $parsed = (new Representation\Documentation($class, $representation['method']))->parse(); - $parsed->filterAnnotationsForVisibility($this->load_capability_docs); + $parsed->filterAnnotationsForVisibility($this->load_vendor_tag_docs); $representations[$class] = $parsed; } @@ -330,17 +330,17 @@ public function setLoadPrivateDocs(bool $load_private_docs = true): self } /** - * Set an array of capabilities that we'll be generating documentation against. + * Set an array of vendor tags that we'll be generating documentation against. * - * If you want all documentation, even that that is behind a capability, supply `null`. If you want documentation - * that either has no capability, or specific ones, supply an array with those capability names. + * If you want all documentation, even that which has a vendor tag, supply `null`. If you want documentation that + * either has no vendor tag, or specific ones, supply an array with those vendor tag names. * - * @param array|null $capabilities - * @return self + * @param array|null $vendor_tags + * @return Generator */ - public function setLoadCapabilityDocs(array $capabilities = null): self + public function setLoadVendorTagDocs(?array $vendor_tags): self { - $this->load_capability_docs = $capabilities; + $this->load_vendor_tag_docs = $vendor_tags; return $this; } @@ -354,25 +354,25 @@ public function setLoadCapabilityDocs(array $capabilities = null): self private function shouldParseUri(Resource\Action\Documentation $method, UriAnnotation $uri): bool { $uri_data = $uri->toArray(); - $capabilities = $method->getCapabilities(); + $vendor_tags = $method->getVendorTags(); - // Should we generate documentation that is locked behind a capability? - if (!empty($capabilities) && !is_null($this->load_capability_docs)) { - // We don't have any configured capabilities to pull documentation for, so this URI shouldn't be parsed. - if (empty($this->load_capability_docs)) { + // Should we generate documentation that has a vendor tag? + if (!empty($vendor_tags) && !is_null($this->load_vendor_tag_docs)) { + // We don't have any configured vendor tags to pull documentation for, so this URI shouldn't be parsed. + if (empty($this->load_vendor_tag_docs)) { return false; } $all_found = true; - /** @var CapabilityAnnotation $capability */ - foreach ($capabilities as $capability) { - if (!in_array($capability->getCapability(), $this->load_capability_docs)) { + /** @var VendorTagAnnotation $vendor_tag */ + foreach ($vendor_tags as $vendor_tag) { + if (!in_array($vendor_tag->getVendorTag(), $this->load_vendor_tag_docs)) { $all_found = false; } } - // This URI should only be parsed if it has every capability we're looking for. + // This URI should only be parsed if it has every vendor tag we're looking for. if ($all_found) { return true; } diff --git a/src/Parser.php b/src/Parser.php index 6d7a11a..ba06c95 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -298,6 +298,10 @@ private function getAnnotationClass(string $annotation): string $annotation = 'UriSegment'; break; + case 'vendortag': + $annotation = 'VendorTag'; + break; + default: $annotation = ucfirst($annotation); } diff --git a/src/Parser/Annotation.php b/src/Parser/Annotation.php index a9a17b2..1834697 100644 --- a/src/Parser/Annotation.php +++ b/src/Parser/Annotation.php @@ -3,9 +3,9 @@ use Mill\Exceptions\Annotations\InvalidMSONSyntaxException; use Mill\Exceptions\Annotations\MissingRequiredFieldException; -use Mill\Parser\Annotations\CapabilityAnnotation; use Mill\Parser\Annotations\ScopeAnnotation; use Mill\Parser\Annotations\UriAnnotation; +use Mill\Parser\Annotations\VendorTagAnnotation; /** * Base class for supported annotations. @@ -13,9 +13,6 @@ */ abstract class Annotation { - /** @var string */ - const REGEX_CAPABILITY = '/(\+[^\+]*\+)/'; - /** * Does this annotation require a visibility decorator? * @@ -26,35 +23,42 @@ abstract class Annotation /** * Does this annotation support aliasing? * - * @return bool + * @var bool */ const SUPPORTS_ALIASING = false; /** * Does this annotation support being deprecated? * - * @return bool + * @var bool */ const SUPPORTS_DEPRECATION = false; /** * Is this annotation written using MSON? * - * @return bool + * @var bool */ const SUPPORTS_MSON = false; /** * Does this annotation support auth token scopes? * - * @return bool + * @var bool */ const SUPPORTS_SCOPES = false; + /** + * Does this annotation support vendor tags? + * + * @var bool + */ + const SUPPORTS_VENDOR_TAGS = false; + /** * Does this annotation support versioning? * - * @return bool + * @var bool */ const SUPPORTS_VERSIONING = false; @@ -80,11 +84,11 @@ abstract class Annotation protected $method = null; /** - * Capability that this annotation requires. + * Vendor tags that this annotation possesses. * - * @var false|string + * @var array */ - protected $capability = false; + protected $vendor_tags = []; /** * Flag designating if this annotation is visible or not. @@ -224,6 +228,10 @@ protected function optional(string $field, $allow_zero = false) if ($allow_zero && $this->parsed_data[$field] === '0') { return $this->parsed_data[$field]; } elseif (empty($this->parsed_data[$field])) { + if (is_array($this->parsed_data[$field])) { + return []; + } + return false; } @@ -273,23 +281,6 @@ public static function hydrate(array $data = [], Version $version = null) /** @var Annotation $annotation */ $annotation = new $class('', $data['class'], $data['method'], $version); - if (array_key_exists('capability', $data) && !empty($data['capability'])) { - // Since capability annotations have a `capability` value, let's avoid created a CapabilityAnnotation within - // another CapabilityAnnotation. - if ($annotation instanceof CapabilityAnnotation) { - $capability = $data['capability']; - } else { - $capability = (new CapabilityAnnotation( - $data['capability'], - $data['class'], - $data['method'], - $version - ))->process(); - } - - $annotation->setCapability($capability); - } - if ($annotation->requiresVisibilityDecorator()) { $annotation->setVisibility($data['visible']); } @@ -327,6 +318,22 @@ public static function hydrate(array $data = [], Version $version = null) $annotation->setScopes($scopes); } + if ($annotation->supportsVendorTags() && + (array_key_exists('vendor_tags', $data) && !empty($data['vendor_tags'])) + ) { + $vendor_tags = []; + foreach ($data['vendor_tags'] as $vendor_tag) { + $vendor_tags[] = (new VendorTagAnnotation( + $vendor_tag, + $data['class'], + $data['method'], + $version + ))->process(); + } + + $annotation->setVendorTags($vendor_tags); + } + if ($annotation->supportsVersioning() && $version) { $annotation->setVersion($version); } @@ -374,6 +381,16 @@ public function supportsScopes(): bool return static::SUPPORTS_SCOPES; } + /** + * Does this annotation support vendor tags? + * + * @return bool + */ + public function supportsVendorTags(): bool + { + return static::SUPPORTS_VENDOR_TAGS; + } + /** * Does this annotation support versioning? * @@ -416,12 +433,10 @@ public function toArray(): array } } - // If this annotation supports deprecation, then we should include its designation. if ($this->supportsDeprecation()) { $arr['deprecated'] = $this->isDeprecated(); } - // If this annotation supports authentication scopes, then we should include those scopes. if ($this->supportsScopes()) { $arr['scopes'] = []; @@ -431,7 +446,15 @@ public function toArray(): array } } - // If this annotation supports versioning, then we should include its version + if ($this->supportsVendorTags()) { + $arr['vendor_tags'] = []; + + /** @var Annotation $scope */ + foreach ($this->getVendorTags() as $vendor_tag) { + $arr['vendor_tags'][] = $vendor_tag->getVendorTag(); + } + } + if ($this->supportsVersioning()) { $arr['version'] = false; @@ -582,25 +605,23 @@ public function getScopes(): array } /** - * Return the capability, if any, that has been set. - * - * @return false|string|CapabilityAnnotation + * Return an array of vendor tags that this annotation possesses. + * @return array */ - public function getCapability() + public function getVendorTags(): array { - return $this->capability; + return $this->vendor_tags; } /** - * Set a capability that this annotation requires. This is specifically used in tandem with representation depth - * parsing. + * Set vendor tags that this annotation possesses. * - * @param false|string $capability + * @param array $vendor_tags * @return self */ - public function setCapability($capability): self + public function setVendorTags(array $vendor_tags = []): self { - $this->capability = $capability; + $this->vendor_tags = $vendor_tags; return $this; } diff --git a/src/Parser/Annotations/CapabilityAnnotation.php b/src/Parser/Annotations/CapabilityAnnotation.php deleted file mode 100644 index 714ddc2..0000000 --- a/src/Parser/Annotations/CapabilityAnnotation.php +++ /dev/null @@ -1,64 +0,0 @@ -docblock; - - if (!empty($capability)) { - // Validate the supplied capability with what has been configured as allowable. - $capabilities = Container::getConfig()->getCapabilities(); - if (!in_array($capability, $capabilities)) { - /** @var string $method */ - $method = $this->method; - throw InvalidCapabilitySuppliedException::create($capability, $this->class, $method); - } - } - - return [ - 'capability' => $capability - ]; - } - - /** - * {@inheritdoc} - */ - protected function interpreter(): void - { - $this->capability = $this->required('capability'); - } - - /** - * {@inheritdoc} - */ - public static function hydrate(array $data = [], Version $version = null): self - { - /** @var CapabilityAnnotation $annotation */ - $annotation = parent::hydrate($data, $version); - return $annotation; - } -} diff --git a/src/Parser/Annotations/DataAnnotation.php b/src/Parser/Annotations/DataAnnotation.php index b2ffa53..f40bc80 100644 --- a/src/Parser/Annotations/DataAnnotation.php +++ b/src/Parser/Annotations/DataAnnotation.php @@ -15,6 +15,7 @@ class DataAnnotation extends Annotation { const SUPPORTS_MSON = true; const SUPPORTS_SCOPES = true; + const SUPPORTS_VENDOR_TAGS = true; const SUPPORTS_VERSIONING = true; /** @@ -72,7 +73,6 @@ class DataAnnotation extends Annotation * @var array */ protected $arrayable = [ - 'capability', 'description', 'identifier', 'nullable', @@ -100,18 +100,23 @@ protected function parser(): array 'type' => $mson->getType(), 'subtype' => $mson->getSubtype(), 'nullable' => $mson->isNullable(), - 'capability' => $mson->getCapability(), + 'vendor_tags' => $mson->getVendorTags(), 'description' => $mson->getDescription(), 'values' => $mson->getValues() ]; - // Create a capability annotation if one was supplied. - if (!empty($parsed['capability'])) { - $parsed['capability'] = (new CapabilityAnnotation( - $parsed['capability'], - $this->class, - $this->method - ))->process(); + if (!empty($parsed['vendor_tags'])) { + $parsed['vendor_tags'] = array_map( + /** @return Annotation */ + function (string $tag) use ($method) { + return (new VendorTagAnnotation( + $tag, + $this->class, + $method + ))->process(); + }, + $parsed['vendor_tags'] + ); } if (!empty($parsed['identifier'])) { @@ -140,7 +145,7 @@ protected function interpreter(): void $this->description = $this->required('description'); $this->values = $this->optional('values'); - $this->capability = $this->optional('capability'); + $this->vendor_tags = $this->optional('vendor_tags'); $this->nullable = $this->optional('nullable'); } diff --git a/src/Parser/Annotations/ErrorAnnotation.php b/src/Parser/Annotations/ErrorAnnotation.php index 646f57b..94c7460 100644 --- a/src/Parser/Annotations/ErrorAnnotation.php +++ b/src/Parser/Annotations/ErrorAnnotation.php @@ -5,7 +5,6 @@ use Mill\Exceptions\Annotations\MissingRepresentationErrorCodeException; use Mill\Exceptions\Annotations\UnknownErrorRepresentationException; use Mill\Exceptions\Annotations\UnknownReturnCodeException; -use Mill\Exceptions\Config\UnconfiguredErrorRepresentationException; use Mill\Parser\Annotation; use Mill\Parser\Annotations\Traits\HasHttpCodeResponseTrait; use Mill\Parser\MSON; @@ -20,6 +19,7 @@ class ErrorAnnotation extends Annotation use HasHttpCodeResponseTrait; const REQUIRES_VISIBILITY_DECORATOR = true; + const SUPPORTS_VENDOR_TAGS = true; const SUPPORTS_VERSIONING = true; const REGEX_ERROR_CODE = '/^(\(.*\))/'; @@ -47,7 +47,6 @@ class ErrorAnnotation extends Annotation * @var array */ protected $arrayable = [ - 'capability', 'description', 'error_code', 'http_code', @@ -74,7 +73,7 @@ protected function parser(): array 'http_code' => $mson->getField(), 'representation' => $mson->getType(), 'error_code' => $mson->getSubtype(), - 'capability' => $mson->getCapability(), + 'vendor_tags' => $mson->getVendorTags(), 'description' => $mson->getDescription() ]; @@ -86,13 +85,18 @@ protected function parser(): array $parsed['http_code'] .= ' ' . $this->getHttpCodeMessage($parsed['http_code']); } - // Capability is surrounded by +plusses+. - if (!empty($parsed['capability'])) { - $parsed['capability'] = (new CapabilityAnnotation( - $parsed['capability'], - $this->class, - $method - ))->process(); + if (!empty($parsed['vendor_tags'])) { + $parsed['vendor_tags'] = array_map( + /** @return Annotation */ + function (string $tag) use ($method) { + return (new VendorTagAnnotation( + $tag, + $this->class, + $method + ))->process(); + }, + $parsed['vendor_tags'] + ); } if (!empty($parsed['description'])) { @@ -135,7 +139,7 @@ protected function interpreter(): void $this->error_code = (string)$this->error_code; } - $this->capability = $this->optional('capability'); + $this->vendor_tags = $this->optional('vendor_tags'); $this->description = $this->required('description'); } diff --git a/src/Parser/Annotations/ParamAnnotation.php b/src/Parser/Annotations/ParamAnnotation.php index 9079cad..2d484c3 100644 --- a/src/Parser/Annotations/ParamAnnotation.php +++ b/src/Parser/Annotations/ParamAnnotation.php @@ -16,6 +16,7 @@ class ParamAnnotation extends Annotation const REQUIRES_VISIBILITY_DECORATOR = true; const SUPPORTS_DEPRECATION = true; const SUPPORTS_MSON = true; + const SUPPORTS_VENDOR_TAGS = true; const SUPPORTS_VERSIONING = true; /** @@ -73,7 +74,6 @@ class ParamAnnotation extends Annotation * @var array */ protected $arrayable = [ - 'capability', 'description', 'field', 'nullable', @@ -107,18 +107,23 @@ protected function parser(): array 'type' => $mson->getType(), 'required' => $mson->isRequired(), 'nullable' => $mson->isNullable(), - 'capability' => $mson->getCapability(), + 'vendor_tags' => $mson->getVendorTags(), 'description' => $mson->getDescription(), 'values' => $mson->getValues() ]; - // Create a capability annotation if one was supplied. - if (!empty($parsed['capability'])) { - $parsed['capability'] = (new CapabilityAnnotation( - $parsed['capability'], - $this->class, - $this->method - ))->process(); + if (!empty($parsed['vendor_tags'])) { + $parsed['vendor_tags'] = array_map( + /** @return Annotation */ + function (string $tag) use ($method) { + return (new VendorTagAnnotation( + $tag, + $this->class, + $method + ))->process(); + }, + $parsed['vendor_tags'] + ); } return $parsed; @@ -136,7 +141,7 @@ protected function interpreter(): void $this->required = $this->boolean('required'); $this->values = $this->optional('values'); - $this->capability = $this->optional('capability'); + $this->vendor_tags = $this->optional('vendor_tags'); $this->nullable = $this->optional('nullable'); } diff --git a/src/Parser/Annotations/VendorTagAnnotation.php b/src/Parser/Annotations/VendorTagAnnotation.php new file mode 100644 index 0000000..53523ed --- /dev/null +++ b/src/Parser/Annotations/VendorTagAnnotation.php @@ -0,0 +1,90 @@ +docblock); + + if (!empty($vendor_tag)) { + // Validate the supplied vendor tag with what has been configured as allowable. + $vendor_tags = Container::getConfig()->getVendorTags(); + if (!in_array($vendor_tag, $vendor_tags)) { + /** @var string $method */ + $method = $this->method; + throw InvalidVendorTagSuppliedException::create($vendor_tag, $this->class, $method); + } + } + + return [ + 'vendor_tag' => $vendor_tag + ]; + } + + /** + * {@inheritdoc} + */ + protected function interpreter(): void + { + $this->vendor_tag = $this->required('vendor_tag'); + } + + /** + * {@inheritdoc} + */ + public static function hydrate(array $data = [], Version $version = null): self + { + /** @var VendorTagAnnotation $annotation */ + $annotation = parent::hydrate($data, $version); + $annotation->setVendorTag($data['vendor_tag']); + return $annotation; + } + + /** + * @return string + */ + public function getVendorTag(): string + { + return $this->vendor_tag; + } + + /** + * @param string $vendor_tag + * @return self + */ + public function setVendorTag(string $vendor_tag): self + { + $this->vendor_tag = $vendor_tag; + return $this; + } +} diff --git a/src/Parser/MSON.php b/src/Parser/MSON.php index 92e124e..3602cdc 100644 --- a/src/Parser/MSON.php +++ b/src/Parser/MSON.php @@ -7,6 +7,7 @@ use Mill\Exceptions\Config\UnconfiguredErrorRepresentationException; use Mill\Exceptions\Config\UnconfiguredRepresentationException; use Mill\Exceptions\MSON\MissingOptionsException; +use Mill\Parser\Annotations\VendorTagAnnotation; class MSON { @@ -102,11 +103,11 @@ class MSON protected $is_nullable = false; /** - * Application-specific capability that was parsed out of the MSON content. + * Application-specific vendor tags that were parsed out of the MSON content. * - * @var false|string + * @var array */ - protected $capability = false; + protected $vendor_tags = []; /** * Parsed description from the MSON content. @@ -177,9 +178,10 @@ public function parse(string $content): self * - content_rating (string) - MPAA rating * - content_rating `G` (string, required) - MPAA rating * - content_rating `G` (string, required, nullable) - MPAA rating - * - content_rating `G` (string, optional, MOVIE_RATINGS) - MPAA rating - * - content_rating `G` (string, optional, nullable, MOVIE_RATINGS) - MPAA rating - * - content_rating `G` (string, MOVIE_RATINGS) - MPAA rating + * - content_rating `G` (string, optional, tag:MOVIE_RATINGS) - MPAA rating + * - content_rating `G` (string, optional, nullable, tag:MOVIE_RATINGS) - MPAA rating + * - content_rating `G` (string, tag:MOVIE_RATINGS) - MPAA rating + * - content_rating `G` (string, tag:MOVIE_RATINGS, needs:validUser) - MPAA rating * - websites.description (string) - The websites' description * - websites (array) - The users' list of websites. * - cast (array<\Mill\Examples\Showtimes\Representations\Person>) - Cast @@ -189,11 +191,11 @@ public function parse(string $content): self */ $regex_mson = '/((?P[\w.\*]+) (`(?P.+)` )?' . '\((?P[\w\\\]+)(<(?P[\w\\\]+)>)?(, (?Prequired|optional))?(, ' . - '(?Pnullable))?(, (?P\w+))?\)(\n|\s)+-(\n|\s)+(?P.+))/uis'; + '(?Pnullable))?(?P(, ([\w]+:[\w]+))*?)\)(\n|\s)+-(\n|\s)+(?P.+))/uis'; preg_match($regex_mson, $content, $matches); - foreach (['field', 'type', 'description', 'sample_data', 'subtype', 'capability'] as $name) { + foreach (['field', 'type', 'description', 'sample_data', 'subtype'] as $name) { if (isset($matches[$name])) { // Sample data can be input as "0", so we need some special casing to account for that. if (!empty($matches[$name]) || $name === 'sample_data') { @@ -202,6 +204,20 @@ public function parse(string $content): self } } + if (isset($matches['vendor_tag'])) { + $vendor_tags = explode(',', $matches['vendor_tag']); + $vendor_tags = array_filter($vendor_tags); + $vendor_tags = array_values($vendor_tags); + $vendor_tags = array_map( + function (string $tag): string { + return trim($tag); + }, + $vendor_tags + ); + + $this->vendor_tags = $vendor_tags; + } + if (isset($matches['required'])) { if (!empty($matches['required']) && strtolower($matches['required']) == 'required') { $this->is_required = true; @@ -365,13 +381,13 @@ public function isNullable(): bool } /** - * Application-specific capability that was parsed out of the MSON content. + * Application-specific vendor tags that were parsed from the MSON content. * - * @return false|string + * @return array */ - public function getCapability() + public function getVendorTags(): array { - return $this->capability; + return $this->vendor_tags; } /** @@ -413,7 +429,6 @@ public function allowAllSubtypes(): self public function toArray(): array { return [ - 'capability' => $this->getCapability(), 'description' => $this->getDescription(), 'field' => $this->getField(), 'nullable' => $this->isNullable(), @@ -421,7 +436,8 @@ public function toArray(): array 'sample_data' => $this->getSampleData(), 'subtype' => $this->getSubtype(), 'type' => $this->getType(), - 'values' => $this->getValues() + 'values' => $this->getValues(), + 'vendor_tags' => $this->getVendorTags(), ]; } } diff --git a/src/Parser/Representation/Documentation.php b/src/Parser/Representation/Documentation.php index 1b1f021..498f480 100644 --- a/src/Parser/Representation/Documentation.php +++ b/src/Parser/Representation/Documentation.php @@ -132,46 +132,47 @@ public function filterRepresentationForVersion(string $version): array } /** - * Filter down, and return, all annotations on this representation that match a specific visibility. + * Filter down, and return, all annotations on this representation that match a specific vendor tag. * * @psalm-suppress RedundantCondition - * @param array|null $only_capabilities + * @param array|null $only_vendor_tags * @return array */ - public function filterAnnotationsForVisibility(?array $only_capabilities): array + public function filterAnnotationsForVisibility(?array $only_vendor_tags): array { - if (is_null($only_capabilities)) { + if (is_null($only_vendor_tags)) { return $this->representation; } /** @var Parser\Annotation $annotation */ foreach ($this->representation as $name => $annotation) { - // If this annotation has a capability, but that capability isn't in the set of capabilities we're + // If this annotation has vendor tags, but those vendor tags aren't in the set of vendor tags we're // generating documentation for, filter it out. - $capability = $annotation->getCapability(); - if (!empty($capability)) { - if ($capability instanceof Parser\Annotations\CapabilityAnnotation) { - /** @var Parser\Annotations\CapabilityAnnotation $capability */ - $capability = $capability->getCapability(); - } - - // If we don't even have capabilities to look for, then filter this annotation out completely. - if (!is_null($only_capabilities) && empty($only_capabilities)) { + $vendor_tags = $annotation->getVendorTags(); + if (!empty($vendor_tags)) { + // If we don't even have vendor tags to look for, then filter this annotation out completely. + if (!is_null($only_vendor_tags) && empty($only_vendor_tags)) { unset($this->representation[$name]); continue; } - if (!empty($capability) && - ( - !is_null($only_capabilities) && - !in_array($capability, $only_capabilities) - ) - ) { + $all_found = true; + + /** @var Parser\Annotations\VendorTagAnnotation $vendor_tag */ + foreach ($vendor_tags as $vendor_tag) { + $vendor_tag = $vendor_tag->getVendorTag(); + + if (!is_null($only_vendor_tags) && !in_array($vendor_tag, $only_vendor_tags)) { + $all_found = false; + } + } + + if (!$all_found) { unset($this->representation[$name]); continue; } - // Capabilities override individual annotation visibility. + // Vendor tags requirements override individual annotation visibility. continue; } } diff --git a/src/Parser/Representation/RepresentationParser.php b/src/Parser/Representation/RepresentationParser.php index 41fe9b2..ee1a953 100644 --- a/src/Parser/Representation/RepresentationParser.php +++ b/src/Parser/Representation/RepresentationParser.php @@ -52,7 +52,7 @@ public function getAnnotations(string $method_name = null): array // Run through all created annotations and cascade any versioning down into any present child annotations. /** @var DataAnnotation $annotation */ foreach ($annotations as $identifier => $annotation) { - if (!$annotation->getVersion() && !$annotation->getCapability() && !$annotation->getScopes()) { + if (!$annotation->getVersion() && !$annotation->getVendorTags() && !$annotation->getScopes()) { continue; } @@ -130,7 +130,7 @@ public function parseAnnotations(array $tags, string $original_content): array $prefix = array_shift($pointer); // Pass in the current array (by reference) of found annotations that we have so we can do depth - // traversal for version and capability requirements of any implied children, by way of dot-notation. + // traversal for version and requirements of any implied children, by way of dot-notation. $parser = new self($see_class); $see_annotations = $parser->getAnnotations($see_method); @@ -208,7 +208,7 @@ public function parse(string $code): array } /** - * Given a DataAnnotation object, carry any versioning or capabilities on it down to any dot-notation children in + * Given a DataAnnotation object, carry any versioning or vendor tags on it down to any dot-notation children in * an array of other annotations. * * @param DataAnnotation $parent @@ -218,13 +218,11 @@ private function carryAnnotationSettingsToChildren(DataAnnotation $parent, array { $parent_identifier = $parent->getIdentifier(); $parent_version = $parent->getVersion(); + $parent_vendor_tags = $parent->getVendorTags(); /** @var array $parent_scopes */ $parent_scopes = $parent->getScopes(); - /** @var string $parent_capability */ - $parent_capability = $parent->getCapability(); - /** @var DataAnnotation $annotation */ foreach ($annotations as $identifier => $annotation) { if ($identifier === $parent_identifier) { @@ -240,8 +238,8 @@ private function carryAnnotationSettingsToChildren(DataAnnotation $parent, array $annotation->setVersion($parent_version); } - if (!empty($parent_capability) && !$annotation->getCapability()) { - $annotation->setCapability($parent_capability); + if (!empty($parent_vendor_tags) && !$annotation->getVendorTags()) { + $annotation->setVendorTags($parent_vendor_tags); } if (!empty($parent_scopes) && !$annotation->getScopes()) { diff --git a/src/Parser/Resource/Action/Documentation.php b/src/Parser/Resource/Action/Documentation.php index 2ae05e8..b4dad0e 100644 --- a/src/Parser/Resource/Action/Documentation.php +++ b/src/Parser/Resource/Action/Documentation.php @@ -74,14 +74,14 @@ class Documentation * @var array */ protected static $ACCEPTED_ANNOTATIONS = [ - 'capability', 'error', 'param', 'minVersion', 'return', 'scope', 'uri', - 'uriSegment' + 'uriSegment', + 'vendorTag' ]; /** @@ -433,13 +433,13 @@ public function setUriSegments(array $segments = []): void } /** - * Get back any application capabilities that this action has set as being required. + * Get back any application vendor tags that this action has set. * * @return array */ - public function getCapabilities(): array + public function getVendorTags(): array { - return (isset($this->annotations['capability'])) ? $this->annotations['capability'] : []; + return (isset($this->annotations['vendorTag'])) ? $this->annotations['vendorTag'] : []; } /** @@ -514,20 +514,20 @@ public function filterAnnotationsForVersion(string $version): array /** * Filter down, and return, all annotations on this action that match a specific visibility. This can either be - * public, public+private, or capability-locked. + * public, public+private, or vendor tagged. * * @psalm-suppress RedundantCondition * @param bool $allow_private - * @param array|null $only_capabilities + * @param array|null $only_vendor_tags * @return array */ - public function filterAnnotationsForVisibility(bool $allow_private, ?array $only_capabilities): array + public function filterAnnotationsForVisibility(bool $allow_private, ?array $only_vendor_tags): array { - if ($allow_private && empty($only_capabilities)) { + if ($allow_private && empty($only_vendor_tags)) { return $this->annotations; } - $method_capabilities = $this->getCapabilities(); + $method_vendor_tags = $this->getVendorTags(); foreach ($this->annotations as $name => $data) { /** @var Parser\Annotation $annotation */ @@ -551,38 +551,32 @@ public function filterAnnotationsForVisibility(bool $allow_private, ?array $only continue; } - // If this annotation has a capability, but that capability isn't in the set of capabilities we're + // If this annotation has vendor tags, but those vendor tags aren't in the set of vendor tags we're // generating documentation for, filter it out. - $capability = $annotation->getCapability(); - if (!empty($capability) || !empty($method_capabilities)) { - // If we don't even have capabilities to look for, then filter this annotation out completely. - if (!is_null($only_capabilities) && empty($only_capabilities)) { + $vendor_tags = $annotation->getVendorTags(); + if (!empty($vendor_tags) || !empty($method_vendor_tags)) { + // If we don't even have vendor tags to look for, then filter this annotation out completely. + if (!is_null($only_vendor_tags) && empty($only_vendor_tags)) { unset($this->annotations[$name][$k]); continue; } $all_found = true; - /** @var Parser\Annotations\CapabilityAnnotation $method_capability */ - foreach ($method_capabilities as $method_capability) { - /** @var string $capability */ - $capability = $method_capability->getCapability(); - if (!is_null($only_capabilities) && !in_array($capability, $only_capabilities)) { + /** @var Parser\Annotations\VendorTagAnnotation $method_vendor_tag */ + foreach ($method_vendor_tags as $method_vendor_tag) { + $vendor_tag = $method_vendor_tag->getVendorTag(); + if (!is_null($only_vendor_tags) && !in_array($vendor_tag, $only_vendor_tags)) { $all_found = false; } } - if (!$all_found || - ( - !empty($capability) && - (!is_null($only_capabilities) && !in_array($capability, $only_capabilities)) - ) - ) { + if (!$all_found) { unset($this->annotations[$name][$k]); continue; } - // Capabilities override individual annotation visibility. + // Vendor tag requirements override individual annotation visibility. continue; } diff --git a/tests/Command/ChangelogTest.php b/tests/Command/ChangelogTest.php index 98b70a4..90df185 100644 --- a/tests/Command/ChangelogTest.php +++ b/tests/Command/ChangelogTest.php @@ -30,10 +30,10 @@ public function setUp(): void /** * @dataProvider providerTestCommand * @param bool $private_objects - * @param array $capabilities + * @param array $vendor_tags * @param string $expected_file */ - public function testCommand(bool $private_objects, array $capabilities, string $expected_file): void + public function testCommand(bool $private_objects, array $vendor_tags, string $expected_file): void { /** @var string $output_dir */ $output_dir = tempnam(sys_get_temp_dir(), 'mill-generate-test-'); @@ -53,8 +53,8 @@ public function testCommand(bool $private_objects, array $capabilities, string $ $params['--private'] = $private_objects; } - if (!empty($capabilities)) { - $params['--capability'] = $capabilities; + if (!empty($vendor_tags)) { + $params['--vendor_tag'] = $vendor_tags; } $this->tester->execute($params); @@ -85,34 +85,34 @@ public function providerTestCommand(): array // Complete changelog. All documentation parsed. 'complete-changelog' => [ 'private_objects' => true, - 'capabilities' => [], + 'vendor_tags' => [], 'expected_file' => 'changelog.md' ], - // Changelog with public-only parsed docs and all capabilities. - 'changelog-public-docs-with-all-capabilities' => [ + // Changelog with public-only parsed docs and all vendor tags. + 'changelog-public-docs-with-all-vendor-tags' => [ 'private_objects' => false, - 'capabilities' => [], - 'expected' => 'changelog-public-only-all-capabilities.md' + 'vendor_tags' => [], + 'expected' => 'changelog-public-only-all-vendor-tags.md' ], - // Changelog with public-only parsed docs and matched `BUY_TICKETS` and `FEATURE_FLAG` capabilities - 'changelog-public-only-matched-with-tickets-and-feature-capabilities' => [ + // Changelog with public-only parsed docs and matched `tag:BUY_TICKETS` and `tag:FEATURE_FLAG` vendor tags. + 'changelog-public-only-matched-with-tickets-and-feature-vendor-tags' => [ 'private_objects' => false, - 'capabilities' => [ - 'BUY_TICKETS', - 'FEATURE_FLAG' + 'vendor_tags' => [ + 'tag:BUY_TICKETS', + 'tag:FEATURE_FLAG' ], - 'expected' => 'changelog-public-only-matched-with-tickets-and-feature-capabilities.md' + 'expected' => 'changelog-public-only-matched-with-tickets-and-feature-vendor-tags.md' ], - // Changelog with public-only parsed docs and matched `DELETE_CONTENT` capabilities - 'changelog-public-only-matched-with-delete-capabilities' => [ + // Changelog with public-only parsed docs and matched the `tag:DELETE_CONTENT` vendor tag. + 'changelog-public-only-matched-with-delete-vendor-tags' => [ 'private_objects' => false, - 'capabilities' => [ - 'DELETE_CONTENT' + 'vendor_tags' => [ + 'tag:DELETE_CONTENT' ], - 'expected' => 'changelog-public-only-matched-with-delete-capabilities.md' + 'expected' => 'changelog-public-only-matched-with-delete-vendor-tags.md' ] ]; } diff --git a/tests/Command/ErrorMapTest.php b/tests/Command/ErrorMapTest.php index a711156..e4d55da 100644 --- a/tests/Command/ErrorMapTest.php +++ b/tests/Command/ErrorMapTest.php @@ -30,10 +30,10 @@ public function setUp(): void /** * @dataProvider providerTestCommand * @param bool $private_objects - * @param array $capabilities + * @param array $vendor_tags * @param string $expected_file */ - public function testCommand(bool $private_objects, array $capabilities, string $expected_file): void + public function testCommand(bool $private_objects, array $vendor_tags, string $expected_file): void { /** @var string $output_dir */ $output_dir = tempnam(sys_get_temp_dir(), 'mill-generate-test-'); @@ -53,8 +53,8 @@ public function testCommand(bool $private_objects, array $capabilities, string $ $params['--private'] = $private_objects; } - if (!empty($capabilities)) { - $params['--capability'] = $capabilities; + if (!empty($vendor_tags)) { + $params['--vendor_tag'] = $vendor_tags; } $this->tester->execute($params); @@ -165,34 +165,34 @@ public function providerTestCommand(): array // Complete error map. All documentation parsed. 'complete-error-map' => [ 'private_objects' => true, - 'capabilities' => [], + 'vendor_tags' => [], 'expected_file' => 'errors.md' ], - // Error map with public-only parsed docs and all capabilities. - 'error-map-public-docs-with-all-capabilities' => [ + // Error map with public-only parsed docs and all vendor tags. + 'error-map-public-docs-with-all-vendor-tags' => [ 'private_objects' => false, - 'capabilities' => [], - 'expected' => 'errors-public-only-all-capabilities.md' + 'vendor_tags' => [], + 'expected' => 'errors-public-only-all-vendor-tags.md' ], - // Error map with public-only parsed docs and unmatched capabilities - 'error-map-public-docs-with-unmatched-capabilities' => [ + // Error map with public-only parsed docs and unmatched vendor tags. + 'error-map-public-docs-with-unmatched-vendor-tags' => [ 'private_objects' => false, - 'capabilities' => [ - 'BUY_TICKETS', - 'FEATURE_FLAG' + 'vendor_tags' => [ + 'tag:BUY_TICKETS', + 'tag:FEATURE_FLAG' ], - 'expected' => 'errors-public-only-unmatched-capabilities.md' + 'expected' => 'errors-public-only-unmatched-vendor-tags.md' ], - // Error map with public-only parsed docs and matched capabilities - 'error-map-public-docs-with-matched-capabilities' => [ + // Error map with public-only parsed docs and matched vendor tags. + 'error-map-public-docs-with-matched-vendor-tags' => [ 'private_objects' => false, - 'capabilities' => [ + 'vendor_tags' => [ 'DELETE_CONTENT' ], - 'expected' => 'errors-public-only-matched-capabilities.md' + 'expected' => 'errors-public-only-matched-vendor-tags.md' ] ]; } diff --git a/tests/ConfigTest.php b/tests/ConfigTest.php index 8d57af0..2a79eff 100644 --- a/tests/ConfigTest.php +++ b/tests/ConfigTest.php @@ -50,11 +50,11 @@ public function testLoadFromXML(): void ], $config->getBlueprintNamespaceExcludes()); $this->assertSame([ - 'BUY_TICKETS', - 'DELETE_CONTENT', - 'FEATURE_FLAG', - 'MOVIE_RATINGS' - ], $config->getCapabilities()); + 'tag:BUY_TICKETS', + 'tag:DELETE_CONTENT', + 'tag:FEATURE_FLAG', + 'tag:MOVIE_RATINGS' + ], $config->getVendorTags()); $this->assertSame([ 'create', diff --git a/tests/Generator/ChangelogTest.php b/tests/Generator/ChangelogTest.php index 8517cdb..b3d8614 100644 --- a/tests/Generator/ChangelogTest.php +++ b/tests/Generator/ChangelogTest.php @@ -9,14 +9,14 @@ class ChangelogTest extends TestCase /** * @dataProvider providerTestGeneration * @param bool $private_objects - * @param array|null $capabilities + * @param array|null $vendor_tags * @param array $expected */ - public function testGeneration(bool $private_objects, ?array $capabilities, array $expected): void + public function testGeneration(bool $private_objects, ?array $vendor_tags, array $expected): void { $generator = new Changelog($this->getConfig()); $generator->setLoadPrivateDocs($private_objects); - $generator->setLoadCapabilityDocs($capabilities); + $generator->setLoadVendorTagDocs($vendor_tags); $changelog = $generator->generate(); $this->assertSame(array_keys($expected), array_keys($changelog)); @@ -364,7 +364,7 @@ public function providerTestGeneration(): array // Complete changelog. All documentation parsed. 'complete-changelog' => [ 'private_objects' => true, - 'capabilities' => null, + 'vendor_tags' => null, 'expected' => [ '1.1.3' => [ '_details' => [ @@ -387,7 +387,7 @@ function () use ($actions): array { $actions = $actions['1.1.3']['/movies/{id}']['error']['162944fa14']; // Add in the "If something cool happened." exception. It's the - // only private/capability-free exception we're testing, and it + // only private/vendor tag-free exception we're testing, and it // should be available on the complete changelog. $actions[2] = $actions[1]; $actions[1] = [ @@ -542,14 +542,14 @@ function () use ($actions): array { ] ], - // Changelog with public-only parsed docs and all capabilities. - 'changelog-public-docs-with-all-capabilities' => [ + // Changelog with public-only parsed docs and all vendor tags. + 'changelog-public-docs-with-all-vendor-tags' => [ 'private_objects' => false, - 'capabilities' => [ - 'BUY_TICKETS', - 'DELETE_CONTENT', - 'FEATURE_FLAG', - 'MOVIE_RATINGS' + 'vendor_tags' => [ + 'tag:BUY_TICKETS', + 'tag:DELETE_CONTENT', + 'tag:FEATURE_FLAG', + 'tag:MOVIE_RATINGS' ], 'expected' => [ '1.1.3' => [ @@ -699,12 +699,12 @@ function () use ($actions): array { ] ], - // Changelog with public-only parsed docs with matched - 'changelog-public-docs-with-matched-capabilities' => [ + // Changelog with public-only parsed docs with matched. + 'changelog-public-docs-with-matched-vendor-tags' => [ 'private_objects' => false, - 'capabilities' => [ - 'BUY_TICKETS', - 'FEATURE_FLAG' + 'vendor_tags' => [ + 'tag:BUY_TICKETS', + 'tag:FEATURE_FLAG' ], 'expected' => [ '1.1.3' => [ @@ -865,10 +865,10 @@ function () use ($actions): array { ], ], - // Changelog with public-only parsed docs + // Changelog with public-only parsed docs. 'changelog-public-docs' => [ 'private_objects' => false, - 'capabilities' => [], + 'vendor_tags' => [], 'expected' => [ '1.1.3' => [ '_details' => [ diff --git a/tests/Generator/ErrorMapTest.php b/tests/Generator/ErrorMapTest.php index c0c852e..d1c7dec 100644 --- a/tests/Generator/ErrorMapTest.php +++ b/tests/Generator/ErrorMapTest.php @@ -9,14 +9,14 @@ class ErrorMapTestTest extends TestCase /** * @dataProvider providerTestGeneration * @param bool $private_objects - * @param array|null $capabilities + * @param array|null $vendor_tags * @param array $expected */ - public function testGeneration(bool $private_objects, ?array $capabilities, array $expected): void + public function testGeneration(bool $private_objects, ?array $vendor_tags, array $expected): void { $generator = new ErrorMap($this->getConfig()); $generator->setLoadPrivateDocs($private_objects); - $generator->setLoadCapabilityDocs($capabilities); + $generator->setLoadVendorTagDocs($vendor_tags); $error_map = $generator->generate(); $this->assertSame(array_keys($expected), array_keys($error_map)); @@ -69,7 +69,7 @@ public function providerTestGeneration(): array // Complete error map. All documentation parsed. 'complete-error-map' => [ 'private_objects' => true, - 'capabilities' => null, + 'vendor_tags' => null, 'expected' => [ '1.0' => [ 'Theaters' => [ @@ -105,14 +105,14 @@ public function providerTestGeneration(): array ] ], - // Error map with public-only parsed docs and all capabilities. - 'error-map-public-docs-with-all-capabilities' => [ + // Error map with public-only parsed docs and all vendor tags. + 'error-map-public-docs-with-all-vendor-tags' => [ 'private_objects' => false, - 'capabilities' => [ - 'BUY_TICKETS', - 'DELETE_CONTENT', - 'FEATURE_FLAG', - 'MOVIE_RATINGS' + 'vendor_tags' => [ + 'tag:BUY_TICKETS', + 'tag:DELETE_CONTENT', + 'tag:FEATURE_FLAG', + 'tag:MOVIE_RATINGS' ], 'expected' => [ '1.0' => [ @@ -146,12 +146,12 @@ public function providerTestGeneration(): array ] ], - // Error map with public-only parsed docs and unmatched capabilities - 'error-map-public-docs-with-unmatched-capabilities' => [ + // Error map with public-only parsed docs and unmatched vendor tags. + 'error-map-public-docs-with-unmatched-vendor-tags' => [ 'private_objects' => false, - 'capabilities' => [ - 'BUY_TICKETS', - 'FEATURE_FLAG' + 'vendor_tags' => [ + 'tag:BUY_TICKETS', + 'tag:FEATURE_FLAG' ], 'expected' => [ '1.0' => [ @@ -185,11 +185,11 @@ public function providerTestGeneration(): array ], ], - // Error map with public-only parsed docs and matched capabilities - 'error-map-public-docs-with-matched-capabilities' => [ + // Error map with public-only parsed docs and matched vendor tags. + 'error-map-public-docs-with-matched-vendor-tags' => [ 'private_objects' => false, - 'capabilities' => [ - 'DELETE_CONTENT' + 'vendor_tags' => [ + 'tag:DELETE_CONTENT' ], 'expected' => [ '1.0' => [ @@ -223,10 +223,10 @@ public function providerTestGeneration(): array ] ], - // Error map with public-only parsed docs + // Error map with public-only parsed docs. 'error-map-public-docs' => [ 'private_objects' => false, - 'capabilities' => [], + 'vendor_tags' => [], 'expected' => [ '1.0' => [ 'Theaters' => [ diff --git a/tests/GeneratorTest.php b/tests/GeneratorTest.php index d5fbe7f..043b9b8 100644 --- a/tests/GeneratorTest.php +++ b/tests/GeneratorTest.php @@ -49,21 +49,21 @@ public function testGeneratorButExcludeARepresentation(): void * @dataProvider providerGeneratorWithVersion * @param string $version * @param bool $private_objects - * @param array|null $capabilities + * @param array|null $vendor_tags * @param array $expected_representations * @param array $expected_resources */ public function testGeneratorWithVersion( string $version, bool $private_objects, - ?array $capabilities, + ?array $vendor_tags, array $expected_representations, array $expected_resources ): void { $version_obj = new Version($version, __CLASS__, __METHOD__); $generator = new Generator($this->getConfig(), $version_obj); $generator->setLoadPrivateDocs($private_objects); - $generator->setLoadCapabilityDocs($capabilities); + $generator->setLoadVendorTagDocs($vendor_tags); $generator->generate(); // Verify resources @@ -190,7 +190,7 @@ public function providerGeneratorWithVersion(): array 'field' => 'id', 'type' => 'integer', 'uri' => '/movie/+id', - 'values' => false + 'values' => [] ] ], 'uri.visible' => false, @@ -250,7 +250,7 @@ public function providerGeneratorWithVersion(): array 'field' => 'id', 'type' => 'integer', 'uri' => '/movies/+id', - 'values' => false + 'values' => [] ] ], 'uri.visible' => true, @@ -271,7 +271,7 @@ public function providerGeneratorWithVersion(): array 'field' => 'id', 'type' => 'integer', 'uri' => '/movies/+id', - 'values' => false + 'values' => [] ] ], 'uri.visible' => true, @@ -306,19 +306,19 @@ public function providerGeneratorWithVersion(): array 'field' => 'id', 'type' => 'integer', 'uri' => '/movies/+id', - 'values' => false + 'values' => [] ] ], 'uri.visible' => false, 'params.keys' => [], 'annotations.sum' => [ - 'capability' => 1, 'error' => 1, 'minVersion' => 1, 'return' => 1, 'scope' => 1, 'uri' => 1, - 'uriSegment' => 1 + 'uriSegment' => 1, + 'vendorTag' => 1 ] ], '/theaters::GET' => [ @@ -363,7 +363,7 @@ public function providerGeneratorWithVersion(): array 'field' => 'id', 'type' => 'integer', 'uri' => '/theaters/+id', - 'values' => false + 'values' => [] ] ], 'uri.visible' => true, @@ -384,7 +384,7 @@ public function providerGeneratorWithVersion(): array 'field' => 'id', 'type' => 'integer', 'uri' => '/theaters/+id', - 'values' => false + 'values' => [] ] ], 'uri.visible' => true, @@ -411,7 +411,7 @@ public function providerGeneratorWithVersion(): array 'field' => 'id', 'type' => 'integer', 'uri' => '/theaters/+id', - 'values' => false + 'values' => [] ] ], 'uri.visible' => false, @@ -495,7 +495,7 @@ public function providerGeneratorWithVersion(): array 'version-1.0' => [ 'version' => '1.0', 'private_objects' => true, - 'capabilities' => null, + 'vendor_tags' => null, 'expected.representations' => array_merge($error_representations, [ '\Mill\Examples\Showtimes\Representations\Movie' => $representations['Movie'], '\Mill\Examples\Showtimes\Representations\Person' => $representations['Person'], @@ -544,15 +544,15 @@ function () use ($representations): array { ] ], - // API v1.0 with public-only docs and all capabilities - 'version-1.0-public-docs-with-all-capabilities' => [ + // API v1.0 with public-only docs and all vendor tags. + 'version-1.0-public-docs-with-all-vendor-tags' => [ 'version' => '1.0', 'private_objects' => false, - 'capabilities' => [ - 'BUY_TICKETS', - 'DELETE_CONTENT', - 'FEATURE_FLAG', - 'MOVIE_RATINGS' + 'vendor_tags' => [ + 'tag:BUY_TICKETS', + 'tag:DELETE_CONTENT', + 'tag:FEATURE_FLAG', + 'tag:MOVIE_RATINGS' ], 'expected.representations' => array_merge($error_representations, [ '\Mill\Examples\Showtimes\Representations\Movie' => $representations['Movie'], @@ -604,7 +604,7 @@ function () use ($representations): array { 'version-1.1' => [ 'version' => '1.1', 'private_objects' => true, - 'capabilities' => null, + 'vendor_tags' => null, 'expected.representations' => array_merge($error_representations, [ '\Mill\Examples\Showtimes\Representations\Movie' => call_user_func( function () use ($representations): array { @@ -675,13 +675,13 @@ function () use ($representations): array { ] ], - // API v1.1 with public-only docs and unmatched capabilities - 'version-1.1-public-docs-with-unmatched-capabilities' => [ + // API v1.1 with public-only docs and unmatched vendor tags. + 'version-1.1-public-docs-with-unmatched-vendor-tags' => [ 'version' => '1.1', 'private_objects' => false, - 'capabilities' => [ - 'BUY_TICKETS', - 'FEATURE_FLAG' + 'vendor_tags' => [ + 'tag:BUY_TICKETS', + 'tag:FEATURE_FLAG' ], 'expected.representations' => array_merge($error_representations, [ '\Mill\Examples\Showtimes\Representations\Movie' => call_user_func( @@ -750,12 +750,12 @@ function () use ($representations): array { ] ], - // API v1.1 with public-only docs and matched capabilities - 'version-1.1-public-docs-with-matched-capabilities' => [ + // API v1.1 with public-only docs and matched vendor tags. + 'version-1.1-public-docs-with-matched-vendor-tags' => [ 'version' => '1.1', 'private_objects' => false, - 'capabilities' => [ - 'DELETE_CONTENT' + 'vendor_tags' => [ + 'tag:DELETE_CONTENT' ], 'expected.representations' => array_merge($error_representations, [ '\Mill\Examples\Showtimes\Representations\Movie' => call_user_func( @@ -828,7 +828,7 @@ function () use ($representations): array { 'version-1.1.1' => [ 'version' => '1.1.1', 'private_objects' => true, - 'capabilities' => null, + 'vendor_tags' => null, 'expected.representations' => array_merge($error_representations, [ '\Mill\Examples\Showtimes\Representations\Movie' => call_user_func( function () use ($representations): array { @@ -912,7 +912,7 @@ function () use ($representations): array { 'version-1.1.1-public-only-documentation' => [ 'version' => '1.1.1', 'private_objects' => true, - 'capabilities' => [], + 'vendor_tags' => [], 'expected.representations' => array_merge($error_representations, [ '\Mill\Examples\Showtimes\Representations\Movie' => call_user_func( function () use ($representations): array { diff --git a/tests/Parser/Annotations/ContentTypeAnnotationTest.php b/tests/Parser/Annotations/ContentTypeAnnotationTest.php index 91e99d9..055a199 100644 --- a/tests/Parser/Annotations/ContentTypeAnnotationTest.php +++ b/tests/Parser/Annotations/ContentTypeAnnotationTest.php @@ -42,14 +42,15 @@ public function testHydrate(string $content, ?Version $version, array $expected) private function assertAnnotation(ContentTypeAnnotation $annotation, array $expected): void { - $this->assertFalse($annotation->requiresVisibilityDecorator()); - $this->assertTrue($annotation->supportsVersioning()); - $this->assertFalse($annotation->supportsDeprecation()); $this->assertFalse($annotation->supportsAliasing()); + $this->assertFalse($annotation->supportsDeprecation()); + $this->assertTrue($annotation->supportsVersioning()); + $this->assertFalse($annotation->supportsVendorTags()); + $this->assertFalse($annotation->requiresVisibilityDecorator()); $this->assertSame($expected, $annotation->toArray()); $this->assertSame($expected['content_type'], $annotation->getContentType()); - $this->assertFalse($annotation->getCapability()); + $this->assertEmpty($annotation->getVendorTags()); if ($expected['version']) { $this->assertInstanceOf(Version::class, $annotation->getVersion()); diff --git a/tests/Parser/Annotations/DataAnnotationTest.php b/tests/Parser/Annotations/DataAnnotationTest.php index 89cd4a2..65c90bf 100644 --- a/tests/Parser/Annotations/DataAnnotationTest.php +++ b/tests/Parser/Annotations/DataAnnotationTest.php @@ -3,8 +3,8 @@ use Mill\Exceptions\Annotations\UnsupportedTypeException; use Mill\Exceptions\Representation\RestrictedFieldNameException; -use Mill\Parser\Annotations\CapabilityAnnotation; use Mill\Parser\Annotations\DataAnnotation; +use Mill\Parser\Annotations\VendorTagAnnotation; use Mill\Parser\Version; class DataAnnotationTest extends AnnotationTest @@ -42,18 +42,24 @@ public function testHydrate(string $content, ?Version $version, array $expected) private function assertAnnotation(DataAnnotation $annotation, array $expected): void { - $this->assertFalse($annotation->requiresVisibilityDecorator()); - $this->assertTrue($annotation->supportsVersioning()); + $this->assertFalse($annotation->supportsAliasing()); $this->assertFalse($annotation->supportsDeprecation()); + $this->assertTrue($annotation->supportsVersioning()); + $this->assertTrue($annotation->supportsVendorTags()); + $this->assertFalse($annotation->requiresVisibilityDecorator()); $this->assertSame($expected['identifier'], $annotation->getIdentifier()); $this->assertSame($expected, $annotation->toArray()); - if (is_string($expected['capability'])) { - $this->assertInstanceOf(CapabilityAnnotation::class, $annotation->getCapability()); - } else { - $this->assertFalse($annotation->getCapability()); - } + $this->assertSame( + $expected['vendor_tags'], + array_map( + function (VendorTagAnnotation $tag): string { + return $tag->getVendorTag(); + }, + $annotation->getVendorTags() + ) + ); if ($expected['version']) { $this->assertInstanceOf(Version::class, $annotation->getVersion()); @@ -65,13 +71,57 @@ private function assertAnnotation(DataAnnotation $annotation, array $expected): public function providerAnnotation(): array { return [ + '_complete' => [ + 'content' => '/** + * @api-data content_rating `G` (enum, nullable, tag:MOVIE_RATINGS) - MPAA rating + * + Members + * - `G` + * - `PG` + * - `PG-13` + * - `R` + * - `NC-17` + * - `X` + * - `NR` + * - `UR` + * @api-version 1.0 + * @api-scope public + *', + 'version' => new Version('1.0', __CLASS__, __METHOD__), + 'expected' => [ + 'description' => 'MPAA rating', + 'identifier' => 'content_rating', + 'nullable' => true, + 'sample_data' => 'G', + 'scopes' => [ + [ + 'description' => false, + 'scope' => 'public' + ] + ], + 'subtype' => false, + 'type' => 'enum', + 'values' => [ + 'G' => '', + 'NC-17' => '', + 'NR' => '', + 'PG' => '', + 'PG-13' => '', + 'R' => '', + 'UR' => '', + 'X' => '' + ], + 'vendor_tags' => [ + 'tag:MOVIE_RATINGS' + ], + 'version' => '1.0' + ] + ], 'bare' => [ 'content' => '/** * @api-data content_rating (string) - MPAA rating */', 'version' => null, 'expected' => [ - 'capability' => false, 'description' => 'MPAA rating', 'identifier' => 'content_rating', 'nullable' => false, @@ -79,7 +129,8 @@ public function providerAnnotation(): array 'scopes' => [], 'subtype' => false, 'type' => 'string', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ] ], @@ -90,7 +141,6 @@ public function providerAnnotation(): array */', 'version' => new Version('1.0', __CLASS__, __METHOD__), 'expected' => [ - 'capability' => false, 'description' => 'MPAA rating', 'identifier' => 'content_rating', 'nullable' => false, @@ -98,7 +148,8 @@ public function providerAnnotation(): array 'scopes' => [], 'subtype' => false, 'type' => 'string', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => '1.0' ] ], @@ -108,7 +159,6 @@ public function providerAnnotation(): array */', 'version' => null, 'expected' => [ - 'capability' => false, 'description' => 'URL to purchase tickets', 'identifier' => 'tickets.url', 'nullable' => true, @@ -116,25 +166,8 @@ public function providerAnnotation(): array 'scopes' => [], 'subtype' => false, 'type' => 'string', - 'values' => false, - 'version' => false - ] - ], - 'capability' => [ - 'content' => '/** - * @api-data tickets.url (string, BUY_TICKETS) - URL to purchase tickets - */', - 'version' => null, - 'expected' => [ - 'capability' => 'BUY_TICKETS', - 'description' => 'URL to purchase tickets', - 'identifier' => 'tickets.url', - 'nullable' => false, - 'sample_data' => false, - 'scopes' => [], - 'subtype' => false, - 'type' => 'string', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ] ], @@ -153,7 +186,6 @@ public function providerAnnotation(): array */', 'version' => null, 'expected' => [ - 'capability' => false, 'description' => 'MPAA rating', 'identifier' => 'content_rating', 'nullable' => false, @@ -171,6 +203,7 @@ public function providerAnnotation(): array 'UR' => '', 'X' => '' ], + 'vendor_tags' => [], 'version' => false ] ], @@ -181,7 +214,6 @@ public function providerAnnotation(): array */', 'version' => null, 'expected' => [ - 'capability' => false, 'description' => 'URL to purchase tickets', 'identifier' => 'tickets.url', 'nullable' => false, @@ -194,51 +226,29 @@ public function providerAnnotation(): array ], 'subtype' => false, 'type' => 'string', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ] ], - '_complete' => [ + 'vendor-tag' => [ 'content' => '/** - * @api-data content_rating `G` (enum, nullable, MOVIE_RATINGS) - MPAA rating - * + Members - * - `G` - * - `PG` - * - `PG-13` - * - `R` - * - `NC-17` - * - `X` - * - `NR` - * - `UR` - * @api-version 1.0 - * @api-scope public - *', - 'version' => new Version('1.0', __CLASS__, __METHOD__), + * @api-data tickets.url (string, tag:BUY_TICKETS) - URL to purchase tickets + */', + 'version' => null, 'expected' => [ - 'capability' => 'MOVIE_RATINGS', - 'description' => 'MPAA rating', - 'identifier' => 'content_rating', - 'nullable' => true, - 'sample_data' => 'G', - 'scopes' => [ - [ - 'description' => false, - 'scope' => 'public' - ] - ], + 'description' => 'URL to purchase tickets', + 'identifier' => 'tickets.url', + 'nullable' => false, + 'sample_data' => false, + 'scopes' => [], 'subtype' => false, - 'type' => 'enum', - 'values' => [ - 'G' => '', - 'NC-17' => '', - 'NR' => '', - 'PG' => '', - 'PG-13' => '', - 'R' => '', - 'UR' => '', - 'X' => '' + 'type' => 'string', + 'values' => [], + 'vendor_tags' => [ + 'tag:BUY_TICKETS' ], - 'version' => '1.0' + 'version' => false ] ], 'zeroed-out-sample_data' => [ @@ -247,7 +257,6 @@ public function providerAnnotation(): array */', 'version' => null, 'expected' => [ - 'capability' => false, 'description' => 'Is this user a staff member?', 'identifier' => 'is_staff', 'nullable' => false, @@ -255,7 +264,8 @@ public function providerAnnotation(): array 'scopes' => [], 'subtype' => false, 'type' => 'boolean', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ] ], diff --git a/tests/Parser/Annotations/DescriptionAnnotationTest.php b/tests/Parser/Annotations/DescriptionAnnotationTest.php index 078a35e..d12ffc9 100644 --- a/tests/Parser/Annotations/DescriptionAnnotationTest.php +++ b/tests/Parser/Annotations/DescriptionAnnotationTest.php @@ -39,13 +39,14 @@ public function testHydrate(string $content, array $expected): void private function assertAnnotation(DescriptionAnnotation $annotation, array $expected): void { - $this->assertFalse($annotation->requiresVisibilityDecorator()); - $this->assertFalse($annotation->supportsVersioning()); - $this->assertFalse($annotation->supportsDeprecation()); $this->assertFalse($annotation->supportsAliasing()); + $this->assertFalse($annotation->supportsDeprecation()); + $this->assertFalse($annotation->supportsVersioning()); + $this->assertFalse($annotation->supportsVendorTags()); + $this->assertFalse($annotation->requiresVisibilityDecorator()); $this->assertSame($expected, $annotation->toArray()); - $this->assertFalse($annotation->getCapability()); + $this->assertEmpty($annotation->getVendorTags()); $this->assertFalse($annotation->getVersion()); $this->assertEmpty($annotation->getAliases()); } diff --git a/tests/Parser/Annotations/ErrorAnnotationTest.php b/tests/Parser/Annotations/ErrorAnnotationTest.php index 482bb1a..dc3df37 100644 --- a/tests/Parser/Annotations/ErrorAnnotationTest.php +++ b/tests/Parser/Annotations/ErrorAnnotationTest.php @@ -6,8 +6,8 @@ //use Mill\Exceptions\Annotations\MissingRequiredFieldException; use Mill\Exceptions\Annotations\UnknownErrorRepresentationException; use Mill\Exceptions\Annotations\UnknownReturnCodeException; -use Mill\Parser\Annotations\CapabilityAnnotation; use Mill\Parser\Annotations\ErrorAnnotation; +use Mill\Parser\Annotations\VendorTagAnnotation; use Mill\Parser\Version; class ErrorAnnotationTest extends AnnotationTest @@ -51,10 +51,11 @@ public function testHydrate(string $content, $version, bool $visible, array $exp private function assertAnnotation(ErrorAnnotation $annotation, array $expected): void { - $this->assertTrue($annotation->requiresVisibilityDecorator()); - $this->assertTrue($annotation->supportsVersioning()); - $this->assertFalse($annotation->supportsDeprecation()); $this->assertFalse($annotation->supportsAliasing()); + $this->assertFalse($annotation->supportsDeprecation()); + $this->assertTrue($annotation->supportsVersioning()); + $this->assertTrue($annotation->supportsVendorTags()); + $this->assertTrue($annotation->requiresVisibilityDecorator()); $this->assertSame($expected, $annotation->toArray()); $this->assertSame($expected['description'], $annotation->getDescription()); @@ -62,11 +63,15 @@ private function assertAnnotation(ErrorAnnotation $annotation, array $expected): $this->assertSame($expected['representation'], $annotation->getRepresentation()); $this->assertSame($expected['error_code'], $annotation->getErrorCode()); - if (is_string($expected['capability'])) { - $this->assertInstanceOf(CapabilityAnnotation::class, $annotation->getCapability()); - } else { - $this->assertFalse($annotation->getCapability()); - } + $this->assertSame( + $expected['vendor_tags'], + array_map( + function (VendorTagAnnotation $tag): string { + return $tag->getVendorTag(); + }, + $annotation->getVendorTags() + ) + ); if ($expected['version']) { $this->assertInstanceOf(Version::class, $annotation->getVersion()); @@ -85,26 +90,11 @@ public function providerAnnotation(): array 'version' => null, 'visible' => true, 'expected' => [ - 'capability' => false, - 'description' => 'If the movie could not be found.', - 'error_code' => false, - 'http_code' => '404 Not Found', - 'representation' => '\Mill\Examples\Showtimes\Representations\Error', - 'version' => false, - 'visible' => true - ] - ], - 'capability' => [ - 'content' => '404 (\Mill\Examples\Showtimes\Representations\Error, BUY_TICKETS) - If the movie ' . - 'could not be found.', - 'version' => null, - 'visible' => true, - 'expected' => [ - 'capability' => 'BUY_TICKETS', 'description' => 'If the movie could not be found.', 'error_code' => false, 'http_code' => '404 Not Found', 'representation' => '\Mill\Examples\Showtimes\Representations\Error', + 'vendor_tags' => [], 'version' => false, 'visible' => true ] @@ -114,11 +104,11 @@ public function providerAnnotation(): array 'version' => null, 'visible' => true, 'expected' => [ - 'capability' => false, 'description' => 'If an unknown error occurred.', 'error_code' => false, 'http_code' => '400 Bad Request', 'representation' => '\Mill\Examples\Showtimes\Representations\Error', + 'vendor_tags' => [], 'version' => false, 'visible' => true ] @@ -129,11 +119,11 @@ public function providerAnnotation(): array 'version' => null, 'visible' => true, 'expected' => [ - 'capability' => false, 'description' => 'This is a description with a (parenthesis of something).', 'error_code' => false, 'http_code' => '403 Forbidden', 'representation' => '\Mill\Examples\Showtimes\Representations\Error', + 'vendor_tags' => [], 'version' => false, 'visible' => true ] @@ -143,11 +133,11 @@ public function providerAnnotation(): array 'version' => null, 'visible' => true, 'expected' => [ - 'capability' => false, 'description' => 'If movie was not found.', 'error_code' => false, 'http_code' => '404 Not Found', 'representation' => '\Mill\Examples\Showtimes\Representations\Error', + 'vendor_tags' => [], 'version' => false, 'visible' => true ] @@ -157,11 +147,11 @@ public function providerAnnotation(): array 'version' => null, 'visible' => true, 'expected' => [ - 'capability' => false, 'description' => 'If movie was not found in the theater.', 'error_code' => false, 'http_code' => '404 Not Found', 'representation' => '\Mill\Examples\Showtimes\Representations\Error', + 'vendor_tags' => [], 'version' => false, 'visible' => true ] @@ -172,11 +162,11 @@ public function providerAnnotation(): array 'version' => null, 'visible' => true, 'expected' => [ - 'capability' => false, 'description' => 'If the user is not allowed to edit that movie.', 'error_code' => '666', 'http_code' => '403 Forbidden', 'representation' => '\Mill\Examples\Showtimes\Representations\CodedError', + 'vendor_tags' => [], 'version' => false, 'visible' => true ] @@ -187,11 +177,11 @@ public function providerAnnotation(): array 'version' => null, 'visible' => true, 'expected' => [ - 'capability' => false, 'description' => 'If something cool happened.', 'error_code' => '1337', 'http_code' => '403 Forbidden', 'representation' => '\Mill\Examples\Showtimes\Representations\CodedError', + 'vendor_tags' => [], 'version' => false, 'visible' => true ] @@ -201,69 +191,92 @@ public function providerAnnotation(): array 'version' => null, 'visible' => false, 'expected' => [ - 'capability' => false, 'description' => 'If movie was not found.', 'error_code' => false, 'http_code' => '404 Not Found', 'representation' => '\Mill\Examples\Showtimes\Representations\Error', + 'vendor_tags' => [], 'version' => false, 'visible' => false ] ], + 'vendor-tag' => [ + 'content' => '404 (\Mill\Examples\Showtimes\Representations\Error, tag:BUY_TICKETS) - If the movie ' . + 'could not be found.', + 'version' => null, + 'visible' => true, + 'expected' => [ + 'description' => 'If the movie could not be found.', + 'error_code' => false, + 'http_code' => '404 Not Found', + 'representation' => '\Mill\Examples\Showtimes\Representations\Error', + 'vendor_tags' => [ + 'tag:BUY_TICKETS' + ], + 'version' => false, + 'visible' => true + ] + ], 'versioned' => [ 'content' => '404 (\Mill\Examples\Showtimes\Representations\Error) - {movie}', 'version' => new Version('1.1 - 1.2', __CLASS__, __METHOD__), 'visible' => false, 'expected' => [ - 'capability' => false, 'description' => 'If movie was not found.', 'error_code' => false, 'http_code' => '404 Not Found', 'representation' => '\Mill\Examples\Showtimes\Representations\Error', + 'vendor_tags' => [], 'version' => '1.1 - 1.2', 'visible' => false ] ], '_complete.description' => [ - 'content' => '404 (\Mill\Examples\Showtimes\Representations\Error, BUY_TICKETS) - If the tickets ' . + 'content' => '404 (\Mill\Examples\Showtimes\Representations\Error, tag:BUY_TICKETS) - If the tickets ' . 'URL does not exist.', 'version' => null, 'visible' => true, 'expected' => [ - 'capability' => 'BUY_TICKETS', 'description' => 'If the tickets URL does not exist.', 'error_code' => false, 'http_code' => '404 Not Found', 'representation' => '\Mill\Examples\Showtimes\Representations\Error', + 'vendor_tags' => [ + 'tag:BUY_TICKETS' + ], 'version' => false, 'visible' => true ] ], '_complete.error_code' => [ - 'content' => '404 (\Mill\Examples\Showtimes\Representations\CodedError<666>, BUY_TICKETS) - ' . + 'content' => '404 (\Mill\Examples\Showtimes\Representations\CodedError<666>, tag:BUY_TICKETS) - ' . '{movie,theater}', 'version' => null, 'visible' => true, 'expected' => [ - 'capability' => 'BUY_TICKETS', 'description' => 'If movie was not found in the theater.', 'error_code' => '666', 'http_code' => '404 Not Found', 'representation' => '\Mill\Examples\Showtimes\Representations\CodedError', + 'vendor_tags' => [ + 'tag:BUY_TICKETS' + ], 'version' => false, 'visible' => true ] ], '_complete.type_subtype' => [ - 'content' => '404 (\Mill\Examples\Showtimes\Representations\Error, BUY_TICKETS) - {movie,theater}', + 'content' => '404 (\Mill\Examples\Showtimes\Representations\Error, tag:BUY_TICKETS) - {movie,theater}', 'version' => null, 'visible' => true, 'expected' => [ - 'capability' => 'BUY_TICKETS', 'description' => 'If movie was not found in the theater.', 'error_code' => false, 'http_code' => '404 Not Found', 'representation' => '\Mill\Examples\Showtimes\Representations\Error', + 'vendor_tags' => [ + 'tag:BUY_TICKETS' + ], 'version' => false, 'visible' => true ] diff --git a/tests/Parser/Annotations/LabelAnnotationTest.php b/tests/Parser/Annotations/LabelAnnotationTest.php index bbcfa34..5118060 100644 --- a/tests/Parser/Annotations/LabelAnnotationTest.php +++ b/tests/Parser/Annotations/LabelAnnotationTest.php @@ -39,13 +39,14 @@ public function testHydrate(string $content, array $expected): void private function assertAnnotation(LabelAnnotation $annotation, array $expected): void { - $this->assertFalse($annotation->requiresVisibilityDecorator()); - $this->assertFalse($annotation->supportsVersioning()); - $this->assertFalse($annotation->supportsDeprecation()); $this->assertFalse($annotation->supportsAliasing()); + $this->assertFalse($annotation->supportsDeprecation()); + $this->assertFalse($annotation->supportsVersioning()); + $this->assertFalse($annotation->supportsVendorTags()); + $this->assertFalse($annotation->requiresVisibilityDecorator()); $this->assertSame($expected, $annotation->toArray()); - $this->assertFalse($annotation->getCapability()); + $this->assertEmpty($annotation->getVendorTags()); $this->assertFalse($annotation->getVersion()); $this->assertEmpty($annotation->getAliases()); } diff --git a/tests/Parser/Annotations/MinVersionAnnotationTest.php b/tests/Parser/Annotations/MinVersionAnnotationTest.php index 16cd35c..414edfe 100644 --- a/tests/Parser/Annotations/MinVersionAnnotationTest.php +++ b/tests/Parser/Annotations/MinVersionAnnotationTest.php @@ -40,13 +40,14 @@ public function testHydrate(string $content, array $expected): void private function assertAnnotation(MinVersionAnnotation $annotation, array $expected): void { - $this->assertFalse($annotation->requiresVisibilityDecorator()); - $this->assertFalse($annotation->supportsVersioning()); - $this->assertFalse($annotation->supportsDeprecation()); $this->assertFalse($annotation->supportsAliasing()); + $this->assertFalse($annotation->supportsDeprecation()); + $this->assertFalse($annotation->supportsVersioning()); + $this->assertFalse($annotation->supportsVendorTags()); + $this->assertFalse($annotation->requiresVisibilityDecorator()); $this->assertSame($expected, $annotation->toArray()); - $this->assertFalse($annotation->getCapability()); + $this->assertEmpty($annotation->getVendorTags()); $this->assertFalse($annotation->getVersion()); $this->assertEmpty($annotation->getAliases()); } diff --git a/tests/Parser/Annotations/ParamAnnotationTest.php b/tests/Parser/Annotations/ParamAnnotationTest.php index 31e6ff1..98468d8 100644 --- a/tests/Parser/Annotations/ParamAnnotationTest.php +++ b/tests/Parser/Annotations/ParamAnnotationTest.php @@ -1,10 +1,9 @@ assertTrue($annotation->requiresVisibilityDecorator()); - $this->assertTrue($annotation->supportsVersioning()); - $this->assertTrue($annotation->supportsDeprecation()); $this->assertFalse($annotation->supportsAliasing()); + $this->assertTrue($annotation->supportsDeprecation()); + $this->assertTrue($annotation->supportsVersioning()); + $this->assertTrue($annotation->supportsVendorTags()); + $this->assertTrue($annotation->requiresVisibilityDecorator()); $this->assertSame($expected, $annotation->toArray()); $this->assertSame($expected['field'], $annotation->getField()); @@ -72,11 +72,15 @@ private function assertAnnotation(ParamAnnotation $annotation, array $expected): $this->assertSame($expected['required'], $annotation->isRequired()); $this->assertSame($expected['values'], $annotation->getValues()); - if (is_string($expected['capability'])) { - $this->assertInstanceOf(CapabilityAnnotation::class, $annotation->getCapability()); - } else { - $this->assertFalse($annotation->getCapability()); - } + $this->assertSame( + $expected['vendor_tags'], + array_map( + function (VendorTagAnnotation $tag): string { + return $tag->getVendorTag(); + }, + $annotation->getVendorTags() + ) + ); if ($expected['version']) { $this->assertInstanceOf(Version::class, $annotation->getVersion()); @@ -91,7 +95,7 @@ public function providerAnnotation(): array { return [ '_complete' => [ - 'content' => 'content_rating `G` (string, optional, nullable, MOVIE_RATINGS) - MPAA rating + 'content' => 'content_rating `G` (string, optional, nullable, tag:MOVIE_RATINGS) - MPAA rating + Members - `G` - G rated - `PG` - PG rated @@ -100,7 +104,6 @@ public function providerAnnotation(): array 'visible' => true, 'deprecated' => false, 'expected' => [ - 'capability' => 'MOVIE_RATINGS', 'deprecated' => false, 'description' => 'MPAA rating', 'field' => 'content_rating', @@ -113,12 +116,15 @@ public function providerAnnotation(): array 'PG' => 'PG rated', 'PG-13' => 'PG-13 rated' ], + 'vendor_tags' => [ + 'tag:MOVIE_RATINGS' + ], 'version' => false, 'visible' => true ] ], '_complete-with-markdown-description' => [ - 'content' => 'content_rating `G` (string, optional, nullable, MOVIE_RATINGS) - This denotes the + 'content' => 'content_rating `G` (string, optional, nullable, tag:MOVIE_RATINGS) - This denotes the [MPAA rating](http://www.mpaa.org/film-ratings/) for the movie. + Members - `G` - G rated @@ -128,7 +134,6 @@ public function providerAnnotation(): array 'visible' => true, 'deprecated' => false, 'expected' => [ - 'capability' => 'MOVIE_RATINGS', 'deprecated' => false, 'description' => 'This denotes the [MPAA rating](http://www.mpaa.org/film-ratings/) for the movie.', 'field' => 'content_rating', @@ -141,25 +146,9 @@ public function providerAnnotation(): array 'PG' => 'PG rated', 'PG-13' => 'PG-13 rated' ], - 'version' => false, - 'visible' => true - ] - ], - 'capability' => [ - 'content' => 'content_rating `G` (string, REQUIRED, MOVIE_RATINGS) - MPAA rating', - 'version' => null, - 'visible' => true, - 'deprecated' => false, - 'expected' => [ - 'capability' => 'MOVIE_RATINGS', - 'deprecated' => false, - 'description' => 'MPAA rating', - 'field' => 'content_rating', - 'nullable' => false, - 'required' => true, - 'sample_data' => 'G', - 'type' => 'string', - 'values' => false, + 'vendor_tags' => [ + 'tag:MOVIE_RATINGS' + ], 'version' => false, 'visible' => true ] @@ -170,7 +159,6 @@ public function providerAnnotation(): array 'visible' => true, 'deprecated' => true, 'expected' => [ - 'capability' => false, 'deprecated' => true, 'description' => 'MPAA rating', 'field' => 'content_rating', @@ -178,7 +166,8 @@ public function providerAnnotation(): array 'required' => true, 'sample_data' => 'G', 'type' => 'string', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false, 'visible' => true ] @@ -192,7 +181,6 @@ public function providerAnnotation(): array 'visible' => true, 'deprecated' => false, 'expected' => [ - 'capability' => false, 'deprecated' => false, 'description' => 'Is this movie kid friendly?', 'field' => 'is_kid_friendly', @@ -204,6 +192,7 @@ public function providerAnnotation(): array 'no' => '', 'yes' => '' ], + 'vendor_tags' => [], 'version' => false, 'visible' => true ] @@ -223,7 +212,6 @@ public function providerAnnotation(): array 'visible' => true, 'deprecated' => false, 'expected' => [ - 'capability' => false, 'deprecated' => false, 'description' => 'MPAA rating', 'field' => 'content_rating', @@ -241,6 +229,7 @@ public function providerAnnotation(): array 'UR' => 'Unrated', 'X' => 'X-rated' ], + 'vendor_tags' => [], 'version' => false, 'visible' => true ] @@ -251,7 +240,6 @@ public function providerAnnotation(): array 'visible' => true, 'deprecated' => false, 'expected' => [ - 'capability' => false, 'deprecated' => false, 'description' => 'MPAA rating', 'field' => 'content_rating', @@ -259,7 +247,8 @@ public function providerAnnotation(): array 'required' => true, 'sample_data' => 'G', 'type' => 'string', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false, 'visible' => true ] @@ -270,7 +259,6 @@ public function providerAnnotation(): array 'visible' => false, 'deprecated' => false, 'expected' => [ - 'capability' => false, 'deprecated' => false, 'description' => 'MPAA rating', 'field' => 'content_rating', @@ -278,7 +266,8 @@ public function providerAnnotation(): array 'required' => true, 'sample_data' => 'G', 'type' => 'string', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false, 'visible' => false ] @@ -289,7 +278,6 @@ public function providerAnnotation(): array 'visible' => true, 'deprecated' => false, 'expected' => [ - 'capability' => false, 'deprecated' => false, 'description' => 'The page number to show.', 'field' => 'page', @@ -297,7 +285,8 @@ public function providerAnnotation(): array 'required' => false, 'sample_data' => false, 'type' => 'integer', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false, 'visible' => true ] @@ -311,7 +300,6 @@ public function providerAnnotation(): array 'visible' => true, 'deprecated' => false, 'expected' => [ - 'capability' => false, 'deprecated' => false, 'description' => 'Filter to apply to the results.', 'field' => 'filter', @@ -323,6 +311,28 @@ public function providerAnnotation(): array 'embeddable' => 'Embeddable', 'playable' => 'Playable' ], + 'vendor_tags' => [], + 'version' => false, + 'visible' => true + ] + ], + 'vendor-tag' => [ + 'content' => 'content_rating `G` (string, REQUIRED, tag:MOVIE_RATINGS) - MPAA rating', + 'version' => null, + 'visible' => true, + 'deprecated' => false, + 'expected' => [ + 'deprecated' => false, + 'description' => 'MPAA rating', + 'field' => 'content_rating', + 'nullable' => false, + 'required' => true, + 'sample_data' => 'G', + 'type' => 'string', + 'values' => [], + 'vendor_tags' => [ + 'tag:MOVIE_RATINGS' + ], 'version' => false, 'visible' => true ] @@ -333,7 +343,6 @@ public function providerAnnotation(): array 'visible' => true, 'deprecated' => false, 'expected' => [ - 'capability' => false, 'deprecated' => false, 'description' => 'MPAA rating', 'field' => 'content_rating', @@ -341,20 +350,20 @@ public function providerAnnotation(): array 'required' => false, 'sample_data' => 'G', 'type' => 'string', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => '1.1 - 1.2', 'visible' => true ] ], 'with-a-long-description' => [ - 'content' => 'content_rating `G` (string, required) - Voluptate culpa ex, eiusmod rump sint id. Venison - non ribeye landjaeger laboris, enim jowl culpa meatloaf dolore mollit anim. Bacon shankle eiusmod + 'content' => 'content_rating `G` (string, required) - Voluptate culpa ex, eiusmod rump sint id. Venison + non ribeye landjaeger laboris, enim jowl culpa meatloaf dolore mollit anim. Bacon shankle eiusmod hamburger enim. Laboris lorem pastrami t-bone tempor ullamco swine commodo tri-tip in sirloin.', 'version' => null, 'visible' => false, 'deprecated' => false, 'expected' => [ - 'capability' => false, 'deprecated' => false, 'description' => 'Voluptate culpa ex, eiusmod rump sint id. Venison non ribeye landjaeger ' . 'laboris, enim jowl culpa meatloaf dolore mollit anim. Bacon shankle eiusmod hamburger enim. ' . @@ -364,7 +373,8 @@ public function providerAnnotation(): array 'required' => true, 'sample_data' => 'G', 'type' => 'string', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false, 'visible' => false ] @@ -375,7 +385,6 @@ public function providerAnnotation(): array 'visible' => true, 'deprecated' => false, 'expected' => [ - 'capability' => false, 'deprecated' => false, 'description' => 'MPAA rating', 'field' => 'content_rating', @@ -383,18 +392,18 @@ public function providerAnnotation(): array 'required' => false, 'sample_data' => 'G', 'type' => 'string', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false, 'visible' => true ] ], - 'without-defined-requirement-but-capability' => [ - 'content' => 'content_rating `G` (string, MOVIE_RATINGS) - MPAA rating', + 'without-defined-requirement-but-vendor-tag' => [ + 'content' => 'content_rating `G` (string, tag:MOVIE_RATINGS) - MPAA rating', 'version' => null, 'visible' => true, 'deprecated' => false, 'expected' => [ - 'capability' => 'MOVIE_RATINGS', 'deprecated' => false, 'description' => 'MPAA rating', 'field' => 'content_rating', @@ -402,7 +411,10 @@ public function providerAnnotation(): array 'required' => false, 'sample_data' => 'G', 'type' => 'string', - 'values' => false, + 'values' => [], + 'vendor_tags' => [ + 'tag:MOVIE_RATINGS' + ], 'version' => false, 'visible' => true ] @@ -413,7 +425,6 @@ public function providerAnnotation(): array 'visible' => true, 'deprecated' => false, 'expected' => [ - 'capability' => false, 'deprecated' => false, 'description' => 'MPAA rating', 'field' => 'content_rating', @@ -421,7 +432,8 @@ public function providerAnnotation(): array 'required' => false, 'sample_data' => false, 'type' => 'string', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false, 'visible' => true ] diff --git a/tests/Parser/Annotations/ReturnAnnotationTest.php b/tests/Parser/Annotations/ReturnAnnotationTest.php index 6f56a5e..6c8fa29 100644 --- a/tests/Parser/Annotations/ReturnAnnotationTest.php +++ b/tests/Parser/Annotations/ReturnAnnotationTest.php @@ -47,17 +47,18 @@ public function testHydrate(string $content, bool $visible, $version, array $exp private function assertAnnotation(ReturnAnnotation $annotation, array $expected): void { - $this->assertTrue($annotation->requiresVisibilityDecorator()); - $this->assertTrue($annotation->supportsVersioning()); - $this->assertFalse($annotation->supportsDeprecation()); $this->assertFalse($annotation->supportsAliasing()); + $this->assertFalse($annotation->supportsDeprecation()); + $this->assertTrue($annotation->supportsVersioning()); + $this->assertFalse($annotation->supportsVendorTags()); + $this->assertTrue($annotation->requiresVisibilityDecorator()); $this->assertSame($expected, $annotation->toArray()); $this->assertSame($expected['description'], $annotation->getDescription()); $this->assertSame($expected['http_code'], $annotation->getHttpCode()); $this->assertSame($expected['representation'], $annotation->getRepresentation()); $this->assertSame($expected['type'], $annotation->getType()); - $this->assertFalse($annotation->getCapability()); + $this->assertEmpty($annotation->getVendorTags()); if ($expected['version']) { $this->assertInstanceOf(Version::class, $annotation->getVersion()); diff --git a/tests/Parser/Annotations/ScopeAnnotationTest.php b/tests/Parser/Annotations/ScopeAnnotationTest.php index 4600d1b..dec8c3b 100644 --- a/tests/Parser/Annotations/ScopeAnnotationTest.php +++ b/tests/Parser/Annotations/ScopeAnnotationTest.php @@ -40,15 +40,16 @@ public function testHydrate(string $content, array $expected): void private function assertAnnotation(ScopeAnnotation $annotation, array $expected): void { - $this->assertFalse($annotation->requiresVisibilityDecorator()); - $this->assertFalse($annotation->supportsVersioning()); - $this->assertFalse($annotation->supportsDeprecation()); $this->assertFalse($annotation->supportsAliasing()); + $this->assertFalse($annotation->supportsDeprecation()); + $this->assertFalse($annotation->supportsVersioning()); + $this->assertFalse($annotation->supportsVendorTags()); + $this->assertFalse($annotation->requiresVisibilityDecorator()); $this->assertSame($expected, $annotation->toArray()); $this->assertSame($expected['scope'], $annotation->getScope()); $this->assertSame($expected['description'], $annotation->getDescription()); - $this->assertFalse($annotation->getCapability()); + $this->assertEmpty($annotation->getVendorTags()); $this->assertFalse($annotation->getVersion()); $this->assertEmpty($annotation->getAliases()); } diff --git a/tests/Parser/Annotations/UriAnnotationTest.php b/tests/Parser/Annotations/UriAnnotationTest.php index e8a8de6..7175002 100644 --- a/tests/Parser/Annotations/UriAnnotationTest.php +++ b/tests/Parser/Annotations/UriAnnotationTest.php @@ -46,14 +46,15 @@ public function testHydrate(string $content, bool $visible, bool $deprecated, ar private function assertAnnotation(UriAnnotation $annotation, array $expected): void { - $this->assertTrue($annotation->requiresVisibilityDecorator()); - $this->assertFalse($annotation->supportsVersioning()); - $this->assertTrue($annotation->supportsDeprecation()); $this->assertTrue($annotation->supportsAliasing()); + $this->assertTrue($annotation->supportsDeprecation()); + $this->assertFalse($annotation->supportsVersioning()); + $this->assertFalse($annotation->supportsVendorTags()); + $this->assertTrue($annotation->requiresVisibilityDecorator()); $this->assertSame($expected['array'], $annotation->toArray()); $this->assertSame($expected['clean.path'], $annotation->getCleanPath()); - $this->assertFalse($annotation->getCapability()); + $this->assertEmpty($annotation->getVendorTags()); $this->assertFalse($annotation->getVersion()); $this->assertEmpty($annotation->getAliases()); } diff --git a/tests/Parser/Annotations/UriSegmentAnnotationTest.php b/tests/Parser/Annotations/UriSegmentAnnotationTest.php index 118c006..e6badef 100644 --- a/tests/Parser/Annotations/UriSegmentAnnotationTest.php +++ b/tests/Parser/Annotations/UriSegmentAnnotationTest.php @@ -44,17 +44,18 @@ public function testHydrate(string $uri, string $segment, array $expected): void private function assertAnnotation(UriSegmentAnnotation $annotation, array $expected): void { - $this->assertFalse($annotation->requiresVisibilityDecorator()); - $this->assertFalse($annotation->supportsVersioning()); - $this->assertFalse($annotation->supportsDeprecation()); $this->assertFalse($annotation->supportsAliasing()); + $this->assertFalse($annotation->supportsDeprecation()); + $this->assertFalse($annotation->supportsVersioning()); + $this->assertFalse($annotation->supportsVendorTags()); + $this->assertFalse($annotation->requiresVisibilityDecorator()); $this->assertSame($expected, $annotation->toArray()); $this->assertSame($expected['uri'], $annotation->getUri()); $this->assertSame($expected['field'], $annotation->getField()); $this->assertSame($expected['type'], $annotation->getType()); $this->assertSame($expected['description'], $annotation->getDescription()); - $this->assertFalse($annotation->getCapability()); + $this->assertEmpty($annotation->getVendorTags()); $this->assertFalse($annotation->getVersion()); $this->assertEmpty($annotation->getAliases()); } @@ -70,7 +71,7 @@ public function providerAnnotation(): array 'field' => 'id', 'type' => 'string', 'uri' => '/movies/+id', - 'values' => false + 'values' => [] ] ], '_complete' => [ diff --git a/tests/Parser/Annotations/CapabilityAnnotationTest.php b/tests/Parser/Annotations/VendorTagAnnotationTest.php similarity index 62% rename from tests/Parser/Annotations/CapabilityAnnotationTest.php rename to tests/Parser/Annotations/VendorTagAnnotationTest.php index 6155f6f..f7b0dad 100644 --- a/tests/Parser/Annotations/CapabilityAnnotationTest.php +++ b/tests/Parser/Annotations/VendorTagAnnotationTest.php @@ -1,11 +1,11 @@ process(); $this->assertAnnotation($annotation, $expected); @@ -27,7 +27,7 @@ public function testAnnotation(string $content, array $expected): void */ public function testHydrate(string $content, array $expected): void { - $annotation = CapabilityAnnotation::hydrate(array_merge( + $annotation = VendorTagAnnotation::hydrate(array_merge( $expected, [ 'class' => __CLASS__, @@ -38,15 +38,16 @@ public function testHydrate(string $content, array $expected): void $this->assertAnnotation($annotation, $expected); } - private function assertAnnotation(CapabilityAnnotation $annotation, array $expected): void + private function assertAnnotation(VendorTagAnnotation $annotation, array $expected): void { - $this->assertFalse($annotation->requiresVisibilityDecorator()); - $this->assertFalse($annotation->supportsVersioning()); - $this->assertFalse($annotation->supportsDeprecation()); $this->assertFalse($annotation->supportsAliasing()); + $this->assertFalse($annotation->supportsDeprecation()); + $this->assertFalse($annotation->supportsVersioning()); + $this->assertFalse($annotation->supportsVendorTags()); + $this->assertFalse($annotation->requiresVisibilityDecorator()); $this->assertSame($expected, $annotation->toArray()); - $this->assertSame($expected['capability'], $annotation->getCapability()); + $this->assertSame($expected['vendor_tag'], $annotation->getVendorTag()); $this->assertFalse($annotation->getVersion()); $this->assertEmpty($annotation->getAliases()); } @@ -55,9 +56,9 @@ public function providerAnnotation(): array { return [ '_complete' => [ - 'content' => 'BUY_TICKETS', + 'content' => 'tag:BUY_TICKETS', 'expected' => [ - 'capability' => 'BUY_TICKETS' + 'vendor_tag' => 'tag:BUY_TICKETS' ] ] ]; @@ -66,23 +67,23 @@ public function providerAnnotation(): array public function providerAnnotationFailsOnInvalidContent(): array { return [ - 'missing-capability' => [ - 'annotation' => CapabilityAnnotation::class, + 'missing-tag' => [ + 'annotation' => VendorTagAnnotation::class, 'content' => '', 'expected.exception' => MissingRequiredFieldException::class, 'expected.exception.asserts' => [ - 'getRequiredField' => 'capability', - 'getAnnotation' => 'capability', + 'getRequiredField' => 'vendor_tag', + 'getAnnotation' => 'vendortag', 'getDocblock' => '', 'getValues' => [] ] ], - 'capability-was-not-configured' => [ - 'annotation' => CapabilityAnnotation::class, - 'content' => 'UnconfiguredCapability', - 'expected.exception' => InvalidCapabilitySuppliedException::class, + 'tag-was-not-configured' => [ + 'annotation' => VendorTagAnnotation::class, + 'content' => 'tag:notConfigured', + 'expected.exception' => InvalidVendorTagSuppliedException::class, 'expected.exception.asserts' => [ - 'getCapability' => 'UnconfiguredCapability' + 'getVendorTag' => 'tag:notConfigured' ] ] ]; diff --git a/tests/Parser/MSONTest.php b/tests/Parser/MSONTest.php index 8da75a4..24941c5 100644 --- a/tests/Parser/MSONTest.php +++ b/tests/Parser/MSONTest.php @@ -39,13 +39,12 @@ public function providerTestParse(): array { return [ '_complete' => [ - 'content' => 'content_rating `G` (string, optional, MOVIE_RATINGS) - MPAA rating + 'content' => 'content_rating `G` (string, optional, tag:MOVIE_RATINGS, needs:validUser) - MPAA rating + Members - `G` - G rated - `PG` - PG rated - `PG-13` - PG-13 rated', 'expected' => [ - 'capability' => 'MOVIE_RATINGS', 'description' => 'MPAA rating', 'field' => 'content_rating', 'nullable' => false, @@ -57,13 +56,16 @@ public function providerTestParse(): array 'G' => 'G rated', 'PG' => 'PG rated', 'PG-13' => 'PG-13 rated' + ], + 'vendor_tags' => [ + 'tag:MOVIE_RATINGS', + 'needs:validUser' ] ] ], - 'capability' => [ - 'content' => 'content_rating `G` (string, REQUIRED, MOVIE_RATINGS) - MPAA rating', + 'vendor-tag' => [ + 'content' => 'content_rating `G` (string, REQUIRED, tag:MOVIE_RATINGS) - MPAA rating', 'expected' => [ - 'capability' => 'MOVIE_RATINGS', 'description' => 'MPAA rating', 'field' => 'content_rating', 'nullable' => false, @@ -71,7 +73,10 @@ public function providerTestParse(): array 'sample_data' => 'G', 'subtype' => false, 'type' => 'string', - 'values' => [] + 'values' => [], + 'vendor_tags' => [ + 'tag:MOVIE_RATINGS' + ] ] ], 'description-long' => [ @@ -79,7 +84,6 @@ public function providerTestParse(): array non ribeye landjaeger laboris, enim jowl culpa meatloaf dolore mollit anim. Bacon shankle eiusmod hamburger enim. Laboris lorem pastrami t-bone tempor ullamco swine commodo tri-tip in sirloin.', 'expected' => [ - 'capability' => false, 'description' => 'Voluptate culpa ex, eiusmod rump sint id. Venison non ribeye landjaeger ' . 'laboris, enim jowl culpa meatloaf dolore mollit anim. Bacon shankle eiusmod hamburger enim. ' . 'Laboris lorem pastrami t-bone tempor ullamco swine commodo tri-tip in sirloin.', @@ -89,18 +93,18 @@ public function providerTestParse(): array 'sample_data' => 'G', 'subtype' => false, 'type' => 'string', - 'values' => [] + 'values' => [], + 'vendor_tags' => [] ] ], 'description-markdown' => [ - 'content' => 'content_rating `G` (string, optional, nullable, MOVIE_RATINGS) - This denotes the + 'content' => 'content_rating `G` (string, optional, nullable, tag:MOVIE_RATINGS) - This denotes the [MPAA rating](http://www.mpaa.org/film-ratings/) for the movie. + Members - `G` - G rated - `PG` - PG rated - `PG-13` - PG-13 rated', 'expected' => [ - 'capability' => 'MOVIE_RATINGS', 'description' => 'This denotes the [MPAA rating](http://www.mpaa.org/film-ratings/) for the movie.', 'field' => 'content_rating', 'nullable' => true, @@ -112,6 +116,9 @@ public function providerTestParse(): array 'G' => 'G rated', 'PG' => 'PG rated', 'PG-13' => 'PG-13 rated' + ], + 'vendor_tags' => [ + 'tag:MOVIE_RATINGS' ] ] ], @@ -123,7 +130,6 @@ public function providerTestParse(): array - `PG` - PG rated - `PG-13` - PG-13 rated', 'expected' => [ - 'capability' => false, 'description' => 'MPAA Rating', 'field' => 'content_rating', 'nullable' => false, @@ -135,7 +141,8 @@ public function providerTestParse(): array 'G' => 'G rated', 'PG' => 'PG rated', 'PG-13' => 'PG-13 rated' - ] + ], + 'vendor_tags' => [] ] ], 'enum-without-descriptions' => [ @@ -144,7 +151,6 @@ public function providerTestParse(): array - `yes` - `no`', 'expected' => [ - 'capability' => false, 'description' => 'Is this movie kid friendly?', 'field' => 'is_kid_friendly', 'nullable' => false, @@ -155,7 +161,8 @@ public function providerTestParse(): array 'values' => [ 'no' => '', 'yes' => '' - ] + ], + 'vendor_tags' => [] ] ], 'enum-without-set-default' => [ @@ -170,7 +177,6 @@ public function providerTestParse(): array - `NR` - No rating - `UR` - Unrated', 'expected' => [ - 'capability' => false, 'description' => 'MPAA rating', 'field' => 'content_rating', 'nullable' => false, @@ -187,13 +193,13 @@ public function providerTestParse(): array 'R' => 'R rated', 'UR' => 'Unrated', 'X' => 'X-rated' - ] + ], + 'vendor_tags' => [] ] ], 'field-dot-notation' => [ 'content' => 'content.rating `G` (string) - MPAA rating', 'expected' => [ - 'capability' => false, 'description' => 'MPAA rating', 'field' => 'content.rating', 'nullable' => false, @@ -201,13 +207,13 @@ public function providerTestParse(): array 'sample_data' => 'G', 'subtype' => false, 'type' => 'string', - 'values' => [] + 'values' => [], + 'vendor_tags' => [] ] ], 'type-array-with-subtype-object' => [ 'content' => 'websites (array) - The users\' list of websites.', 'expected' => [ - 'capability' => false, 'description' => 'The users\' list of websites.', 'field' => 'websites', 'nullable' => false, @@ -215,13 +221,13 @@ public function providerTestParse(): array 'sample_data' => '', 'subtype' => 'object', 'type' => 'array', - 'values' => [] + 'values' => [], + 'vendor_tags' => [] ] ], 'type-array-with-subytpe-representation' => [ 'content' => 'cast (array<\Mill\Examples\Showtimes\Representations\Person>) - Cast members', 'expected' => [ - 'capability' => false, 'description' => 'Cast members', 'field' => 'cast', 'nullable' => false, @@ -229,13 +235,13 @@ public function providerTestParse(): array 'sample_data' => '', 'subtype' => '\Mill\Examples\Showtimes\Representations\Person', 'type' => 'array', - 'values' => [] + 'values' => [], + 'vendor_tags' => [] ] ], 'type-representation' => [ 'content' => 'director (\Mill\Examples\Showtimes\Representations\Person) - Director', 'expected' => [ - 'capability' => false, 'description' => 'Director', 'field' => 'director', 'nullable' => false, @@ -243,13 +249,13 @@ public function providerTestParse(): array 'sample_data' => '', 'subtype' => false, 'type' => '\Mill\Examples\Showtimes\Representations\Person', - 'values' => [] + 'values' => [], + 'vendor_tags' => [] ] ], - 'without-defined-requirement-but-capability' => [ - 'content' => 'content_rating `G` (string, MOVIE_RATINGS) - MPAA rating', + 'without-defined-requirement-but-vendor-tags' => [ + 'content' => 'content_rating `G` (string, tag:MOVIE_RATINGS) - MPAA rating', 'expected' => [ - 'capability' => 'MOVIE_RATINGS', 'description' => 'MPAA rating', 'field' => 'content_rating', 'nullable' => false, @@ -257,13 +263,15 @@ public function providerTestParse(): array 'sample_data' => 'G', 'subtype' => false, 'type' => 'string', - 'values' => [] + 'values' => [], + 'vendor_tags' => [ + 'tag:MOVIE_RATINGS' + ] ] ], 'without-sample-data' => [ 'content' => 'content_rating (string) - MPAA rating', 'expected' => [ - 'capability' => false, 'description' => 'MPAA rating', 'field' => 'content_rating', 'nullable' => false, @@ -271,7 +279,8 @@ public function providerTestParse(): array 'sample_data' => '', 'subtype' => false, 'type' => 'string', - 'values' => [] + 'values' => [], + 'vendor_tags' => [] ] ] ]; diff --git a/tests/Parser/Representation/DocumentationTest.php b/tests/Parser/Representation/DocumentationTest.php index 0c5d75c..9fcab3b 100644 --- a/tests/Parser/Representation/DocumentationTest.php +++ b/tests/Parser/Representation/DocumentationTest.php @@ -70,7 +70,6 @@ public function providerParseDocumentationReturnsRepresentation(): array 'description.length' => 41, 'content' => [ 'cast' => [ - 'capability' => false, 'description' => 'Cast', 'identifier' => 'cast', 'nullable' => false, @@ -83,11 +82,11 @@ public function providerParseDocumentationReturnsRepresentation(): array ], 'subtype' => '\Mill\Examples\Showtimes\Representations\Person', 'type' => 'array', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ], 'content_rating' => [ - 'capability' => false, 'description' => 'MPAA rating', 'identifier' => 'content_rating', 'nullable' => false, @@ -105,10 +104,10 @@ public function providerParseDocumentationReturnsRepresentation(): array 'UR' => '', 'X' => '' ], + 'vendor_tags' => [], 'version' => false ], 'description' => [ - 'capability' => false, 'description' => 'Description', 'identifier' => 'description', 'nullable' => false, @@ -116,11 +115,11 @@ public function providerParseDocumentationReturnsRepresentation(): array 'scopes' => [], 'subtype' => false, 'type' => 'string', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ], 'director' => [ - 'capability' => false, 'description' => 'Director', 'identifier' => 'director', 'nullable' => false, @@ -133,11 +132,11 @@ public function providerParseDocumentationReturnsRepresentation(): array ], 'subtype' => false, 'type' => '\Mill\Examples\Showtimes\Representations\Person', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ], 'external_urls' => [ - 'capability' => false, 'description' => 'External URLs', 'identifier' => 'external_urls', 'nullable' => false, @@ -145,11 +144,11 @@ public function providerParseDocumentationReturnsRepresentation(): array 'scopes' => [], 'subtype' => false, 'type' => 'object', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => '>=1.1' ], 'external_urls.imdb' => [ - 'capability' => false, 'description' => 'IMDB URL', 'identifier' => 'external_urls.imdb', 'nullable' => false, @@ -157,11 +156,11 @@ public function providerParseDocumentationReturnsRepresentation(): array 'scopes' => [], 'subtype' => false, 'type' => 'string', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => '>=1.1' ], 'external_urls.tickets' => [ - 'capability' => 'BUY_TICKETS', 'description' => 'Tickets URL', 'identifier' => 'external_urls.tickets', 'nullable' => false, @@ -169,11 +168,13 @@ public function providerParseDocumentationReturnsRepresentation(): array 'scopes' => [], 'subtype' => false, 'type' => 'string', - 'values' => false, + 'values' => [], + 'vendor_tags' => [ + 'tag:BUY_TICKETS' + ], 'version' => '>=1.1 <1.1.3' ], 'external_urls.trailer' => [ - 'capability' => false, 'description' => 'Trailer URL', 'identifier' => 'external_urls.trailer', 'nullable' => false, @@ -181,11 +182,11 @@ public function providerParseDocumentationReturnsRepresentation(): array 'scopes' => [], 'subtype' => false, 'type' => 'string', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => '>=1.1' ], 'genres' => [ - 'capability' => false, 'description' => 'Genres', 'identifier' => 'genres', 'nullable' => false, @@ -193,11 +194,11 @@ public function providerParseDocumentationReturnsRepresentation(): array 'scopes' => [], 'subtype' => false, 'type' => 'array', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ], 'id' => [ - 'capability' => false, 'description' => 'Unique ID', 'identifier' => 'id', 'nullable' => false, @@ -205,11 +206,11 @@ public function providerParseDocumentationReturnsRepresentation(): array 'scopes' => [], 'subtype' => false, 'type' => 'number', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ], 'kid_friendly' => [ - 'capability' => false, 'description' => 'Kid friendly?', 'identifier' => 'kid_friendly', 'nullable' => false, @@ -217,11 +218,11 @@ public function providerParseDocumentationReturnsRepresentation(): array 'scopes' => [], 'subtype' => false, 'type' => 'boolean', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ], 'name' => [ - 'capability' => false, 'description' => 'Name', 'identifier' => 'name', 'nullable' => false, @@ -229,11 +230,11 @@ public function providerParseDocumentationReturnsRepresentation(): array 'scopes' => [], 'subtype' => false, 'type' => 'string', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ], 'purchase.url' => [ - 'capability' => false, 'description' => 'URL to purchase the film.', 'identifier' => 'purchase.url', 'nullable' => false, @@ -241,11 +242,11 @@ public function providerParseDocumentationReturnsRepresentation(): array 'scopes' => [], 'subtype' => false, 'type' => 'string', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ], 'rotten_tomatoes_score' => [ - 'capability' => false, 'description' => 'Rotten Tomatoes score', 'identifier' => 'rotten_tomatoes_score', 'nullable' => false, @@ -253,11 +254,11 @@ public function providerParseDocumentationReturnsRepresentation(): array 'scopes' => [], 'subtype' => false, 'type' => 'number', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ], 'runtime' => [ - 'capability' => false, 'description' => 'Runtime', 'identifier' => 'runtime', 'nullable' => false, @@ -265,11 +266,11 @@ public function providerParseDocumentationReturnsRepresentation(): array 'scopes' => [], 'subtype' => false, 'type' => 'string', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ], 'showtimes' => [ - 'capability' => false, 'description' => 'Non-theater specific showtimes', 'identifier' => 'showtimes', 'nullable' => false, @@ -277,11 +278,11 @@ public function providerParseDocumentationReturnsRepresentation(): array 'scopes' => [], 'subtype' => false, 'type' => 'array', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ], 'theaters' => [ - 'capability' => false, 'description' => 'Theaters the movie is currently showing in', 'identifier' => 'theaters', 'nullable' => false, @@ -289,11 +290,11 @@ public function providerParseDocumentationReturnsRepresentation(): array 'scopes' => [], 'subtype' => '\Mill\Examples\Showtimes\Representations\Theater', 'type' => 'array', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ], 'uri' => [ - 'capability' => false, 'description' => 'Movie URI', 'identifier' => 'uri', 'nullable' => false, @@ -301,14 +302,14 @@ public function providerParseDocumentationReturnsRepresentation(): array 'scopes' => [], 'subtype' => false, 'type' => 'uri', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ] ], 'content.exploded' => [ 'cast' => [ '__FIELD_DATA__' => [ - 'capability' => false, 'description' => 'Cast', 'identifier' => 'cast', 'nullable' => false, @@ -321,13 +322,13 @@ public function providerParseDocumentationReturnsRepresentation(): array ], 'subtype' => '\Mill\Examples\Showtimes\Representations\Person', 'type' => 'array', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ] ], 'content_rating' => [ '__FIELD_DATA__' => [ - 'capability' => false, 'description' => 'MPAA rating', 'identifier' => 'content_rating', 'nullable' => false, @@ -345,12 +346,12 @@ public function providerParseDocumentationReturnsRepresentation(): array 'UR' => '', 'X' => '' ], + 'vendor_tags' => [], 'version' => false ] ], 'description' => [ '__FIELD_DATA__' => [ - 'capability' => false, 'description' => 'Description', 'identifier' => 'description', 'nullable' => false, @@ -358,13 +359,13 @@ public function providerParseDocumentationReturnsRepresentation(): array 'scopes' => [], 'subtype' => false, 'type' => 'string', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ] ], 'director' => [ '__FIELD_DATA__' => [ - 'capability' => false, 'description' => 'Director', 'identifier' => 'director', 'nullable' => false, @@ -377,13 +378,13 @@ public function providerParseDocumentationReturnsRepresentation(): array ], 'subtype' => false, 'type' => '\Mill\Examples\Showtimes\Representations\Person', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ] ], 'external_urls' => [ '__FIELD_DATA__' => [ - 'capability' => false, 'description' => 'External URLs', 'identifier' => 'external_urls', 'nullable' => false, @@ -391,12 +392,12 @@ public function providerParseDocumentationReturnsRepresentation(): array 'scopes' => [], 'subtype' => false, 'type' => 'object', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => '>=1.1' ], 'imdb' => [ '__FIELD_DATA__' => [ - 'capability' => false, 'description' => 'IMDB URL', 'identifier' => 'external_urls.imdb', 'nullable' => false, @@ -404,13 +405,13 @@ public function providerParseDocumentationReturnsRepresentation(): array 'scopes' => [], 'subtype' => false, 'type' => 'string', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => '>=1.1' ] ], 'tickets' => [ '__FIELD_DATA__' => [ - 'capability' => 'BUY_TICKETS', 'description' => 'Tickets URL', 'identifier' => 'external_urls.tickets', 'nullable' => false, @@ -418,13 +419,15 @@ public function providerParseDocumentationReturnsRepresentation(): array 'scopes' => [], 'subtype' => false, 'type' => 'string', - 'values' => false, + 'values' => [], + 'vendor_tags' => [ + 'tag:BUY_TICKETS' + ], 'version' => '>=1.1 <1.1.3' ] ], 'trailer' => [ '__FIELD_DATA__' => [ - 'capability' => false, 'description' => 'Trailer URL', 'identifier' => 'external_urls.trailer', 'nullable' => false, @@ -432,14 +435,14 @@ public function providerParseDocumentationReturnsRepresentation(): array 'scopes' => [], 'subtype' => false, 'type' => 'string', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => '>=1.1' ] ] ], 'genres' => [ '__FIELD_DATA__' => [ - 'capability' => false, 'description' => 'Genres', 'identifier' => 'genres', 'nullable' => false, @@ -447,13 +450,13 @@ public function providerParseDocumentationReturnsRepresentation(): array 'scopes' => [], 'subtype' => false, 'type' => 'array', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ] ], 'id' => [ '__FIELD_DATA__' => [ - 'capability' => false, 'description' => 'Unique ID', 'identifier' => 'id', 'nullable' => false, @@ -461,13 +464,13 @@ public function providerParseDocumentationReturnsRepresentation(): array 'scopes' => [], 'subtype' => false, 'type' => 'number', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ] ], 'kid_friendly' => [ '__FIELD_DATA__' => [ - 'capability' => false, 'description' => 'Kid friendly?', 'identifier' => 'kid_friendly', 'nullable' => false, @@ -475,13 +478,13 @@ public function providerParseDocumentationReturnsRepresentation(): array 'scopes' => [], 'subtype' => false, 'type' => 'boolean', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ] ], 'name' => [ '__FIELD_DATA__' => [ - 'capability' => false, 'description' => 'Name', 'identifier' => 'name', 'nullable' => false, @@ -489,14 +492,14 @@ public function providerParseDocumentationReturnsRepresentation(): array 'scopes' => [], 'subtype' => false, 'type' => 'string', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ] ], 'purchase' => [ 'url' => [ '__FIELD_DATA__' => [ - 'capability' => false, 'description' => 'URL to purchase the film.', 'identifier' => 'purchase.url', 'nullable' => false, @@ -504,14 +507,14 @@ public function providerParseDocumentationReturnsRepresentation(): array 'scopes' => [], 'subtype' => false, 'type' => 'string', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ] ] ], 'rotten_tomatoes_score' => [ '__FIELD_DATA__' => [ - 'capability' => false, 'description' => 'Rotten Tomatoes score', 'identifier' => 'rotten_tomatoes_score', 'nullable' => false, @@ -519,13 +522,13 @@ public function providerParseDocumentationReturnsRepresentation(): array 'scopes' => [], 'subtype' => false, 'type' => 'number', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ] ], 'runtime' => [ '__FIELD_DATA__' => [ - 'capability' => false, 'description' => 'Runtime', 'identifier' => 'runtime', 'nullable' => false, @@ -533,13 +536,13 @@ public function providerParseDocumentationReturnsRepresentation(): array 'scopes' => [], 'subtype' => false, 'type' => 'string', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ] ], 'showtimes' => [ '__FIELD_DATA__' => [ - 'capability' => false, 'description' => 'Non-theater specific showtimes', 'identifier' => 'showtimes', 'nullable' => false, @@ -547,13 +550,13 @@ public function providerParseDocumentationReturnsRepresentation(): array 'scopes' => [], 'subtype' => false, 'type' => 'array', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ] ], 'theaters' => [ '__FIELD_DATA__' => [ - 'capability' => false, 'description' => 'Theaters the movie is currently showing in', 'identifier' => 'theaters', 'nullable' => false, @@ -561,13 +564,13 @@ public function providerParseDocumentationReturnsRepresentation(): array 'scopes' => [], 'subtype' => '\Mill\Examples\Showtimes\Representations\Theater', 'type' => 'array', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ] ], 'uri' => [ '__FIELD_DATA__' => [ - 'capability' => false, 'description' => 'Movie URI', 'identifier' => 'uri', 'nullable' => false, @@ -575,7 +578,8 @@ public function providerParseDocumentationReturnsRepresentation(): array 'scopes' => [], 'subtype' => false, 'type' => 'uri', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ] ] diff --git a/tests/Parser/Representation/RepresentationParserTest.php b/tests/Parser/Representation/RepresentationParserTest.php index 1a3cddd..b895dd2 100644 --- a/tests/Parser/Representation/RepresentationParserTest.php +++ b/tests/Parser/Representation/RepresentationParserTest.php @@ -156,11 +156,11 @@ public function testRepresentationThatHasVersioningAcrossMultipleAnnotations(): return $annotation->toArray(); }, $annotations); - $this->assertEmpty($annotations['connections']['capability']); - $this->assertSame('FEATURE_FLAG', $annotations['connections.things']['capability']); - $this->assertSame('MOVIE_RATINGS', $annotations['connections.things.name']['capability']); - $this->assertSame('FEATURE_FLAG', $annotations['connections.things.uri']['capability']); - $this->assertEmpty($annotations['unrelated']['capability']); + $this->assertEmpty($annotations['connections']['vendor_tags']); + $this->assertSame(['tag:FEATURE_FLAG'], $annotations['connections.things']['vendor_tags']); + $this->assertSame(['tag:MOVIE_RATINGS'], $annotations['connections.things.name']['vendor_tags']); + $this->assertSame(['tag:FEATURE_FLAG'], $annotations['connections.things.uri']['vendor_tags']); + $this->assertEmpty($annotations['unrelated']['vendor_tags']); $this->assertSame('>=3.3', $annotations['connections']['version']); $this->assertSame('>=3.3', $annotations['connections.things']['version']); @@ -184,7 +184,6 @@ public function providerParseAnnotations(): array 'expected' => [ 'annotations' => [ 'cast' => [ - 'capability' => false, 'description' => 'Cast', 'identifier' => 'cast', 'nullable' => false, @@ -197,11 +196,11 @@ public function providerParseAnnotations(): array ], 'subtype' => '\Mill\Examples\Showtimes\Representations\Person', 'type' => 'array', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ], 'content_rating' => [ - 'capability' => false, 'description' => 'MPAA rating', 'identifier' => 'content_rating', 'nullable' => false, @@ -219,10 +218,10 @@ public function providerParseAnnotations(): array 'UR' => '', 'X' => '' ], + 'vendor_tags' => [], 'version' => false ], 'description' => [ - 'capability' => false, 'description' => 'Description', 'identifier' => 'description', 'nullable' => false, @@ -230,11 +229,11 @@ public function providerParseAnnotations(): array 'scopes' => [], 'subtype' => false, 'type' => 'string', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ], 'director' => [ - 'capability' => false, 'description' => 'Director', 'identifier' => 'director', 'nullable' => false, @@ -247,11 +246,11 @@ public function providerParseAnnotations(): array ], 'subtype' => false, 'type' => '\Mill\Examples\Showtimes\Representations\Person', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ], 'external_urls' => [ - 'capability' => false, 'description' => 'External URLs', 'identifier' => 'external_urls', 'nullable' => false, @@ -259,11 +258,11 @@ public function providerParseAnnotations(): array 'scopes' => [], 'subtype' => false, 'type' => 'object', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => '>=1.1' ], 'external_urls.imdb' => [ - 'capability' => false, 'description' => 'IMDB URL', 'identifier' => 'external_urls.imdb', 'nullable' => false, @@ -271,11 +270,11 @@ public function providerParseAnnotations(): array 'scopes' => [], 'subtype' => false, 'type' => 'string', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => '>=1.1' ], 'external_urls.tickets' => [ - 'capability' => 'BUY_TICKETS', 'description' => 'Tickets URL', 'identifier' => 'external_urls.tickets', 'nullable' => false, @@ -283,11 +282,13 @@ public function providerParseAnnotations(): array 'scopes' => [], 'subtype' => false, 'type' => 'string', - 'values' => false, + 'values' => [], + 'vendor_tags' => [ + 'tag:BUY_TICKETS' + ], 'version' => '>=1.1 <1.1.3' ], 'external_urls.trailer' => [ - 'capability' => false, 'description' => 'Trailer URL', 'identifier' => 'external_urls.trailer', 'nullable' => false, @@ -295,11 +296,11 @@ public function providerParseAnnotations(): array 'scopes' => [], 'subtype' => false, 'type' => 'string', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => '>=1.1' ], 'genres' => [ - 'capability' => false, 'description' => 'Genres', 'identifier' => 'genres', 'nullable' => false, @@ -307,11 +308,11 @@ public function providerParseAnnotations(): array 'scopes' => [], 'subtype' => false, 'type' => 'array', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ], 'id' => [ - 'capability' => false, 'description' => 'Unique ID', 'identifier' => 'id', 'nullable' => false, @@ -319,11 +320,11 @@ public function providerParseAnnotations(): array 'scopes' => [], 'subtype' => false, 'type' => 'number', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ], 'kid_friendly' => [ - 'capability' => false, 'description' => 'Kid friendly?', 'identifier' => 'kid_friendly', 'nullable' => false, @@ -331,11 +332,11 @@ public function providerParseAnnotations(): array 'scopes' => [], 'subtype' => false, 'type' => 'boolean', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ], 'name' => [ - 'capability' => false, 'description' => 'Name', 'identifier' => 'name', 'nullable' => false, @@ -343,11 +344,11 @@ public function providerParseAnnotations(): array 'scopes' => [], 'subtype' => false, 'type' => 'string', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ], 'purchase.url' => [ - 'capability' => false, 'description' => 'URL to purchase the film.', 'identifier' => 'purchase.url', 'nullable' => false, @@ -355,11 +356,11 @@ public function providerParseAnnotations(): array 'scopes' => [], 'subtype' => false, 'type' => 'string', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ], 'rotten_tomatoes_score' => [ - 'capability' => false, 'description' => 'Rotten Tomatoes score', 'identifier' => 'rotten_tomatoes_score', 'nullable' => false, @@ -367,11 +368,11 @@ public function providerParseAnnotations(): array 'scopes' => [], 'subtype' => false, 'type' => 'number', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ], 'runtime' => [ - 'capability' => false, 'description' => 'Runtime', 'identifier' => 'runtime', 'nullable' => false, @@ -379,11 +380,11 @@ public function providerParseAnnotations(): array 'scopes' => [], 'subtype' => false, 'type' => 'string', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ], 'showtimes' => [ - 'capability' => false, 'description' => 'Non-theater specific showtimes', 'identifier' => 'showtimes', 'nullable' => false, @@ -391,11 +392,11 @@ public function providerParseAnnotations(): array 'scopes' => [], 'subtype' => false, 'type' => 'array', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ], 'theaters' => [ - 'capability' => false, 'description' => 'Theaters the movie is currently showing in', 'identifier' => 'theaters', 'nullable' => false, @@ -403,11 +404,11 @@ public function providerParseAnnotations(): array 'scopes' => [], 'subtype' => '\Mill\Examples\Showtimes\Representations\Theater', 'type' => 'array', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ], 'uri' => [ - 'capability' => false, 'description' => 'Movie URI', 'identifier' => 'uri', 'nullable' => false, @@ -415,7 +416,8 @@ public function providerParseAnnotations(): array 'scopes' => [], 'subtype' => false, 'type' => 'uri', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false ] ] diff --git a/tests/Parser/Resource/Action/DocumentationTest.php b/tests/Parser/Resource/Action/DocumentationTest.php index 869cb6e..83526bc 100644 --- a/tests/Parser/Resource/Action/DocumentationTest.php +++ b/tests/Parser/Resource/Action/DocumentationTest.php @@ -64,7 +64,7 @@ private function assertMethodDocumentation( ); } - $this->assertCount($expected['capabilities.total'], $parser->getCapabilities()); + $this->assertCount($expected['vendor_tags.total'], $parser->getVendorTags()); /** @var \Mill\Parser\Annotations\MinVersionAnnotation $min_version */ $min_version = $parser->getMinimumVersion(); @@ -195,7 +195,7 @@ public function providerParseMethodDocumentation(): array 'expected' => [ 'label' => 'Get a single movie.', 'description' => $get_description, - 'capabilities.total' => 0, + 'vendor_tags.total' => 0, 'content_types.latest-version' => '1.1.2', 'content_types' => [ [ @@ -212,33 +212,52 @@ public function providerParseMethodDocumentation(): array 'annotations' => [ 'error' => [ [ - 'capability' => false, 'description' => 'If the movie could not be found.', 'error_code' => false, 'http_code' => '404 Not Found', 'representation' => '\Mill\Examples\Showtimes\Representations\Error', + 'vendor_tags' => [], 'version' => false, 'visible' => true ], [ - 'capability' => false, 'description' => 'For no reason.', 'error_code' => false, 'http_code' => '404 Not Found', 'representation' => '\Mill\Examples\Showtimes\Representations\Error', + 'vendor_tags' => [], 'version' => '>=1.1.3', 'visible' => true ], [ - 'capability' => false, 'description' => 'For some other reason.', 'error_code' => false, 'http_code' => '404 Not Found', 'representation' => '\Mill\Examples\Showtimes\Representations\Error', + 'vendor_tags' => [], 'version' => '>=1.1.3', 'visible' => true ] ], + 'return' => [ + [ + 'description' => false, + 'http_code' => '200 OK', + 'representation' => '\Mill\Examples\Showtimes\Representations\Movie', + 'type' => 'object', + 'version' => false, + 'visible' => true + ], + [ + 'description' => 'If no content has been modified since the supplied Last-Modified ' . + 'header.', + 'http_code' => '304 Not Modified', + 'representation' => false, + 'type' => 'notmodified', + 'version' => false, + 'visible' => true + ] + ], 'uri' => [ [ 'aliased' => true, @@ -272,33 +291,14 @@ public function providerParseMethodDocumentation(): array 'field' => 'id', 'type' => 'integer', 'uri' => '/movie/+id', - 'values' => false + 'values' => [] ], [ 'description' => 'Movie ID', 'field' => 'id', 'type' => 'integer', 'uri' => '/movies/+id', - 'values' => false - ] - ], - 'return' => [ - [ - 'description' => false, - 'http_code' => '200 OK', - 'representation' => '\Mill\Examples\Showtimes\Representations\Movie', - 'type' => 'object', - 'version' => false, - 'visible' => true - ], - [ - 'description' => 'If no content has been modified since the supplied Last-Modified ' . - 'header.', - 'http_code' => '304 Not Modified', - 'representation' => false, - 'type' => 'notmodified', - 'version' => false, - 'visible' => true + 'values' => [] ] ] ] @@ -309,7 +309,7 @@ public function providerParseMethodDocumentation(): array 'expected' => [ 'label' => 'Update a movie.', 'description' => 'Update a movies data.', - 'capabilities.total' => 0, + 'vendor_tags.total' => 0, 'content_types.latest-version' => '1.1.2', 'content_types' => [ [ @@ -327,79 +327,60 @@ public function providerParseMethodDocumentation(): array 'annotations' => [ 'error' => [ [ - 'capability' => false, 'description' => 'If there is a problem with the request.', 'error_code' => false, 'http_code' => '400 Bad Request', 'representation' => '\Mill\Examples\Showtimes\Representations\Error', + 'vendor_tags' => [], 'version' => false, 'visible' => true ], [ - 'capability' => false, 'description' => 'If the IMDB URL could not be validated.', 'error_code' => false, 'http_code' => '400 Bad Request', 'representation' => '\Mill\Examples\Showtimes\Representations\Error', + 'vendor_tags' => [], 'version' => false, 'visible' => true ], [ - 'capability' => false, 'description' => 'If the movie could not be found.', 'error_code' => false, 'http_code' => '404 Not Found', 'representation' => '\Mill\Examples\Showtimes\Representations\Error', + 'vendor_tags' => [], 'version' => false, 'visible' => true ], [ - 'capability' => false, 'description' => 'If the trailer URL could not be validated.', 'error_code' => false, 'http_code' => '404 Not Found', 'representation' => '\Mill\Examples\Showtimes\Representations\Error', + 'vendor_tags' => [], 'version' => '>=1.1.3', 'visible' => true ], [ - 'capability' => false, 'description' => 'If something cool happened.', 'error_code' => '1337', 'http_code' => '403 Forbidden', 'representation' => '\Mill\Examples\Showtimes\Representations\CodedError', + 'vendor_tags' => [], 'version' => '>=1.1.3', 'visible' => false ], [ - 'capability' => false, 'description' => 'If the user is not allowed to edit that movie.', 'error_code' => '666', 'http_code' => '403 Forbidden', 'representation' => '\Mill\Examples\Showtimes\Representations\CodedError', + 'vendor_tags' => [], 'version' => '>=1.1.3', 'visible' => true ] ], - 'uri' => [ - [ - 'aliased' => false, - 'aliases' => [], - 'deprecated' => false, - 'namespace' => 'Movies', - 'path' => '/movies/+id', - 'visible' => true - ] - ], - 'uriSegment' => [ - [ - 'description' => 'Movie ID', - 'field' => 'id', - 'type' => 'integer', - 'uri' => '/movies/+id', - 'values' => false - ] - ], 'minVersion' => [ [ 'minimum_version' => '1.1' @@ -407,7 +388,6 @@ public function providerParseMethodDocumentation(): array ], 'param' => [ 'cast' => [ - 'capability' => false, 'deprecated' => false, 'description' => 'Array of names of the cast.', 'field' => 'cast', @@ -415,12 +395,12 @@ public function providerParseMethodDocumentation(): array 'required' => false, 'sample_data' => false, 'type' => 'array', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false, 'visible' => true ], 'content_rating' => [ - 'capability' => false, 'deprecated' => false, 'description' => 'MPAA rating', 'field' => 'content_rating', @@ -438,11 +418,11 @@ public function providerParseMethodDocumentation(): array 'UR' => '', 'X' => '' ], + 'vendor_tags' => [], 'version' => false, 'visible' => true ], 'description' => [ - 'capability' => false, 'deprecated' => false, 'description' => 'Description, or tagline, for the movie.', 'field' => 'description', @@ -450,12 +430,12 @@ public function providerParseMethodDocumentation(): array 'required' => true, 'sample_data' => false, 'type' => 'string', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false, 'visible' => true ], 'director' => [ - 'capability' => false, 'deprecated' => false, 'description' => 'Name of the director.', 'field' => 'director', @@ -463,12 +443,12 @@ public function providerParseMethodDocumentation(): array 'required' => false, 'sample_data' => false, 'type' => 'string', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false, 'visible' => true ], 'is_kid_friendly' => [ - 'capability' => false, 'deprecated' => false, 'description' => 'Is this movie kid friendly?', 'field' => 'is_kid_friendly', @@ -476,12 +456,12 @@ public function providerParseMethodDocumentation(): array 'required' => false, 'sample_data' => false, 'type' => 'boolean', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false, 'visible' => true ], 'name' => [ - 'capability' => false, 'deprecated' => false, 'description' => 'Name of the movie.', 'field' => 'name', @@ -489,12 +469,12 @@ public function providerParseMethodDocumentation(): array 'required' => true, 'sample_data' => false, 'type' => 'string', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false, 'visible' => true ], 'genres' => [ - 'capability' => false, 'deprecated' => false, 'description' => 'Array of movie genres.', 'field' => 'genres', @@ -502,12 +482,12 @@ public function providerParseMethodDocumentation(): array 'required' => false, 'sample_data' => false, 'type' => 'array', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false, 'visible' => true ], 'imdb' => [ - 'capability' => false, 'deprecated' => false, 'description' => 'IMDB URL', 'field' => 'imdb', @@ -515,12 +495,12 @@ public function providerParseMethodDocumentation(): array 'required' => false, 'sample_data' => false, 'type' => 'string', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => '>=1.1.1', 'visible' => true ], 'rotten_tomatoes_score' => [ - 'capability' => false, 'deprecated' => false, 'description' => 'Rotten Tomatoes score', 'field' => 'rotten_tomatoes_score', @@ -528,12 +508,12 @@ public function providerParseMethodDocumentation(): array 'required' => false, 'sample_data' => false, 'type' => 'integer', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false, 'visible' => true ], 'runtime' => [ - 'capability' => false, 'deprecated' => false, 'description' => 'Movie runtime, in `HHhr MMmin` format.', 'field' => 'runtime', @@ -541,12 +521,12 @@ public function providerParseMethodDocumentation(): array 'required' => false, 'sample_data' => false, 'type' => 'string', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false, 'visible' => true ], 'trailer' => [ - 'capability' => false, 'deprecated' => false, 'description' => 'Trailer URL', 'field' => 'trailer', @@ -554,7 +534,8 @@ public function providerParseMethodDocumentation(): array 'required' => false, 'sample_data' => false, 'type' => 'string', - 'values' => false, + 'values' => [], + 'vendor_tags' => [], 'version' => false, 'visible' => true ] @@ -582,6 +563,25 @@ public function providerParseMethodDocumentation(): array 'description' => false, 'scope' => 'edit' ] + ], + 'uri' => [ + [ + 'aliased' => false, + 'aliases' => [], + 'deprecated' => false, + 'namespace' => 'Movies', + 'path' => '/movies/+id', + 'visible' => true + ] + ], + 'uriSegment' => [ + [ + 'description' => 'Movie ID', + 'field' => 'id', + 'type' => 'integer', + 'uri' => '/movies/+id', + 'values' => [] + ] ] ] ] @@ -591,7 +591,7 @@ public function providerParseMethodDocumentation(): array 'expected' => [ 'label' => 'Delete a movie.', 'description' => 'Delete a movie.', - 'capabilities.total' => 1, + 'vendor_tags.total' => 1, 'content_types.latest-version' => null, 'content_types' => [ [ @@ -603,46 +603,22 @@ public function providerParseMethodDocumentation(): array 'responses.length' => 2, 'uri.aliases' => [], 'annotations' => [ - 'capability' => [ - [ - 'capability' => 'DELETE_CONTENT' - ] - ], 'error' => [ [ - 'capability' => false, 'description' => 'If the movie could not be found.', 'error_code' => false, 'http_code' => '404 Not Found', 'representation' => '\Mill\Examples\Showtimes\Representations\Error', + 'vendor_tags' => [], 'version' => false, 'visible' => false ] ], - 'uri' => [ - [ - 'aliased' => false, - 'aliases' => [], - 'deprecated' => false, - 'namespace' => 'Movies', - 'path' => '/movies/+id', - 'visible' => false - ] - ], 'minVersion' => [ [ 'minimum_version' => '1.1' ] ], - 'uriSegment' => [ - [ - 'description' => 'Movie ID', - 'field' => 'id', - 'type' => 'integer', - 'uri' => '/movies/+id', - 'values' => false - ] - ], 'return' => [ [ 'description' => false, @@ -658,6 +634,30 @@ public function providerParseMethodDocumentation(): array 'description' => false, 'scope' => 'delete' ] + ], + 'uri' => [ + [ + 'aliased' => false, + 'aliases' => [], + 'deprecated' => false, + 'namespace' => 'Movies', + 'path' => '/movies/+id', + 'visible' => false + ] + ], + 'uriSegment' => [ + [ + 'description' => 'Movie ID', + 'field' => 'id', + 'type' => 'integer', + 'uri' => '/movies/+id', + 'values' => [] + ] + ], + 'vendorTag' => [ + [ + 'vendor_tag' => 'tag:DELETE_CONTENT' + ] ] ] ] @@ -759,17 +759,17 @@ public function providerParsingOfSpecificUseCases(): array * * @api-contentType application/json * @api-scope delete - * @api-capability DELETE_CONTENT + * @api-vendorTag tag:DELETE_CONTENT * * @api-return:private {deleted} */', 'asserts' => [ - 'getCapabilities' => [ + 'getVendorTags' => [ 'total' => 1, - 'annotation.name' => 'capability', + 'annotation.name' => 'vendorTag', 'data' => [ [ - 'capability' => 'DELETE_CONTENT' + 'vendor_tag' => 'tag:DELETE_CONTENT' ] ] ] diff --git a/tests/ParserTest.php b/tests/ParserTest.php index a2c12a5..781116e 100644 --- a/tests/ParserTest.php +++ b/tests/ParserTest.php @@ -175,10 +175,6 @@ public function providerParseAnnotationsOnClassMethod(): array 'DELETE' => [ 'method' => 'DELETE', 'expected' => [ - 'capability' => [ - 'class' => Parser\Annotations\CapabilityAnnotation::class, - 'count' => 1 - ], 'contentType' => [ 'class' => Parser\Annotations\ContentTypeAnnotation::class, 'count' => 1 @@ -214,6 +210,10 @@ public function providerParseAnnotationsOnClassMethod(): array 'uriSegment' => [ 'class' => Parser\Annotations\UriSegmentAnnotation::class, 'count' => 1 + ], + 'vendorTag' => [ + 'class' => Parser\Annotations\VendorTagAnnotation::class, + 'count' => 1 ] ] ] diff --git a/tests/_fixtures/Representations/RepresentationWithVersioningAcrossMultipleAnnotations.php b/tests/_fixtures/Representations/RepresentationWithVersioningAcrossMultipleAnnotations.php index 6ac38dc..094cf75 100644 --- a/tests/_fixtures/Representations/RepresentationWithVersioningAcrossMultipleAnnotations.php +++ b/tests/_fixtures/Representations/RepresentationWithVersioningAcrossMultipleAnnotations.php @@ -18,7 +18,7 @@ public function create(): void */ /** - * @api-data connections.things (object, FEATURE_FLAG) - Information about this thing. + * @api-data connections.things (object, tag:FEATURE_FLAG) - Information about this thing. * @api-scope public * @api-see self::someMethod connections.things */ @@ -32,7 +32,7 @@ public function someMethod(): void */ /** - * @api-data name (string, MOVIE_RATINGS) - Name of a thing. + * @api-data name (string, tag:MOVIE_RATINGS) - Name of a thing. */ } } diff --git a/tests/_fixtures/mill.test.xml b/tests/_fixtures/mill.test.xml index d8e2b3f..4c74113 100644 --- a/tests/_fixtures/mill.test.xml +++ b/tests/_fixtures/mill.test.xml @@ -60,12 +60,12 @@ - - - - - - + + + + + + page (integer, optional) - The page number to show. From d69a18db8f8913e79d7e24784ff8781cee97311a Mon Sep 17 00:00:00 2001 From: Jon Ursenbach Date: Sun, 1 Apr 2018 13:32:08 -0400 Subject: [PATCH 04/53] Making array annotation `arrayable` properties a constant. --- src/Parser/Annotation.php | 16 +++++------ .../Annotations/ContentTypeAnnotation.php | 13 +++------ src/Parser/Annotations/DataAnnotation.php | 25 +++++++---------- .../Annotations/DescriptionAnnotation.php | 13 +++------ src/Parser/Annotations/ErrorAnnotation.php | 19 +++++-------- src/Parser/Annotations/LabelAnnotation.php | 13 +++------ .../Annotations/MinVersionAnnotation.php | 13 +++------ src/Parser/Annotations/ParamAnnotation.php | 27 ++++++++----------- src/Parser/Annotations/ReturnAnnotation.php | 21 ++++++--------- src/Parser/Annotations/ScopeAnnotation.php | 15 ++++------- src/Parser/Annotations/UriAnnotation.php | 15 ++++------- .../Annotations/UriSegmentAnnotation.php | 21 ++++++--------- .../Annotations/VendorTagAnnotation.php | 13 +++------ 13 files changed, 82 insertions(+), 142 deletions(-) diff --git a/src/Parser/Annotation.php b/src/Parser/Annotation.php index 1834697..37770e9 100644 --- a/src/Parser/Annotation.php +++ b/src/Parser/Annotation.php @@ -62,6 +62,13 @@ abstract class Annotation */ const SUPPORTS_VERSIONING = false; + /** + * An array of items that should be included in an array representation of this annotation. + * + * @var array + */ + const ARRAYABLE = []; + /** * The raw annotation from the docblock. * @@ -139,13 +146,6 @@ abstract class Annotation */ protected $parsed_data = []; - /** - * An array of items that should be included in an array representation of this annotation. - * - * @var array - */ - protected $arrayable = []; - /** * @param string $doc * @param string $class @@ -409,7 +409,7 @@ public function supportsVersioning(): bool public function toArray(): array { $arr = []; - foreach ($this->arrayable as $var) { + foreach (static::ARRAYABLE as $var) { if ($this->{$var} instanceof Annotation) { $arr += $this->{$var}->toArray(); } else { diff --git a/src/Parser/Annotations/ContentTypeAnnotation.php b/src/Parser/Annotations/ContentTypeAnnotation.php index 0d832ae..e2c222c 100644 --- a/src/Parser/Annotations/ContentTypeAnnotation.php +++ b/src/Parser/Annotations/ContentTypeAnnotation.php @@ -12,18 +12,13 @@ class ContentTypeAnnotation extends Annotation { const SUPPORTS_VERSIONING = true; - /** @var string */ - protected $content_type; - - /** - * An array of items that should be included in an array representation of this annotation. - * - * @var array - */ - protected $arrayable = [ + const ARRAYABLE = [ 'content_type' ]; + /** @var string */ + protected $content_type; + /** * {@inheritdoc} */ diff --git a/src/Parser/Annotations/DataAnnotation.php b/src/Parser/Annotations/DataAnnotation.php index f40bc80..17513e5 100644 --- a/src/Parser/Annotations/DataAnnotation.php +++ b/src/Parser/Annotations/DataAnnotation.php @@ -18,6 +18,16 @@ class DataAnnotation extends Annotation const SUPPORTS_VENDOR_TAGS = true; const SUPPORTS_VERSIONING = true; + const ARRAYABLE = [ + 'description', + 'identifier', + 'nullable', + 'sample_data', + 'subtype', + 'type', + 'values' + ]; + /** * Identifier for this data. * @@ -67,21 +77,6 @@ class DataAnnotation extends Annotation */ protected $description; - /** - * An array of items that should be included in an array representation of this annotation. - * - * @var array - */ - protected $arrayable = [ - 'description', - 'identifier', - 'nullable', - 'sample_data', - 'subtype', - 'type', - 'values' - ]; - /** * {@inheritdoc} * @throws RestrictedFieldNameException If a restricted `@api-field` name is detected. diff --git a/src/Parser/Annotations/DescriptionAnnotation.php b/src/Parser/Annotations/DescriptionAnnotation.php index 72ea8d7..409fd9d 100644 --- a/src/Parser/Annotations/DescriptionAnnotation.php +++ b/src/Parser/Annotations/DescriptionAnnotation.php @@ -10,18 +10,13 @@ */ class DescriptionAnnotation extends Annotation { - /** @var string */ - protected $description; - - /** - * An array of items that should be included in an array representation of this annotation. - * - * @var array - */ - protected $arrayable = [ + const ARRAYABLE = [ 'description' ]; + /** @var string */ + protected $description; + /** * {@inheritdoc} */ diff --git a/src/Parser/Annotations/ErrorAnnotation.php b/src/Parser/Annotations/ErrorAnnotation.php index 94c7460..081ec22 100644 --- a/src/Parser/Annotations/ErrorAnnotation.php +++ b/src/Parser/Annotations/ErrorAnnotation.php @@ -27,6 +27,13 @@ class ErrorAnnotation extends Annotation const REGEX_ERROR_TYPE = '/{([\w\s]+)}/'; const REGEX_ERROR_SUB_TYPE = '/{([\w\s]+),([\w\s]+)}/'; + const ARRAYABLE = [ + 'description', + 'error_code', + 'http_code', + 'representation' + ]; + /** * Optional unique error code for the error that this exception handles. * @@ -41,18 +48,6 @@ class ErrorAnnotation extends Annotation */ protected $description; - /** - * An array of items that should be included in an array representation of this annotation. - * - * @var array - */ - protected $arrayable = [ - 'description', - 'error_code', - 'http_code', - 'representation' - ]; - /** * {@inheritdoc} * @throws UnknownReturnCodeException If a supplied HTTP code is invalid. diff --git a/src/Parser/Annotations/LabelAnnotation.php b/src/Parser/Annotations/LabelAnnotation.php index 0fd0354..ca90044 100644 --- a/src/Parser/Annotations/LabelAnnotation.php +++ b/src/Parser/Annotations/LabelAnnotation.php @@ -10,18 +10,13 @@ */ class LabelAnnotation extends Annotation { - /** @var string */ - protected $label; - - /** - * An array of items that should be included in an array representation of this annotation. - * - * @var array - */ - protected $arrayable = [ + const ARRAYABLE = [ 'label' ]; + /** @var string */ + protected $label; + /** * {@inheritdoc} */ diff --git a/src/Parser/Annotations/MinVersionAnnotation.php b/src/Parser/Annotations/MinVersionAnnotation.php index 65c86d1..804d620 100644 --- a/src/Parser/Annotations/MinVersionAnnotation.php +++ b/src/Parser/Annotations/MinVersionAnnotation.php @@ -17,18 +17,13 @@ */ class MinVersionAnnotation extends Annotation { - /** @var string */ - protected $minimum_version; - - /** - * An array of items that should be included in an array representation of this annotation. - * - * @var array - */ - protected $arrayable = [ + const ARRAYABLE = [ 'minimum_version' ]; + /** @var string */ + protected $minimum_version; + /** * {@inheritdoc} * @throws AbsoluteMinimumVersionException If an `@api-minVersion` annotation version is not absolute. diff --git a/src/Parser/Annotations/ParamAnnotation.php b/src/Parser/Annotations/ParamAnnotation.php index 2d484c3..ee9c122 100644 --- a/src/Parser/Annotations/ParamAnnotation.php +++ b/src/Parser/Annotations/ParamAnnotation.php @@ -19,6 +19,17 @@ class ParamAnnotation extends Annotation const SUPPORTS_VENDOR_TAGS = true; const SUPPORTS_VERSIONING = true; + const ARRAYABLE = [ + 'description', + 'field', + 'nullable', + 'required', + 'sample_data', + 'type', + 'values', + 'visible' + ]; + /** * Name of this parameter's field. * @@ -68,22 +79,6 @@ class ParamAnnotation extends Annotation */ protected $values = []; - /** - * An array of items that should be included in an array representation of this annotation. - * - * @var array - */ - protected $arrayable = [ - 'description', - 'field', - 'nullable', - 'required', - 'sample_data', - 'type', - 'values', - 'visible' - ]; - /** * {@inheritdoc} * @throws UnsupportedTypeException If an unsupported parameter type has been supplied. diff --git a/src/Parser/Annotations/ReturnAnnotation.php b/src/Parser/Annotations/ReturnAnnotation.php index 65cd762..b36d358 100644 --- a/src/Parser/Annotations/ReturnAnnotation.php +++ b/src/Parser/Annotations/ReturnAnnotation.php @@ -22,6 +22,14 @@ class ReturnAnnotation extends Annotation const REGEX_TYPE = '/^({[^}]*})/'; + const ARRAYABLE = [ + 'description', + 'http_code', + 'representation', + 'type', + 'visible' + ]; + /** * Description for what this annotations' action return is. * @@ -36,19 +44,6 @@ class ReturnAnnotation extends Annotation */ protected $type; - /** - * An array of items that should be included in an array representation of this annotation. - * - * @var array - */ - protected $arrayable = [ - 'description', - 'http_code', - 'representation', - 'type', - 'visible' - ]; - /** * {@inheritdoc} * @throws UnknownRepresentationException If a supplied representation has not been configured. diff --git a/src/Parser/Annotations/ScopeAnnotation.php b/src/Parser/Annotations/ScopeAnnotation.php index 5604040..08211b1 100644 --- a/src/Parser/Annotations/ScopeAnnotation.php +++ b/src/Parser/Annotations/ScopeAnnotation.php @@ -12,6 +12,11 @@ */ class ScopeAnnotation extends Annotation { + const ARRAYABLE = [ + 'description', + 'scope' + ]; + /** @var string */ protected $scope; @@ -22,16 +27,6 @@ class ScopeAnnotation extends Annotation */ protected $description = null; - /** - * An array of items that should be included in an array representation of this annotation. - * - * @var array - */ - protected $arrayable = [ - 'description', - 'scope' - ]; - /** * {@inheritdoc} * @throws InvalidScopeSuppliedException If a supplied scope isn't present in the config file. diff --git a/src/Parser/Annotations/UriAnnotation.php b/src/Parser/Annotations/UriAnnotation.php index cbc7e3e..70b93ff 100644 --- a/src/Parser/Annotations/UriAnnotation.php +++ b/src/Parser/Annotations/UriAnnotation.php @@ -17,6 +17,11 @@ class UriAnnotation extends Annotation const NAMESPACE_REGEX = '/{([\w\/\\\ ]+)}/'; + const ARRAYABLE = [ + 'namespace', + 'path' + ]; + /** * Namespace that this URI belongs to. * @@ -31,16 +36,6 @@ class UriAnnotation extends Annotation */ protected $path; - /** - * An array of items that should be included in an array representation of this annotation. - * - * @var array - */ - protected $arrayable = [ - 'namespace', - 'path' - ]; - /** * {@inheritdoc} */ diff --git a/src/Parser/Annotations/UriSegmentAnnotation.php b/src/Parser/Annotations/UriSegmentAnnotation.php index 82d2c81..d94997a 100644 --- a/src/Parser/Annotations/UriSegmentAnnotation.php +++ b/src/Parser/Annotations/UriSegmentAnnotation.php @@ -15,6 +15,14 @@ class UriSegmentAnnotation extends Annotation const REGEX_URI = '/^({[^}]*})/'; + const ARRAYABLE = [ + 'description', + 'field', + 'type', + 'uri', + 'values' + ]; + /** * URI that this segment is for. * @@ -50,19 +58,6 @@ class UriSegmentAnnotation extends Annotation */ protected $values = []; - /** - * An array of items that should be included in an array representation of this annotation. - * - * @var array - */ - protected $arrayable = [ - 'description', - 'field', - 'type', - 'uri', - 'values' - ]; - /** * {@inheritdoc} */ diff --git a/src/Parser/Annotations/VendorTagAnnotation.php b/src/Parser/Annotations/VendorTagAnnotation.php index 53523ed..3f75957 100644 --- a/src/Parser/Annotations/VendorTagAnnotation.php +++ b/src/Parser/Annotations/VendorTagAnnotation.php @@ -12,6 +12,10 @@ */ class VendorTagAnnotation extends Annotation { + const ARRAYABLE = [ + 'vendor_tag' + ]; + /** * Name of this vendor tag. * @@ -19,15 +23,6 @@ class VendorTagAnnotation extends Annotation */ protected $vendor_tag; - /** - * An array of items that should be included in an array representation of this annotation. - * - * @var array - */ - protected $arrayable = [ - 'vendor_tag' - ]; - /** * {@inheritdoc} * @throws InvalidVendorTagSuppliedException If a found vendor tag is not present in your config file. From 025681576776e2122b31e7179dbc7b6e9bd9d2e4 Mon Sep 17 00:00:00 2001 From: Jon Ursenbach Date: Sun, 1 Apr 2018 17:59:04 -0400 Subject: [PATCH 05/53] Simplifying `@api-uri` annotations by splitting the namespace into `@api-group`. --- config.xsd | 2 +- docs/_layouts/default.html | 1 + docs/configuration.md | 8 +- docs/generate/changelogs.md | 2 +- docs/getting-started.md | 3 +- docs/reference.md | 1 + docs/reference/actions.md | 1 + docs/reference/api-group.md | 45 ++++ docs/reference/api-minversion.md | 5 +- docs/reference/api-scope.md | 5 +- docs/reference/api-uri.md | 7 +- docs/reference/deprecation.md | 5 +- docs/reference/uri-segment.md | 2 +- docs/reference/visibility.md | 7 +- .../examples/Showtimes/Controllers/Movie.php | 11 +- .../examples/Showtimes/Controllers/Movies.php | 6 +- .../Showtimes/Controllers/Theater.php | 9 +- .../Showtimes/Controllers/Theaters.php | 6 +- src/Command/Generate.php | 8 +- src/Config.php | 42 ++-- src/Generator.php | 32 +-- src/Generator/Blueprint.php | 14 +- src/Generator/Changelog.php | 45 ++-- src/Generator/Changelog/Changesets/Action.php | 2 +- .../Changelog/Changesets/ActionError.php | 2 +- .../Changelog/Changesets/ActionParam.php | 4 +- .../Changelog/Changesets/ActionReturn.php | 2 +- src/Generator/Changelog/Formats/Json.php | 14 +- src/Generator/ErrorMap.php | 22 +- src/Generator/ErrorMap/Formats/Markdown.php | 6 +- src/Generator/Traits/ChangelogTemplate.php | 2 +- src/Parser/Annotations/GroupAnnotation.php | 67 ++++++ src/Parser/Annotations/UriAnnotation.php | 45 +--- src/Parser/Resource/Action/Documentation.php | 135 ++++++----- tests/ConfigTest.php | 8 +- tests/Generator/BlueprintTest.php | 4 +- .../Generator/Changelog/Formats/JsonTest.php | 218 +++++++++--------- tests/Generator/ChangelogTest.php | 50 ++-- .../Annotations/GroupAnnotationTest.php | 82 +++++++ .../Parser/Annotations/UriAnnotationTest.php | 58 +---- .../Resource/Action/DocumentationTest.php | 48 ++-- tests/ParserTest.php | 17 +- tests/_fixtures/mill.test.xml | 4 +- 43 files changed, 611 insertions(+), 446 deletions(-) create mode 100644 docs/reference/api-group.md create mode 100644 src/Parser/Annotations/GroupAnnotation.php create mode 100644 tests/Parser/Annotations/GroupAnnotationTest.php diff --git a/config.xsd b/config.xsd index 9e13858..0146010 100644 --- a/config.xsd +++ b/config.xsd @@ -53,7 +53,7 @@ - + diff --git a/docs/_layouts/default.html b/docs/_layouts/default.html index 344c32d..1696833 100644 --- a/docs/_layouts/default.html +++ b/docs/_layouts/default.html @@ -38,6 +38,7 @@