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

Eloquent Serialize Laravel Package

anourvalar/eloquent-serialize

Serialize and restore Laravel Eloquent QueryBuilder instances. Save complex queries (with relations, where clauses, limits, etc.) to an array/package and later unserialize back into a builder to run the query again. Supports Laravel 6–12.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps to First Use:

  1. Install the package:
    composer require anourvalar/eloquent-serialize
    
  2. Serialize a basic query:
    use EloquentSerialize;
    
    $serialized = EloquentSerialize::serialize(
        \App\User::query()->where('active', true)->limit(10)
    );
    
  3. Unserialize and execute:
    $builder = EloquentSerialize::unserialize($serialized);
    $users = $builder->get(); // Returns active users
    

Where to Look First:

  • Facade API: EloquentSerialize::serialize() and EloquentSerialize::unserialize() in the README.
  • Supported Features: Check the description for with(), where(), orderBy(), and pagination.
  • Limitations: Review the assessment for unsupported cases (e.g., raw SQL, global scopes).

First Use Case: Cache a paginated API response:

// Cache the serialized query for 1 hour
$cacheKey = 'users:active:paginated';
$serialized = EloquentSerialize::serialize(
    \App\User::query()->where('active', true)->paginate(15)
);

// Later, retrieve and execute
$cachedData = cache()->get($cacheKey);
if ($cachedData) {
    $builder = EloquentSerialize::unserialize($cachedData);
    return $builder->get();
}

Implementation Patterns

Core Workflows:

  1. Query Caching for APIs

    // Controller method
    public function index(Request $request)
    {
        $query = \App\User::query()
            ->when($request->filled('search'), fn($q) => $q->where('name', 'like', '%'.$request->search.'%'))
            ->with('posts');
    
        $cacheKey = 'users:'.md5($request->search);
        $serialized = EloquentSerialize::serialize($query);
    
        cache()->put($cacheKey, $serialized, now()->addMinutes(5));
    
        return EloquentSerialize::unserialize($serialized)->get();
    }
    
  2. Background Job with Serialized Queries

    // Job class
    public function handle()
    {
        $serialized = $this->serializedQuery; // From job payload
        $builder = EloquentSerialize::unserialize($serialized);
    
        // Process results (e.g., send emails, generate reports)
        foreach ($builder->get() as $user) {
            // ...
        }
    }
    
    // Dispatch job
    SerializeQueryJob::dispatch(
        EloquentSerialize::serialize(\App\User::query()->where('is_admin', true))
    );
    
  3. Multi-Tenant Query Serialization

    // Middleware to attach tenant ID
    public function handle($request, Closure $next)
    {
        $request->merge(['tenant_id' => auth()->tenant()->id]);
        return $next($request);
    }
    
    // Controller
    public function tenantDashboard()
    {
        $query = \App\User::query()
            ->where('tenant_id', request('tenant_id'))
            ->with(['orders' => function($q) {
                $q->where('status', 'completed');
            }]);
    
        $serialized = EloquentSerialize::serialize($query);
        cache()->put("tenant:{$request->tenant_id}:dashboard", $serialized, now()->addHours(1));
    }
    

Integration Tips:

  • Validation Layer: Always validate unserialized queries against the current schema:

    $builder = EloquentSerialize::unserialize($serialized);
    $builder->getQuery()->from; // Check table exists
    $builder->getQuery()->columns; // Verify columns
    
  • Error Handling:

    try {
        $builder = EloquentSerialize::unserialize($serialized);
    } catch (\AnourValar\EloquentSerialize\Exceptions\InvalidQueryException $e) {
        Log::error("Failed to unserialize query: " . $e->getMessage());
        return response()->json(['error' => 'Query invalid'], 500);
    }
    
  • Testing: Use Laravel’s Mockery to test serialization:

    $mockQuery = Mockery::mock(\Illuminate\Database\Eloquent\Builder::class);
    $mockQuery->shouldReceive('getQuery')->andReturn(new \Illuminate\Database\Query\Builder);
    
    $serialized = EloquentSerialize::serialize($mockQuery);
    $unserialized = EloquentSerialize::unserialize($serialized);
    
  • Custom Serialization: Extend the serializer for unsupported features:

    use AnourValar\EloquentSerialize\Serializer;
    
    class CustomSerializer extends Serializer
    {
        protected function serializeWhereRaw($whereRaw)
        {
            // Custom logic for raw SQL
            return parent::serializeWhereRaw($whereRaw);
        }
    }
    
    // Register in AppServiceProvider
    $this->app->bind('EloquentSerialize', function () {
        return new CustomSerializer();
    });
    

Gotchas and Tips

Pitfalls:

  1. Schema Drift:

    • Issue: Unserialized queries fail if the database schema changes (e.g., column renamed).
    • Fix: Add a validation step:
      $builder = EloquentSerialize::unserialize($serialized);
      $query = $builder->getQuery();
      if (!Schema::hasColumn($query->from, 'column_name')) {
          throw new \RuntimeException("Schema mismatch for column 'column_name'");
      }
      
  2. Global Scopes:

    • Issue: Global scopes (e.g., SoftDeletes) are not serialized by default.
    • Fix: Explicitly include/exclude them:
      $builder = \App\User::query()->withoutGlobalScopes();
      $serialized = EloquentSerialize::serialize($builder);
      
  3. Complex Relationships:

    • Issue: Deeply nested with() or polymorphic relationships may fail.
    • Fix: Test incrementally and extend the serializer:
      // Example: Add support for polymorphic relations
      protected function serializeWith($with)
      {
          foreach ($with as $relation) {
              if (str_contains($relation, 'morphTo')) {
                  // Custom logic
              }
          }
          return parent::serializeWith($with);
      }
      
  4. Performance Overhead:

    • Issue: Serialization adds latency (especially for large queries).
    • Fix: Benchmark and cache results:
      $serialized = cache()->remember("query:{$queryHash}", now()->addHours(1), function () {
          return EloquentSerialize::serialize(\App\User::query()->where(...));
      });
      
  5. Laravel Version Quirks:

    • Issue: Behavior may vary across Laravel 6–12 (e.g., query builder changes).
    • Fix: Test in your target Laravel version and pin the package version:
      composer require anourvalar/eloquent-serialize:^1.0
      

Debugging Tips:

  • Log Serialized Queries:

    $serialized = EloquentSerialize::serialize($query);
    Log::debug('Serialized query:', ['data' => $serialized]);
    
  • Inspect Unserialized Builders:

    $builder = EloquentSerialize::unserialize($serialized);
    Log::debug('Unserialized query:', [
        'toSql' => $builder->toSql(),
        'bindings' => $builder->getBindings(),
        'with' => $builder->getEagerLoads(),
    ]);
    
  • Common Errors:

    • InvalidQueryException: Query structure is unsupported (e.g., raw SQL).
    • RuntimeException: Schema mismatch (e.g., missing table/column).
    • BindingResolutionException: Model not found (e.g., App\User not autoloaded).

Extension Points:

  1. Custom Serializer: Override methods in AnourValar\EloquentSerialize\Serializer:

    class AppSerializer extends Serializer
    {
        protected function serializeWhere($where)
        {
            // Add custom logic for your `where` clauses
            return parent::serializeWhere($where);
        }
    }
    
  2. Middleware for Validation:

    public function handle($request, Closure $next)
    {
        if ($request->has('serialized_query')) {
            try {
                EloquentSerialize::unserialize($request->serialized_query);
            } catch (\Exception $e) {
                return response()->json(['error' => 'Invalid query'], 400);
            }
        }
        return $next($request);
    }
    
  3. Queue Payloads: Serialize queries for delayed execution:

    // Job payload
    $job = new ProcessUsersJob(
        EloquentSerialize::serialize(\App\User
    
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.
datacore/hub-sdk
alengo/sulu-http-cache-bundle
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
imbo/imbo-coding-standard
visualbuilder/filament-lottie
servicioslineaonce/starter-kit
atomcoder/laravel-reorderable
irajul/filament-shadcn-theme
agtp/agtp-php
agtp/mod-php
centraldesktop/protobuf-php
trappistes/laravel-custom-fields
splash/sonata-admin
splash/metadata