Looping through category hierarchy - php

JSON: http://pastebin.com/XjK1VKE3
I need to loop through each category and create a nested list like so:
Electronics(31110)
Mobile & Accessories(31087)
Mobile Accessories(31080)
Cases & Covers(29808)
Screen Guards(729)
Mobile Accessories Combos(355)
Cables(153)
Chargers(21)
Power Banks(9)
Batteries(2)
Selfie Stick(2)
Mobile Lenses(1)
Mobiles(7)
Computers & Accessories(15)
...
...
My code which is starting to get ugly:
if ($object->frontend_filters[0]->values->cats) {
foreach ($object->frontend_filters[0]->values->cats as $cat) {
echo print_r($cat,1);
if ($cat->cats) {
foreach ($cat->cats as $subcat) {
if ($subcat->cats) {
foreach ($subcat->cats as $subcat3) {
$results['categories'][$cat->name][$subcat->name][] = $subcat3->name;
}
}
else {
$results['categories'][$cat->name][] = $subcat->name;
}
}
}
else {
$results['categories'][$cat->name] = [];
}
}
}
How do I do this without creating n number of loops because I'm not sure how many levels deep it might be each time.

Use the following function, see demo here:
// convert your json to a php array
$data = json_decode($yourJson,true);
function doList($data)
{
echo "<ul>";
foreach($data as $i =>$value)
{
if(is_array($value))
{
doList($value);
}
else
{
if($i == 'name' && $value != 'All')
{
echo "<li>$value({$data['count']})</li>";
}
}
}
echo '</ul>';
}
doList($data);

Related

rewrite using array filter

How would I write the following foreach with some conditions using array_filter?
foreach ($categories as $category) {
if ($this->request->getParam('category_id')) {
if ($category->getCategoryId() == $this->request->getParam('category_id')) {
$selectedCategory = $category;
break;
}
} else {
No category id in request. Select the first one.
if (array_key_exists(0, $categoryTree) &&
$category->getCategoryId() == $categoryTree[0]['id']
) {
$selectedCategory = $category;
break;
}
}
}
First off, using array_filter isn't helpful in this case as it reduces an array instead of selecting an element. But to show its principles, you could rewrite the code to something like this.
if($this->request->getParam('category_id')){
$filteredCategories = array_filter($categories, function ($category) use ($this){
return $category->getCategoryId() == $this->request->getParam('category_id');
});
if(count($filteredCategories)>0){
return $filteredCategories[0];
}
} else {
[...]
}
I think you want an intersection function and not an array filter.
function key_compare_func($key1, $key2)
{
if ($key1 == $key2->getCategoryId()) {
return 1;
} else {
return 0;
}
}
$selectedCategory = array_intersect_ukey(
$this>request>getParam('category_id'),
$categories,
'key_compare_func'
)
For more information on the different array functions you can look at the PHP manual

PHP if condition: Logical operators for filter from a form

I'm working with a form using the <datalist> tag, I have two input tags getting information from two different arrays. Below the form there is a Kanban board, the objective of the form is to serve as a filter, so when a user fills any of the inputs (or both) the board with fill accordingly.
Here is the problem: I had made two if staments (one for input) that work great when I use them alone but that I don't know how to put together because I don't know how to check which of the inputs has been filled (for that I believe I may have to use the issset() function), then if only one of them is used I need to use the || logical operator between them but if both are filled I need to use the && operator.
Using this condition (|| logical operator):
if (($tasksArray[$i]["responsible-party-names"] == $_POST['members'] && isset($_POST['members'])) ||
(($tasksArray[$i]['project-name'] == $_POST['projects'] && isset($_POST['projects']))))
If I fill only the members input it returns what it should.
If I fill only the projects input it returns all the projects in the array (although when using the if condition without the left part it works well).
Finally, if I fill both inputs I get the right project but all the team members.
What would be the simplest way to get it right?
Update:
This if condition it's inside the moveArray function, what comes after the if block looks like this:
{
$task = '<div id="item'.$i.'"'.'draggable="true" class="c-drag">';
$task .= '<div class="card cardTitle">'.$tasksArray[$i]['content'].'</div>';
$task .= '<div class="card cardDescription">'.$tasksArray[$i]['description'].'</div>';
$task .= '<div class="card cardProjectName">'.$tasksArray[$i]['project-name'].'</div>';
if (isset($tasksArray[$i]["responsible-party-names"])) {
$task .= '<div class="card cardProjectResponsibleName">'.$tasksArray[$i]['responsible-party-names'].'</div>';
} else {
$task .= '<div class="card cardProjectResponsibleName">'."Anyone".'</div>';
}
if ($tasksArray[$i]["due-date"] != "") {
$task .= '<div class="card cardDueDate">'.date("d/m/Y", strtotime($tasksArray[$i]["due-date"])).'</div>';
}
$task .= '</div>';
return $task;
}
Then I call the function on every part of the board (unassigned, to do, in progress, finished)
echo '<div id="board">';
echo '<div id="unassing">';
echo '<div id="unassing-bg" class="title">Unassigned</div>';
for ($i=0; $i < $tasksLenght; $i++) {
if (isset($tasksArray[$i]['boardColumn']) === false) {
echo(moveArray($i, $tasksArray));
}
}
echo '</div>';
echo '<div id="todo">';
echo '<div id="todo-bg" class="title">To Do</div>';
for ($i=0; $i < $tasksLenght; $i++) {
if (isset($tasksArray[$i]['boardColumn']) && $tasksArray[$i]['boardColumn']['id'] == "9805") {
echo(moveArray($i, $tasksArray));
}
}
echo '</div>';
echo '</div>';
And that produce sort of "a card" with data about a task in the corresponding place of the board.
You actually need the isset to come before trying to access the key on $_POST to prevent the "undefined" error.
I am assuming you have some code that looks like this:
$matchingTasks = [];
for ($i=0; $i <= count($tasksArray); $i++) {
...
}
return $matchingTasks; // or something
If that is the case, what you want is more like this:
matchingTasks = [];
foreach ($tasksArray as $task) {
// Store your search values
$members = isset($_POST['members']) ? $_POST['members'] : false;
$projects = isset($_POST['projects']) ? $_POST['projects'] : false;
// Store the search matches, only if you are searching by that key
$members_match = $members && $task["responsible-party-names"] == $members;
$projects_match = $projects && $task['project-name'] == $projects;
// if you are searching for BOTH must match BOTH
if ($members && $projects)
if ($members_match && $projects_match) {
$matchingTasks[] = $task;
}
continue;
}
// if you are searching for EITHER can match EITHER
if ($members XOR $projects) {
if ($members_match || $projects_match) {
$matchingTasks[] = $task;
}
continue;
}
// if you are not searching match ALL
$matchingTasks[] = $task;
}
return $matchingTasks;
More advanced, and would allow for more customization, is to stack these in a filter pattern like this:
$members = isset($_POST['members']) ? $_POST['members'] : false;
$projects = isset($_POST['projects']) ? $_POST['projects'] : false;
if ($members)
$tasksArray = filter_by_members($tasksArray, $members);
if ($projects)
$tasksArray = filter_by_project($tasksArray, $projects);
return $tasksArray;
//... elsewhere
function filter_by_members($tasks, $members) {
$result = [];
foreach ($tasks as $t) {
if ($task["responsible-party-names"] == $members) {
$result[] = $task;
}
}
return $tasks;
}
function filter_by_project($tasks, $project) {
$result = [];
foreach ($tasks as $t) {
if ($task["project-name"] == $project) {
$result[] = $task;
}
}
return $tasks;
}
This would let you stack new search filters, like filter_by_id or filter_by_date and by defining filter functions you can stack as many as you like without getting crazy with the logic.

How to get the total COUNT for the results in For Loop

I have a query for one of my search function. A while loop is applied to this query. I have used many sets of if functions inside this while loop to further filter the results as per the user search requirement. And the {email id} (one of the variable in the step1 result) of the final filter result in the if statement set is used to query another table where in a foreach loop is used & obtain other specific details in that table.
// WHILE SEARCH PROFILES
while ($result = mysql_fetch_array($result_finda)) {
$emails=$result['email'];
$age=$result['age'];
$name=$result['name'];
$height=$result['height'];
$groups=$result['groups'];
$country=$result['country'];
if (($age_from <= $age)&& ($age <= $age_to)) {
$a_emails =$emails;
$a_age=$age;
$a_firstname=$name;
$a_height=$height;
$a_groups=$groups;
$a_country=$country;
}
if (($height_from <= $a_height)&& ($a_height <= $height_to)) {
$h_emails =$a_emails;
$h_age=$a_age;
$h_firstname=$a_firstname;
$h_groups=$a_groups;
$h_country=$a_country;
}
foreach ($_POST['groups'] as $workgroup) {
if (strpos($workgroup, $h_groups) !== false) {
$m_emails =$h_emails;
$m_age=$h_age;
$m_name=$h_name;
$m_groups=$h_groups;
$m_country=$h_country;
}
}
foreach ($_POST['country'] as $workcountry) {
if (strpos($workcountry, $m_country) !== false) {
$c_emails =$m_emails;
$c_age=$m_age;
$c_name=$m_name;
$c_groups=$m_groups;
$c_country=$m_country;
}
}
$findeducation="SELECT * FROM education WHERE email='$c_emails'";
$result_findeducation=mysql_query($findeducation);
$educationstatus = mysql_fetch_array($result_findeducation);
$profile_ed=$educationstatus['education'];
foreach ($_POST['education'] as $educationstatus) {
if (strpos($educationstatus, $profile_ed) !== false) {
$e_emails =$_c_emails;
$e_age=$c_age;
$e_name=$c_name;
$e_groups=$c_groups;
$e_country=$c_country;
$e_education=$profile_ed;
}
}
if ($e_name) {
$count++;
}
echo $e_name;echo '&nbsp';
echo $e_emails;echo '&nbsp';
echo $e_age;echo '</br>';
echo $e_groups;echo '</br>';
echo $e_country;echo '</br>';
}
I'm getting the desired result and The results are filtered and shown as per the code above.
My problem is that I'm not getting the total COUNT of the results displayed. Kindly advise for a solution.
Lot of thanks in advance.
SQL :
$count = mysql_num_rows($result_finda);
PHP :
$count = count(mysql_fetch_array($result_finda));
EDIT
Use the following :
$count = 0; // Initialize $count
while ($result = mysql_fetch_array($result_finda))
{
// Filter your results
$count++; // Increment $count for each result that matches with your filters
}
print $count; // number of results after filtering
In your code :
$finda="SELECT * FROM USERS WHERE gender='$gender'";
$result_finda=mysql_query($finda);
$count = 0;
while ($result = mysql_fetch_array($result_finda)) {
$emails=$result['email'];
$age=$result['age'];
$name=$result['name'];
$height=$result['height'];
$groups=$result['groups'];
$country=$result['country'];
if (($age_from <= $age)&& ($age <= $age_to)) {
$a_emails =$emails;
$a_age=$age;
$a_firstname=$name;
$a_height=$height;
$a_groups=$groups;
$a_country=$country;
}
if (($height_from <= $a_height)&& ($a_height <= $height_to)) {
$h_emails =$a_emails;
$h_age=$a_age;
$h_firstname=$a_firstname;
$h_groups=$a_groups;
$h_country=$a_country;
}
foreach ($_POST['groups'] as $workgroup) {
if (strpos($workgroup, $h_groups) !== false) {
$m_emails =$h_emails;
$m_age=$h_age;
$m_name=$h_name;
$m_groups=$h_groups;
$m_country=$h_country;
}
}
foreach ($_POST['country'] as $workcountry) {
if (strpos($workcountry, $m_country) !== false) {
$c_emails =$m_emails;
$c_age=$m_age;
$c_name=$m_name;
$c_groups=$m_groups;
$c_country=$m_country;
}
}
$findeducation="SELECT * FROM education WHERE email='$c_emails'";
$result_findeducation=mysql_query($findeducation);
$educationstatus = mysql_fetch_array($result_findeducation);
$profile_ed=$educationstatus['education'];
foreach ($_POST['education'] as $educationstatus) {
if (strpos($educationstatus, $profile_ed) !== false) {
$e_emails =$_c_emails;
$e_age=$c_age;
$e_name=$c_name;
$e_groups=$c_groups;
$e_country=$c_country;
$e_education=$profile_ed;
}
}
if ($e_name) {
$count++;
 }
echo $e_name;echo '&nbsp';
echo $e_emails;echo '&nbsp';
echo $e_age;echo '</br>';
echo $e_groups;echo '</br>';
echo $e_country;echo '</br>';
}
print "$count RESULTS"; // [number] RESULTS

How do you use break in php 5.4 after it lost its ability to receive variables?

The php manual states under 'Changelog for break':
5.4.0 Removed the ability to pass in variables (e.g., $num = 2; break $num;) as the numerical argument.
I have a function that copies a table with a tree structure to another table.
After copying each record, the function tests a relation to see if that record has more child records in the next "level" of the tree.
If child records are found, this same function is executed for each child record using a foreach() loop. If they also have child records, the process is repeated, etc. etc.
So the number of "branches" and "levels" in the table will determine how many foreach() loops will be executed. Since the user creates the records, I have no control over the number of "branches" and "levels" in the table.
If break cannot receive a variable any more (I cannot run "branch" and "level" counters any more) - how do you break out of ALL loops if an error occurs?
Scaled down example:
public function copyTreeModels($row, $id)
{
try
{
/* copy current record. */
$status == 'ok';
/* loop to this same function if $status == 'ok' and hasChildren */
if($status == 'ok')
{
If ($row['hasChildren'] == 'yes') // check relation
{
foreach($row['children'] as $child)
{
$this->copyTreeModels($child, $id);
}
}
}
else
{
// break;
throw new CDbException($message);
}
}
catch(CDbException $e)
{
$message .= $e->getMessage();
}
return($message);
}
Don't put try in the recursive function. You need a wrapper function around the whole thing that establishes the condition handler:
public function copyTreeModels($row, $id) {
try {
$this->copytreeModelsRecurse($row, $id);
}
catch(CDbException $e)
{
$message .= $e->getMessage();
}
return($message);
}
copyTreeModelsRecurse would then be your copyTreeModels function, but without the try/catch blocks.
The only thing I can think of is to set a variable which determines whether or not to break all.
An example (untested) is
$break_all = false;
foreach($values as $val) {
foreach($val as $val1) {
foreach($val1 as $val2) {
if($val2 == "xyz") {
$break_all = true;
}
if($break_all) break;
}
if($break_all) break;
}
if($break_all) break;
}
I'll agree with the fact it's not a pretty solution however.
Edit:
An alternative suggestion if the amount of nested loops to break; from is a variable amount is setting a counter and decrementing the break counter for each break, and only breaking if it is greater than 0:
$break_count = 0;
foreach($values as $val) {
foreach($val as $val1) {
foreach($val1 as $val2) {
if($val2 == "xyz") {
$break_count = 3;
}
if($break_count > 0) { $break_count--; break; }
}
if($break_count > 0) { $break_count--; break; }
}
if($break_count > 0) { $break_count--; break; }
}

Page Headings and Functions with their headings

I have one more question for the day. I'm trying to make my biography page totally customizable for my custom CMS project I'm doing. If you notice in the view I have 3 h2 tags for Quotes, Allies, Rivals. What I would like to do is put the h3's into my db and then have it do a foreach loop for each one of them so I'm thinking some how I"m going to have to store the function that goes with the pageheading that way it doesn't have to run it if its not active on the page. I know this can be easily done however there's too much for me to focus on what I need to do in order to complete this. Keep in mind that depending on which page you are in the bio will impact which headings will be available.
As of right now here is my controller:
$activeTemplate = $this->sitemodel->getTemplate();
$footerLinks = $this->sitemodel->getFooterNav();
$bodyContent = "bio";//which view file
$bodyType = "main";//type of template
$this->data['activeTemplate'] = $activeTemplate;
$this->data['footerLinks']= $footerLinks;
$this->load->model('biomodel');
if($character !== "jfkdlsjl")
{
if((!empty($character))||(!isset($character))||(trim($character) !== '')||($character !== NULL))
{
$bioArray = $this->biomodel->getCharacterBio($character);
if ($bioArray == "empty")
{
$this->data['bioArray']= array();
}
else
{
if (($bioArray[0]->characters_statuses_id == 2)||($bioArray[0]->characters_statuses_id == 3)||($bioArray[0]->characters_statuses_id == 5))
{
$this->data['bioArray']= array();
}
else
{
$this->data['bioArray']= $bioArray;
$bioPagesArray = $this->biomodel->getBioPages();
$alliesArray = $this->biomodel->getCharacterAllies($bioArray[0]->id);
$rivalsArray = $this->biomodel->getCharacterRivals($bioArray[0]->id);
$quotesArray = $this->biomodel->getCharacterQuotes($bioArray[0]->id);
$this->data['bioPagesArray']= $bioPagesArray;
$this->data['alliesArray']= $alliesArray;
$this->data['rivalsArray']= $rivalsArray;
$this->data['quotesArray']= $quotesArray;
}
}
}
}
And here is my view:
echo "<h2>Quotes</h2>";
if (!empty($quotesArray))
{
echo "<ul>";
for($x = 0; $x <= (count($quotesArray)-1); $x++)
{
echo "<li>".stripslashes($quotesArray[$x]->quote)."</li>";
}
echo "</ul>";
}
echo "<h2>Allies</h2>";
if (!empty($alliesArray))
{
echo "<ul>";
foreach ($alliesArray as $row)
{
echo "<li>".stripslashes($row)."</li>";
}
echo "</ul>";
}
echo "<h2>Rivals</h2>";
if (!empty($rivalsArray))
{
echo "<ul>";
foreach ($rivalsArray as $row)
{
echo "<li>".stripslashes($row)."</li>";
}
echo "</ul>";
}
I don't know what you mean about storing the function nor which function you don't want to run.
Assuming we're working with the last else statement in your controller
$alliesArray = $this->biomodel->getCharacterAllies($bioArray[0]->id);
$rivalsArray = $this->biomodel->getCharacterRivals($bioArray[0]->id);
$quotesArray = $this->biomodel->getCharacterQuotes($bioArray[0]->id);
... and the function you "don't want to run" is the foreach loop on the array in the view, just handle the logic in your view:
if(($this->uri->segment(n)=='pageIwantQuotesOn') && (!empty($quotesArray)){
echo "<h2>Quotes</h2>";
echo "<ul>";
for($x = 0; $x <= (count($quotesArray)-1); $x++)
{
echo "<li>".stripslashes($quotesArray[$x]->quote)."</li>";
}
echo "</ul>";
}
...

Categories