yiisoft/yii2-twig

Cannot replace main.php with main.twig or main.html.twig

jblac opened this issue · 3 comments

jblac commented

What steps will reproduce the problem?

Using twig in the backend of the advanced template
using 2.0.13.1 for Yii
and following the instructions at: to setup the base layout.
https://github.com/yiisoft/yii2-twig/blob/master/docs/guide/layouts-and-widgets.md#main-layout
delete the main.php file from the layouts folder

What's expected?

Everything works as expected.

What do you get instead?

The view file does not exist: /var/www/myawesomeapp/backend/views/layouts/main.php

Additional info

Q A
Yii version 2.0.13.1
Yii Twig version 2.2.1
Twig version 2.5.0
PHP version 7
Operating system Ubuntu 16.04
cebe commented
  1. I found the description in the guide was not accurate, as some paths were wrong.
  2. are you sure you do not reference main.php in some other places? Make sure to set the layout to main.twig in application config.
jblac commented

Hi Cebe,

I did a search of both the backend folder and common folder recursively for anything containing main.php and the only files referenced were within the config directories.

My main.php file for backend looks like:

<?php

$params = array_merge(
    require __DIR__ . '/../../common/config/params.php',
    require __DIR__ . '/../../common/config/params-local.php',
    require __DIR__ . '/params.php',
    require __DIR__ . '/params-local.php'
);

return [
    'id' => 'app-backend',
    'basePath' => dirname(__DIR__),
    'controllerNamespace' => 'backend\controllers',
    'timezone' => 'UTC',
    'modules' => [],
    'layout' => 'main.html.twig',
    'components' => [
        'urlManager' => [
            'enablePrettyUrl' => true,

            'showScriptName' => false,
            'rules' => [
                '/' => 'site/index',
                '/login' => 'site/login',
                '/logout' => 'site/logout',
            ],
        ],
        'view' => [
            'class' => 'yii\web\View',
            'renderers' => [
                'twig' => [
                    'class' => 'yii\twig\ViewRenderer',
                    'cachePath' => '@runtime/Twig/cache',
                    'options' => [
                        'debug' => YII_DEBUG,
                        'auto_reload' => true,
                    ],
                    'globals' => [
                        'html' => ['class' => '\yii\\helpers\Html'],
                    ],
                    'functions' => [
                        new Twig_SimpleFunction('is_granted', function($permission) {
                           return Yii::$app->user->can($permission);
                        })
                    ],
                    'filters' => [
                        new Twig_SimpleFilter('constant', function($argument) {
                            $arguments = explode('::', $argument);
                            $class = new $arguments[0];
                            return $class::$arguments[1];
                        })
                    ],
                    'uses' => ['yii\bootstrap'],
                ],
            ],
        ],
        'request' => [
            'csrfParam' => '_csrf-backend',
            'cookieValidationKey' => getenv('APP_COOKIE'),
        ],
        'user' => [
            'class' => 'common\components\User',
            'identityClass' => 'common\models\User',
            'enableAutoLogin' => true,
            'identityCookie' => [
                'name' => '_backendUser',
                'path' => '/myapp/backend/web'
            ]
        ],
        'session' => [
            'name' => 'myapp-backend',
        ],
        'log' => [
            'traceLevel' => YII_DEBUG ? 3 : 0,
            'targets' => [
                [
                    'class' => 'yii\log\FileTarget',
                    'levels' => ['error', 'warning']
                ]
            ]
        ],
        'errorHandler' => [
            'errorAction' => 'site/error'
        ],
    ],
    'params' => $params
];

my main.html.twig located at backend/views/layouts/main.html.twig:

{{ register_asset_bundle('backend/assets/AppAsset') }} 
    {{   void(this.beginPage()) }}
<!DOCTYPE html>
<html lang="{{ app.language }}">
<head>
    <meta charset="{{ app.charset }}">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>{{ html.encode(this.title) }}</title>
    {{ html.csrfMetaTags | raw }}
    {{   void(this.head) }}
</head>
<body>
{{   void(this.beginBody()) }}
{{ content | raw }}
{{   void(this.endBody()) }}
</body>
</html>
{{   void(this.endPage()) }}

my SiteController.php located at backend/controllers/SiteController.php:

<?php

namespace backend\controllers;

use Yii;
use yii\helpers\Url;
use yii\web\Controller;
use yii\filters\VerbFilter;
use yii\filters\AccessControl;

class SiteController extends Controller
{

    public function events()
    {
        return [
            self::EVENT_BEFORE_ACTION => 'beforeAction'
        ];
    }

    /**
     * {@inheritdoc}
     */
    public function behaviors()
    {
        return [
            'access' => [
                'class' => AccessControl::className(),
                'rules' => [
                    [
                        'actions' => ['login', 'error'],
                        'allow' => true,
                    ],
                    [
                        'actions' => ['logout', 'index'],
                        'allow' => true,
                        'roles' => ['@']
                    ],
                ],
            ],
            'verbs' => [
                'class' => VerbFilter::className(),
                'actions' => [
                    'logout' => ['delete'],
                ],
            ],
        ];
    }

    /**
     * {@inheritdoc}
     */
    public function actions()
    {
        return [
            'error' => [
                'class' => 'yii\web\ErrorAction',
            ],
        ];
    }

    public function beforeAction($action)
    {
        if (Yii::$app->user->isGuest && Yii::$app->getRequest()->url !== Url::to('/login')) {
            $this->redirect('/login');
        }
    }

    public function actionIndex()
    {
        return $this->render('index.html.twig');
    }

    public function actionLogin()
    {
        if (!Yii::$app->user->isGuest) {
            return $this->goHome();
        }

        /**
         * commented out because there should be some other things done here.
         * $model = new LoginForm();
         * if ($model->load(Yii::$app->request->post()) && $model->login()) {
         *     return $this->goBack();
         * }
         *
         * $model->password = '';
         * return $this->render('login', ['model' => $model]);
         */
        return $this->render('login.html.twig', ['model' => 'hi']);
    }

    public function actionLogout()
    {
        Yii::$app->user->logout();
        return $this->goLogin();
    }
}

and my views (which are stupid simple atm with no functionality); For index.html.twig, login.html.twig and error.html.twig i have a corresponding h1 tag:
<h1>Login Page</h1> for each page.

As of right now I delete the main.php which previously (for me) just had <?= $content; ?> in it, and i get the 404. When I dig deeper into the YII2 code, most notably yii\base\Controller.php renderContent function, it looks like line 397 is returning /var/www/mycoolapp/backend/views/layouts/main.php . It would appear that the view object has a default extension of php making line 521 of the yii\base\Controller.php to be essentially: $path = "$file.php";

so, adding 'defaultExtension' => 'html.twig', into my main.php configuration then makes the layout file be seen as the right file name. Which removing all my debugging stuff from the yii\base\Controller and reload my screen - it begins to work.

So now the view portion of my main configuration looks like:

'view' => [
            'class' => 'yii\web\View',
            'defaultExtension' => 'html.twig',
            'renderers' => [
                'twig' => [
                    'class' => 'yii\twig\ViewRenderer',
                    'cachePath' => '@runtime/Twig/cache',
                    'options' => [
                        'debug' => YII_DEBUG,
                        'auto_reload' => true,
                    ],
                    'globals' => [
                        'html' => ['class' => '\yii\\helpers\Html'],
                    ],
                    'functions' => [
                        new Twig_SimpleFunction('is_granted', function($permission) {
                           return Yii::$app->user->can($permission);
                        })
                    ],
                    'filters' => [
                        new Twig_SimpleFilter('constant', function($argument) {
                            $arguments = explode('::', $argument);
                            $class = new $arguments[0];
                            return $class::$arguments[1];
                        })
                    ],
                    'uses' => ['yii\bootstrap'],
                ],
            ],
        ],

helped me: add 'layout' => 'main.twig' in config