/** * Analyzes the supplied query string and decides how to dispatch the request. */ public function Dispatch($ImportRequest = NULL, $Permanent = TRUE) { if ($ImportRequest && is_string($ImportRequest)) { $ImportRequest = Gdn_Request::Create()->FromEnvironment()->WithURI($ImportRequest); } if (is_a($ImportRequest, 'Gdn_Request') && $Permanent) { Gdn::Request($ImportRequest); } $Request = is_a($ImportRequest, 'Gdn_Request') ? $ImportRequest : Gdn::Request(); if (Gdn::Session()->NewVisit()) { Gdn::UserModel()->FireEvent('Visit'); } // Move this up to allow pre-routing $this->FireEvent('BeforeDispatch'); // By default, all requests can be blocked by UpdateMode/PrivateCommunity $CanBlock = self::BLOCK_ANY; try { $BlockExceptions = array('/^utility(\\/.*)?$/' => self::BLOCK_NEVER, '/^plugin(\\/.*)?$/' => self::BLOCK_NEVER, '/^sso(\\/.*)?$/' => self::BLOCK_NEVER, '/^discussions\\/getcommentcounts/' => self::BLOCK_NEVER, '/^entry(\\/.*)?$/' => self::BLOCK_PERMISSION, '/^user\\/usernameavailable(\\/.*)?$/' => self::BLOCK_PERMISSION, '/^user\\/emailavailable(\\/.*)?$/' => self::BLOCK_PERMISSION, '/^home\\/termsofservice(\\/.*)?$/' => self::BLOCK_PERMISSION); $this->EventArguments['BlockExceptions'] =& $BlockExceptions; $this->FireEvent('BeforeBlockDetect'); $PathRequest = Gdn::Request()->Path(); foreach ($BlockExceptions as $BlockException => $BlockLevel) { if (preg_match($BlockException, $PathRequest)) { throw new Exception("Block detected - {$BlockException}", $BlockLevel); } } // Never block an admin if (Gdn::Session()->CheckPermission('Garden.Settings.Manage')) { throw new Exception("Block detected", self::BLOCK_NEVER); } if (Gdn::Session()->IsValid()) { throw new Exception("Block detected", self::BLOCK_PERMISSION); } } catch (Exception $e) { // BlockLevel // TRUE = Block any time // FALSE = Absolutely no blocking // NULL = Block for permissions (e.g. PrivateCommunity) $CanBlock = $e->getCode(); } // If we're in updatemode and arent explicitly prevented from blocking, block if (Gdn::Config('Garden.UpdateMode', FALSE) && $CanBlock > self::BLOCK_NEVER) { $Request->WithURI(Gdn::Router()->GetDestination('UpdateMode')); } // Analze the request AFTER checking for update mode. $this->AnalyzeRequest($Request); $this->FireEvent('AfterAnalyzeRequest'); // If we're in updatemode and can block, redirect to signin if (C('Garden.PrivateCommunity') && $CanBlock > self::BLOCK_PERMISSION) { Redirect('/entry/signin?Target=' . urlencode($this->Request)); exit; } $ControllerName = $this->ControllerName(); if ($ControllerName != '' && class_exists($ControllerName)) { // Create it and call the appropriate method/action $Controller = new $ControllerName(); Gdn::Controller($Controller); $this->EventArguments['Controller'] =& $Controller; $this->FireEvent('AfterControllerCreate'); // Pass along any assets if (is_array($this->_AssetCollection)) { foreach ($this->_AssetCollection as $AssetName => $Assets) { foreach ($Assets as $Asset) { $Controller->AddAsset($AssetName, $Asset); } } } // Instantiate Imported & Uses classes $Controller->GetImports(); // Pass in the syndication method $Controller->SyndicationMethod = $this->_SyndicationMethod; // Pass along the request $Controller->SelfUrl = $this->Request; // Pass along any objects foreach ($this->_PropertyCollection as $Name => $Mixed) { $Controller->{$Name} = $Mixed; } // Pass along any data. if (is_array($this->_Data)) { $Controller->Data = $this->_Data; } // Set up a default controller method in case one isn't defined. $ControllerMethod = str_replace('_', '', $this->ControllerMethod); $Controller->OriginalRequestMethod = $ControllerMethod; // Take enabled plugins into account, as well $PluginReplacement = Gdn::PluginManager()->HasNewMethod($this->ControllerName(), $this->ControllerMethod); if (!$PluginReplacement && ($this->ControllerMethod == '' || !method_exists($Controller, $ControllerMethod))) { // Check to see if there is an 'x' version of the method. if (method_exists($Controller, 'x' . $ControllerMethod)) { // $PluginManagerHasReplacementMethod = TRUE; $ControllerMethod = 'x' . $ControllerMethod; } else { if ($this->ControllerMethod != '') { array_unshift($this->_ControllerMethodArgs, $this->ControllerMethod); } $this->ControllerMethod = 'Index'; $ControllerMethod = 'Index'; $PluginReplacement = Gdn::PluginManager()->HasNewMethod($this->ControllerName(), $this->ControllerMethod); } } // Pass in the querystring values $Controller->ApplicationFolder = $this->_ApplicationFolder; $Controller->Application = $this->EnabledApplication(); $Controller->ControllerFolder = $this->ControllerFolder; $Controller->RequestMethod = $this->ControllerMethod; $Controller->RequestArgs = $this->_ControllerMethodArgs; $Controller->Request = $Request; $Controller->DeliveryType($Request->GetValue('DeliveryType', $this->_DeliveryType)); $Controller->DeliveryMethod($Request->GetValue('DeliveryMethod', $this->_DeliveryMethod)); // Set special controller method options for REST APIs. $Controller->Initialize(); $this->EventArguments['Controller'] =& $Controller; $this->FireEvent('AfterControllerInit'); // Call the requested method on the controller - error out if not defined. if ($PluginReplacement) { // Set the application folder to the plugin's key. // $PluginInfo = Gdn::PluginManager()->GetPluginInfo($PluginReplacement, Gdn_PluginManager::ACCESS_CLASSNAME); // if ($PluginInfo) { // $Controller->ApplicationFolder = 'plugins/'.GetValue('Index', $PluginInfo); // } // Reflect the args for the method. $Callback = Gdn::PluginManager()->GetCallback($Controller->ControllerName, $ControllerMethod); // Augment the arguments to the plugin with the sender and these arguments. $InputArgs = array_merge(array($Controller), $this->_ControllerMethodArgs, array('Sender' => $Controller, 'Args' => $this->_ControllerMethodArgs)); // decho(array_keys($InputArgs), 'InputArgs'); $Args = ReflectArgs($Callback, $InputArgs, $Request->Get()); $Controller->ReflectArgs = $Args; try { $this->FireEvent('BeforeControllerMethod'); Gdn::PluginManager()->CallEventHandlers($Controller, $Controller->ControllerName, $ControllerMethod, 'Before'); call_user_func_array($Callback, $Args); } catch (Exception $Ex) { $Controller->RenderException($Ex); } } elseif (method_exists($Controller, $ControllerMethod)) { $Args = ReflectArgs(array($Controller, $ControllerMethod), $this->_ControllerMethodArgs, $Request->Get()); $this->_ControllerMethodArgs = $Args; $Controller->ReflectArgs = $Args; try { $this->FireEvent('BeforeControllerMethod'); Gdn::PluginManager()->CallEventHandlers($Controller, $Controller->ControllerName, $ControllerMethod, 'Before'); call_user_func_array(array($Controller, $ControllerMethod), $Args); } catch (Exception $Ex) { $Controller->RenderException($Ex); exit; } } else { $this->EventArguments['Handled'] = FALSE; $Handled =& $this->EventArguments['Handled']; $this->FireEvent('NotFound'); if (!$Handled) { Gdn::Request()->WithRoute('Default404'); return $this->Dispatch(); } else { return $Handled; } } } }
/** * Call a method on the given model. */ public function Model() { $this->Permission('Garden.Settings.Manage'); $this->DeliveryMethod(DELIVERY_METHOD_JSON); $this->DeliveryType(DELIVERY_TYPE_DATA); $Args = func_get_args(); // Check to see if we have a model. $ModelName = StringEndsWith(array_shift($Args), 'Model', TRUE, TRUE); $ModelName = ucfirst($ModelName) . 'Model'; if (!class_exists($ModelName)) { throw NotFoundException($ModelName); } // Check for json/xml style extension. if (count($Args)) { $LastArg = $Args[count($Args) - 1]; $Extension = strrchr($LastArg, '.'); if ($Extension) { $Args[count($Args) - 1] = substr($LastArg, 0, -strlen($Extension)); $Extension = strtolower($Extension); if ($Extension == '.xml') { $this->DeliveryMethod(DELIVERY_METHOD_XML); } } } // Instantiate the model. $Model = new $ModelName(); $MethodName = array_shift($Args); // Reflect the arguments. $Callback = array($Model, $MethodName); if ($this->Request->Get('help')) { $this->SetData('Model', get_class($Model)); if ($MethodName) { if (!method_exists($Model, $MethodName)) { throw NotFoundException($ModelName . '->' . $MethodName . '()'); } $this->SetData('Method', $MethodName); $Meth = new ReflectionMethod($Callback[0], $Callback[1]); $MethArgs = $Meth->getParameters(); $Args = array(); foreach ($MethArgs as $Index => $MethArg) { $ParamName = $MethArg->getName(); if ($MethArg->isDefaultValueAvailable()) { $Args[$ParamName] = $MethArg->getDefaultValue(); } else { $Args[$ParamName] = 'REQUIRED'; } } $this->SetData('Args', $Args); } else { $Class = new ReflectionClass($Model); $Meths = $Class->getMethods(); $Methods = array(); foreach ($Meths as $Meth) { $MethodName = $Meth->getName(); if (StringBeginsWith($MethodName, '_')) { continue; } $MethArgs = $Meth->getParameters(); $Args = array(); foreach ($MethArgs as $Index => $MethArg) { $ParamName = $MethArg->getName(); if ($MethArg->isDefaultValueAvailable()) { $Args[$ParamName] = $MethArg->getDefaultValue(); } else { $Args[$ParamName] = 'REQUIRED'; } } $Methods[$MethodName] = array('Method' => $MethodName, 'Args' => $Args); } $this->SetData('Methods', $Methods); } } else { if (!method_exists($Model, $MethodName)) { throw NotFoundException($ModelName . '->' . $MethodName . '()'); } $MethodArgs = ReflectArgs($Callback, $this->Request->Get(), $Args); $Result = call_user_func_array($Callback, $MethodArgs); if (is_array($Result)) { $this->Data = $Result; } elseif (is_a($Result, 'Gdn_DataSet')) { $Result = $Result->ResultArray(); $this->Data = $Result; } elseif (is_a($Result, 'stdClass')) { $this->Data = (array) $Result; } else { $this->SetData('Result', $Result); } } $this->Render(); }