Skip to content

Commit

Permalink
Add Smarty and Twig template engines (#3452)
Browse files Browse the repository at this point in the history
* Add Smarty and Twig template engines

* Update composer.json

* Convert Widgets class to template engine and PHPStan fixes

* Fix widget initialisation

* Fix panel widget initialisation

* chore: remove debug return

* feat: convert 403/404 pages to new template system and general tidy

* chore: style fixes

* feat: update latest pages to new template engine

* feat: template base should not be nullable in onPageLoad

* feat: set template base directory upon initialisation and allow custom smarty security directories

* chore: fix style
  • Loading branch information
samerton authored Feb 24, 2025
1 parent b0db19a commit db647d9
Show file tree
Hide file tree
Showing 136 changed files with 3,579 additions and 2,351 deletions.
34 changes: 21 additions & 13 deletions 403.php
Original file line number Diff line number Diff line change
@@ -1,30 +1,38 @@
<?php
/*
* Made by Samerton
* https://github.com/NamelessMC/Nameless/
* NamelessMC version 2.0.0-pr8
/**
* 403 forbidden.
*
* License: MIT
* @author Samerton
* @license MIT
* @version 2.2.0
*
* 403 Forbidden page
* @var Cache $cache
* @var FakeSmarty $smarty
* @var Language $language
* @var Navigation $cc_nav
* @var Navigation $navigation
* @var Navigation $staffcp_nav
* @var Pages $pages
* @var TemplateBase $template
* @var User $user
* @var Widgets $widgets
*/

header($_SERVER['SERVER_PROTOCOL'] . ' 403 Forbidden');

const PAGE = 403;
$page_title = '403';
require_once(ROOT_PATH . '/core/templates/frontend_init.php');
require_once ROOT_PATH . '/core/templates/frontend_init.php';

// Load modules + template
Module::loadPage($user, $pages, $cache, $smarty, [$navigation, $cc_nav, $staffcp_nav], $widgets, $template);

$template->onPageLoad();

require(ROOT_PATH . '/core/templates/navbar.php');
require(ROOT_PATH . '/core/templates/footer.php');
require ROOT_PATH . '/core/templates/navbar.php';
require ROOT_PATH . '/core/templates/footer.php';

// Assign Smarty variables
$smarty->assign(
// Assign template variables
$template->getEngine()->addVariables(
[
'403_TITLE' => $language->get('errors', '403_title'),
'CONTENT' => $language->get('errors', '403_content'),
Expand All @@ -38,4 +46,4 @@
);

// Display template
$template->displayTemplate('403.tpl', $smarty);
$template->displayTemplate('403.tpl');
34 changes: 21 additions & 13 deletions 404.php
Original file line number Diff line number Diff line change
@@ -1,30 +1,38 @@
<?php
/*
* Made by Samerton
* https://github.com/NamelessMC/Nameless/
* NamelessMC version 2.0.0-pr8
/**
* 404 not found.
*
* License: MIT
* @author Samerton
* @license MIT
* @version 2.2.0
*
* 404 Not Found page
* @var Cache $cache
* @var FakeSmarty $smarty
* @var Language $language
* @var Navigation $cc_nav
* @var Navigation $navigation
* @var Navigation $staffcp_nav
* @var Pages $pages
* @var TemplateBase $template
* @var User $user
* @var Widgets $widgets
*/

header($_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found');

const PAGE = 404;
$page_title = '404';
require_once(ROOT_PATH . '/core/templates/frontend_init.php');
require_once ROOT_PATH . '/core/templates/frontend_init.php';

// Load modules + template
Module::loadPage($user, $pages, $cache, $smarty, [$navigation, $cc_nav, $staffcp_nav], $widgets, $template);

$template->onPageLoad();

require(ROOT_PATH . '/core/templates/navbar.php');
require(ROOT_PATH . '/core/templates/footer.php');
require ROOT_PATH . '/core/templates/navbar.php';
require ROOT_PATH . '/core/templates/footer.php';

// Assign Smarty variables
$smarty->assign(
// Assign template variables
$template->getEngine()->addVariables(
[
'404_TITLE' => $language->get('errors', '404_title'),
'CONTENT' => $language->get('errors', '404_content'),
Expand All @@ -36,4 +44,4 @@
);

// Display template
$template->displayTemplate('404.tpl', $smarty);
$template->displayTemplate('404.tpl');
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@
"joypixels/emoji-toolkit": "^7.0",
"geoip2/geoip2": "^2.13",
"jenssegers/agent": "^2.6",
"php-di/php-di": "^6.4"
"php-di/php-di": "^6.4",
"twig/twig": "^3.0"
},
"require-dev": {
"phpstan/phpstan": "1.6.9",
Expand Down
24 changes: 12 additions & 12 deletions core/classes/Core/Module.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*
* @package NamelessMC\Core
* @author Samerton
* @version 2.0.0-pr13
* @version 2.2.0
* @license MIT
*/
abstract class Module
Expand Down Expand Up @@ -48,15 +48,15 @@ public function __construct(
/**
* Call `onPageLoad()` function for all registered modules.
*
* @param User $user User viewing the page.
* @param Pages $pages Instance of pages class.
* @param Cache $cache Instance of cache to pass.
* @param Smarty $smarty Instance of smarty to pass.
* @param Navigation[] $navs Array of loaded navigation menus.
* @param Widgets $widgets Instance of widget class to pass.
* @param TemplateBase $template Template to pass.
* @param User $user User viewing the page.
* @param Pages $pages Instance of pages class.
* @param Cache $cache Instance of cache to pass.
* @param FakeSmarty|Smarty|null $smarty Instance of Smarty to pass
* @param Navigation[] $navs Array of loaded navigation menus.
* @param Widgets $widgets Instance of widget class to pass.
* @param TemplateBase $template Template to pass.
*/
public static function loadPage(User $user, Pages $pages, Cache $cache, Smarty $smarty, iterable $navs, Widgets $widgets, TemplateBase $template): void
public static function loadPage(User $user, Pages $pages, Cache $cache, $smarty, iterable $navs, Widgets $widgets, TemplateBase $template): void
{
foreach (self::getModules() as $module) {
$module->onPageLoad($user, $pages, $cache, $smarty, $navs, $widgets, $template);
Expand All @@ -76,12 +76,12 @@ public static function getModules(): iterable
* @param User $user User viewing the page.
* @param Pages $pages Instance of pages class.
* @param Cache $cache Instance of cache to pass.
* @param Smarty $smarty Instance of smarty to pass.
* @param FakeSmarty|Smarty $smarty Instance of smarty to pass, to be removed in 2.3.0
* @param Navigation[] $navs Array of loaded navigation menus.
* @param Widgets $widgets Instance of widget class to pass.
* @param TemplateBase|null $template Active template to render.
* @param TemplateBase $template Active template to render.
*/
abstract public function onPageLoad(User $user, Pages $pages, Cache $cache, Smarty $smarty, iterable $navs, Widgets $widgets, ?TemplateBase $template);
abstract public function onPageLoad(User $user, Pages $pages, Cache $cache, $smarty, iterable $navs, Widgets $widgets, TemplateBase $template);

/**
* Determine loading arrangement of modules.
Expand Down
31 changes: 25 additions & 6 deletions core/classes/Misc/DebugBarHelper.php
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
<?php

use DebugBar\Bridge\NamespacedTwigProfileCollector;
use DebugBar\DataCollector\ConfigCollector;
use DebugBar\DataCollector\DataCollector;
use DebugBar\DataCollector\MemoryCollector;
use DebugBar\DataCollector\PDO\PDOCollector;
use DebugBar\DataCollector\PhpInfoCollector;
use DebugBar\DataCollector\RequestDataCollector;
use DebugBar\DataCollector\TimeDataCollector;
use DebugBar\DebugBar;
use Junker\DebugBar\Bridge\SmartyCollector;
use Twig\Environment;
use Twig\Extension\ProfilerExtension;
use Twig\Profiler\Profile;

/**
* Class to help integrate the PHPDebugBar with NamelessMC.
*
* @package NamelessMC\Misc
* @author Aberdeener
* @version 2.0.0-pr13
* @version 2.2.0
* @license MIT
*/
class DebugBarHelper extends Instanceable
Expand All @@ -24,7 +29,7 @@ class DebugBarHelper extends Instanceable
/**
* Enable the PHPDebugBar.
*/
public function enable(Smarty $smarty): void
public function enable(): void
{
$debugbar = new DebugBar();

Expand All @@ -47,16 +52,30 @@ public function enable(Smarty $smarty): void
$pdoCollector->setRenderSqlWithParams(true, '`');
$debugbar->addCollector($pdoCollector);

$smartyCollector = new SmartyCollector($smarty);
$smartyCollector->useHtmlVarDumper();
$debugbar->addCollector($smartyCollector);

$debugbar->addCollector(new PhpInfoCollector());
$debugbar->addCollector(new MemoryCollector());

$this->_debugBar = $debugbar;
}

public function addCollector(DataCollector $collector): void
{
$this->_debugBar->addCollector($collector);
}

public function addSmartyCollector(Smarty $smarty): void
{
$smartyCollector = new SmartyCollector($smarty);
$smartyCollector->useHtmlVarDumper();
$this->addCollector($smartyCollector);
}

public function addTwigCollector(Environment $twig, Profile $profile): void
{
$twig->addExtension(new ProfilerExtension($profile));
$this->addCollector(new NamespacedTwigProfileCollector($profile));
}

public function getDebugBar(): ?DebugBar
{
return $this->_debugBar;
Expand Down
30 changes: 30 additions & 0 deletions core/classes/Templates/FakeSmarty.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php
/**
* Fake Smarty class to help with migration to 2.2.0 template system
* It aims to wrap around TemplateBase to ensure $smarty->assign still works until 2.3.0, when this will be removed.
*
* @author Samerton
* @license MIT
* @version 2.2.0
* @deprecated
*/
class FakeSmarty
{
private TemplateEngine $_engine;

public function __construct(TemplateEngine $engine)
{
$this->_engine = $engine;
}

public function assign($key, $value = null)
{
if (is_string($key)) {
$this->_engine->addVariable($key, $value);
}

if (is_array($key)) {
$this->_engine->addVariables($key);
}
}
}
26 changes: 26 additions & 0 deletions core/classes/Templates/SmartyTemplateBase.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php
/**
* Base class which templates should extend to add functionality.
* Uses Smarty template engine.
*
* @package NamelessMC\Templates
* @author Samerton
* @version 2.2.0
* @license MIT
*/
abstract class SmartyTemplateBase extends TemplateBase
{
/**
* @param string $name
* @param string $version
* @param string $nameless_version
* @param string $author
* @param string $dir
*/
public function __construct(string $name, string $version, string $nameless_version, string $author, string $dir)
{
$this->_engine = new SmartyTemplateEngine($dir);

parent::__construct($name, $version, $nameless_version, $author);
}
}
95 changes: 95 additions & 0 deletions core/classes/Templates/SmartyTemplateEngine.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<?php
/**
* Smarty template engine.
*
* @author Samerton
* @license MIT
* @version 2.2.0
*/
class SmartyTemplateEngine extends TemplateEngine
{
protected Smarty_Security $_securityPolicy;
private Smarty $_smarty;

/**
* @param string $dir Path to template directory
* @throws SmartyException
*/
public function __construct(string $dir)
{
$smarty = new Smarty();

$securityPolicy = new Smarty_Security($smarty);
$securityPolicy->php_modifiers = [
'escape',
'count',
'key',
'round',
'ucfirst',
'defined',
'date',
'explode',
'implode',
'strtolower',
'strtoupper',
];
$securityPolicy->php_functions = [
'isset',
'empty',
'count',
'sizeof',
'in_array',
'is_array',
'time',
'nl2br',
'is_numeric',
'file_exists',
'array_key_exists',
];
$securityPolicy->secure_dir = [ROOT_PATH . '/custom/templates', ROOT_PATH . '/custom/panel_templates'];
$smarty->enableSecurity($securityPolicy);

$smarty->setCompileDir(ROOT_PATH . '/cache/templates_c');
$smarty->setTemplateDir($dir);

if (defined('PHPDEBUGBAR')) {
DebugBarHelper::getInstance()->addSmartyCollector($smarty);
}

$this->_securityPolicy = $securityPolicy;
$this->_smarty = $smarty;

parent::__construct();
}

public function render(string $templateFile): void
{
echo $this->fetch($templateFile);
}

public function fetch(string $templateFile): string
{
$templateFile = str_replace('.tpl', '', $templateFile);

$this->_smarty->assign($this->getVariables());

return $this->_smarty->fetch("$templateFile.tpl");
}

public function clearCache(): void
{
$this->_smarty->clearAllCache();
}

/**
* Add an extra directory to the Smarty security policy.
*
* @param string $dir Directory to add to policy
* @return void
*/
public function addSecurityPolicyDirectory(string $dir): void
{
$this->_securityPolicy->secure_dir = [...$this->_securityPolicy->secure_dir, $dir];
$this->_smarty->enableSecurity($this->_securityPolicy);
}
}
Loading

0 comments on commit db647d9

Please sign in to comment.