Weave 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

Contract Laravel Package

controleonline/contract

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps to Begin

  1. Installation

    composer require controleonline/contract
    

    Publish the package configuration and migrations:

    php artisan vendor:publish --provider="ControleOnline\Contract\ContractServiceProvider"
    php artisan migrate
    
  2. First Use Case: Basic Contract Creation

    • Define a Contract model extending ControleOnline\Contract\Models\Contract:
      use ControleOnline\Contract\Models\Contract;
      
      class MyContract extends Contract
      {
          // Custom fields or logic
      }
      
    • Create a contract via Trait or Model:
      $contract = MyContract::create([
          'title' => 'Service Agreement',
          'start_date' => now(),
          'end_date' => now()->addYear(),
          'status' => 'draft', // or 'signed', 'expired'
      ]);
      
  3. Key Files to Review

    • config/contract.php: Core settings (e.g., document templates, signature workflows).
    • database/migrations/: Schema for contracts, contract_people, and related tables.
    • src/Models/Contract.php: Base model with core fields (title, status, dates).
    • src/Models/ContractPeople.php: Junction table for contract-participant relationships.

Implementation Patterns

Core Workflows

  1. Contract-Participant Relationships Attach people (users, clients) to contracts via ContractPeople:

    $contract->people()->attach($userId, [
        'role' => 'client', // 'signatory', 'witness', etc.
        'signed_at' => now(),
    ]);
    
    • Use hasManyThrough or query scopes for common lookups:
      $contract->people->where('role', 'signatory');
      
  2. Document Generation Leverage the generateDocument() trait method:

    $pdf = $contract->generateDocument(); // Returns a PDF stream or path
    
    • Customize templates by overriding getDocumentTemplate() in your model:
      protected function getDocumentTemplate(): string
      {
          return 'custom.contract_template';
      }
      
  3. Signature Workflow

    • Trigger signature requests via events or commands:
      event(new ContractNeedsSignature($contract));
      
    • Integrate with external providers (e.g., DocuSign) in the integration/ layer:
      // Example: Extend the base service
      class CustomSignatureService extends \ControleOnline\Contract\Services\SignatureService
      {
          public function sendForSignature($contract): void
          {
              // Custom logic (e.g., API call to external service)
          }
      }
      
  4. Status Transitions Use the status field to track lifecycle (e.g., draft → signed):

    $contract->update(['status' => 'signed']);
    
    • Add observers or policies to enforce transitions:
      class ContractObserver
      {
          public function saving(Contract $contract)
          {
              if ($contract->isDirty('status') && $contract->status === 'signed') {
                  $contract->people()->update(['signed_at' => now()]);
              }
          }
      }
      

Integration Tips

  • API Platform: If using API Platform, expose Contract and ContractPeople as resources:
    # config/api_platform/resources.yaml
    resources:
        ControleOnline\Contract\Models\Contract:
            collectionOperations:
                - 'get'
                - 'post'
            itemOperations:
                - 'get'
                - 'put'
                - 'generate_document'  # Custom operation
    
  • Events: Listen for contract events to trigger side effects:
    Contract::created(function ($contract) {
        // Send notification, log, etc.
    });
    
  • Testing: Mock the SignatureService for unit tests:
    $this->app->instance(
        \ControleOnline\Contract\Services\SignatureService::class,
        Mockery::mock()
    );
    

Gotchas and Tips

Pitfalls

  1. Document Generation Assumptions

    • The package assumes Blade templates for PDF generation (e.g., via laravel-dompdf).
    • Fix: Install barryvdh/laravel-dompdf and configure the template path in config/contract.php:
      'document_templates' => resource_path('views/contracts'),
      
  2. Signature Provider Coupling

    • The integration/ layer is abstract, but the base SignatureService expects specific methods.
    • Tip: Extend the service and override only required methods to avoid breaking changes.
  3. Status Field Validation

    • The status field uses a limited set of values (draft, signed, expired).
    • Workaround: Add a custom validation rule or use a Status enum:
      use ControleOnline\Contract\Enums\ContractStatus;
      
      $contract->update(['status' => ContractStatus::SIGNED]);
      
  4. Migration Conflicts

    • If extending the base tables, run migrations in this order:
      php artisan migrate --path=vendor/controleonline/contract/database/migrations
      php artisan migrate
      

Debugging Tips

  • Log Contract Events: Enable contract event logging in config/contract.php:
    'log_events' => true,
    
  • Inspect Document Templates: Use dd($contract->getDocumentTemplate()) to verify template paths.
  • Signature Workflow: Check the contract_signature_requests table for stuck requests:
    SELECT * FROM contract_signature_requests WHERE status = 'pending';
    

Extension Points

  1. Custom Fields Add fields to the contracts table via migration, then extend the model:

    class MyContract extends Contract
    {
        protected $casts = [
            'custom_field' => 'boolean',
        ];
    }
    
  2. Signature Providers Register a custom provider in config/contract.php:

    'signature_providers' => [
        'default' => \App\Services\CustomSignatureService::class,
    ],
    
  3. Document Types Support multiple document types (e.g., PDF, Word) by extending the generateDocument() method:

    public function generateDocument(): string
    {
        if ($this->type === 'word') {
            return $this->generateWordDocument();
        }
        return parent::generateDocument();
    }
    
  4. Validation Rules Override validation in your model:

    public static function boot()
    {
        parent::boot();
        static::addGlobalScope('customValidation', function (Builder $builder) {
            $builder->where('end_date', '>=', now());
        });
    }
    
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.
steadrun/laravel-monitor
labyrinthe/connect-laravel
elmogy/layan
drewdan/sentinel-client
dskripchenko/laravel-llm
fatryst/nuonuo
stevenay/myanfont
gmostafa/php-graphql-client
xeviant/paystack
snowsoft/faker
meditationsteps/blogetc
animalyoung/laravel-influxdb
onix-solutions/sms-telera
lonely-lights/prosetta
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin