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

Contracts Laravel Package

dragon-code/contracts

Dragon Code Contracts provides a lightweight set of PHP interfaces (contracts) you can reuse across any project to standardize key behaviors, improve type-safety, and keep implementations decoupled. Ideal as a shared dependency for packages and applications.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require dragon-code/contracts
    

    Add to composer.json under require-dev if only for testing.

  2. First Use Case: Implement a Dtoable contract for a data transfer object:

    use DragonCode\Contracts\Dto\Dtoable;
    
    class UserDto implements Dtoable
    {
        public function toArray(): array
        {
            return [
                'name' => $this->name,
                'email' => $this->email,
            ];
        }
    }
    
  3. Where to Look First:

    • Browse the contracts directory for relevant interfaces.
    • Check the releases for Laravel version compatibility (e.g., ShouldQueue for Laravel 11/12).

Implementation Patterns

Usage Patterns

  1. DTOs: Use Dtoable for consistent serialization across APIs:

    class ApiResponse implements Dtoable
    {
        public function toArray(): array
        {
            return ['data' => $this->data, 'status' => $this->status];
        }
    }
    

    Pair with dragon-code/helpers for advanced features like JSON serialization.

  2. Caching: Extend Laravel’s cache with Cache\Store or Cache\Ttl:

    use DragonCode\Contracts\Cache\Store;
    
    class RedisCache implements Store
    {
        public function rememberForever(string $key, Closure $callback): mixed
        {
            return Cache::rememberForever($key, $callback);
        }
    }
    
  3. Queues: Enforce job deduplication with ShouldQueue or ShouldBeUnique:

    use DragonCode\Contracts\Queue\ShouldQueue;
    
    class ProcessPayment implements ShouldQueue
    {
        public function handle(): void
        {
            // Job logic
        }
    }
    
  4. HTTP Clients: Standardize domain handling with Http\Builder:

    use DragonCode\Contracts\Http\Builder;
    
    class ApiClient implements Builder
    {
        public function getBaseDomain(): string
        {
            return config('services.api.base_url');
        }
    }
    

Workflows

  • Dependency Injection: Bind contracts to implementations in AppServiceProvider:

    $this->app->bind(
        DragonCode\Contracts\Cache\Store::class,
        DragonCode\Contracts\Cache\RedisCache::class
    );
    
  • Testing: Mock contracts for isolated tests:

    $mockCache = Mockery::mock(DragonCode\Contracts\Cache\Store::class);
    $mockCache->shouldReceive('get')->andReturn('value');
    
  • Modular Monoliths: Use contracts to define module boundaries (e.g., DragonCode\Contracts\Queue\ShouldQueue for cross-module jobs).

Integration Tips

  • Laravel Facades: Extend existing facades to support contracts:

    class CacheFacade extends Illuminate\Support\Facades\Cache
    {
        public static function rememberForever(string $key, Closure $callback): mixed
        {
            return app(DragonCode\Contracts\Cache\Store::class)->rememberForever($key, $callback);
        }
    }
    
  • Service Providers: Register contracts as aliases for framework services:

    $this->app->alias(
        DragonCode\Contracts\Cache\Store::class,
        Illuminate\Contracts\Cache\Store::class
    );
    
  • Laravel 11/12: Leverage ShouldQueue for job batching or Dtoable with API resources.


Gotchas and Tips

Pitfalls

  1. Laravel Version Mismatches:

    • Ensure compatibility (e.g., ShouldQueue requires Laravel 11+).
    • Check releases for Symfony dependencies (e.g., symfony/http-kernel 7.0+).
  2. Over-Engineering:

    • Avoid implementing contracts for trivial classes (e.g., Dtoable for a single-use DTO).
    • Prefer native Laravel interfaces (e.g., Illuminate\Contracts\Cache\Store) when contracts add no value.
  3. Testing Quirks:

    • Mock contracts explicitly in tests to avoid runtime binding issues:
      $this->app->instance(DragonCode\Contracts\Cache\Store::class, $mockCache);
      
  4. Namespace Collisions:

    • Use fully qualified namespaces (e.g., \DragonCode\Contracts\Dto\Dtoable) to avoid conflicts with custom interfaces.

Debugging

  • Undefined Method Errors: Verify implementations match the contract’s methods (e.g., toArray() for Dtoable).

    php artisan ide-helper:generate  # Generate stubs for IDE autocompletion
    
  • Cache Contracts: If rememberForever fails, ensure the underlying cache driver supports it (e.g., Redis, file cache).

  • Queue Contracts: For ShouldBeUnique, check if the queue driver supports deduplication (e.g., database queues).

Tips

  1. IDE Support: Use PHPStorm’s "Implement Methods" (Ctrl+I) to auto-generate contract methods.

  2. Custom Contracts: Extend existing contracts for project-specific needs:

    namespace App\Contracts;
    
    use DragonCode\Contracts\Dto\Dtoable;
    
    interface ExtendedDtoable extends Dtoable
    {
        public function toJson(): string;
    }
    
  3. Performance:

    • Contracts add zero runtime overhead (pure type hints).
    • Use Dtoable with dragon-code/helpers for optimized serialization.
  4. Documentation:

    • Add PHPDoc blocks to implemented contracts for clarity:
      /**
       * @return array<string, mixed> Serialized data
       */
      public function toArray(): array
      {
          return [...];
      }
      
  5. Migration Contracts: Use DragonCode\Contracts\Database\MigrateDb for custom migration logic:

    class CustomMigration implements MigrateDb
    {
        public function up(): void
        {
            // Custom migration logic
        }
    }
    
  6. HTTP Domain Handling: For multi-tenant apps, implement getDomainLevel() to extract subdomains:

    public function getDomainLevel(): int
    {
        return 2; // e.g., "tenant.example.com" → "tenant"
    }
    
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.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport