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

Laravel Cti Laravel Package

pannella/laravel-cti

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require pannella/laravel-cti:^3.5.1
    

    Publish the config (optional):

    php artisan vendor:publish --provider="Pannella\LaravelCTI\CTIServiceProvider"
    
  2. Define CTI Structure:

    • Create a parent table (e.g., assessments) with shared columns.
    • Create subtype tables (e.g., assessment_technical, assessment_creative) with type-specific columns.
    • Add a type column to the parent table (e.g., assessment_type).
    • Add a foreign key column (e.g., subtype_id) to the parent table.
  3. First Use Case: Define a parent model (Assessment) and subtype models (TechnicalAssessment, CreativeAssessment):

    use Pannella\LaravelCTI\HasCTI;
    
    class Assessment extends Model
    {
        use HasCTI;
    
        protected $ctiTypeColumn = 'assessment_type';
        protected $ctiSubtypeColumn = 'subtype_id';
        protected $ctiSubtypeTable = 'assessment_subtypes';
        protected $ctiSubtypeModels = [
            'technical' => TechnicalAssessment::class,
            'creative' => CreativeAssessment::class,
        ];
    }
    

    Create a subtype:

    $assessment = Assessment::create([
        'name' => 'Performance Review',
        'assessment_type' => 'technical',
        'technical_specific_field' => 'value',
    ]);
    

Implementation Patterns

Core Workflows

  1. Model Instantiation: Fetch a parent record with its subtype automatically:

    $assessment = Assessment::find(1); // Returns TechnicalAssessment or CreativeAssessment
    
  2. Querying Subtypes: Query parent records and filter by subtype:

    $technicalAssessments = Assessment::whereType('technical')->get();
    
  3. Saving/Updating: Save subtype-specific data seamlessly:

    $assessment->technical_specific_field = 'updated_value';
    $assessment->save(); // Automatically persists to subtype table
    
  4. Relationships: Define relationships on parent or subtype models. Note: Inherited relationships now work correctly (fixed in 3.5.1):

    class Assessment extends Model
    {
        public function comments()
        {
            return $this->morphMany(Comment::class, 'commentable');
        }
    }
    
    // Subtype-specific relationships also work as expected
    class TechnicalAssessment extends Assessment
    {
        public function technicalReviews()
        {
            return $this->hasMany(TechnicalReview::class);
        }
    }
    
  5. Batch Loading: Avoid N+1 queries with eager loading:

    $assessments = Assessment::with('subtype')->get();
    

Integration Tips

  • Migrations: Use the cti() method in migrations for subtype tables:
    Schema::create('assessment_technical', function (Blueprint $table) {
        $table->cti('assessments', 'technical');
        $table->string('technical_specific_field');
    });
    
  • Events: Subtype models trigger parent model events (e.g., created, updated).
  • Polymorphic Relations: Works with Laravel’s polymorphic relationships out of the box.
  • API Resources: Use App\Http\Resources\AssessmentResource to handle subtype serialization:
    public function toArray($request)
    {
        return [
            'id' => $this->id,
            'type' => $this->ctiType(),
            'data' => $this->whenLoaded('subtype', function () {
                return $this->subtype->toArray();
            }),
        ];
    }
    

Gotchas and Tips

Pitfalls

  1. Foreign Key Constraints:

    • Ensure the subtype_id column in the parent table has a foreign key constraint pointing to the subtype table’s primary key.
    • Example migration:
      $table->unsignedBigInteger('subtype_id')->nullable();
      $table->foreign('subtype_id')->references('id')->on('assessment_technical');
      
  2. Type Resolution:

    • The ctiType() method must return a value that matches the keys in $ctiSubtypeModels. Use a lookup table if types are dynamic:
      protected $ctiSubtypeModels = [
          AssessmentSubtype::where('name', 'technical')->value('id') => TechnicalAssessment::class,
          AssessmentSubtype::where('name', 'creative')->value('id') => CreativeAssessment::class,
      ];
      
  3. Mass Assignment:

    • Subtype-specific fields must be explicitly whitelisted in $fillable for both the parent and subtype models:
      class TechnicalAssessment extends Assessment
      {
          protected $fillable = ['technical_specific_field'];
      }
      
  4. Circular Dependencies:

    • Avoid defining relationships that create circular dependencies between parent and subtype models.
  5. Inherited Relationships:

    • Fixed in 3.5.1: Previously, relationships defined on parent models might not work correctly on subtype instances. This is now resolved. Ensure your relationships are defined on the parent model for consistency.

Debugging

  • Type Mismatches: If a record isn’t returning the expected subtype, check:
    • The value of $ctiTypeColumn matches the database column.
    • The subtype model class exists in $ctiSubtypeModels with the correct key.
    • The subtype_id is not null when a subtype is expected.
  • Query Logs: Enable query logging to debug N+1 issues:
    DB::enableQueryLog();
    $assessments = Assessment::all();
    dd(DB::getQueryLog());
    

Extension Points

  1. Custom Type Resolution: Override the resolveSubtype() method in the parent model for dynamic logic:

    protected function resolveSubtype()
    {
        if ($this->isPremium()) {
            return 'premium';
        }
        return parent::resolveSubtype();
    }
    
  2. Subtype-Specific Logic: Use trait composition to add subtype-specific behavior:

    trait HasTechnicalFields
    {
        public function getTechnicalScore()
        {
            return $this->technical_specific_field * 2;
        }
    }
    
  3. Custom Lookup Tables: Extend the Pannella\LaravelCTI\SubtypeLookup class to handle dynamic subtype definitions from a separate table.

  4. Soft Deletes: Ensure both parent and subtype tables use the same deleted_at column if using soft deletes:

    use SoftDeletes;
    
    class Assessment extends Model
    {
        use HasCTI, SoftDeletes;
    }
    
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.
daikazu/eloquent-salesforce-objects
unseen-codes/chat
romalytar/yammi-jobs-monitoring-laravel
kisame76/filament-db-table-state
nqxcode/laravel-lucene-search
dpfx/laravel-livewire-wizards
workos/workos-php-laravel
sofa/laravel-global-scope
nawasara/auth-primitives
adhocrat-io/arkhe-main
make-dev/orca-harpoon
itsemon245/lamet
baks-dev/dashboard
amoifr/pickle-panther-bundle
make-dev/orca
dmstr/symfony-system-resources-bundle
dmstr/symfony-job-queue-bundle
dmstr/openapi-json-schema-bundle
dmstr/keycloak-security-bundle
dmstr/doctrine-audit-log-bundle