Skip to content

Commit

Permalink
Merge #21 remote-tracking branch 'php-openapi/20-consider-openapi-spe…
Browse files Browse the repository at this point in the history
…c-examples-in-faker-code-generation'

* php-openapi/20-consider-openapi-spec-examples-in-faker-code-generation: (28 commits)
  Enhance docs
  Add test spec file
  Handle example
  Add docs for `x-no-relation` and create its constant
  Fix bug
  Refactor
  Fix issues + add support for all refs only in oneOf
  Add typehint to fn args
  Fix count issue for nested array
  Fix failing test in PHP >= 8.1
  Fix errors 2 + implement custom attribute `x-no-relation`
  Fix errors
  Fix failing test
  Fix failing test
  Fix bug
  Fix failing test for x_db_type
  Implement complex oneOf + fix error 'Creating default object from empty value in PHP'
  Complex oneOf - WIP
  Implement oneOf and refactor - WIP 3
  Implement oneOf and refactor - WIP 2
  ...
  • Loading branch information
cebe committed Nov 12, 2024
2 parents 1e837f3 + 775ff26 commit 92e2b97
Show file tree
Hide file tree
Showing 43 changed files with 1,199 additions and 113 deletions.
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ up:
cli:
docker-compose exec --user=$(UID) php bash

cli_root:
docker-compose exec --user="root" php bash

cli_mysql:
docker-compose exec --user=$(UID) mysql bash

Expand Down
67 changes: 62 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,9 @@ return $config;

To use the web generator, open `index.php?r=gii` and select the `REST API Generator`.

On console you can run the generator with `./yii gii/api --openApiPath=@app/openapi.yaml`. Where `@app/openapi.yaml` should be the absolute path to your OpenAPI spec file. This can be JSON as well as YAML (see also [php-openapi/php-openapi](https://github.com/php-openapi/php-openapi/) for supported formats).
On console, you can run the generator with `./yii gii/api --openApiPath=@app/openapi.yaml`. Where `@app/openapi.yaml`
should be the absolute path to your OpenAPI spec file. This can be JSON as well as YAML (see
also [php-openapi/php-openapi](https://github.com/php-openapi/php-openapi/) for supported formats).

Run `./yii gii/api --help` for all options. Example: Disable generation of migrations files `./yii gii/api --generateMigrations=0`

Expand Down Expand Up @@ -317,6 +319,60 @@ Provide custom database table column name in case of relationship column. This w
- x-fk-column-name: redelivery_of # this will create `redelivery_of` column instead of `redelivery_of_id`
```
### `x-no-relation`

To differentiate a component schema property from one-to-many or many-to-many relation in favour of array(json) of
related objects, `x-no-relation` (type: boolean, default: false) is used.

```yaml
comments:
type: array
items:
$ref: "#/components/schemas/Comment"
```

This will not generate 'comments' column in database migrations. But it will generate `getComments()` relation in Yii model file.

In order to make it real database column, extension `x-no-relation` can be used.

```yaml
comments:
type: array
x-no-relation: true
items:
$ref: "#/components/schemas/Comment"
```

Database column type can be `array`, `json` etc. to store such data.

Now if the Comment schema from the above example is

```yaml
Comment:
properties:
id:
type: integer
content:
type: string
```

then the value for `comments` can be

```json
[
{
"id": 1,
"content": "Hi there"
},
{
"id": 2,
"content": "Hi there 2"
}
]
```

`x-no-relation` can be only used with OpenAPI schema data type `array`.

### `x-route`

To customize route (controller ID/action ID) for a path, use custom key `x-route` with value `<controller ID>/<action ID>`. It can be used for non-crud paths. It must be used under HTTP method key but not
Expand Down Expand Up @@ -399,8 +455,8 @@ There are two ways for define many-to-many relations:
### Simple many-to-many without junction model

- property name for many-to-many relation should be equal lower-cased, pluralized related schema name
- referenced schema should contains mirrored reference to current schema

- referenced schema should contain mirrored reference to current schema

- migration for junction table can be generated automatically - table name should be [pluralized, lower-cased
schema_name1]2[pluralized, lower-cased schema name2], in alphabetical order;
Expand Down Expand Up @@ -591,12 +647,13 @@ created_at:
## Assumptions

When generating code from an OpenAPI description there are many possible ways to achive a fitting result.
Thus there are some assumptions and limitations that are currently applied to make this work.
Thus, there are some assumptions and limitations that are currently applied to make this work.
Here is a (possibly incomplete) list:

- The current implementation works best with OpenAPI description that follows the [JSON:API](https://jsonapi.org/) guidelines.
- The request and response format/schema is currently not extracted from OpenAPI schema and may need to be adjusted manually if it does not follow JSON:API
- column/field/property with name `id` is considered as Primary Key by this library and it is automatically handled by DB/Yii; so remove it from validation `rules()`
- column/field/property with name `id` is considered as Primary Key by this library, and it is automatically handled by
DB/Yii; so remove it from validation `rules()`
- other fields can currently be used as primary keys using the `x-pk` OpenAPI extension (see below) but it may not be work correctly in all cases, please report bugs if you find them.

Other things to keep in mind:
Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,14 @@
},
"require": {
"php": "^7.4 || ^8.0",
"cebe/php-openapi": "^1.5.0",
"cebe/php-openapi": "^1.7.0",
"yiisoft/yii2": "~2.0.48",
"yiisoft/yii2-gii": "~2.0.0 | ~2.1.0 | ~2.2.0| ~2.3.0",
"laminas/laminas-code": ">=3.4 <=4.13",
"php-openapi/yii2-fractal": "^1.0.0",
"fakerphp/faker": "^1.9",
"sam-it/yii2-mariadb": "^2.0",
"symfony/var-exporter": "^5.4",
"symfony/polyfill-php80": "^1.30"
},
"require-dev": {
Expand Down
12 changes: 10 additions & 2 deletions src/lib/AttributeResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -219,15 +219,22 @@ protected function resolveProperty(
$nullableValue = $property->getProperty()->getSerializableData()->nullable ?? null;
}
$attribute = Yii::createObject(Attribute::class, [$property->getName()]);

if (!empty($property->getAttr(CustomSpecAttr::NO_RELATION))) {
$this->attributes[$property->getName()] = $attribute->setFakerStub($this->guessFakerStub($attribute, $property));
}

$attribute->setRequired($isRequired)
->setPhpType($property->guessPhpType())
->setDescription($property->getAttr('description', ''))
->setReadOnly($property->isReadonly())
->setDefault($property->guessDefault())
->setXDbType($property->getAttr(CustomSpecAttr::DB_TYPE))
->setXDbDefaultExpression($property->getAttr(CustomSpecAttr::DB_DEFAULT_EXPRESSION))
->setNullable($nullableValue)
->setIsPrimary($property->isPrimaryKey())
->setForeignKeyColumnName($property->fkColName);
->setForeignKeyColumnName($property->fkColName)
->setFakerStub($this->guessFakerStub($attribute, $property));
if ($property->isReference()) {
if ($property->isVirtual()) {
throw new InvalidDefinitionException('References not supported for virtual attributes');
Expand Down Expand Up @@ -261,7 +268,8 @@ protected function resolveProperty(
->setSize($fkProperty->getMaxLength())
->setDescription($property->getRefSchema()->getDescription())
->setDefault($fkProperty->guessDefault())
->setLimits($min, $max, $fkProperty->getMinLength());
->setLimits($min, $max, $fkProperty->getMinLength())
->setFakerStub($this->guessFakerStub($attribute, $property));

$relation = Yii::createObject(
AttributeRelation::class,
Expand Down
5 changes: 5 additions & 0 deletions src/lib/CustomSpecAttr.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ class CustomSpecAttr
*/
public const FK_COLUMN_NAME = 'x-fk-column-name';

/**
* Foreign key column name. See README for usage docs
*/
public const NO_RELATION = 'x-no-relation';

/**
* Custom route (controller ID/action ID) instead of auto-generated. See README for usage docs. https://github.com/cebe/yii2-openapi/issues/144
*/
Expand Down
Loading

0 comments on commit 92e2b97

Please sign in to comment.