I have two function to add remove parameters to the query string. The "add_query_params" (thanks to this forum) is working nicely and I can now add multiple tags to the query string of the same type.
For example
http://example.com?tags[]=flowers&tags[]=shrubs&category[]=garden
As you can see, I can add multiple of the same parameters, I am also querying these nicely using queryfilters.
However my newest problem, is simply removing a single tag type without affecting the rest of the query string. I will then rebuild the query without the deleted tag.
Someone kindly yesterday helped me to to a point but this removes ALL tag key values, not just the specified tag.
So if I was to delete say $tags[]shrubs from the above URL it would actually delete BOTH tag[]shrubs AND $tags[]flowers.
This obviously isn't very intuitive for a filter system I am devising. What I would like to know is how to remove just the single key value pair and leave the other keys pairs intact.
Here is my helper function
//Accept a param array which passthrough through tag type eg category/tag and value
function remove_query_params(array $params = [])
{
//Set to array
$existingParams = [];
$existingParams = request()->query();
foreach($params as $key=>$value){
if (isset($existingParams[$value])) {
unset($existingParams[$value]);
}
}
$query = http_build_query($existingParams);
return url()->current() . '?' . $query;
}
//Need to return: user removes tag from filter in blade, URL recontructs without the passed through tag value
//Before
//http://example.com?tags[]=flowers&tags[]=shrubs&category[]=garden
//After
//http://example.com?tags[]=flowers&category[]=garden
This does not work, if I change $value to $key then it will will, but it will remove all keys of the same type, not the behaviour I would like.
I activate this behaviour via a call in the blade template, this forms a href
//Pass through parameter type and parameter value
{{remove_query_params(['category' => $category->id]) }}
Has anybody got any pointers as to where I go next?#
Thanks and fingers crossed I am not far off :)
Adam
I hope this solution will help you:
<?php
function remove_query_params(array $params = [])
{
//Set to array
$existingParams = [
'tags' => [
'aaaa',
'bbbb'
],
'category' => 'ccc'
];
// go trough all parameters
foreach ($existingParams as $key1 => $value1) {
// go to the parameters, which need to be deleted
foreach ($params as $key2 => $value2) {
// only if the keys equals, do something
if ($key1 === $key2) {
// if the param is an array
if (is_array($value1)) {
foreach ($value1 as $k => $v) {
// if the elements to delete are an array
if (is_array($value2)) {
foreach ($value2 as $b => $r) {
if ($v == $r) {
unset($existingParams[$key1][$k]);
}
}
} else {
if ($v == $value2) {
unset($existingParams[$key1][$k]);
}
}
}
} else {
if (isset($existingParams[$key2])) {
unset($existingParams[$key2]);
}
}
}
}
}
$query = http_build_query($existingParams);
return $query;
}
echo remove_query_params(['tags' => 'aaaa']);
echo "\n";
echo remove_query_params(['tags' => ['aaaa', 'bbbb']]);
echo "\n";
echo remove_query_params(['category' => 'ccc']);
echo "\n";
tags is not an associated array. It is just a list of strings. Also, look at the value of $existingParams = request()->query(); It is not the tags array. It is an object that contains it. That is why when you use $key it works but deletes everything because $key is tags. So, in your check $existingParams['tags'] should be checked for the shrubs value. in_array is what you are looking in this case.
Hope this will solve your problem.I just provided the core function to get the things done in a way
$query = "tags[]=flowers&tags[]=shrubs&category[]=garden";
echo (remove_query_params( [ 'tags' => 'shrubs' ], $query ));
function remove_query_params(array $params = [], $query )
{
parse_str( $query, $existingParams );
$existing_keys = array_keys( $existingParams);
foreach($params as $key=>$value){
if( in_array( $key, $existing_keys ) ){
foreach ($existingParams[$key] as $param_key => $param_value) {
if( $param_value == $value ){
unset( $existingParams[$key][$param_key] );
}
}
}
}
$query = http_build_query($existingParams);
return $query;
}
Related
I have an array that looks like this.
$array = [
0 => 'abc',
1 => [
0 => 'def',
1 => 'ghi'
],
'assoc1' => [
'nassoc' => 'jkl',
'nassoc2' => 'mno',
'nassoc3' => '',
'nassoc4' => false
]
];
The $array can have numeric keys or be an assoc array or a mixed one. The level of nesting is not known. Also the values of the array can also be bool or null or an empty string ''
I need to able to convert this into a scalar array with key value pairs. And then later reconvert it back to the exact same array.
So the scalar array could look like
$arrayScalar = [
'0' => 'abc',
'1[0]' => 'def',
'1[1]' => 'ghi',
'assoc1[nassoc]' => 'jkl',
'assoc1[nassoc2]' => 'mno',
'assoc1[nassoc3]' => '',
'assoc1[nassoc4]' => false
];
And then later be able to get back to the initial $array.
I wrote a parser and it does not currently handle bool values correctly.
I have a feeling this is at best a super hacky method to do what I am after. Also I have been able to test it only so much.
function flattenNestedArraysRecursively($nestedArray, $parent = '', &$flattened = [])
{
$keys = array_keys($nestedArray);
if (empty($keys)) {
$flattened[$parent] = 'emptyarray';
} else {
foreach ($keys as $value) {
if (is_array($nestedArray[$value])) {
$reqParent = (!empty($parent)) ? $parent . '|!|' . $value : $value;
$this->flattenNestedArraysRecursively($nestedArray[$value], $reqParent, $flattened);
} else {
$reqKey = (!empty($parent)) ? $parent . '|!|' . $value : $value;
$flattened[$reqKey] = $nestedArray[$value];
}
}
}
return $flattened;
}
function reCreateFlattenedArray($flatArray): array
{
$arr = [];
foreach ($flatArray as $key => $value) {
$keys = explode('|!|', $key);
$arr = $this->reCreateArrayRecursiveWorker($keys, $value, $arr);
}
return $arr;
}
function reCreateArrayRecursiveWorker($keys, $value, $existingArr)
{
//Outside to Inside
$keyCur = array_shift($keys);
//Check if keyCur Exists in the existingArray
if (key_exists($keyCur, $existingArr)) {
// Check if we have reached the deepest level
if (empty($keys)) {
//Return the Key => value mapping
$existingArr[$keyCur] = $value;
return $existingArr;
} else {
// If not then continue to go deeper while appending deeper levels values to current key
$existingArr[$keyCur] = $this->reCreateArrayRecursiveWorker($keys, $value, $existingArr[$keyCur]);
return $existingArr;
}
} else {
// If Key does not exists in current Array
// Check deepest
if (empty($keys)) {
//Return the Key => value mapping
$existingArr[$keyCur] = $value;
return $existingArr;
} else {
// Add the key
$existingArr[$keyCur] = $this->reCreateArrayRecursiveWorker($keys, $value, []);
return $existingArr;
}
}
}
Is there a better more elegant way of doing this, maybe http_build_query or something else I am not aware of.
Sandbox link -> http://sandbox.onlinephpfunctions.com/code/50b3890e5bdc515bc145eda0a1b34c29eefadcca
Flattening:
Your approach towards recursion is correct. I think we can make it more simpler.
We loop over the array. if the value is an array in itself, we recursively make a call to this new child subarray.
This way, we visit each key and each value. Now, we are only left to manage the keys to assign them when adding to our final resultant array, say $arrayScalar.
For this, we make a new function parameter which takes the parent key into account when assigning. That's it.
Snippet:
$arrayScalar = [];
function flatten($array,&$arrayScalar,$parent_key){
foreach($array as $key => $value){
$curr_key = empty($parent_key) ? $key : $parent_key . '[' . $key . ']';
if(is_array($value)){
flatten($value,$arrayScalar,$curr_key);
}else{
$arrayScalar[$curr_key] = $value;
}
}
}
flatten($array,$arrayScalar,'');
var_export($arrayScalar);
Demo: http://sandbox.onlinephpfunctions.com/code/1e3092e9e163330f43d495cc9d4acb672289a987
Unflattening:
This one is a little tricky.
You might have already noticed that the keys in the flattened array are of the form key1[key2][key3][key4] etc.
So, we collect all these individually in a new array, say $split_key. It might look like this.
array (
'key1',
'key2',
'key3',
'key4',
)
To achieve the above, we do a basic string parsing and added in-between keys to the array whenever we reach the end of the key string or [ or ].
Next, to add them to our final resultant array, we loop over the collected keys and check if they are set in our final array. If not so, set them. We now pass child array reference to our temporary variable $temp. This is to edit the same copy of the array. In the end, we return the result.
Snippet:
<?php
function unflatten($arrayScalar){
$result = [];
foreach($arrayScalar as $key => $value){
if(is_int($key)) $key = strval($key);
$split_key = [];
$key_len = strlen($key);
$curr = '';
// collect them as individual keys
for($i = 0; $i < $key_len; ++$i){
if($key[ $i ] == '[' || $key[ $i ] == ']'){
if(strlen($curr) === 0) continue;
$split_key[] = $curr;
$curr = '';
}else{
$curr .= $key[ $i ];
}
if($i === $key_len - 1 && strlen($curr) > 0){
$split_key[] = $curr;
}
}
// collecting them ends
//add them to our resultant array.
$temp = &$result;
foreach($split_key as $sk){
if(!isset($temp[ $sk ])){
$temp[ $sk ] = [];
}
$temp = &$temp[$sk];
}
$temp = $value;
}
return $result;
}
var_export(unflatten($arrayScalar));
Demo: http://sandbox.onlinephpfunctions.com/code/66136a699c3c5285eed3d3350ed4faa5bbce4b76
I need help to change the index of an array.
I have this array:
$items = array('items' => array(
0 => array(
'item_id' => 1,
'item_amount' => 100,
),
1 => array(),
));
Now I want to remove the index, based on the value of item_id, but I don't know how to do this.
I've tried to do it as follows, but doesn't work.
foreach($items['items'] as $key) {
$removeIndex = $key['item_id'] == 1;
if($removeIndex) {
unset($removeIndex);
}
}
How can I do this?
You need to use unset like this:
foreach($items['items'] as $index => $key) { // also get the index!
if (!isset($key['item_id'])) continue; // skip
$removeIndex = $key['item_id'] == 1;
if($removeIndex) {
unset($items['items'][$index]['item_id']); // specify path to that entry
}
}
See it run on eval.in.
To unset something in your nested array structure, you need to act on that array itself. unset($removeIndex) does not change the array, because that is a boolean value.
The extra if is there for the case when you don't have an item_id in some sub-array: in that case that iteration of the loop is skipped.
Removing the entire "row"
If your aim is to also remove the sub-array to which the item_id belongs (so including the item_amount and any other value in that sub-array), then just shorten the "path" in the unset statement:
foreach($items['items'] as $index => $key) { // also get the index!
if (!isset($key['item_id'])) continue; // skip
$removeIndex = $key['item_id'] == 1;
if($removeIndex) {
unset($items['items'][$index]); // specify path to that entry
}
}
See it run on eval.in.
You need to call unset($items['items'][0]). For your case it will be something like this:
$id = 1;
$keyToRemove = false;
foreach ($items['items'] as $key => $value) {
if ($value['item_id'] == $id) {
$keyToRemove = $key;
break;
};
}
if ($keyToRemove) {
unset($items['items'][$keyToRemove]);
}
If you want to remove the specific entry 'item_id' in the $items array, you have to refer to it and use both keys, like in:
foreach($items['items'] as $key => $val) {
if (!isset($val['item_id'])) continue;
$removeIndex = $val['item_id'] == 1;
if($removeIndex)
unset($items['items'][$key]);
}
If you downvote, please state why you think this answer is not appropriate.
I have an array that I would like to pass to a function as a parameter. These array values will be used to pull values out of another array and display them.
My Function:
function showTreadmills($listbrands) {
global $treadmills;
foreach( $treadmills as $brand=>&$features ) {
if ($brand == $listbrands) {
return '<p>'.$features["description"].'</p>';
}
}
}
Treadmills Array:
$treadmills = [
'bowflexseries3' => [
'description' => 'Bowflex Series 3',
'image' => '/images/bowflex-series-3-150x150.jpg',
'url' => '/treadmills/bowflex/series-3',
],
'solef85' => [
'description' => 'Sole F85',
'image' => '/images/sole-f85-150x150.jpg',
'url' => '/treadmills/sole/f-85',
],
'endurancet10hrc' => [
'description' => 'Endurance T10HRC',
'image' => '/images/endurance-t10hrc-150x150.jpg',
'url' => '/treadmills/endurance/t10hrc',
]
];
Values that I'm trying to pull out of array in my function:
<?php echo showTreadmills('bowflexseries3','solef85'); ?>
This only returns the first Description from the array, which is Bowflex Series 3. I'm trying to figure out how to get it to pull the description for bowflexseries3 and solef85. I'm sure it's a dumb oversight. Thanks in advance!
You're not passing an array to the function, you're passing two strings. You need to call array() to wrap an array around them:
echo showTreadmills(array('bowflexseries3','solef85'));
Then you need to change showTreadmills. You can't use == to compare a string to an array. It looks like you want to test whether the string is in the array, so it should be:
if (in_array($brand, $listbrands))
Or instead of looping through $treadmills and testing whether it's equal to one of $listbands, you could loop through $listbrands:
$result = '';
foreach ($listbrands as $brand) {
if (isset($treadmills[$brand])) {
$result .= '<p>'.$treadmills[$brand]["description"].'</p>';
}
}
return $result;
This is better, since it loops through the smaller array. And in_array() has to do a search, while accessing an associative array is just a hash lookup.
Notice that you need to concatenate the results into a string during the loop. If you use return in the loop, you'll only return the first brand found.
The problem is that you are returning on your first match:
if ($brand == $listbrands) {
return '<p>'.$features["description"].'</p>';
}
You will need to store all your matches so the entire loop can finish and then send back everything that matched.
$matches = '';
foreach( $treadmills as $brand=>&$features ) {
if ($brand == $listbrands) {
$matches .= '<p>'.$features["description"].'</p>';
}
}
return $matches;
function showTreadmills($listbrands) {
global $treadmills;
$out = '';
foreach( $treadmills as $brand=>&$features ) {
if ($brand == $listbrands) {
$out .= '<p>'.$features["description"].'</p>';
}
}
return $out;
}
I'm trying to figure out a better/cleaner way to have something like this in PHP:
// This will be parsed as the only argument in a function...
$params = array('Name', 'Age', 'Mail' => 'some#mail.com');
"Name" and "Age" are values with automatic keys (0 and 1, eg.), and "Mail" is a key with "some#mail.com" value:
[0] => 'Name',
[1] => 'Age',
['Mail'] => 'some#mail.com'
When running through it in a foreach loop, to have "Name" and "Age" as the actual parameters I'm using this:
foreach ($params as $k => $i) {
// This is the ugly part!
if (is_int($k)) {
$k = $i;
$i = false;
}
// To do something like this, for example...
$out = "";
if ($i) {
$out .= "<p>$k</p>\n";
} else {
$out .= "<p>$k<p>\n";
}
}
That will return something like this:
<p>Name</p>
<p>Age</p>
<p>Mail</p>
Is there a better way to do it?
Thanks in advance.
Edit #1: Elaborating the question: is there a clean PHP way to distinguish elements that have explicitly informed keys from the ones that have not in the same array?
You are right about the ugly part. It should be better when you use keys for all elements, and decide on the key name whether of not to use the mail link:
$params = array('name'=>'Name', 'age'=>'Age', 'mail'=>'some#mail.com');
foreach ($params as $k => $i) {
$out .= ($k == 'mail') ? '$k' : $k;
}
Why not just give name and age a key?
Or better yet, if you know that the params array will always be in this format, ditch the loop all together:
echo '<p>'.$params[0].'</p>';
echo '<p>'.$params[1].'</p>';
echo '<p>Mail</p>;
if (!is_int($k)) {
$out .= "<p>$k</p>\n";
} else {
$out .= "<p>$i<p>\n";
}
I found 2 solution for what I wanted:
1 - Sticking to the original approach, I could pass the arguments as follows:
my_function(['Name', 'Age', ['Mail' => 'a#mail.com']]);
or...
my_function(array('Name', 'Age', array('Mail' => 'a#mail.com')));
Using "is_array()" later on to distinguish the parameter's type:
if (is_array($i)) {
$p = current($i);
$c = key($i);
$out .= "<p>$c</p>\n";
} else {
$out .= "<p>$i<p>\n";
}
2 - But, changing my original paradigm, I found another option to parse a undefined number of arguments: the function "func_get_args()". My function would be called like this:
my_function('Name', 'Age', ['Mail' => 'a#mail.com']);
or...
my_function('Name', 'Age', array('Mail' => 'a#mail.com'));
Here is an example to create table rows:
function add_table_row() {
$args = func_get_args(); // returns an array of arguments...
$o = "<tr>\n";
foreach ($args as $value) {
if (is_array($value)) { // If the argument is an array...
$cellcont = key($value); // The contents is the key...
$param = current($value); // And the parameter is the value...
$o .= "<td $param>$cellcont</td>\n";
} else {
$o .= "<td>$value</td>\n";
}
}
$o .= "</tr>\n";
return $o;
}
Bottom line, both solutions uses "is_array" the same way, but the second one looks more clear, IMO.
I am getting results from a mysql table and putting each cell into an array as follows:
$sqlArray = mysql_query("SELECT id,firstName FROM members WHERE id='$id'");
while ($arrayRow = mysql_fetch_array($sqlArray)) {
$friendArray[] = array(
'id' => $arrayRow['id'],
'firstName' => $arrayRow['firstName'],
);
}
Then I do a search for a specific friend. For example if I want to search for a friend name Osman, i would type and o and it will return to me all the results that start with the letter o. Here is my code for that:
function array_multi_search($array, $index, $pattern, $invert = FALSE) {
$output = array();
if (is_array($array)) {
foreach($array as $i => $arr) {
// The index must exist and match the pattern
if (isset($arr[$index]) && (bool) $invert !== (bool) preg_match($pattern, $arr[$index])) {
$output[$i] = $arr;
}
}
}
return $output;
}
$filtered = array_multi_search($friendArray, 'firstName', '/^o/i');
and then it will print out all the results. My problem is that it returned an error saying "Invalid argument supplied to foreach()" and that is why I added the if(is_array)) condition. It is working fine if I leave this code in the index.php page, but I moved it to a subfolder named phpScripts and it doesn't work there. Any Help?
$output is not returning any value because apparently $friendArray is not an array. But I verified that it is by using print_r($friendArray) and it returns all the member's id and firstName.
P.S. I use JavaScript to the the call using AJAX.
If your array structure is such:
$friendArray[] = array(
'id' => $arrayRow['id'],
'firstName' => $arrayRow['firstName'],
);
This means your array is indexed and two levels.
So the correct way to walk through it is:
foreach($array as $cur_element) {
$id = $cur_element['id'];
$firstName = $cur_element['firstName'];
}
Change this:
foreach($array as $i => $arr) {
To this:
foreach((array)$array as $i => $arr) {
Are you sure that $array is not empty?