How to create a template system with PHP slots/sections?

Asked

Viewed 44 times

0

I have a question for study purposes. I am developing an MVC and AJAX project and, on the pages that would use Javascript, I would use these delimiters.

Code:

<?php $script->start('js'); :>
      <script> console.log("hellow Word")</script>
<?php $script->end(); ?>

On the index page of my styles and script would call this function below the scripts:

<?php $scripts->section('js'); ?> //execulta o codigo acima.
  • 1

    Do you already have more or less an idea? Have you done something? I’ve developed one PHP view system, and for that I used ob_start.

  • 1

    It is important to provide a [mcve] for your question. Click [Edit] and add more information. The question is half vacant...

  • I found a reference to what I’m trying to explain: https://platesphp.com/templates/sections/ Thanks

  • 1

    Exactly what I said. You can use the function ob_start(). It captures all output coming from the code. Then you can recover it with ob_get_end().

  • 1

    What you really want is to know how to work with "section" system in a php template.

  • Thank you for clarifying my doubt, could you give me a simple example ?

  • Hello, young man. I made a very simple example for you to understand.

Show 2 more comments

1 answer

2


Quite simply, I imagine you want to build a layout system and template slots in PHP.

A long time ago I made a lib called Phplegends/View that has it.

Only that, in a very simplified way, you can do the way I will explain below:

Create the Class View, that represents the template that will be rendered.

class View
{
    
    protected $sections    = [];
    protected $lastSection = null;
    protected $layout      = null;
    protected $data        = [];
    protected $filename    = null;

    public function __construct($filename, array $data = [])
    {
        $this->filename = $filename;
        $this->data = $data;
    }

    public function getSection($name)
    {
        return $this->sections[$name] ?? null;
    }

    public function section($name)
    {
        ob_start();

        $this->lastSection = $name;
    }

    public function end()
    {

        $this->sections[$this->lastSection] = trim(ob_get_clean());

        $this->lastSection = null;
    }

    public function render()
    {
        extract($this->data);

        ob_start();

        require $this->filename;

        if ($this->layout) {
            require $this->layout;
        }

        return ob_get_clean();
    }

    public function layout($layout)
    {
        $this->layout = $layout;
    }
}

Next, you now need to create two files to test. Create the file templates/layout.php and templates/teste.php. With the following contents:

php layout.:

<!DOCTYPE html>
<html>
<head>
    <title><?= $this->getSection('title') ?></title>
</head>
<body>
    <?= $this->getSection('content') ?>

    <footer><?= $this->getSection('footer') ?></footer>
</body>
</html>

and test.php

<?php $this->layout('templates/layout.php') ?>

<?php $this->section('footer') ?>
Meu footer bonito
<?php $this->end() ?>

<?php $this->section('content') ?>
Olá, estou na sessão "content". Meu nome é <?= $nome ?> e tenho <?= $idade ?> anos.
<?= $this->end() ?>


<?php $this->section('title') ?>
Título do meu site
<?php $this->end() ?>

Then do the test calling so:

$view = new View('templates/teste.php', [
    'nome' => 'Wallace',
    'idade' => 30,
]);

echo $view->render();

The result will be:

<!DOCTYPE html>
<html>
<head>
    <title>Título do meu site</title>
</head>
<body>
    Olá, estou na sessão "content". Meu nome é Wallace e tenho 30 anos.
    <footer>Meu footer bonito</footer>
</body>
</html>

Explanation

ob_start and ob_get_end

The secret is in the ob_start() and ob_get_end(). The first function captures to memory everything that is going to output (the things you give echo or writes as html). Then when we call ob_get_end you get all stored content and capture is terminated. For ease, we always take the name and put in the variable $sections with a key and a value captured until the call of end.

Note that in render we call again the ob_start(). This is for the content of require not be displayed, but just captured. Even you calling ob_start several times, is considered just the stretch where you called ob_start until the call of ob_get_end. PHP internally stacks until you "close" all ob_start with the call of ob_get_end.

Remembering that this example was the least, only to understand the functioning. You can separate the code better if you feel it necessary, as I did in my library.

Extract

This function transforms the values passed into a array variables. How we use require within the method render, variables will be available in your "template".

So second, in our case, the value ['nome' => 'Wallace', 'idade' => 30] were transformed to $nome and $idade.

Access to $this

How our template was called through the function require, everything inside the class View will be accessible in templates/layout.php and templates/teste.php, including the variable $this. That’s why in my library I created the class Context, to isolate the scope of templates for the instance of Context, since I had things in View who did not want it to be accessible by the template. But in this case, it is only an idea, it is up to you to implement this or otherwise.

NOTE: My section is equivalent to its start, followed by end. And mine getSection is equivalent to its section. Feel free to change the names =)

  • 1

    Thanks a lot for your help, I’ll study thanks but once.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.