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";
}
Related
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();
}
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 !!',
));
}
}
}
I have a table of:
id title type expl bubble_content onfocus req dorder label mirror
1 Fullname 1 1 Your fullname Yes 0 0 0 NULL
Then another table of:
id fieldid relid dorder
4 1 2 0
5 1 1 0
How would I join the two tables so that the result would be something like:
0 => array(
'id' => 1,
'title' => 'Fullname',
.... etc ....
'relid' => 2,
'relid' => 1),
1 => array(
.... etc ....
))
I've tried using INNER JOIN / LEFT JOIN but this produces two rows/arrays for each relid, I would really like all the data for the particular fieldid to exist within the same array, as illustrated above.
You can't have 2 keys with the same name in an array. On your example you have 2 'relid', the second one will overwrite the first.
You can code PHP so that it merges those rows into one:
$output = array();
while ($row = mysql_fetch_assoc($result))
{
// Capture all values for this row first.
// If this is the new row from the first table, store.
if (!isset($output[$row['id']]))
{
$output[$row['id']] = $row;
// Make a new array for relids.
$output[$row['id']]['relids'] = array();
}
$output[$row['id']]['relids'][] = $row['relid'];
}
Your output array will look like this:
0 => array(
'id' => 1,
'title' => 'Fullname',
.... etc ....
'relids' => array(2, 1),
1 => array(
.... etc ....
))
I am trying to generate nested json data like in this example from one mysql table.
var data = {
"62" : {
"section" : "bodyImage",
"img" : "imageurl/image62.png",
"label" : "blue",
"price" : "100"
},
"63" : {
"section" : "bodyImage",
"img" : "imageurl/image63.png",
"label" : "red",
"price" : "120"
}
}
62 and 63 are from the row data_id in the following table:
+-----------+------------+-------------------------+-------+---------+
| data_id | section | img | label | price |
+-----------+------------+-------------------------+-------+----------
| 62 | bodyImage | imagpath/image62.png | blue | 100 |
| 63 | bodyImage | imagpath/image62.png | red | 120 |
+-----------+------------+-------------------------+-------+---------
+
This is the php file with the query:
$result = mysql_query("SELECT data_id, section, img, label, price FROM table WHERE active != 'no'");
$data = array();
while($row=#mysql_fetch_object($result)) {
$data[] = array (
'section' => $row['sub_section'],
'img' => $row['big_image'],
'label' => $row['label_client_en'],
'price' => $row['price']
);
}
echo json_encode( $data );
I cannot get it working. Please help me with the right syntax for the multi-dimensional array.
You cannot json_encode "sub arrays" directly on the main array
You must do json_encode for each array in your while:
$data[] = json_encode(array (
'section' => $row['sub_section'],
'img' => $row['big_image'],
'label' => $row['label_client_en'],
'price' => $row['price']
));
And then you must also encode the main array as you already do.
Consider the following table:
mysql> select * from vCountryStatus;
+-------------+------------+------+---------+--------+-----------------+
| CountryName | CountryISO | Code | Status | Symbol | CurrencyName |
+-------------+------------+------+---------+--------+-----------------+
| Brazil | BR | 55 | LIVE | BRL | Brazilian Real |
| France | FR | 33 | offline | EUR | Euro |
| Philippines | PH | 63 | LIVE | PHP | Philippino Peso |
+-------------+------------+------+---------+--------+-----------------+
3 rows in set (0.00 sec)
I am trying to construct a hash based on this table. For this I do the following:
#!/usr/bin/perl
use DBI;
use Data::Dumper;
my $dbh = DBI->connect("dbi:mysql:database=db", "user", "password", {RaiseError => 1, AutoCommit => 0, FetchHashKeyName => "NAME_lc"}) || die "DB open error: $DBI::errstr";
my $sth = $dbh->prepare("select * from vCountryStatus");
$sth->execute;
my $hash = $sth->fetchall_hashref('countryiso');
print Dumper($hash);
Here is the output this generates:
$VAR1 = {
'PH' => {
'symbol' => 'PHP',
'status' => 'LIVE',
'countryname' => 'Philippines',
'countryiso' => 'PH',
'currencyname' => 'Philippino Peso',
'code' => '63'
},
'BR' => {
'symbol' => 'BRL',
'status' => 'LIVE',
'countryname' => 'Brazil',
'countryiso' => 'BR',
'currencyname' => 'Brazilian Real',
'code' => '55'
},
'FR' => {
'symbol' => 'EUR',
'status' => 'offline',
'countryname' => 'France',
'countryiso' => 'FR',
'currencyname' => 'Euro',
'code' => '33'
}
};
The question is: why is the key of the hash (countryiso) repeated in the values inside the hash?
What I would prefer is the following output:
$VAR1 = {
'PH' => {
'symbol' => 'PHP',
'status' => 'LIVE',
'countryname' => 'Philippines',
'currencyname' => 'Philippino Peso',
'code' => '63'
},
'BR' => {
'symbol' => 'BRL',
'status' => 'LIVE',
'countryname' => 'Brazil',
'currencyname' => 'Brazilian Real',
'code' => '55'
},
'FR' => {
'symbol' => 'EUR',
'status' => 'offline',
'countryname' => 'France',
'currencyname' => 'Euro',
'code' => '33'
}
};
Is it possible using fetchall_hashref DBI method? Or do I have to go the traditional way, looping through each row and constructing the hash on the fly?
No, it cannot be done using fetchall_hashref. But you can iterate over the hash values and delete the key:
delete $_->{countryiso} for values %$hash;
I had this same problem but was using multiple keys on fetchall_hashref, so I had to go deeper in the hash references. Not exactly rocket science, but here it is:
(...)
my #keys=('key1','key2','key3');
my $result_ref=$sth->fetchall_hashref(\#keys);
remove_key_values($result_ref,\#keys);
(...)
sub remove_key_values {
my ($href_values,$aref_keys) = (#_);
foreach my $hk (keys %$href_values) {
foreach my $ak (#$aref_keys) {
if ($ak eq $hk) {
delete $href_values->{$hk};
}
}
if (exists $href_values->{$hk} and ref($href_values->{$hk}) eq 'HASH') {
remove_key_values($href_values->{$hk},$aref_keys);
}
}
}