Using an array as function parameter php - php

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;
}

Related

Removing an associated key/value pair from array (nested)

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;
}

Avoid Nested Loop in PHP

I am writing a method which takes an array of $topicNames and an array of $app and concatenates each $app to $topicNames like the following
public function getNotificationTopicByAppNames(array $topicNames, array $apps)
{
$topics = [];
foreach ($topicNames as $topicName) {
foreach ($apps as $app) {
$topic = $app . '_' . $topicName;
$topics[] = $topic;
}
}
return $topics;
}
}
The input and result are like the following...
$topicNames = [
'one_noti',
'two_noti',
'three_noti'
];
$apps = [
'one_app',
'two_app'
];
// The return result of the method will be like the following
[
'one_app_one_noti',
'two_app_one_noti',
'one_app_two_noti',
'two_app_two_noti',
'one_app_three_noti',
'two_app_three_noti'
]
My question is instead of doing nested loops, is there any other way I can do? Why do I want to avoid nested loops? Because currently, I have $topic. Later, I might want to add languages, locations etc...
I know I can use map, reduce, array_walks, each those are basically going through one by one. Instead of that which another alternative way I can use? I am okay changing different data types instead of the array as well.
If you dont care about the order you can use this
function getNotificationTopicByAppNames(array $topicNames, array $apps)
{
$topics = [];
foreach($apps as $app){
$topics = array_merge($topics, preg_filter('/^/', $app.'_', $topicNames));
}
return $topics;
}
print_r(getNotificationTopicByAppNames($topicNames,$apps));
Output
Array
(
[0] => one_app_one_noti
[1] => one_app_two_noti
[2] => one_app_three_noti
[3] => two_app_one_noti
[4] => two_app_two_noti
[5] => two_app_three_noti
)
Sandbox
You can also switch loops and use the $ instead to postfix instead of prefix. Which turns out to be in the same order you had. I thought of prefixing as a way to remove the loop. Then i thought why not flip it.
function getNotificationTopicByAppNames(array $topicNames, array $apps)
{
$topics = [];
foreach($topicNames as $topic){
$topics = array_merge($topics, preg_filter('/$/', '_'.$topic, $apps));
}
return $topics;
}
print_r(getNotificationTopicByAppNames($topicNames,$apps));
Output
Array
(
[0] => one_app_one_noti
[1] => two_app_one_noti
[2] => one_app_two_noti
[3] => two_app_two_noti
[4] => one_app_three_noti
[5] => two_app_three_noti
)
Sandbox
The trick here is using preg_filter.
http://php.net/manual/en/function.preg-filter.php
preg_filter — Perform a regular expression search and replace
So we search with ^ start or $ end which doesn't capture anything to replace and then we just add on what we want. I've used this before when I wanted to prefix a whole array with something, etc.
I couldn't test it in a class, so I made it a regular function, so adjust as needed.
Cheers!
You can use :
<?php
public function mergeStacks(...$stacks)
{
$allStacks = call_user_func_array('array_merge', $stacks);
return $this->concatString($allStacks);
}
private function concatString(&$stack, $index = 0, &$result = [])
{
if(count($stack) == 0){
return '';
}
if($index == count($stack)){
return $result;
}
array_walk($stack, function($value, $key) use($index, &$result, $stack){
if($key > $index){
array_push($result, $stack[$index] . '_' . $value);
}
});
$index = $index + 1;
return $this->concatString($stack, $index, $result);
}
And then when you want to get the array, no matter if you have languages or topics etc, you can just do :
$this->mergeStacks($languages, $topics, $locations, .....);
Where $languages, $topics, $locations are simple arrays.
Instead of accepting only topics name parameter try something like this:
function getNotificationTopicByAppNames(array $apps, array ...$names)
{
$topics = [];
foreach ($names as $nameArray) {
foreach ($nameArray as $topicName) {
foreach ($apps as $app) {
$topic = $app . '_' . $topicName;
$topics[] = $topic;
}
}
}
return $topics;
}
$topicNames = [
'one_noti',
'two_noti',
'three_noti'
];
$languagesNames = [
'test_en',
'test_other',
'test_other2'
];
$apps = [
'one_app',
'two_app'
];
print_r(getNotificationTopicByAppNames($apps,$topicNames,$languagesNames));
you can pass any number of arrays to array.

php foreach supplied argument not valid

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?

Converting array into multidimensional array in PHP when result is send from Oracle

Here is example how my array should look like:
$library = array(
'book' => array(
array(
'authorFirst' => 'Mark',
'authorLast' => 'Twain',
'title' => 'The Innocents Abroad'
),
array(
'authorFirst' => 'Charles',
'authorLast' => 'Dickens',
'title' => 'Oliver Twist'
)
)
);
When I get results from oracle database:
$row = oci_fetch_array($refcur, OCI_ASSOC+OCI_RETURN_NULLS);
But when I execute my code I only get one row.
For example: <books><book></book><name></name></books>
But I want all rows to be shown in xml.
EDIT:
This is my class for converting array to xml:
public static function toXml($data, $rootNodeName = 'data', &$xml=null)
{
// turn off compatibility mode as simple xml throws a wobbly if you don't.
if (ini_get('zend.ze1_compatibility_mode') == 1)
{
ini_set ('zend.ze1_compatibility_mode', 0);
}
if (is_null($xml))
{
$xml = simplexml_load_string("<".key($data)."/>");
}
// loop through the data passed in.
foreach($data as $key => $value)
{
// if numeric key, assume array of rootNodeName elements
if (is_numeric($key))
{
$key = $rootNodeName;
}
// delete any char not allowed in XML element names
$key = preg_replace('/[^a-z0-9\-\_\.\:]/i', '', $key);
// if there is another array found recrusively call this function
if (is_array($value))
{
// create a new node unless this is an array of elements
$node = ArrayToXML::isAssoc($value) ? $xml->addChild($key) : $xml;
// recrusive call - pass $key as the new rootNodeName
ArrayToXML::toXml($value, $key, $node);
}
else
{
// add single node.
$value = htmlentities($value);
$xml->addChild($key,$value);
}
}
// pass back as string. or simple xml object if you want!
return $xml->asXML();
}
// determine if a variable is an associative array
public static function isAssoc( $array ) {
return (is_array($array) && 0 !== count(array_diff_key($array, array_keys(array_keys($array)))));
}
}
?>
Now with below responde I have tried problem is I get following output: <book>...</book> tags after each row.. then I tried 3 dimensional array now I get: <book><book>...</book></book> on the proper place but I have 2 of them.
This is the line where I have determine which is root on that array and that's why I get this output. But don't know how to change it : $xml = simplexml_load_string("<".key($data)."/>");
Thank you.
oci_fetch_array() will always return a single row, you need to call it until there are no more rows to fetch in order to get all of them:
while ($row = oci_fetch_array($refcur, OCI_ASSOC+OCI_RETURN_NULLS))
{
$library['book'][] = $row;
}

PHP adding foreach to my array

I would like to append html to an item in my array before echoing it on my page and am unsure how to go about doing it.
My data is put into an array like so:
$query = $this->db->get();
foreach ($query->result() as $row) {
$data = array(
'seo_title' => $row->seo_title,
'seo_description' => $row->seo_description,
'seo_keywords' => $row->seo_keywords,
'category' => $row->category,
'title' => $row->title,
'intro' => $row->intro,
'content' => $row->content,
'tags' => $row->tags
);
}
return $data;
I would like to perform the following on my 'tags' before returning the data to my view:
$all_tags = explode( ',' , $row->tags );
foreach ( $all_tags as $one_tag ){
echo '' . $one_tag . '';
The reason for doing this is that the tags in my database contain no html and are simply separated by commas like so news,latest,sports and I want to convert them into
sports ...
My reason for doing this here rather than when I echo the data is that I don't want to repeat myself on every page.
You could just create a function to be used everyhwere you are including tags in your output:
function formatTags($tags) {
$tmp = explode(',', $tags);
$result = "";
foreach ($tmp as $t) {
$result .= sprintf('%s',
urlencode(trim($t)), htmlentities(trim($t)));
}
return $result;
}
And whenever you do something like echo $tags; you do echo formatTags($tags); instead. View code should be separated from model code, which is why I would advise to not put HTML inside your array.
Well first of all you're overwriting $data with every run of the loop so only the final result row will be listed.
Once that's out of the way (fix with $data[] = ...), try this:
...
'tags' => preg_replace( "/(?:^|,)([^,]+)/", "$1", $row->tags);
...

Categories