datalogix / laravel-builder-macros
A set of useful Laravel builder macros.
Package info
github.com/datalogix/laravel-builder-macros
pkg:composer/datalogix/laravel-builder-macros
Requires
- php: ^8.2
- illuminate/database: ^12.0|^13.0
- illuminate/support: ^12.0|^13.0
Requires (Dev)
- graham-campbell/testbench: ^6.3
- laravel/pint: ^1.30
- phpunit/phpunit: ^11.5
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
A set of useful Laravel builder macros.
Installation
You can install the package via composer:
composer require datalogix/laravel-builder-macros
The package will automatically register itself.
Macros
addSubSelect
Add a select sub query.
// Params: $column, $query (Eloquent or query builder) $query->addSubSelect('primary_address_id', Address::select('id') ->where('user_id', $user->id) ->primary() ); // It adds primary_address_id to the result set
defaultSelectAll
It selects all columns from the query. Useful for queries with joins and additional selects.
$query->defaultSelectAll() ->join('contacts', 'users.id', '=', 'contacts.user_id') ->addSelect('contacts.name as contact_name');
filter
Filter in your models. Each filter is applied with whereLike, and blank values are ignored.
$query->filter(['name' => 'john'])->get(); // Returns all results where name includes `john`
You can also supply multiple filters:
$query->filter(['name' => 'john', 'contact.email' => '@'])->get(); // Returns all results where name includes `john` and contact.email includes `@`
When filtering with request input, pass the allowed columns as the second argument:
$query->filter($request->all(), ['name', 'email', 'contact.email'])->get(); // Or $query->filter($request->only(['name', 'email', 'contact.email']))->get();
Pass true as the third argument to escape %, _ and ! in the values, so they are matched literally (see whereLike):
$query->filter($request->all(), ['name', 'email'], true)->get();
Warning
Never pass unfiltered input such as $request->all() without allowed columns: every key becomes a column (or a relation, when it contains a .), so users could filter on any column, like password, or break the query with keys like page.
joinRelation
A query way to join relations.
// Params: $relationName, $operator $query->joinRelation('contact');
Nested relations are joined one after another:
$query->joinRelation('posts.comments'); // Joins posts and then comments
Supports BelongsTo, HasOne, HasMany, MorphOne and MorphMany relations. Polymorphic relations also match the morph type, so only rows of the model type are joined. MorphTo relations aren't supported, as the related table depends on each row.
When no columns are selected, it selects only the columns of the main table (see defaultSelectAll), so columns of the joined table like id don't override the model attributes. Soft deleted rows of models using SoftDeletes are not joined. Other constraints defined in the relation (where, latestOfMany, etc.) are not applied to the join. Joining a HasMany relation returns the main model once for each related row.
Relations to the same table, like parent or children, are joined under the relation name, so its columns are referenced through it:
$query->joinRelation('parent')->addSelect('parent.name as parent_name');
The same applies to relations to a table that is already joined, like author and editor both to users. The first one keeps the table name and the next ones are joined under the relation name:
$query->joinRelation('author') ->joinRelation('editor') ->addSelect('users.name as author_name', 'editor.name as editor_name');
leftJoinRelation
A query to left join relations.
// Params: $relationName, $operator $query->leftJoinRelation('contact');
It works like joinRelation, with a LEFT JOIN.
map
A direct method to retrieve the results and map it.
$userIds = $query->where('user_id', 10)->map(function ($user) { return $user->id; }); // Returns a collection
search
An alias of whereLike, with the same arguments, that doesn't conflict with the query builder's native whereLike.
$query->search(['title', 'contact.name'], 'john')->get();
Note
Models using Laravel Scout have a static search method, so Model::search() calls Scout. Use Model::query()->search() instead.
whereLike
Search in your models with the LIKE operator.
Note
The query builder has a native whereLike($column, $value, $caseSensitive = false) method. On Eloquent builders this macro takes precedence over it, with a different behavior: the value is wrapped with % and the third argument is $start, not $caseSensitive. On DB::table() queries the native method is used. Prefer the search alias to avoid the confusion.
$query->whereLike('title', 'john')->get(); // Returns all results where title includes `john`
$query->whereLike('title', 'john', false)->get(); // Returns all results where title starts with `john`
$query->whereLike('title', 'john', true, false)->get(); // Returns all results where title ends with `john`
You can also supply an array of columns to search in:
$query->whereLike(['title', 'contact.name'], 'john')->get(); // Returns all results where title or contact.name includes `john`
Notes:
- Columns containing a
.are searched in relations (contact.namesearchesnamein thecontactrelation, andposts.comments.bodysearches nested relations). Table-prefixed columns likeusers.nameare not supported. Relation searches don't support aliased tables (from('users as u')), as Laravel'swhereHasdoesn't. - Columns ending in
_idare compared with=instead ofLIKE. - Blank and boolean values are ignored.
%and_in the value act as wildcards, unless escaped with the$escapeargument:
// Params: $columns, $value, $start, $end, $escape $query->whereLike('title', '100%', true, true, true)->get(); // Or $query->whereLike('title', '100%', escape: true)->get(); // Returns all results where title includes `100%`, but not `1000`
Escaping uses LIKE ? ESCAPE '!', so it works the same way in MySQL, PostgreSQL, SQLite and SQL Server.