Dealing with nested sets in mysql? - php

I have decided to follow http://www.artfulsoftware.com/mysqlbook/sampler/mysqled1ch20.html
So now I am looking for some help with the code.
I am using their data for my testing,
So, I visualized the tree being like so:
array('value' => 'Richard Shakespeare',
array('value' => 'Henry',
array('value' => 'Joan'),
array('value' => 'Margaret'),
array('value' => 'William',
array('value' => 'Susana',
array('value' => 'Elizabeth Hall',
array('value' => 'John Bernard'))),
array('value' => 'Hamnet'),
array('value' => 'Judith',
array('value' => 'Shakespeare Quiney'),
array('value' => 'Richard Quiney'),
array('value' => 'Thomas Quiney'))),
array('value' => 'Gilbert'),
array('value' => 'Joan',
array('value' => 'William Hart'),
array('value' => 'Mary Hart'),
array('value' => 'Thomas Hart'),
array('value' => 'Micheal Hart')),
array('value' => 'Anne'),
array('value' => 'Richard'),
array('value' => 'Edmond')),
array('value' => 'John'));
So if we want to insert that into the database we want to end up with
Array
(
[0] => Array
(
[value] => Richard Shakespeare
[left] => 1
[right] => 46
)
[1] => Array
(
[value] => Henry
[left] => 2
[right] => 43
)
[2] => Array
(
[value] => Joan
[left] => 3
[right] => 4
)
[3] => Array
(
[value] => Margaret
[left] => 5
[right] => 6
)
[4] => Array
(
[value] => William
[left] => 7
[right] => 24
)
[5] => Array
(
[value] => Susana
[left] => 8
[right] => 13
)
[6] => Array
(
[value] => Elizabeth Hall
[left] => 9
[right] => 12
)
[7] => Array
(
[value] => John Bernard
[left] => 10
[right] => 11
)
[8] => Array
(
[value] => Hamnet
[left] => 14
[right] => 15
)
[9] => Array
(
[value] => Judith
[left] => 16
[right] => 23
)
[10] => Array
(
[value] => Shakespeare Quiney
[left] => 17
[right] => 18
)
[11] => Array
(
[value] => Richard Quiney
[left] => 19
[right] => 20
)
[12] => Array
(
[value] => Thomas Quiney
[left] => 21
[right] => 22
)
[13] => Array
(
[value] => Gilbert
[left] => 25
[right] => 26
)
[14] => Array
(
[value] => Joan
[left] => 27
[right] => 36
)
[15] => Array
(
[value] => William Hart
[left] => 28
[right] => 29
)
[16] => Array
(
[value] => Mary Hart
[left] => 30
[right] => 31
)
[17] => Array
(
[value] => Thomas Hart
[left] => 32
[right] => 33
)
[18] => Array
(
[value] => Micheal Hart
[left] => 34
[right] => 35
)
[19] => Array
(
[value] => Anne
[left] => 37
[right] => 38
)
[20] => Array
(
[value] => Richard
[left] => 39
[right] => 40
)
[21] => Array
(
[value] => Edmond
[left] => 41
[right] => 42
)
[22] => Array
(
[value] => John
[left] => 44
[right] => 45
)
)
So the issue comes to mind of, How best to do this?
My solution was:
$container = array();
function children($item){
$children = 0;
foreach($item as $node)
if(is_array($node))
$children += children($node)+1;
return $children;
}
function calculate($item, &$container, $data = array(0,0)){
//althought this one is actually of no use, it could be useful as it contains a count
$data[0]++; //$left
$right = ($data[0]+(children($item)*2))+1;
//store the values in the passed container
$container[] = array(
'value' => $item['value'],
'left' => $data[0],
'right' => $right,
);
//continue looping
$level = $data[1]++;
foreach($item as &$node)
if(is_array($node))
$data = calculate($node, $container, $data);
$data[1] = $level;
$data[0]++;
return $data;
}
calculate($tree, $container);
How efficient it is I do not know.
But now onto the queries.
To select all descendants of a node we can use
SELECT child.value AS 'Descendants of William', COUNT(*) AS `Level`
FROM tester AS parent
JOIN tester AS child ON child.`left` BETWEEN parent.`left` AND parent.`right`
WHERE parent.`left` > 7 AND parent.`right` < 24
GROUP BY child.value ORDER BY `level`;
To select all descendants of a node, to a specific depth we can use
Note that we are selecting Descendants of William to a depth of 2
Williams left: 7, Williams right: 24, Levels: 2
SELECT child.value AS 'Descendants of William', COUNT(*) AS `Level`
FROM tester AS parent
JOIN tester AS child ON child.`left` BETWEEN parent.`left` AND parent.`right`
WHERE parent.`left` > 7 AND parent.`right` < 24
GROUP BY child.value HAVING `level` <= 2 ORDER BY `level`;
So that's easy enough.
But now I want to know a few things,
Note that in the actual database as well as left/right all rows have a unique id, and a "parent" column containing their inviteers id, or null if not invited
Lets say I want to insert David as a child of Judith, How do I do that?
Lets say I want to get Mary Hart's Parent, and the Parents Parent (array('Henery', 'Joan', 'Mary Hart')), How do I do that?
Lets say I want to delete William Hart from Joan How so I do that?

To update/delete you will need to increase/decrease left/right values of all elements of branch.
Examples of queries you can find here.
How efficient it is I do not know.
Nested sets works VERY slowly with big trees on update/insert/delete. And very fast to select.
So use this model only with static data, which will be stored without changes most of the time, and this tree will not contain thousands of nodes (or any update will take minutes to complete). Materialized path works much faster.

to get the parents of a node you need nodes with left_id < child.left_id and right_id > child.right_id, if you only want the direct ancestor choose the one from previous set with the highest left_id.
to delete a node remove it and then lower twice all left/right ids that are greater than deleted element right id. if( leftId > deleted.leftId ) leftId-=2 same for rightId
to insert a node make some space for it adding+2 to all nodes with leftId > parent.rightId then parent.rightId += 2 then insert node with leftId = parent.rightId-2 and rightId=parent.rightId-1

All of your questions can be solved very easy if you use a DFS for each relationship and then use your function calculate() again if you want it more detailed.

Related

How to create html table dynamically using loop in PHP?

I want to display result in html table of array data using php foreach or for loop. I have placed array below. In the array there is field 'bs_column' and it values can be 12, 6 or 4. In the loop I want to display one td in each tr(one column in each row) if bs_column is equal 12 and two td in each tr(two column in each row) if bs_column==6 and three td in each tr (three column in each row) if bs_column==4.
In case if not paired bs_column==6 which are two fields (<tr><td>field one</td><td>field two</td></tr>) in loop sequence then need to one column in a row (<tr><td>single field</td></tr>).
In case if not paired bs_column==4 which are three fields (<tr><td>field one</td><td>field two</td><td>field three</td></tr>) in loop sequence then make two fields (<tr><td>field one</td><td>field two</td></tr>) pair if not pair then make single field (<tr><td>single field</td></tr>) in column in row.
Array is
$fields= Array ( [0] => Array ( [id] => 1 [form_id] => 3 [name] => THE APPLICANT [slug] => customers_the-applicant_heading [required] => 0 [type] => heading [options] => [field_order] => 0 [bs_column] => 12 ) [1] => Array ( [id] => 2 [form_id] => 3 [name] => Applicant(s) Name [slug] => customers_applicants-name_input [required] => 0 [type] => input [options] => [field_order] => 1 [bs_column] => 12 ) [2] => Array ( [id] => 3 [form_id] => 3 [name] => Email [slug] => customers_email_input [required] => 0 [type] => input [options] => [field_order] => 2 [bs_column] => 6 ) [3] => Array ( [id] => 4 [form_id] => 3 [name] => Telephone [slug] => customers_telephone_input [required] => 0 [type] => input [options] => [field_order] => 3 [bs_column] => 6 ) [4] => Array ( [id] => 5 [form_id] => 3 [name] => s this Property currently insured? [slug] => customers_s-this-property-currently-insured_checkbox [required] => 0 [type] => select [options] => Yes,No [field_order] => 4 [bs_column] => 12 ) [5] => Array ( [id] => 6 [form_id] => 3 [name] => Name of insurer(s) [slug] => customers_name-of-insurers_input [required] => 0 [type] => input [options] => [field_order] => 5 [bs_column] => 6 ) [6] => Array ( [id] => 7 [form_id] => 3 [name] => Current insurer expiry date [slug] => customers_current-insurer-expiry-date_date_picker [required] => 0 [type] => date_picker [options] => [field_order] => 6 [bs_column] => 6 ) [7] => Array ( [id] => 8 [form_id] => 3 [name] => D.O.B. of eldest insured [slug] => customers_dob-of-eldest-insured_date_picker [required] => 0 [type] => date_picker [options] => [field_order] => 7 [bs_column] => 6 ) [8] => Array ( [id] => 9 [form_id] => 3 [name] => Applicant postal address [slug] => customers_applicant-postal-address_input [required] => 0 [type] => textarea [options] => [field_order] => 8 [bs_column] => 12 ) [9] => Array ( [id] => 10 [form_id] => 3 [name] => Suburb [slug] => customers_suburb_input [required] => 0 [type] => input [options] => [field_order] => 9 [bs_column] => 4 ) [10] => Array ( [id] => 11 [form_id] => 3 [name] => State [slug] => customers_state_input [required] => 0 [type] => input [options] => [field_order] => 10 [bs_column] => 4 ) [11] => Array ( [id] => 12 [form_id] => 3 [name] => Postcode [slug] => customers_postcode_input [required] => 0 [type] => input [options] => [field_order] => 11 [bs_column] => 4 ) [12] => Array ( [id] => 13 [form_id] => 3 [name] => PERIOD OF INSURANCE [slug] => customers_period-of-insurance_heading [required] => 0 [type] => heading [options] => [field_order] => 12 [bs_column] => 12 ) [13] => Array ( [id] => 14 [form_id] => 3 [name] => Cover required From [slug] => customers_cover-required-from_input [required] => 0 [type] => input [options] => [field_order] => 13 [bs_column] => 6 ) [14] => Array ( [id] => 15 [form_id] => 3 [name] => Cover required to [slug] => customers_cover-required-to_input [required] => 0 [type] => input [options] => [field_order] => 14 [bs_column] => 6 ) [15] => Array ( [id] => 16 [form_id] => 3 [name] => INSURED DETAILS [slug] => customers_insured-details_heading [required] => 0 [type] => heading [options] => [field_order] => 15 [bs_column] => 12 ) [16] => Array ( [id] => 17 [form_id] => 3 [name] => What are the premises you wish to insure? [slug] => customers_what-are-the-premises-you-wish-to-insure-_note [required] => 0 [type] => note [options] => [field_order] => 16 [bs_column] => 12 ) [17] => Array ( [id] => 18 [form_id] => 3 [name] => Address of property [slug] => customers_address-of-property_input [required] => 0 [type] => input [options] => [field_order] => 17 [bs_column] => 12 ) [18] => Array ( [id] => 19 [form_id] => 3 [name] => CONSTRUCTION DETAILS [slug] => customers_construction-details_heading [required] => 0 [type] => heading [options] => [field_order] => 21 [bs_column] => 12 ) [19] => Array ( [id] => 20 [form_id] => 3 [name] => Cover type required [slug] => customers_cover-type-required_checkbox [required] => 0 [type] => checkbox [options] => Specified events,Accidental damage (specified events + accidental damage) [field_order] => 22 [bs_column] => 12 ) [20] => Array ( [id] => 23 [form_id] => 3 [name] => Year built [slug] => customers_year-built_date_picker [required] => 0 [type] => date_picker [options] => [field_order] => 25 [bs_column] => 6 ) [21] => Array ( [id] => 24 [form_id] => 3 [name] => Number of storeys [slug] => customers_number-of-storeys_input [required] => 0 [type] => input [options] => [field_order] => 26 [bs_column] => 6 ) [22] => Array ( [id] => 25 [form_id] => 3 [name] => Is the building elevated or multi storey? [slug] => customers_is-the-building-elevated-or-multi-storey_checkbox [required] => 0 [type] => checkbox [options] => Single storey,Single storey elevated,Double storey,Three or more storey [field_order] => 27 [bs_column] => 12 ) [23] => Array ( [id] => 26 [form_id] => 3 [name] => Is the property well maintained structurally sound and secured against wind and rain? [slug] => customers_is-the-property-well-maintained-structurally-sound-and-secured-against-wind-and-rain_checkbox [required] => 0 [type] => checkbox [options] => Yes,No [field_order] => 28 [bs_column] => 12 ) [24] => Array ( [id] => 27 [form_id] => 3 [name] => Is the property undergoing renovations over $75,000, OR, under construction, OR, to be demolished? [slug] => customers_is-the-property-undergoing-renovations-over-75000-or-under-construction-or-to-be-demolished_checkbox [required] => 0 [type] => checkbox [options] => Yes,No [field_order] => 29 [bs_column] => 12 ) [25] => Array ( [id] => 28 [form_id] => 3 [name] => Is your home location on a site exceeding 20,000 square metres? [slug] => customers_is-your-home-location-on-a-site-exceeding-20000-square-metres_checkbox [required] => 0 [type] => checkbox [options] => Yes,No [field_order] => 30 [bs_column] => 12 ) [26] => Array ( [id] => 29 [form_id] => 3 [name] => Has the land where the building or contents are been flooded or inundated by water more than once in the last 10 years? [slug] => customers_has-the-land-where-the-building-or-contents-are-been-flooded-or-inundated-by-water-more-than-once-in-the-last-10-years_checkbox [required] => 0 [type] => checkbox [options] => Yes,No [field_order] => 31 [bs_column] => 12 ) [27] => Array ( [id] => 30 [form_id] => 3 [name] => Is there a pool on your property? [slug] => customers_is-there-a-pool-on-your-property_checkbox [required] => 0 [type] => checkbox [options] => Yes,No [field_order] => 32 [bs_column] => 6 ) [28] => Array ( [id] => 31 [form_id] => 3 [name] => Building type: [slug] => customers_building-type_checkbox [required] => 0 [type] => checkbox [options] => House on slab/foundation,House on poles,Villa/Townhouse,Unit/Flat,Terrace/semi,Course of construction,Granny flat,Heritage property,Holiday home,Mobile home,Display home,Nursing home Caravan,Retirement village [field_order] => 33 [bs_column] => 12 ) [29] => Array ( [id] => 32 [form_id] => 3 [name] => Floor Construction: [slug] => customers_floor-construction_checkbox [required] => 0 [type] => checkbox [options] => Concrete,Wood [field_order] => 31 [bs_column] => 6 ) [30] => Array ( [id] => 34 [form_id] => 3 [name] => Wall construction:If mixed construction, please detail % of each [slug] => customers_wall-constructionif-mixed-construction-please-detail-of-each_checkbox [required] => 0 [type] => checkbox [options] => Double Brick Timber/,Brick Veneer Steel,Weatherboard,Fibro/Asbestos,Concrete/Hebel,Stone/ Sandstone,Cement,Polystyrene/EP,Mud brick [field_order] => 33 [bs_column] => 12 ) [31] => Array ( [id] => 35 [form_id] => 3 [name] => other [slug] => customers_other_input [required] => 0 [type] => input [options] => [field_order] => 34 [bs_column] => 12 ) [32] => Array ( [id] => 36 [form_id] => 3 [name] => Roof: [slug] => customers_roof_checkbox [required] => 0 [type] => checkbox [options] => Cement Tiles,Iron,Slate,Terracotta,Colour bond,Steel,Wood [field_order] => 35 [bs_column] => 12 ) [33] => Array ( [id] => 37 [form_id] => 3 [name] => other [slug] => customers_other_input [required] => 0 [type] => input [options] => [field_order] => 36 [bs_column] => 12 ) [34] => Array ( [id] => 38 [form_id] => 3 [name] => Sandwich Foam Panel construction (EPS) [slug] => customers_sandwich-foam-panel-construction-eps_checkbox [required] => 0 [type] => checkbox [options] => Yes,No [field_order] => 37 [bs_column] => 6 ) [35] => Array ( [id] => 39 [form_id] => 3 [name] => If yes, percentage % [slug] => customers_if-yes-percentage-_input [required] => 0 [type] => input [options] => [field_order] => 38 [bs_column] => 6 ) )`
php code
$max_six_per_row = 2;
$max_four_per_row = 3;
$item_count_two = 0;
$item_count_three = 0;
$fields_html .= '<table><tbody>';
foreach ($fields as $field) {
$field['name'] = $field['name'];
if ($field['bs_column'] == 12) {
$fields_html .="<tr><td width='100%'>".$field['name'] ."</td></tr>";
}
if ($field['bs_column'] == 6) {
if ($item_count_two == 0)
{
$fields_html .="<tr>";
}
$fields_html .="<td width='50%'>".$field['name'] ."</td>";
if ($item_count_two == $max_six_per_row)
{
$fields_html .="</tr>";
$item_count_two = 0;
}
$item_count_two++;
}
if ($field['bs_column'] == 4) {
if ($item_count_three == 0)
{
$fields_html .="<tr>";
}
$fields_html .="<td>".$field['name'] ."</td>";
if ($item_count_three == $max_four_per_row)
{
$fields_html .="</tr>";
$item_count_three = 0;
}
$item_count_three++;
}
}
$fields_html .= '</tbody></table>';
echo $fields_html;
Ok, here is a 1st draft. I need a better understanding of field2 and field3. Do they come from the same field name from different rows? Or is field from the same row? Depending on your answer this code logic might change.
<!DOCTYPE HTML>
<html lang="en">
<head>
<title>Loop Test</title>
</head>
<body>
<?php
$rows = json_decode('[{"id":"21","name":"THE APPLICANT","req":"0","type":"heading","opt":"","f_ord":"0","b_c":"12","val":""},{"id":"22","name":"Applicant(s) Name","req":"0","type":"input","opt":"","f_ord":"1","b_c":"12","val":"Ali Hasan"},{"id":"23","name":"Email","req":"0","type":"input","opt":"","f_ord":"2","b_c":"6","val":"ghulamseratalikhan#gmail.com"},{"id":"24","name":"Telephone","req":"0","type":"input","opt":"","f_ord":"3","b_c":"6","val":"03100865443"},{"id":"25","name":"s this Property currently insured?","req":"0","type":"checkbox","opt":"Yes,No","f_ord":"4","b_c":"12","val":"No"},{"id":"26","name":"Name of insurer(s)","req":"0","type":"input","opt":"","f_ord":"5","b_c":"6","val":"Insurer Name"},{"id":"27","name":"Current insurer expiry date","req":"0","type":"date_picker","opt":"","f_ord":"6","b_c":"6","val":"2021-08-20 00:00:00"},{"id":"28","name":"D.O.B. of eldest insured","req":"0","type":"date_picker","opt":"","f_ord":"7","b_c":"6","val":"2006-08-24 00:00:00"},{"id":"29","name":"Applicant postal address","req":"0","type":"input","opt":"","f_ord":"8","b_c":"12","val":"1535 service road g-11\/2 Islamabad first floor"},{"id":"30","name":"Suburb","req":"0","type":"input","opt":"","f_ord":"9","b_c":"12","val":"Capital Terriority"},{"id":"31","name":"State","req":"0","type":"input","opt":"","f_ord":"10","b_c":"6","val":"Capital"},{"id":"32","name":"Postcode","req":"0","type":"input","opt":"","f_ord":"11","b_c":"6","val":"58000"},{"id":"33","name":"PERIOD OF INSURANCE","req":"0","type":"heading","opt":"","f_ord":"12","b_c":"12","val":""},{"id":"34","name":"Cover required From","req":"0","type":"input","opt":"","f_ord":"13","b_c":"6","val":"Rashid Ali"},{"id":"35","name":"Cover required to","req":"0","type":"input","opt":"","f_ord":"14","b_c":"6","val":"Hasan Ali"},{"id":"36","name":"INSURED DETAILS","req":"0","type":"heading","opt":"","f_ord":"15","b_c":"12","val":""},{"id":"37","name":"What are the premises you wish to insure? ","req":"0","type":"note","opt":"","f_ord":"16","b_c":"12","val":""},{"id":"38","name":"Address of property","req":"0","type":"input","opt":"","f_ord":"17","b_c":"12","val":"F-10\/4 house 45 street 345 near F-10 marakaz"},{"id":"39","name":"CONSTRUCTION DETAILS","req":"0","type":"heading","opt":"","f_ord":"21","b_c":"12","val":""},{"id":"40","name":"Cover type required","req":"0","type":"checkbox","opt":"Specified events","f_ord":"22","b_c":"4","val":""},{"id":"41","name":"OR ","req":"0","type":"note","opt":"","f_ord":"23","b_c":"4","val":""},{"id":"42","name":"","req":"0","type":"checkbox","opt":"Accidental damage (specified events + accidental damage)","f_ord":"24","b_c":"4","val":"Accidental damage (specified events + accidental damage)"},{"id":"43","name":"Year built","req":"0","type":"date_picker","opt":"","f_ord":"25","b_c":"6","val":"2014-08-22 00:00:00"},{"id":"44","name":"Number of storeys","req":"0","type":"input","opt":"","f_ord":"26","b_c":"6","val":"3"},{"id":"45","name":"Is the building elevated or multi storey?","req":"0","type":"checkbox","opt":"Single storey,Single storey elevated,Double storey,Three or more storey","f_ord":"27","b_c":"12","val":"Double storey, Three or more storey"},{"id":"46","name":"Is the property well maintained structurally sound and secured against wind and rain?","req":"0","type":"checkbox","opt":"Yes,No","f_ord":"28","b_c":"12","val":"Yes"},{"id":"47","name":"Is the property undergoing renovations over $75,000, OR, under construction, OR, to be demolished?","req":"0","type":"checkbox","opt":"Yes,No","f_ord":"29","b_c":"12","val":"Yes"},{"id":"48","name":"Is your home location on a site exceeding 20,000 square metres?","req":"0","type":"checkbox","opt":"Yes,No","f_ord":"30","b_c":"12","val":"No"},{"id":"49","name":"Has the land where the building or contents are been flooded or inundated by water more than once in the last 10 years?","req":"0","type":"checkbox","opt":"Yes,No","f_ord":"31","b_c":"12","val":"Yes"},{"id":"50","name":"Is there a pool on your property?","req":"0","type":"checkbox","opt":"Yes,No","f_ord":"32","b_c":"12","val":"Yes"},{"id":"51","name":"Building type:","req":"0","type":"checkbox","opt":"House on slab\/foundation,House on poles,Villa\/Townhouse,Unit\/Flat,Terrace\/semi,Course of construction,Granny flat,Heritage property,Holiday home,Mobile home,Display home,Nursing home Caravan,Retirement village","f_ord":"33","b_c":"12","val":"House on poles, Unit\/Flat, Holiday home, Mobile home, Display home"},{"id":"52","name":"Floor Construction:","req":"0","type":"checkbox","opt":"Concrete,Wood","f_ord":"31","b_c":"6","val":"Concrete, Wood"},{"id":"53","name":"Other","req":"0","type":"input","opt":"","f_ord":"32","b_c":"6","val":"Marble Sfloor"},{"id":"54","name":"Wall construction:If mixed construction, please detail % of each<\/small>","req":"0","type":"checkbox","opt":"Double Brick Timber\/,Brick Veneer Steel,Weatherboard,Fibro\/Asbestos,Concrete\/Hebel,Stone\/ Sandstone,Cement,Polystyrene\/EP,Mud brick","f_ord":"33","b_c":"12","val":"Weatherboard, Fibro\/Asbestos, Cement, Mud brick"},{"id":"55","name":"other","req":"0","type":"input","opt":"","f_ord":"34","b_c":"12","val":"Mud bv construction"},{"id":"56","name":"Roof:","req":"0","type":"checkbox","opt":"Cement Tiles,Iron,Slate,Terracotta,Colour bond,Steel,Wood","f_ord":"35","b_c":"12","val":"Cement Tiles, Slate, Colour bond"},{"id":"57","name":"other","req":"0","type":"input","opt":"","f_ord":"36","b_c":"12","val":"steael wooddd roof"},{"id":"58","name":"Sandwich Foam Panel construction (EPS)","req":"0","type":"checkbox","opt":"Yes,No","f_ord":"37","b_c":"4","val":"Yes"},{"id":"59","name":"If yes, percentage %","req":"0","type":"input","opt":"","f_ord":"38","b_c":"4","val":"45%"}]', true);
//$max_cols = 3;
//$max_tds = 1;
echo("<table>" . PHP_EOL);
echo(" <tbody>" . PHP_EOL);
foreach($rows as $key => $row)
{
echo(" <tr>" . PHP_EOL);
switch($row["b_c"])
{
case 4:
echo(" <td>{$row['name']}</td><td>{$row['name']}</td><td>{$row['name']}</td>" . PHP_EOL);
// $max_tds = 3;
break;
case 6:
echo(" <td>{$row['name']}</td><td>{$row['name']}</td><td></td>" . PHP_EOL);
// $max_tds = 2;
break;
case 12:
echo(" <td>{$row['name']}</td><td></td><td></td>" . PHP_EOL);
// $max_tds = 1;
break;
default:
echo(" <td>{$row['name']}</td><td></td><td></td>" . PHP_EOL);
break;
}
echo(" </tr>" . PHP_EOL);
// echo("Key: " . $key . PHP_EOL);
// print_r($row);
}
echo(" </tbody>" . PHP_EOL);
echo("</table>" . PHP_EOL);
?>
</body>
</html>
Once I have a better understanding I can help change this code.
Table displayed correct output. In foreach loop first need to check $field['b_c']==6
,the this check if two tds paired inside a tr then close the tr and if not paired and source data has single consecutive $field['b_c']==6 row then also close tr. 2nd need to check if $field['b_c']==4 and close tr if rows less than three or equal to three.
For $field['b_c']==12 just one row and one column.
<!DOCTYPE HTML>
<html lang="en">
<head>
<title>Loop Test</title>
<style>
.table{
/*width:100%;*/
border-collapse:collapse;
border:1px solid #ccc;
margin:30px;
padding:8px;
}
.table tr,.table tr>td{
border:1px solid #ccc;
padding:5px;
}
</style>
</head>
<body>
<?php
$rows = json_decode('[{"id":"21","name":"THE APPLICANT","req":"0","type":"heading","opt":"","f_ord":"0","b_c":"12","val":""},{"id":"22","name":"Applicant(s) Name","req":"0","type":"input","opt":"","f_ord":"1","b_c":"12","val":"Ali Hasan"},{"id":"23","name":"Email","req":"0","type":"input","opt":"","f_ord":"2","b_c":"6","val":"ghulamseratalikhan#gmail.com"},{"id":"24","name":"Telephone","req":"0","type":"input","opt":"","f_ord":"3","b_c":"6","val":"03100865443"},{"id":"25","name":"s this Property currently insured?","req":"0","type":"checkbox","opt":"Yes,No","f_ord":"4","b_c":"12","val":"No"},{"id":"26","name":"Name of insurer(s)","req":"0","type":"input","opt":"","f_ord":"5","b_c":"6","val":"Insurer Name"},{"id":"27","name":"Current insurer expiry date","req":"0","type":"date_picker","opt":"","f_ord":"6","b_c":"6","val":"2021-08-20 00:00:00"},{"id":"28","name":"D.O.B. of eldest insured","req":"0","type":"date_picker","opt":"","f_ord":"7","b_c":"6","val":"2006-08-24 00:00:00"},{"id":"29","name":"Applicant postal address","req":"0","type":"input","opt":"","f_ord":"8","b_c":"12","val":"1535 service road g-11\/2 Islamabad first floor"},{"id":"30","name":"Suburb","req":"0","type":"input","opt":"","f_ord":"9","b_c":"12","val":"Capital Terriority"},{"id":"31","name":"State","req":"0","type":"input","opt":"","f_ord":"10","b_c":"6","val":"Capital"},{"id":"32","name":"Postcode","req":"0","type":"input","opt":"","f_ord":"11","b_c":"6","val":"58000"},{"id":"33","name":"PERIOD OF INSURANCE","req":"0","type":"heading","opt":"","f_ord":"12","b_c":"12","val":""},{"id":"34","name":"Cover required From","req":"0","type":"input","opt":"","f_ord":"13","b_c":"6","val":"Rashid Ali"},{"id":"35","name":"Cover required to","req":"0","type":"input","opt":"","f_ord":"14","b_c":"6","val":"Hasan Ali"},{"id":"36","name":"INSURED DETAILS","req":"0","type":"heading","opt":"","f_ord":"15","b_c":"12","val":""},{"id":"37","name":"What are the premises you wish to insure? ","req":"0","type":"note","opt":"","f_ord":"16","b_c":"12","val":""},{"id":"38","name":"Address of property","req":"0","type":"input","opt":"","f_ord":"17","b_c":"12","val":"F-10\/4 house 45 street 345 near F-10 marakaz"},{"id":"39","name":"CONSTRUCTION DETAILS","req":"0","type":"heading","opt":"","f_ord":"21","b_c":"12","val":""},{"id":"40","name":"Cover type required","req":"0","type":"checkbox","opt":"Specified events","f_ord":"22","b_c":"4","val":""},{"id":"41","name":"OR ","req":"0","type":"note","opt":"","f_ord":"23","b_c":"4","val":""},{"id":"42","name":"","req":"0","type":"checkbox","opt":"Accidental damage (specified events + accidental damage)","f_ord":"24","b_c":"4","val":"Accidental damage (specified events + accidental damage)"},{"id":"43","name":"Year built","req":"0","type":"date_picker","opt":"","f_ord":"25","b_c":"6","val":"2014-08-22 00:00:00"},{"id":"44","name":"Number of storeys","req":"0","type":"input","opt":"","f_ord":"26","b_c":"6","val":"3"},{"id":"45","name":"Is the building elevated or multi storey?","req":"0","type":"checkbox","opt":"Single storey,Single storey elevated,Double storey,Three or more storey","f_ord":"27","b_c":"12","val":"Double storey, Three or more storey"},{"id":"46","name":"Is the property well maintained structurally sound and secured against wind and rain?","req":"0","type":"checkbox","opt":"Yes,No","f_ord":"28","b_c":"12","val":"Yes"},{"id":"47","name":"Is the property undergoing renovations over $75,000, OR, under construction, OR, to be demolished?","req":"0","type":"checkbox","opt":"Yes,No","f_ord":"29","b_c":"12","val":"Yes"},{"id":"48","name":"Is your home location on a site exceeding 20,000 square metres?","req":"0","type":"checkbox","opt":"Yes,No","f_ord":"30","b_c":"12","val":"No"},{"id":"49","name":"Has the land where the building or contents are been flooded or inundated by water more than once in the last 10 years?","req":"0","type":"checkbox","opt":"Yes,No","f_ord":"31","b_c":"12","val":"Yes"},{"id":"50","name":"Is there a pool on your property?","req":"0","type":"checkbox","opt":"Yes,No","f_ord":"32","b_c":"12","val":"Yes"},{"id":"51","name":"Building type:","req":"0","type":"checkbox","opt":"House on slab\/foundation,House on poles,Villa\/Townhouse,Unit\/Flat,Terrace\/semi,Course of construction,Granny flat,Heritage property,Holiday home,Mobile home,Display home,Nursing home Caravan,Retirement village","f_ord":"33","b_c":"12","val":"House on poles, Unit\/Flat, Holiday home, Mobile home, Display home"},{"id":"52","name":"Floor Construction:","req":"0","type":"checkbox","opt":"Concrete,Wood","f_ord":"31","b_c":"6","val":"Concrete, Wood"},{"id":"53","name":"Other","req":"0","type":"input","opt":"","f_ord":"32","b_c":"6","val":"Marble Sfloor"},{"id":"54","name":"Wall construction:If mixed construction, please detail % of each<\/small>","req":"0","type":"checkbox","opt":"Double Brick Timber\/,Brick Veneer Steel,Weatherboard,Fibro\/Asbestos,Concrete\/Hebel,Stone\/ Sandstone,Cement,Polystyrene\/EP,Mud brick","f_ord":"33","b_c":"12","val":"Weatherboard, Fibro\/Asbestos, Cement, Mud brick"},{"id":"55","name":"other","req":"0","type":"input","opt":"","f_ord":"34","b_c":"12","val":"Mud bv construction"},{"id":"56","name":"Roof:","req":"0","type":"checkbox","opt":"Cement Tiles,Iron,Slate,Terracotta,Colour bond,Steel,Wood","f_ord":"35","b_c":"12","val":"Cement Tiles, Slate, Colour bond"},{"id":"57","name":"other","req":"0","type":"input","opt":"","f_ord":"36","b_c":"12","val":"steael wooddd roof"},{"id":"58","name":"Sandwich Foam Panel construction (EPS)","req":"0","type":"checkbox","opt":"Yes,No","f_ord":"37","b_c":"4","val":"Yes"},{"id":"59","name":"If yes, percentage %","req":"0","type":"input","opt":"","f_ord":"38","b_c":"4","val":"45%"}]', true);
//count tds inside a rows when 'b_c'=6 or 'b_c'=4.
$tempSixCount = 0;
$tempfourCount = 0;
$table='<table class="table"><tbody>';
foreach ($rows as $k=>$field) {
$field_name = $field['name'];
$value = $field['val'];
if ($field['b_c'] == '' || $field['b_c'] == 0) {
$field['b_c'] = 12;
}
//first check if b_c=6
if($field['b_c'] == 6){
//opening tr #row start here for b_c=6
if($tempSixCount==0){
$table .='<tr>';
}
$table .='<td colspan="2"><strong>'.$field_name.':</strong> '.$value.'</td>';
//increasing tds inside tr for b_c=6
$tempSixCount++;
//second check if b_c=4
}elseif($field['b_c'] == 4){
//opening tr #row start here for b_c=4
if($tempfourCount==0){
$table .='<tr>';
}
$table .='<td colspan=""><strong>'.$field_name.':</strong> '.$value.'</td>';
//increasing tds inside tr for b_c=4
$tempfourCount++;
//on else condition it will check b_c=12 and also close tr for above b_c=6 and b_c=4
}else{
//here check if for b_c=6 has not pair of two tds inside a tr and has single td then clsoe tr and start again counting tds from 0.
if($tempSixCount>0)
{
$table .='</tr>';
$tempSixCount = 0;
}
//here check if for b_c=4 has not pair of three tds inside a tr and has single td or two tds then clsoe tr and start again counting tds from 0.
if($tempfourCount>0)
{
$table .='</tr>';
$tempfourCount = 0;
}
// open and clsoe tr having single tds bcoz b_c=12 has one row and one column
if($field['b_c'] == 12)
{
$table .='<tr><td colspan="3"><strong>'.$field_name.':</strong> '.$value.'</td></tr>';
}
}
//here check if for b_c=6 has pair of two tds inside a tr then clsoe tr and start again counting tds from 0.
if ($tempSixCount == 2)
{
$table .='</tr>';
$tempSixCount = 0;
}
//here check if for b_c=4 has pair of three tds inside a tr then clsoe tr and start again counting tds from 0.
if ($tempfourCount == 3)
{
$table .='</tr>';
$tempfourCount = 0;
}
}
$table .='</tbody></table>';
echo $table;
?>
</body>
</html>

search inside arrays with condition in php

I have an api with a list of arrays inside one array and each array inside this array it has one key [attributes] and inside this key one array with key [CITY_NAME]
this is my array coming from api
this array number is 0 but every day this number is changed and my figures come wrong, what is the good way to always have my city figures using the key [CITY_NAME]
I am fetching the data using this code
$json = file_get_contents($url);
$json_data = json_decode($json, true);
$data = $json_data['features'];
$mycity = $data[0]['attributes'];
Array
(
[0] => Array
(
[attributes] => Array
(
[CITY_NAME] => city1
[Name] => city1
[ADMIN_NAME] => city1
[POP_CLASS] => 5,000,000 to10,000,000
[Population] => 7676654
[Population_Data_Source] => Wikipedia
[Population_Data_Date] => 2018
[CityID] => 14
[Longitude] => 46.7614868685786
[Latitude] => 24.7388786516234
[Confirmed] => 0
[Recovered] => 0
[Deaths] => 0
[Active] => 0
[Tested] => 0
[Name_Eng] => city1
[Join_Count] => 61
[Confirmed_SUM] => 5152
[Deaths_SUM] => 9
[Recovered_SUM] => 1407
[Active_SUM] => 3736
[Tested_SUM] => 376607
[ObjectId] => 14
)
)
[1] => Array
(
[attributes] => Array
(
[CITY_NAME] => city2
[Name] => city2
[ADMIN_NAME] => city2
[POP_CLASS] => 1,000,000 to 5,000,000
[Population] => 1675368
[Population_Data_Source] => Wikipedia
[Population_Data_Date] => 2010
[CityID] => 9
[Longitude] => 39.8148987363852
[Latitude] => 21.4273876500039
[Confirmed] => 0
[Recovered] => 0
[Deaths] => 0
[Active] => 0
[Tested] => 0
[Name_Eng] => city2
[Join_Count] => 59
[Confirmed_SUM] => 6848
[Deaths_SUM] => 85
[Recovered_SUM] => 1145
[Active_SUM] => 5618
[Tested_SUM] => 0
[ObjectId] => 9
)
)
Since I may have misunderstood and you may have many, just build a new array with CITY_NAME:
foreach($data as $values) {
$result[$values['attributes']['CITY_NAME']] = $values['attributes'];
}
Now you can access by CITY_NAME:
echo $result['city1']['Population'];
This might be easier. Extract all attributes from all arrays into an array, then create an array from that indexed by CITY_NAME:
$data = array_column(array_column($json_data['features'], 'attributes'),
null, 'CITY_NAME');

Removing row from array based on duplicate value of a key

I have a array called $data['job_list'] which is as follows
Array
(
[0] => Array
(
[job_id] => 2
[job_title] => JQuery developer
[job_desc] => Developer
[job_slug] => 2-JQuery-developer
[job_type] => 191
[job_skill] => 2
[job_salary] => 2
[job_experience] => 1
[company_name] => IGUTS
[company_desc] => IGUTS is a fresh company
[company_industry] => 24
[company_address] => 35 Lawrence Street
[company_state] => 35
[company_city] => 650
[user_id] => 1
[concerned_fname] => Saswat
[concerned_lname] => Routroy
[contact] => 8961287928
[date_of_post] => 26-04-2014
[job_timestamp] => 1398517810
[industry_id] => 191
[industry_title] => Web Designer/Developer
[p_cid] => 24
[industry_slug] => 191-Web-Designer-Developer
[industry_desc] =>
[industry_image] =>
[industry_priority] => 0
[industry_timestamp] => 1396535046
)
[1] => Array
(
[job_id] => 1
[job_title] => PHP developer
[job_desc] => Developer
[job_slug] => 1-PHP-developer
[job_type] => 191
[job_skill] => 1,2
[job_salary] => 1
[job_experience] => 1
[company_name] => IGUTS
[company_desc] => IGUTS Company
[company_industry] => 24
[company_address] => 35 Lawrence Street
[company_state] => 35
[company_city] => 650
[user_id] => 1
[concerned_fname] => Saswat
[concerned_lname] => Routroy
[contact] => 8961287928
[date_of_post] => 18-04-2014
[job_timestamp] => 1397842605
[skill_id] => 2
[skill_title] => JQuery
[skill_slug] => 2-JQuery
[industry] => 24
[skill_timestamp] => 1397395987
)
[2] => Array
(
[job_id] => 2
[job_title] => JQuery developer
[job_desc] => Developer
[job_slug] => 2-JQuery-developer
[job_type] => 191
[job_skill] => 2
[job_salary] => 2
[job_experience] => 1
[company_name] => IGUTS
[company_desc] => IGUTS is a fresh company
[company_industry] => 24
[company_address] => 35 Lawrence Street
[company_state] => 35
[company_city] => 650
[user_id] => 1
[concerned_fname] => Saswat
[concerned_lname] => Routroy
[contact] => 8961287928
[date_of_post] => 26-04-2014
[job_timestamp] => 1398517810
[skill_id] => 2
[skill_title] => JQuery
[skill_slug] => 2-JQuery
[industry] => 24
[skill_timestamp] => 1397395987
)
)
[job_id] => 2 is present twice
What I want is that, the row with duplicate job_id => 2 should be removed
How can I achieve that??
$jobIds = array();
foreach ($jobs as $key => $job) {
if (in_array($jobIds, $job['job_id'])) {
unset($jobs[$key]);
continue;
}
$jobIds[] = $job['job_id'];
}
print_r($jobs);
I would cycle though each "job" and create an array of Job IDs. If I see the same ID twice then I would remove the duplicate and store it somewhere else if needed.
As Matei Mihai stated, i made some minor changes in his script and bingo it solved..
Matei Mihai made a mistake regarding the data-type of arguments of the in_array() function
I fixed that.
here's my code
$jobIds = array();
for($i = 0;$i < count($data['job_list']); $i++ )
{
if (in_array($data['job_list'][$i]['job_id'], $jobIds))
{
unset($data['job_list'][$i]);
continue;
}
$jobIds[] = $data['job_list'][$i]['job_id'];
}

Merge arrays from 2 SQL results

So i have a tags table setup in SQL
lists, lists_tags, tags
Each list can have multiple tags, and tags have two types genre and producer. Now if we are looking for all lists with tags 'action' these are the steps im following
SELECT GROUP_CONCAT(mini_lists_tags.list_id) AS list_ids
FROM (`mini_tags`)
LEFT JOIN `mini_lists_tags` ON `mini_lists_tags`.`tag_id` = `mini_tags`.`tag_id`
WHERE `mini_tags`.`tag_slug` = 'action'
That will return an array 1,2 for the ids of the list.
SELECT *
FROM (`mini_lists_anime`)
JOIN `mini_lists` ON `mini_lists`.`list_id` = `mini_lists_anime`.`list_id`
WHERE `mini_lists`.`list_id` IN ('1', '2')
AND `mini_lists`.`list_state` = 'active'
that gets all the lists in an array EXAMPLE:
Array
(
[0] => stdClass Object
(
[list_id] => 1
[list_episodes] => 13
[list_duration] => 24
[list_aired] => 1238623200
[list_age_rate] => PG-13 - Teens 13 or older
[user_id] => 1
[list_mal] => 5342
[list_category] => Anime
[list_type] => TV
[list_status] => Completed
[list_title] => Asura Cryin'
[list_alt_titles] => アスラクライン
[list_thumb] => 17071
[list_likes] => 0
[list_date] => 1300609723
[list_update] => 0
[list_state] => active
[list_info] =>
)
[1] => stdClass Object
(
[list_id] => 2
[list_episodes] => 26
[list_duration] => 23
[list_aired] => 1238623200
[list_age_rate] => PG-13 - Teens 13 or older
[user_id] => 1
[list_mal] => 329
[list_category] => Anime
[list_type] => TV
[list_status] => Completed
[list_title] => Planetes
[list_alt_titles] => プラネテス
[list_thumb] => 4822
[list_likes] => 0
[list_date] => 1300609723
[list_update] => 0
[list_state] => active
[list_info] =>
)
)
And then we get the tags
SELECT `mini_lists_tags`.`list_id`, `mini_tags`.`tag_type`, GROUP_CONCAT(mini_tags.tag_name) AS tag_names
FROM (`mini_lists_tags`)
INNER JOIN `mini_tags` ON `mini_tags`.`tag_id` = `mini_lists_tags`.`tag_id`
WHERE `mini_lists_tags`.`list_id` IN ('1', '2')
GROUP BY `mini_lists_tags`.`list_id`, `mini_tags`.`tag_type`
that gets all the tags in an array EXAMPLE:
Array
(
[0] => stdClass Object
(
[list_id] => 1
[tag_type] => Genre
[tag_names] => Supernatural,Action,Mecha
)
[1] => stdClass Object
(
[list_id] => 1
[tag_type] => Producers
[tag_names] => Seven Arcs
)
[2] => stdClass Object
(
[list_id] => 2
[tag_type] => Genre
[tag_names] => Romance,Action,Sci-fi,Comedy,Slice of Life,Drama,Space
)
[3] => stdClass Object
(
[list_id] => 2
[tag_type] => Producers
[tag_names] => Sunrise,Bandai Entertainment,Bandai Visual,Bang Zoom! Entertainment
)
)
Now the problem is I need to get them merged on the list_id so it returns something like this for each one.
stdClass Object
(
[list_id] => 1
[list_episodes] => 13
[list_duration] => 24
[list_aired] => 1238623200
[list_age_rate] => PG-13 - Teens 13 or older
[user_id] => 1
[list_mal] => 5342
[list_category] => Anime
[list_type] => TV
[list_status] => Completed
[list_title] => Asura Cryin'
[list_alt_titles] => アスラクライン
[list_thumb] => 17071
[list_likes] => 0
[list_date] => 1300609723
[list_update] => 0
[list_state] => active
[list_info] =>
[list_tags] => Array
(
[0] => stdClass Object
(
[tag_type] => Genre
[tag_names] => Mecha,Action,Supernatural
)
[1] => stdClass Object
(
[tag_type] => Producers
[tag_names] => Seven Arcs
)
)
)
Any advice is appreciated, i'm really lost. if there is better solution than this, i am all ears.
You can do another type of join that will return the parent item multiple times merged with each child object like so:
Array(
[0] => stdClass Object
(
[list_id] => 1
[list_episodes] => 13
[list_duration] => 24
...etc
[tag_type] => Genre
[tag_names] => Supernatural,Action,Mecha
...etc
)
[1] => stdClass Object
(
[list_id] => 1
[list_episodes] => 13
[list_duration] => 24
...etc
[tag_type] => Producers
[tag_names] => Seven Arcs
...etc
)
[2] => stdClass Object
(
[list_id] => 2
[list_episodes] => 26
[list_duration] => 23
...etc
[tag_type] => Genre
[tag_names] => Supernatural,Action,Mecha
...etc
)
[3] => stdClass Object
(
[list_id] => 2
[list_episodes] => 26
[list_duration] => 23
...etc
[tag_type] => Producers
[tag_names] => Seven Arcs
...etc
)
)
You will then need to loop through your results merging down the results into their child/parent relationships. This is because SQL always returns rows as results, not complex structures.
Although this is more complex to deal with, it's ususally less process intensive than making looped sql queries for each parent object (known as n+1 queries)

php merging arrays

In the multidimensional array below, I would like to merge arrays that have the same merge_id. I'm not sure "merge" is the right word: in the example below, array['0'] should become array['0'] with in it array['0']['0'] and array['0']['1'], the latter being equal to array['1']. I hope this makes sense ...
The array comes out of the db sorted on merge_id so arrays with matching merge_id are always "next to" each other, and there will only ever be 2 with the same merge_id
As I loop through the array I know I need to keep a variable that is always equal to the previous merge_id and if there is a match between previous and current, then merge.
Array
(
[0] => Array
(
[client_id] => 5
[company_name] => company111_name
[id] => 3
[fee] => 111
[year] => 2009
[quarter] => 3
[date_inserted] => 1264948583
[description] => 2009 - Q3
[fee_type] =>
[merge_id] => a87ff679a2f3e71d9181a67b7542122c
[total_paid] => 0
[total_remainder] => 0
)
[1] => Array
(
[client_id] => 5
[company_name] => company111_name
[id] => 6
[fee] => 55.5
[year] => 2010
[quarter] => 2
[date_inserted] => 1264949470
[description] => 2010 - Q2
[fee_type] =>
[merge_id] => a87ff679a2f3e71d9181a67b7542122c
[total_paid] => 0
[total_remainder] => 0
)
[2] => Array
(
[client_id] => 5
[company_name] => company111_name
[id] => 4
[fee] => 111
[year] => 2009
[quarter] => 4
[date_inserted] => 1264948583
[description] => 2009 - Q4
[fee_type] =>
[merge_id] =>
[total_paid] => 0
[total_remainder] => 0
)
[3] => Array
(
[client_id] => 5
[company_name] => company111_name
[id] => 7
[fee] => 55.5
[year] => 2010
[quarter] => 3
[date_inserted] => 1264949470
[description] => 2010 - Q3
[fee_type] =>
[merge_id] =>
[total_paid] => 0
[total_remainder] => 0
)
)
Code
$merger = $data['search']['0']['merge_id'];
$i = 0;
foreach($data['search'] as $fee)
{
if($fee['merge_id'] == $merger)
{
//bump up & merge arrays
???
}
$merger = $fee['merge_id'];
$i++;
}
You can use the ID as key to put all items with the same ID in the same array:
$merged = array();
foreach ($data['search'] as $fee) {
if ($fee['merge_id'] == '') {
continue;
}
if (!isset($merged[$fee['merge_id']])) {
$merged[$fee['merge_id']] = array();
}
$merged[$fee['merge_id']][] = $fee;
}
$merged = array_values($merged);
Notice that this will skip the items with an empty merge ID. You could also use a default merge ID in that case by replacing continue; with $fee['merge_id'] = 0;.
foreach($array as $p)
$result[$p['merge_id']][] = $p;

Categories