Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Id Contracts Laravel Package

boson-php/id-contracts

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require boson-php/id-contracts
    

    No additional configuration is required—this is a pure contract package with zero runtime dependencies.

  2. First Use Case Define a simple identifier contract for a domain entity (e.g., UserId):

    use Boson\IdContracts\Id;
    
    class UserId implements Id
    {
        private string $value;
    
        public function __construct(string $value)
        {
            $this->value = $value;
        }
    
        public function value(): string
        {
            return $this->value;
        }
    }
    

    Use it in a repository or service:

    class UserRepository
    {
        public function findById(UserId $id): ?User
        {
            // Fetch user logic...
        }
    }
    
  3. Key Files to Explore

    • src/Id.php: The core Id interface.
    • src/IdGenerator.php: Optional trait for generating IDs (if extended).

Implementation Patterns

1. Domain-Driven Design (DDD) Integration

  • Aggregate Roots: Use Id contracts as root identifiers for aggregates.
    class Order implements AggregateRoot
    {
        public function __construct(
            public OrderId $id,
            public CustomerId $customerId,
            public Collection<OrderItem> $items
        ) {}
    }
    
  • Value Objects: Embed Id in value objects for relationships.
    class OrderItem
    {
        public function __construct(
            public ProductId $productId,
            public int $quantity
        ) {}
    }
    

2. Type Safety with PHP 8+

  • Leverage union types for flexible ID handling:
    public function findById(string|UserId $id): ?User
    {
        $id = is_string($id) ? new UserId($id) : $id;
        // ...
    }
    
  • Use constructor property promotion with Id types:
    class UserService
    {
        public function __construct(private UserId $userId) {}
    }
    

3. Database Abstraction

  • ORM Integration: Cast database IDs to Id objects in repositories.
    class UserRepository
    {
        public function findById(string $rawId): ?User
        {
            return User::query()->find(new UserId($rawId));
        }
    }
    
  • Query Builder: Extend query builders to accept Id objects:
    class UserQueryBuilder
    {
        public function whereId(UserId $id): self
        {
            return $this->where('id', $id->value());
        }
    }
    

4. API Layer

  • DTOs: Convert API input to Id objects in request handlers.
    class StoreUserRequest
    {
        public function toUserId(): UserId
        {
            return new UserId($this->id);
        }
    }
    
  • Serialization: Customize JSON serialization for Id values.
    class UserId implements JsonSerializable
    {
        public function jsonSerialize(): string
        {
            return $this->value();
        }
    }
    

5. Testing

  • Mocking: Use Id interfaces in unit tests for isolation.
    $mockId = $this->createMock(Id::class);
    $mockId->method('value')->willReturn('test-id');
    
  • Factories: Generate test IDs with IdGenerator (if extended).

Gotchas and Tips

Pitfalls

  1. Over-Engineering

    • Avoid creating Id classes for every primitive ID (e.g., PostId, CommentId) if the domain doesn’t require it. Use string or int directly for simple cases.
    • Tip: Reserve Id contracts for aggregate roots or globally unique identifiers.
  2. Performance Overhead

    • Instantiating Id objects adds minor overhead. Benchmark if used in hot paths (e.g., loop iterations).
    • Tip: Use value objects (e.g., StringObject) for lightweight wrappers if needed.
  3. Database Migrations

    • Ensure database columns match the Id::value() return type (e.g., VARCHAR for string IDs).
    • Gotcha: Forgetting to cast IDs during migration can cause type mismatches.
  4. Serialization Quirks

    • Some serializers (e.g., Laravel’s Illuminate\Support\Collection) may not handle custom Id objects by default.
    • Fix: Implement Arrayable or JsonSerializable for seamless integration.

Debugging

  1. Type Errors

    • If you see Argument of type 'string' is not assignable to 'Id', ensure all entry points (APIs, factories) convert raw values to Id objects.
    • Debug: Use instanceof checks or IDE hints to catch mismatches early.
  2. Circular References

    • Bidirectional relationships (e.g., UserId in Order and OrderId in User) can cause serialization loops.
    • Solution: Implement __toString() or JsonSerializable to break cycles.

Extension Points

  1. Custom ID Generators

    • Extend IdGenerator to create domain-specific IDs (e.g., UUIDs, ULIDs).
      class UuidIdGenerator implements IdGenerator
      {
          public function generate(): string
          {
              return Uuid::generate()->toString();
          }
      }
      
  2. Validation

    • Add validation logic to Id classes (e.g., regex for UUIDs).
      class UserId implements Id
      {
          public function __construct(string $value)
          {
              if (!preg_match('/^[0-9a-f]{8}-[0-9a-f]{4}/', $value)) {
                  throw new InvalidArgumentException('Invalid UUID format.');
              }
              $this->value = $value;
          }
      }
      
  3. Laravel-Specific

    • Eloquent Models: Use accessors to auto-convert database IDs.
      class User extends Model
      {
          public function getIdAttribute(string $value): UserId
          {
              return new UserId($value);
          }
      }
      
    • Service Providers: Bind Id interfaces to concrete implementations for dependency injection.
      $this->app->bind(UserId::class, function () {
          return new UserId('default-id');
      });
      
  4. API Resources

    • Customize JSON:API or REST responses to include Id values.
      class UserResource extends JsonResource
      {
          public function toArray($request)
          {
              return [
                  'id' => $this->resource->id->value(),
                  // ...
              ];
          }
      }
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours