I have a table with various entries such as start date (contract), some random documents and monthly invoices and receipt in it, like this:
DOCUMENT TYPES
ID TYPE CHECK? MONTHLY?
1 Contract Yes No
2 Documents No No
3 Policy Yes No
4 Order No No
5 Invoice Yes Yes
6 Receipt Yes Yes
DOCUMENTS
ID TYPE DATE
1 1 01/01/2013
2 2 01/01/2013
3 3 01/01/2013
4 5 01/02/2013
5 6 01/02/2013
6 4 14/02/2013
7 5 01/03/2013
8 6 01/03/2013
TODAY 05/05/2013
My goal is to produce the output as shown below.
Display all existent documents, where CHECK? is Yes, and display missing documents where MONTHLY? is Yes.
01 Contract 01/01/2013 OK
02 Documents 01/01/2013 OK
03 Policy 01/01/2013 OK
04 Invoice 01/02/2013 OK
05 Receipt 01/02/2013 OK
06 Invoice 01/03/2013 OK
07 Receipt 01/03/2013 OK
08 Invoice 01/04/2013 Missing
09 Receipt 01/04/2013 Missing
10 Invoice 01/05/2013 Missing
11 Receipt 01/05/2013 Missing
I have written some code, but I not understand how to include monthly loop to display invoices and receipts.
QUERY
// Get type
$query = "SELECT * FROM doc_type
WHERE check='1'";
$result = mysql_query($query) or die(mysql_error());
$num = mysql_numrows($result);
// Get docs
$check = array();
$query2 = mysql_query("SELECT document_type_id FROM documents");
while ($row = mysql_fetch_assoc($query2)) {
$check[] = $row['document_type_id'];
WHILE
<tbody>
<?php
$i=0;
while ($i < $num) {
$document_type_id = mysql_result($result,$i,"document_type_id");
$document_type = mysql_result($result,$i,"document_type");
?>
<tr class="grade">
<td><?php echo $document_type_id; ?></td>
<td><?php echo $document_type; ?></td>
<td>
<?php
if (in_array($document_type_id, $check)) {
echo "<p style='color:green'>Ok</p>";
} else {
echo "<p style='color:red'>Miss</p>";
}
?>
</td>
</tr>
<?php
$i++;
}
?>
</tbody>
First, I must point out that I am slightly confused by the example data, because it looks like you are loading the data from a database for the first table, but the example implies that there is a list of documents that is being saved elsewhere for each job or project.
If it were me, I'd create either an object or an array representing your final table. That object you can then fill based on the available data. Given the data structure that you seem to be already using, I will assume that you would rather not use an Object Oriented Programming approach.
First, create an array or object that stores your original table information that matches the document type and the monthly setting. Once you choose a data format, you can load the data format from your database for each different group of settings. I will use the settings you have shown in your example.
Personally, I'd use the document type id as the index key and use boolean values to represent Yes (true) and No (false) like this:
$doc_requirements = array(
1 => array( "name" => "Contract", "check" => true, "monthly" => false ),
2 => array( "name" => "Documents", "check" => false, "monthly" => false ),
3 => array( "name" => "Policy", "check"=>true, "monthly"=>false ),
4 => array( "name" => "Order", "check"=>false, "monthly"=>false ),
5 => array( "name" => "Invoice", "check"=>true, "monthly"=>false ),
6 => array( "name" => "Receipt", "check"=>true, "monthly"=>false )
);
Use your database to store as many of these tables as you need and load them before reviewing your document list.
Next I would create an array that represents the output table. Index it by date so you can determine if you have missing documents. Your data implies that on each date, that we can have more than one document, but not more than one document of the same type, so you might be able to use something like this:
/* pseudo_code */ $temp_table = array(
[date] => array(
[doc_type_name] => array(
/* I assume that the document id is actually just the line number
on the table, so I will leave the id out of this, but if it is
not just the line on the table, add this field to the array:
"id" => [id], */
"status" => [status] )
),
[doc_type_name] => array(
"status" => [status] )
),
...
),
[date2] => array( ... ),
....
);
Load this array with the documents that you know about from your document array:
(note: you are using the mysql functions, which are currently deprecated, so you should look at using the msyqli functions instead)
$sql = #### /* SQL query string for your list of documents that are not missing */
$result = mysql_query($sql) or die(mysql_error());
if($result){
while( $document = mysql_fetch_assoc( $result ) ){
$date = $document[ "date" ];
$doc_type_id = $document[ "type_id" ];
$doc_type_name = $doc_requirements[ $doc_type_id ]["name"];
$temp_table[ $date ][ $doc_type_name ]["status"]= "OK"
/* we have the document, therefore, we know it is okay,
we can set that value immediately */
}
}
$start_date=#### /* set start date of contract */
$end_date=##### /*set end date of contract */
foreach( $doc_requirements as $requirement ){
if( $requirement["monthly"] == true ){
for( $cur_date = $start_date; $cur_date <= $end_date; $cur_date=#### ){
/*increment the date by whatever function you choose,
I recommend using a DateTime object
for your dates and incrementing by using the add() method */
$current_doc_name = $requirement[ "name"];
if( !isset( $temp_table[$cur_date][ $current_doc_name ] ) ){
/* if the array value is not set,
then a document of the type_name
and current date specified does not exist,
because the requirement for "monthly" == true,
we know that we should have it, so we will
set the status to "Missing" */
$temp_table[$cur_date][$current_doc_name]["status"] = "Missing";
}
}
}
}
Now we have an array organized by date, containing one document record for each document that we have a record of in our database (but no more than one of each type per date...If you need to change this, just change the data structure of the array to match your needs or use an object oriented approach that helps map out your thoughts more naturally). For any item that is Monthly = true (YES) we have a "Missing" stub created for it indicating that something was expected there but not found. Having this data array, we can cycle through it and produce the output.
I have noted above that your document id appears to just be the line number on the output table, so I will represent it the same way here:
$doc_id = 1;
foreach($temp_table as $cur_date){
foreach($cur_date as $doc_name){
$doc_id_string = your_func_format_id( $doc_id );
/* use whatever function you like to make your doc_id two digits.
Perhaps printf() would be useful */
$color_code = "style='color:green'";
if( $doc_name["status"]=="Missing" ) $color_code = "style='color:red'";
echo "<tr class='grade'><td>$doc_id_string</td><td>$doc_name</td><td>$cur_date</td><td><p $color_code>{$doc_name["status"]}</p></td>";
}
}
I have learned that using the correct data structure makes everything more simple. I have tried to use a data structure that reflects your example code. I highly recommend using Object Oriented Programming (OOP) techniques to implement your designs, because OOP forces every programmer to consider the shape of the data before considering the programming code, and it solves many problems.
Related
I am preparing a menu system for a restaurant which provides food on a monthly basis. This is my problem:
There are different packages that the restaurant offers. Each package consists of a number of servings each day. For example, package A serves 3 times a day, whereas package B serves 2 times a day. The online ordering system that I am building is a multi-page ordering system divided as per the number of days. So for 20 days, there are 20 pages. Once the selection of one day is completed, I want to store the selection in a multi-dimensional array. Refer to the below structure for reference.
$selection_package_a = array(
"Serving_Day1" => array (
"Serving_1" => Pizza,
"Serving_2" => Salad,
"Serving_3" => Smoothies
),
"Serving_Day2" => array (
"Serving_1" => Salad,
"Serving_2" => Juices,
"Serving_3" => Fruits
),
);
$selection_package_b = array(
"Serving_Day1" => array (
"Serving_1" => Pizza,
"Serving_2" => Salad
),
"Serving_Day2" => array (
"Serving_1" => Salad,
"Serving_2" => Juices
),
);
"Serving_Day1" to "Serving_Day20" depends on the number of days served during a month. So if the package serves only 10 days a month, then "Serving_Day10" will be the last field.
Within "Serving_Day1", "Serving_1" and so on depends on the number of servings stored in the database.
Taking the answer of #yarwest a step forward, I have pasted the progress till now. I guess it is just one more step to acheive the desired output.
$meals_selected_array = [];
$total_meals_array = [];
if( $num_row_packages >= 1 ) {
while($row_packages = mysqli_fetch_array ($result_packages)) {
$package_id = $row_packages['package_id'];
$package_name = $row_packages['package_name'];
$servings_count = $row_packages['servings_count'];
$days_served = $row_packages['days_served'];
//repeating it based on the number of days_served
for ($i = 1; $i <= $days_served; $i++) {
//how to define/declare $total_meals_array['day_' . $i]
//adding user selection for the day in $meals_selected_array array
for ($y = 1; $y <= $servings_count; $y++) {
$meals_selected_array["meal_id_day_" .$i] = "Not Available";
$meals_selected_array["meal_code_day_" .$i] = "Not Available";
$meals_selected_array["meal_type_day_" .$i] = "Meal";
}
//what to do either here or after the below loop in order to add $meals_selected_array above values to $total_meals_array['day_' . $i].
}
}
}
When I $print_r($meals_selected_array), I get the result as an Associative Array with perfect labelling and values. Now I just have to add this Associative Array to each day to make my primary Array as a Multidimensional Array.
So my desired output for $total_meals_array is as below:
Array
(
[day_1] => Array
(
[meal_id_day_1] => "1" //This will be my Unique ID of selected meal
[meal_code_day_1] => "Pizza" //This will be the name of meal
[meal_type_day_1] => "Main Course" //This will be the serving Type
)
[day_2] => Array
(
[meal_id_day_2] => "4" //This will be my Unique ID of selected meal
[meal_code_day_2] => "Lemonade" //This will be the name of meal
[meal_type_day_2] => "Drinks" //This will be the serving Type
)
[day_3] => Array
(
[meal_id_day_3] => "8" //This will be my Unique ID of selected meal
[meal_code_day_3] => "Custard" //This will be the name of meal
[meal_type_day_3] => "Dessert" //This will be the serving Type
)
)
Important note beforehand
It is very unsafe to use mysqli functions. They can easily be manipulated with, for example, SQL injections. Instead use PDO and Prepared Statements.
The solution
You retrieved a package from the database.
The next step is to loop based on the amount of servings and amount of days to create a new array to hold the package.
if( $num_row_packages >= 1 ) {
while($row_packages = mysqli_fetch_array ($result_packages)) {
$package_id = $row_packages['package_id'];
$package_name = $row_packages['package_name'];
$servings_count = $row_packages['servings_count'];
$days_served = $row_packages['days_served'];
//Create a new array to hold the servings skeleton
$servingsArray = [];
//For every serving add an empty string to the servingArray
for($i = 0; $i < $servings_count; $i++){
array_push(
$servingsArray,
""
);
}
//Create a new array to hold the package skeleton
$selection_package = [];
//For every day add an servingArray to the package array
for($i = 0; $i < $days_served; $i++){
array_push(
$selection_package,
$servingsArray
);
}
}
}
This will create an entirely empty array according to the specified structure.
Now here is the code that works best in the given situation.
Situation
The Order Form is multipage depending on the number of days served based on the package selected. Details of each package are stored in the database with the following fields:
package_id (Unique Field)
package_name (Name of the Package, e.g. Package A)
servings_count (Total Servings in a Day)
days_served (Number of Days Served in a Month)
In order to carry forward the selection of meals for each day and serving of that day to store as an Order in the database, I required a Multidimensional Array of PHP that can be defined/populated dynamically.
Expected output is something like:
Array
(
[Day 1] => Array
(
[meal_id_1] => Unique ID //to be replaced with user selection
[meal_code_1] => Meal Name //to be replaced with user selection
[meal_type_1] => Meal //prefilled based on the selected package
[meal_id_2] => Not Available //to be replaced with user selection
[meal_code_2] => 2 //to be replaced with user selection
[meal_type_2] => Meal //prefilled based on the selected package
)
[Day 2] => Array
(
[meal_id_1] => Unique ID //to be replaced with user selection
[meal_code_1] => Meal Name //to be replaced with user selection
[meal_type_1] => Meal //prefilled based on the selected package
[meal_id_2] => Not Available //to be replaced with user selection
[meal_code_2] => 2 //to be replaced with user selection
[meal_type_2] => Meal //prefilled based on the selected package
)
This above array has been created 100% dynamically based on the explained structure and number of servings and days. Below is the code with some explanation.
First, we have to declare two PHP Arrays.
$total_meals_array = []; //Primary, Multidimension Array
$meals_selected_array = []; //Meals Details Array to be used as primary array's key value.
After doing this, run MySQL query to read packages from the database. Now based on the result, do the following:
$total_meals_array = []; //Primary, Multidimension Array
$meals_selected_array = []; //Meals Details Array to be used as primary array's key value.
if( $num_row_packages >= 1 ) {
while($row_packages = mysqli_fetch_array ($result_packages)) {
$package_id = $row_packages['package_id'];
$package_name = $row_packages['package_name'];
$servings_count = $row_packages['servings_count'];
$days_served = $row_packages['days_served'];
//this for loop is to repeat the code inside `$days_served` number of times. This will be defining our primary and main Multidimensional Array `$total_meals_array`.
for ($y = 1; $y <= $days_served; $y++) {
//once inside the code, now is the time to define/populate our secondary array that will be used as primary array's key value. `$i`, which is the meal count of each day, will be added to the key name to make it easier to read it later. This will be repeated `$meals_count` times.
for ($i = 1; $i <= $meals_count; $i++) {
$meals_selected_array["meal_id_" . $i] = "Unique ID";
$meals_selected_array["meal_code_" . $i] = "Meal Name";
$meals_selected_array["meal_type_" . $i] = "Meal";
}
//once our secondary array, which will be used as the primary array's key value, is ready, we will start defining/populating our Primary Multidimensional Array with Keys Named based on `$days_served`.
$total_meals_array["Day " . $y] = $meals_selected_array;
}
}
}
That's it! Our dynamic Multidimensional Array is ready and can be viewed by simply the below code:
print "<pre>";
print_r($total_meals_array);
print "</pre>";
Thank you everyone, specially #yarwest for being kind enough to answer my question.
I am pulling data from three MySQL tables to produce a bootstrap dataTable via AJAX and JSON in PHP.
I have multiple organizational units (Unit 1, Unit 2, Unit 3, etc.) I also have multiple program types (Beginning, Intermediate and Advanced). Finally, I want to show two years data (2105 and 2014) for each organizational unit side-by-side.
In other words, the resulting table would be structured like this (with one row of dummy values for the Beginning program type):
Unit 1 Unit 2 Unit 3
2015 2014 2015 2014 2015 - 2014
Beginning 7 9 136 152 0 3
Intermediate
Advanced
The JSON object that will create and fill this dataTable would need to look something like:
[{"program_category":"Beginning","unit_1":{"2015":"7","2014":"9"},
"unit_2":{"2015":"136","2014":"152"},
"unit_3":{"2015":"0","2014":"3"}}]
So far, I've been able to write a SQL query that produces a JSON string that gets me pretty close, but as you can see the, 'program_type' repeats itself for each organizational unit:
Here's the SQL:
select all_programs_test.program_category as program_category, report_db.unit,
sum(case when all_programs_test.year = '2015' then 1 else 0 end) yr_2015,
sum(case when all_programs_test.year = '2014' then 1 else 0 end) yr_2014
from all_programs_test
JOIN report_db on report_db.id = all_programs_test.id
group by all_programs_test.program_category,report_db.unit
Which I then json_encode in PHP:
while($row = mysql_fetch_assoc($query4)) {
$query4_result[] = array (
'program_category' => $row['program_category'],
$row['unit'] => array(
'2015' => $row['yr_2015'],
'2014' => $row['yr_2014']
)
);
which then produces
[{"program_category":"Beginning","unit_1":{"2015":"7","2014":"9"}},
{"program_category":"Beginning","unit_2":{"2015":"136","2014":"152"}},
{"program_category":"Beginning","unit_3":{"2015":"0","2014":"3"}}]
As you can see in the json object snippet above, 'Beginning' is repeated for each organizational unit. Any ideas on how to get to this instead:
[{"program_category":"Beginning","unit_1":{"2015":"7","2014":"9"},
"unit_2":{"2015":"136","2014":"152"},
"unit_3":{"2015":"0","2014":"3"}}]
Thanks!
Try this:
$category_aux = '';
$record_aux = array();
while($row = mysql_fetch_assoc($query4)) {
if ($category_aux !== $row['program_category']){
$category_aux = $row['program_category'];
if ( ! empty($record_aux)) {
$query4_result[] = $record_aux;
}
$record_aux = array();
$record_aux['program_category'] = $category_aux;
}
$record_aux[$row['unit']] = array(
'2015' => $row['yr_2015'],
'2014' => $row['yr_2014']
);
}
// For the last one.
$query4_result[] = $record_aux;
I have built an static version of your code to try to reproduce your issue however it worked with no issues.
I think the problem may have something to do with your grouping in the query. Can you maybe show us the result of the query?
I'll note that this is a very special case, hence the question to begin with. Under normal circumstances, such a function would be simple:
I have an array named $post_id, which contains 5 values
(Each numerical)
In order to print each value in the array, I use the following loop:
.
for ($i = 0; $i < $num; $i++)
{
echo $post_id[$i] . ' ';
}
...Which prints the following: 49, 48, 47, 46, 43
3. In my database, I have a table that looks like this:
post_categories
_____________________
post_id | category
__________|__________
43 | puppies
43 | trucks
46 | sports
46 | rio
46 | dolphins
49 | fifa
4. So, using the data in the array $post_id, I'd like to loop a database query to retrieve each value in the category column from the post_categories table, and place them into uniquely named arrays based on the "post id", so that something like...
echo $post_id_49[0] . ' ', $post_id_46[1];
...Would print "fifa rio", assuming you use the above table.
An example of such a query:
//Note - This is "false" markup, you'll find out why below
for ($i = 0; $i < $num; $i++)
{
$query = "SELECT category FROM post_categories WHERE post_id = $post_id[$i]";
fakeMarkup_executeQuery($query);
}
Why is this a "special" case? For the same reason the above query is "false".
To elaborate, I'm working inside of a software package that doesn't allow for "normal" queries so to say, it uses it's own query markup so that the same code can work with multiple database types, leaving it up to the user to specify their database type which leaves the program to interpret the query according to the type of database. It does, however, allow the query to be stored in the same "form" that all queries are, like "$result = *query here*" (With the only difference being that it executes itself).
For that reason, functions such as mysql_fetch_array (Or any MySQL/MySQLi function akin to that) cannot, and will not work. The software does not provide any form of built in alternatives either, effectively leaving the user to invent their own methods to achieve the same results. I know, pretty lame.
So, this is where I'm stuck. As you'd expect, all and any information you find on the Internet assumes you can use these MySQL & MySQLi functions. What I need, is an alternative method to grab one array from the results of a looped query per loop. I simply cannot come to any conclusion that actually works.
tl;dr I need to be able to (1) loop a query, (2) get the output from each loop as it's own array with it's own name, and (3), do so without the use of functions like mysql_fetch_array. The query itself does not actually matter, so don't focus on that. I know what do with the query.
I understand this is horrifically confusing, long, and complicated. I've been trudging through this mess for days - Close to the point of "cheating" and storing the data I'm trying to get here as raw code in the database. Bad practice, but sure as heck a lot easier on my aching mind.
I salute any brave soul who attempts to unravel this mess, good luck. If this is genuinely impossible, let me know so that I can send the software devs an angry letter. All I can guess is that they never considered that a case like mine would come up. Maybe this is much more simple then I make it to be, but regardless, I personally cannot come to an logical conclusion.
Additional note: I had to rewrite this twice due to some un explained error eliminating it. For the sake of my own sanity, I'm going to take a break after posting, so I may not be able to answer any follow up questions right away. Refer to the tl;dr for the simplest explanation of my need.
Sure you can do this , here ( assuming $post_ids is an array of post_id that you stated you had in the OP ), can I then assume that I could get category in a similar array with a similar query?
I don't see why you couldn't simply do this.
$post_id = array(49, 48, 47, 46, 43);
$result = array();
foreach($post_id as $id)
{
//without knowing the data returned i cant write exact code, what is returned?
$query = "SELECT category FROM post_categories WHERE post_id = $id";
$cats = fakeMarkup_executeQuery($query);
if(!empty($cats)) {
if(!isset($result[$id])){
$result[$id] = array();
}
foreach( $cats as $cat ){
$result[$id][] => $cat;
}
}
}
Output should be.
Array
(
[49] => Array
(
[0] => fifa
)
[46] => Array
(
[0] => sports
[1] => rio
[2] => dolphins
)
[43] => Array
(
[0] => puppies
[1] => trucks
)
)
Ok, assuming you can run a function (we'll call it find select) that accepts your query / ID and returns an array (list of rows) of associative arrays of column names to values (row), try this...
$post_categories = [];
foreach ($post_id as $id) {
$rows = select("SOME QUERY WHERE post_id = $id");
/*
for example, for $id = 46
$rows = [
['category' => 'sports'],
['category' => 'rio'],
['category' => 'dolphins']
];
*/
if ($rows) { // check for empty / no records found
$post_categories[$id] = array_map(function($row) {
return $row['category'];
}, $rows);
}
}
This will result in something like the following array...
Array
(
[49] => Array
(
[0] => fifa
)
[46] => Array
(
[0] => sports
[1] => rio
[2] => dolphins
)
[43] => Array
(
[0] => puppies
[1] => trucks
)
)
I started getting into arrays and don't quite get it to work well. I'm used to work with explode/implode functions but I though arrays would make my life easier in this part of the code. Here is the function called:
function save_event($event_items = NULL) {
include 'connect.php';
$now = date("Y-m-d H:i:s");
$sqla = "
INSERT INTO `event`(`event_items`, `event_entered`)
VALUES ('$event_items','$now')";
$resulta = mysqli_query($link, $sqla);
if(!$resulta)
{
echo '<br/>An error occurred while inserting your data. Please try again later.<br/>';
}
else
{ echo 'this is the variable to be stored:<br/>';
print_r($event_items);
$sql = "SELECT * FROM `event` WHERE event_entered = '".$now."'";
$result = mysqli_query($link, $sql);
if($result)
{ while($row = mysqli_fetch_assoc($result))
{ echo '<br/></br>This is the value of the database:<br/>';
print_r ($row['event_items']);
}
}
}
}
This function prints:
this is the variable to be stored:
Array( [0] => Array ( [item] => Powered Speaker [note] => [quantity] => 2 [price] => 200.00 [category] => Audio ) [1] => Array ( [item] => Wireless Microphone [note] => Lavalier [quantity] => 3 [price] => 175.00 [category] => Audio ))
This is the value of the database:
Array
In phpMyAdmin, all I see in the column event_items is the word Array.
Additional info:
I have a table called Groups, each group will have one or multiple orders (another table called Order) and each order will have also one or multiple events (another table). Lastly, each event will have one or multiple items (each item with its corresponding price, quantity, note and category), which are stored in one (or many) columns in the Event table.
Don't try to store an array in one field. You should store each item in the array as it's own row in a related table.
You are trying to insert multiple values in a single database record, this is not impossible but it's also not recommended in general.
The main reason someone would do this would be for optimization, which is not at all something you should worry about for now.
What you really want to do is review your database schema, if you wish to store an array of value, you need to create a new row (record) for each of those. This might necessitate the creation of another table, depending on what you want to do.
You could serialize your array with the serialize() function.
Example:
serialize($event_items);
Generates a storable representation of a value.
This is useful for storing or passing PHP values around without losing
their type and structure.
http://php.net/manual/en/function.serialize.php
I currently have a script that parses a text file with (for example) 100 lines, from 10 different users, and for each line pulls out a $userName, $timestamp and a variety of other things. Is there a way that I can loop through (after it does the parsing) and work with 1 group of $userName at a time.
The end goal is to enter the data into google docs 1 user at a time.
I have tried using $i and $i++ however due to the fact that my primary loop is an array within an array things get a little goofy.
What I would like is the ability to see the following
$userName | $timeStamp
mhopkins321 | 13-12-30
mhopkins321 | 14-59-01
mhopkins321 | 19-32-59
You just have to make the proper array structure:
$users = array(
'mhopkins321' => array(
'13-12-30',
'14-59-01',
...
),
'anotherUser' => array(
...
)
);
So when you're parsing, and run into a username and timestamp:
$users[$username][] = $timestamp;
And when you want to make that table
foreach($users as $user) {
foreach ($user as $timestamp) {
echo $user."| ".$timestamp."\n";
}
}
...probably with better formatting, but there ya go.