openrat-cms

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

VariableResolver.class.php (5263B)


      1 <?php
      2 
      3 
      4 namespace util\text\variables;
      5 
      6 /**
      7  * VariableResolver for resolving variables in strings and arrays.
      8  */
      9 
     10 class VariableResolver
     11 {
     12 	public $marker   = '$';
     13 	public $open     = '{';
     14 	public $close    = '}';
     15 	public $namespaceSeparator  = '.';
     16 	public $defaultSeparator    = ':';
     17 	public $renderOnlyVariables = false;
     18 
     19 	/**
     20 	 * @var callable
     21 	 */
     22 	private $filterValue = null;
     23 
     24 	private $resolvers = [];
     25 
     26 	private $value = null;
     27 
     28 
     29 	/**
     30 	 * Adding a filter function for values.
     31 	 * @param $filter callable
     32 	 */
     33 	public function addFilter( $filter ) {
     34 		$this->filterValue = $filter;
     35 	}
     36 
     37 	/**
     38 	 * Adding a default variable resolver.
     39 	 * @param $resolver callable|array
     40 	 */
     41 	public function addDefaultResolver( $resolver ) {
     42 		$this->resolvers[''] = $resolver;
     43 	}
     44 
     45 	/**
     46 	 * Adding a variable resolver for a key.
     47 	 *
     48 	 * @param $key string key
     49 	 * @param $resolver callable|array
     50 	 */
     51 	public function addResolver( $key, $resolver ) {
     52 		$this->resolvers[$key] = $resolver;
     53 	}
     54 
     55 
     56 	/**
     57 	 * Resolving a variable in a text like 'name is ${env:username:default}.'
     58 	 *
     59 	 * @param $value string
     60 	 * @return string
     61 	 */
     62 	public function resolveVariables($value) {
     63 
     64 		$this->parseString( $value );
     65 		return $this->renderToString();
     66 	}
     67 
     68 	/**
     69 	 * Resolving a variable in a text like 'name is ${env.username:default}.'
     70 	 *
     71 	 * @param $value array
     72 	 * @return array
     73 	 */
     74 	public function resolveVariablesInArray($value) {
     75 
     76 		// pass-by-reference
     77 		array_walk_recursive($value, function (&$item, $keyI) {
     78 
     79 			$item = $this->resolveVariables($item);
     80 			return $item;
     81 		});
     82 
     83 		return $value;
     84 
     85 	}
     86 
     87 	/**
     88 	 * Resolving a variable in a text like 'name is ${env:username:default}'.
     89 	 *
     90 	 * @param $value
     91 	 * @param $key
     92 	 * @param $resolver
     93 	 * @return string
     94 	 */
     95 	public function parseString($value)
     96 	{
     97 		$this->value = $this->parseToValue($value);
     98 	}
     99 
    100 	public function renderToString()
    101 	{
    102 		return $this->render( $this->value );
    103 	}
    104 
    105 
    106 
    107 	protected function render( $value )
    108 	{
    109 		$text = '';
    110 
    111 		foreach( $value->expressions as $expression )
    112 		{
    113 			if   ( $expression instanceof ValueExpression ) {
    114 				$key = $this->render($expression->prefix);
    115 				$resolver = @$this->resolvers[ $key ];
    116 				$v = '';
    117 				if   ( is_callable($resolver) ) {
    118 					$v = $resolver( $this->render($expression->name) );
    119 				}
    120 				elseif   ( is_array($resolver) ) {
    121 					$v = @$resolver[ $this->render($expression->name ) ];
    122 				}
    123 				if   ( strlen($v)==0 )
    124 					$v = $this->render($expression->default);
    125 
    126 				if   ( $this->filterValue ) {
    127 					$filter = $this->filterValue;
    128 					$v = $filter( $v );
    129 				}
    130 
    131 				$text .= $v;
    132 			}else {
    133 				$text .= strval( $expression );
    134 			}
    135 		}
    136 
    137 		return $text;
    138 	}
    139 
    140 
    141 	private function findNextPosOfChar( $haystack, $needle ) {
    142 
    143 		$chars = str_split($haystack);
    144 		$depth = 0;
    145 		$pos   = 0;
    146 		foreach( $chars as $char) {
    147 
    148 			if   ( $char == $this->open )
    149 				$depth++;
    150 			elseif   ( $char == $needle && $depth == 0 )
    151 				return $pos;
    152 			elseif   ( $char == $this->close )
    153 				$depth--;
    154 
    155 			$pos++;
    156 		}
    157 
    158 		return false;
    159 
    160 	}
    161 
    162 	/**
    163 	 * @param $inputText
    164 	 * @return Value
    165 	 */
    166 	public function parseToValue($inputText)
    167 	{
    168 		$v = new Value();
    169 
    170 		while (true) {
    171 
    172 			if	( strlen($inputText)==0 ) // Do not compare to "false" here, as '0' is false ;)
    173 				break;
    174 
    175 			// Search the next variable marker '$'
    176 			$nextVariableMarkerPos = strpos($inputText, $this->marker.$this->open);
    177 
    178 			if   ($nextVariableMarkerPos === false )
    179 			{
    180 				// no variable found.
    181 				$v->expressions[] = $inputText;
    182 				break;
    183 			}
    184 			else
    185 			{
    186 				$v->expressions[] = substr($inputText,0,$nextVariableMarkerPos);
    187 
    188 				$inputText = substr($inputText,$nextVariableMarkerPos+strlen($this->marker)+strlen($this->open));
    189 
    190 				$pos = $this->findNextPosOfChar($inputText,$this->close);
    191 
    192 				if   ( $pos  === false)
    193 					throw new \RuntimeException('non-closed variable: '.$inputText);
    194 
    195 				$vv = substr($inputText,0,$pos);
    196 				$namespace = '';
    197 				$default   = '';
    198 
    199 				$prefixSepPos = $this->findNextPosOfChar($vv,$this->namespaceSeparator);
    200 				if   ( $prefixSepPos!==false) {
    201 					$namespace = substr($vv,0,$prefixSepPos);
    202 					$vv        = substr($vv,$prefixSepPos+strlen($this->namespaceSeparator));
    203 				}
    204 
    205 				$defaultSepPos = $this->findNextPosOfChar($vv,$this->defaultSeparator);
    206 				if   ( $defaultSepPos!==false) {
    207 					$default = substr($vv,$defaultSepPos+strlen($this->defaultSeparator));
    208 					$vv      = substr($vv, 0,$defaultSepPos);
    209 				}
    210 
    211 				$v->expressions[] = new ValueExpression($this->parseToValue($namespace),$this->parseToValue($vv),$this->parseToValue($default));
    212 
    213 				$inputText = substr($inputText,$pos+1);
    214 			}
    215 
    216 		}
    217 
    218 		return $v;
    219 	}
    220 
    221 
    222 	public function createExpression($namespace, $name, $default='')
    223 	{
    224 		return $this->marker.$this->open.($namespace?$namespace.$this->namespaceSeparator:'').$name.($default?$this->defaultSeparator.$default:'').$this->close;
    225 	}
    226 }
    227 
    228 /** Usage: *
    229 
    230 $resolver = new VariableResolver();
    231 print_r( $resolver->resolveVariables('Born in the ${bruce:birthcountry}.','bruce',function($name){return 'USA';} ) );
    232 print_r( $resolver->resolveVariables('Born in ${bruce:birthyear:19??}.','bruce',function($name){return '';} ) );
    233 print_r( $resolver->resolveVariables('Born in the ${bruce:birthcountry}.${x:y}${x}','bruce',function($name){return 'USA';} ) );
    234 exit;
    235 */