Eloquent
Query Builder vs Scopes
- Use Query Builder for simple queries or one-off queries
- Use Scopes for reusable queries
- Use Scopes for complex queries
- Use Scopes for queries that require multiple conditions
Large Number of Query Scopes
If you have a 3+ query scopes use a query builder object instead.
class User extends Model
{
#[\Override]
public function newEloquentBuilder($query): UserEloquentBuilder
{
return new UserEloquentBuilder($query);
}
}
class UserEloquentBuilder extends EloquentBuilder
{
public function active(): self
{
return $this->where('active', true);
}
public function hasPosts(): self
{
return $this->whereHas('posts');
}
public function hasComments(): self
{
return $this->whereHas('comments');
}
}
Reusable Query Scopes
If you have a query scope that is used in multiple models, use a trait.
trait HasActive
{
public function scopeActive($query)
{
return $query->where('active', true);
}
}
Eager Loading
- Use Eager Loading to reduce the number of queries and N+1 problems
$users = User::with('posts')->get();
Factories
- Use factories to generate test data
- If possible, use states to generate different data
- Folder structure should match the models
final class UserFactory extends Factory
{
protected $model = User::class;
public function definition(): array
{
return [
'name' => $this->faker->name,
'email' => $this->faker->unique()->safeEmail,
'password' => Hash::make('password'),
];
}
public function admin(): self
{
return $this->state(function (array $attributes) {
return [
'is_admin' => true,
];
});
}
}