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

Query Laravel Package

derafu/query

Expressive path-based query builder for PHP from Derafu. Build queries using readable, JSONPath-like paths for nested data structures and collections. Lightweight package with full documentation at derafu.dev/docs/data/query.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require derafu/query
    

    Requires PHP 8.5+ and Laravel 10+ (for Eloquent integration).

  2. First Use Case: Basic Filtering Query an Eloquent model with nested relationships:

    use Derafu\Query\Query;
    use App\Models\User;
    
    $users = User::all()->toArray();
    $query = Query::from($users)
        ->where('address.city', 'eq', 'Berlin')
        ->where('posts[*].status', 'eq', 'published')
        ->get();
    
  3. Where to Look First:

    • Official Docs: Covers syntax, operators, and path traversal.
    • src/QueryBuilder.php: Core logic for path resolution and SQL generation.
    • tests/: Example use cases for filtering, projections, and aggregations.

Implementation Patterns

1. Path-Based Querying with Eloquent

Workflow: Use Derafu for complex filters, then hydrate results back to Eloquent.

$rawData = User::with('posts')->get()->toArray();
$filtered = Query::from($rawData)
    ->where('posts[*].views > 100')
    ->get();
// Convert back to Eloquent collection if needed

2. Dynamic API Filtering

Workflow: Parse frontend query params into path conditions.

$filters = [
    'user.address.city' => 'Berlin',
    'posts[*].status'   => 'published',
];
$query = Query::from($users)
    ->where(...array_map(fn($val) => ["$val[0]", 'eq', $val[1]], $filters))
    ->get();

3. Hybrid Eloquent + Derafu

Pattern: Use Eloquent for relationships, Derafu for post-filtering.

$query = User::query()
    ->whereHas('posts', fn($q) => $q->where('status', 'published'))
    ->get()
    ->filter(fn($user) => Query::from($user->toArray())
        ->where('address.city', 'eq', 'Berlin')
        ->get()['users'][0] ?? false);

4. Doctrine ORM Integration

Workflow: Replace Doctrine queries with path-based syntax.

$em = $entityManager;
$users = $em->getRepository(User::class)->findAll();
$filtered = Query::from($users)
    ->where('address.city', 'eq', 'Paris')
    ->get();

5. Aggregations and Grouping

Pattern: Use Derafu for pre-processing before Laravel aggregations.

$grouped = Query::from($users)
    ->groupBy('address.city')
    ->get();
// Pass to Laravel for further processing

6. Custom Operators

Extension Point: Extend the query builder with domain-specific operators.

Query::extend('contains', function($query, $path, $value) {
    return $query->where("{$path} LIKE '%{$value}%'");
});
// Usage:
$query->where('user.bio', 'contains', 'PHP');

Gotchas and Tips

Pitfalls

  1. SQL Injection Risks:

    • Always use parameterized paths (e.g., where('user.$id.address', ...)).
    • Avoid dynamic path construction from user input:
      // UNSAFE: User-controlled path
      $path = $_GET['path'];
      $query->where($path, 'eq', 'value'); // ❌
      
  2. Performance with Deep Paths:

    • Nested paths (e.g., user.address.city.country) generate complex SQL.
    • Mitigation: Use select() to limit fields:
      $query->select('user.name', 'user.address.city');
      
  3. Eloquent Hydration Issues:

    • Derafu returns arrays, not Eloquent models. Use ->toArray() carefully:
      // ❌ Breaks relationships
      $users = User::all()->toArray();
      $filtered = Query::from($users)->where(...)->get();
      // ✅ Fix: Re-fetch from DB or hydrate manually
      
  4. Circular References:

    • Paths with loops (e.g., user.posts[*].author.user) cause infinite recursion.
    • Fix: Add depth limits or validate paths pre-execution.
  5. Case Sensitivity:

    • Paths are case-sensitive (e.g., User.Nameuser.name).
    • Tip: Normalize paths in config or use constants.

Debugging Tips

  1. Inspect Generated SQL: Enable logging for raw SQL:

    Query::enableLogging();
    $query->where(...)->get(); // Logs SQL to storage/logs/derafu.log
    
  2. Validate Paths: Use Query::validatePath($path) to check syntax before execution.

  3. Test Edge Cases:

    • Null values: where('user.address.city', 'eq', null)
    • Empty arrays: where('user.tags[*]', 'exists')
    • Mixed data types: where('user.metadata', 'type', 'string')

Configuration Quirks

  1. Path Auto-Completion:

    • No built-in IDE support. Workaround: Use PHPDoc annotations:
      /**
       * @property string $address->city
       * @property Post[] $posts
       */
      class User {}
      
  2. Laravel Service Provider:

    • No official Laravel binding. Manual setup:
      Query::macro('users', fn() => Query::from(User::all()->toArray()));
      
  3. Caching:

    • Derafu queries cannot be cached directly (stateful paths).
    • Workaround: Cache raw data + filter in memory:
      $cachedUsers = cache()->remember('users', now()->addHour(), fn() => User::all());
      $filtered = Query::from($cachedUsers)->where(...)->get();
      

Extension Points

  1. Custom Data Sources: Override Query::from() for non-array inputs (e.g., Doctrine collections):

    Query::extendSource('doctrine', function($collection) {
        return array_map(fn($entity) => $entity->toArray(), $collection);
    });
    // Usage:
    Query::from($doctrineCollection, 'doctrine')->where(...);
    
  2. Operator Aliases: Add shorthand for common operations:

    Query::alias('gt', '>');
    // Usage:
    $query->where('user.age', 'gt', 25);
    
  3. Path Normalization: Transform paths before execution (e.g., snake_case to camelCase):

    Query::normalizePaths(fn($path) => Str::of($path)->snake()->__toString());
    
  4. Query Monitoring: Hook into the query lifecycle:

    Query::on('beforeExecute', fn($query) => logger()->info('Executing:', $query->getPath()));
    
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.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky