Skip to content

Commit

Permalink
Merge branch 'master' into 2212-type-info
Browse files Browse the repository at this point in the history
# Conflicts:
#	src/ModelDescriber/ObjectModelDescriber.php
#	tests/Functional/Fixtures/MapQueryStringController.json
#	tests/Functional/Fixtures/MapRequestPayloadController.json
  • Loading branch information
DjordyKoert committed Oct 17, 2024
2 parents 7eaa240 + 9587aa7 commit f19b9b5
Show file tree
Hide file tree
Showing 29 changed files with 319 additions and 7,361 deletions.
12 changes: 11 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@
## 4.30.0
* Create top level OpenApi Tag from Tags top level annotations/attributes

## 4.25.3

* Calling `DocumentationExtension::getExtendedType()` has been deprecated in favor of `DocumentationExtension::getExtendedTypes()` to align with the deprecation introduced with `symfony/symfony` version `4.2`.


## 4.26.0

* Add ability to configure UI through configuration
Expand Down Expand Up @@ -149,6 +154,11 @@ doc-api:
* Added Redocly as an alternative to Swagger UI. https://github.com/Redocly/redoc.
* Added support for describing dictionary types in OpenAPI 3.0.

## 4.17.0

* Passing groups to `PropertyDescriberInterface::describe()` via the `$groups` parameter is deprecated, the parameter will get removed in a future version. Pass groups via `$context['groups']` instead.


## 4.0.0

* Added support of OpenAPI 3.0. The internals were completely reworked and this version introduces BC breaks.
Expand All @@ -175,7 +185,7 @@ doc-api:

* Add a documentation form extension. Use the ``documentation`` option to define how a form field is documented.
* Allow references to config definitions in controllers.
* Using `@Model` implicitely in `@SWG\Schema`, `@SWG\Items` and `@SWG\Property` is deprecated. Use `ref=@Model()` instead.
* Using `@Model` implicitly in `@SWG\Schema`, `@SWG\Items` and `@SWG\Property` is deprecated. Use `ref=@Model()` instead.

Before:
```php
Expand Down
6 changes: 3 additions & 3 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ It generates an OpenAPI documentation from your Symfony app thanks to
routes, etc.

If you configured the ``app.swagger_ui`` route above, you can browse your
documentation at `http://example.org/api/doc`.
documentation at ``http://example.org/api/doc``.

Using the bundle
----------------
Expand Down Expand Up @@ -350,7 +350,7 @@ properties and validator constraints. Take the model class below:
}
The ``NotBlank`` constraint will apply only to the ``default`` and ``create``
group, but not ``update``. In more practical terms: the `username` property
group, but not ``update``. In more practical terms: the ``username`` property
would show as ``required`` for both model create and default, but not update.
When using code generators to build API clients, this often translates into
client side validation and types. ``NotBlank`` adding ``required`` will cause
Expand Down Expand Up @@ -509,7 +509,7 @@ General PHP objects
nelmio_api_doc:
models: { use_jms: false }
Alternatively, it is also possible to opt out of JMS serializer usage per endpoint by setting `useJms` in the serializationContext:
Alternatively, it is also possible to opt out of JMS serializer usage per endpoint by setting ``useJms`` in the serializationContext:

.. configuration-block::

Expand Down
2 changes: 1 addition & 1 deletion docs/symfony_attributes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -197,4 +197,4 @@ Make sure to use at least php 8.1 (attribute support) to make use of this functi
.. _`Symfony MapQueryString`: https://symfony.com/doc/current/controller.html#mapping-the-whole-query-string
.. _`Symfony MapQueryParameter`: https://symfony.com/doc/current/controller.html#mapping-query-parameters-individually
.. _`Symfony MapRequestPayload`: https://symfony.com/doc/current/controller.html#mapping-request-payload
.. _`RouteArgumentDescriberInterface`: https://github.com/DjordyKoert/NelmioApiDocBundle/blob/master/RouteDescriber/RouteArgumentDescriber/RouteArgumentDescriberInterface.php
.. _`RouteArgumentDescriberInterface`: https://github.com/DjordyKoert/NelmioApiDocBundle/blob/master/src/RouteDescriber/RouteArgumentDescriber/RouteArgumentDescriberInterface.php
7,317 changes: 0 additions & 7,317 deletions phpunit-baseline.json

This file was deleted.

2 changes: 2 additions & 0 deletions phpunit-ignore.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Ignoring deprecations from Nelmio\ApiDocBundle 4.17.0
/^Since nelmio\/api-doc-bundle 4\.17\.0: Using the \$groups parameter of "Nelmio\\ApiDocBundle\\PropertyDescriber\\(PropertyDescriber|IntegerPropertyDescriber|NullablePropertyDescriber|StringPropertyDescriber|ObjectPropertyDescriber)::describe\(\)" is deprecated/
2 changes: 1 addition & 1 deletion phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<ini name="memory_limit" value="512M" />

<!-- add "generateBaseline=true&amp;" to the value to generate a new baseline. Keep in mind to clear the test cache before. -->
<env name="SYMFONY_DEPRECATIONS_HELPER" value="baselineFile=./phpunit-baseline.json&amp;max[self]=0" />
<env name="SYMFONY_DEPRECATIONS_HELPER" value="ignoreFile=./phpunit-ignore.txt&amp;max[self]=0" />
</php>

<testsuites>
Expand Down
42 changes: 34 additions & 8 deletions public/init-swagger-ui.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,26 +25,52 @@ function loadSwaggerUI(userOptions = {}) {

const storageKey = 'nelmio_api_auth';

// if we have auth in storage use it
if (sessionStorage.getItem(storageKey)) {
try {
ui.authActions.authorize(JSON.parse(sessionStorage.getItem(storageKey)));
} catch (ignored) {
// catch any errors here so it does not stop script execution
function getAuthorizationsFromStorage() {
if (sessionStorage.getItem(storageKey)) {
try {
return JSON.parse(sessionStorage.getItem(storageKey));
} catch (ignored) {
// catch any errors here so it does not stop script execution
}
}

return {};
}

// if we have auth in storage use it
try {
const currentAuthorizations = getAuthorizationsFromStorage();
Object.keys(currentAuthorizations).forEach(k => ui.authActions.authorize({[k]: currentAuthorizations[k]}));
} catch (ignored) {
// catch any errors here so it does not stop script execution
}

// hook into authorize to store the auth in local storage when user performs authorization
const currentAuthorize = ui.authActions.authorize;
ui.authActions.authorize = function (payload) {
sessionStorage.setItem(storageKey, JSON.stringify(payload));
try {
sessionStorage.setItem(storageKey, JSON.stringify(Object.assign(
getAuthorizationsFromStorage(),
payload
)));
} catch (ignored) {
// catch any errors here so it does not stop script execution
}

return currentAuthorize(payload);
};

// hook into logout to clear auth from storage if user logs out
const currentLogout = ui.authActions.logout;
ui.authActions.logout = function (payload) {
sessionStorage.removeItem(storageKey);
try {
let currentAuth = getAuthorizationsFromStorage();
payload.forEach(k => delete currentAuth[k]);
sessionStorage.setItem(storageKey, JSON.stringify(currentAuth));
} catch (ignored) {
// catch any errors here so it does not stop script execution
}

return currentLogout(payload);
};

Expand Down
12 changes: 0 additions & 12 deletions src/DependencyInjection/NelmioApiDocExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -278,18 +278,6 @@ public function load(array $configs, ContainerBuilder $container): void

// Import the base configuration
$container->getDefinition('nelmio_api_doc.describers.config')->replaceArgument(0, $config['documentation']);

// Compatibility Symfony
$controllerNameConverter = null;
if ($container->hasDefinition('.legacy_controller_name_converter')) { // 4.4
$controllerNameConverter = $container->getDefinition('.legacy_controller_name_converter');
} elseif ($container->hasDefinition('controller_name_converter')) { // < 4.4
$controllerNameConverter = $container->getDefinition('controller_name_converter');
}

if (null !== $controllerNameConverter) {
$container->getDefinition('nelmio_api_doc.controller_reflector')->setArgument(1, $controllerNameConverter);
}
}

/**
Expand Down
7 changes: 7 additions & 0 deletions src/Exception/UndocumentedArrayItemsException.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@

namespace Nelmio\ApiDocBundle\Exception;

trigger_deprecation(
'nelmio/api-doc-bundle',
'4.17.0',
'The "%s" class is deprecated and will be removed in a future version',
UndocumentedArrayItemsException::class,
);

/**
* @deprecated since 4.17, this exception is not used anymore
*/
Expand Down
8 changes: 8 additions & 0 deletions src/Form/Extension/DocumentationExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ public function configureOptions(OptionsResolver $resolver): void
*/
public function getExtendedType()
{
trigger_deprecation(
'nelmio/api-doc-bundle',
'4.28.1',
'Calling %s is deprecated since Symfony 4.2, call %s instead',
__METHOD__,
'DocumentationExtension::getExtendedTypes()',
);

return self::getExtendedTypes()[0];
}

Expand Down
9 changes: 6 additions & 3 deletions src/ModelDescriber/Annotations/AnnotationsReader.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,12 @@ public function updateProperty($reflection, OA\Property $property, ?array $seria
}

/**
* if an objects schema type and ref are undefined OR the object was manually
* defined as an object, then we're good to do the normal describe flow of
* class properties.
* Whether the model describer should continue reading class properties
* after updating the open api schema from an `OA\Schema` definition.
*
* Users may manually define a `type` or `ref` on a schema, and if that's the case
* model describers should _probably_ not describe any additional properties or try
* to merge in properties.
*/
private function shouldDescribeModelProperties(OA\Schema $schema): bool
{
Expand Down
4 changes: 0 additions & 4 deletions src/ModelDescriber/FormModelDescriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
use OpenApi\Analysis;
use OpenApi\Annotations as OA;
use OpenApi\Generator;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\FormType;
use Symfony\Component\Form\FormConfigInterface;
use Symfony\Component\Form\FormFactoryInterface;
Expand Down Expand Up @@ -74,9 +73,6 @@ public function __construct(

public function describe(Model $model, OA\Schema $schema): void
{
if (method_exists(AbstractType::class, 'setDefaultOptions')) {
throw new \LogicException('symfony/form < 3.0 is not supported, please upgrade to an higher version to use a form as a model.');
}
if (null === $this->formFactory) {
throw new \LogicException('You need to enable forms in your application to use a form as a model.');
}
Expand Down
21 changes: 17 additions & 4 deletions src/ModelDescriber/ObjectModelDescriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,8 @@ public function describe(Model $model, OA\Schema $schema)

$this->describeProperty($types, $model, $property, $propertyName, $schema);
}
}
$this->markRequiredProperties($schema);
}

$this->markRequiredProperties($schema);
}
Expand Down Expand Up @@ -260,21 +261,33 @@ private function describeProperty(array $types, Model $model, OA\Schema $propert
throw new \Exception(sprintf('Type "%s" is not supported in %s::$%s. You may use the `@OA\Property(type="")` annotation to specify it manually.', $types[0]->getBuiltinType(), $model->getType()->getClassName(), $propertyName));
}

/**
* Mark properties as required while ordering them in the same order as the properties of the schema.
* Then append the original required properties.
*/
private function markRequiredProperties(OA\Schema $schema): void
{
if (Generator::isDefault($properties = $schema->properties)) {
return;
}

$newRequired = [];
foreach ($properties as $property) {
if (is_array($schema->required) && \in_array($property->property, $schema->required, true)) {
$newRequired[] = $property->property;
continue;
}

if (true === $property->nullable || !Generator::isDefault($property->default)) {
continue;
}
$newRequired[] = $property->property;
}

$existingRequiredFields = Generator::UNDEFINED !== $schema->required ? $schema->required : [];
$existingRequiredFields[] = $property->property;
if ([] !== $newRequired) {
$originalRequired = Generator::isDefault($schema->required) ? [] : $schema->required;

$schema->required = array_values(array_unique($existingRequiredFields));
$schema->required = array_values(array_unique(array_merge($newRequired, $originalRequired)));
}
}

Expand Down
18 changes: 18 additions & 0 deletions src/PropertyDescriber/ArrayPropertyDescriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,24 @@ class ArrayPropertyDescriber implements PropertyDescriberInterface, ModelRegistr
*/
public function describe(array $types, OA\Schema $property, ?array $groups = null, ?OA\Schema $schema = null, array $context = [])
{
if (null === $schema) {
trigger_deprecation(
'nelmio/api-doc-bundle',
'4.15.0',
'"%s()" will have a new "OA\Schema $schema" argument in a future version. Not defining it or passing null is deprecated',
__METHOD__
);
}

if (null !== $groups) {
trigger_deprecation(
'nelmio/api-doc-bundle',
'4.17.0',
'Using the $groups parameter of "%s()" is deprecated and will be removed in a future version. Pass groups via $context[\'groups\']',
__METHOD__
);
}

$property->type = 'array';
/** @var OA\Items $property */
$property = Util::getChild($property, OA\Items::class);
Expand Down
18 changes: 18 additions & 0 deletions src/PropertyDescriber/BooleanPropertyDescriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,24 @@ class BooleanPropertyDescriber implements PropertyDescriberInterface
*/
public function describe(array $types, OA\Schema $property, ?array $groups = null, ?OA\Schema $schema = null, array $context = [])
{
if (null === $schema) {
trigger_deprecation(
'nelmio/api-doc-bundle',
'4.15.0',
'"%s()" will have a new "OA\Schema $schema" argument in a future version. Not defining it or passing null is deprecated',
__METHOD__
);
}

if (null !== $groups) {
trigger_deprecation(
'nelmio/api-doc-bundle',
'4.17.0',
'Using the $groups parameter of "%s()" is deprecated and will be removed in a future version. Pass groups via $context[\'groups\']',
__METHOD__
);
}

$property->type = 'boolean';
}

Expand Down
18 changes: 18 additions & 0 deletions src/PropertyDescriber/CompoundPropertyDescriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,24 @@ class CompoundPropertyDescriber implements PropertyDescriberInterface, ModelRegi
*/
public function describe(array $types, OA\Schema $property, ?array $groups = null, ?OA\Schema $schema = null, array $context = [])
{
if (null === $schema) {
trigger_deprecation(
'nelmio/api-doc-bundle',
'4.15.0',
'"%s()" will have a new "OA\Schema $schema" argument in a future version. Not defining it or passing null is deprecated',
__METHOD__
);
}

if (null !== $groups) {
trigger_deprecation(
'nelmio/api-doc-bundle',
'4.17.0',
'Using the $groups parameter of "%s()" is deprecated and will be removed in a future version. Pass groups via $context[\'groups\']',
__METHOD__
);
}

$property->oneOf = Generator::UNDEFINED !== $property->oneOf ? $property->oneOf : [];

foreach ($types as $type) {
Expand Down
18 changes: 18 additions & 0 deletions src/PropertyDescriber/DateTimePropertyDescriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,24 @@ class DateTimePropertyDescriber implements PropertyDescriberInterface
*/
public function describe(array $types, OA\Schema $property, ?array $groups = null, ?OA\Schema $schema = null, array $context = [])
{
if (null === $schema) {
trigger_deprecation(
'nelmio/api-doc-bundle',
'4.15.0',
'"%s()" will have a new "OA\Schema $schema" argument in a future version. Not defining it or passing null is deprecated',
__METHOD__
);
}

if (null !== $groups) {
trigger_deprecation(
'nelmio/api-doc-bundle',
'4.17.0',
'Using the $groups parameter of "%s()" is deprecated and will be removed in a future version. Pass groups via $context[\'groups\']',
__METHOD__
);
}

$property->type = 'string';
$property->format = 'date-time';
}
Expand Down
18 changes: 18 additions & 0 deletions src/PropertyDescriber/DictionaryPropertyDescriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,24 @@ final class DictionaryPropertyDescriber implements PropertyDescriberInterface, M
*/
public function describe(array $types, OA\Schema $property, ?array $groups = null, ?OA\Schema $schema = null, array $context = [])
{
if (null === $schema) {
trigger_deprecation(
'nelmio/api-doc-bundle',
'4.15.0',
'"%s()" will have a new "OA\Schema $schema" argument in a future version. Not defining it or passing null is deprecated',
__METHOD__
);
}

if (null !== $groups) {
trigger_deprecation(
'nelmio/api-doc-bundle',
'4.17.0',
'Using the $groups parameter of "%s()" is deprecated and will be removed in a future version. Pass groups via $context[\'groups\']',
__METHOD__
);
}

$property->type = 'object';
/** @var OA\AdditionalProperties $additionalProperties */
$additionalProperties = Util::getChild($property, OA\AdditionalProperties::class);
Expand Down
Loading

0 comments on commit f19b9b5

Please sign in to comment.