Overview
Comment:Move compile blocks to Functions and Sections classes
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | dev
Files: files | file ages | folders
SHA3-256: ef65cc5003f87438020eefc4ae1a0874fcfc366cda0aa558bc781589618e0231
User & Date: bohwaz on 2023-02-05 18:10:05
Other Links: branch diff | manifest | tags
Context
2023-02-05
18:59
Brindille: Use '!' as a prefix for unprotected parameters in #select section, also use a blacklist of tables and columns that shouldn't be available in Brindille check-in: df8b3222cd user: bohwaz tags: dev
18:10
Move compile blocks to Functions and Sections classes check-in: ef65cc5003 user: bohwaz tags: dev
16:41
Allow raw SQL in {{#select section check-in: cffb3e4c6c user: bohwaz tags: dev
Changes

Modified src/include/lib/Garradin/UserTemplate/Functions.php from [eb3ad6a62e] to [468eaf74a1].

29
30
31
32
33
34
35
























36
37
38
39
40
41
42
		'read',
		'save',
		'admin_header',
		'admin_footer',
		'signature',
		'mail',
	];

























	static public function admin_header(array $params): string
	{
		$tpl = Template::getInstance();
		$tpl->assign($params);
		return $tpl->fetch('_head.tpl');
	}







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
		'read',
		'save',
		'admin_header',
		'admin_footer',
		'signature',
		'mail',
	];

	const COMPILE_FUNCTIONS_LIST = [
		':break' => [self::class, 'break'],
	];

	/**
	 * Compile function to break inside a loop
	 */
	static public function break(string $name, string $params, Brindille $tpl, int $line)
	{
		$in_loop = false;
		foreach ($this->_stack as $element) {
			if ($element[0] == $this::SECTION) {
				$in_loop = true;
				break;
			}
		}

		if (!$in_loop) {
			throw new Brindille_Exception(sprintf('Error on line %d: break can only be used inside a section', $line));
		}

		return '<?php break; ?>';
	}

	static public function admin_header(array $params): string
	{
		$tpl = Template::getInstance();
		$tpl->assign($params);
		return $tpl->fetch('_head.tpl');
	}

Modified src/include/lib/Garradin/UserTemplate/Sections.php from [051dbaf312] to [97903e3514].

36
37
38
39
40
41
42
43





44

































45
46
47
48
49
50
51
		'transaction_users',
		'accounts',
		'balances',
		'sql',
		'restrict',
		'module',
	];






	static protected $_cache = [];


































	static protected function _debug(string $str): void
	{
		echo sprintf('<pre style="padding: 5px; margin: 5px; background: yellow; white-space: pre-wrap;">%s</pre>', htmlspecialchars($str));
	}

	static protected function _debugExplain(string $sql): void








>
>
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
		'transaction_users',
		'accounts',
		'balances',
		'sql',
		'restrict',
		'module',
	];

	const COMPILE_SECTIONS_LIST = [
		'#select' => [self::class, 'selectStart'],
		'/select' => [self::class, 'selectEnd'],
	];

	static protected $_cache = [];

	static public function selectStart(string $name, string $sql, UserTemplate $tpl, int $line): string
	{
		$sql = strtok($sql, ';');
		$extra_params = strtok(false);

		$i = 0;
		$params = '';

		$sql = preg_replace_callback('/\{(.*?)\}/', function ($match) use (&$params, &$i) {
			// Raw SQL
			if ('!' === substr($match[1], 0, 1)) {
				$params .= ' **' . $i . '**=' . substr($match[1], 1);
				return '**' . $i++ . '**';
			}
			else {
				$params .= ' :p' . $i . '=' . $match[1];
				return ':p' . $i++;
			}
		}, $sql);

		$sql = 'SELECT ' . $sql;
		$sql = var_export($sql, true);

		$params .= ' sql=' . $sql . ' ' . $extra_params;

		return $tpl->_section('sql', $params, $line);
	}

	static public function selectEnd(string $name, string $params, UserTemplate $tpl, int $line): string
	{
		return $tpl->_close('sql', '{{/select}}');
	}

	static protected function _debug(string $str): void
	{
		echo sprintf('<pre style="padding: 5px; margin: 5px; background: yellow; white-space: pre-wrap;">%s</pre>', htmlspecialchars($str));
	}

	static protected function _debugExplain(string $sql): void
900
901
902
903
904
905
906

907
908
909
910
911
912
913
			'limit' => 100,
			'where' => '',
		];

		if (isset($params['sql'])) {
			$sql = $params['sql'];


			foreach ($params as $k => $v) {
				if (substr($k, 0, 2) == '**') {
					$sql = str_replace($k, $v, $sql);
				}
			}
		}
		else {







>







938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
			'limit' => 100,
			'where' => '',
		];

		if (isset($params['sql'])) {
			$sql = $params['sql'];

			// Replace raw SQL parameters (undocumented feature, this is for #select section)
			foreach ($params as $k => $v) {
				if (substr($k, 0, 2) == '**') {
					$sql = str_replace($k, $v, $sql);
				}
			}
		}
		else {

Modified src/include/lib/Garradin/UserTemplate/UserTemplate.php from [ca4feae2ff] to [fae41f22ea].

176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
			$this->registerModifier(is_int($key) ? $name : $key, is_int($key) ? [Modifiers::class, $name] : $name);
		}

		// Local functions
		foreach (Functions::FUNCTIONS_LIST as $name) {
			$this->registerFunction($name, [Functions::class, $name]);
		}

		// Local sections
		foreach (Sections::SECTIONS_LIST as $name) {
			$this->registerSection($name, [Sections::class, $name]);
		}

		$this->registerCompileBlock(':break', function (string $name, string $params, Brindille $tpl, int $line) {
			$in_loop = false;
			foreach ($this->_stack as $element) {
				if ($element[0] == $this::SECTION) {
					$in_loop = true;
					break;
				}
			}

			if (!$in_loop) {
				throw new Brindille_Exception(sprintf('Error on line %d: break can only be used inside a section', $line));
			}

			return '<?php break; ?>';
		});


		$this->registerCompileBlock('#select', function (string $name, string $sql, Brindille $tpl, int $line) {
			$sql = strtok($sql, ';');
			$extra_params = strtok(false);

			$i = 0;
			$params = '';

			$sql = preg_replace_callback('/\{(.*?)\}/', function ($match) use (&$params, &$i) {
				// Raw SQL
				if ('**' === substr($match[1], 0, 2)) {
					$params .= ' **' . $i . '**=' . substr($match[1], 2);
					return '**' . $i++ . '**';
				}
				else {
					$params .= ' :p' . $i . '=' . $match[1];
					return ':p' . $i++;
				}
			}, $sql);

			$sql = 'SELECT ' . $sql;
			$sql = var_export($sql, true);

			$params .= ' sql=' . $sql . ' ' . $extra_params;

			return $this->_section('sql', $params, $line);
		});

		$this->registerCompileBlock('/select', function (string $name, string $params, Brindille $tpl, int $line) {
			return $this->_close('sql', '{{/select}}');
		});
	}

	public function setSource(string $path)
	{
		$this->file = null;
		$this->path = $path;
		$this->modified = filemtime($path);








<
|
<
<
<
|
<
<
<
<
<
|
|
|
<
<
<
|
<
<
|
|
<
<
<

<
<
|
<
<
<
<
<
<
<
<
<
<
<
|
<
<
|
<
<
<
<
<
<
<
<







176
177
178
179
180
181
182
183

184



185





186
187
188



189


190
191



192


193











194


195








196
197
198
199
200
201
202
			$this->registerModifier(is_int($key) ? $name : $key, is_int($key) ? [Modifiers::class, $name] : $name);
		}

		// Local functions
		foreach (Functions::FUNCTIONS_LIST as $name) {
			$this->registerFunction($name, [Functions::class, $name]);
		}


		foreach (Functions::COMPILE_FUNCTIONS_LIST as $name => $callback) {



			$this->registerCompileBlock($name, $callback);





		}

		// Local sections



		foreach (Sections::SECTIONS_LIST as $name) {


			$this->registerSection($name, [Sections::class, $name]);
		}






		foreach (Sections::COMPILE_SECTIONS_LIST as $name => $callback) {











			$this->registerCompileBlock($name, $callback);


		}








	}

	public function setSource(string $path)
	{
		$this->file = null;
		$this->path = $path;
		$this->modified = filemtime($path);