Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
namespace Illuminate\Database\Console\Migrations;
4
 
5
use Illuminate\Console\ConfirmableTrait;
6
use Illuminate\Contracts\Console\Isolatable;
7
use Illuminate\Contracts\Events\Dispatcher;
8
use Illuminate\Database\Events\SchemaLoaded;
9
use Illuminate\Database\Migrations\Migrator;
10
use Illuminate\Database\SQLiteDatabaseDoesNotExistException;
11
use Illuminate\Database\SqlServerConnection;
12
use PDOException;
13
use Throwable;
14
 
15
class MigrateCommand extends BaseCommand implements Isolatable
16
{
17
    use ConfirmableTrait;
18
 
19
    /**
20
     * The name and signature of the console command.
21
     *
22
     * @var string
23
     */
24
    protected $signature = 'migrate {--database= : The database connection to use}
25
                {--force : Force the operation to run when in production}
26
                {--path=* : The path(s) to the migrations files to be executed}
27
                {--realpath : Indicate any provided migration file paths are pre-resolved absolute paths}
28
                {--schema-path= : The path to a schema dump file}
29
                {--pretend : Dump the SQL queries that would be run}
30
                {--seed : Indicates if the seed task should be re-run}
31
                {--seeder= : The class name of the root seeder}
32
                {--step : Force the migrations to be run so they can be rolled back individually}';
33
 
34
    /**
35
     * The console command description.
36
     *
37
     * @var string
38
     */
39
    protected $description = 'Run the database migrations';
40
 
41
    /**
42
     * The migrator instance.
43
     *
44
     * @var \Illuminate\Database\Migrations\Migrator
45
     */
46
    protected $migrator;
47
 
48
    /**
49
     * The event dispatcher instance.
50
     *
51
     * @var \Illuminate\Contracts\Events\Dispatcher
52
     */
53
    protected $dispatcher;
54
 
55
    /**
56
     * Create a new migration command instance.
57
     *
58
     * @param  \Illuminate\Database\Migrations\Migrator  $migrator
59
     * @param  \Illuminate\Contracts\Events\Dispatcher  $dispatcher
60
     * @return void
61
     */
62
    public function __construct(Migrator $migrator, Dispatcher $dispatcher)
63
    {
64
        parent::__construct();
65
 
66
        $this->migrator = $migrator;
67
        $this->dispatcher = $dispatcher;
68
    }
69
 
70
    /**
71
     * Execute the console command.
72
     *
73
     * @return int
74
     */
75
    public function handle()
76
    {
77
        if (! $this->confirmToProceed()) {
78
            return 1;
79
        }
80
 
81
        $this->migrator->usingConnection($this->option('database'), function () {
82
            $this->prepareDatabase();
83
 
84
            // Next, we will check to see if a path option has been defined. If it has
85
            // we will use the path relative to the root of this installation folder
86
            // so that migrations may be run for any path within the applications.
87
            $migrations = $this->migrator->setOutput($this->output)
88
                    ->run($this->getMigrationPaths(), [
89
                        'pretend' => $this->option('pretend'),
90
                        'step' => $this->option('step'),
91
                    ]);
92
 
93
            // Finally, if the "seed" option has been given, we will re-run the database
94
            // seed task to re-populate the database, which is convenient when adding
95
            // a migration and a seed at the same time, as it is only this command.
96
            if ($this->option('seed') && ! $this->option('pretend')) {
97
                $this->call('db:seed', [
98
                    '--class' => $this->option('seeder') ?: 'Database\\Seeders\\DatabaseSeeder',
99
                    '--force' => true,
100
                ]);
101
            }
102
        });
103
 
104
        return 0;
105
    }
106
 
107
    /**
108
     * Prepare the migration database for running.
109
     *
110
     * @return void
111
     */
112
    protected function prepareDatabase()
113
    {
114
        if (! $this->repositoryExists()) {
115
            $this->components->info('Preparing database.');
116
 
117
            $this->components->task('Creating migration table', function () {
118
                return $this->callSilent('migrate:install', array_filter([
119
                    '--database' => $this->option('database'),
120
                ])) == 0;
121
            });
122
 
123
            $this->newLine();
124
        }
125
 
126
        if (! $this->migrator->hasRunAnyMigrations() && ! $this->option('pretend')) {
127
            $this->loadSchemaState();
128
        }
129
    }
130
 
131
    /**
132
     * Determine if the migrator repository exists.
133
     *
134
     * @return bool
135
     */
136
    protected function repositoryExists()
137
    {
138
        return retry(2, fn () => $this->migrator->repositoryExists(), 0, function ($e) {
139
            try {
140
                if ($e->getPrevious() instanceof SQLiteDatabaseDoesNotExistException) {
141
                    return $this->createMissingSqliteDatbase($e->getPrevious()->path);
142
                }
143
 
144
                $connection = $this->migrator->resolveConnection($this->option('database'));
145
 
146
                if (
147
                    $e->getPrevious() instanceof PDOException &&
148
                    $e->getPrevious()->getCode() === 1049 &&
149
                    $connection->getDriverName() === 'mysql') {
150
                    return $this->createMissingMysqlDatabase($connection);
151
                }
152
 
153
                return false;
154
            } catch (Throwable) {
155
                return false;
156
            }
157
        });
158
    }
159
 
160
    /**
161
     * Create a missing SQLite database.
162
     *
163
     * @param  string  $path
164
     * @return bool
165
     */
166
    protected function createMissingSqliteDatbase($path)
167
    {
168
        if ($this->option('force')) {
169
            return touch($path);
170
        }
171
 
172
        if ($this->option('no-interaction')) {
173
            return false;
174
        }
175
 
176
        $this->components->warn('The SQLite database does not exist: '.$path);
177
 
178
        if (! $this->components->confirm('Would you like to create it?')) {
179
            return false;
180
        }
181
 
182
        return touch($path);
183
    }
184
 
185
    /**
186
     * Create a missing MySQL database.
187
     *
188
     * @return bool
189
     */
190
    protected function createMissingMysqlDatabase($connection)
191
    {
192
        if ($this->laravel['config']->get("database.connections.{$connection->getName()}.database") !== $connection->getDatabaseName()) {
193
            return false;
194
        }
195
 
196
        if (! $this->option('force') && $this->option('no-interaction')) {
197
            return false;
198
        }
199
 
200
        if (! $this->option('force') && ! $this->option('no-interaction')) {
201
            $this->components->warn("The database '{$connection->getDatabaseName()}' does not exist on the '{$connection->getName()}' connection.");
202
 
203
            if (! $this->components->confirm('Would you like to create it?')) {
204
                return false;
205
            }
206
        }
207
 
208
        try {
209
            $this->laravel['config']->set("database.connections.{$connection->getName()}.database", null);
210
 
211
            $this->laravel['db']->purge();
212
 
213
            $freshConnection = $this->migrator->resolveConnection($this->option('database'));
214
 
215
            return tap($freshConnection->unprepared("CREATE DATABASE IF NOT EXISTS `{$connection->getDatabaseName()}`"), function () {
216
                $this->laravel['db']->purge();
217
            });
218
        } finally {
219
            $this->laravel['config']->set("database.connections.{$connection->getName()}.database", $connection->getDatabaseName());
220
        }
221
    }
222
 
223
    /**
224
     * Load the schema state to seed the initial database schema structure.
225
     *
226
     * @return void
227
     */
228
    protected function loadSchemaState()
229
    {
230
        $connection = $this->migrator->resolveConnection($this->option('database'));
231
 
232
        // First, we will make sure that the connection supports schema loading and that
233
        // the schema file exists before we proceed any further. If not, we will just
234
        // continue with the standard migration operation as normal without errors.
235
        if ($connection instanceof SqlServerConnection ||
236
            ! is_file($path = $this->schemaPath($connection))) {
237
            return;
238
        }
239
 
240
        $this->components->info('Loading stored database schemas.');
241
 
242
        $this->components->task($path, function () use ($connection, $path) {
243
            // Since the schema file will create the "migrations" table and reload it to its
244
            // proper state, we need to delete it here so we don't get an error that this
245
            // table already exists when the stored database schema file gets executed.
246
            $this->migrator->deleteRepository();
247
 
248
            $connection->getSchemaState()->handleOutputUsing(function ($type, $buffer) {
249
                $this->output->write($buffer);
250
            })->load($path);
251
        });
252
 
253
        $this->newLine();
254
 
255
        // Finally, we will fire an event that this schema has been loaded so developers
256
        // can perform any post schema load tasks that are necessary in listeners for
257
        // this event, which may seed the database tables with some necessary data.
258
        $this->dispatcher->dispatch(
259
            new SchemaLoaded($connection, $path)
260
        );
261
    }
262
 
263
    /**
264
     * Get the path to the stored schema for the given connection.
265
     *
266
     * @param  \Illuminate\Database\Connection  $connection
267
     * @return string
268
     */
269
    protected function schemaPath($connection)
270
    {
271
        if ($this->option('schema-path')) {
272
            return $this->option('schema-path');
273
        }
274
 
275
        if (file_exists($path = database_path('schema/'.$connection->getName().'-schema.dump'))) {
276
            return $path;
277
        }
278
 
279
        return database_path('schema/'.$connection->getName().'-schema.sql');
280
    }
281
}