Refactor template engine code
- Convert ITemplateEngine interface to abstract class - Remove dependency to App in FriendicaSmarty and FriendicaSmartyEngine - Normalize replaceMacro parameter behavior using Smarty template string prefixes - Remove obsolete FriendicaSmarty->parsed method - Update unused Smarty directory paths
This commit is contained in:
parent
75a0b80888
commit
c6ba92c43d
5 changed files with 97 additions and 72 deletions
|
@ -23,8 +23,7 @@ namespace Friendica\Core;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
use Friendica\DI;
|
use Friendica\DI;
|
||||||
use Friendica\Render\FriendicaSmarty;
|
use Friendica\Render\TemplateEngine;
|
||||||
use Friendica\Render\ITemplateEngine;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class handles Renderer related functions.
|
* This class handles Renderer related functions.
|
||||||
|
@ -66,25 +65,23 @@ class Renderer
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is our template processor
|
* Returns the rendered template output from the template string and variables
|
||||||
*
|
*
|
||||||
* @param string|FriendicaSmarty $s The string requiring macro substitution or an instance of FriendicaSmarty
|
* @param string $template
|
||||||
* @param array $vars Key value pairs (search => replace)
|
* @param array $vars
|
||||||
*
|
* @return string
|
||||||
* @return string substituted string
|
|
||||||
* @throws Exception
|
|
||||||
*/
|
*/
|
||||||
public static function replaceMacros($s, array $vars = [])
|
public static function replaceMacros(string $template, array $vars)
|
||||||
{
|
{
|
||||||
$stamp1 = microtime(true);
|
$stamp1 = microtime(true);
|
||||||
|
|
||||||
// pass $baseurl to all templates if it isn't set
|
// pass $baseurl to all templates if it isn't set
|
||||||
$vars = array_merge(['$baseurl' => DI::baseUrl()->get()], $vars);
|
$vars = array_merge(['$baseurl' => DI::baseUrl()->get(), '$APP' => DI::app()], $vars);
|
||||||
|
|
||||||
$t = self::getTemplateEngine();
|
$t = self::getTemplateEngine();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$output = $t->replaceMacros($s, $vars);
|
$output = $t->replaceMacros($template, $vars);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
echo "<pre><b>" . __FUNCTION__ . "</b>: " . $e->getMessage() . "</pre>";
|
echo "<pre><b>" . __FUNCTION__ . "</b>: " . $e->getMessage() . "</pre>";
|
||||||
exit();
|
exit();
|
||||||
|
@ -98,19 +95,19 @@ class Renderer
|
||||||
/**
|
/**
|
||||||
* Load a given template $s
|
* Load a given template $s
|
||||||
*
|
*
|
||||||
* @param string $s Template to load.
|
* @param string $file Template to load.
|
||||||
* @param string $subDir Subdirectory (Optional)
|
* @param string $subDir Subdirectory (Optional)
|
||||||
*
|
*
|
||||||
* @return string template.
|
* @return string template.
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public static function getMarkupTemplate($s, $subDir = '')
|
public static function getMarkupTemplate($file, $subDir = '')
|
||||||
{
|
{
|
||||||
$stamp1 = microtime(true);
|
$stamp1 = microtime(true);
|
||||||
$t = self::getTemplateEngine();
|
$t = self::getTemplateEngine();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$template = $t->getTemplateFile($s, $subDir);
|
$template = $t->getTemplateFile($file, $subDir);
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
echo "<pre><b>" . __FUNCTION__ . "</b>: " . $e->getMessage() . "</pre>";
|
echo "<pre><b>" . __FUNCTION__ . "</b>: " . $e->getMessage() . "</pre>";
|
||||||
exit();
|
exit();
|
||||||
|
@ -130,8 +127,7 @@ class Renderer
|
||||||
{
|
{
|
||||||
$v = get_class_vars($class);
|
$v = get_class_vars($class);
|
||||||
|
|
||||||
if (!empty($v['name']))
|
if (!empty($v['name'])) {
|
||||||
{
|
|
||||||
$name = $v['name'];
|
$name = $v['name'];
|
||||||
self::$template_engines[$name] = $class;
|
self::$template_engines[$name] = $class;
|
||||||
} else {
|
} else {
|
||||||
|
@ -146,7 +142,7 @@ class Renderer
|
||||||
* If $name is not defined, return engine defined by theme,
|
* If $name is not defined, return engine defined by theme,
|
||||||
* or default
|
* or default
|
||||||
*
|
*
|
||||||
* @return ITemplateEngine Template Engine instance
|
* @return TemplateEngine Template Engine instance
|
||||||
*/
|
*/
|
||||||
public static function getTemplateEngine()
|
public static function getTemplateEngine()
|
||||||
{
|
{
|
||||||
|
@ -156,8 +152,9 @@ class Renderer
|
||||||
if (isset(self::$template_engine_instance[$template_engine])) {
|
if (isset(self::$template_engine_instance[$template_engine])) {
|
||||||
return self::$template_engine_instance[$template_engine];
|
return self::$template_engine_instance[$template_engine];
|
||||||
} else {
|
} else {
|
||||||
|
$a = DI::app();
|
||||||
$class = self::$template_engines[$template_engine];
|
$class = self::$template_engines[$template_engine];
|
||||||
$obj = new $class;
|
$obj = new $class($a->getCurrentTheme(), $a->theme_info);
|
||||||
self::$template_engine_instance[$template_engine] = $obj;
|
self::$template_engine_instance[$template_engine] = $obj;
|
||||||
return $obj;
|
return $obj;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
|
|
||||||
namespace Friendica\Render;
|
namespace Friendica\Render;
|
||||||
|
|
||||||
use Friendica\DI;
|
|
||||||
use Smarty;
|
use Smarty;
|
||||||
use Friendica\Core\Renderer;
|
use Friendica\Core\Renderer;
|
||||||
|
|
||||||
|
@ -34,26 +33,23 @@ class FriendicaSmarty extends Smarty
|
||||||
|
|
||||||
public $filename;
|
public $filename;
|
||||||
|
|
||||||
function __construct()
|
function __construct(string $theme, array $theme_info)
|
||||||
{
|
{
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
|
|
||||||
$a = DI::app();
|
|
||||||
$theme = $a->getCurrentTheme();
|
|
||||||
|
|
||||||
// setTemplateDir can be set to an array, which Smarty will parse in order.
|
// setTemplateDir can be set to an array, which Smarty will parse in order.
|
||||||
// The order is thus very important here
|
// The order is thus very important here
|
||||||
$template_dirs = ['theme' => "view/theme/$theme/" . self::SMARTY3_TEMPLATE_FOLDER . "/"];
|
$template_dirs = ['theme' => "view/theme/$theme/" . self::SMARTY3_TEMPLATE_FOLDER . "/"];
|
||||||
if (!empty($a->theme_info['extends'])) {
|
if (!empty($theme_info['extends'])) {
|
||||||
$template_dirs = $template_dirs + ['extends' => "view/theme/" . $a->theme_info["extends"] . "/" . self::SMARTY3_TEMPLATE_FOLDER . "/"];
|
$template_dirs = $template_dirs + ['extends' => "view/theme/" . $theme_info["extends"] . "/" . self::SMARTY3_TEMPLATE_FOLDER . "/"];
|
||||||
}
|
}
|
||||||
|
|
||||||
$template_dirs = $template_dirs + ['base' => "view/" . self::SMARTY3_TEMPLATE_FOLDER . "/"];
|
$template_dirs = $template_dirs + ['base' => "view/" . self::SMARTY3_TEMPLATE_FOLDER . "/"];
|
||||||
$this->setTemplateDir($template_dirs);
|
$this->setTemplateDir($template_dirs);
|
||||||
|
|
||||||
$this->setCompileDir('view/smarty3/compiled/');
|
$this->setCompileDir('view/smarty3/compiled/');
|
||||||
$this->setConfigDir('view/smarty3/config/');
|
$this->setConfigDir('view/smarty3/');
|
||||||
$this->setCacheDir('view/smarty3/cache/');
|
$this->setCacheDir('view/smarty3/');
|
||||||
|
|
||||||
$this->left_delimiter = Renderer::getTemplateLeftDelimiter('smarty3');
|
$this->left_delimiter = Renderer::getTemplateLeftDelimiter('smarty3');
|
||||||
$this->right_delimiter = Renderer::getTemplateRightDelimiter('smarty3');
|
$this->right_delimiter = Renderer::getTemplateRightDelimiter('smarty3');
|
||||||
|
@ -63,13 +59,4 @@ class FriendicaSmarty extends Smarty
|
||||||
// Don't report errors so verbosely
|
// Don't report errors so verbosely
|
||||||
$this->error_reporting = E_ALL & ~E_NOTICE;
|
$this->error_reporting = E_ALL & ~E_NOTICE;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
function parsed($template = '')
|
|
||||||
{
|
|
||||||
if ($template) {
|
|
||||||
return $this->fetch('string:' . $template);
|
|
||||||
}
|
|
||||||
return $this->fetch('file:' . $this->filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -23,56 +23,69 @@ namespace Friendica\Render;
|
||||||
|
|
||||||
use Friendica\Core\Hook;
|
use Friendica\Core\Hook;
|
||||||
use Friendica\DI;
|
use Friendica\DI;
|
||||||
|
use Friendica\Util\Strings;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Smarty implementation of the Friendica template engine interface
|
* Smarty implementation of the Friendica template abstraction
|
||||||
*/
|
*/
|
||||||
class FriendicaSmartyEngine implements ITemplateEngine
|
final class FriendicaSmartyEngine extends TemplateEngine
|
||||||
{
|
{
|
||||||
static $name = "smarty3";
|
static $name = "smarty3";
|
||||||
|
|
||||||
public function __construct()
|
const FILE_PREFIX = 'file:';
|
||||||
|
const STRING_PREFIX = 'string:';
|
||||||
|
|
||||||
|
/** @var FriendicaSmarty */
|
||||||
|
private $smarty;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function __construct(string $theme, array $theme_info)
|
||||||
{
|
{
|
||||||
if (!is_writable(__DIR__ . '/../../view/smarty3/')) {
|
$this->theme = $theme;
|
||||||
|
$this->theme_info = $theme_info;
|
||||||
|
$this->smarty = new FriendicaSmarty($this->theme, $this->theme_info);
|
||||||
|
|
||||||
|
if (!is_writable(DI::basePath() . '/view/smarty3')) {
|
||||||
echo "<b>ERROR:</b> folder <tt>view/smarty3/</tt> must be writable by webserver.";
|
echo "<b>ERROR:</b> folder <tt>view/smarty3/</tt> must be writable by webserver.";
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ITemplateEngine interface
|
/**
|
||||||
public function replaceMacros($s, $r)
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function replaceMacros(string $template, array $vars)
|
||||||
{
|
{
|
||||||
$template = '';
|
if (!Strings::startsWith($template, self::FILE_PREFIX)) {
|
||||||
if (gettype($s) === 'string') {
|
$template = self::STRING_PREFIX . $template;
|
||||||
$template = $s;
|
|
||||||
$s = new FriendicaSmarty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$r['$APP'] = DI::app();
|
|
||||||
|
|
||||||
// "middleware": inject variables into templates
|
// "middleware": inject variables into templates
|
||||||
$arr = [
|
$arr = [
|
||||||
"template" => basename($s->filename),
|
'template' => basename($this->smarty->filename),
|
||||||
"vars" => $r
|
'vars' => $vars
|
||||||
];
|
];
|
||||||
Hook::callAll("template_vars", $arr);
|
Hook::callAll('template_vars', $arr);
|
||||||
$r = $arr['vars'];
|
$vars = $arr['vars'];
|
||||||
|
|
||||||
foreach ($r as $key => $value) {
|
foreach ($vars as $key => $value) {
|
||||||
if ($key[0] === '$') {
|
if ($key[0] === '$') {
|
||||||
$key = substr($key, 1);
|
$key = substr($key, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
$s->assign($key, $value);
|
$this->smarty->assign($key, $value);
|
||||||
}
|
}
|
||||||
return $s->parsed($template);
|
|
||||||
|
return $this->smarty->fetch($template);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getTemplateFile($file, $subDir = '')
|
/**
|
||||||
|
* @inheritDoc
|
||||||
|
*/
|
||||||
|
public function getTemplateFile(string $file, string $subDir = '')
|
||||||
{
|
{
|
||||||
$a = DI::app();
|
|
||||||
$template = new FriendicaSmarty();
|
|
||||||
|
|
||||||
// Make sure $root ends with a slash /
|
// Make sure $root ends with a slash /
|
||||||
if ($subDir !== '' && substr($subDir, -1, 1) !== '/') {
|
if ($subDir !== '' && substr($subDir, -1, 1) !== '/') {
|
||||||
$subDir = $subDir . '/';
|
$subDir = $subDir . '/';
|
||||||
|
@ -80,21 +93,20 @@ class FriendicaSmartyEngine implements ITemplateEngine
|
||||||
|
|
||||||
$root = DI::basePath() . '/' . $subDir;
|
$root = DI::basePath() . '/' . $subDir;
|
||||||
|
|
||||||
$theme = $a->getCurrentTheme();
|
$filename = $this->smarty::SMARTY3_TEMPLATE_FOLDER . '/' . $file;
|
||||||
$filename = $template::SMARTY3_TEMPLATE_FOLDER . '/' . $file;
|
|
||||||
|
|
||||||
if (file_exists("{$root}view/theme/$theme/$filename")) {
|
if (file_exists("{$root}view/theme/$this->theme/$filename")) {
|
||||||
$template_file = "{$root}view/theme/$theme/$filename";
|
$template_file = "{$root}view/theme/$this->theme/$filename";
|
||||||
} elseif (!empty($a->theme_info['extends']) && file_exists(sprintf('%sview/theme/%s}/%s', $root, $a->theme_info['extends'], $filename))) {
|
} elseif (!empty($this->theme_info['extends']) && file_exists(sprintf('%sview/theme/%s}/%s', $root, $this->theme_info['extends'], $filename))) {
|
||||||
$template_file = sprintf('%sview/theme/%s}/%s', $root, $a->theme_info['extends'], $filename);
|
$template_file = sprintf('%sview/theme/%s}/%s', $root, $this->theme_info['extends'], $filename);
|
||||||
} elseif (file_exists("{$root}/$filename")) {
|
} elseif (file_exists("{$root}/$filename")) {
|
||||||
$template_file = "{$root}/$filename";
|
$template_file = "{$root}/$filename";
|
||||||
} else {
|
} else {
|
||||||
$template_file = "{$root}view/$filename";
|
$template_file = "{$root}view/$filename";
|
||||||
}
|
}
|
||||||
|
|
||||||
$template->filename = $template_file;
|
$this->smarty->filename = $template_file;
|
||||||
|
|
||||||
return $template;
|
return self::FILE_PREFIX . $template_file;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,8 +24,37 @@ namespace Friendica\Render;
|
||||||
/**
|
/**
|
||||||
* Interface for template engines
|
* Interface for template engines
|
||||||
*/
|
*/
|
||||||
interface ITemplateEngine
|
abstract class TemplateEngine
|
||||||
{
|
{
|
||||||
public function replaceMacros($s, $v);
|
/** @var string */
|
||||||
public function getTemplateFile($file, $subDir = '');
|
static $name;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
protected $theme;
|
||||||
|
/** @var array */
|
||||||
|
protected $theme_info;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $theme The current theme name
|
||||||
|
* @param array $theme_info The current theme info array
|
||||||
|
*/
|
||||||
|
abstract public function __construct(string $theme, array $theme_info);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the rendered template output from the template string and variables
|
||||||
|
*
|
||||||
|
* @param string $template
|
||||||
|
* @param array $vars
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
abstract public function replaceMacros(string $template, array $vars);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the template string from a file path and an optional sub-directory from the project root
|
||||||
|
*
|
||||||
|
* @param string $file
|
||||||
|
* @param string $subDir
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
abstract public function getTemplateFile(string $file, string $subDir = '');
|
||||||
}
|
}
|
|
@ -108,7 +108,7 @@ trait AppMockTrait
|
||||||
->andReturn($this->configMock);
|
->andReturn($this->configMock);
|
||||||
$this->app
|
$this->app
|
||||||
->shouldReceive('getTemplateEngine')
|
->shouldReceive('getTemplateEngine')
|
||||||
->andReturn(new FriendicaSmartyEngine());
|
->andReturn(new FriendicaSmartyEngine('frio', []));
|
||||||
$this->app
|
$this->app
|
||||||
->shouldReceive('getCurrentTheme')
|
->shouldReceive('getCurrentTheme')
|
||||||
->andReturn('Smarty3');
|
->andReturn('Smarty3');
|
||||||
|
|
Loading…
Reference in a new issue