Compizfox Compizfox - 2 months ago 5
PHP Question

Insert model unless it exists and attach it

I'm a Laravel noob rewriting some old code to Laravel.

I have a system for managing purchases and games and I'm writing the

store
method of the PurchaseController. The form for creating new purchases contains data about the purchase and an array with data about the games.

There is a many-to-many relationship between games and purchases: a purchase can contain many games and a game may be linked to multiple purchases.

The thing is that the game may already exist in the database. I want to do the following:


  1. Insert the new purchase into the database (this part I got sorted out already ;))

  2. Check if the POSTed name of the game already exists in the database.

  3. If it exists, attach it to the newly inserted purchase. If it doesn't exist, insert it and attach it to the newly inserted purchase.



I don't want to update the game if it already exists in the database, just to attach it to the purchase.

I've looked into
firstOrCreate
but that doesn't do what I want. It checks on all the arguments you feed it, you can't just make it check only the name (this issue basically).

The undocumented method
updateOrCreate
does accept two arrays (one for attributes to check on, another for values to insert) but it updates the record if it exists, which is not what I want.

So, is there a nice, proper way to do this with Eloquent or do I simply need to manually write some code that checks if the game exists in the database and inserts the game unless that's the case?

EDIT:



It seems that this is possible with
firstOrCreate
after all in Laravel 5.3: https://github.com/laravel/framework/pull/13236

Answer

I was probably overthinking this too much. The following code does what I want:

// Insert games (unless they exist) and attach to new purchase
foreach($request->games as $game) {
    $gameModel = Game::firstOrNew(['name' => $game['name']]);
    if(!$gameModel->exists) {
        $gameModel->status_id = $game['status'];
        $gameModel->note = $game['note'];
        $gameModel->save();
    }
    $gameModel->purchases()->attach($purchase->id);
}

I just thought maybe there was a nicer/shorter way to do this.

Comments