JQuery Select2 - Format nested list from PHP/MySQL results - php

I have a Select2 list which I want to populate with a nested structure for the data:
Level 1
Condition 1
Condition 2
Level 2
Condition 3
Condition 4
etc
The JSON needs to be in the following format:
data: [{
'text': 'Level 1',
'children': [{
'id': 1,
'text': 'Condition 1'
}, {
'id': 2,
'text': 'Condition 2'
}, ],
'text': 'Level 2',
'children': [{
'id': 3,
'text': 'Condition 3'
}, {
'id': 4,
'text': 'Condition 4'
}, ]
}]
The JQuery Select2:
$.ajax( {
url: "scripts/get_conditions.php",
dataType: 'json'
} ).then( function ( response ) {
$( "#condition_tree" ).select2( {
placeholder: "Select a Condition...",
allowClear: true,
width: 'resolve',
containerCssClass: "show-hide",
data: response
} );
} );
Currently using the following PHP and MySQL which I am unsure of how to change to produce the required results:
$query = 'SELECT * FROM mcondition ORDER BY mcondition_name ASC';
$result = $connection->query( $query );
$presentations = array();
while ($row = mysqli_fetch_array($result)) {
$mconditions[] = array("id"=>$row['mcondition_pk'], "text"=>$row['mcondition_name']);
}
echo json_encode($mconditions);
?>
And the mcondition table:
+---------+-----------+------------------------------+
| mcondition_pk | mcondition_name | mcondition_level |
+---------+-----------+------------------------------+
| 1 | Condition 1 | Level 1 |
+---------+-----------+------------------------------+
| 2 | Condition 2 | Level 1 |
+---------+-----------+------------------------------+
| 3 | Condition 3 | Level 2 |
+---------+-----------+------------------------------+
| 4 | Condition 4 | Level 2 |
+---------+-----------+------------------------------+
Note PHP version is 5.3.3, no chance of upgrading at present.

Use the level name as key of a two-dimensional array to gather your data under, add each row’s data to the children under the appropriate key.
// fake mysql row data
$data = [
['mcondition_pk' => 1, 'mcondition_name' => 'Condition 1', 'mcondition_level' => 'Level 1'],
['mcondition_pk' => 2, 'mcondition_name' => 'Condition 2', 'mcondition_level' => 'Level 1'],
['mcondition_pk' => 3, 'mcondition_name' => 'Condition 3', 'mcondition_level' => 'Level 2'],
['mcondition_pk' => 4, 'mcondition_name' => 'Condition 4', 'mcondition_level' => 'Level 2'],
];
$temp = [];
// foreach loop over fake data, replace that with your original `while(…)` again
foreach($data as $row) {
$temp[$row['mcondition_level']]['text'] = $row['mcondition_level'];
$temp[$row['mcondition_level']]['children'][] = [
'id' => $row['mcondition_pk'],
'text' => $row['mcondition_name']
];
}
// replace the associative keys with simple numeric ones again
$temp = array_values($temp);
echo json_encode($temp);

Related

I need to know how to make associated array of country and city

i need to know how i can make a array from db tables. i want something like that. i have 3 tables in data base country - state - city
data base structure is as follow
countries-table:
| id | country |
|----|----------------|
| 1 | united kingdom |
states-table
| id | state |
|----|----------------------|
| 1 | united westyorkshite |
cities-table
| id | city |
|----|----------------------|
| 1 | united wakefield |
The expected result:
{
value: '12',
label: 'United Kingdom',
children: [
{
values: '34',
labels: 'West YorkShire',
children: [
{
value: '400',
label: 'Dewsbury'
},
{
value: '401',
label: 'Wakefield'
}
]
}
This is what I've tried:
$country_array = array();
$array = Country::select('countries.country', 'countries.country_id')
->isDefault()
->active()
->sorted()
->pluck('countries.country', 'countries.country_id')
->toArray();
// print_r($array);
foreach($array as $key => $arr) {
$array_state = State::select('states.state', 'states.state_id')
->where('states.country_id', '=', $key)
->isDefault()
->active()
->sorted()
->pluck('states.state', 'states.state_id')
->toArray();
foreach($array_state as $key_1 => $arr_1) {
$array_city = City::select('cities.city', 'cities.city_id')
->where('cities.state_id', '=', $key_1)
->active()
->sorted()
->pluck('cities.city', 'cities.city_id')
->toArray();
$array_state_1 [] = array (
'value' => $key_1,
'label' => $arr_1,
'children' => $array_city
);
}
$country_array [] = array (
'value' => $key,
'label' => $arr,
'children' => $array_state
);
}
dd($country_array);
I need these labels as well like value and label. i cant remove that as i am using vuejs element ui component.
I try to use normal foreach loop but its doing time out. any idea how i can do that in laravel using maps or collection or what is the best solution.
I am using php 7 and laravel version is 5.6
To retrieve all necessary data in a single statement, I would use nested with's. For example:
$result = Country::where('country_id', 12)
->with(['states' => function ($query) {
$query->where('state_id', 34);
$query->with('cities');
}])
->get();
The next step is to modify the data. The map() function is indeed very useful for this purpose, although the nesting makes it look a little complex:
$mapped = $result->map(function ($country, $key) {
return [
'value' => $country->country_id,
'label' => $country->country,
'children' => $country->states->map(function ($state, $key) {
return [
'value' => $state->state_id,
'label' => $state->state,
'children' => $state->cities->map(function ($city, $key) {
return [
'value' => $city->city_id,
'label' => $city->city,
];
}),
];
}),
];
});
Finally to display it, we convert the whole thing to a JSON array.
echo '<pre>' . $mapped->toJson(JSON_PRETTY_PRINT) . '</pre>';
Which gives me:
[
{
"value": 12,
"label": "United Kingdom",
"children": [
{
"value": 34,
"label": "West YorkShire",
"children": [
{
"value": 400,
"label": "Dewsbury"
},
{
"value": 401,
"label": "Wakefield"
}
]
}
]
}
]

How to do multi sort in Elastic Search

I need to divide my search result into two parts. 1 with those goods in which the number> 0 sort them by price and withdraw first. 2 products whose quantity = 0 sort by price and display at the end, after those products that are in stock. The main thing is that in the first group of goods (whose quantity> 0) there were no goods from the second group (whose quantity = 0) What unfortunately happens when I sort by two conditions
Use PHP 7.1
and Elastic Search 6.6.0
Small example, there is a table of goods
id | site_price | count
1 | 10 | 0
2 | 5 | 5
3 | 15 | 2
4 | 20 | 10
5 | 15 | 0
I need to sort first by quantity, and then by price (without losing the first sorting).
First sort: ('count'=>'desc').
Second sort: ('site_price'=>'asc').
Should get this result:
id | site_price | count
2 | 5 | 10
3 | 15 | 5
4 | 20 | 2
1 | 10 | 0
5 | 15 | 0
$this->params['body'] = array(
'from' => ($filters['page'] - 1) * 15,
'size' => 15,
'query' => array(
'bool' => array(
'must' => array(
"query_string" => array(
'query' => "*" . $filters['text'] . "*",
)
),
)
),
'sort' => array(
array("shops_count" => "desc"),
array("site_price" => "asc")
)
);
$result = $this->client->search($this->params);
It looks like that you want to achieve behavior similar to UNION in SQL, since you first want to split the result set into 2 groups, sort each group and then attach one group after another.
There are a few ways to do it.
1) By doing 2 queries
Like in this answer, it is suggested to do 2 queries:
POST /orders/_search
{
"query": {
"range": {
"count": {
"gt": 0
}
}
},
"sort" : [
{"site_price": "asc"},
]
}
POST /orders/_search
{
"query": {
"range": {
"count": {
"gte": 0,
"lte": 0
}
}
},
"sort" : [
{"site_price": "asc"},
]
}
And then joining them on the client side.
There is also a way to do it completely on the Elasticsearch side.
2) By using script sorting
We can use script based sorting and sort first on the availability (count > 0), then by price:
POST /orders/_search
{
"sort" : [
{
"_script" : {
"type" : "number",
"script" : {
"lang": "painless",
"source": "if (doc['count'].value > 0) { 1 } else { 0 } "
},
"order" : "desc"
}
},
{"site_price": "asc"}
]
}
However, scripting always has performance overhead. Solution #1 is more robust, although it performs 2 queries.
Here is another solution that uses single query and does not use expensive scripting.
3) Adding new field - for sorting
If we add a special field, "available", we will not need to use script sorting.
The documents might look like this:
doc1 = {
"id": 1,
"site_price": 10,
"count": 0,
"available": 0
}
doc2 = {
"id": 2,
"site_price": 5,
"count": 5,
"available": 1
}
Then the sorting will look like this:
POST /orders/_search
{
"sort" : [
{"available": "desc"},
{"site_price": "asc"}
]
}
This is a common pattern called denormalization which proves useful when tuning for best performance.
Hope that helps!
#Nikolay, thanks for the help.
Unfortunately, this did not help. I tried rewrote the query - but the result is the same. Here is an example: removed too much left only search and sorting
enter code here
$this->params['body'] = array(
'from' => ($filters['page'] - 1) * 15,
'size' => 15,
'query' => array(
'bool' => array(
'must' => array(
"query_string" => array(
'query' => "*" . $filters['text'] . "*",
)
),
)
),
'sort' => array(
array("shops_count" => "desc"),
array("site_price" => "asc")
)
);
$result = $this->client->search($this->params);

Restructure array from sql query so that I can echo proper values

I'm trying to get the content I need from a joined query and properly use values as an array key so that I can build some DIV lists properly
My php query and array:
$getTickers = "
SELECT d.ID as displayID, d.display_name as display, l.location_name as locationName, d.location_id as location, t.id as ticker, tc.id as contentID, tc.content
FROM displays d
INNER JOIN locations l on d.location_id = l.id
INNER JOIN tickers t on d.id = t.display_id
INNER JOIN ticker_content tc on t.id = tc.ticker_id;
";
$tickers = $mysqlConn->query($getTickers);
$tickerDisplays = array();
foreach($tickers as $subArray) {
if(!array_key_exists($subArray['displayID'], $tickerDisplays)) {
$tickerDisplays[$subArray['displayID']] = array();
}
// here you add `display_name` under key `display_id`
$tickerDisplays[$subArray['displayID']][$subArray['location']] = $subArray['display'];
}
All examples and code below, but I don't need the html structure help with this, just how to restructure the array/key to give me the desired results and how I should loop them on the front end.
I'm getting 4 divs as I expect right now (one for each unique display/location)
but I need to figure out how to correcty arrange it so I can echo the DIsplay name as the h4, the location as h5, and then each content in my list
So the query result gives me this:
displayID | display | locationName | location | ticker | contentID | content |
1 Office Building 4 4 1 1 testing content
2 Lobby Building 4 4 2 2 testing content 2
3 Lobby Building 1 1 3 3 testing content 3
4 Office Building 1 1 4 4 testing content 4
4 Office Building 1 1 4 5 testing content again
I'm trying to loop on this with the expected result of having a a div for each location/display combo like so:
OFFICE
Building 4
testing content
---------------
LOBBY
Building 4
testing content 2
------------------
LOBBY
Building 1
testing content 3
------------------
OFFICE
Building 1
testing content 4
testing content again
----------------------
Here's the way I'm currently trying to loop that
<?php foreach($tickerDisplays as $key => $ticker):?>
<h4><?php echo $key ?></h4> //so this should be the display Name (office, lobby)
<h5><?php echo //location?></h5> //this should be the location name (Building 1, Building 4)
//This will be another foreach for any content associated with the location/display
<ul class="tickerContent">
<li>
</ul>
</div>
</div>
<?php endforeach;?>
The approach here is to make a child array for each display line to contain all
the multiple content records.
// Dummy the data from the query
$tickers = [
['displayID' => 1, 'display' => 'Office', 'locationName' => 'Building 4', 'location' => 4, 'ticker' => 1, 'contentID' => 1, 'content' => 'testing content'],
['displayID' => 2, 'display' => 'Lobby', 'locationName' => 'Building 4', 'location' => 4, 'ticker' => 2, 'contentID' => 2, 'content' => 'testing content 2'],
['displayID' => 3, 'display' => 'Lobby', 'locationName' => 'Building 1', 'location' => 1, 'ticker' => 3, 'contentID' => 3, 'content' => 'testing content 3'],
['displayID' => 4, 'display' => 'Office', 'locationName' => 'Building 1', 'location' => 1, 'ticker' => 4, 'contentID' => 4, 'content' => 'testing content 4'],
['displayID' => 4, 'display' => 'Office', 'locationName' => 'Building 1', 'location' => 1, 'ticker' => 4, 'contentID' => 5, 'content' => 'testing content again']
];
// A place to keep the reorganized data
$tickerDisplays = [];
// Walk through the query result
foreach($tickers as $row) {
$displayID = $row['displayID']; // for convenience and readability
$location = $row['location']; // for convenience and readability
$display = $row['display'];
$contentID = $row['contentID'];
if ( ! array_key_exists($row['displayID'], $tickerDisplays) ) {
$tickerDisplays[$displayID] = [
'displayID' => $row['displayID'],
'display' => $row['display'],
'ticker' => $row['ticker'],
'contentID' => $row['contentID'],
'content' => $row['content'],
'location' => $row['location'],
'locationName' => $row['locationName'],
'#content' => [] // to store the content data
];
}
$tickerDisplays[$displayID]['#content'][$contentID] = ['content' => $row['content']];
}
print_r($tickerDisplays);
foreach ( $tickerDisplays as $key => $ticker ) {
// Output the display and location name
out($ticker['display']);
out($ticker['locationName']);
// Output all the content records.
foreach ( $ticker['#content'] as $contentID => $content ) {
out($content['content']);
}
out('------------');
}
// Just a utility function
function out($msg) {
echo "$msg\n";
}
Output:
Office
Building 4
testing content
------------
Lobby
Building 4
testing content 2
------------
Lobby
Building 1
testing content 3
------------
Office
Building 1
testing content 4
testing content again
------------

How to create a php mysql dynamic tree

How can using php mysql create a dynamic tree for this tables
tbl_folder
db_id db_foldername
1 accounting
2 hr
3 it
tbl_subfolder
db_id db_folderid db_subfoldername
1 1 xxx
2 1 yyy
3 2 zzz
tbl_childsubfolder
db_id db_subfolderid db_childsubfoldername
1 1 ffff
2 2 llll
tbl_subchild
db_id db_childsubfolderid db_subchildname
1 1 eee
2 1 ppp
accounting
xxx
fff
eee
ppp
yyy
lll
hr
zzz
it
include("include/connect.php");
--SELECT--
$name";
}
?>
if(isset($_POST['add'])){
$foldername=$_POST['txt_name'];
$select=$_POST['txt_select'];echo $select;
$explod=explode("-",$select);
$path=$explod['0'].';'.$explod['1'];
if($path==";"){$path="";}
$parent_id=$explod['1'];
if($foldername==""){echo"enter a name";}
else{
$insert_query=mysqli_query($conn,"insert into tbl_folders(parent_id,path,name)values('$parent_id','$path','$foldername')")or die(mysqli_error($conn));
header("location:index.php");
}
}
$sql=mysqli_query($conn,"select * from tbl_folders where parent_id='0'")or die(mysqli_error($conn));
while($row=mysqli_fetch_array($sql)){
$name=$row['name'];
$id=$row['db_id'];
echo $name;echo"<br/>";
$sqli=mysqli_query($conn,"select * from tbl_folders where parent_id='$id'")or die(mysqli_error($conn));
while($row=mysqli_fetch_array($sqli)){
$name=$row['name'];
$id=$row['db_id'];
$path=$row['path'];
$x=explode(";",$path);echo $path;echo"<br/>";
$pa=$x['1'];
echo $name;echo"<br/>";
$sqli=mysqli_query($conn,"select * from tbl_folders where parent_id='$id' and path='$pa'")or die(mysqli_error($conn));
while($row=mysqli_fetch_array($sqli)){
$name=$row['name'];
$id=$row['db_id'];
$path=$row['db_path'];
echo $name;echo"<br/>";}
}
}
Building the tree
You can build one table with the following fields:
`id (int), parent_id (int), path (vachar), name`
id - is the identifier
parent_id - refers to the id of the parent in the same table
path - is the path of parent ids to the given element
Example entries in the table:
|id | parent_id | path | name|
-------------------------------
|1 | 0 | | A |
-------------------------------
|2 | 1 |;1; | B |
-------------------------------
|3 | 2 |;1;2; | C |
where A is the parent, B is child of A, and C is child of B.
In your backend logic you need to have the following:
When you add/edit new item in this table - if it is root parent (with no parents above it) you insert it with parent_id=0 and path=''
When you add/edit new item in this table - if it has parent then you insert it with parent_id=:idOfParent and path=CONCAT(:parentPath, ';', :idOfParent, ';')
where :idOfParent - is the parent id value and :parentPath is the path of the parent which you concatenate with the ;:idOfParent;
; - is the separator for the ids in the path
Path column gives you the advantage of directly getting all the parents of given element without using recursive approaches.
So if you select an item with path ';1;2;3;' and you need the info for the parents also you will have 1 + 3 SELECT queries in total.
And when deleting an item you can do this:
DELETE FROM table WHERE path LIKE (';:deleteId;')
where :deletedId is the id of the deleted element. This query will delete all the entries that have deleted item as a parent.
Visualization of the tree
you can get the $data with this query
'SELECT id, parent_id, path, name FROM table WHERE 1;'
But for the test i use the following example array
$data = [
0 => ['id' => 1, 'parent_id' => 0, 'path' => '', 'name' => 'A'],
1 => ['id' => 2, 'parent_id' => 1, 'path' => ';1;', 'name' => 'B'],
2 => ['id' => 3, 'parent_id' => 2, 'path' => ';1;2;', 'name' => 'C'],
3 => ['id' => 4, 'parent_id' => 3, 'path' => ';1;2;3;', 'name' => 'D'],
4 => ['id' => 5, 'parent_id' => 1, 'path' => ';1;', 'name' => 'E'],
5 => ['id' => 6, 'parent_id' => 2, 'path' => ';1;2;', 'name' => 'G'],
6 => ['id' => 7, 'parent_id' => 0, 'path' => '', 'name' => 'H'],
];
$ref = null;
$tree = [];
foreach($data as $item) {
if($item['path']) {
$path = ltrim($item['path'], ';');
$path = rtrim($path, ';');
$pathArray = explode(';', $path);
$i = 0;
foreach($pathArray as $parentId) {
if($i === 0) {
if(!isset($tree[$parentId])) {$tree[$parentId] = ['name' => [], 'children' => []];}
$ref = &$tree[$parentId]['children'];
}
else {
if(!isset($ref[$parentId])) $ref[$parentId] = ['name' => [], 'children' => []];
$ref = &$ref[$parentId]['children'];
}
$i++;
}
if($ref !== null) {
$ref[$item['id']]['name'] = $item['name'];
$ref[$item['id']]['children'] = [];
}
}
else {
$tree[$item['id']]['name'] = $item['name'];
$tree[$item['id']]['children'] = [];
}
}
Output part:
print '<pre>';
print_r($tree);
print '</pre>';
So here you change the code according to your needs. Print it in the way you want (may be you will need recurrsion to access every tree node)

MySQL query on table structure to make JSON friendly format

I want to have a result like this, to expand all nodes and make a defined treeview.
var defaultData = [
{
text: 'Parent 1',
href: '#parent1',
tags: ['4'],
nodes: [
{
text: 'Child 1',
href: '#child1',
tags: ['2'],
nodes: [
{
text: 'Grandchild 1',
href: '#grandchild1',
tags: ['0']
},
{
text: 'Grandchild 2',
href: '#grandchild2',
tags: ['0']
}
]
},
{
text: 'Child 2',
href: '#child2',
tags: ['0']
}
]
},
{
text: 'Parent 2',
href: '#parent2',
tags: ['0']
},
{
text: 'Parent 3',
href: '#parent3',
tags: ['0']
},
{
text: 'Parent 4',
href: '#parent4',
tags: ['0']
},
{
text: 'Parent 5',
href: '#parent5' ,
tags: ['0']
}
];
I've create a table like this, is it correct?
and how to query them in order to have result as above by json_encode the result?
First of all, you need to fix your table. It is highly irregular and text values will not work well with matching in any language. Try a table like this:
------------------------------
| id | parent | desc |
------------------------------
| 1 | 0 | parent 1 |
------------------------------
| 2 | 0 | parent 2 |
------------------------------
| 3 | 0 | parent 1 |
------------------------------
| 4 | 0 | parent 2 |
------------------------------
| 5 | 0 | parent 1 |
------------------------------
| 6 | 1 | child 1 |
------------------------------
| 7 | 1 | child 2 |
------------------------------
| 8 | 6 | Grandchild 1 |
------------------------------
| 9 | 6 | Grandchild 2 |
------------------------------
id and parent should be integer fields and desc can be text/varchar. Root or top level items should have a parent value of zero (0).
Then you can use a script similar to:
$db = new mysqli('127.0.0.1', 'your_db_user', 'your_secure_password', 'your_db_schema');
if( $mysqli->connect_error ) {
echo 'Something went wrong: ' . $mysqli->connect_error;
}
$json = [];
function sanitize_id($id) {
return preg_replace( '/[^a-z0-9]/', '', strtolower($id) );
}
function recursive( $parentId, &$json ) {
global $mysqli;
if ($stmt = $mysqli->prepare("SELECT * FROM your-table WHERE parent = ?")) {
// Bind parent id to query
$stmt->bind_param('i', $parentId);
$results = $stmt->execute();
// Loop over results
while ( $result = $results->fetch_assoc() ) {
// Add result to JSON structure at referenced location
$json[] = [
'text' => $result['desc'],
'href' => '#' . sanitize_id($result['desc']),
'tags' => ['0'], // Are the tags another field?
'nodes' => []
];
// Rerun recusive function to check for and add any children
recursive( $result['id'], $json['nodes'] );
}
$stmt->close();
}
};
recursive(0, $json);
echo json_encode( $json );
$db->close();

Categories