Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel - replace null with empty array when no relation is found

Is it possible to replace null with an empty array when no relation is found?

E.g. The customer has contacts and contracts but one of the contract has no web.

$customers = Customer::with('contacts', 'contracts.web')
        ->orderBy('company')->orderBy('prename')->get();

The result would be as following...

2 => array:21 [
  "id" => 1
  "contacts" => array:2 [
    0 => array:12 [
      "id" => 1
      "customer_id" => 1
    ]
    1 => array:12 [
      "id" => 2
      "customer_id" => 1
    ]
  ]
  "contracts" => array:2 [
    0 => array:9 [
      "id" => 1
      "customer_id" => 1
      "web" => array:7 [
        "id" => 1
        "contract_id" => 1
      ]
    ]
    1 => array:9 [
      "id" => 2
      "customer_id" => 1
      "web" => null // should be replaced with []
    ]
  ]
]

As I read in the docs (Constraining Eager Loads), it's only possible to manipulate the query with constraining eager loads.

UPDATE

Contract class

class Contract extends Model
{
    public function web()
    {
        return $this->hasOne(Web::class);
    }
}
like image 803
Ilario Engler Avatar asked Jul 02 '26 05:07

Ilario Engler


1 Answers

For further readers here's an explanation how to solve this kind of problem.

Laravel returns an empty array if no records are found on a hasMany relation. If a hasOne relation is implemented, null will be returned.

So if you need an array also if no record is found on a hasOne relation, you need to do the following.

class Contract extends Model
{

    public function web()
    {
        return $this->hasOne(Web::class)
            ->withDefault(function () {
                return new Web();
            });
    }
}

As implemented like this its not possible to just return an empty array. Why this isn't possible, check out this issue on Laravel GitHub Issue Tracker.

There is existing code that depends on the result of any Eloquent relationship to either be null, a Model instance, or a Collection of Model instances. However, the current functionality of the withDefault() method opens up the potential for returning an object that is not one of those three expected values.

If you return a new \stdClass; or an empty array, an empty instance of web is returned. To get an empty array just instanciate a new Object of the relation class. In my case new Web();.

like image 172
Ilario Engler Avatar answered Jul 03 '26 17:07

Ilario Engler