skip to Main Content

In my (Laravel) application receive a JSON which looks like:

{
  "name": "order 1",
  "customer": "cus123",
  "orderItems": [
    {
      "amount": 1,
      "name": "cola",
      "price": "2.10"
    },
    {
      "amount": 3,
      "name": "fanta",
      "price": "2.00"
    },
  ]
}

I have create 2 models in Laravel, one Order and one OrderItem. I want to parse the received JSON to one Order instance $order.
I can get this done so by doing this in my OrderController:

class OrderController extends Controller
{
  public function store(Request $request) {
    $order = new Order();
    $order->forceFill($request->toArray());
  }
}

It’s possible to access properties now like $order->name and $order->customer in the store function of the controller. When i access the $order->orderItems i receive an array with "orderItemsbut as array, not as instance ofOrderItem`.

I want that $order->orderItems returns an array of OrderItem instances. I tried the following in Order but this does not work as 'orderItems' is not a OrderItem::class but is an array with multiple "OrderItems".

  protected $casts = [
    'orderItems' => OrderItem::class,
  ];

How can i achieve that $order->orderItems returns an array of OrderItem instances?
Thanks for any help in advance!

2

Answers


  1. Try to add the following to your controller

    • validation
    • manual storing your Order
    • manual storing each of your order items

    .

    class OrderController extends Controller
    {
      public function store(Request $request) 
      {
        $your_rules = [
           'name' => 'required|string',
           'customer' => 'required|string', // related to customer id ?
           'orderItems' => 'array',
           'orderItems.*.name' => 'string',
           'orderItems.*.amount' => 'integer|gte:1',
           'orderItems.*.price' => 'numeric|between:0,99.99',
        ];
    
        $validated = $request->validate($your_rules);
        $order = Order::create([
           'name' => $validated['name'],
           'customer' => $validated['customer'], // is this customer id or name ?
        ]);
    
        // I assume you already declare relationship to OrderItem inside your Order model
        foreach ($validated['orderItems'] as $orderItem) {
            // this array only is optional
            $orderItem = Arr::only($orderItem, ['name', 'amount', 'price');
    
            $order->orderItems()->save($orderItem);
        }
    
        // reload saved order items
        $order->load('orderItems');
    
        dd($order);
      }
    }
    

    You can also create multiple children in single command.

    $order->orderItems()->saveMany([
        new OrderItem(['name' => '...', ... ]),
        new OrderItem(['name' => '...', ... ]),
    ]);
    

    Read here for more info https://laravel.com/docs/9.x/eloquent-relationships#the-save-method

    You can move this into your model as extra custom method.
    For example:

    public function saveOrderItems(array $orderItems): void
    {
       $this->orderItems()->saveMany($orderItems);
    }
    

    And you call it as $order->saveOrderItems($orderItems);

    P.S.

    Dont forget to declare relationship in Order model.

    public function orderItems()
    {
        return $this->hasMany(OrderItem::class);
    }
    
    Login or Signup to reply.
  2. I think you are confuse with the whole Model relationship. Checkout the documentation here, you need to define proper relationship and foreign key between your Order and OrderItem model.

    Then your model should be like this;

    //Order.php
    class Order extends Model {
    
        protected $fillable = [
            'name',
            'customer',
        ];
    
        public function items() {
            return $this->hasMany(OrderItem::class);
        }
        
    }
    
    //OrderItem.php
    class OrderItem extends Model {
    
        protected $fillable = [
            'amount',
            'name',
            'price'
        ];
    
        public function order() {
            return $this->belongsTo(Order::class);
        }
        
    }
    

    Then your store method

    public function store( Request $request ) {
    
        $request->validate([
            'name' => 'required',
            'customer' => 'required|exists:customers_table,id',
            'orderItems' => 'required|array'
        ]);
    
        $order = Order::create( $request->except('orderItems') );
    
        $items = $order->items()->createMany( $request->input('orderItems') );
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search