Skip to content

Commit c3c07e7

Browse files
committed
Merge branches 'master' and '158-bug-giiapi-generated-rules-enum-with-trim' of github.com:SOHELAHMED7/yii2-openapi into 158-bug-giiapi-generated-rules-enum-with-trim
2 parents 2bed3ca + 4e77f4d commit c3c07e7

File tree

122 files changed

+2095
-190
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

122 files changed

+2095
-190
lines changed

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,8 @@ Such values are not allowed:
182182
- `int null default null after low_price` (null and default will be handled by `nullable` and `default` keys respectively)
183183
- MEDIUMINT(10) UNSIGNED ZEROFILL NULL DEFAULT '7' COMMENT 'comment' AFTER `seti`, ADD INDEX `t` (`w`)
184184

185+
If `enum` and `x-db-type` both are provided then for database column schema (migrations), only `x-db-type` will be considered ignoring `enum`.
186+
185187
### `x-indexes`
186188

187189
Specify table indexes
@@ -285,7 +287,7 @@ Allow to set foreign key constraint in migrations for ON UPDATE event of row in
285287

286288
### `x-fk-column-name`
287289

288-
Provide custom column name in case of relationship column. Example:
290+
Provide custom database table column name in case of relationship column. This will not reflect in models relations, faker etc. Example:
289291

290292
```yaml
291293
components:
@@ -446,6 +448,8 @@ It works on all 3 DB: MySQL, MariaDb and PgSQL.
446448

447449
Note: Changes in enum values are not very simple. For Mysql and Mariadb, migrations will be generated but in many cases custom modification in it are required. For Pgsql migrations for change in enum values will not be generated. It should be handled manually.
448450

451+
It will be ignored for database column schema (migrations) if `x-db-type` is provided.
452+
449453
## Handling of `numeric` (#numeric, #MariaDb)
450454

451455
precision-default = 10

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
"source": "https://github.com/cebe/yii2-openapi"
1919
},
2020
"require": {
21-
"php": ">=7.2.0",
21+
"php": "^7.4 || ^8.0",
2222
"cebe/php-openapi": "^1.5.0",
2323
"yiisoft/yii2": "~2.0.48",
2424
"yiisoft/yii2-gii": "~2.0.0 | ~2.1.0 | ~2.2.0| ~2.3.0",

src/generator/default/transformer.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,14 @@
2323
class <?=$transformer->name?> extends TransformerAbstract
2424
{
2525
<?php if (!empty($transformer->availableRelations)):?>
26-
protected $availableIncludes = ['<?=implode("', '", $transformer->availableRelations)?>'];
26+
protected array $availableIncludes = ['<?=implode("', '", $transformer->availableRelations)?>'];
2727
<?php else:?>
28-
protected $availableIncludes = [];
28+
protected array $availableIncludes = [];
2929
<?php endif;?>
3030
<?php if (!empty($transformer->defaultRelations)):?>
31-
protected $defaultIncludes = ['<?=implode("', '", $transformer->defaultRelations)?>'];
31+
protected array $defaultIncludes = ['<?=implode("', '", $transformer->defaultRelations)?>'];
3232
<?php else:?>
33-
protected $defaultIncludes = [];
33+
protected array $defaultIncludes = [];
3434
<?php endif;?>
3535

3636
public function transform(<?=$transformer->dbModel->getClassName()?> $model)

src/lib/AttributeResolver.php

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -436,10 +436,30 @@ protected function prepareIndexes(array $indexes):array
436436
}
437437
$props = array_map('trim', explode(',', trim($props)));
438438
$columns = [];
439+
$xFkColumnNames = [];
440+
foreach ($this->attributes as $key => $value) {
441+
if (!empty($value->fkColName)) {
442+
$xFkColumnNames[$value->fkColName] = $key;
443+
}
444+
}
439445
foreach ($props as $prop) {
446+
// for more info see test tests/specs/fk_col_name/fk_col_name.yaml
447+
// File: ForeignKeyColumnNameTest::testIndexForColumnWithCustomName
448+
// first check direct column names
440449
if (!isset($this->attributes[$prop])) {
441-
throw new InvalidDefinitionException('Invalid index definition - property ' . $prop
442-
. ' not declared');
450+
// then check x-fk-column-name
451+
if (!in_array($prop, array_keys($xFkColumnNames))) {
452+
// then check relations/reference e.g. `user`/`user_id`
453+
$refPropName = (substr($prop, -3) === '_id') ? rtrim($prop, '_id') : null;
454+
if ($refPropName && !isset($this->attributes[$refPropName])) {
455+
throw new InvalidDefinitionException('Invalid index definition - property ' . $prop
456+
. ' not declared');
457+
} else {
458+
$prop = $refPropName;
459+
}
460+
} else {
461+
$prop = $xFkColumnNames[$prop];
462+
}
443463
}
444464
$columns[] = $this->attributes[$prop]->columnName;
445465
}

src/lib/ColumnToCode.php

Lines changed: 12 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ public function getCode(bool $quoted = false):string
169169
$default = '';
170170
} elseif (ApiGenerator::isPostgres() && $this->isEnum()) {
171171
$default =
172-
$this->rawParts['default'] !== null ? ' DEFAULT ' . self::escapeQuotes(trim($this->rawParts['default'])) : '';
172+
$this->rawParts['default'] !== null ? ' DEFAULT ' . trim($this->rawParts['default']) : '';
173173
} else {
174174
$default = $this->rawParts['default'] !== null ? ' DEFAULT ' . trim($this->rawParts['default']) : '';
175175
}
@@ -178,13 +178,10 @@ public function getCode(bool $quoted = false):string
178178
if ((ApiGenerator::isMysql() || ApiGenerator::isMariaDb()) && $this->rawParts['position']) {
179179
$code .= ' ' . $this->rawParts['position'];
180180
}
181-
if ((ApiGenerator::isMysql() || ApiGenerator::isMariaDb()) && $this->isEnum()) {
182-
return $quoted ? "'" . $code . "'" : $code;
183-
}
184181
if (ApiGenerator::isPostgres() && $this->alterByXDbType) {
185-
return $quoted ? "'" . $this->rawParts['type'] . "'" : $this->rawParts['type'];
182+
return $quoted ? VarDumper::export($this->rawParts['type']) : $this->rawParts['type'];
186183
}
187-
return $quoted ? "'" . $code . "'" : $code;
184+
return $quoted ? VarDumper::export($code) : $code;
188185
}
189186

190187
public function getAlterExpression(bool $addUsingExpression = false):string
@@ -226,7 +223,7 @@ public function isJson():bool
226223

227224
public function isEnum():bool
228225
{
229-
return !empty($this->column->enumValues);
226+
return BaseMigrationBuilder::isEnum($this->column);
230227
}
231228

232229
public function isDecimal()
@@ -313,14 +310,14 @@ public static function mysqlEnumToString(array $enum):string
313310
private function defaultValueJson(array $value):string
314311
{
315312
if ($this->alter === true) {
316-
return "'" . str_replace('"', '\"', Json::encode($value)). "'";
313+
return "'" . str_replace('"', '\"', Json::encode($value, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_HEX_QUOT)) . "'";
317314
}
318-
return "\\'" . new Expression(Json::encode($value)) . "\\'";
315+
return "'" . Json::encode($value, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_HEX_QUOT) . "'";
319316
}
320317

321318
private function defaultValueArray(array $value):string
322319
{
323-
return "'{" . str_replace('"', "\"", trim(Json::encode($value), '[]')) . "}'";
320+
return "'{" . trim(Json::encode($value, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_HEX_QUOT), '[]') . "}'";
324321
}
325322

326323
private function resolve():void
@@ -442,10 +439,10 @@ private function resolveDefaultValue():void
442439
break;
443440
case 'object':
444441
if ($value instanceof JsonExpression) {
445-
$this->fluentParts['default'] = "defaultValue('" . Json::encode($value->getValue()) . "')";
442+
$this->fluentParts['default'] = "defaultValue('" . Json::encode($value->getValue(), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_HEX_QUOT) . "')";
446443
$this->rawParts['default'] = $this->defaultValueJson($value->getValue());
447444
} elseif ($value instanceof ArrayExpression) {
448-
$this->fluentParts['default'] = "defaultValue('" . Json::encode($value->getValue()) . "')";
445+
$this->fluentParts['default'] = "defaultValue('" . Json::encode($value->getValue(), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_HEX_QUOT) . "')";
449446
$this->rawParts['default'] = $this->defaultValueArray($value->getValue());
450447
} else {
451448
// $value instanceof \yii\db\Expression
@@ -454,19 +451,15 @@ private function resolveDefaultValue():void
454451
}
455452
break;
456453
case 'array':
457-
$this->fluentParts['default'] = "defaultValue('" . Json::encode($value) . "')";
454+
$this->fluentParts['default'] = "defaultValue('" . Json::encode($value, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_HEX_QUOT) . "')";
458455
$this->rawParts['default'] = $this->isJson()
459456
? $this->defaultValueJson($value)
460457
: $this->defaultValueArray($value);
461458
break;
462459
default:
463460
$this->fluentParts['default'] = $expectInteger
464-
? 'defaultValue(' . $value . ')' : 'defaultValue("' . self::escapeQuotes((string)$value) . '")';
465-
$this->rawParts['default'] = $expectInteger ? $value : self::wrapQuotes($value);
466-
467-
if ((ApiGenerator::isMysql() || ApiGenerator::isMariaDb()) && $this->isEnum()) {
468-
$this->rawParts['default'] = self::escapeQuotes($this->rawParts['default']);
469-
}
461+
? 'defaultValue(' . $value . ')' : 'defaultValue(' . VarDumper::export((string)$value) . ')';
462+
$this->rawParts['default'] = $expectInteger ? $value : VarDumper::export((string)$value);
470463
}
471464
}
472465

src/lib/FakerStubResolver.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public function resolve():?string
6262
}
6363

6464
// column name ends with `_id`
65-
if (substr($this->attribute->columnName, -strlen('_id'))==='_id') {
65+
if (substr($this->attribute->columnName, -3) === '_id' || !empty($this->attribute->fkColName)) {
6666
$config = $this->config;
6767
if (!$config) {
6868
$config = new Config;

src/lib/ValidationRulesBuilder.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,8 @@ private function addRulesByAttributeName(Attribute $attribute):void
142142
'~(url|site|website|href|link)~i' => 'url',
143143
];
144144
foreach ($patterns as $pattern => $validator) {
145-
if (preg_match($pattern, strtolower($attribute->columnName))) {
145+
if (empty($attribute->reference) # ignore column name based rules in case of reference/relation # https://github.com/cebe/yii2-openapi/issues/159
146+
&& preg_match($pattern, strtolower($attribute->columnName))) {
146147
$key = $attribute->columnName . '_' . $validator;
147148
$this->rules[$key] = new ValidationRule([$attribute->columnName], $validator);
148149
return;

src/lib/migrations/BaseMigrationBuilder.php

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,14 @@ public function buildFresh():MigrationModel
141141
$this->migration->addUpCode($builder->addPrimaryKey($tableName, $this->model->junctionCols))
142142
->addDownCode($builder->dropPrimaryKey($tableName, $this->model->junctionCols));
143143
}
144+
145+
foreach ($this->model->indexes as $index) {
146+
$upCode = $index->isUnique ? $builder->addUniqueIndex($tableName, $index->name, $index->columns)
147+
: $builder->addIndex($tableName, $index->name, $index->columns, $index->type);
148+
$this->migration->addUpCode($upCode)
149+
->addDownCode($builder->dropIndex($tableName, $index->name));
150+
}
151+
144152
foreach ($this->model->getHasOneRelations() as $relation) {
145153
$fkCol = $relation->getColumnName();
146154
$refCol = $relation->getForeignName();
@@ -153,13 +161,6 @@ public function buildFresh():MigrationModel
153161
}
154162
}
155163

156-
foreach ($this->model->indexes as $index) {
157-
$upCode = $index->isUnique ? $builder->addUniqueIndex($tableName, $index->name, $index->columns)
158-
: $builder->addIndex($tableName, $index->name, $index->columns, $index->type);
159-
$this->migration->addUpCode($upCode)
160-
->addDownCode($builder->dropIndex($tableName, $index->name));
161-
}
162-
163164
return $this->migration;
164165
}
165166

@@ -211,14 +212,14 @@ function (string $unknownColumn) {
211212
}
212213
$this->buildColumnChanges($current, $desired, $changedAttributes);
213214
}
215+
if (!$relation) {
216+
$this->buildIndexChanges();
217+
}
214218
if ($relation) {
215219
$this->buildRelationsForJunction($relation);
216220
} else {
217221
$this->buildRelations();
218222
}
219-
if (!$relation) {
220-
$this->buildIndexChanges();
221-
}
222223
return $this->migration;
223224
}
224225

@@ -478,10 +479,7 @@ public function newColStr(string $tableAlias, \cebe\yii2openapi\db\ColumnSchema
478479

479480
public static function isEnum(\yii\db\ColumnSchema $columnSchema): bool
480481
{
481-
if (!empty($columnSchema->enumValues) && is_array($columnSchema->enumValues)) {
482-
return true;
483-
}
484-
return false;
482+
return !empty($columnSchema->enumValues) && is_array($columnSchema->enumValues) && empty($columnSchema->xDbType);
485483
}
486484

487485
public static function isEnumValuesChanged(

src/lib/migrations/MigrationRecordBuilder.php

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ final class MigrationRecordBuilder
2424
public const DROP_FK = MigrationRecordBuilder::INDENT . "\$this->dropForeignKey('%s', '%s');";
2525
public const DROP_PK = MigrationRecordBuilder::INDENT . "\$this->dropPrimaryKey('%s', '%s');";
2626
public const ADD_TABLE = MigrationRecordBuilder::INDENT . "\$this->createTable('%s', %s);";
27-
public const ADD_UNIQUE = MigrationRecordBuilder::INDENT . "\$this->createIndex('%s', '%s', '%s', true);";
28-
public const ADD_INDEX = MigrationRecordBuilder::INDENT . "\$this->createIndex('%s', '%s', '%s', %s);";
27+
public const ADD_UNIQUE = MigrationRecordBuilder::INDENT . "\$this->createIndex('%s', '%s', %s, true);";
28+
public const ADD_INDEX = MigrationRecordBuilder::INDENT . "\$this->createIndex('%s', '%s', %s, %s);";
2929
public const DROP_COLUMN = MigrationRecordBuilder::INDENT . "\$this->dropColumn('%s', '%s');";
3030
public const ADD_ENUM = MigrationRecordBuilder::INDENT . "\$this->execute('CREATE TYPE \"enum_%s_%s\" AS ENUM(%s)');";
3131
public const DROP_ENUM = MigrationRecordBuilder::INDENT . "\$this->execute('DROP TYPE \"enum_%s_%s\"');";
@@ -88,7 +88,7 @@ public function addColumn(string $tableAlias, ColumnSchema $column, ?string $pos
8888
if (is_string($column->xDbType) && !empty($column->xDbType)) {
8989
$converter = $this->columnToCode($tableAlias, $column, false, false, false, false, $position);
9090
$name = static::quote($column->name);
91-
return sprintf(self::ADD_COLUMN_RAW, $tableAlias, $name, $converter->getCode());
91+
return sprintf(self::ADD_COLUMN_RAW, $tableAlias, $name, ColumnToCode::escapeQuotes($converter->getCode()));
9292
}
9393

9494
$converter = $this->columnToCode($tableAlias, $column, false, false, false, false, $position);
@@ -103,7 +103,7 @@ public function addDbColumn(string $tableAlias, ColumnSchema $column, ?string $p
103103
if (property_exists($column, 'xDbType') && is_string($column->xDbType) && !empty($column->xDbType)) {
104104
$converter = $this->columnToCode($tableAlias, $column, true, false, false, false, $position);
105105
$name = static::quote($column->name);
106-
return sprintf(self::ADD_COLUMN_RAW, $tableAlias, $column->name, $converter->getCode());
106+
return sprintf(self::ADD_COLUMN_RAW, $tableAlias, $column->name, ColumnToCode::escapeQuotes($converter->getCode()));
107107
}
108108
$converter = $this->columnToCode($tableAlias, $column, true, false, false, false, $position);
109109
return sprintf(self::ADD_COLUMN, $tableAlias, $column->name, $converter->getCode(true));
@@ -120,7 +120,7 @@ public function alterColumn(string $tableAlias, ColumnSchema $column):string
120120
ApiGenerator::isPostgres() ? self::ALTER_COLUMN_RAW_PGSQL : self::ALTER_COLUMN_RAW,
121121
$tableAlias,
122122
$column->name,
123-
$converter->getCode()
123+
ColumnToCode::escapeQuotes($converter->getCode())
124124
);
125125
}
126126
$converter = $this->columnToCode($tableAlias, $column, true);
@@ -231,13 +231,24 @@ public function addFk(string $fkName, string $tableAlias, string $fkCol, string
231231

232232
public function addUniqueIndex(string $tableAlias, string $indexName, array $columns):string
233233
{
234-
return sprintf(self::ADD_UNIQUE, $indexName, $tableAlias, implode(',', $columns));
234+
return sprintf(
235+
self::ADD_UNIQUE,
236+
$indexName,
237+
$tableAlias,
238+
count($columns) === 1 ? "'{$columns[0]}'" : '["'.implode('", "', $columns).'"]'
239+
);
235240
}
236241

237242
public function addIndex(string $tableAlias, string $indexName, array $columns, ?string $using = null):string
238243
{
239244
$indexType = $using === null ? 'false' : "'".ColumnToCode::escapeQuotes($using)."'";
240-
return sprintf(self::ADD_INDEX, $indexName, $tableAlias, implode(',', $columns), $indexType);
245+
return sprintf(
246+
self::ADD_INDEX,
247+
$indexName,
248+
$tableAlias,
249+
count($columns) === 1 ? "'{$columns[0]}'" : '["'.implode('", "', $columns).'"]',
250+
$indexType
251+
);
241252
}
242253

243254
public function addPrimaryKey(string $tableAlias, array $columns, string $pkName= null):string
@@ -329,7 +340,7 @@ public static function makeString(array $codeColumns): string
329340
}
330341
}
331342

332-
$codeColumns = str_replace([PHP_EOL, "\\\'"], [PHP_EOL . self::INDENT.' ', "'"], $finalStr);
343+
$codeColumns = str_replace([PHP_EOL], [PHP_EOL . self::INDENT.' '], $finalStr);
333344
$codeColumns = trim($codeColumns);
334345
$codeColumns = '['.PHP_EOL.self::INDENT.' '.$codeColumns.PHP_EOL . self::INDENT.']';
335346
return $codeColumns;

src/lib/migrations/PostgresMigrationBuilder.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,10 @@ protected function createEnumMigrations():void
147147
$tableAlias = $this->model->getTableAlias();
148148
$enums = $this->model->getEnumAttributes();
149149
foreach ($enums as $attr) {
150+
if (!empty($attr->xDbType)) {
151+
// do not generate enum types when custom x-db-type is used
152+
continue;
153+
}
150154
$this->migration
151155
->addUpCode($this->recordBuilder->createEnum($tableAlias, $attr->columnName, $attr->enumValues), true)
152156
->addDownCode($this->recordBuilder->dropEnum($tableAlias, $attr->columnName), true);

0 commit comments

Comments
 (0)