Anibal Cardozo
Anibal Cardozo

Reputation: 83

Eloquent: count(): Parameter must be an array or an object that implements Countable

Ok Im using Illuminate on my php project and recently upgrade from PHP 5 to PHP 7.2.

I have this scope in my Model

Model.php

public function scopeWhereInOrAny(Builder $query, $field, $value)
    {
        if ($value === null || $value === '' || count($value) === 0) {
            return $query;
        }

        return $query->whereIn($field, $value);
    }

a pretty simple scope to accept null when using whereIn. Now I use it in a function

public function getList($params = []) {
        
        $cancelReasons = CancellationReasons
            ::orderBy('id', 'asc')
            ->whereInOrAny('type_booking', $params['type_booking']) // HERE
            ->where('status', '=', 1)
            ->get(['id','name','type_client']);

        return $cancelReasons;

And when I call that method, it kinda works, it returns what it should return but also adds a warning at the end like this

[{"id":1,"name":"He cancelado mi viaje","type_client":1},{"id":2,"name":"Quiero hacer otra actividad","type_client":1},{"id":3,"name":"Quiero modificar la reserva","type_client":1},{"id":4,"name":"He encontrado un precio m\u00e1s barato en otra web","type_client":1},{"id":5,"name":"El proveedor me ha pedido que cancele","type_client":1},{"id":6,"name":"Otros motivos","type_client":1},{"id":7,"name":"Condiciones climatol\u00f3gicas","type_client":2},{"id":8,"name":"Problemas en el destino","type_client":2},{"id":9,"name":"No hay un n\u00famero m\u00ednimo de personas","type_client":2},{"id":10,"name":"Falta de disponibilidad","type_client":2},{"id":11,"name":"Restricciones Covid","type_client":2},{"id":12,"name":"Cancelaci\u00f3n solicitada por el cliente","type_client":2},{"id":13,"name":"Otros motivos","type_client":2},{"id":14,"name":"Cese de la colaboraci\u00f3n con el proveedor","type_client":3},{"id":15,"name":"El proveedor no realiz\u00f3 la actividad","type_client":3},{"id":16,"name":"Otros motivos","type_client":3}]<br />
<b>Warning</b>:  count(): Parameter must be an array or an object that implements Countable in <b>/var/www/html/newadmin/vendor7/illuminate/database/Eloquent/Builder.php</b> on line <b>1015</b><br />

Now debugging I found the issue is here in Builder.php


/**
     * Apply the given scope on the current builder instance.
     *
     * @param  callable $scope
     * @param  array $parameters
     * @return mixed
     */
    protected function callScope(callable $scope, $parameters = [])
    {
        array_unshift($parameters, $this);

        $query = $this->getQuery();

        // We will keep track of how many wheres are on the query before running the
        // scope so that we can properly group the added scope constraints in the
        // query as their own isolated nested where statement and avoid issues.
        $originalWhereCount = count($query->wheres); // HERE IS THE PROBLEM

        $result = $scope(...array_values($parameters)) ?: $this;

        if (count($query->wheres) > $originalWhereCount) {
            $this->addNewWheresWithinGroup($query, $originalWhereCount);
        }

        return $result;
    }

Aparently $query->wheres is equals null on this case and in php 7.2 when using count on null it throws a warning, now why $query->wheres is equals to null? because there are no other wheres before the custom scope so if I change the order of my wheres to

public function getList($params = []) {
    
        $cancelReasons = CancellationReasons
            ::orderBy('id', 'asc')
            ->where('status', '=', 1) //This where before the scope
            ->whereInOrAny('type_booking', $params['type_booking'])
            ->get(['id','name','type_client']);

        return $cancelReasons;
    }


It works perfectly!, but I don't think this really solves the issue long term, sure it solves this particular case but now every time I want to use a scope I need to add a random where first? even if I don't need it? that doesn't seems to be right. So Im looking for a cleaner solution to this issue that will work with other parts where Im using a scope on the querybuilder.

I hope anybody can help me

Upvotes: 0

Views: 42

Answers (0)

Related Questions