for example i have Session::instance()->get('orders') which is an array of some arrays:
$first = array('id' = 1, 'name' => 'first', 'price' => 100);
$second = array('id' => 2, 'name' => 'second', 'price' => 200);
$_SESSION['orders'] = array($first, $second);
but if i use this
Session::instance()->set('orders', array(array('id' => 3, 'name' => 'third', 'price' => 300)));
this will erase first orders (id 1, id 2).
so how can i ADD but not ERASE data arrays to session array named 'orders'? array_push or something else?
Edit, didn't see your comment, it's perfect.
Self explanatory.
$session = Session::instance();
// Find existing data
$data = $session->get('orders');
// Add new array
$data[] = array('id' => 3, 'name' => 'new data', 'price' => 300);
// Resave it
$session->set('orders', $data);
As for me, I think that best way:
public function before() {
...
$this->variable = Session::instance()->get('key', array());
...
}
some code...
public function after() {
...
Session::instance()->set('key', $this->variable, Date::MINUTE);
...
}
Related
I am adding order to database. It works like this: When ordering is clicked, the order is created in the Order table, at the same time the product items are also added to the OrderItem table, via the order_id foreign key. But I don't know how to get the order_id, because it is added at the same time, and the Order id is increments.
public function save(array $data, int $id = null){
$idCurrent = Auth::id();
$orderItems = $data['orderItems'];
//add to Order
Order::updateOrCreate(
[
'id' => $id
],
[
'user_id' => $idCurrent,
'shipping_fee' => $data['shipping_fee'],
'total' => $data['total'],
'payment' => $data['payment'],
'status_id' => 1,
]
);
//add to OrderItem
foreach($orderItems as $item){
OrderItem::Create([
'order_id' => 222, //=> ?????????????
'product_id' => $item -> product_id,
'quantity' => $item->quantity,
]);
}
return true;
}
$order = Order::updateOrCreate(
[
'id' => $id
],
[
'user_id' => $idCurrent,
'shipping_fee' => $data['shipping_fee'],
'total' => $data['total'],
'payment' => $data['payment'],
'status_id' => 1,
]
);
//add to OrderItem
foreach($orderItems as $item){
OrderItem::Create([
'order_id' =>$order->id
'product_id' => $item -> product_id,
'quantity' => $item->quantity,
]);
}
return true;
Avoid multiple call to databases.
When you create order with
$order = Order::updateOrCreate(
[
'id' => $id
],
[
'user_id' => $idCurrent,
'shipping_fee' => $data['shipping_fee'],
'total' => $data['total'],
'payment' => $data['payment'],
'status_id' => 1,
]
);
next you should is to send just one request to database with
// create batch array
$insertOrderItems = [];
foreach($orderItems as $item){
$insertOrderItems[] = [
'product_id' => $item->product_id,
'quantity' => $item->quantity,
];
}
// insert all at once in batch mode making just one call to database
$order->orderItems()->create($insertOrderItems);
Presuming you have sorted relations in Order and OrderItem models.
I'm using the repeatable, from Laravel-Backpack I can save the data into the two tables. However, I can not load these data when trying to edit a sale. It does not load the data in the form that were saved through the Repeatable.
Example:
When viewing the example of the demo through the link.
https://demo.backpackforelaravel.com/admin/dummy/create
It converts the data from the fields from the REPEATABLE to JSON, and saves in the database in a field called Extra.
Saved format in the extra field in the database:
{
"simple": "[{\"text\":\"TesteTesteTesteTeste\",\"email\":\"admin#admin\",\"textarea\":\"teste\",\"number\":\"1\",\"float\":\"1\",\"number_with_prefix\":\"1\",\"number_with_suffix\":\"0\",\"text_with_both_prefix_and_suffix\":\"1\",\"password\":\"123\",\"radio\":\"1\",\"checkbox\":\"1\",\"hidden\":\"6318\"}]",
}
In my case I am saving the data in different tables without using JSON.
//My Model
class Sales extends Model
protected $casts = [
'id' => 'integer',
'user_id' => 'integer',
'date_purchase' => 'date',
'client_id' => 'integer',
];
public function getProductsAttribute()
{
$objects = ItensProducts::where('product_id', $this->id)->get();
$array = [];
if (!empty($objects)) {
foreach ($objects as $itens) {
$obj = new stdClass();
$obj->product_id = "" . $itens->product_id;
$obj->quantity = "" . $itens->quantity;
$categoryProduct = CategoryProduct::where('product_id', $itens->product_id)->get();
$arrayCategoryProduct = [];
foreach ($categoryProduct as $stItens) {
$arrayCategoryProduct[] = $stItens->name;
}
$obj->categories_product = $arrayCategoryProduct;
$array[] = $obj;
}
}
//Converts JSON to the example of the extra database field
$array_result = json_encode(\json_encode($array), JSON_HEX_QUOT | JSON_HEX_APOS);
$array_result = str_replace(['\u0022', '\u0027'], ["\\\"", "\\'"], $array_result);
return $array_result;
}
My form:
//SalesCruController.php
protected function setupCreateOperation()
{
CRUD::addField([ // repeatable
'name' => 'products',
'label' => 'Produtos(s)',
'type' => 'repeatable',
'fields' => [
[
'name' => 'product_id', 'type' => 'select2', 'label' => 'Produtos',
'attribute' => "name",
'model' => "App\Models\Product",
'entity' => 'products',
'placeholder' => "Selecione o Produto",
'wrapper' => [
'class' => 'form-group col-md-6'
],
],
[
'name' => 'category_id', 'type' => 'select2', 'label' => "Categoria",
'attribute' => "name",
'model' => "App\Models\CategoryProduct",
'entity' => 'categories',
'placeholder' => "Selecione uma Categoria",
],
[
'name' => 'quantity',
'label' => "Quantidade",
'type' => 'text',
],
],
// optional
'new_item_label' => 'Adicionar',
'init_rows' => 1,
'min_rows' => 1,
'max_rows' => 3,
],);
}
}
Method Store
public function store()
{
$item = $this->crud->create($this->crud->getRequest()->except(['save_action', '_token', '_method']));
$products = json_decode($this->crud->getRequest()->input('products'));
$this->validateRepeatableFields($categoryProduct);
if (is_array($products)) {
foreach ($products as $itens) {
$obj = new ItensProduct();
$obj->sale_id = $item->getKey();
$obj->product_id = $itens->product_id;
$obj->quantity = $itens->quantity;
$obj->save();
$categoryProduct = json_decode($itens->categories);
foreach ($categoryProduct as $cItens) {
$objCat = new CategoryProduct();
$objCat->product_id = $obj->getKey();
$objCat->name = $cItens;
$objCat->save();
}
}
} else {
\Alert::add('warning', '<b>Preencha os campos de pelo menos um produto.</b>')->flash();
return redirect('admin/sales/create');
}
\Alert::success(trans('backpack::crud.insert_success'))->flash();
return redirect('admin/sales');
}
function validateRepeatableFields($categoryProduct)
{
foreach ($categoryProduct as $group) {
Validator::make((array)$group, [
'sale_id' => 'required',
'product_id' => 'required',
'quantity' => 'required',
], [
"product_id.required" => "O campo Produto é obrigatório",
"quantity.required" => "O campo quantidade é obrigatório",
])->validate();
}
}
I was able to solve the problem of returning the fields to the Repeatable form.
I want to share the solution if someone needs it. The error occurred when I tried to put the data from the category_id field which is a vector in a json it has to return like this, as shown below.
{"product_id": "4", quantity: "3", "category_id": "[10, 4, 8, 8]"}
The vector would have to be inside a string, I was passing the fields but was not converting the whole vector to a string in the format that the repeatable expected. Then I conceded the IDs in a string and in the end I conceded with the cohets and used the substring to remove the last virgulation, as the code below shows.
In this way I was able to return the fields with the appropriate information that were saved in the database in the Repeatable form.
public function getProductsAttribute()
{
$objects = ItensProducts::where('product_id', $this->id)->get();
$response = [];
if (!empty($objects)) {
foreach ($objects as $itens) {
$categoryProduct = CategoryProduct::where('product_id', $itens->product_id)->get();
$itensCatProd = '';
foreach ($categoryProduct as $itensCatProd) {
$itensCatProd .= $itensCatProd->id . ',';
};
$response[] = [
'product_id' => $itens->product_id,
'category_id' => '[' . substr($itensCatProd, 0, -1) . ']',
'quantity' => $itens->quantity,
];
return json_encode($response);
}
}
}
I'm using the isDirty() method in my controller to check if any field is changed. Then I am saving the old data of a field and the new data in a table. The code is working fine; however, how can I optimize this code?
By using the below code, I will have to write each field name again and again. If request->all() has 20 fields, but I want to check six fields if they are modified, how can I pass only 6 fields in the below code, without repeating?
Controller
if ($teacher->isDirty('field1')) {
$new_data = $teacher->field1;
$old_data = $teacher->getOriginal('field1');
DB::table('teacher_logs')->insert(
[
'user_id' => $user->id,
'teacher_id' => $teacher->id,
'old_value' => $old_data,
'new_value' => $new_data,
'column_changed' => "First Name",
]);
}
You can set a list of what fields you want to be checking for then you can loop through the dirty fields and build your insert records.
use Illuminate\Support\Arr;
...
$fields = [
'field1' => 'First Name',
'field2' => '...',
...
];
$dirtied = Arr::only($teacher->getDirty(), array_keys($fields));
$inserts = [];
foreach ($dirtied as $key => $value) {
$inserts[] = [
'user_id' => $user->id,
'teacher_id' => $teacher->id,
'old_value' => $teacher->getOriginal($key),
'new_value' => $value,
'column_changed' => $fields[$key];
];
}
DB::table(...)->insert($inserts);
i tried following code after getting idea by lagbox in comments, and i have found solution to my problem.
$dirty = $teacher->getDirty('field1','field2','field3');
foreach ($dirty as $field => $newdata)
{
$olddata = $teacher->getOriginal($field);
if ($olddata != $newdata)
{
DB::table('teacher_logs')->insert(
['user_id' => $user->id,
'teacher_id' => $teacher->id,
'old_value' => $olddata,
'new_value' => $newdata,
'column_changed' => "changed",
]);
}
}
I have an array storing 3 merged collections:
public function answer() {
$interview = Interview::find(1);
$videoQuestions = $interview->VideoQuestions()->get();
foreach ($videoQuestions as $vq) {
$vq->type = 'video';
}
$textQuestions = $interview->TextQuestions()->get();
foreach ($textQuestions as $tq) {
$tq->type = 'text';
}
$uploadQuestions = $interview->UploadQuestions()->get();
foreach ($uploadQuestions as $uq) {
$uq->type = 'upload';
}
$questions = collect($videoQuestions);
$questions = $questions->merge($textQuestions);
$questions = $questions->merge($uploadQuestions);
$questions->sortBy('order_position');
dd($questions);
}
The ->sortBy is not working as I assume it doesn't work on an array of collections.
This is what I have:
But I really just want it to be a merged collection not an array inside the collection.
Each VideoQuestion or TextQuestion has an order_position field that I would like to sort by.
Any help is appreciated!
First thing collection is a class containing an array of elements with special methods to filter sort, docs:
The Illuminate\Support\Collection class provides a fluent, convenient
wrapper for working with arrays of data.
The sortBy method returns a sorted collection (it does not apply to the item it has):
$collection = collect([
['name' => 'Desk', 'price' => 200],
['name' => 'Chair', 'price' => 100],
['name' => 'Bookcase', 'price' => 150],
]);
$sorted = $collection->sortBy('price');
$sorted->values()->all();
/*
[
['name' => 'Chair', 'price' => 100],
['name' => 'Bookcase', 'price' => 150],
['name' => 'Desk', 'price' => 200],
]
*/
So you should have something like:
$questions = $questions->sortBy('order_position');
dd($questions);
This could be an alternative:
$interview = Interview::find(1)->with(['VideoQuestions',
'TextQuestions',
'UploadQuestions',
'Questions' => function($query){
$query->orderBy('order_position', 'asc');
}])->get();
Define the relationships and make a table Questions that holds an order_position that you can sort on instead of each table.
I'm going to attach a specific present item with various pivot values to a single order. I'm looking around for something like :
$order->presents()->attach(1,[
['price' => '2400, 'qty' => 2],
['price => '1000, 'qty' => 4]
]);
of course its not a valid code.i can attach items one by one:
$order->presents()->attach(1,['price' => '2400, 'qty' => 2]);
$order->presents()->attach(1,['price => '1000, 'qty' => 4]);
but i think there should be a better way, can anyone let me know how may i do a bunch attach?
Lookin at the documentation I can see you almost got the solution.
Referring to the documentation you should use an array like array(id => [values]). In your case:
$order->presents()->attach([
1 => [
'price' => 2400,
'qty' => 2
],
....
]);
This code has not been tested.
Edit
When you check the attach() function in the deep dungeons of the Laravel framework can see it also accepts a Model, Collection or integer. When you look further you can see it (maybe) also accepts an array of ID's.
/**
* Attach a model to the parent.
*
* #param mixed $id
* #param array $attributes
* #param bool $touch
* #return void
*/
public function attach($id, array $attributes = [], $touch = true)
{
if ($id instanceof Model) {
$id = $id->getKey();
}
if ($id instanceof Collection) {
$id = $id->modelKeys();
}
$query = $this->newPivotStatement();
$query->insert($this->createAttachRecords((array) $id, $attributes));
if ($touch) {
$this->touchIfTouching();
}
}
Don't know if it works, but try:
$order->presents()->attach([1, 1], [[
'price' => 2400,
'qty' => 2
], [
'price' => 1337,
'qty' => 420
]
]
]);
You can do it like this:
$order->presents()->attach([
1 => ['count' => 3, 'price' => '2400, 'qty' => 2],
2 => ['count' => 4, 'price' => '2400, 'qty' => 2]
]);