Is there a way to reduce multiple comparison with similar parameters? - php

I am using php as backend of a website. I made a form of around 50 questions and I have to store it in a table every single time I answer something different.
So my first newbie thought was to compare the $request->Question1 with the $table->Question1 and if this is different, I create a new record on the History table.
But it took my to an endless and nothing good looking comparison lines, repeating some of the code like:
if ($table->Question1 != $request->Question1)
{
$Question = new HistoryTable();
$Question ->reason = 'Change Answer';
$Question ->column_affected = 'Question1';
$Question ->old_value = $table->Question1;
$Question ->new_value = $request->Question1;
$Question ->created_at = Carbon::now();
$Question ->save();
}
Is there a way it could be reduced ? I was thinking in using a form, but I have to mention I have columns/values as Question23_1 and Question23_2 ... but they are the same name as in table
Thanks in advance!

Well, some might suggest a different database-table architecture – one that does not involve these "repeating groups." But there might be other compelling reasons to have done what you did.
Maybe you could retrieve the record, instead of as a "PHP object," as an array ("hash" ...) indexed by field-name. Then you could use interpolation of strings such as "Question$x_$y" ... substituting the values of $x and $y to obtain the name of the field whose value you are now interested in ...

Related

Perform operations after extract()

I have been looking for an answer, but maybe because I am searching the wrong terms or concepts - I did not yet find any lead on how to perform operations on extracted arguments .
I have an array, which is dynamic ( I can not predict how many $vars or of what name or type )
global $o99_option;
extract( $o99_option );
so now, theoretically, I can have any number of $vars with any possible name..
example :
$first_var = 'first-var';
$my_second_var = 'another';
$enigma = NULL;
$answer = '42';
my question is - how can I perform operations on the result of extract ( after extraction ) in a manner that will effect all the created $vars ?
for example, let´s say I want to trim all of those variables - How do I achieve that ?
( that , In my twisted mind, should have the same effect as
foreach (extract( $o99_option ) as $single_var ){
do_something($single_var);
}
)
Edit I : So, is there a way to perform operations on all extracted elements ? ( assuming I DO need to extract them ..) Or should I always do that BEFORE the extraction ( for example with the help of array_map() ) - or, should I , like people here suggested just forget that extract ever existed never ever use it..
Edit II :
Sure, like many here said , I can also do
$first_var = $o99_option['first-var'];
$my_second_var = $o99_option['my_second_var'];
$enigma = $o99_option[enigma];
$answer = $o99_option['answer'];
but
1) it seems a little absurd doing that for 100+ variables, and
2 ) what to do with the ones that I need to use their value as name ?
right now, for example, I use
${$title_field} = $formdata[$post_title_field];
where I know that $title_field exists as $o99_option['title_field'], and therefore exists as a variable after extract ..
Again, I might be approaching that all wrong, but up until now the script works great , and actually , the first comment by #Mark Baker ( using array_map() ) might be the best option when doing so BEFORE the extract ...
You must not extract the variables, you need to keep them in the $o99_option array otherwise it's impossible to determine the number of elements.
foreach ($o99_option as $variable) {
// Do something with the variable
}
Imagine you're sitting in one of those kids ball pits. This is your variable scope. You have all sorts of variables floating around in this scope. Now you get handed a box full of even more colourful balls. Those balls are important balls, they're more interesting to you than all the other balls around you.
What you're doing with extract is you're turning the box upside down and empty all those balls into the ball pit and mix them with all the other balls. And you didn't even really know what balls were in that box exactly, but you emptied the box anyway. Well, good luck finding those balls again now and doing anything with them.
Keep the balls in the box! While they're in the box, you can inspect them one by one. You can look at each one in turn and do something with it. You can carry them all around inside that box together. Don't extract!
If you know what you're looking for in that box:
echo $o99_option['first-var'];
Simple. Just take that ball directly and do whatever you want with it.
If you want to check whether a specific ball is in the box:
if (isset($o99_option['first-var']))
If you want to look through all balls and do something with each of them:
foreach ($o99_option as $name => $ball) {
echo "$name: $ball";
}
If you want to do something to all the variables:
foreach ($o99_option as &$variable) {
$variable = strtoupper($variable); //for example
}
Then you should work with each element individually. Don't extract.

Sorting table contents with php? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I have a table full of band listings for our Musician Finder program. We want to sort them by genre while still only having one .html or .php file containing all the information.
How would I even start to do this? Preferably with php and avoiding JS because most of our users have noscripts.
Here is a link to the test page HERE. Any suggestions would be great or even just an example of where someone else has done it.
And here is the table on paste bin.
Thanks
Also, avoiding SQL is a priority to my boss.
EDIT: So apparently this isn't feasible in php. I'd be willing to use javascript. Or Jquery. If this was just a simple table I'd be fine but obviously mine is more detailed and I don't know where to start and haven't found anything on google. If anyone wants to kindly suggest anything about this that'd be great but honestly nobody comes on here to read about how someone else doesn't like that I asked a question on stackoverflow. Lol.
EDIT AGAIN: Ok so I was looking more... And why can't I just make all my <tr>'s have display:block; per class in css, then use a JS function to change all but the right class to display:none;? This would be extremely simple.
#robert is correct as you can't sort elements on the page without using some javascript. so if you want to sort your table with php, you have to start by putting the contents of your table into data set of some sort, like a large array. from what i understand of what you're looking to do is that every row of your table falls into one of your sortable categories. so then when defining your array, you have to specify what category each row falls under and then sort on that field.
so your array definition could be something like this:
$master_array[] = array(
'category' => 'acoustic',
'tr_html' => '<tr><td> .... </td></tr>'
);
then sort the array on the category field. a bit of googling will help you with this.
then when it comes to writing the table, just do:
echo "<table>";
foreach( $master_array as $key => $val ) {
echo $val["tr_html"];
}
echo "</table>";
hope this helps...
If you create a 'Table' object in php, with a $tbl = array(0 => $arr_row1, 1 => $arr_row2) etc. property, then you can easily create a view method to render the $tbl in html using a loop. (All $arr_rowx are associative arrays with the same column names as keys.)
Then you can use this method to order or reverse order $tbl on a string column key:
public function order($str_key_name, $bool_reverse = false) {
$code = "return strnatcmp(\$a['$str_key_name'], \$b['$str_key_name']);";
usort($this->tbl, create_function('$a,$b', $code));
if ($bool_reverse) $this->tbl = array_reverse($this->tbl);
return $this->tbl;
}
and to re-index sequentially on an integer column:
public function reIndex($str_index_name, $int_start_index = 0) {
if ($this->tbl) {
$num = count($this->tbl);
for ($i = 0; $i < $num; $i++)
$this->tbl[$i][$str_index_name] = ($i + $int_start_index);
}
return $this->tbl;
}
Using an existing table plugin in JavaScript would probably be the best solution for you since it would avoid the round trip back to the server to do something that JavaScript can do quite easily. But seeing that you say that JavaScript is not your first option then you can do it in PHP if you choose to store all the data in a PHP array.
So you start by putting all the data into PHP arrays. Then write a function that will sort the array by whichever field you wish. There are many sorting algirithms available for this.
Display the table of data in its default order and add links that will let the user select a different column to sort. In each link you set the name of the column to sort by like this:
Sort By Name
You can then simply use the parameter "sort" to decide how to sort your array before you echo it out into an HTML table.
I ended up using jquery. Anyone that doesn't have JS on just won't be able to sort haha. Thanks for the suggestions guys.

How to bulk insert with RedBeanPhp?

I was hoping for an example on how to bulk insert new "beans" in readbeanphp without looping over each instance.
It shows an example creating and saving a beans here: http://redbeanphp.com/manual/create_a_bean
It makes mention of storeAll($beans) method, but I am unsure exactly how I am suppose to format the data in $beans.
I have tried googling for this and can not find anything related to bulk inserts. Maybe I have searched for the wrong terms.
I am new to this ORM, any help with would appreciated, thanks!
You are definitely right on track. Create a new bean using $bean=R::dispense('bean'); or multiple beans as an array $beans=R::dispense('bean',5);
Then you populate the beans with data:
$bean->title='Hello World!';
//or with an array
$beans[0]->title='Hello World!';
$beans[1]->title='Hello World! Bean 1';
//etc
Then store the bean(s):
R::store($bean);
//or
R::storeAll($beans);
All the beans must be the same type if you have multiples as far as I know, so you can do something like:
$beans=array();
$beans[]=R::dispense('bean');
$beans[]=R::dispense('bean');
$beans[0]->title='Hello World!';
$beans[1]->title='Hello World!1';
R::storeAll($beans);
I could be wrong about that though. The main thing is that this is all a typical ORM, but redbean also supports regular SQL if you need to use it. Hope that helps!
Some real data behind this approach.
FIRST APPROACH.
foreach item found
$bean = R::dispense('bean');
$bean->title = "hello";
R::store("bean");
time taken for 5660 rows = 43s on my mac
SECOND APPROACH.
$beans=array();
$beans[]=R::dispense('bean');
$beans[]=R::dispense('bean');
$beans[0]->title='Hello World!';
$beans[1]->title='Hello World!1';
R::storeAll($beans);
For 5660 rows, 46s. The storeAll is where all the time is. So its taking ages to store these beans.
THIRD APPROACH
$beans=R::dispense('bean',5560);
for loop
$bean[$i]->title = "hello world";
end for
R::storeAll($beans);
For 5660 rows 45s.
Result. None of these approaches are any quicker. : (
RedBean Transactions didn't seem to make this any quicker either
From the creator of RedBean https://stackoverflow.com/a/18811996/445492 Bulk Insert is not supported, use pure sql.
FOURTH APPROACH
for loop
R::exec("insert into bean(title) values (1,'hello world')");
end for
for 5660 rows 7.3s <----- WOW
(please note: I am actually doing some stuff prior so all these results are -4.3 seconds.)
Hence every bean needs to be created first and the method to create a bean is dispense
$bean = R::dispense('customers');
$bean->name = "John";
R::store($bean);
$bean->name = "Walter"
R::store($bean);
the code above creates only one bean even after storing it. Still $bean refers to the same object, so for each record you have to create a new been by using dispense method.
Luckily we have storeAll method that stores all the beans but it requires an array of beans. So we create a bean in each iteration and push it to the array and then at the end of loop we just pass that array to storeAll function.
//create empty array
$beans = array();
//for each customer post create a new bean as a row/record
foreach ($post as $customer) {
$bean = R::dispense('customers');
//assign column values
$bean->firstName = $customer['first_name'];
$bean->lastName = $customer['last_name'];
//push row to array
$beans[] = $bean;
}
//store the whole array of beans at once
R::storeAll($beans);
In the approaches 1, 2 and 3 suggested by John Ballinger, one way to optimize the run time is to put all the insertions performed by storeAll($beans) inside one database transaction. This could be done as follows: replace the line "R::storeAll($beans)" by the following three lines:
R::begin();
R::storeAll($beans);
R::commit();
This approach reduces dramatically the run time when the array $beans is large, AND is not necessary to use SQL "explicitly".

PHP Compare Two Arrays?

I'm trying to compare two entries in a database, so when a user makes a change, I can fetch both database entries and compare them to see what the user changed, so I would have an output similar to:
User changed $fieldName from $originalValue to $newValue
I've looked into this and came across array_diff but it doesn't give me the output format I need.
Before I go ahead and write a function that does this, and returns it as a nice $mtextFormatDifferenceString, can anyone point me in the direction of a solution that already does this?
I don't want to re-invent the wheel..
Since you require "from $originalValue to $newValue", I would go ahead and select the two rows, put them in assoc arrays, then foreach through the keys, saving the ones that aren't equal. Kind of like:
$fields = array_keys($row1);
$changedFields = array();
foreach ($fields as $field) {
if ($row1[$field] != $row2[$field]) {
$changedFields[] = $field;
}
}
I realize you were asking about the existence of pre-built wheels but I felt the solution was pretty simple.
?>
Although you didn't define what format you needed, but well-known diff algorithm is probably for you. Google for PHP diff algorithm and you'll find some suggestions I am sure.
You could get the changed values ($newValue) with array_diff_assoc and then just use the keys ($fieldName) to find the original value $originalValue and output it in anyformat you want

Most efficient way to get data from the database to session

What is the quickest way to get a large amount of data (think golf) and the most efficient (think performance) to get a large amount of data from a MySQL database to a session without having to continue doing what I already have:
$sql = "SELECT * FROM users WHERE username='" . mysql_escape_string($_POST['username']) . "' AND password='" . mysql_escape_string(md5($_POST['password'])) . "'";
$result = mysql_query($sql, $link) or die("There was an error while trying to get your information.\n<!--\n" . mysql_error($link) . "\n-->");
if(mysql_num_rows($result) < 1)
{
$_SESSION['username'] = $_POST['username'];
redirect('index.php?p=signup');
}
$_SESSION['id'] = mysql_result($result, '0', 'id');
$_SESSION['fName'] = mysql_result($result, '0', 'fName');
$_SESSION['lName'] = mysql_result($result, '0', 'lName');
...
And before anyone asks yes I do really need to 'SELECT
Edit: Yes, I am sanitizing the data, so that there can be no SQL injection, that is further up in the code.
I came up with this and it appears to work.
while($row = mysql_fetch_assoc($result))
{
$_SESSION = array_merge_recursive($_SESSION, $row);
}
Most efficient:
$get = mysql_query("SELECT * FROM table_name WHERE field_name=$something") or die(mysql_error());
$_SESSION['data'] = mysql_fetch_assoc($get);
Done.
This is now stored in an array. So say a field is username you just do:
echo $_SESSION['data']['username'];
Data is the name of the array - username is the array field.. which holds the value for that field.
EDIT: fixed some syntax mistakes :P but you get the idea.
OK, this doesn't answer your question, but doesn't your current code leave you open to SQL Injection?
I could be wrong, never worked in PHP, just saw the use of strings in the SQL and alarm bells started ringing!
Edit:
I am not trying to tamper with your post, I was correcting a spelling error, please do not roll back.
I am not sure what you mean by "large amounts of data", but it looks to me like you are only initializing data for one user? If so, I don't see any reason to optimize this unless you have hundreds of columns in your database with several megabytes of data in them.
Or, to put it differently, why do you need to optimize this? Are you having performance problems?
What you are doing now is the straight-forward approach, and I can't really see any reason to do it differently unless you have some specific problems with it.
Wrapping the user data in a user object might help some on the program structure though. Validating your input is probably also a good idea.
#Unkwntech
Looks like you are correct, but following a Google, which led here looks like you may want to change to mysql_real_escape_string()
As for the edit, I corrected the spelling of efficient as well as removed the "what is the".. Since that's not really required since the topic says it all.
You can review the edit history (which nicely highlights the actual changes) by clicking the "edited a min ago" text at the bottom of your question.
Try using json for example:
$_SESSION['data'] = json_encode(mysql_fetch_array($result));
Is the implementation of that function faster than what he is already doing?
Does anyone else have trouble entering ] into markdown? I have to paste it in
Yes, it's bugged.
#Anders - there are something like 50-75 columns.
Again, unless this is actually causing performance problems in your application I would not bother with optimizing it. If, however, performance is a problem I would consider only getting some of the data initially and lazy-loading the other columns as they are needed.
If Unkwntech's suggestion does indeed work, I suggest you change your SELECT statement so that it doesn't grab everything, since your password column would be one of those fields.
As for whether or not you need to keep this stuff in the session, I say why not? If you're going to check the DB when the user logs in (I'm assuming this would be done then, no?) anyway, you might as well store fairly non-sensitive information (like name) in the session if you plan on using that information throughout the person's visit.
It's not so much that it causing performance problems but that I would like the code to look a bit cleaner.
Then wrap the user data in a class. Modifyng $_SESSION directly looks somewhat dirty. If you want to keep the data in a dictionary—which you can still do even if you put it in a separate class.
You could also implement a loop that iterates over all columns, gets their names and copy the data to a map with the same key names. That way your internal variables—named by key in the dictionary—and database column names would always be the same. (This also has the downside of changing the variable name when you change the column name in the database, but this is a quite common and well-accepted trade-off.)
Try using json for example:
$_SESSION['data'] = json_encode(mysql_fetch_array($result));
Edit
Later you then json_decode the $_SESSION['data'] variable and you got an array with all the data you need.
Clarification:
You can use json_encode and json_decode if you want to reduce the number of lines of code you write. In the example in the question, a line of code was needed to copy each column in the database to the SESSION array. Instead of doing it with 50-75 lines of code, you could do it with 1 by json_encoding the entire database record into a string. This string can be stored in the SESSION variable. Later, when the user visits another page, the SESSION variable is there with the entire JSON string. If you then want to know the first name, you can use the following code:
$fname = json_decode($_SESSION['data'])['fname'];
This method won't be faster than a line by line copy, but it will save coding and it will be more resistant to changes in your database or code.
BTW
Does anyone else have trouble entering ] into markdown? I have to paste it in.

Categories