Overview

Namespaces

  • Simpletools
    • Autoload
    • Config
    • Db
      • Mysql
    • Event
    • Http
    • Mvc
    • Page
    • Store

Classes

  • Simpletools\Autoload\Loader
  • Simpletools\Config\Ini
  • Simpletools\Db\Mysql\Client
  • Simpletools\Db\Mysql\Iterator
  • Simpletools\Db\Mysql\Model
  • Simpletools\Db\Mysql\QueryBuilder
  • Simpletools\Db\Mysql\Result
  • Simpletools\Db\Mysql\Sql
  • Simpletools\Event\Event
  • Simpletools\Http\Ssl
  • Simpletools\Mvc\Common
  • Simpletools\Mvc\Controller
  • Simpletools\Mvc\Model
  • Simpletools\Mvc\Router
  • Simpletools\Mvc\RoutingHook
  • Simpletools\Mvc\View
  • Simpletools\Page\Layout
  • Simpletools\Store\Cookie
  • Simpletools\Store\Flash
  • Simpletools\Store\Session
  • Overview
  • Namespace
  • Class
   1: <?php
   2: /**
   3:  * Simpletools Framework.
   4:  * Copyright (c) 2009, Marcin Rosinski. (https://www.getsimpletools.com/)
   5:  * All rights reserved.
   6:  * 
   7:  * LICENCE
   8:  *
   9:  * Redistribution and use in source and binary forms, with or without modification, 
  10:  * are permitted provided that the following conditions are met:
  11:  *
  12:  * -    Redistributions of source code must retain the above copyright notice, 
  13:  *      this list of conditions and the following disclaimer.
  14:  * 
  15:  * -    Redistributions in binary form must reproduce the above copyright notice, 
  16:  *      this list of conditions and the following disclaimer in the documentation and/or other 
  17:  *      materials provided with the distribution.
  18:  * 
  19:  * -    Neither the name of the Simpletools nor the names of its contributors may be used to 
  20:  *      endorse or promote products derived from this software without specific prior written permission.
  21:  * 
  22:  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 
  23:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 
  24:  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
  25:  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
  26:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
  27:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 
  28:  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 
  29:  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30:  * 
  31:  * @framework       Simpletools
  32:  * @description     MVC framework
  33:  * @copyright       Copyright (c) 2009 Marcin Rosinski. (https://www.getsimpletools.com/)
  34:  * @license         (BSD)
  35:  *
  36:  */
  37: 
  38:     namespace Simpletools\Mvc;
  39: 
  40:     /**
  41:     * MVC Router
  42:     */
  43:     class Router extends \Simpletools\Mvc\Common
  44:     {
  45:         //anti dupliate content settings
  46:         const NOSLASH_NOINDEX           = 1;
  47:         const SLASH_NOINDEX             = 2;
  48:         const NOSLASH_INDEX             = 3;
  49:         const SLASH_INDEX               = 4;
  50: 
  51:         private $_duplicate_content     = 0;
  52: 
  53:         //settings properties
  54:         protected $_appDir              = '';
  55:         protected $_forwarded           = false;
  56:         protected $_params              = '';
  57:         protected $_autoRender          = true;
  58:         protected $_errorCode           = false;
  59:         protected $_error               = null;
  60:         protected $_classes             = array();
  61:         protected $_404_error_header    = true;
  62:         protected $_enableRouterHooks   = false;
  63: 
  64:         //instance holder
  65:         private static $_instance       = null;
  66:         protected $_shifts_params       = false;
  67: 
  68:         //custom objects
  69:         protected $_objects                 = false;
  70: 
  71:         //routing namespaces
  72:         protected $_routingNamespaces               = array();
  73:         protected $_activeRoutingNamespace          = '';
  74:         protected $_activeRoutingNamespaceUrlPath   = '';
  75: 
  76:         private $_settings              = array(
  77:             'defaultController'                     => 'index',
  78:             'defaultAction'                         => 'index',
  79:             'uri_app_position'                      => 0,
  80:             'redirect_missing_location_to_default'  => false,
  81:             '404_error_header'                      => true,
  82:             'overrideController'                    => false,
  83:             'overrideAction'                        => 'index'
  84:         );
  85: 
  86:         //view object
  87:         protected $_view            = '';
  88:         protected $_view_enabled    = true;
  89: 
  90:         public function __construct(array $settings=null)
  91:         {
  92:             if(
  93:                     (isset($settings['applicationDir']) && is_dir($settings['applicationDir']))
  94:                 OR
  95:                     (isset($settings['application_dir']) && is_dir($settings['application_dir']))
  96:             )
  97:             {
  98:                 $vext                                                       = isset($settings['view_extension']) ? $settings['view_extension'] : 'phtml';
  99:                 $this->_appDir                                              = isset($settings['applicationDir']) ? rtrim($settings['applicationDir'],'/') : rtrim($settings['application_dir'],'/');
 100:                 $this->_view                                                = new \Simpletools\Mvc\View($vext);
 101:                 $this->_settings['uri_app_position']                        = isset($settings['uri_app_position']) ? (integer) $settings['uri_app_position'] : 0;
 102:                 $this->_settings['redirect_missing_location_to_default']    = isset($settings['redirect_missing_location_to_default']) ? (boolean) $settings['redirect_missing_location_to_default'] : false;
 103:                 $this->_settings['use_subdomain']                           = isset($settings['use_subdomain']) ? $settings['use_subdomain'] : false;
 104: 
 105:                 $this->_settings['overrideController']                      = isset($settings['overrideController']) ? $settings['overrideController'] : false;
 106:                 $this->_settings['overrideAction']                          = isset($settings['overrideAction']) ? $settings['overrideAction'] : $this->_settings['overrideAction'];
 107: 
 108:                 $this->_404_error_header                                    = isset($settings['404_error_header']) ? (boolean) $settings['404_error_header'] : true;
 109:                 $this->_duplicate_content                                   = isset($settings['duplicate_content']) ? (int) $settings['duplicate_content'] : 0;
 110: 
 111:                 $this->_routingHooks                                    = isset($settings['routingHooks']) ? (bool) $settings['routingHooks'] : false;
 112: 
 113:                 if(isset($settings['routingNamespaces']))
 114:                 {
 115:                     $this->registerRoutingNamespaces($settings['routingNamespaces']);
 116:                 }
 117: 
 118:                 if(isset($settings['customRoutes']))
 119:                 {
 120:                     $this->_customRoutes = array();
 121:                     $this->_addCustomRoutes($settings['customRoutes']);
 122:                 }
 123: 
 124:                 $this->_params  = $this->getParams(true);
 125: 
 126:                 $this->_view->setParams($this->_params,$this->_shifts_params);
 127: 
 128:                 new \Simpletools\Mvc\Model($this->_appDir,$this->_activeRoutingNamespace);
 129:             }
 130:             else
 131:             {
 132:                 trigger_error("<br />You must to specify correct directory to application folder as an argument of SimpleMVC object constructor to be able to use SimpleMVC framework<br />", E_USER_ERROR);
 133:             }
 134:         }
 135: 
 136:         protected $_customRoutes            = false;
 137:         protected $_activeCustomRouteArgs   = false;
 138:         protected $_httpMethods             = array(
 139:             "OPTIONS"   => "OPTIONS",
 140:             "GET"       => "GET",
 141:             "HEAD"      => "HEAD",
 142:             "POST"      => "POST",
 143:             "PUT"       => "PUT",
 144:             "DELETE"    => "DELETE",
 145:             "TRACE"     => "TRACE",
 146:             "CONNECT"   => "CONNECT",
 147:         );
 148: 
 149:         protected function _addCustomRoutes($routes,$method='ANY')
 150:         {
 151:             foreach($routes as $route=>$invoke)
 152:             {
 153:                 $httpMethod = isset($this->_httpMethods[$route]) ? $this->_httpMethods[$route] : false;
 154: 
 155:                 if($httpMethod)
 156:                 {
 157:                     $this->_addCustomRoutes($invoke,$httpMethod);
 158:                 }
 159:                 else
 160:                 {
 161:                     $this->_customRoutes[$method][$route]   = $this->_parseCustomRoutes($route,$invoke);
 162:                 }
 163:             }
 164:         }
 165: 
 166:         /**
 167:         * Custom routes parser
 168:         *
 169:         * Internal custom routes parser/compiler
 170:         *
 171:         * @param string $path Uri path to match against
 172:         * @param array $invoke Action to perform if $path matches current URI.
 173:         *
 174:         * @return array Array of compiled custom routes
 175:         */
 176:         protected function _parseCustomRoutes($path,$invoke)
 177:         {
 178:             preg_match_all('/\{(.*?)\}/', $path, $matches);
 179: 
 180:             if(isset($matches[0]))
 181:             {
 182:                 $path = str_replace(array('\*','\^','\?'),array('.*','^','?'),preg_quote($path,'/'));
 183:                 $map = array();
 184:                 foreach($matches[0] as $index => $match)
 185:                 {
 186:                     $path = str_replace(preg_quote($match),'([A-Za-z0-9\-_]*)',$path);
 187:                     $map[] = $matches[1][$index];
 188:                 }
 189:             }
 190: 
 191:             return array(
 192:                 'pattern'   => '/'.$path.'$/',
 193:                 'map'       => $map,
 194:                 'invoke'    => $invoke
 195:             );
 196:         }
 197: 
 198:         public function registerRoutingNamespaces($namespaces)
 199:         {
 200:             foreach($namespaces as $namespace)
 201:             {
 202:                 $namespace  = str_replace('/','\\',$namespace);
 203:                 $namespace  = explode('\\',$namespace);
 204: 
 205:                 $_namespace = array();
 206:                 foreach($namespace as $n)
 207:                 {
 208:                     $_namespace[] = self::getCorrectControllerName($n);
 209:                 }
 210: 
 211:                 $this->_routingNamespaces[implode('\\',$_namespace)] = 1;
 212:             }
 213:         }
 214: 
 215:         public function getActiveRoutingNamespaceDir()
 216:         {
 217:             return str_replace('\\',DIRECTORY_SEPARATOR,$this->_activeRoutingNamespace);
 218:         }
 219: 
 220:         public function getActiveRoutingNamespaceUrlPath()
 221:         {
 222:             return '/'.$this->_activeRoutingNamespaceUrlPath;
 223:         }
 224: 
 225:         public function getActiveRoutingNamespace($useDirectorySeparator=false)
 226:         {
 227:             return $this->_activeRoutingNamespace;
 228:         }
 229: 
 230:         public static function &getInstance(array $settings=null)
 231:         {
 232:              if (empty(self::$_instance))
 233:                  self::$_instance = new \Simpletools\Mvc\Router($settings);
 234:              
 235:              return self::$_instance;
 236:         }
 237:         
 238:         public static function &settings(array $settings)
 239:         {
 240:              if(empty(self::$_instance)) 
 241:                  self::$_instance = new \Simpletools\Mvc\Router($settings);
 242:              
 243:              return self::$_instance;
 244:         }
 245:         
 246:         //depracted - use registerViewObject instead
 247:         public function registerObject($objectName,&$object)
 248:         {
 249:             $this->registerViewObject($objectName,$object);
 250:         }
 251:         
 252:         public function registerViewObject($objectName,&$object)
 253:         {
 254:             $this->_objects[$objectName] = &$object;
 255:             $this->_view->registerObject($objectName,$object);
 256:         }
 257: 
 258:         public static function &run($dir_emulate=false)
 259:         {
 260:              self::getInstance()->dispatch($dir_emulate);
 261:              return self::$_instance;
 262:         }
 263: 
 264:         //controller dispatcher
 265:         public function &dispatch($dir_emulate=false)
 266:         {
 267:             if($this->_routingHooks)
 268:             {
 269:                 \Simpletools\Mvc\RoutingHook::setEnv(array(
 270:                     'routingNamespace'  => $this->_activeRoutingNamespace,
 271:                     'router'            => &$this
 272:                 ));
 273: 
 274:                 \Simpletools\Mvc\RoutingHook::fire('dispatchStart');
 275:             }
 276: 
 277:             /*
 278:              * subdomain usage only
 279:              */
 280:             if(
 281:                 isset($this->_settings['use_subdomain']) && 
 282:                 isset($this->_settings['use_subdomain']['controller']) &&
 283:                 isset($this->_settings['use_subdomain']['action'])
 284:             )
 285:             {
 286:                 $subdomain      = $this->_getSubdomain();
 287:                 if($subdomain)
 288:                 {
 289:                     $old_action         = $this->getParam('action');
 290:                     $old_controller     = $this->getParam('controller');
 291: 
 292:                     $this->setParam('controller',$this->_settings['use_subdomain']['controller']);
 293:                     $this->setParam('action',$this->_settings['use_subdomain']['action']);
 294:                     $this->setParam('subdomain',$subdomain);
 295:                     $this->setParam('old_controller',$old_controller);
 296:                     $this->setParam('old_action',$old_action);
 297:                 }
 298:             }
 299: 
 300:             $param = 2;
 301: 
 302:             if(
 303:                 ($dir_emulate === true) && '/' != substr($_SERVER['REQUEST_URI'],-1) && 
 304:                 ($this->getParam_($param) === null)
 305:             )
 306:             {
 307:                 $this->redirect($_SERVER['REQUEST_URI'],true);
 308:             }
 309:             
 310:             if(!$this->_settings['overrideController'])
 311:                 $this->forwardDispatch($this->getParam('controller'),$this->getParam('action'));
 312:             else
 313:             {
 314:                 if(strtolower($this->_settings['overrideController'])==strtolower($this->getParam('controller')))
 315:                     $this->forwardDispatch($this->_settings['overrideController'],'self.reference');
 316:                 else
 317:                     $this->forwardDispatch($this->_settings['overrideController'],$this->_settings['overrideAction']);
 318:             }
 319:                 
 320:             return $this;
 321:         }
 322:         
 323:         public function disable404OnError()
 324:         {
 325:             $this->_404_error_header = false;
 326:         }
 327:         
 328:         public function enable404OnError()
 329:         {
 330:             $this->_404_error_header = true;
 331:         }
 332:         
 333:         public function error($errorCode='v404')
 334:         {
 335:             $this->_autoRender = true;
 336:             if($this->_404_error_header) header($_SERVER['SERVER_PROTOCOL'].' 404 Not Found'); 
 337:             $this->_errorCode           = $errorCode;
 338:             
 339:             $namespace = $this->_activeRoutingNamespace;
 340:             $path = (!$namespace) ? '' : str_replace('\\',DIRECTORY_SEPARATOR,$namespace).'/';
 341:             $path = $this->_appDir. '/controllers/'.$path.'ErrorController.php';
 342: 
 343:             $className = $namespace.'\ErrorController';
 344: 
 345:             if($namespace && !($_c = realpath($path))) 
 346:             {
 347:                 $namespace = '';
 348:                 $path = $this->_appDir.'/controllers/ErrorController.php';
 349:                 if(!($_c = realpath($path)))
 350:                 {
 351:                     trigger_error("<u>SimpleMVC ERROR</u> - Missing ErrorController.php", E_USER_ERROR);
 352:                 }
 353:                 else
 354:                 {
 355:                     $className = 'ErrorController';
 356:                 }
 357:             }
 358:             elseif(!$namespace)
 359:             {
 360:                 $className  = 'ErrorController';
 361:                 $path       = $this->_appDir.'/controllers/ErrorController.php';
 362: 
 363:                 if(!($_c = realpath($path)))
 364:                 {
 365:                     trigger_error("<u>SimpleMVC ERROR</u> - Missing ErrorController.php", E_USER_ERROR);
 366:                 }
 367:             }
 368:             
 369:             $this->forward('Error','error');
 370:         }
 371:         
 372:         private function &_getEnv()
 373:         {
 374:             $env                        = new \StdClass();
 375:             $env->appDir                = &$this->_appDir;
 376:             $env->view                  = &$this->_view;
 377:             $env->autoRender            = &$this->_autoRender;
 378:             $env->forwarded             = &$this->_forwarded;
 379:             $env->params                = &$this->_params;
 380:             $env->objects               = &$this->_objects;
 381:             $env->errorCode             = &$this->_errorCode;
 382:             $env->shifts_params         = &$this->_shifts_params;
 383:             $env->classes               = &$this->_classes;
 384:             $env->current_controller    = &$this->_current_controller;
 385:             $env->_404_error_header     = &$this->_404_error_header;
 386:             $env->view_enabled          = &$this->_view_enabled;
 387:             $env->_routingHooks         = &$this->_routingHooks;
 388: 
 389:             $env->routingNamespaces             = &$this->_routingNamespaces;
 390:             $env->activeRoutingNamespace        = &$this->_activeRoutingNamespace;
 391:             $env->activeRoutingNamespaceUrlPath = &$this->_activeRoutingNamespaceUrlPath;
 392:             
 393:             return $env;
 394:         }
 395: 
 396:         private function _callReflectionMethod($controller, $methodName, array $args = array()) 
 397:         { 
 398:             $reflection = new \ReflectionMethod($controller, $methodName); 
 399: 
 400:             $pass = array(); 
 401:             foreach($reflection->getParameters() as $param) 
 402:             { 
 403:                 $name = $param->getName();
 404:                 if(isset($args[$name])) 
 405:                 { 
 406:                     $pass[] = $args[$name]; 
 407:                 } 
 408:                 else 
 409:                 { 
 410:                     try
 411:                     {
 412:                         $pass[] = $param->getDefaultValue(); 
 413:                     }
 414:                     catch(\Exception $e)
 415:                     {
 416:                         $pass[] = null;
 417:                     }
 418:                 } 
 419:             }
 420: 
 421:             return $reflection->invokeArgs($controller, $pass); 
 422:         } 
 423:         
 424:         private function forwardDispatch($controller,$action,$params=false)
 425:         {               
 426:             $controller         = self::getCorrectControllerName($controller);
 427:             $action             = self::getCorrectActionName($action);
 428: 
 429:             $namespace          = $this->_activeRoutingNamespace;
 430: 
 431:             $path = (!$namespace) ? $controller.'Controller.php' : str_replace('\\',DIRECTORY_SEPARATOR,$namespace).'/'.$controller.'Controller.php';
 432:             $path = $this->_appDir.'/controllers/'.$path;
 433:             
 434:             if(($_c = realpath($path)))
 435:             {
 436:                 require_once($_c);
 437:                 $className = (!$namespace) ? $controller.'Controller' : $namespace."\\".$controller.'Controller';
 438: 
 439:                 if(class_exists($className))
 440:                 {
 441:                     $this->_current_controller = $controller;
 442: 
 443:                     $this->_classes[$className] = new $className($this->_getEnv());
 444: 
 445:                     if($this->_routingHooks)
 446:                     {
 447:                         \Simpletools\Mvc\RoutingHook::fire('beforeControllerInit',array('controller'=>$controller,'action'=>$action));
 448:                     }
 449: 
 450:                     if(is_callable(array($this->_classes[$className],'init')))
 451:                     {
 452:                         $this->_classes[$className]->init();
 453:                     }
 454: 
 455:                     if($this->_routingHooks)
 456:                     {
 457:                         \Simpletools\Mvc\RoutingHook::fire('afterControllerInit',array('controller'=>$controller,'action'=>$action));
 458:                     }
 459: 
 460:                     if(!$this->_forwarded && $this->_autoRender)
 461:                     {
 462:                         $actionMethod = $action.'Action';
 463:                         $this->_forwarded = true;
 464: 
 465:                         if(is_callable(array($this->_classes[$className],$actionMethod)))
 466:                         {
 467:                             if($this->_routingHooks)
 468:                             {
 469:                                 \Simpletools\Mvc\RoutingHook::fire('beforeControllerAction',array('controller'=>$controller,'action'=>$action));
 470:                             }
 471: 
 472:                             if($this->_activeCustomRouteArgs)
 473:                             {
 474:                                 $this->_callReflectionMethod($this->_classes[$className],$actionMethod,$this->_activeCustomRouteArgs);
 475:                             }
 476:                             else
 477:                             {
 478:                                 $this->_classes[$className]->$actionMethod();
 479:                             }
 480: 
 481:                             if($this->_routingHooks)
 482:                             {
 483:                                 \Simpletools\Mvc\RoutingHook::fire('afterControllerAction',array('controller'=>$controller,'action'=>$action));
 484:                             }
 485:                         }
 486:                         else
 487:                         {
 488:                             if($this->_routingHooks)
 489:                             {
 490:                                 \Simpletools\Mvc\RoutingHook::fire('missingControllerActionError',array('controller'=>$controller,'action'=>$action));
 491:                             }
 492: 
 493:                             if($this->_autoRender) $this->error('a404');
 494:                         }
 495:                     }
 496: 
 497:                 }
 498:                 else
 499:                 {
 500:                     if($this->_routingHooks)
 501:                     {
 502:                         \Simpletools\Mvc\RoutingHook::fire('missingControllerError',array('controller'=>$controller,'action'=>$action));
 503:                     }
 504: 
 505:                     $this->error('c405');
 506:                 }
 507: 
 508:                 if($this->_autoRender)
 509:                 {
 510:                     $this->_render($controller,$action);
 511:                 }
 512:             }
 513:             else
 514:             {
 515:                 if($this->_routingHooks)
 516:                 {
 517:                     \Simpletools\Mvc\RoutingHook::fire('missingControllerError',array('controller'=>$controller,'action'=>$action));
 518:                 }
 519: 
 520:                 $this->error('c404');
 521:             }
 522: 
 523:             if($this->_routingHooks)
 524:             {
 525:                 \Simpletools\Mvc\RoutingHook::fire('dispatchEnd');
 526:             }
 527:         }
 528: 
 529:         public function forward($controller,$action=null,$params=false)
 530:         {
 531:             $this->_autoRender = true;
 532: 
 533:             if($controller == 'error' || $action == 'error') 
 534:                 $this->_errorCode = 'custom error';
 535: 
 536:             $_c = false;
 537: 
 538:             $namespace          = $this->_activeRoutingNamespace;
 539:             $orgController      = $controller;
 540: 
 541:             $n = substr($controller,0,1);
 542:             if($n=='\\' OR $n == '/')
 543:             {
 544:                 $controller         = trim(str_replace('/','\\',$controller),'\\');
 545:                 $_path              = explode('\\',$controller);
 546:                 $controller         = array_pop($_path);
 547:                 $namespace          = implode('\\',$_path);
 548:             }
 549: 
 550:             $className          = (!$namespace) ? $controller.'Controller' : $namespace."\\".$controller.'Controller';
 551: 
 552:             if($namespace && strtolower($controller) == 'error')
 553:             {
 554:                 $path = str_replace('\\',DIRECTORY_SEPARATOR,$namespace).'/'.$controller.'Controller.php';
 555:                 $path = $this->_appDir.'/controllers/'.$path;
 556: 
 557:                 if(
 558:                     !isset($this->_classes[$className]) && 
 559:                     !($_c = realpath($path))
 560:                 )
 561:                 {
 562:                     $namespace          = '';
 563:                     $className          = $controller.'Controller';
 564:                 }
 565:             }
 566: 
 567:             $path = (!$namespace) ? $controller.'Controller.php' : str_replace('\\',DIRECTORY_SEPARATOR,$namespace).'/'.$controller.'Controller.php';
 568:             $path = $this->_appDir.'/controllers/'.$path;
 569:             
 570:             if(
 571:                 isset($this->_classes[$className]) || 
 572:                 ($_c = realpath($path))
 573:             )
 574:             {
 575:                 if(!isset($this->_classes[$className]) && $_c)
 576:                 {
 577:                     require($_c);
 578:                 }
 579: 
 580:                 if(class_exists($className))
 581:                 {   
 582:                     if(!isset($this->_classes[$className]))
 583:                     {
 584:                         $this->_classes[$className] = new $className($this->_getEnv());
 585:                         $this->_forwarded = false;
 586:                     }
 587:                     
 588:                     if(is_callable(array($this->_classes[$className],'init')) && !$this->_forwarded)
 589:                     {
 590:                         if($this->_current_controller != $controller) 
 591:                         {
 592:                             $this->_classes[$className]->init();
 593:                             $this->_current_controller = $controller;
 594:                         }
 595:                         $this->_forwarded = true;
 596:                     }
 597:                     
 598:                     if($this->_autoRender)
 599:                     {
 600:                         $actionMethod = $action.'Action';
 601:                         
 602:                         if(is_callable(array($this->_classes[$className],$actionMethod)))
 603:                         {
 604:                             $this->_classes[$className]->$actionMethod();
 605:                         }
 606:                         elseif($className!='ErrorController') 
 607:                         {
 608:                             return $this->error('a404');
 609:                         }
 610:                         elseif($actionMethod=='errorAction')
 611:                         {
 612:                             throw new \Exception("Missing errorAction() under ErrorController", 1);
 613:                         }
 614:                         else
 615:                         {
 616:                             throw new \Exception("Missing correct error handling structure", 1);
 617:                         }
 618:                     }
 619: 
 620:                     if($this->_autoRender)
 621:                     {
 622:                         $this->_render($orgController,$action);
 623:                     }
 624: 
 625:                 }
 626:                 else
 627:                 {
 628:                     $this->error('c405');
 629:                 }
 630:             }
 631:             else
 632:             {
 633:                 $this->error('c404');
 634:             }
 635:             
 636:         }
 637:                 
 638:         //views rendering function
 639:         public function enableView()
 640:         {
 641:             $this->_view_enabled = true;
 642:         }
 643:         
 644:         public function disableView()
 645:         {
 646:             $this->_view_enabled = false;
 647:         }
 648:         
 649:         protected function _render($controller,$view=null)
 650:         {
 651:             if(!$this->_view_enabled) return;
 652: 
 653:             /**/
 654:             $namespace          = $this->_activeRoutingNamespace;
 655: 
 656:             if($this->_routingHooks)
 657:             {
 658:                 \Simpletools\Mvc\RoutingHook::fire('beforeRenderView',array('controller'=>$controller,'view'=>$view));
 659:             }
 660: 
 661:             $n = substr($controller,0,1);
 662:             if($n=='\\' OR $n == '/')
 663:             {
 664:                 $controller         = trim(str_replace('/','\\',$controller),'\\');
 665:                 $_path              = explode('\\',$controller);
 666:                 $controller         = array_pop($_path);
 667:                 $namespace          = implode('\\',$_path);
 668:             }
 669: 
 670:             if($namespace)
 671:             {
 672:                 $namespacePath      = str_replace('\\', DIRECTORY_SEPARATOR, $namespace)."/";
 673: 
 674:                 if(strtolower($view) == 'error')
 675:                 {
 676:                     $path = $this->_appDir.'/views/'.$namespacePath.$controller.'/'.$view.'.'.$this->_view->getViewExt();
 677:                     
 678:                     if(!realpath($path))
 679:                     {
 680:                         $namespacePath  = '';
 681:                     }
 682:                 }
 683:             }
 684:             else
 685:             {
 686:                 $namespacePath      = '';
 687:             }
 688:             
 689:             $v              = realpath($this->_appDir.'/views/'.$namespacePath.$controller.'/'.$view.'.'.$this->_view->getViewExt());
 690:             
 691:             if($v)
 692:             {
 693:                 $this->_autoRender = false;
 694:                 $this->_view->render($v);
 695: 
 696:                 if($this->_routingHooks)
 697:                 {
 698:                     \Simpletools\Mvc\RoutingHook::fire('afterRenderView',array('controller'=>$controller,'view'=>$view));
 699:                 }
 700:             }
 701:             else
 702:             {
 703:                 if($view != 'error')
 704:                 {
 705:                     if($this->_routingHooks)
 706:                     {
 707:                         \Simpletools\Mvc\RoutingHook::fire('missingViewError',array('controller'=>$controller,'view'=>$view));
 708:                     }
 709: 
 710:                     $this->error('v404');
 711:                 }
 712:                 else
 713:                 {
 714:                     if($this->_routingHooks)
 715:                     {
 716:                         \Simpletools\Mvc\RoutingHook::fire('missingViewError',array('controller'=>$controller,'view'=>$view));
 717:                     }
 718: 
 719:                     trigger_error("<u>SimpleMVC ERROR</u> - There is a missing Error View.", E_USER_ERROR);
 720:                     exit;
 721:                 }
 722:             }
 723:         }
 724: 
 725:         protected function _getSubdomain()
 726:         {
 727:             $domain = $_SERVER['SERVER_NAME'];
 728:             $sub = trim(str_ireplace($this->_settings['use_subdomain']['domain'],'',$domain),'.');
 729: 
 730:             if(strtolower($sub) == 'www' || '')
 731:                 return null;
 732: 
 733:             return $sub;
 734:         }
 735: 
 736:         public function isController($controller)
 737:         {
 738:             $controller         = self::getCorrectControllerName($controller);
 739:             $className          = $controller.'Controller';
 740: 
 741:             return (isset($this->_classes[$className]) || realpath($this->_appDir.'/controllers/'.$controller.'Controller.php'));
 742:         }
 743: 
 744:         public function getParams($fix_duplicate_content=false)
 745:         {
 746:             $_params = array();
 747: 
 748:             //to avoid notice errors if running from command line
 749:             $SERVER_REQUEST_URI = isset($_SERVER['REQUEST_URI']) ? parse_url('http://simpletools.php'.$_SERVER['REQUEST_URI'],PHP_URL_PATH) : null;
 750: 
 751:             if(($p = stripos($SERVER_REQUEST_URI,'#')) !== false)
 752:                 $SERVER_REQUEST_URI = substr($SERVER_REQUEST_URI,0,$p);
 753: 
 754:             $params = explode('/',rtrim(substr($SERVER_REQUEST_URI,1),'/'));
 755: 
 756:             //sanitasation
 757:             foreach($params as $index => $param)
 758:             {
 759:                 //$params[$index] = $param = preg_replace('/[^a-z0-9\-\/\.]/i','',urldecode($param));
 760:                 $params[$index] = $param = filter_var(urldecode($param),FILTER_SANITIZE_STRING,array('flags'=>FILTER_FLAG_STRIP_HIGH));
 761:             }
 762: 
 763:             if(count($this->_routingNamespaces))
 764:             {
 765:                 $params_ = array();
 766:                 foreach($params as $param)
 767:                 {
 768:                     $params_[] = self::getCorrectControllerName($param);
 769:                 }
 770: 
 771:                 $length  = count($params);
 772:                 while($length)
 773:                 {
 774:                     $key = implode('\\',array_slice($params_,0,$length));
 775:                     if(isset($this->_routingNamespaces[$key]))
 776:                     {
 777:                         $this->_activeRoutingNamespace = $key;
 778: 
 779:                         $this->_activeRoutingNamespaceUrlPath = implode('/',array_slice($params,0,$length));
 780:                         $params = array_slice($params,$length);
 781: 
 782:                         break;
 783:                     }
 784: 
 785:                     $length--;
 786:                 }
 787: 
 788:                 unset($params_);
 789:             }
 790:     
 791:             if($this->_settings['uri_app_position'] > 0)
 792:             {
 793:                 for($i=0; $i<$this->_settings['uri_app_position']; $i++)
 794:                 {
 795:                     $this->_shifts_params[] = array_shift($params);
 796:                 }
 797:             }
 798: 
 799:             if($this->_customRoutes)
 800:             {
 801:                 $METHOD = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : 'GET';
 802: 
 803:                 $routes = isset($this->_customRoutes[$METHOD]) ? $this->_customRoutes[$METHOD] : array();
 804:                 $routes = isset($this->_customRoutes['ANY']) ? array_merge($this->_customRoutes['ANY'],$routes) : $routes;
 805: 
 806:                 foreach($routes as $route)
 807:                 {
 808:                     if(preg_match($route['pattern'], $SERVER_REQUEST_URI, $matches))
 809:                     {
 810:                         $invoke = explode('@',$route['invoke']);
 811: 
 812:                         $invoke[0]  = str_replace('Controller','',$invoke[0]);
 813:                         $invoke[1]  = isset($invoke[1]) ? str_replace('Action','',$invoke[1]) : null;
 814: 
 815:                         $controller = implode('-',preg_split('/(?<=\\w)(?=[A-Z])/', $invoke[0]));
 816: 
 817:                         $_params['associative']['controller']   = $controller;
 818:                         $_params['associative']['action']       = isset($invoke[1]) ? $invoke[1] : $this->_settings['defaultAction'];
 819: 
 820:                         array_shift($matches);
 821: 
 822:                         foreach($matches as $i=>$m)
 823:                         {
 824:                             if(!isset($route['map'][$i])) continue;
 825: 
 826:                             $this->_activeCustomRouteArgs[$route['map'][$i]] = $m;
 827:                         }
 828:                         
 829:                         return $_params;
 830:                     }
 831:                 }               
 832:             }
 833: 
 834:             if(count($params))
 835:             {
 836:                 $index = count($params)-1;
 837:                 if(($position = strpos($params[$index],'?')) !== false)
 838:                 {
 839:                     $params[$index] = substr($params[$index],0,$position);
 840:                     if($params[$index] == '') $params[$index] = null;
 841:                 }
 842:                 
 843:                 $controllerKey = 0; $actionKey = 1;
 844:                 
 845:                 $_params['associative']['controller'] = null;
 846:                 $_params['associative']['action'] = null;
 847:                 
 848:                 foreach($params as $key => $val)
 849:                 {
 850:                     $_params['number'][$key] = $val;
 851:                         
 852:                     if($key == $controllerKey)
 853:                     {
 854:                         if($val != null) $_params['associative']['controller'] =  $val;
 855:                     }
 856:                     else if($key == $actionKey)
 857:                     {                   
 858:                         if($val != null) $_params['associative']['action'] =  $val;
 859:                     }
 860:                     else
 861:                     {
 862:                         if(!($key%2))
 863:                         {
 864:                             $prev_key = $val;
 865:                             $_params['associative'][$val] =  '';
 866:                             unset($val);
 867:                             continue;
 868:                         }
 869:                         else
 870:                         {
 871:                             if(isset($prev_key)) $_params['associative'][$prev_key] =  $val;
 872:                         }
 873:                     }
 874:                 }
 875:             }
 876:             
 877:             if($fix_duplicate_content)
 878:                 $this->_fixDuplicateContent($_params,$SERVER_REQUEST_URI);
 879:             
 880:             if(!isset($_params['associative']['action']))
 881:             {
 882:                 $_params['associative']['action'] = $this->_settings['defaultAction'];
 883:             }
 884:             
 885:             if(!isset($_params['associative']['controller']))
 886:             {
 887:                 $_params['associative']['controller'] = $this->_settings['defaultController'];
 888:             }
 889: 
 890:             return $_params;    
 891:         }
 892:         
 893:         private function _fixDuplicateContent($_params,$uri_path)
 894:         {
 895:             $GET = isset($_SERVER['QUERY_STRING']) ? $_SERVER['QUERY_STRING'] : '';
 896:                         
 897:             switch($this->_duplicate_content)
 898:             {
 899:                 //NOSLASH_NOINDEX
 900:                 case 1:
 901:                 {
 902:                     if(
 903:                         (!isset($_params['associative']['action']) && $_params['associative']['controller'] == $this->_settings['defaultController']) OR
 904:                         (count($_params['associative']) == 2 && $_params['associative']['controller'] == $this->_settings['defaultController'] && $_params['associative']['action'] == $this->_settings['defaultAction'])   
 905:                     ){
 906:                         $this->redirect('/',false,false,301,$GET);
 907:                     }
 908:                     else if(count($_params['associative']) == 2 && $_params['associative']['action'] == $this->_settings['defaultAction']) {
 909:                         $this->redirect('/'.$_params['associative']['controller'],false,false,301,$GET);
 910:                     }
 911:                     else if(strlen($uri_path) > 1 && substr($uri_path,-1) == '/'){
 912:                         $this->redirect($_params['associative'],false,false,301,$GET);
 913:                     }
 914:                     
 915:                     break;
 916:                 }
 917:                 
 918:                 //SLASH_NOINDEX
 919:                 case 2:
 920:                 {
 921:                     if(
 922:                         (!isset($_params['associative']['action']) && $_params['associative']['controller'] == $this->_settings['defaultController']) OR
 923:                         (count($_params['associative']) == 2 && $_params['associative']['controller'] == $this->_settings['defaultController'] && $_params['associative']['action'] == $this->_settings['defaultAction'])   
 924:                     ){
 925:                         $this->redirect('/',false,false,301,$GET);
 926:                     }
 927:                     else if(count($_params['associative']) == 2 && $_params['associative']['action'] == $this->_settings['defaultAction']) {
 928:                         $this->redirect('/'.$_params['associative']['controller'].'/',false,false,301,$GET);
 929:                     }
 930:                     else if(strlen($uri_path) > 1 && substr($uri_path,-1) != '/'){
 931:                         $this->redirect($_params['associative'],true,false,301,$GET);
 932:                     }
 933:                     
 934:                     break;
 935:                 }
 936:                 
 937:                 //NOSLASH_INDEX
 938:                 case 3:
 939:                 {
 940:                     if(!isset($_params['associative']['controller'])){
 941:                         $this->redirect('/index/index',false,false,301,$GET);
 942:                     }
 943:                     else if(!isset($_params['associative']['action'])){
 944:                         $this->redirect('/'.$_params['associative']['controller'].'/index',false,false,301,$GET);
 945:                     }
 946:                     else if(strlen($uri_path) > 1 && substr($uri_path,-1) == '/'){
 947:                         $this->redirect($_params['associative'],false,false,301,$GET);
 948:                     }
 949:                     
 950:                     break;
 951:                 }
 952:                 
 953:                 //SLASH_INDEX
 954:                 case 4:
 955:                 {
 956:                     if(!isset($_params['associative']['controller'])){
 957:                         $this->redirect('/index/index/',false,false,301,$GET);
 958:                     }
 959:                     else if(!isset($_params['associative']['action'])){
 960:                         $this->redirect('/'.$_params['associative']['controller'].'/index/',false,false,301,$GET);
 961:                     }
 962:                     else if(strlen($uri_path) > 1 && substr($uri_path,-1) != '/'){
 963:                         $this->redirect($_params['associative'],true,false,301,$GET);
 964:                     }
 965: 
 966:                     break;
 967:                 }
 968:             }
 969:         }
 970: 
 971:         public function setParam($id,$value)
 972:         {
 973:             $this->_params['associative'][$id] = $value;
 974:         }
 975: 
 976:         public function getDisplayedParam($id)
 977:         {
 978:             $params = $this->getParams();
 979:             return isset($params['associative'][$id]) ? (string) $params['associative'][$id] : null;
 980:         }
 981: 
 982:         public function getDisplayedParam_($id)
 983:         {
 984:             $params = $this->getParams();
 985:             return isset($params['number'][$id]) ? (string) $params['number'][$id] : null;
 986:         }
 987: 
 988:         public function url(Array $urls, $slashEnd=false, $https=false, $absolute=false)
 989:         {
 990:             return $this->_view->url($urls, $absolute, $https, $slashEnd);  
 991:         }
 992: 
 993:         public function isError404()
 994:         {
 995:             if($this->_errorCode !== false) return true;
 996:             else return false;
 997:         }
 998: 
 999:         public function setViewProperty($key,$value)
1000:         {
1001:             $this->_view->{$key} = $value;
1002:         }
1003: 
1004:         public function __destruct()
1005:         {
1006:             if($this->_routingHooks)
1007:             {
1008:                 \Simpletools\Mvc\RoutingHook::fire('routerDestruct');
1009:             }
1010:         }
1011:     }
1012: 
1013: ?>
API documentation generated by ApiGen