【问题标题】:laravel generate database from modellaravel 从模型生成数据库
【发布时间】:2018-12-12 00:21:54
【问题描述】:

我正在使用 Laravel 的现有项目,并且这个现有项目已经有模型,这里是一个示例:

<?php

/**
 * Created by Reliese Model.
 * Date: Fri, 20 Apr 2018 08:56:36 +0000.
 */

namespace App\Models;

use Reliese\Database\Eloquent\Model as Eloquent;

/**
 * Class PdTcountry
 * 
 * @property int $pkcountry
 * @property string $country_code
 * @property string $country_name
 * @property string $country_localName
 * @property string $country_webCode
 * @property string $country_region
 * @property string $country_continent
 * @property float $country_latitude
 * @property float $country_longitude
 * @property string $country_surfaceArea
 * @property string $country_population
 * @property string $country_postcodeexpression
 * @property \Carbon\Carbon $create_at
 * @property \Carbon\Carbon $update_at
 * 
 * @property \Illuminate\Database\Eloquent\Collection $pd_tregions
 *
 * @package App\Models
 */
class PdTcountry extends Eloquent
{
    protected $table = 'pd_tcountry';
    protected $primaryKey = 'pkcountry';
    public $timestamps = false;

    protected $casts = [
        'country_latitude' => 'float',
        'country_longitude' => 'float'
    ];

    protected $dates = [
        'create_at',
        'update_at'
    ];

    protected $fillable = [
        'country_code',
        'country_name',
        'country_localName',
        'country_webCode',
        'country_region',
        'country_continent',
        'country_latitude',
        'country_longitude',
        'country_surfaceArea',
        'country_population',
        'country_postcodeexpression',
        'create_at',
        'update_at'
    ];

    public function pd_tregions()
    {
        return $this->hasMany(\App\Models\PdTregion::class, 'fkcountry');
    }
}

我的问题是,这个模型是否可以通过 php artisan 从模型中创建数据库表?如果有一个 php artisan 命令可以为我所有的模型做这将是超级的。

在我的数据库文件夹中,我有这些,但我不知道它们是做什么的。

【问题讨论】:

  • 复制try this
  • 项目是否也有迁移?这应该是构成数据库的表所在的位置。
  • 您可能可以安装Doctrine 来执行此操作。
  • @Stranger,恰恰相反。从数据库生成模型很好,从模型生成数据库是个坏主意。模型中没有任何内容可以确定确切的数据类型(BLOB、CHAR、VARCHAR 和 TEXT),也没有任何内容可以确定可为空的字段,等等。

标签: php laravel laravel-artisan


【解决方案1】:

如果您希望自动生成这些表格,那么不,Laravel 真的没有办法做到这一点。理论上,您可以编写自己的命令来为每个模型生成迁移文件,但无论如何它仍然需要您提供所有列名、数据类型等。以 Laravel 的 make:migration 命令为例。它只是使用存根文件并在生成时替换关键字(vendor/laravel/framework/src/Illuminate/Database/Migrations/MigrationCreator.php)。如果您有大量需要数据库表的模型,那么这可能是您深入研究的好方法。

但是,如果没有,您最好使用标准命令生成迁移,并为其提供 --create 标记。之后,您只需在模型中定义表(或使用命名约定以便它自动找到它,请参阅:https://laravel.com/docs/5.6/eloquent#defining-models 了解有关命名约定的更多信息)。

例子:

php artisan make:migration create_my_model_table --create=my_model_table_name

如果您不使用命名约定,请将您的表名添加到您的模型中:

class PdTcountry extends Eloquent {

    protected $table = "my_model_table_name"

    ...
}

【讨论】:

    【解决方案2】:

    在控制台中运行php artisan migrate。这将为您的database/migrations 文件夹中存在的定义生成表,如问题中的图片所示。

    【讨论】:

    • @SimoneCabrino 他说,他有一个包含模型和迁移文件的现有项目。他说的生成表还有什么意思?
    • 他的意思是代码优先的数据库,使用模型而不是迁移来创建数据库
    【解决方案3】:

    有没有办法通过php artisan 从模型中创建数据库表?

    听起来您想要的是“代码优先设计”。这在 Microsoft 的 Entity Framework 中得到支持,但是在 Laravel 中,事情的工作方式有些不同。在带有实体框架的 C# 中,可以创建属性(基本上是 getter 方法)以对应于每个数据库列。借助 Eloquent(Laravel 的 ORM 库),它使用 PHP magic methods 动态生成这些变量,PHP 变量也像 C# 那样缺少类型。因此,无法以您想要的方式根据代码填充数据库。您在问题中发布的 doc cmets 看起来像是使用 laravel-ide-helper 包从数据库到代码以相反的方式生成的。

    另外,像Sequel Pro 这样的一些数据库客户端有一个插件可以将现有的数据库模式导出到 Laravel 迁移中,我在过去发现它非常快速和有用,并且可能是您可以获得的最接近工作流程的东西寻找。祝你好运!

    我的数据库文件夹中有(一组迁移文件),但我不知道它们的作用。

    您应该查看相关的documentation on the Laravel website。迁移已生成,因此您需要配置本地数据库并运行migrate 命令。这将创建应用程序所需的表和列。当您对架构进行更改时,您应该添加更多迁移并重新运行 migrate 命令。

    php artisan migrate
    

    【讨论】:

      【解决方案4】:

      正如其他人所指出的:这不是 Laravel 或者准确地说是 Eloquent ORM 的工作方式。通常,您首先创建一个表(即进行迁移),然后创建您的模型。坚持 Laravel model conventions 可以节省很多时间。

      但是,您已经有一个或多个模型似乎缺少迁移。我建议您简单地为这些模型添加迁移。不幸的是,如果您有很多模型,尤其是(就像您的示例模型一样)当您不遵守表名和其他约定时,这将是很多工作。

      另一方面,您的模型中已经有了很多要用于迁移的信息。您可以从 DocComments 和 $table$primaryKey$fillable 等属性中提取此信息。这可以自动完成。我整理了一个远未完成的示例,但至少应该让您开始了解迁移的基础。然后,您可以决定手动完成剩余部分或将功能添加到自动过程中。如果我有很多模型,我个人只会做后者。


      示例

      我基于您问题中包含的模型示例。

      正如我所说;它远未完成,我想到了以下添加/改进:

      1. 确定关系并以此为基础的外键。 (看看这个post 以获得一些灵感。)
      2. switch 添加更多数据类型。
      3. ...

      将以下特征保存为app/SchemaBuilder.php

      <?php
      
      namespace App;
      
      trait SchemaBuilder
      {
          public function printMigration()
          {
              echo '<pre>';
              echo htmlspecialchars($this->generateMigration());
              echo '</pre>';
          }
      
          public function makeMigrationFile()
          {
              if ($this->migrationFileExists()) {
                  die('It appears that a migration for this model already exists. Please check it out.');
              }
              $filename = date('Y_m_t_His') . '_create_' . $this->table . '_table.php';
              if (file_put_contents(database_path('migrations/') . $filename, $this->generateMigration())) {
                  return true;
              }
      
              return false;
          }
      
          protected function generateMigration()
          {
              return sprintf($this->getSchemaTemplate(),
                  ucfirst($this->table), $this->table,
                  implode("\n\t\t\t", $this->generateFieldCreationFunctions()),
                  $this->table
              );
          }
      
          protected function getSchemaTemplate()
          {
              $schema = "<?php\n";
              $schema .= "\n";
              $schema .= "use Illuminate\\Support\\Facades\\Schema;\n";
              $schema .= "use Illuminate\\Database\\Schema\\Blueprint;\n";
              $schema .= "use Illuminate\\Database\\Migrations\\Migration;\n";
              $schema .= "\n";
              $schema .= "class Create%sTable extends Migration\n";
              $schema .= "{\n";
              $schema .= "\t/**\n";
              $schema .= "\t* Run the migrations.\n";
              $schema .= "\t*\n";
              $schema .= "\t* @return void\n";
              $schema .= "\t*/\n";
              $schema .= "\tpublic function up()\n";
              $schema .= "\t{\n";
              $schema .= "\t\tSchema::create('%s', function (Blueprint \$table) {\n";
              $schema .= "\t\t\t%s\n"; # Actual database fields will be added here.
              $schema .= "\t\t});\n";
              $schema .= "\t}\n";
              $schema .= "\n";
              $schema .= "\t/**\n";
              $schema .= "\t* Reverse the migrations.\n";
              $schema .= "\t*\n";
              $schema .= "\t* @return void\n";
              $schema .= "\t*/\n";
              $schema .= "\tpublic function down()\n";
              $schema .= "\t{\n";
              $schema .= "\t\tSchema::drop('%s');\n";
              $schema .= "\t}\n";
              $schema .= "}";
      
              return $schema;
          }
      
          protected function generateFieldCreationFunctions()
          {
              $functions = [];
      
              if (isset($this->primaryKey)) {
                  $functions[] = "\$table->increments('$this->primaryKey');";
              }
      
              $featuresFromDoc = $this->extractFieldDataFromCommentDoc();
              $functions[] = ""; # Hack our way to an empty line.
              foreach ($this->fillable as $fillableField) {
                  if (in_array($fillableField, $this->dates)) { # We'll handle fields in $dates later.
                      continue;
                  }
      
                  if (!isset($featuresFromDoc[$fillableField])) {
                      $functions[] = "//Manually do something with $fillableField";
                  }
      
                  switch ($featuresFromDoc[$fillableField]) {
                      case 'string':
                          $functions[] = "\$table->string('$fillableField'); //TODO: check whether varchar is the correct field type.";
                          break;
                      case 'int':
                          $functions[] = "\$table->integer('$fillableField'); //TODO: check whether integer is the correct field type.";
                          break;
                      case 'float':
                          $functions[] = "\$table->float('$fillableField', 12, 10);";
                          break;
                      default:
                          $functions[] = "//Manually do something with $fillableField";
                  }
              }
      
              $functions[] = ""; # Empty line.
              foreach ($this->dates as $dateField) {
                  $functions[] = "\$table->dateTime('$dateField');";
              }
      
              $functions[] = ""; # Empty line.
              if (!empty($this->timestamps)) {
      
                  $functions[] = "\$table->timestamps();";
              }
              return $functions;
          }
      
          protected function extractFieldDataFromCommentDoc()
          {
              $doc_comment = (new \ReflectionClass(get_parent_class($this)))->getDocComment();
      
              preg_match_all('/@property (.+) \$(.+)/', $doc_comment, $matches, PREG_SET_ORDER);
      
              foreach ($matches as $match) {
                  $features[$match[2]] = $match[1];
              }
      
              return $features;
          }
      
          protected function migrationFileExists()
          {
              $path = database_path('migrations');
      
              if ($handle = opendir($path)) {
                  while (false !== ($file = readdir($handle))) {
                      if (strpos($file, 'create_' . $this->table . '_table') !== false) {
                          return true;
                      }
                  }
                  closedir($handle);
              }
      
              return false;
          }
      }
      

      创建以下控制器并注册一个路由,以便您可以访问它:

      <?php
      
      namespace App\Http\Controllers;
      
      use App\PdTcountry;
      use Illuminate\Http\Request;
      
      class TestController extends Controller
      {
          public function index()
          {
              # Specify for which model you'd like to build a migration.
              $buildSchemaFor = 'App\PdTcountry';
      
              eval(sprintf('class MigrationBuilder extends %s{use \App\SchemaBuilder;}', $buildSchemaFor));
      
              if ((new \MigrationBuilder)->makeMigrationFile()) {
                  echo 'Migration file successfully created.';
              }
              else {
                  echo 'Encountered error while making migration file.';
              }
      
              # Or alternatively, print the migration file to the browser:
      //        (new \MigrationBuilder)->printMigration();
      
      
          }
      }
      

      【讨论】:

        【解决方案5】:

        这是一个可以安装的 composer 包,它可以从你的模型创建数据库表。它被称为依赖。

        https://github.com/reliese/laravel

        希望这会有所帮助,并且是您正在寻找的。​​p>

        【讨论】:

        • OP 的要求正好相反
        猜你喜欢
        • 2012-07-01
        • 2011-02-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-12
        • 1970-01-01
        相关资源
        最近更新 更多