ViewRenderer.php 7.02 KB
Newer Older
1 2 3
<?php
/**
 * @link http://www.yiiframework.com/
Carsten Brandt committed
4
 * @copyright Copyright (c) 2008 Yii Software LLC
5 6 7
 * @license http://www.yiiframework.com/license/
 */

Qiang Xue committed
8
namespace yii\twig;
9

Qiang Xue committed
10 11
use Yii;
use yii\base\View;
12
use yii\base\ViewRenderer as BaseViewRenderer;
13 14 15 16

/**
 * TwigViewRenderer allows you to use Twig templates in views.
 *
17 18
 * @property array $lexerOptions @see self::$lexerOptions. This property is write-only.
 *
19 20 21
 * @author Alexander Makarov <sam@rmcreative.ru>
 * @since 2.0
 */
22
class ViewRenderer extends BaseViewRenderer
23
{
24
    /**
Alexander Makarov committed
25 26
     * @var string the directory or path alias pointing to where Twig cache will be stored. Set to false to disable
     * templates cache.
27 28
     */
    public $cachePath = '@runtime/Twig/cache';
29

30 31 32 33 34
    /**
     * @var array Twig options.
     * @see http://twig.sensiolabs.org/doc/api.html#environment-options
     */
    public $options = [];
35

36 37 38 39 40 41 42
    /**
     * @var array Objects or static classes.
     * Keys of the array are names to call in template, values are objects or names of static classes.
     * Example: `['html' => '\yii\helpers\Html']`.
     * In the template you can use it like this: `{{ html.a('Login', 'site/login') | raw }}`.
     */
    public $globals = [];
43

44 45 46 47 48 49 50
    /**
     * @var array Custom functions.
     * Keys of the array are names to call in template, values are names of functions or static methods of some class.
     * Example: `['rot13' => 'str_rot13', 'a' => '\yii\helpers\Html::a']`.
     * In the template you can use it like this: `{{ rot13('test') }}` or `{{ a('Login', 'site/login') | raw }}`.
     */
    public $functions = [];
51

52 53 54 55 56 57 58
    /**
     * @var array Custom filters.
     * Keys of the array are names to call in template, values are names of functions or static methods of some class.
     * Example: `['rot13' => 'str_rot13', 'jsonEncode' => '\yii\helpers\Json::encode']`.
     * In the template you can use it like this: `{{ 'test'|rot13 }}` or `{{ model|jsonEncode }}`.
     */
    public $filters = [];
59

60 61
    /**
     * @var array Custom extensions.
62
     * Example: `['Twig_Extension_Sandbox', new \Twig_Extension_Text()]`
63 64
     */
    public $extensions = [];
65

66 67
    /**
     * @var array Twig lexer options.
68
     *
69 70 71 72 73 74 75 76 77 78 79
     * Example: Smarty-like syntax:
     * ```php
     * [
     *     'tag_comment'  => ['{*', '*}'],
     *     'tag_block'    => ['{', '}'],
     *     'tag_variable' => ['{$', '}']
     * ]
     * ```
     * @see http://twig.sensiolabs.org/doc/recipes.html#customizing-the-syntax
     */
    public $lexerOptions = [];
80

81
    /**
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
     * @var array namespaces and classes to import.
     *
     * Example:
     *
     * ```php
     * [
     *     'yii\bootstrap',
     *     'app\assets',
     *     \yii\bootstrap\NavBar::className(),
     * ]
     * ```
     */
    public $uses = [];

    /**
     * @var \Twig_Environment twig environment object that renders twig templates
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
     */
    public $twig;

    public function init()
    {
        $this->twig = new \Twig_Environment(null, array_merge([
            'cache' => Yii::getAlias($this->cachePath),
            'charset' => Yii::$app->charset,
        ], $this->options));

        // Adding custom globals (objects or static classes)
        if (!empty($this->globals)) {
            $this->addGlobals($this->globals);
        }

        // Adding custom functions
        if (!empty($this->functions)) {
            $this->addFunctions($this->functions);
        }

        // Adding custom filters
        if (!empty($this->filters)) {
            $this->addFilters($this->filters);
        }

123 124
        $this->addExtensions([new Extension($this->uses)]);

125 126 127 128 129 130
        // Adding custom extensions
        if (!empty($this->extensions)) {
            $this->addExtensions($this->extensions);
        }

        $this->twig->addGlobal('app', \Yii::$app);
131 132 133 134 135

        // Change lexer syntax (must be set after other settings)
        if (!empty($this->lexerOptions)) {
            $this->setLexerOptions($this->lexerOptions);
        }
136 137 138 139 140 141 142 143
    }

    /**
     * Renders a view file.
     *
     * This method is invoked by [[View]] whenever it tries to render a view.
     * Child classes must implement this method to render the given view file.
     *
144 145 146
     * @param View $view the view object used for rendering the file.
     * @param string $file the view file.
     * @param array $params the parameters to be passed to the view file.
147 148 149 150 151 152
     *
     * @return string the rendering result
     */
    public function render($view, $file, $params)
    {
        $this->twig->addGlobal('this', $view);
153
        $this->twig->setLoader(new FileLoader(dirname($file)));
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196

        return $this->twig->render(pathinfo($file, PATHINFO_BASENAME), $params);
    }

    /**
     * Adds global objects or static classes
     * @param array $globals @see self::$globals
     */
    public function addGlobals($globals)
    {
        foreach ($globals as $name => $value) {
            if (!is_object($value)) {
                $value = new ViewRendererStaticClassProxy($value);
            }
            $this->twig->addGlobal($name, $value);
        }
    }

    /**
     * Adds custom functions
     * @param array $functions @see self::$functions
     */
    public function addFunctions($functions)
    {
        $this->_addCustom('Function', $functions);
    }

    /**
     * Adds custom filters
     * @param array $filters @see self::$filters
     */
    public function addFilters($filters)
    {
        $this->_addCustom('Filter', $filters);
    }

    /**
     * Adds custom extensions
     * @param array $extensions @see self::$extensions
     */
    public function addExtensions($extensions)
    {
        foreach ($extensions as $extName) {
197
            $this->twig->addExtension(is_object($extName) ? $extName : new $extName());
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
        }
    }

    /**
     * Sets Twig lexer options to change templates syntax
     * @param array $options @see self::$lexerOptions
     */
    public function setLexerOptions($options)
    {
        $lexer = new \Twig_Lexer($this->twig, $options);
        $this->twig->setLexer($lexer);
    }

    /**
     * Adds custom function or filter
213 214
     * @param string $classType 'Function' or 'Filter'
     * @param array $elements Parameters of elements to add
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
     * @throws \Exception
     */
    private function _addCustom($classType, $elements)
    {
        $classFunction = 'Twig_' . $classType . '_Function';

        foreach ($elements as $name => $func) {
            $twigElement = null;

            switch ($func) {
                // Just a name of function
                case is_string($func):
                    $twigElement = new $classFunction($func);
                    break;
                // Name of function + options array
                case is_array($func) && is_string($func[0]) && isset($func[1]) && is_array($func[1]):
                    $twigElement = new $classFunction($func[0], $func[1]);
                    break;
            }

            if ($twigElement !== null) {
                $this->twig->{'add'.$classType}($name, $twigElement);
            } else {
                throw new \Exception("Incorrect options for \"$classType\" $name.");
            }
        }
    }
242
}