0

I have a custom MVC PHP framework that has a router class, which calls a controller, which uses a model, then the controller presents the view, etc etc.

My problem is that I can't figure out technically how to allow variables to pass between the controller and the view, semantically. I could do a quick-and-dirty fix, but what I want to have is this for a controller:

class IndexController extends Controller{
    var $name = "John"; // instance variable
}

And have this for a view:

<p> <?=$name?> </p>

My question is this:

  1. How can I create a Controller->render() function, or something similar, that allows the view to access instance variables from the controller? and,
  2. How can I do this without doing klutzy things like $data['view']['name'] = "John"; or having to write ten lines of code by default for any new controller I make. I want to do this so it's as DRY as possible.

Thanks.

Edit: FabioCosta's solution

I'm not sure I understand, so far I have my base controller like this:

<?php
    class Controller{
        public function __get($key){
            if(isset($this->$$key)) return $this->$$key;
        }
    }
?>

My base view class looks like this:

<?php
    class View{
         public $controller;
         public function render(){
         $this->controller = $this;
    }
?>

And I initialize from the router like this:

<?php
    $controller = new IndexController();
    $view = new IndexView();
    $view->render();
?>

However, this doesn't work, and I know I'm doing something wrong.

element119
  • 7,475
  • 8
  • 51
  • 74
  • What version of PHP are you on? – PeeHaa Jun 14 '12 at 11:58
  • What framework are you using for your MVC? – Gavin Jun 14 '12 at 11:58
  • I'm using the latest, PHP 5.3 I think. @Gavin "I have a custom MVC PHP framework...", as in I made my own. – element119 Jun 14 '12 at 12:07
  • Why are you still using the `var` keyword when you are on 5.3? – PeeHaa Jun 14 '12 at 12:11
  • I think @FabioCosta's suggestion might be the best? – Gavin Jun 14 '12 at 12:11
  • In relation to your `View` class... From my experience with CodeIgniter, they simply include the view file and export the `$data` contents so you can access `$data['Test'] = 'abc';` as `= $Test; ?>` in your view. If your View class uses this method, you could then use `= $this->controller->name; ?>` - That said, you will need to set a controller variable in your View class and set it to the controller calling it. – Gavin Jun 14 '12 at 12:26
  • 2
    @Gavin , please do not use CodeIgniter as example of proper MVC .. or even proper development practices in general – tereško Jun 14 '12 at 12:29

2 Answers2

3

Why not pass the controller that instantiates the view and use the __get magic method?

like so:

  public function __get($key){

      if(isset($this->$key)) return $this->$key;
  }

Here is a working example View.php:

class View{
   protected $_controller;
   public function __construct(Controller $controller){
        $this->_controller=$controller;
   }
   public function render(){
        echo '<h1>Hello '.$this->_controller->name.'</h1>';
   }
}

Controller.php

class Controller{
    protected $name='fabio';
    protected $_myView;

    public function __get($key){

        if(isset($this->$key)) return $this->$key;
   }
    public function __construct(){
        $this->_myView=new View($this);
    }

    public function indexAction(){
        $this->_myView->render();
    }
}

And the router:

$c=new Controller();
$c->indexAction();
FabioCosta
  • 3,069
  • 6
  • 28
  • 50
  • Looks good, how would this work in my code? For example, how do I pass the controller? – element119 Jun 14 '12 at 12:12
  • maybe in the render method, in the controller you put the get magic method. In the render function you put $view->setController($this) – FabioCosta Jun 14 '12 at 12:13
  • Also, does that go in the controller or the view class? Thanks. – element119 Jun 14 '12 at 12:14
  • The controller class http://www.php.net/manual/en/language.oop5.overloading.php#object.get, and you would set the method setController in the view class – FabioCosta Jun 14 '12 at 12:15
  • I'm really confused, see the edit to my question. If you could use that as a base and edit your answer to show me how I should do this, I'd really appreciate it, thanks. – element119 Jun 14 '12 at 12:22
  • 1
    Right now you have an example where controller depends on **name** for a class `View` and where controller is leaking encapsulation. Thats really bad OOP there. – tereško Jun 14 '12 at 12:37
  • Yeah i wouldn't call my example the best framework MVC aproach, it's just what the asker is wanting to do. – FabioCosta Jun 14 '12 at 12:40
  • What would be better OOP? Plus, I don't see how the view would have a render method, shouldn't views just be `.html.php` files, like in Rails where views are `.html.rb` files? – element119 Jun 14 '12 at 12:42
  • teresko is right when he says that data should be model problem. I think you could take a look at zend aproach to build your own http://framework.zend.com/manual/en/learning.quickstart.intro.html The view should be the presentation layer, it should call a file with the html but also call other fucntions to present properly the data (In zend they have view helpers) – FabioCosta Jun 14 '12 at 12:46
2
  1. Controller should not be responsible for rendering output. That is something view instances should do. Rendering should happen outside the controller.

  2. View should request data from model layer. Then, based on information it received, select the right template, assign data and render this template (or in some cases - group of templates).

Also , router should not initialize neither controllers nor views. Controller should be responsible only for processing the request.

Community
  • 1
  • 1
tereško
  • 58,060
  • 25
  • 98
  • 150
  • I really like the idea of the View requesting data from the view. Would the view be a layer, then? It would be responsible for filling various templates with data. I think this is what I called a controller before. If this is true, then what you're saying here about routers and controllers is confusing to me. What does the controller do? Where is it called from? Is the router just called before the controller? – Stephane Sep 28 '12 at 05:17
  • Routing mechanism is a separate concern. It takes user's input, and transforms in a form that can be used by rest of the application (I usually end up with `Request` instance). The controller only takes that request and distributes data to appropriate services and current view. Controller basically goes : "here is the data we received - deal with it". – tereško Sep 28 '12 at 12:32
  • Does that mean that for you the controller is no longer in the picture after it passes on the request? Do you have an example? – Stephane Sep 28 '12 at 16:16