插入一对一关系片段

时间:2016-12-16 12:48:11

标签: php laravel blade laravel-5.3 laravel-blade

我有两个一对一关系的表:

参观:

id|title|content

featured_image:

id|tour_id|name|path

我的模型FeaturedImage.php

class FeaturedImage extends Model
{
public function tour()
 {
    return $this->hasOne('App\Tour');
 }
}

Tour.php

class Tour extends Model
{
  public function featuredimage()
  {
    return $this->belongsTo('App\FeaturedImage');
  }
}

我想在创建游览时将tour_id保存在featured_image表格中。我使用相同的表单填写tours表并上传featured_image

这是我的商店方法看起来像:

    public function store(Request $request)
{

    //validate the date
    $this->validate($request, [
            'title'    => 'required|max:255',
            'content'  => 'required'
        ]);
    //store the date
    $tour = new Tour;

    $tour->title   = $request->title;
    $tour->content = $request->trip_code;

    $tour->save();

    $featured_image= new FeaturedImage;
    // save featured_image
    if($request->hasFile('featured_image')){
        $image = $request->file('featured_image');
        $filename = $image->getClientOriginalName();
        $location = public_path('images/featured_image/'.$filename);
        Image::make($image)->resize(800, 600)->save($location);

     $featured_image->path= $location;
     $featured_image->tour()->associate($tour);
     $featured_image->save();
    }

    //redirect to 
    Session::flash('success','Tour is successfully created !');
    return redirect()->route('tours.show',$tour->id);
}

我成功将数据保存到tours表中,但无法保存在featured_image表中。我收到了这个错误:

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

如果有人能帮助我,我会感激不尽。

2 个答案:

答案 0 :(得分:2)

您可以使用Mass Assignment在DB中创建条目:

$this->validate(request()->all(), [
    'title'    => 'required|max:255',
    'content'  => 'required'
]);

$tour_inputs = array_only(
    $tour_inputs.
    [
        'title',
        'content',
    ]
);

$tour = Tour::create($tour_inputs);

if($request->hasFile('featured_image')) {
    $image = $request->file('featured_image');
    $filename = $image->getClientOriginalName();
    $location = public_path('images/featured_image/'.$filename);
    Image::make($image)->resize(800, 600)->save($location);

    $featuredImage = $tour->featuredImage()->save(new FeaturedImage([
        'name' => $filename,
        'path' => $location,
    ]));
}
  

请记住来定义模型中的$fillables,模型应该如下所示,

     

检查你的关系,你在模特中做过的,据我说他们不正确:

class Tour extends Model
{
    protected $fillables = [
        'title',
        'content',
    ];

    public function featuredImage()
    {
      return $this->hasOne('App\FeaturedImage');
    }
}


class FeaturedImage extends Model
{
    protected $fillables = [
        'name',
        'path',
        'tour_id',
    ];

    public function tour()
    {
      return $this->belongsTo('App\Tour');
    }
}

希望这有帮助!

答案 1 :(得分:0)

从您的代码中,您定义的关系的顺序相反。

我的意思是逻辑上,Tour有一个FeaturedImageFeaturedImage属于Tour

class Tour extends Model
{
    //Mass Assignable fields for the model.
    $fillable = ['title', 'content'];

    public function featuredimage()
    {
        return $this->hasOne('App\FeaturedImage');
    }
}  

class FeaturedImage extends Model
{

    //Mass Assignable fields for the model
    $fillable = ['tour_id', 'name', 'path'];

     public function tour()
     {
        return $this->belongsTo('App\Tour');
     }
} 

然后在您的控制器中

public function store(Request $request)
{

    //validate the data
    $this->validate($request, [
        'title'    => 'required|max:255',
        'content'  => 'required'
    ]);
    //store the data

    $tour = Tour::firstOrCreate([  //protection against duplicate entry
        'title' => $request->get('title'),
        'content' => $request->get('trip_code')
    ]);


    if($tour)  //if the Tour exists then continue
    {        
        // save featured_image
        if($request->hasFile('featured_image')){
            $image = $request->file('featured_image');
            $filename = $image->getClientOriginalName();
            $location = public_path('images/featured_image/'.$filename);
            Image::make($image)->resize(800, 600)->save($location);

           $featured_image = $tour->featuredimage()->create([
                'path' => $location,
                'name' => $filename //if you have this field on your FeaturedImage           
        }
        //you could also have an else block to redirect back if the input doesn't have a file


        //redirect to 
        Session::flash('success','Tour is successfully created !');
        return redirect()->route('tours.show',$tour->id);
    }
    else
    {
        //if there occurs any error display the error message and redirect back - probably with validation errors or exception errors
        Session::flash('error','Error message');
        return redirect()->back()->withInput()->withErrors();
    }

}

并且不要忘记将质量可分配字段添加到模型上的$fillable数组中。

更新

对于单个表单提交包含多个表中的数据库事务的情况,您应该使用try{}catch{}来确保所有相关事务运行时没有任何问题或两个事务都没有通过 - 以避免数据差异。

您可以将控制器代码重写为

public function store(Request $request)
{

    //validate the data
    $this->validate($request, [
        'title'    => 'required|max:255',
        'content'  => 'required'
    ]);
    //store the data

    //use the DB::beginTransaction() to manually control the transaction
    //You would ideally want to persist the data to the database only if the input provided by the user
    //has valid inputs for Tour as well as FeaturedImage, in case if any one invalid input you do not
    //want to persist the data
    DB::beginTransaction();

    try
    {
        //firstOrCreate gives protection against duplicate entry for tour with same title and content
        $tour = Tour::firstOrCreate([  
            'title' => $request->get('title'),
            'content' => $request->get('trip_code')
        ]);

        //proceed further only if $tour exists
        if($tour)  
        {        
            // get featured_image
            if($request->hasFile('featured_image')){
                $image = $request->file('featured_image');
                $filename = $image->getClientOriginalName();
                $location = public_path('images/featured_image/'.$filename);
                Image::make($image)->resize(800, 600)->save($location);

            //save the featured_image   
               $featured_image = $tour->featuredimage()->create([
                    'path' => $location,
                    'name' => $filename //if you have this field on your FeaturedImage           
            }

       }
    }
    catch(\ValidationException $e)
    {
        //In case of validation error, rollback the database transactions to avoid data discrepancy.
        DB::rollBack();

        $errors = $e->getMessage();
        Session::flash('error', 'Whoops.. Please check the provided inputs');
        return redirect()->back()->withInput()->withErrors['errors', $errors];
    }
    catch(\Exception $e)
    {
        //In case of any other error, rollback the database transactions to avoid data discrepancy.
        DB::rollBack();

        $errors = $e->getMessage();
        Session::flash('error', 'Whoops.. Something went wrong. Please try again');
        return redirect()->back()->withInput()->withErrors['errors', $errors];
    }

    //If both the transactions to the database i.e. saving the Tour as well as FeaturedImage ran without problem
    //Commit to the database
    DB::commit();

    //redirect to 
    Session::flash('success','Tour is successfully created !');
    return redirect()->route('tours.show',$tour->id);  

}

希望这有帮助。