mpen
mpen

Reputation: 282955

Laravel create or update without two queries

I'm trying to use one form for both creates and updates. Both actions save through this method:

public function store() {
    $data = Input::all();
    $data['company_id'] = Auth::user()->company_id;
    $validator = Validator::make($data, Feature::$rules);

    if($validator->fails()) {
        return Redirect::back()->withErrors($validator)->withInput();
    }

    Feature::firstOrNew(['id' => Input::get('id')])->update($data);

    return Redirect::route('features.index');
}

How can I rewrite this line:

Feature::firstOrNew(['id' => Input::get('id')])->update($data);

So that it doesn't fetch the object from the database first? There's no need for that; I'm not doing anything with it. It should either issue a INSERT if Input::get('id') is set, or an UPDATE if it's not.

Upvotes: 13

Views: 39346

Answers (6)

Vladislav Rastrusny
Vladislav Rastrusny

Reputation: 29985

If you have all fields unguarded in your model, I think you can do it like this:

$feature = new Feature($data);
$feature->exists = Input::has('id');
$feature->save();

If you have some guarded fields, then you can unguard it first:

$feature = new Feature();
$feature->unguard();
$feature->fill($data);
$feature->exists = Input::has('id');
$feature->reguard();
$feature->save();

The reguard() call is not actually needed if you don't do anything else with the model.

Upvotes: 10

Majbah Habib
Majbah Habib

Reputation: 8548

Find or New based on primary key id

$data = Input::all();
$user = User::findOrNew($id);  // if exist then update else insert
$user->name= $data['user_name'];
$user->save();

First or New based on non-primary key single filed

$user = User::firstOrNew(['field' => $data['value'] ]);
$user->name= $data['user_name'];
$user->save();

First or New based on non-primary key multiple filed

$user = User::firstOrNew([
                     'field1'=>$data['value1'],
                     'field2'=>$data['value2']
                     ]);
$user->name= $data['user_name'];
$user->save();

Upvotes: 5

Keith Holliday
Keith Holliday

Reputation: 1732

This is what I use:

Model::updateOrCreate(
   ['primary_key' => 8],
   ['field' => 'value', 'another_field' => 'another value']
);

The second parameter is an array of the data for the model you want to save.

Upvotes: 33

yajra
yajra

Reputation: 221

I used to have this problem and created an accepted pull request on Laravel which you can use. Try the code below. The method you will basically need is the findOrNew.

public function store($id=0)
{
    $user = User::findOrNew($id);
    $data = Input::all();

    if (!$user->validate($data)) {
        return Redirect::back()->withInput()->withErrors($user->errors);
    }

    $user->fill($data);
    $user->save();
    return Redirect::to('/')->with('message','Record successfully saved!');
}

My model uses self validation but you can create your own validation like the one you have now.

Upvotes: 6

The Alpha
The Alpha

Reputation: 146201

You may try this:

$data = Input::except('_token');
$newOrUpdate = Input::has('id') ? true : false;
$isSaved = with(new Feature)->newInstance($data, $newOrUpdate)->save();

If $data contains an id/primary key it'll be updated otherwise insert will be performed. In other words, for updating, you need to pass the id/primary key in the $data/attributes with other attributes and second argument in the newInstance method must be true.

If you pass false/default to newInstance method then it'll perform an insert but $data can't contain an id/primary key. You got the idea and these three lines of code should work. $isSaved will be a Boolean value, true/false.

You may write the code using one line:

with(new Feature)->newInstance($data, array_key_exists('id', $data))->save();

If $data contains id/primary key then it'll be updated, otherwise an insert will be performed.

Upvotes: 2

peaceman
peaceman

Reputation: 2609

If you are following the resource router methodology of laravel, you should use a separate method named update to update your model, so the separation can be done by the framework. With this it is still possible to reuse your form.

If you really want to avoid a new method to update the model, you could rewrite it as follows:

public function store() {
    $model = Input::has('id')
        ? ModelClass::findOrFail(Input::get('id'))
        : new ModelClass;

    $inputData = Input::all();
    $validator = Validator::make($inputData, ModelClass::$rules);

    if ($validator->fails()) {
        return Redirect::back()
            ->withErrors($validator)
            ->withInput();
    }

    $model->fill($inputData);
    $model->save();

    return Redirect::route('modelclass.index');
}

Upvotes: 2

Related Questions