nested foreach codeigniter
In codeigniter 1.73 i'm trying to display books by category. so if i have a category called cars, i should see a list of books within cars. so i tried a nested foreach loop to accomplish this but can't seem to get it to work.
<?php
class Book_model extends Model {
function books_by_category()
{
$this->db->select('*');
$this->db->from('categories');
$this->db->join('books', 'books.category_id = categories.id');
$query = $this->db->get();
return $query->result();
}
}
then in the view:
foreach($data as $category) {
if (sizeof($category['books']))
{
foreach($category['books'] as $book)
{
<li>$book->book_number anchor("book/chapters/$book->id", $book->book_title)</li>
}
} else {
// show 'no books'
}
}
controller:
function index() {
$data = array();
if($query = $this->book_model->books_by_category())
{
$data['books_by_category'开发者_StackOverflow社区] = $query;
foreach($query as $row)
{
if (!isset($data[$row['id']]))
{
$data[$row['id']] = $row;
$data[$row['id']]['books'] = array();
}
$data[$row['id']]['books'][] = $row;
}
$data['main_content'] = 'books_view';
$this->load->view('includes/template', $data);
}
}
Foreach does not have an "else" clause, as you've used.
foreach($category['books'] as $book)
{
// show books
} else {
// show 'no books'
}
Instead, you could do this: (my PHP is rusty)
if(count($category['books']) <= 0)
{
//No books
}
else
{
foreach($category['books'] as $book)
{
//You have books
}
}
A couple of points
function books_by_category()
{
$this->db->select('*');
$this->db->from('categories');
$this->db->join('books', 'books.category_id = categories.id');
$query = $this->db->get();
return $query->result();
}
This code returns all columns for categories and books that have a category set, is this really what you are trying to do? The function name 'books_by_category' would suggest to me that you are only interested in books for one specific category, from looking at your question I'm guessing this isn't the case.
Presuming you are trying to get all books but group them by category I would do the following:
model
function get_books()
{
$this->db->select('*');
$this->db->from('books');
$this->db->join('categories', 'categories.id = books.category_id');
$query = $this->db->get();
if($query->num_rows() == 0)
{
#no books
return false;
}
return $query->result();
}
controller
function index() {
$data = array();
$book_list = $this->book_model->get_books();
if($book_list)
{
$categories = array();
$books_by_category = array();
foreach($book_list as $book)
{
$category_id = $book['category.id'];
$category_name = $book['category.name'];
if(array_key_exists($category_id, $categories))
{
$categories[$category_id] = $category_name;
}
if(array_key_exists($category_id, $books_by_category))
{
$books_by_category[$category_id] = array();
}
$books_by_category[$category_id][] = $book;
}
$data['categories'] = $categories;
$data['books_by_category'] = $books_by_category;
}
$data['main_content'] = 'books_view';
$this->load->view('includes/template', $data);
}
and the view
<?php if(isSet($books_by_category)) : ?>
<?php foreach($books_by_category as $category => $book_list): ?>
<p>Category: <?php echo $categories[$category]; ?></p>
<ul>
<?php foreach($book_list as $book) : ?>
<li><?php echo $book->book_number; ?>. <?php echo anchor('bible/chapters/' . $book->id, $book->book_title); ?></li>
<?php endforeach; ?>
</ul>
<?php endforeach; ?>
<?php else: ?>
<p>Sorry dude, no books.</p>
<?php endif; ?>
There are a few errors in the code which might be causing this.
- You have an extra closing bracket before the end of the foreach loop in your controller.
- In your view, you are looping through the books category as $book but then you are trying to work with the $row object inside the loop. Try changing this to $book.
- Also in your view, you trying to output some HTML without closing out of your PHP tags. The
<li>
tags in your code are inside your PHP block and then you try to open up a new PHP block again without ever closing the first one.
I came across this and tried to follow along with the example @mattumotu posted and it was really helpful, but I think it might have some errors - specifically with the way the array is being indexed and then looped through. If you are using a number as an id value, and your ids do not start from zero and increase in numerical order from 0 to x, then you will get unknown index orders in your view when you attempt to loop through the array (at least I did). So I modified the example as follows (note I changed the variable names slightly for my own use):
Model:
public function get_imagery_by_category(){
$this->db->select('extra_imagery.*', FALSE); //MH - not sure what FALSE does here
$this->db->select('extra_image_categories.id as cat_id, extra_image_categories.name as cat_name', FALSE); //MH alias the category id and name as they are the same column names as the imagery name and id
$this->db->from('extra_imagery');
$this->db->join('extra_image_categories', 'extra_image_categories.id = extra_imagery.cat'); //get all images where the image cat matches category id
$this->db->order_by('extra_image_categories.id');
$query = $this->db->get();
if($query->num_rows() == 0){
return false;
} else {
return $query->result_array();
}
}
Here we're just sorting all of our items by the category ID, to ensure we are moving through all of our items in numerical order by their category ID, essentially listing items out by category.
Controller:
$imagery_list = $this->imagery_model->get_imagery_by_category();
if($imagery_list){
$categories = array();
$imagery_by_category = array();
$curCatIndex = -1;
$curCatID = NULL;
foreach($imagery_list as $i=>$image){
$category_id = $image['cat_id'];
$category_name = $image['cat_name'];
if ($curCatID != $category_id){
$curCatIndex+=1;
$categories[$curCatIndex] = $category_name;
$curCatID = $category_id;
}
$imagery_by_category[$curCatIndex][] = $image;
}
//print_r($imagery_by_category);
$data['categories'] = $categories;
$data['imagery_by_category'] = $imagery_by_category;
}
Here we're setting an array to hold our categoriesand an array to hold our items. The $imagery_by_category will be a multidimensional array, such that all items in the first category end up in the first array, all items in the second category are in the second array, etc. Like this:
$imagery_by_category[0][0] = category0, item0
$imagery_by_category[0][1] = category0, item1
$imagery_by_category[1][0] = category1, item0
We're setting a counter ($curCatIndex) that will keep track of each time we hit a new category id, and a variable for the category ID to check if our category id has changed ($curCatID). If we hit a new category ID, we know we've collected all the items for that category, so we increment the curCatIndex counter:
$curCatIndex+=1;
Because our $curCatID starts out as NULL when we begin our loop, we increment the $curCatIndex so that our array will start out at index 0.
Whenever we hit a new category id, we push the name of that category to our $categories array:
$categories[$curCatIndex] = $category_name;
and set the $curCatID equal to our new id:
$curCatID = $category_id;
Then, regardless of whether we are in a new category or not, we push the item to the proper place in the multidimensional array:
$imagery_by_category[$curCatIndex][] = $image;
and lastly we just make these arrays available to our view:
$data['categories'] = $categories;
$data['imagery_by_category'] = $imagery_by_category;
Then, in our view:
<?php if(isSet($imagery_by_category)) : ?>
<?php foreach($categories as $i=>$category_item): ?>
<p><?php echo $category_item ?></p>
<?php foreach($imagery_by_category[$i] as $image_item) : ?>
<?php
echo $image_item['id'];
?>
<?php endforeach; ?>
<?php endforeach; ?>
<?php else: ?>
<p>No imagery</p>
<?php endif; ?>
We have a nested loop. The outer loop loops through our categories:
<?php foreach($categories as $i=>$category_item): ?>
Notice that we've added a variable $i to keep track of the loop index (i.e. array index)
Then we print out the name of the category:
<p><?php echo $category_item ?></p>
and then the inner loop loops through the items in that category:
<?php foreach($imagery_by_category[$i] as $image_item) : ?>
Notice we're using the $i variable here to make sure we select the right dimension from our item array.
Then inside this loop you can do whatever you want. Here I'm just printing out the unique id of my item:
echo $image_item['id'];
Probably a more elegant way to do this, but hope it helps someone. I banged my head against the wall on this for awhile. Thanks to mattumotu for getting me on the right track. I've posted a clearer code example here:
http://mikeheavers.com/main/code-item/order_items_in_one_database_table_by_categories_from_another_database_table
精彩评论