4

I have the following db and php. I am trying to make a unordered list of category menu. The original php is working by itself. I am trying to convert this to MVC in codeigniter and the following is what I got so far and not working. If someone can point out what I am doing wrong, I will appreciate it.

Database

CREATE TABLE IF NOT EXISTS `categories` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(255) NOT NULL,
  `shortdesc` varchar(255) NOT NULL,
  `longdesc` text NOT NULL,
  `status` enum('active','inactive') NOT NULL,
  `parentid` int(11) NOT NULL,
  PRIMARY KEY  (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=10 DEFAULT CHARSET=latin1 AUTO_INCREMENT=10 ;

-- 
-- Dumping data for table `categories`
-- 

INSERT INTO `categories` (`id`, `name`, `shortdesc`, `longdesc`, `status`, `parentid`) VALUES (1, 'shoes', 'Shoes for boys and girls.', '', 'active', 7);
INSERT INTO `categories` (`id`, `name`, `shortdesc`, `longdesc`, `status`, `parentid`) VALUES (2, 'shirts', 'Shirts and blouses!', '', 'active', 7);
...
...

menu.php (original php and working)

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
    <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
    <title>View Tasks</title>
</head>
<body>
<h3>Menu</h3>
<?php 
function make_list ($parent) {

    global $data;
    echo '<ul>';

    foreach ($parent as $task_id => $todo) {

        echo "<li>$todo";

        if (isset($data[$task_id])) { 

            make_list($data[$task_id]);
        }

        echo '</li>';

    }
    echo '</ul>';

} 

$dbc = @mysqli_connect ('localhost', 'root1', 'root', 'ci_day6') OR die ('<p>Could not connect to the database!</p></body></html>');

$q = 'SELECT id, parentid, name FROM categories ORDER BY parentid ASC'; 
$r = mysqli_query($dbc, $q);

$data = array();

while (list($id, $parentid, $name) = mysqli_fetch_array($r, MYSQLI_NUM)) {

    $data[$parentid][$id] =  $name;

}

make_list($data[0]);

?>

</body>
</html>

This php output the following html

Menu

    * clothes
          o shoes
          o shirts
          o pants
          o dresses
    * fun
          o toys
          o games

My MVC so far and not working.

cat_menu_model.php(model)

<?php

class Cat_menu_model extends Model
{
         function Cat_menu_model()
        {
            parent::Model();

        }

        function get_categories_nav()
        {

            $data = array();
            $this->db->select('id,name,parentid');
            $this->db->where('status', 'active');
            $this->db->orderby('parentid','asc');
            $this->db->orderby('name','asc');

            $Q = $this->db->get('categories');
        if ($Q -> num_rows() > 0){
          foreach ($Q -> result_array() as $row){
          $data[$row['parentid']][$row['id']] = $row['name'];
          }
          }

           $Q->free_result(); 
           return $data; 

        }
}

cat_menu.php (controller)

<?php

class Cat_menu extends Controller
{

    function Cat_menu()
    {
        parent::Controller();
    }
    function make_menu($parent)
    {
        $this->load->model('cat_menu_model');

        $data['navlist'] = $this->cat_menu_model->get_categories_nav();
            $this -> load ->view('menu');
    }
}

menu.php(view)

<?php
if (count($navlist))
{
  $this->make_menu($data[0]);
  echo '<ol>';
    foreach ($parent as $id => $catname) {

        echo "<li>$catname";

        if (isset($data[$id])) { 

        make_menu($data[$id]);

        }

        echo '</li>';

    } 
 echo '</ol>';
}
?>

It shows an error messages.

A PHP Error was encountered

Severity: Warning

Message: Missing argument 1 for Cat_menu::make_menu()

Filename: controllers/cat_menu.php

Line Number: 10
tereško
  • 58,060
  • 25
  • 98
  • 150
shin
  • 31,901
  • 69
  • 184
  • 271

3 Answers3

4

Given the PHP error message above, it's saying that you've told the method Cat_menu::make_menu() to accept an argument. In this case the function make_menu($parent) in the Cat_menu controller.

If this function does not require any input -- doesn't look like $parent is used -- then just remove the $parent argument from make_menu.

Alternatively, set a default value if you would like the function to accept no arguments. See below:

cat_menu.php (Controller)

<?php

class Cat_menu extends Controller
{

    function Cat_menu()
    {
        parent::Controller();
    }

    function make_menu($parent = FALSE) //Is this $parent argument needed?
    {
        $this->load->model('cat_menu_model');

        $data['navlist'] = $this->cat_menu_model->get_categories_nav();

        //If you want to parse data to a view you need to state it
        $this->load->view('menu', $data);
    }
}

Assuming the rest of your code is correct, this should now work. Please see the CodeIgniter User Guide for reference from now on. Specifically the views documentation on parsing values across.


OP* has since responded in the comments below, this is my response.

**OP = Original Poster*

When running print_r($navlist) in the view. The OP gets the following output:

Array ( 
    [0] => Array ( 
        [7] => clothes 
        [8] => fun 
    ) 
    [7] => Array ( 
        [3] => pants 
        [2] => shirts 
        [1] => shoes 
    ) 
    [8] => Array ( 
        [6] => games 
        [5] => toys 
    )
)

However, it is worth noting that the OP's CI model ActiveRecord query is significantly different than the original -- non MVC -- query:

SELECT 
    id, 
    parentid, 
    name 
FROM 
    categories 
ORDER BY 
    parentid ASC

vs.

$this->db->select('id,name,parentid');
$this->db->where('status', 'active');
$this->db->orderby('parentid','asc');
$this->db->orderby('name','asc');
$Q = $this->db->get('categories');

The CI model query is different than the original SQL to begin with. When converted into SQL it would produce the following:

SELECT
    id, 
    name,
    parentid
FROM
    categories
WHERE
    status = 'active'
ORDER BY
    parentid ASC,
    name ASC

However, it seems that this is the correct data being brought back so I'll continue on.

The OP would like the array formatted like a heirarchy. For future reference, please see: PHP/MySQL - building a nav menu hierarchy. The easiest way to do this, would be to follow the OP's original (non MVC) function and add it as a model function. This model function would create a nested array, rather than the direct html output -- the reason for this is to separate application logic from output.

You can add the following to your model as a function. Originally taken from Nested sets, php array and transformation but since re-written due to errors appearing for OP:

function to_hierarchy($collection = NULL)
{
    if (is_null($collection)) return false;

    $tree = array();

    foreach($collection[0] as $key => $value)
    {
        $tree[$value] = array();

        foreach($collection[$key] as $item)
        {
            array_push($tree[$value], $item);
        }
    }

    return $tree;
}

Now we can update our controller to be the following:

cat_menu.php (Controller)

<?php

class Cat_menu extends Controller
{

    function Cat_menu()
    {
        parent::Controller();
    }

    function make_menu($parent = FALSE) //Is this $parent argument needed?
    {
        $this->load->model('cat_menu_model');

        $get_nav_list = $this->cat_menu_model->get_categories_nav();

        $format_nav_list = $this->cat_menu_model->to_hierarchy($get_nav_list);

        //Load the HTML helper for ul/ol conversion
        $this->load->helper('html');

        $data['navlist'] = $format_nav_list;

        //If you want to parse data to a view you need to state it
        $this->load->view('menu', $data);
    }
}

Now we can update our view to be the following:

menu.php (View)

<?php
    echo ul($navlist);
?>

Disclaimer: None of the above has been tested using PHP as I currently don't have access to the interpreter from this computer. Please make sure you check over any syntax.

Community
  • 1
  • 1
KushalP
  • 10,976
  • 6
  • 34
  • 27
  • Thanks for your reply. I tested it and the outputs are Array Array Array. It does not show menu. – shin Oct 11 '09 at 15:35
  • Change your view to simply read: echo '
    '.print_r($navlist).'
    '; From this you can see what output is created from your model function, and alter your view (or model?) accordingly.
    – KushalP Oct 11 '09 at 15:37
  • Array ( [0] => Array ( [7] => clothes [8] => fun ) [7] => Array ( [3] => pants [2] => shirts [1] => shoes ) [8] => Array ( [6] => games [5] => toys ) ) – shin Oct 11 '09 at 15:42
  • @scorchin: Thanks again. I tink line $format_nav_list = $this->cat_menu_model->to_hierarchy($navlist); should be $format_nav_list = $this->cat_menu_model->to_hierarchy($get_nav_list); However I get an error "Message: Undefined index: depth" – shin Oct 11 '09 at 16:57
  • Thanks. I've since ammended the code to be a lot simpler and it should now fit your problem, rather than be a generic nested array builder. Let me know if you have anymore trouble – KushalP Oct 11 '09 at 18:40
  • Excellent! Thanks Scorchin. I needed to add echo in front of ul in view. Otherwise it works! Thanks again for your help. – shin Oct 12 '09 at 05:46
  • @Scorchin: Can you explain what is happening in your code here? 'foreach($collection[0] as $key => $value) { $tree[$value] = array(); foreach($collection[$key] as $item) { array_push($tree[$value], $item); } }' – shin Oct 12 '09 at 05:54
  • @shin I've updated the view code above to fit. As for the to_hierarchy() function, it goes through the result array, where parent = 0 and sets the base of the array tree: $tree[$value] = array(); Then for all other elements in the result array, it will try to find the respective parent and it as a child value: array_push($tree[$value], $item); Hope this helps. – KushalP Oct 12 '09 at 10:30
  • I have updated: function to_hierarchy($collection = NULL) { if (is_null($collection)) return false; $tree = array(); foreach($collection[0] as $key => $value) { $tree[$value] = array(); if (isset($collection[$key])){ foreach($collection[$key] as $item) { array_push($tree[$value], $item); } } } return $tree; } – shin Oct 17 '09 at 15:48
1

You might also consider looking at the ul() function in the built-in HTML helper, which lets you create a <ul> out of an array, recursively.

Austin Hyde
  • 26,347
  • 28
  • 96
  • 129
  • Thanks, but it seems this helper does not suit in this situation. But I learnt new thing. – shin Oct 11 '09 at 15:36
0

Also, you're not passing the data to the view in the controller. it should be:

$this -> load ->view('menu',$data);

also, it looks like you would cause an infinite loop the way you currently have it set up. make_menu loads the menu.php view, but then the view calls that method.

GSto
  • 41,512
  • 37
  • 133
  • 184