PHP if condition for adding and removing without completely rebuilding - php

I'm creating a PostgreSQL table column management tool to quickly add, remove and rearrange columns in tables. Thus far it is working great in simple scenarios where I simply append a column to the end or remove an existing column. Each of my if conditions call other functions to append a new column, delete an existing column or to rebuild the table as a whole; these functions work great as far as I can currently test.
How do I create an if condition where I'll call both the append function and the delete function instead of the rebuild function?
I have several arrays to help me determine the logic though I'm having trouble getting it worked out. Here are the arrays of column names and again in this scenario I should not be calling the rebuild function, need to call the append function and the delete function.
In this scenario all I'm going to do is delete the column id_2 and add the column id_4 so there is no need to rearrange the order or columns.
$columns_db - The columns as they exist in the PostgreSQL database.
Array
(
[0] => id
[1] => id_1
[2] => id_2
[3] => id_3
)
$columns_updated - The columns in the database that we're going to keep.
Array
(
[0] => id
[1] => id_2
[2] => id_3
)
$columns_submitted - The final way the columns should appear when all is done,
Array
(
[0] => id
[1] => id_2
[2] => id_3
[3] => id_4
)
$columns_slice
$columns_slice = array_slice($columns_submitted,0,(count($columns_updated) - 1),true);
Array
(
[0] => id
[1] => id_2
)
$columns_remove - The column(s) that will be dropped.
Array
(
[1] => id_1
)
$columns_append - The column(s) that will be created.
Array
(
[id_4] => bigint
)

Perform column deletions first
implode column list after deletions ($before = implode($columns_updated);)
implode column list after additions ($after = implode($columns_submitted))
if (strpos($after, $before) === 0) { /* the additions are at the end */ }
Make sure you use the === operator.
As a one-liner:
$rebuild = (strpos(implode($columns_submitted), implode($columns_updated)) !== 0);

I generally prefer straight forward if / else if conditions though it seemed that it would be simply too wildly convoluted to maintain. #AbraCadaver had the good sense to keep the add/remove detection separate which I adapted (would have up-voted if it wasn't deleted). I've tested about a dozen tricky combinations and haven't been able to find any false-positives. Here is the debug version I used to help visualize the logic:
$rebuild = 0;
foreach ($columns_append as $k1 => $v1)
{
//echo '<div class="clear">k1 = '.$k1.'</div>';
if (in_array($k1,$columns_slice)) {$rebuild = 1; break;}
else
{
$columns_submitted_key = array_search($k1,$columns_submitted);
//echo '<div class="clear">columns_submitted_key: '.$columns_submitted_key.', $columns_updated count = '.count($columns_updated).'</div>';
if ($columns_submitted_key<count($columns_updated)) {$rebuild = 1; break;}//echo '<div class="error">Yeah, rebuild here.</div>';
}
}
if ($rebuild>0) {echo '<div class="clear">1, rebuild.</div>';}
else
{
if (count($columns_append)>0) {echo '<div class="clear">2,append</div>';}
if (count($columns_remove)>0) {echo '<div class="clear">3,delete</div>';}
}

Related

PHP - Multiple Time Difference Calculations

For the life of me I cannot find anywhere on the internet that has any documentation on how to solve my problem. I've seen a massive amount of ways to calculate differences in time but I can not seem to put something together that works for my situation.
I'm currently building a time management/ticket system that is a plugin for WordPress. I am using custom tables and not the WordPress tables. I have a table that contains all the main ticket information and another table that contains all the start/stop times. Once the user marks the ticket as complete it will then take all the start/stop time values and calculate the total time spent and then place that total time value into a "total_time" column in the main ticket table.
I'm querying the database and pulling the start/stop times by using:
$start_times = $wpdb->get_results($start_times_query);
$stop_times = $wpdb->get_results($stop_times_query);
Now I have the information in 2 array's. Is this the way I should be doing this?
The array's give me this (for start times):
Array ( [0] => Array ( [time] => 2016-04-29 12:02:43 ) [1] => Array ( [time] => 2016-04-29 12:04:18 ) [2] => Array ( [time] => 2016-04-29 12:06:07 ) [3] => Array ( [time] => 2016-04-29 12:07:56 ) [4] => Array ( [time] => 2016-04-29 12:10:30 ) [5] => Array ( [time] => 2016-04-29 12:11:59 ) )
(Same format for the end times)
Then I break down the array using:
$startTimes = array_column($startTimes, 'time');
$endTimes = array_column($endTimes, 'time');
Which now gives me this as the array (this one is just the start times, but same format for the end times):
Array ( [0] => 2016-04-29 12:02:43 [1] => 2016-04-29 12:04:18 [2] => 2016-04-29 12:06:07 [3] => 2016-04-29 12:07:56 [4] => 2016-04-29 12:10:30 [5] => 2016-04-29 12:11:59 )
Usually I can do a foreach ($start_time as $time){} to itterate through all the values, but (correct me if I'm wrong) I can't put two array's into the foreach brackets and I can't place another foreach statement in the current one because then it will just return all the times for the second array and only return one value for the first array. I feel like I'm missing something simple, what can I do to accomplish this?
EDIT
Thanks to Scopey I've worked out a while loop, but it's not functioning correctly. Here is what I have:
$startTimes = array_column($startTimes, 'time');
$endTimes = array_column($endTimes, 'time');
while (($startTime = current($startTimes)) !== false && ($endTime = current($endTimes) !== false)) {
$startTimesConv = strtotime($startTimes);
$endTimesConv = strtotime($endTimes);
$totalTime = ($startTimesConv - $endTimesConv)/60/60;
next($startTimes);
next($endTimes);
}
If you want to loop two arrays at the same time, you can use the PHP functions for traversing arrays by manipulating their internal pointer: current, next, reset, end and prev.
You just need to make a while loop:
while (($startTime = current($startTimes)) !== false && ($endTime = current($endTimes) !== false) {
// ... Do things
next($startTimes);
next($endTimes);
}
See the documentation for next and current
To iterate two regular arrays with the same length use for instead of foreach:
$length = count($start_times);
for ($i = 0; $i < $length; $i++) {
$start_time = $start_times[$i]["time"];
$stop_time = $stop_times[$i]["time"];
// do things
}
But in your case, I strongly recommend that calculate the differences in SQL.
I would take a step back and look at the queries themselves. You are trying to do a calculation between two times which are related in your database however, the relationship gets lost by separating the times into two separate arrays. Or at the very least is ambiguously related as an array index.
My pseudocode would look like this:
#For each ticket which is closed
#Get an array (time entries) of arrays (start, stop) (each having it's start and stop time)
#total_time = 0
#For each time entry
#Perform a time calc function to get_time_differnce(start, stop)
#Add the time to Total_time
#Add total_time to ticket record in DB
If you showed some more detail I might be able to expand. (i.e The queries themselves)

Combine array items by name with a separator?

I have the following PHP code which runs a MySQL query and returns the results as an array:
function mysql_resultTo2DAssocArray ( $result) {
$i=0;
$ret = array();
while ($row = mysql_fetch_assoc($result)) {
foreach ($row as $key => $value) {
$ret[$i][$key] = $value;
}
$i++;
}
return ($ret);
}
$compare = mysql_resultTo2DAssocArray(mysql_query("SELECT Temp.School, Temp.Status, Snow.Token FROM Temp
JOIN Snow ON Temp.School = Snow.School"));
The results of this look like:
Array
(
[0] => Array
(
[School] => School Name 1
[Status] => Delayed Two Hours
[Token] => Token1
)
[1] => Array
(
[School] => School Name 1
[Status] => Delayed Two Hours
[Token] => Token2
)
)
Is it possible to combine the Token items by a comma within those arrays if the School item is the same for each?
One thing is that it's possible for there to be more arrays within the global array, with different School names, that shouldn't be grouped but left alone. Basically, is it possible to ONLY group when School is the same. It's also possible for there to be more than two tokens.
SELECT Temp.School, Temp.Status, GROUP_CONCAT(Snow.Token) Tokens
FROM Temp JOIN Snow USING (School)
GROUP BY Temp.School
This isn't completely valid, because the Status column is not aggregated or part of the GROUP BY; however MySQL normally allows it (there's an option to disallow it, I don't remember the name offhand). If there are rows with different Status values, it will pick one of them arbitrarily; you didn't say what should happen with different Statuses.

How to group events from different queries together in an array by time

I am pulling out a number of notes associated with a time from my database.
I'm not too hot with multidimensional arrays, but I'd like to group all the events together under the time that they occurred.
Here is one of my queries:
SELECT TIME(date) AS time, followupNote, completed, entityRef
FROM entity_followups
WHERE userRef = ?
AND DAY(date) = ?
AND MONTH(date) = ?
AND YEAR(date) = ?
An example output from this could be three rows, the first column being the time, then the note, completed, then the entityRef.
I want any rows with the same time to be grouped together in the array, e.g.
Array (
[0] => Array (
[0] => 12:00:00
[1] => Array (
[0] => note
[1] => completed
[2] => entityRef
)
[2] => Array (
[0] => note2
[1] => completed2
[2] => entityRef2
)
)
)
But later on there will be other queries that collect other kinds of events which need to be added into the top level array, and if an event has the same time as one in the subarray, it needs to be added into that.
I'll assume that your existing code is enough for getting the time and value. Thus you will have these items in whatever variable or data structure you choose to use. For the purposes of this answer, I will assume these values already exist in the individual variables: $time, $value[0], $value[1], and $value[2]. Further, I will assume that the results are being loaded into the array $timesAndValues[]
I think the key is to have the $timesAndValues[] array indexed on the corresponding time:
if (isset($timesAndValues[$time]))
{ //The corresponding sub-array already exists, so we just need to load it
//Push the array of values into the sub-array
array_push($timesAndValues[$time], $value);
}
else
{ //The corresponding sub-array does not exist yet, so we need to create it and load it
//Create the sub-array
$timesAndValues[$time] = array($time);
//Push the array of values into the sub-array
array_push($timesAndValues[$time], $value);
}

MongoDB Group Array Value exists Check

I have a Entries looks like
[Title] => test - Title - 33
[readedBy] => Array (0 => 5999,
1 => 85343
)
[clickedBy] => Array (
)
[deletedBy] => Array (
)
And i want to Check in my GROUP reduce function
function (obj, prev) {
obj.readedBy.forEach(function (doc){
if(doc == 800){
prev.status1.push(obj);
}else{
prev.status2.push(obj);
}
});
}
If is there my ID in the Relevan Array to push it to the right Status Array.
Foreach is no solution, because that ID array grows > 100k .
Is there a good way? Or is that solution rubbish ?
So far using mongodb map / reduce from what I've gathered, most of the time when you use map reduce you are going to suffer from an O(n) process, which means you will end up doing .forEach() on your result sets. They get faster as you add nodes. as you shard your collections.

PHP 5.2 Function needed for GENERIC sorting of a recordset array

Somebody must have come up with a solution for this by now. We are using PHP 5.2. (Don't ask me why.) I wrote a PHP class to display a recordset as an HTML table/datagrid, and I wish to expand it so that we can sort the datagrid by whichever column the user selects. In the below example data, we may need to sort the recordset array by Name, Shirt, Assign, or Age fields. I will take care of the display part, I just need help with sorting the data array.
As usual, I query a database to get a result, iterate throught he result, and put the records into an assciateiave array. So, we end up with an array of arrays. (See below.) I need to be able to sort by any column in the dataset. However, I will not know the column names at design time, nor will I know if the colums will be string or numeric values.
I have seen a ton of solutions to this, but I have not seen a GOOD and GENERIC solution Can somebody please suggest a way that I can sort the recordset array that is GENERIC, and will work on any recordset? Again, I will not know the fields names or datatypes at design time. The array presented below is ONLY an example.
UPDATE: Yes, I would love to have the database do the sorting, but that is just not going to happen. The queries that we are running are very complex. (I am not really querying a table of Star Trek characters.) They include joins, limits, and complex WHERE clauses. Writing a function to pick apart the SQL statement to add an ORDER BY is really not an option. Besides, sometimes we already have the array that is a result of the query, rather than the ability to run a new query.
Array
(
[0] => Array
(
[name] => Kirk
[shrit] => Gold
[assign] => Bridge
)
[1] => Array
(
[name] => Spock
[shrit] => Blue
[assign] => Bridge
)
[2] => Array
(
[name] => Uhura
[shrit] => Red
[assign] => Bridge
)
[3] => Array
(
[name] => Scotty
[shrit] => Red
[assign] => Engineering
)
[4] => Array
(
[name] => McCoy
[shrit] => Blue
[assign] => Sick Bay
)
)
Well, first off, you should be sorting in the database (it's more efficient). If not
In php 5.3+:
function getSortCommand($field, $sortfunc) {
return function($var1, $var2) use ($field, $sortfunc) {
return $sortfunc($var1[$field], $var2[$field]);
}
}
in php <= 5.2, you'll need to create a pure function:
function getSortCommand($field, $sortfunc) {
return create_function('$var1, $var2', 'return '.$sortfunc.'($var1["'.$field.'"], $var2["'.$field.'"]);');
}
Usage for both:
$array = usort($array, getSortCommand('name', 'strnatcasecmp'));
To adjust the field, you just change the $field parameter. To change the sort function, just change the $sortfunc parameter...
I suggest you do it in the database. Otherwise, you can use this:
function sortby(&$arr, $column) {
usort($arr,
function ($a, $b) use ($column) {
return strcmp($a[$column], $b[$column]);
}
);
}
You should definitely do the sorting when querying the database.
You do this by adding a link like ?orderby=name&dir=asc to the <TH>s
Then when you query the database you check for the existence of $_GET['orderby']. If it exists you add an order by clause.
A clientside option is http://tablesorter.com/docs/

Categories