Is there a way to create a dynamic sql query so that certain where clauses only run if a variable isn't null?
So say a user can select various options to filter results and they can chose not to select a an option from certain dropdowns if they don't need to. That would result in certain variables being null.
I'd like to do it in a way that wouldn't result in writing if statements to cater for every eventuality.
Don't mind suggestions in PHP or Laravel specific answers.
Thanks!
I'd prefer the if statements, but you can look into the Coalesce operator: http://dev.mysql.com/doc/refman/5.0/en/comparison-operators.html#function_coalesce
Create a client-side jQuery function
One of the things you could do is write a bit if jQuery that goes through all your input client-side and only submits the input where the value is not empty/null. The jquery code could be used for all your forms or input data. So you simply never get the passed parameters that have null values coming into your server-side controller (and eventually into your dynamic query). You can find solutions in this stackoverflow question here for this. Personally, I just have all my input in a class and cycle through it to remove the empty values. See my simple Fiddle here. You can even create special conditions for special types of inputs, that way your script covers for all types of null/empty/etc if you wanted.
OR
Create a helper function in PHP/Laravel
You could also do this server-side. You could write a helper function that loops through all your input coming in and removes the empty inputs. It could also build the WHERE clause at the same time for you (either raw, or you could pass your query object into the helper and it could add each ->where as it loops through the input and returns the query object back to you).
$query = DB::table('my_table')->select('abc', 'xyz');
// This could be your helper. Pass in your query and input...
dynamicWhereHelper($query, Input::all());
$rows = $query->get();
and in your dynamicWhereHelper:
function dynamicWhereHelper($query, $input = array())
{
// Assuming you named each of your inputs the same as your database fields
foreach ($input as $key => $value){
if(!empty($value)){
$query->where($key, $value);
}
}
}
NOTE: A safer approach would be to additionally pass an array of acceptable input names in order to verify that no random $key is passed into the WHERE. You can define this array once per page you build, and it could be used to both build your form and then later used in the helper: dynamicWhereHelper($query, Input::all(), $acceptableInputs);
Related
I'm creating a HTML form that had a dynamically-generated list of select inputs. I'd like to cycle through these inputs (in the $_POST array) with a foreach block and make updates in the DB based on the information in each of these inputs. I know I have to name each select input something different so I've appended a unique identifier onto the inputs name (i.e. name="confidenceLevel45").
Is there are a way to preg_match the associative keys in the $_POST array and have a callback to process the values associated with them? Is there another way to do this besides regex'ing the $_POST array keys? I feel like this is a fairly common occurrence in application development but, for some reason, I can't find any answers online. I rather not make an AJAX call and use jQuery to process such a form...
Thank you in advance!
I don't have the reputation to make comments, slightly confused by what you are attempting to do and whether you want to process this client side in jQuery or server side in PHP.
If you want to process on the server side you could foreach over the $_POST array and match the key value to a switch case or condition:
foreach ($_POST as $key => value) {
switch ($key) {
case 'foo':
callToFunctionA($value);
break;
case 'bar':
callToFunctionB($value);
break;
}
if ($key == 'fizzbuzz') {
callToFunctionC($value);
}
}
Where your cases or conditions match up to the name attributes on your form.
I was dealing with security, and I came up with an idea:
if (!isset($_POST['id']))
{
$_POST['id'] = 0;
}
$_POST['id'] = (int)$_POST['id']; // kill SQL injection
but what if id was an array? It would force this method to knee! But I dont know if its even possible to generate array.
Don't reinvent the wheel: php has a nice set of filters to deal with $_GET and $_POST: see http://php.net/filter - there are filters even for arrays.
If in your form you have a <SELECT multiple>, which will send out an array of options picked by the user, the name must be something like name="MySelection[]" instead of a plain name="MySelection". In this way, with the square brackets, an array will be automatically generated, and it will be $_POST['MySelection'][0], $_POST['MySelection'][1] and so on. You can loop on it with a the usual foreach.
I'm developing a website in CodeIgniter. It's kind of basic, except it has some enormous forms (150 fields) some dynamically created/locked/predefined/removed etc..
I'm having trouble doing the transition between the form and the database, which of course is very complicated. What I mean is that the submit of the form inserts more than one line in some tables and some data is not even saved. (some radio buttons etc..)
I have created a very large object with as many properties as possible named after the form input names in order to fill with the $_POST data using:
foreach ($largeObj as $key=>$value)
{
if (isset($_POST[$key])){
$largeObj[$key]=$value; //mind the data escaping
}
}
Of course this only works for half the inputs, for the others I need to do something like this:
$largeObj['tanks']=Array();
for ($i=0;$i<$_POST['nbrTanks'];$i++){
$tank=new Tank();
// some if's in order to set some properties
$largeObj['tanks'][]=$tank;
}
Then I do all the calculations and prepare my DTO's to insert in each table the corresponding data. Btw I used PHPDAO to map the database tables as they were a bit too large to write the entire CRUD operations.
Is there a better approach? something annotation-driven or a more efficient way because I also need to fill the entire forms with the data from my DB. Any suggestions are welcome.
If you have a list of the inputs that go to either method, you can do something like this:
##Array of items to be checked with `isset()`
$array_isset = array('field1', 'field2', 'field3');
foreach ($array_isset as $line) {
#.... same thing you did before
}
$array_tank = array('field4', 'field5', 'field6');
foreach ($array_tank as $line) {
$tank = new Tank()
}
If I understand your question, the above method would allow you to sort the fields by the operations that need to be performed on them.
That being said, I've had multiple projects where I've had to deal with large amounts of information. What I found, every single time, was that the best approach is to find a way to put the raw data in to the database, and perform your calculations at a later date.
This also makes it easy, because in CodeIgniter, you can just do this:
$array = $this->input->post(NULL, True);
$this->db->insert('table', $array);
If your form fields match up with your database column names.
If you have a list of data, then you can store the data as a comma-separted list like this:
$array = array('value1', 'value2', 'value3');
$insert_string = implode(',', $array);
And explode it when you select it.
This may not work in your situation, but it does have value in certain situations.
Good luck with your application; I hope I helped!
I am trying to save some db action by compiling a looped bit of code with a single query, Before I was simply adding to the the like statements using a loop before firing off the query but i cant get the same idea going in Mongo, id appreciate any ideas....
I am basically trying to do a like, but with the value as an array
('app', replaces 'mongodb' down to my CI setup )
Here's how I was doing it pre mongofication:
foreach ($workids as $workid):
$this->ci->app->or_like('work',$workid) ;
endforeach;
$query = $this->ci->db->get("who_users");
$results = $query->result();
print_r($results);
and this is how I was hoping I could get it to work, but no joy here, that function is only designed to accept strings
$query = $this->ci->app->like('work',$workids,'.',TRUE,TRUE)->get("who_users");
print_r($query);
If anyone can think of a way any cunning methods I can get my returned array with a single call again it would be great I've not found any documentation on this sort of query, The only way i can think of is to loop over the query and push it into a new results array.... but that is really gonna hurt if my app scales up.
Are you using codeigniter-mongodb-library? Based on the existing or_like() documentation, it looks like CI wraps each match with % wildcards. The equivalent query in Mongo would be a series of regex matches in an $or clause:
db.who_users.find({
$or: [
{ work: /.*workIdA.*/ },
{ work: /.*workIdB.*/ },
...
]});
Unfortunately, this is going to be quite inefficient unless (1) the work field is indexed and (2) your regexes are anchored with some constant value (e.g. /^workId.*/). This is described in more detail in Mongo's regex documentation.
Based on your comments to the OP, it looks like you're storing multiple ID's in the work field as a comma-delimited string. To take advantage of Mongo's schema, you should model this as an array of strings. Thereafter, when you query on the work field, Mongo will consider all values in the array (documented discussed here).
db.who_users.find({
work: "workIdA"
});
This query would match a record whose work value was ["workIdA", "workIdB"]. And if we need to search for one of a set of ID's (taking this back to your OR query), we can extend this example with the $in operator:
db.who_users.find({
work: { $in: ["workIdA", "workIdB", ...] }
});
If that meets your needs, be sure to index the work field as well.
Basically, I have working solution for this, but I'm wondering if it could (should?) be done better in some other way.
I have table I'm creating in PHP with values from MYSQL. Each item in table has multiple values. In each line there is single link and clicking on this link fires up jQuery function. In each link there is also VALUE attribute with values from multiple MYSQL fields and joined with &&:
PHP code is:
foreach ($this->_data as $l)
{
?>
...
<td>Link</td>
...
<?php
}
And jQuery function to fire up when clickin' on link is:
$(".clickMe").click(function() {
myData = $(this).attr('value').split('&&');
});
Script splits string in VALUE attribute on && and creates an array myData with values:
myData[0] => value passed from $l->_data1 in PHP
myData[1] => value passed from $l->_data2 in PHP
Is this the right way to do it?
It's fine, as long as you'll never have && in your data. You could use json_encode() in PHP and then decode this into an array in JavaScript. That would be a more standard solution.
I would recommend against using && which looks like a boolean AND. Instead I would probably use something like a pipe to separate them val1|val2.
I think you're better off passing the whole joined string in to PHP and splitting it out there. It saves you work on both ends having to put the two resultant values into the proper post or get variables to send to PHP.
Then on the PHP side, it's a little easier to validate the one value's format before splitting it, as you can use a single regex like:
// Validate both values at once: 1 or more digits, a pipe, and one or more digits
if (preg_match('/^(\d+)\|(\d+)$/', $_POST['jqueryinput'])) {
// explode() and use in PHP...
list($val1, $val2) = explode("|", $_POST['jqueryinput']);
}