0

So I've been researching and working on building my own MVC framework but keep running into 6 different ways of implementing it and I'd like to know if I'm on the right track with what I have so far. And yes, I know I could use Zend or others like it but I really want to learn how frameworks work and not just use someone else's.

Here is a simple version of my index file:

if(isset($_GET['url']))
{
    $url = strtolower($_GET['url']);
}
else
{
    $url = 'home';
}

switch($url)  // Select the controller based on the GET var in the url
{
    case 'home': include(ROOT_DIR . 'app/controllers/homeCon.php'); // This page has the link to the DB test page on it
        break;
    case 'dbtest': include(ROOT_DIR . 'app/controllers/dbTestCon.php');
        break;
    default: include(ROOT_DIR . 'app/views/error404View.php');
}

Here is a simple version of my dbTestCon.php controller:

if(isset($_POST['dbSubBtn']))
{
    $model = new DbTestModel();

    if($_POST['firstName'] != '' && $_POST['lastName'] != '')
    {
        $model->submitToDb($_POST['firstName'], $_POST['lastName'])
        $model->displayPage('goodToGo');
    }  
    else
    {
        $model->displayPage('noInput');
    }
}
else
{
    $model->displayPage('normal');
}

Here is my DbTestModel.php:

class DbTestModel
{
    public function displayPage($version)
    {
        $title = "DB Test Page";
        $themeStylesheetPath = 'public/css/cssStyles.css';

        include(ROOT_DIR . 'app/views/headerView.php');
        include(ROOT_DIR . 'app/views/dbTestView.php');

        switch($version)
        {
            case 'goodToGo':
                include(ROOT_DIR . 'app/views/dbTestSuccessView.php');
                break;
            case 'noInput':
                include(ROOT_DIR . 'app/views/noInputView.php');
                break;
        }
        include(ROOT_DIR . 'app/views/footerView.php');
    }

    public function submitToDb($firstName, $lastName)
    {
        try 
        {
            $db = new PDO("mysql:host=" . DB_HOST . ";dbname=" . DB_NAME, DB_USER, DB_PASS); 
            $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 

            $sql = $db->prepare('insert into dbtest(firstName, lastName) values(:firstName, :lastName)');
            $sql->bindParam(':firstName', $firstName);
            $sql->bindParam(':lastName', $lastName);
            $sql->execute();
            $db = null;
        }
        catch(PDOException $e)
        {
            echo "It seems there was an error.  Please refresh your browser and try again. " . $e->getMessage();
        }
    }
}

And here is my dbTestView.php:

<form name="dbTestForm" id="dbTestForm" method="POST" action="dbtest">
    <label for="firstName">First Name</label>
    <input type="text" name="firstName" id="firstName" />
    <label for="lastName">Last Name</label>
    <input type="text" name="lastName" id="lastName" />
    <input type="submit" name="dbSubBtn" id="dbSubBtn" value="Submit to DB" />
</form>

This simple example works in my testing environment but I'm worried I'll start using it on my next project and realize half way into it that there is something fundamentally wrong with my framework and have to start over again. Thank you for any help or advice.

Matt Whitehead
  • 1,743
  • 3
  • 19
  • 34

2 Answers2

1

NO, it is not the right way!

  • Completely inadequate routing mechanism:

    In your current codebase you would have to manually register every single controller, which would obviously make the bootstrap stage (the index.php file) confusing and error-prone.

  • You have "models" rendering templates

    This would be wrong even in the most primitive interpretations of MVC design pattern. Views are supposed to be instances which contain presentation logic, not templates which are rendered by something you call "models".

  • Model is a layer, not any single class

    MVC design pattern is made from two layers: presentation layer and model layer. Model layer contains all the domain business logic and interacts with storage through some form of abstraction.

  • Do not reinitialize DB connection every time.

    Your "models" initialize new PDO instance every time you need to work with database. Instead you should be creating the connection instance only once and passing it to each of object through constructor.

  • Stop writing code with hidden warnings and error message !

tereško
  • 58,060
  • 25
  • 98
  • 150
  • Thank for your advice. Do you have any recommended tutorials I could check out? As I said in the question, I've found about 6 different ways to build an MVC framework... – Matt Whitehead Sep 09 '12 at 21:14
  • There are no good tutorials for MVC in php, because most of them just assume that Rails was an MVC framework (which it wasn't). I would instead recommend for you to read [GUI Architectures](http://martinfowler.com/eaaDev/uiArchs.html) by Martin Fowler and every linked material [here](http://stackoverflow.com/a/9855170/727208) (there are several lectures for studying advanced OOP). Also you might find [this](http://stackoverflow.com/a/9685039/727208) and [this](http://stackoverflow.com/a/5864000/727208) post post of mine relevant. – tereško Sep 09 '12 at 22:21
0

It's usually considered bad form to do both data storage (e.g Model logic) and output (e.g View logic) in the same place, which is happening in DbTestModel.

There's an absolute tonne of refactoring you could do, but I ain't gonna spell it out for you because I'd end up writing paragraphs.

I'd urge you to read Fabien Potiencer's blog series Create your own framework... on top of the Symfony2 Components.

Even if you don't want to use his components to help build anything, it should give you a heap of good ideas.

Ivo
  • 5,378
  • 2
  • 18
  • 18