Mastering Laravel 12.21: Global Factory Controls and Attribute Singletons

Overview

introduces significant quality-of-life improvements that streamline testing workflows and database querying. This update focuses on reducing boilerplate when handling model relationships in factories, simplifying complex range queries between multiple columns, and leveraging
PHP
attributes to manage the service container more declaratively. These features help developers maintain cleaner codebases while improving application performance.

Prerequisites

To follow this tutorial, you should have a solid grasp of:

  • PHP 8.2+: Specifically understanding attributes and classes.
  • Eloquent ORM: Familiarity with factories and model relationships.
  • Service Container: Basic knowledge of singletons and dependency injection.

Key Libraries & Tools

  • Laravel Framework 12.21: The core PHP framework receiving these updates.
  • Eloquent Factories: Tools for generating fake data for testing.
  • PHP Attributes: Native metadata used for container configuration.

Code Walkthrough

Disabling Factory Relationships

When testing, you often want to create a model without triggering the creation of its parent relationships. Previously, you had to chain withoutParents() on every call. Now, you can disable them globally for a factory.

// In a test or service provider
PostFactory::don'tExpandRelationshipsByDefault();

// This now returns a model with user_id as null without creating a User
$post = Post::factory()->make();

querying Ranges Between Columns

Instead of manual where clauses to check if a single value (like a timestamp) falls between two different columns (like start_date and end_date), use the expressive whereValueBetween method.

$now = now();
$currentEvents = Event::whereValueBetween($now, ['start_date', 'end_date'])->get();

Class-Level Singletons

You can now skip the AppServiceProvider binding for singletons by using

attributes directly on the class definition.

namespace App\Services;

use Illuminate\Container\Attributes\Singleton;

#[Singleton]
class Counter
{
    public int $count = 0;
}

Syntax Notes

  • don'tExpandRelationshipsByDefault(): This static method acts as a global toggle for the factory's internal expansion logic.
  • #[Singleton]: This attribute instructs the
    Laravel
    container to resolve the same instance every time the class is requested, centralizing configuration within the class itself.

Practical Examples

  • Performance Tuning: Use don'tExpandRelationshipsByDefault in large test suites to prevent unnecessary database writes, significantly cutting down execution time.
  • Event Management: The whereValueBetween method is perfect for booking systems, scheduling apps, or any platform where you must validate a specific time against a duration defined by two columns.

Tips & Gotchas

  • Database Constraints: Remember that disabling factory parents will cause create() to fail if your database schema has a NOT NULL constraint on the foreign key.
  • Global State: Be careful with global factory settings in tests; ensure they don't leak into other tests by resetting them or using them within specific test groups.
3 min read