Commit e1bdc9cd by Alexander Makarov

Fixes #3674: Various Twig enhancements:

- Removed `FileLoader` and used `\Twig_Loader_Filesystem` instead. - Added support of Yii's aliases. - Added `set()` that allows setting object properties.
parent 898499ed
...@@ -82,6 +82,15 @@ In case you don't need result you shoud use `void` wrapper: ...@@ -82,6 +82,15 @@ In case you don't need result you shoud use `void` wrapper:
{{ void(myObject.my_function({'a' : 'b'})) }} {{ void(myObject.my_function({'a' : 'b'})) }}
``` ```
#### Setting object properties
There's a special function called `set` that allows you to set property of an object. For example, the following
in the template will change page title:
```
{{ set(this, 'title', 'New title') }}
```
#### Importing namespaces and classes #### Importing namespaces and classes
You can import additional classes and namespaces right in the template: You can import additional classes and namespaces right in the template:
...@@ -97,6 +106,23 @@ Aliased class import: ...@@ -97,6 +106,23 @@ Aliased class import:
{{ use({'alias' => '/app/widgets/MyWidget'}) }} {{ use({'alias' => '/app/widgets/MyWidget'}) }}
``` ```
#### Referencing other views
There are two ways of referencing views in `include` and `extends` statements:
```
{% include "comment.twig" %}
{% extends "post.twig" %
{% include "@app/views/snippets/avatar.twig" %}
{% extends "@app/views/layouts/2columns.twig" %}
```
In the first case the view will be searched relatively to the path current view is in. For `comment.twig` and `post.twig`
that means these will be searched in the same directory as the view that's rendered currently.
In the second case we're using path aliases. All the Yii aliases such as `@app` are available by default.
#### Widgets #### Widgets
Extension helps using widgets in convenient way converting their syntax to function calls: Extension helps using widgets in convenient way converting their syntax to function calls:
......
...@@ -8,6 +8,10 @@ Yii Framework 2 twig extension Change Log ...@@ -8,6 +8,10 @@ Yii Framework 2 twig extension Change Log
- Bug #3767: Fixed repeated adding of extensions when using config. One may now pass extension instances as well (grachov) - Bug #3767: Fixed repeated adding of extensions when using config. One may now pass extension instances as well (grachov)
- Bug #3877: Fixed `lexerOptions` throwing exception (dapatrese) - Bug #3877: Fixed `lexerOptions` throwing exception (dapatrese)
- Enh #1799: Added `form_begin`, `form_end` to twig extension (samdark) - Enh #1799: Added `form_begin`, `form_end` to twig extension (samdark)
- Enh #3674: Various enhancements (samdark)
- Removed `FileLoader` and used `\Twig_Loader_Filesystem` instead.
- Added support of Yii's aliases.
- Added `set()` that allows setting object properties.
- Chg #3535: Syntax changes: - Chg #3535: Syntax changes:
- Removed `form_begin`, `form_end` (samdark) - Removed `form_begin`, `form_end` (samdark)
- Added `use()` and `ViewRenderer::uses` that are importing classes and namespaces (grachov, samdark) - Added `use()` and `ViewRenderer::uses` that are importing classes and namespaces (grachov, samdark)
......
...@@ -71,6 +71,7 @@ class Extension extends \Twig_Extension ...@@ -71,6 +71,7 @@ class Extension extends \Twig_Extension
new \Twig_SimpleFunction('path', [$this, 'path']), new \Twig_SimpleFunction('path', [$this, 'path']),
new \Twig_SimpleFunction('url', [$this, 'url']), new \Twig_SimpleFunction('url', [$this, 'url']),
new \Twig_SimpleFunction('void', function(){}), new \Twig_SimpleFunction('void', function(){}),
new \Twig_SimpleFunction('set', [$this, 'setProperty']),
]; ];
$options = array_merge($options, [ $options = array_merge($options, [
...@@ -187,6 +188,11 @@ class Extension extends \Twig_Extension ...@@ -187,6 +188,11 @@ class Extension extends \Twig_Extension
return Url::to(array_merge([$path], $args), true); return Url::to(array_merge([$path], $args), true);
} }
public function setProperty($object, $property, $value)
{
$object->$property = $value;
}
/** /**
* @inheritdoc * @inheritdoc
*/ */
......
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\twig;
/**
* Twig view file loader class.
*
* @author dev-mraj <dev.meghraj@gmail.com>
*/
class FileLoader implements \Twig_LoaderInterface
{
/**
* @var string Path to directory
*/
private $_dir;
/**
* @param string $dir path to directory
*/
public function __construct($dir)
{
$this->_dir = $dir;
}
/**
* Compare a file's freshness with previously stored timestamp
*
* @param string $name file name to check
* @param integer $time timestamp to compare with
* @return boolean true if file is still fresh and not changes, false otherwise
*/
public function isFresh($name, $time)
{
return filemtime($this->getFilePath($name)) <= $time;
}
/**
* Get the source of given file name
*
* @param string $name file name
* @return string contents of given file name
*/
public function getSource($name)
{
return file_get_contents($this->getFilePath($name));
}
/**
* Get unique key that can represent this file uniquely among other files.
* @param string $name
* @return string
*/
public function getCacheKey($name)
{
return $this->getFilePath($name);
}
/**
* internally used to get absolute path of given file name
* @param string $name file name
* @return string absolute path of file
*/
protected function getFilePath($name)
{
return $this->_dir . '/' . $name;
}
}
...@@ -143,7 +143,12 @@ class ViewRenderer extends BaseViewRenderer ...@@ -143,7 +143,12 @@ class ViewRenderer extends BaseViewRenderer
public function render($view, $file, $params) public function render($view, $file, $params)
{ {
$this->twig->addGlobal('this', $view); $this->twig->addGlobal('this', $view);
$this->twig->setLoader(new FileLoader(dirname($file))); $loader = new \Twig_Loader_Filesystem(dirname($file));
foreach (Yii::$aliases as $alias => $path) {
$loader->addPath($path, substr($alias, 1));
}
$this->twig->setLoader($loader);
return $this->twig->render(pathinfo($file, PATHINFO_BASENAME), $params); return $this->twig->render(pathinfo($file, PATHINFO_BASENAME), $params);
} }
......
...@@ -69,6 +69,30 @@ class ViewRendererTest extends TestCase ...@@ -69,6 +69,30 @@ class ViewRendererTest extends TestCase
$this->assertTrue(strpos($content, 'variable') !== false, 'variable should be there:' . $content); $this->assertTrue(strpos($content, 'variable') !== false, 'variable should be there:' . $content);
} }
public function testInheritance()
{
$view = $this->mockView();
$content = $view->renderFile('@yiiunit/extensions/twig/views/extends2.twig');
$this->assertTrue(strpos($content, 'Hello, I\'m inheritance test!') !== false, 'Hello, I\'m inheritance test! should be there:' . $content);
$this->assertTrue(strpos($content, 'extends2 block') !== false, 'extends2 block should be there:' . $content);
$this->assertFalse(strpos($content, 'extends1 block') !== false, 'extends1 block should not be there:' . $content);
$content = $view->renderFile('@yiiunit/extensions/twig/views/extends3.twig');
$this->assertTrue(strpos($content, 'Hello, I\'m inheritance test!') !== false, 'Hello, I\'m inheritance test! should be there:' . $content);
$this->assertTrue(strpos($content, 'extends3 block') !== false, 'extends3 block should be there:' . $content);
$this->assertFalse(strpos($content, 'extends1 block') !== false, 'extends1 block should not be there:' . $content);
}
public function testChangeTitle()
{
$view = $this->mockView();
$view->title = 'Original title';
$content = $view->renderFile('@yiiunit/extensions/twig/views/changeTitle.twig');
$this->assertTrue(strpos($content, 'New title') !== false, 'New title should be there:' . $content);
$this->assertFalse(strpos($content, 'Original title') !== false, 'Original title should not be there:' . $content);
}
/** /**
* Mocks view instance * Mocks view instance
* @return View * @return View
......
{{ set(this, 'title', 'New title') }}
<title>{{ this.title }}</title>
\ No newline at end of file
Hello, I'm inheritance test!
{% block test %}
extends1 block
{% endblock %}
\ No newline at end of file
{% extends "extends1.twig" %}
{% block test %}
extends2 block
{% endblock %}
\ No newline at end of file
{% extends "@yiiunit/extensions/twig/views/extends1.twig" %}
{% block test %}
extends3 block
{% endblock %}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment