В моем приложении (Laravel) вы получите JSON, который выглядит так:
{
"name": "order 1",
"customer": "cus123",
"orderItems": [
{
"amount": 1,
"name": "cola",
"price": "2.10"
},
{
"amount": 3,
"name": "fanta",
"price": "2.00"
},
]
}
Я создал 2 модели в Laravel, одну Order
и одну OrderItem
. Я хочу разобрать полученный JSON на один Order
экземпляр $order
.
Я могу сделать это, выполнив это в моем OrderController
:
class OrderController extends Controller
{
public function store(Request $request) {
$order = new Order();
$order->forceFill($request->toArray());
}
}
Теперь можно получить доступ к свойствам, таким как $order->name
и $order->customer
, в функции store
контроллера. Когда я обращаюсь к $order->orderItems
, я получаю массив с «orderItemsbut as array, not as instance of
OrderItem`.
Я хочу, чтобы $order->orderItems
возвращал массив экземпляров OrderItem
. Я попробовал следующее в Order
, но это не работает, поскольку 'orderItems'
не является OrderItem::class
, а представляет собой массив с несколькими «OrderItems».
protected $casts = [
'orderItems' => OrderItem::class,
];
Как мне добиться, чтобы $order->orderItems
возвращал массив экземпляров OrderItem
?
Спасибо за любую помощь заранее!
Я не уверен, чего вы пытаетесь достичь, но я вижу 2 проблемы. 1. Вы не можете преобразовать несуществующий атрибут в свою модель, 2. Приведение - это преобразование атрибута модели в общий тип данных, вы не можете передавать туда случайные вещи laravel.com/docs/9.x/eloquent-mutators #приведение атрибутов
Попробуйте добавить следующее в свой контроллер
.
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);
}
}
Вы также можете создать несколько дочерних элементов одной командой.
$order->orderItems()->saveMany([
new OrderItem(['name' => '...', ... ]),
new OrderItem(['name' => '...', ... ]),
]);
Подробнее читайте здесь https://laravel.com/docs/9.x/eloquent-relationships#the-save-method
Вы можете переместить это в свою модель как дополнительный пользовательский метод. Например:
public function saveOrderItems(array $orderItems): void
{
$this->orderItems()->saveMany($orderItems);
}
И вы называете это как $order->saveOrderItems($orderItems);
P.S.
Не забудьте объявить отношения в модели Order.
public function orderItems()
{
return $this->hasMany(OrderItem::class);
}
Я знаю о проверке и т. д., Но это не имело отношения к вопросу, все равно спасибо, я реализую это так! Я тоже пользуюсь $fillable =
;-). Я мог бы сам прийти к твоему решению, глупый. Но интересно, нет ли способа сделать это с помощью одной команды? Я имею в виду, что синтаксический анализ JSON для объектов - это такая обычная вещь, что я не могу себе представить, что нет более простого способа сделать это.
вы можете добавить всю свою логику в класс обслуживания и вызвать ее из своего контроллера, это будет одна команда, правильно ^_^. ... в любом случае, если вы делаете только создание порядка, это будет одна команда создания, проблема в отношениях ... для одной дополнительной команды, которую вы можете использовать ->saveMany
.. я обновлю свой ответ с помощью этого метода
я забыл добавить проверку для orderItems в виде массива и его содержимого, вы можете установить «количество», «имя» и «цену» по мере необходимости
Я думаю, вы запутались во всех отношениях модели. Ознакомьтесь с документацией здесь, вам нужно определить правильное отношение и внешний ключ между вашими моделями Order и OrderItem.
Тогда ваша модель должна быть такой;
//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);
}
}
Тогда ваш метод магазина
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') );
}
не забывайте проверять все запросы, поступающие от вашего пользователя, никогда не доверяйте своему пользователю, включая себя, когда речь идет об изменении вашей базы данных ^_^