Skip to content

Commit 58b7fc3

Browse files
committed
Merge branch 'master' of github.com:SOHELAHMED7/yii2-openapi into 175-bug-allof-with-multiple-dollarrefs
2 parents f41f0fa + a6d8786 commit 58b7fc3

File tree

70 files changed

+789
-130
lines changed

Some content is hidden

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

70 files changed

+789
-130
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ Allow to set foreign key constraint in migrations for ON UPDATE event of row in
285285

286286
### `x-fk-column-name`
287287

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

290290
```yaml
291291
components:

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/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);

tests/migrations/m100000_000000_pgsql.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ public function safeUp()
103103
'json3' => $this->json()->defaultValue(Json::encode(['foo' => 'bar', 'bar' => 'baz'])),
104104
'json4' => "json DEFAULT '" . new Expression(Json::encode(['ffo' => 'bar'])) . "'",
105105
'status' => '"'.$enumTypeName.'"',
106+
'status_x' => 'varchar(10)',
106107
'search' => 'tsvector'
107108
]);
108109
$columns = [

tests/specs/blog/migrations/m200000_000001_create_table_users.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ public function up()
1212
'username' => $this->string(200)->notNull(),
1313
'email' => $this->string(200)->notNull(),
1414
'password' => $this->string()->notNull(),
15-
'role' => $this->string(20)->null()->defaultValue("reader"),
15+
'role' => $this->string(20)->null()->defaultValue('reader'),
1616
'flags' => $this->integer()->null()->defaultValue(0),
1717
'created_at' => $this->timestamp()->null()->defaultExpression("(CURRENT_TIMESTAMP)"),
1818
]);
1919
$this->createIndex('users_username_key', '{{%users}}', 'username', true);
2020
$this->createIndex('users_email_key', '{{%users}}', 'email', true);
21-
$this->createIndex('users_role_flags_index', '{{%users}}', 'role,flags', false);
21+
$this->createIndex('users_role_flags_index', '{{%users}}', ["role", "flags"], false);
2222
}
2323

2424
public function down()

tests/specs/blog/migrations/m200000_000002_create_table_blog_posts.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,18 @@ public function up()
1717
'created_by_id' => $this->integer()->null()->defaultValue(null),
1818
]);
1919
$this->addPrimaryKey('pk_blog_posts_uid', '{{%blog_posts}}', 'uid');
20-
$this->addForeignKey('fk_blog_posts_category_id_categories_id', '{{%blog_posts}}', 'category_id', '{{%categories}}', 'id');
21-
$this->addForeignKey('fk_blog_posts_created_by_id_users_id', '{{%blog_posts}}', 'created_by_id', '{{%users}}', 'id');
2220
$this->createIndex('blog_posts_title_key', '{{%blog_posts}}', 'title', true);
2321
$this->createIndex('blog_posts_slug_key', '{{%blog_posts}}', 'slug', true);
22+
$this->addForeignKey('fk_blog_posts_category_id_categories_id', '{{%blog_posts}}', 'category_id', '{{%categories}}', 'id');
23+
$this->addForeignKey('fk_blog_posts_created_by_id_users_id', '{{%blog_posts}}', 'created_by_id', '{{%users}}', 'id');
2424
}
2525

2626
public function down()
2727
{
28-
$this->dropIndex('blog_posts_slug_key', '{{%blog_posts}}');
29-
$this->dropIndex('blog_posts_title_key', '{{%blog_posts}}');
3028
$this->dropForeignKey('fk_blog_posts_created_by_id_users_id', '{{%blog_posts}}');
3129
$this->dropForeignKey('fk_blog_posts_category_id_categories_id', '{{%blog_posts}}');
30+
$this->dropIndex('blog_posts_slug_key', '{{%blog_posts}}');
31+
$this->dropIndex('blog_posts_title_key', '{{%blog_posts}}');
3232
$this->dropPrimaryKey('pk_blog_posts_uid', '{{%blog_posts}}');
3333
$this->dropTable('{{%blog_posts}}');
3434
}

0 commit comments

Comments
 (0)