-
Notifications
You must be signed in to change notification settings - Fork 11.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
About migrations and multiple class names #5899
Comments
Just use different names? recreate_news_table? |
No, this is still a bug. If I have to recreate it again, I'd have to use recreate_news_table_again, and then recreate_news_table_again_again. This is not what we're looking for. As I said, migrations should not have an unique name, because this is a wrong concept. Also, the migrations filename has a timestamp on it, meaning it should NOT be unique, but the classes are (???). |
This is not a bug. It's just an inconvenience. |
Can we have core just add the timestamp to the class name? Something like Edit: I've modified MigrationCreator.php to reflect my idea above, though I doubt Taylor would accept it as it wouldn't jive with the LR philosophy: 99fb2c4 |
@jsanc623 It seems a good alternative with much less code, but I'll ask again, why do migrations uses classes rather than lambdas? They're very similar to routes. Just imagine if each route had one class... |
@joaocagnoni Not quite sure on the design decision behind using classes - though I would imagine its easier to organize the migration. For example, in a project I worked on, this was one of the migrations:
Doing the above with lambdas would be a pain and would create very ugly code. |
The timestamp is added to migration filename automatically. Why just we can't add same timestamp to migration class name as well? |
Maybe something to discus on the forums/irc. |
@jsanc623 Why are you checking if a table exists? Are you changing the DB without migrations? It's a bad practice. I think the code i'll look much cleaner with closures. There's no sense at creating a class using only 2 methods in 99% of the time. So here it is: Migration::create(function() {
Schema::create('news', function ($table) {
$table->string("title");
$table->string("category");
$table->string("author");
});
}, function() {
Schema::drop('news');
}); Syntax looks like a "hover" on jQuery. Everybody understands a hover. |
Why not just extends <?php namespace App\Database\Migrations;
class MigrationCreator extends \Illuminate\Database\Migrations\MigrationCreator
{
// customize.
} Create your own <?php namespace App\Providers;
use App\Database\Migrations\MigrationCreator;
class MigrationServiceProvider extends \Illuminate\Database\MigrationServiceProvider
{
/**
* Register the migration creator.
*
* @return void
*/
protected function registerCreator()
{
$this->app->bindShared('migration.creator', function($app)
{
return new MigrationCreator($app['files']);
});
}
} This however will not work if you use any package that use migration, and I don't think most package developer would love the idea to change the migration structure. p/s: Also maintaining a SaaS, and don't have a problem with current implementation. |
@crynobone Thanks for that, I've been able to override the For reference, here's how the class looks like <?php
namespace App\Database\Migrations;
class MigrationCreator extends \Illuminate\Database\Migrations\MigrationCreator
{
protected function getClassName($name)
{
return parent::getClassName($name) . 'Migration_' . str_replace('_', '', $this->getDatePrefix());
}
} |
Forgot a thing, for the migrate to work, I had to override the For reference, here's how the class looks like <?php
namespace App\Database\Migrations;
use Illuminate\Support\Str;
class Migrator extends \Illuminate\Database\Migrations\Migrator
{
/**
* Resolve a migration instance from a file.
*
* @param string $file
* @return object
*/
public function resolve($file)
{
$fileParts = explode('_', $file);
$class = Str::studly(implode(' ', array_slice($fileParts, 4))) . 'Migration_' . implode('', array_slice($fileParts, 0, 4));
if (!class_exists($class)) {
return parent::resolve($file);
}
return new $class;
}
} |
Had a fairly nasty deploy because of that "inconvenience". @isometriq That's sensible approach. Thanks for your solution. |
@asvae I had the exact same experience yesterday. I think when |
Was anything ever made of this? I am going to go ahead and just start using the filename as the classname with the big timestamp appended to it. |
For php7+ and laravel 5.4 This code worked great for me. `<?php namespace App\Providers; class MigrationServiceProvider extends \Illuminate\Database\MigrationServiceProvider
}` And add it to config/app.php |
This sucks.. on Lumen the Why isn't fixed!? maybe you could do at least something like @asvae indeed ..i can hear Doctrine calling me |
In case someone is interested, I was able to hack it by overriding the Kernel included in my app
The MigrationCreator, Migrator and MigrationServiceProbider described above are still needed. This is a hack so that my registration of the provider is the last one ..sadly it's not elegant, but does the job right? Now I'm able to create migrations with timestamp and then use them with all migrate:* commands. If you want to use this in your Lumen installation, please do some test before... |
Yeah, I'm maintaining a project with about 200 migrations and the migration names at this point are just ridiculous. On the topic of using lambdas (what @joaocagnoni mentioned), I don't think that would be a better solution. In our case we have "system" migrations (the central database) and we have "tenant" migrations in a different folder (each client's database). Some tenant tables are exactly the same as the system ones so we just instantiate the system migration class and run it in a tenant (we subclassed our own migration class to be able to pass the DB connection around). This would not have been pretty with closures. Still I feel your pain and wish the problem you mention had a better solution. |
Same situation as above. What's worse is that adding and executing migrations one by one used to work but after upgrading laravel (unsure which version changed this, went from 5.2->6.x) you can't create new migrations from artisan without fixing all previous name conflicts. edit May be a good thing now that I think about it. |
Thanks everyone! Laravel 7. filename: m200703_124707_create_user_table <?php
namespace App\Providers;
use Illuminate\Database\Migrations\MigrationCreator;
use Illuminate\Database\Migrations\Migrator;
class MigrationServiceProvider extends \Illuminate\Database\MigrationServiceProvider
{
protected function registerMigrator()
{
$this->app->singleton('migrator', function ($app) {
$repository = $app['migration.repository'];
return new class($repository, $app['db'], $app['files']) extends Migrator {
public function resolve($file)
{
$class = $file;
if (!class_exists($class)) {
return parent::resolve($file);
}
return new $class;
}
};
});
}
protected function registerCreator()
{
$this->app->singleton('migration.creator', function ($app) {
return new class($app['files'], $app->basePath('stubs')) extends MigrationCreator {
protected function getDatePrefix()
{
return 'm' . date('ymd_His');
}
protected function getClassName($name)
{
return $this->getDatePrefix() . '_' . $name;
}
};
});
}
} And add it to config/app.php |
Why is this closed yet? |
Fully agree. What's the problem with making this behavior bc-compatible with config param? |
I think this could be solved if migrations were anonymous classes:
I don't see the point on having names for migration classes, considering that the migration key is the file name anyways. |
@thiagorb I couldn't agree more. 👍🏼 |
Laravel 8 migration not working with different namespace and different migration folder |
I'll try to simplify my problem with a common case:
1- On the version 1.0 of my app I create a migration "create_news_table".
2- On 1.1, I create a migration which removes the news table.
3- On 1.2, I try to create the migration "create_news_table" with a totally different table.
On the step 3, the class name of the migration is the same of the first migration (causing an error). If I rename the class name of the last migration, the first one will be created.
Any solution for this? Why do we have to use names for migrations? They should have been using lambdas intead of classes as they are not unique and don't have an identity.
I found another issue talking about this, but the comment of taylorotwell is ridiculous: #5459
You shouldn't really answer issues like this if you don't want to see Laravel being used only for static sites and/or landing pages like CodeIgniter was. It's a problem that affects all the users that's using Laravel on complex websites/systems with a short to medium sized versions story.
The text was updated successfully, but these errors were encountered: