Ver Fonte

* Add the ability to filter based on null/not null
* Add default values that are not contant
* Clean up template class
* Add parentmatch to template class (For compiled templates only)

Nathaniel van Diepen há 7 anos atrás
pai
commit
721ea7c8ad
4 ficheiros alterados com 288 adições e 141 exclusões
  1. 200 126
      Data/template.class.php
  2. 30 0
      PDO/defaultvalue.class.php
  3. 33 0
      PDO/filter.class.php
  4. 25 15
      pdo.class.php

+ 200 - 126
Data/template.class.php

@@ -12,6 +12,7 @@
 		public static $basedir = __DIR__;
 		private static $regex = [
 			'match'=>'/\{([^#\/?_][^}\n]*?)\}/i',
+			'parentmatch'=>'/\{\.\.\/([^#\/?_][^}\n]*?)\}/i',
 			'each'=>'/\{#each ([^}]*)\}([\S\s]*)\{\/each \1\}/i',
 			'exist'=>'/\{#exist ([^}]*)\}([\S\s]*)\{\/exist \1\}/i',
 			'existelse'=>'/\{#exist ([^}]*)\}([\S\s]*)\{#else \1\}([\S\s]*)\{\/exist \1\}/i',
@@ -23,6 +24,7 @@
 			'eval'=>'/\{\?([\W\w\S\s]+)\?\}/i',
 			'include'=>'/{#include ([^}]+)}/i'
 		];
+		protected static $parsers;
 		private $template;
 		private $name;
 		private $path;
@@ -41,6 +43,176 @@
 			$this->name = $name;
 			$this->path = static::$cachedir."/{$this->name}.".md5($this->template).'.php';
 			static::$templates[$name] = $this;
+			if(is_null(static::$parsers)){
+				static::$parsers = [
+					'ignore'=>function(&$output, &$ignored){
+						$output = preg_replace_callback(static::$regex['ignore'], function($matches) use(&$ignored){
+							$ignored[] = $matches[1];
+							return '{#ignored '.(count($ignored) - 1).'}';
+						}, $output);
+					},
+					'include'=>function(&$output, &$ignored){
+						$output = preg_replace_callback(static::$regex['include'], function($matches) use(&$ignored){
+							$path = static::$basedir.'/'.$matches[1];
+							if(file_exists($path)){
+								$output = file_get_contents($path);
+								static::$parsers['ignore']($output, $ignored);
+								return $output;
+							}
+							return '';
+						}, $output);
+					},
+					'each'=>[
+						function(&$output, $data){
+							$output = preg_replace_callback(static::$regex['each'], function($matches) use($data){
+								$output = '';
+								if(isset($data[$matches[1]])){
+									foreach($data[$matches[1]] as $item){
+										$output = static::parse($matches[2], $item);
+									}
+								}
+								return $output;
+							}, $output);
+						},
+						function(&$output){
+							$output = preg_replace_callback(static::$regex['each'], function($matches){
+							$output = "<?php if(isset(\$data[".var_export($matches[1], true)."])): ";
+							$output .= "foreach(\$data[".var_export($matches[1], true)."] as \$item): ";
+							$output .= "\$parent[] = \$data; \$data = \$item; ?>";
+							$output .= static::compile($matches[2]);
+							$output .= "<?php \$data = array_pop(\$parent);";
+							$output .= "endforeach;endif; ?>";
+							return $output;
+						}, $output);
+						}
+					],
+					'existelse'=>[
+						function(&$output, $data){
+							$output = preg_replace_callback(static::$regex['existelse'], function($matches) use($data){
+								if(isset($data[$matches[1]])){
+									$output = static::parse($matches[2], $data);
+								}else{
+									$output = static::parse($matches[3], $data);
+								}
+								return $output;
+							}, $output);
+						},
+						function(&$output){
+							$output = preg_replace_callback(static::$regex['existelse'], function($matches){
+								$output = "<?php if(isset(\$data[".var_export($matches[1], true)."])): ?>";
+								$output .= static::compile($matches[2]);
+								$output .= "<php else: ?>";
+								$output .= static::compile($matches[3]);
+								$output .= "<?php endif; ?>";
+								return $output;
+							}, $output);
+						}
+					],
+					'exist'=>[
+						function(&$output, $data){
+							$output = preg_replace_callback(static::$regex['exist'], function($matches) use($data){
+								if(isset($data[$matches[1]])){
+									return static::parse($data[$matches[2]], $data);
+								}
+								return '';
+							}, $output);
+						},
+						function(&$output){
+							$output = preg_replace_callback(static::$regex['exist'], function($matches){
+								$output = "<?php if(isset(\$data[".var_export($matches[1], true)."])): ?>";
+								$output .= static::compile($matches[2]);
+								$output .= "<?php endif; ?>";
+							}, $output);
+						}
+					],
+					'gettext'=>[
+						function(&$output, $data){
+							$output = preg_replace_callback(static::$regex['gettext'], function($matches) use($data){
+								$args = array_map(function($item) use($data){
+									if(preg_match(static::$regex['gettext_string'], $item)){
+										return preg_replace(static::$regex['gettext_string'], '\2', $item);
+									}else{
+										return $data[$item] ?? '';
+									}
+								}, array_slice($matches, 1));
+								return _(sprintf(...$args));
+							}, $output);
+						},
+						function(&$output){
+							$output = preg_replace_callback(static::$regex['gettext'], function($matches){
+								if(count($matches) > 2){
+									$output = "<?= sprintf(_({$matches[1]})";
+									foreach(array_slice($matches, 2) as $item){
+										if(preg_match(static::$regex['gettext_string'], $item)){
+											$output .= ", $item";
+										}else{
+											$output .= ", (\$data['{$item}'] ?? '')";
+										}
+									}
+								}else{
+									$output = "<?= _({$matches[1]}";
+								}
+								return "{$output}); ?>";
+							}, $output);
+						}
+					],
+					'echo'=>[
+						function(&$output){
+							$output = preg_replace_callback(static::$regex['echo'], function($matches){
+								return eval("return {$matches[1]};");
+							}, $output);
+						},
+						function(&$output){
+							$output = preg_replace_callback(static::$regex['echo'], function($matches){
+								return "<?= {$matches[1]}; ?>";
+							}, $output);
+						}
+					],
+					'eval'=>[
+						function(&$output){
+							$output = preg_replace_callback(static::$regex['eval'], function($matches){
+								ob_start();
+								eval($matches[1]);
+								$output = ob_get_contents();
+								ob_end_clean();
+								return $output;
+							}, $output);
+						},
+						function(&$output){
+							$output = preg_replace_callback(static::$regex['eval'], function($matches){
+								return "<?php {$matches[1]}; ?>";
+							}, $output);
+						}
+					],
+					'match'=>[
+						function(&$output, $data){
+							$output = preg_replace_callback(static::$regex['match'], function($matches) use($data){
+								return $data[$matches[1]] ?? '';
+							}, $output);
+						},
+						function(&$output){
+							$output = preg_replace_callback(static::$regex['match'], function($matches){
+								return "<?=(\$data[".var_export($matches[1], true)."] ?? ''); ?>";
+							}, $output);
+						}
+					],
+					'parentmatch'=>[
+						function(&$output, $data){
+							throw new \Exception("Not supported in non-compiled templates");
+						},
+						function(&$output){
+							$output = preg_replace_callback(static::$regex['parentmatch'], function($matches){
+								return "<?=(\$parent[count(\$parent)-1][".var_export($matches[1], true)."] ?? ''); ?>";
+							}, $output);
+						}
+					],
+					'ignored'=>function(&$output, $ignored){
+						$output = preg_replace_callback(static::$regex['ignored'], function($matches) use($ignored){
+							return htmlentities($ignored[(int)$matches[1]] ?? '');
+						}, $output);
+					}
+				];
+			}
 		}
 		public function run(array $data) : string{
 			$data = EArray::from($data);
@@ -70,155 +242,57 @@
 		}
 		public static function compile(string $template) : string{
 			$ignored = [];
+			$output = $template;
 			// Handle {#ignore code}
-			$output = preg_replace_callback(static::$regex['ignore'], function($matches) use(&$ignored){
-				$ignored[] = $matches[1];
-				return '{#ignored '.(count($ignored) - 1).'}';
-			}, $template);
+			static::$parsers['ignore']($output, $ignored);
 			// Handle {#include path/to/file}
-			$output = preg_replace_callback(static::$regex['include'], function($matches) use(&$ignored){
-				$path = static::$basedir.'/'.$matches[1];
-				if(file_exists($path)){
-					return preg_replace_callback(static::$regex['ignore'], function($matches) use(&$ignored){
-						$ignored[] = $matches[1];
-						return '{#ignored '.(count($ignored) - 1).'}';
-					}, file_get_contents($path));
-				}
-				return '';
-			}, $output);
+			static::$parsers['include']($output, $ignored);
 			// Handle {#each name}{/each}
-			$output = preg_replace_callback(static::$regex['each'], function($matches){
-				$output = "<?php if(isset(\$data[".var_export($matches[1], true)."])): ";
-				$output .= "foreach(\$data[".var_export($matches[1], true)."] as \$item): ";
-				$output .= "\$parent[] = \$data; \$data = \$item; ?>";
-				$output .= static::compile($matches[2]);
-				$output .= "<?php \$data = array_pop(\$parent);";
-				$output .= "endforeach;endif; ?>";
-				return $output;
-			}, $output);
+			static::$parsers['each'][1]($output);
 			// Handle {#exist name}{#else}{/exist}
-			$output = preg_replace_callback(static::$regex['existelse'], function($matches){
-				$output = "<?php if(isset(\$data[".var_export($matches[1], true)."])): ?>";
-				$output .= static::compile($matches[2]);
-				$output .= "<php else: ?>";
-				$output .= static::compile($matches[3]);
-				$output .= "<?php endif; ?>";
-				return $output;
-			}, $output);
+			static::$parsers['existelse'][1]($output);
 			// Handle {#exist name}{/exist}
-			$output = preg_replace_callback(static::$regex['exist'], function($matches){
-				$output = "<?php if(isset(\$data[".var_export($matches[1], true)."])): ?>";
-				$output .= static::compile($matches[2]);
-				$output .= "<?php endif; ?>";
-			}, $output);
+			static::$parsers['exist'][1]($output);
 			// Handle {gettext}
-			$output = preg_replace_callback(static::$regex['gettext'], function($matches){
-				if(count($matches) > 2){
-					$output = "<?= sprintf(_({$matches[1]})";
-					foreach(array_slice($matches, 2) as $item){
-						if(preg_match(static::$regex['gettext_string'], $item)){
-							$output .= ", $item";
-						}else{
-							$output .= ", (\$data['{$item}'] ?? '')";
-						}
-					}
-				}else{
-					$output = "<?= _({$matches[1]}";
-				}
-				return "{$output}); ?>";
-			}, $output);
+			static::$parsers['gettext'][1]($output);
 			// Handle {=expression}
-			$output = preg_replace_callback(static::$regex['echo'], function($matches){
-				return "<?= {$matches[1]}; ?>";
-			}, $output);
+			static::$parsers['echo'][1]($output);
 			// Handle {? expression ?}
-			$output = preg_replace_callback(static::$regex['eval'], function($matches){
-				return "<?php {$matches[1]}; ?>";
-			}, $output);
+			static::$parsers['eval'][1]($output);
+			// Handle {../name}
+			static::$parsers['parentmatch'][1]($output);
 			// Handle {name}
-			$output = preg_replace_callback(static::$regex['match'], function($matches){
-				return "<?=(\$data[".var_export($matches[1], true)."] ?? ''); ?>";
-			}, $output);
+			static::$parsers['match'][1]($output);
 			// Handle {#ignored i}
-			return preg_replace_callback(static::$regex['ignored'], function($matches) use(&$ignored){
-				return htmlentities($ignored[(int)$matches[1]] ?? '');
-			}, $output);
+			static::$parsers['ignored']($output, $ignored);
+			return $output;
 		}
 		public static function parse(string $template, $data) : string{
 			$ignored = [];
+			$output = $template;
 			// Handle {#ignore code}
-			$output = preg_replace_callback(static::$regex['ignore'], function($matches) use(&$ignored){
-				$ignored[] = $matches[1];
-				return '{#ignored '.(count($ignored) - 1).'}';
-			}, $template);
+			static::$parsers['ignore']($output, $ignored);
 			// Handle {#include path/to/file}
-			$output = preg_replace_callback(static::$regex['include'], function($matches) use(&$ignored){
-				$path = static::$basedir.'/'.$matches[1];
-				if(file_exists($path)){
-					return preg_replace_callback(static::$regex['ignore'], function($matches) use(&$ignored){
-						$ignored[] = $matches[1];
-						return '{#ignored '.(count($ignored) - 1).'}';
-					}, file_get_contents($path));
-				}
-				return '';
-			}, $output);
+			static::$parsers['include']($output, $ignored);
 			// Handle {#each name}{/each}
-			$output = preg_replace_callback(static::$regex['each'], function($matches) use($data){
-				$output = '';
-				if(isset($data[$matches[1]])){
-					foreach($data[$matches[1]] as $item){
-						$output = static::parse($matches[2], $item);
-					}
-				}
-				return $output;
-			}, $output);
+			static::$parsers['each'][0]($output, $data);
 			// Handle {#exist name}{#else}{/exist}
-			$output = preg_replace_callback(static::$regex['existelse'], function($matches) use($data){
-				if(isset($data[$matches[1]])){
-					$output = static::parse($matches[2], $data);
-				}else{
-					$output = static::parse($matches[3], $data);
-				}
-				return $output;
-			}, $output);
+			static::$parsers['existelse'][0]($output, $data);
 			// Handle {#exist name}{/exist}
-			$output = preg_replace_callback(static::$regex['exist'], function($matches) use($data){
-				if(isset($data[$matches[1]])){
-					return static::parse($data[$matches[2]], $data);
-				}
-				return '';
-			}, $output);
+			static::$parsers['exist'][0]($output, $data);
 			// Handle {gettext}
-			$output = preg_replace_callback(static::$regex['gettext'], function($matches) use($data){
-				$args = array_map(function($item) use($data){
-					if(preg_match(static::$regex['gettext_string'], $item)){
-						return preg_replace(static::$regex['gettext_string'], '\2', $item);
-					}else{
-						return $data[$item] ?? '';
-					}
-				}, array_slice($matches, 1));
-				return _(sprintf(...$args));
-			}, $output);
+			static::$parsers['gettext'][0]($output, $data);
 			// Handle {=expression}
-			$output = preg_replace_callback(static::$regex['echo'], function($matches) use($data){
-				return eval("return {$matches[1]};");
-			}, $output);
+			static::$parsers['echo'][0]($output);
 			// Handle {? expression ?}
-			$output = preg_replace_callback(static::$regex['eval'], function($matches) use($data){
-				ob_start();
-				eval($matches[1]);
-				$output = ob_get_contents();
-				ob_end_clean();
-				return $output;
-			}, $output);
+			static::$parsers['eval'][0]($output);
+			// Handle {../name}
+			static::$parsers['parentmatch'][1]($output, $data);
 			// Handle {name}
-			$output = preg_replace_callback(static::$regex['match'], function($matches) use($data){
-				return $data[$matches[1]] ?? '';
-			}, $output);
+			static::$parsers['match'][0]($output, $data);
 			// Handle {#ignored i}
-			return preg_replace_callback(static::$regex['ignored'], function($matches) use(&$ignored){
-				return $ignored[(int)$matches[1]] ?? '';
-			}, $output);
+			static::$parsers['ignored']($output, $ignored);
+			return $output;
 		}
 		public static function execute(string $path, $data) : string{
 			ob_start();

+ 30 - 0
PDO/defaultvalue.class.php

@@ -0,0 +1,30 @@
+<?php
+	namespace Juju\PDO;
+
+	class DefaultValue {
+		private static $defaults = [];
+		private $name;
+		private $default;
+		private function __construct(string $name, string $default){
+			$this->name = $name;
+			$this->default = $default;
+			self::$defaults[$name] = $this;
+		}
+		public function __toString(){
+			return $this->default;
+		}
+		public static function named(string $name){
+			if(!isset(self::$defaults[$name])){
+				throw new \Exception("DefaultValue {$name} not defined");
+			}
+			return self::$defaults[$name];
+		}
+		public static function add(string $name, string $default){
+			if(isset(self::$defaults[$name])){
+				throw new \Exception("DefaultValue {$name} already defined");
+			}
+			return new DefaultValue($name, $default);
+		}
+	}
+	DefaultValue::add('current_timestamp', 'current_timestamp');
+?>

+ 33 - 0
PDO/filter.class.php

@@ -0,0 +1,33 @@
+<?php
+	namespace Juju\PDO;
+
+	class Filter {
+		private static $filters = [];
+		private $name;
+		private $filter;
+		private function __construct(string $name, string $filter){
+			$this->name = $name;
+			self::$filters[$name] = $this;
+		}
+		public function name(){
+			return $this->name;
+		}
+		public function __toString(){
+			return $this->filter;
+		}
+		public static function named(string $name){
+			if(!isset(self::$filters[$name])){
+				throw new \Exception("Filter {$name} is not defined");
+			}
+			return self::$filters[$name];
+		}
+		public static function add(string $name, string $filter){
+			if(isset(self::$filters[$name])){
+				throw new \Exception("Filter {$name} is already defined");
+			}
+			return new  Filter($name, $filter);
+		}
+	}
+	Filter::add('not null', 'is not null');
+	Filter::add('null', 'is null');
+?>

+ 25 - 15
pdo.class.php

@@ -2,8 +2,10 @@
 	namespace Juju;
 	require_once('Data/securestring.class.php');
 	require_once('PDO/transaction.class.php');
+	require_once('PDO/defaultvalue.class.php');
+	require_once('PDO/filter.class.php');
 	require_once('PDO/table.class.php');
-	use Juju\{Data\SecureString, PDO\Table, PDO\Transaction};
+	use Juju\{Data\SecureString, PDO\DefaultValue, PDO\Filter, PDO\Table, PDO\Transaction};
 
 	class PDO {
 		public static function from(string $dsnstring){
@@ -149,16 +151,20 @@
 				$where = 'where ';
 				foreach($filter as $name => $value){
 					$value = $column['default'];
-					if(is_integer($value)){
-						$type = \PDO::PARAM_INT;
-					}elseif(is_bool($value)){
-						$type = \PDO::PARAM_BOOL;
-					}elseif(is_null($value)){
-						$type = \PDO::PARAM_NULL;
+					if($value instanceof Filter){
+						$where .= "`{$name}` {$value} and";
 					}else{
-						$type = \PDO::PARAM_STR;
+						if(is_integer($value)){
+							$type = \PDO::PARAM_INT;
+						}elseif(is_bool($value)){
+							$type = \PDO::PARAM_BOOL;
+						}elseif(is_null($value)){
+							$type = \PDO::PARAM_NULL;
+						}else{
+							$type = \PDO::PARAM_STR;
+						}
+						$where .= "`{$name}` = {$this->quote($value, $type)} and";
 					}
-					$where .= "`{$name}` = {$this->quote($value, $type)} and";
 				}
 				$where = rtrim($where, ' and');
 			}
@@ -178,14 +184,18 @@
 			$default = '';
 			if(!is_null($column['default'])){
 				$value = $column['default'];
-				if(is_integer($value)){
-					$type = \PDO::PARAM_INT;
-				}elseif(is_bool($value)){
-					$type = \PDO::PARAM_BOOL;
+				if($value instanceof DefaultValue){
+					$default .= " DEFAULT {$value}";
 				}else{
-					$type = \PDO::PARAM_STR;
+					if(is_integer($value)){
+						$type = \PDO::PARAM_INT;
+					}elseif(is_bool($value)){
+						$type = \PDO::PARAM_BOOL;
+					}else{
+						$type = \PDO::PARAM_STR;
+					}
+					$default .= " DEFAULT {$this->quote($value, $type)}";
 				}
-				$default .= " DEFAULT {$this->quote($value, $type)}";
 			}
 			$null = $column['null'] ? ' NULL' : ' NOT NULL';
 			$ai = $column['increment'] ? ' AUTO_INCREMENT' : '';