Skip to content

Instantly share code, notes, and snippets.

@palypster
Created March 14, 2020 14:06
Show Gist options
  • Save palypster/2ad4c87afb83382cb92e4c5e0a485187 to your computer and use it in GitHub Desktop.
Save palypster/2ad4c87afb83382cb92e4c5e0a485187 to your computer and use it in GitHub Desktop.
Introducing beforeCreating
<?php
namespace App\Providers;
use App\ExtendedFactory;
use Faker\Generator as FakerGenerator;
use Illuminate\Database\Eloquent\Factory as EloquentFactory;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*
* @return void
*/
public function register()
{
//
}
/**
* Bootstrap any application services.
*
* @return void
*/
public function boot()
{
$this->app->singleton(EloquentFactory::class, function ($app) {
return ExtendedFactory::construct(
$app->make(FakerGenerator::class), $this->app->databasePath('factories')
);
});
}
}
<?php
namespace App;
use Illuminate\Database\Eloquent\Factory;
class ExtendedFactory extends Factory {
/**
* The registered after creating callbacks.
*
* @var array
*/
protected $beforeCreating = [];
/**
* Define a callback to run before creating a model.
*
* @param string $class
* @param callable $callback
* @param string $name
* @return $this
*/
public function beforeCreating($class, callable $callback, $name = 'default')
{
$this->beforeCreating[$class][$name][] = $callback;
return $this;
}
/**
* Define a callback to run before creating a model with given state.
*
* @param string $class
* @param string $state
* @param callable $callback
* @return $this
*/
public function beforeCreatingState($class, $state, callable $callback)
{
return $this->beforeCreating($class, $callback, $state);
}
/**
* Create a builder for the given model.
*
* @param string $class
* @return \Illuminate\Database\Eloquent\FactoryBuilder
*/
public function of($class)
{
return new ExtendedFactoryBuilder(
$class, $this->definitions, $this->states,
$this->afterMaking, $this->afterCreating, $this->beforeCreating, $this->faker
);
}
}
<?php
namespace App;
use Faker\Generator as Faker;
use Illuminate\Database\Eloquent\FactoryBuilder;
use Illuminate\Database\Eloquent\Model;
class ExtendedFactoryBuilder extends FactoryBuilder
{
/**
* @var array
*/
private $beforeCreating = [];
public function __construct($class, array $definitions, array $states,
array $afterMaking, array $afterCreating, array $beforeCreating, Faker $faker)
{
parent::__construct($class, $definitions, $states, $afterMaking, $afterCreating, $faker);
$this->beforeCreating = $beforeCreating;
}
/**
* Create a collection of models and persist them to the database.
*
* @param array $attributes
* @return \Illuminate\Database\Eloquent\Collection|\Illuminate\Database\Eloquent\Model|mixed
*/
public function create(array $attributes = [])
{
$results = $this->make($attributes);
if ($results instanceof Model) {
$this->callBeforeCreating(collect([$results]));
$this->store(collect([$results]));
$this->callAfterCreating(collect([$results]));
} else {
$this->callBeforeCreating(collect([$results]));
$this->store($results);
$this->callAfterCreating($results);
}
return $results;
}
/**
* Run before creating callbacks on a collection of models.
*
* @param \Illuminate\Support\Collection $models
* @return void
*/
public function callBeforeCreating($models)
{
$this->callBefore($this->beforeCreating, $models);
}
/**
* Call before callbacks for each model and state.
*
* @param array $beforeCallbacks
* @param \Illuminate\Support\Collection $models
* @return void
*/
protected function callBefore(array $beforeCallbacks, $models)
{
$states = array_merge(['default'], $this->activeStates);
$models->each(function ($model) use ($states, $beforeCallbacks) {
foreach ($states as $state) {
$this->callBeforeCallbacks($beforeCallbacks, $model, $state);
}
});
}
/**
* Call before callbacks for each model and state.
*
* @param array $beforeCallbacks
* @param \Illuminate\Database\Eloquent\Model $model
* @param string $state
* @return void
*/
protected function callBeforeCallbacks(array $beforeCallbacks, $model, $state)
{
if (! isset($beforeCallbacks[$this->class][$state])) {
return;
}
foreach ($beforeCallbacks[$this->class][$state] as $callback) {
$callback($model, $this->faker);
}
}
/**
* Determine if the given state has an "after" of "before" callback.
*
* @param string $state
* @return bool
*/
protected function stateHasAfterCallback($state)
{
return isset($this->afterMaking[$this->class][$state]) ||
isset($this->beforeCreating[$this->class][$state]) ||
isset($this->afterCreating[$this->class][$state]);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment