1: <?php
2: namespace Opencart\System\Library\Template;
3: /**
4: * Class Twig
5: *
6: * @package Opencart\System\Library\Template
7: */
8: class Twig {
9: /**
10: * @var string
11: */
12: protected string $root;
13: /**
14: * @var \Twig\Loader\FilesystemLoader
15: */
16: protected \Twig\Loader\FilesystemLoader $loader;
17: /**
18: * @var string
19: */
20: protected string $directory;
21: /**
22: * @var array<string, string>
23: */
24: protected array $path = [];
25:
26: /**
27: * Constructor
28: */
29: public function __construct() {
30: // Unfortunately, we have to set the web root directory as the base since Twig confuses which template cache to use.
31: $this->root = substr(DIR_OPENCART, 0, -1);
32:
33: // We have to add the C directory as the base directory because twig can only accept the first namespace/,
34: // rather than a multiple namespace system, which took me less than a minute to write. If symphony is like
35: // this, then I have no idea why people use the framework.
36: $this->loader = new \Twig\Loader\FilesystemLoader('./', $this->root);
37: }
38:
39: /**
40: * addPath
41: *
42: * @param string $namespace
43: * @param string $directory
44: *
45: * @return void
46: */
47: public function addPath(string $namespace, string $directory = ''): void {
48: if (!$directory) {
49: $this->directory = $namespace;
50: } else {
51: $this->path[$namespace] = $directory;
52: }
53: }
54:
55: /**
56: * Render
57: *
58: * @param string $filename
59: * @param array<string, mixed> $data
60: * @param string $code
61: *
62: * @return string
63: */
64: public function render(string $filename, array $data = [], string $code = ''): string {
65: $file = $this->directory . $filename . '.twig';
66:
67: /*
68: * FYI all the Twig lovers out there!
69: * The Twig syntax is good, but the implementation and the available methods is a joke!
70: *
71: * All the Symfony developer has done is create a garbage frame work putting 3rd party scripts into DI containers.
72: * The Twig syntax he ripped off from Jinja and Django templates then did a garbage implementation!
73: *
74: * The fact that this system cache is just compiling php into more php code instead of html is a disgrace!
75: */
76:
77: $namespace = '';
78:
79: $parts = explode('/', $filename);
80:
81: foreach ($parts as $part) {
82: if (!$namespace) {
83: $namespace .= $part;
84: } else {
85: $namespace .= '/' . $part;
86: }
87:
88: if (isset($this->path[$namespace])) {
89: $file = $this->path[$namespace] . substr($filename, strlen($namespace) + 1) . '.twig';
90: }
91: }
92:
93: // We have to remove the root web directory.
94: $file = substr($file, strlen($this->root) + 1);
95:
96: if ($code) {
97: // render from modified template code
98: $loader = new \Twig\Loader\ArrayLoader([$file => $code]);
99: } else {
100: $loader = $this->loader;
101: }
102:
103: try {
104: // Initialize Twig environment
105: $config = [
106: 'charset' => 'utf-8',
107: 'autoescape' => false,
108: 'debug' => true,
109: 'auto_reload' => true,
110: 'cache' => DIR_CACHE . 'template/'
111: ];
112:
113: $twig = new \Twig\Environment($loader, $config);
114:
115: if ($config['debug']) {
116: $twig->addExtension(new \Twig\Extension\DebugExtension());
117: }
118:
119: return $twig->render($file, $data);
120: } catch (\Twig\Error\SyntaxError $e) {
121: throw new \Exception('Error: Could not load template ' . $filename . '!');
122: }
123: }
124: }
125: