mirror of
https://github.com/flarum/core.git
synced 2025-08-16 13:24:11 +02:00
Compare commits
4 Commits
dw/3020-co
...
dk/2890-ve
Author | SHA1 | Date | |
---|---|---|---|
|
43f379093c | ||
|
f5c602c234 | ||
|
0727f3d6d4 | ||
|
979a471214 |
28
migrations/v1.0/2021_05_31_000000_rename_beta_migrations.php
Normal file
28
migrations/v1.0/2021_05_31_000000_rename_beta_migrations.php
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Flarum.
|
||||||
|
*
|
||||||
|
* For detailed copyright and license information, please view the
|
||||||
|
* LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use Illuminate\Database\Schema\Builder;
|
||||||
|
|
||||||
|
return [
|
||||||
|
'up' => function (Builder $schema) {
|
||||||
|
$db = $schema->getConnection();
|
||||||
|
|
||||||
|
$db->table('migrations')
|
||||||
|
->whereNull('extension')
|
||||||
|
->update(['migration' => $db->raw("CONCAT('v0.1/', migration)")]);
|
||||||
|
},
|
||||||
|
|
||||||
|
'down' => function (Builder $schema) {
|
||||||
|
$db = $schema->getConnection();
|
||||||
|
|
||||||
|
$db->table('migrations')
|
||||||
|
->whereNull('extension')
|
||||||
|
->update(['migration' => $db->raw("REPLACE('v0.1/', '')")]);
|
||||||
|
}
|
||||||
|
];
|
48
migrations/v1.0/create_discussions_table.php
Normal file
48
migrations/v1.0/create_discussions_table.php
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Flarum.
|
||||||
|
*
|
||||||
|
* For detailed copyright and license information, please view the
|
||||||
|
* LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use Flarum\Post\Post;
|
||||||
|
use Flarum\User\User;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Schema\Builder;
|
||||||
|
|
||||||
|
return [
|
||||||
|
'up' => function (Builder $schema) {
|
||||||
|
$schema->create('discussions', function (Blueprint $table) {
|
||||||
|
$table->increments('id');
|
||||||
|
$table->string('title', 200);
|
||||||
|
$table->unsignedInteger('comments_count')->default(0);
|
||||||
|
$table->unsignedInteger('participants_count')->default(0);
|
||||||
|
$table->unsignedInteger('post_number_index')->default(0);
|
||||||
|
|
||||||
|
$table->dateTime('created_at');
|
||||||
|
$table->foreignIdFor(User::class, 'user_id')->nullable();
|
||||||
|
$table->foreignIdFor(Post::class, 'first_post_id')->nullable();
|
||||||
|
|
||||||
|
$table->dateTime('last_posted_at')->nullable();
|
||||||
|
$table->foreignIdFor(User::class, 'last_posted_user_id')->nullable();
|
||||||
|
$table->foreignIdFor(Post::class, 'last_post_id')->nullable();
|
||||||
|
$table->unsignedInteger('last_post_number')->nullable();
|
||||||
|
|
||||||
|
$table->dateTime('hidden_at')->nullable();
|
||||||
|
$table->foreignIdFor(User::class, 'hidden_user_id')->nullable();
|
||||||
|
|
||||||
|
$table->string('slug', 200);
|
||||||
|
$table->boolean('is_private')->default(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
$connection = $schema->getConnection();
|
||||||
|
$prefix = $connection->getTablePrefix();
|
||||||
|
$connection->statement('ALTER TABLE '.$prefix.'discussions ADD FULLTEXT title (title)');
|
||||||
|
},
|
||||||
|
|
||||||
|
'down' => function (Builder $schema) {
|
||||||
|
$schema->drop('discussions');
|
||||||
|
},
|
||||||
|
];
|
48
migrations/v1.0/create_posts_table.php
Normal file
48
migrations/v1.0/create_posts_table.php
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Flarum.
|
||||||
|
*
|
||||||
|
* For detailed copyright and license information, please view the
|
||||||
|
* LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use Flarum\Discussion\Discussion;
|
||||||
|
use Flarum\User\User;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Database\Schema\Builder;
|
||||||
|
|
||||||
|
// We need a full custom migration here, because we need to add the fulltext
|
||||||
|
// index for the content with a raw SQL statement after creating the table.
|
||||||
|
return [
|
||||||
|
'up' => function (Builder $schema) {
|
||||||
|
$schema->create('posts', function (Blueprint $table) {
|
||||||
|
$table->increments('id');
|
||||||
|
$table->foreignIdFor(Discussion::class, 'discussion_id');
|
||||||
|
$table->unsignedInteger('number')->nullable();
|
||||||
|
|
||||||
|
$table->dateTime('created_at');
|
||||||
|
$table->foreignIdFor(User::class, 'user_id')->nullable();
|
||||||
|
$table->string('type', 100)->nullable();
|
||||||
|
$table->mediumText('content')->nullable();
|
||||||
|
|
||||||
|
$table->dateTime('edited_at')->nullable();
|
||||||
|
$table->foreignIdFor(User::class, 'edited_user_id')->nullable();
|
||||||
|
$table->dateTime('hidden_at')->nullable();
|
||||||
|
$table->foreignIdFor(User::class, 'hidden_user_id')->nullable();
|
||||||
|
|
||||||
|
$table->string('ip_address', 45)->nullable();
|
||||||
|
$table->boolean('is_private');
|
||||||
|
|
||||||
|
$table->unique(['discussion_id', 'number']);
|
||||||
|
});
|
||||||
|
|
||||||
|
$connection = $schema->getConnection();
|
||||||
|
$prefix = $connection->getTablePrefix();
|
||||||
|
$connection->statement('ALTER TABLE '.$prefix.'posts ADD FULLTEXT content (content)');
|
||||||
|
},
|
||||||
|
|
||||||
|
'down' => function (Builder $schema) {
|
||||||
|
$schema->drop('posts');
|
||||||
|
}
|
||||||
|
];
|
19
migrations/v1.0/create_settings_table.php
Normal file
19
migrations/v1.0/create_settings_table.php
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Flarum.
|
||||||
|
*
|
||||||
|
* For detailed copyright and license information, please view the
|
||||||
|
* LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use Flarum\Database\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
|
||||||
|
return Migration::createTable(
|
||||||
|
'settings',
|
||||||
|
function (Blueprint $table) {
|
||||||
|
$table->string('key', 100)->primary();
|
||||||
|
$table->binary('value')->nullable();
|
||||||
|
}
|
||||||
|
);
|
35
migrations/v1.0/create_users_table.php
Normal file
35
migrations/v1.0/create_users_table.php
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Flarum.
|
||||||
|
*
|
||||||
|
* For detailed copyright and license information, please view the
|
||||||
|
* LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
use Flarum\Database\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
|
||||||
|
return Migration::createTable(
|
||||||
|
'users',
|
||||||
|
function (Blueprint $table) {
|
||||||
|
$table->increments('id');
|
||||||
|
$table->string('username', 100)->unique();
|
||||||
|
$table->string('email', 150)->unique();
|
||||||
|
$table->boolean('is_email_confirmed')->default(0);
|
||||||
|
$table->string('password', 100);
|
||||||
|
$table->string('avatar_url', 100)->nullable();
|
||||||
|
$table->text('preferences')->nullable();
|
||||||
|
$table->dateTime('join_time')->nullable();
|
||||||
|
$table->dateTime('last_seen_time')->nullable();
|
||||||
|
$table->dateTime('read_time')->nullable();
|
||||||
|
$table->dateTime('notification_read_time')->nullable();
|
||||||
|
$table->integer('discussions_count')->unsigned()->default(0);
|
||||||
|
$table->integer('comments_count')->unsigned()->default(0);
|
||||||
|
|
||||||
|
$table->index('joined_at');
|
||||||
|
$table->index('last_seen_at');
|
||||||
|
$table->index('discussion_count');
|
||||||
|
$table->index('comment_count');
|
||||||
|
}
|
||||||
|
);
|
141
src/Database/MigrationSourceRepository.php
Normal file
141
src/Database/MigrationSourceRepository.php
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of Flarum.
|
||||||
|
*
|
||||||
|
* For detailed copyright and license information, please view the
|
||||||
|
* LICENSE file that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Flarum\Database;
|
||||||
|
|
||||||
|
use Flarum\Extension\Extension;
|
||||||
|
use Flarum\Foundation\Application;
|
||||||
|
use Illuminate\Database\ConnectionInterface;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
class MigrationSourceRepository
|
||||||
|
{
|
||||||
|
protected $connection;
|
||||||
|
|
||||||
|
public function __construct(ConnectionInterface $connection)
|
||||||
|
{
|
||||||
|
$this->connection = $connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function flarum(): array
|
||||||
|
{
|
||||||
|
if (! $this->databaseVersion()) {
|
||||||
|
return $this->wrap($this->install());
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->wrap($this->upgrade());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function extension(Extension $extension): array
|
||||||
|
{
|
||||||
|
if (! $extension->hasMigrations()) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->wrap(glob($extension->getPath().'/migrations/*_*.php'));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function install(): array
|
||||||
|
{
|
||||||
|
// We read every file from the latest major/minor version migrations directory.
|
||||||
|
// Including the create_<table>_table statements.
|
||||||
|
$files = glob(__DIR__.'/../../migrations/'.$this->installedVersion(true).'/[0-9_]**.php');
|
||||||
|
|
||||||
|
// Sort by timestamp.
|
||||||
|
sort($files);
|
||||||
|
|
||||||
|
// Read and prepend the create_<table>_table statements.
|
||||||
|
$create = glob(__DIR__.'/../../migrations/'.$this->installedVersion(true).'/create_*_table.php');
|
||||||
|
|
||||||
|
return array_merge($create, $files);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function upgrade(): array
|
||||||
|
{
|
||||||
|
$files = [];
|
||||||
|
$add = false;
|
||||||
|
|
||||||
|
$directories = glob(__DIR__.'/../../migrations/*', GLOB_ONLYDIR);
|
||||||
|
sort($directories, SORT_NATURAL);
|
||||||
|
|
||||||
|
// Upgrade
|
||||||
|
// Loop over all version migrations directory until we find the version that is currently active.
|
||||||
|
foreach ($directories as $directory) {
|
||||||
|
$directoryVersion = substr(basename($directory), 1);
|
||||||
|
|
||||||
|
// We have found the directory matching the version database version. Start adding files.
|
||||||
|
if ($directoryVersion === $this->databaseVersion(true)) {
|
||||||
|
$add = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($add) {
|
||||||
|
// Selectively add files, but only include those matching the format YYYY_MM_DD_HHIISS_<something>.php
|
||||||
|
// This excludes the create_<table>_table.
|
||||||
|
$files = array_merge($files, glob(realpath($directory).'/[0-9_]**.php'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Once we found the version that is installed, we can quit.
|
||||||
|
// Theoretically this should never be necessary, it could just loop over all remaining ones.
|
||||||
|
if ($directoryVersion === $this->installedVersion(true)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort by timestamp.
|
||||||
|
sort($files);
|
||||||
|
|
||||||
|
return $files;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function shortVersion(string $version): string
|
||||||
|
{
|
||||||
|
if (preg_match('~(?<version>^[0-9]+\.[0-9]+)~', $version, $m)) {
|
||||||
|
return $m['version'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $version;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function installedVersion(bool $short = false): string
|
||||||
|
{
|
||||||
|
$version = Application::VERSION;
|
||||||
|
|
||||||
|
if ($short && $version) {
|
||||||
|
return $this->shortVersion($version);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $version;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function databaseVersion(bool $short = false): ?string
|
||||||
|
{
|
||||||
|
$version = $this->connection->getSchemaBuilder()->hasTable('settings')
|
||||||
|
? $this->connection->table('settings')->where('key', 'version')->value('value')
|
||||||
|
: null;
|
||||||
|
|
||||||
|
if ($short && $version) {
|
||||||
|
return $this->shortVersion($version);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $version;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function wrap(array $migrations): array
|
||||||
|
{
|
||||||
|
return collect($migrations)
|
||||||
|
->mapWithKeys(function (string $path) {
|
||||||
|
$path = realpath($path);
|
||||||
|
$path = Str::after($path, 'migrations/');
|
||||||
|
$basename = Str::before($path, '.php');
|
||||||
|
|
||||||
|
return [$path => $basename];
|
||||||
|
})
|
||||||
|
->toArray();
|
||||||
|
}
|
||||||
|
}
|
@@ -48,6 +48,10 @@ class Migrator
|
|||||||
* @var OutputInterface
|
* @var OutputInterface
|
||||||
*/
|
*/
|
||||||
protected $output;
|
protected $output;
|
||||||
|
/**
|
||||||
|
* @var MigrationSourceRepository
|
||||||
|
*/
|
||||||
|
protected $source;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new migrator instance.
|
* Create a new migrator instance.
|
||||||
@@ -64,6 +68,7 @@ class Migrator
|
|||||||
$this->files = $files;
|
$this->files = $files;
|
||||||
$this->repository = $repository;
|
$this->repository = $repository;
|
||||||
|
|
||||||
|
$this->source = new MigrationSourceRepository($connection);
|
||||||
$this->schemaBuilder = $connection->getSchemaBuilder();
|
$this->schemaBuilder = $connection->getSchemaBuilder();
|
||||||
|
|
||||||
// Workaround for https://github.com/laravel/framework/issues/1186
|
// Workaround for https://github.com/laravel/framework/issues/1186
|
||||||
@@ -73,13 +78,13 @@ class Migrator
|
|||||||
/**
|
/**
|
||||||
* Run the outstanding migrations at a given path.
|
* Run the outstanding migrations at a given path.
|
||||||
*
|
*
|
||||||
* @param string $path
|
* @param string $path
|
||||||
* @param Extension $extension
|
* @param Extension|null $extension
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function run($path, Extension $extension = null)
|
public function run(string $path, Extension $extension = null)
|
||||||
{
|
{
|
||||||
$files = $this->getMigrationFiles($path);
|
$files = $this->getMigrationFiles($extension);
|
||||||
|
|
||||||
$ran = $this->repository->getRan($extension ? $extension->getId() : null);
|
$ran = $this->repository->getRan($extension ? $extension->getId() : null);
|
||||||
|
|
||||||
@@ -91,12 +96,12 @@ class Migrator
|
|||||||
/**
|
/**
|
||||||
* Run an array of migrations.
|
* Run an array of migrations.
|
||||||
*
|
*
|
||||||
* @param string $path
|
* @param string $path
|
||||||
* @param array $migrations
|
* @param array $migrations
|
||||||
* @param Extension $extension
|
* @param Extension|null $extension
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
public function runMigrationList($path, $migrations, Extension $extension = null)
|
public function runMigrationList(string $path, array $migrations, Extension $extension = null)
|
||||||
{
|
{
|
||||||
// First we will just make sure that there are any migrations to run. If there
|
// First we will just make sure that there are any migrations to run. If there
|
||||||
// aren't, we will just make a note of it to the developer so they're aware
|
// aren't, we will just make a note of it to the developer so they're aware
|
||||||
@@ -118,13 +123,13 @@ class Migrator
|
|||||||
/**
|
/**
|
||||||
* Run "up" a migration instance.
|
* Run "up" a migration instance.
|
||||||
*
|
*
|
||||||
* @param string $path
|
* @param string $path
|
||||||
* @param string $file
|
* @param string $file
|
||||||
* @param string $path
|
* @param Extension|null $extension
|
||||||
* @param Extension $extension
|
|
||||||
* @return void
|
* @return void
|
||||||
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
protected function runUp($path, $file, Extension $extension = null)
|
protected function runUp(string $path, string $file, Extension $extension = null)
|
||||||
{
|
{
|
||||||
$migration = $this->resolve($path, $file);
|
$migration = $this->resolve($path, $file);
|
||||||
|
|
||||||
@@ -203,30 +208,9 @@ class Migrator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function getMigrationFiles(Extension $extension = null): array
|
||||||
* Get all of the migration files in a given path.
|
|
||||||
*
|
|
||||||
* @param string $path
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getMigrationFiles($path)
|
|
||||||
{
|
{
|
||||||
$files = $this->files->glob($path.'/*_*.php');
|
return $extension ? $this->source->extension($extension) : $this->source->flarum();
|
||||||
|
|
||||||
if ($files === false) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
$files = array_map(function ($file) {
|
|
||||||
return str_replace('.php', '', basename($file));
|
|
||||||
}, $files);
|
|
||||||
|
|
||||||
// Once we have all of the formatted file names we will sort them and since
|
|
||||||
// they all start with a timestamp this should give us the migrations in
|
|
||||||
// the order they were actually created by the application developers.
|
|
||||||
sort($files);
|
|
||||||
|
|
||||||
return $files;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -459,20 +459,7 @@ class Extension implements Arrayable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public function migrate(Migrator $migrator, string $direction)
|
||||||
* Tests whether the extension has migrations.
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function hasMigrations()
|
|
||||||
{
|
|
||||||
return realpath($this->path.'/migrations/') !== false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
public function migrate(Migrator $migrator, $direction = 'up')
|
|
||||||
{
|
{
|
||||||
if (! $this->hasMigrations()) {
|
if (! $this->hasMigrations()) {
|
||||||
return;
|
return;
|
||||||
@@ -485,6 +472,16 @@ class Extension implements Arrayable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests whether the extension has migrations.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasMigrations()
|
||||||
|
{
|
||||||
|
return realpath($this->path.'/migrations/') !== false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates an array result for the object.
|
* Generates an array result for the object.
|
||||||
*
|
*
|
||||||
|
Reference in New Issue
Block a user