Skip to content

Commit

Permalink
Reverses breaking change by introducing no SwagEntity attribute #224
Browse files Browse the repository at this point in the history
Maintains prior isVisible functionality. Accomplishes feature by
introducing new isPublic attribute.
  • Loading branch information
cnizzardini committed Dec 19, 2020
1 parent 3687a6b commit 00a373a
Show file tree
Hide file tree
Showing 9 changed files with 80 additions and 17 deletions.
15 changes: 11 additions & 4 deletions docs/annotations.md
Original file line number Diff line number Diff line change
Expand Up @@ -473,18 +473,25 @@ class UsersController extends AppController {
```

### @SwagEntity
Class level annotation for exposing entities to Swagger UI. By default, all entities with routes will display as Swagger
schema. You can hide a schema or display a schema that does not have an associated route.
Class level annotation for exposing entities to Swagger UI.

| Attribute | Type / Default | Description |
| ------------- | ------------- | ------------- |
| isVisible | boolean `true` | Is the schema is visible in OpenAPI schema list (hidden schema appears in `/x-swagger-bake-bake/components/schemas/`) |
| isVisible | boolean `true` | All entities with routes are added to OpenAPI schema. To completely hide a schema from appearing anywhere in OpenAPI JSON output set to false |
| isPublic | boolean `true` | To hide from the default via in Swagger 3.0 set to false. isVisible takes precedence (see isVisible vs isPublic below) |
| title | string `""` | Overwrites the default title |
| description | string `""` | Overwrites the default description (if any) |

**isVisible vs isPublic:**

`isVisible` takes precedence over `isPublic`. If you've set `isVisible` to `false` then whatever you've defined for
`isPublic` becomes inert. If a schema is visible, but not public it be accessed via
`#/x-swagger-bake-bake/components/schemas/EntityName`. This is helpful if you want to reduce cluter in your Swagger
schemas, but still want the ability to reference it via `@SwagResponseSchema`

```php
/**
* @Swag\SwagEntity(isVisible=false, title="optional title", description="optional description")
* @Swag\SwagEntity(isVisible=true, isPublic=false, title="optional title", description="optional description")
*/
class Employee extends Entity {
```
Expand Down
6 changes: 6 additions & 0 deletions src/Lib/Annotation/SwagEntity.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
* @Target({"CLASS"})
* @Attributes({
* @Attribute("isVisible", type="bool"),
* @Attribute("isPublic", type="bool"),
* @Attribute("title", type="string"),
* @Attribute("description", type="string"),
* })
Expand All @@ -23,6 +24,11 @@ class SwagEntity
**/
public $isVisible = true;

/**
* @var bool
**/
public $isPublic = true;

/**
* @var string|null
*/
Expand Down
27 changes: 27 additions & 0 deletions src/Lib/Model/ModelScanner.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@
use MixerApi\Core\Model\Model;
use MixerApi\Core\Model\ModelFactory;
use MixerApi\Core\Utility\NamespaceUtility;
use SwaggerBake\Lib\Annotation\SwagEntity;
use SwaggerBake\Lib\Configuration;
use SwaggerBake\Lib\Exception\SwaggerBakeRunTimeException;
use SwaggerBake\Lib\Route\RouteDecorator;
use SwaggerBake\Lib\Route\RouteScanner;
use SwaggerBake\Lib\Utility\AnnotationUtility;

/**
* Finds all Entities associated with RESTful routes based on userland configurations
Expand Down Expand Up @@ -75,6 +77,9 @@ public function getModelDecorators(): array
}

$routeDecorator = $this->getRouteDecorator($model);
if (!$this->hasVisibility($model, $routeDecorator)) {
continue;
}

if ($routeDecorator) {
$controllerFqn = $routeDecorator->getControllerFqn();
Expand Down Expand Up @@ -125,4 +130,26 @@ private function getRouteDecorator(Model $model): ?RouteDecorator

return $result->first();
}

/**
* @param \MixerApi\Core\Model\Model $model Model instance
* @param \SwaggerBake\Lib\Route\RouteDecorator|null $routeDecorator RouteDecorator instance
* @return bool
*/
private function hasVisibility(Model $model, ?RouteDecorator $routeDecorator): bool
{
$annotations = AnnotationUtility::getClassAnnotationsFromFqns(get_class($model->getEntity()));

$swagEntities = array_filter($annotations, function ($annotation) {
return $annotation instanceof SwagEntity;
});

if (empty($swagEntities)) {
return $routeDecorator !== null;
}

$swagEntity = reset($swagEntities);

return $swagEntity->isVisible;
}
}
12 changes: 6 additions & 6 deletions src/Lib/OpenApi/Schema.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ class Schema implements JsonSerializable
/**
* @var bool
*/
private $isVisible = true;
private $isPublic = true;

/**
* @return array
Expand Down Expand Up @@ -566,18 +566,18 @@ public function getReadSchemaRef(): string
/**
* @return bool
*/
public function isVisible(): bool
public function isPublic(): bool
{
return $this->isVisible;
return $this->isPublic;
}

/**
* @param bool $isVisible indicates visibility
* @param bool $isPublic indicates visibility
* @return $this
*/
public function setIsVisible(bool $isVisible)
public function setIsPublic(bool $isPublic)
{
$this->isVisible = $isVisible;
$this->isPublic = $isPublic;

return $this;
}
Expand Down
10 changes: 7 additions & 3 deletions src/Lib/Schema/SchemaFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,18 @@ class SchemaFactory
*
* @param \SwaggerBake\Lib\Model\ModelDecorator $modelDecorator ModelDecorator
* @param int $propertyType see public constants for o
* @return \SwaggerBake\Lib\OpenApi\Schema
* @return \SwaggerBake\Lib\OpenApi\Schema|null
* @throws \ReflectionException
*/
public function create(ModelDecorator $modelDecorator, int $propertyType = 6): Schema
public function create(ModelDecorator $modelDecorator, int $propertyType = 6): ?Schema
{
$model = $modelDecorator->getModel();
$swagEntity = $this->getSwagEntityAnnotation($model->getEntity());

if ($swagEntity !== null && $swagEntity->isVisible === false) {
return null;
}

$this->validator = $this->getValidator($model);

$docBlock = $this->getDocBlock($model->getEntity());
Expand All @@ -71,7 +75,7 @@ public function create(ModelDecorator $modelDecorator, int $propertyType = 6): S
->setDescription($swagEntity->description)
->setType('object')
->setProperties($properties)
->setIsVisible($swagEntity->isVisible);
->setIsPublic($swagEntity->isPublic);

if (empty($schema->getDescription())) {
$schema->setDescription($docBlock ? $docBlock->getSummary() : null);
Expand Down
5 changes: 4 additions & 1 deletion src/Lib/Swagger.php
Original file line number Diff line number Diff line change
Expand Up @@ -255,8 +255,11 @@ private function buildSchemasFromModels(): void
}

$schema = $schemaFactory->create($model);
if (!$schema) {
continue;
}

if ($schema->isVisible()) {
if ($schema->isPublic()) {
$this->pushSchema($schema);
} else {
$this->pushVendorSchema($schema);
Expand Down
18 changes: 16 additions & 2 deletions tests/TestCase/Lib/Annotations/SwagEntityTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class SwagEntityTest extends TestCase
public $fixtures = [
'plugin.SwaggerBake.Employees',
'plugin.SwaggerBake.EmployeeSalaries',
'plugin.SwaggerBake.DepartmentEmployees',
];

/**
Expand All @@ -40,6 +41,7 @@ public function setUp(): void
$builder->resources('Employees', function (RouteBuilder $routes) {
$routes->resources('EmployeeSalaries');
});
$builder->resources('DepartmentEmployees');
});
$this->router = $router;

Expand Down Expand Up @@ -73,7 +75,7 @@ public function testEntityExists()
$this->assertArrayHasKey('Employee', $arr['components']['schemas']);
}

public function testEntityInvisible()
public function testEntityIsVisibleFalse()
{
$cakeRoute = new RouteScanner($this->router, $this->config);

Expand All @@ -82,7 +84,19 @@ public function testEntityInvisible()
$arr = json_decode($swagger->toString(), true);

$this->assertArrayNotHasKey('EmployeeSalary', $arr['components']['schemas']);
$this->assertArrayHasKey('EmployeeSalary', $arr['x-swagger-bake']['components']['schemas']);
$this->assertArrayNotHasKey('EmployeeSalary', $arr['x-swagger-bake']['components']['schemas']);
}

public function testEntityIsPublicFalse()
{
$cakeRoute = new RouteScanner($this->router, $this->config);

$swagger = new Swagger(new ModelScanner($cakeRoute, $this->config));

$arr = json_decode($swagger->toString(), true);

$this->assertArrayNotHasKey('DepartmentEmployee', $arr['components']['schemas']);
$this->assertArrayHasKey('DepartmentEmployee', $arr['x-swagger-bake']['components']['schemas']);
}

public function testEntityAttribute()
Expand Down
3 changes: 2 additions & 1 deletion tests/test_app/src/Model/Entity/DepartmentEmployee.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
namespace SwaggerBakeTest\App\Model\Entity;

use Cake\ORM\Entity;
use SwaggerBake\Lib\Annotation\SwagEntity;

/**
* DepartmentEmployee Entity
*
* @SwagEntity(isPublic=false)
* @property int $employee_id
* @property int $department_id
* @property \Cake\I18n\FrozenDate $from_date
Expand Down
1 change: 1 addition & 0 deletions tests/test_app/src/Model/Entity/EmployeeTitle.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
namespace SwaggerBakeTest\App\Model\Entity;

use Cake\ORM\Entity;
use SwaggerBake\Lib\Annotation\SwagEntity;

/**
* EmployeeTitle Entity
Expand Down

0 comments on commit 00a373a

Please sign in to comment.