Glen Robson
Glen Robson

Reputation: 938

Laravel parse request into Eloquent model with relations

Im developing a Laravel API that will host and manage the data for a mobile application. The application that I am writing will make AJAX requests and send over JSON data to the Laravel controller.

This works fine for a basic model however I am unable to get this working for nested models. Ill explain:

So I have the following model structure:

Shelf ---- Has Many ----> Boxes ---- Has Many ----> Products

Shelf:

class Shelf extends Model
{
    protected $fillable = ['name', 'location'];

    public function boxes()
    {
        return $this->hasMany('App\Box');
    }
}

Box:

class Box extends Model
{
    protected $fillable = ['name', 'size', 'label'];

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

    public function products()
    {
        return $this->hasMany('App\Product');
    }
}

Product:

class Product extends Model
{
    protected $fillable = ['name', 'price', 'quantity'];

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

All my models have validation checking before anything is saved.

I send the following request to my Laravel controller:

{
  "name":"Shelf 1",
  "location":"LOC1"
  "boxes":[{
    "name":"box 1",
    "size": 130,
    "label": "B1",
    "products":[
      {"name":"Prod1","price":23.00,"quantity":5},
      {"name":"Prod2","price":13.00,"quantity":2}
    ]
  }, {
    "name":"box 2",
    "size": 130,
    "label": "B2",
    "products":[
      {"name":"Prod3","price":3.00,"quantity":15},
      {"name":"Prod4","price":7.00,"quantity":8}
    ]
  }, {
    "name":"box 3",
    "size": 160,
    "label": "B3",
    "products":[
      {"name":"Prod5","price":103.00,"quantity":9},
      {"name":"Prod6","price":83.00,"quantity":1}
    ]
  }]
}

When I receive the above data in my Laravel controller i use:

$shelf = new Shelf;
$shelf->fill($request->all());
$shelf->save();

To get all of the data however this will only save the Shelf and not any of the relationships. Is there a common way (or library) I can use to parse the JSON within the Laravel controller?

Upvotes: 3

Views: 3698

Answers (1)

Styphon
Styphon

Reputation: 10447

As far as I'm aware Eloquent doesn't offer anything like that. You would need to save each one individually. May I suggest something like this:

$shelf = Shelf::create($request->only(['name', 'location']));
foreach ( $request->input('boxes') as $box )
{
    $box = new Box($box);
    $shelf->boxes()->save($box);
    $pTemp = [];
    foreach ( $box['products'] as $product )
    {
        $pTemp[] = new Product($product);
    }
    $box->products()->saveMany($pTemp);
}

Update

To minimise the number of queries run we can loop through all the boxes once, create them then loop through them again to create all the products. You're still having to run one query per box to create the products, but as far as I can see there is no way around that.

$shelf = Shelf::create($request->only(['name', 'location']));
$bTemp = [];
foreach ( $request->input('boxes') as $i => $box )
{
    $bTemp[$i] = new Box($box);
}
$shelf->boxes()->saveMany($bTemp);
foreach ( $request->input('boxes') as $i => $box )
{
    $pTemp = [];
    foreach ( $box['products'] as $product )
    {
        $pTemp[] = new Product($product);
    }
    $bTemp[$i]->products()->saveMany($pTemp);
}

Upvotes: 5

Related Questions