Michael
Michael

Reputation: 576

Laravel 5.0 Collection contains() not working as expected?

I have a collection of my relationship. 1 Mailgroup has many ExternalClients.

When I dd this collection like this:

dd($mailgroup->externalClients);

I get this result:

Collection {#304 ▼
  #items: array:1 [▼
    0 => ExternalClient {#303 ▼
      #table: "external_clients"
      +timestamps: false
      #casts: array:1 [▶]
      #fillable: array:7 [▶]
      #connection: null
      #primaryKey: "id"
      #perPage: 15
      +incrementing: true
      #attributes: array:8 [▼
        "id" => 1
        "firstname" => "Ganesan "
        "lastname" => "Pandaram"
        "email" => "[email protected]"
        "active" => 1
        "lang" => "nl"
        "company" => "ypto"
        "site_id" => 4
      ]
      #original: array:10 [▶]
      #relations: array:1 [▶]
      #hidden: []
      #visible: []
      #appends: []
      #guarded: array:1 [▶]
      #dates: []
      #touches: []
      #observables: []
      #with: []
      #morphClass: null
      +exists: true
    }
  ]
}

Now I want I try the $collection->contains() function like this I get nothing.

if ($mailgroup->externalClients->contains('[email protected]')) {
    echo 'yes';
}

I am expecting to see 'yes' because we can see that the "[email protected]" is in the collection.

I've also tried this:

if ($mailgroup->externalClients->contains('email', '[email protected]')) {
    echo 'yes';
}

This gives me this error:

Object of class Closure could not be converted to int

Upvotes: 0

Views: 1380

Answers (3)

Robert
Robert

Reputation: 5963

Which version of Laravel are you using?

In v5.8 I am able to filter the objects based on attribute name and value.

See:

>>> $users = factory(App\User::class, 3)->make();
=> Illuminate\Database\Eloquent\Collection {#3278
     all: [
       App\User {#3276
         customer_id: 57,
         name: "Jeanie Cassin V",
         email: "[email protected]",
         is_active: true,
         email_verified_at: DateTime @184931115 {#3273
           date: 1975-11-11 09:45:15.0 UTC (+00:00),
         },
         last_login_at: "2018-12-16 09:06:01",
       },
       App\User {#3285
         customer_id: 58,
         name: "Prof. Lula Moore",
         email: "[email protected]",
         is_active: true,
         email_verified_at: DateTime @270031087 {#3275
           date: 1978-07-23 08:38:07.0 UTC (+00:00),
         },
         last_login_at: "2007-02-19 00:27:52",
       },
       App\User {#3287
         customer_id: 59,
         name: "Conrad Hansen",
         email: "[email protected]",
         is_active: true,
         email_verified_at: DateTime @1026743001 {#3289
           date: 2002-07-15 14:23:21.0 UTC (+00:00),
         },
         last_login_at: "1987-10-06 18:45:35",
       },
     ],    }
>>> $rs = $users->contains('email', '[email protected]');
=> true
>>> $rs = $users->contains('email', '[email protected]');
=> false
>>> $rs = $users->contains(function($user) { return $user->email === '[email protected]'; });
=> true
>>> $rs = $users->contains(function($user) { return $user->email === '[email protected]'; });
=> false

But as stated this is tested in Laravel 5.8.


You could try using an anonymous function to get a true/false return value with a custom comparison.

It will pass 2 params (in 5.8):

  1. The object
  2. The key of the object within the collection

In your case you could skip the second param.

For example:

$email = '[email protected]';

$clientExists = $mailgroup->externalClients->contains(
    function (ExternalClient $externalClient) use ($email) {
        return $externalClient->email === $email;
    });

if ($clientExists) {
    // yes
}

If you need the key of the item (object) within the collection you can use:

$result = $collection->contains(
    function ($object, $key) {
        // check something with $object->x or $key and return bool
    });

Upvotes: 0

Prafulla Kumar Sahu
Prafulla Kumar Sahu

Reputation: 9693

In tinker I did some test, it seems where is not the correct way to do this.

>>> App\User::find(1)->roles->where('role_id', '<', 1)
=> Illuminate\Database\Eloquent\Collection {#3185
     all: [
       App\models\Role {#3176
         id: 1,
         name: "super-admin",
         display_name: "Super Admin",
         description: "This will be one permission, that can not be assigned or
modified.",
         created_at: "2018-12-13 12:09:07",
         updated_at: "2018-12-13 12:09:07",
         pivot: Illuminate\Database\Eloquent\Relations\Pivot {#3177
           user_id: 1,
           role_id: 1,
         },
       },
     ],
   }
>>>
Dell@DESKTOP-KU6707L MINGW64 /d/work/www/charmboard (master)
$ php artisan tinker
Psy Shell v0.9.9 (PHP 7.2.10 — cli) by Justin Hileman
>>> App\User::find(1)->roles->where('role_id', 1)
=> Illuminate\Database\Eloquent\Collection {#3129
     all: [],
   }
>>> App\User::find(1)->roles->where('role_id', 1)->count()
=> 0
>>>

and working for

>>> App\models\Role::where('id', 1)->count()
=> 1

and your case is first 1, I think, you can eager load and use where like

>>> App\User::find(1)->roles()->where('role_id', 1)->get()
=> Illuminate\Database\Eloquent\Collection {#3138
     all: [
       App\models\Role {#3129
         id: 1,
         name: "super-admin",
         display_name: "Super Admin",
         description: "This will be one permission, that can not be assigned or
modified.",
         created_at: "2018-12-13 12:09:07",
         updated_at: "2018-12-13 12:09:07",
         pivot: Illuminate\Database\Eloquent\Relations\Pivot {#3128
           user_id: 1,
           role_id: 1,
         },
       },
     ],
   }
>>>

Before some days, here, I learned this lesson.

Upvotes: 0

Lakhwinder Singh
Lakhwinder Singh

Reputation: 5582

You can try where() collection helper function. Which will provide the correct result. Below is the result for that:-

$externalClients = $mailgroup->externalClients;
if($externalClients->where('email', '[email protected]')->count() > 0) {
    echo "yes";
}

Here is the reference of collection helper function: where() docs.

For Laravel 5.0, you can refer this.

Try this and check. I think this will work.

Upvotes: 1

Related Questions