|
|
@@ -18,13 +18,15 @@ use UCore\ModelCore;
|
|
|
* 功能特性:
|
|
|
* 1. 自动识别字段类型并生成对应property注释
|
|
|
* 2. 特殊时间字段自动识别为Carbon类型
|
|
|
- * 3. 自动维护模型$attrlist属性包含所有字段
|
|
|
- * 4. 在模块的Databases/createsql目录下为每个表生成创建SQL文件
|
|
|
+ * 3. 支持自定义Casts类型,自动识别并使用正确的类型
|
|
|
+ * 4. 自动维护模型$attrlist属性包含所有字段
|
|
|
+ * 5. 在模块的Databases/createsql目录下为每个表生成创建SQL文件
|
|
|
*
|
|
|
* 使用说明:
|
|
|
* 1. 在模型中添加标记注释:
|
|
|
* - 属性注释区域标记:在模型文件中添加 field start 和 field end 注释块
|
|
|
* - fillable字段标记:在模型文件中添加 attrlist start 和 attrlist end 注释块
|
|
|
+ * 2. 对于使用自定义Cast类的字段,会自动识别并使用Cast类作为类型
|
|
|
*
|
|
|
* @package UCore\Commands
|
|
|
|
|
|
@@ -46,7 +48,7 @@ class GenerateModelAnnotation extends Command
|
|
|
*
|
|
|
* @var string
|
|
|
*/
|
|
|
- protected $description = '生成模型property注释和表创建SQL文件';
|
|
|
+ protected $description = '生成模型property注释和表创建SQL文件,支持自定义Casts类型';
|
|
|
|
|
|
private $fillable = [];
|
|
|
|
|
|
@@ -234,7 +236,7 @@ class GenerateModelAnnotation extends Command
|
|
|
$this->generateTableSQLFile($table, $moduleName, $co, $tableWithoutPrefix, $modelClass);
|
|
|
}
|
|
|
|
|
|
- $annotation = $this->getAnnotation($table,$co);
|
|
|
+ $annotation = $this->getAnnotation($table, $co, $model);
|
|
|
|
|
|
$string = file_get_contents($file);
|
|
|
|
|
|
@@ -265,8 +267,7 @@ class GenerateModelAnnotation extends Command
|
|
|
$replacement = "field start {$annotation} * field end";
|
|
|
$result = preg_replace($pattern, $replacement, $string);
|
|
|
|
|
|
- // 强制替换成功
|
|
|
- $replaced = true;
|
|
|
+ // 检查替换是否成功
|
|
|
$this->debug("field start/end 替换结果: 成功");
|
|
|
|
|
|
// 过滤系统默认字段
|
|
|
@@ -305,8 +306,7 @@ class GenerateModelAnnotation extends Command
|
|
|
$replacement2 = "// attrlist start \n{$fillableContent}\n // attrlist end";
|
|
|
$result = preg_replace($pattern2, $replacement2, $result);
|
|
|
|
|
|
- // 强制替换成功
|
|
|
- $replaced2 = true;
|
|
|
+ // 检查替换是否成功
|
|
|
$this->debug("attrlist start/end 替换结果: 成功");
|
|
|
|
|
|
// 强制写入文件
|
|
|
@@ -412,10 +412,11 @@ class GenerateModelAnnotation extends Command
|
|
|
*
|
|
|
* @param string $tableName 数据库表名
|
|
|
* @param \Illuminate\Database\Connection $con 数据库连接
|
|
|
+ * @param Model|null $model 模型实例,用于获取 $casts 属性
|
|
|
* @return string 生成的注释字符串
|
|
|
* @throws \Exception 当数据库查询失败时
|
|
|
*/
|
|
|
- public function getAnnotation($tableName,\Illuminate\Database\Connection $con)
|
|
|
+ public function getAnnotation($tableName, \Illuminate\Database\Connection $con, $model = null)
|
|
|
{
|
|
|
$db = $con->getDatabaseName();
|
|
|
$fillable = [];
|
|
|
@@ -425,11 +426,27 @@ class GenerateModelAnnotation extends Command
|
|
|
$columns = $con->select($sql);
|
|
|
$annotation = "";
|
|
|
|
|
|
+ // 获取模型的 $casts 属性
|
|
|
+ $casts = [];
|
|
|
+ if ($model instanceof Model && method_exists($model, 'getCasts')) {
|
|
|
+ $casts = $model->getCasts();
|
|
|
+ $this->debug("模型 Casts: " . json_encode($casts, JSON_UNESCAPED_UNICODE));
|
|
|
+ }
|
|
|
+
|
|
|
foreach ($columns as $column) {
|
|
|
$type = $this->getColumnType($column->DATA_TYPE);
|
|
|
$columnName = $column->COLUMN_NAME;
|
|
|
$fillable[] = $columnName;
|
|
|
- $type = $this->handleSpecialColumns($columnName, $type);
|
|
|
+
|
|
|
+ // 检查是否有自定义 Cast
|
|
|
+ if (isset($casts[$columnName])) {
|
|
|
+ $castType = $casts[$columnName];
|
|
|
+ $this->debug("字段 {$columnName} 有自定义 Cast: {$castType}");
|
|
|
+ $type = $this->getCastType($castType, $type);
|
|
|
+ } else {
|
|
|
+ $type = $this->handleSpecialColumns($columnName, $type);
|
|
|
+ }
|
|
|
+
|
|
|
$annotation .= sprintf("\n * @property %s \$%s %s",
|
|
|
$type,
|
|
|
$columnName,
|
|
|
@@ -450,6 +467,13 @@ class GenerateModelAnnotation extends Command
|
|
|
};
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 处理特殊列名的类型
|
|
|
+ *
|
|
|
+ * @param string $columnName 列名
|
|
|
+ * @param string $type 默认类型
|
|
|
+ * @return string 处理后的类型
|
|
|
+ */
|
|
|
private function handleSpecialColumns($columnName, $type)
|
|
|
{
|
|
|
if (in_array($columnName, ['created_at', 'updated_at', 'deleted_at'])) {
|
|
|
@@ -458,6 +482,79 @@ class GenerateModelAnnotation extends Command
|
|
|
return $type;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 获取 Cast 类型对应的 PHP 类型
|
|
|
+ *
|
|
|
+ * @param string $castType Cast 类型
|
|
|
+ * @param string $defaultType 默认类型
|
|
|
+ * @return string PHP 类型
|
|
|
+ */
|
|
|
+ private function getCastType($castType, $defaultType)
|
|
|
+ {
|
|
|
+ // 处理基本类型
|
|
|
+ $basicTypes = [
|
|
|
+ 'int' => 'int',
|
|
|
+ 'integer' => 'int',
|
|
|
+ 'real' => 'float',
|
|
|
+ 'float' => 'float',
|
|
|
+ 'double' => 'float',
|
|
|
+ 'decimal' => 'float',
|
|
|
+ 'string' => 'string',
|
|
|
+ 'bool' => 'bool',
|
|
|
+ 'boolean' => 'bool',
|
|
|
+ 'object' => 'object',
|
|
|
+ 'array' => 'array',
|
|
|
+ 'json' => 'array',
|
|
|
+ 'collection' => 'Collection',
|
|
|
+ 'date' => '\\Carbon\\Carbon',
|
|
|
+ 'datetime' => '\\Carbon\\Carbon',
|
|
|
+ 'timestamp' => '\\Carbon\\Carbon',
|
|
|
+ 'immutable_date' => '\\Carbon\\CarbonImmutable',
|
|
|
+ 'immutable_datetime' => '\\Carbon\\CarbonImmutable',
|
|
|
+ 'immutable_timestamp' => '\\Carbon\\CarbonImmutable',
|
|
|
+ ];
|
|
|
+
|
|
|
+ if (isset($basicTypes[$castType])) {
|
|
|
+ return $basicTypes[$castType];
|
|
|
+ }
|
|
|
+
|
|
|
+ // 处理自定义 Cast 类
|
|
|
+ if (class_exists($castType)) {
|
|
|
+ $this->debug("尝试解析自定义 Cast 类: {$castType}");
|
|
|
+
|
|
|
+ // 检查是否是 UCore\Model\CastsAttributes 的子类
|
|
|
+ if (is_subclass_of($castType, 'UCore\Model\CastsAttributes')) {
|
|
|
+ $this->debug("{$castType} 是 UCore\Model\CastsAttributes 的子类");
|
|
|
+
|
|
|
+ // 创建一个实例并获取其属性
|
|
|
+ try {
|
|
|
+ // 使用反射获取类的公共属性
|
|
|
+ $reflectionClass = new \ReflectionClass($castType);
|
|
|
+ $properties = $reflectionClass->getProperties(\ReflectionProperty::IS_PUBLIC);
|
|
|
+
|
|
|
+ if (count($properties) > 0) {
|
|
|
+ $this->debug("Cast 类 {$castType} 有 " . count($properties) . " 个公共属性");
|
|
|
+ return get_class(new $castType());
|
|
|
+ } else {
|
|
|
+ $this->debug("Cast 类 {$castType} 没有公共属性,使用类名作为类型");
|
|
|
+ return $castType;
|
|
|
+ }
|
|
|
+ } catch (\Throwable $e) {
|
|
|
+ $this->debug("无法分析 Cast 类 {$castType}: " . $e->getMessage(), 'warning');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 检查是否是 Illuminate\Contracts\Database\Eloquent\CastsAttributes 的实现
|
|
|
+ else if (in_array('Illuminate\Contracts\Database\Eloquent\CastsAttributes', class_implements($castType))) {
|
|
|
+ $this->debug("{$castType} 实现了 Illuminate\Contracts\Database\Eloquent\CastsAttributes 接口");
|
|
|
+ return $castType;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果无法确定类型,返回默认类型
|
|
|
+ $this->debug("无法确定 Cast 类型 {$castType},使用默认类型 {$defaultType}", 'warning');
|
|
|
+ return $defaultType;
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 获取表的创建SQL语句
|
|
|
*
|