|
<?php |
|
namespace yii\twig\Extension; |
|
|
|
use yii\base\InvalidCallException; |
|
use yii\helpers\Inflector; |
|
use yii\helpers\StringHelper; |
|
use yii\twig\NodeVisitor\Optimizer; |
|
|
|
class YiiHelper extends \Twig_Extension |
|
{ |
|
protected $namespaces = []; |
|
protected $aliases = []; |
|
protected $widgets = []; |
|
|
|
public function __construct(array $namespaces = [], array $aliases = []) |
|
{ |
|
$this->addNamespaces($namespaces); |
|
$this->addAliases($aliases); |
|
} |
|
|
|
public function getNodeVisitors() |
|
{ |
|
return [ |
|
new Optimizer(), |
|
]; |
|
} |
|
|
|
public function getFunctions() |
|
{ |
|
$options = [ |
|
'is_safe' => [ |
|
'html', |
|
], |
|
]; |
|
$functions = [ |
|
new \Twig_SimpleFunction('use', [ |
|
$this, |
|
'addAliases', |
|
], $options), |
|
new \Twig_SimpleFunction('register_*_asset', [ |
|
$this, |
|
'registerAsset', |
|
], array_merge($options, [ |
|
'needs_context' => true, |
|
])), |
|
new \Twig_SimpleFunction('begin_*_widget', [ |
|
$this, |
|
'beginWidget', |
|
], $options), |
|
new \Twig_SimpleFunction('end_*_widget', [ |
|
$this, |
|
'endWidget', |
|
], $options), |
|
new \Twig_SimpleFunction('end_widget', [ |
|
$this, |
|
'endWidget', |
|
], $options), |
|
new \Twig_SimpleFunction('widget_*', [ |
|
$this, |
|
'widget', |
|
], $options), |
|
]; |
|
$options = array_merge($options, [ |
|
'needs_context' => true, |
|
]); |
|
foreach (['begin_page', 'end_page', 'begin_body', 'end_body', 'head'] as $helper) { |
|
$functions[] = new \Twig_SimpleFunction($helper, [ |
|
$this, |
|
'viewHelper', |
|
], $options); |
|
} |
|
return $functions; |
|
} |
|
|
|
public function registerAsset($context, $asset) |
|
{ |
|
return $this->resolveAndCall($asset . '_asset', 'register', [ |
|
isset($context['this']) ? $context['this'] : null, |
|
]); |
|
} |
|
|
|
public function beginWidget($widget, $config = []) |
|
{ |
|
$widget = $this->resolveClassName($widget); |
|
$this->widgets[] = $widget; |
|
return $this->call($widget, 'begin', [ |
|
$config, |
|
]); |
|
} |
|
|
|
public function endWidget($widget = null) |
|
{ |
|
if ($widget === null) { |
|
if (empty($this->widgets)) { |
|
throw new InvalidCallException('Unexpected end_widget() call. A matching begin_widget() is not found.'); |
|
} |
|
$this->call(array_pop($this->widgets), 'end'); |
|
} else { |
|
array_pop($this->widgets); |
|
$this->resolveAndCall($widget, 'end'); |
|
} |
|
} |
|
|
|
public function widget($widget, $config = []) |
|
{ |
|
return $this->resolveAndCall($widget, 'widget', [ |
|
$config, |
|
]); |
|
} |
|
|
|
public function viewHelper($context, $name = null) |
|
{ |
|
if ($name === null || !isset($context['this'])) { |
|
return; |
|
} |
|
$this->call($context['this'], Inflector::variablize($name)); |
|
} |
|
|
|
public function resolveAndCall($className, $method, $arguments = null) |
|
{ |
|
return $this->call($this->resolveClassName($className), $method, $arguments); |
|
} |
|
|
|
public function call($className, $method, $arguments = null) |
|
{ |
|
$method = [ |
|
$className, |
|
$method, |
|
]; |
|
if ($arguments === null) { |
|
return call_user_func($method); |
|
} else { |
|
return call_user_func_array($method, $arguments); |
|
} |
|
} |
|
|
|
public function resolveClassName($className) |
|
{ |
|
$className = Inflector::id2camel($className, '_'); |
|
if (isset($this->aliases[$className])) { |
|
return $this->aliases[$className]; |
|
} |
|
$found = false; |
|
$resolvedClassName = null; |
|
foreach ($this->namespaces as $namespace) { |
|
$resolvedClassName = $namespace . '\\' . $className; |
|
if (class_exists($resolvedClassName)) { |
|
$found = true; |
|
break; |
|
} |
|
} |
|
if ($found) { |
|
return $this->aliases[$className] = $resolvedClassName; |
|
} |
|
return $className; |
|
} |
|
|
|
public function addNamespaces(array $namespaces = []) |
|
{ |
|
$this->namespaces = array_merge($this->namespaces, $namespaces); |
|
} |
|
|
|
public function addAliases($aliases = []) |
|
{ |
|
foreach ((array)$aliases as $alias => $class) { |
|
$class = str_replace('/', '\\', $class); |
|
if (is_int($alias)) { |
|
$alias = StringHelper::basename($class); |
|
} |
|
$this->aliases[$alias] = $class; |
|
} |
|
} |
|
|
|
public function getName() |
|
{ |
|
return 'yiiHelper'; |
|
} |
|
} |