i want to make condition with logical operators (&& or ||) into one varialbe with concatination, and then run into if ($var)...
<?php
$ar = array(
'index1' => array('bedrooms'=> '1','suburb' => 'one'),
'index2' => array('bedrooms'=>'2', 'suburb'=>'two')
);
$userValBed = '1';
$userSuburb = 'one';
$c = '';
$c .= '($value["'.'bedrooms'.'"] == "'.$userValBed.'") && ';
$c .= '($value["'.'suburb'.'"] == "'.$userSuburb.'")';
foreach($ar as $key => $value){
if($c): // here occurs problem, please fix this.
// if($value["bedrooms"] == "1" && $value["suburb"] == "one"): // comment this line, and uncommet above 'if'.
echo "<br>";
echo "this condtions matches to ";
echo $key . ' key '. '<br>';
endif;
}
?>
What you could use is a Command pattern. The command pattern seeks to wrap up functionality inside of a class. The advantage of this is that you can swap out functionality at run time by specifying what you would like in the config. Here is a more in depth explanation.
class Command {
function doSomething($v1, $v2);
}
Then you create sub classes of that class:
class CommandAdd extends Command
{
function doSomething($v1, $v2)
{
return $v1 === $v2;
}
}
You can make as many classes with doSomething as you want. Then all you have to do is define your functionality:
$command = new CommandAdd();
if($command->doSomething()) {
// Code here
}
You can specify the type of Command in an external file, or something similar.
Putting code into variables is not a good design. It may work, but it's ugly and hard to understand.
Instead, you may use inner foreach for checking wheter the user's parameters matches the item's parameters.
Anyway, it's even better to store the data in some kind of database, say, SQL database, so the problem will change to: how to create SQL query from user's parameters.
Related
i have some condition if request isset or no and retun in view blade laravel like this:
$compare1 = $request->compare1;
$compare2 = $request->compare2;
if (isset($compare1)) {
$laptop1 = Laptop::where('slug', $compare1)->firstOrFail();
return view('compare.index', ['laptop1' => $laptop1->id]);
} elseif(isset($compare2)) {
$laptop2 = Laptop::where('slug', $compare2)->firstOrFail();
return view('compare.index', ['laptop1' => $laptop1->id, 'laptop2' => $laptop2->id]);
}elseif(isset($compare1, $compare)) {
$laptop1 = Laptop::where('slug', $compare1)->firstOrFail();
$laptop2 = Laptop::where('slug', $compare2)->firstOrFail();
return view('compare.index', ['laptop1' => $laptop1->id, 'laptop2' => $laptop2->id]);
}else {
return view('compare.index');
}
if isset($compare1, $compare) run, $laptop2 not found, any solution for this case...?
Thanks before
The structure you have is incorrect. Currently, your code elseif(isset($compare1, $compare)) will never execute because if either $compare1 or $compare2 are set, your if statement will already exit before it gets to the 3rd one. You also have a lot of redundant code (repeating a line of code depending on which if block is executed) which is easily reduced to fewer lines and cleaner code.
Simple Approach
Consider this; (You should be able to replace your entire if block with this)
//set up an empty array to return
$return = [];
//check if `$compare1` is set, and add to return array if it is
if(isset($compare1)) {
$return['laptop1'] = (Laptop::where('slug', $compare1)->firstOrFail())->id;
}
//same as above but for `$compare2`
if(isset($compare2)) {
$return['laptop2'] = (Laptop::where('slug', $compare2)->firstOrFail())->id;
}
return view('compare.index', $return);
Dynamic Approach
This may be a little bit overkill if you are just doing 2 comparisons but it definitely has some upsides.
Similar amount of code as the simple approach
No need to define separate variables for every comparison (e.g $compare1 = $request->compare1;, etc)
Easily add more comparisons to your return by simply adding them to the $comparisons array
Future Proof
Code:
//empty array to return
$return = [];
//list of variables to compare
$comparisons = ['compare1', 'compare2'];
//loop through each comparison
foreach($comparisons as $key => $request_object) {
$count = $key + 1; //keys start at 0, so we add 1 to make it count sequentially 1,2,3 ...
$comparison = $request->{$request_object}; //grab your comparison object
//check if comparison object is set, add it to return array if it is
if(isset($comparison)) {
$return["laptop{$count}"] = (Laptop::where('slug', $comparison)->firstOrFail())->id;
}
}
return view('compare.index', $return);
Maybe it should be better to split code in parts to improve code quality.
Some thoughts after analyze your code:
Always returns view('compare.index')
Laravel Request contains a has method
Multiple conditional concatenation using if elseif.. (it decrease legibility)
It's more logical to pass the complete model to view instead of only id.
Otherwise, rename var to laptop1Id or similar
Take care of code duplication
Proposal
if($request->has('compare1')) {
$laptop1 = Laptop::where('slug', $request->get('compare1'))->firstOrFail();
}
if($request->has('compare2')) {
$laptop2 = Laptop::where('slug', $request->get('compare2'))->firstOrFail();
}
return view('compare.index', compact('laptop1', 'laptop2'));
If find/search a Laptop is a domain rule, you could encapsulate it in a method/scope in model, querying like:
$laptop = Laptop::findOrFailBySlug($val);
$laptop = Laptop::slug($val)->firstOrFail();
When dealing with arrays I am forced to add a bunch of repetitive code to handle arrays with one child versus multiple:
//If more than one step, process each step, elcse processs single
if(!array_key_exists('command',$pullcase['steps']['step'])) {
foreach($pullcase['steps']['step'] as $step) {
$command=$step['command'];
$parameter=$step['parameter'];
if(isset($step['value'])){
$value = $step['value'];
$this->runCommands($command,$parameter,$value);
} else {
$this->runCommands($command,$parameter);
}
}
} else {
$command = $pullcase['steps']['step']['command'];
$parameter = $pullcase['steps']['step']['parameter'];
if(isset($pullcase['steps']['step']['value'])){
$value = $pullcase['steps']['step']['value'];
$this->runCommands($command,$parameter,$value);
}
else { $this->runCommands($command,$parameter); }
}
As you can see, I'm having to duplicate my efforts depending on if there is a single item in an array versus multiple:
$pullcase['steps']['step'][0]['command']
vs
$pullcase['steps']['step']['command']
How can I simplify this code so that I can use a single variable for all instances?
If you control the creation of the array, make step an array of one even if there is only one so you always have an array. Is that possible?
You either have a step array [step][0][command] or you have a single step [step][command]. So when you create the array instead of [step][command] make it [step][0][command] etc. Standard way of doing it, problem solved as you only need the foreach.
If you can't do it at array creation then consider doing it before the loop:
if(is_array($pullcase['steps']['step'])) {
$steps = $pullcase['steps']['step'];
} else {
$steps[] = $pullcase['steps']['step'];
}
foreach($steps as $step) {
$value = isset($step['value']) ? $step['value'] : null;
$this->runCommands($step['command'], $step['parameter'], $value);
}
Also, if runCommands() can detect a empty argument, then an alternative to the if/else for the function call is used above.
The following may help. It doesn't do much but call the function "runcommands" on a value if the key is 'command'. I am using it to show how you can use array_walk_recursive to possibly solve your problem.
First, you need the function to use:
function runcommandswhencommand($value, $key)
{
if($key == 'command') runcommands($value);
}
Now, you can use the recursive walk on your array:
array_walk_recursive($pullcase, 'runcommandswhencommand');
With this, whenever the key is 'command', the value of that index will be used in the parameter of the function runcommands().
I've been given the task to remove undefined variable and undefined index errors, which i know how to
$value = isset($_POST['value']) ? $_POST['value'] : '';
The problem is this is way too time consuming, I predict over 2000 variables, $_GET, $_POST hasn't been set. So is there a regular expression i can use to set these variables quickly?
How do i do regex to change this $category = $_GET['c'] to this
$category = isset($_GET['c']) ? $_GET['c'] : ''?
And how do i do regex to change if($page or $category or $profile) to this
if(isset($page) or isset($category) or isset($profile))?
This is the best method i can think of by using regex find & replace in Notepad++. I assume over 2000 PHP variable/index undefined errors. How do i solve this without turning off errors?
you should not use regex because it's kind of heavy :)
if i'm understanding your question right, you can do this like this,
with this approach, it does not matter how many parameters contains POST or GET, you simply filter them through foreach loop and getting clean arrays with parameters, also you can make it a function that returning array.and then you just need to check if_array_key_exests() and do your things.
$_POST = ["user"=>"1", "num"=>2];
$_GET = ["user" => '', "num"=>1];
//function method
function filter($array)
{
$arr = array();
foreach ($array as $key => $val) {
if (!empty($val)) {
$arr[$key] = $val;
}
}
return $arr;
}
without function
$post = array();
foreach ($_POST as $key => $val) {
if (!empty($val)) {
$post[$key] = $val;
}
}
$get = array();
foreach ($_GET as $key => $val) {
if (!empty($val)) {
$get[$key] = $val;
}
}
For your first problem, replacing something like
(\$\w+)\s*=\s*\$_GET\[['"]?(\w+)['"]?\]\s*;
by
$1 = isset($_GET['$2']) ? $_GET['$2'] : '';
should work.
Regarding the second, I don't know if this is possible with a variable number of variables. This one works for 3 variables, replace
if\s*\(\s*\s*(\$\w+)\s+or\s+(\$\w+)\s+or\s+(\$\w+)\s*\)
by
if (isset($1) or isset($2) or isset($3))
You can add another \s+or\s+(\$\w+) before the last \s* in the search, and add another or isset($4) in the replacement for 4 variables etc.
I recommend you to replace them one by one instead of replacing all at once ;-)
Also note that if ($a) is not the same as if (isset($a)). Consider something like this:
// query string is a=0
$a = $_GET['a'];
if ($a) // will be false
if (isset($a)) // will be true
if (!empty($a)) // will be false
So, perhaps you want to use !empty() instead of isset(). This should work without notices, too.
resove first issue:
define a function like:
function global_get($key){
return isset($_GET[$key])?$_GET[$key]:'';
}
then use sed(linux tool) to replace all parts like this(it will modify all the $_GET[.*] of php extension files in your project,so be careful to use this):
find /yourproject -name "*.php" -exec sed -i "s/\$_GET\[\([^]]*\)\]/global_get(\1)/" \;
you may modify this command to apply your own demand.
The second issue could be harmful if you use the regex expression because it is hard to make a role rule.so I recommend you to replace manually.
This method takes search a search keyword and parsed mysql query, and rewrites the where expression to include LIKE %keyword%.
It works well, but I dont know if its good or bad practice to have a method with this many loops...
private function build_where($query_array, $options)
{
//add WHERE starting point
$where = '';
if(!empty($query_array['WHERE']))
{
//build where array
$where_array = $query_array['WHERE'];
//start the where
$where .= 'WHERE ';
//get columns array
$columns_array = $this->build_columns_array($query_array);
//if there is a search string
if(!empty($options['sSearch']))
{
//check for enabled columns
$i = 0;
$columns_length = count($columns_array);
for($i; $i < intval($columns_length); $i++)
{
//create the options boolean array
$searchable_columns['bSearchable_'.$i] = $options['bSearchable_'.$i];
}
//loop through searchable_columns for true values
foreach($searchable_columns as $searchable_column_key => $searchable_column_val)
{
if($searchable_column_val == true)
{
//get an integer from the searchable_column key
$column_id = preg_replace("/[^0-9]/", '', $searchable_column_key);
//lookup column name by index
foreach($columns_array as $columns_array_key => $columns_array_val)
{
//if the $columns_array_key matches the $column_id
if($columns_array_key == $column_id)
{
//loop to build where foreach base expression
$i = 0;
$where_length = count($where_array);
for($i; $i < intval($where_length); $i++)
{
//append the existing WHERE Expressions
$where .= $where_array[$i]['base_expr'];
}
//append the LIKE '%$options['sSearch'])%'
$where .= ' AND '.$columns_array_val." LIKE '%".$options['sSearch']."%' OR ";
}
}
}
}
//remove the last OR
$where = substr_replace($where, "", -3);
}
else
{
//loop to build where
$i = 0;
$where_length = count($where_array);
for($i; $i < intval($where_length); $i++)
{
$where .= $where_array[$i]['base_expr'];
}
}
}
//print_r($where_length);
return $where;
}
The school of thought of Kent Beck or Martin Fowler would actually advise you to refactor this large methods down to many small methods. It's not easily read in my opinion, which would be the main reason to refactor.
Breaking up methods is not primarily about reuse. Doing so can make code easier to read, test, and maintain. Clear method names can also substitute for inline comments. This method does two high-level things which could be separated: building a where clause with options and without options. Another hint for me is that the logic that builds the where clause with options looks meaty enough to warrant its own method.
private function build_where($query_array, $options) {
if(!empty($query_array['WHERE'])) {
$where_array = $query_array['WHERE'];
$columns_array = $this->build_columns_array($query_array);
if (empty($options['sSearch'])) {
return $this->build_where_with_options($where_array, $columns_array, $options);
}
else {
return $this->build_where_without_options($where_array, $columns_array);
}
}
else {
return '';
}
}
Now you can quickly scan build_where() to see that there are three possible forms the where clause may take and when along with the input each form needs to produce its result.
Here are some minor improvements you can make throughout your code:
count() returns an integer and doesn't need the intval() calls in your for loops. Even if you left those in, it would be better to apply the call outside the loop so its done only once as it yields the same value each time.
if($searchable_column_val == true) is equivalent to if($searchable_column_val) since both cast $searchable_column_val to a boolean value and the latter passes when that casted boolean value equals true.
$where = substr_replace($where, "", -3) can be replace with $where = substr($where, 0, -3) and is a little clearer.
Instead of looping through an array looking for a specific key you can take advantage of PHP's arrays by simply grabbing the value with that key.
For the last one, this code
foreach($columns_array as $columns_array_key => $columns_array_val)
{
//if the $columns_array_key matches the $column_id
if($columns_array_key == $column_id)
{ ... }
}
can be replaced by this
$columns_array_val = $columns_array[$column_id];
...
Personal preference really. Some programmers would chop this up into several functions. Personally, I think it's fine the way you have it. If I saw something that I thought might be reusable, I'd refactor it out into a separate file that could be included.
In my opinion, some programmers are too quick to make things "reuesable" before they even have something to reuse it with.
I have found a bug report(http://bugs.php.net/bug.php?id=24286) about this though I am not sure if it's relevant to my problem and it's very old. This is my code:
class RegExp {
function name($e){ .... }
function email($e){ .... }
function phone($e){ .... }
}
$regexp = new RegExp();
$final_keys= array("name", "email", "phone");
for($index=0; $index < count($final_keys); $index ++){
if(!$regexp->$final_keys[$index]($_POST[$final_keys[$index]])){
$invalid_uri_vars .= $final_keys[$index].",";
}
else{
$uri_vars = "&".$final_keys[$index]."=".$_POST[$final_keys[$index]];
}
}
What it does is it uses a value from an array as the name of the method to be called. In other words, I am trying to implement a function call using a variable $final_keys[$index] as its name.
*UPDATE: I tried implementing the suggestions below, nothing seems to work. Here's one of my modifications as suggested:
for($key=0; $key < count($final_keys); $key ++){
if(!$regexp->{$final_keys[$key]}($_POST[$final_keys[$key]])){
$invalid_uri_vars .= $final_keys[$key].",";
}
else{
$uri_vars = "&".$final_keys[$key]."=".$_POST[$final_keys[$key]];
}
}
I get the same error as my original code. Another method using call_user_func but I am not sure if did it right:
for($key=0; $key < count($final_keys); $key++){
if(!call_user_func(array($regexp, $final_keys[$key]), $_POST[$final_keys[$key]])){
$invalid_uri_vars .= $final_keys[$key].",";
}
else{
$uri_vars = "&".$final_keys[$key]."=".$_POST[$final_keys[$key]];
}
}
And I get this error: Warning: call_user_func(Array) [function.call-user-func]: First argument is expected to be a valid callback in /.........testreqmeta.php on line 91
I'm still not getting any errors (other than the undefined $key in the second sample) when trying the sample code, so I can't say for certain what will fix it, but here's an approach that simplifies things and gets rid of the array indexing operation: use a foreach loop rather than a for loop.
$query = array();
foreach ($final_keys as $key) {
if(!$regexp->$key($_POST[$key])) {
$invalid_uri_vars[] = $key;
} else {
$query[] = "$key={$_POST[$key]}";
}
}
$uri_vars = implode('&', $query);
I've also replaced the repeated string appends with an array implosion, which should be slightly more performant. It also makes it easier to further process the query string, if necessary, before submitting it. There are better approaches yet, but that's a whole other topic.
NB. RegExp isn't a very good description of what the class does, hence it isn't a very good name. The class may use regular expressions, but it isn't itself a regular expression (which support operations such as "match" and "replace"; RegExp's API has none of these).
Quoting from your link:
ok, here is some workaround on this problem:
in case of
<?
class Test {
var $var = Array('test_function');
function test_function($echo_var) {
echo $echo_var;
}
}
$test_obj = new test;
$test_obj->var[0]('bla');
?>
you can avoid Fatal error in last string using this instead:
<?
$test_obj->{$test_obj->var[0]}('bla');
?>
So then:
if($regexp->{$final_keys[$index]}($_POST[$final_keys[$index]])){
There's a function for what you are trying to achieve call_user_func:
http://de2.php.net/manual/en/function.call-user-func.php