Paulund

Disable Laravel Model Events On Factories

Recently I had to create a model factory for my tests but I didn't want it to fire the standard Laravel model events.

Model events are fired whenever a record is created, updated, deleted and retrieved.

You can learn more about model events on the Laravel documentation.

Normally to remove the model events you can use the flushEventListeners method on the HasEvents trait.

    /**
     * Remove all of the event listeners for the model.
     *
     * @return void
     */
    public static function flushEventListeners()
    {
        if (! isset(static::$dispatcher)) {
            return;
        }

        $instance = new static;

        foreach ($instance->getObservableEvents() as $event) {
            static::$dispatcher->forget("eloquent.{$event}: ".static::class);
        }

        foreach (array_values($instance->dispatchesEvents) as $event) {
            static::$dispatcher->forget($event);
        }
    }

When using Laravel factories they go through the FactoryBuilder class, which has the Macroable trait. This means we can easily extend this class to do what we want it to do.

In your factory classes you can use the following code.

<?php
use \Illuminate\Database\Eloquent\FactoryBuilder;
FactoryBuilder::macro('disableEvents', function () {
    $this->class::flushEventListeners();
  
    return $this;
});

Now in your tests when building your factory you can use the disableEvents method.

<?php

factory(User::class)->disableEvents()->create();