10

When I try the firstOrCreate() on a relationship of another model, it does not work:

Client::find($id)->users()->firstOrCreate(array('email' => $email));

This returns an error saying

Call to undefined method Illuminate\Database\Query\Builder::firstOrCreate()

Running this directly on the model User will work though.

The Alpha
  • 143,660
  • 29
  • 287
  • 307
Kousha
  • 32,871
  • 51
  • 172
  • 296
  • 2
    This won't work, you have to do it manually/directly using User model because `users()` should return a collection object when `get()` gets called and in this case it'll return a `Builfer` instance. – The Alpha Jun 01 '14 at 00:29
  • I tested this with my own models and this works - how had you defined your relation? Do you use any of the belongsTo, hasOne, hasMany relations or did you defined your own using the DB class or anything like this? Or is it possible that you haven't any Client with the given id? – Gummibeer Sep 14 '15 at 13:16
  • It's also documented http://laravel.com/docs/5.1/eloquent-relationships#inserting-related-models if you use the laravel relations than it should work. If you do and it doesn't work than we need a bit more code. – Gummibeer Sep 14 '15 at 13:20

4 Answers4

12

This won't work, you have to do it manually/directly using User model because users() should return a collection object

This is correct, the users() function does not return a (new, empty or created) User model, it returns a collection object.

It's also documented http://laravel.com/docs/5.1/eloquent-relationships#inserting-related-models if you use the laravel relations than it should work.

You are misinterpreting that document. The relationship object has a create() method and a save() method, however the relationship object is not a full model object. To get all of the functionality of a full User model object (such as firstOrCreate()) then you have to call them on the model object.

So, for example, this code should work:

$user = User::firstOrNew(array('email' => $email));
Client::find($id)->users()->save($user);

Note that it should be OK to save the $user object here directly from the Client model's relationship, even though it may already exist here, it should just update the client_id field on the $user object when you do so.

delatbabel
  • 3,601
  • 24
  • 29
2

You can use updateOrCreate:

$user = App\User::query()->firstWhere('email', 'radical@example.com');

$user->sandwiches()->updateOrCreate(['user_id' => $user->id], [
    'cabbage' => false,
    'bacon' => 9001,
]);

updateOrCreate has two parameters. The first one is the match condition(s). The second one is the upsert data. For example, if there is no row with user_id === $user->id, a record will be created with that and the fields from the second parameter.

agm1984
  • 15,500
  • 6
  • 89
  • 113
  • 1
    Actually, since `sandwiches` is already a relationship on the `User` model, it will already match the `user_id`; therefore the first parameter `['user_id' => $user->id]` can actually just be left as an empty array `[]` – Inigo Dec 04 '21 at 23:51
1

The firstOrCreate method will attempt to locate a database record using the given column / value pairs. If the model can not be found in the database

public function firstOrCreate() {
    $requestData = [
        'name' => 'Salma Klocko',
        'email' => 'maida39@frami.biz'
    ];
    $customer = Customer::firstOrCreate($requestData);
    echo "Insert customer detail Successfully with ID : " . $customer->id;
}
0

This should do:

Client::find($id)->first()->users()->firstOrCreate(array('email' => $email));
Julio Popócatl
  • 712
  • 8
  • 16