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 Laravel, PHP, Tips & Tricks

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()

        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": [

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(
                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(