diff --git a/src/lib/ValidationRulesBuilder.php b/src/lib/ValidationRulesBuilder.php index 3f3c1398..75f07be5 100644 --- a/src/lib/ValidationRulesBuilder.php +++ b/src/lib/ValidationRulesBuilder.php @@ -10,8 +10,6 @@ use cebe\yii2openapi\lib\items\Attribute; use cebe\yii2openapi\lib\items\DbModel; use cebe\yii2openapi\lib\items\ValidationRule; -use yii\helpers\VarDumper; -use yii\validators\DateValidator; use function count; use function implode; use function in_array; @@ -65,7 +63,7 @@ public function build():array } } foreach ($this->model->attributes as $attribute) { - // 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()` if (in_array($attribute->columnName, ['id', $this->model->pkName]) || in_array($attribute->propertyName, ['id', $this->model->pkName]) ) { @@ -136,16 +134,32 @@ private function resolveAttributeRules(Attribute $attribute):void private function addRulesByAttributeName(Attribute $attribute):void { - //@TODO: probably also patterns for file, image $patterns = [ '~e?mail~i' => 'email', '~(url|site|website|href|link)~i' => 'url', + + # below patters will only work if `format: binary` (file) is present in OpenAPI spec + # also `string` validation rule will be removed + '~(image|photo|picture)~i' => 'image', + '~(file|pdf|audio|video|document|json|yml|yaml|zip|tar|7z)~i' => 'file', ]; + $addRule = function (Attribute $attribute, string $validator): void { + $key = $attribute->columnName . '_' . $validator; + $this->rules[$key] = new ValidationRule([$attribute->columnName], $validator); + }; foreach ($patterns as $pattern => $validator) { if (empty($attribute->reference) # ignore column name based rules in case of reference/relation # https://github.com/cebe/yii2-openapi/issues/159 && preg_match($pattern, strtolower($attribute->columnName))) { - $key = $attribute->columnName . '_' . $validator; - $this->rules[$key] = new ValidationRule([$attribute->columnName], $validator); + if (in_array($validator, ['image', 'file'], true)) { + if ($attribute->dbType === 'binary') { + $addRule($attribute, $validator); + // for files, we don't need `string` validation + $key = $attribute->columnName . '_string'; + unset($this->rules[$key]); + } + } else { + $addRule($attribute, $validator); + } return; } } @@ -223,7 +237,7 @@ private function prepareTypeScope():void if ($attribute->isReadOnly()) { continue; } - // 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()` if (in_array($attribute->columnName, ['id', $this->model->pkName]) || in_array($attribute->propertyName, ['id', $this->model->pkName]) ) { diff --git a/tests/specs/issue_fix/30_add_validation_rules_by_attribute_name_or_pattern/index.php b/tests/specs/issue_fix/30_add_validation_rules_by_attribute_name_or_pattern/index.php new file mode 100644 index 00000000..4415beda --- /dev/null +++ b/tests/specs/issue_fix/30_add_validation_rules_by_attribute_name_or_pattern/index.php @@ -0,0 +1,14 @@ + '@specs/issue_fix/30_add_validation_rules_by_attribute_name_or_pattern/index.yaml', + 'generateUrls' => false, + 'generateModels' => true, + 'excludeModels' => [ + 'Error', + ], + 'generateControllers' => false, + 'generateMigrations' => false, + 'generateModelFaker' => false, // `generateModels` must be `true` in order to use `generateModelFaker` as `true` +]; + diff --git a/tests/specs/issue_fix/30_add_validation_rules_by_attribute_name_or_pattern/index.yaml b/tests/specs/issue_fix/30_add_validation_rules_by_attribute_name_or_pattern/index.yaml new file mode 100644 index 00000000..4561070f --- /dev/null +++ b/tests/specs/issue_fix/30_add_validation_rules_by_attribute_name_or_pattern/index.yaml @@ -0,0 +1,45 @@ + +openapi: 3.0.3 + +info: + title: Add validation rules by attribute name or pattern \#30 + version: 1.0.0 + +components: + schemas: + User: + type: object + required: + - id + - name + properties: + id: + type: integer + readOnly: true + name: + description: name + type: string + maxLength: 128 + photo: + type: string + format: binary + profile_photo: + type: string + format: binary + pdf: + type: string + format: binary + a_file: + type: string + format: binary + profile: + type: string + +paths: + '/': + get: + operationId: opId + summary: summary + responses: + '200': + description: OK diff --git a/tests/specs/issue_fix/30_add_validation_rules_by_attribute_name_or_pattern/mysql/models/User.php b/tests/specs/issue_fix/30_add_validation_rules_by_attribute_name_or_pattern/mysql/models/User.php new file mode 100644 index 00000000..9b837d6e --- /dev/null +++ b/tests/specs/issue_fix/30_add_validation_rules_by_attribute_name_or_pattern/mysql/models/User.php @@ -0,0 +1,10 @@ + [['name', 'photo', 'profile_photo', 'pdf', 'a_file', 'profile'], 'trim'], + 'required' => [['name'], 'required'], + 'name_string' => [['name'], 'string', 'max' => 128], + 'photo_image' => [['photo'], 'image'], + 'profile_photo_image' => [['profile_photo'], 'image'], + 'pdf_file' => [['pdf'], 'file'], + 'a_file_file' => [['a_file'], 'file'], + 'profile_string' => [['profile'], 'string'], + ]; + } +} diff --git a/tests/unit/IssueFixTest.php b/tests/unit/IssueFixTest.php index b6c7abdb..e08e6b2b 100644 --- a/tests/unit/IssueFixTest.php +++ b/tests/unit/IssueFixTest.php @@ -360,4 +360,18 @@ public function test158BugGiiapiGeneratedRulesEnumWithTrim() ]); $this->checkFiles($actualFiles, $expectedFiles); } + + // https://github.com/php-openapi/yii2-openapi/issues/30 + public function test30AddValidationRulesByAttributeNameOrPattern() + { + $testFile = Yii::getAlias("@specs/issue_fix/30_add_validation_rules_by_attribute_name_or_pattern/index.php"); + $this->runGenerator($testFile); + $actualFiles = FileHelper::findFiles(Yii::getAlias('@app'), [ + 'recursive' => true, + ]); + $expectedFiles = FileHelper::findFiles(Yii::getAlias("@specs/issue_fix/30_add_validation_rules_by_attribute_name_or_pattern/mysql"), [ + 'recursive' => true, + ]); + $this->checkFiles($actualFiles, $expectedFiles); + } }