laravel generate database from model

2020-01-19 05:12发布

I am using an existing project of Laravel and this existing project already has models, here is an example of one:

<?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');
    }
}

My question is, with this Model is there away via php artisan to create a database table from the model? If there is a php artisan command to do it for all my models that would be super.

In my database folder I have these, but I don't know what they do.

enter image description here

5条回答
叛逆
2楼-- · 2020-01-19 05:44

Here is a composer package that you can install that creates database tables from your models. It's called reliese.

https://github.com/reliese/laravel

Hope this helps and is what you are looking for.

查看更多
The star\"
3楼-- · 2020-01-19 05:46

Run php artisan migrate in the console. This will generate tables for definition existing in your database/migrations folder as shown in the pic in the question.

查看更多
Ridiculous、
4楼-- · 2020-01-19 05:47

Is there a way via php artisan to create a database table from the model?

It sounds like what you want is "Code-First Design". This is supported in Microsoft's Entity Framework however in Laravel the way things work is somewhat different. In C# with Entity framework one would create properties (basically getter methods) to correspond with each database column. With Eloquent (Laravel's ORM library) it generates these dynamically using PHP magic methods, PHP variables also lack types in the way that C# does. Because of this there is no way to populate the database based on the code in the way you want. The doc comments you posted in your question look like they were generated the other way around from database to code, using the laravel-ide-helper package.

Alternatively some database clients like Sequel Pro have a plugin to export the existing database schema into a Laravel migration which I have found very quick and helpful in the past and might be the closest thing you can get to the workflow you're looking for. Good luck!

Exporting a database schema as a Laravel migration

I have (a set of migration files) in my database folder, but I don't know what they do.

You should check out the relevant documentation on the Laravel website. The migrations have already been generated so you need to configure a local database and run the migrate command. This will create the tables and columns necessary for your application. As you make changes to the schema you should add more migrations and rerun the migrate command.

php artisan migrate
查看更多
放荡不羁爱自由
5楼-- · 2020-01-19 05:50

If you are looking to generate these tables automagically, then no, Laravel doesn't really have a way to do that. In theory, you could write your own command to generate migration files for each of your models, but it will still require you to provide all the column names, data types, etc. anyways. Take a look at Laravel's make:migration command for instance. It just uses stub files and replaces key words when generating (vendor/laravel/framework/src/Illuminate/Database/Migrations/MigrationCreator.php). If you have a ton of models that need database tables, then maybe this would be a good approach for you to dive into.

If not, however, you're probably best off generating a migration using the standard command and just supply it with the --create tag. Afterwards, you would just have to define your table in your model (or use the naming convention so it finds it automatically, see: https://laravel.com/docs/5.6/eloquent#defining-models for more info on the naming conventions).

Example:

php artisan make:migration create_my_model_table --create=my_model_table_name

If you don't use the naming convention, add your table name to your model:

class PdTcountry extends Eloquent {

    protected $table = "my_model_table_name"

    ...
}
查看更多
成全新的幸福
6楼-- · 2020-01-19 05:53

As others have pointed out: this is not how Laravel, or the Eloquent ORM to be exact, works. Normally you'd first create a table (i.e. make a migration) and then create your model. A lot of time can be saved by adhering to Laravels model conventions.

However, you already have one or more models that seem to be missing a migration. I'd advice you to simply add migrations for these models. Unfortunately this will be a lot of work if you have a lot of models and, especially (as is the case with your example model) when you didn't adhere to the table name, and other, conventions.

On the other hand, you already have a lot of the information that's going to go into your migration, available in your Model. You could extract this information from the DocComments and properties like $table, $primaryKey, $fillable, etc. This could be done automatically. I've put together an example that's far from complete, but should at least get you started with the base of your migration. You can then decide to do the remaining parts manually or add functionality to the automatic process. I'd personally only do the latter if I had a lot of models.


Example

I've based this example of the model included in your question.

As I said; it's far from complete, the following additions/improvements come to mind:

  1. Determine relations and base foreign keys on that. (Take a look at this post to get some inspiration.)
  2. Add more data types to the switch.
  3. ...

Save the following trait as 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;
    }
}

Create the following controller and register a route so that you can access it:

<?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();


    }
}
查看更多
登录 后发表回答