Forums

The forums ran from 2008-2020 and are now closed and viewable here as an archive.

Home Forums Back End MVC Re-Org – need help with templating / views

  • This topic is empty.
Viewing 15 posts - 1 through 15 (of 21 total)
  • Author
    Posts
  • #170402
    shaneisme
    Participant

    About a year ago I started down the road of building my first full-stack PHP site for learning purposes (but also a project at work).

    I had a decent OO version up and running, but I wanted to do a full MVC reorganization since the codebase (even though it’s only about halfway done) is becoming difficult to maintain. I’ve learned a lot over the last year, but I’m still trying to figure out the templating / view portion.

    My main stipulation is that I’ve got to write everything custom without the need for template engines – I will probably switch to a template engine in the future, I just need to learn how to do it.

    Currently, my model and controller are talking back and forth very well and I’m getting raw data from the database without an issue.

    I have a “master” template file that loads up the basics and styles around the content, as well as loading different modules if they’re into the “admin” section of the site.

    I’ve read a couple tutorials on custom templating:

    http://www.gabrielemittica.com/cont/guide/how-you-can-create-a-light-and-useful-template-engine-for-php/10/1.html
    http://www.rasmuslarsson.se/2013/05/a-template-engine-in-php/

    I get how to pass info from my controller over to the view – say build a table with data from the DB. But what I don’t get is how to bring my master template into things.

    Does anyone have any reading material to point me in the right direction? Or know of an open template engine that I can study? Am I making sense?

    If you need more precise details or code examples just let me know what you need, I’m not sure what to provide exactly.

    #170410
    __
    Participant

    I use the master template as a “view controller,” of sorts. Once all of the data models are prepared, I have a method that brings them all into a local scope and then include the template (typically wrapped in an output buffer).

    For example (oversimplified pseudocode):

    controller.php:

    <?php
    
    $page = new webpage( "/route/to/page" );
    $table = new table( $data );
    $article = new article( $content );
    
    $model = array( 'page'=>$page,'table'=>$table,'article'=>$article );
    
    $output = viewTemplate( ""path/to/template.php",$model );
    print $output;
    exit;
    
    

    viewTemplate function:

    function viewTemplate( $template,array $model=[] ){
        // bring data models into local scope
        extract( $model,EXTR_PREFIX_ALL,"__" );
        ob_start();
        require $template;
        return ob_get_clean();
    }
    

    template.php:

    <!doctype html>
    <html>
    <head>
        <title><?= $__page->title ?></title>
        <meta charset=utf-8>
    </head>
    <body>
        <h1><?= $__page->title ?></h1>
        <?= $__article->asHTML() ?>
        <?= $__table->asHTML() ?>
    </body>
    </html>
    
    #170412
    __
    Participant

    http://www.gabrielemittica.com/cont/guide/how-you-can-create-a-light-and-useful-template-engine-for-php/10/1.html

    After reading that, it seems basically similar to what I’m doing. Have you already tried this approach? did you run into problems with it?

    I will probably switch to a template engine in the future

    Honestly, I would discourage that. PHP is already a templating language (in fact, all of its “legitimate” programming capabilities are basically tacked on as an afterthought).

    Add any special methods you find a need for, sure.
    But a full-blown TL (e.g., Smarty) only adds execution time and a second learning curve.

    #170413
    shaneisme
    Participant

    OK – I understand how that works on a high level. Let’s take it one deeper.

    Say you had your template.php, but you wanted to bring in the HTML to build a table from company_table.php or something. So basically, a template within a template.

    At that point, would you just use the viewTemplate function again? If so, how would I insert the company_table.php code which, say, has a foreach loop to build up the table?

    #170414
    shaneisme
    Participant

    After reading that, it seems basically similar to what I’m doing. Have you already tried this approach? did you run into problems with it?

    I think I understand that example + yours, but I needed more functionality (I think, see post above), unless I’m not seeing it yet.

    #170416
    __
    Participant

    So basically, a template within a template.

    I have a “viewable” interface for data models that can be used inside templates. This not only makes certain that every model has its “viewAsHTML (JSON, whatever)” method, but also provides a framework where they can be nested.

    Basically, the controller only need choose the top-level template. This template has no need to know how its data models find the data they need: they handle their own templating. An article may simply wrap its contents in <article> tags, or it might be composed of header, author, body, pullquote, figure, and/or footer objects, each responsible for their own templates.

    I might have a template directory set up more-or-less like so:

    views/
        general/
            article.html
            table.html
        current-theme/
            current-page/
                article.html
            article.html
    

    Each “viewable” model might look for their template (in order):

    • in the current page + current theme directory
    • in the current theme directory
    • in the “general” directory
    • I usually include a default template in the class itself as a fallback (though this is almost always the one that is actually used).

    Under this design, using my example above:

    • $article would use the current-theme/current-page/article.html template
    • $table would use the general/table.html template
    • if we added another model to the page (say, $pageViewCounter), it would use its “fallback” template.

    Each “viewable” model returns its contents, as a string, to the viewable that called it. Eventually, it reaches the top-level template and becomes part of the finished HTML markup.

    how would I insert the company_table.php code which, say, has a foreach loop to build up the table?

    The specific logic of how to do display the data is handled by the particular model (or the model’s template). Because each component template is called from inside a class method, it will already have access to the model via $this. A table template, for example, could simply look like this:

    <?php
    
    foreach( $this->data as $tr ){
        $tds = [];
        foreach( $tr as $td ){
            $tds[] = "<td>$td</td>";
        }
        $trs = "<tr>".implode( "",$tds )."</tr>";
    }
    // remember, we are inside an output buffer
    print "<table>".implode( "",$trs )."</table>";
    
    #170417
    shaneisme
    Participant

    Each “viewable” model returns its contents, as a string, to the viewable that called it. Eventually, it reaches the top-level template and becomes part of the finished HTML markup.

    OK – this is the part I think I’m having difficulty wrapping my head around.

    My current config does the following:

    1) Via front-controller, client builds controller based on URI
    2) Controller talks to model to get data to build view client is requesting
    3) Controller passes data to view

    In my understanding, this is a classical MVC setup (correct me if I’m wrong).

    In your example, you’re going to have the master template being called by the controller and passing the data through to it. What step out of my simplified list above should all the compiling of different templates occur?

    My original understanding would be that it occurs after the controller gets its data from the model and then the controller itself would call each template and put them together.

    #170418
    __
    Participant

    The controller doesn’t have to do everything. Think about leadership in the real world: you figure out what needs to be done, and then tell your workers (who specialize in their individual tasks) to do this, or that. Good leaders don’t micromanage: you tell specialist X that you need a Y, and they make you one. You don’t make the specialist scoot over and follow the step-by-step Y instructions while you read them off one at a time.

    The controller figures out what the user wants, makes sure everything needed is available, and then sets things in motion. Then it’s done: it gets to just sit back and wait until it is given the finished HTML, and print it.

    Views should have access to the models directly. Instead of asking the Controller for a from X, b from X, and c from X, it just asks for X.

    In other words, the Controller doesn’t get data from the Model and pass it the the View, it gets the Model itself and passes it to the View. Simple.

    1) front-controller chooses Controller based on client’s request.
    2) controller decides on a View and gathers required Models*.
    3) controller passes the models to the view, which returns the rendered data.
    4) controller prints the rendered view and exits.

    * note; this is only the models required bythe View: if those models are made from other models, it’s their own business and no one else needs to know.

    #170419
    shaneisme
    Participant

    OK… I’m going to think on this a while. I have another project I’m working on before I continue on this project, so I’ll check in later.

    Thanks for your thoughts @traq, appreciate it.

    More later.

    #170421
    __
    Participant

    NB; the “nesting” I am describing might be more correctly called “m (modular) MVC” or “H (hierarchical) MVC” —and, sure, whatever, I don’t care to be drawn into that debate— but the C in MVC was never meant to micromanage.

    #170422
    __
    Participant

    OK… I’m going to think on this a while. …appreciate it.

    No problem. I’m in the process of rewriting my framework, so I don’t have much finished code to share. It took me a while to nail all this down, and my last version had a few wrong turns in it (which is a big reason behind the rewrite).

    #178350
    shaneisme
    Participant

    I’m just now getting back into my project, but either A) I’ve forgotten something, or B) something broke while I was working on other things…

    Please school me if necessary.

    In my core controller, I’m setting a PDO DB object and saving it under a public variable $db.

    In the children controllers, I extend the core controller. However, $this->db comes up NULL in the child now. I could have swore that was working when I left it…

    Very basic example just to illustrate what I mean:

    controller\core:

    `
    namespace controller;
    use PDO;

    class core {
    protected $variable = null;

    public function __construct() {
    $this->variable = 1;
    }

    }
    `

    controller\example\test:

    `
    namespace controller\example;
    use controller\core as Controller;

    class test extends Controller {

    public function __construct() {
    var_dump($this->db);
    }

    }

    `
    I expect the var_dump to return 1, however it’s returning NULL.

    What’s wrong?

    P.S. – sorry for the formatting, I can’t get it working for some reason.

    #178355
    shaneisme
    Participant

    Ah hah, ok… that’s what I missed.

    Now I’ve got some sort of database connection loop going on which I’m fairly certain I can debug.

    Thanks!

    #183294
    shaneisme
    Participant

    Question – if I had hard-coded HTML emails, I should store this among my model correct?

    I was almost going to just put them in my template folder… but then I thought this is technically data to be fetched with some variables set inside the controller… like I would a SQL call.

    #183305
    shaneisme
    Participant

    At this point in the project, my model consists mostly of SQL calls which accept parameters and variables from the controller.

    The controller handles user inputs, sends them to the model and when it has what it needs it passes everything to the view. The view will return HTML given the parameters given to it by the controller.

    First, I’m thinking about that correctly?

    If that’s true, then setting it up as a view (and pulling reusable HTML templates) and then emailing that final HTML is basically the same thing, from what you’re saying, as outputting to a browser.

    If all that sounds right, I know what I need to do!

Viewing 15 posts - 1 through 15 (of 21 total)
  • The forum ‘Back End’ is closed to new topics and replies.