暂存
This commit is contained in:
Vendored
+2148
File diff suppressed because it is too large
Load Diff
+2150
File diff suppressed because it is too large
Load Diff
+26
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "webman/validation",
|
||||
"type": "library",
|
||||
"license": "MIT",
|
||||
"description": "Webman plugin webman/validation",
|
||||
"require": {
|
||||
"illuminate/validation": "*",
|
||||
"illuminate/translation": "*",
|
||||
"workerman/webman-framework": "^2.1 || dev-master",
|
||||
"webman/console": ">=2.1.7"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Webman\\Validation\\": "src",
|
||||
"support\\validation\\": "src/support/validation"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"Webman\\Validation\\Tests\\": "src/Tests"
|
||||
}
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "*"
|
||||
}
|
||||
}
|
||||
Vendored
+10
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit bootstrap="src/Tests/bootstrap.php"
|
||||
colors="true"
|
||||
cacheDirectory=".phpunit.cache">
|
||||
<testsuites>
|
||||
<testsuite name="webman-validation">
|
||||
<directory>src/Tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
</phpunit>
|
||||
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Validierungsmeldungen
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
'accepted' => 'Das Feld :attribute muss akzeptiert werden.',
|
||||
'accepted_if' => 'Das Feld :attribute muss akzeptiert werden, wenn :other :value ist.',
|
||||
'active_url' => 'Das Feld :attribute muss eine gültige URL sein.',
|
||||
'after' => 'Das Feld :attribute muss ein Datum nach dem :date sein.',
|
||||
'after_or_equal' => 'Das Feld :attribute muss ein Datum nach oder gleich :date sein.',
|
||||
'alpha' => 'Das Feld :attribute darf nur Buchstaben enthalten.',
|
||||
'alpha_dash' => 'Das Feld :attribute darf nur Buchstaben, Zahlen, Bindestriche und Unterstriche enthalten.',
|
||||
'alpha_num' => 'Das Feld :attribute darf nur Buchstaben und Zahlen enthalten.',
|
||||
'any_of' => 'Das Feld :attribute ist ungültig.',
|
||||
'array' => 'Das Feld :attribute muss ein Array sein.',
|
||||
'ascii' => 'Das Feld :attribute darf nur einbyte alphanumerische Zeichen und Symbole enthalten.',
|
||||
'before' => 'Das Feld :attribute muss ein Datum vor dem :date sein.',
|
||||
'before_or_equal' => 'Das Feld :attribute muss ein Datum vor oder gleich :date sein.',
|
||||
'between' => [
|
||||
'array' => 'Das Feld :attribute muss zwischen :min und :max Elemente haben.',
|
||||
'file' => 'Das Feld :attribute muss zwischen :min und :max Kilobyte sein.',
|
||||
'numeric' => 'Das Feld :attribute muss zwischen :min und :max liegen.',
|
||||
'string' => 'Das Feld :attribute muss zwischen :min und :max Zeichen haben.',
|
||||
],
|
||||
'boolean' => 'Das Feld :attribute muss wahr oder falsch sein.',
|
||||
'can' => 'Das Feld :attribute enthält einen nicht autorisierten Wert.',
|
||||
'confirmed' => 'Die Bestätigung des Feldes :attribute stimmt nicht überein.',
|
||||
'contains' => 'Das Feld :attribute enthält keinen erforderlichen Wert.',
|
||||
'current_password' => 'Das Passwort ist falsch.',
|
||||
'date' => 'Das Feld :attribute muss ein gültiges Datum sein.',
|
||||
'date_equals' => 'Das Feld :attribute muss ein Datum gleich :date sein.',
|
||||
'date_format' => 'Das Feld :attribute muss dem Format :format entsprechen.',
|
||||
'decimal' => 'Das Feld :attribute muss :decimal Dezimalstellen haben.',
|
||||
'declined' => 'Das Feld :attribute muss abgelehnt werden.',
|
||||
'declined_if' => 'Das Feld :attribute muss abgelehnt werden, wenn :other :value ist.',
|
||||
'different' => 'Die Felder :attribute und :other müssen unterschiedlich sein.',
|
||||
'digits' => 'Das Feld :attribute muss :digits Ziffern haben.',
|
||||
'digits_between' => 'Das Feld :attribute muss zwischen :min und :max Ziffern haben.',
|
||||
'dimensions' => 'Das Feld :attribute hat ungültige Bildabmessungen.',
|
||||
'distinct' => 'Das Feld :attribute hat einen doppelten Wert.',
|
||||
'doesnt_contain' => 'Das Feld :attribute darf Folgendes nicht enthalten: :values.',
|
||||
'doesnt_end_with' => 'Das Feld :attribute darf nicht mit Folgendem enden: :values.',
|
||||
'doesnt_start_with' => 'Das Feld :attribute darf nicht mit Folgendem beginnen: :values.',
|
||||
'email' => 'Das Feld :attribute muss eine gültige E-Mail-Adresse sein.',
|
||||
'encoding' => 'Das Feld :attribute muss in :encoding kodiert sein.',
|
||||
'ends_with' => 'Das Feld :attribute muss mit Folgendem enden: :values.',
|
||||
'enum' => 'Die ausgewählte :attribute ist ungültig.',
|
||||
'exists' => 'Die ausgewählte :attribute ist ungültig.',
|
||||
'extensions' => 'Das Feld :attribute muss eine der folgenden Erweiterungen haben: :values.',
|
||||
'file' => 'Das Feld :attribute muss eine Datei sein.',
|
||||
'filled' => 'Das Feld :attribute muss einen Wert haben.',
|
||||
'gt' => [
|
||||
'array' => 'Das Feld :attribute muss mehr als :value Elemente haben.',
|
||||
'file' => 'Das Feld :attribute muss größer als :value Kilobyte sein.',
|
||||
'numeric' => 'Das Feld :attribute muss größer als :value sein.',
|
||||
'string' => 'Das Feld :attribute muss mehr als :value Zeichen haben.',
|
||||
],
|
||||
'gte' => [
|
||||
'array' => 'Das Feld :attribute muss :value oder mehr Elemente haben.',
|
||||
'file' => 'Das Feld :attribute muss größer oder gleich :value Kilobyte sein.',
|
||||
'numeric' => 'Das Feld :attribute muss größer oder gleich :value sein.',
|
||||
'string' => 'Das Feld :attribute muss :value oder mehr Zeichen haben.',
|
||||
],
|
||||
'hex_color' => 'Das Feld :attribute muss eine gültige Hexadezimalfarbe sein.',
|
||||
'image' => 'Das Feld :attribute muss ein Bild sein.',
|
||||
'in' => 'Die ausgewählte :attribute ist ungültig.',
|
||||
'in_array' => 'Das Feld :attribute muss in :other existieren.',
|
||||
'in_array_keys' => 'Das Feld :attribute muss mindestens einen der folgenden Schlüssel enthalten: :values.',
|
||||
'integer' => 'Das Feld :attribute muss eine ganze Zahl sein.',
|
||||
'ip' => 'Das Feld :attribute muss eine gültige IP-Adresse sein.',
|
||||
'ipv4' => 'Das Feld :attribute muss eine gültige IPv4-Adresse sein.',
|
||||
'ipv6' => 'Das Feld :attribute muss eine gültige IPv6-Adresse sein.',
|
||||
'json' => 'Das Feld :attribute muss eine gültige JSON-Zeichenkette sein.',
|
||||
'list' => 'Das Feld :attribute muss eine Liste sein.',
|
||||
'lowercase' => 'Das Feld :attribute muss in Kleinbuchstaben sein.',
|
||||
'lt' => [
|
||||
'array' => 'Das Feld :attribute muss weniger als :value Elemente haben.',
|
||||
'file' => 'Das Feld :attribute muss kleiner als :value Kilobyte sein.',
|
||||
'numeric' => 'Das Feld :attribute muss kleiner als :value sein.',
|
||||
'string' => 'Das Feld :attribute muss weniger als :value Zeichen haben.',
|
||||
],
|
||||
'lte' => [
|
||||
'array' => 'Das Feld :attribute darf nicht mehr als :value Elemente haben.',
|
||||
'file' => 'Das Feld :attribute muss kleiner oder gleich :value Kilobyte sein.',
|
||||
'numeric' => 'Das Feld :attribute muss kleiner oder gleich :value sein.',
|
||||
'string' => 'Das Feld :attribute darf nicht mehr als :value Zeichen haben.',
|
||||
],
|
||||
'mac_address' => 'Das Feld :attribute muss eine gültige MAC-Adresse sein.',
|
||||
'max' => [
|
||||
'array' => 'Das Feld :attribute darf nicht mehr als :max Elemente haben.',
|
||||
'file' => 'Das Feld :attribute darf nicht größer als :max Kilobyte sein.',
|
||||
'numeric' => 'Das Feld :attribute darf nicht größer als :max sein.',
|
||||
'string' => 'Das Feld :attribute darf nicht mehr als :max Zeichen haben.',
|
||||
],
|
||||
'max_digits' => 'Das Feld :attribute darf nicht mehr als :max Ziffern haben.',
|
||||
'mimes' => 'Das Feld :attribute muss eine Datei vom Typ :values sein.',
|
||||
'mimetypes' => 'Das Feld :attribute muss eine Datei vom Typ :values sein.',
|
||||
'min' => [
|
||||
'array' => 'Das Feld :attribute muss mindestens :min Elemente haben.',
|
||||
'file' => 'Das Feld :attribute muss mindestens :min Kilobyte sein.',
|
||||
'numeric' => 'Das Feld :attribute muss mindestens :min sein.',
|
||||
'string' => 'Das Feld :attribute muss mindestens :min Zeichen haben.',
|
||||
],
|
||||
'min_digits' => 'Das Feld :attribute muss mindestens :min Ziffern haben.',
|
||||
'missing' => 'Das Feld :attribute muss fehlen.',
|
||||
'missing_if' => 'Das Feld :attribute muss fehlen, wenn :other :value ist.',
|
||||
'missing_unless' => 'Das Feld :attribute muss fehlen, es sei denn :other ist :value.',
|
||||
'missing_with' => 'Das Feld :attribute muss fehlen, wenn :values vorhanden ist.',
|
||||
'missing_with_all' => 'Das Feld :attribute muss fehlen, wenn :values vorhanden sind.',
|
||||
'multiple_of' => 'Das Feld :attribute muss ein Vielfaches von :value sein.',
|
||||
'not_in' => 'Die ausgewählte :attribute ist ungültig.',
|
||||
'not_regex' => 'Das Format des Feldes :attribute ist ungültig.',
|
||||
'numeric' => 'Das Feld :attribute muss eine Zahl sein.',
|
||||
'password' => [
|
||||
'letters' => 'Das Feld :attribute muss mindestens einen Buchstaben enthalten.',
|
||||
'mixed' => 'Das Feld :attribute muss mindestens einen Groß- und einen Kleinbuchstaben enthalten.',
|
||||
'numbers' => 'Das Feld :attribute muss mindestens eine Zahl enthalten.',
|
||||
'symbols' => 'Das Feld :attribute muss mindestens ein Symbol enthalten.',
|
||||
'uncompromised' => 'Die angegebene :attribute ist in einem Datenleck aufgetaucht. Bitte wählen Sie eine andere :attribute.',
|
||||
],
|
||||
'present' => 'Das Feld :attribute muss vorhanden sein.',
|
||||
'present_if' => 'Das Feld :attribute muss vorhanden sein, wenn :other :value ist.',
|
||||
'present_unless' => 'Das Feld :attribute muss vorhanden sein, es sei denn :other ist :value.',
|
||||
'present_with' => 'Das Feld :attribute muss vorhanden sein, wenn :values vorhanden ist.',
|
||||
'present_with_all' => 'Das Feld :attribute muss vorhanden sein, wenn :values vorhanden sind.',
|
||||
'prohibited' => 'Das Feld :attribute ist verboten.',
|
||||
'prohibited_if' => 'Das Feld :attribute ist verboten, wenn :other :value ist.',
|
||||
'prohibited_if_accepted' => 'Das Feld :attribute ist verboten, wenn :other akzeptiert wird.',
|
||||
'prohibited_if_declined' => 'Das Feld :attribute ist verboten, wenn :other abgelehnt wird.',
|
||||
'prohibited_unless' => 'Das Feld :attribute ist verboten, es sei denn :other ist in :values.',
|
||||
'prohibits' => 'Das Feld :attribute verbietet die Anwesenheit von :other.',
|
||||
'regex' => 'Das Format des Feldes :attribute ist ungültig.',
|
||||
'required' => 'Das Feld :attribute ist erforderlich.',
|
||||
'required_array_keys' => 'Das Feld :attribute muss Einträge für Folgendes enthalten: :values.',
|
||||
'required_if' => 'Das Feld :attribute ist erforderlich, wenn :other :value ist.',
|
||||
'required_if_accepted' => 'Das Feld :attribute ist erforderlich, wenn :other akzeptiert wird.',
|
||||
'required_if_declined' => 'Das Feld :attribute ist erforderlich, wenn :other abgelehnt wird.',
|
||||
'required_unless' => 'Das Feld :attribute ist erforderlich, es sei denn :other ist in :values.',
|
||||
'required_with' => 'Das Feld :attribute ist erforderlich, wenn :values vorhanden ist.',
|
||||
'required_with_all' => 'Das Feld :attribute ist erforderlich, wenn :values vorhanden sind.',
|
||||
'required_without' => 'Das Feld :attribute ist erforderlich, wenn :values nicht vorhanden ist.',
|
||||
'required_without_all' => 'Das Feld :attribute ist erforderlich, wenn keines von :values vorhanden ist.',
|
||||
'same' => 'Die Felder :attribute und :other müssen übereinstimmen.',
|
||||
'size' => [
|
||||
'array' => 'Das Feld :attribute muss :size Elemente enthalten.',
|
||||
'file' => 'Das Feld :attribute muss :size Kilobyte sein.',
|
||||
'numeric' => 'Das Feld :attribute muss :size sein.',
|
||||
'string' => 'Das Feld :attribute muss :size Zeichen haben.',
|
||||
],
|
||||
'starts_with' => 'Das Feld :attribute muss mit Folgendem beginnen: :values.',
|
||||
'string' => 'Das Feld :attribute muss eine Zeichenkette sein.',
|
||||
'timezone' => 'Das Feld :attribute muss eine gültige Zeitzone sein.',
|
||||
'unique' => 'Die :attribute wurde bereits verwendet.',
|
||||
'uploaded' => 'Der Upload von :attribute ist fehlgeschlagen.',
|
||||
'uppercase' => 'Das Feld :attribute muss in Großbuchstaben sein.',
|
||||
'url' => 'Das Feld :attribute muss eine gültige URL sein.',
|
||||
'ulid' => 'Das Feld :attribute muss eine gültige ULID sein.',
|
||||
'uuid' => 'Das Feld :attribute muss eine gültige UUID sein.',
|
||||
|
||||
'custom' => [
|
||||
'attribute-name' => [
|
||||
'rule-name' => 'custom-message',
|
||||
],
|
||||
],
|
||||
|
||||
'attributes' => [],
|
||||
];
|
||||
@@ -0,0 +1,180 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Validation Language Lines
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
'accepted' => 'The :attribute field must be accepted.',
|
||||
'accepted_if' => 'The :attribute field must be accepted when :other is :value.',
|
||||
'active_url' => 'The :attribute field must be a valid URL.',
|
||||
'after' => 'The :attribute field must be a date after :date.',
|
||||
'after_or_equal' => 'The :attribute field must be a date after or equal to :date.',
|
||||
'alpha' => 'The :attribute field must only contain letters.',
|
||||
'alpha_dash' => 'The :attribute field must only contain letters, numbers, dashes, and underscores.',
|
||||
'alpha_num' => 'The :attribute field must only contain letters and numbers.',
|
||||
'any_of' => 'The :attribute field is invalid.',
|
||||
'array' => 'The :attribute field must be an array.',
|
||||
'ascii' => 'The :attribute field must only contain single-byte alphanumeric characters and symbols.',
|
||||
'before' => 'The :attribute field must be a date before :date.',
|
||||
'before_or_equal' => 'The :attribute field must be a date before or equal to :date.',
|
||||
'between' => [
|
||||
'array' => 'The :attribute field must have between :min and :max items.',
|
||||
'file' => 'The :attribute field must be between :min and :max kilobytes.',
|
||||
'numeric' => 'The :attribute field must be between :min and :max.',
|
||||
'string' => 'The :attribute field must be between :min and :max characters.',
|
||||
],
|
||||
'boolean' => 'The :attribute field must be true or false.',
|
||||
'can' => 'The :attribute field contains an unauthorized value.',
|
||||
'confirmed' => 'The :attribute field confirmation does not match.',
|
||||
'contains' => 'The :attribute field is missing a required value.',
|
||||
'current_password' => 'The password is incorrect.',
|
||||
'date' => 'The :attribute field must be a valid date.',
|
||||
'date_equals' => 'The :attribute field must be a date equal to :date.',
|
||||
'date_format' => 'The :attribute field must match the format :format.',
|
||||
'decimal' => 'The :attribute field must have :decimal decimal places.',
|
||||
'declined' => 'The :attribute field must be declined.',
|
||||
'declined_if' => 'The :attribute field must be declined when :other is :value.',
|
||||
'different' => 'The :attribute field and :other must be different.',
|
||||
'digits' => 'The :attribute field must be :digits digits.',
|
||||
'digits_between' => 'The :attribute field must be between :min and :max digits.',
|
||||
'dimensions' => 'The :attribute field has invalid image dimensions.',
|
||||
'distinct' => 'The :attribute field has a duplicate value.',
|
||||
'doesnt_contain' => 'The :attribute field must not contain any of the following: :values.',
|
||||
'doesnt_end_with' => 'The :attribute field must not end with one of the following: :values.',
|
||||
'doesnt_start_with' => 'The :attribute field must not start with one of the following: :values.',
|
||||
'email' => 'The :attribute field must be a valid email address.',
|
||||
'encoding' => 'The :attribute field must be encoded in :encoding.',
|
||||
'ends_with' => 'The :attribute field must end with one of the following: :values.',
|
||||
'enum' => 'The selected :attribute is invalid.',
|
||||
'exists' => 'The selected :attribute is invalid.',
|
||||
'extensions' => 'The :attribute field must have one of the following extensions: :values.',
|
||||
'file' => 'The :attribute field must be a file.',
|
||||
'filled' => 'The :attribute field must have a value.',
|
||||
'gt' => [
|
||||
'array' => 'The :attribute field must have more than :value items.',
|
||||
'file' => 'The :attribute field must be greater than :value kilobytes.',
|
||||
'numeric' => 'The :attribute field must be greater than :value.',
|
||||
'string' => 'The :attribute field must be greater than :value characters.',
|
||||
],
|
||||
'gte' => [
|
||||
'array' => 'The :attribute field must have :value items or more.',
|
||||
'file' => 'The :attribute field must be greater than or equal to :value kilobytes.',
|
||||
'numeric' => 'The :attribute field must be greater than or equal to :value.',
|
||||
'string' => 'The :attribute field must be greater than or equal to :value characters.',
|
||||
],
|
||||
'hex_color' => 'The :attribute field must be a valid hexadecimal color.',
|
||||
'image' => 'The :attribute field must be an image.',
|
||||
'in' => 'The selected :attribute is invalid.',
|
||||
'in_array' => 'The :attribute field must exist in :other.',
|
||||
'in_array_keys' => 'The :attribute field must contain at least one of the following keys: :values.',
|
||||
'integer' => 'The :attribute field must be an integer.',
|
||||
'ip' => 'The :attribute field must be a valid IP address.',
|
||||
'ipv4' => 'The :attribute field must be a valid IPv4 address.',
|
||||
'ipv6' => 'The :attribute field must be a valid IPv6 address.',
|
||||
'json' => 'The :attribute field must be a valid JSON string.',
|
||||
'list' => 'The :attribute field must be a list.',
|
||||
'lowercase' => 'The :attribute field must be lowercase.',
|
||||
'lt' => [
|
||||
'array' => 'The :attribute field must have less than :value items.',
|
||||
'file' => 'The :attribute field must be less than :value kilobytes.',
|
||||
'numeric' => 'The :attribute field must be less than :value.',
|
||||
'string' => 'The :attribute field must be less than :value characters.',
|
||||
],
|
||||
'lte' => [
|
||||
'array' => 'The :attribute field must not have more than :value items.',
|
||||
'file' => 'The :attribute field must be less than or equal to :value kilobytes.',
|
||||
'numeric' => 'The :attribute field must be less than or equal to :value.',
|
||||
'string' => 'The :attribute field must be less than or equal to :value characters.',
|
||||
],
|
||||
'mac_address' => 'The :attribute field must be a valid MAC address.',
|
||||
'max' => [
|
||||
'array' => 'The :attribute field must not have more than :max items.',
|
||||
'file' => 'The :attribute field must not be greater than :max kilobytes.',
|
||||
'numeric' => 'The :attribute field must not be greater than :max.',
|
||||
'string' => 'The :attribute field must not be greater than :max characters.',
|
||||
],
|
||||
'max_digits' => 'The :attribute field must not have more than :max digits.',
|
||||
'mimes' => 'The :attribute field must be a file of type: :values.',
|
||||
'mimetypes' => 'The :attribute field must be a file of type: :values.',
|
||||
'min' => [
|
||||
'array' => 'The :attribute field must have at least :min items.',
|
||||
'file' => 'The :attribute field must be at least :min kilobytes.',
|
||||
'numeric' => 'The :attribute field must be at least :min.',
|
||||
'string' => 'The :attribute field must be at least :min characters.',
|
||||
],
|
||||
'min_digits' => 'The :attribute field must have at least :min digits.',
|
||||
'missing' => 'The :attribute field must be missing.',
|
||||
'missing_if' => 'The :attribute field must be missing when :other is :value.',
|
||||
'missing_unless' => 'The :attribute field must be missing unless :other is :value.',
|
||||
'missing_with' => 'The :attribute field must be missing when :values is present.',
|
||||
'missing_with_all' => 'The :attribute field must be missing when :values are present.',
|
||||
'multiple_of' => 'The :attribute field must be a multiple of :value.',
|
||||
'not_in' => 'The selected :attribute is invalid.',
|
||||
'not_regex' => 'The :attribute field format is invalid.',
|
||||
'numeric' => 'The :attribute field must be a number.',
|
||||
'password' => [
|
||||
'letters' => 'The :attribute field must contain at least one letter.',
|
||||
'mixed' => 'The :attribute field must contain at least one uppercase and one lowercase letter.',
|
||||
'numbers' => 'The :attribute field must contain at least one number.',
|
||||
'symbols' => 'The :attribute field must contain at least one symbol.',
|
||||
'uncompromised' => 'The given :attribute has appeared in a data leak. Please choose a different :attribute.',
|
||||
],
|
||||
'present' => 'The :attribute field must be present.',
|
||||
'present_if' => 'The :attribute field must be present when :other is :value.',
|
||||
'present_unless' => 'The :attribute field must be present unless :other is :value.',
|
||||
'present_with' => 'The :attribute field must be present when :values is present.',
|
||||
'present_with_all' => 'The :attribute field must be present when :values are present.',
|
||||
'prohibited' => 'The :attribute field is prohibited.',
|
||||
'prohibited_if' => 'The :attribute field is prohibited when :other is :value.',
|
||||
'prohibited_if_accepted' => 'The :attribute field is prohibited when :other is accepted.',
|
||||
'prohibited_if_declined' => 'The :attribute field is prohibited when :other is declined.',
|
||||
'prohibited_unless' => 'The :attribute field is prohibited unless :other is in :values.',
|
||||
'prohibits' => 'The :attribute field prohibits :other from being present.',
|
||||
'regex' => 'The :attribute field format is invalid.',
|
||||
'required' => 'The :attribute field is required.',
|
||||
'required_array_keys' => 'The :attribute field must contain entries for: :values.',
|
||||
'required_if' => 'The :attribute field is required when :other is :value.',
|
||||
'required_if_accepted' => 'The :attribute field is required when :other is accepted.',
|
||||
'required_if_declined' => 'The :attribute field is required when :other is declined.',
|
||||
'required_unless' => 'The :attribute field is required unless :other is in :values.',
|
||||
'required_with' => 'The :attribute field is required when :values is present.',
|
||||
'required_with_all' => 'The :attribute field is required when :values are present.',
|
||||
'required_without' => 'The :attribute field is required when :values is not present.',
|
||||
'required_without_all' => 'The :attribute field is required when none of :values are present.',
|
||||
'same' => 'The :attribute field must match :other.',
|
||||
'size' => [
|
||||
'array' => 'The :attribute field must contain :size items.',
|
||||
'file' => 'The :attribute field must be :size kilobytes.',
|
||||
'numeric' => 'The :attribute field must be :size.',
|
||||
'string' => 'The :attribute field must be :size characters.',
|
||||
],
|
||||
'starts_with' => 'The :attribute field must start with one of the following: :values.',
|
||||
'string' => 'The :attribute field must be a string.',
|
||||
'timezone' => 'The :attribute field must be a valid timezone.',
|
||||
'unique' => 'The :attribute has already been taken.',
|
||||
'uploaded' => 'The :attribute failed to upload.',
|
||||
'uppercase' => 'The :attribute field must be uppercase.',
|
||||
'url' => 'The :attribute field must be a valid URL.',
|
||||
'ulid' => 'The :attribute field must be a valid ULID.',
|
||||
'uuid' => 'The :attribute field must be a valid UUID.',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Custom Validation Language Lines
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
'custom' => [
|
||||
'attribute-name' => [
|
||||
'rule-name' => 'custom-message',
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Custom Validation Attributes
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
'attributes' => [],
|
||||
];
|
||||
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Mensajes de validación
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
'accepted' => 'El campo :attribute debe ser aceptado.',
|
||||
'accepted_if' => 'El campo :attribute debe ser aceptado cuando :other sea :value.',
|
||||
'active_url' => 'El campo :attribute debe ser una URL válida.',
|
||||
'after' => 'El campo :attribute debe ser una fecha posterior a :date.',
|
||||
'after_or_equal' => 'El campo :attribute debe ser una fecha posterior o igual a :date.',
|
||||
'alpha' => 'El campo :attribute solo debe contener letras.',
|
||||
'alpha_dash' => 'El campo :attribute solo debe contener letras, números, guiones y guiones bajos.',
|
||||
'alpha_num' => 'El campo :attribute solo debe contener letras y números.',
|
||||
'any_of' => 'El campo :attribute no es válido.',
|
||||
'array' => 'El campo :attribute debe ser un array.',
|
||||
'ascii' => 'El campo :attribute solo debe contener caracteres alfanuméricos y símbolos de un byte.',
|
||||
'before' => 'El campo :attribute debe ser una fecha anterior a :date.',
|
||||
'before_or_equal' => 'El campo :attribute debe ser una fecha anterior o igual a :date.',
|
||||
'between' => [
|
||||
'array' => 'El campo :attribute debe tener entre :min y :max elementos.',
|
||||
'file' => 'El campo :attribute debe tener entre :min y :max kilobytes.',
|
||||
'numeric' => 'El campo :attribute debe estar entre :min y :max.',
|
||||
'string' => 'El campo :attribute debe tener entre :min y :max caracteres.',
|
||||
],
|
||||
'boolean' => 'El campo :attribute debe ser verdadero o falso.',
|
||||
'can' => 'El campo :attribute contiene un valor no autorizado.',
|
||||
'confirmed' => 'La confirmación del campo :attribute no coincide.',
|
||||
'contains' => 'El campo :attribute no contiene un valor requerido.',
|
||||
'current_password' => 'La contraseña es incorrecta.',
|
||||
'date' => 'El campo :attribute debe ser una fecha válida.',
|
||||
'date_equals' => 'El campo :attribute debe ser una fecha igual a :date.',
|
||||
'date_format' => 'El campo :attribute debe coincidir con el formato :format.',
|
||||
'decimal' => 'El campo :attribute debe tener :decimal decimales.',
|
||||
'declined' => 'El campo :attribute debe ser rechazado.',
|
||||
'declined_if' => 'El campo :attribute debe ser rechazado cuando :other sea :value.',
|
||||
'different' => 'Los campos :attribute y :other deben ser diferentes.',
|
||||
'digits' => 'El campo :attribute debe tener :digits dígitos.',
|
||||
'digits_between' => 'El campo :attribute debe tener entre :min y :max dígitos.',
|
||||
'dimensions' => 'El campo :attribute tiene dimensiones de imagen inválidas.',
|
||||
'distinct' => 'El campo :attribute tiene un valor duplicado.',
|
||||
'doesnt_contain' => 'El campo :attribute no debe contener: :values.',
|
||||
'doesnt_end_with' => 'El campo :attribute no debe terminar con: :values.',
|
||||
'doesnt_start_with' => 'El campo :attribute no debe comenzar con: :values.',
|
||||
'email' => 'El campo :attribute debe ser una dirección de correo electrónico válida.',
|
||||
'encoding' => 'El campo :attribute debe estar codificado en :encoding.',
|
||||
'ends_with' => 'El campo :attribute debe terminar con: :values.',
|
||||
'enum' => 'El :attribute seleccionado no es válido.',
|
||||
'exists' => 'El :attribute seleccionado no es válido.',
|
||||
'extensions' => 'El campo :attribute debe tener una de las siguientes extensiones: :values.',
|
||||
'file' => 'El campo :attribute debe ser un archivo.',
|
||||
'filled' => 'El campo :attribute debe tener un valor.',
|
||||
'gt' => [
|
||||
'array' => 'El campo :attribute debe tener más de :value elementos.',
|
||||
'file' => 'El campo :attribute debe ser mayor que :value kilobytes.',
|
||||
'numeric' => 'El campo :attribute debe ser mayor que :value.',
|
||||
'string' => 'El campo :attribute debe tener más de :value caracteres.',
|
||||
],
|
||||
'gte' => [
|
||||
'array' => 'El campo :attribute debe tener :value elementos o más.',
|
||||
'file' => 'El campo :attribute debe ser mayor o igual que :value kilobytes.',
|
||||
'numeric' => 'El campo :attribute debe ser mayor o igual que :value.',
|
||||
'string' => 'El campo :attribute debe tener :value caracteres o más.',
|
||||
],
|
||||
'hex_color' => 'El campo :attribute debe ser un color hexadecimal válido.',
|
||||
'image' => 'El campo :attribute debe ser una imagen.',
|
||||
'in' => 'El :attribute seleccionado no es válido.',
|
||||
'in_array' => 'El campo :attribute debe existir en :other.',
|
||||
'in_array_keys' => 'El campo :attribute debe contener al menos una de las siguientes claves: :values.',
|
||||
'integer' => 'El campo :attribute debe ser un número entero.',
|
||||
'ip' => 'El campo :attribute debe ser una dirección IP válida.',
|
||||
'ipv4' => 'El campo :attribute debe ser una dirección IPv4 válida.',
|
||||
'ipv6' => 'El campo :attribute debe ser una dirección IPv6 válida.',
|
||||
'json' => 'El campo :attribute debe ser una cadena JSON válida.',
|
||||
'list' => 'El campo :attribute debe ser una lista.',
|
||||
'lowercase' => 'El campo :attribute debe estar en minúsculas.',
|
||||
'lt' => [
|
||||
'array' => 'El campo :attribute debe tener menos de :value elementos.',
|
||||
'file' => 'El campo :attribute debe ser menor que :value kilobytes.',
|
||||
'numeric' => 'El campo :attribute debe ser menor que :value.',
|
||||
'string' => 'El campo :attribute debe tener menos de :value caracteres.',
|
||||
],
|
||||
'lte' => [
|
||||
'array' => 'El campo :attribute no debe tener más de :value elementos.',
|
||||
'file' => 'El campo :attribute debe ser menor o igual que :value kilobytes.',
|
||||
'numeric' => 'El campo :attribute debe ser menor o igual que :value.',
|
||||
'string' => 'El campo :attribute debe tener :value caracteres o menos.',
|
||||
],
|
||||
'mac_address' => 'El campo :attribute debe ser una dirección MAC válida.',
|
||||
'max' => [
|
||||
'array' => 'El campo :attribute no debe tener más de :max elementos.',
|
||||
'file' => 'El campo :attribute no debe ser mayor que :max kilobytes.',
|
||||
'numeric' => 'El campo :attribute no debe ser mayor que :max.',
|
||||
'string' => 'El campo :attribute no debe tener más de :max caracteres.',
|
||||
],
|
||||
'max_digits' => 'El campo :attribute no debe tener más de :max dígitos.',
|
||||
'mimes' => 'El campo :attribute debe ser un archivo de tipo: :values.',
|
||||
'mimetypes' => 'El campo :attribute debe ser un archivo de tipo: :values.',
|
||||
'min' => [
|
||||
'array' => 'El campo :attribute debe tener al menos :min elementos.',
|
||||
'file' => 'El campo :attribute debe tener al menos :min kilobytes.',
|
||||
'numeric' => 'El campo :attribute debe ser al menos :min.',
|
||||
'string' => 'El campo :attribute debe tener al menos :min caracteres.',
|
||||
],
|
||||
'min_digits' => 'El campo :attribute debe tener al menos :min dígitos.',
|
||||
'missing' => 'El campo :attribute debe estar ausente.',
|
||||
'missing_if' => 'El campo :attribute debe estar ausente cuando :other sea :value.',
|
||||
'missing_unless' => 'El campo :attribute debe estar ausente a menos que :other sea :value.',
|
||||
'missing_with' => 'El campo :attribute debe estar ausente cuando :values esté presente.',
|
||||
'missing_with_all' => 'El campo :attribute debe estar ausente cuando :values estén presentes.',
|
||||
'multiple_of' => 'El campo :attribute debe ser un múltiplo de :value.',
|
||||
'not_in' => 'El :attribute seleccionado no es válido.',
|
||||
'not_regex' => 'El formato del campo :attribute no es válido.',
|
||||
'numeric' => 'El campo :attribute debe ser un número.',
|
||||
'password' => [
|
||||
'letters' => 'El campo :attribute debe contener al menos una letra.',
|
||||
'mixed' => 'El campo :attribute debe contener al menos una mayúscula y una minúscula.',
|
||||
'numbers' => 'El campo :attribute debe contener al menos un número.',
|
||||
'symbols' => 'El campo :attribute debe contener al menos un símbolo.',
|
||||
'uncompromised' => 'El :attribute proporcionado ha aparecido en una filtración de datos. Por favor elija un :attribute diferente.',
|
||||
],
|
||||
'present' => 'El campo :attribute debe estar presente.',
|
||||
'present_if' => 'El campo :attribute debe estar presente cuando :other sea :value.',
|
||||
'present_unless' => 'El campo :attribute debe estar presente a menos que :other sea :value.',
|
||||
'present_with' => 'El campo :attribute debe estar presente cuando :values esté presente.',
|
||||
'present_with_all' => 'El campo :attribute debe estar presente cuando :values estén presentes.',
|
||||
'prohibited' => 'El campo :attribute está prohibido.',
|
||||
'prohibited_if' => 'El campo :attribute está prohibido cuando :other sea :value.',
|
||||
'prohibited_if_accepted' => 'El campo :attribute está prohibido cuando :other sea aceptado.',
|
||||
'prohibited_if_declined' => 'El campo :attribute está prohibido cuando :other sea rechazado.',
|
||||
'prohibited_unless' => 'El campo :attribute está prohibido a menos que :other esté en :values.',
|
||||
'prohibits' => 'El campo :attribute prohíbe que :other esté presente.',
|
||||
'regex' => 'El formato del campo :attribute no es válido.',
|
||||
'required' => 'El campo :attribute es obligatorio.',
|
||||
'required_array_keys' => 'El campo :attribute debe contener entradas para: :values.',
|
||||
'required_if' => 'El campo :attribute es obligatorio cuando :other sea :value.',
|
||||
'required_if_accepted' => 'El campo :attribute es obligatorio cuando :other sea aceptado.',
|
||||
'required_if_declined' => 'El campo :attribute es obligatorio cuando :other sea rechazado.',
|
||||
'required_unless' => 'El campo :attribute es obligatorio a menos que :other esté en :values.',
|
||||
'required_with' => 'El campo :attribute es obligatorio cuando :values esté presente.',
|
||||
'required_with_all' => 'El campo :attribute es obligatorio cuando :values estén presentes.',
|
||||
'required_without' => 'El campo :attribute es obligatorio cuando :values no esté presente.',
|
||||
'required_without_all' => 'El campo :attribute es obligatorio cuando ninguno de :values esté presente.',
|
||||
'same' => 'Los campos :attribute y :other deben coincidir.',
|
||||
'size' => [
|
||||
'array' => 'El campo :attribute debe contener :size elementos.',
|
||||
'file' => 'El campo :attribute debe tener :size kilobytes.',
|
||||
'numeric' => 'El campo :attribute debe ser :size.',
|
||||
'string' => 'El campo :attribute debe tener :size caracteres.',
|
||||
],
|
||||
'starts_with' => 'El campo :attribute debe comenzar con: :values.',
|
||||
'string' => 'El campo :attribute debe ser una cadena de caracteres.',
|
||||
'timezone' => 'El campo :attribute debe ser una zona horaria válida.',
|
||||
'unique' => 'El :attribute ya ha sido utilizado.',
|
||||
'uploaded' => 'La subida del :attribute ha fallado.',
|
||||
'uppercase' => 'El campo :attribute debe estar en mayúsculas.',
|
||||
'url' => 'El campo :attribute debe ser una URL válida.',
|
||||
'ulid' => 'El campo :attribute debe ser un ULID válido.',
|
||||
'uuid' => 'El campo :attribute debe ser un UUID válido.',
|
||||
|
||||
'custom' => [
|
||||
'attribute-name' => [
|
||||
'rule-name' => 'custom-message',
|
||||
],
|
||||
],
|
||||
|
||||
'attributes' => [],
|
||||
];
|
||||
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Messages de validation
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
'accepted' => 'Le champ :attribute doit être accepté.',
|
||||
'accepted_if' => 'Le champ :attribute doit être accepté lorsque :other est :value.',
|
||||
'active_url' => 'Le champ :attribute doit être une URL valide.',
|
||||
'after' => 'Le champ :attribute doit être une date postérieure à :date.',
|
||||
'after_or_equal' => 'Le champ :attribute doit être une date postérieure ou égale à :date.',
|
||||
'alpha' => 'Le champ :attribute ne doit contenir que des lettres.',
|
||||
'alpha_dash' => 'Le champ :attribute ne doit contenir que des lettres, des chiffres, des tirets et des underscores.',
|
||||
'alpha_num' => 'Le champ :attribute ne doit contenir que des lettres et des chiffres.',
|
||||
'any_of' => 'Le champ :attribute est invalide.',
|
||||
'array' => 'Le champ :attribute doit être un tableau.',
|
||||
'ascii' => 'Le champ :attribute ne doit contenir que des caractères alphanumériques et des symboles sur un octet.',
|
||||
'before' => 'Le champ :attribute doit être une date antérieure à :date.',
|
||||
'before_or_equal' => 'Le champ :attribute doit être une date antérieure ou égale à :date.',
|
||||
'between' => [
|
||||
'array' => 'Le champ :attribute doit contenir entre :min et :max éléments.',
|
||||
'file' => 'Le champ :attribute doit être entre :min et :max kilo-octets.',
|
||||
'numeric' => 'Le champ :attribute doit être entre :min et :max.',
|
||||
'string' => 'Le champ :attribute doit contenir entre :min et :max caractères.',
|
||||
],
|
||||
'boolean' => 'Le champ :attribute doit être vrai ou faux.',
|
||||
'can' => 'Le champ :attribute contient une valeur non autorisée.',
|
||||
'confirmed' => 'La confirmation du champ :attribute ne correspond pas.',
|
||||
'contains' => 'Le champ :attribute ne contient pas une valeur requise.',
|
||||
'current_password' => 'Le mot de passe est incorrect.',
|
||||
'date' => 'Le champ :attribute doit être une date valide.',
|
||||
'date_equals' => 'Le champ :attribute doit être une date égale à :date.',
|
||||
'date_format' => 'Le champ :attribute doit correspondre au format :format.',
|
||||
'decimal' => 'Le champ :attribute doit avoir :decimal décimales.',
|
||||
'declined' => 'Le champ :attribute doit être refusé.',
|
||||
'declined_if' => 'Le champ :attribute doit être refusé lorsque :other est :value.',
|
||||
'different' => 'Les champs :attribute et :other doivent être différents.',
|
||||
'digits' => 'Le champ :attribute doit contenir :digits chiffres.',
|
||||
'digits_between' => 'Le champ :attribute doit contenir entre :min et :max chiffres.',
|
||||
'dimensions' => 'Le champ :attribute a des dimensions d\'image invalides.',
|
||||
'distinct' => 'Le champ :attribute a une valeur en double.',
|
||||
'doesnt_contain' => 'Le champ :attribute ne doit pas contenir :values.',
|
||||
'doesnt_end_with' => 'Le champ :attribute ne doit pas se terminer par :values.',
|
||||
'doesnt_start_with' => 'Le champ :attribute ne doit pas commencer par :values.',
|
||||
'email' => 'Le champ :attribute doit être une adresse e-mail valide.',
|
||||
'encoding' => 'Le champ :attribute doit être encodé en :encoding.',
|
||||
'ends_with' => 'Le champ :attribute doit se terminer par :values.',
|
||||
'enum' => 'Le :attribute sélectionné est invalide.',
|
||||
'exists' => 'Le :attribute sélectionné est invalide.',
|
||||
'extensions' => 'Le champ :attribute doit avoir l\'une des extensions suivantes : :values.',
|
||||
'file' => 'Le champ :attribute doit être un fichier.',
|
||||
'filled' => 'Le champ :attribute doit avoir une valeur.',
|
||||
'gt' => [
|
||||
'array' => 'Le champ :attribute doit contenir plus de :value éléments.',
|
||||
'file' => 'Le champ :attribute doit être supérieur à :value kilo-octets.',
|
||||
'numeric' => 'Le champ :attribute doit être supérieur à :value.',
|
||||
'string' => 'Le champ :attribute doit contenir plus de :value caractères.',
|
||||
],
|
||||
'gte' => [
|
||||
'array' => 'Le champ :attribute doit contenir :value éléments ou plus.',
|
||||
'file' => 'Le champ :attribute doit être supérieur ou égal à :value kilo-octets.',
|
||||
'numeric' => 'Le champ :attribute doit être supérieur ou égal à :value.',
|
||||
'string' => 'Le champ :attribute doit contenir :value caractères ou plus.',
|
||||
],
|
||||
'hex_color' => 'Le champ :attribute doit être une couleur hexadécimale valide.',
|
||||
'image' => 'Le champ :attribute doit être une image.',
|
||||
'in' => 'Le :attribute sélectionné est invalide.',
|
||||
'in_array' => 'Le champ :attribute doit exister dans :other.',
|
||||
'in_array_keys' => 'Le champ :attribute doit contenir au moins une des clés suivantes : :values.',
|
||||
'integer' => 'Le champ :attribute doit être un entier.',
|
||||
'ip' => 'Le champ :attribute doit être une adresse IP valide.',
|
||||
'ipv4' => 'Le champ :attribute doit être une adresse IPv4 valide.',
|
||||
'ipv6' => 'Le champ :attribute doit être une adresse IPv6 valide.',
|
||||
'json' => 'Le champ :attribute doit être une chaîne JSON valide.',
|
||||
'list' => 'Le champ :attribute doit être une liste.',
|
||||
'lowercase' => 'Le champ :attribute doit être en minuscules.',
|
||||
'lt' => [
|
||||
'array' => 'Le champ :attribute doit contenir moins de :value éléments.',
|
||||
'file' => 'Le champ :attribute doit être inférieur à :value kilo-octets.',
|
||||
'numeric' => 'Le champ :attribute doit être inférieur à :value.',
|
||||
'string' => 'Le champ :attribute doit contenir moins de :value caractères.',
|
||||
],
|
||||
'lte' => [
|
||||
'array' => 'Le champ :attribute ne doit pas contenir plus de :value éléments.',
|
||||
'file' => 'Le champ :attribute doit être inférieur ou égal à :value kilo-octets.',
|
||||
'numeric' => 'Le champ :attribute doit être inférieur ou égal à :value.',
|
||||
'string' => 'Le champ :attribute doit contenir :value caractères ou moins.',
|
||||
],
|
||||
'mac_address' => 'Le champ :attribute doit être une adresse MAC valide.',
|
||||
'max' => [
|
||||
'array' => 'Le champ :attribute ne doit pas contenir plus de :max éléments.',
|
||||
'file' => 'Le champ :attribute ne doit pas dépasser :max kilo-octets.',
|
||||
'numeric' => 'Le champ :attribute ne doit pas être supérieur à :max.',
|
||||
'string' => 'Le champ :attribute ne doit pas contenir plus de :max caractères.',
|
||||
],
|
||||
'max_digits' => 'Le champ :attribute ne doit pas contenir plus de :max chiffres.',
|
||||
'mimes' => 'Le champ :attribute doit être un fichier de type : :values.',
|
||||
'mimetypes' => 'Le champ :attribute doit être un fichier de type : :values.',
|
||||
'min' => [
|
||||
'array' => 'Le champ :attribute doit contenir au moins :min éléments.',
|
||||
'file' => 'Le champ :attribute doit faire au moins :min kilo-octets.',
|
||||
'numeric' => 'Le champ :attribute doit être au moins :min.',
|
||||
'string' => 'Le champ :attribute doit contenir au moins :min caractères.',
|
||||
],
|
||||
'min_digits' => 'Le champ :attribute doit contenir au moins :min chiffres.',
|
||||
'missing' => 'Le champ :attribute doit être absent.',
|
||||
'missing_if' => 'Le champ :attribute doit être absent lorsque :other est :value.',
|
||||
'missing_unless' => 'Le champ :attribute doit être absent sauf si :other est :value.',
|
||||
'missing_with' => 'Le champ :attribute doit être absent lorsque :values est présent.',
|
||||
'missing_with_all' => 'Le champ :attribute doit être absent lorsque :values sont présents.',
|
||||
'multiple_of' => 'Le champ :attribute doit être un multiple de :value.',
|
||||
'not_in' => 'Le :attribute sélectionné est invalide.',
|
||||
'not_regex' => 'Le format du champ :attribute est invalide.',
|
||||
'numeric' => 'Le champ :attribute doit être un nombre.',
|
||||
'password' => [
|
||||
'letters' => 'Le champ :attribute doit contenir au moins une lettre.',
|
||||
'mixed' => 'Le champ :attribute doit contenir au moins une majuscule et une minuscule.',
|
||||
'numbers' => 'Le champ :attribute doit contenir au moins un chiffre.',
|
||||
'symbols' => 'Le champ :attribute doit contenir au moins un symbole.',
|
||||
'uncompromised' => 'Le :attribute donné est apparu dans une fuite de données. Veuillez choisir un autre :attribute.',
|
||||
],
|
||||
'present' => 'Le champ :attribute doit être présent.',
|
||||
'present_if' => 'Le champ :attribute doit être présent lorsque :other est :value.',
|
||||
'present_unless' => 'Le champ :attribute doit être présent sauf si :other est :value.',
|
||||
'present_with' => 'Le champ :attribute doit être présent lorsque :values est présent.',
|
||||
'present_with_all' => 'Le champ :attribute doit être présent lorsque :values sont présents.',
|
||||
'prohibited' => 'Le champ :attribute est interdit.',
|
||||
'prohibited_if' => 'Le champ :attribute est interdit lorsque :other est :value.',
|
||||
'prohibited_if_accepted' => 'Le champ :attribute est interdit lorsque :other est accepté.',
|
||||
'prohibited_if_declined' => 'Le champ :attribute est interdit lorsque :other est refusé.',
|
||||
'prohibited_unless' => 'Le champ :attribute est interdit sauf si :other est dans :values.',
|
||||
'prohibits' => 'Le champ :attribute interdit la présence de :other.',
|
||||
'regex' => 'Le format du champ :attribute est invalide.',
|
||||
'required' => 'Le champ :attribute est obligatoire.',
|
||||
'required_array_keys' => 'Le champ :attribute doit contenir les entrées suivantes : :values.',
|
||||
'required_if' => 'Le champ :attribute est obligatoire lorsque :other est :value.',
|
||||
'required_if_accepted' => 'Le champ :attribute est obligatoire lorsque :other est accepté.',
|
||||
'required_if_declined' => 'Le champ :attribute est obligatoire lorsque :other est refusé.',
|
||||
'required_unless' => 'Le champ :attribute est obligatoire sauf si :other est dans :values.',
|
||||
'required_with' => 'Le champ :attribute est obligatoire lorsque :values est présent.',
|
||||
'required_with_all' => 'Le champ :attribute est obligatoire lorsque :values sont présents.',
|
||||
'required_without' => 'Le champ :attribute est obligatoire lorsque :values n\'est pas présent.',
|
||||
'required_without_all' => 'Le champ :attribute est obligatoire lorsqu\'aucun de :values n\'est présent.',
|
||||
'same' => 'Les champs :attribute et :other doivent correspondre.',
|
||||
'size' => [
|
||||
'array' => 'Le champ :attribute doit contenir :size éléments.',
|
||||
'file' => 'Le champ :attribute doit faire :size kilo-octets.',
|
||||
'numeric' => 'Le champ :attribute doit être :size.',
|
||||
'string' => 'Le champ :attribute doit contenir :size caractères.',
|
||||
],
|
||||
'starts_with' => 'Le champ :attribute doit commencer par :values.',
|
||||
'string' => 'Le champ :attribute doit être une chaîne de caractères.',
|
||||
'timezone' => 'Le champ :attribute doit être un fuseau horaire valide.',
|
||||
'unique' => 'Le :attribute a déjà été utilisé.',
|
||||
'uploaded' => 'Le téléchargement du :attribute a échoué.',
|
||||
'uppercase' => 'Le champ :attribute doit être en majuscules.',
|
||||
'url' => 'Le champ :attribute doit être une URL valide.',
|
||||
'ulid' => 'Le champ :attribute doit être un ULID valide.',
|
||||
'uuid' => 'Le champ :attribute doit être un UUID valide.',
|
||||
|
||||
'custom' => [
|
||||
'attribute-name' => [
|
||||
'rule-name' => 'custom-message',
|
||||
],
|
||||
],
|
||||
|
||||
'attributes' => [],
|
||||
];
|
||||
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Pesan validasi
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
'accepted' => 'Bidang :attribute harus diterima.',
|
||||
'accepted_if' => 'Bidang :attribute harus diterima ketika :other adalah :value.',
|
||||
'active_url' => 'Bidang :attribute harus berupa URL yang valid.',
|
||||
'after' => 'Bidang :attribute harus berupa tanggal setelah :date.',
|
||||
'after_or_equal' => 'Bidang :attribute harus berupa tanggal setelah atau sama dengan :date.',
|
||||
'alpha' => 'Bidang :attribute hanya boleh berisi huruf.',
|
||||
'alpha_dash' => 'Bidang :attribute hanya boleh berisi huruf, angka, tanda hubung, dan garis bawah.',
|
||||
'alpha_num' => 'Bidang :attribute hanya boleh berisi huruf dan angka.',
|
||||
'any_of' => 'Bidang :attribute tidak valid.',
|
||||
'array' => 'Bidang :attribute harus berupa array.',
|
||||
'ascii' => 'Bidang :attribute hanya boleh berisi karakter alfanumerik dan simbol satu byte.',
|
||||
'before' => 'Bidang :attribute harus berupa tanggal sebelum :date.',
|
||||
'before_or_equal' => 'Bidang :attribute harus berupa tanggal sebelum atau sama dengan :date.',
|
||||
'between' => [
|
||||
'array' => 'Bidang :attribute harus memiliki antara :min dan :max item.',
|
||||
'file' => 'Bidang :attribute harus antara :min dan :max kilobyte.',
|
||||
'numeric' => 'Bidang :attribute harus antara :min dan :max.',
|
||||
'string' => 'Bidang :attribute harus antara :min dan :max karakter.',
|
||||
],
|
||||
'boolean' => 'Bidang :attribute harus benar atau salah.',
|
||||
'can' => 'Bidang :attribute berisi nilai yang tidak diizinkan.',
|
||||
'confirmed' => 'Konfirmasi bidang :attribute tidak cocok.',
|
||||
'contains' => 'Bidang :attribute tidak berisi nilai yang wajib.',
|
||||
'current_password' => 'Kata sandi salah.',
|
||||
'date' => 'Bidang :attribute harus berupa tanggal yang valid.',
|
||||
'date_equals' => 'Bidang :attribute harus berupa tanggal yang sama dengan :date.',
|
||||
'date_format' => 'Bidang :attribute harus sesuai format :format.',
|
||||
'decimal' => 'Bidang :attribute harus memiliki :decimal tempat desimal.',
|
||||
'declined' => 'Bidang :attribute harus ditolak.',
|
||||
'declined_if' => 'Bidang :attribute harus ditolak ketika :other adalah :value.',
|
||||
'different' => 'Bidang :attribute dan :other harus berbeda.',
|
||||
'digits' => 'Bidang :attribute harus :digits digit.',
|
||||
'digits_between' => 'Bidang :attribute harus antara :min dan :max digit.',
|
||||
'dimensions' => 'Bidang :attribute memiliki dimensi gambar yang tidak valid.',
|
||||
'distinct' => 'Bidang :attribute memiliki nilai duplikat.',
|
||||
'doesnt_contain' => 'Bidang :attribute tidak boleh berisi: :values.',
|
||||
'doesnt_end_with' => 'Bidang :attribute tidak boleh diakhiri dengan: :values.',
|
||||
'doesnt_start_with' => 'Bidang :attribute tidak boleh diawali dengan: :values.',
|
||||
'email' => 'Bidang :attribute harus berupa alamat email yang valid.',
|
||||
'encoding' => 'Bidang :attribute harus dikodekan dalam :encoding.',
|
||||
'ends_with' => 'Bidang :attribute harus diakhiri dengan: :values.',
|
||||
'enum' => ':attribute yang dipilih tidak valid.',
|
||||
'exists' => ':attribute yang dipilih tidak valid.',
|
||||
'extensions' => 'Bidang :attribute harus memiliki salah satu ekstensi berikut: :values.',
|
||||
'file' => 'Bidang :attribute harus berupa file.',
|
||||
'filled' => 'Bidang :attribute harus memiliki nilai.',
|
||||
'gt' => [
|
||||
'array' => 'Bidang :attribute harus memiliki lebih dari :value item.',
|
||||
'file' => 'Bidang :attribute harus lebih besar dari :value kilobyte.',
|
||||
'numeric' => 'Bidang :attribute harus lebih besar dari :value.',
|
||||
'string' => 'Bidang :attribute harus lebih dari :value karakter.',
|
||||
],
|
||||
'gte' => [
|
||||
'array' => 'Bidang :attribute harus memiliki :value item atau lebih.',
|
||||
'file' => 'Bidang :attribute harus lebih besar atau sama dengan :value kilobyte.',
|
||||
'numeric' => 'Bidang :attribute harus lebih besar atau sama dengan :value.',
|
||||
'string' => 'Bidang :attribute harus :value karakter atau lebih.',
|
||||
],
|
||||
'hex_color' => 'Bidang :attribute harus berupa warna heksadesimal yang valid.',
|
||||
'image' => 'Bidang :attribute harus berupa gambar.',
|
||||
'in' => ':attribute yang dipilih tidak valid.',
|
||||
'in_array' => 'Bidang :attribute harus ada di :other.',
|
||||
'in_array_keys' => 'Bidang :attribute harus berisi setidaknya salah satu kunci berikut: :values.',
|
||||
'integer' => 'Bidang :attribute harus berupa bilangan bulat.',
|
||||
'ip' => 'Bidang :attribute harus berupa alamat IP yang valid.',
|
||||
'ipv4' => 'Bidang :attribute harus berupa alamat IPv4 yang valid.',
|
||||
'ipv6' => 'Bidang :attribute harus berupa alamat IPv6 yang valid.',
|
||||
'json' => 'Bidang :attribute harus berupa string JSON yang valid.',
|
||||
'list' => 'Bidang :attribute harus berupa daftar.',
|
||||
'lowercase' => 'Bidang :attribute harus huruf kecil.',
|
||||
'lt' => [
|
||||
'array' => 'Bidang :attribute harus memiliki kurang dari :value item.',
|
||||
'file' => 'Bidang :attribute harus kurang dari :value kilobyte.',
|
||||
'numeric' => 'Bidang :attribute harus kurang dari :value.',
|
||||
'string' => 'Bidang :attribute harus kurang dari :value karakter.',
|
||||
],
|
||||
'lte' => [
|
||||
'array' => 'Bidang :attribute tidak boleh memiliki lebih dari :value item.',
|
||||
'file' => 'Bidang :attribute harus kurang dari atau sama dengan :value kilobyte.',
|
||||
'numeric' => 'Bidang :attribute harus kurang dari atau sama dengan :value.',
|
||||
'string' => 'Bidang :attribute harus :value karakter atau kurang.',
|
||||
],
|
||||
'mac_address' => 'Bidang :attribute harus berupa alamat MAC yang valid.',
|
||||
'max' => [
|
||||
'array' => 'Bidang :attribute tidak boleh memiliki lebih dari :max item.',
|
||||
'file' => 'Bidang :attribute tidak boleh lebih besar dari :max kilobyte.',
|
||||
'numeric' => 'Bidang :attribute tidak boleh lebih besar dari :max.',
|
||||
'string' => 'Bidang :attribute tidak boleh lebih dari :max karakter.',
|
||||
],
|
||||
'max_digits' => 'Bidang :attribute tidak boleh memiliki lebih dari :max digit.',
|
||||
'mimes' => 'Bidang :attribute harus berupa file bertipe: :values.',
|
||||
'mimetypes' => 'Bidang :attribute harus berupa file bertipe: :values.',
|
||||
'min' => [
|
||||
'array' => 'Bidang :attribute harus memiliki setidaknya :min item.',
|
||||
'file' => 'Bidang :attribute harus setidaknya :min kilobyte.',
|
||||
'numeric' => 'Bidang :attribute harus setidaknya :min.',
|
||||
'string' => 'Bidang :attribute harus setidaknya :min karakter.',
|
||||
],
|
||||
'min_digits' => 'Bidang :attribute harus memiliki setidaknya :min digit.',
|
||||
'missing' => 'Bidang :attribute harus tidak ada.',
|
||||
'missing_if' => 'Bidang :attribute harus tidak ada ketika :other adalah :value.',
|
||||
'missing_unless' => 'Bidang :attribute harus tidak ada kecuali :other adalah :value.',
|
||||
'missing_with' => 'Bidang :attribute harus tidak ada ketika :values ada.',
|
||||
'missing_with_all' => 'Bidang :attribute harus tidak ada ketika :values ada.',
|
||||
'multiple_of' => 'Bidang :attribute harus kelipatan dari :value.',
|
||||
'not_in' => ':attribute yang dipilih tidak valid.',
|
||||
'not_regex' => 'Format bidang :attribute tidak valid.',
|
||||
'numeric' => 'Bidang :attribute harus berupa angka.',
|
||||
'password' => [
|
||||
'letters' => 'Bidang :attribute harus berisi setidaknya satu huruf.',
|
||||
'mixed' => 'Bidang :attribute harus berisi setidaknya satu huruf besar dan satu huruf kecil.',
|
||||
'numbers' => 'Bidang :attribute harus berisi setidaknya satu angka.',
|
||||
'symbols' => 'Bidang :attribute harus berisi setidaknya satu simbol.',
|
||||
'uncompromised' => ':attribute yang diberikan telah muncul dalam kebocoran data. Silakan pilih :attribute yang berbeda.',
|
||||
],
|
||||
'present' => 'Bidang :attribute harus ada.',
|
||||
'present_if' => 'Bidang :attribute harus ada ketika :other adalah :value.',
|
||||
'present_unless' => 'Bidang :attribute harus ada kecuali :other adalah :value.',
|
||||
'present_with' => 'Bidang :attribute harus ada ketika :values ada.',
|
||||
'present_with_all' => 'Bidang :attribute harus ada ketika :values ada.',
|
||||
'prohibited' => 'Bidang :attribute dilarang.',
|
||||
'prohibited_if' => 'Bidang :attribute dilarang ketika :other adalah :value.',
|
||||
'prohibited_if_accepted' => 'Bidang :attribute dilarang ketika :other diterima.',
|
||||
'prohibited_if_declined' => 'Bidang :attribute dilarang ketika :other ditolak.',
|
||||
'prohibited_unless' => 'Bidang :attribute dilarang kecuali :other ada di :values.',
|
||||
'prohibits' => 'Bidang :attribute melarang :other untuk ada.',
|
||||
'regex' => 'Format bidang :attribute tidak valid.',
|
||||
'required' => 'Bidang :attribute wajib diisi.',
|
||||
'required_array_keys' => 'Bidang :attribute harus berisi entri untuk: :values.',
|
||||
'required_if' => 'Bidang :attribute wajib diisi ketika :other adalah :value.',
|
||||
'required_if_accepted' => 'Bidang :attribute wajib diisi ketika :other diterima.',
|
||||
'required_if_declined' => 'Bidang :attribute wajib diisi ketika :other ditolak.',
|
||||
'required_unless' => 'Bidang :attribute wajib diisi kecuali :other ada di :values.',
|
||||
'required_with' => 'Bidang :attribute wajib diisi ketika :values ada.',
|
||||
'required_with_all' => 'Bidang :attribute wajib diisi ketika :values ada.',
|
||||
'required_without' => 'Bidang :attribute wajib diisi ketika :values tidak ada.',
|
||||
'required_without_all' => 'Bidang :attribute wajib diisi ketika tidak ada :values.',
|
||||
'same' => 'Bidang :attribute dan :other harus cocok.',
|
||||
'size' => [
|
||||
'array' => 'Bidang :attribute harus berisi :size item.',
|
||||
'file' => 'Bidang :attribute harus :size kilobyte.',
|
||||
'numeric' => 'Bidang :attribute harus :size.',
|
||||
'string' => 'Bidang :attribute harus :size karakter.',
|
||||
],
|
||||
'starts_with' => 'Bidang :attribute harus diawali dengan: :values.',
|
||||
'string' => 'Bidang :attribute harus berupa string.',
|
||||
'timezone' => 'Bidang :attribute harus berupa zona waktu yang valid.',
|
||||
'unique' => ':attribute sudah digunakan.',
|
||||
'uploaded' => 'Unggah :attribute gagal.',
|
||||
'uppercase' => 'Bidang :attribute harus huruf besar.',
|
||||
'url' => 'Bidang :attribute harus berupa URL yang valid.',
|
||||
'ulid' => 'Bidang :attribute harus berupa ULID yang valid.',
|
||||
'uuid' => 'Bidang :attribute harus berupa UUID yang valid.',
|
||||
|
||||
'custom' => [
|
||||
'attribute-name' => [
|
||||
'rule-name' => 'custom-message',
|
||||
],
|
||||
],
|
||||
|
||||
'attributes' => [],
|
||||
];
|
||||
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| バリデーション文言
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
'accepted' => ':attribute を受け入れる必要があります。',
|
||||
'accepted_if' => ':other が :value の場合、:attribute を受け入れる必要があります。',
|
||||
'active_url' => ':attribute は有効なURLである必要があります。',
|
||||
'after' => ':attribute は :date より後の日付である必要があります。',
|
||||
'after_or_equal' => ':attribute は :date 以降の日付である必要があります。',
|
||||
'alpha' => ':attribute は英字のみを含む必要があります。',
|
||||
'alpha_dash' => ':attribute は英字、数字、ハイフン、アンダースコアのみを含む必要があります。',
|
||||
'alpha_num' => ':attribute は英字と数字のみを含む必要があります。',
|
||||
'any_of' => ':attribute は無効です。',
|
||||
'array' => ':attribute は配列である必要があります。',
|
||||
'ascii' => ':attribute はASCII文字のみを含む必要があります。',
|
||||
'before' => ':attribute は :date より前の日付である必要があります。',
|
||||
'before_or_equal' => ':attribute は :date 以前の日付である必要があります。',
|
||||
'between' => [
|
||||
'array' => ':attribute は :min から :max 個である必要があります。',
|
||||
'file' => ':attribute は :min から :max KB である必要があります。',
|
||||
'numeric' => ':attribute は :min から :max の間である必要があります。',
|
||||
'string' => ':attribute は :min から :max 文字である必要があります。',
|
||||
],
|
||||
'boolean' => ':attribute は真偽値である必要があります。',
|
||||
'can' => ':attribute に許可されていない値が含まれています。',
|
||||
'confirmed' => ':attribute の確認が一致しません。',
|
||||
'contains' => ':attribute に必須の値が含まれていません。',
|
||||
'current_password' => 'パスワードが正しくありません。',
|
||||
'date' => ':attribute は有効な日付である必要があります。',
|
||||
'date_equals' => ':attribute は :date と等しい日付である必要があります。',
|
||||
'date_format' => ':attribute は :format 形式である必要があります。',
|
||||
'decimal' => ':attribute は :decimal 桁の小数である必要があります。',
|
||||
'declined' => ':attribute は拒否する必要があります。',
|
||||
'declined_if' => ':other が :value の場合、:attribute は拒否する必要があります。',
|
||||
'different' => ':attribute と :other は異なる必要があります。',
|
||||
'digits' => ':attribute は :digits 桁の数字である必要があります。',
|
||||
'digits_between' => ':attribute は :min から :max 桁の数字である必要があります。',
|
||||
'dimensions' => ':attribute の画像サイズが無効です。',
|
||||
'distinct' => ':attribute に重複した値があります。',
|
||||
'doesnt_contain' => ':attribute に以下を含めることはできません::values。',
|
||||
'doesnt_end_with' => ':attribute は以下で終わってはいけません::values。',
|
||||
'doesnt_start_with' => ':attribute は以下で始まってはいけません::values。',
|
||||
'email' => ':attribute は有効なメールアドレスである必要があります。',
|
||||
'encoding' => ':attribute は :encoding でエンコードされている必要があります。',
|
||||
'ends_with' => ':attribute は以下で終わる必要があります::values。',
|
||||
'enum' => '選択した :attribute は無効です。',
|
||||
'exists' => '選択した :attribute は無効です。',
|
||||
'extensions' => ':attribute は以下の拡張子のいずれかである必要があります::values。',
|
||||
'file' => ':attribute はファイルである必要があります。',
|
||||
'filled' => ':attribute には値が必要です。',
|
||||
'gt' => [
|
||||
'array' => ':attribute は :value 個より多い必要があります。',
|
||||
'file' => ':attribute は :value KB より大きい必要があります。',
|
||||
'numeric' => ':attribute は :value より大きい必要があります。',
|
||||
'string' => ':attribute は :value 文字より多い必要があります。',
|
||||
],
|
||||
'gte' => [
|
||||
'array' => ':attribute は :value 個以上である必要があります。',
|
||||
'file' => ':attribute は :value KB 以上である必要があります。',
|
||||
'numeric' => ':attribute は :value 以上である必要があります。',
|
||||
'string' => ':attribute は :value 文字以上である必要があります。',
|
||||
],
|
||||
'hex_color' => ':attribute は有効な16進数カラーである必要があります。',
|
||||
'image' => ':attribute は画像である必要があります。',
|
||||
'in' => '選択した :attribute は無効です。',
|
||||
'in_array' => ':attribute は :other に存在する必要があります。',
|
||||
'in_array_keys' => ':attribute は以下のキーのいずれかを含む必要があります::values。',
|
||||
'integer' => ':attribute は整数である必要があります。',
|
||||
'ip' => ':attribute は有効なIPアドレスである必要があります。',
|
||||
'ipv4' => ':attribute は有効なIPv4アドレスである必要があります。',
|
||||
'ipv6' => ':attribute は有効なIPv6アドレスである必要があります。',
|
||||
'json' => ':attribute は有効なJSON文字列である必要があります。',
|
||||
'list' => ':attribute はリストである必要があります。',
|
||||
'lowercase' => ':attribute は小文字である必要があります。',
|
||||
'lt' => [
|
||||
'array' => ':attribute は :value 個未満である必要があります。',
|
||||
'file' => ':attribute は :value KB 未満である必要があります。',
|
||||
'numeric' => ':attribute は :value 未満である必要があります。',
|
||||
'string' => ':attribute は :value 文字未満である必要があります。',
|
||||
],
|
||||
'lte' => [
|
||||
'array' => ':attribute は :value 個以下である必要があります。',
|
||||
'file' => ':attribute は :value KB 以下である必要があります。',
|
||||
'numeric' => ':attribute は :value 以下である必要があります。',
|
||||
'string' => ':attribute は :value 文字以下である必要があります。',
|
||||
],
|
||||
'mac_address' => ':attribute は有効なMACアドレスである必要があります。',
|
||||
'max' => [
|
||||
'array' => ':attribute は :max 個以下である必要があります。',
|
||||
'file' => ':attribute は :max KB 以下である必要があります。',
|
||||
'numeric' => ':attribute は :max 以下である必要があります。',
|
||||
'string' => ':attribute は :max 文字以下である必要があります。',
|
||||
],
|
||||
'max_digits' => ':attribute は :max 桁以下である必要があります。',
|
||||
'mimes' => ':attribute は :values タイプのファイルである必要があります。',
|
||||
'mimetypes' => ':attribute は :values タイプのファイルである必要があります。',
|
||||
'min' => [
|
||||
'array' => ':attribute は少なくとも :min 個である必要があります。',
|
||||
'file' => ':attribute は少なくとも :min KB である必要があります。',
|
||||
'numeric' => ':attribute は少なくとも :min である必要があります。',
|
||||
'string' => ':attribute は少なくとも :min 文字である必要があります。',
|
||||
],
|
||||
'min_digits' => ':attribute は少なくとも :min 桁である必要があります。',
|
||||
'missing' => ':attribute は存在してはいけません。',
|
||||
'missing_if' => ':other が :value の場合、:attribute は存在してはいけません。',
|
||||
'missing_unless' => ':other が :value でない限り、:attribute は存在してはいけません。',
|
||||
'missing_with' => ':values が存在する場合、:attribute は存在してはいけません。',
|
||||
'missing_with_all' => ':values がすべて存在する場合、:attribute は存在してはいけません。',
|
||||
'multiple_of' => ':attribute は :value の倍数である必要があります。',
|
||||
'not_in' => '選択した :attribute は無効です。',
|
||||
'not_regex' => ':attribute の形式が無効です。',
|
||||
'numeric' => ':attribute は数値である必要があります。',
|
||||
'password' => [
|
||||
'letters' => ':attribute は少なくとも1文字の英字を含む必要があります。',
|
||||
'mixed' => ':attribute は少なくとも1つの大文字と1つの小文字を含む必要があります。',
|
||||
'numbers' => ':attribute は少なくとも1つの数字を含む必要があります。',
|
||||
'symbols' => ':attribute は少なくとも1つの記号を含む必要があります。',
|
||||
'uncompromised' => ':attribute はデータ漏洩で発見されました。別の :attribute を選択してください。',
|
||||
],
|
||||
'present' => ':attribute は存在する必要があります。',
|
||||
'present_if' => ':other が :value の場合、:attribute は存在する必要があります。',
|
||||
'present_unless' => ':other が :value でない限り、:attribute は存在する必要があります。',
|
||||
'present_with' => ':values が存在する場合、:attribute は存在する必要があります。',
|
||||
'present_with_all' => ':values がすべて存在する場合、:attribute は存在する必要があります。',
|
||||
'prohibited' => ':attribute は禁止されています。',
|
||||
'prohibited_if' => ':other が :value の場合、:attribute は禁止されています。',
|
||||
'prohibited_if_accepted' => ':other が受け入れられた場合、:attribute は禁止されています。',
|
||||
'prohibited_if_declined' => ':other が拒否された場合、:attribute は禁止されています。',
|
||||
'prohibited_unless' => ':other が :values に含まれていない限り、:attribute は禁止されています。',
|
||||
'prohibits' => ':attribute が存在する場合、:other は禁止されています。',
|
||||
'regex' => ':attribute の形式が無効です。',
|
||||
'required' => ':attribute は必須です。',
|
||||
'required_array_keys' => ':attribute は以下のキーを含む必要があります::values。',
|
||||
'required_if' => ':other が :value の場合、:attribute は必須です。',
|
||||
'required_if_accepted' => ':other が受け入れられた場合、:attribute は必須です。',
|
||||
'required_if_declined' => ':other が拒否された場合、:attribute は必須です。',
|
||||
'required_unless' => ':other が :values に含まれていない限り、:attribute は必須です。',
|
||||
'required_with' => ':values が存在する場合、:attribute は必須です。',
|
||||
'required_with_all' => ':values がすべて存在する場合、:attribute は必須です。',
|
||||
'required_without' => ':values が存在しない場合、:attribute は必須です。',
|
||||
'required_without_all' => ':values がすべて存在しない場合、:attribute は必須です。',
|
||||
'same' => ':attribute と :other は一致する必要があります。',
|
||||
'size' => [
|
||||
'array' => ':attribute は :size 個である必要があります。',
|
||||
'file' => ':attribute は :size KB である必要があります。',
|
||||
'numeric' => ':attribute は :size である必要があります。',
|
||||
'string' => ':attribute は :size 文字である必要があります。',
|
||||
],
|
||||
'starts_with' => ':attribute は以下で始まる必要があります::values。',
|
||||
'string' => ':attribute は文字列である必要があります。',
|
||||
'timezone' => ':attribute は有効なタイムゾーンである必要があります。',
|
||||
'unique' => ':attribute は既に使用されています。',
|
||||
'uploaded' => ':attribute のアップロードに失敗しました。',
|
||||
'uppercase' => ':attribute は大文字である必要があります。',
|
||||
'url' => ':attribute は有効なURLである必要があります。',
|
||||
'ulid' => ':attribute は有効なULIDである必要があります。',
|
||||
'uuid' => ':attribute は有効なUUIDである必要があります。',
|
||||
|
||||
'custom' => [
|
||||
'attribute-name' => [
|
||||
'rule-name' => 'custom-message',
|
||||
],
|
||||
],
|
||||
|
||||
'attributes' => [],
|
||||
];
|
||||
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| 유효성 검사 메시지
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
'accepted' => ':attribute을(를) 수락해야 합니다.',
|
||||
'accepted_if' => ':other이(가) :value일 때 :attribute을(를) 수락해야 합니다.',
|
||||
'active_url' => ':attribute은(는) 유효한 URL이어야 합니다.',
|
||||
'after' => ':attribute은(는) :date 이후 날짜여야 합니다.',
|
||||
'after_or_equal' => ':attribute은(는) :date 이후이거나 같은 날짜여야 합니다.',
|
||||
'alpha' => ':attribute은(는) 문자만 포함해야 합니다.',
|
||||
'alpha_dash' => ':attribute은(는) 문자, 숫자, 대시, 밑줄만 포함해야 합니다.',
|
||||
'alpha_num' => ':attribute은(는) 문자와 숫자만 포함해야 합니다.',
|
||||
'any_of' => ':attribute이(가) 유효하지 않습니다.',
|
||||
'array' => ':attribute은(는) 배열이어야 합니다.',
|
||||
'ascii' => ':attribute은(는) ASCII 문자만 포함해야 합니다.',
|
||||
'before' => ':attribute은(는) :date 이전 날짜여야 합니다.',
|
||||
'before_or_equal' => ':attribute은(는) :date 이전이거나 같은 날짜여야 합니다.',
|
||||
'between' => [
|
||||
'array' => ':attribute은(는) :min개에서 :max개 사이여야 합니다.',
|
||||
'file' => ':attribute은(는) :min KB에서 :max KB 사이여야 합니다.',
|
||||
'numeric' => ':attribute은(는) :min에서 :max 사이여야 합니다.',
|
||||
'string' => ':attribute은(는) :min자에서 :max자 사이여야 합니다.',
|
||||
],
|
||||
'boolean' => ':attribute은(는) 참 또는 거짓이어야 합니다.',
|
||||
'can' => ':attribute에 허용되지 않은 값이 포함되어 있습니다.',
|
||||
'confirmed' => ':attribute 확인이 일치하지 않습니다.',
|
||||
'contains' => ':attribute에 필수 값이 없습니다.',
|
||||
'current_password' => '비밀번호가 올바르지 않습니다.',
|
||||
'date' => ':attribute은(는) 유효한 날짜여야 합니다.',
|
||||
'date_equals' => ':attribute은(는) :date와 같은 날짜여야 합니다.',
|
||||
'date_format' => ':attribute은(는) :format 형식이어야 합니다.',
|
||||
'decimal' => ':attribute은(는) :decimal자리 소수여야 합니다.',
|
||||
'declined' => ':attribute을(를) 거부해야 합니다.',
|
||||
'declined_if' => ':other이(가) :value일 때 :attribute을(를) 거부해야 합니다.',
|
||||
'different' => ':attribute과(와) :other은(는) 달라야 합니다.',
|
||||
'digits' => ':attribute은(는) :digits자리 숫자여야 합니다.',
|
||||
'digits_between' => ':attribute은(는) :min자리에서 :max자리 숫자여야 합니다.',
|
||||
'dimensions' => ':attribute 이미지 크기가 유효하지 않습니다.',
|
||||
'distinct' => ':attribute에 중복된 값이 있습니다.',
|
||||
'doesnt_contain' => ':attribute에 다음을 포함할 수 없습니다: :values.',
|
||||
'doesnt_end_with' => ':attribute은(는) 다음으로 끝나면 안 됩니다: :values.',
|
||||
'doesnt_start_with' => ':attribute은(는) 다음으로 시작하면 안 됩니다: :values.',
|
||||
'email' => ':attribute은(는) 유효한 이메일 주소여야 합니다.',
|
||||
'encoding' => ':attribute은(는) :encoding으로 인코딩되어야 합니다.',
|
||||
'ends_with' => ':attribute은(는) 다음 중 하나로 끝나야 합니다: :values.',
|
||||
'enum' => '선택한 :attribute이(가) 유효하지 않습니다.',
|
||||
'exists' => '선택한 :attribute이(가) 유효하지 않습니다.',
|
||||
'extensions' => ':attribute은(는) 다음 확장자 중 하나여야 합니다: :values.',
|
||||
'file' => ':attribute은(는) 파일이어야 합니다.',
|
||||
'filled' => ':attribute에는 값이 있어야 합니다.',
|
||||
'gt' => [
|
||||
'array' => ':attribute은(는) :value개보다 많아야 합니다.',
|
||||
'file' => ':attribute은(는) :value KB보다 커야 합니다.',
|
||||
'numeric' => ':attribute은(는) :value보다 커야 합니다.',
|
||||
'string' => ':attribute은(는) :value자보다 많아야 합니다.',
|
||||
],
|
||||
'gte' => [
|
||||
'array' => ':attribute은(는) :value개 이상이어야 합니다.',
|
||||
'file' => ':attribute은(는) :value KB 이상이어야 합니다.',
|
||||
'numeric' => ':attribute은(는) :value 이상이어야 합니다.',
|
||||
'string' => ':attribute은(는) :value자 이상이어야 합니다.',
|
||||
],
|
||||
'hex_color' => ':attribute은(는) 유효한 16진수 색상이어야 합니다.',
|
||||
'image' => ':attribute은(는) 이미지여야 합니다.',
|
||||
'in' => '선택한 :attribute이(가) 유효하지 않습니다.',
|
||||
'in_array' => ':attribute은(는) :other에 존재해야 합니다.',
|
||||
'in_array_keys' => ':attribute은(는) 다음 키 중 하나를 포함해야 합니다: :values.',
|
||||
'integer' => ':attribute은(는) 정수여야 합니다.',
|
||||
'ip' => ':attribute은(는) 유효한 IP 주소여야 합니다.',
|
||||
'ipv4' => ':attribute은(는) 유효한 IPv4 주소여야 합니다.',
|
||||
'ipv6' => ':attribute은(는) 유효한 IPv6 주소여야 합니다.',
|
||||
'json' => ':attribute은(는) 유효한 JSON 문자열이어야 합니다.',
|
||||
'list' => ':attribute은(는) 목록이어야 합니다.',
|
||||
'lowercase' => ':attribute은(는) 소문자여야 합니다.',
|
||||
'lt' => [
|
||||
'array' => ':attribute은(는) :value개 미만이어야 합니다.',
|
||||
'file' => ':attribute은(는) :value KB 미만이어야 합니다.',
|
||||
'numeric' => ':attribute은(는) :value 미만이어야 합니다.',
|
||||
'string' => ':attribute은(는) :value자 미만이어야 합니다.',
|
||||
],
|
||||
'lte' => [
|
||||
'array' => ':attribute은(는) :value개 이하여야 합니다.',
|
||||
'file' => ':attribute은(는) :value KB 이하여야 합니다.',
|
||||
'numeric' => ':attribute은(는) :value 이하여야 합니다.',
|
||||
'string' => ':attribute은(는) :value자 이하여야 합니다.',
|
||||
],
|
||||
'mac_address' => ':attribute은(는) 유효한 MAC 주소여야 합니다.',
|
||||
'max' => [
|
||||
'array' => ':attribute은(는) :max개 이하여야 합니다.',
|
||||
'file' => ':attribute은(는) :max KB 이하여야 합니다.',
|
||||
'numeric' => ':attribute은(는) :max 이하여야 합니다.',
|
||||
'string' => ':attribute은(는) :max자 이하여야 합니다.',
|
||||
],
|
||||
'max_digits' => ':attribute은(는) :max자리 이하여야 합니다.',
|
||||
'mimes' => ':attribute은(는) :values 유형의 파일이어야 합니다.',
|
||||
'mimetypes' => ':attribute은(는) :values 유형의 파일이어야 합니다.',
|
||||
'min' => [
|
||||
'array' => ':attribute은(는) 최소 :min개여야 합니다.',
|
||||
'file' => ':attribute은(는) 최소 :min KB여야 합니다.',
|
||||
'numeric' => ':attribute은(는) 최소 :min이어야 합니다.',
|
||||
'string' => ':attribute은(는) 최소 :min자여야 합니다.',
|
||||
],
|
||||
'min_digits' => ':attribute은(는) 최소 :min자리여야 합니다.',
|
||||
'missing' => ':attribute은(는) 없어야 합니다.',
|
||||
'missing_if' => ':other이(가) :value일 때 :attribute은(는) 없어야 합니다.',
|
||||
'missing_unless' => ':other이(가) :value가 아니면 :attribute은(는) 없어야 합니다.',
|
||||
'missing_with' => ':values이(가) 있으면 :attribute은(는) 없어야 합니다.',
|
||||
'missing_with_all' => ':values이(가) 모두 있으면 :attribute은(는) 없어야 합니다.',
|
||||
'multiple_of' => ':attribute은(는) :value의 배수여야 합니다.',
|
||||
'not_in' => '선택한 :attribute이(가) 유효하지 않습니다.',
|
||||
'not_regex' => ':attribute 형식이 유효하지 않습니다.',
|
||||
'numeric' => ':attribute은(는) 숫자여야 합니다.',
|
||||
'password' => [
|
||||
'letters' => ':attribute은(는) 최소 한 개의 문자를 포함해야 합니다.',
|
||||
'mixed' => ':attribute은(는) 최소 한 개의 대문자와 한 개의 소문자를 포함해야 합니다.',
|
||||
'numbers' => ':attribute은(는) 최소 한 개의 숫자를 포함해야 합니다.',
|
||||
'symbols' => ':attribute은(는) 최소 한 개의 기호를 포함해야 합니다.',
|
||||
'uncompromised' => ':attribute이(가) 데이터 유출에서 발견되었습니다. 다른 :attribute을(를) 선택하세요.',
|
||||
],
|
||||
'present' => ':attribute이(가) 있어야 합니다.',
|
||||
'present_if' => ':other이(가) :value일 때 :attribute이(가) 있어야 합니다.',
|
||||
'present_unless' => ':other이(가) :value가 아니면 :attribute이(가) 있어야 합니다.',
|
||||
'present_with' => ':values이(가) 있으면 :attribute이(가) 있어야 합니다.',
|
||||
'present_with_all' => ':values이(가) 모두 있으면 :attribute이(가) 있어야 합니다.',
|
||||
'prohibited' => ':attribute은(는) 금지되어 있습니다.',
|
||||
'prohibited_if' => ':other이(가) :value일 때 :attribute은(는) 금지되어 있습니다.',
|
||||
'prohibited_if_accepted' => ':other이(가) 수락되면 :attribute은(는) 금지되어 있습니다.',
|
||||
'prohibited_if_declined' => ':other이(가) 거부되면 :attribute은(는) 금지되어 있습니다.',
|
||||
'prohibited_unless' => ':other이(가) :values에 없으면 :attribute은(는) 금지되어 있습니다.',
|
||||
'prohibits' => ':attribute이(가) 있으면 :other은(는) 금지되어 있습니다.',
|
||||
'regex' => ':attribute 형식이 유효하지 않습니다.',
|
||||
'required' => ':attribute은(는) 필수입니다.',
|
||||
'required_array_keys' => ':attribute은(는) 다음 키를 포함해야 합니다: :values.',
|
||||
'required_if' => ':other이(가) :value일 때 :attribute은(는) 필수입니다.',
|
||||
'required_if_accepted' => ':other이(가) 수락되면 :attribute은(는) 필수입니다.',
|
||||
'required_if_declined' => ':other이(가) 거부되면 :attribute은(는) 필수입니다.',
|
||||
'required_unless' => ':other이(가) :values에 없으면 :attribute은(는) 필수입니다.',
|
||||
'required_with' => ':values이(가) 있으면 :attribute은(는) 필수입니다.',
|
||||
'required_with_all' => ':values이(가) 모두 있으면 :attribute은(는) 필수입니다.',
|
||||
'required_without' => ':values이(가) 없으면 :attribute은(는) 필수입니다.',
|
||||
'required_without_all' => ':values이(가) 모두 없으면 :attribute은(는) 필수입니다.',
|
||||
'same' => ':attribute과(와) :other은(는) 일치해야 합니다.',
|
||||
'size' => [
|
||||
'array' => ':attribute은(는) :size개여야 합니다.',
|
||||
'file' => ':attribute은(는) :size KB여야 합니다.',
|
||||
'numeric' => ':attribute은(는) :size여야 합니다.',
|
||||
'string' => ':attribute은(는) :size자여야 합니다.',
|
||||
],
|
||||
'starts_with' => ':attribute은(는) 다음 중 하나로 시작해야 합니다: :values.',
|
||||
'string' => ':attribute은(는) 문자열이어야 합니다.',
|
||||
'timezone' => ':attribute은(는) 유효한 시간대여야 합니다.',
|
||||
'unique' => ':attribute은(는) 이미 사용 중입니다.',
|
||||
'uploaded' => ':attribute 업로드에 실패했습니다.',
|
||||
'uppercase' => ':attribute은(는) 대문자여야 합니다.',
|
||||
'url' => ':attribute은(는) 유효한 URL이어야 합니다.',
|
||||
'ulid' => ':attribute은(는) 유효한 ULID여야 합니다.',
|
||||
'uuid' => ':attribute은(는) 유효한 UUID여야 합니다.',
|
||||
|
||||
'custom' => [
|
||||
'attribute-name' => [
|
||||
'rule-name' => 'custom-message',
|
||||
],
|
||||
],
|
||||
|
||||
'attributes' => [],
|
||||
];
|
||||
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Mensagens de validação
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
'accepted' => 'O campo :attribute deve ser aceito.',
|
||||
'accepted_if' => 'O campo :attribute deve ser aceito quando :other for :value.',
|
||||
'active_url' => 'O campo :attribute deve ser uma URL válida.',
|
||||
'after' => 'O campo :attribute deve ser uma data posterior a :date.',
|
||||
'after_or_equal' => 'O campo :attribute deve ser uma data posterior ou igual a :date.',
|
||||
'alpha' => 'O campo :attribute deve conter apenas letras.',
|
||||
'alpha_dash' => 'O campo :attribute deve conter apenas letras, números, traços e sublinhados.',
|
||||
'alpha_num' => 'O campo :attribute deve conter apenas letras e números.',
|
||||
'any_of' => 'O campo :attribute é inválido.',
|
||||
'array' => 'O campo :attribute deve ser um array.',
|
||||
'ascii' => 'O campo :attribute deve conter apenas caracteres alfanuméricos e símbolos de um byte.',
|
||||
'before' => 'O campo :attribute deve ser uma data anterior a :date.',
|
||||
'before_or_equal' => 'O campo :attribute deve ser uma data anterior ou igual a :date.',
|
||||
'between' => [
|
||||
'array' => 'O campo :attribute deve ter entre :min e :max itens.',
|
||||
'file' => 'O campo :attribute deve ter entre :min e :max kilobytes.',
|
||||
'numeric' => 'O campo :attribute deve estar entre :min e :max.',
|
||||
'string' => 'O campo :attribute deve ter entre :min e :max caracteres.',
|
||||
],
|
||||
'boolean' => 'O campo :attribute deve ser verdadeiro ou falso.',
|
||||
'can' => 'O campo :attribute contém um valor não autorizado.',
|
||||
'confirmed' => 'A confirmação do campo :attribute não corresponde.',
|
||||
'contains' => 'O campo :attribute não contém um valor obrigatório.',
|
||||
'current_password' => 'A senha está incorreta.',
|
||||
'date' => 'O campo :attribute deve ser uma data válida.',
|
||||
'date_equals' => 'O campo :attribute deve ser uma data igual a :date.',
|
||||
'date_format' => 'O campo :attribute deve corresponder ao formato :format.',
|
||||
'decimal' => 'O campo :attribute deve ter :decimal casas decimais.',
|
||||
'declined' => 'O campo :attribute deve ser recusado.',
|
||||
'declined_if' => 'O campo :attribute deve ser recusado quando :other for :value.',
|
||||
'different' => 'Os campos :attribute e :other devem ser diferentes.',
|
||||
'digits' => 'O campo :attribute deve ter :digits dígitos.',
|
||||
'digits_between' => 'O campo :attribute deve ter entre :min e :max dígitos.',
|
||||
'dimensions' => 'O campo :attribute tem dimensões de imagem inválidas.',
|
||||
'distinct' => 'O campo :attribute tem um valor duplicado.',
|
||||
'doesnt_contain' => 'O campo :attribute não deve conter: :values.',
|
||||
'doesnt_end_with' => 'O campo :attribute não deve terminar com: :values.',
|
||||
'doesnt_start_with' => 'O campo :attribute não deve começar com: :values.',
|
||||
'email' => 'O campo :attribute deve ser um endereço de e-mail válido.',
|
||||
'encoding' => 'O campo :attribute deve estar codificado em :encoding.',
|
||||
'ends_with' => 'O campo :attribute deve terminar com: :values.',
|
||||
'enum' => 'O :attribute selecionado é inválido.',
|
||||
'exists' => 'O :attribute selecionado é inválido.',
|
||||
'extensions' => 'O campo :attribute deve ter uma das seguintes extensões: :values.',
|
||||
'file' => 'O campo :attribute deve ser um arquivo.',
|
||||
'filled' => 'O campo :attribute deve ter um valor.',
|
||||
'gt' => [
|
||||
'array' => 'O campo :attribute deve ter mais de :value itens.',
|
||||
'file' => 'O campo :attribute deve ser maior que :value kilobytes.',
|
||||
'numeric' => 'O campo :attribute deve ser maior que :value.',
|
||||
'string' => 'O campo :attribute deve ter mais de :value caracteres.',
|
||||
],
|
||||
'gte' => [
|
||||
'array' => 'O campo :attribute deve ter :value itens ou mais.',
|
||||
'file' => 'O campo :attribute deve ser maior ou igual a :value kilobytes.',
|
||||
'numeric' => 'O campo :attribute deve ser maior ou igual a :value.',
|
||||
'string' => 'O campo :attribute deve ter :value caracteres ou mais.',
|
||||
],
|
||||
'hex_color' => 'O campo :attribute deve ser uma cor hexadecimal válida.',
|
||||
'image' => 'O campo :attribute deve ser uma imagem.',
|
||||
'in' => 'O :attribute selecionado é inválido.',
|
||||
'in_array' => 'O campo :attribute deve existir em :other.',
|
||||
'in_array_keys' => 'O campo :attribute deve conter pelo menos uma das seguintes chaves: :values.',
|
||||
'integer' => 'O campo :attribute deve ser um número inteiro.',
|
||||
'ip' => 'O campo :attribute deve ser um endereço IP válido.',
|
||||
'ipv4' => 'O campo :attribute deve ser um endereço IPv4 válido.',
|
||||
'ipv6' => 'O campo :attribute deve ser um endereço IPv6 válido.',
|
||||
'json' => 'O campo :attribute deve ser uma string JSON válida.',
|
||||
'list' => 'O campo :attribute deve ser uma lista.',
|
||||
'lowercase' => 'O campo :attribute deve estar em minúsculas.',
|
||||
'lt' => [
|
||||
'array' => 'O campo :attribute deve ter menos de :value itens.',
|
||||
'file' => 'O campo :attribute deve ser menor que :value kilobytes.',
|
||||
'numeric' => 'O campo :attribute deve ser menor que :value.',
|
||||
'string' => 'O campo :attribute deve ter menos de :value caracteres.',
|
||||
],
|
||||
'lte' => [
|
||||
'array' => 'O campo :attribute não deve ter mais de :value itens.',
|
||||
'file' => 'O campo :attribute deve ser menor ou igual a :value kilobytes.',
|
||||
'numeric' => 'O campo :attribute deve ser menor ou igual a :value.',
|
||||
'string' => 'O campo :attribute deve ter :value caracteres ou menos.',
|
||||
],
|
||||
'mac_address' => 'O campo :attribute deve ser um endereço MAC válido.',
|
||||
'max' => [
|
||||
'array' => 'O campo :attribute não deve ter mais de :max itens.',
|
||||
'file' => 'O campo :attribute não deve ser maior que :max kilobytes.',
|
||||
'numeric' => 'O campo :attribute não deve ser maior que :max.',
|
||||
'string' => 'O campo :attribute não deve ter mais de :max caracteres.',
|
||||
],
|
||||
'max_digits' => 'O campo :attribute não deve ter mais de :max dígitos.',
|
||||
'mimes' => 'O campo :attribute deve ser um arquivo do tipo: :values.',
|
||||
'mimetypes' => 'O campo :attribute deve ser um arquivo do tipo: :values.',
|
||||
'min' => [
|
||||
'array' => 'O campo :attribute deve ter pelo menos :min itens.',
|
||||
'file' => 'O campo :attribute deve ter pelo menos :min kilobytes.',
|
||||
'numeric' => 'O campo :attribute deve ser pelo menos :min.',
|
||||
'string' => 'O campo :attribute deve ter pelo menos :min caracteres.',
|
||||
],
|
||||
'min_digits' => 'O campo :attribute deve ter pelo menos :min dígitos.',
|
||||
'missing' => 'O campo :attribute deve estar ausente.',
|
||||
'missing_if' => 'O campo :attribute deve estar ausente quando :other for :value.',
|
||||
'missing_unless' => 'O campo :attribute deve estar ausente a menos que :other seja :value.',
|
||||
'missing_with' => 'O campo :attribute deve estar ausente quando :values estiver presente.',
|
||||
'missing_with_all' => 'O campo :attribute deve estar ausente quando :values estiverem presentes.',
|
||||
'multiple_of' => 'O campo :attribute deve ser um múltiplo de :value.',
|
||||
'not_in' => 'O :attribute selecionado é inválido.',
|
||||
'not_regex' => 'O formato do campo :attribute é inválido.',
|
||||
'numeric' => 'O campo :attribute deve ser um número.',
|
||||
'password' => [
|
||||
'letters' => 'O campo :attribute deve conter pelo menos uma letra.',
|
||||
'mixed' => 'O campo :attribute deve conter pelo menos uma letra maiúscula e uma minúscula.',
|
||||
'numbers' => 'O campo :attribute deve conter pelo menos um número.',
|
||||
'symbols' => 'O campo :attribute deve conter pelo menos um símbolo.',
|
||||
'uncompromised' => 'O :attribute fornecido apareceu em um vazamento de dados. Por favor, escolha um :attribute diferente.',
|
||||
],
|
||||
'present' => 'O campo :attribute deve estar presente.',
|
||||
'present_if' => 'O campo :attribute deve estar presente quando :other for :value.',
|
||||
'present_unless' => 'O campo :attribute deve estar presente a menos que :other seja :value.',
|
||||
'present_with' => 'O campo :attribute deve estar presente quando :values estiver presente.',
|
||||
'present_with_all' => 'O campo :attribute deve estar presente quando :values estiverem presentes.',
|
||||
'prohibited' => 'O campo :attribute é proibido.',
|
||||
'prohibited_if' => 'O campo :attribute é proibido quando :other for :value.',
|
||||
'prohibited_if_accepted' => 'O campo :attribute é proibido quando :other for aceito.',
|
||||
'prohibited_if_declined' => 'O campo :attribute é proibido quando :other for recusado.',
|
||||
'prohibited_unless' => 'O campo :attribute é proibido a menos que :other esteja em :values.',
|
||||
'prohibits' => 'O campo :attribute proíbe que :other esteja presente.',
|
||||
'regex' => 'O formato do campo :attribute é inválido.',
|
||||
'required' => 'O campo :attribute é obrigatório.',
|
||||
'required_array_keys' => 'O campo :attribute deve conter entradas para: :values.',
|
||||
'required_if' => 'O campo :attribute é obrigatório quando :other for :value.',
|
||||
'required_if_accepted' => 'O campo :attribute é obrigatório quando :other for aceito.',
|
||||
'required_if_declined' => 'O campo :attribute é obrigatório quando :other for recusado.',
|
||||
'required_unless' => 'O campo :attribute é obrigatório a menos que :other esteja em :values.',
|
||||
'required_with' => 'O campo :attribute é obrigatório quando :values estiver presente.',
|
||||
'required_with_all' => 'O campo :attribute é obrigatório quando :values estiverem presentes.',
|
||||
'required_without' => 'O campo :attribute é obrigatório quando :values não estiver presente.',
|
||||
'required_without_all' => 'O campo :attribute é obrigatório quando nenhum de :values estiver presente.',
|
||||
'same' => 'Os campos :attribute e :other devem corresponder.',
|
||||
'size' => [
|
||||
'array' => 'O campo :attribute deve conter :size itens.',
|
||||
'file' => 'O campo :attribute deve ter :size kilobytes.',
|
||||
'numeric' => 'O campo :attribute deve ser :size.',
|
||||
'string' => 'O campo :attribute deve ter :size caracteres.',
|
||||
],
|
||||
'starts_with' => 'O campo :attribute deve começar com: :values.',
|
||||
'string' => 'O campo :attribute deve ser uma string.',
|
||||
'timezone' => 'O campo :attribute deve ser um fuso horário válido.',
|
||||
'unique' => 'O :attribute já foi utilizado.',
|
||||
'uploaded' => 'O upload do :attribute falhou.',
|
||||
'uppercase' => 'O campo :attribute deve estar em maiúsculas.',
|
||||
'url' => 'O campo :attribute deve ser uma URL válida.',
|
||||
'ulid' => 'O campo :attribute deve ser um ULID válido.',
|
||||
'uuid' => 'O campo :attribute deve ser um UUID válido.',
|
||||
|
||||
'custom' => [
|
||||
'attribute-name' => [
|
||||
'rule-name' => 'custom-message',
|
||||
],
|
||||
],
|
||||
|
||||
'attributes' => [],
|
||||
];
|
||||
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Сообщения валидации
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
'accepted' => 'Поле :attribute должно быть принято.',
|
||||
'accepted_if' => 'Поле :attribute должно быть принято, когда :other равно :value.',
|
||||
'active_url' => 'Поле :attribute должно быть действительным URL.',
|
||||
'after' => 'Поле :attribute должно быть датой после :date.',
|
||||
'after_or_equal' => 'Поле :attribute должно быть датой после или равной :date.',
|
||||
'alpha' => 'Поле :attribute должно содержать только буквы.',
|
||||
'alpha_dash' => 'Поле :attribute должно содержать только буквы, цифры, дефисы и подчёркивания.',
|
||||
'alpha_num' => 'Поле :attribute должно содержать только буквы и цифры.',
|
||||
'any_of' => 'Поле :attribute недействительно.',
|
||||
'array' => 'Поле :attribute должно быть массивом.',
|
||||
'ascii' => 'Поле :attribute должно содержать только однобайтовые буквенно-цифровые символы и символы.',
|
||||
'before' => 'Поле :attribute должно быть датой до :date.',
|
||||
'before_or_equal' => 'Поле :attribute должно быть датой до или равной :date.',
|
||||
'between' => [
|
||||
'array' => 'Поле :attribute должно содержать от :min до :max элементов.',
|
||||
'file' => 'Поле :attribute должно быть от :min до :max килобайт.',
|
||||
'numeric' => 'Поле :attribute должно быть от :min до :max.',
|
||||
'string' => 'Поле :attribute должно содержать от :min до :max символов.',
|
||||
],
|
||||
'boolean' => 'Поле :attribute должно быть истиной или ложью.',
|
||||
'can' => 'Поле :attribute содержит неразрешённое значение.',
|
||||
'confirmed' => 'Подтверждение поля :attribute не совпадает.',
|
||||
'contains' => 'Поле :attribute не содержит обязательного значения.',
|
||||
'current_password' => 'Пароль неверный.',
|
||||
'date' => 'Поле :attribute должно быть действительной датой.',
|
||||
'date_equals' => 'Поле :attribute должно быть датой, равной :date.',
|
||||
'date_format' => 'Поле :attribute должно соответствовать формату :format.',
|
||||
'decimal' => 'Поле :attribute должно иметь :decimal десятичных знаков.',
|
||||
'declined' => 'Поле :attribute должно быть отклонено.',
|
||||
'declined_if' => 'Поле :attribute должно быть отклонено, когда :other равно :value.',
|
||||
'different' => 'Поля :attribute и :other должны различаться.',
|
||||
'digits' => 'Поле :attribute должно содержать :digits цифр.',
|
||||
'digits_between' => 'Поле :attribute должно содержать от :min до :max цифр.',
|
||||
'dimensions' => 'Поле :attribute имеет недействительные размеры изображения.',
|
||||
'distinct' => 'Поле :attribute содержит повторяющееся значение.',
|
||||
'doesnt_contain' => 'Поле :attribute не должно содержать: :values.',
|
||||
'doesnt_end_with' => 'Поле :attribute не должно заканчиваться на: :values.',
|
||||
'doesnt_start_with' => 'Поле :attribute не должно начинаться с: :values.',
|
||||
'email' => 'Поле :attribute должно быть действительным адресом электронной почты.',
|
||||
'encoding' => 'Поле :attribute должно быть закодировано в :encoding.',
|
||||
'ends_with' => 'Поле :attribute должно заканчиваться на: :values.',
|
||||
'enum' => 'Выбранное :attribute недействительно.',
|
||||
'exists' => 'Выбранное :attribute недействительно.',
|
||||
'extensions' => 'Поле :attribute должно иметь одно из следующих расширений: :values.',
|
||||
'file' => 'Поле :attribute должно быть файлом.',
|
||||
'filled' => 'Поле :attribute должно иметь значение.',
|
||||
'gt' => [
|
||||
'array' => 'Поле :attribute должно содержать более :value элементов.',
|
||||
'file' => 'Поле :attribute должно быть больше :value килобайт.',
|
||||
'numeric' => 'Поле :attribute должно быть больше :value.',
|
||||
'string' => 'Поле :attribute должно содержать более :value символов.',
|
||||
],
|
||||
'gte' => [
|
||||
'array' => 'Поле :attribute должно содержать :value элементов или более.',
|
||||
'file' => 'Поле :attribute должно быть больше или равно :value килобайт.',
|
||||
'numeric' => 'Поле :attribute должно быть больше или равно :value.',
|
||||
'string' => 'Поле :attribute должно содержать :value символов или более.',
|
||||
],
|
||||
'hex_color' => 'Поле :attribute должно быть действительным шестнадцатеричным цветом.',
|
||||
'image' => 'Поле :attribute должно быть изображением.',
|
||||
'in' => 'Выбранное :attribute недействительно.',
|
||||
'in_array' => 'Поле :attribute должно существовать в :other.',
|
||||
'in_array_keys' => 'Поле :attribute должно содержать хотя бы один из следующих ключей: :values.',
|
||||
'integer' => 'Поле :attribute должно быть целым числом.',
|
||||
'ip' => 'Поле :attribute должно быть действительным IP-адресом.',
|
||||
'ipv4' => 'Поле :attribute должно быть действительным IPv4-адресом.',
|
||||
'ipv6' => 'Поле :attribute должно быть действительным IPv6-адресом.',
|
||||
'json' => 'Поле :attribute должно быть действительной JSON-строкой.',
|
||||
'list' => 'Поле :attribute должно быть списком.',
|
||||
'lowercase' => 'Поле :attribute должно быть в нижнем регистре.',
|
||||
'lt' => [
|
||||
'array' => 'Поле :attribute должно содержать менее :value элементов.',
|
||||
'file' => 'Поле :attribute должно быть меньше :value килобайт.',
|
||||
'numeric' => 'Поле :attribute должно быть меньше :value.',
|
||||
'string' => 'Поле :attribute должно содержать менее :value символов.',
|
||||
],
|
||||
'lte' => [
|
||||
'array' => 'Поле :attribute не должно содержать более :value элементов.',
|
||||
'file' => 'Поле :attribute должно быть меньше или равно :value килобайт.',
|
||||
'numeric' => 'Поле :attribute должно быть меньше или равно :value.',
|
||||
'string' => 'Поле :attribute должно содержать :value символов или менее.',
|
||||
],
|
||||
'mac_address' => 'Поле :attribute должно быть действительным MAC-адресом.',
|
||||
'max' => [
|
||||
'array' => 'Поле :attribute не должно содержать более :max элементов.',
|
||||
'file' => 'Поле :attribute не должно быть больше :max килобайт.',
|
||||
'numeric' => 'Поле :attribute не должно быть больше :max.',
|
||||
'string' => 'Поле :attribute не должно содержать более :max символов.',
|
||||
],
|
||||
'max_digits' => 'Поле :attribute не должно содержать более :max цифр.',
|
||||
'mimes' => 'Поле :attribute должно быть файлом типа: :values.',
|
||||
'mimetypes' => 'Поле :attribute должно быть файлом типа: :values.',
|
||||
'min' => [
|
||||
'array' => 'Поле :attribute должно содержать не менее :min элементов.',
|
||||
'file' => 'Поле :attribute должно быть не менее :min килобайт.',
|
||||
'numeric' => 'Поле :attribute должно быть не менее :min.',
|
||||
'string' => 'Поле :attribute должно содержать не менее :min символов.',
|
||||
],
|
||||
'min_digits' => 'Поле :attribute должно содержать не менее :min цифр.',
|
||||
'missing' => 'Поле :attribute должно отсутствовать.',
|
||||
'missing_if' => 'Поле :attribute должно отсутствовать, когда :other равно :value.',
|
||||
'missing_unless' => 'Поле :attribute должно отсутствовать, если :other не равно :value.',
|
||||
'missing_with' => 'Поле :attribute должно отсутствовать, когда присутствует :values.',
|
||||
'missing_with_all' => 'Поле :attribute должно отсутствовать, когда присутствуют :values.',
|
||||
'multiple_of' => 'Поле :attribute должно быть кратным :value.',
|
||||
'not_in' => 'Выбранное :attribute недействительно.',
|
||||
'not_regex' => 'Формат поля :attribute недействителен.',
|
||||
'numeric' => 'Поле :attribute должно быть числом.',
|
||||
'password' => [
|
||||
'letters' => 'Поле :attribute должно содержать хотя бы одну букву.',
|
||||
'mixed' => 'Поле :attribute должно содержать хотя бы одну заглавную и одну строчную букву.',
|
||||
'numbers' => 'Поле :attribute должно содержать хотя бы одну цифру.',
|
||||
'symbols' => 'Поле :attribute должно содержать хотя бы один символ.',
|
||||
'uncompromised' => 'Указанное :attribute появилось в утечке данных. Пожалуйста, выберите другое :attribute.',
|
||||
],
|
||||
'present' => 'Поле :attribute должно присутствовать.',
|
||||
'present_if' => 'Поле :attribute должно присутствовать, когда :other равно :value.',
|
||||
'present_unless' => 'Поле :attribute должно присутствовать, если :other не равно :value.',
|
||||
'present_with' => 'Поле :attribute должно присутствовать, когда присутствует :values.',
|
||||
'present_with_all' => 'Поле :attribute должно присутствовать, когда присутствуют :values.',
|
||||
'prohibited' => 'Поле :attribute запрещено.',
|
||||
'prohibited_if' => 'Поле :attribute запрещено, когда :other равно :value.',
|
||||
'prohibited_if_accepted' => 'Поле :attribute запрещено, когда :other принято.',
|
||||
'prohibited_if_declined' => 'Поле :attribute запрещено, когда :other отклонено.',
|
||||
'prohibited_unless' => 'Поле :attribute запрещено, если :other не в :values.',
|
||||
'prohibits' => 'Поле :attribute запрещает присутствие :other.',
|
||||
'regex' => 'Формат поля :attribute недействителен.',
|
||||
'required' => 'Поле :attribute обязательно.',
|
||||
'required_array_keys' => 'Поле :attribute должно содержать записи для: :values.',
|
||||
'required_if' => 'Поле :attribute обязательно, когда :other равно :value.',
|
||||
'required_if_accepted' => 'Поле :attribute обязательно, когда :other принято.',
|
||||
'required_if_declined' => 'Поле :attribute обязательно, когда :other отклонено.',
|
||||
'required_unless' => 'Поле :attribute обязательно, если :other не в :values.',
|
||||
'required_with' => 'Поле :attribute обязательно, когда присутствует :values.',
|
||||
'required_with_all' => 'Поле :attribute обязательно, когда присутствуют :values.',
|
||||
'required_without' => 'Поле :attribute обязательно, когда :values отсутствует.',
|
||||
'required_without_all' => 'Поле :attribute обязательно, когда ни одно из :values не присутствует.',
|
||||
'same' => 'Поля :attribute и :other должны совпадать.',
|
||||
'size' => [
|
||||
'array' => 'Поле :attribute должно содержать :size элементов.',
|
||||
'file' => 'Поле :attribute должно быть :size килобайт.',
|
||||
'numeric' => 'Поле :attribute должно быть :size.',
|
||||
'string' => 'Поле :attribute должно содержать :size символов.',
|
||||
],
|
||||
'starts_with' => 'Поле :attribute должно начинаться с: :values.',
|
||||
'string' => 'Поле :attribute должно быть строкой.',
|
||||
'timezone' => 'Поле :attribute должно быть действительным часовым поясом.',
|
||||
'unique' => 'Такое :attribute уже существует.',
|
||||
'uploaded' => 'Загрузка :attribute не удалась.',
|
||||
'uppercase' => 'Поле :attribute должно быть в верхнем регистре.',
|
||||
'url' => 'Поле :attribute должно быть действительным URL.',
|
||||
'ulid' => 'Поле :attribute должно быть действительным ULID.',
|
||||
'uuid' => 'Поле :attribute должно быть действительным UUID.',
|
||||
|
||||
'custom' => [
|
||||
'attribute-name' => [
|
||||
'rule-name' => 'custom-message',
|
||||
],
|
||||
],
|
||||
|
||||
'attributes' => [],
|
||||
];
|
||||
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| ข้อความการตรวจสอบ
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
'accepted' => 'ฟิลด์ :attribute ต้องได้รับการยอมรับ',
|
||||
'accepted_if' => 'ฟิลด์ :attribute ต้องได้รับการยอมรับเมื่อ :other เป็น :value',
|
||||
'active_url' => 'ฟิลด์ :attribute ต้องเป็น URL ที่ถูกต้อง',
|
||||
'after' => 'ฟิลด์ :attribute ต้องเป็นวันที่หลังจาก :date',
|
||||
'after_or_equal' => 'ฟิลด์ :attribute ต้องเป็นวันที่หลังหรือเท่ากับ :date',
|
||||
'alpha' => 'ฟิลด์ :attribute ต้องมีเฉพาะตัวอักษรเท่านั้น',
|
||||
'alpha_dash' => 'ฟิลด์ :attribute ต้องมีเฉพาะตัวอักษร ตัวเลข ขีด และขีดล่างเท่านั้น',
|
||||
'alpha_num' => 'ฟิลด์ :attribute ต้องมีเฉพาะตัวอักษรและตัวเลขเท่านั้น',
|
||||
'any_of' => 'ฟิลด์ :attribute ไม่ถูกต้อง',
|
||||
'array' => 'ฟิลด์ :attribute ต้องเป็นอาร์เรย์',
|
||||
'ascii' => 'ฟิลด์ :attribute ต้องมีเฉพาะอักขระตัวเลขและสัญลักษณ์แบบไบต์เดียวเท่านั้น',
|
||||
'before' => 'ฟิลด์ :attribute ต้องเป็นวันที่ก่อน :date',
|
||||
'before_or_equal' => 'ฟิลด์ :attribute ต้องเป็นวันที่ก่อนหรือเท่ากับ :date',
|
||||
'between' => [
|
||||
'array' => 'ฟิลด์ :attribute ต้องมีระหว่าง :min ถึง :max รายการ',
|
||||
'file' => 'ฟิลด์ :attribute ต้องมีขนาดระหว่าง :min ถึง :max กิโลไบต์',
|
||||
'numeric' => 'ฟิลด์ :attribute ต้องอยู่ระหว่าง :min ถึง :max',
|
||||
'string' => 'ฟิลด์ :attribute ต้องมีความยาวระหว่าง :min ถึง :max ตัวอักษร',
|
||||
],
|
||||
'boolean' => 'ฟิลด์ :attribute ต้องเป็นจริงหรือเท็จ',
|
||||
'can' => 'ฟิลด์ :attribute มีค่าที่ไม่ได้รับอนุญาต',
|
||||
'confirmed' => 'การยืนยันฟิลด์ :attribute ไม่ตรงกัน',
|
||||
'contains' => 'ฟิลด์ :attribute ไม่มีค่าที่จำเป็น',
|
||||
'current_password' => 'รหัสผ่านไม่ถูกต้อง',
|
||||
'date' => 'ฟิลด์ :attribute ต้องเป็นวันที่ที่ถูกต้อง',
|
||||
'date_equals' => 'ฟิลด์ :attribute ต้องเป็นวันที่เท่ากับ :date',
|
||||
'date_format' => 'ฟิลด์ :attribute ต้องตรงกับรูปแบบ :format',
|
||||
'decimal' => 'ฟิลด์ :attribute ต้องมีทศนิยม :decimal ตำแหน่ง',
|
||||
'declined' => 'ฟิลด์ :attribute ต้องถูกปฏิเสธ',
|
||||
'declined_if' => 'ฟิลด์ :attribute ต้องถูกปฏิเสธเมื่อ :other เป็น :value',
|
||||
'different' => 'ฟิลด์ :attribute และ :other ต้องแตกต่างกัน',
|
||||
'digits' => 'ฟิลด์ :attribute ต้องมี :digits หลัก',
|
||||
'digits_between' => 'ฟิลด์ :attribute ต้องมีระหว่าง :min ถึง :max หลัก',
|
||||
'dimensions' => 'ฟิลด์ :attribute มีขนาดรูปภาพไม่ถูกต้อง',
|
||||
'distinct' => 'ฟิลด์ :attribute มีค่าซ้ำ',
|
||||
'doesnt_contain' => 'ฟิลด์ :attribute ต้องไม่มี: :values',
|
||||
'doesnt_end_with' => 'ฟิลด์ :attribute ต้องไม่ลงท้ายด้วย: :values',
|
||||
'doesnt_start_with' => 'ฟิลด์ :attribute ต้องไม่ขึ้นต้นด้วย: :values',
|
||||
'email' => 'ฟิลด์ :attribute ต้องเป็นที่อยู่อีเมลที่ถูกต้อง',
|
||||
'encoding' => 'ฟิลด์ :attribute ต้องเข้ารหัสด้วย :encoding',
|
||||
'ends_with' => 'ฟิลด์ :attribute ต้องลงท้ายด้วย: :values',
|
||||
'enum' => ':attribute ที่เลือกไม่ถูกต้อง',
|
||||
'exists' => ':attribute ที่เลือกไม่ถูกต้อง',
|
||||
'extensions' => 'ฟิลด์ :attribute ต้องมีนามสกุลใดนามสกุลหนึ่งต่อไปนี้: :values',
|
||||
'file' => 'ฟิลด์ :attribute ต้องเป็นไฟล์',
|
||||
'filled' => 'ฟิลด์ :attribute ต้องมีค่า',
|
||||
'gt' => [
|
||||
'array' => 'ฟิลด์ :attribute ต้องมีมากกว่า :value รายการ',
|
||||
'file' => 'ฟิลด์ :attribute ต้องใหญ่กว่า :value กิโลไบต์',
|
||||
'numeric' => 'ฟิลด์ :attribute ต้องมากกว่า :value',
|
||||
'string' => 'ฟิลด์ :attribute ต้องยาวกว่า :value ตัวอักษร',
|
||||
],
|
||||
'gte' => [
|
||||
'array' => 'ฟิลด์ :attribute ต้องมี :value รายการขึ้นไป',
|
||||
'file' => 'ฟิลด์ :attribute ต้องใหญ่กว่าหรือเท่ากับ :value กิโลไบต์',
|
||||
'numeric' => 'ฟิลด์ :attribute ต้องมากกว่าหรือเท่ากับ :value',
|
||||
'string' => 'ฟิลด์ :attribute ต้องยาว :value ตัวอักษรขึ้นไป',
|
||||
],
|
||||
'hex_color' => 'ฟิลด์ :attribute ต้องเป็นสีฐานสิบหกที่ถูกต้อง',
|
||||
'image' => 'ฟิลด์ :attribute ต้องเป็นรูปภาพ',
|
||||
'in' => ':attribute ที่เลือกไม่ถูกต้อง',
|
||||
'in_array' => 'ฟิลด์ :attribute ต้องมีอยู่ใน :other',
|
||||
'in_array_keys' => 'ฟิลด์ :attribute ต้องมีคีย์อย่างน้อยหนึ่งรายการต่อไปนี้: :values',
|
||||
'integer' => 'ฟิลด์ :attribute ต้องเป็นจำนวนเต็ม',
|
||||
'ip' => 'ฟิลด์ :attribute ต้องเป็นที่อยู่ IP ที่ถูกต้อง',
|
||||
'ipv4' => 'ฟิลด์ :attribute ต้องเป็นที่อยู่ IPv4 ที่ถูกต้อง',
|
||||
'ipv6' => 'ฟิลด์ :attribute ต้องเป็นที่อยู่ IPv6 ที่ถูกต้อง',
|
||||
'json' => 'ฟิลด์ :attribute ต้องเป็นสตริง JSON ที่ถูกต้อง',
|
||||
'list' => 'ฟิลด์ :attribute ต้องเป็นรายการ',
|
||||
'lowercase' => 'ฟิลด์ :attribute ต้องเป็นตัวพิมพ์เล็ก',
|
||||
'lt' => [
|
||||
'array' => 'ฟิลด์ :attribute ต้องมีน้อยกว่า :value รายการ',
|
||||
'file' => 'ฟิลด์ :attribute ต้องเล็กกว่า :value กิโลไบต์',
|
||||
'numeric' => 'ฟิลด์ :attribute ต้องน้อยกว่า :value',
|
||||
'string' => 'ฟิลด์ :attribute ต้องสั้นกว่า :value ตัวอักษร',
|
||||
],
|
||||
'lte' => [
|
||||
'array' => 'ฟิลด์ :attribute ต้องไม่เกิน :value รายการ',
|
||||
'file' => 'ฟิลด์ :attribute ต้องเล็กกว่าหรือเท่ากับ :value กิโลไบต์',
|
||||
'numeric' => 'ฟิลด์ :attribute ต้องน้อยกว่าหรือเท่ากับ :value',
|
||||
'string' => 'ฟิลด์ :attribute ต้องไม่เกิน :value ตัวอักษร',
|
||||
],
|
||||
'mac_address' => 'ฟิลด์ :attribute ต้องเป็นที่อยู่ MAC ที่ถูกต้อง',
|
||||
'max' => [
|
||||
'array' => 'ฟิลด์ :attribute ต้องไม่เกิน :max รายการ',
|
||||
'file' => 'ฟิลด์ :attribute ต้องไม่เกิน :max กิโลไบต์',
|
||||
'numeric' => 'ฟิลด์ :attribute ต้องไม่เกิน :max',
|
||||
'string' => 'ฟิลด์ :attribute ต้องไม่เกิน :max ตัวอักษร',
|
||||
],
|
||||
'max_digits' => 'ฟิลด์ :attribute ต้องไม่เกิน :max หลัก',
|
||||
'mimes' => 'ฟิลด์ :attribute ต้องเป็นไฟล์ประเภท: :values',
|
||||
'mimetypes' => 'ฟิลด์ :attribute ต้องเป็นไฟล์ประเภท: :values',
|
||||
'min' => [
|
||||
'array' => 'ฟิลด์ :attribute ต้องมีอย่างน้อย :min รายการ',
|
||||
'file' => 'ฟิลด์ :attribute ต้องมีอย่างน้อย :min กิโลไบต์',
|
||||
'numeric' => 'ฟิลด์ :attribute ต้องมีอย่างน้อย :min',
|
||||
'string' => 'ฟิลด์ :attribute ต้องมีอย่างน้อย :min ตัวอักษร',
|
||||
],
|
||||
'min_digits' => 'ฟิลด์ :attribute ต้องมีอย่างน้อย :min หลัก',
|
||||
'missing' => 'ฟิลด์ :attribute ต้องไม่มี',
|
||||
'missing_if' => 'ฟิลด์ :attribute ต้องไม่มีเมื่อ :other เป็น :value',
|
||||
'missing_unless' => 'ฟิลด์ :attribute ต้องไม่มีเว้นแต่ :other เป็น :value',
|
||||
'missing_with' => 'ฟิลด์ :attribute ต้องไม่มีเมื่อ :values มีอยู่',
|
||||
'missing_with_all' => 'ฟิลด์ :attribute ต้องไม่มีเมื่อ :values มีอยู่',
|
||||
'multiple_of' => 'ฟิลด์ :attribute ต้องเป็นพหุคูณของ :value',
|
||||
'not_in' => ':attribute ที่เลือกไม่ถูกต้อง',
|
||||
'not_regex' => 'รูปแบบฟิลด์ :attribute ไม่ถูกต้อง',
|
||||
'numeric' => 'ฟิลด์ :attribute ต้องเป็นตัวเลข',
|
||||
'password' => [
|
||||
'letters' => 'ฟิลด์ :attribute ต้องมีอย่างน้อยหนึ่งตัวอักษร',
|
||||
'mixed' => 'ฟิลด์ :attribute ต้องมีอย่างน้อยหนึ่งตัวพิมพ์ใหญ่และหนึ่งตัวพิมพ์เล็ก',
|
||||
'numbers' => 'ฟิลด์ :attribute ต้องมีอย่างน้อยหนึ่งตัวเลข',
|
||||
'symbols' => 'ฟิลด์ :attribute ต้องมีอย่างน้อยหนึ่งสัญลักษณ์',
|
||||
'uncompromised' => ':attribute ที่ให้มามีการปรากฏในการรั่วไหลของข้อมูล กรุณาเลือก :attribute อื่น',
|
||||
],
|
||||
'present' => 'ฟิลด์ :attribute ต้องมีอยู่',
|
||||
'present_if' => 'ฟิลด์ :attribute ต้องมีอยู่เมื่อ :other เป็น :value',
|
||||
'present_unless' => 'ฟิลด์ :attribute ต้องมีอยู่เว้นแต่ :other เป็น :value',
|
||||
'present_with' => 'ฟิลด์ :attribute ต้องมีอยู่เมื่อ :values มีอยู่',
|
||||
'present_with_all' => 'ฟิลด์ :attribute ต้องมีอยู่เมื่อ :values มีอยู่',
|
||||
'prohibited' => 'ฟิลด์ :attribute ถูกห้าม',
|
||||
'prohibited_if' => 'ฟิลด์ :attribute ถูกห้ามเมื่อ :other เป็น :value',
|
||||
'prohibited_if_accepted' => 'ฟิลด์ :attribute ถูกห้ามเมื่อ :other ถูกยอมรับ',
|
||||
'prohibited_if_declined' => 'ฟิลด์ :attribute ถูกห้ามเมื่อ :other ถูกปฏิเสธ',
|
||||
'prohibited_unless' => 'ฟิลด์ :attribute ถูกห้ามเว้นแต่ :other อยู่ใน :values',
|
||||
'prohibits' => 'ฟิลด์ :attribute ห้าม :other มีอยู่',
|
||||
'regex' => 'รูปแบบฟิลด์ :attribute ไม่ถูกต้อง',
|
||||
'required' => 'ฟิลด์ :attribute จำเป็นต้องมี',
|
||||
'required_array_keys' => 'ฟิลด์ :attribute ต้องมีรายการสำหรับ: :values',
|
||||
'required_if' => 'ฟิลด์ :attribute จำเป็นต้องมีเมื่อ :other เป็น :value',
|
||||
'required_if_accepted' => 'ฟิลด์ :attribute จำเป็นต้องมีเมื่อ :other ถูกยอมรับ',
|
||||
'required_if_declined' => 'ฟิลด์ :attribute จำเป็นต้องมีเมื่อ :other ถูกปฏิเสธ',
|
||||
'required_unless' => 'ฟิลด์ :attribute จำเป็นต้องมีเว้นแต่ :other อยู่ใน :values',
|
||||
'required_with' => 'ฟิลด์ :attribute จำเป็นต้องมีเมื่อ :values มีอยู่',
|
||||
'required_with_all' => 'ฟิลด์ :attribute จำเป็นต้องมีเมื่อ :values มีอยู่',
|
||||
'required_without' => 'ฟิลด์ :attribute จำเป็นต้องมีเมื่อ :values ไม่มีอยู่',
|
||||
'required_without_all' => 'ฟิลด์ :attribute จำเป็นต้องมีเมื่อไม่มี :values',
|
||||
'same' => 'ฟิลด์ :attribute และ :other ต้องตรงกัน',
|
||||
'size' => [
|
||||
'array' => 'ฟิลด์ :attribute ต้องมี :size รายการ',
|
||||
'file' => 'ฟิลด์ :attribute ต้องมีขนาด :size กิโลไบต์',
|
||||
'numeric' => 'ฟิลด์ :attribute ต้องเป็น :size',
|
||||
'string' => 'ฟิลด์ :attribute ต้องมีความยาว :size ตัวอักษร',
|
||||
],
|
||||
'starts_with' => 'ฟิลด์ :attribute ต้องขึ้นต้นด้วย: :values',
|
||||
'string' => 'ฟิลด์ :attribute ต้องเป็นสตริง',
|
||||
'timezone' => 'ฟิลด์ :attribute ต้องเป็นเขตเวลาที่ถูกต้อง',
|
||||
'unique' => ':attribute ถูกใช้ไปแล้ว',
|
||||
'uploaded' => 'การอัปโหลด :attribute ล้มเหลว',
|
||||
'uppercase' => 'ฟิลด์ :attribute ต้องเป็นตัวพิมพ์ใหญ่',
|
||||
'url' => 'ฟิลด์ :attribute ต้องเป็น URL ที่ถูกต้อง',
|
||||
'ulid' => 'ฟิลด์ :attribute ต้องเป็น ULID ที่ถูกต้อง',
|
||||
'uuid' => 'ฟิลด์ :attribute ต้องเป็น UUID ที่ถูกต้อง',
|
||||
|
||||
'custom' => [
|
||||
'attribute-name' => [
|
||||
'rule-name' => 'custom-message',
|
||||
],
|
||||
],
|
||||
|
||||
'attributes' => [],
|
||||
];
|
||||
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Doğrulama mesajları
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
'accepted' => ':attribute alanı kabul edilmelidir.',
|
||||
'accepted_if' => ':other :value olduğunda :attribute alanı kabul edilmelidir.',
|
||||
'active_url' => ':attribute alanı geçerli bir URL olmalıdır.',
|
||||
'after' => ':attribute alanı :date tarihinden sonra bir tarih olmalıdır.',
|
||||
'after_or_equal' => ':attribute alanı :date tarihinden sonra veya aynı tarihte olmalıdır.',
|
||||
'alpha' => ':attribute alanı yalnızca harf içermelidir.',
|
||||
'alpha_dash' => ':attribute alanı yalnızca harf, rakam, tire ve alt çizgi içermelidir.',
|
||||
'alpha_num' => ':attribute alanı yalnızca harf ve rakam içermelidir.',
|
||||
'any_of' => ':attribute alanı geçersiz.',
|
||||
'array' => ':attribute alanı bir dizi olmalıdır.',
|
||||
'ascii' => ':attribute alanı yalnızca tek baytlık alfanümerik karakterler ve semboller içermelidir.',
|
||||
'before' => ':attribute alanı :date tarihinden önce bir tarih olmalıdır.',
|
||||
'before_or_equal' => ':attribute alanı :date tarihinden önce veya aynı tarihte olmalıdır.',
|
||||
'between' => [
|
||||
'array' => ':attribute alanı :min ile :max öğe arasında olmalıdır.',
|
||||
'file' => ':attribute alanı :min ile :max kilobayt arasında olmalıdır.',
|
||||
'numeric' => ':attribute alanı :min ile :max arasında olmalıdır.',
|
||||
'string' => ':attribute alanı :min ile :max karakter arasında olmalıdır.',
|
||||
],
|
||||
'boolean' => ':attribute alanı doğru veya yanlış olmalıdır.',
|
||||
'can' => ':attribute alanı yetkisiz bir değer içeriyor.',
|
||||
'confirmed' => ':attribute alanı onayı eşleşmiyor.',
|
||||
'contains' => ':attribute alanı gerekli bir değer içermiyor.',
|
||||
'current_password' => 'Şifre yanlış.',
|
||||
'date' => ':attribute alanı geçerli bir tarih olmalıdır.',
|
||||
'date_equals' => ':attribute alanı :date tarihine eşit bir tarih olmalıdır.',
|
||||
'date_format' => ':attribute alanı :format biçimine uymalıdır.',
|
||||
'decimal' => ':attribute alanı :decimal ondalık basamağa sahip olmalıdır.',
|
||||
'declined' => ':attribute alanı reddedilmelidir.',
|
||||
'declined_if' => ':other :value olduğunda :attribute alanı reddedilmelidir.',
|
||||
'different' => ':attribute ve :other alanları farklı olmalıdır.',
|
||||
'digits' => ':attribute alanı :digits basamaklı olmalıdır.',
|
||||
'digits_between' => ':attribute alanı :min ile :max basamak arasında olmalıdır.',
|
||||
'dimensions' => ':attribute alanının görsel boyutları geçersiz.',
|
||||
'distinct' => ':attribute alanında yinelenen bir değer var.',
|
||||
'doesnt_contain' => ':attribute alanı şunları içermemelidir: :values.',
|
||||
'doesnt_end_with' => ':attribute alanı şunlarla bitmemelidir: :values.',
|
||||
'doesnt_start_with' => ':attribute alanı şunlarla başlamamalıdır: :values.',
|
||||
'email' => ':attribute alanı geçerli bir e-posta adresi olmalıdır.',
|
||||
'encoding' => ':attribute alanı :encoding ile kodlanmış olmalıdır.',
|
||||
'ends_with' => ':attribute alanı şunlarla bitmelidir: :values.',
|
||||
'enum' => 'Seçilen :attribute geçersiz.',
|
||||
'exists' => 'Seçilen :attribute geçersiz.',
|
||||
'extensions' => ':attribute alanı şu uzantılardan birine sahip olmalıdır: :values.',
|
||||
'file' => ':attribute alanı bir dosya olmalıdır.',
|
||||
'filled' => ':attribute alanının bir değeri olmalıdır.',
|
||||
'gt' => [
|
||||
'array' => ':attribute alanı :value öğeden fazla içermelidir.',
|
||||
'file' => ':attribute alanı :value kilobayttan büyük olmalıdır.',
|
||||
'numeric' => ':attribute alanı :value değerinden büyük olmalıdır.',
|
||||
'string' => ':attribute alanı :value karakterden fazla içermelidir.',
|
||||
],
|
||||
'gte' => [
|
||||
'array' => ':attribute alanı :value veya daha fazla öğe içermelidir.',
|
||||
'file' => ':attribute alanı :value kilobayt veya daha fazla olmalıdır.',
|
||||
'numeric' => ':attribute alanı :value veya daha fazla olmalıdır.',
|
||||
'string' => ':attribute alanı :value veya daha fazla karakter içermelidir.',
|
||||
],
|
||||
'hex_color' => ':attribute alanı geçerli bir onaltılık renk olmalıdır.',
|
||||
'image' => ':attribute alanı bir görsel olmalıdır.',
|
||||
'in' => 'Seçilen :attribute geçersiz.',
|
||||
'in_array' => ':attribute alanı :other içinde bulunmalıdır.',
|
||||
'in_array_keys' => ':attribute alanı şu anahtarlardan en az birini içermelidir: :values.',
|
||||
'integer' => ':attribute alanı bir tam sayı olmalıdır.',
|
||||
'ip' => ':attribute alanı geçerli bir IP adresi olmalıdır.',
|
||||
'ipv4' => ':attribute alanı geçerli bir IPv4 adresi olmalıdır.',
|
||||
'ipv6' => ':attribute alanı geçerli bir IPv6 adresi olmalıdır.',
|
||||
'json' => ':attribute alanı geçerli bir JSON dizisi olmalıdır.',
|
||||
'list' => ':attribute alanı bir liste olmalıdır.',
|
||||
'lowercase' => ':attribute alanı küçük harf olmalıdır.',
|
||||
'lt' => [
|
||||
'array' => ':attribute alanı :value öğeden az içermelidir.',
|
||||
'file' => ':attribute alanı :value kilobayttan küçük olmalıdır.',
|
||||
'numeric' => ':attribute alanı :value değerinden küçük olmalıdır.',
|
||||
'string' => ':attribute alanı :value karakterden az içermelidir.',
|
||||
],
|
||||
'lte' => [
|
||||
'array' => ':attribute alanı :value öğeden fazla içermemelidir.',
|
||||
'file' => ':attribute alanı :value kilobayt veya daha az olmalıdır.',
|
||||
'numeric' => ':attribute alanı :value veya daha az olmalıdır.',
|
||||
'string' => ':attribute alanı :value karakter veya daha az içermelidir.',
|
||||
],
|
||||
'mac_address' => ':attribute alanı geçerli bir MAC adresi olmalıdır.',
|
||||
'max' => [
|
||||
'array' => ':attribute alanı :max öğeden fazla içermemelidir.',
|
||||
'file' => ':attribute alanı :max kilobayttan büyük olmamalıdır.',
|
||||
'numeric' => ':attribute alanı :max değerinden büyük olmamalıdır.',
|
||||
'string' => ':attribute alanı :max karakterden fazla içermemelidir.',
|
||||
],
|
||||
'max_digits' => ':attribute alanı :max basamaktan fazla içermemelidir.',
|
||||
'mimes' => ':attribute alanı şu türde bir dosya olmalıdır: :values.',
|
||||
'mimetypes' => ':attribute alanı şu türde bir dosya olmalıdır: :values.',
|
||||
'min' => [
|
||||
'array' => ':attribute alanı en az :min öğe içermelidir.',
|
||||
'file' => ':attribute alanı en az :min kilobayt olmalıdır.',
|
||||
'numeric' => ':attribute alanı en az :min olmalıdır.',
|
||||
'string' => ':attribute alanı en az :min karakter içermelidir.',
|
||||
],
|
||||
'min_digits' => ':attribute alanı en az :min basamak içermelidir.',
|
||||
'missing' => ':attribute alanı eksik olmalıdır.',
|
||||
'missing_if' => ':other :value olduğunda :attribute alanı eksik olmalıdır.',
|
||||
'missing_unless' => ':other :value olmadıkça :attribute alanı eksik olmalıdır.',
|
||||
'missing_with' => ':values mevcut olduğunda :attribute alanı eksik olmalıdır.',
|
||||
'missing_with_all' => ':values mevcut olduğunda :attribute alanı eksik olmalıdır.',
|
||||
'multiple_of' => ':attribute alanı :value\'nin katı olmalıdır.',
|
||||
'not_in' => 'Seçilen :attribute geçersiz.',
|
||||
'not_regex' => ':attribute alanı biçimi geçersiz.',
|
||||
'numeric' => ':attribute alanı bir sayı olmalıdır.',
|
||||
'password' => [
|
||||
'letters' => ':attribute alanı en az bir harf içermelidir.',
|
||||
'mixed' => ':attribute alanı en az bir büyük ve bir küçük harf içermelidir.',
|
||||
'numbers' => ':attribute alanı en az bir rakam içermelidir.',
|
||||
'symbols' => ':attribute alanı en az bir sembol içermelidir.',
|
||||
'uncompromised' => 'Verilen :attribute bir veri sızıntısında göründü. Lütfen farklı bir :attribute seçin.',
|
||||
],
|
||||
'present' => ':attribute alanı mevcut olmalıdır.',
|
||||
'present_if' => ':other :value olduğunda :attribute alanı mevcut olmalıdır.',
|
||||
'present_unless' => ':other :value olmadıkça :attribute alanı mevcut olmalıdır.',
|
||||
'present_with' => ':values mevcut olduğunda :attribute alanı mevcut olmalıdır.',
|
||||
'present_with_all' => ':values mevcut olduğunda :attribute alanı mevcut olmalıdır.',
|
||||
'prohibited' => ':attribute alanı yasaktır.',
|
||||
'prohibited_if' => ':other :value olduğunda :attribute alanı yasaktır.',
|
||||
'prohibited_if_accepted' => ':other kabul edildiğinde :attribute alanı yasaktır.',
|
||||
'prohibited_if_declined' => ':other reddedildiğinde :attribute alanı yasaktır.',
|
||||
'prohibited_unless' => ':other :values içinde olmadıkça :attribute alanı yasaktır.',
|
||||
'prohibits' => ':attribute alanı :other\'ın mevcut olmasını yasaklar.',
|
||||
'regex' => ':attribute alanı biçimi geçersiz.',
|
||||
'required' => ':attribute alanı zorunludur.',
|
||||
'required_array_keys' => ':attribute alanı şunlar için girişler içermelidir: :values.',
|
||||
'required_if' => ':other :value olduğunda :attribute alanı zorunludur.',
|
||||
'required_if_accepted' => ':other kabul edildiğinde :attribute alanı zorunludur.',
|
||||
'required_if_declined' => ':other reddedildiğinde :attribute alanı zorunludur.',
|
||||
'required_unless' => ':other :values içinde olmadıkça :attribute alanı zorunludur.',
|
||||
'required_with' => ':values mevcut olduğunda :attribute alanı zorunludur.',
|
||||
'required_with_all' => ':values mevcut olduğunda :attribute alanı zorunludur.',
|
||||
'required_without' => ':values mevcut olmadığında :attribute alanı zorunludur.',
|
||||
'required_without_all' => ':values\'tan hiçbiri mevcut olmadığında :attribute alanı zorunludur.',
|
||||
'same' => ':attribute ve :other alanları eşleşmelidir.',
|
||||
'size' => [
|
||||
'array' => ':attribute alanı :size öğe içermelidir.',
|
||||
'file' => ':attribute alanı :size kilobayt olmalıdır.',
|
||||
'numeric' => ':attribute alanı :size olmalıdır.',
|
||||
'string' => ':attribute alanı :size karakter içermelidir.',
|
||||
],
|
||||
'starts_with' => ':attribute alanı şunlarla başlamalıdır: :values.',
|
||||
'string' => ':attribute alanı bir dizge olmalıdır.',
|
||||
'timezone' => ':attribute alanı geçerli bir saat dilimi olmalıdır.',
|
||||
'unique' => ':attribute zaten kullanılmış.',
|
||||
'uploaded' => ':attribute yüklenemedi.',
|
||||
'uppercase' => ':attribute alanı büyük harf olmalıdır.',
|
||||
'url' => ':attribute alanı geçerli bir URL olmalıdır.',
|
||||
'ulid' => ':attribute alanı geçerli bir ULID olmalıdır.',
|
||||
'uuid' => ':attribute alanı geçerli bir UUID olmalıdır.',
|
||||
|
||||
'custom' => [
|
||||
'attribute-name' => [
|
||||
'rule-name' => 'custom-message',
|
||||
],
|
||||
],
|
||||
|
||||
'attributes' => [],
|
||||
];
|
||||
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Thông báo xác thực
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
'accepted' => 'Trường :attribute phải được chấp nhận.',
|
||||
'accepted_if' => 'Trường :attribute phải được chấp nhận khi :other là :value.',
|
||||
'active_url' => 'Trường :attribute phải là URL hợp lệ.',
|
||||
'after' => 'Trường :attribute phải là ngày sau :date.',
|
||||
'after_or_equal' => 'Trường :attribute phải là ngày sau hoặc bằng :date.',
|
||||
'alpha' => 'Trường :attribute chỉ được chứa chữ cái.',
|
||||
'alpha_dash' => 'Trường :attribute chỉ được chứa chữ cái, số, dấu gạch ngang và gạch dưới.',
|
||||
'alpha_num' => 'Trường :attribute chỉ được chứa chữ cái và số.',
|
||||
'any_of' => 'Trường :attribute không hợp lệ.',
|
||||
'array' => 'Trường :attribute phải là mảng.',
|
||||
'ascii' => 'Trường :attribute chỉ được chứa ký tự chữ số và ký hiệu một byte.',
|
||||
'before' => 'Trường :attribute phải là ngày trước :date.',
|
||||
'before_or_equal' => 'Trường :attribute phải là ngày trước hoặc bằng :date.',
|
||||
'between' => [
|
||||
'array' => 'Trường :attribute phải có từ :min đến :max phần tử.',
|
||||
'file' => 'Trường :attribute phải từ :min đến :max kilobyte.',
|
||||
'numeric' => 'Trường :attribute phải từ :min đến :max.',
|
||||
'string' => 'Trường :attribute phải có từ :min đến :max ký tự.',
|
||||
],
|
||||
'boolean' => 'Trường :attribute phải là đúng hoặc sai.',
|
||||
'can' => 'Trường :attribute chứa giá trị không được phép.',
|
||||
'confirmed' => 'Xác nhận trường :attribute không khớp.',
|
||||
'contains' => 'Trường :attribute thiếu giá trị bắt buộc.',
|
||||
'current_password' => 'Mật khẩu không đúng.',
|
||||
'date' => 'Trường :attribute phải là ngày hợp lệ.',
|
||||
'date_equals' => 'Trường :attribute phải là ngày bằng :date.',
|
||||
'date_format' => 'Trường :attribute phải khớp với định dạng :format.',
|
||||
'decimal' => 'Trường :attribute phải có :decimal chữ số thập phân.',
|
||||
'declined' => 'Trường :attribute phải bị từ chối.',
|
||||
'declined_if' => 'Trường :attribute phải bị từ chối khi :other là :value.',
|
||||
'different' => 'Các trường :attribute và :other phải khác nhau.',
|
||||
'digits' => 'Trường :attribute phải có :digits chữ số.',
|
||||
'digits_between' => 'Trường :attribute phải có từ :min đến :max chữ số.',
|
||||
'dimensions' => 'Trường :attribute có kích thước hình ảnh không hợp lệ.',
|
||||
'distinct' => 'Trường :attribute có giá trị trùng lặp.',
|
||||
'doesnt_contain' => 'Trường :attribute không được chứa: :values.',
|
||||
'doesnt_end_with' => 'Trường :attribute không được kết thúc bằng: :values.',
|
||||
'doesnt_start_with' => 'Trường :attribute không được bắt đầu bằng: :values.',
|
||||
'email' => 'Trường :attribute phải là địa chỉ email hợp lệ.',
|
||||
'encoding' => 'Trường :attribute phải được mã hóa bằng :encoding.',
|
||||
'ends_with' => 'Trường :attribute phải kết thúc bằng: :values.',
|
||||
'enum' => ':attribute được chọn không hợp lệ.',
|
||||
'exists' => ':attribute được chọn không hợp lệ.',
|
||||
'extensions' => 'Trường :attribute phải có một trong các phần mở rộng sau: :values.',
|
||||
'file' => 'Trường :attribute phải là tệp.',
|
||||
'filled' => 'Trường :attribute phải có giá trị.',
|
||||
'gt' => [
|
||||
'array' => 'Trường :attribute phải có nhiều hơn :value phần tử.',
|
||||
'file' => 'Trường :attribute phải lớn hơn :value kilobyte.',
|
||||
'numeric' => 'Trường :attribute phải lớn hơn :value.',
|
||||
'string' => 'Trường :attribute phải có nhiều hơn :value ký tự.',
|
||||
],
|
||||
'gte' => [
|
||||
'array' => 'Trường :attribute phải có :value phần tử trở lên.',
|
||||
'file' => 'Trường :attribute phải lớn hơn hoặc bằng :value kilobyte.',
|
||||
'numeric' => 'Trường :attribute phải lớn hơn hoặc bằng :value.',
|
||||
'string' => 'Trường :attribute phải có :value ký tự trở lên.',
|
||||
],
|
||||
'hex_color' => 'Trường :attribute phải là màu hex hợp lệ.',
|
||||
'image' => 'Trường :attribute phải là hình ảnh.',
|
||||
'in' => ':attribute được chọn không hợp lệ.',
|
||||
'in_array' => 'Trường :attribute phải tồn tại trong :other.',
|
||||
'in_array_keys' => 'Trường :attribute phải chứa ít nhất một trong các khóa sau: :values.',
|
||||
'integer' => 'Trường :attribute phải là số nguyên.',
|
||||
'ip' => 'Trường :attribute phải là địa chỉ IP hợp lệ.',
|
||||
'ipv4' => 'Trường :attribute phải là địa chỉ IPv4 hợp lệ.',
|
||||
'ipv6' => 'Trường :attribute phải là địa chỉ IPv6 hợp lệ.',
|
||||
'json' => 'Trường :attribute phải là chuỗi JSON hợp lệ.',
|
||||
'list' => 'Trường :attribute phải là danh sách.',
|
||||
'lowercase' => 'Trường :attribute phải viết thường.',
|
||||
'lt' => [
|
||||
'array' => 'Trường :attribute phải có ít hơn :value phần tử.',
|
||||
'file' => 'Trường :attribute phải nhỏ hơn :value kilobyte.',
|
||||
'numeric' => 'Trường :attribute phải nhỏ hơn :value.',
|
||||
'string' => 'Trường :attribute phải có ít hơn :value ký tự.',
|
||||
],
|
||||
'lte' => [
|
||||
'array' => 'Trường :attribute không được có quá :value phần tử.',
|
||||
'file' => 'Trường :attribute phải nhỏ hơn hoặc bằng :value kilobyte.',
|
||||
'numeric' => 'Trường :attribute phải nhỏ hơn hoặc bằng :value.',
|
||||
'string' => 'Trường :attribute phải có :value ký tự trở xuống.',
|
||||
],
|
||||
'mac_address' => 'Trường :attribute phải là địa chỉ MAC hợp lệ.',
|
||||
'max' => [
|
||||
'array' => 'Trường :attribute không được có quá :max phần tử.',
|
||||
'file' => 'Trường :attribute không được lớn hơn :max kilobyte.',
|
||||
'numeric' => 'Trường :attribute không được lớn hơn :max.',
|
||||
'string' => 'Trường :attribute không được có quá :max ký tự.',
|
||||
],
|
||||
'max_digits' => 'Trường :attribute không được có quá :max chữ số.',
|
||||
'mimes' => 'Trường :attribute phải là tệp loại: :values.',
|
||||
'mimetypes' => 'Trường :attribute phải là tệp loại: :values.',
|
||||
'min' => [
|
||||
'array' => 'Trường :attribute phải có ít nhất :min phần tử.',
|
||||
'file' => 'Trường :attribute phải ít nhất :min kilobyte.',
|
||||
'numeric' => 'Trường :attribute phải ít nhất :min.',
|
||||
'string' => 'Trường :attribute phải có ít nhất :min ký tự.',
|
||||
],
|
||||
'min_digits' => 'Trường :attribute phải có ít nhất :min chữ số.',
|
||||
'missing' => 'Trường :attribute phải vắng mặt.',
|
||||
'missing_if' => 'Trường :attribute phải vắng mặt khi :other là :value.',
|
||||
'missing_unless' => 'Trường :attribute phải vắng mặt trừ khi :other là :value.',
|
||||
'missing_with' => 'Trường :attribute phải vắng mặt khi :values có mặt.',
|
||||
'missing_with_all' => 'Trường :attribute phải vắng mặt khi :values có mặt.',
|
||||
'multiple_of' => 'Trường :attribute phải là bội số của :value.',
|
||||
'not_in' => ':attribute được chọn không hợp lệ.',
|
||||
'not_regex' => 'Định dạng trường :attribute không hợp lệ.',
|
||||
'numeric' => 'Trường :attribute phải là số.',
|
||||
'password' => [
|
||||
'letters' => 'Trường :attribute phải chứa ít nhất một chữ cái.',
|
||||
'mixed' => 'Trường :attribute phải chứa ít nhất một chữ hoa và một chữ thường.',
|
||||
'numbers' => 'Trường :attribute phải chứa ít nhất một số.',
|
||||
'symbols' => 'Trường :attribute phải chứa ít nhất một ký hiệu.',
|
||||
'uncompromised' => ':attribute đã xuất hiện trong rò rỉ dữ liệu. Vui lòng chọn :attribute khác.',
|
||||
],
|
||||
'present' => 'Trường :attribute phải có mặt.',
|
||||
'present_if' => 'Trường :attribute phải có mặt khi :other là :value.',
|
||||
'present_unless' => 'Trường :attribute phải có mặt trừ khi :other là :value.',
|
||||
'present_with' => 'Trường :attribute phải có mặt khi :values có mặt.',
|
||||
'present_with_all' => 'Trường :attribute phải có mặt khi :values có mặt.',
|
||||
'prohibited' => 'Trường :attribute bị cấm.',
|
||||
'prohibited_if' => 'Trường :attribute bị cấm khi :other là :value.',
|
||||
'prohibited_if_accepted' => 'Trường :attribute bị cấm khi :other được chấp nhận.',
|
||||
'prohibited_if_declined' => 'Trường :attribute bị cấm khi :other bị từ chối.',
|
||||
'prohibited_unless' => 'Trường :attribute bị cấm trừ khi :other nằm trong :values.',
|
||||
'prohibits' => 'Trường :attribute cấm :other có mặt.',
|
||||
'regex' => 'Định dạng trường :attribute không hợp lệ.',
|
||||
'required' => 'Trường :attribute là bắt buộc.',
|
||||
'required_array_keys' => 'Trường :attribute phải chứa mục cho: :values.',
|
||||
'required_if' => 'Trường :attribute là bắt buộc khi :other là :value.',
|
||||
'required_if_accepted' => 'Trường :attribute là bắt buộc khi :other được chấp nhận.',
|
||||
'required_if_declined' => 'Trường :attribute là bắt buộc khi :other bị từ chối.',
|
||||
'required_unless' => 'Trường :attribute là bắt buộc trừ khi :other nằm trong :values.',
|
||||
'required_with' => 'Trường :attribute là bắt buộc khi :values có mặt.',
|
||||
'required_with_all' => 'Trường :attribute là bắt buộc khi :values có mặt.',
|
||||
'required_without' => 'Trường :attribute là bắt buộc khi :values vắng mặt.',
|
||||
'required_without_all' => 'Trường :attribute là bắt buộc khi không có :values nào có mặt.',
|
||||
'same' => 'Các trường :attribute và :other phải khớp.',
|
||||
'size' => [
|
||||
'array' => 'Trường :attribute phải chứa :size phần tử.',
|
||||
'file' => 'Trường :attribute phải là :size kilobyte.',
|
||||
'numeric' => 'Trường :attribute phải là :size.',
|
||||
'string' => 'Trường :attribute phải có :size ký tự.',
|
||||
],
|
||||
'starts_with' => 'Trường :attribute phải bắt đầu bằng: :values.',
|
||||
'string' => 'Trường :attribute phải là chuỗi.',
|
||||
'timezone' => 'Trường :attribute phải là múi giờ hợp lệ.',
|
||||
'unique' => ':attribute đã được sử dụng.',
|
||||
'uploaded' => 'Tải lên :attribute thất bại.',
|
||||
'uppercase' => 'Trường :attribute phải viết hoa.',
|
||||
'url' => 'Trường :attribute phải là URL hợp lệ.',
|
||||
'ulid' => 'Trường :attribute phải là ULID hợp lệ.',
|
||||
'uuid' => 'Trường :attribute phải là UUID hợp lệ.',
|
||||
|
||||
'custom' => [
|
||||
'attribute-name' => [
|
||||
'rule-name' => 'custom-message',
|
||||
],
|
||||
],
|
||||
|
||||
'attributes' => [],
|
||||
];
|
||||
@@ -0,0 +1,180 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| 验证提示语
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
'accepted' => ':attribute 必须接受。',
|
||||
'accepted_if' => '当 :other 为 :value 时 :attribute 必须接受。',
|
||||
'active_url' => ':attribute 必须是一个有效的 URL。',
|
||||
'after' => ':attribute 必须是 :date 之后的日期。',
|
||||
'after_or_equal' => ':attribute 必须是 :date 之后或相同的日期。',
|
||||
'alpha' => ':attribute 只能包含字母。',
|
||||
'alpha_dash' => ':attribute 只能包含字母、数字、短横线和下划线。',
|
||||
'alpha_num' => ':attribute 只能包含字母和数字。',
|
||||
'any_of' => ':attribute 无效。',
|
||||
'array' => ':attribute 必须是数组。',
|
||||
'ascii' => ':attribute 只能包含 ASCII 字符。',
|
||||
'before' => ':attribute 必须是 :date 之前的日期。',
|
||||
'before_or_equal' => ':attribute 必须是 :date 之前或相同的日期。',
|
||||
'between' => [
|
||||
'array' => ':attribute 必须在 :min 到 :max 个之间。',
|
||||
'file' => ':attribute 必须在 :min 到 :max KB 之间。',
|
||||
'numeric' => ':attribute 必须在 :min 到 :max 之间。',
|
||||
'string' => ':attribute 必须在 :min 到 :max 个字符之间。',
|
||||
],
|
||||
'boolean' => ':attribute 必须是布尔值。',
|
||||
'can' => ':attribute 包含未授权的值。',
|
||||
'confirmed' => ':attribute 两次输入不一致。',
|
||||
'contains' => ':attribute 缺少必需值。',
|
||||
'current_password' => '密码不正确。',
|
||||
'date' => ':attribute 必须是有效日期。',
|
||||
'date_equals' => ':attribute 必须等于 :date。',
|
||||
'date_format' => ':attribute 格式必须为 :format。',
|
||||
'decimal' => ':attribute 必须有 :decimal 位小数。',
|
||||
'declined' => ':attribute 必须拒绝。',
|
||||
'declined_if' => '当 :other 为 :value 时 :attribute 必须拒绝。',
|
||||
'different' => ':attribute 与 :other 必须不同。',
|
||||
'digits' => ':attribute 必须是 :digits 位数字。',
|
||||
'digits_between' => ':attribute 必须在 :min 到 :max 位数字之间。',
|
||||
'dimensions' => ':attribute 图片尺寸无效。',
|
||||
'distinct' => ':attribute 存在重复值。',
|
||||
'doesnt_contain' => ':attribute 不能包含以下内容::values。',
|
||||
'doesnt_end_with' => ':attribute 不能以下列之一结尾::values。',
|
||||
'doesnt_start_with' => ':attribute 不能以下列之一开头::values。',
|
||||
'email' => ':attribute 必须是有效的邮箱地址。',
|
||||
'encoding' => ':attribute 必须使用 :encoding 编码。',
|
||||
'ends_with' => ':attribute 必须以下列之一结尾::values。',
|
||||
'enum' => '所选的 :attribute 无效。',
|
||||
'exists' => '所选的 :attribute 无效。',
|
||||
'extensions' => ':attribute 必须具有以下扩展名之一::values。',
|
||||
'file' => ':attribute 必须是文件。',
|
||||
'filled' => ':attribute 必须有值。',
|
||||
'gt' => [
|
||||
'array' => ':attribute 必须多于 :value 个元素。',
|
||||
'file' => ':attribute 必须大于 :value KB。',
|
||||
'numeric' => ':attribute 必须大于 :value。',
|
||||
'string' => ':attribute 必须大于 :value 个字符。',
|
||||
],
|
||||
'gte' => [
|
||||
'array' => ':attribute 必须不少于 :value 个元素。',
|
||||
'file' => ':attribute 必须大于等于 :value KB。',
|
||||
'numeric' => ':attribute 必须大于等于 :value。',
|
||||
'string' => ':attribute 必须大于等于 :value 个字符。',
|
||||
],
|
||||
'hex_color' => ':attribute 必须是有效的十六进制颜色值。',
|
||||
'image' => ':attribute 必须是图片。',
|
||||
'in' => '所选的 :attribute 无效。',
|
||||
'in_array' => ':attribute 必须存在于 :other 中。',
|
||||
'in_array_keys' => ':attribute 必须包含以下键之一::values。',
|
||||
'integer' => ':attribute 必须是整数。',
|
||||
'ip' => ':attribute 必须是有效的 IP 地址。',
|
||||
'ipv4' => ':attribute 必须是有效的 IPv4 地址。',
|
||||
'ipv6' => ':attribute 必须是有效的 IPv6 地址。',
|
||||
'json' => ':attribute 必须是有效的 JSON 字符串。',
|
||||
'list' => ':attribute 必须是列表。',
|
||||
'lowercase' => ':attribute 必须是小写。',
|
||||
'lt' => [
|
||||
'array' => ':attribute 必须少于 :value 个元素。',
|
||||
'file' => ':attribute 必须小于 :value KB。',
|
||||
'numeric' => ':attribute 必须小于 :value。',
|
||||
'string' => ':attribute 必须小于 :value 个字符。',
|
||||
],
|
||||
'lte' => [
|
||||
'array' => ':attribute 不能多于 :value 个元素。',
|
||||
'file' => ':attribute 必须小于等于 :value KB。',
|
||||
'numeric' => ':attribute 必须小于等于 :value。',
|
||||
'string' => ':attribute 必须小于等于 :value 个字符。',
|
||||
],
|
||||
'mac_address' => ':attribute 必须是有效的 MAC 地址。',
|
||||
'max' => [
|
||||
'array' => ':attribute 不能超过 :max 个元素。',
|
||||
'file' => ':attribute 不能大于 :max KB。',
|
||||
'numeric' => ':attribute 不能大于 :max。',
|
||||
'string' => ':attribute 不能大于 :max 个字符。',
|
||||
],
|
||||
'max_digits' => ':attribute 不能超过 :max 位数字。',
|
||||
'mimes' => ':attribute 必须是 :values 类型的文件。',
|
||||
'mimetypes' => ':attribute 必须是 :values 类型的文件。',
|
||||
'min' => [
|
||||
'array' => ':attribute 至少有 :min 个元素。',
|
||||
'file' => ':attribute 至少 :min KB。',
|
||||
'numeric' => ':attribute 至少 :min。',
|
||||
'string' => ':attribute 至少 :min 个字符。',
|
||||
],
|
||||
'min_digits' => ':attribute 至少 :min 位数字。',
|
||||
'missing' => ':attribute 必须不存在。',
|
||||
'missing_if' => '当 :other 为 :value 时 :attribute 必须不存在。',
|
||||
'missing_unless' => '除非 :other 为 :value,否则 :attribute 必须不存在。',
|
||||
'missing_with' => '当 :values 存在时 :attribute 必须不存在。',
|
||||
'missing_with_all' => '当 :values 都存在时 :attribute 必须不存在。',
|
||||
'multiple_of' => ':attribute 必须是 :value 的倍数。',
|
||||
'not_in' => '所选的 :attribute 无效。',
|
||||
'not_regex' => ':attribute 格式无效。',
|
||||
'numeric' => ':attribute 必须是数字。',
|
||||
'password' => [
|
||||
'letters' => ':attribute 必须包含至少一个字母。',
|
||||
'mixed' => ':attribute 必须包含至少一个大写和一个小写字母。',
|
||||
'numbers' => ':attribute 必须包含至少一个数字。',
|
||||
'symbols' => ':attribute 必须包含至少一个符号。',
|
||||
'uncompromised' => ':attribute 已出现在数据泄露中,请更换。',
|
||||
],
|
||||
'present' => ':attribute 必须存在。',
|
||||
'present_if' => '当 :other 为 :value 时 :attribute 必须存在。',
|
||||
'present_unless' => '除非 :other 为 :value,否则 :attribute 必须存在。',
|
||||
'present_with' => '当 :values 存在时 :attribute 必须存在。',
|
||||
'present_with_all' => '当 :values 都存在时 :attribute 必须存在。',
|
||||
'prohibited' => ':attribute 被禁止。',
|
||||
'prohibited_if' => '当 :other 为 :value 时 :attribute 被禁止。',
|
||||
'prohibited_if_accepted' => '当 :other 被接受时 :attribute 被禁止。',
|
||||
'prohibited_if_declined' => '当 :other 被拒绝时 :attribute 被禁止。',
|
||||
'prohibited_unless' => '除非 :other 在 :values 中,否则 :attribute 被禁止。',
|
||||
'prohibits' => ':attribute 禁止 :other 出现。',
|
||||
'regex' => ':attribute 格式无效。',
|
||||
'required' => ':attribute 为必填项。',
|
||||
'required_array_keys' => ':attribute 必须包含以下键::values。',
|
||||
'required_if' => '当 :other 为 :value 时 :attribute 为必填项。',
|
||||
'required_if_accepted' => '当 :other 被接受时 :attribute 为必填项。',
|
||||
'required_if_declined' => '当 :other 被拒绝时 :attribute 为必填项。',
|
||||
'required_unless' => '除非 :other 在 :values 中,否则 :attribute 为必填项。',
|
||||
'required_with' => '当 :values 存在时 :attribute 为必填项。',
|
||||
'required_with_all' => '当 :values 都存在时 :attribute 为必填项。',
|
||||
'required_without' => '当 :values 不存在时 :attribute 为必填项。',
|
||||
'required_without_all' => '当 :values 都不存在时 :attribute 为必填项。',
|
||||
'same' => ':attribute 与 :other 必须相同。',
|
||||
'size' => [
|
||||
'array' => ':attribute 必须包含 :size 个元素。',
|
||||
'file' => ':attribute 必须为 :size KB。',
|
||||
'numeric' => ':attribute 必须为 :size。',
|
||||
'string' => ':attribute 必须为 :size 个字符。',
|
||||
],
|
||||
'starts_with' => ':attribute 必须以下列之一开头::values。',
|
||||
'string' => ':attribute 必须是字符串。',
|
||||
'timezone' => ':attribute 必须是有效的时区。',
|
||||
'unique' => ':attribute 已存在。',
|
||||
'uploaded' => ':attribute 上传失败。',
|
||||
'uppercase' => ':attribute 必须是大写。',
|
||||
'url' => ':attribute 必须是有效的 URL。',
|
||||
'ulid' => ':attribute 必须是有效的 ULID。',
|
||||
'uuid' => ':attribute 必须是有效的 UUID。',
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| 自定义验证语言行
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
'custom' => [
|
||||
'attribute-name' => [
|
||||
'rule-name' => 'custom-message',
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| 自定义属性名称
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
'attributes' => [],
|
||||
];
|
||||
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| 驗證提示語
|
||||
|--------------------------------------------------------------------------
|
||||
*/
|
||||
'accepted' => ':attribute 必須接受。',
|
||||
'accepted_if' => '當 :other 為 :value 時 :attribute 必須接受。',
|
||||
'active_url' => ':attribute 必須是一個有效的 URL。',
|
||||
'after' => ':attribute 必須是 :date 之後的日期。',
|
||||
'after_or_equal' => ':attribute 必須是 :date 之後或相同的日期。',
|
||||
'alpha' => ':attribute 只能包含字母。',
|
||||
'alpha_dash' => ':attribute 只能包含字母、數字、短橫線和底線。',
|
||||
'alpha_num' => ':attribute 只能包含字母和數字。',
|
||||
'any_of' => ':attribute 無效。',
|
||||
'array' => ':attribute 必須是陣列。',
|
||||
'ascii' => ':attribute 只能包含 ASCII 字元。',
|
||||
'before' => ':attribute 必須是 :date 之前的日期。',
|
||||
'before_or_equal' => ':attribute 必須是 :date 之前或相同的日期。',
|
||||
'between' => [
|
||||
'array' => ':attribute 必須在 :min 到 :max 個之間。',
|
||||
'file' => ':attribute 必須在 :min 到 :max KB 之間。',
|
||||
'numeric' => ':attribute 必須在 :min 到 :max 之間。',
|
||||
'string' => ':attribute 必須在 :min 到 :max 個字元之間。',
|
||||
],
|
||||
'boolean' => ':attribute 必須是布林值。',
|
||||
'can' => ':attribute 包含未授權的值。',
|
||||
'confirmed' => ':attribute 兩次輸入不一致。',
|
||||
'contains' => ':attribute 缺少必需值。',
|
||||
'current_password' => '密碼不正確。',
|
||||
'date' => ':attribute 必須是有效日期。',
|
||||
'date_equals' => ':attribute 必須等於 :date。',
|
||||
'date_format' => ':attribute 格式必須為 :format。',
|
||||
'decimal' => ':attribute 必須有 :decimal 位小數。',
|
||||
'declined' => ':attribute 必須拒絕。',
|
||||
'declined_if' => '當 :other 為 :value 時 :attribute 必須拒絕。',
|
||||
'different' => ':attribute 與 :other 必須不同。',
|
||||
'digits' => ':attribute 必須是 :digits 位數字。',
|
||||
'digits_between' => ':attribute 必須在 :min 到 :max 位數字之間。',
|
||||
'dimensions' => ':attribute 圖片尺寸無效。',
|
||||
'distinct' => ':attribute 存在重複值。',
|
||||
'doesnt_contain' => ':attribute 不能包含以下內容::values。',
|
||||
'doesnt_end_with' => ':attribute 不能以下列之一結尾::values。',
|
||||
'doesnt_start_with' => ':attribute 不能以下列之一開頭::values。',
|
||||
'email' => ':attribute 必須是有效的電子郵件地址。',
|
||||
'encoding' => ':attribute 必須使用 :encoding 編碼。',
|
||||
'ends_with' => ':attribute 必須以下列之一結尾::values。',
|
||||
'enum' => '所選的 :attribute 無效。',
|
||||
'exists' => '所選的 :attribute 無效。',
|
||||
'extensions' => ':attribute 必須具有以下副檔名之一::values。',
|
||||
'file' => ':attribute 必須是檔案。',
|
||||
'filled' => ':attribute 必須有值。',
|
||||
'gt' => [
|
||||
'array' => ':attribute 必須多於 :value 個元素。',
|
||||
'file' => ':attribute 必須大於 :value KB。',
|
||||
'numeric' => ':attribute 必須大於 :value。',
|
||||
'string' => ':attribute 必須大於 :value 個字元。',
|
||||
],
|
||||
'gte' => [
|
||||
'array' => ':attribute 必須不少於 :value 個元素。',
|
||||
'file' => ':attribute 必須大於等於 :value KB。',
|
||||
'numeric' => ':attribute 必須大於等於 :value。',
|
||||
'string' => ':attribute 必須大於等於 :value 個字元。',
|
||||
],
|
||||
'hex_color' => ':attribute 必須是有效的十六進位顏色值。',
|
||||
'image' => ':attribute 必須是圖片。',
|
||||
'in' => '所選的 :attribute 無效。',
|
||||
'in_array' => ':attribute 必須存在於 :other 中。',
|
||||
'in_array_keys' => ':attribute 必須包含以下鍵之一::values。',
|
||||
'integer' => ':attribute 必須是整數。',
|
||||
'ip' => ':attribute 必須是有效的 IP 位址。',
|
||||
'ipv4' => ':attribute 必須是有效的 IPv4 位址。',
|
||||
'ipv6' => ':attribute 必須是有效的 IPv6 位址。',
|
||||
'json' => ':attribute 必須是有效的 JSON 字串。',
|
||||
'list' => ':attribute 必須是列表。',
|
||||
'lowercase' => ':attribute 必須是小寫。',
|
||||
'lt' => [
|
||||
'array' => ':attribute 必須少於 :value 個元素。',
|
||||
'file' => ':attribute 必須小於 :value KB。',
|
||||
'numeric' => ':attribute 必須小於 :value。',
|
||||
'string' => ':attribute 必須小於 :value 個字元。',
|
||||
],
|
||||
'lte' => [
|
||||
'array' => ':attribute 不能多於 :value 個元素。',
|
||||
'file' => ':attribute 必須小於等於 :value KB。',
|
||||
'numeric' => ':attribute 必須小於等於 :value。',
|
||||
'string' => ':attribute 必須小於等於 :value 個字元。',
|
||||
],
|
||||
'mac_address' => ':attribute 必須是有效的 MAC 位址。',
|
||||
'max' => [
|
||||
'array' => ':attribute 不能超過 :max 個元素。',
|
||||
'file' => ':attribute 不能大於 :max KB。',
|
||||
'numeric' => ':attribute 不能大於 :max。',
|
||||
'string' => ':attribute 不能大於 :max 個字元。',
|
||||
],
|
||||
'max_digits' => ':attribute 不能超過 :max 位數字。',
|
||||
'mimes' => ':attribute 必須是 :values 類型的檔案。',
|
||||
'mimetypes' => ':attribute 必須是 :values 類型的檔案。',
|
||||
'min' => [
|
||||
'array' => ':attribute 至少有 :min 個元素。',
|
||||
'file' => ':attribute 至少 :min KB。',
|
||||
'numeric' => ':attribute 至少 :min。',
|
||||
'string' => ':attribute 至少 :min 個字元。',
|
||||
],
|
||||
'min_digits' => ':attribute 至少 :min 位數字。',
|
||||
'missing' => ':attribute 必須不存在。',
|
||||
'missing_if' => '當 :other 為 :value 時 :attribute 必須不存在。',
|
||||
'missing_unless' => '除非 :other 為 :value,否則 :attribute 必須不存在。',
|
||||
'missing_with' => '當 :values 存在時 :attribute 必須不存在。',
|
||||
'missing_with_all' => '當 :values 都存在時 :attribute 必須不存在。',
|
||||
'multiple_of' => ':attribute 必須是 :value 的倍數。',
|
||||
'not_in' => '所選的 :attribute 無效。',
|
||||
'not_regex' => ':attribute 格式無效。',
|
||||
'numeric' => ':attribute 必須是數字。',
|
||||
'password' => [
|
||||
'letters' => ':attribute 必須包含至少一個字母。',
|
||||
'mixed' => ':attribute 必須包含至少一個大寫和一個小寫字母。',
|
||||
'numbers' => ':attribute 必須包含至少一個數字。',
|
||||
'symbols' => ':attribute 必須包含至少一個符號。',
|
||||
'uncompromised' => ':attribute 已出現在資料外洩中,請更換。',
|
||||
],
|
||||
'present' => ':attribute 必須存在。',
|
||||
'present_if' => '當 :other 為 :value 時 :attribute 必須存在。',
|
||||
'present_unless' => '除非 :other 為 :value,否則 :attribute 必須存在。',
|
||||
'present_with' => '當 :values 存在時 :attribute 必須存在。',
|
||||
'present_with_all' => '當 :values 都存在時 :attribute 必須存在。',
|
||||
'prohibited' => ':attribute 被禁止。',
|
||||
'prohibited_if' => '當 :other 為 :value 時 :attribute 被禁止。',
|
||||
'prohibited_if_accepted' => '當 :other 被接受時 :attribute 被禁止。',
|
||||
'prohibited_if_declined' => '當 :other 被拒絕時 :attribute 被禁止。',
|
||||
'prohibited_unless' => '除非 :other 在 :values 中,否則 :attribute 被禁止。',
|
||||
'prohibits' => ':attribute 禁止 :other 出現。',
|
||||
'regex' => ':attribute 格式無效。',
|
||||
'required' => ':attribute 為必填項。',
|
||||
'required_array_keys' => ':attribute 必須包含以下鍵::values。',
|
||||
'required_if' => '當 :other 為 :value 時 :attribute 為必填項。',
|
||||
'required_if_accepted' => '當 :other 被接受時 :attribute 為必填項。',
|
||||
'required_if_declined' => '當 :other 被拒絕時 :attribute 為必填項。',
|
||||
'required_unless' => '除非 :other 在 :values 中,否則 :attribute 為必填項。',
|
||||
'required_with' => '當 :values 存在時 :attribute 為必填項。',
|
||||
'required_with_all' => '當 :values 都存在時 :attribute 為必填項。',
|
||||
'required_without' => '當 :values 不存在時 :attribute 為必填項。',
|
||||
'required_without_all' => '當 :values 都不存在時 :attribute 為必填項。',
|
||||
'same' => ':attribute 與 :other 必須相同。',
|
||||
'size' => [
|
||||
'array' => ':attribute 必須包含 :size 個元素。',
|
||||
'file' => ':attribute 必須為 :size KB。',
|
||||
'numeric' => ':attribute 必須為 :size。',
|
||||
'string' => ':attribute 必須為 :size 個字元。',
|
||||
],
|
||||
'starts_with' => ':attribute 必須以下列之一開頭::values。',
|
||||
'string' => ':attribute 必須是字串。',
|
||||
'timezone' => ':attribute 必須是有效的時區。',
|
||||
'unique' => ':attribute 已存在。',
|
||||
'uploaded' => ':attribute 上傳失敗。',
|
||||
'uppercase' => ':attribute 必須是大寫。',
|
||||
'url' => ':attribute 必須是有效的 URL。',
|
||||
'ulid' => ':attribute 必須是有效的 ULID。',
|
||||
'uuid' => ':attribute 必須是有效的 UUID。',
|
||||
|
||||
'custom' => [
|
||||
'attribute-name' => [
|
||||
'rule-name' => 'custom-message',
|
||||
],
|
||||
],
|
||||
|
||||
'attributes' => [],
|
||||
];
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Webman\Validation\Annotation;
|
||||
|
||||
use Attribute;
|
||||
|
||||
#[Attribute(Attribute::TARGET_PARAMETER)]
|
||||
class Param
|
||||
{
|
||||
public function __construct(
|
||||
public string|array $rules = '',
|
||||
public array $messages = [],
|
||||
public string $attribute = '',
|
||||
public string|array|null $in = null
|
||||
) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Webman\Validation\Annotation;
|
||||
|
||||
use Attribute;
|
||||
|
||||
#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
|
||||
class Validate
|
||||
{
|
||||
public function __construct(
|
||||
public array $rules = [],
|
||||
public array $messages = [],
|
||||
public array $attributes = [],
|
||||
public ?string $validator = null,
|
||||
public ?string $scene = null,
|
||||
public string|array|null $in = null
|
||||
) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,710 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Webman\Validation\Command;
|
||||
|
||||
use Symfony\Component\Console\Attribute\AsCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Question\ConfirmationQuestion;
|
||||
use Webman\Validation\Command\ValidatorGenerator\Illuminate\IlluminateConnectionResolver;
|
||||
use Webman\Validation\Command\ValidatorGenerator\Rules\DefaultRuleInferrer;
|
||||
use Webman\Validation\Command\ValidatorGenerator\Support\ExcludedColumns;
|
||||
use Webman\Validation\Command\ValidatorGenerator\Support\OrmDetector;
|
||||
use Webman\Validation\Command\ValidatorGenerator\Support\SchemaIntrospectorFactory;
|
||||
use Webman\Validation\Command\ValidatorGenerator\ThinkOrm\ThinkOrmConnectionResolver;
|
||||
use Webman\Validation\Command\ValidatorGenerator\Support\ValidatorClassRenderer;
|
||||
use Webman\Validation\Command\ValidatorGenerator\Support\ValidatorFileWriter;
|
||||
use Webman\Validation\Command\Messages;
|
||||
|
||||
#[AsCommand('make:validator', 'Make validation validator class.')]
|
||||
final class MakeValidatorCommand extends Command
|
||||
{
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->setDescription($this->selectByLocale(Messages::getDescription()));
|
||||
|
||||
$this->addArgument(
|
||||
'name',
|
||||
InputArgument::REQUIRED,
|
||||
$this->selectByLocale(Messages::getArgumentName())
|
||||
);
|
||||
$this->addOption(
|
||||
'plugin',
|
||||
'p',
|
||||
InputOption::VALUE_REQUIRED,
|
||||
$this->selectByLocale(Messages::getOptionPlugin())
|
||||
);
|
||||
$this->addOption(
|
||||
'path',
|
||||
'P',
|
||||
InputOption::VALUE_REQUIRED,
|
||||
$this->selectByLocale(Messages::getOptionPath())
|
||||
);
|
||||
$this->addOption(
|
||||
'force',
|
||||
'f',
|
||||
InputOption::VALUE_NONE,
|
||||
$this->selectByLocale(Messages::getOptionForce())
|
||||
);
|
||||
$this->addOption(
|
||||
'table',
|
||||
't',
|
||||
InputOption::VALUE_REQUIRED,
|
||||
$this->selectByLocale(Messages::getOptionTable())
|
||||
);
|
||||
$this->addOption(
|
||||
'database',
|
||||
'd',
|
||||
InputOption::VALUE_REQUIRED,
|
||||
$this->selectByLocale(Messages::getOptionDatabase())
|
||||
);
|
||||
$this->addOption(
|
||||
'scenes',
|
||||
's',
|
||||
InputOption::VALUE_REQUIRED,
|
||||
$this->selectByLocale(Messages::getOptionScenes())
|
||||
);
|
||||
$this->addOption(
|
||||
'orm',
|
||||
'o',
|
||||
InputOption::VALUE_REQUIRED,
|
||||
$this->selectByLocale(Messages::getOptionOrm())
|
||||
);
|
||||
|
||||
$this->setHelp($this->buildHelpText());
|
||||
$this->addUsage('UserValidator');
|
||||
$this->addUsage('admin/UserValidator');
|
||||
$this->addUsage('UserValidator -p admin');
|
||||
$this->addUsage('UserValidator -P plugin/admin/app/validation');
|
||||
$this->addUsage('UserValidator -t users -d default');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output): int
|
||||
{
|
||||
$rawName = (string)$input->getArgument('name');
|
||||
$name = $this->nameToClass($rawName);
|
||||
$name = str_replace('\\', '/', $name);
|
||||
$name = trim($name, '/');
|
||||
|
||||
$plugin = $this->normalizeOptionValue($input->getOption('plugin'));
|
||||
$path = $this->normalizeOptionValue($input->getOption('path'));
|
||||
$force = (bool)$input->getOption('force');
|
||||
$table = $input->getOption('table');
|
||||
$table = is_string($table) ? trim($table) : '';
|
||||
// Some Symfony Console versions parse `-t=foo` as `=foo` for short options.
|
||||
$table = ltrim($table, '=');
|
||||
$databaseOptionRaw = $input->getOption('database');
|
||||
$databaseOptionRaw = is_string($databaseOptionRaw) ? trim($databaseOptionRaw) : '';
|
||||
// Some Symfony Console versions parse `-d=foo` as `=foo` for short options.
|
||||
$databaseOptionRaw = ltrim($databaseOptionRaw, '=');
|
||||
$connectionName = $databaseOptionRaw !== '' ? $databaseOptionRaw : null;
|
||||
$scenesOption = $input->getOption('scenes');
|
||||
$scenesOption = is_string($scenesOption) ? trim($scenesOption) : '';
|
||||
// Some Symfony Console versions parse `-s=crud` as `=crud` for short options.
|
||||
$scenesOption = ltrim($scenesOption, '=');
|
||||
$ormOption = $input->getOption('orm');
|
||||
$ormOption = is_string($ormOption) ? trim($ormOption) : OrmDetector::ORM_AUTO;
|
||||
// Some Symfony Console versions parse `-o=xxx` as `=xxx` for short options.
|
||||
$ormOption = ltrim($ormOption, '=');
|
||||
if ($ormOption === '') {
|
||||
$ormOption = OrmDetector::ORM_AUTO;
|
||||
}
|
||||
|
||||
if ($name === '') {
|
||||
$output->writeln($this->msg('invalid_name_empty'));
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
if ($plugin && (str_contains($plugin, '/') || str_contains($plugin, '\\'))) {
|
||||
$output->writeln($this->msg('invalid_plugin', ['{plugin}' => $plugin]));
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
if ($plugin && !$this->pluginExists($plugin)) {
|
||||
$output->writeln($this->msg('plugin_not_found', ['{plugin}' => $plugin]));
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
try {
|
||||
if ($plugin || $path) {
|
||||
$resolved = $this->resolveTargetByPluginOrPath(
|
||||
$name,
|
||||
$plugin,
|
||||
$path,
|
||||
$output,
|
||||
fn(string $p): string => $this->getPluginValidationRelativePath($p),
|
||||
fn(string $key, array $replace = []): string => $this->msg($key, $replace)
|
||||
);
|
||||
if ($resolved === null) {
|
||||
return self::FAILURE;
|
||||
}
|
||||
[$class, $namespace, $file] = $resolved;
|
||||
} else {
|
||||
[$namespace, $class, $file] = $this->resolveAppValidationTarget($name);
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
$output->writeln($this->msg('invalid_name', ['{name}' => $rawName]));
|
||||
$output->writeln($this->msg('reason', ['{reason}' => $e->getMessage()]));
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
if (is_file($file)) {
|
||||
// Ask for confirmation when overwriting in interactive mode.
|
||||
// If the environment is non-interactive, do not block on prompting.
|
||||
if ($input->isInteractive()) {
|
||||
$helper = $this->getHelper('question');
|
||||
$relative = $this->toRelativePath($file);
|
||||
$prompt = $this->msg('override_prompt', ['{path}' => $relative]);
|
||||
$question = new ConfirmationQuestion($prompt, true);
|
||||
if (!$helper->ask($input, $output, $question)) {
|
||||
return self::SUCCESS;
|
||||
}
|
||||
} elseif (!$force) {
|
||||
// Non-interactive mode and no --force: refuse to overwrite.
|
||||
$output->writeln($this->msg('file_exists', ['{path}' => $this->toRelativePath($file)]));
|
||||
$output->writeln($this->msg('use_force'));
|
||||
return self::FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
$rules = [];
|
||||
$messages = [];
|
||||
$attributes = [];
|
||||
$scenes = [];
|
||||
|
||||
if ($scenesOption !== '' && $table === '') {
|
||||
$output->writeln($this->msg('scenes_requires_table'));
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
if ($table !== '') {
|
||||
try {
|
||||
$detector = new OrmDetector();
|
||||
$orm = $detector->resolve($ormOption);
|
||||
|
||||
if (!in_array($orm, [OrmDetector::ORM_LARAVEL, OrmDetector::ORM_THINKORM], true)) {
|
||||
$output->writeln($this->msg('unsupported_orm', ['{orm}' => (string)$orm]));
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
$resolver = $orm === OrmDetector::ORM_THINKORM
|
||||
? new ThinkOrmConnectionResolver()
|
||||
: new IlluminateConnectionResolver();
|
||||
|
||||
$resolvedConnectionName = $this->resolveDatabaseConnectionNameForTable(
|
||||
$plugin,
|
||||
$connectionName,
|
||||
$databaseOptionRaw,
|
||||
$orm,
|
||||
$output
|
||||
);
|
||||
if ($resolvedConnectionName === null) {
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
$connection = $resolver->resolve($resolvedConnectionName);
|
||||
|
||||
$factory = new SchemaIntrospectorFactory();
|
||||
$introspector = $factory->createForDriver($connection->driverName());
|
||||
|
||||
$tableDef = $introspector->introspect($connection, $table);
|
||||
|
||||
$excludeColumns = match ($orm) {
|
||||
OrmDetector::ORM_THINKORM => ExcludedColumns::defaultForThinkOrm(),
|
||||
default => ExcludedColumns::defaultForIlluminate(),
|
||||
};
|
||||
|
||||
$inferrer = new DefaultRuleInferrer();
|
||||
$result = $inferrer->infer($tableDef, [
|
||||
'exclude_columns' => $excludeColumns,
|
||||
'with_scenes' => $scenesOption !== '',
|
||||
'scenes' => $scenesOption,
|
||||
]);
|
||||
|
||||
$rules = $result['rules'] ?? [];
|
||||
$attributes = $result['attributes'] ?? [];
|
||||
$scenes = $result['scenes'] ?? [];
|
||||
|
||||
if ($rules === []) {
|
||||
$output->writeln($this->msg('no_rules_from_table', ['{table}' => $table]));
|
||||
return self::FAILURE;
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
$output->writeln($this->msg('failed_generate_from_table', ['{table}' => $table]));
|
||||
$output->writeln($this->msg('reason', ['{reason}' => $e->getMessage()]));
|
||||
return self::FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
$renderer = new ValidatorClassRenderer();
|
||||
$content = $renderer->render($namespace, $class, $rules, $messages, $attributes, $scenes);
|
||||
|
||||
try {
|
||||
(new ValidatorFileWriter())->write($file, $content);
|
||||
} catch (\Throwable $e) {
|
||||
$output->writeln($this->msg('failed_write_file', ['{path}' => $this->toRelativePath($file)]));
|
||||
$output->writeln($this->msg('reason', ['{reason}' => $e->getMessage()]));
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
$output->writeln($this->msg('created', ['{path}' => $this->toRelativePath($file)]));
|
||||
$output->writeln($this->msg('class', ['{class}' => $namespace . '\\' . $class]));
|
||||
if ($table !== '') {
|
||||
$output->writeln($this->msg('table', ['{table}' => $table]));
|
||||
$output->writeln($this->msg('rules_count', ['{count}' => (string)count($rules)]));
|
||||
if ($scenesOption !== '') {
|
||||
$output->writeln($this->msg('scenes_count', ['{count}' => (string)count($scenes)]));
|
||||
}
|
||||
}
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{0:string,1:string,2:string} [namespace, class, file]
|
||||
*/
|
||||
private function resolveAppValidationTarget(string $name): array
|
||||
{
|
||||
$name = trim($name);
|
||||
if ($name === '') {
|
||||
throw new \InvalidArgumentException($this->plain('invalid_name_empty_plain'));
|
||||
}
|
||||
|
||||
// Normalize separators for Windows/Unix inputs.
|
||||
$normalized = str_replace('\\', '/', $name);
|
||||
$normalized = trim($normalized, '/');
|
||||
|
||||
$segments = array_values(array_filter(explode('/', $normalized), static fn (string $s): bool => $s !== ''));
|
||||
if ($segments === []) {
|
||||
throw new \InvalidArgumentException($this->plain('invalid_name_empty_plain'));
|
||||
}
|
||||
|
||||
$classSegment = array_pop($segments);
|
||||
|
||||
// Convert to PSR-friendly StudlyCase for both directory segments and class name.
|
||||
$dirSegments = array_map([$this, 'toStudly'], $segments);
|
||||
$class = $this->toStudly($classSegment);
|
||||
|
||||
$namespace = 'app\\validation';
|
||||
if ($dirSegments !== []) {
|
||||
$namespace .= '\\' . implode('\\', $dirSegments);
|
||||
}
|
||||
|
||||
$validationDirName = $this->guessPath(app_path(), 'validation') ?: 'validation';
|
||||
$baseDir = app_path() . DIRECTORY_SEPARATOR . $validationDirName;
|
||||
$dir = $dirSegments === []
|
||||
? $baseDir
|
||||
: ($baseDir . DIRECTORY_SEPARATOR . implode(DIRECTORY_SEPARATOR, $dirSegments));
|
||||
$file = $dir . DIRECTORY_SEPARATOR . $class . '.php';
|
||||
|
||||
return [$namespace, $class, $file];
|
||||
}
|
||||
|
||||
private function toStudly(string $name): string
|
||||
{
|
||||
$name = trim($name);
|
||||
if ($name === '') {
|
||||
throw new \InvalidArgumentException($this->plain('invalid_segment_empty_plain'));
|
||||
}
|
||||
|
||||
$studly = $this->nameToClass($name);
|
||||
if (str_contains($studly, '/')) {
|
||||
// Should never happen because we pass a single segment.
|
||||
$studly = basename(str_replace('/', DIRECTORY_SEPARATOR, $studly));
|
||||
}
|
||||
|
||||
if (!preg_match('/^[A-Za-z_][A-Za-z0-9_]*$/', $studly)) {
|
||||
throw new \InvalidArgumentException($this->plain('invalid_segment_plain', ['{name}' => $name]));
|
||||
}
|
||||
|
||||
return $studly;
|
||||
}
|
||||
|
||||
// Rendering moved to ValidatorGenerator\Support\ValidatorClassRenderer
|
||||
|
||||
/**
|
||||
* @param string $plugin
|
||||
* @return string relative path
|
||||
*/
|
||||
private function getPluginValidationRelativePath(string $plugin): string
|
||||
{
|
||||
$plugin = trim($plugin);
|
||||
$appDir = base_path('plugin' . DIRECTORY_SEPARATOR . $plugin . DIRECTORY_SEPARATOR . 'app');
|
||||
$validationDir = $this->guessPath($appDir, 'validation') ?: 'validation';
|
||||
return $this->normalizeRelativePath("plugin/{$plugin}/app/{$validationDir}");
|
||||
}
|
||||
|
||||
/**
|
||||
* CLI messages (bilingual).
|
||||
*
|
||||
* @param string $key
|
||||
* @param array $replace
|
||||
* @return string
|
||||
*/
|
||||
private function msg(string $key, array $replace = []): string
|
||||
{
|
||||
$map = $this->selectMessageMap(Messages::getCliMessages());
|
||||
$text = $map[$key] ?? $key;
|
||||
return $replace ? strtr($text, $replace) : $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Plain (no console tags) bilingual messages for exception messages.
|
||||
*
|
||||
* @param string $key
|
||||
* @param array $replace
|
||||
* @return string
|
||||
*/
|
||||
private function plain(string $key, array $replace = []): string
|
||||
{
|
||||
$map = $this->selectMessageMap(Messages::getPlainMessages());
|
||||
$text = $map[$key] ?? $key;
|
||||
return $replace ? strtr($text, $replace) : $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Command help text (bilingual).
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function buildHelpText(): string
|
||||
{
|
||||
return $this->selectByLocale(Messages::getHelpText());
|
||||
}
|
||||
|
||||
private function getLocale(): string
|
||||
{
|
||||
$locale = 'en';
|
||||
if (function_exists('config')) {
|
||||
$value = config('translation.locale', 'en');
|
||||
$value = is_string($value) ? trim($value) : '';
|
||||
if ($value !== '') {
|
||||
$locale = $value;
|
||||
}
|
||||
}
|
||||
return $locale;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string> $localeToValue
|
||||
*/
|
||||
private function selectByLocale(array $localeToValue): string
|
||||
{
|
||||
$locale = $this->getLocale();
|
||||
if (isset($localeToValue[$locale])) {
|
||||
return $localeToValue[$locale];
|
||||
}
|
||||
$lang = explode('_', $locale)[0] ?? '';
|
||||
if ($lang !== '' && isset($localeToValue[$lang])) {
|
||||
return $localeToValue[$lang];
|
||||
}
|
||||
if (isset($localeToValue['en'])) {
|
||||
return $localeToValue['en'];
|
||||
}
|
||||
if (isset($localeToValue['zh_CN'])) {
|
||||
return $localeToValue['zh_CN'];
|
||||
}
|
||||
$first = reset($localeToValue);
|
||||
return is_string($first) ? $first : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, array<string, string>> $localeToMessages
|
||||
* @return array<string, string>
|
||||
*/
|
||||
private function selectMessageMap(array $localeToMessages): array
|
||||
{
|
||||
$locale = $this->getLocale();
|
||||
if (isset($localeToMessages[$locale])) {
|
||||
return $localeToMessages[$locale];
|
||||
}
|
||||
$lang = explode('_', $locale)[0] ?? '';
|
||||
if ($lang !== '' && isset($localeToMessages[$lang])) {
|
||||
return $localeToMessages[$lang];
|
||||
}
|
||||
if (isset($localeToMessages['en'])) {
|
||||
return $localeToMessages['en'];
|
||||
}
|
||||
if (isset($localeToMessages['zh_CN'])) {
|
||||
return $localeToMessages['zh_CN'];
|
||||
}
|
||||
$first = reset($localeToMessages);
|
||||
return is_array($first) ? $first : [];
|
||||
}
|
||||
|
||||
private function normalizeOptionValue(mixed $value): ?string
|
||||
{
|
||||
if ($value === null) {
|
||||
return null;
|
||||
}
|
||||
$value = trim((string)$value);
|
||||
$value = ltrim($value, '=');
|
||||
return $value === '' ? null : $value;
|
||||
}
|
||||
|
||||
private function normalizeRelativePath(string $path): string
|
||||
{
|
||||
$path = trim($path);
|
||||
$path = str_replace('\\', '/', $path);
|
||||
$path = preg_replace('#^\\./+#', '', $path);
|
||||
$path = trim($path, '/');
|
||||
return $path;
|
||||
}
|
||||
|
||||
private function isAbsolutePath(string $path): bool
|
||||
{
|
||||
$path = trim($path);
|
||||
if ($path === '') {
|
||||
return false;
|
||||
}
|
||||
if (preg_match('/^[a-zA-Z]:[\\\\\\/]/', $path)) {
|
||||
return true;
|
||||
}
|
||||
if (str_starts_with($path, '\\\\') || str_starts_with($path, '//')) {
|
||||
return true;
|
||||
}
|
||||
return str_starts_with($path, '/') || str_starts_with($path, '\\');
|
||||
}
|
||||
|
||||
private function pathsEqual(string $a, string $b): bool
|
||||
{
|
||||
$a = strtolower($this->normalizeRelativePath($a));
|
||||
$b = strtolower($this->normalizeRelativePath($b));
|
||||
return $a === $b;
|
||||
}
|
||||
|
||||
private function pluginExists(string $plugin): bool
|
||||
{
|
||||
if (!function_exists('config')) {
|
||||
return false;
|
||||
}
|
||||
$cfg = config("plugin.$plugin");
|
||||
return !empty($cfg);
|
||||
}
|
||||
|
||||
private function resolveDatabaseConnectionNameForTable(
|
||||
?string $plugin,
|
||||
?string $explicitConnection,
|
||||
string $explicitConnectionRaw,
|
||||
string $orm,
|
||||
OutputInterface $output
|
||||
): ?string {
|
||||
if (!function_exists('config')) {
|
||||
throw new \RuntimeException($this->plain('config_not_available'));
|
||||
}
|
||||
|
||||
if ($orm === OrmDetector::ORM_THINKORM) {
|
||||
$main = config('think-orm');
|
||||
if (!is_array($main) || $main === []) {
|
||||
$alt = config('thinkorm');
|
||||
$main = is_array($alt) ? $alt : [];
|
||||
}
|
||||
|
||||
$mainConnections = $main['connections'] ?? null;
|
||||
$mainConnections = is_array($mainConnections) ? $mainConnections : [];
|
||||
$mainDefault = $main['default'] ?? null;
|
||||
$mainDefault = is_string($mainDefault) ? trim($mainDefault) : '';
|
||||
|
||||
$usePlugin = false;
|
||||
$connections = $mainConnections;
|
||||
$defaultConnection = $mainDefault;
|
||||
|
||||
if ($plugin) {
|
||||
$pluginCfg = config("plugin.$plugin.thinkorm");
|
||||
if (!is_array($pluginCfg) || $pluginCfg === []) {
|
||||
$alt = config("plugin.$plugin.think-orm");
|
||||
$pluginCfg = is_array($alt) ? $alt : [];
|
||||
}
|
||||
$pluginConnections = $pluginCfg['connections'] ?? null;
|
||||
if (is_array($pluginConnections) && $pluginConnections !== []) {
|
||||
$usePlugin = true;
|
||||
$connections = $pluginConnections;
|
||||
$pluginDefault = config("plugin.$plugin.thinkorm.default");
|
||||
if (!is_string($pluginDefault) || trim($pluginDefault) === '') {
|
||||
$pluginDefault = config("plugin.$plugin.think-orm.default");
|
||||
}
|
||||
$defaultConnection = is_string($pluginDefault) ? trim($pluginDefault) : '';
|
||||
}
|
||||
}
|
||||
|
||||
$name = $explicitConnection !== null ? trim($explicitConnection) : '';
|
||||
if ($name === '') {
|
||||
$name = trim((string)$defaultConnection);
|
||||
}
|
||||
if ($name === '') {
|
||||
throw new \RuntimeException($this->plain('database_connection_not_provided'));
|
||||
}
|
||||
|
||||
if (!array_key_exists($name, $connections)) {
|
||||
if ($explicitConnection !== null && $explicitConnectionRaw !== '') {
|
||||
$output->writeln($this->msg('database_connection_not_found', ['{connection}' => $explicitConnectionRaw]));
|
||||
return null;
|
||||
}
|
||||
$available = implode(', ', array_keys($connections));
|
||||
throw new \RuntimeException($this->plain('thinkorm_connection_not_found', ['{name}' => $name, '{available}' => $available]));
|
||||
}
|
||||
|
||||
return ($usePlugin && $plugin) ? "plugin.$plugin.$name" : $name;
|
||||
}
|
||||
|
||||
$dbConfig = config('database', []);
|
||||
if (!is_array($dbConfig)) {
|
||||
throw new \RuntimeException($this->plain('database_config_invalid'));
|
||||
}
|
||||
$mainConnections = $dbConfig['connections'] ?? null;
|
||||
$mainConnections = is_array($mainConnections) ? $mainConnections : [];
|
||||
$mainDefault = $dbConfig['default'] ?? null;
|
||||
$mainDefault = is_string($mainDefault) ? trim($mainDefault) : '';
|
||||
|
||||
$usePlugin = false;
|
||||
$connections = $mainConnections;
|
||||
$defaultConnection = $mainDefault;
|
||||
|
||||
if ($plugin) {
|
||||
$pluginDb = config("plugin.$plugin.database");
|
||||
if (is_array($pluginDb)) {
|
||||
$pluginConnections = $pluginDb['connections'] ?? null;
|
||||
if (is_array($pluginConnections) && $pluginConnections !== []) {
|
||||
$usePlugin = true;
|
||||
$connections = $pluginConnections;
|
||||
$pluginDefault = config("plugin.$plugin.database.default");
|
||||
$defaultConnection = is_string($pluginDefault) ? trim($pluginDefault) : '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$name = $explicitConnection !== null ? trim($explicitConnection) : '';
|
||||
if ($name === '') {
|
||||
$name = trim((string)$defaultConnection);
|
||||
}
|
||||
if ($name === '') {
|
||||
throw new \RuntimeException($this->plain('database_connection_not_provided'));
|
||||
}
|
||||
|
||||
if (!array_key_exists($name, $connections)) {
|
||||
if ($explicitConnection !== null && $explicitConnectionRaw !== '') {
|
||||
$output->writeln($this->msg('database_connection_not_found', ['{connection}' => $explicitConnectionRaw]));
|
||||
return null;
|
||||
}
|
||||
$available = implode(', ', array_keys($connections));
|
||||
throw new \RuntimeException($this->plain('database_connection_not_found_available', ['{name}' => $name, '{available}' => $available]));
|
||||
}
|
||||
|
||||
return ($usePlugin && $plugin) ? "plugin.$plugin.$name" : $name;
|
||||
}
|
||||
|
||||
private function toRelativePath(string $path): string
|
||||
{
|
||||
$base = base_path();
|
||||
$baseNorm = rtrim(str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $base), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
|
||||
$pathNorm = str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $path);
|
||||
if (str_starts_with(strtolower($pathNorm), strtolower($baseNorm))) {
|
||||
$rel = substr($pathNorm, strlen($baseNorm));
|
||||
} else {
|
||||
$rel = $pathNorm;
|
||||
}
|
||||
return str_replace(DIRECTORY_SEPARATOR, '/', $rel);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{0:string,1:string,2:string}|null [class, namespace, file]
|
||||
*/
|
||||
private function resolveTargetByPluginOrPath(
|
||||
string $name,
|
||||
?string $plugin,
|
||||
?string $path,
|
||||
OutputInterface $output,
|
||||
callable $pluginDefaultPathResolver,
|
||||
callable $msg
|
||||
): ?array {
|
||||
$pathNorm = $path ? $this->normalizeRelativePath($path) : null;
|
||||
if ($pathNorm !== null && $this->isAbsolutePath($pathNorm)) {
|
||||
$output->writeln($msg('invalid_path', ['{path}' => (string)$path]));
|
||||
return null;
|
||||
}
|
||||
|
||||
$expected = null;
|
||||
if ($plugin) {
|
||||
$expected = $pluginDefaultPathResolver($plugin);
|
||||
}
|
||||
|
||||
if ($plugin && $pathNorm) {
|
||||
$pluginPrefix = 'plugin/' . $plugin . '/';
|
||||
if (!str_starts_with(strtolower($pathNorm), strtolower($pluginPrefix))) {
|
||||
$output->writeln($msg('plugin_path_conflict', [
|
||||
'{plugin}' => $plugin,
|
||||
'{path}' => $pathNorm,
|
||||
]));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
$targetRel = $pathNorm ?: $expected;
|
||||
if (!$targetRel) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$targetDir = base_path($targetRel);
|
||||
$namespaceRoot = trim(str_replace('/', '\\', $targetRel), '\\');
|
||||
|
||||
if (!($pos = strrpos($name, '/'))) {
|
||||
$class = ucfirst($name);
|
||||
$subPath = '';
|
||||
} else {
|
||||
$subPath = substr($name, 0, $pos);
|
||||
$class = ucfirst(substr($name, $pos + 1));
|
||||
}
|
||||
|
||||
$subDir = $subPath ? str_replace('/', DIRECTORY_SEPARATOR, $subPath) . DIRECTORY_SEPARATOR : '';
|
||||
$file = $targetDir . DIRECTORY_SEPARATOR . $subDir . $class . '.php';
|
||||
$namespace = $namespaceRoot . ($subPath ? '\\' . str_replace('/', '\\', $subPath) : '');
|
||||
|
||||
return [$class, $namespace, $file];
|
||||
}
|
||||
|
||||
private function nameToClass(string $class): string
|
||||
{
|
||||
$class = preg_replace_callback(['/-([a-zA-Z])/', '/_([a-zA-Z])/'], function ($matches) {
|
||||
return strtoupper($matches[1]);
|
||||
}, $class);
|
||||
|
||||
if (!($pos = strrpos($class, '/'))) {
|
||||
$class = ucfirst($class);
|
||||
} else {
|
||||
$path = substr($class, 0, $pos);
|
||||
$class = ucfirst(substr($class, $pos + 1));
|
||||
$class = "$path/$class";
|
||||
}
|
||||
return $class;
|
||||
}
|
||||
|
||||
private function guessPath(string $basePath, string $name, bool $returnFullPath = false)
|
||||
{
|
||||
if (!is_dir($basePath)) {
|
||||
return false;
|
||||
}
|
||||
$names = explode('/', trim(strtolower($name), '/'));
|
||||
$realname = [];
|
||||
$path = $basePath;
|
||||
foreach ($names as $n) {
|
||||
$found = false;
|
||||
foreach (scandir($path) ?: [] as $tmpName) {
|
||||
if (strtolower($tmpName) === $n && is_dir($path . DIRECTORY_SEPARATOR . $tmpName)) {
|
||||
$path = $path . DIRECTORY_SEPARATOR . $tmpName;
|
||||
$realname[] = $tmpName;
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$found) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$realname = implode(DIRECTORY_SEPARATOR, $realname);
|
||||
return $returnFullPath ? realpath($basePath . DIRECTORY_SEPARATOR . $realname) : $realname;
|
||||
}
|
||||
}
|
||||
|
||||
+936
@@ -0,0 +1,936 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Webman\Validation\Command;
|
||||
|
||||
/**
|
||||
* Multi-language messages for make:validator command.
|
||||
*/
|
||||
final class Messages
|
||||
{
|
||||
/**
|
||||
* @return array<string, string> locale => description
|
||||
*/
|
||||
public static function getDescription(): array
|
||||
{
|
||||
return [
|
||||
'zh_CN' => '生成验证器类',
|
||||
'zh_TW' => '產生驗證器類',
|
||||
'en' => 'Create a validator class',
|
||||
'ja' => 'バリデータークラスを作成',
|
||||
'ko' => '유효성 검사 클래스 생성',
|
||||
'fr' => 'Créer une classe de validation',
|
||||
'de' => 'Validierungsklasse erstellen',
|
||||
'es' => 'Crear clase de validación',
|
||||
'pt_BR' => 'Criar classe de validação',
|
||||
'ru' => 'Создать класс валидации',
|
||||
'vi' => 'Tạo lớp xác thực',
|
||||
'tr' => 'Doğrulama sınıfı oluştur',
|
||||
'id' => 'Buat kelas validasi',
|
||||
'th' => 'สร้างคลาสตรวจสอบความถูกต้อง',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string> locale => argument description
|
||||
*/
|
||||
public static function getArgumentName(): array
|
||||
{
|
||||
return [
|
||||
'zh_CN' => '验证器类名(例如:UserValidator、admin/UserValidator)',
|
||||
'zh_TW' => '驗證器類名(例如:UserValidator、admin/UserValidator)',
|
||||
'en' => 'Validator class name (e.g. UserValidator, admin/UserValidator)',
|
||||
'ja' => 'バリデータークラス名(例:UserValidator、admin/UserValidator)',
|
||||
'ko' => '유효성 검사 클래스 이름 (예: UserValidator, admin/UserValidator)',
|
||||
'fr' => 'Nom de la classe de validation (ex. UserValidator, admin/UserValidator)',
|
||||
'de' => 'Name der Validierungsklasse (z. B. UserValidator, admin/UserValidator)',
|
||||
'es' => 'Nombre de la clase de validación (ej. UserValidator, admin/UserValidator)',
|
||||
'pt_BR' => 'Nome da classe de validação (ex.: UserValidator, admin/UserValidator)',
|
||||
'ru' => 'Имя класса валидации (напр. UserValidator, admin/UserValidator)',
|
||||
'vi' => 'Tên lớp xác thực (vd: UserValidator, admin/UserValidator)',
|
||||
'tr' => 'Doğrulayıcı sınıf adı (örn. UserValidator, admin/UserValidator)',
|
||||
'id' => 'Nama kelas validasi (mis. UserValidator, admin/UserValidator)',
|
||||
'th' => 'ชื่อคลาสตรวจสอบ (เช่น UserValidator, admin/UserValidator)',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string> locale => option description
|
||||
*/
|
||||
public static function getOptionPlugin(): array
|
||||
{
|
||||
return [
|
||||
'zh_CN' => '插件名(plugin/ 下的目录名),例如:admin',
|
||||
'zh_TW' => '外掛名稱(plugin/ 下的目錄名),例如:admin',
|
||||
'en' => 'Plugin name (directory under plugin/). e.g. admin',
|
||||
'ja' => 'プラグイン名(plugin/ 以下のディレクトリ名)。例:admin',
|
||||
'ko' => '플러그인 이름 (plugin/ 하위 디렉터리). 예: admin',
|
||||
'fr' => 'Nom du plugin (répertoire sous plugin/). Ex. : admin',
|
||||
'de' => 'Plugin-Name (Unterverzeichnis von plugin/). z. B. admin',
|
||||
'es' => 'Nombre del plugin (directorio bajo plugin/). Ej.: admin',
|
||||
'pt_BR' => 'Nome do plugin (diretório em plugin/). Ex.: admin',
|
||||
'ru' => 'Имя плагина (каталог в plugin/). Напр.: admin',
|
||||
'vi' => 'Tên plugin (thư mục trong plugin/). VD: admin',
|
||||
'tr' => 'Eklenti adı (plugin/ altındaki dizin). Örn.: admin',
|
||||
'id' => 'Nama plugin (direktori di bawah plugin/). Mis.: admin',
|
||||
'th' => 'ชื่อปลั๊กอิน (โฟลเดอร์ใต้ plugin/) เช่น admin',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string> locale => option description
|
||||
*/
|
||||
public static function getOptionPath(): array
|
||||
{
|
||||
return [
|
||||
'zh_CN' => '目标目录(相对项目根目录),例如:plugin/admin/app/validation',
|
||||
'zh_TW' => '目標目錄(相對專案根目錄),例如:plugin/admin/app/validation',
|
||||
'en' => 'Target directory (relative to project root). e.g. plugin/admin/app/validation',
|
||||
'ja' => '出力先ディレクトリ(プロジェクトルートからの相対パス)。例:plugin/admin/app/validation',
|
||||
'ko' => '대상 디렉터리 (프로젝트 루트 기준 상대 경로). 예: plugin/admin/app/validation',
|
||||
'fr' => 'Répertoire cible (relatif à la racine du projet). Ex. : plugin/admin/app/validation',
|
||||
'de' => 'Zielverzeichnis (relativ zum Projektstamm). z. B. plugin/admin/app/validation',
|
||||
'es' => 'Directorio destino (relativo a la raíz del proyecto). Ej.: plugin/admin/app/validation',
|
||||
'pt_BR' => 'Diretório de destino (relativo à raiz do projeto). Ex.: plugin/admin/app/validation',
|
||||
'ru' => 'Целевой каталог (относительно корня проекта). Напр.: plugin/admin/app/validation',
|
||||
'vi' => 'Thư mục đích (tương đối so với thư mục gốc dự án). VD: plugin/admin/app/validation',
|
||||
'tr' => 'Hedef dizin (proje köküne göre). Örn.: plugin/admin/app/validation',
|
||||
'id' => 'Direktori tujuan (relatif ke root proyek). Mis.: plugin/admin/app/validation',
|
||||
'th' => 'โฟลเดอร์ปลายทาง (สัมพันธ์กับรากโปรเจกต์) เช่น plugin/admin/app/validation',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string> locale => option description
|
||||
*/
|
||||
public static function getOptionForce(): array
|
||||
{
|
||||
return [
|
||||
'zh_CN' => '文件已存在时强制覆盖',
|
||||
'zh_TW' => '檔案已存在時強制覆蓋',
|
||||
'en' => 'Overwrite if file already exists',
|
||||
'ja' => 'ファイルが既に存在する場合に上書き',
|
||||
'ko' => '파일이 이미 있으면 덮어쓰기',
|
||||
'fr' => 'Écraser si le fichier existe déjà',
|
||||
'de' => 'Überschreiben, wenn die Datei bereits existiert',
|
||||
'es' => 'Sobrescribir si el archivo ya existe',
|
||||
'pt_BR' => 'Sobrescrever se o arquivo já existir',
|
||||
'ru' => 'Перезаписать, если файл уже существует',
|
||||
'vi' => 'Ghi đè nếu tệp đã tồn tại',
|
||||
'tr' => 'Dosya zaten varsa üzerine yaz',
|
||||
'id' => 'Timpa jika berkas sudah ada',
|
||||
'th' => 'เขียนทับถ้ามีไฟล์อยู่แล้ว',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string> locale => option description
|
||||
*/
|
||||
public static function getOptionTable(): array
|
||||
{
|
||||
return [
|
||||
'zh_CN' => '从数据库表推断并生成规则(例如:users)',
|
||||
'zh_TW' => '從資料庫資料表推斷並產生規則(例如:users)',
|
||||
'en' => 'Generate rules from database table (e.g. users)',
|
||||
'ja' => 'データベーステーブルからルールを推論して生成(例:users)',
|
||||
'ko' => '데이터베이스 테이블에서 규칙 생성 (예: users)',
|
||||
'fr' => 'Générer les règles à partir d\'une table (ex. : users)',
|
||||
'de' => 'Regeln aus Datenbanktabelle ableiten (z. B. users)',
|
||||
'es' => 'Generar reglas desde la tabla de base de datos (ej.: users)',
|
||||
'pt_BR' => 'Gerar regras a partir da tabela do banco (ex.: users)',
|
||||
'ru' => 'Сформировать правила по таблице БД (напр. users)',
|
||||
'vi' => 'Sinh quy tắc từ bảng cơ sở dữ liệu (vd: users)',
|
||||
'tr' => 'Veritabanı tablosundan kurallar üret (örn.: users)',
|
||||
'id' => 'Hasilkan aturan dari tabel database (mis. users)',
|
||||
'th' => 'สร้างกฎจากตารางฐานข้อมูล (เช่น users)',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string> locale => option description
|
||||
*/
|
||||
public static function getOptionDatabase(): array
|
||||
{
|
||||
return [
|
||||
'zh_CN' => '数据库连接名',
|
||||
'zh_TW' => '資料庫連線名稱',
|
||||
'en' => 'Database connection name',
|
||||
'ja' => 'データベース接続名',
|
||||
'ko' => '데이터베이스 연결 이름',
|
||||
'fr' => 'Nom de la connexion à la base de données',
|
||||
'de' => 'Datenbankverbindungsname',
|
||||
'es' => 'Nombre de la conexión a la base de datos',
|
||||
'pt_BR' => 'Nome da conexão do banco de dados',
|
||||
'ru' => 'Имя подключения к БД',
|
||||
'vi' => 'Tên kết nối cơ sở dữ liệu',
|
||||
'tr' => 'Veritabanı bağlantı adı',
|
||||
'id' => 'Nama koneksi database',
|
||||
'th' => 'ชื่อการเชื่อมต่อฐานข้อมูล',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string> locale => option description
|
||||
*/
|
||||
public static function getOptionScenes(): array
|
||||
{
|
||||
return [
|
||||
'zh_CN' => '生成场景(支持:crud)',
|
||||
'zh_TW' => '產生場景(支援:crud)',
|
||||
'en' => 'Generate scenes (supported: crud)',
|
||||
'ja' => 'シーンを生成(対応:crud)',
|
||||
'ko' => '장면 생성 (지원: crud)',
|
||||
'fr' => 'Générer des scènes (supporté : crud)',
|
||||
'de' => 'Szenen erzeugen (unterstützt: crud)',
|
||||
'es' => 'Generar escenas (soportado: crud)',
|
||||
'pt_BR' => 'Gerar cenas (suportado: crud)',
|
||||
'ru' => 'Создать сцены (поддержка: crud)',
|
||||
'vi' => 'Tạo cảnh (hỗ trợ: crud)',
|
||||
'tr' => 'Sahneleri oluştur (desteklenen: crud)',
|
||||
'id' => 'Hasilkan adegan (didukung: crud)',
|
||||
'th' => 'สร้างฉาก (รองรับ: crud)',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, string> locale => option description
|
||||
*/
|
||||
public static function getOptionOrm(): array
|
||||
{
|
||||
return [
|
||||
'zh_CN' => '使用的 ORM:auto|laravel|thinkorm(默认:auto)',
|
||||
'zh_TW' => '使用的 ORM:auto|laravel|thinkorm(預設:auto)',
|
||||
'en' => 'ORM to use: auto|laravel|thinkorm (default: auto)',
|
||||
'ja' => '使用する ORM:auto|laravel|thinkorm(既定:auto)',
|
||||
'ko' => '사용할 ORM: auto|laravel|thinkorm (기본: auto)',
|
||||
'fr' => 'ORM à utiliser : auto|laravel|thinkorm (défaut : auto)',
|
||||
'de' => 'Zu verwendende ORM: auto|laravel|thinkorm (Standard: auto)',
|
||||
'es' => 'ORM a usar: auto|laravel|thinkorm (por defecto: auto)',
|
||||
'pt_BR' => 'ORM a usar: auto|laravel|thinkorm (padrão: auto)',
|
||||
'ru' => 'ORM: auto|laravel|thinkorm (по умолчанию: auto)',
|
||||
'vi' => 'ORM sử dụng: auto|laravel|thinkorm (mặc định: auto)',
|
||||
'tr' => 'Kullanılacak ORM: auto|laravel|thinkorm (varsayılan: auto)',
|
||||
'id' => 'ORM yang digunakan: auto|laravel|thinkorm (baku: auto)',
|
||||
'th' => 'ORM ที่ใช้: auto|laravel|thinkorm (ค่าเริ่มต้น: auto)',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* CLI messages (with Symfony console tags). locale => [ key => text ]
|
||||
*
|
||||
* @return array<string, array<string, string>>
|
||||
*/
|
||||
public static function getCliMessages(): array
|
||||
{
|
||||
return [
|
||||
'zh_CN' => [
|
||||
'invalid_name_empty' => '<error>验证器类名不能为空。</error>',
|
||||
'invalid_name' => '<error>验证器类名无效:{name}</error>',
|
||||
'invalid_plugin' => '<error>插件名无效:{plugin}。`--plugin/-p` 只能是 plugin/ 目录下的目录名,不能包含 / 或 \\。</error>',
|
||||
'plugin_not_found' => "<error>插件不存在:</error> <comment>{plugin}</comment>\n请检查插件名是否输入正确,或确认插件已正确安装/启用。",
|
||||
'plugin_path_conflict' => "<error>`--path/-P` 指定的路径不在 plugin/{plugin}/ 目录下。\n同时使用 `--plugin/-p` 时,`--path/-P` 必须是 plugin/{plugin}/ 下的路径。</error>",
|
||||
'invalid_path' => '<error>路径无效:{path}。`--path/-P` 必须是相对路径(相对于项目根目录),不能是绝对路径。</error>',
|
||||
'file_exists' => '<error>文件已存在:</error> {path}',
|
||||
'override_prompt' => "<question>文件已存在:{path}</question>\n<question>是否覆盖?[Y/n](回车=Y)</question>\n",
|
||||
'use_force' => '使用 <comment>--force/-f</comment> 强制覆盖。',
|
||||
'scenes_requires_table' => '<error>选项 --scenes 需要同时指定 --table。</error>',
|
||||
'unsupported_orm' => '<error>不支持的 ORM:{orm}(支持:auto/laravel/thinkorm)。</error>',
|
||||
'database_connection_not_found' => '<error>数据库连接不存在:</error> <comment>{connection}</comment>',
|
||||
'no_rules_from_table' => '<error>无法从数据表推断出规则:</error> {table}',
|
||||
'failed_generate_from_table' => '<error>从数据表生成验证器失败:</error> {table}',
|
||||
'failed_write_file' => '<error>写入文件失败:</error> {path}',
|
||||
'reason' => '<comment>原因:</comment> {reason}',
|
||||
'created' => '<info>已创建:</info> {path}',
|
||||
'class' => '<info>类:</info> {class}',
|
||||
'table' => '<info>数据表:</info> {table}',
|
||||
'rules_count' => '<info>规则数:</info> {count}',
|
||||
'scenes_count' => '<info>场景数:</info> {count}',
|
||||
],
|
||||
'zh_TW' => [
|
||||
'invalid_name_empty' => '<error>驗證器類名不能為空。</error>',
|
||||
'invalid_name' => '<error>驗證器類名無效:{name}</error>',
|
||||
'invalid_plugin' => '<error>外掛名稱無效:{plugin}。`--plugin/-p` 只能是 plugin/ 目錄下的目錄名,不能包含 / 或 \\。</error>',
|
||||
'plugin_not_found' => "<error>外掛不存在:</error> <comment>{plugin}</comment>\n請檢查外掛名稱是否正確,或確認外掛已正確安裝/啟用。",
|
||||
'plugin_path_conflict' => "<error>`--path/-P` 指定的路徑不在 plugin/{plugin}/ 目錄下。\n同時使用 `--plugin/-p` 時,`--path/-P` 必須是 plugin/{plugin}/ 下的路徑。</error>",
|
||||
'invalid_path' => '<error>路徑無效:{path}。`--path/-P` 必須是相對路徑(相對於專案根目錄),不能是絕對路徑。</error>',
|
||||
'file_exists' => '<error>檔案已存在:</error> {path}',
|
||||
'override_prompt' => "<question>檔案已存在:{path}</question>\n<question>是否覆蓋?[Y/n](Enter=Y)</question>\n",
|
||||
'use_force' => '使用 <comment>--force/-f</comment> 強制覆蓋。',
|
||||
'scenes_requires_table' => '<error>選項 --scenes 需要同時指定 --table。</error>',
|
||||
'unsupported_orm' => '<error>不支援的 ORM:{orm}(支援:auto/laravel/thinkorm)。</error>',
|
||||
'database_connection_not_found' => '<error>資料庫連線不存在:</error> <comment>{connection}</comment>',
|
||||
'no_rules_from_table' => '<error>無法從資料表推斷出規則:</error> {table}',
|
||||
'failed_generate_from_table' => '<error>從資料表產生驗證器失敗:</error> {table}',
|
||||
'failed_write_file' => '<error>寫入檔案失敗:</error> {path}',
|
||||
'reason' => '<comment>原因:</comment> {reason}',
|
||||
'created' => '<info>已建立:</info> {path}',
|
||||
'class' => '<info>類別:</info> {class}',
|
||||
'table' => '<info>資料表:</info> {table}',
|
||||
'rules_count' => '<info>規則數:</info> {count}',
|
||||
'scenes_count' => '<info>場景數:</info> {count}',
|
||||
],
|
||||
'en' => [
|
||||
'invalid_name_empty' => '<error>Validator name cannot be empty.</error>',
|
||||
'invalid_name' => '<error>Invalid validator name: {name}</error>',
|
||||
'invalid_plugin' => '<error>Invalid plugin name: {plugin}. `--plugin/-p` must be a directory name under plugin/ and must not contain / or \\.</error>',
|
||||
'plugin_not_found' => "<error>Plugin not found:</error> <comment>{plugin}</comment>\nPlease check the plugin name, or ensure the plugin is properly installed/enabled.",
|
||||
'plugin_path_conflict' => "<error>`--path/-P` is not under plugin/{plugin}/.\nWhen `--plugin/-p` is specified, `--path/-P` must be under plugin/{plugin}/.</error>",
|
||||
'invalid_path' => '<error>Invalid path: {path}. `--path/-P` must be a relative path (to project root) and must not be an absolute path.</error>',
|
||||
'file_exists' => '<error>File already exists:</error> {path}',
|
||||
'override_prompt' => "<question>File already exists: {path}</question>\n<question>Overwrite? [Y/n] (Enter = Y)</question>\n",
|
||||
'use_force' => 'Use <comment>--force/-f</comment> to overwrite.',
|
||||
'scenes_requires_table' => '<error>Option --scenes requires --table.</error>',
|
||||
'unsupported_orm' => '<error>Unsupported ORM: {orm} (supported: auto/laravel/thinkorm).</error>',
|
||||
'database_connection_not_found' => '<error>Database connection not found:</error> <comment>{connection}</comment>',
|
||||
'no_rules_from_table' => '<error>No rules inferred from table:</error> {table}',
|
||||
'failed_generate_from_table' => '<error>Failed to generate validator from table:</error> {table}',
|
||||
'failed_write_file' => '<error>Failed to write file:</error> {path}',
|
||||
'reason' => '<comment>Reason:</comment> {reason}',
|
||||
'created' => '<info>Created:</info> {path}',
|
||||
'class' => '<info>Class:</info> {class}',
|
||||
'table' => '<info>Table:</info> {table}',
|
||||
'rules_count' => '<info>Rules:</info> {count}',
|
||||
'scenes_count' => '<info>Scenes:</info> {count}',
|
||||
],
|
||||
'ja' => [
|
||||
'invalid_name_empty' => '<error>バリデーター名を空にできません。</error>',
|
||||
'invalid_name' => '<error>無効なバリデーター名:{name}</error>',
|
||||
'invalid_plugin' => '<error>無効なプラグイン名:{plugin}。`--plugin/-p` は plugin/ 以下のディレクトリ名のみ指定でき、/ または \\ を含めません。</error>',
|
||||
'plugin_not_found' => "<error>プラグインが見つかりません:</error> <comment>{plugin}</comment>\nプラグイン名を確認するか、正しくインストール/有効化されているか確認してください。",
|
||||
'plugin_path_conflict' => "<error>`--path/-P` が plugin/{plugin}/ 配下にありません。\n`--plugin/-p` 指定時、`--path/-P` は plugin/{plugin}/ 配下のパスでなければなりません。</error>",
|
||||
'invalid_path' => '<error>無効なパス:{path}。`--path/-P` はプロジェクトルートからの相対パスで、絶対パスは指定できません。</error>',
|
||||
'file_exists' => '<error>ファイルは既に存在します:</error> {path}',
|
||||
'override_prompt' => "<question>ファイルは既に存在します:{path}</question>\n<question>上書きしますか?[Y/n](Enter=Y)</question>\n",
|
||||
'use_force' => '<comment>--force/-f</comment> で上書きしてください。',
|
||||
'scenes_requires_table' => '<error>オプション --scenes には --table の指定が必要です。</error>',
|
||||
'unsupported_orm' => '<error>サポートされていない ORM:{orm}(対応:auto/laravel/thinkorm)。</error>',
|
||||
'database_connection_not_found' => '<error>データベース接続が見つかりません:</error> <comment>{connection}</comment>',
|
||||
'no_rules_from_table' => '<error>テーブルからルールを推論できません:</error> {table}',
|
||||
'failed_generate_from_table' => '<error>テーブルからバリデーターの生成に失敗しました:</error> {table}',
|
||||
'failed_write_file' => '<error>ファイルの書き込みに失敗しました:</error> {path}',
|
||||
'reason' => '<comment>理由:</comment> {reason}',
|
||||
'created' => '<info>作成しました:</info> {path}',
|
||||
'class' => '<info>クラス:</info> {class}',
|
||||
'table' => '<info>テーブル:</info> {table}',
|
||||
'rules_count' => '<info>ルール数:</info> {count}',
|
||||
'scenes_count' => '<info>シーン数:</info> {count}',
|
||||
],
|
||||
'ko' => [
|
||||
'invalid_name_empty' => '<error>유효성 검사 클래스 이름을 비워 둘 수 없습니다.</error>',
|
||||
'invalid_name' => '<error>잘못된 유효성 검사 클래스 이름: {name}</error>',
|
||||
'invalid_plugin' => '<error>잘못된 플러그인 이름: {plugin}. `--plugin/-p`는 plugin/ 아래의 디렉터리 이름만 가능하며 / 또는 \\를 포함할 수 없습니다.</error>',
|
||||
'plugin_not_found' => "<error>플러그인을 찾을 수 없습니다:</error> <comment>{plugin}</comment>\n플러그인 이름을 확인하거나, 올바르게 설치/활성화되었는지 확인하세요.",
|
||||
'plugin_path_conflict' => "<error>`--path/-P`가 plugin/{plugin}/ 아래에 없습니다.\n`--plugin/-p` 지정 시 `--path/-P`는 plugin/{plugin}/ 하위 경로여야 합니다.</error>",
|
||||
'invalid_path' => '<error>잘못된 경로: {path}. `--path/-P`는 프로젝트 루트 기준 상대 경로여야 하며 절대 경로는 사용할 수 없습니다.</error>',
|
||||
'file_exists' => '<error>파일이 이미 존재합니다:</error> {path}',
|
||||
'override_prompt' => "<question>파일이 이미 존재합니다: {path}</question>\n<question>덮어쓰시겠습니까? [Y/n] (Enter=Y)</question>\n",
|
||||
'use_force' => '<comment>--force/-f</comment>로 덮어쓰세요.',
|
||||
'scenes_requires_table' => '<error>--scenes 옵션에는 --table 지정이 필요합니다.</error>',
|
||||
'unsupported_orm' => '<error>지원하지 않는 ORM: {orm} (지원: auto/laravel/thinkorm).</error>',
|
||||
'database_connection_not_found' => '<error>데이터베이스 연결을 찾을 수 없습니다:</error> <comment>{connection}</comment>',
|
||||
'no_rules_from_table' => '<error>테이블에서 규칙을 추론할 수 없습니다:</error> {table}',
|
||||
'failed_generate_from_table' => '<error>테이블에서 유효성 검사 클래스 생성에 실패했습니다:</error> {table}',
|
||||
'failed_write_file' => '<error>파일 쓰기에 실패했습니다:</error> {path}',
|
||||
'reason' => '<comment>사유:</comment> {reason}',
|
||||
'created' => '<info>생성됨:</info> {path}',
|
||||
'class' => '<info>클래스:</info> {class}',
|
||||
'table' => '<info>테이블:</info> {table}',
|
||||
'rules_count' => '<info>규칙 수:</info> {count}',
|
||||
'scenes_count' => '<info>장면 수:</info> {count}',
|
||||
],
|
||||
'fr' => [
|
||||
'invalid_name_empty' => '<error>Le nom du validateur ne peut pas être vide.</error>',
|
||||
'invalid_name' => '<error>Nom de validateur invalide : {name}</error>',
|
||||
'invalid_plugin' => '<error>Nom de plugin invalide : {plugin}. `--plugin/-p` doit être un nom de répertoire sous plugin/ et ne doit pas contenir / ou \\.</error>',
|
||||
'plugin_not_found' => "<error>Plugin introuvable :</error> <comment>{plugin}</comment>\nVérifiez le nom du plugin ou assurez-vous qu'il est correctement installé/activé.",
|
||||
'plugin_path_conflict' => "<error>`--path/-P` n'est pas sous plugin/{plugin}/.\nAvec `--plugin/-p`, `--path/-P` doit être un chemin sous plugin/{plugin}/.</error>",
|
||||
'invalid_path' => '<error>Chemin invalide : {path}. `--path/-P` doit être un chemin relatif (à la racine du projet), pas un chemin absolu.</error>',
|
||||
'file_exists' => '<error>Le fichier existe déjà :</error> {path}',
|
||||
'override_prompt' => "<question>Le fichier existe déjà : {path}</question>\n<question>Écraser ? [Y/n] (Entrée = Y)</question>\n",
|
||||
'use_force' => 'Utilisez <comment>--force/-f</comment> pour écraser.',
|
||||
'scenes_requires_table' => '<error>L\'option --scenes nécessite --table.</error>',
|
||||
'unsupported_orm' => '<error>ORM non pris en charge : {orm} (pris en charge : auto/laravel/thinkorm).</error>',
|
||||
'database_connection_not_found' => '<error>Connexion à la base de données introuvable :</error> <comment>{connection}</comment>',
|
||||
'no_rules_from_table' => '<error>Aucune règle déduite de la table :</error> {table}',
|
||||
'failed_generate_from_table' => '<error>Échec de la génération du validateur à partir de la table :</error> {table}',
|
||||
'failed_write_file' => '<error>Échec de l\'écriture du fichier :</error> {path}',
|
||||
'reason' => '<comment>Raison :</comment> {reason}',
|
||||
'created' => '<info>Créé :</info> {path}',
|
||||
'class' => '<info>Classe :</info> {class}',
|
||||
'table' => '<info>Table :</info> {table}',
|
||||
'rules_count' => '<info>Règles :</info> {count}',
|
||||
'scenes_count' => '<info>Scènes :</info> {count}',
|
||||
],
|
||||
'de' => [
|
||||
'invalid_name_empty' => '<error>Der Name des Validators darf nicht leer sein.</error>',
|
||||
'invalid_name' => '<error>Ungültiger Validator-Name: {name}</error>',
|
||||
'invalid_plugin' => '<error>Ungültiger Plugin-Name: {plugin}. `--plugin/-p` muss ein Verzeichnisname unter plugin/ sein und darf / oder \\ nicht enthalten.</error>',
|
||||
'plugin_not_found' => "<error>Plugin nicht gefunden:</error> <comment>{plugin}</comment>\nBitte prüfen Sie den Plugin-Namen oder stellen Sie sicher, dass das Plugin korrekt installiert/aktiviert ist.",
|
||||
'plugin_path_conflict' => "<error>`--path/-P` liegt nicht unter plugin/{plugin}/.\nBei Angabe von `--plugin/-p` muss `--path/-P` unter plugin/{plugin}/ liegen.</error>",
|
||||
'invalid_path' => '<error>Ungültiger Pfad: {path}. `--path/-P` muss ein relativer Pfad (zum Projektstamm) sein, kein absoluter Pfad.</error>',
|
||||
'file_exists' => '<error>Datei existiert bereits:</error> {path}',
|
||||
'override_prompt' => "<question>Datei existiert bereits: {path}</question>\n<question>Überschreiben? [Y/n] (Eingabe = Y)</question>\n",
|
||||
'use_force' => 'Mit <comment>--force/-f</comment> überschreiben.',
|
||||
'scenes_requires_table' => '<error>Option --scenes erfordert --table.</error>',
|
||||
'unsupported_orm' => '<error>Nicht unterstützte ORM: {orm} (unterstützt: auto/laravel/thinkorm).</error>',
|
||||
'database_connection_not_found' => '<error>Datenbankverbindung nicht gefunden:</error> <comment>{connection}</comment>',
|
||||
'no_rules_from_table' => '<error>Keine Regeln aus Tabelle abgeleitet:</error> {table}',
|
||||
'failed_generate_from_table' => '<error>Validator konnte aus Tabelle nicht erzeugt werden:</error> {table}',
|
||||
'failed_write_file' => '<error>Datei konnte nicht geschrieben werden:</error> {path}',
|
||||
'reason' => '<comment>Grund:</comment> {reason}',
|
||||
'created' => '<info>Erstellt:</info> {path}',
|
||||
'class' => '<info>Klasse:</info> {class}',
|
||||
'table' => '<info>Tabelle:</info> {table}',
|
||||
'rules_count' => '<info>Regeln:</info> {count}',
|
||||
'scenes_count' => '<info>Szenen:</info> {count}',
|
||||
],
|
||||
'es' => [
|
||||
'invalid_name_empty' => '<error>El nombre del validador no puede estar vacío.</error>',
|
||||
'invalid_name' => '<error>Nombre de validador no válido: {name}</error>',
|
||||
'invalid_plugin' => '<error>Nombre de plugin no válido: {plugin}. `--plugin/-p` debe ser un nombre de directorio bajo plugin/ y no puede contener / ni \\.</error>',
|
||||
'plugin_not_found' => "<error>Plugin no encontrado:</error> <comment>{plugin}</comment>\nCompruebe el nombre del plugin o asegúrese de que está correctamente instalado/habilitado.",
|
||||
'plugin_path_conflict' => "<error>`--path/-P` no está bajo plugin/{plugin}/.\nAl usar `--plugin/-p`, `--path/-P` debe ser una ruta bajo plugin/{plugin}/.</error>",
|
||||
'invalid_path' => '<error>Ruta no válida: {path}. `--path/-P` debe ser una ruta relativa (a la raíz del proyecto), no absoluta.</error>',
|
||||
'file_exists' => '<error>El archivo ya existe:</error> {path}',
|
||||
'override_prompt' => "<question>El archivo ya existe: {path}</question>\n<question>¿Sobrescribir? [Y/n] (Enter = Y)</question>\n",
|
||||
'use_force' => 'Use <comment>--force/-f</comment> para sobrescribir.',
|
||||
'scenes_requires_table' => '<error>La opción --scenes requiere --table.</error>',
|
||||
'unsupported_orm' => '<error>ORM no soportada: {orm} (soportadas: auto/laravel/thinkorm).</error>',
|
||||
'database_connection_not_found' => '<error>Conexión a la base de datos no encontrada:</error> <comment>{connection}</comment>',
|
||||
'no_rules_from_table' => '<error>No se pudieron inferir reglas de la tabla:</error> {table}',
|
||||
'failed_generate_from_table' => '<error>Error al generar el validador desde la tabla:</error> {table}',
|
||||
'failed_write_file' => '<error>Error al escribir el archivo:</error> {path}',
|
||||
'reason' => '<comment>Motivo:</comment> {reason}',
|
||||
'created' => '<info>Creado:</info> {path}',
|
||||
'class' => '<info>Clase:</info> {class}',
|
||||
'table' => '<info>Tabla:</info> {table}',
|
||||
'rules_count' => '<info>Reglas:</info> {count}',
|
||||
'scenes_count' => '<info>Escenas:</info> {count}',
|
||||
],
|
||||
'pt_BR' => [
|
||||
'invalid_name_empty' => '<error>O nome do validador não pode estar vazio.</error>',
|
||||
'invalid_name' => '<error>Nome de validador inválido: {name}</error>',
|
||||
'invalid_plugin' => '<error>Nome de plugin inválido: {plugin}. `--plugin/-p` deve ser um nome de diretório em plugin/ e não pode conter / ou \\.</error>',
|
||||
'plugin_not_found' => "<error>Plugin não encontrado:</error> <comment>{plugin}</comment>\nVerifique o nome do plugin ou confira se está instalado/ativado corretamente.",
|
||||
'plugin_path_conflict' => "<error>`--path/-P` não está em plugin/{plugin}/.\nAo usar `--plugin/-p`, `--path/-P` deve estar sob plugin/{plugin}/.</error>",
|
||||
'invalid_path' => '<error>Caminho inválido: {path}. `--path/-P` deve ser um caminho relativo (à raiz do projeto), não absoluto.</error>',
|
||||
'file_exists' => '<error>O arquivo já existe:</error> {path}',
|
||||
'override_prompt' => "<question>O arquivo já existe: {path}</question>\n<question>Sobrescrever? [Y/n] (Enter = Y)</question>\n",
|
||||
'use_force' => 'Use <comment>--force/-f</comment> para sobrescrever.',
|
||||
'scenes_requires_table' => '<error>A opção --scenes exige --table.</error>',
|
||||
'unsupported_orm' => '<error>ORM não suportada: {orm} (suportadas: auto/laravel/thinkorm).</error>',
|
||||
'database_connection_not_found' => '<error>Conexão com o banco não encontrada:</error> <comment>{connection}</comment>',
|
||||
'no_rules_from_table' => '<error>Nenhuma regra inferida da tabela:</error> {table}',
|
||||
'failed_generate_from_table' => '<error>Falha ao gerar validador a partir da tabela:</error> {table}',
|
||||
'failed_write_file' => '<error>Falha ao escrever o arquivo:</error> {path}',
|
||||
'reason' => '<comment>Motivo:</comment> {reason}',
|
||||
'created' => '<info>Criado:</info> {path}',
|
||||
'class' => '<info>Classe:</info> {class}',
|
||||
'table' => '<info>Tabela:</info> {table}',
|
||||
'rules_count' => '<info>Regras:</info> {count}',
|
||||
'scenes_count' => '<info>Cenas:</info> {count}',
|
||||
],
|
||||
'ru' => [
|
||||
'invalid_name_empty' => '<error>Имя класса валидации не может быть пустым.</error>',
|
||||
'invalid_name' => '<error>Недопустимое имя валидатора: {name}</error>',
|
||||
'invalid_plugin' => '<error>Недопустимое имя плагина: {plugin}. Для `--plugin/-p` допустимо только имя каталога в plugin/, без / и \\.</error>',
|
||||
'plugin_not_found' => "<error>Плагин не найден:</error> <comment>{plugin}</comment>\nПроверьте имя плагина или убедитесь, что он установлен и включён.",
|
||||
'plugin_path_conflict' => "<error>`--path/-P` не находится в plugin/{plugin}/.\nПри использовании `--plugin/-p` `--path/-P` должен быть путём внутри plugin/{plugin}/.</error>",
|
||||
'invalid_path' => '<error>Недопустимый путь: {path}. Для `--path/-P` нужен относительный путь (от корня проекта), не абсолютный.</error>',
|
||||
'file_exists' => '<error>Файл уже существует:</error> {path}',
|
||||
'override_prompt' => "<question>Файл уже существует: {path}</question>\n<question>Перезаписать? [Y/n] (Enter = Y)</question>\n",
|
||||
'use_force' => 'Используйте <comment>--force/-f</comment> для перезаписи.',
|
||||
'scenes_requires_table' => '<error>Для опции --scenes необходимо указать --table.</error>',
|
||||
'unsupported_orm' => '<error>Неподдерживаемая ORM: {orm} (поддерживаются: auto/laravel/thinkorm).</error>',
|
||||
'database_connection_not_found' => '<error>Подключение к БД не найдено:</error> <comment>{connection}</comment>',
|
||||
'no_rules_from_table' => '<error>Не удалось вывести правила по таблице:</error> {table}',
|
||||
'failed_generate_from_table' => '<error>Не удалось сформировать валидатор по таблице:</error> {table}',
|
||||
'failed_write_file' => '<error>Не удалось записать файл:</error> {path}',
|
||||
'reason' => '<comment>Причина:</comment> {reason}',
|
||||
'created' => '<info>Создано:</info> {path}',
|
||||
'class' => '<info>Класс:</info> {class}',
|
||||
'table' => '<info>Таблица:</info> {table}',
|
||||
'rules_count' => '<info>Правил:</info> {count}',
|
||||
'scenes_count' => '<info>Сцен:</info> {count}',
|
||||
],
|
||||
'vi' => [
|
||||
'invalid_name_empty' => '<error>Tên lớp xác thực không được để trống.</error>',
|
||||
'invalid_name' => '<error>Tên lớp xác thực không hợp lệ: {name}</error>',
|
||||
'invalid_plugin' => '<error>Tên plugin không hợp lệ: {plugin}. `--plugin/-p` phải là tên thư mục trong plugin/ và không được chứa / hoặc \\.</error>',
|
||||
'plugin_not_found' => "<error>Không tìm thấy plugin:</error> <comment>{plugin}</comment>\nVui lòng kiểm tra tên plugin hoặc đảm bảo plugin đã được cài đặt/bật đúng cách.",
|
||||
'plugin_path_conflict' => "<error>`--path/-P` không nằm trong plugin/{plugin}/.\nKhi dùng `--plugin/-p`, `--path/-P` phải là đường dẫn trong plugin/{plugin}/.</error>",
|
||||
'invalid_path' => '<error>Đường dẫn không hợp lệ: {path}. `--path/-P` phải là đường dẫn tương đối (so với thư mục gốc dự án), không phải đường dẫn tuyệt đối.</error>',
|
||||
'file_exists' => '<error>Tệp đã tồn tại:</error> {path}',
|
||||
'override_prompt' => "<question>Tệp đã tồn tại: {path}</question>\n<question>Ghi đè? [Y/n] (Enter = Y)</question>\n",
|
||||
'use_force' => 'Dùng <comment>--force/-f</comment> để ghi đè.',
|
||||
'scenes_requires_table' => '<error>Tùy chọn --scenes yêu cầu --table.</error>',
|
||||
'unsupported_orm' => '<error>ORM không được hỗ trợ: {orm} (hỗ trợ: auto/laravel/thinkorm).</error>',
|
||||
'database_connection_not_found' => '<error>Không tìm thấy kết nối cơ sở dữ liệu:</error> <comment>{connection}</comment>',
|
||||
'no_rules_from_table' => '<error>Không suy ra được quy tắc từ bảng:</error> {table}',
|
||||
'failed_generate_from_table' => '<error>Không thể tạo lớp xác thực từ bảng:</error> {table}',
|
||||
'failed_write_file' => '<error>Không thể ghi tệp:</error> {path}',
|
||||
'reason' => '<comment>Lý do:</comment> {reason}',
|
||||
'created' => '<info>Đã tạo:</info> {path}',
|
||||
'class' => '<info>Lớp:</info> {class}',
|
||||
'table' => '<info>Bảng:</info> {table}',
|
||||
'rules_count' => '<info>Số quy tắc:</info> {count}',
|
||||
'scenes_count' => '<info>Số cảnh:</info> {count}',
|
||||
],
|
||||
'tr' => [
|
||||
'invalid_name_empty' => '<error>Doğrulayıcı adı boş bırakılamaz.</error>',
|
||||
'invalid_name' => '<error>Geçersiz doğrulayıcı adı: {name}</error>',
|
||||
'invalid_plugin' => '<error>Geçersiz eklenti adı: {plugin}. `--plugin/-p` yalnızca plugin/ altındaki bir dizin adı olmalı, / veya \\ içeremez.</error>',
|
||||
'plugin_not_found' => "<error>Eklenti bulunamadı:</error> <comment>{plugin}</comment>\nEklenti adını kontrol edin veya doğru kurulduğundan/etkinleştirildiğinden emin olun.",
|
||||
'plugin_path_conflict' => "<error>`--path/-P` plugin/{plugin}/ altında değil.\n`--plugin/-p` belirtildiğinde `--path/-P` plugin/{plugin}/ altında bir yol olmalıdır.</error>",
|
||||
'invalid_path' => '<error>Geçersiz yol: {path}. `--path/-P` proje köküne göre göreli yol olmalı, mutlak yol olmamalı.</error>',
|
||||
'file_exists' => '<error>Dosya zaten mevcut:</error> {path}',
|
||||
'override_prompt' => "<question>Dosya zaten mevcut: {path}</question>\n<question>Üzerine yazılsın mı? [Y/n] (Enter = Y)</question>\n",
|
||||
'use_force' => 'Üzerine yazmak için <comment>--force/-f</comment> kullanın.',
|
||||
'scenes_requires_table' => '<error>--scenes seçeneği --table gerektirir.</error>',
|
||||
'unsupported_orm' => '<error>Desteklenmeyen ORM: {orm} (desteklenen: auto/laravel/thinkorm).</error>',
|
||||
'database_connection_not_found' => '<error>Veritabanı bağlantısı bulunamadı:</error> <comment>{connection}</comment>',
|
||||
'no_rules_from_table' => '<error>Tablodan kural çıkarılamadı:</error> {table}',
|
||||
'failed_generate_from_table' => '<error>Tablodan doğrulayıcı oluşturulamadı:</error> {table}',
|
||||
'failed_write_file' => '<error>Dosya yazılamadı:</error> {path}',
|
||||
'reason' => '<comment>Neden:</comment> {reason}',
|
||||
'created' => '<info>Oluşturuldu:</info> {path}',
|
||||
'class' => '<info>Sınıf:</info> {class}',
|
||||
'table' => '<info>Tablo:</info> {table}',
|
||||
'rules_count' => '<info>Kural sayısı:</info> {count}',
|
||||
'scenes_count' => '<info>Sahne sayısı:</info> {count}',
|
||||
],
|
||||
'id' => [
|
||||
'invalid_name_empty' => '<error>Nama validator tidak boleh kosong.</error>',
|
||||
'invalid_name' => '<error>Nama validator tidak valid: {name}</error>',
|
||||
'invalid_plugin' => '<error>Nama plugin tidak valid: {plugin}. `--plugin/-p` harus nama direktori di bawah plugin/ dan tidak boleh berisi / atau \\.</error>',
|
||||
'plugin_not_found' => "<error>Plugin tidak ditemukan:</error> <comment>{plugin}</comment>\nPeriksa nama plugin atau pastikan plugin terpasang/diaktifkan dengan benar.",
|
||||
'plugin_path_conflict' => "<error>`--path/-P` tidak berada di bawah plugin/{plugin}/.\nSaat `--plugin/-p` ditentukan, `--path/-P` harus di bawah plugin/{plugin}/.</error>",
|
||||
'invalid_path' => '<error>Path tidak valid: {path}. `--path/-P` harus path relatif (ke root proyek), bukan path absolut.</error>',
|
||||
'file_exists' => '<error>Berkas sudah ada:</error> {path}',
|
||||
'override_prompt' => "<question>Berkas sudah ada: {path}</question>\n<question>Timpa? [Y/n] (Enter = Y)</question>\n",
|
||||
'use_force' => 'Gunakan <comment>--force/-f</comment> untuk menimpa.',
|
||||
'scenes_requires_table' => '<error>Opsi --scenes memerlukan --table.</error>',
|
||||
'unsupported_orm' => '<error>ORM tidak didukung: {orm} (didukung: auto/laravel/thinkorm).</error>',
|
||||
'database_connection_not_found' => '<error>Koneksi database tidak ditemukan:</error> <comment>{connection}</comment>',
|
||||
'no_rules_from_table' => '<error>Tidak ada aturan yang disimpulkan dari tabel:</error> {table}',
|
||||
'failed_generate_from_table' => '<error>Gagal membuat validator dari tabel:</error> {table}',
|
||||
'failed_write_file' => '<error>Gagal menulis berkas:</error> {path}',
|
||||
'reason' => '<comment>Alasan:</comment> {reason}',
|
||||
'created' => '<info>Dibuat:</info> {path}',
|
||||
'class' => '<info>Kelas:</info> {class}',
|
||||
'table' => '<info>Tabel:</info> {table}',
|
||||
'rules_count' => '<info>Jumlah aturan:</info> {count}',
|
||||
'scenes_count' => '<info>Jumlah adegan:</info> {count}',
|
||||
],
|
||||
'th' => [
|
||||
'invalid_name_empty' => '<error>ชื่อคลาสตรวจสอบไม่สามารถเว้นว่างได้</error>',
|
||||
'invalid_name' => '<error>ชื่อคลาสตรวจสอบไม่ถูกต้อง: {name}</error>',
|
||||
'invalid_plugin' => '<error>ชื่อปลั๊กอินไม่ถูกต้อง: {plugin} สำหรับ `--plugin/-p` ต้องเป็นชื่อโฟลเดอร์ภายใต้ plugin/ และห้ามมี / หรือ \\</error>',
|
||||
'plugin_not_found' => "<error>ไม่พบปลั๊กอิน:</error> <comment>{plugin}</comment>\nกรุณาตรวจสอบชื่อปลั๊กอิน หรือตรวจสอบว่าติดตั้ง/เปิดใช้แล้วอย่างถูกต้อง",
|
||||
'plugin_path_conflict' => "<error>`--path/-P` ไม่อยู่ภายใต้ plugin/{plugin}/\nเมื่อระบุ `--plugin/-p` `--path/-P` ต้องเป็นเส้นทางภายใต้ plugin/{plugin}/</error>",
|
||||
'invalid_path' => '<error>เส้นทางไม่ถูกต้อง: {path} สำหรับ `--path/-P` ต้องเป็นเส้นทางสัมพัทธ์ (จากรากโปรเจกต์) ไม่ใช่เส้นทางสัมบูรณ์</error>',
|
||||
'file_exists' => '<error>มีไฟล์อยู่แล้ว:</error> {path}',
|
||||
'override_prompt' => "<question>มีไฟล์อยู่แล้ว: {path}</question>\n<question>เขียนทับหรือไม่? [Y/n] (Enter = Y)</question>\n",
|
||||
'use_force' => 'ใช้ <comment>--force/-f</comment> เพื่อเขียนทับ',
|
||||
'scenes_requires_table' => '<error>ตัวเลือก --scenes ต้องใช้ร่วมกับ --table</error>',
|
||||
'unsupported_orm' => '<error>ไม่รองรับ ORM: {orm} (รองรับ: auto/laravel/thinkorm)</error>',
|
||||
'database_connection_not_found' => '<error>ไม่พบการเชื่อมต่อฐานข้อมูล:</error> <comment>{connection}</comment>',
|
||||
'no_rules_from_table' => '<error>ไม่สามารถสรุปกฎจากตารางได้:</error> {table}',
|
||||
'failed_generate_from_table' => '<error>สร้างคลาสตรวจสอบจากตารางไม่สำเร็จ:</error> {table}',
|
||||
'failed_write_file' => '<error>เขียนไฟล์ไม่สำเร็จ:</error> {path}',
|
||||
'reason' => '<comment>สาเหตุ:</comment> {reason}',
|
||||
'created' => '<info>สร้างแล้ว:</info> {path}',
|
||||
'class' => '<info>คลาส:</info> {class}',
|
||||
'table' => '<info>ตาราง:</info> {table}',
|
||||
'rules_count' => '<info>จำนวนกฎ:</info> {count}',
|
||||
'scenes_count' => '<info>จำนวนฉาก:</info> {count}',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Plain (no console tags) messages for exception messages. locale => [ key => text ]
|
||||
*
|
||||
* @return array<string, array<string, string>>
|
||||
*/
|
||||
public static function getPlainMessages(): array
|
||||
{
|
||||
return [
|
||||
'zh_CN' => [
|
||||
'invalid_name_empty_plain' => '验证器类名不能为空。',
|
||||
'invalid_segment_empty_plain' => '类名段不能为空。',
|
||||
'invalid_segment_plain' => '类名段无效:{name}',
|
||||
'config_not_available' => '配置不可用。',
|
||||
'database_connection_not_provided' => '未提供数据库连接名。',
|
||||
'thinkorm_connection_not_found' => 'ThinkORM 连接不存在:{name}(可用:{available})。',
|
||||
'database_config_invalid' => '数据库配置无效。',
|
||||
'database_connection_not_found_available' => '数据库连接不存在:{name}(可用:{available})。',
|
||||
],
|
||||
'zh_TW' => [
|
||||
'invalid_name_empty_plain' => '驗證器類名不能為空。',
|
||||
'invalid_segment_empty_plain' => '類名段不能為空。',
|
||||
'invalid_segment_plain' => '類名段無效:{name}',
|
||||
'config_not_available' => '配置不可用。',
|
||||
'database_connection_not_provided' => '未提供資料庫連線名稱。',
|
||||
'thinkorm_connection_not_found' => 'ThinkORM 連線不存在:{name}(可用:{available})。',
|
||||
'database_config_invalid' => '資料庫配置無效。',
|
||||
'database_connection_not_found_available' => '資料庫連線不存在:{name}(可用:{available})。',
|
||||
],
|
||||
'en' => [
|
||||
'invalid_name_empty_plain' => 'Validator class name cannot be empty.',
|
||||
'invalid_segment_empty_plain' => 'Class name segment cannot be empty.',
|
||||
'invalid_segment_plain' => 'Invalid class name segment: {name}',
|
||||
'config_not_available' => 'Configuration is not available.',
|
||||
'database_connection_not_provided' => 'Database connection name not provided.',
|
||||
'thinkorm_connection_not_found' => 'ThinkORM connection not found: {name} (available: {available}).',
|
||||
'database_config_invalid' => 'Database configuration is invalid.',
|
||||
'database_connection_not_found_available' => 'Database connection not found: {name} (available: {available}).',
|
||||
],
|
||||
'ja' => [
|
||||
'invalid_name_empty_plain' => 'バリデータークラス名を空にできません。',
|
||||
'invalid_segment_empty_plain' => 'クラス名セグメントを空にできません。',
|
||||
'invalid_segment_plain' => '無効なクラス名セグメント:{name}',
|
||||
'config_not_available' => '設定が利用できません。',
|
||||
'database_connection_not_provided' => 'データベース接続名が提供されていません。',
|
||||
'thinkorm_connection_not_found' => 'ThinkORM 接続が見つかりません:{name}(利用可能:{available})。',
|
||||
'database_config_invalid' => 'データベース設定が無効です。',
|
||||
'database_connection_not_found_available' => 'データベース接続が見つかりません:{name}(利用可能:{available})。',
|
||||
],
|
||||
'ko' => [
|
||||
'invalid_name_empty_plain' => '유효성 검사 클래스 이름을 비워 둘 수 없습니다.',
|
||||
'invalid_segment_empty_plain' => '클래스 이름 세그먼트를 비워 둘 수 없습니다.',
|
||||
'invalid_segment_plain' => '잘못된 클래스 이름 세그먼트: {name}',
|
||||
'config_not_available' => '구성이 사용할 수 없습니다.',
|
||||
'database_connection_not_provided' => '데이터베이스 연결 이름이 제공되지 않았습니다.',
|
||||
'thinkorm_connection_not_found' => 'ThinkORM 연결을 찾을 수 없습니다: {name} (사용 가능: {available}).',
|
||||
'database_config_invalid' => '데이터베이스 구성이 유효하지 않습니다.',
|
||||
'database_connection_not_found_available' => '데이터베이스 연결을 찾을 수 없습니다: {name} (사용 가능: {available}).',
|
||||
],
|
||||
'fr' => [
|
||||
'invalid_name_empty_plain' => 'Le nom de la classe de validation ne peut pas être vide.',
|
||||
'invalid_segment_empty_plain' => 'Le segment du nom de classe ne peut pas être vide.',
|
||||
'invalid_segment_plain' => 'Segment de nom de classe invalide : {name}',
|
||||
'config_not_available' => 'La configuration n\'est pas disponible.',
|
||||
'database_connection_not_provided' => 'Nom de connexion à la base de données non fourni.',
|
||||
'thinkorm_connection_not_found' => 'Connexion ThinkORM introuvable : {name} (disponible : {available}).',
|
||||
'database_config_invalid' => 'La configuration de la base de données est invalide.',
|
||||
'database_connection_not_found_available' => 'Connexion à la base de données introuvable : {name} (disponible : {available}).',
|
||||
],
|
||||
'de' => [
|
||||
'invalid_name_empty_plain' => 'Der Name der Validierungsklasse darf nicht leer sein.',
|
||||
'invalid_segment_empty_plain' => 'Klassennamensegment darf nicht leer sein.',
|
||||
'invalid_segment_plain' => 'Ungültiges Klassennamensegment: {name}',
|
||||
'config_not_available' => 'Konfiguration ist nicht verfügbar.',
|
||||
'database_connection_not_provided' => 'Datenbankverbindungsname nicht angegeben.',
|
||||
'thinkorm_connection_not_found' => 'ThinkORM-Verbindung nicht gefunden: {name} (verfügbar: {available}).',
|
||||
'database_config_invalid' => 'Datenbankkonfiguration ist ungültig.',
|
||||
'database_connection_not_found_available' => 'Datenbankverbindung nicht gefunden: {name} (verfügbar: {available}).',
|
||||
],
|
||||
'es' => [
|
||||
'invalid_name_empty_plain' => 'El nombre de la clase de validación no puede estar vacío.',
|
||||
'invalid_segment_empty_plain' => 'El segmento del nombre de clase no puede estar vacío.',
|
||||
'invalid_segment_plain' => 'Segmento de nombre de clase no válido: {name}',
|
||||
'config_not_available' => 'La configuración no está disponible.',
|
||||
'database_connection_not_provided' => 'Nombre de conexión a la base de datos no proporcionado.',
|
||||
'thinkorm_connection_not_found' => 'Conexión ThinkORM no encontrada: {name} (disponible: {available}).',
|
||||
'database_config_invalid' => 'La configuración de la base de datos es inválida.',
|
||||
'database_connection_not_found_available' => 'Conexión a la base de datos no encontrada: {name} (disponible: {available}).',
|
||||
],
|
||||
'pt_BR' => [
|
||||
'invalid_name_empty_plain' => 'O nome da classe de validação não pode estar vazio.',
|
||||
'invalid_segment_empty_plain' => 'O segmento do nome da classe não pode estar vazio.',
|
||||
'invalid_segment_plain' => 'Segmento de nome de classe inválido: {name}',
|
||||
'config_not_available' => 'A configuração não está disponível.',
|
||||
'database_connection_not_provided' => 'Nome da conexão do banco de dados não fornecido.',
|
||||
'thinkorm_connection_not_found' => 'Conexão ThinkORM não encontrada: {name} (disponível: {available}).',
|
||||
'database_config_invalid' => 'A configuração do banco de dados é inválida.',
|
||||
'database_connection_not_found_available' => 'Conexão com o banco de dados não encontrada: {name} (disponível: {available}).',
|
||||
],
|
||||
'ru' => [
|
||||
'invalid_name_empty_plain' => 'Имя класса валидации не может быть пустым.',
|
||||
'invalid_segment_empty_plain' => 'Сегмент имени класса не может быть пустым.',
|
||||
'invalid_segment_plain' => 'Недопустимый сегмент имени класса: {name}',
|
||||
'config_not_available' => 'Конфигурация недоступна.',
|
||||
'database_connection_not_provided' => 'Имя подключения к БД не указано.',
|
||||
'thinkorm_connection_not_found' => 'Подключение ThinkORM не найдено: {name} (доступно: {available}).',
|
||||
'database_config_invalid' => 'Конфигурация БД недействительна.',
|
||||
'database_connection_not_found_available' => 'Подключение к БД не найдено: {name} (доступно: {available}).',
|
||||
],
|
||||
'vi' => [
|
||||
'invalid_name_empty_plain' => 'Tên lớp xác thực không được để trống.',
|
||||
'invalid_segment_empty_plain' => 'Đoạn tên lớp không được để trống.',
|
||||
'invalid_segment_plain' => 'Đoạn tên lớp không hợp lệ: {name}',
|
||||
'config_not_available' => 'Cấu hình không khả dụng.',
|
||||
'database_connection_not_provided' => 'Tên kết nối cơ sở dữ liệu chưa được cung cấp.',
|
||||
'thinkorm_connection_not_found' => 'Không tìm thấy kết nối ThinkORM: {name} (có sẵn: {available}).',
|
||||
'database_config_invalid' => 'Cấu hình cơ sở dữ liệu không hợp lệ.',
|
||||
'database_connection_not_found_available' => 'Không tìm thấy kết nối cơ sở dữ liệu: {name} (có sẵn: {available}).',
|
||||
],
|
||||
'tr' => [
|
||||
'invalid_name_empty_plain' => 'Doğrulama sınıf adı boş bırakılamaz.',
|
||||
'invalid_segment_empty_plain' => 'Sınıf adı segmenti boş bırakılamaz.',
|
||||
'invalid_segment_plain' => 'Geçersiz sınıf adı segmenti: {name}',
|
||||
'config_not_available' => 'Yapılandırma kullanılamıyor.',
|
||||
'database_connection_not_provided' => 'Veritabanı bağlantı adı sağlanmadı.',
|
||||
'thinkorm_connection_not_found' => 'ThinkORM bağlantısı bulunamadı: {name} (mevcut: {available}).',
|
||||
'database_config_invalid' => 'Veritabanı yapılandırması geçersiz.',
|
||||
'database_connection_not_found_available' => 'Veritabanı bağlantısı bulunamadı: {name} (mevcut: {available}).',
|
||||
],
|
||||
'id' => [
|
||||
'invalid_name_empty_plain' => 'Nama kelas validasi tidak boleh kosong.',
|
||||
'invalid_segment_empty_plain' => 'Segmen nama kelas tidak boleh kosong.',
|
||||
'invalid_segment_plain' => 'Segmen nama kelas tidak valid: {name}',
|
||||
'config_not_available' => 'Konfigurasi tidak tersedia.',
|
||||
'database_connection_not_provided' => 'Nama koneksi database tidak diberikan.',
|
||||
'thinkorm_connection_not_found' => 'Koneksi ThinkORM tidak ditemukan: {name} (tersedia: {available}).',
|
||||
'database_config_invalid' => 'Konfigurasi database tidak valid.',
|
||||
'database_connection_not_found_available' => 'Koneksi database tidak ditemukan: {name} (tersedia: {available}).',
|
||||
],
|
||||
'th' => [
|
||||
'invalid_name_empty_plain' => 'ชื่อคลาสตรวจสอบไม่สามารถเว้นว่างได้',
|
||||
'invalid_segment_empty_plain' => 'ส่วนชื่อคลาสไม่สามารถเว้นว่างได้',
|
||||
'invalid_segment_plain' => 'ส่วนชื่อคลาสไม่ถูกต้อง: {name}',
|
||||
'config_not_available' => 'การกำหนดค่าไม่พร้อมใช้งาน',
|
||||
'database_connection_not_provided' => 'ไม่ได้ระบุชื่อการเชื่อมต่อฐานข้อมูล',
|
||||
'thinkorm_connection_not_found' => 'ไม่พบการเชื่อมต่อ ThinkORM: {name} (มีให้: {available})',
|
||||
'database_config_invalid' => 'การกำหนดค่าฐานข้อมูลไม่ถูกต้อง',
|
||||
'database_connection_not_found_available' => 'ไม่พบการเชื่อมต่อฐานข้อมูล: {name} (มีให้: {available})',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Command help text (bilingual).
|
||||
*
|
||||
* @return array<string, string> locale => help text
|
||||
*/
|
||||
public static function getHelpText(): array
|
||||
{
|
||||
return [
|
||||
'zh_CN' => <<<'EOF'
|
||||
生成验证器类文件(默认在 app/validation 下)。
|
||||
|
||||
推荐用法:
|
||||
php webman make:validator UserValidator
|
||||
php webman make:validator admin/UserValidator
|
||||
php webman make:validator UserValidator -p admin
|
||||
php webman make:validator UserValidator -P plugin/admin/app/validation
|
||||
|
||||
说明:
|
||||
- 默认生成到 app/validation(大小写以现有目录为准)。
|
||||
- 使用 -p/--plugin 时默认生成到 plugin/<plugin>/app/validation。
|
||||
- 使用 -P/--path 时生成到指定相对目录(相对于项目根目录)。
|
||||
- 文件已存在时默认拒绝覆盖;使用 -f/--force 可强制覆盖。
|
||||
- 使用 -t/--table 可从数据库数据表推断规则;如需生成场景请同时指定 -s/--scenes(例如 crud)。
|
||||
EOF,
|
||||
'zh_TW' => <<<'EOF'
|
||||
產生驗證器類檔案(預設在 app/validation 下)。
|
||||
|
||||
推薦用法:
|
||||
php webman make:validator UserValidator
|
||||
php webman make:validator admin/UserValidator
|
||||
php webman make:validator UserValidator -p admin
|
||||
php webman make:validator UserValidator -P plugin/admin/app/validation
|
||||
|
||||
說明:
|
||||
- 預設產生到 app/validation(大小寫以現有目錄為準)。
|
||||
- 使用 -p/--plugin 時預設產生到 plugin/<plugin>/app/validation。
|
||||
- 使用 -P/--path 時產生到指定相對目錄(相對於專案根目錄)。
|
||||
- 檔案已存在時預設拒絕覆蓋;使用 -f/--force 可強制覆蓋。
|
||||
- 使用 -t/--table 可從資料庫資料表推斷規則;如需產生場景請同時指定 -s/--scenes(例如 crud)。
|
||||
EOF,
|
||||
'en' => <<<'EOF'
|
||||
Generate a validator class file (default under app/validation).
|
||||
|
||||
Recommended:
|
||||
php webman make:validator UserValidator
|
||||
php webman make:validator admin/UserValidator
|
||||
php webman make:validator UserValidator -p admin
|
||||
php webman make:validator UserValidator -P plugin/admin/app/validation
|
||||
|
||||
Notes:
|
||||
- By default, it generates under app/validation (case depends on existing directory).
|
||||
- With -p/--plugin, it generates under plugin/<plugin>/app/validation by default.
|
||||
- With -P/--path, it generates under the specified relative directory (to project root).
|
||||
- If the file already exists, it refuses to overwrite by default; use -f/--force to overwrite.
|
||||
- With -t/--table, it infers rules from a database table; to generate scenes, also provide -s/--scenes (e.g. crud).
|
||||
EOF,
|
||||
'ja' => <<<'EOF'
|
||||
バリデータークラスファイルを生成します(デフォルトは app/validation 以下)。
|
||||
|
||||
推奨用法:
|
||||
php webman make:validator UserValidator
|
||||
php webman make:validator admin/UserValidator
|
||||
php webman make:validator UserValidator -p admin
|
||||
php webman make:validator UserValidator -P plugin/admin/app/validation
|
||||
|
||||
説明:
|
||||
- デフォルトでは app/validation 以下に生成(大文字小文字は既存ディレクトリに合わせます)。
|
||||
- -p/--plugin 使用時は plugin/<plugin>/app/validation 以下に生成。
|
||||
- -P/--path 使用時は指定した相対ディレクトリ(プロジェクトルート基準)に生成。
|
||||
- ファイルが既に存在する場合はデフォルトで上書きしません。-f/--force で上書きできます。
|
||||
- -t/--table でデータベーステーブルからルールを推論。シーンも生成する場合は -s/--scenes(例:crud)を指定してください。
|
||||
EOF,
|
||||
'ko' => <<<'EOF'
|
||||
유효성 검사 클래스 파일을 생성합니다 (기본 위치: app/validation).
|
||||
|
||||
권장 사용법:
|
||||
php webman make:validator UserValidator
|
||||
php webman make:validator admin/UserValidator
|
||||
php webman make:validator UserValidator -p admin
|
||||
php webman make:validator UserValidator -P plugin/admin/app/validation
|
||||
|
||||
설명:
|
||||
- 기본적으로 app/validation 아래에 생성합니다 (대소문자는 기존 디렉터리에 맞춤).
|
||||
- -p/--plugin 사용 시 plugin/<plugin>/app/validation 아래에 생성합니다.
|
||||
- -P/--path 사용 시 지정한 상대 디렉터리(프로젝트 루트 기준)에 생성합니다.
|
||||
- 파일이 이미 있으면 기본적으로 덮어쓰지 않습니다. -f/--force로 덮어쓸 수 있습니다.
|
||||
- -t/--table로 데이터베이스 테이블에서 규칙을 추론합니다. 장면도 생성하려면 -s/--scenes(예: crud)를 함께 지정하세요.
|
||||
EOF,
|
||||
'fr' => <<<'EOF'
|
||||
Génère un fichier de classe de validation (par défaut sous app/validation).
|
||||
|
||||
Recommandé :
|
||||
php webman make:validator UserValidator
|
||||
php webman make:validator admin/UserValidator
|
||||
php webman make:validator UserValidator -p admin
|
||||
php webman make:validator UserValidator -P plugin/admin/app/validation
|
||||
|
||||
Notes :
|
||||
- Par défaut, génération sous app/validation (casse selon le répertoire existant).
|
||||
- Avec -p/--plugin, génération sous plugin/<plugin>/app/validation par défaut.
|
||||
- Avec -P/--path, génération dans le répertoire relatif indiqué (par rapport à la racine du projet).
|
||||
- Si le fichier existe déjà, refus d'écraser par défaut ; utilisez -f/--force pour écraser.
|
||||
- Avec -t/--table, déduction des règles à partir d'une table ; pour générer des scènes, indiquez aussi -s/--scenes (ex. crud).
|
||||
EOF,
|
||||
'de' => <<<'EOF'
|
||||
Erstellt eine Validierungsklassen-Datei (Standard: unter app/validation).
|
||||
|
||||
Empfohlen:
|
||||
php webman make:validator UserValidator
|
||||
php webman make:validator admin/UserValidator
|
||||
php webman make:validator UserValidator -p admin
|
||||
php webman make:validator UserValidator -P plugin/admin/app/validation
|
||||
|
||||
Hinweise:
|
||||
- Standardmäßig wird unter app/validation erzeugt (Groß-/Kleinschreibung nach vorhandenem Verzeichnis).
|
||||
- Mit -p/--plugin wird standardmäßig unter plugin/<plugin>/app/validation erzeugt.
|
||||
- Mit -P/--path wird im angegebenen relativen Verzeichnis (zum Projektstamm) erzeugt.
|
||||
- Wenn die Datei bereits existiert, wird standardmäßig nicht überschrieben; mit -f/--force erzwingen.
|
||||
- Mit -t/--table werden Regeln aus einer Datenbanktabelle abgeleitet; für Szenen zusätzlich -s/--scenes angeben (z. B. crud).
|
||||
EOF,
|
||||
'es' => <<<'EOF'
|
||||
Genera un archivo de clase de validación (por defecto bajo app/validation).
|
||||
|
||||
Recomendado:
|
||||
php webman make:validator UserValidator
|
||||
php webman make:validator admin/UserValidator
|
||||
php webman make:validator UserValidator -p admin
|
||||
php webman make:validator UserValidator -P plugin/admin/app/validation
|
||||
|
||||
Notas:
|
||||
- Por defecto genera bajo app/validation (mayúsculas/minúsculas según el directorio existente).
|
||||
- Con -p/--plugin genera bajo plugin/<plugin>/app/validation por defecto.
|
||||
- Con -P/--path genera en el directorio relativo indicado (respecto a la raíz del proyecto).
|
||||
- Si el archivo ya existe, por defecto no se sobrescribe; use -f/--force para sobrescribir.
|
||||
- Con -t/--table infiere reglas desde una tabla; para generar escenas, indique también -s/--scenes (ej. crud).
|
||||
EOF,
|
||||
'pt_BR' => <<<'EOF'
|
||||
Gera um arquivo de classe de validação (padrão em app/validation).
|
||||
|
||||
Recomendado:
|
||||
php webman make:validator UserValidator
|
||||
php webman make:validator admin/UserValidator
|
||||
php webman make:validator UserValidator -p admin
|
||||
php webman make:validator UserValidator -P plugin/admin/app/validation
|
||||
|
||||
Notas:
|
||||
- Por padrão gera em app/validation (maiúsculas/minúsculas conforme o diretório existente).
|
||||
- Com -p/--plugin gera em plugin/<plugin>/app/validation por padrão.
|
||||
- Com -P/--path gera no diretório relativo informado (em relação à raiz do projeto).
|
||||
- Se o arquivo já existir, por padrão não sobrescreve; use -f/--force para sobrescrever.
|
||||
- Com -t/--table infere regras a partir de uma tabela; para gerar cenas, informe também -s/--scenes (ex.: crud).
|
||||
EOF,
|
||||
'ru' => <<<'EOF'
|
||||
Создаёт файл класса валидации (по умолчанию в app/validation).
|
||||
|
||||
Рекомендуется:
|
||||
php webman make:validator UserValidator
|
||||
php webman make:validator admin/UserValidator
|
||||
php webman make:validator UserValidator -p admin
|
||||
php webman make:validator UserValidator -P plugin/admin/app/validation
|
||||
|
||||
Примечания:
|
||||
- По умолчанию создаётся в app/validation (регистр по существующей папке).
|
||||
- С -p/--plugin по умолчанию создаётся в plugin/<plugin>/app/validation.
|
||||
- С -P/--path создаётся в указанной относительной директории (от корня проекта).
|
||||
- Если файл уже есть, по умолчанию не перезаписывается; используйте -f/--force для перезаписи.
|
||||
- С -t/--table правила выводятся из таблицы БД; для сцен укажите также -s/--scenes (напр. crud).
|
||||
EOF,
|
||||
'vi' => <<<'EOF'
|
||||
Tạo tệp lớp xác thực (mặc định trong app/validation).
|
||||
|
||||
Khuyến nghị:
|
||||
php webman make:validator UserValidator
|
||||
php webman make:validator admin/UserValidator
|
||||
php webman make:validator UserValidator -p admin
|
||||
php webman make:validator UserValidator -P plugin/admin/app/validation
|
||||
|
||||
Ghi chú:
|
||||
- Mặc định tạo trong app/validation (chữ hoa/thường theo thư mục hiện có).
|
||||
- Dùng -p/--plugin thì mặc định tạo trong plugin/<plugin>/app/validation.
|
||||
- Dùng -P/--path thì tạo vào thư mục tương đối chỉ định (so với thư mục gốc dự án).
|
||||
- Nếu tệp đã tồn tại thì mặc định không ghi đè; dùng -f/--force để ghi đè.
|
||||
- Dùng -t/--table để suy ra quy tắc từ bảng cơ sở dữ liệu; để tạo cảnh thì thêm -s/--scenes (vd: crud).
|
||||
EOF,
|
||||
'tr' => <<<'EOF'
|
||||
Doğrulama sınıf dosyası oluşturur (varsayılan: app/validation altında).
|
||||
|
||||
Önerilen:
|
||||
php webman make:validator UserValidator
|
||||
php webman make:validator admin/UserValidator
|
||||
php webman make:validator UserValidator -p admin
|
||||
php webman make:validator UserValidator -P plugin/admin/app/validation
|
||||
|
||||
Notlar:
|
||||
- Varsayılan olarak app/validation altında oluşturulur (büyük/küçük harf mevcut dizine göre).
|
||||
- -p/--plugin ile varsayılan olarak plugin/<plugin>/app/validation altında oluşturulur.
|
||||
- -P/--path ile belirtilen göreli dizinde (proje köküne göre) oluşturulur.
|
||||
- Dosya zaten varsa varsayılan olarak üzerine yazılmaz; üzerine yazmak için -f/--force kullanın.
|
||||
- -t/--table ile veritabanı tablosundan kurallar çıkarılır; sahneleri de oluşturmak için -s/--scenes (örn. crud) belirtin.
|
||||
EOF,
|
||||
'id' => <<<'EOF'
|
||||
Membuat berkas kelas validasi (baku: di bawah app/validation).
|
||||
|
||||
Disarankan:
|
||||
php webman make:validator UserValidator
|
||||
php webman make:validator admin/UserValidator
|
||||
php webman make:validator UserValidator -p admin
|
||||
php webman make:validator UserValidator -P plugin/admin/app/validation
|
||||
|
||||
Catatan:
|
||||
- Secara baku dibuat di bawah app/validation (huruf besar/kecil mengikuti direktori yang ada).
|
||||
- Dengan -p/--plugin secara baku dibuat di bawah plugin/<plugin>/app/validation.
|
||||
- Dengan -P/--path dibuat di direktori relatif yang ditentukan (terhadap root proyek).
|
||||
- Jika berkas sudah ada, secara baku tidak menimpa; gunakan -f/--force untuk menimpa.
|
||||
- Dengan -t/--table aturan disimpulkan dari tabel database; untuk membuat adegan, berikan juga -s/--scenes (mis. crud).
|
||||
EOF,
|
||||
'th' => <<<'EOF'
|
||||
สร้างไฟล์คลาสตรวจสอบความถูกต้อง (ค่าเริ่มต้นอยู่ใต้ app/validation)
|
||||
|
||||
แนะนำ:
|
||||
php webman make:validator UserValidator
|
||||
php webman make:validator admin/UserValidator
|
||||
php webman make:validator UserValidator -p admin
|
||||
php webman make:validator UserValidator -P plugin/admin/app/validation
|
||||
|
||||
หมายเหตุ:
|
||||
- ค่าเริ่มต้นจะสร้างใต้ app/validation (ตัวพิมพ์ตามโฟลเดอร์ที่มีอยู่)
|
||||
- ใช้ -p/--plugin จะสร้างใต้ plugin/<plugin>/app/validation โดยค่าเริ่มต้น
|
||||
- ใช้ -P/--path จะสร้างในโฟลเดอร์สัมพัทธ์ที่กำหนด (เทียบกับรากโปรเจกต์)
|
||||
- ถ้ามีไฟล์อยู่แล้วโดยค่าเริ่มต้นจะไม่เขียนทับ ใช้ -f/--force เพื่อเขียนทับ
|
||||
- ใช้ -t/--table จะสรุปกฎจากตารางฐานข้อมูล เพื่อสร้างฉากให้ระบุ -s/--scenes ด้วย (เช่น crud)
|
||||
EOF,
|
||||
];
|
||||
}
|
||||
}
|
||||
Vendored
+13
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Webman\Validation\Command\ValidatorGenerator\Contracts;
|
||||
|
||||
interface ConnectionResolverInterface
|
||||
{
|
||||
/**
|
||||
* @throws \RuntimeException When connection cannot be resolved.
|
||||
*/
|
||||
public function resolve(?string $connectionName = null): SchemaConnectionInterface;
|
||||
}
|
||||
|
||||
Vendored
+16
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Webman\Validation\Command\ValidatorGenerator\Contracts;
|
||||
|
||||
use Webman\Validation\Command\ValidatorGenerator\DTO\TableDefinition;
|
||||
|
||||
interface RuleInferrerInterface
|
||||
{
|
||||
/**
|
||||
* @param array{exclude_columns?: list<string>} $options
|
||||
* @return array{rules: array<string, string>, attributes: array<string, string>, scenes?: array<string, list<string>>}
|
||||
*/
|
||||
public function infer(TableDefinition $table, array $options = []): array;
|
||||
}
|
||||
|
||||
Vendored
+23
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Webman\Validation\Command\ValidatorGenerator\Contracts;
|
||||
|
||||
/**
|
||||
* A minimal DB connection abstraction for schema introspection.
|
||||
*
|
||||
* This intentionally avoids binding to a specific ORM (Illuminate/ThinkOrm).
|
||||
*/
|
||||
interface SchemaConnectionInterface
|
||||
{
|
||||
public function driverName(): string;
|
||||
|
||||
public function databaseName(): ?string;
|
||||
|
||||
/**
|
||||
* @param array<int, mixed> $bindings
|
||||
* @return array<int, array<string, mixed>>
|
||||
*/
|
||||
public function select(string $sql, array $bindings = []): array;
|
||||
}
|
||||
|
||||
Vendored
+15
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Webman\Validation\Command\ValidatorGenerator\Contracts;
|
||||
|
||||
use Webman\Validation\Command\ValidatorGenerator\DTO\TableDefinition;
|
||||
|
||||
interface SchemaIntrospectorInterface
|
||||
{
|
||||
/**
|
||||
* @throws \RuntimeException When schema cannot be read.
|
||||
*/
|
||||
public function introspect(SchemaConnectionInterface $connection, string $table): TableDefinition;
|
||||
}
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Webman\Validation\Command\ValidatorGenerator\DTO;
|
||||
|
||||
final class ColumnDefinition
|
||||
{
|
||||
/**
|
||||
* @param list<string> $enumValues
|
||||
*/
|
||||
public function __construct(
|
||||
public readonly string $name,
|
||||
public readonly string $dataType,
|
||||
public readonly string $columnType,
|
||||
public readonly bool $nullable,
|
||||
public readonly mixed $defaultValue,
|
||||
public readonly ?int $characterMaximumLength,
|
||||
public readonly ?int $numericPrecision,
|
||||
public readonly ?int $numericScale,
|
||||
public readonly bool $unsigned,
|
||||
public readonly bool $autoIncrement,
|
||||
public readonly array $enumValues,
|
||||
public readonly string $comment,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Webman\Validation\Command\ValidatorGenerator\DTO;
|
||||
|
||||
final class TableDefinition
|
||||
{
|
||||
/**
|
||||
* @param list<ColumnDefinition> $columns
|
||||
* @param list<string> $primaryKeyColumns
|
||||
*/
|
||||
public function __construct(
|
||||
public readonly string $table,
|
||||
public readonly array $columns,
|
||||
public readonly array $primaryKeyColumns = [],
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+78
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Webman\Validation\Command\ValidatorGenerator\Illuminate;
|
||||
|
||||
use Illuminate\Database\ConnectionInterface;
|
||||
use Webman\Validation\Command\ValidatorGenerator\Contracts\ConnectionResolverInterface;
|
||||
use Webman\Validation\Command\ValidatorGenerator\Contracts\SchemaConnectionInterface;
|
||||
|
||||
final class IlluminateConnectionResolver implements ConnectionResolverInterface
|
||||
{
|
||||
public function resolve(?string $connectionName = null): SchemaConnectionInterface
|
||||
{
|
||||
if (!class_exists(\support\Db::class)) {
|
||||
throw new \RuntimeException('Database support not found. Please install/enable webman/database plugin.');
|
||||
}
|
||||
|
||||
$dbConfig = config('database', []);
|
||||
if (!is_array($dbConfig)) {
|
||||
throw new \RuntimeException('Invalid database config: config("database") must be an array.');
|
||||
}
|
||||
|
||||
$connections = $dbConfig['connections'] ?? null;
|
||||
if (!is_array($connections) || $connections === []) {
|
||||
throw new \RuntimeException('Invalid database config: database.connections must be a non-empty array.');
|
||||
}
|
||||
|
||||
$name = $connectionName;
|
||||
if ($name === null || trim($name) === '') {
|
||||
$default = $dbConfig['default'] ?? null;
|
||||
if (!is_string($default) || trim($default) === '') {
|
||||
throw new \RuntimeException('Database connection name not provided and database.default is not set.');
|
||||
}
|
||||
$name = trim($default);
|
||||
}
|
||||
|
||||
$name = trim((string)$name);
|
||||
$connKey = $name;
|
||||
if (str_starts_with($name, 'plugin.')) {
|
||||
// plugin.<plugin>.<connection>
|
||||
$parts = explode('.', $name, 3);
|
||||
$plugin = $parts[1] ?? '';
|
||||
$conn = $parts[2] ?? '';
|
||||
$plugin = is_string($plugin) ? trim($plugin) : '';
|
||||
$conn = is_string($conn) ? trim($conn) : '';
|
||||
if ($plugin === '' || $conn === '') {
|
||||
throw new \RuntimeException("Invalid plugin connection name: {$name}");
|
||||
}
|
||||
|
||||
$pluginDb = config("plugin.$plugin.database", []);
|
||||
$pluginConnections = (is_array($pluginDb) ? ($pluginDb['connections'] ?? null) : null);
|
||||
if (is_array($pluginConnections) && $pluginConnections !== []) {
|
||||
if (!array_key_exists($conn, $pluginConnections)) {
|
||||
$available = implode(', ', array_keys($pluginConnections));
|
||||
throw new \RuntimeException("Database connection not found: {$name}. Available connections: {$available}");
|
||||
}
|
||||
$connKey = "plugin.$plugin.$conn";
|
||||
} else {
|
||||
// No plugin database connections: fallback to main project config.
|
||||
$connKey = $conn;
|
||||
if (!array_key_exists($connKey, $connections)) {
|
||||
$available = implode(', ', array_keys($connections));
|
||||
throw new \RuntimeException("Database connection not found: {$connKey}. Available connections: {$available}");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!array_key_exists($connKey, $connections)) {
|
||||
$available = implode(', ', array_keys($connections));
|
||||
throw new \RuntimeException("Database connection not found: {$connKey}. Available connections: {$available}");
|
||||
}
|
||||
}
|
||||
|
||||
/** @var ConnectionInterface $connection */
|
||||
$connection = \support\Db::connection($connKey);
|
||||
return new IlluminateSchemaConnection($connection);
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+49
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Webman\Validation\Command\ValidatorGenerator\Illuminate;
|
||||
|
||||
use Illuminate\Database\ConnectionInterface;
|
||||
use Webman\Validation\Command\ValidatorGenerator\Contracts\SchemaConnectionInterface;
|
||||
|
||||
final class IlluminateSchemaConnection implements SchemaConnectionInterface
|
||||
{
|
||||
public function __construct(private readonly ConnectionInterface $connection)
|
||||
{
|
||||
}
|
||||
|
||||
public function driverName(): string
|
||||
{
|
||||
return (string)$this->connection->getDriverName();
|
||||
}
|
||||
|
||||
public function databaseName(): ?string
|
||||
{
|
||||
$name = (string)$this->connection->getDatabaseName();
|
||||
return $name !== '' ? $name : null;
|
||||
}
|
||||
|
||||
public function select(string $sql, array $bindings = []): array
|
||||
{
|
||||
/** @var array<int, mixed> $rows */
|
||||
$rows = $this->connection->select($sql, $bindings);
|
||||
|
||||
$result = [];
|
||||
foreach ($rows as $row) {
|
||||
if (is_array($row)) {
|
||||
$result[] = $row;
|
||||
continue;
|
||||
}
|
||||
if (is_object($row)) {
|
||||
/** @var array<string, mixed> $arr */
|
||||
$arr = get_object_vars($row);
|
||||
$result[] = $arr;
|
||||
continue;
|
||||
}
|
||||
$result[] = ['value' => $row];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Webman\Validation\Command\ValidatorGenerator\Illuminate;
|
||||
|
||||
use Webman\Validation\Command\ValidatorGenerator\Contracts\SchemaConnectionInterface;
|
||||
use Webman\Validation\Command\ValidatorGenerator\Contracts\SchemaIntrospectorInterface;
|
||||
use Webman\Validation\Command\ValidatorGenerator\DTO\ColumnDefinition;
|
||||
use Webman\Validation\Command\ValidatorGenerator\DTO\TableDefinition;
|
||||
|
||||
final class MySqlInformationSchemaIntrospector implements SchemaIntrospectorInterface
|
||||
{
|
||||
public function introspect(SchemaConnectionInterface $connection, string $table): TableDefinition
|
||||
{
|
||||
$table = trim($table);
|
||||
if ($table === '') {
|
||||
throw new \InvalidArgumentException('Table name cannot be empty.');
|
||||
}
|
||||
|
||||
$database = $connection->databaseName();
|
||||
if (!$database) {
|
||||
throw new \RuntimeException('Database name is empty for current connection.');
|
||||
}
|
||||
|
||||
$rows = $connection->select(
|
||||
"SELECT
|
||||
COLUMN_NAME AS column_name,
|
||||
DATA_TYPE AS data_type,
|
||||
COLUMN_TYPE AS column_type,
|
||||
IS_NULLABLE AS is_nullable,
|
||||
COLUMN_DEFAULT AS column_default,
|
||||
CHARACTER_MAXIMUM_LENGTH AS character_maximum_length,
|
||||
NUMERIC_PRECISION AS numeric_precision,
|
||||
NUMERIC_SCALE AS numeric_scale,
|
||||
EXTRA AS extra,
|
||||
COLUMN_COMMENT AS column_comment
|
||||
FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = ?
|
||||
AND TABLE_NAME = ?
|
||||
ORDER BY ORDINAL_POSITION",
|
||||
[$database, $table]
|
||||
);
|
||||
|
||||
if ($rows === []) {
|
||||
throw new \RuntimeException("Table not found or has no columns: {$database}.{$table}");
|
||||
}
|
||||
|
||||
$pkRows = $connection->select(
|
||||
"SELECT
|
||||
COLUMN_NAME AS column_name
|
||||
FROM information_schema.KEY_COLUMN_USAGE
|
||||
WHERE TABLE_SCHEMA = ?
|
||||
AND TABLE_NAME = ?
|
||||
AND CONSTRAINT_NAME = 'PRIMARY'
|
||||
ORDER BY ORDINAL_POSITION",
|
||||
[$database, $table]
|
||||
);
|
||||
$primaryKeyColumns = [];
|
||||
foreach ($pkRows as $pkRow) {
|
||||
$pkName = (string)($pkRow['column_name'] ?? '');
|
||||
if ($pkName !== '') {
|
||||
$primaryKeyColumns[] = $pkName;
|
||||
}
|
||||
}
|
||||
|
||||
$columns = [];
|
||||
foreach ($rows as $row) {
|
||||
$name = (string)($row['column_name'] ?? '');
|
||||
if ($name === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$dataType = strtolower((string)($row['data_type'] ?? ''));
|
||||
$columnType = strtolower((string)($row['column_type'] ?? $dataType));
|
||||
$nullable = strtoupper((string)($row['is_nullable'] ?? 'NO')) === 'YES';
|
||||
$defaultValue = $row['column_default'] ?? null;
|
||||
|
||||
$charLen = $row['character_maximum_length'] ?? null;
|
||||
$characterMaximumLength = $charLen === null ? null : (int)$charLen;
|
||||
|
||||
$precision = $row['numeric_precision'] ?? null;
|
||||
$numericPrecision = $precision === null ? null : (int)$precision;
|
||||
|
||||
$scale = $row['numeric_scale'] ?? null;
|
||||
$numericScale = $scale === null ? null : (int)$scale;
|
||||
|
||||
$extra = strtolower((string)($row['extra'] ?? ''));
|
||||
$autoIncrement = str_contains($extra, 'auto_increment');
|
||||
$unsigned = str_contains($columnType, 'unsigned');
|
||||
|
||||
$comment = (string)($row['column_comment'] ?? '');
|
||||
|
||||
$enumValues = $this->parseEnumValues($dataType, $columnType);
|
||||
|
||||
$columns[] = new ColumnDefinition(
|
||||
name: $name,
|
||||
dataType: $dataType,
|
||||
columnType: $columnType,
|
||||
nullable: $nullable,
|
||||
defaultValue: $defaultValue,
|
||||
characterMaximumLength: $characterMaximumLength,
|
||||
numericPrecision: $numericPrecision,
|
||||
numericScale: $numericScale,
|
||||
unsigned: $unsigned,
|
||||
autoIncrement: $autoIncrement,
|
||||
enumValues: $enumValues,
|
||||
comment: $comment,
|
||||
);
|
||||
}
|
||||
|
||||
return new TableDefinition($table, $columns, $primaryKeyColumns);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<string>
|
||||
*/
|
||||
private function parseEnumValues(string $dataType, string $columnType): array
|
||||
{
|
||||
if ($dataType !== 'enum' && !str_starts_with($columnType, 'enum(')) {
|
||||
return [];
|
||||
}
|
||||
|
||||
// column_type example: enum('a','b','c')
|
||||
if (!preg_match('/^enum\((.*)\)$/i', $columnType, $m)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$inner = $m[1];
|
||||
// Match MySQL quoted strings inside enum(...)
|
||||
if (!preg_match_all("/'((?:\\\\'|[^'])*)'/", $inner, $matches)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$values = [];
|
||||
foreach ($matches[1] as $v) {
|
||||
$values[] = str_replace("\\'", "'", (string)$v);
|
||||
}
|
||||
return $values;
|
||||
}
|
||||
}
|
||||
|
||||
+186
@@ -0,0 +1,186 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Webman\Validation\Command\ValidatorGenerator\Illuminate;
|
||||
|
||||
use Webman\Validation\Command\ValidatorGenerator\Contracts\SchemaConnectionInterface;
|
||||
use Webman\Validation\Command\ValidatorGenerator\Contracts\SchemaIntrospectorInterface;
|
||||
use Webman\Validation\Command\ValidatorGenerator\DTO\ColumnDefinition;
|
||||
use Webman\Validation\Command\ValidatorGenerator\DTO\TableDefinition;
|
||||
|
||||
final class PostgresInformationSchemaIntrospector implements SchemaIntrospectorInterface
|
||||
{
|
||||
public function introspect(SchemaConnectionInterface $connection, string $table): TableDefinition
|
||||
{
|
||||
$table = trim($table);
|
||||
if ($table === '') {
|
||||
throw new \InvalidArgumentException('Table name cannot be empty.');
|
||||
}
|
||||
|
||||
[$schema, $tableName] = $this->splitSchemaTable($table);
|
||||
|
||||
$rows = $connection->select(
|
||||
"SELECT
|
||||
c.column_name AS column_name,
|
||||
c.data_type AS data_type,
|
||||
c.udt_name AS udt_name,
|
||||
c.is_nullable AS is_nullable,
|
||||
c.column_default AS column_default,
|
||||
c.character_maximum_length AS character_maximum_length,
|
||||
c.numeric_precision AS numeric_precision,
|
||||
c.numeric_scale AS numeric_scale
|
||||
FROM information_schema.columns c
|
||||
WHERE c.table_schema = ?
|
||||
AND c.table_name = ?
|
||||
ORDER BY c.ordinal_position",
|
||||
[$schema, $tableName]
|
||||
);
|
||||
|
||||
if ($rows === []) {
|
||||
throw new \RuntimeException("Table not found or has no columns: {$schema}.{$tableName}");
|
||||
}
|
||||
|
||||
$pkRows = $connection->select(
|
||||
"SELECT kcu.column_name AS column_name
|
||||
FROM information_schema.table_constraints tc
|
||||
JOIN information_schema.key_column_usage kcu
|
||||
ON tc.constraint_name = kcu.constraint_name
|
||||
AND tc.table_schema = kcu.table_schema
|
||||
AND tc.table_name = kcu.table_name
|
||||
WHERE tc.constraint_type = 'PRIMARY KEY'
|
||||
AND tc.table_schema = ?
|
||||
AND tc.table_name = ?
|
||||
ORDER BY kcu.ordinal_position",
|
||||
[$schema, $tableName]
|
||||
);
|
||||
$primaryKeyColumns = [];
|
||||
foreach ($pkRows as $pkRow) {
|
||||
$pkName = (string)($pkRow['column_name'] ?? '');
|
||||
if ($pkName !== '') {
|
||||
$primaryKeyColumns[] = $pkName;
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch column comments (best-effort).
|
||||
$commentRows = $connection->select(
|
||||
"SELECT
|
||||
a.attname AS column_name,
|
||||
COALESCE(col_description(a.attrelid, a.attnum), '') AS column_comment
|
||||
FROM pg_attribute a
|
||||
JOIN pg_class t ON t.oid = a.attrelid
|
||||
JOIN pg_namespace n ON n.oid = t.relnamespace
|
||||
WHERE n.nspname = ?
|
||||
AND t.relname = ?
|
||||
AND a.attnum > 0
|
||||
AND NOT a.attisdropped",
|
||||
[$schema, $tableName]
|
||||
);
|
||||
$commentsByColumn = [];
|
||||
foreach ($commentRows as $cr) {
|
||||
$cn = (string)($cr['column_name'] ?? '');
|
||||
if ($cn !== '') {
|
||||
$commentsByColumn[$cn] = (string)($cr['column_comment'] ?? '');
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch enum values (best-effort) for user-defined enum types.
|
||||
$enumValuesByType = $this->loadEnumValuesByType($connection);
|
||||
|
||||
$columns = [];
|
||||
foreach ($rows as $row) {
|
||||
$name = (string)($row['column_name'] ?? '');
|
||||
if ($name === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$dataType = strtolower((string)($row['data_type'] ?? ''));
|
||||
$udtName = strtolower((string)($row['udt_name'] ?? ''));
|
||||
$nullable = strtoupper((string)($row['is_nullable'] ?? 'NO')) === 'YES';
|
||||
$defaultValue = $row['column_default'] ?? null;
|
||||
|
||||
$charLen = $row['character_maximum_length'] ?? null;
|
||||
$characterMaximumLength = $charLen === null ? null : (int)$charLen;
|
||||
|
||||
$precision = $row['numeric_precision'] ?? null;
|
||||
$numericPrecision = $precision === null ? null : (int)$precision;
|
||||
|
||||
$scale = $row['numeric_scale'] ?? null;
|
||||
$numericScale = $scale === null ? null : (int)$scale;
|
||||
|
||||
$autoIncrement = false;
|
||||
if (is_string($defaultValue) && str_contains($defaultValue, 'nextval(')) {
|
||||
$autoIncrement = true;
|
||||
}
|
||||
|
||||
$comment = (string)($commentsByColumn[$name] ?? '');
|
||||
|
||||
$enumValues = [];
|
||||
if ($dataType === 'user-defined' && isset($enumValuesByType[$udtName])) {
|
||||
$enumValues = $enumValuesByType[$udtName];
|
||||
$dataType = 'enum';
|
||||
}
|
||||
|
||||
$columns[] = new ColumnDefinition(
|
||||
name: $name,
|
||||
dataType: $dataType,
|
||||
columnType: $udtName !== '' ? $udtName : $dataType,
|
||||
nullable: $nullable,
|
||||
defaultValue: $defaultValue,
|
||||
characterMaximumLength: $characterMaximumLength,
|
||||
numericPrecision: $numericPrecision,
|
||||
numericScale: $numericScale,
|
||||
unsigned: false,
|
||||
autoIncrement: $autoIncrement,
|
||||
enumValues: $enumValues,
|
||||
comment: $comment,
|
||||
);
|
||||
}
|
||||
|
||||
return new TableDefinition($tableName, $columns, $primaryKeyColumns);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{0:string,1:string} [schema, table]
|
||||
*/
|
||||
private function splitSchemaTable(string $table): array
|
||||
{
|
||||
$parts = array_values(array_filter(explode('.', $table), static fn(string $p): bool => $p !== ''));
|
||||
if (count($parts) === 1) {
|
||||
return ['public', $parts[0]];
|
||||
}
|
||||
if (count($parts) === 2) {
|
||||
return [$parts[0], $parts[1]];
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException("Invalid table name for Postgres: {$table}");
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, list<string>> map udt_name => enum labels
|
||||
*/
|
||||
private function loadEnumValuesByType(SchemaConnectionInterface $connection): array
|
||||
{
|
||||
$rows = $connection->select(
|
||||
"SELECT
|
||||
t.typname AS type_name,
|
||||
e.enumlabel AS enum_label
|
||||
FROM pg_type t
|
||||
JOIN pg_enum e ON e.enumtypid = t.oid
|
||||
ORDER BY t.typname, e.enumsortorder"
|
||||
);
|
||||
|
||||
$map = [];
|
||||
foreach ($rows as $row) {
|
||||
$type = strtolower((string)($row['type_name'] ?? ''));
|
||||
$label = (string)($row['enum_label'] ?? '');
|
||||
if ($type === '' || $label === '') {
|
||||
continue;
|
||||
}
|
||||
$map[$type] ??= [];
|
||||
$map[$type][] = $label;
|
||||
}
|
||||
|
||||
return $map;
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+131
@@ -0,0 +1,131 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Webman\Validation\Command\ValidatorGenerator\Illuminate;
|
||||
|
||||
use Webman\Validation\Command\ValidatorGenerator\Contracts\SchemaConnectionInterface;
|
||||
use Webman\Validation\Command\ValidatorGenerator\Contracts\SchemaIntrospectorInterface;
|
||||
use Webman\Validation\Command\ValidatorGenerator\DTO\ColumnDefinition;
|
||||
use Webman\Validation\Command\ValidatorGenerator\DTO\TableDefinition;
|
||||
|
||||
final class SqlServerIntrospector implements SchemaIntrospectorInterface
|
||||
{
|
||||
public function introspect(SchemaConnectionInterface $connection, string $table): TableDefinition
|
||||
{
|
||||
$table = trim($table);
|
||||
if ($table === '') {
|
||||
throw new \InvalidArgumentException('Table name cannot be empty.');
|
||||
}
|
||||
|
||||
[$schema, $tableName] = $this->splitSchemaTable($table);
|
||||
|
||||
$rows = $connection->select(
|
||||
"SELECT
|
||||
c.name AS column_name,
|
||||
t.name AS data_type,
|
||||
CASE
|
||||
WHEN t.name IN ('nvarchar','nchar') THEN c.max_length / 2
|
||||
ELSE c.max_length
|
||||
END AS character_maximum_length,
|
||||
c.precision AS numeric_precision,
|
||||
c.scale AS numeric_scale,
|
||||
c.is_nullable AS is_nullable,
|
||||
dc.definition AS column_default,
|
||||
c.is_identity AS is_identity,
|
||||
ep.value AS column_comment
|
||||
FROM sys.columns c
|
||||
JOIN sys.tables tb ON tb.object_id = c.object_id
|
||||
JOIN sys.schemas s ON s.schema_id = tb.schema_id
|
||||
JOIN sys.types t ON t.user_type_id = c.user_type_id
|
||||
LEFT JOIN sys.default_constraints dc ON dc.parent_object_id = c.object_id AND dc.parent_column_id = c.column_id
|
||||
LEFT JOIN sys.extended_properties ep ON ep.major_id = c.object_id AND ep.minor_id = c.column_id AND ep.name = 'MS_Description'
|
||||
WHERE s.name = ?
|
||||
AND tb.name = ?
|
||||
ORDER BY c.column_id",
|
||||
[$schema, $tableName]
|
||||
);
|
||||
|
||||
if ($rows === []) {
|
||||
throw new \RuntimeException("Table not found or has no columns: {$schema}.{$tableName}");
|
||||
}
|
||||
|
||||
$pkRows = $connection->select(
|
||||
"SELECT c.name AS column_name
|
||||
FROM sys.indexes i
|
||||
JOIN sys.index_columns ic ON ic.object_id = i.object_id AND ic.index_id = i.index_id
|
||||
JOIN sys.columns c ON c.object_id = ic.object_id AND c.column_id = ic.column_id
|
||||
JOIN sys.tables tb ON tb.object_id = i.object_id
|
||||
JOIN sys.schemas s ON s.schema_id = tb.schema_id
|
||||
WHERE i.is_primary_key = 1
|
||||
AND s.name = ?
|
||||
AND tb.name = ?
|
||||
ORDER BY ic.key_ordinal",
|
||||
[$schema, $tableName]
|
||||
);
|
||||
$primaryKeyColumns = [];
|
||||
foreach ($pkRows as $pkRow) {
|
||||
$pkName = (string)($pkRow['column_name'] ?? '');
|
||||
if ($pkName !== '') {
|
||||
$primaryKeyColumns[] = $pkName;
|
||||
}
|
||||
}
|
||||
|
||||
$columns = [];
|
||||
foreach ($rows as $row) {
|
||||
$name = (string)($row['column_name'] ?? '');
|
||||
if ($name === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$dataType = strtolower((string)($row['data_type'] ?? ''));
|
||||
$nullable = (int)($row['is_nullable'] ?? 0) === 1;
|
||||
$defaultValue = $row['column_default'] ?? null;
|
||||
|
||||
$charLen = $row['character_maximum_length'] ?? null;
|
||||
$characterMaximumLength = $charLen === null ? null : (int)$charLen;
|
||||
|
||||
$precision = $row['numeric_precision'] ?? null;
|
||||
$numericPrecision = $precision === null ? null : (int)$precision;
|
||||
|
||||
$scale = $row['numeric_scale'] ?? null;
|
||||
$numericScale = $scale === null ? null : (int)$scale;
|
||||
|
||||
$autoIncrement = (int)($row['is_identity'] ?? 0) === 1;
|
||||
$comment = is_string($row['column_comment'] ?? null) ? (string)$row['column_comment'] : '';
|
||||
|
||||
$columns[] = new ColumnDefinition(
|
||||
name: $name,
|
||||
dataType: $dataType,
|
||||
columnType: $dataType,
|
||||
nullable: $nullable,
|
||||
defaultValue: $defaultValue,
|
||||
characterMaximumLength: $characterMaximumLength,
|
||||
numericPrecision: $numericPrecision,
|
||||
numericScale: $numericScale,
|
||||
unsigned: false,
|
||||
autoIncrement: $autoIncrement,
|
||||
enumValues: [],
|
||||
comment: $comment,
|
||||
);
|
||||
}
|
||||
|
||||
return new TableDefinition($tableName, $columns, $primaryKeyColumns);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{0:string,1:string} [schema, table]
|
||||
*/
|
||||
private function splitSchemaTable(string $table): array
|
||||
{
|
||||
$parts = array_values(array_filter(explode('.', $table), static fn(string $p): bool => $p !== ''));
|
||||
if (count($parts) === 1) {
|
||||
return ['dbo', $parts[0]];
|
||||
}
|
||||
if (count($parts) === 2) {
|
||||
return [$parts[0], $parts[1]];
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException("Invalid table name for SQL Server: {$table}");
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+120
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Webman\Validation\Command\ValidatorGenerator\Illuminate;
|
||||
|
||||
use Webman\Validation\Command\ValidatorGenerator\Contracts\SchemaConnectionInterface;
|
||||
use Webman\Validation\Command\ValidatorGenerator\Contracts\SchemaIntrospectorInterface;
|
||||
use Webman\Validation\Command\ValidatorGenerator\DTO\ColumnDefinition;
|
||||
use Webman\Validation\Command\ValidatorGenerator\DTO\TableDefinition;
|
||||
|
||||
final class SqlitePragmaIntrospector implements SchemaIntrospectorInterface
|
||||
{
|
||||
public function introspect(SchemaConnectionInterface $connection, string $table): TableDefinition
|
||||
{
|
||||
$table = trim($table);
|
||||
if ($table === '') {
|
||||
throw new \InvalidArgumentException('Table name cannot be empty.');
|
||||
}
|
||||
if (!preg_match('/^[A-Za-z_][A-Za-z0-9_]*$/', $table)) {
|
||||
throw new \InvalidArgumentException("Invalid table name for SQLite: {$table}");
|
||||
}
|
||||
|
||||
$rows = $connection->select("PRAGMA table_info('{$table}')");
|
||||
if ($rows === []) {
|
||||
throw new \RuntimeException("Table not found or has no columns: {$table}");
|
||||
}
|
||||
|
||||
$primaryKeyColumns = [];
|
||||
$columns = [];
|
||||
|
||||
foreach ($rows as $row) {
|
||||
$name = (string)($row['name'] ?? '');
|
||||
if ($name === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$type = strtolower((string)($row['type'] ?? ''));
|
||||
$notNull = (int)($row['notnull'] ?? 0) === 1;
|
||||
$nullable = !$notNull;
|
||||
$defaultValue = $row['dflt_value'] ?? null;
|
||||
$pk = (int)($row['pk'] ?? 0);
|
||||
if ($pk > 0) {
|
||||
$primaryKeyColumns[] = $name;
|
||||
}
|
||||
|
||||
[$dataType, $charLen, $precision, $scale] = $this->parseType($type);
|
||||
|
||||
$autoIncrement = false;
|
||||
// Best-effort: INTEGER PRIMARY KEY behaves like auto-increment rowid.
|
||||
if ($pk > 0 && $dataType === 'integer') {
|
||||
$autoIncrement = true;
|
||||
}
|
||||
|
||||
$columns[] = new ColumnDefinition(
|
||||
name: $name,
|
||||
dataType: $dataType,
|
||||
columnType: $type !== '' ? $type : $dataType,
|
||||
nullable: $nullable,
|
||||
defaultValue: $defaultValue,
|
||||
characterMaximumLength: $charLen,
|
||||
numericPrecision: $precision,
|
||||
numericScale: $scale,
|
||||
unsigned: false,
|
||||
autoIncrement: $autoIncrement,
|
||||
enumValues: [],
|
||||
comment: '',
|
||||
);
|
||||
}
|
||||
|
||||
return new TableDefinition($table, $columns, $primaryKeyColumns);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{0:string,1:?int,2:?int,3:?int} [dataType, charLen, precision, scale]
|
||||
*/
|
||||
private function parseType(string $type): array
|
||||
{
|
||||
$type = strtolower(trim($type));
|
||||
if ($type === '') {
|
||||
return ['string', null, null, null];
|
||||
}
|
||||
|
||||
if (str_contains($type, 'int')) {
|
||||
return ['integer', null, null, null];
|
||||
}
|
||||
if (str_contains($type, 'char') || str_contains($type, 'clob') || str_contains($type, 'text')) {
|
||||
$len = null;
|
||||
if (preg_match('/\((\d+)\)/', $type, $m)) {
|
||||
$len = (int)$m[1];
|
||||
}
|
||||
return ['varchar', $len, null, null];
|
||||
}
|
||||
if (str_contains($type, 'blob')) {
|
||||
return ['string', null, null, null];
|
||||
}
|
||||
if (str_contains($type, 'real') || str_contains($type, 'floa') || str_contains($type, 'doub')) {
|
||||
return ['double', null, null, null];
|
||||
}
|
||||
if (str_contains($type, 'dec') || str_contains($type, 'num')) {
|
||||
$precision = null;
|
||||
$scale = null;
|
||||
if (preg_match('/\((\d+)\s*,\s*(\d+)\)/', $type, $m)) {
|
||||
$precision = (int)$m[1];
|
||||
$scale = (int)$m[2];
|
||||
} elseif (preg_match('/\((\d+)\)/', $type, $m)) {
|
||||
$precision = (int)$m[1];
|
||||
}
|
||||
return ['decimal', null, $precision, $scale];
|
||||
}
|
||||
if (str_contains($type, 'bool')) {
|
||||
return ['boolean', null, null, null];
|
||||
}
|
||||
if (str_contains($type, 'date') || str_contains($type, 'time')) {
|
||||
return ['datetime', null, null, null];
|
||||
}
|
||||
|
||||
return ['string', null, null, null];
|
||||
}
|
||||
}
|
||||
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Webman\Validation\Command\ValidatorGenerator\Rules;
|
||||
|
||||
use Webman\Validation\Command\ValidatorGenerator\Contracts\RuleInferrerInterface;
|
||||
use Webman\Validation\Command\ValidatorGenerator\DTO\ColumnDefinition;
|
||||
use Webman\Validation\Command\ValidatorGenerator\DTO\TableDefinition;
|
||||
|
||||
final class DefaultRuleInferrer implements RuleInferrerInterface
|
||||
{
|
||||
public function infer(TableDefinition $table, array $options = []): array
|
||||
{
|
||||
$exclude = array_map('strtolower', $options['exclude_columns'] ?? []);
|
||||
$excludeMap = array_fill_keys($exclude, true);
|
||||
$withScenes = (bool)($options['with_scenes'] ?? false);
|
||||
|
||||
$rules = [];
|
||||
$attributes = [];
|
||||
|
||||
foreach ($table->columns as $column) {
|
||||
if (isset($excludeMap[strtolower($column->name)])) {
|
||||
continue;
|
||||
}
|
||||
if ($column->autoIncrement && !$withScenes) {
|
||||
// For create/update validators we generally don't validate auto-increment columns (e.g. id).
|
||||
continue;
|
||||
}
|
||||
|
||||
$ruleParts = $this->inferRuleParts($column);
|
||||
if ($ruleParts === []) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$rules[$column->name] = implode('|', $ruleParts);
|
||||
|
||||
$comment = trim($column->comment);
|
||||
if ($comment !== '') {
|
||||
$attributes[$column->name] = $comment;
|
||||
}
|
||||
}
|
||||
|
||||
$result = ['rules' => $rules, 'attributes' => $attributes];
|
||||
|
||||
if ($withScenes) {
|
||||
$scenesType = strtolower(trim((string)($options['scenes'] ?? 'crud')));
|
||||
if ($scenesType !== 'crud') {
|
||||
throw new \InvalidArgumentException("Unsupported scenes type: {$scenesType}");
|
||||
}
|
||||
|
||||
$result['scenes'] = $this->buildCrudScenes($table, $rules);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, string> $rules
|
||||
* @return array<string, list<string>>
|
||||
*/
|
||||
private function buildCrudScenes(TableDefinition $table, array $rules): array
|
||||
{
|
||||
$ruleKeys = array_keys($rules);
|
||||
$pk = array_values(array_intersect($table->primaryKeyColumns, $ruleKeys));
|
||||
if ($pk === []) {
|
||||
throw new \RuntimeException("Cannot generate CRUD scenes: primary key columns not found in rules for table {$table->table}");
|
||||
}
|
||||
|
||||
$nonPk = array_values(array_diff($ruleKeys, $pk));
|
||||
|
||||
return [
|
||||
'create' => $nonPk,
|
||||
// Full update (PUT semantics) generally requires primary key + full payload.
|
||||
'update' => array_values(array_merge($pk, $nonPk)),
|
||||
'delete' => $pk,
|
||||
'detail' => $pk,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<string>
|
||||
*/
|
||||
private function inferRuleParts(ColumnDefinition $column): array
|
||||
{
|
||||
$parts = [];
|
||||
|
||||
if ($this->shouldBeRequired($column)) {
|
||||
$parts[] = 'required';
|
||||
} elseif ($column->nullable) {
|
||||
$parts[] = 'nullable';
|
||||
}
|
||||
|
||||
$typeParts = $this->inferTypeParts($column);
|
||||
foreach ($typeParts as $p) {
|
||||
$parts[] = $p;
|
||||
}
|
||||
|
||||
return $parts;
|
||||
}
|
||||
|
||||
private function shouldBeRequired(ColumnDefinition $column): bool
|
||||
{
|
||||
if ($column->nullable) {
|
||||
return false;
|
||||
}
|
||||
// If default exists, allow omitting the field.
|
||||
if ($column->defaultValue !== null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<string>
|
||||
*/
|
||||
private function inferTypeParts(ColumnDefinition $column): array
|
||||
{
|
||||
$type = strtolower($column->dataType);
|
||||
|
||||
if ($column->enumValues !== []) {
|
||||
// Values containing commas are not representable; keep best-effort.
|
||||
return ['in:' . implode(',', $column->enumValues)];
|
||||
}
|
||||
|
||||
return match ($type) {
|
||||
'varchar', 'char' => $this->stringRules($column),
|
||||
'text', 'tinytext', 'mediumtext', 'longtext' => ['string'],
|
||||
'int', 'integer', 'tinyint', 'smallint', 'mediumint', 'bigint' => $this->integerRules($column),
|
||||
'decimal', 'numeric', 'float', 'double' => $this->numericRules($column),
|
||||
'date', 'datetime', 'timestamp', 'time' => ['date'],
|
||||
'json' => ['json'],
|
||||
'bool', 'boolean' => ['boolean'],
|
||||
default => [],
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<string>
|
||||
*/
|
||||
private function stringRules(ColumnDefinition $column): array
|
||||
{
|
||||
$rules = ['string'];
|
||||
if ($column->characterMaximumLength !== null && $column->characterMaximumLength > 0) {
|
||||
$rules[] = 'max:' . $column->characterMaximumLength;
|
||||
}
|
||||
return $rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<string>
|
||||
*/
|
||||
private function integerRules(ColumnDefinition $column): array
|
||||
{
|
||||
$rules = ['integer'];
|
||||
if ($column->unsigned) {
|
||||
$rules[] = 'min:0';
|
||||
}
|
||||
return $rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<string>
|
||||
*/
|
||||
private function numericRules(ColumnDefinition $column): array
|
||||
{
|
||||
$rules = ['numeric'];
|
||||
if ($column->unsigned) {
|
||||
$rules[] = 'min:0';
|
||||
}
|
||||
return $rules;
|
||||
}
|
||||
}
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Webman\Validation\Command\ValidatorGenerator\Support;
|
||||
|
||||
final class ExcludedColumns
|
||||
{
|
||||
/**
|
||||
* @return list<string>
|
||||
*/
|
||||
public static function defaultForIlluminate(): array
|
||||
{
|
||||
return ['created_at', 'updated_at', 'deleted_at'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return list<string>
|
||||
*/
|
||||
public static function defaultForThinkOrm(): array
|
||||
{
|
||||
// ThinkORM (ThinkPHP) commonly uses *_time fields for timestamps/soft delete.
|
||||
return ['create_time', 'update_time', 'delete_time'];
|
||||
}
|
||||
}
|
||||
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Webman\Validation\Command\ValidatorGenerator\Support;
|
||||
|
||||
final class OrmDetector
|
||||
{
|
||||
public const ORM_AUTO = 'auto';
|
||||
public const ORM_LARAVEL = 'laravel';
|
||||
public const ORM_THINKORM = 'thinkorm';
|
||||
|
||||
/**
|
||||
* @return array{laravel: bool, thinkorm: bool}
|
||||
*/
|
||||
public function availability(): array
|
||||
{
|
||||
return [
|
||||
'laravel' => $this->isIlluminateAvailable(),
|
||||
'thinkorm' => $this->isThinkOrmAvailable(),
|
||||
];
|
||||
}
|
||||
|
||||
public function resolve(string $requestedOrm): string
|
||||
{
|
||||
$requestedOrm = strtolower(trim($requestedOrm));
|
||||
if ($requestedOrm === '' || $requestedOrm === self::ORM_AUTO) {
|
||||
$availability = $this->availability();
|
||||
if ($availability['laravel']) {
|
||||
return self::ORM_LARAVEL;
|
||||
}
|
||||
if ($availability['thinkorm']) {
|
||||
return self::ORM_THINKORM;
|
||||
}
|
||||
throw new \RuntimeException('No ORM available. Please install/configure illuminate/database or think-orm.');
|
||||
}
|
||||
|
||||
// Backward compatible alias: `illuminate` => `laravel`
|
||||
if ($requestedOrm === 'illuminate') {
|
||||
$requestedOrm = self::ORM_LARAVEL;
|
||||
}
|
||||
|
||||
if ($requestedOrm === self::ORM_LARAVEL) {
|
||||
if (!$this->isIlluminateAvailable()) {
|
||||
throw new \RuntimeException('Requested orm=laravel but illuminate/database is not available.');
|
||||
}
|
||||
return self::ORM_LARAVEL;
|
||||
}
|
||||
|
||||
if ($requestedOrm === self::ORM_THINKORM) {
|
||||
if (!$this->isThinkOrmAvailable()) {
|
||||
throw new \RuntimeException('Requested orm=thinkorm but think-orm is not available.');
|
||||
}
|
||||
return self::ORM_THINKORM;
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException("Unsupported orm value: {$requestedOrm}");
|
||||
}
|
||||
|
||||
private function isIlluminateAvailable(): bool
|
||||
{
|
||||
if (!class_exists(\support\Db::class)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$database = config('database');
|
||||
if (!is_array($database)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Follow webman make:model behavior: plugin.* defaults are not treated as local database config.
|
||||
$default = $database['default'] ?? null;
|
||||
if (is_string($default) && str_starts_with($default, 'plugin.')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$connections = $database['connections'] ?? null;
|
||||
return is_array($connections) && $connections !== [];
|
||||
}
|
||||
|
||||
private function isThinkOrmAvailable(): bool
|
||||
{
|
||||
$thinkorm = config('think-orm') ?: config('thinkorm');
|
||||
if (!is_array($thinkorm)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$default = $thinkorm['default'] ?? null;
|
||||
if (is_string($default) && str_starts_with($default, 'plugin.')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$connections = $thinkorm['connections'] ?? null;
|
||||
if (!is_array($connections) || $connections === []) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Think-orm v2 uses support\think\Db; v1 uses think\facade\Db.
|
||||
$hasRuntime = class_exists(\support\think\Db::class) || class_exists(\think\facade\Db::class);
|
||||
if (!$hasRuntime) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
+133
@@ -0,0 +1,133 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Webman\Validation\Command\ValidatorGenerator\Support;
|
||||
|
||||
final class PhpArrayExporter
|
||||
{
|
||||
public static function export(array $value, int $indentLevel = 1): string
|
||||
{
|
||||
return self::exportArray($value, $indentLevel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Export an array for use as a class property initializer.
|
||||
*
|
||||
* Expected output style:
|
||||
* - Empty: []
|
||||
* - Non-empty:
|
||||
* [
|
||||
* 'k' => 'v',
|
||||
* ]
|
||||
*/
|
||||
public static function exportForProperty(array $value, int $propertyIndentLevel = 1): string
|
||||
{
|
||||
if ($value === []) {
|
||||
return '[]';
|
||||
}
|
||||
|
||||
$propertyIndent = str_repeat(' ', $propertyIndentLevel);
|
||||
$childIndent = str_repeat(' ', $propertyIndentLevel + 1);
|
||||
|
||||
$lines = ['['];
|
||||
foreach ($value as $k => $v) {
|
||||
$key = is_int($k) ? null : self::exportScalar($k);
|
||||
|
||||
if (is_array($v)) {
|
||||
$exported = self::exportArrayValue($v, $propertyIndentLevel + 1);
|
||||
} else {
|
||||
$exported = self::exportScalar($v);
|
||||
}
|
||||
|
||||
if ($key === null) {
|
||||
$lines[] = "{$childIndent}{$exported},";
|
||||
} else {
|
||||
$lines[] = "{$childIndent}{$key} => {$exported},";
|
||||
}
|
||||
}
|
||||
$lines[] = "{$propertyIndent}]";
|
||||
|
||||
return implode("\n", $lines);
|
||||
}
|
||||
|
||||
private static function exportArray(array $value, int $indentLevel): string
|
||||
{
|
||||
if ($value === []) {
|
||||
return '[]';
|
||||
}
|
||||
|
||||
$indent = str_repeat(' ', $indentLevel);
|
||||
$childIndent = str_repeat(' ', $indentLevel + 1);
|
||||
|
||||
$lines = ["{$indent}["];
|
||||
foreach ($value as $k => $v) {
|
||||
$key = is_int($k) ? null : self::exportScalar($k);
|
||||
|
||||
if (is_array($v)) {
|
||||
$exported = self::exportArray($v, $indentLevel + 1);
|
||||
} else {
|
||||
$exported = self::exportScalar($v);
|
||||
}
|
||||
|
||||
if ($key === null) {
|
||||
$lines[] = "{$childIndent}{$exported},";
|
||||
} else {
|
||||
$lines[] = "{$childIndent}{$key} => {$exported},";
|
||||
}
|
||||
}
|
||||
$lines[] = "{$indent}]";
|
||||
return implode("\n", $lines);
|
||||
}
|
||||
|
||||
/**
|
||||
* Export an array as a value after `=> `, i.e. first line has no leading indent.
|
||||
*/
|
||||
private static function exportArrayValue(array $value, int $closingIndentLevel): string
|
||||
{
|
||||
if ($value === []) {
|
||||
return '[]';
|
||||
}
|
||||
|
||||
$closingIndent = str_repeat(' ', $closingIndentLevel);
|
||||
$childIndent = str_repeat(' ', $closingIndentLevel + 1);
|
||||
|
||||
$lines = ['['];
|
||||
foreach ($value as $k => $v) {
|
||||
$key = is_int($k) ? null : self::exportScalar($k);
|
||||
|
||||
if (is_array($v)) {
|
||||
$exported = self::exportArrayValue($v, $closingIndentLevel + 1);
|
||||
} else {
|
||||
$exported = self::exportScalar($v);
|
||||
}
|
||||
|
||||
if ($key === null) {
|
||||
$lines[] = "{$childIndent}{$exported},";
|
||||
} else {
|
||||
$lines[] = "{$childIndent}{$key} => {$exported},";
|
||||
}
|
||||
}
|
||||
$lines[] = "{$closingIndent}]";
|
||||
return implode("\n", $lines);
|
||||
}
|
||||
|
||||
private static function exportScalar(mixed $value): string
|
||||
{
|
||||
if ($value === null) {
|
||||
return 'null';
|
||||
}
|
||||
if (is_bool($value)) {
|
||||
return $value ? 'true' : 'false';
|
||||
}
|
||||
if (is_int($value) || is_float($value)) {
|
||||
return (string)$value;
|
||||
}
|
||||
if (is_string($value)) {
|
||||
return "'" . str_replace(["\\", "'"], ["\\\\", "\\'"], $value) . "'";
|
||||
}
|
||||
|
||||
// Fallback to string casting for unexpected scalars.
|
||||
return "'" . str_replace(["\\", "'"], ["\\\\", "\\'"], (string)$value) . "'";
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+27
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Webman\Validation\Command\ValidatorGenerator\Support;
|
||||
|
||||
use Webman\Validation\Command\ValidatorGenerator\Contracts\SchemaIntrospectorInterface;
|
||||
use Webman\Validation\Command\ValidatorGenerator\Illuminate\MySqlInformationSchemaIntrospector;
|
||||
use Webman\Validation\Command\ValidatorGenerator\Illuminate\PostgresInformationSchemaIntrospector;
|
||||
use Webman\Validation\Command\ValidatorGenerator\Illuminate\SqlitePragmaIntrospector;
|
||||
use Webman\Validation\Command\ValidatorGenerator\Illuminate\SqlServerIntrospector;
|
||||
|
||||
final class SchemaIntrospectorFactory
|
||||
{
|
||||
public function createForDriver(string $driver): SchemaIntrospectorInterface
|
||||
{
|
||||
$driver = strtolower(trim($driver));
|
||||
|
||||
return match ($driver) {
|
||||
'mysql', 'mariadb' => new MySqlInformationSchemaIntrospector(),
|
||||
'pgsql', 'postgres', 'postgresql' => new PostgresInformationSchemaIntrospector(),
|
||||
'sqlite' => new SqlitePragmaIntrospector(),
|
||||
'sqlsrv' => new SqlServerIntrospector(),
|
||||
default => throw new \RuntimeException("Unsupported database driver: {$driver}"),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Webman\Validation\Command\ValidatorGenerator\Support;
|
||||
|
||||
final class ValidatorClassRenderer
|
||||
{
|
||||
/**
|
||||
* @param array<string, string> $rules
|
||||
* @param array<string, string> $messages
|
||||
* @param array<string, string> $attributes
|
||||
* @param array<string, list<string>> $scenes
|
||||
*/
|
||||
public function render(
|
||||
string $namespace,
|
||||
string $class,
|
||||
array $rules,
|
||||
array $messages = [],
|
||||
array $attributes = [],
|
||||
array $scenes = [],
|
||||
): string {
|
||||
$rulesCode = PhpArrayExporter::exportForProperty($rules, 1);
|
||||
$messagesCode = PhpArrayExporter::exportForProperty($messages, 1);
|
||||
$attributesCode = PhpArrayExporter::exportForProperty($attributes, 1);
|
||||
$scenesCode = PhpArrayExporter::exportForProperty($scenes, 1);
|
||||
|
||||
return <<<PHP
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace {$namespace};
|
||||
|
||||
use support\\validation\\Validator;
|
||||
|
||||
class {$class} extends Validator
|
||||
{
|
||||
protected array \$rules = {$rulesCode};
|
||||
|
||||
protected array \$messages = {$messagesCode};
|
||||
|
||||
protected array \$attributes = {$attributesCode};
|
||||
|
||||
protected array \$scenes = {$scenesCode};
|
||||
}
|
||||
|
||||
PHP;
|
||||
}
|
||||
}
|
||||
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Webman\Validation\Command\ValidatorGenerator\Support;
|
||||
|
||||
final class ValidatorFileWriter
|
||||
{
|
||||
public function write(string $file, string $content): void
|
||||
{
|
||||
$dir = \dirname($file);
|
||||
if (!is_dir($dir) && !mkdir($dir, 0777, true) && !is_dir($dir)) {
|
||||
throw new \RuntimeException("Failed to create directory: {$dir}");
|
||||
}
|
||||
|
||||
if (file_put_contents($file, $content) === false) {
|
||||
throw new \RuntimeException("Failed to write file: {$file}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+102
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Webman\Validation\Command\ValidatorGenerator\ThinkOrm;
|
||||
|
||||
use Webman\Validation\Command\ValidatorGenerator\Contracts\ConnectionResolverInterface;
|
||||
use Webman\Validation\Command\ValidatorGenerator\Contracts\SchemaConnectionInterface;
|
||||
|
||||
final class ThinkOrmConnectionResolver implements ConnectionResolverInterface
|
||||
{
|
||||
public function resolve(?string $connectionName = null): SchemaConnectionInterface
|
||||
{
|
||||
$thinkorm = config('think-orm');
|
||||
if (!is_array($thinkorm) || $thinkorm === []) {
|
||||
$alt = config('thinkorm');
|
||||
$thinkorm = is_array($alt) ? $alt : null;
|
||||
}
|
||||
if (!is_array($thinkorm)) {
|
||||
throw new \RuntimeException('Think-orm config not found: config("think-orm") or config("thinkorm").');
|
||||
}
|
||||
|
||||
$mainConnections = $thinkorm['connections'] ?? null;
|
||||
if (!is_array($mainConnections) || $mainConnections === []) {
|
||||
throw new \RuntimeException('Invalid think-orm config: connections must be a non-empty array.');
|
||||
}
|
||||
|
||||
$name = $connectionName;
|
||||
if ($name === null || trim($name) === '') {
|
||||
$default = $thinkorm['default'] ?? null;
|
||||
if (!is_string($default) || trim($default) === '') {
|
||||
throw new \RuntimeException('Think-orm connection name not provided and think-orm.default is not set.');
|
||||
}
|
||||
$name = trim($default);
|
||||
}
|
||||
|
||||
$name = trim((string)$name);
|
||||
$connKey = $name;
|
||||
$connections = $mainConnections;
|
||||
|
||||
if (str_starts_with($name, 'plugin.')) {
|
||||
// plugin.<plugin>.<connection>
|
||||
$parts = explode('.', $name, 3);
|
||||
$plugin = $parts[1] ?? '';
|
||||
$conn = $parts[2] ?? '';
|
||||
$plugin = is_string($plugin) ? trim($plugin) : '';
|
||||
$conn = is_string($conn) ? trim($conn) : '';
|
||||
if ($plugin === '' || $conn === '') {
|
||||
throw new \RuntimeException("Invalid plugin connection name: {$name}");
|
||||
}
|
||||
|
||||
$pluginCfg = config("plugin.$plugin.thinkorm");
|
||||
if (!is_array($pluginCfg) || $pluginCfg === []) {
|
||||
$alt = config("plugin.$plugin.think-orm");
|
||||
$pluginCfg = is_array($alt) ? $alt : [];
|
||||
}
|
||||
$pluginConnections = $pluginCfg['connections'] ?? null;
|
||||
if (is_array($pluginConnections) && $pluginConnections !== []) {
|
||||
$connections = $pluginConnections;
|
||||
$connKey = "plugin.$plugin.$conn";
|
||||
$name = $conn;
|
||||
} else {
|
||||
// No plugin think-orm connections: fallback to main project config.
|
||||
$connections = $mainConnections;
|
||||
$connKey = $conn;
|
||||
$name = $conn;
|
||||
}
|
||||
}
|
||||
|
||||
if (!array_key_exists($name, $connections)) {
|
||||
$available = implode(', ', array_keys($connections));
|
||||
throw new \RuntimeException("Think-orm connection not found: {$name}. Available connections: {$available}");
|
||||
}
|
||||
|
||||
/** @var array<string, mixed> $cfg */
|
||||
$cfg = is_array($connections[$name]) ? $connections[$name] : [];
|
||||
$driver = (string)($cfg['type'] ?? 'mysql');
|
||||
$database = isset($cfg['database']) ? (string)$cfg['database'] : null;
|
||||
|
||||
$connection = $this->connect($connKey);
|
||||
return new ThinkOrmSchemaConnection($connection, strtolower($driver), $database);
|
||||
}
|
||||
|
||||
private function connect(string $name): object
|
||||
{
|
||||
// Think-orm v2
|
||||
if (class_exists(\support\think\Db::class)) {
|
||||
/** @var object $conn */
|
||||
$conn = \support\think\Db::connect($name);
|
||||
return $conn;
|
||||
}
|
||||
|
||||
// Think-orm v1
|
||||
if (class_exists(\think\facade\Db::class)) {
|
||||
/** @var object $conn */
|
||||
$conn = \think\facade\Db::connect($name);
|
||||
return $conn;
|
||||
}
|
||||
|
||||
throw new \RuntimeException('Think-orm is not installed. Missing support\\think\\Db or think\\facade\\Db.');
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+61
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Webman\Validation\Command\ValidatorGenerator\ThinkOrm;
|
||||
|
||||
use Webman\Validation\Command\ValidatorGenerator\Contracts\SchemaConnectionInterface;
|
||||
|
||||
final class ThinkOrmSchemaConnection implements SchemaConnectionInterface
|
||||
{
|
||||
/**
|
||||
* @param object $connection Think-orm connection instance.
|
||||
*/
|
||||
public function __construct(
|
||||
private readonly object $connection,
|
||||
private readonly string $driver,
|
||||
private readonly ?string $database,
|
||||
) {
|
||||
}
|
||||
|
||||
public function driverName(): string
|
||||
{
|
||||
return $this->driver;
|
||||
}
|
||||
|
||||
public function databaseName(): ?string
|
||||
{
|
||||
return $this->database;
|
||||
}
|
||||
|
||||
public function select(string $sql, array $bindings = []): array
|
||||
{
|
||||
// Think-orm uses `query` for SELECT statements.
|
||||
if (!method_exists($this->connection, 'query')) {
|
||||
throw new \RuntimeException('Think-orm connection does not support query().');
|
||||
}
|
||||
|
||||
/** @var mixed $rows */
|
||||
$rows = $this->connection->query($sql, $bindings);
|
||||
if (!is_array($rows)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$result = [];
|
||||
foreach ($rows as $row) {
|
||||
if (is_array($row)) {
|
||||
$result[] = $row;
|
||||
continue;
|
||||
}
|
||||
if (is_object($row)) {
|
||||
/** @var array<string, mixed> $arr */
|
||||
$arr = get_object_vars($row);
|
||||
$result[] = $arr;
|
||||
continue;
|
||||
}
|
||||
$result[] = ['value' => $row];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Webman\Validation\Exception;
|
||||
|
||||
use Webman\Exception\BusinessException;
|
||||
|
||||
class ValidationException extends BusinessException
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Webman\Validation\Factory;
|
||||
|
||||
use Illuminate\Container\Container;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Filesystem\Filesystem;
|
||||
use Illuminate\Translation\FileLoader;
|
||||
use Illuminate\Translation\Translator;
|
||||
use Illuminate\Validation\Factory;
|
||||
use Illuminate\Validation\DatabasePresenceVerifier;
|
||||
use Illuminate\Validation\DatabasePresenceVerifierInterface;
|
||||
use Illuminate\Support\Facades\Facade;
|
||||
|
||||
final class ValidationFactory
|
||||
{
|
||||
private static ?Factory $factory = null;
|
||||
private static bool $presenceVerifierBound = false;
|
||||
|
||||
public static function getFactory(): Factory
|
||||
{
|
||||
if (self::$factory === null) {
|
||||
self::$factory = self::createFactory();
|
||||
}
|
||||
|
||||
if (!self::$presenceVerifierBound) {
|
||||
self::bindPresenceVerifier(self::$factory);
|
||||
}
|
||||
|
||||
return self::$factory;
|
||||
}
|
||||
|
||||
private static function createFactory(): Factory
|
||||
{
|
||||
$loader = self::createLoader();
|
||||
$translator = new Translator($loader, self::getLocale());
|
||||
|
||||
$fallback = self::getFallbackLocale();
|
||||
if ($fallback !== '') {
|
||||
$translator->setFallback($fallback);
|
||||
}
|
||||
|
||||
$factory = new Factory($translator);
|
||||
self::bindFacadeRoot($factory);
|
||||
self::bindPresenceVerifier($factory);
|
||||
return $factory;
|
||||
}
|
||||
|
||||
private static function bindFacadeRoot(Factory $factory): void
|
||||
{
|
||||
if (Facade::getFacadeApplication() !== null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$container = new Container();
|
||||
$container->instance('validator', $factory);
|
||||
Facade::setFacadeApplication($container);
|
||||
}
|
||||
|
||||
private static function bindPresenceVerifier(Factory $factory): void
|
||||
{
|
||||
try {
|
||||
if ($factory->getPresenceVerifier() instanceof DatabasePresenceVerifierInterface) {
|
||||
self::$presenceVerifierBound = true;
|
||||
return;
|
||||
}
|
||||
} catch (\Throwable) {
|
||||
// Verifier not yet set; continue to try binding.
|
||||
}
|
||||
|
||||
if (!class_exists(DatabasePresenceVerifier::class) || !class_exists(Model::class)) {
|
||||
self::$presenceVerifierBound = true;
|
||||
return;
|
||||
}
|
||||
|
||||
$resolver = Model::getConnectionResolver();
|
||||
if ($resolver === null && class_exists('support\\Model')) {
|
||||
$resolver = Model::getConnectionResolver();
|
||||
}
|
||||
if ($resolver === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$factory->setPresenceVerifier(new DatabasePresenceVerifier($resolver));
|
||||
self::$presenceVerifierBound = true;
|
||||
}
|
||||
|
||||
private static function createLoader(): FileLoader
|
||||
{
|
||||
$filesystem = new Filesystem();
|
||||
|
||||
$packagePath = self::getPackageTranslationsPath();
|
||||
$illuminatePath = self::getIlluminateTranslationsPath();
|
||||
$projectPaths = self::getProjectTranslationsPaths();
|
||||
|
||||
$orderedPaths = array_values(array_filter([
|
||||
$packagePath,
|
||||
$illuminatePath,
|
||||
...$projectPaths,
|
||||
], fn ($path) => $path !== ''));
|
||||
|
||||
$basePath = $orderedPaths[0] ?? '';
|
||||
$loader = new FileLoader($filesystem, $basePath);
|
||||
|
||||
foreach ($orderedPaths as $path) {
|
||||
if ($path !== $basePath) {
|
||||
$loader->addPath($path);
|
||||
}
|
||||
}
|
||||
|
||||
return $loader;
|
||||
}
|
||||
|
||||
private static function getLocale(): string
|
||||
{
|
||||
if (self::canUseLocaleFunction() && function_exists('locale')) {
|
||||
$locale = locale();
|
||||
if (is_string($locale) && $locale !== '') {
|
||||
return $locale;
|
||||
}
|
||||
}
|
||||
|
||||
$locale = config('translation.locale', 'en');
|
||||
return is_string($locale) && $locale !== '' ? $locale : 'en';
|
||||
}
|
||||
|
||||
private static function getFallbackLocale(): string
|
||||
{
|
||||
$fallback = config('translation.fallback_locale', []);
|
||||
if (is_array($fallback)) {
|
||||
$fallback = $fallback[0] ?? '';
|
||||
}
|
||||
return is_string($fallback) ? $fallback : '';
|
||||
}
|
||||
|
||||
private static function getProjectTranslationsPaths(): array
|
||||
{
|
||||
$path = config('translation.path', '');
|
||||
$paths = is_array($path) ? $path : [$path];
|
||||
|
||||
$result = [];
|
||||
foreach ($paths as $item) {
|
||||
if (is_string($item) && $item !== '' && is_dir($item)) {
|
||||
$result[] = $item;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private static function canUseLocaleFunction(): bool
|
||||
{
|
||||
$path = config('translation.path', '');
|
||||
return is_string($path) && $path !== '' && is_dir($path);
|
||||
}
|
||||
|
||||
private static function getPackageTranslationsPath(): string
|
||||
{
|
||||
$path = dirname(__DIR__, 2) . '/resources/lang';
|
||||
return is_dir($path) ? $path : '';
|
||||
}
|
||||
|
||||
private static function getIlluminateTranslationsPath(): string
|
||||
{
|
||||
$path = dirname(__DIR__, 2) . '/vendor/illuminate/translation/lang';
|
||||
return is_dir($path) ? $path : '';
|
||||
}
|
||||
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
namespace Webman\Validation;
|
||||
|
||||
class Install
|
||||
{
|
||||
const WEBMAN_PLUGIN = true;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected static array $pathRelation = [
|
||||
'config/plugin/webman/validation' => 'config/plugin/webman/validation',
|
||||
];
|
||||
|
||||
/**
|
||||
* Install
|
||||
* @return void
|
||||
*/
|
||||
public static function install()
|
||||
{
|
||||
static::installByRelation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstall
|
||||
* @return void
|
||||
*/
|
||||
public static function uninstall()
|
||||
{
|
||||
self::uninstallByRelation();
|
||||
}
|
||||
|
||||
/**
|
||||
* installByRelation
|
||||
* @return void
|
||||
*/
|
||||
public static function installByRelation()
|
||||
{
|
||||
foreach (static::$pathRelation as $source => $dest) {
|
||||
if ($pos = strrpos($dest, '/')) {
|
||||
$parent_dir = base_path().'/'.substr($dest, 0, $pos);
|
||||
if (!is_dir($parent_dir)) {
|
||||
mkdir($parent_dir, 0777, true);
|
||||
}
|
||||
}
|
||||
//symlink(__DIR__ . "/$source", base_path()."/$dest");
|
||||
copy_dir(__DIR__ . "/$source", base_path()."/$dest");
|
||||
echo "Create $dest
|
||||
";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* uninstallByRelation
|
||||
* @return void
|
||||
*/
|
||||
public static function uninstallByRelation()
|
||||
{
|
||||
foreach (static::$pathRelation as $source => $dest) {
|
||||
$path = base_path()."/$dest";
|
||||
if (!is_dir($path) && !is_file($path)) {
|
||||
continue;
|
||||
}
|
||||
echo "Remove $dest
|
||||
";
|
||||
if (is_file($path) || is_link($path)) {
|
||||
unlink($path);
|
||||
continue;
|
||||
}
|
||||
remove_dir($path);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+417
@@ -0,0 +1,417 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Webman\Validation;
|
||||
|
||||
use Closure;
|
||||
use InvalidArgumentException;
|
||||
use ReflectionFunction;
|
||||
use ReflectionFunctionAbstract;
|
||||
use ReflectionMethod;
|
||||
use ReflectionNamedType;
|
||||
use ReflectionParameter;
|
||||
use ReflectionUnionType;
|
||||
use Webman\Http\Request;
|
||||
use Webman\Validation\Annotation\Param;
|
||||
use Webman\Validation\Annotation\Validate;
|
||||
|
||||
final class Middleware
|
||||
{
|
||||
private static array $metadataCache = [];
|
||||
|
||||
public function process(Request $request, callable $handler)
|
||||
{
|
||||
$metadata = $this->resolveMetadata($request);
|
||||
if ($metadata === null || !$metadata['has']) {
|
||||
return $handler($request);
|
||||
}
|
||||
|
||||
$defaultData = $this->getRequestData($request);
|
||||
|
||||
$this->handleMethodValidation($request, $metadata['methods'], $defaultData);
|
||||
$this->handleParamValidation($request, $metadata['params'], $defaultData);
|
||||
|
||||
return $handler($request);
|
||||
}
|
||||
|
||||
private function resolveMetadata(Request $request): ?array
|
||||
{
|
||||
$controller = $request->controller ?: '';
|
||||
$action = $request->action ?: '';
|
||||
|
||||
if ($controller !== '' && $action !== '' && class_exists($controller)) {
|
||||
return $this->getMethodMetadata($controller, $action);
|
||||
}
|
||||
|
||||
return $this->getCallableMetadata($request);
|
||||
}
|
||||
|
||||
private function handleMethodValidation(Request $request, array $methods, array $defaultData): void
|
||||
{
|
||||
if ($methods === []) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($methods as $config) {
|
||||
$data = $this->resolveRequestData($request, $config->in, $defaultData);
|
||||
$this->validateMethod($config, $data);
|
||||
}
|
||||
}
|
||||
|
||||
private function handleParamValidation(Request $request, array $params, array $defaultData): void
|
||||
{
|
||||
if ($params === []) {
|
||||
return;
|
||||
}
|
||||
|
||||
$allData = [];
|
||||
$allRules = [];
|
||||
$allMessages = [];
|
||||
$allAttributes = [];
|
||||
|
||||
foreach ($params as $item) {
|
||||
$name = $item['name'];
|
||||
/** @var \Webman\Validation\Annotation\Param $config */
|
||||
$config = $item['config'];
|
||||
|
||||
$dataForParam = $this->resolveRequestData($request, $config->in, $defaultData);
|
||||
$value = $dataForParam[$name] ?? null;
|
||||
if ($value === null && $item['hasDefault']) {
|
||||
$value = $item['default'];
|
||||
}
|
||||
|
||||
$allData[$name] = $value;
|
||||
$allRules[$name] = $config->rules;
|
||||
|
||||
// 处理 messages,确保 key 带有字段前缀,避免冲突
|
||||
foreach ($config->messages as $key => $message) {
|
||||
if (!str_contains($key, '.')) {
|
||||
// 没有点号的 key 自动添加字段名前缀
|
||||
$key = $name . '.' . $key;
|
||||
}
|
||||
$allMessages[$key] = $message;
|
||||
}
|
||||
|
||||
if ($config->attribute !== '') {
|
||||
$allAttributes[$name] = $config->attribute;
|
||||
}
|
||||
}
|
||||
|
||||
Validator::make($allData, $allRules, $allMessages, $allAttributes)->validate();
|
||||
}
|
||||
|
||||
private function validateMethod(Validate $config, array $data): void
|
||||
{
|
||||
if ($config->validator !== null) {
|
||||
if ($config->rules !== []) {
|
||||
throw new InvalidArgumentException('Validate cannot set both validator and rules.');
|
||||
}
|
||||
if (!class_exists($config->validator)) {
|
||||
throw new InvalidArgumentException("Validator class not found: {$config->validator}");
|
||||
}
|
||||
if (!is_subclass_of($config->validator, \Webman\Validation\Validator::class)) {
|
||||
throw new InvalidArgumentException("Validator must extend Webman\\Validation\\Validator (or support\\validation\\Validator): {$config->validator}");
|
||||
}
|
||||
|
||||
$validator = $config->validator::make($data);
|
||||
if ($config->scene !== null) {
|
||||
$validator = $validator->withScene($config->scene);
|
||||
}
|
||||
$validator->validate();
|
||||
return;
|
||||
}
|
||||
|
||||
if ($config->rules === []) {
|
||||
return;
|
||||
}
|
||||
|
||||
Validator::make($data, $config->rules, $config->messages, $config->attributes)->validate();
|
||||
}
|
||||
|
||||
private function getRequestData(Request $request): array
|
||||
{
|
||||
$routeParams = $request->route ? $request->route->param() : [];
|
||||
if (!is_array($routeParams)) {
|
||||
$routeParams = [];
|
||||
}
|
||||
return array_merge($request->all() ?: [], $routeParams);
|
||||
}
|
||||
|
||||
private function resolveRequestData(Request $request, string|array|null $in, array $defaultData): array
|
||||
{
|
||||
if ($in === null || $in === []) {
|
||||
return $defaultData;
|
||||
}
|
||||
|
||||
$parts = is_array($in) ? $in : [$in];
|
||||
$data = [];
|
||||
foreach ($parts as $part) {
|
||||
$data = array_merge($data, $this->getRequestPartData($request, $part));
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
private function getRequestPartData(Request $request, mixed $part): array
|
||||
{
|
||||
if (!is_string($part) || $part === '') {
|
||||
throw new InvalidArgumentException('Validate/Param in must be a non-empty string or string array.');
|
||||
}
|
||||
|
||||
return match ($part) {
|
||||
'query' => $request->get() ?: [],
|
||||
'body' => $request->post() ?: [],
|
||||
'path' => $this->getPathParams($request),
|
||||
default => throw new InvalidArgumentException("Unsupported in value: {$part}. Only query|body|path are supported."),
|
||||
};
|
||||
}
|
||||
|
||||
private function getPathParams(Request $request): array
|
||||
{
|
||||
$routeParams = $request->route ? $request->route->param() : [];
|
||||
return is_array($routeParams) ? $routeParams : [];
|
||||
}
|
||||
|
||||
private function getMethodMetadata(string $controller, string $action): ?array
|
||||
{
|
||||
$key = $controller . '::' . $action;
|
||||
if (isset(self::$metadataCache[$key])) {
|
||||
return self::$metadataCache[$key];
|
||||
}
|
||||
|
||||
if (!method_exists($controller, $action)) {
|
||||
return self::$metadataCache[$key] = null;
|
||||
}
|
||||
|
||||
$reflection = new ReflectionMethod($controller, $action);
|
||||
|
||||
return self::$metadataCache[$key] = $this->buildMetadataFromReflection($reflection, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve metadata for closure / named-function route handlers.
|
||||
*/
|
||||
private function getCallableMetadata(Request $request): ?array
|
||||
{
|
||||
$route = $request->route;
|
||||
if (!$route || !method_exists($route, 'getCallback')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$callback = $route->getCallback();
|
||||
|
||||
// Only handle closures and named function strings.
|
||||
if (!$callback instanceof Closure && !is_string($callback)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (is_string($callback) && !function_exists($callback)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$cacheKey = is_string($callback)
|
||||
? 'func::' . $callback
|
||||
: 'callable::' . $route->getPath();
|
||||
|
||||
if (isset(self::$metadataCache[$cacheKey])) {
|
||||
return self::$metadataCache[$cacheKey];
|
||||
}
|
||||
|
||||
$reflection = new ReflectionFunction($callback);
|
||||
|
||||
// Named functions support function-level #[Validate]; closures do not.
|
||||
$supportsMethodAttributes = is_string($callback);
|
||||
|
||||
return self::$metadataCache[$cacheKey] = $this->buildMetadataFromReflection(
|
||||
$reflection,
|
||||
$supportsMethodAttributes
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build validation metadata from a ReflectionMethod or ReflectionFunction.
|
||||
*/
|
||||
private function buildMetadataFromReflection(
|
||||
ReflectionFunctionAbstract $reflection,
|
||||
bool $supportsMethodAttributes
|
||||
): array {
|
||||
$methods = [];
|
||||
if ($supportsMethodAttributes) {
|
||||
foreach ($reflection->getAttributes(Validate::class, \ReflectionAttribute::IS_INSTANCEOF) as $attribute) {
|
||||
$methods[] = $attribute->newInstance();
|
||||
}
|
||||
}
|
||||
|
||||
$parameters = $reflection->getParameters();
|
||||
$hasAnyParamAttribute = false;
|
||||
foreach ($parameters as $parameter) {
|
||||
if ($parameter->getAttributes(Param::class, \ReflectionAttribute::IS_INSTANCEOF) !== []) {
|
||||
$hasAnyParamAttribute = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$inferWhenAnnotationsPresent = $methods !== [] || $hasAnyParamAttribute;
|
||||
|
||||
$params = [];
|
||||
foreach ($parameters as $parameter) {
|
||||
$paramConfig = $this->resolveParamConfig($parameter, $inferWhenAnnotationsPresent);
|
||||
if ($paramConfig === null) {
|
||||
continue;
|
||||
}
|
||||
$hasDefault = $parameter->isDefaultValueAvailable();
|
||||
$params[] = [
|
||||
'name' => $parameter->getName(),
|
||||
'config' => $paramConfig,
|
||||
'hasDefault' => $hasDefault,
|
||||
'default' => $hasDefault ? $parameter->getDefaultValue() : null,
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'has' => $methods !== [] || $params !== [],
|
||||
'methods' => $methods,
|
||||
'params' => $params,
|
||||
];
|
||||
}
|
||||
|
||||
private function resolveParamConfig(ReflectionParameter $parameter, bool $inferWhenAnnotationsPresent): ?Param
|
||||
{
|
||||
$attributes = $parameter->getAttributes(Param::class, \ReflectionAttribute::IS_INSTANCEOF);
|
||||
if ($attributes !== []) {
|
||||
/** @var Param $config */
|
||||
$config = $attributes[0]->newInstance();
|
||||
|
||||
// Auto-complete rules based on parameter signature.
|
||||
$completedRules = $this->completeRulesFromParameter($parameter, $config->rules);
|
||||
if ($completedRules !== $config->rules) {
|
||||
return new Param(
|
||||
rules: $completedRules,
|
||||
messages: $config->messages,
|
||||
attribute: $config->attribute,
|
||||
in: $config->in
|
||||
);
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
if (!$inferWhenAnnotationsPresent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->shouldSkipParameter($parameter)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$rules = $this->inferRulesFromParameter($parameter);
|
||||
return new Param(rules: $rules);
|
||||
}
|
||||
|
||||
private function shouldSkipParameter(ReflectionParameter $parameter): bool
|
||||
{
|
||||
$type = $parameter->getType();
|
||||
if (!$type instanceof ReflectionNamedType || $type->isBuiltin()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$name = $type->getName();
|
||||
if ($name === '') {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Skip framework request injection.
|
||||
if (is_a($name, Request::class, true)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Skip other class-typed parameters by default (services/DTOs/etc).
|
||||
return true;
|
||||
}
|
||||
|
||||
private function inferRulesFromParameter(ReflectionParameter $parameter): string|array
|
||||
{
|
||||
$rules = [];
|
||||
|
||||
$type = $parameter->getType();
|
||||
$isNullable = $type instanceof ReflectionNamedType && $type->allowsNull();
|
||||
|
||||
// Required when: no default value AND not nullable.
|
||||
if (!$parameter->isDefaultValueAvailable() && !$isNullable) {
|
||||
$rules[] = 'required';
|
||||
}
|
||||
|
||||
if ($type instanceof ReflectionUnionType) {
|
||||
// Union types are not inferred by default (developer can explicitly use #[Param]).
|
||||
return implode('|', $rules);
|
||||
}
|
||||
|
||||
if ($type instanceof ReflectionNamedType && $type->isBuiltin()) {
|
||||
$mapped = $this->mapBuiltinTypeToRule($type->getName());
|
||||
if ($mapped !== '') {
|
||||
$rules[] = $mapped;
|
||||
}
|
||||
if ($isNullable) {
|
||||
$rules[] = 'nullable';
|
||||
}
|
||||
}
|
||||
|
||||
return implode('|', $rules);
|
||||
}
|
||||
|
||||
private function completeRulesFromParameter(ReflectionParameter $parameter, string|array $existingRules): string|array
|
||||
{
|
||||
$isArray = is_array($existingRules);
|
||||
$rulesList = $isArray
|
||||
? $existingRules
|
||||
: ($existingRules !== '' ? explode('|', $existingRules) : []);
|
||||
|
||||
$type = $parameter->getType();
|
||||
$isNullable = $type instanceof ReflectionNamedType && $type->allowsNull();
|
||||
|
||||
// Build rule name set for O(1) lookups instead of iterating per check.
|
||||
$ruleNames = [];
|
||||
foreach ($rulesList as $rule) {
|
||||
$ruleNames[explode(':', $rule, 2)[0]] = true;
|
||||
}
|
||||
|
||||
// Auto-complete 'required' if: no default value, not nullable, and not already present.
|
||||
if (!$parameter->isDefaultValueAvailable() && !$isNullable && !isset($ruleNames['required'])) {
|
||||
array_unshift($rulesList, 'required');
|
||||
$ruleNames['required'] = true;
|
||||
}
|
||||
|
||||
// Auto-complete type rule if: has builtin type and no type rule present.
|
||||
if ($type instanceof ReflectionNamedType && $type->isBuiltin()) {
|
||||
$mappedRule = $this->mapBuiltinTypeToRule($type->getName());
|
||||
if ($mappedRule !== '' && !isset($ruleNames[$mappedRule])) {
|
||||
// Insert type rule after 'required' if present, otherwise at the beginning.
|
||||
$requiredIndex = array_search('required', $rulesList, true);
|
||||
if ($requiredIndex !== false) {
|
||||
array_splice($rulesList, $requiredIndex + 1, 0, $mappedRule);
|
||||
} else {
|
||||
array_unshift($rulesList, $mappedRule);
|
||||
}
|
||||
$ruleNames[$mappedRule] = true;
|
||||
}
|
||||
|
||||
// Auto-complete 'nullable' if: type is nullable and not already present.
|
||||
if ($isNullable && !isset($ruleNames['nullable'])) {
|
||||
$rulesList[] = 'nullable';
|
||||
}
|
||||
}
|
||||
|
||||
return $isArray ? $rulesList : implode('|', $rulesList);
|
||||
}
|
||||
|
||||
private function mapBuiltinTypeToRule(string $type): string
|
||||
{
|
||||
return match ($type) {
|
||||
'string' => 'string',
|
||||
'int' => 'integer',
|
||||
'float' => 'numeric',
|
||||
'bool' => 'boolean',
|
||||
'array' => 'array',
|
||||
default => '',
|
||||
};
|
||||
}
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Webman\Validation\Tests;
|
||||
|
||||
use Illuminate\Validation\Rule as IlluminateRule;
|
||||
use Illuminate\Validation\Rules\In;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use support\validation\Rule;
|
||||
use support\validation\Validator;
|
||||
use support\validation\ValidationException;
|
||||
|
||||
final class RuleTest extends TestCase
|
||||
{
|
||||
public function testRuleExtendsIlluminateRule(): void
|
||||
{
|
||||
$this->assertTrue(is_subclass_of(Rule::class, IlluminateRule::class));
|
||||
}
|
||||
|
||||
public function testRuleInProxy(): void
|
||||
{
|
||||
$rule = Rule::in(['a', 'b']);
|
||||
$this->assertInstanceOf(In::class, $rule);
|
||||
}
|
||||
|
||||
public function testRuleInPassesValidation(): void
|
||||
{
|
||||
$validated = Validator::make(
|
||||
['status' => 'enabled'],
|
||||
['status' => ['required', Rule::in(['enabled', 'disabled'])]]
|
||||
)->validate();
|
||||
|
||||
$this->assertSame(['status' => 'enabled'], $validated);
|
||||
}
|
||||
|
||||
public function testRuleInFailsValidation(): void
|
||||
{
|
||||
try {
|
||||
Validator::make(
|
||||
['status' => 'unknown'],
|
||||
['status' => ['required', Rule::in(['enabled', 'disabled'])]],
|
||||
['status.in' => 'Status invalid']
|
||||
)->validate();
|
||||
$this->fail('Expected ValidationException was not thrown.');
|
||||
} catch (ValidationException $exception) {
|
||||
$this->assertSame('Status invalid', $exception->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function testRuleAnyOfPassesValidation(): void
|
||||
{
|
||||
$validated = Validator::make(
|
||||
['username' => 'user@example.com'],
|
||||
['username' => [
|
||||
'required',
|
||||
Rule::anyOf([
|
||||
['string', 'email'],
|
||||
['string', 'alpha_dash', 'min:6'],
|
||||
]),
|
||||
]]
|
||||
)->validate();
|
||||
|
||||
$this->assertSame(['username' => 'user@example.com'], $validated);
|
||||
}
|
||||
|
||||
public function testRuleAnyOfFailsValidation(): void
|
||||
{
|
||||
try {
|
||||
Validator::make(
|
||||
['username' => 'a?'],
|
||||
['username' => [
|
||||
'required',
|
||||
Rule::anyOf([
|
||||
['string', 'email'],
|
||||
['string', 'alpha_dash', 'min:6'],
|
||||
]),
|
||||
]],
|
||||
['username.any_of' => 'Username invalid']
|
||||
)->validate();
|
||||
$this->fail('Expected ValidationException was not thrown.');
|
||||
} catch (ValidationException $exception) {
|
||||
$this->assertSame('Username invalid', $exception->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,142 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Webman\Validation\Tests;
|
||||
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use ReflectionProperty;
|
||||
use Webman\Validation\Factory\ValidationFactory;
|
||||
use support\validation\Validator;
|
||||
use support\validation\ValidationException;
|
||||
|
||||
final class TranslationTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @return array<string, array{string, string}>
|
||||
*/
|
||||
public static function localeEmailMessageProvider(): array
|
||||
{
|
||||
return [
|
||||
'zh_CN' => ['zh_CN', '必须是有效的邮箱地址'],
|
||||
'zh_TW' => ['zh_TW', '必須是有效的電子郵件地址'],
|
||||
'en' => ['en', 'must be a valid email address'],
|
||||
'ja' => ['ja', '有効なメールアドレスである必要があります'],
|
||||
'ko' => ['ko', '유효한 이메일 주소여야 합니다'],
|
||||
'fr' => ['fr', 'doit être une adresse e-mail valide'],
|
||||
'de' => ['de', 'muss eine gültige E-Mail-Adresse sein'],
|
||||
'es' => ['es', 'debe ser una dirección de correo electrónico válida'],
|
||||
'pt_BR' => ['pt_BR', 'deve ser um endereço de e-mail válido'],
|
||||
'ru' => ['ru', 'должно быть действительным адресом электронной почты'],
|
||||
'vi' => ['vi', 'phải là địa chỉ email hợp lệ'],
|
||||
'tr' => ['tr', 'geçerli bir e-posta adresi olmalıdır'],
|
||||
'id' => ['id', 'harus berupa alamat email yang valid'],
|
||||
'th' => ['th', 'ต้องเป็นที่อยู่อีเมลที่ถูกต้อง'],
|
||||
];
|
||||
}
|
||||
|
||||
#[DataProvider('localeEmailMessageProvider')]
|
||||
public function testValidationMessageInLocale(string $locale, string $expectedSubstring): void
|
||||
{
|
||||
$packageLangPath = dirname(__DIR__, 2) . '/resources/lang';
|
||||
if (!is_dir($packageLangPath) || !is_dir($packageLangPath . '/' . $locale)) {
|
||||
$this->markTestSkipped("Locale {$locale} not found in package resources/lang.");
|
||||
}
|
||||
|
||||
validation_test_set_config([
|
||||
'translation' => [
|
||||
'path' => $packageLangPath,
|
||||
'locale' => $locale,
|
||||
'fallback_locale' => [$locale],
|
||||
],
|
||||
]);
|
||||
if (function_exists('locale')) {
|
||||
locale($locale);
|
||||
}
|
||||
$this->resetTranslationInstance();
|
||||
$this->resetFactory();
|
||||
|
||||
try {
|
||||
Validator::make(['email' => 'bad-email'], ['email' => 'required|email'])->validate();
|
||||
$this->fail('Expected ValidationException was not thrown.');
|
||||
} catch (ValidationException $exception) {
|
||||
$this->assertStringContainsString(
|
||||
$expectedSubstring,
|
||||
$exception->getMessage(),
|
||||
"Locale {$locale}: expected message to contain '{$expectedSubstring}'"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function testLocalTranslationsOverridePackage(): void
|
||||
{
|
||||
if (!class_exists(\Symfony\Component\Translation\Translator::class)) {
|
||||
$this->markTestSkipped('symfony/translation is not installed.');
|
||||
}
|
||||
|
||||
validation_test_set_config([
|
||||
'translation' => [
|
||||
'path' => $this->fixturePath('translations'),
|
||||
'locale' => 'zh_CN',
|
||||
'fallback_locale' => ['zh_CN'],
|
||||
],
|
||||
]);
|
||||
if (function_exists('locale')) {
|
||||
locale('zh_CN');
|
||||
}
|
||||
$this->resetTranslationInstance();
|
||||
$this->resetFactory();
|
||||
|
||||
try {
|
||||
Validator::make(['email' => 'bad-email'], ['email' => 'required|email'])->validate();
|
||||
$this->fail('Expected ValidationException was not thrown.');
|
||||
} catch (ValidationException $exception) {
|
||||
$this->assertSame('[LOCAL_ZH] email invalid.', $exception->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function testFallbackToPackageTranslations(): void
|
||||
{
|
||||
validation_test_set_config([
|
||||
'translation' => [
|
||||
'path' => $this->fixturePath('empty'),
|
||||
'locale' => 'en',
|
||||
'fallback_locale' => ['en'],
|
||||
],
|
||||
]);
|
||||
if (function_exists('locale')) {
|
||||
locale('en');
|
||||
}
|
||||
$this->resetTranslationInstance();
|
||||
$this->resetFactory();
|
||||
|
||||
try {
|
||||
Validator::make(['email' => 'bad-email'], ['email' => 'required|email'])->validate();
|
||||
$this->fail('Expected ValidationException was not thrown.');
|
||||
} catch (ValidationException $exception) {
|
||||
$this->assertSame('The email field must be a valid email address.', $exception->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private function resetFactory(): void
|
||||
{
|
||||
$property = new ReflectionProperty(ValidationFactory::class, 'factory');
|
||||
$property->setAccessible(true);
|
||||
$property->setValue(null, null);
|
||||
}
|
||||
|
||||
private function resetTranslationInstance(): void
|
||||
{
|
||||
if (!class_exists(\support\Translation::class)) {
|
||||
return;
|
||||
}
|
||||
$property = new ReflectionProperty(\support\Translation::class, 'instance');
|
||||
$property->setAccessible(true);
|
||||
$property->setValue(null, []);
|
||||
}
|
||||
|
||||
private function fixturePath(string $name): string
|
||||
{
|
||||
return __DIR__ . '/fixtures/' . $name;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Webman\Validation\Tests;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use support\validation\Validator as SupportValidator;
|
||||
use support\validation\ValidationException as SupportValidationException;
|
||||
use Webman\Validation\Validator as CoreValidator;
|
||||
|
||||
final class ValidatorExceptionTest extends TestCase
|
||||
{
|
||||
public function test_core_validator_uses_support_validation_exception_by_default(): void
|
||||
{
|
||||
$this->expectException(SupportValidationException::class);
|
||||
|
||||
CoreValidator::make(
|
||||
['name' => null],
|
||||
['name' => 'required']
|
||||
)->validate();
|
||||
}
|
||||
|
||||
public function test_support_validator_uses_support_validation_exception_by_default(): void
|
||||
{
|
||||
$this->expectException(SupportValidationException::class);
|
||||
|
||||
SupportValidator::make(
|
||||
['name' => null],
|
||||
['name' => 'required']
|
||||
)->validate();
|
||||
}
|
||||
|
||||
public function test_exception_override_uses_custom_exception(): void
|
||||
{
|
||||
$this->expectException(\RuntimeException::class);
|
||||
|
||||
CoreValidator::make(
|
||||
['name' => null],
|
||||
['name' => 'required']
|
||||
)
|
||||
->withException(\RuntimeException::class)
|
||||
->validate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Webman\Validation\Tests;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use support\validation\ValidationException;
|
||||
use support\validation\Validator as SupportValidator;
|
||||
|
||||
final class ValidatorPublicMethodsTest extends TestCase
|
||||
{
|
||||
public function testOverrideRulesMethodIsUsed(): void
|
||||
{
|
||||
$validator = OverrideRulesValidator::make(['email' => 'not-an-email']);
|
||||
|
||||
$this->expectException(ValidationException::class);
|
||||
$validator->validate();
|
||||
}
|
||||
|
||||
public function testOverrideMessagesMethodIsUsed(): void
|
||||
{
|
||||
$validator = OverrideMessagesValidator::make([]);
|
||||
|
||||
$this->expectException(ValidationException::class);
|
||||
$this->expectExceptionMessage('Custom required message');
|
||||
$validator->validate();
|
||||
}
|
||||
|
||||
public function testOverrideAttributesMethodIsUsed(): void
|
||||
{
|
||||
$validator = OverrideAttributesValidator::make([]);
|
||||
|
||||
$this->expectException(ValidationException::class);
|
||||
$this->expectExceptionMessage('E-mail is required');
|
||||
$validator->validate();
|
||||
}
|
||||
|
||||
public function testOverrideDataMethodIsUsed(): void
|
||||
{
|
||||
$validated = OverrideDataValidator::make(['email' => 'not-an-email'])->validate();
|
||||
$this->assertSame(['email' => 'user@example.com'], $validated);
|
||||
}
|
||||
|
||||
public function testReuseRulesFromAnotherValidatorViaPublicMethod(): void
|
||||
{
|
||||
$validated = ReuseRulesValidator::make(['email' => 'user@example.com'])->validate();
|
||||
$this->assertSame(['email' => 'user@example.com'], $validated);
|
||||
}
|
||||
}
|
||||
|
||||
final class OverrideRulesValidator extends SupportValidator
|
||||
{
|
||||
protected array $rules = [
|
||||
'dummy' => 'nullable',
|
||||
];
|
||||
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'email' => 'required|email',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
final class OverrideMessagesValidator extends SupportValidator
|
||||
{
|
||||
protected array $rules = [
|
||||
'email' => 'required',
|
||||
];
|
||||
|
||||
public function messages(): array
|
||||
{
|
||||
return [
|
||||
'email.required' => 'Custom required message',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
final class OverrideAttributesValidator extends SupportValidator
|
||||
{
|
||||
protected array $rules = [
|
||||
'email' => 'required',
|
||||
];
|
||||
|
||||
public function messages(): array
|
||||
{
|
||||
return [
|
||||
'email.required' => ':attribute is required',
|
||||
];
|
||||
}
|
||||
|
||||
public function attributes(): array
|
||||
{
|
||||
return [
|
||||
'email' => 'E-mail',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
final class OverrideDataValidator extends SupportValidator
|
||||
{
|
||||
protected array $rules = [
|
||||
'email' => 'required|email',
|
||||
];
|
||||
|
||||
public function data(): array
|
||||
{
|
||||
return [
|
||||
'email' => 'user@example.com',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
final class RulesSourceValidator extends SupportValidator
|
||||
{
|
||||
protected array $rules = [
|
||||
'email' => 'required|email',
|
||||
];
|
||||
}
|
||||
|
||||
final class ReuseRulesValidator extends SupportValidator
|
||||
{
|
||||
protected array $rules = [
|
||||
'dummy' => 'nullable',
|
||||
];
|
||||
|
||||
public function rules(): array
|
||||
{
|
||||
return RulesSourceValidator::make($this->data)->rules();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Webman\Validation\Tests;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use support\validation\Validator;
|
||||
use support\validation\ValidationException;
|
||||
use Webman\Validation\Exception\ValidationException as BaseValidationException;
|
||||
|
||||
final class ValidatorTest extends TestCase
|
||||
{
|
||||
public function testValidatePassReturnsValidatedData(): void
|
||||
{
|
||||
$validated = Validator::make(
|
||||
['email' => 'user@example.com'],
|
||||
['email' => 'required|email']
|
||||
)->validate();
|
||||
|
||||
$this->assertSame(['email' => 'user@example.com'], $validated);
|
||||
}
|
||||
|
||||
public function testValidateFailThrowsConfiguredExceptionWithFirstMessage(): void
|
||||
{
|
||||
try {
|
||||
Validator::make(
|
||||
['email' => 'not-an-email'],
|
||||
['email' => 'required|email'],
|
||||
['email.email' => 'Email invalid']
|
||||
)->validate();
|
||||
$this->fail('Expected ValidationException was not thrown.');
|
||||
} catch (ValidationException $exception) {
|
||||
$this->assertSame('Email invalid', $exception->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function testValidateFailUsesConfigExceptionClass(): void
|
||||
{
|
||||
$this->setValidationExceptionConfig(ConfigValidationException::class);
|
||||
|
||||
try {
|
||||
Validator::make(
|
||||
['email' => 'not-an-email'],
|
||||
['email' => 'required|email']
|
||||
)->validate();
|
||||
$this->fail('Expected ConfigValidationException was not thrown.');
|
||||
} catch (ConfigValidationException $exception) {
|
||||
$this->assertSame('The email field must be a valid email address.', $exception->getMessage());
|
||||
} finally {
|
||||
$this->setValidationExceptionConfig(ValidationException::class);
|
||||
}
|
||||
}
|
||||
|
||||
public function testCustomValidatorWithoutScenesUsesAllRulesByDefault(): void
|
||||
{
|
||||
$validated = UserValidatorWithoutScenes::make([
|
||||
'email' => 'user@example.com',
|
||||
])->validate();
|
||||
|
||||
$this->assertSame(['email' => 'user@example.com'], $validated);
|
||||
}
|
||||
|
||||
// ───── Closure as validation rule tests ─────
|
||||
|
||||
public function testClosureRuleValidationPasses(): void
|
||||
{
|
||||
$validated = Validator::make(
|
||||
['age' => 20],
|
||||
['age' => ['required', 'integer', function ($attribute, $value, $fail) {
|
||||
if ($value < 18) {
|
||||
$fail("The {$attribute} must be at least 18.");
|
||||
}
|
||||
}]]
|
||||
)->validate();
|
||||
|
||||
$this->assertSame(['age' => 20], $validated);
|
||||
}
|
||||
|
||||
public function testClosureRuleValidationFails(): void
|
||||
{
|
||||
try {
|
||||
Validator::make(
|
||||
['age' => 15],
|
||||
['age' => ['required', 'integer', function ($attribute, $value, $fail) {
|
||||
if ($value < 18) {
|
||||
$fail("The {$attribute} must be at least 18.");
|
||||
}
|
||||
}]]
|
||||
)->validate();
|
||||
$this->fail('Expected ValidationException was not thrown.');
|
||||
} catch (ValidationException $exception) {
|
||||
$this->assertSame('The age must be at least 18.', $exception->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function testMultipleClosureRulesValidation(): void
|
||||
{
|
||||
$validated = Validator::make(
|
||||
['code' => 'prefix_abc'],
|
||||
['code' => ['required', 'string',
|
||||
function ($attribute, $value, $fail) {
|
||||
if (!str_starts_with($value, 'prefix_')) {
|
||||
$fail("The {$attribute} must start with prefix_.");
|
||||
}
|
||||
},
|
||||
function ($attribute, $value, $fail) {
|
||||
if (strlen($value) < 5) {
|
||||
$fail("The {$attribute} must be at least 5 characters.");
|
||||
}
|
||||
},
|
||||
]]
|
||||
)->validate();
|
||||
|
||||
$this->assertSame(['code' => 'prefix_abc'], $validated);
|
||||
}
|
||||
|
||||
public function testClosureRuleInCustomValidator(): void
|
||||
{
|
||||
$validated = ClosureRuleValidator::make(['score' => 85])->validate();
|
||||
$this->assertSame(['score' => 85], $validated);
|
||||
}
|
||||
|
||||
public function testClosureRuleInCustomValidatorFails(): void
|
||||
{
|
||||
try {
|
||||
ClosureRuleValidator::make(['score' => 150])->validate();
|
||||
$this->fail('Expected ValidationException was not thrown.');
|
||||
} catch (ValidationException $exception) {
|
||||
$this->assertStringContainsString('score', $exception->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// ───── Helpers ─────
|
||||
|
||||
private function setValidationExceptionConfig(string $exceptionClass): void
|
||||
{
|
||||
validation_test_set_config([
|
||||
'plugin' => [
|
||||
'webman' => [
|
||||
'validation' => [
|
||||
'app' => [
|
||||
'exception' => $exceptionClass,
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
final class ConfigValidationException extends BaseValidationException
|
||||
{
|
||||
}
|
||||
|
||||
final class UserValidatorWithoutScenes extends Validator
|
||||
{
|
||||
protected array $rules = [
|
||||
'email' => 'required|email',
|
||||
];
|
||||
}
|
||||
|
||||
final class ClosureRuleValidator extends Validator
|
||||
{
|
||||
protected array $rules = [
|
||||
'score' => 'required|integer',
|
||||
];
|
||||
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'score' => ['required', 'integer', function ($attribute, $value, $fail) {
|
||||
if ($value < 0 || $value > 100) {
|
||||
$fail("The {$attribute} must be between 0 and 100.");
|
||||
}
|
||||
}],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
if (!function_exists('validation_test_set_config')) {
|
||||
function validation_test_set_config(array $overrides = []): void
|
||||
{
|
||||
$defaults = [
|
||||
'container' => new \Webman\Container(),
|
||||
'translation' => [
|
||||
'locale' => 'en',
|
||||
'fallback_locale' => ['en'],
|
||||
'path' => '',
|
||||
],
|
||||
'plugin' => [
|
||||
'webman' => [
|
||||
'validation' => [
|
||||
'app' => [
|
||||
'enable' => true,
|
||||
'exception' => \support\validation\ValidationException::class,
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$current = $GLOBALS['validation_test_config'] ?? [];
|
||||
$merged = array_replace_recursive($defaults, $current, $overrides);
|
||||
$GLOBALS['validation_test_config'] = $merged;
|
||||
|
||||
if (class_exists(\Webman\Config::class)) {
|
||||
$property = new ReflectionProperty(\Webman\Config::class, 'config');
|
||||
$property->setAccessible(true);
|
||||
$property->setValue(null, $merged);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
validation_test_set_config();
|
||||
|
||||
if (!function_exists('config')) {
|
||||
function config(string $key, mixed $default = null): mixed
|
||||
{
|
||||
$config = $GLOBALS['validation_test_config'] ?? [];
|
||||
if ($key === null || $key === '') {
|
||||
return $config;
|
||||
}
|
||||
|
||||
$parts = explode('.', $key);
|
||||
$value = $config;
|
||||
foreach ($parts as $part) {
|
||||
if (!is_array($value) || !array_key_exists($part, $value)) {
|
||||
return $default;
|
||||
}
|
||||
$value = $value[$part];
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'email' => '[LOCAL_EN] :attribute invalid.',
|
||||
];
|
||||
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'email' => '[LOCAL_ZH] :attribute invalid.',
|
||||
];
|
||||
+216
@@ -0,0 +1,216 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Webman\Validation;
|
||||
|
||||
use Illuminate\Support\MessageBag;
|
||||
use Illuminate\Validation\Validator as IlluminateValidator;
|
||||
use InvalidArgumentException;
|
||||
use support\Container;
|
||||
use Throwable;
|
||||
use Webman\Validation\Factory\ValidationFactory;
|
||||
|
||||
class Validator
|
||||
{
|
||||
public static function make(
|
||||
array $data,
|
||||
?array $rules = null,
|
||||
?array $messages = null,
|
||||
?array $attributes = null
|
||||
): static {
|
||||
/** @var static $instance */
|
||||
$instance = Container::make(static::class);
|
||||
$instance->data = $data;
|
||||
|
||||
$instance->rules = $rules ?? $instance->rules;
|
||||
$instance->messages = $messages ?? $instance->messages;
|
||||
$instance->attributes = $attributes ?? $instance->attributes;
|
||||
|
||||
if ($instance->rules === []) {
|
||||
throw new InvalidArgumentException('Validation rules cannot be empty.');
|
||||
}
|
||||
|
||||
return $instance;
|
||||
}
|
||||
|
||||
protected array $rules = [];
|
||||
protected array $messages = [];
|
||||
protected array $attributes = [];
|
||||
protected array $scenes = [];
|
||||
|
||||
protected array $data = [];
|
||||
protected ?string $scene = null;
|
||||
private ?IlluminateValidator $validator = null;
|
||||
private ?string $exceptionClass = null;
|
||||
private static array $validatedExceptionClasses = [];
|
||||
|
||||
public function withScene(string $scene): static
|
||||
{
|
||||
$clone = clone $this;
|
||||
$clone->scene = $scene;
|
||||
$clone->validator = null;
|
||||
return $clone;
|
||||
}
|
||||
|
||||
public function withException(string $exceptionClass): static
|
||||
{
|
||||
if ($exceptionClass === '') {
|
||||
throw new InvalidArgumentException('Validation exception must be a non-empty class string.');
|
||||
}
|
||||
|
||||
$clone = clone $this;
|
||||
$clone->exceptionClass = $exceptionClass;
|
||||
$clone->validator = null;
|
||||
return $clone;
|
||||
}
|
||||
|
||||
public function validate(): array
|
||||
{
|
||||
$validator = $this->toIlluminate();
|
||||
if ($validator->fails()) {
|
||||
$exceptionClass = $this->resolveExceptionClass();
|
||||
$message = $validator->errors()->first() ?: 'Validation failed';
|
||||
throw new $exceptionClass($message, 400);
|
||||
}
|
||||
return $validator->validated();
|
||||
}
|
||||
|
||||
public function passes(): bool
|
||||
{
|
||||
return $this->toIlluminate()->passes();
|
||||
}
|
||||
|
||||
public function fails(): bool
|
||||
{
|
||||
return $this->toIlluminate()->fails();
|
||||
}
|
||||
|
||||
public function errors(): MessageBag
|
||||
{
|
||||
return $this->toIlluminate()->errors();
|
||||
}
|
||||
|
||||
public function validated(): array
|
||||
{
|
||||
return $this->toIlluminate()->validated();
|
||||
}
|
||||
|
||||
public function toIlluminate(): IlluminateValidator
|
||||
{
|
||||
if ($this->validator !== null) {
|
||||
return $this->validator;
|
||||
}
|
||||
|
||||
$factory = ValidationFactory::getFactory();
|
||||
$this->validator = $factory->make(
|
||||
$this->data(),
|
||||
$this->rules(),
|
||||
$this->messages(),
|
||||
$this->attributes()
|
||||
);
|
||||
return $this->validator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this in subclasses to build validation rules dynamically.
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return $this->resolveRules();
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this in subclasses to build custom messages dynamically.
|
||||
*/
|
||||
public function messages(): array
|
||||
{
|
||||
return $this->messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override this in subclasses to build custom attribute names dynamically.
|
||||
*/
|
||||
public function attributes(): array
|
||||
{
|
||||
return $this->attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expose incoming validation data for subclasses.
|
||||
*/
|
||||
public function data(): array
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expose current scene for subclasses.
|
||||
*/
|
||||
protected function scene(): ?string
|
||||
{
|
||||
return $this->scene;
|
||||
}
|
||||
|
||||
public function __call(string $name, array $arguments): mixed
|
||||
{
|
||||
$validator = $this->toIlluminate();
|
||||
if (!method_exists($validator, $name)) {
|
||||
throw new InvalidArgumentException("Validator method not found: {$name}");
|
||||
}
|
||||
return $validator->{$name}(...$arguments);
|
||||
}
|
||||
|
||||
private function resolveRules(): array
|
||||
{
|
||||
$scene = $this->scene;
|
||||
if ($scene === null) {
|
||||
return $this->rules;
|
||||
}
|
||||
|
||||
if (!array_key_exists($scene, $this->scenes)) {
|
||||
throw new InvalidArgumentException("Validation scene not defined: {$scene}");
|
||||
}
|
||||
|
||||
$fields = $this->scenes[$scene];
|
||||
if (!is_array($fields) || $fields === []) {
|
||||
throw new InvalidArgumentException("Validation scene has no fields: {$scene}");
|
||||
}
|
||||
|
||||
$rules = array_intersect_key($this->rules, array_flip($fields));
|
||||
if ($rules === []) {
|
||||
throw new InvalidArgumentException("Validation rules not found for scene: {$scene}");
|
||||
}
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
private function resolveExceptionClass(): string
|
||||
{
|
||||
$exceptionClass = $this->exceptionClass;
|
||||
if ($exceptionClass === null) {
|
||||
$exceptionClass = config(
|
||||
'plugin.webman.validation.app.exception',
|
||||
\support\validation\ValidationException::class
|
||||
);
|
||||
}
|
||||
|
||||
if (!is_string($exceptionClass) || $exceptionClass === '') {
|
||||
throw new InvalidArgumentException('Validation exception must be a non-empty class string.');
|
||||
}
|
||||
|
||||
// Cache validation result per class name to avoid repeated reflection checks.
|
||||
if (isset(self::$validatedExceptionClasses[$exceptionClass])) {
|
||||
return $exceptionClass;
|
||||
}
|
||||
|
||||
if (!class_exists($exceptionClass)) {
|
||||
throw new InvalidArgumentException("Validation exception class not found: {$exceptionClass}");
|
||||
}
|
||||
if (!is_subclass_of($exceptionClass, Throwable::class)) {
|
||||
throw new InvalidArgumentException("Validation exception must implement Throwable: {$exceptionClass}");
|
||||
}
|
||||
|
||||
self::$validatedExceptionClasses[$exceptionClass] = true;
|
||||
return $exceptionClass;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
use support\validation\ValidationException;
|
||||
|
||||
return [
|
||||
'enable' => true,
|
||||
'exception' => ValidationException::class,
|
||||
];
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
use Webman\Validation\Command\MakeValidatorCommand;
|
||||
|
||||
return [
|
||||
MakeValidatorCommand::class
|
||||
];
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
use Webman\Validation\Middleware;
|
||||
|
||||
return [
|
||||
'@' => [
|
||||
Middleware::class,
|
||||
],
|
||||
];
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit bootstrap="../../autoload.php"
|
||||
colors="true"
|
||||
verbose="true">
|
||||
<testsuites>
|
||||
<testsuite name="Validation Test Suite">
|
||||
<directory>Tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
</phpunit>
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace support\validation;
|
||||
|
||||
use Illuminate\Validation\Rule as IlluminateRule;
|
||||
|
||||
class Rule extends IlluminateRule
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace support\validation;
|
||||
|
||||
class ValidationException extends \Webman\Validation\Exception\ValidationException
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace support\validation;
|
||||
|
||||
class Validator extends \Webman\Validation\Validator
|
||||
{
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace support\validation\annotation;
|
||||
|
||||
use Attribute;
|
||||
|
||||
#[Attribute(Attribute::TARGET_PARAMETER)]
|
||||
class Param extends \Webman\Validation\Annotation\Param
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace support\validation\annotation;
|
||||
|
||||
use Attribute;
|
||||
|
||||
#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
|
||||
class Validate extends \Webman\Validation\Annotation\Validate
|
||||
{
|
||||
}
|
||||
Reference in New Issue
Block a user