Example #1
0
 /**
  * Static factory.
  * @param  string element name (or NULL)
  * @param  array|string element's attributes (or textual content)
  * @return Html
  */
 public static function el($name = NULL, $attrs = NULL)
 {
     $el = new static();
     $parts = explode(' ', $name, 2);
     $el->setName($parts[0]);
     if (is_array($attrs)) {
         $el->attrs = $attrs;
     } elseif ($attrs !== NULL) {
         $el->setText($attrs);
     }
     if (isset($parts[1])) {
         foreach (Nette\String::matchAll($parts[1] . ' ', '#([a-z0-9:-]+)(?:=(["\'])?(.*?)(?(2)\\2|\\s))?#i') as $m) {
             $el->attrs[$m[1]] = isset($m[3]) ? $m[3] : TRUE;
         }
     }
     return $el;
 }
Example #2
0
 /**
  * Process <texy>...</texy> elements.
  * @param  string
  * @return string
  */
 public static function texyElements($s)
 {
     return String::replace($s, '#<texy([^>]*)>(.*?)</texy>#s', function ($m) {
         list(, $mAttrs, $mContent) = $m;
         // parse attributes
         $attrs = array();
         if ($mAttrs) {
             foreach (String::matchAll($mAttrs, '#([a-z0-9:-]+)\\s*(?:=\\s*(\'[^\']*\'|"[^"]*"|[^\'"\\s]+))?()#isu') as $m) {
                 $key = strtolower($m[1]);
                 $val = $m[2];
                 if ($val == NULL) {
                     $attrs[$key] = TRUE;
                 } elseif ($val[0] === '\'' || $val[0] === '"') {
                     $attrs[$key] = html_entity_decode(substr($val, 1, -1), ENT_QUOTES, 'UTF-8');
                 } else {
                     $attrs[$key] = html_entity_decode($val, ENT_QUOTES, 'UTF-8');
                 }
             }
         }
         return TemplateFilters::$texy->process($m[2]);
     });
 }
Example #3
0
	function tokenize($input)
	{
		$this->input = $input;
		if ($this->names) {
			$this->tokens = String::matchAll($input, $this->re);
			$len = 0;
			foreach ($this->tokens as & $match) {
				$name = NULL;
				for ($i = 1; $i < count($this->names); $i++) {
					if (!isset($match[$i])) {
						break;
					} elseif ($match[$i] != NULL) {
						$name = $this->names[$i - 1]; break;
					}
				}
				$match = array($match[0], $name);
				$len += strlen($match[0]);
			}
			if ($len !== strlen($input)) {
				$errorOffset = $len;
			}

		} else {
			$this->tokens = String::split($input, $this->re, PREG_SPLIT_NO_EMPTY);
			if ($this->tokens && !String::match(end($this->tokens), $this->re)) {
				$tmp = String::split($this->input, $this->re, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_OFFSET_CAPTURE);
				list(, $errorOffset) = end($tmp);
			}
		}

		if (isset($errorOffset)) {
			$line = $errorOffset ? substr_count($this->input, "\n", 0, $errorOffset) + 1 : 1;
			$col = $errorOffset - strrpos(substr($this->input, 0, $errorOffset), "\n") + 1;
			$token = str_replace("\n", '\n', substr($input, $errorOffset, 10));
			throw new TokenizerException("Unexpected '$token' on line $line, column $col.");
		}
		return $this;
	}
    /**
     * Parses phpDoc comment.
     * @param  string
     * @return array
     */
    private static function parseComment($comment)
    {
        static $tokens = array('true' => TRUE, 'false' => FALSE, 'null' => NULL, '' => TRUE);
        $matches = String::matchAll(trim($comment, '/*'), '~
				(?<=\\s)@(' . self::RE_IDENTIFIER . ')[ \\t]*      ##  annotation
				(
					\\((?>' . self::RE_STRING . '|[^\'")@]+)+\\)|  ##  (value)
					[^(@\\r\\n][^@\\r\\n]*|)                     ##  value
			~xi');
        $res = array();
        foreach ($matches as $match) {
            list(, $name, $value) = $match;
            if (substr($value, 0, 1) === '(') {
                $items = array();
                $key = '';
                $val = TRUE;
                $value[0] = ',';
                while ($m = String::match($value, '#\\s*,\\s*(?>(' . self::RE_IDENTIFIER . ')\\s*=\\s*)?(' . self::RE_STRING . '|[^\'"),\\s][^\'"),]*)#A')) {
                    $value = substr($value, strlen($m[0]));
                    list(, $key, $val) = $m;
                    if ($val[0] === "'" || $val[0] === '"') {
                        $val = substr($val, 1, -1);
                    } elseif (is_numeric($val)) {
                        $val = 1 * $val;
                    } else {
                        $lval = strtolower($val);
                        $val = array_key_exists($lval, $tokens) ? $tokens[$lval] : $val;
                    }
                    if ($key === '') {
                        $items[] = $val;
                    } else {
                        $items[$key] = $val;
                    }
                }
                $value = count($items) < 2 && $key === '' ? $val : $items;
            } else {
                $value = trim($value);
                if (is_numeric($value)) {
                    $value = 1 * $value;
                } else {
                    $lval = strtolower($value);
                    $value = array_key_exists($lval, $tokens) ? $tokens[$lval] : $value;
                }
            }
            $class = $name . 'Annotation';
            if (class_exists($class)) {
                $res[$name][] = new $class(is_array($value) ? $value : array('value' => $value));
            } else {
                $res[$name][] = is_array($value) ? new \ArrayObject($value, \ArrayObject::ARRAY_AS_PROPS) : $value;
            }
        }
        return $res;
    }
Example #5
0
 /**
  * Parse mask and array of default values; initializes object.
  * @param  string
  * @param  array
  * @return void
  */
 private function setMask($mask, array $metadata)
 {
     $this->mask = $mask;
     // detect '//host/path' vs. '/abs. path' vs. 'relative path'
     if (substr($mask, 0, 2) === '//') {
         $this->type = self::HOST;
     } elseif (substr($mask, 0, 1) === '/') {
         $this->type = self::PATH;
     } else {
         $this->type = self::RELATIVE;
     }
     foreach ($metadata as $name => $meta) {
         if (!is_array($meta)) {
             $metadata[$name] = array(self::VALUE => $meta, 'fixity' => self::CONSTANT);
         } elseif (array_key_exists(self::VALUE, $meta)) {
             $metadata[$name]['fixity'] = self::CONSTANT;
         }
     }
     // PARSE MASK
     $parts = String::split($mask, '/<([^># ]+) *([^>#]*)(#?[^>\\[\\]]*)>|(\\[!?|\\]|\\s*\\?.*)/');
     // <parameter-name [pattern] [#class]> or [ or ] or ?...
     $this->xlat = array();
     $i = count($parts) - 1;
     // PARSE QUERY PART OF MASK
     if (isset($parts[$i - 1]) && substr(ltrim($parts[$i - 1]), 0, 1) === '?') {
         $matches = String::matchAll($parts[$i - 1], '/(?:([a-zA-Z0-9_.-]+)=)?<([^># ]+) *([^>#]*)(#?[^>]*)>/');
         // name=<parameter-name [pattern][#class]>
         foreach ($matches as $match) {
             list(, $param, $name, $pattern, $class) = $match;
             // $pattern is not used
             if ($class !== '') {
                 if (!isset(self::$styles[$class])) {
                     throw new \InvalidStateException("Parameter '{$name}' has '{$class}' flag, but Route::\$styles['{$class}'] is not set.");
                 }
                 $meta = self::$styles[$class];
             } elseif (isset(self::$styles['?' . $name])) {
                 $meta = self::$styles['?' . $name];
             } else {
                 $meta = self::$styles['?#'];
             }
             if (isset($metadata[$name])) {
                 $meta = $metadata[$name] + $meta;
             }
             if (array_key_exists(self::VALUE, $meta)) {
                 $meta['fixity'] = self::OPTIONAL;
             }
             unset($meta['pattern']);
             $meta['filterTable2'] = empty($meta[self::FILTER_TABLE]) ? NULL : array_flip($meta[self::FILTER_TABLE]);
             $metadata[$name] = $meta;
             if ($param !== '') {
                 $this->xlat[$name] = $param;
             }
         }
         $i -= 5;
     }
     $brackets = 0;
     // optional level
     $re = '';
     $sequence = array();
     $autoOptional = array(0, 0);
     // strlen($re), count($sequence)
     do {
         array_unshift($sequence, $parts[$i]);
         $re = preg_quote($parts[$i], '#') . $re;
         if ($i === 0) {
             break;
         }
         $i--;
         $part = $parts[$i];
         // [ or ]
         if ($part === '[' || $part === ']' || $part === '[!') {
             $brackets += $part[0] === '[' ? -1 : 1;
             if ($brackets < 0) {
                 throw new \InvalidArgumentException("Unexpected '{$part}' in mask '{$mask}'.");
             }
             array_unshift($sequence, $part);
             $re = ($part[0] === '[' ? '(?:' : ')?') . $re;
             $i -= 4;
             continue;
         }
         $class = $parts[$i];
         $i--;
         // validation class
         $pattern = trim($parts[$i]);
         $i--;
         // validation condition (as regexp)
         $name = $parts[$i];
         $i--;
         // parameter name
         array_unshift($sequence, $name);
         if ($name[0] === '?') {
             // "foo" parameter
             $re = '(?:' . preg_quote(substr($name, 1), '#') . '|' . $pattern . ')' . $re;
             $sequence[1] = substr($name, 1) . $sequence[1];
             continue;
         }
         // check name (limitation by regexp)
         if (preg_match('#[^a-z0-9_-]#i', $name)) {
             throw new \InvalidArgumentException("Parameter name must be alphanumeric string due to limitations of PCRE, '{$name}' given.");
         }
         // pattern, condition & metadata
         if ($class !== '') {
             if (!isset(self::$styles[$class])) {
                 throw new \InvalidStateException("Parameter '{$name}' has '{$class}' flag, but Route::\$styles['{$class}'] is not set.");
             }
             $meta = self::$styles[$class];
         } elseif (isset(self::$styles[$name])) {
             $meta = self::$styles[$name];
         } else {
             $meta = self::$styles['#'];
         }
         if (isset($metadata[$name])) {
             $meta = $metadata[$name] + $meta;
         }
         if ($pattern == '' && isset($meta[self::PATTERN])) {
             $pattern = $meta[self::PATTERN];
         }
         $meta['filterTable2'] = empty($meta[self::FILTER_TABLE]) ? NULL : array_flip($meta[self::FILTER_TABLE]);
         if (array_key_exists(self::VALUE, $meta)) {
             if (isset($meta['filterTable2'][$meta[self::VALUE]])) {
                 $meta['defOut'] = $meta['filterTable2'][$meta[self::VALUE]];
             } elseif (isset($meta[self::FILTER_OUT])) {
                 $meta['defOut'] = call_user_func($meta[self::FILTER_OUT], $meta[self::VALUE]);
             } else {
                 $meta['defOut'] = $meta[self::VALUE];
             }
         }
         $meta[self::PATTERN] = "#(?:{$pattern})\$#A" . ($this->flags & self::CASE_SENSITIVE ? '' : 'iu');
         // include in expression
         $re = '(?P<' . str_replace('-', '___', $name) . '>' . $pattern . ')' . $re;
         // str_replace is dirty trick to enable '-' in parameter name
         if ($brackets) {
             // is in brackets?
             if (!isset($meta[self::VALUE])) {
                 $meta[self::VALUE] = $meta['defOut'] = NULL;
             }
             $meta['fixity'] = self::PATH_OPTIONAL;
         } elseif (isset($meta['fixity'])) {
             // auto-optional
             $re = '(?:' . substr_replace($re, ')?', strlen($re) - $autoOptional[0], 0);
             array_splice($sequence, count($sequence) - $autoOptional[1], 0, array(']', ''));
             array_unshift($sequence, '[', '');
             $meta['fixity'] = self::PATH_OPTIONAL;
         } else {
             $autoOptional = array(strlen($re), count($sequence));
         }
         $metadata[$name] = $meta;
     } while (TRUE);
     if ($brackets) {
         throw new \InvalidArgumentException("Missing closing ']' in mask '{$mask}'.");
     }
     $this->re = '#' . $re . '/?$#A' . ($this->flags & self::CASE_SENSITIVE ? '' : 'iu');
     $this->metadata = $metadata;
     $this->sequence = $sequence;
 }
Example #6
0
	/**
	 * Builds HTML content.
	 * @return void
	 */
	protected function buildHtml()
	{
		if ($this->html instanceof Nette\Templates\ITemplate) {
			$this->html->mail = $this;
			if ($this->basePath === NULL && $this->html instanceof Nette\Templates\IFileTemplate) {
				$this->basePath = dirname($this->html->getFile());
			}
			$this->html = $this->html->__toString(TRUE);
		}

		if ($this->basePath !== FALSE) {
			$cids = array();
			$matches = String::matchAll($this->html, '#(src\s*=\s*|background\s*=\s*|url\()(["\'])(?![a-z]+:|[/\\#])(.+?)\\2#i', PREG_OFFSET_CAPTURE);
			foreach (array_reverse($matches) as $m)	{
				$file = rtrim($this->basePath, '/\\') . '/' . $m[3][0];
				$cid = isset($cids[$file]) ? $cids[$file] : $cids[$file] = substr($this->addEmbeddedFile($file)->getHeader("Content-ID"), 1, -1);
				$this->html = substr_replace($this->html, "{$m[1][0]}{$m[2][0]}cid:$cid{$m[2][0]}", $m[0][1], strlen($m[0][0]));
			}
		}

		if (!$this->getSubject() && $matches = String::match($this->html, '#<title>(.+?)</title>#is')) {
			$this->setSubject(html_entity_decode($matches[1], ENT_QUOTES, 'UTF-8'));
		}
	}
Example #7
0
    /**
     * Applies modifiers.
     * @param  string
     * @param  string
     * @return string
     */
    public static function formatModifiers($var, $modifiers)
    {
        if (!$modifiers) {
            return $var;
        }
        $tokens = String::matchAll($modifiers . '|', '~
				' . self::RE_STRING . '|  ## single or double quoted string
				[^\'"|:,\\s]+|         ## symbol
				[|:,]                 ## separator
			~xs', PREG_PATTERN_ORDER);
        $inside = FALSE;
        $prev = '';
        foreach ($tokens[0] as $token) {
            if ($token === '|' || $token === ':' || $token === ',') {
                if ($prev === '') {
                } elseif (!$inside) {
                    if (!String::match($prev, '#^' . self::RE_IDENTIFIER . '$#')) {
                        throw new \InvalidStateException("Modifier name must be alphanumeric string, '{$prev}' given.");
                    }
                    $var = "\$template->{$prev}({$var}";
                    $prev = '';
                    $inside = TRUE;
                } else {
                    $var .= ', ' . self::formatString($prev);
                    $prev = '';
                }
                if ($token === '|' && $inside) {
                    $var .= ')';
                    $inside = FALSE;
                }
            } else {
                $prev .= $token;
            }
        }
        return $var;
    }