1

I was working with a MVC architecture in my php webapp. My architecture it's pretty simple, if I send a request to an url in this way localhost/Dispatcher.php?class=SampleController&method=sampleMethod this will instantiate the controller SampleController and invoke the method sampleMethod of this controller. BTW I can't use the .htaccess file. Now I want to get rid of the Dispatcher.php, so I thought that I could achieve that if I change the sintax of the url to something like this localhost/SampleController.php?method=sampleMethod. To do this I must use $_SERVER['SCRIPT_NAME'] to get the controller class name. All my controllers extends from Controller. I thought that I could instantiate the controller there, in the Controller.php. So, my Controller.php looks like this.

<?php
//Enable errors
ini_set('display_errors',1);
ini_set('display_startup_errors',1);
error_reporting(-1);

//Include the controller
$include = explode("/",$_SERVER['SCRIPT_NAME'])[2]; //This return MainController.php
include_once $include;

//Get the method (Like this is an example I don't care the validations)
$method = $_GET['method'];

$class = explode(".",$include)[0]; //Get rid of the *.php extention
$controller = new $class(); 
$controller->$method(); // I get Class 'MainController' not found

include_once 'View.php';
class Controller {
    public $view;
    public function __construct() {
        $this->view = new View();
    }
}

?>

And this is my MainController.php

<?php
include_once 'Controller.php';
include_once 'MainModel.php';
class MainController extends Controller {

    public $model;

    public function __construct() {
        parent::__construct();
        $this->model = new MainModel();
    }

    public function index(){
        $this->view->render('mainView','headerMain','footerMain');

    }
}

?>

Here I'm trying to hit this url MainController.php?method=index

All the names are ok, the paths are also ok. BTW if I hardcode the paths I get the same error, can be this a includes error? If I can't achieve this in the Controller.php there's some place where I can handle the controller instantiation without add another .php file? (I don't want get back to use the Dispatcher.php)

UPDATE If I change the Controller.php in this way, works, but I get an Fatal error: Cannot redeclare class maincontroller in MainController.php on line 9

<?php
include_once 'View.php';

//Enable errors
ini_set('display_errors',1);
ini_set('display_startup_errors',1);
error_reporting(-1);

//Include the controller
$include = explode("/",$_SERVER['SCRIPT_NAME'])[2]; //This return MainController.php

//Get the method (Like this is an example I don't care the validations)
$method = $_GET['method'];
$class = explode(".",$include)[0];

require($include);

$controller = new $class();
$controller->$method();


class Controller {
    public $view;
    public function __construct() {
        $this->view = new View();
    }
}
?>

WORKAROUND

I achieved what I want in this way:

MainController.php

<?php
//Enable errors
ini_set('display_errors',1);
ini_set('display_startup_errors',1);
error_reporting(-1);

include_once 'Controller.php';
include_once 'MainModel.php';
class MainController extends Controller {

    public $model;

    public function __construct() {
        parent::__construct();
        $this->model = new MainModel();
    }

    public function index(){
        $this->view->render('mainView','headerMain','footerMain');

    }
}

require_once("Core.php");

?>

Controller.php

<?php
include_once 'View.php';

class Controller {
    public $view;
    public function __construct() {
        $this->view = new View();
    }
}
?>

Core.php

<?php
//Enable errors
ini_set('display_errors',1);
ini_set('display_startup_errors',1);
error_reporting(-1);

//Include the controller
$include = explode("/",$_SERVER['SCRIPT_NAME'])[2]; //This return MainController.php

//Get the method (Like this is an example I don't care the validations)
$method = $_GET['method'];
$class = explode(".",$include)[0];

$controller = new $class();
$controller->$method();

?>

But this solution still doesn't satisfice me, this isn't the object oriented solution that I want. Isn't some way of do this in the Controller.php?

4gus71n
  • 3,717
  • 3
  • 39
  • 66
  • Dumb question here: The files you are including is in same path? – Jorge Campos Nov 02 '13 at 04:29
  • There's no dumb questions buddy ;). Yup I strongly checked that. – 4gus71n Nov 02 '13 at 04:33
  • You might want to read [this](http://stackoverflow.com/a/19309893/727208). – tereško Nov 02 '13 at 14:15
  • @teresko Nice info. But what I want It's pretty simple: I want to be capable of send a request to `SampleController.php` the class there, extends from `Controller`, this class contains an method called `doRouting` that do the above stuff, how can I do that without add some extra lines outside the class definition, at the end of `SampleController.php`?. If I can achive that I think that I'll be capable of solve the problem. – 4gus71n Nov 02 '13 at 17:41

1 Answers1

0

Your problem might be that in MainController.php you called include_once 'Controller.php' before the definition of your class. Then the Controller.php won't include MainController.php anymore because include_once noticed that it was already loaded. If you use require that includes MainController.php again, the include_once in MainController.php won't include Controller.php another time, declares the class and returns to Controller.php. When Controller.php is done, it will return to the original MainController.php and this fails to declare the class again.

You might be able to use die() or exit() at the end of Controller.php but I would prefer declaring a function, let's say Process(), that does all the stuff after initializing and call that as the last line of MainController.php.

Controller.php

<?php
//Enable errors
ini_set('display_errors',1);
ini_set('display_startup_errors',1);
error_reporting(-1);

function Process()
{
    //Get the method (Like this is an example I don't care the validations)
    $method = $_GET['method'];

    $class = explode(".",$include)[0]; //Get rid of the *.php extention
    $controller = new $class(); 
    $controller->$method(); // I get Class 'MainController' not found

    include_once 'View.php';
}

class Controller {
    public $view;
    public function __construct() {
        $this->view = new View();
    }
}

?>

MainController.php

<?php
include_once 'Controller.php';
include_once 'MainModel.php';
class MainController extends Controller {

    public $model;

    public function __construct() {
        parent::__construct();
        $this->model = new MainModel();
    }

    public function index(){
        $this->view->render('mainView','headerMain','footerMain');

    }
}

Process();

?>
  • So I have to put `Process();` at the end of each controller. Is there a way to get rid of that? or put it in one place only. – 4gus71n Jan 06 '14 at 01:17
  • Like I said - you might just add `exit()` to the end of your `Controller.php` - but that would be a little dirty solution. If it's important to you to you use the URL of the Controller but without that little `Process()` call, then that might be okay for you. – user3161380 Jan 07 '14 at 19:51