From d1abd79a50a52f18468dfe0982d23180e187e382 Mon Sep 17 00:00:00 2001 From: Anatoly Ressin Date: Wed, 6 Jun 2012 14:28:07 +0300 Subject: [PATCH] Added router --- router/iterator/iterator.class.php | 45 +++++ router/router.class.php | 286 +++++++++++++++++++++++++++++ 2 files changed, 331 insertions(+) create mode 100644 router/iterator/iterator.class.php create mode 100644 router/router.class.php diff --git a/router/iterator/iterator.class.php b/router/iterator/iterator.class.php new file mode 100644 index 0000000..75a3e95 --- /dev/null +++ b/router/iterator/iterator.class.php @@ -0,0 +1,45 @@ +owner = $owner; + $data = $owner->getData(); + if (is_array($data)) { + $data = new ArrayObject($data); + $this->useKeys = true; + } + $this->internal = $data->getIterator(); + } + + public function current(){ + return $this->owner->wrap($this->internal->current()); + } + + public function key(){ + return $this->owner->formatKey($this->useKeys + ? $this->internal->key() + : $this->internal->current() + ); + } + + public function next() { + $this->internal->next(); + } + + public function valid() { + return $this->internal->valid(); + } + + public function rewind() { + $this->internal->rewind(); + } + + } + + +?> \ No newline at end of file diff --git a/router/router.class.php b/router/router.class.php new file mode 100644 index 0000000..dca2217 --- /dev/null +++ b/router/router.class.php @@ -0,0 +1,286 @@ +wrapperClass = ''; + $this->wrap = array($wrap, $method); + } else if($wrap === false) { + $this->wrapperClass = ''; + $this->wrap = array(&$this,'sameObject'); + } else if(is_string($wrap)) { + $this->wrapperClass = $wrap; + $this->wrap = array(&$this,'staticWrap'); + } else { + $this->wrapperClass = ''; + $this->wrap = $wrap; + } + return $this; + } + + public function setUnwrap($unwrap, $method = false) { + if($method !== false) { + $this->unwrapMethod = ''; + $this->unwrap = array($unwrap, $method); + } else if($unwrap === false) { + $this->unwrapMethod = ''; + $this->unwrap = array(&$this,'sameObject'); + } else if (is_string($unwrap)) { + $this->unwrapMethod = $unwrap; + $this->unwrap = array(&$this,'staticUnwrap'); + } else { + $this->unwrapMethod = ''; + $this->unwrap = $unwrap; + } + return $this; + } + + public function __construct($pattern, $data, $wrap = false, $unwrap = false) { + $this->pattern = $pattern; + $this->data = $data; + $this->setWrap($wrap); + $this->setUnwrap($unwrap); + } + + private function &sameObject(&$obj){ + return $obj; + } + + private function staticWrap($obj){ + return $this->new_($this->wrapperClass,array($obj)); + } + + private function staticUnwrap($obj){ + return $obj->{$this->unwrapMethod}(); + } + + public function wrap($obj){ + return call_user_func($this->wrap,$obj); + } + + public function unwrap($obj){ + return call_user_func($this->unwrap,$obj); + } + + private function url($data, $encode) { + return $encode + ? urldecode($data) + : urldecode($data) + ; + } + private function any($data, $encode) { + return $data; + } + + private function getTypeConfig($type){ + if(!preg_match(self::TYPES_REGEXP, $type, $match)) { + throw new Exception('Unrecognized type'); + } + switch (count($match)) { + case 2: return array(self::INT_REGEXP_BARE, 'any'); + case 3: return array(self::STR_REGEXP_BARE, 'any'); + case 4: return array(self::URL_REGEXP_BARE, 'url'); + case 5: return array(self::URL_REGEXP_BARE, 'any'); + case 6: return $match[3]; + } + } + + public function formatKey($data){ + $params = array(); + foreach($this->params as $name => $config) { + list($regexp, $transform) = $config; + if(!$transform) $transform = 'any'; + $value = $this->$transform( + (($this->type === self::ARRAY_TYPE || $this->autoPopulate) + ? $data + : $data[$name] + ), true + ); + assert('preg_match($regexp, $value)'); + $params[$name] = $value; + } + return preg_replace(self::PARAM_REGEXP . 'e', "\$params['\\1']", $this->pattern); + } + + public function parseKey($str) { + if(!$this->matchKey($str, $key)) { + assert('$str!=$str'); + } + return $key; + } + + public function getData() { + return $this->data; + } + + public function getType() { + return $this->type; + } + + public function getRegexp() { + return $this->regexp; + } + + public function offsetExists($offset) { + if (!$this->matchKey($offset, $key)) return false; + return $this->autoPopulate || isset($this->data[$key]); + } + + //TODO: Change return mode to reference on php 5.3.4+ + public function offsetGet($offset) { + if ($this->autoPopulate) { + $key = $this->parseKey($offset); + if(!isset($this->data[$offset])) { + $this->data[$offset] = $this->wrap($key); + } + return $this->data[$offset]; + } else { + return $this->wrap( + $this->data[ + $this->parseKey($offset) + ] + ); + } + } + + public function offsetSet($offset, $value) { + $this->data[$this->parseKey($offset)] = $this->unwrap($value); + } + + public function offsetUnset($offset) { + unset($this->data[$this->parseKey($offset)]); + } + + public function count(){ + $this->ensureAuto(); + return count($this->data); + } + + private function ensureAuto() { + if(!$this->autoPopulate) return; + if(count($this->data)>0) return; + if(!$this->autoRoute) return; + $key = $this->parseKey($this->autoRoute); + $this->data[$this->autoRoute] = $this->wrap($key); + } + + public function getIterator() { + $this->ensureAuto(); + return $this->scope->Oxygen_Router_Iterator($this); + } + + private function extractKey($match) { + $key = array(); + foreach($this->params as $name => $config){ + $key[$name] = $this->{$config[1]}($match[$name], false); + } + return $key; + } + + public function matchKey($str, &$key) { + if(preg_match($this->extract, $str, $match)) { + switch($this->type){ + case self::SINGLE: + reset($match); + $key = current($match); + break; + case self::COLLECTION: + $key = $this->extractKey($match); + break; + case self::ARRAY_TYPE: + $key = $this->extractKey($match); + reset($key); + $key = current($key); + break; + } + return true; + } else { + $key = array(); + return false; + } + } + + private function compile() { + if(0 < preg_match_all(self::PARAM_REGEXP, $this->pattern, $match)){ + $names = $match[1]; + $types = $match[2]; + $params = array(); + foreach($names as $i => $name){ + if(isset($params[$name])) { + $this->throw_Exception(self::ROUTE_PARAM_REDEFINED); + } else { + $config = self::getTypeConfig($t = $types[$i]); + $params[$name] = $config[0]; + $this->params[$name] = array('/'.$config[0].'/',$config[1]); + } + } + $compiled = preg_replace(self::PARAM_REGEXP,self::PARAM_GUARD_REPLACE, $this->pattern); + $compiled = preg_quote($compiled,'/'); + $this->extract = '/' . preg_replace ( + self::PARAM_GUARD_REGEXP, + "'(?P<\\1>'.\$params['\\1'].')'", + $compiled + ) . '/'; + $this->regexp = preg_replace(self::PARAM_GUARD_REGEXP,"\$params['\\1']", $compiled); + if(is_array($this->data)){ + assert('count($names) === 1'); + $this->type = self::ARRAY_TYPE; + } else if(is_string($this->data) || !$this->data) { + $this->autoRoute = $this->data; + $this->data = array(); + $this->autoPopulate = true; + } else { + $this->type = self::COLLECTION; + } + } else { + $this->type = self::SINGLE; + $this->regexp = preg_quote($this->pattern, '/'); + $this->extract = '/' . $this->regexp . '/'; + $data = array(); + $data[$this->pattern] = $this->data; + $this->data = $data; + } + } + + + public function __complete($scope) { + echo "COMPLETE"; + $this->compile(); + } + } + + +?> \ No newline at end of file