PHP MVC. Как разделить файлы вёрстки в views

Можно ли используя MVC реализовать разделение файла index.php (основная страница с контентом) на header, content, footer, то есть на несколько частей. Если да, то как? Проблема заключается в том, что мне нужно вывести все данные из таблицы, но вывод я могу сделать только в начале или конце index.php.

Каталог views

default.php (макет) Вывод табличных данных в конце кода

<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" href="<?php echo $style; ?>" type="text/css"/>
    <title><?php echo $title ;?></title>
</head>
<body>
    <header class="header">
        <div class="header__inner">
            <div class="header__btns">
                <a id="nickname" href="#"><button><?php echo $_SESSION['user']['nickname']; ?></button></a>
                <a href="/admin"><button>Админка</button></a>
            </div>
            <div class="header__headline">
                <h1>Литературный <span>мир</span></h1>
                <p>Электронная библиотека литературы</p>
            </div>
            <div class="header__search-book">
                <form action="#" method="get">
                    <input type="text" placeholder="Найти книгу...">
                    <button type="submit"><img src="public/image/icon_search.png" alt="#"></button>
                </form>
            </div>
        </div>
    </header>


<?php echo $booksContent; ?>  <--------------- Вывод табличных данных которые хранятся в переменной
<?php echo $content; ?>
<script src="<?php echo $script ?>"></script>
</body>
</html>

View.php (рендеринг макета) Наверное лишнее, но оставлю на всякий случай.

public function render($title, $vars = []) : void {

        extract($vars);
        $pathView = 'application/views/' . $this->path . '.php';
        if(file_exists($pathView)) {
            ob_start();
            require  $pathView;
            $content = ob_get_clean();

            ob_start();
            $db = new Db();
            $result = $db::prepare("SELECT * FROM books ORDER BY id");
            $result->execute();
            if($result->rowCount() > 0){
                while($row = $result->fetch()){
            
            ?>
                    <div class="book">
                        <div class="book__image">
                            <img src="" alt="">
                        </div>
                        <div class="book__title"><?php echo $row['name'] ?></div>
                        <div class="book__author">Автор: <span class="bold_info"><a href="#"><?php echo $row['author'] ?></a></span></div>
                        <div class="book__genre">Жанр: <span class="bold_info"><?php echo $row['genre'] ?></span></div>
                        <div class="book__pages">Страниц: <span class="bold_info"><?php echo $row['pages'] ?></span></div>
                        <a href="#"><button>Читать</button></a>
                </div>
            <?php

                }   
            }
            
            $booksContent = ob_get_clean();

Ответы (1 шт):

Автор решения: Егор Банин

Конечно можно. View это не только шаблоны, а целый слой вашего приложения, который выражает логику формирования HTML. Этот слой может содержать классы форм, меню и прочего.

Забабахайте класс Layout

<?php

class Layout implements Stringable {

    // ...

    public function render(): string
    {
        return ob_include($this->template, [
            'styles' => $this->styles,
            'scripts' => $this->scripts,
            'header' => $this->header,
            'content' => $this->content,
            'footer' => $this->footer,
            'menu' => $this->menu?->render()?? '',
        ]);
    }

    public function __toString(): string
    {
        return $this->render();
    }
}

Который будет рендерить шаблон типа:

<html>
    <head>
        <?php foreach($styles as $href): ?>
            <link href="<?= htmlspecialchars($href) ?>" rel="stylesheet">
        <?php endforeach ?>
        <?php foreach ($scripts as $src): ?>
            <script src="<?= htmlspecialchars($src) ?>"></script>
        <?php endforeach ?>
    </head>
    <body>
        <?= $header ?>
        <nav class="menu">
            <?= $menu ?>
        </nav>
        <?= $content ?>
        <?= $footer ?>
    </body>
</html>

Отдельно отрендерите шаблоны шапки, контента и подвала и передайте их в инстанс Layout. Чаще всего шапка и подвал не зависят о того, что отображается в части content, поэтому их можно отрендерить заранее, а в конкретном контроллере останется только добить content.

<?php 

// ...

return $layout
        ->setMenu($menu->setActive('/myPage'))
        ->setContent(ob_include(__DIR__ . '/myPage.phtml', []));

Ваш код функции render содержит ошибку (extract может извлекать переменные с именами, которые вы используете ниже). Я написал небольшую заметку про php-шаблоны для новичков. Почитайте.

→ Ссылка