How can I update multiple rows at the same time by their report_id? My Inventory table looks like this:
| id | report_id | product_id | shelf_quantity | display_quantity |
|----|-----------|------------|----------------|------------------|
| 1 | 2 | 12 | 1 | 5 |
| 2 | 2 | 13 | 2 | 6 |
| 3 | 2 | 14 | 3 | 23 |
My attempt to solve the problem:
My controller:
function update($id, Request $request) {
$report = Report::find($id);
$inputs = $request->input('display');
$report->user_id = $user_id;
$report->save();
//Updating inventory table
$inventory = Inventory::where('report_id', $report->id)->get();
foreach($inputs as $key => $value) {
$inventory->display = $request->input('display')[$key] ?: 0;
$inventory->storage = $request->input('storage')[$key] ?: 0;
$inventory->save();
}
My web route:
Route::put('/reports/{id}', 'ReportController#update');
The problem here is that it is only saving the last value that I input.
Additional information
I'm also using the same code in storing new rows and it's working fine. Please see code below:
public function store(Request $request) {
//Adding inventory table
$new_inventories = new Inventory();
foreach($inputs as $key => $value) {
$data[] = [
'user_id' => $user_id,
'report_id' => $new_report->id,
'display' => $request->input('display')[$key] ?: 0,
'storage' => $request->input('storage')[$key] ?: 0,
'product_id' => $request->product_id[$key],
'created_at' => $now,
'updated_at' => $now,
// 'remark' => $request->remark[$key] ?? null,
];
}
Inventory::insert($data);
//End of inventory table
}
Any form of help would be appreciated. Thank you!
EDIT:
My form looks like this:
<form action="/reports/{{$report->id}}" method="post">
#csrf
{{method_field('PUT')}}
#foreach($products as $product)
<input type="number" name="product_id[]" value="{{ $product->id}}" hidden>
<input type="number" name="storage[]">
<input type="number" name="display[]">
#endforeach
</form>
You cannot update multiple rows in one shot. In this case the best way is to get one by one the items in inventory and update them. So you loop through $request->input('product_id'), get the Inventory model for that product_id and $report->id, update and save.
for($i=0; $i<count($request->input('product_id');$i++) {
$inventory = Inventory::where('report_id', $report->id)->where('product_id', $request->input('product_id')[$i])->first();
$inventory->display = $inventory->display = $request->input('display')[$i];
$inventory->storage = $inventory->storage = $request->input('storage')[$i];
$inventory->save();
}
I have 2 tables :
Product Option Group
id | opt_name | active_flag
------------------------------
1 | Cook level | 0
Product Option List
id | optgrp_id | list_name | active_flag
------------------------------------------
1 | 1 | 25 | 0
2 | 1 | 50 | 1
3 | 1 | 75 | 0
4 | 1 | 100 | 0
Product Option Group Model
public function getOptList()
{
return $this->hasMany(ProdOptlist::className(),['optgrp_id'=>'id']);
}
Product Option List Model
public function getOptGrp()
{
return $this->hasOne(ProdOptgrp::className(),['id'=>'optgrp_id']);
}
Product Option Group Controller
public function actionUpdate($id)
{
$model = $this->findModel($id);
if($model->load(Yii::$app->request->post()) && $model->validate())
{
...
}
else
return $this->render('update', ['model'=>$model]);
}
protected function findModel($id)
{
if (($model = ProdOptgrp::find()
->joinWith('optList')
->where([ProdOptgrp::tableName().'.id'=>$id,
ProdOptgrp::tableName().'.active_flag'=>0,
ProdOptlist::tableName().'.active_flag'=>0])
->one()) !== null) {
return $model;
}
throw new NotFoundHttpException('The requested page does not exist.');
}
Update View
Expected output for print_r($model->optList) :
{
[id] => 1
[optgrp_id] => 1
[list_name] => 25
[active_flag] => 0
},
{
[id] => 3
[optgrp_id] => 1
[list_name] => 75
[active_flag] => 0
},
{
[id] => 4
[optgrp_id] => 1
[optList_name] => 100
[active_flag] => 0
}
Actual output :
{
[id] => 1
[optgrp_id] => 1
[list_name] => 25
[active_flag] => 0
},
{
[id] => 2
[optgrp_id] => 1
[list_name] => 50
[active_flag] => 1
},
{
[id] => 3
[optgrp_id] => 1
[list_name] => 75
[active_flag] => 0
},
{
[id] => 4
[optgrp_id] => 1
[optList_name] => 100
[active_flag] => 0
}
Yii2 debugger showing correct query but output still consist of all 4 elements.
Kindly advice if there is any mistake, thank you in advance :)
Even if you use the joinWith() the where() part of your $model = ProdOptgrp::find()... code only limits the result that is returned by the query executed by one() method call. It doesn't affect what is loaded for relations.
If you want to limit what is loaded for relations you can do it:
1) By modifing the existing relation
This is the solution you've come to. You add the where condition directly to the getOptList() method of your ProdOptgrp model. If you do it this way, the $model->optList will always return filtered relation. Depending on case that might be advantage or disadvantage.
2) By adding second relation
You can create another method in your ProdOptgrp model that will define the filtered relation while keeping the original getOptList() unfiltered.
For example like this:
class ProdOptgrp extends \yii\db\ActiveRecord
{
public function getOptList()
{
return $this->hasMany(ProdOptlist::className(),['optgrp_id'=>'id']);
}
public function getFilteredOptList()
{
return $this->getOptList()->where([
ProdOptlist::tableName() . '.active_flag' => 0
]);
}
}
In this case the $model->optList will still contain unfiltered OptLists and the $model->filteredOptList will contain filtered. This solution is good when you need to use both at different spots of your application.
3) By using callback syntax in joinWith() or with()
In case you want to filter the relation only in one particular case you don't need to modify your model. You can modify the relation with callback that is called before loading the data.
$model = ProdOptgrp::find()
->joinWith([
'optList' => function(\yii\db\ActiveQuery $query) {
$query->where([
ProdOptlist::tableName() . '.active_flag' => 0
]);
}
])->where([
ProdOptgrp::tableName().'.id'=>$id,
ProdOptgrp::tableName().'.active_flag'=>0,
ProdOptlist::tableName() . '.active_flag'=>0,
])->one();
The last condition in where() will cause the $model to be null when the active_flag is 0 in optgrp table but 1 in all related records in optlist table. I'm not sure if that is inteded behavior.
You can do it this way too:
//Controller
protected function findModel($id)
{
if (($model = ProdOptgrp::findOne($id)) !== null && $model->isActive()) {
return $model;
}
throw new NotFoundHttpException('The requested page does not exist.');
}
//Model
/*
*Check if model is active
*/
public function isActive(){
return ($this->active_flag == 0) ? true: false;
}
public function getOptList()
{
return $this->hasMany(ProdOptlist::className(),['optgrp_id'=>'id'])->where([ProdOptgrp::tableName().'.active_flag'=>0]);
}
//View
foreach($model->optList as optItem): // you get filtered result
Right now, I build my menu doing many request and loop with symfony.
I would like to be able to retrieve the same thing in a single sql request
MenuItem (Id,parent_id,level,weight)
parent_id is a reference to an other MenuItem
If I have these records
1,null,1,50
2,null,1,20
3,1,2,100
4,1,2,0
5,2,2,40
6,5,3,900
7,5,3,500
I want the results to be
2
5
7
6
1
4
3
The weigtht attribute is used to order the menu items inside their own level.
That means id 2 come before id 1 because weight 20 < weight 50 but id 2 still comes before id 4 because level 1 < level 2
I'm not even sure this is possible.
EDIT: Right now, I have to do something very ugly
$menu = $this->factory->createItem('root');
$menu->setLabel("Menu");
$item_repository = $this->getDoctrine()->getRepository(MenuItem::class);
//profondeur max defini à 5
//On récupère les items du niveau 1 trié par poids (profondeur)
$items_lv1 = $item_repository->findBy(array('menu' => $id_main_menu,'active' => 1, 'niveau' => 1),array('poids' => 'ASC'));
//On récupère les items du niveau 2 trié par parent et poids (profondeur)
$items_lv2 = $item_repository->findBy(array('menu' => $id_main_menu,'active' => 1,'niveau' => 2),array('parent' => 'ASC','poids' => 'ASC'));
$items_lv3 = $item_repository->findBy(array('menu' => $id_main_menu,'active' => 1,'niveau' => 3),array('parent' => 'ASC','poids' => 'ASC'));
$items_lv4 = $item_repository->findBy(array('menu' => $id_main_menu,'active' => 1,'niveau' => 4),array('parent' => 'ASC','poids' => 'ASC'));
$items_lv5 = $item_repository->findBy(array('menu' => $id_main_menu,'active' => 1,'niveau' => 5),array('parent' => 'ASC','poids' => 'ASC'));
$cptLv1 = 1;
foreach ($items_lv1 as $item_lv1){
$lv1 = $menu->addChild($cptLv1,
['uri' => $item_lv1->getUrl(),'label' => $item_lv1->getLabel(),
'attributes' => array('title' => $item_lv1->getTitle(),
'id_css' => $item_lv1->getIdCss(), 'class_css' => $item_lv1->getClassCss(), 'target' => $item_lv1->getTarget())]);
$cptLv2 = 1;
foreach ($items_lv2 as $item_lv2){
if($item_lv2->getParent()->getUrl() == $item_lv1->getUrl()){
$lv2 = $lv1->addChild($cptLv1.$cptLv2,
['uri' => $item_lv2->getUrl(),'label' => $item_lv2->getLabel(),
'attributes' => array('title' => $item_lv2->getTitle(),
'id_css' => $item_lv2->getIdCss(), 'class_css' => $item_lv2->getClassCss(), 'target' => $item_lv2->getTarget())]);
$cptLv3 = 1;
foreach ($items_lv3 as $item_lv3){
if($item_lv3->getParent()->getUrl() == $item_lv2->getUrl()) {
$lv3 = $lv2->addChild($cptLv1.$cptLv2.$cptLv3,
['uri' => $item_lv3->getUrl(), 'label' => $item_lv3->getLabel(),
'attributes' => array('title' => $item_lv3->getTitle(),
'id_css' => $item_lv3->getIdCss(), 'class_css' => $item_lv3->getClassCss(), 'target' => $item_lv3->getTarget())]);
$cptLv4 = 1;
foreach ($items_lv4 as $item_lv4){
if($item_lv4->getParent()->getUrl() == $item_lv3->getUrl()) {
$lv4 = $lv3->addChild($cptLv1.$cptLv2.$cptLv3.$cptLv4,
['uri' => $item_lv4->getUrl(), 'label' => $item_lv4->getLabel(),
'attributes' => array('title' => $item_lv4->getTitle(),
'id_css' => $item_lv4->getIdCss(), 'class_css' => $item_lv4->getClassCss(), 'target' => $item_lv4->getTarget())]);
$cptLv5 = 1;
foreach ($items_lv5 as $item_lv5){
if($item_lv5->getParent()->getUrl() == $item_lv4->getUrl()) {
$lv4->addChild($cptLv1.$cptLv2.$cptLv3.$cptLv4.$cptLv5,
['uri' => $item_lv5->getUrl(), 'label' => $item_lv5->getLabel(),
'attributes' => array('title' => $item_lv5->getTitle(),
'id_css' => $item_lv5->getIdCss(), 'class_css' => $item_lv5->getClassCss(), 'target' => $item_lv5->getTarget())]);
}
$cptLv4 += 1;
}
}
$cptLv4 += 1;
}
}
$cptLv3 += 1;
}
}
$cptLv2 +=1;
}
$cptLv1+=1;
}
Consider the following:
DROP TABLE IF EXISTS my_table;
CREATE TABLE my_table
(id SERIAL PRIMARY KEY
,parent_id INT NULL
,level INT NOT NULL
,weight INT NOT NULL
);
INSERT INTO my_table VALUES
(1,null,1,50),
(2,null,1,20),
(3,1,2,100),
(4,1,2,0);
SELECT *,COALESCE(y.level,x.level) my_level,COALESCE(y.weight,x.weight) my_weight FROM my_table x LEFT JOIN my_table y ON y.id = x.parent_id;
+----+-----------+-------+--------+------+-----------+-------+--------+----------+-----------+
| id | parent_id | level | weight | id | parent_id | level | weight | my_level | my_weight |
+----+-----------+-------+--------+------+-----------+-------+--------+----------+-----------+
| 1 | NULL | 1 | 50 | NULL | NULL | NULL | NULL | 1 | 50 |
| 2 | NULL | 1 | 20 | NULL | NULL | NULL | NULL | 1 | 20 |
| 3 | 1 | 2 | 100 | 1 | NULL | 1 | 50 | 1 | 50 |
| 4 | 1 | 2 | 0 | 1 | NULL | 1 | 50 | 1 | 50 |
+----+-----------+-------+--------+------+-----------+-------+--------+----------+-----------+
Extract from that whatever you like.
you do not have to use level and weight ... just use the weight ("order" would be better).
do not worry if id 2 is before or after id 4, because id4 is in id2 (parent level).
an element with parent_id = null is a id with level 0.
think like this :
select Id,parent_id,level ,weight from mytable order by level,weight
Here is a piece of code that allows you, after your select, to have a recursive table that you can browse to display the menus.
It takes into account that an element can be related to "null" (root), and that there can be non-consecutive "weights" ...
the $ result variable is constructed as if you had made a select with a sort on level + weight
<style>
ul {
list-style-type: none;
margin: 0;
padding: 0;
background-color: #D0D0D0;
}
li {
margin-left:2em;
border-left:solid 2px green;
text-align:left;
padding-left:1em;
}
</style>
<?php
/*
* warn ! this array looks like a result after a select, ordered by level+weight
*/
$result=array(
array( 'id'=>2, 'parent_id'=>null, 'level'=>1, 'weight'=>20 ),
array( 'id'=>1, 'parent_id'=>null, 'level'=>1, 'weight'=>50 ),
array( 'id'=>4, 'parent_id'=>1, 'level'=>2, 'weight'=>0 ),
array( 'id'=>3, 'parent_id'=>1, 'level'=>2, 'weight'=>100 ),
array( 'id'=>5, 'parent_id'=>2, 'level'=>2, 'weight'=>40 ),
array( 'id'=>7, 'parent_id'=>5, 'level'=>3, 'weight'=>500 ),
array( 'id'=>6, 'parent_id'=>5, 'level'=>3, 'weight'=>900 )
);
// store recursive array of menus
$menus=array();
// store link of an id in the recursive array of menus
$keysIds=array();
// start with a empty menu
$menus[0]=array('element'=>'ROOT','subMenus'=>array());
$keysIds[0]=&$menus[0];
// build a menus array
foreach ($result as $element) {
$idParent=$element['parent_id'];
$id=$element['id'];
// check for idParent=0 !!
if ($idParent==null) {
$idParent=0;
}
// check if parent exists
// don't forget, result is sorted by level+weight,
// so the idParent is always in array
if (!isset($keysIds[$idParent])) {
echo "<H2>PARENT = $idParent , not exists while INSERTING Id {$id} </H2>";
continue;
}
// JSON index sorting prevention
$max=sizeof($keysIds[$idParent]['subMenus']);
// create a entry
$keysIds[$idParent]['subMenus'][$max]=array('element'=>$element,'subMenus'=>array());
// for next entries, keep this id accessible quickly..it can be a parent.
$keysIds[$id]=&$keysIds[$idParent]['subMenus'][$max];
}
// show the HTML LISTE
htmlMenus($menus,0);
// Recursive iteration on $menus
function htmlMenus($root,$listeLevel) {
echo str_repeat(" ", $listeLevel*2); // beautifull source...
echo "<ul>\n";
foreach ($root as $datas) {
echo str_repeat(" ", $listeLevel*2+2);
echo "<li>\n ";
if ($datas['element']!='ROOT') {
echo str_repeat(" ", $listeLevel*2+2);
echo "ID : {$datas['element']['id']} weight:{$datas['element']['weight']}\n";
}
htmlMenus($datas['subMenus'],$listeLevel+1);
echo str_repeat(" ", $listeLevel*2+2);
echo '</li>';
}
echo str_repeat(" ", $listeLevel*2);
echo "</ul>\n";
}
I was wondering if its possible to group appointments by dates with 1 query so my response will be something like this (in JSON):
{
"appointmentsByDay":[
"01-07-2018":[
{
"appointment":"test"
},
{
"appointment":"test"
}
],
"02-07-2018":[
{
"appointment":"test"
},
{
"appointment":"test"
}
],
..................
"31-07-2018":[
{
"appointment":"test"
},
{
"appointment":"test"
}
]
]
}
I know this is possible looping through all the days within a Month but then I have to call a similar query up to 31 times for a single month.
Currently I'm getting all my appointments in between a month the way below but these are not grouped by each day and appointments falling between a bigger range will get ordered wrong:
$startOfMonth = Carbon::parse($date)->startOfMonth();
$endOfMonth = Carbon::parse($date)->endOfMonth();
$appointments = Appointment::
where('user_id', '=', $userId)->
where(function ($query) use($endOfMonth, $startOfMonth) {
$query->where(function ($query) use($endOfMonth, $startOfMonth) {
$query->where('from_date', '<', $startOfMonth->format('Ymd'))
->where('to_date', '>', $endOfMonth->format('Ymd'));
})
->orWhere(function ($query) use($endOfMonth, $startOfMonth) {
$query->where('from_date', '>=', $startOfMonth->format('Ymd'))
->where('to_date', '<=', $endOfMonth->format('Ymd'));
})
->orWhere(function ($query) use($endOfMonth, $startOfMonth) {
$query->where('from_date', '<', $startOfMonth->format('Ymd'))
->where('to_date', '>=', $startOfMonth->format('Ymd'));
})
->orWhere(function ($query) use($endOfMonth, $startOfMonth) {
$query->where('from_date', '<=', $endOfMonth->format('Ymd'))
->where('to_date', '>', $endOfMonth->format('Ymd'));
});
})
->with(user')
->get();
My model looks like this:
namespace App\Models;
use Reliese\Database\Eloquent\Model as Eloquent;
class Appointment extends Eloquent
{
protected $table = 'appointments';
public $timestamps = false;
protected $fillable = [
'from_date',
'to_date',
'title'
];
}
My appointments table looks like this: (I'm using MYSQL)
+-----------+----------------+---------------------+-------------------+
| id (int) | title (varchar)| from_date (varchar) | to_date (varchar) |
+-----------+----------------+---------------------+-------------------+
| 1 | appointment1 | 20180725 | 20180725 |
+-----------+----------------+---------------------+-------------------+
| 2 | appointment2 | 20180726 | 20180726 |
+-----------+----------------+---------------------+-------------------+
| 3 | appointment3 | 20180723 | 20180812 |
+-----------+----------------+---------------------+-------------------+
| 4 | appointment4 | 20180726 | 20180726 |
+-----------+----------------+---------------------+-------------------+
| 5 | appointment5 | 20180612 | 20181123 |
+-----------+----------------+---------------------+-------------------+
im making an api in laravel but when i send from a post request it display nothing it work only when i send the values in the url what im i doing wrong here is my code !
$user = new userInscription;
$user->nom = Request::get('name');
$user->pseudo = Request::get('pseudo');
$user->userId = Request::get('userId');
$user->hasFiat = Request::get('hasFiat');
$user->optin = Request::get('optin');
$user->mail = Request::get('mail');
$pseudo = Input::get('pseudo');
$userId = Input::get('userId');
$hasFiat = Input::get('hasFiat');
if($pseudo == '' || $hasFiat == '' )
{
return Response::json( array(
'status' => 'ko',
'message' => 'missing mandatory parameters')
);
}
else if($userId == '')
{
if( $user->save() )
{
$id = DB::table('user')
->where('pseudo','LIKE',$pseudo)
->pluck('userId');
return Response::json(array(
'status' => 'ok',
'message' => 'success',
'userId' => $id
));
}
else
{
return Response::json(array(
'message' => 'error while saving this user !!',
));
}
}
Laravel REST-ful (Resourceful) controlllers has pre-configured routes (can be re-configured):
According to : http://laravel.com/docs/controllers#resource-controllers
+-----------+---------------------------+---------+------------------+
| Verb | Path | Action | Route Name |
+-----------+---------------------------+---------+------------------+
| GET | /resource | index | resource.index |
| GET | /resource/create | create | resource.create |
| POST | /resource | store | resource.store |
| GET | /resource/{resource} | show | resource.show |
| GET | /resource/{resource}/edit | edit | resource.edit |
| PUT/PATCH | /resource/{resource} | update | resource.update |
| DELETE | /resource/{resource} | destroy | resource.destroy |
+-----------+---------------------------+---------+------------------+
Referencing the table each of the Verb must correspond to the action method in the controller.
For example if your Resourceful Route is registered as:
Route::resource('user', 'userInscriptionController');
Then to POST to user resource, you need to have userInscriptionController#store action (i.e. method called store() in your userInscriptionController.
To avoid manually creating each of these actions, you can use Laravel's artisan controller:make
php artisan controller:make userInscriptionController
which will generate all these actions for you, then you just need to fill in your logic to complete the resource.
From your comment, you are using
Route::resource('user', 'userInscriptionController');
which will generate following routes
Verb | Path | Action | Route Name
------------------------------------------------------------------------
GET | /resource | index | resource.index
GET | /resource/create | create | resource.create
POST | /resource | store | resource.store
GET | /resource/{resource} | show | resource.show
GET | /resource/{resource}/edit | edit | resource.edit
PUT/PATCH | /resource/{resource} | update | resource.update
DELETE | /resource/{resource} | destroy | resource.destroy
And as you can see, the only action allowing post is store. So you should use this one or add post route for an other method like this :
Route::post('your_url', array('as' => 'your_route_name', 'uses' => 'YourController#yourMethod'));
I hope it's clear now
if request is GET then:
if (Request::isMethod('get'))
{
$user = new userInscription;
$user->nom = Request::get('name');
$user->pseudo = Request::get('pseudo');
$user->userId = Request::get('userId');
$user->hasFiat = Request::get('hasFiat');
$user->optin = Request::get('optin');
$user->mail = Request::get('mail');
$pseudo = Input::get('pseudo');
$userId = Input::get('userId');
$hasFiat = Input::get('hasFiat');
if($pseudo == '' || $hasFiat == '' )
{
return Response::json( array(
'status' => 'ko',
'message' => 'missing mandatory parameters')
);
}
else if($userId == '')
{
if( $user->save() )
{
$id = DB::table('user')
->where('pseudo','LIKE',$pseudo)
->pluck('userId');
return Response::json(array(
'status' => 'ok',
'message' => 'success',
'userId' => $id
));
}
else
{
return Response::json(array(
'message' => 'error while saving this user !!',
));
}
}
}
===================
if request is POST then:
if (Request::isMethod('post'))
{
$user = new userInscription;
$user->nom = Request::post('name');
$user->pseudo = Request::post('pseudo');
$user->userId = Request::post('userId');
$user->hasFiat = Request::post('hasFiat');
$user->optin = Request::post('optin');
$user->mail = Request::post('mail');
$pseudo = Input::post('pseudo');
$userId = Input::post('userId');
$hasFiat = Input::post('hasFiat');
if($pseudo == '' || $hasFiat == '' )
{
return Response::json( array(
'status' => 'ko',
'message' => 'missing mandatory parameters')
);
}
else if($userId == '')
{
if( $user->save() )
{
$id = DB::table('user')
->where('pseudo','LIKE',$pseudo)
->pluck('userId');
return Response::json(array(
'status' => 'ok',
'message' => 'success',
'userId' => $id
));
}
else
{
return Response::json(array(
'message' => 'error while saving this user !!',
));
}
}
}