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 Steps

  1. Install the package:
    composer require pannella/laravel-cti
    
  2. Define parent table (shared columns + type discriminator):
    Schema::create('assessments', function (Blueprint $table) {
        $table->id();
        $table->string('title');
        $table->string('type')->comment('Discriminator column');
        $table->timestamps();
    });
    
  3. Create subtype tables (type-specific columns):
    Schema::create('assessment_quiz', function (Blueprint $table) {
        $table->foreignId('assessment_id')->constrained()->onDelete('cascade');
        $table->integer('passing_score');
        $table->timestamps();
    });
    
  4. Configure parent model (app/Models/Assessment.php):
    use Pannella\LaravelCti\HasSubtypes;
    
    class Assessment extends Model
    {
        use HasSubtypes;
    
        protected static $subtypeMap = [
            'quiz' => Quiz::class,
            'survey' => Survey::class,
        ];
        protected static $subtypeKey = 'type'; // Discriminator column
    }
    
  5. Define subtype model (app/Models/Quiz.php):
    use Pannella\LaravelCti\SubtypeModel;
    
    class Quiz extends SubtypeModel
    {
        protected $subtypeTable = 'assessment_quiz';
        protected $subtypeAttributes = ['passing_score'];
        protected $ctiParentClass = Assessment::class;
    }
    

First Use Case: Create a Subtype

// Create a Quiz (automatically handles parent + subtype tables)
$quiz = Quiz::create([
    'title' => 'Math Test',
    'passing_score' => 75,
]);

// Query subtypes directly (auto-joins parent table)
$hardQuizzes = Quiz::where('passing_score', '>', 90)->get();

// Query parent and get typed results
$allAssessments = Assessment::all(); // Returns mixed collection of Quiz/Survey

Key Files to Reference:


Implementation Patterns

Core Workflow: CRUD with Subtypes

  1. Creation:

    // Subtype creation (parent + subtype tables)
    $survey = Survey::create([
        'title' => 'Customer Feedback',
        'anonymous' => true,
    ]);
    
    • Package handles:
      • Parent table insert (with discriminator).
      • Subtype table insert (with foreign key).
      • Transaction wrapping.
  2. Reading:

    // Parent query returns typed instances
    $assessment = Assessment::find(1); // Returns Quiz or Survey
    
    // Subtype query (auto-joins parent)
    $quizzes = Quiz::whereHas('parent', fn($q) => $q->where('title', 'like', '%Exam%'))->get();
    
    • Batch loading: Subtype data is loaded in a single query per batch (no N+1).
  3. Updating:

    // Update parent + subtype in one operation
    $quiz->update(['title' => 'Updated Quiz', 'passing_score' => 80]);
    
    • Package tracks which tables need updates.
  4. Deletion:

    $quiz->delete(); // Cascades to subtype table
    

Integration Patterns

  1. Relationships:

    // Parent has many subtypes
    class Assessment extends Model
    {
        public function quizzes() { return $this->hasOne(Quiz::class); }
    }
    
    // Subtype belongs to parent
    class Quiz extends SubtypeModel
    {
        public function parent() { return $this->belongsTo(Assessment::class); }
    }
    
    • Use hasOne/belongsTo with subtype models (package handles the join logic).
  2. Events:

    // Listen for subtype-specific events
    Quiz::created(fn($quiz) => Log::info("Quiz created: {$quiz->title}"));
    
    • Supported events: created, updated, deleted, saved, retrieved.
  3. Polymorphic Relations:

    // Store assessments in a polymorphic relation
    class User extends Model
    {
        public function assessments()
        {
            return $this->morphMany(Assessment::class, 'assessable');
        }
    }
    
    • Works seamlessly with Laravel’s polymorphic system.
  4. API Resources:

    class AssessmentResource extends JsonResource
    {
        public function toArray($request)
        {
            return [
                'id' => $this->id,
                'title' => $this->title,
                'type' => $this->getSubtypeLabel(),
                'data' => $this->getSubtypeAttributes(), // Returns quiz/survey-specific fields
            ];
        }
    }
    
    • Use getSubtypeLabel() and getSubtypeAttributes() for dynamic responses.

Advanced Patterns

  1. Direct Discriminator Mode (no lookup table):

    // Parent model
    protected static $subtypeKey = 'type'; // Uses column directly
    protected static $subtypeMap = ['quiz' => Quiz::class];
    
    • Simplifies schema for small hierarchies.
  2. Subtypes Without Tables (for simple extensions):

    class SimpleSurvey extends SubtypeModel
    {
        protected $subtypeTable = null; // No separate table
        protected $subtypeAttributes = ['anonymous'];
    }
    
    • Stores subtype data in parent table (use sparingly).
  3. Custom Type Resolution:

    // Override type resolution logic
    public function resolveSubtype()
    {
        return $this->type === 'premium' ? PremiumQuiz::class : Quiz::class;
    }
    

Gotchas and Tips

Common Pitfalls

  1. Foreign Key Mismatches:

    • Issue: Subtype table’s foreign key doesn’t match parent’s primary key.
    • Fix: Ensure assessment_id in subtype table references id in parent table.
    • Debug: Run php artisan schema:dump to verify constraints.
  2. Missing Subtype Handling:

    • Issue: Querying a parent returns null for unknown subtypes.
    • Fix: Configure in config/cti.php:
      'missing_subtype' => 'ignore', // or 'throw', 'null'
      
  3. N+1 Queries:

    • Issue: Eager loading subtypes doesn’t work as expected.
    • Fix: Use withSubtypes():
      $assessments = Assessment::withSubtypes()->get();
      
  4. Fillable/Cast Inheritance:

    • Issue: Subtype attributes aren’t mass-assignable.
    • Fix: Explicitly define $fillable in both parent and subtype:
      // Parent
      protected $fillable = ['title', 'type'];
      
      // Subtype
      protected $fillable = ['passing_score']; // Parent fillable still works
      
  5. Timestamps:

    • Issue: Subtype table timestamps conflict with parent.
    • Fix: Disable timestamps in subtype table or use timestamps = false in Blueprint.

Debugging Tips

  1. Query Logging: Enable Laravel’s query logging to inspect auto-generated joins:

    DB::enableQueryLog();
    $assessment = Assessment::find(1);
    dd(DB::getQueryLog());
    
  2. Type Resolution: Debug subtype resolution with:

    $assessment = Assessment::find(1);
    dd($assessment->getSubtypeClass(), $assessment->getSubtypeInstance());
    
  3. Event Debugging: Listen for all events to trace the flow:

    Assessment::created(fn($model) => Log::debug("Created: {$model->id}"));
    Quiz::saved(fn($model) => Log::debug("Saved Quiz: {$model->id}"));
    

Performance Tips

  1. Batch Loading:

    • Subtype data is loaded in batches of 100 by default. Adjust in config:
      'batch_size' => 500, // For large datasets
      
  2. Indexing:

    • Add indexes to subtype tables for frequent queries:
      Schema::table('assessment_quiz', function (Blueprint $table) {
          $table->index('passing_score');
      });
      
  3. Caching:

    • Subtype labels are cached by default. Clear with:
      php artisan cache:clear
      

Extension Points

  1. Custom Subtype Resolution: Override resolveSubtype() in parent
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.
calmfox/watch-sylius
damienfern/grpc-symfony-bundle
atoolo/index-bundle
atoolo/genai-bundle
coprotoai/laravel-ticket
davidjln/llm-carbon-bundle
cryonighter/valid-request-bundle
coolms/taxonomy-bundle
coolms/field-bundle
articulate-orm/symfony
aaix/laravel-tall-architect
ephoto/akeneo-connector
emmanuelballery/eb-plantumlbundle
emielburgman/symfony-visitor-beacon
emielburgman/symfony-visit-storage
emielburgman/symfony-security-headers
emielburgman/symfony-log-viewer
emarref/xdebug-bundle
emarref/pubnub-bundle
elriseio/finance-money-bundle