3

I am trying to learn MVC and i want to to display a store page when the url is www.example.com/store and another cart page wenn the url is www.example.com/store/cart. Both methods are inside one class:

class store extends controller {
    function __construct() {
        parent::__construct ();
    }

    function Store() { //this should display the store page
        $this->view->render ( "store" );
    }

    function cart() { //this should display the cart page
        $this->view->render ( "store", "cart.php" );
    }
}

the method $this->view->render() includes the pages with the html code. How can I decide which method to execute based on the url?

tereško
  • 58,060
  • 25
  • 98
  • 150
Kable
  • 117
  • 5
  • 13
  • Are you creating your own system? Or are you using an existing MVC system? How do you get all urls to use the same php script? Or are you actually creating all the folders and placing a index.php that includes the same script? – nl-x Apr 08 '13 at 11:47
  • Look up the term: "url routing". That should cover the basics of what you need. Also, never use same method name as the name of the class. It will get treated as a constructor. – tereško Apr 08 '13 at 11:54
  • use front controller pattern, use .htaccess to rewrite your all requests to the front controller, and in your front controller parse the `$_SERVER['REQUEST_URI']` to find appropriate class and method. I could be wrong :D (we'll find out soon ;)) – Ejaz Apr 08 '13 at 12:05
  • 1
    @tereško - in PHP 5 you can have a method named like the class as long as you have a `__construct()` method as well. Only when PHP cannot find `__construct()` it will use the method named as the class as the constructor. As of PHP 5.3.3. in namespaced classes the function named like the class is never treated as a constructor. – Michal Trojanowski Apr 08 '13 at 12:34
  • possible duplicate of [CMS Routing in MVC](http://stackoverflow.com/questions/11770104/cms-routing-in-mvc) – tereško Apr 08 '13 at 12:37
  • I try to create my own MVC to understand how it works. I have Mod Rewrite on to get all requests to index.php. It all works so far. For example, the url www.example.com/home/welcome/name executes the class "home" with the method "welcome" and passes de param "name". Google helped me with url routing and now I'm trying to implement it into my code. – Kable Apr 08 '13 at 12:54

3 Answers3

11

I can see you are trying to write your own MVC so I will try to explain things you should be aware of while doing this.

First thing you want to do while writing MVC is utilize Front Controller pattern. What this means is that every HTTP Request will go through one file, index.php. This will help you to cofigure your application in one file. You can do this by just always opening your lets say:

www.example.com/index.php/controller/method/param1/param2

or you can force users to go through index.php using .htaccess file. For reference check other frameworks like Codeigniter and CakePHP, see how they use .htaccess files.

When you are in your front controller file, you should think about routing your HTTP Request to appropriate Controller / Method. There are really lots of ways to achive that, and its up to you to figure out the best way to do that.

Anyway you need Router class that will analyse your URL, and extract Controller / Method / Params you need from URL. Then when you know what Controller / Method you need to invoke, you need Dispatcher class that would instantiate Controller, and call Method you need. You should also think about Params you want to pass to your Method so you can use them there.

The easiest way to play around with this is to use query strings.

So lets say you have URL like this:

http://localhost/test/index.php?controller=home&method=welcome

You can easily get Controller and Method names.

Now you can do something like this:

// Get controller and method names
$controller = $_GET['controller'];
$method = $_GET['method'];

// Instantiate controller object
$app = new $controller();

// Call method on you controller object
call_user_func_array(array($app, $method));

This is like the simplest thing you can do just to play around. Once you get hold of this, write your Router class so it can look like this:

http://localhost/test/index.php/controller/method/param1/param2

Anyway you need these classes:

Front Controller so every request goes through one file, and this is where you bootstrap you application, register class autoloading, configure everything etc... This is not a class but a file with procedural code that boots everything up.

Router that will analyse URL and give you back Controller, Method, and Params that you want to pass to invoked Method.

Dispatcher that will instantiate Controller and call Method passing Params to your Method.

And then all control goes to user of your system, then you do your magic inside your controller / method.

While Dispatching request you can also use this:

call_user_func_array(array($app, $method), $params);

this way you are passing $params to $method, so you can use $params inside your method.

Also, check out Reflection class, this can help you to analyse if method you want to invoke exists, if not you should call HTTP 404 etc...

There is no simple answere to your question, but I hope this helps, have fun building your system and just improve until you get it perfect :)

Matija
  • 2,610
  • 1
  • 18
  • 18
  • This may be the best answer of its kind on Stackoverflow. Excellent! There are so many ways to go from URL to `Cotnroller`, and everyone has an opinion. I like how your answer leaves it to the OP to figure what is best. Also, I like how you differentiate between `Router` and `Dispatcher`. There is a *PHP MVC* book by Chris Pitt that fails to recognize this distinction. – Anthony Rutledge May 07 '19 at 00:34
  • The PHP Reflection API is a clever way to determine information about a class, but you can do without it and make your `Router` lightweight. What's crucial in the long run is having something like PSR-4 autoloading setup. – Anthony Rutledge May 07 '19 at 00:36
2

You need to have a separate Router class which does the routes requests to the controller. I suggest looking at/copying Symfony's Router.

Danack
  • 24,939
  • 16
  • 90
  • 122
1

I once did something like this for a home brew approach. Use .htaccess (apache) / Web.config (iis) to redirect all requests to the following script.

// include callable controllers here
$partsA = explode("?", $_SERVER['REQUEST_URI']); // split querystring
$partsB = explode("/", $partsA[0]); // get url parts
if (count($partsB) < 2)
    die("missing controller in url");
elseif (count($partsB) < 3)
    die("missing action in url");
$className = $partsB[1];
$methodName = $partsB[2];
if (class_exists($className))
    if (!is_subclass_of($className, "controller"))
        die(htmlspecialchars("Class $className doesn't extend controller")); // prevents use of unauthorized classes
    else
        $controller = new $className();
else
    die(htmlspecialchars("Class $className doesn't exist"));

if (!method_exists($controller, $methodName))
    die(htmlspecialchars("Method $methodName doesn't exist"));
else
    $controller->$methodName();
nl-x
  • 11,762
  • 7
  • 33
  • 61