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:

    "dragon-code/contracts": "^2.25"
    
  2. First Use Case: Implement a Dtoable contract for a simple data transfer object:

    use DragonCode\Contracts\Dto\Dtoable;
    
    class UserDto implements Dtoable
    {
        public function __construct(
            public string $name,
            public int $age
        ) {}
    
        // No additional methods required for basic usage
    }
    
  3. Where to Look First:

    • Browse contracts in vendor/dragon-code/contracts/src/Contracts/.
    • Focus on these core namespaces for Laravel integration:
      • Cache\Store (caching operations)
      • Queue\ShouldQueue (job queueing)
      • Dto\Dtoable (data transfer objects)
      • Http\Builder (HTTP request building)

Implementation Patterns

Core Workflows

1. DTO Pattern

  • Use Case: Standardize data transfer between layers (e.g., API responses, service inputs).
  • Pattern:
    use DragonCode\Contracts\Dto\Dtoable;
    
    class CreateUserRequest implements Dtoable
    {
        public function __construct(
            public string $name,
            public string $email,
            public string $password
        ) {}
    }
    
  • Integration with DragonCode Ecosystem:
    use DragonCode\Helpers\Dto\DtoHelper;
    
    $dto = DtoHelper::fromArray($request->all(), CreateUserRequest::class);
    

2. Queue Contracts

  • Use Case: Enforce queueable behavior and deduplication.
  • Pattern:
    use DragonCode\Contracts\Queue\ShouldQueue;
    use DragonCode\Contracts\Queue\ShouldBeUnique;
    
    class SendWelcomeEmail implements ShouldQueue, ShouldBeUnique
    {
        public function handle(): void
        {
            // Job logic
        }
    
        public function uniqueKey(): string
        {
            return 'email_' . $this->userId;
        }
    }
    

3. Cache Contracts

  • Use Case: Standardize cache operations across services.
  • Pattern:
    use DragonCode\Contracts\Cache\Store;
    use DragonCode\Contracts\Cache\Ttl;
    
    class UserCacheService
    {
        public function __construct(private Store $cache) {}
    
        public function getUser(int $id): ?array
        {
            return $this->cache->get("user_{$id}");
        }
    
        public function rememberUser(int $id, callable $callback, Ttl $ttl): array
        {
            return $this->cache->remember("user_{$id}", $ttl->value(), $callback);
        }
    }
    

4. HTTP Builder

  • Use Case: Centralize URL/domain logic for API clients.
  • Pattern:
    use DragonCode\Contracts\Http\Builder;
    
    class ApiClient
    {
        public function __construct(private Builder $builder) {}
    
        public function getBaseUrl(): string
        {
            return $this->builder->getBaseDomain();
        }
    
        public function buildUrl(string $endpoint): string
        {
            return $this->builder->url($endpoint);
        }
    }
    

5. Database Migrations

  • Use Case: Define migration contracts for reusable schema logic.
  • Pattern:
    use DragonCode\Contracts\Database\Migrations\ShouldMigrate;
    
    class CreateUsersTable implements ShouldMigrate
    {
        public function up(): void
        {
            Schema::create('users', function (Blueprint $table) {
                $table->id();
                $table->string('name');
                $table->timestamps();
            });
        }
    
        public function down(): void
        {
            Schema::dropIfExists('users');
        }
    }
    

Integration Tips

Laravel Service Providers

Bind contracts to Laravel’s container in AppServiceProvider:

use DragonCode\Contracts\Cache\Store;
use Illuminate\Support\Facades\Cache;

public function register(): void
{
    $this->app->bind(Store::class, function ($app) {
        return new class($app['cache']) implements Store {
            public function __construct(private \Illuminate\Contracts\Cache\Store $cache) {}
            // Delegate methods to Laravel's cache store
        };
    });
}

Testing

Use contracts for dependency injection in tests:

use DragonCode\Contracts\Cache\Store;

public function testCacheOperations()
{
    $mockCache = $this->createMock(Store::class);
    $mockCache->method('get')->willReturn(['name' => 'John']);

    $service = new UserCacheService($mockCache);
    $this->assertEquals(['name' => 'John'], $service->getUser(1));
}

Extending Existing Classes

Leverage traits or interfaces to add contracts to existing classes:

use DragonCode\Contracts\Queue\ShouldQueue;

class ExistingJob
{
    // Existing implementation
}

class QueueableJob extends ExistingJob implements ShouldQueue
{
    public function handle(): void
    {
        // Existing logic
    }
}

Gotchas and Tips

Pitfalls

  1. Laravel Version Mismatches:

    • The package actively updates for Laravel 11/12. If using an older version, some contracts (e.g., ShouldQueue) may not work as expected.
    • Fix: Pin to a stable version (e.g., ^2.20) if targeting Laravel 10.
  2. Over-Engineering for Simple Projects:

    • Contracts add minimal runtime value but introduce compile-time checks. Avoid using them for trivial classes.
    • Tip: Reserve contracts for shared layers (e.g., DTOs, services) rather than domain entities.
  3. Cache Contract Inconsistencies:

    • The Cache\Store contract mirrors Laravel’s cache store but may miss newer methods (e.g., pull, forget).
    • Workaround: Extend the contract or use a facade wrapper:
      $this->cache->store()->forget($key); // If not in contract
      
  4. Queue Contracts and Laravel Jobs:

    • ShouldQueue is not a drop-in replacement for Laravel’s ShouldQueue interface. It’s designed for custom queueable logic.
    • Tip: Use alongside Laravel’s Illuminate\Contracts\Queue\ShouldQueue for full compatibility:
      use DragonCode\Contracts\Queue\ShouldQueue as DragonShouldQueue;
      use Illuminate\Contracts\Queue\ShouldQueue as LaravelShouldQueue;
      
      class MyJob implements LaravelShouldQueue, DragonShouldQueue
      {
          // ...
      }
      
  5. DTO Serialization Quirks:

    • Dtoable alone does not enforce serialization. Pair with DragonCode\Helpers\Dto\DtoHelper for full functionality.
    • Gotcha: Nested DTOs require recursive type hints:
      class UserDto implements Dtoable
      {
          public function __construct(
              public string $name,
              public AddressDto $address // Must also implement Dtoable
          ) {}
      }
      

Debugging Tips

  1. Interface Not Found Errors:

    • Ensure the package is autoloaded (composer dump-autoload).
    • Verify the namespace in vendor/composer/autoload_psr4.php includes:
      'DragonCode\\Contracts\\' => [__DIR__ . '/../dragon-code/contracts/src/Contracts'],
      
  2. Method Not Implemented:

    • Use PHPStorm’s "Implement Methods" refactor (right-click → Implement Methods) to auto-generate stubs for missing contract methods.
  3. Cache Contract Conflicts:

    • If using multiple cache stores, explicitly bind the contract to the desired store in the service provider:
      $this->app->bind(Store::class, function ($app) {
          return $app['cache']->store('redis');
      });
      

Extension Points

  1. Custom TTL Contracts: Extend Cache\Ttl for domain-specific timeouts:

    use DragonCode\Contracts\Cache\Ttl;
    
    class SessionTtl implements Ttl
    {
        public function value(): int
        {
            return 60 * 30; // 30 minutes
        }
    }
    
  2. Queue Deduplication: Implement ShouldBeUnique for idempotent jobs:

    use DragonCode\Contracts\Queue\ShouldBeUnique;
    
    class ProcessPayment implements ShouldBeUnique
    {
        public function uniqueKey(): string
        {
            return 'payment_' . $this->paymentId;
        }
    }
    
  3. HTTP Domain Logic: Extend Http\Builder for multi-tenant domains:

    use DragonCode\
    
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.
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
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope