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

Embed Relation Laravel Package

tusimo/embed-relation

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require tusimo/embed-relation
    

    Add to composer.json if manually managing dependencies:

    "require": {
        "tusimo/embed-relation": "^0.1"
    }
    
  2. Model Integration: Add the traits to your Eloquent model:

    use Tusimo\Eloquent\Traits\EmbedsRelation;
    use Tusimo\Eloquent\Traits\CastAttributes;
    
  3. Define Virtual Columns: Configure $virtualColumnMaps to map JSON fields to virtual columns:

    protected $virtualColumnMaps = [
        'data' => [
            'address' => 'home_address',
            'follower_ids',
        ],
    ];
    
  4. Cast Attributes: Use the custom casts (integer_array, string_array, etc.) in $casts:

    protected $casts = [
        'data' => 'array',
        'follower_ids' => 'integer_array',
    ];
    
  5. First Use Case: Access embedded relations directly:

    $user = User::find(1);
    $user->address; // Accesses 'home_address' from JSON
    $user->follower_ids; // Returns array of integers
    

Implementation Patterns

Workflows

  1. Embedding JSON Data: Store nested JSON in a single column (e.g., data) and access fields as properties:

    $user->data['address']['city']; // Direct JSON access
    $user->address; // Virtual column (if mapped)
    
  2. Dynamic Virtual Columns: Use $virtualColumnMaps to flatten JSON into model properties:

    // Model
    protected $virtualColumnMaps = [
        'metadata' => [
            'preferences' => 'user_prefs',
        ],
    ];
    
    // Usage
    $user->user_prefs; // Accesses `metadata.preferences`
    
  3. Array Casting: Leverage custom casts for type safety:

    protected $casts = [
        'tags' => 'string_array',
        'scores' => 'float_array',
    ];
    
    // Usage
    $user->tags[0]; // Returns string
    $user->scores[0] + 1.0; // Works as float
    
  4. Querying Embedded Data: Use whereJsonContains or custom scopes for JSON filtering:

    User::whereJsonContains('data->address', ['city' => 'New York'])
        ->get();
    
  5. Mass Assignment: Update embedded data via mass assignment:

    $user->update([
        'data' => ['address' => ['city' => 'London']],
        'follower_ids' => [1, 2, 3],
    ]);
    

Integration Tips

  • Database Schema: Ensure your JSON column is defined as JSON or TEXT in migrations:

    Schema::table('users', function (Blueprint $table) {
        $table->json('data')->nullable();
    });
    
  • API Responses: Use $appends to include virtual columns in API responses:

    protected $appends = ['address', 'follower_ids'];
    
  • Validation: Validate JSON structure in Form Requests:

    $this->validate($request, [
        'data.address.city' => 'required|string',
    ]);
    
  • Relationships: Combine with Laravel’s built-in relationships for hybrid data:

    public function posts() {
        return $this->hasMany(Post::class);
    }
    
    // Access
    $user->posts; // Eloquent relation
    $user->data['recent_post']; // Embedded data
    

Gotchas and Tips

Pitfalls

  1. Outdated Package:

    • Last release in 2018 (PHP 5.6+). Test thoroughly with modern Laravel (8/9/10).
    • Potential compatibility issues with newer Eloquent features (e.g., accessors/mutators).
  2. JSON Parsing Errors:

    • Malformed JSON in the database column will throw exceptions. Use json()->safe or try-catch:
      try {
          $user->data['address'];
      } catch (\JsonException $e) {
          // Handle invalid JSON
      }
      
  3. Virtual Column Overrides:

    • Virtual columns shadow actual JSON keys. Avoid naming conflicts:
      // Bad: 'data' column and 'data' virtual column
      protected $virtualColumnMaps = ['data' => ['nested']];
      
  4. Casting Quirks:

    • Custom casts (*_array) may not handle null values gracefully. Add null checks:
      public function getFollowerIdsAttribute($value) {
          return $value === null ? [] : $value;
      }
      
  5. Database-Specific JSON Functions:

    • Some JSON query methods (e.g., ->>) may not work across all databases (MySQL, PostgreSQL, SQLite). Test in your environment.

Debugging

  1. Log Virtual Columns: Add a temporary accessor to inspect mappings:

    public function getDebugVirtualColumnsAttribute() {
        return $this->virtualColumnMaps;
    }
    
  2. Check Casted Attributes: Override getAttribute to debug casting:

    public function getAttribute($key) {
        \Log::debug("Fetching attribute: $key", ['value' => parent::getAttribute($key)]);
        return parent::getAttribute($key);
    }
    
  3. Raw JSON Inspection: Use toJson() to verify stored data:

    $user->data->toJson(); // Dump raw JSON
    

Extension Points

  1. Custom Virtual Mappings: Extend EmbedsRelation trait to add dynamic mappings:

    protected function getVirtualColumnMaps() {
        $maps = parent::getVirtualColumnMaps();
        $maps['dynamic_data'] = ['key' => 'dynamic_key'];
        return $maps;
    }
    
  2. New Cast Types: Add support for custom array casts in CastAttributes:

    // In a service provider
    Tusimo\Eloquent\Traits\CastAttributes::macro('customCast', function ($value) {
        return json_decode($value, true);
    });
    
  3. Query Scopes: Create reusable scopes for embedded queries:

    public function scopeWithAddressIn($query, $cities) {
        return $query->whereJsonContains('data->address', ['city' => $cities]);
    }
    
  4. Event Listeners: Listen for retrieved events to modify embedded data:

    public static function boot() {
        static::retrieved(function ($model) {
            $model->normalizeEmbeddedData();
        });
    }
    
  5. Testing: Use refreshModel to reset virtual columns in tests:

    public function testVirtualColumns() {
        $user = User::factory()->create(['data' => json_encode(['address' => ['city' => 'Test']])]);
        $user->refreshModel(); // Re-fetch virtual columns
        $this->assertEquals('Test', $user->address);
    }
    
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.
babelqueue/symfony
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