367 lines
7.6 KiB
PHP
367 lines
7.6 KiB
PHP
|
<?php
|
||
|
/**
|
||
|
* Routen
|
||
|
*
|
||
|
* Routen dienen der Zuordnung einer Adresszeile
|
||
|
* zu einem Modul.
|
||
|
*
|
||
|
* @package federleicht
|
||
|
* @subpackage base
|
||
|
* @author Matthias Viehweger <kronn@kronn.de>
|
||
|
* @version 0.3
|
||
|
*/
|
||
|
class fl_route {
|
||
|
protected $route = '';
|
||
|
protected $regex = '';
|
||
|
protected $modul = '';
|
||
|
protected $defaults = array();
|
||
|
protected $priority = 1;
|
||
|
protected $language_key = '';
|
||
|
|
||
|
protected $default_regex = array();
|
||
|
protected $partial_regex = array();
|
||
|
|
||
|
/**
|
||
|
* Konstruktor
|
||
|
*
|
||
|
* @param string $route
|
||
|
* @param string $regex
|
||
|
*/
|
||
|
public function __construct($route, $regex='') {
|
||
|
$this->route = (string) $route;
|
||
|
|
||
|
$this->default_regex = array(
|
||
|
'normal_item'=>'[-_0-9a-z\.]+',
|
||
|
'last_item'=>'[-_/0-9a-zA-Z%\.]+'
|
||
|
);
|
||
|
|
||
|
if ( $route === 'regex' AND $regex != '' ) {
|
||
|
$this->regex = $regex;
|
||
|
} else {
|
||
|
$this->regex = $this->compile($route);
|
||
|
}
|
||
|
|
||
|
$this->set_priority( 1 );
|
||
|
$this->set_defaults( array() );
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Vereinfachte Objekterzeugung
|
||
|
*
|
||
|
* @pattern facade
|
||
|
*
|
||
|
* @param string $route
|
||
|
* @param string $defaults
|
||
|
* @param int $priority
|
||
|
* @param array $partial_regex
|
||
|
* @return fl_route
|
||
|
*/
|
||
|
public static function get_instance($route, $defaults, $priority, array $partial_regex=array()) {
|
||
|
$route_object = new self($route);
|
||
|
|
||
|
$defaults = is_string($defaults)?
|
||
|
fl_converter::string_to_array($defaults):
|
||
|
$defaults;
|
||
|
$route_object->set_defaults($defaults);
|
||
|
|
||
|
$route_object->set_priority((int) $priority);
|
||
|
$route_object->set_language_key('lang');
|
||
|
|
||
|
foreach ( $partial_regex as $part ) {
|
||
|
$route_object->set_partial_regex($part['key'], $part['regex']);
|
||
|
}
|
||
|
|
||
|
return $route_object;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Route zu regulärem Asudruck umwandeln
|
||
|
*
|
||
|
* @param string $route
|
||
|
* @return $string
|
||
|
*/
|
||
|
protected function compile($route) {
|
||
|
$elements = explode('/', $route);
|
||
|
$group_count = 0;
|
||
|
|
||
|
$beginning = '@^/';
|
||
|
$route_regex = '';
|
||
|
$end = '$@';
|
||
|
|
||
|
foreach( $elements as $key => $value ) {
|
||
|
if ( empty($value) ) {
|
||
|
unset($elements[$key]);
|
||
|
}
|
||
|
}
|
||
|
$elements = array_values($elements);
|
||
|
|
||
|
foreach( $elements as $key => $value ) {
|
||
|
if ( empty($value) ) continue;
|
||
|
|
||
|
$is_last = ( $key === ( count($elements) - 1 ) )? TRUE: FALSE;
|
||
|
|
||
|
if ( strpos($value, ':') === 0 ) {
|
||
|
$name = substr($value, 1);
|
||
|
$transformed_route = '(?P<'.$name.'>';
|
||
|
|
||
|
$regex = $this->get_partial_regex($name, $is_last);
|
||
|
if ( !empty( $regex ) ) {
|
||
|
$transformed_route .= $regex;
|
||
|
} elseif ( $is_last ) {
|
||
|
$transformed_route .= $this->default_regex['last_item'];
|
||
|
} else {
|
||
|
$transformed_route .= $this->default_regex['normal_item'];
|
||
|
}
|
||
|
|
||
|
$transformed_route .= ')';
|
||
|
|
||
|
if ( $group_count > 0 ) {
|
||
|
$transformed_route = '(?('.$group_count.')' . $transformed_route . '?+)';
|
||
|
}
|
||
|
|
||
|
$group_count++;
|
||
|
|
||
|
} else {
|
||
|
$transformed_route = $value;
|
||
|
}
|
||
|
|
||
|
$route_regex .= $transformed_route;
|
||
|
|
||
|
if ( !$is_last ) {
|
||
|
$route_regex .= '(/)?';
|
||
|
$group_count++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$regex = $beginning . $route_regex . $end;
|
||
|
return $regex;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Versuchen, Route in URL zu erkennen
|
||
|
*
|
||
|
* @param string $url
|
||
|
* @param boolean $last_route
|
||
|
* @return boolean
|
||
|
*/
|
||
|
public function try_route($url, $last_route=FALSE) {
|
||
|
$treffer = array();
|
||
|
|
||
|
$host = ( isset($_SERVER['HTTP_HOST']) )? $_SERVER['HTTP_HOST']: 'localhost';
|
||
|
$parsed_url = parse_url('http://'.$host.'/'.ltrim($url,'/'));
|
||
|
$url_path = $parsed_url['path'];
|
||
|
|
||
|
$result = preg_match($this->regex, $url_path, $treffer);
|
||
|
|
||
|
$request = $this->defaults;
|
||
|
$request['query'] = (isset($parsed_url['query']))? $parsed_url['query']:'';
|
||
|
|
||
|
foreach ( $treffer as $key => $value ) {
|
||
|
if ( is_numeric($key) ) continue;
|
||
|
if ( empty($value) ) continue;
|
||
|
|
||
|
$request[$key] = $value;
|
||
|
}
|
||
|
|
||
|
if ( $url === '/' AND $last_route === TRUE ) {
|
||
|
$result = 1;
|
||
|
}
|
||
|
if ( $this->modul === $this->defaults['controller'] ) {
|
||
|
$request['modul'] = $request['controller'];
|
||
|
}
|
||
|
|
||
|
$this->request = $request;
|
||
|
|
||
|
$route_success = ( intval($result) > 0 )? TRUE: FALSE;
|
||
|
return $route_success;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Defaultwerte setzen
|
||
|
*
|
||
|
* @param array $defaults
|
||
|
* @param string $modul
|
||
|
*/
|
||
|
public function set_defaults(array $defaults, $modul=NULL) {
|
||
|
$this->defaults = array_merge($this->defaults, $defaults);
|
||
|
|
||
|
if ( is_null($modul) AND isset($this->defaults['controller']) ) {
|
||
|
$modul = $this->defaults['controller'];
|
||
|
} else {
|
||
|
$modul = '';
|
||
|
}
|
||
|
|
||
|
$this->set_modul($modul);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Priorität der Route setzen
|
||
|
*
|
||
|
* @param integer $priority
|
||
|
*/
|
||
|
public function set_priority($priority) {
|
||
|
$this->priority = (integer) $priority;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Defaultkey für Sprachinformationen setzen
|
||
|
*
|
||
|
* @param string $key
|
||
|
*/
|
||
|
public function set_language_key($key) {
|
||
|
$this->language_key = (string) $key;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Teilregeln für einzelne Routenbestandteile setzen
|
||
|
*
|
||
|
* Nach dem setzen der Regeln wird die Route neu kompiliert.
|
||
|
*
|
||
|
* @param string $key
|
||
|
* @param string $regex
|
||
|
*/
|
||
|
public function set_partial_regex($key, $regex) {
|
||
|
$this->partial_regex[$key] = $regex;
|
||
|
$this->regex = $this->compile($this->route);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Modulzugehörigkeit setzen
|
||
|
*
|
||
|
* @param string $modul
|
||
|
*/
|
||
|
public function set_modul($modul) {
|
||
|
$this->modul = (string) $modul;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Request-Daten holen
|
||
|
*
|
||
|
* @return array
|
||
|
*/
|
||
|
public function get_request() {
|
||
|
$request = array_merge($this->request, array('modul'=>$this->modul));
|
||
|
|
||
|
return $request;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Priorität holen
|
||
|
*
|
||
|
* @return integer
|
||
|
*/
|
||
|
public function get_priority() {
|
||
|
return $this->priority;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Teilregel für eine Routenbestandteil holen
|
||
|
*
|
||
|
* @param string $key
|
||
|
* @param boolean $is_last
|
||
|
* @return string
|
||
|
*/
|
||
|
public function get_partial_regex($key, $is_last = false) {
|
||
|
if ( isset( $this->partial_regex[$key] ) ) {
|
||
|
$regex = $this->partial_regex[$key];
|
||
|
} elseif ( $is_last ) {
|
||
|
$regex = $this->default_regex['last_item'];
|
||
|
} else {
|
||
|
$regex = $this->default_regex['normal_item'];
|
||
|
}
|
||
|
|
||
|
return $regex;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sprachschlüssel holen
|
||
|
*
|
||
|
* Entweder ist der Sprachschlüssel mit $this->set_language_key
|
||
|
* gesetzt worden, oder es wird der letzte Eintrag der Default-
|
||
|
* Werte verwendet.
|
||
|
*
|
||
|
* @return string
|
||
|
*/
|
||
|
public function get_language_key() {
|
||
|
if ( isset( $this->language_key ) AND !empty($this->language_key) ) {
|
||
|
return $this->language_key;
|
||
|
} else {
|
||
|
return array_pop(array_keys($this->defaults));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* URL erzeugen, die der aktuellen Route entspricht
|
||
|
*
|
||
|
* @param string $route
|
||
|
* @param array $parts
|
||
|
* @return string
|
||
|
*/
|
||
|
public function make_url($route, array $parts) {
|
||
|
$elements = explode('/', $route);
|
||
|
|
||
|
$url = '';
|
||
|
|
||
|
foreach( $elements as $key => $value ) {
|
||
|
if ( empty($value) ) {
|
||
|
unset($elements[$key]);
|
||
|
}
|
||
|
}
|
||
|
$elements = array_values($elements);
|
||
|
|
||
|
foreach( $elements as $key => $value ) {
|
||
|
if ( empty($value) ) continue;
|
||
|
|
||
|
if ( strpos($value, ':') === 0 ) {
|
||
|
$name = substr($value, 1);
|
||
|
|
||
|
$part = $parts[$name];
|
||
|
if ( !empty( $part ) ) {
|
||
|
$url .= $part;
|
||
|
} else {
|
||
|
$url .= $this->defaults[$name];
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
$url = $value;
|
||
|
}
|
||
|
|
||
|
$url .= '/';
|
||
|
}
|
||
|
|
||
|
return $url;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* URL zurückgeben, die zur aktuellen Route passt
|
||
|
*
|
||
|
* @return string
|
||
|
*/
|
||
|
public function get_current_url() {
|
||
|
return $this->make_url($this->route, $this->request);
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Vergleichsfunktion zur Sortierung von Routen
|
||
|
*
|
||
|
* Kann mit usort($array_of_routes, array('route', 'compare_routes');
|
||
|
* verwendet werden.
|
||
|
*
|
||
|
* @param fl_route $a
|
||
|
* @param fl_route $b
|
||
|
* @return integer
|
||
|
*/
|
||
|
public function compare_routes(fl_route $a, fl_route $b) {
|
||
|
$ap = $a->get_priority();
|
||
|
$bp = $b->get_priority();
|
||
|
|
||
|
if ( $ap == $bp ) {
|
||
|
$result = 0;
|
||
|
} else {
|
||
|
$result = ( $ap > $bp )? 1: -1;
|
||
|
}
|
||
|
return $result;
|
||
|
}
|
||
|
}
|