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 Builder Laravel Package

mohammad-fouladgar/eloquent-builder

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require mohammad-fouladgar/eloquent-builder
    

    Add the service provider to config/app.php under providers:

    MohammadFouladgar\EloquentBuilder\EloquentBuilderServiceProvider::class,
    
  2. First Use Case: Define a query builder class for your model (e.g., User). Create a file at app/Builders/UserBuilder.php:

    namespace App\Builders;
    
    use MohammadFouladgar\EloquentBuilder\EloquentBuilder;
    
    class UserBuilder extends EloquentBuilder
    {
        protected $model = \App\Models\User::class;
    
        public function defaultScope()
        {
            return $this->model::where('is_active', true);
        }
    
        public function applyFilters($filters)
        {
            if (isset($filters['age_more_than'])) {
                return $this->where('age', '>', $filters['age_more_than']);
            }
    
            if (isset($filters['gender'])) {
                return $this->where('gender', $filters['gender']);
            }
    
            if (isset($filters['has_published_post'])) {
                return $this->whereHas('posts', function ($query) {
                    $query->where('published', true);
                });
            }
        }
    }
    
  3. Usage in Controller:

    use App\Builders\UserBuilder;
    
    public function index(Request $request)
    {
        $users = (new UserBuilder)->get($request->all());
        return response()->json($users);
    }
    

Implementation Patterns

Common Workflows

  1. Filtering:

    • Use applyFilters() to handle request parameters dynamically.
    • Example: Filter by multiple conditions with nested logic:
      public function applyFilters($filters)
      {
          if (isset($filters['search'])) {
              return $this->where('name', 'like', "%{$filters['search']}%")
                          ->orWhere('email', 'like', "%{$filters['search']}%");
          }
      }
      
  2. Sorting:

    • Override applySort() to handle sort_by and sort_direction:
      public function applySort($sortBy, $sortDirection = 'asc')
      {
          if (!empty($sortBy)) {
              return $this->orderBy($sortBy, $sortDirection);
          }
      }
      
  3. Pagination:

    • Leverage Laravel’s built-in pagination:
      $users = (new UserBuilder)->paginate($request->all());
      
  4. Relationships:

    • Use with() or whereHas() in defaultScope() or applyFilters():
      public function defaultScope()
      {
          return $this->model::with(['posts', 'profile']);
      }
      
  5. Custom Query Logic:

    • Extend applyFilters() for complex logic (e.g., date ranges):
      public function applyFilters($filters)
      {
          if (isset($filters['created_after'])) {
              return $this->where('created_at', '>', $filters['created_after']);
          }
      }
      

Integration Tips

  1. Request Validation:

    • Validate request parameters before passing them to the builder:
      $validated = $request->validate([
          'age_more_than' => 'sometimes|integer',
          'gender' => 'sometimes|in:male,female',
      ]);
      $users = (new UserBuilder)->get($validated);
      
  2. API Resources:

    • Pair with Laravel’s API Resources for consistent JSON responses:
      return UserResource::collection($users);
      
  3. Testing:

    • Mock the builder in tests:
      $builder = $this->app->make(UserBuilder::class);
      $result = $builder->get(['age_more_than' => 25]);
      $this->assertCount(1, $result);
      
  4. Caching:

    • Cache frequent queries (e.g., with Cache::remember):
      return Cache::remember("users_{$request->queryString}", now()->addHours(1), function () use ($request) {
          return (new UserBuilder)->get($request->all());
      });
      

Gotchas and Tips

Pitfalls

  1. N+1 Queries:

    • Avoid eager-loading relationships in applyFilters() without with(). Use with() in defaultScope() or manually in the builder:
      // Bad: Causes N+1 queries
      public function applyFilters($filters) {
          if (isset($filters['post_id'])) {
              return $this->whereHas('posts', fn($q) => $q->where('id', $filters['post_id']));
          }
      }
      // Good: Use with() in defaultScope()
      
  2. SQL Injection:

    • Always sanitize input in applyFilters(). The package handles basic cases, but custom logic may expose risks:
      // Risky: Directly interpolating user input
      public function applyFilters($filters) {
          return $this->where('name', 'like', "%{$filters['name']}%"); // Safe if $filters['name'] is validated
      }
      
  3. Overriding Methods:

    • Ensure you call parent::applyFilters() if extending existing logic:
      public function applyFilters($filters)
      {
          parent::applyFilters($filters); // Preserve parent behavior
          // Add custom logic
      }
      
  4. Deprecated Methods:

    • The package is last updated in 2019. Check for Laravel version compatibility (e.g., avoid whereHas syntax changes in Laravel 9+).

Debugging Tips

  1. Log Queries:

    • Enable Laravel’s query logging to debug SQL:
      \DB::enableQueryLog();
      $users = (new UserBuilder)->get($request->all());
      dd(\DB::getQueryLog());
      
  2. Validate Filters:

    • Log or dump $filters in applyFilters() to verify input:
      public function applyFilters($filters) {
          \Log::debug('Filters received:', $filters);
          // ...
      }
      
  3. Test Edge Cases:

    • Test with empty arrays, null values, and invalid inputs:
      $this->get('/users?invalid_param=123')->assertOk(); // Ensure graceful handling
      

Extension Points

  1. Custom Directives:

    • Extend the builder with custom directives (e.g., range, in) by overriding applyFilters():
      public function applyFilters($filters) {
          if (isset($filters['age_range'])) {
              [$min, $max] = explode(',', $filters['age_range']);
              return $this->whereBetween('age', [$min, $max]);
          }
      }
      
  2. Conditional Scopes:

    • Use when() for dynamic scopes:
      public function defaultScope()
      {
          return $this->model::when($this->request->has('active_only'), fn($q) => $q->where('is_active', true));
      }
      
  3. Reusable Builders:

    • Create base builders for shared logic (e.g., BaseBuilder with common methods):
      abstract class BaseBuilder extends EloquentBuilder {
          protected function applySearch($searchTerm) {
              return $this->where('name', 'like', "%{$searchTerm}%");
          }
      }
      
  4. Event Hooks:

    • Dispatch events before/after query execution (e.g., for analytics):
      public function get($filters = [])
      {
          event(new QueryBuilding($this->model, $filters));
          return parent::get($filters);
      }
      
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.
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
leek/filament-subtenant-scope