As an intern I realized that I spend the bulk of my time building and manipulating tables from sql queries in PHP. My current method is to use two foreach loops:
foreach($query as $record){
foreach($record as $field => $value){
*Things that need to be done on each field-value pair*
}
*Things that need to be done on each row*
}
Is there a better way of doing this?
Also I tend to pack data together as a ~ separated list and store it in the server, is this a bad practice?
I'd rather put some code up for review but I don't want to risk exposing the internals of the company cod.
Foreach loops are the best way to iterate through your data. If you are looking to make your code a bit prettier, try using the ternary version
<?php foreach($query as $record) : ?>
<?php foreach($record as $field => $value) : ?>
*Things that need to be done on each field-value pair*
<?php endforeach; ?>
*Things that need to be done on each row*
<?php endforeach; ?>
Also, like mentioned in the comments above, you lose a lot of functionality when storing ~ seperated data in the db. If you must do this, you can try storing serialized objects instead of delimited strings. You can manipulate the objects in a number of ways such as json_encode() and json_decode()
$myArray = array();
$myArray['User1']['book'] = 'Pride and Prejudice';
$myArray['User1']['favorites'] = 'Water skiing';
$myArray['User2']['book'] = 'Mansfield Park';
$myArray['User2']['favorites'] = array('skateboarding', 'surfing', 'running');
$myArray['description'] = 'Things people like.';
echo '<pre>';
print_r(json_encode($myArray)); //This will convert your array to a string for the db
echo '</pre>';
echo '<pre>';
$myArrayString = json_encode($myArray);
print_r(json_decode($myArrayString)); //This will convert the db string to an object for manipulation
echo '</pre>';
There is no built in way to produce a HTML table from the result of a query. If you find yourself writing that sort of code over and over, then it would be a good candidate to make a reusable class or library. For example:
$table = new HTMLTable();
$table->setData($data);
echo $table->toHTML();
The above is not working code, just an example of how you could create reusable code instead of repeating the same table building code many times.
I tend to use a while loop with one of the mysql_fetch_.. functions. But essentially it's the same as what you do.
$query = 'SELECT
stuff
FROM
table';
if ($query = mysql_query($query)) {
while ($row = mysql_fetch_assoc($query)) {
foreach ($row as $key => $value) {
/* Things that need to be done on each field-value pair */
}
/* Things that need to be done on each row */
}
}
And as to the ~ separated list. I strongly recommend to save the data in separate DB fields, instead of packing it like that. Just create a new table for each such pack.
Related
Any idea on how to restructure the json below:
$jsonArray = [{"Level":"77.2023%","Product":"Milk","Temperature":"4"},
{"Level":"399.2023%","Product":"Coffee","Temperature":"34"},
{"Level":"109.2023%","Product":"Chocolate","Temperature":"14"}]
Expected outcome:
$expected = {"Milk":{"Level":"77.2023%","Temperature":"4"},
"Coffee":{"Level":"399.2023%","Temperature":"34"},
"Chocolate":{"Level":"109.2023%","Temperature":"14"}
}
I'm new and my thinking is get the product value in array and again use foreach loop to find the others value? .
Here's one possibility:
$jsonArray = '[{"Level":"77.2023%","Product":"Milk","Temperature":"4"},
{"Level":"399.2023%","Product":"Coffee","Temperature":"34"},
{"Level":"109.2023%","Product":"Chocolate","Temperature":"14"}]';
$output = array();
foreach (json_decode($jsonArray, true) as $row) {
$product = $row['Product'];
$output[$product] = $row;
unset($output[$product]['Product']);
}
echo json_encode($output);
Output:
{"Milk":{"Level":"77.2023%","Temperature":"4"},
"Coffee":{"Level":"399.2023%","Temperature":"34"},
"Chocolate":{"Level":"109.2023%","Temperature":"14"}
}
Demo on 3v4l.org
This made some trick
$a = '[{"Level":"77.2023%","Product":"Milk","Temperature":"4"},
{"Level":"399.2023%","Product":"Coffee","Temperature":"34"},
{"Level":"109.2023%","Product":"Chocolate","Temperature":"14"}]';
$newAr = array();
foreach(json_decode($a,true) as $key=>$value)
{
$newAr[$value['Product']] = array(
'Level' => $value['Level'],
'Temperature' => $value['Temperature'],
);
}
There are many ways to perform this with Loops in PHP. Other answers demonstrate it accurately. I would also suggest to integrate some form of Error handling, data validation/filtering/restriction in your code to avoid unexpected results down the road.
For instance, json_decode(), either assigned to a variable pre-foreach or straight in the foreach() 1st argument will just raise a warning if the original json is not valid-json, and just skip over the foreach used to construct your final goal. Then if you pass the result (that may have failed) directly to your next logic construct, it could create some iffy-behavior.
Also, on the concept of data-validation & filtering, you could restrict the foreach(), or any other looping mechanism, to check against a Product_List_Array[Milk,Coffee,Chocolate], using if(in_array() ...) so the final/goal object only contains the expected Products, this, in the case the original json has other artifacts. Filtering the values can also increase stability in restricting, for example, Temperature to Float.
I'm just transitioning over to PDO from mysql_
I have been pointed in the direction of some helpful tutorials, but there is one issue I haven't seen raised and I wanted to check I am doing it in the 'correct way'
I want to reuse the same values that I am dropping into an array in two different areas (both different PHP code blocks) within one page. Both are styled differently depending on media queries (hidden/not hidden etc.)
At the moment I am running a query like this:
<?php
$data = $pdo->query("SELECT * FROM sitelinks WHERE `show` = 'yes' ORDER BY `Order` ASC")->fetchAll();
foreach ($data as $links)
{
echo "\n<li class=\"linkitem\">{$links['Text']}</li>";
}
?>
So my understanding is that I should then be able to load and loop through the $links variable somewhere else on the page. I am doing that like this:
<?php
foreach ($data as $links)
{
echo "\n<li class=\"desktoplinkitem\">{$links['Text']}</li>";
}
?>
Is that correct? It's working, but seems a little crazy to use ($data as $links) again. Following on, really stupid question but why does the $data variable then have to be stored as $links. Could it not just be run as foreach ($links) to begin with?
Assuming you do not write some code later that changes/destroys the $data variable between these 2 usages there is no problem doing this. It in fact reduces the runtime to reuse data if you can rather than getting it again.
What you need to remember is that ->fetchAll() returns all the rows from your resultset into an array. Its your array from then on, which you can do whatever you like with once the ->fetchAll() is completed
Second question:
the foreach
foreach ($data as $links)
processes over an array $data and returns one occurance (row in your case) at a time. So you have to give it another variable name. That name can be anything.
If you use sensible names for things they normally look like this
foreach ($rows as $row)
foreach ($sitelinks as $sitelink)
Using the plural for the original array and the singular for the single occurance returned by each iteration over the array.
So I would amend your code like so:
<?php
$sitelinks = $pdo->query("SELECT *
FROM sitelinks
WHERE `show` = 'yes'
ORDER BY `Order` ASC")
->fetchAll();
foreach ($sitelinks as $sitelink) {
echo "\n<li class=\"linkitem\">{$links['Text']}</li>";
}
?>
And the second use of the array
<?php
foreach ($sitelinks as $sitelink) {
echo '\n<li class=\"desktoplinkitem\">{$sitelink['Text']}</li>";
}
?>
Which of these two methods (array_count_values or array_key_exists) is more 'friendly' with regard to memory consumption, resource usage and ease of code processing. And is the difference big enough to where a significant performance bump or loss could take place?
If more details on how these methods may be used are needed, I will be parsing a very large XML file and using simpleXML to retrieve certain XML values into an array (to store URL's), like this:
$XMLproducts = simplexml_load_file("products.xml");
foreach($XMLproducts->product as $Product) {
if (condition exists) {
$storeArray[] = (string)$Product->store; //potentially several more arrays will have values stored in them
}}
No duplicate values will be inserted into the array, and I am debating on either using the array_key_exists or array_count_values method to prevent duplicate values. I understand array_key_exists is more , but my question is how much more resource friendly is it? Enough to slow down performance significantly?
I would much rather use the array_count_values method primarily because along with preventing duplicate value in the array, you can also easily display how many duplicate values are in each value. IE if in the storeArray "Ace Hardware" had 3 instances, you could easily display "3" next to the URL, like this:
// The foreach loop builds the arrays with values from the XML file, like this:
$storeArray2[] = (string)$Product->store;
// Then we later display the filter links like this:
$storeUniques = array_count_values($storeArray)
foreach ($storeUniques as $stores => $amts) {
?>
<?php echo $stores; ?> <?php echo "(" . ($amts) . ")" . "<br>";
}
If there is a big performance gap between the 2 methods, I will go with the array_key_exists method. But the code below only prevents duplicate values from being displayed. Is there a way to also display the number of duplicate values (for each value) that would have occurred?
// The foreach loop builds the arrays with values from the XML file, like this:
$Store = (string)$Product->store;
if (!array_key_exists($Store, $storeArray)) {
$storeArray[$Store] = "<a href='webpage.php?Keyword=".$keyword."&Features=".$features."&store=".$Product->store"'>" . $Store . "</a>";
}
// Then we later display the filter links like this:
foreach ($storeArray as $storeLinks) {
echo $storeLinks . "<br>";
}
Use isset() !
It's 2.5x faster than array_key_exists
Source :
Here
my returned json looks like this http://pastebin.com/Nbr161s3
I want to echo
body->airTicketListResponse->routings->mainAirlineName
body->airTicketListResponse->routings->adultBasePrice
body->airTicketListResponse->routings->trips->segments->departureAirportCode
body->airTicketListResponse->routings->trips->segments->departureTime //only the time here
body->airTicketListResponse->routings->trips->segments->duration
for each routings.
How do I do this? Here is what I have but I am lost and I know it is way off.
$result = data returned here http://pastebin.com/Nbr161s3
$airTicketListResponse = $result->body->airTicketListResponse;
$routings = $result->body->airTicketListResponse->routings;
$trips = $result->body->airTicketListResponse->routings->trips;
$segments = $result->body->airTicketListResponse->routings->trips->segments;
foreach($airTicketListResponse as $item){
$i=0;
$i<count($routings);
echo '<span style="font-weight:bold;">Airline - '.$item->routings[i]->mainAirlineName.' Price - '.$item->routings[i]->adultBasePrice.'</span><br />'.$item->routings[i]->trips[i]->segments[i]->departureAirportCode.' '.$item->routings[i]->trips[i]->segments[i]->departureTime.'<br /><br />';
$i++;
}
Please help if you can.
Before working with JSON you should be familiar with working with arrays and objects since JSON is nothing more than that.
It seems you already know these two concepts
To access an object property in PHP you use obj->property
To access a value of an array you specify the index inside brackets array[0]
With JSON you just have to keep in mind that some of your object properties will be arrays.
Now, since your data comes in a multi-level three-like structure you should also be familiar with traversing arrays, PHP offers an implementation of a foreach loop that is ideal for traversing dynamically generated arrays
using foreach($array as $index => $var) the $index and $var variables are automatically set to the index and value of each element in the array as they are being traversed, so you don't manually need to keep track of the index (i.e. $i)
Now let's start going through your data:
First we find your routings array
$result = json_decode($data);
$airTicketListResponse = $result->body->airTicketListResponse;
$routings = $airTicketListResponse->routings;
Now we use foreach to loop through every routing and print the needed properties
foreach($routings as $routing){ //$routing will hold the object value in each loop
echo 'Airline '.$routing->mainAirlineName.'<br>';
echo 'Adult Base Price '.$routing->adultBasePrice.'<br>';
}
Getting single properties like the above is pretty straight forward, but for the information of the segments we would first need a nested foreach since we have multiple trips for each routing and then a second nested foreach since each trip has multiple segments
foreach($routings as $routing){ //$routing will hold the object value in each loop
echo 'Airline '.$routing->mainAirlineName.'<br>';
echo 'Adult Base Price '.$routing->adultBasePrice.'<br>';
foreach($routing->trips as $trip){
foreach($trip->segments as $index => $segment){
echo 'Segment '.$index.':<br>'
echo 'Depart From '.$segment->departureAirportCode.'<br>';
echo 'Departure Time '.$segment->departureTime.'<br>';
echo 'Duration '.$segment->duration.'<br>';
}
}
}
And that would be it. I hope my explanation was clear and you got the idea of how to traverse JSON objects
If you feel more comfortable working with an array than with an object to access your data [which might be where you're getting confused here] then you can use json_decode with an additional argument:
$data = json_decode($result, true);
This will leave you with an array ($data) containing all your flight information, you can then var_dump() it and see the hierarchy you're dealing with and loop through it.
foreach ( $this->parent->get_sections(null, $this->parent->author) as $section)
{
//...
}
I'm trying to do is force the loop to output each $section in the order I want. Each $section's name can be retrieved by $section->name. Let's say that I want to output $section "Section 2" first and then "Section 1" (and not in the order of the foreach). How can I force it do that? I presume the proper way would be a for loop with an if checking section names each time.
The proper way would be sorting the results when you call parent->get_sections(). How you would do this is entirely up to the implementation of that class and method. Changing this foreach to for for the sake of sorting seems like a code smell to me.
For the sake of answering the question as technical as possible.
$sections = $this->parent->get_sections(null, $this->parent->author);
$num_sections = count($sections);
for ($i = 0; $i < $num_sections; $i++) {
// what you do here is up to you $sections[$i]
}
Especially if you are not aware of the specific number of sections, you could use usort() to do a dynamic custom sort on the get_sections()-returned array or object and then utilize the existing code. (This is a little more elegant, imo, than doing the same in a for/foreach loop).
Not knowing the structure of your code, I would do something like.
// Get Org Sections
$sections = $this->parent->get_sections(null, $this->parent->author);
// Loop thru sections to get an array of names
foreach ( $sections as $key=>$section)
{
$sorted_sections[$section->name] = $key;
}
// Sort Array
//ksort — Sort an array by key
//krsort — Sort an array by key in reverse order
krsort($sorted_sections);
foreach ( $sorted_sections as $section)
{
// Orig Code
}
$section = $this->parent->get_sections(null, $this->parent->author);
echo $section[2]->name;
echo $section[1]->name;//just output the indexes the way you want
if you want it sorted, in say descending order, you can sort it that way and then use a for loop to display.