Laravel 智能验证规则生成器:企业级增强方案
namespace App\Services\Validation;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;
use InvalidArgumentException;
class SchemaDrivenValidator
{
protected $config;
protected $schemaCacheKey = 'database_schema_v2';
protected $connection;
protected $databaseDriver;
protected $customRules = [];
protected $ignoreRules = [];
protected $tableAliases = [];
protected $currentTable;
protected $nestedValidators = [];
public function __construct()
{
$this->loadConfig();
$this->connection = config('database.default');
$this->databaseDriver = config("database.connections.{
$this->connection}.driver");
}
protected function loadConfig()
{
$this->config = config('validation', [
'cache_ttl' => 86400,
'auto_relation' => true,
'strict_types' => false,
'default_string_max' => 255,
'password_min_length' => 8,
'image_max_size' => 2048,
'custom_rules' => [],
'ignore_fields' => [],
'table_aliases' => [],
'type_mappings' => [
'int' => 'integer',
'varchar' => 'string',
'text' => 'string',
'datetime' => 'date',
'timestamp' => 'date',
'json' => 'array',
],
'special_field_handlers' => [
'email' => ['email'],
'phone' => ['phone'],
'password' => ['min::password_min_length', 'confirmed'],
'image' => ['image', 'mimes:jpg,png,jpeg', 'max::image_max_size'],
'_at' => ['date'],
'_image' => ['image', 'mimes:jpg,png,jpeg', 'max::image_max_size'],
'_avatar' => ['image', 'mimes:jpg,png,jpeg', 'max::image_max_size'],
]
]);
$this->customRules = $this->config['custom_rules'] ?? [];
$this->ignoreRules = $this->config['ignore_fields'] ?? [];
$this->tableAliases = $this->config['table_aliases'] ?? [];
}
public function getDatabaseSchema(bool $forceRefresh = false)
{
$cacheKey = $this->schemaCacheKey . '_' . $this->connection;
if ($forceRefresh) {
Cache::forget($cacheKey);
}
return Cache::remember($cacheKey, $this->config['cache_ttl'], function () {
return $this->fetchDatabaseSchema();
});
}
protected function fetchDatabaseSchema()
{
switch ($this->databaseDriver) {
case 'mysql':
return $this->getMysqlSchema();
case 'pgsql':
return $this->getPostgresSchema();
case 'sqlite':
return $this->getSqliteSchema();
default:
throw new InvalidArgumentException("Unsupported database driver: {
$this->databaseDriver}");
}
}
protected function getMysqlSchema()
{
$databaseName = config("database.connections.{
$this->connection}.database");
$columns = DB::connection($this->connection)
->table('information_schema.columns')
->select(
'table_name',
'column_name',
'column_comment',
'data_type',
'character_maximum_length',
'is_nullable',
'column_default',
'column_type',
'numeric_precision',
'numeric_scale',
'extra'
)
->where('table_schema', $databaseName)
->get();
$indexes = DB::connection($this->connection)
->table('information_schema.statistics')
->select(
'table_name',
'column_name',
'index_name',
'non_unique'
)
->where('table_schema', $databaseName)
->get();
$foreignKeys = DB::connection($this->connection)
->table('information_schema.key_column_usage')
->select(
'table_name',
'column_name',
'referenced_table_name',
'referenced_column_name'
)
->where('table_schema', $databaseName)
->whereNotNull('referenced_table_name')
->get();
return $this->processSchemaData($columns, $indexes, $foreignKeys);
}
protected function getPostgresSchema()
{
$schema = config("database.connections.{
$this->connection}.schema", 'public');
$columns = DB::connection($this->connection)
->table('information_schema.columns')
->select(
'table_name',
'column_name',
'column_default',
'is_nullable',
'data_type',
'character_maximum_length',
'numeric_precision',
'numeri