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 Custom Fields Laravel Package

trappistes/laravel-custom-fields

Flexible EAV custom fields for Laravel Eloquent: add dynamic attributes without schema changes. Supports strong types (int, bool, json, date, ranges), polymorphic relations for any model, eager loading to avoid N+1, auto casting, batch upsert, validation, and soft deletes.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation

    composer require trappistes/laravel-custom-fields
    php artisan vendor:publish --provider="Trappistes\CustomFields\Providers\CustomFieldsServiceProvider"
    php artisan migrate
    
  2. Enable on Model Add the trait to any Eloquent model:

    use Trappistes\CustomFields\Traits\HasCustomFields;
    
    class User extends Model
    {
        use HasCustomFields;
    }
    
  3. First Use Case

    $user = User::find(1);
    $user->setCustomField('premium_until', now()->addYear());
    $expiryDate = $user->getCustomField('premium_until');
    

Where to Look First

  • Documentation: Focus on the README for type support, preloading, and mass assignment.
  • Config: Check config/custom-fields.php for table/key overrides.
  • Migration: Review database/migrations/[timestamp]_create_custom_fields_table.php for schema details.

Implementation Patterns

Core Workflows

  1. Dynamic Field Management

    // Single field
    $user->setCustomField('subscription_plan', 'pro');
    
    // Batch upsert (atomic)
    $user->setCustomFields([
        'last_login' => now(),
        'notifications' => ['email', 'sms'],
    ]);
    
  2. Preloading for Performance

    // Avoid N+1 queries
    $users = User::with('customFields')->get();
    
    foreach ($users as $user) {
        $user->getCustomField('preferences'); // No extra query
    }
    
  3. Type-Safe Access

    // Auto-inferred types
    $user->setCustomField('age', 30); // Stored as `bigint`
    $user->setCustomField('settings', ['theme' => 'dark']); // Stored as `json`
    
    // Explicit casting
    $user->setCustomField('expiry', now(), 'datetime');
    
  4. Mass Assignment Integration

    // Fill with custom fields
    $user->fill([
        'name' => 'John',
        'bio' => 'Developer', // Custom field
    ])->save();
    
  5. Polymorphic Usage

    // Shared custom fields across models
    class Product extends Model { use HasCustomFields; }
    class Order extends Model { use HasCustomFields; }
    
    $product->setCustomField('weight', 2.5);
    $order->setCustomField('shipping_method', 'express');
    

Integration Tips

  • Validation: Use validateCustomField to enforce rules:
    $user->validateCustomField('age', 'required|integer|min:18');
    
  • Observers: Extend CustomFieldObserver for custom logic:
    CustomField::observe(CustomFieldObserver::class);
    
  • Scopes: Add query scopes to filter by custom fields:
    public function scopeWithPremium($query) {
        return $query->whereHas('customFields', fn($q) =>
            $q->where('field_key', 'premium_until')
               ->where('field_value', '>', now())
        );
    }
    

Gotchas and Tips

Pitfalls

  1. Field Key Conflicts

    • Reserved keys (e.g., id, model_id) will throw InvalidArgumentException.
    • Fix: Validate keys before use:
      if (!$user->isValidCustomFieldKey('user_@key')) {
          throw new \InvalidArgumentException('Invalid field key');
      }
      
  2. N+1 Queries

    • Forgetting with('customFields') in eager loading triggers N+1.
    • Fix: Always preload when accessing custom fields in loops.
  3. Type Mismatches

    • Storing a string as int may cause silent failures.
    • Fix: Explicitly cast types:
      $user->setCustomField('count', '42', 'bigint');
      
  4. Soft Deletes

    • Custom fields are not deleted on soft delete by default.
    • Fix: Use forceDelete() to purge custom fields.
  5. JSON Depth Limits

    • Nested JSON > json_max_depth (default: 64) throws RuntimeException.
    • Fix: Increase in config or flatten data.

Debugging

  • Query Logs: Enable Laravel debug mode to inspect EAV queries:
    \DB::enableQueryLog();
    $user->getCustomField('key');
    \DB::getQueryLog();
    
  • Field Existence: Use hasCustomField() to avoid null errors:
    if ($user->hasCustomField('metadata')) {
        $data = $user->getCustomField('metadata');
    }
    

Extension Points

  1. Custom Field Types

    • Extend Trappistes\CustomFields\Contracts\FieldType:
      class CustomType implements FieldType {
          public function getType(): string { return 'custom'; }
          public function serialize($value): string { /* ... */ }
          public function deserialize(string $value) { /* ... */ }
      }
      
    • Register in config/custom-fields.php:
      'types' => [
          'custom' => \App\CustomType::class,
      ],
      
  2. Model Events

    • Hook into retrieving, saved, or deleted events:
      CustomField::saved(function ($field) {
          \Log::info("Field updated: {$field->field_key}");
      });
      
  3. Batch Operations

    • Use CustomField::upsert() for bulk inserts/updates:
      CustomField::upsert([
          ['model_type' => User::class, 'model_id' => 1, 'field_key' => 'key1', 'field_value' => 'value1'],
          ['model_type' => User::class, 'model_id' => 2, 'field_key' => 'key2', 'field_value' => 'value2'],
      ]);
      

Performance Quirks

  • Index Usage: The package relies on custom_fields_model_index and custom_fields_key_index. Ensure these are optimized in production.
  • Batch Size: For large setCustomFields(), chunk data to avoid memory issues:
    $user->setCustomFields(array_chunk($fields, 100));
    
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.
aashan/pimcore-mcp-bundle
solution-forest/ai-kit-core
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin