Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

I have a MVC framework, and I am struggling with the following dynamic menu code.

A menu is pretty much HTML, so technically it should reside in the View, but the dynamic part is driven by PHP and a config class that holds all the menu items.

  1. Where would I place this class? (model layer, view, library, or helper folder)

  2. How would I re-factor this to be OOP?

  3. How would I deploy this from my View?

Note: It should all be in regards to MVC principles.

class Menu {
    public static function get() {
        $URI = $_SERVER['REQUEST_URI'];

        $user = new User();

        if (!$user->isLoggedIn()) {
            $navArr = Config::get('navigation');

            $navigation = '<ul id="nav-left">' . PHP_EOL;

            foreach ($navArr as $name => $path) {
                $navigation .= '    <li' . ((in_array($URI, $path)) ? ' class="active"' : false) . '><a href="' . $path[1] . '">' . $name . '</a></li>' . PHP_EOL;
            }

            $navigation .= '</ul>' . PHP_EOL . PHP_EOL;
        } else {
            //logged off navigation
        }


        return $navigation;
    }
}
share|improve this question
add comment

1 Answer

up vote 0 down vote accepted

Ok, firstly, you never want HTML in your controller. Always keep your output in your view, your application flow in the controller and your business logic in the model. Otherwise, this breaks separation of concerns (SoC). See http://stackoverflow.com/questions/1376643/mvc-separation-of-concerns for a relevant answer.

Below, I am defining two classes - URI and User. These two should exist in your MVC platform to handle URI and User based actions (checking if a user is logged in, checking for the current URI or Permalink, etc). These would likely be helpers. We will use these later on by injecting them into our Menu::get() function.

# Placeholder classes URI and User, which handle all URI and User activity
class URI{
    # ...
}

class User{
    # ...
}

Below is the Menu class. Note that I namespaced it, considering its a helper, this would allow it to be called with full namespace path if you placed the helper directory into your autoloader.

Note how we are injecting an instance of URI via parameter $uri, and an instance of User via parameter $user. This is Dependency Injection (see http://stackoverflow.com/questions/130794/what-is-dependency-injection).

# Helper class "Menu"
namespace KidDiamond\MVC\Helpers;

class Menu {
    # Rather than defining a new User object, just inject the user object as a parameter
    public static function get(URI $uri, User $User){
        if (!$user->isLoggedIn()) {
            $navArr = Config::get('navigation');

            $menu = '<ul id="nav-left">' . PHP_EOL;
            foreach ($navArr as $name => $path) {
                $xor_active = ((in_array($URI, $path)) ? ' class="active"' : false);
                $menu .= '\t<li' . $xor_active . '><a href="' . $path[1] . '">' . $name . '</a></li>' . PHP_EOL;
            }
            $menu .= '</ul>' . PHP_EOL . PHP_EOL;
        } else {
            # logged off navigation menu
        }


        return $menu;
    }
}

Now, we move on to the Controller. Notice how all its doing is maintaining an initialized $menu_helper variable. You could technically inject the Menu helper...but I personally prefer to initialize it to a property.

The $data variable inside the index() method is automatically returned, and injected into our view, below.

# Controller class HomeController
namespace KidDiamond\MVC\Controllers;

class HomeController extends \BaseController{
    private $menu_helper;

    public function __construct(){
        $this->menu_helper = new KidDiamond\MVC\Helpers\Menu;
    }

    public function index(){
        $data['dynamic-menu'] = $this->menu_helper();

        return $data;
    }
}

This is our (simple) view. Notice that we're using a templating system (Blade, Mustache, etc) to output our variable dynamic-menu which was in the $data array in our controller method.

# View for /index
<html>
    <head></head>
    <body>
        <div class="menu">
            {{dynamic-menu}}
        </div>
    </body>
</html>

I hope this helps. Do note that the code above is completely untested and is only there to help point you in the right direction. There may be syntax errors and other general errors.

share|improve this answer
    
You forgot to inject your Uri and User into the Menu. Seems quite critical in this structure... –  PeterVR May 13 at 17:50
1  
Hence the disclaimer at the bottom. –  jsanc623 May 13 at 19:18
1  
I know, but since your answer relies on dependency injection, and you don't inject any dependencies, it thought it was worth mentioning, as it might confuse readers. –  PeterVR May 17 at 0:19
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.