Laravel Eloquent Macro's ... continued
In this post I take the use of these macro's to the next level (and show one for performance....)
In the previous post on this we looked at how using a macro made for a nice re-usable query builder macro.
Click here to view the previous post
Now doing this is all good, however while building my Laravel Api Controller package i put together 2 macro's to deal with larger queries causing quite a slowdown when using eloquent, these are getRaw and paginateRaw and as they read they run raw queries bypassing eloquent models.
they look like:
EloquentBuilder::macro('getRaw', function (array $columns = ['*']) {
return $this->getQuery()
->get($columns);
});
EloquentBuilder::macro('paginateRaw', function ($limit = 25, array $columns = ['*'], $pageName = 'page', $page = null) {
return $this->getQuery()
->paginate($limit, $columns, $pageName, $page);
});
Now these methods behind the scene simply grab the sql query and run it returning the result bypassing eloquent mapping each record back to an eloquent model instance.
Now I cannot realistically tell people to copy that code into their AppServiceProvider now can i?
Enter Service Providers -- simply when you create a package for laravel you add a service provider and add this in to your own service provider, register it by making sure the following is in your composer.json for the package
"extra": {
"laravel": {
"providers": [
"Phpsa\\LaravelApiController\\ServiceProvider"
]
}
},
this will register the service provider and run its register method, and hey, you now have your macro's in your project.
Here are a few others that i tend to use now and again -- perhaps i should look at building them into a single package at some stage???
//where date and time instead of simply date or time
Builder::macro('whereDateTime', function ($column, $operator, $value = null, $boolean = 'and') {
return $this->whereDate($column, $operator, $value, $boolean)
->whereTime($column, $operator, $value, $boolean);
});
//where null or empty
Builder::macro('nullOrEmpty', function (string $column) {
return $this->where(function (Builder $builder) use ($column) {
$builder->where($column, '=', '')->orWhereNull($column);
});
});
//added for an or null or empty option
Builder::macro('orNullOrEmpty', function (string $column) {
return $this->orWhere(function (Builder $builder) use ($column) {
$builder->where($column, '=', '')->orWhereNull($column);
});
});
//case insensitive where clause.
Builder::macro('iWhere', function ($column, $operator = null, $value = null, $boolean = 'and') {
if (is_array($column)) {
return $this->addArrayOfWheres($column, $boolean, 'iWhere');
}
[$value, $operator] = $this->prepareValueAndOperator(
$value,
$operator,
func_num_args() === 2
);
return $this->whereRaw("LOWER({$column}) {$operator} ?", [strtolower($value)], $boolean);
});
//ok this one a bit different --needed to convert a hasMany into a hasOne relationship.
HasMany::macro('toHasOne', function () {
return new HasOne(
$this->query,
$this->parent,
$this->foreignKey,
$this->localKey
);
});