简体   繁体   中英

Laravel save one to many relationship

I have the following relationships set up in Laravel:

OrderStatus Model
  - hasMany('Order')

 Order Model
  - 'belongsTo('OrderStatus');

The database is set up with an orders table and an order_statuses table. The orders table has a field for order_status_id .

When I save an Order, I manually set the order_status_id by fetching the appropriate Order Status model, like this:

$status = OrderStatus::where(['name'=>'sample_status'])->firstOrFail();
$order->order_status_id = $status->id;
$order->save();

I'm wondering if there is a built in function to do this rather than setting the order_status_id manually. I've read about "Attaching a related model", and "Associating Models" in the Laravel docs, but I can't figure out if these fit my use case. I think the issue I'm having is that I'm working directly with the child model (the order), and trying to set it's parent. Is there a function for this?

Sure you can do this:

$status = OrderStatus::where(['name'=>'sample_status'])->firstOrFail();
$order = new Order;
$order->status()->associate($status);
$order->save();

( status() is the belongsTo relation. You might need to adjust that name)

The correct way, to save a relationship for a new related model is as follows:

$status = OrderStatus::where(['name'=>'sample_status'])->firstOrFail();
$order = new Order;
$status->order()->save($order);

Documentation link : http://laravel.com/docs/4.2/eloquent#inserting-related-models

You can go with a custom solution.

I am explaining an example, just coded and very much similar to your question, hope it will help. I have a Question Model and AnswerOption Model as below.

Question Model

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Question extends Model
{
    protected $table = 'questions';
    protected $fillable =  [
        'title',
        'created_at',
        'updated_at'            
    ];


    /**
     * Get the answer options for the question.
     */
    public function answerOptions()
    {
        return $this->hasMany('App\Models\AnswerOption');
    }


    /**
     * @param array $answerOptions
     */
    public function syncAnswerOptions(array $answerOptions)
    {
        $children = $this->answerOptions;
        $answerOptions = collect($answerOptions);        
        $deleted_ids = $children->filter(
            function ($child) use ($answerOptions) {
                return empty(
                    $answerOptions->where('id', $child->id)->first()
                );
            }
        )->map(function ($child) {
                $id = $child->id;
                $child->delete();                
                return $id;
            }
        );        
        $attachments = $answerOptions->filter(
            function ($answerOption) {
                 // Old entry (you can add your custom code here)
                return empty($answerOption['id']);
            }
        )->map(function ($answerOption) use ($deleted_ids) {
                // New entry (you can add your custom code here)           
                $answerOption['id'] = $deleted_ids->pop();                
                return new AnswerOption($answerOption);
        });        
        $this->answerOptions()->saveMany($attachments);
    }   
}

AnswerOption Model

namespace App\Models;
use Illuminate\Database\Eloquent\Model;

class AnswerOption extends Model
{
    protected $table = 'answer_options';

    protected $fillable =  [
        'question_id',
        'title',
        'ord',
        'created_at',
        'updated_at'            
    ];      

    /**
     * Get the question that owns the answer.
     */
    public function question()
    {
        return $this->belongsTo('App\Models\Question');
    }   
}

Here you can see a single question hasMany answer options, you can see I have used BelongsTo , hasMany relationsip in models.

Now in QuestionController during Question save and update, you can also save the answer options.

For this I have written syncAnswerOptions method in Question Model .

You just need to pass the array of options with id, if id is present already in the database then it will update, if id is blank it will add a new record, If Id was there but not in your new array, then that record will get deleted.

/**
 * If you are attaching AnswerOption(s) for the first time, then pass
 * in just the array of attributes:
 * [
 *     [
 *         // answer option attributes...
 *     ],
 *     [
 *         // answer option attributes...
 *     ],
 * ]
 *//**
 * If you are attaching new AnswerOption(s) along with existing
 * options, then you need to pass the `id` attribute as well.
 * [
 *     [
 *         'id' => 24
 *     ],
 *     [
 *         // new answer option attributes...
 *     ],
 * ]
 */

In Question controller's store and update method call this method just after question add and update call.

$question->syncAnswerOptions($data['answerOptions']);

$data['answerOptions'] is Array of answer options just like described in the comments.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM