PHPackages                             issam-elkhadir/laravel-query-macros - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. issam-elkhadir/laravel-query-macros

ActiveLibrary[Database &amp; ORM](/categories/database)

issam-elkhadir/laravel-query-macros
===================================

A collection of useful, production-ready Eloquent query macros for Laravel

v1.0.0(4mo ago)10MITPHPPHP ^8.2CI passing

Since Dec 15Pushed 4mo agoCompare

[ Source](https://github.com/issamElkhadirYC/laravel-query-macros)[ Packagist](https://packagist.org/packages/issam-elkhadir/laravel-query-macros)[ Docs](https://github.com/issamElkhadirYC/laravel-query-macros)[ RSS](/packages/issam-elkhadir-laravel-query-macros/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (5)Versions (2)Used By (0)

Laravel Query Macros
====================

[](#laravel-query-macros)

[![Tests](https://github.com/issamElkhadirYC/laravel-query-macros/actions/workflows/tests.yml/badge.svg)](https://github.com/issamElkhadirYC/laravel-query-macros/actions)[![Latest Version](https://camo.githubusercontent.com/e99b37e098127512be5ec3774f159f3665b8c6c414e86e278a8b0cb370fb86a4/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f697373616d2d656c6b68616469722f6c61726176656c2d71756572792d6d6163726f732e737667)](https://packagist.org/packages/issam-elkhadir/laravel-query-macros)[![PHP Version](https://camo.githubusercontent.com/c5e8da782b1a0673c08b4f474108036d2cc973470eed2d5d89d48e8c8475eee6/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d253345253344382e322d626c75652e737667)](https://php.net)[![Laravel Version](https://camo.githubusercontent.com/3413b01aac22dae409978d6232e25fbf749bacd26b92908c407fb16ea97d70d7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c61726176656c2d25334525334431302e302d7265642e737667)](https://laravel.com)[![License](https://camo.githubusercontent.com/7013272bd27ece47364536a221edb554cd69683b68a46fc0ee96881174c4214c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d626c75652e737667)](LICENSE)

A collection of useful, production-ready Eloquent query macros that solve common pain points in Laravel applications.

Features
--------

[](#features)

- 🔍 **Cross-database LIKE search** with case sensitivity control
- 📦 **JSON array searching** - check if JSON contains ANY of multiple values
- 🚀 **Zero dependencies** (except Laravel)
- ✅ **Production-tested** with comprehensive test suite
- 🌐 **Multi-database support** - MySQL, PostgreSQL, SQLite, SQL Server
- 🎯 **Type-safe** with strict PHP 8.2+ typing

Requirements
------------

[](#requirements)

- PHP 8.2+
- Laravel 10+ or 11+

Installation
------------

[](#installation)

```
composer require issam-elkhadir/laravel-query-macros
```

The service provider will be auto-discovered. If you're using Laravel &lt; 5.5, manually register it in `config/app.php`:

```
'providers' => [
    // ...
    LaravelQueryMacros\QueryMacros\QueryMacrosServiceProvider::class,
],
```

Available Macros
----------------

[](#available-macros)

### 1. `whereLike()` - Cross-Database LIKE Search

[](#1-wherelike---cross-database-like-search)

Cross-database LIKE search with case sensitivity control and wildcard escaping.

**Signature:**

```
whereLike(string $column, string $value, bool $caseSensitive = false, bool $escapeWildcards = false)
```

**Why use this?** Standard `where('column', 'LIKE', '%value%')` doesn't handle case sensitivity consistently across databases. This macro provides a unified API with performance optimizations per database.

**Examples:**

```
// Case-insensitive search (default)
User::whereLike('name', 'john')->get();
// Finds: "John Doe", "johnny", "JOHN", etc.

// Case-sensitive search
User::whereLike('name', 'john', caseSensitive: true)->get();
// Only finds exact case matches

// Escape wildcards for literal % or _ search
Product::whereLike('name', '100%', escapeWildcards: true)->get();
// Finds products with literal "100%" in name

// Chain with other conditions
User::where('status', 'active')
    ->whereLike('name', 'john')
    ->get();

// Multiple whereLike conditions
User::whereLike('name', 'john')
    ->whereLike('email', 'example.com')
    ->get();
```

**Database Implementation:**

- **MySQL/MariaDB**: Uses `LOWER()` function for case-insensitive, `LIKE BINARY` for case-sensitive
- **PostgreSQL**: Uses `ILIKE` operator for case-insensitive, `LIKE` for case-sensitive
- **SQLite**: Uses `LOWER()` function for case-insensitive, `COLLATE BINARY` for case-sensitive
- **SQL Server**: Uses `LOWER()` function

**Performance Note:** Case-insensitive searches using `LOWER()` cannot utilize indexes. For large datasets with frequent searches, consider:

- Adding a full-text index
- Creating a generated/computed column with lowercase values
- Using database-specific full-text search features

---

### 2. `orWhereLike()` - OR Variant of whereLike

[](#2-orwherelike---or-variant-of-wherelike)

OR variant of `whereLike` - adds an OR condition for LIKE search.

**Signature:**

```
orWhereLike(string $column, string $value, bool $caseSensitive = false, bool $escapeWildcards = false)
```

**Why use this?** Useful for searching across multiple columns or adding alternative conditions with consistent case handling.

**Examples:**

```
// Search in multiple columns with OR
User::where('status', 'active')
    ->orWhereLike('name', 'john')
    ->orWhereLike('email', 'john')
    ->get();

// Combine whereLike and orWhereLike
User::whereLike('name', 'john')
    ->orWhereLike('name', 'jane')
    ->get();

// With initial WHERE condition
User::where('id', '>', 100)
    ->orWhereLike('email', 'gmail.com')
    ->get();
```

---

### 3. `whereJsonContainsAny()` - JSON Array Search

[](#3-wherejsoncontainsany---json-array-search)

Check if a JSON column contains ANY of the provided values.

**Signature:**

```
whereJsonContainsAny(string $column, array $values)
```

**Why use this?** Laravel's `whereJsonContains()` only checks for a single value. This macro allows checking for multiple values in a single, efficient query.

**Examples:**

```
// Find users with any of these roles
User::whereJsonContainsAny('roles', ['admin', 'moderator', 'editor'])->get();

// Find products in any of these categories (numeric IDs)
Product::whereJsonContainsAny('category_ids', [1, 2, 3])->get();

// Search for tags
Post::whereJsonContainsAny('tags', ['laravel', 'php', 'vue'])->get();

// Chain with other conditions
Product::where('status', 'active')
    ->whereJsonContainsAny('tags', ['featured', 'popular'])
    ->get();

// Multiple JSON conditions
Product::whereJsonContainsAny('tags', ['electronics'])
    ->whereJsonContainsAny('categories', [1, 2, 3])
    ->get();
```

**Supported Value Types:**

- ✅ Strings: `['admin', 'moderator']`
- ✅ Numbers: `[1, 2, 3]`
- ✅ Mixed types: `['admin', 123, true]`

**Database Implementation:**

- **MySQL/MariaDB**: Uses `JSON_CONTAINS()` function (MySQL 5.7+)
- **PostgreSQL**: Uses `?|` operator with `::jsonb` (PostgreSQL 9.4+)
- **SQLite**: Uses `json_each()` function (SQLite 3.9+)
- **SQL Server**: Uses `OPENJSON()` function (SQL Server 2016+)

**Edge Cases:**

- Empty array (`[]`): Returns no results (returns `WHERE 1 = 0`)
- Null JSON column: Excluded from results
- Duplicate values in search array: Handled correctly (no duplicates in results)
- Special characters: Properly encoded with `JSON_UNESCAPED_UNICODE`
- Unicode strings: Fully supported (emoji, Chinese, Arabic, etc.)

**Performance Note:** JSON operations can be slower than regular column searches. For frequently queried JSON columns, consider:

- Adding JSON indexes (MySQL 5.7+, PostgreSQL supports GIN indexes on JSONB)
- Normalizing data into separate tables if performance is critical
- Using generated/virtual columns for frequently searched JSON keys

**Example JSON Index (MySQL):**

```
// In your migration
Schema::table('users', function (Blueprint $table) {
    $table->index('roles', 'users_roles_index', 'json');
});
```

---

Database Support
----------------

[](#database-support)

DatabasewhereLikeorWhereLikewhereJsonContainsAnyNotes**MySQL 5.7+**✅✅✅Full support**MariaDB 10.2+**✅✅✅Full support**PostgreSQL 9.4+**✅✅✅Full support, uses JSONB**SQLite 3.9+**✅✅✅See limitations below**SQL Server 2016+**✅✅✅Full support### SQLite Limitations

[](#sqlite-limitations)

**escapeWildcards Parameter:**SQLite's `LIKE` operator does not support the standard SQL `ESCAPE` clause. This means:

- ⚠️ `escapeWildcards: true` has **limited effect** in SQLite
- ✅ Works correctly on **MySQL, PostgreSQL, and SQL Server**
- 🔧 **Workaround for SQLite**: Use exact matching with `where('column', '=', 'value')` if you need literal wildcard characters

**Example of the limitation:**

```
// On MySQL/PostgreSQL - works as expected
Product::whereLike('name', '100%', escapeWildcards: true)->get();
// Returns only products with literal "100%" in name

// On SQLite - may match more broadly
Product::whereLike('name', '100%', escapeWildcards: true)->get();
// May also match "100x", "1000", etc. due to SQLite limitations
```

**Recommendation:** For production applications using MySQL, PostgreSQL, or SQL Server, the `escapeWildcards` feature works correctly and can be used confidently.

---

Performance Considerations
--------------------------

[](#performance-considerations)

### Indexing Strategies

[](#indexing-strategies)

**For LIKE Searches:**

```
// Case-sensitive searches can use regular indexes
Schema::table('users', function (Blueprint $table) {
    $table->index('email');
});

// Case-insensitive searches benefit from expression indexes (PostgreSQL)
DB::statement('CREATE INDEX users_email_lower_idx ON users (LOWER(email))');

// Or use full-text indexes for better performance
Schema::table('posts', function (Blueprint $table) {
    $table->fullText('content');
});
```

**For JSON Searches:**

```
// MySQL 8.0+ multi-valued index on JSON array
Schema::table('products', function (Blueprint $table) {
    DB::statement('ALTER TABLE products ADD INDEX tags_idx ((CAST(tags AS CHAR(255) ARRAY)))');
});

// PostgreSQL GIN index on JSONB
DB::statement('CREATE INDEX products_tags_gin_idx ON products USING GIN (tags)');
```

### When NOT to Use These Macros

[](#when-not-to-use-these-macros)

- ❌ **Full-text search needs**: Use Laravel Scout or database full-text search
- ❌ **Very large datasets (millions of rows)**: Use specialized search engines (Elasticsearch, Meilisearch)
- ❌ **Complex text matching**: Use regular expressions or full-text search features
- ❌ **When you need ranking/relevance scores**: Use full-text search

### When to Use These Macros

[](#when-to-use-these-macros)

- ✅ **Simple partial matching**: Finding names, emails, descriptions
- ✅ **Cross-database compatibility**: Need same behavior across databases
- ✅ **Small to medium datasets**: &lt; 100k rows with proper indexes
- ✅ **JSON array membership**: Checking if value exists in JSON array
- ✅ **Case-sensitive control**: Need explicit case handling

---

Testing
-------

[](#testing)

Run the test suite:

```
composer test
```

Or with Pest:

```
./vendor/bin/pest
```

Run tests with coverage:

```
./vendor/bin/pest --coverage
```

### Test Coverage

[](#test-coverage)

- ✅ All macros tested across multiple scenarios
- ✅ Edge cases (empty strings, null values, special characters, unicode)
- ✅ Cross-database compatibility (tests run on SQLite)
- ✅ Query execution verification (not just syntax checking)
- ✅ Case sensitivity testing
- ✅ Chainability testing

---

Code Quality
------------

[](#code-quality)

- ✅ **PSR-4** autoloading
- ✅ **PSR-12** coding standards
- ✅ **Strict types** (`declare(strict_types=1)`)
- ✅ **Comprehensive PHPDoc** blocks with examples
- ✅ **Zero dependencies** (except Laravel)
- ✅ **Cross-database compatibility** tested
- ✅ **Type-safe** with PHP 8.2+ features
- ✅ **SQL injection prevention** via parameterized queries

---

Real-World Examples
-------------------

[](#real-world-examples)

### User Search with Multiple Criteria

[](#user-search-with-multiple-criteria)

```
// Search users by name or email
User::where('status', 'active')
    ->where(function($query) use ($searchTerm) {
        $query->whereLike('name', $searchTerm)
              ->orWhereLike('email', $searchTerm);
    })
    ->paginate(20);
```

### Product Filtering by Tags

[](#product-filtering-by-tags)

```
// Find products with any of the selected tags
Product::where('in_stock', true)
    ->whereJsonContainsAny('tags', $selectedTags)
    ->orderBy('created_at', 'desc')
    ->get();
```

### Case-Sensitive Email Search

[](#case-sensitive-email-search)

```
// Find exact email match (case-sensitive)
User::whereLike('email', $email, caseSensitive: true)->first();
```

### Multi-Role Access Control

[](#multi-role-access-control)

```
// Find users with any admin-level role
User::whereJsonContainsAny('roles', ['super-admin', 'admin', 'moderator'])
    ->get();
```

---

Contributing
------------

[](#contributing)

Contributions are welcome! Please ensure:

1. **All tests pass**: `composer test`
2. **Code follows PSR-12** standards
3. **New macros include**:
    - Comprehensive tests (including edge cases)
    - PHPDoc blocks with examples
    - Cross-database support where applicable
    - Performance notes
4. **Documentation is updated** in README.md

### Development Setup

[](#development-setup)

```
# Clone the repository
git clone https://github.com/issamElkhadirYC/laravel-query-macros.git

# Install dependencies
composer install

# Run tests
composer test
```

---

Changelog
---------

[](#changelog)

See [CHANGELOG.md](CHANGELOG.md) for version history.

---

Security
--------

[](#security)

If you discover any security-related issues, please email  instead of using the issue tracker.

---

Credits
-------

[](#credits)

- **[Issam Elkhadir](https://github.com/issamElkhadirYC)**
- [All Contributors](../../contributors)

---

License
-------

[](#license)

The MIT License (MIT). Please see [LICENSE](LICENSE) for more information.

---

Support
-------

[](#support)

- 📖 [Documentation](https://github.com/issamElkhadirYC/laravel-query-macros/wiki)
- 🐛 [Issue Tracker](https://github.com/issamElkhadirYC/laravel-query-macros/issues)
- 💬 [Discussions](https://github.com/issamElkhadirYC/laravel-query-macros/discussions)

---

###  Health Score

34

—

LowBetter than 77% of packages

Maintenance73

Regular maintenance activity

Popularity2

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity47

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

149d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/cdc59c77d9689ab7a12cff8d0e27000b4b11c5de4b5bb4af270f9fd28ed06ec5?d=identicon)[issamElkhadirYC](/maintainers/issamElkhadirYC)

---

Top Contributors

[![issamElkhadirYC](https://avatars.githubusercontent.com/u/147394866?v=4)](https://github.com/issamElkhadirYC "issamElkhadirYC (9 commits)")

---

Tags

eloquentlaravelphpquery-macrosjsonsearchlaraveldatabaseeloquentquerylikemacros

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/issam-elkhadir-laravel-query-macros/health.svg)

```
[![Health](https://phpackages.com/badges/issam-elkhadir-laravel-query-macros/health.svg)](https://phpackages.com/packages/issam-elkhadir-laravel-query-macros)
```

###  Alternatives

[tucker-eric/eloquentfilter

An Eloquent way to filter Eloquent Models

1.8k4.8M26](/packages/tucker-eric-eloquentfilter)[mongodb/laravel-mongodb

A MongoDB based Eloquent model and Query builder for Laravel

7.1k7.2M71](/packages/mongodb-laravel-mongodb)[mehdi-fathi/eloquent-filter

Eloquent Filter adds custom filters automatically to your Eloquent Models in Laravel.It's easy to use and fully dynamic, just with sending the Query Strings to it.

450191.6k1](/packages/mehdi-fathi-eloquent-filter)[cybercog/laravel-love

Make Laravel Eloquent models reactable with any type of emotions in a minutes!

1.2k302.7k1](/packages/cybercog-laravel-love)[reedware/laravel-relation-joins

Adds the ability to join on a relationship by name.

2121.2M13](/packages/reedware-laravel-relation-joins)[toponepercent/baum

Baum is an implementation of the Nested Set pattern for Eloquent models.

3154.7k](/packages/toponepercent-baum)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
