Skip to content

[5.8] Migration Events - #28342

Merged
taylorotwell merged 11 commits into
laravel:5.8from
alexbowers:feature/migration-events
May 2, 2019
Merged

taylorotwell merged 11 commits into
laravel:5.8from
alexbowers:feature/migration-events

Conversation

@alexbowers

Copy link
Copy Markdown
Contributor

This PR adds events to migrations.

Events added:

migrations.beforeAll:up
migrations.afterAll:up
migrations.beforeAll:down
migrations.afterAll:down
migrations.before:up
migrations.after:up
migrations.before:down
migrations.after:down

The benefit of having these methods is it will allow users to clear cache on migrations, perform maintainence if necessary.

The before:up, before:down, after:up and after:down methods all receive the migration that was ran as a parameter, so that you can check which migration you are running to see if you need to perform any specific action.

Fixes laravel/ideas#854

Comment thread src/Illuminate/Database/MigrationServiceProvider.php Outdated
Comment thread src/Illuminate/Database/Migrations/Migrator.php Outdated

@driesvints driesvints left a comment •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're on the right track but I believe we can do better. First of all: there's no need for the static keyword anywhere. Check my comments.

I also believe it might be better if we used dedicated classes instead of the string based ones. There's an Illuminate\Database\Events where you can add these.

Based on your list above these could be:

  • UpMigrationsStarted
  • UpMigrationsEnded
  • DownMigrationsStarted
  • DownMigrationsEnded
  • UpMigrationStarted
  • UpMigrationEnded
  • DownMigrationStarted
  • DownMigrationEnded

And might I suggest adding:

  • MigrationsStarted
  • MigrationsEnded
  • MigrationStarted
  • MigrationEnded

Maybe we only need the last four above? Do we really need to know if a migration is a down migration or not?

Nice job so far 👍

Comment thread src/Illuminate/Database/Migrations/Migrator.php Outdated
Comment thread src/Illuminate/Database/Migrations/Migrator.php Outdated
Comment thread src/Illuminate/Database/Migrations/Migrator.php
Comment thread src/Illuminate/Database/Migrations/Migrator.php Outdated
Comment thread src/Illuminate/Database/Migrations/Migrator.php Outdated
Comment thread src/Illuminate/Database/Migrations/Migrator.php Outdated
@alexbowers

Copy link
Copy Markdown
Contributor Author

@driesvints I have made those changes. Couple of things to note.

For the events, in the old system there was wildcard support, which is why I have put a Contract in there, since that allows the same thing:

Events::listen(\Illuminate\Contracts\Database\MigrationEvent::class, ...);

I have also changed how data is passed around, the events now instead store the migration and the direction, instead of it being a separate parameter.

@driesvints driesvints left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice job man. Just a few small things and the StyleCI failures.

Comment thread src/Illuminate/Database/Events/MigrationEvent.php Outdated
Comment thread src/Illuminate/Database/Migrations/Migrator.php Outdated
Comment thread src/Illuminate/Database/Migrations/Migrator.php Outdated
Comment thread src/Illuminate/Database/Migrations/Migrator.php Outdated

@driesvints driesvints left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few more things. Also: this PR could also use some tests.

Comment thread src/Illuminate/Contracts/Database/MigrationEvent.php Outdated
Comment thread src/Illuminate/Database/Migrations/Migrator.php Outdated
@deleugpn

deleugpn commented Apr 26, 2019 •

Copy link
Copy Markdown
Contributor

I would like this as well. I have some migrations that change information inside the database and I wanted to write tests to make sure the migration was doing the expected process, I ended up doing this:

    private function afterMigration(string $migrationName, callable $callback)
    {
        DB::listen(function (QueryExecuted $query) use ($migrationName, $callback) {
            if (isset($query->bindings[0]) && $query->bindings[0] === $migrationName) {
                $callback();
            }
        });
    }


    private function migrate()
    {
        $this->afterMigration('2018_11_14_154917_some_migration', function () {
            // Add some seed data at this point before changing the database format
        });

        Artisan::call('migrate');
    }

@alexbowers

Copy link
Copy Markdown
Contributor Author

@driesvints I have done the above, but I was having some trouble with the tests. Not sure why, but Event:assertDispatched was not working for me.

Any advice? As it stands, it basically is fine if it has assertions.

Not ideal, but it does test it.

@driesvints driesvints left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any advice? As it stands, it basically is fine if it has assertions.

Current assertions are fine 👍

I see you've added a merge commit. Can you try to purge this commit and use rebase instead? Because this adds unnecessary extra commits to the PR.

Comment thread tests/Integration/Database/MigrateWithRealpathTest.php Outdated
Comment thread src/Illuminate/Database/Migrations/Migrator.php Outdated
Comment thread src/Illuminate/Database/Migrations/Migrator.php Outdated
@alexbowers

Copy link
Copy Markdown
Contributor Author

@driesvints I can try to collapse the commits down. Do you want me to just squash them all?

@alexbowers

Copy link
Copy Markdown
Contributor Author

@driesvints I haven't been able to get the merge commit fixed. Any chance when this is merged it just gets squashed instead? Or can you help me with fixing the merge commit? Either or is fine by me :D

Comment thread src/Illuminate/Database/Migrations/Migrator.php Outdated

@driesvints driesvints left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost there.

Comment thread src/Illuminate/Database/Migrations/Migrator.php Outdated
@driesvints

Copy link
Copy Markdown
Member

@alexbowers squashing can't be done anymore because you're used merged commits. If you want to fix this you'll need to start a new branch from 5.8 and cherry pick your commits on top. You've used multiple merge commits atm.

@alexbowers

Copy link
Copy Markdown
Contributor Author

Ok i'll figure it out this evening. Might have to be a new PR or a force push or something.

@driesvints

Copy link
Copy Markdown
Member

@alexbowers should be able to do it with a force push. Don't need to open up a new pr. Don't forget to backup your branch first to prevent losing stuff.

@alexbowers

Copy link
Copy Markdown
Contributor Author

Ok @driesvints I think thats worked.

@driesvints driesvints left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice job 👍

@alexbowers

Copy link
Copy Markdown
Contributor Author

Any more changes, or are you good with this?

@driesvints

Copy link
Copy Markdown
Member

@alexbowers see the approval above :)

@driesvints

Copy link
Copy Markdown
Member

You could perhaps squash your commits.

@alexbowers

Copy link
Copy Markdown
Contributor Author

Ah missed that. It should be able to be squashed by the merger, since if I was to squash now that'd be another force push. I'd rather avoid that just incase I bin it :D

Comment thread src/Illuminate/Contracts/Database/Events/Migration.php
@devcircus

Copy link
Copy Markdown
Contributor

Just a thought, but in Illuminate/Auth/Events the namespace delineates the classes within as events. The classes themselves are "Login", "Logout". etc. So Illuminate/Contracts/Database/Events/Migration makes sense in that context.

@driesvints

Copy link
Copy Markdown
Member

@devcircus right. Let's just leave it at this.

@ttomdewit

Copy link
Copy Markdown

Thanks for everyone's hard work this past week, hopefully it'll be considered and merged. 👍

@taylorotwell
taylorotwell merged commit 3dd96ad into laravel:5.8 May 2, 2019
@alexbowers
alexbowers deleted the feature/migration-events branch May 2, 2019 20:29
@jasonmccreary

Copy link
Copy Markdown
Contributor

Were these added to the docs anywhere? Glad to do it. Just didn't want to duplicate work.

@driesvints

Copy link
Copy Markdown
Member

@jasonmccreary I don't think they were.

@wouterrutgers

Copy link
Copy Markdown
Contributor

Was it intended that no events will be executed if there are no migrations available? (See: https://github.com/laravel/framework/blob/5.8/src/Illuminate/Database/Migrations/Migrator.php#L141)

A use case for where it would be useful to always send the events:

We have our own migrator which will run a migration multiply times with different variables given to the migration. We run this migrator on the MigrationsEnded event. When we have no default migrations but only custom migrations the event is never executed. Therefor our custom migrations are never ran.

@ttomdewit

Copy link
Copy Markdown

@wouter2203 Personally I’ve never thought about that particular requirement.

@wouterrutgers

wouterrutgers commented Aug 2, 2019 •

Copy link
Copy Markdown
Contributor

We were just calling another command after php artisan migrate that would run our own migrations. Then we read somewhere (laravel-news I think) that migration events were available, so we deleted that command and used the events. Only to notice that our custom migrations were not always running..

Would be cool if we get some extra events, something in the lines of Starting, Running, Ended. Where Running would just never be fired when no migrations are available.

@driesvints

Copy link
Copy Markdown
Member

@wouter2203 you're always free to send in a follow-up pr. Make sure to thoroughly describe your use-case.

@ArlonAntonius

Copy link
Copy Markdown

I don't know @wouter2203's exact use case, but I actually need something among the same lines and was wondering if you guys would be open to the following:

Would love to hear your feedback on this as well @wouter2203 would it help with your use case or would you also need the Running Event?

@driesvints

Copy link
Copy Markdown
Member

@ArlonAntonius that sounds reasonable. Let's wait to see what @wouter2203 thinks.

@wouterrutgers

Copy link
Copy Markdown
Contributor

@ArlonAntonius If the Ended event is also fired when no migrations are ran it'll work for my use case. The normal migrations should run before the custom migrations, so we need to listen for Ended. And in that case the Ended migration would just contain an empty array.

To elaborate on (one of) my use case(s):

Let's say we have a multilingual cms system where users can manage the mailings that are send by that system. When a new mailing is added we'll make a custom migration that'll run the following:

    public function up($locale)
    {
        Mailing::create([
            'locale' => $locale,
            'template' => 'A new mailing',
        ]);
    }

To have the above work we need the normal migrations to be ran first, otherwise the mailings table would not exist.

Now if we have configured ['en', 'nl', 'de'] as locales for that cms the above is executed 3 times, each time with a different $locale.

Ofcourse the mailing would be added with an English template for all 3 locales, but now the user can edit the template for nl and de in the cms.

I can create a pull request in which the Starting and Ended events are implemented, If you agree with both the Starting and Ended events always firing.

@ArlonAntonius

Copy link
Copy Markdown

@wouter2203 Sounds good to me should be enough to fix my actual use case, please mention me @ the PR so I can double-check.

@ttomdewit

Copy link
Copy Markdown

Thanks for taking this to the next level.

@gasparyanm

gasparyanm commented May 12, 2020 •

Copy link
Copy Markdown

Laravel Migration event listeners don't work in my case.

namespace App\Providers;

use App\Listeners\DeleteUnitsAwsImages;
use Illuminate\Database\Events\MigrationsStarted;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Event;

class EventServiceProvider extends ServiceProvider
{
    /**
     * The event listener mappings for the application.
     *
     * @var array
     */
    protected $listen = [
        MigrationsStarted::class => [
            DeleteUnitsAwsImages::class,
        ]
    ];
....

@alexbowers

Copy link
Copy Markdown
Contributor Author

Please can you open an issue if you think this is a bug

@gasparyanm

gasparyanm commented May 12, 2020 •

Copy link
Copy Markdown

Please can you open an issue if you think this is a bug

I opened the discussion, as I need something like support or additional info related to doc
Please see here #32778 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fire events on migrations