public function __construct()
 {
     $this->brokenOnConstruct = false;
     // Check necessary to avoid class conflicts before manifest is rebuilt
     if (class_exists('NullHTTPRequest')) {
         $this->setRequest(new NullHTTPRequest());
     }
     // This will prevent bugs if setDataModel() isn't called.
     $this->model = DataModel::inst();
     parent::__construct();
 }
 /**
  * @param string $identifier Unique identifier for this fixture type
  * @param array $data Map of property names to their values.
  * @param array $fixtures Map of fixture names to an associative array of their in-memory
  *                        identifiers mapped to their database IDs. Used to look up
  *                        existing fixtures which might be referenced in the $data attribute
  *                        via the => notation.
  * @return DataObject
  * @throws Exception
  */
 public function createObject($identifier, $data = null, $fixtures = null)
 {
     // We have to disable validation while we import the fixtures, as the order in
     // which they are imported doesnt guarantee valid relations until after the import is complete.
     // Also disable filesystem manipulations
     Config::nest();
     Config::inst()->update('SilverStripe\\ORM\\DataObject', 'validation_enabled', false);
     Config::inst()->update('File', 'update_filesystem', false);
     $this->invokeCallbacks('beforeCreate', array($identifier, &$data, &$fixtures));
     try {
         $class = $this->class;
         $obj = DataModel::inst()->{$class}->newObject();
         // If an ID is explicitly passed, then we'll sort out the initial write straight away
         // This is just in case field setters triggered by the population code in the next block
         // Call $this->write().  (For example, in FileTest)
         if (isset($data['ID'])) {
             $obj->ID = $data['ID'];
             // The database needs to allow inserting values into the foreign key column (ID in our case)
             $conn = DB::get_conn();
             $baseTable = DataObject::getSchema()->baseDataTable($class);
             if (method_exists($conn, 'allowPrimaryKeyEditing')) {
                 $conn->allowPrimaryKeyEditing($baseTable, true);
             }
             $obj->write(false, true);
             if (method_exists($conn, 'allowPrimaryKeyEditing')) {
                 $conn->allowPrimaryKeyEditing($baseTable, false);
             }
         }
         // Populate defaults
         if ($this->defaults) {
             foreach ($this->defaults as $fieldName => $fieldVal) {
                 if (isset($data[$fieldName]) && $data[$fieldName] !== false) {
                     continue;
                 }
                 if (is_callable($fieldVal)) {
                     $obj->{$fieldName} = $fieldVal($obj, $data, $fixtures);
                 } else {
                     $obj->{$fieldName} = $fieldVal;
                 }
             }
         }
         // Populate overrides
         if ($data) {
             foreach ($data as $fieldName => $fieldVal) {
                 // Defer relationship processing
                 if ($obj->manyManyComponent($fieldName) || $obj->hasManyComponent($fieldName) || $obj->hasOneComponent($fieldName)) {
                     continue;
                 }
                 $this->setValue($obj, $fieldName, $fieldVal, $fixtures);
             }
         }
         $obj->write();
         // Save to fixture before relationship processing in case of reflexive relationships
         if (!isset($fixtures[$class])) {
             $fixtures[$class] = array();
         }
         $fixtures[$class][$identifier] = $obj->ID;
         // Populate all relations
         if ($data) {
             foreach ($data as $fieldName => $fieldVal) {
                 if ($obj->manyManyComponent($fieldName) || $obj->hasManyComponent($fieldName)) {
                     $obj->write();
                     $parsedItems = array();
                     if (is_array($fieldVal)) {
                         // handle lists of many_many relations. Each item can
                         // specify the many_many_extraFields against each
                         // related item.
                         foreach ($fieldVal as $relVal) {
                             $item = key($relVal);
                             $id = $this->parseValue($item, $fixtures);
                             $parsedItems[] = $id;
                             array_shift($relVal);
                             $obj->getManyManyComponents($fieldName)->add($id, $relVal);
                         }
                     } else {
                         $items = preg_split('/ *, */', trim($fieldVal));
                         foreach ($items as $item) {
                             // Check for correct format: =><relationname>.<identifier>.
                             // Ignore if the item has already been replaced with a numeric DB identifier
                             if (!is_numeric($item) && !preg_match('/^=>[^\\.]+\\.[^\\.]+/', $item)) {
                                 throw new InvalidArgumentException(sprintf('Invalid format for relation "%s" on class "%s" ("%s")', $fieldName, $class, $item));
                             }
                             $parsedItems[] = $this->parseValue($item, $fixtures);
                         }
                         if ($obj->hasManyComponent($fieldName)) {
                             $obj->getComponents($fieldName)->setByIDList($parsedItems);
                         } elseif ($obj->manyManyComponent($fieldName)) {
                             $obj->getManyManyComponents($fieldName)->setByIDList($parsedItems);
                         }
                     }
                 } else {
                     $hasOneField = preg_replace('/ID$/', '', $fieldName);
                     if ($className = $obj->hasOneComponent($hasOneField)) {
                         $obj->{$hasOneField . 'ID'} = $this->parseValue($fieldVal, $fixtures, $fieldClass);
                         // Inject class for polymorphic relation
                         if ($className === 'SilverStripe\\ORM\\DataObject') {
                             $obj->{$hasOneField . 'Class'} = $fieldClass;
                         }
                     }
                 }
             }
         }
         $obj->write();
         // If LastEdited was set in the fixture, set it here
         if ($data && array_key_exists('LastEdited', $data)) {
             $this->overrideField($obj, 'LastEdited', $data['LastEdited'], $fixtures);
         }
     } catch (Exception $e) {
         Config::unnest();
         throw $e;
     }
     Config::unnest();
     $this->invokeCallbacks('afterCreate', array($obj, $identifier, &$data, &$fixtures));
     return $obj;
 }
 /**
  * Test a URL request, returning a response object. This method is the counterpart of
  * Director::direct() that is used in functional testing. It will execute the URL given, and
  * return the result as an SS_HTTPResponse object.
  *
  * @uses getControllerForURL() The rule-lookup logic is handled by this.
  * @uses Controller::run() Handles the page logic for a Director::direct() call.
  *
  * @param string $url The URL to visit.
  * @param array $postVars The $_POST & $_FILES variables.
  * @param array|Session $session The {@link Session} object representing the current session.
  * By passing the same object to multiple  calls of Director::test(), you can simulate a persisted
  * session.
  * @param string $httpMethod The HTTP method, such as GET or POST.  It will default to POST if
  * postVars is set, GET otherwise. Overwritten by $postVars['_method'] if present.
  * @param string $body The HTTP body.
  * @param array $headers HTTP headers with key-value pairs.
  * @param array|Cookie_Backend $cookies to populate $_COOKIE.
  * @param HTTP_Request $request The {@see HTTP_Request} object generated as a part of this request.
  *
  * @return SS_HTTPResponse
  *
  * @throws SS_HTTPResponse_Exception
  */
 public static function test($url, $postVars = null, $session = array(), $httpMethod = null, $body = null, $headers = array(), $cookies = array(), &$request = null)
 {
     Config::nest();
     Injector::nest();
     // These are needed so that calling Director::test() does not muck with whoever is calling it.
     // Really, it's some inappropriate coupling and should be resolved by making less use of statics.
     $oldReadingMode = Versioned::get_reading_mode();
     $getVars = array();
     if (!$httpMethod) {
         $httpMethod = $postVars || is_array($postVars) ? "POST" : "GET";
     }
     if (!$session) {
         $session = Injector::inst()->create('Session', array());
     }
     $cookieJar = $cookies instanceof Cookie_Backend ? $cookies : Injector::inst()->createWithArgs('Cookie_Backend', array($cookies ?: array()));
     // Back up the current values of the superglobals
     $existingRequestVars = isset($_REQUEST) ? $_REQUEST : array();
     $existingGetVars = isset($_GET) ? $_GET : array();
     $existingPostVars = isset($_POST) ? $_POST : array();
     $existingSessionVars = isset($_SESSION) ? $_SESSION : array();
     $existingCookies = isset($_COOKIE) ? $_COOKIE : array();
     $existingServer = isset($_SERVER) ? $_SERVER : array();
     $existingRequirementsBackend = Requirements::backend();
     Config::inst()->update('Cookie', 'report_errors', false);
     Requirements::set_backend(Injector::inst()->create('Requirements_Backend'));
     // Set callback to invoke prior to return
     $onCleanup = function () use($existingRequestVars, $existingGetVars, $existingPostVars, $existingSessionVars, $existingCookies, $existingServer, $existingRequirementsBackend, $oldReadingMode) {
         // Restore the super globals
         $_REQUEST = $existingRequestVars;
         $_GET = $existingGetVars;
         $_POST = $existingPostVars;
         $_SESSION = $existingSessionVars;
         $_COOKIE = $existingCookies;
         $_SERVER = $existingServer;
         Requirements::set_backend($existingRequirementsBackend);
         // These are needed so that calling Director::test() does not muck with whoever is calling it.
         // Really, it's some inappropriate coupling and should be resolved by making less use of statics
         Versioned::set_reading_mode($oldReadingMode);
         Injector::unnest();
         // Restore old CookieJar, etc
         Config::unnest();
     };
     if (strpos($url, '#') !== false) {
         $url = substr($url, 0, strpos($url, '#'));
     }
     // Handle absolute URLs
     if (parse_url($url, PHP_URL_HOST)) {
         $bits = parse_url($url);
         // If a port is mentioned in the absolute URL, be sure to add that into the HTTP host
         if (isset($bits['port'])) {
             $_SERVER['HTTP_HOST'] = $bits['host'] . ':' . $bits['port'];
         } else {
             $_SERVER['HTTP_HOST'] = $bits['host'];
         }
     }
     // Ensure URL is properly made relative.
     // Example: url passed is "/ss31/my-page" (prefixed with BASE_URL), this should be changed to "my-page"
     $url = self::makeRelative($url);
     $urlWithQuerystring = $url;
     if (strpos($url, '?') !== false) {
         list($url, $getVarsEncoded) = explode('?', $url, 2);
         parse_str($getVarsEncoded, $getVars);
     }
     // Replace the super globals with appropriate test values
     $_REQUEST = ArrayLib::array_merge_recursive((array) $getVars, (array) $postVars);
     $_GET = (array) $getVars;
     $_POST = (array) $postVars;
     $_SESSION = $session ? $session->inst_getAll() : array();
     $_COOKIE = $cookieJar->getAll(false);
     Injector::inst()->registerService($cookieJar, 'Cookie_Backend');
     $_SERVER['REQUEST_URI'] = Director::baseURL() . $urlWithQuerystring;
     $request = new SS_HTTPRequest($httpMethod, $url, $getVars, $postVars, $body);
     if ($headers) {
         foreach ($headers as $k => $v) {
             $request->addHeader($k, $v);
         }
     }
     // Pre-request filtering
     // @see issue #2517
     $model = DataModel::inst();
     $output = Injector::inst()->get('RequestProcessor')->preRequest($request, $session, $model);
     if ($output === false) {
         $onCleanup();
         throw new SS_HTTPResponse_Exception(_t('Director.INVALID_REQUEST', 'Invalid request'), 400);
     }
     // TODO: Pass in the DataModel
     $result = Director::handleRequest($request, $session, $model);
     // Ensure that the result is an SS_HTTPResponse object
     if (is_string($result)) {
         if (substr($result, 0, 9) == 'redirect:') {
             $response = new SS_HTTPResponse();
             $response->redirect(substr($result, 9));
             $result = $response;
         } else {
             $result = new SS_HTTPResponse($result);
         }
     }
     $output = Injector::inst()->get('RequestProcessor')->postRequest($request, $result, $model);
     if ($output === false) {
         $onCleanup();
         throw new SS_HTTPResponse_Exception("Invalid response");
     }
     // Return valid response
     $onCleanup();
     return $result;
 }
示例#4
0
        return $reloadToken->reloadWithToken();
    }
    // Fail and redirect the user to the login page
    $loginPage = Director::absoluteURL(Security::config()->login_url);
    $loginPage .= "?BackURL=" . urlencode($_SERVER['REQUEST_URI']);
    header('location: ' . $loginPage, true, 302);
    die;
})->thenIfErrored(function () use($reloadToken) {
    if ($reloadToken) {
        $reloadToken->reloadWithToken();
    }
})->execute();
global $databaseConfig;
// Redirect to the installer if no database is selected
if (!isset($databaseConfig) || !isset($databaseConfig['database']) || !$databaseConfig['database']) {
    if (!file_exists(BASE_PATH . '/install.php')) {
        header($_SERVER['SERVER_PROTOCOL'] . " 500 Server Error");
        die('SilverStripe Framework requires a $databaseConfig defined.');
    }
    $s = isset($_SERVER['SSL']) || isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off' ? 's' : '';
    $installURL = "http{$s}://" . $_SERVER['HTTP_HOST'] . BASE_URL . '/install.php';
    // The above dirname() will equate to "\" on Windows when installing directly from http://localhost (not using
    // a sub-directory), this really messes things up in some browsers. Let's get rid of the backslashes
    $installURL = str_replace('\\', '', $installURL);
    header("Location: {$installURL}");
    die;
}
// Direct away - this is the "main" function, that hands control to the appropriate controller
DataModel::set_inst(new DataModel());
Director::direct($url, DataModel::inst());
 /**
  * Return all objects matching the filter
  * sub-classes are automatically selected and included
  *
  * @param string $callerClass The class of objects to be returned
  * @param string|array $filter A filter to be inserted into the WHERE clause.
  * Supports parameterised queries. See SQLSelect::addWhere() for syntax examples.
  * @param string|array $sort A sort expression to be inserted into the ORDER
  * BY clause.  If omitted, self::$default_sort will be used.
  * @param string $join Deprecated 3.0 Join clause. Use leftJoin($table, $joinClause) instead.
  * @param string|array $limit A limit expression to be inserted into the LIMIT clause.
  * @param string $containerClass The container class to return the results in.
  *
  * @todo $containerClass is Ignored, why?
  *
  * @return DataList The objects matching the filter, in the class specified by $containerClass
  */
 public static function get($callerClass = null, $filter = "", $sort = "", $join = "", $limit = null, $containerClass = DataList::class)
 {
     if ($callerClass == null) {
         $callerClass = get_called_class();
         if ($callerClass == self::class) {
             throw new \InvalidArgumentException('Call <classname>::get() instead of DataObject::get()');
         }
         if ($filter || $sort || $join || $limit || $containerClass != DataList::class) {
             throw new \InvalidArgumentException('If calling <classname>::get() then you shouldn\'t pass any other' . ' arguments');
         }
         $result = DataList::create(get_called_class());
         $result->setDataModel(DataModel::inst());
         return $result;
     }
     if ($join) {
         throw new \InvalidArgumentException('The $join argument has been removed. Use leftJoin($table, $joinClause) instead.');
     }
     $result = DataList::create($callerClass)->where($filter)->sort($sort);
     if ($limit && strpos($limit, ',') !== false) {
         $limitArguments = explode(',', $limit);
         $result = $result->limit($limitArguments[1], $limitArguments[0]);
     } elseif ($limit) {
         $result = $result->limit($limit);
     }
     $result->setDataModel(DataModel::inst());
     return $result;
 }
 public function setUp()
 {
     //nest config and injector for each test so they are effectively sandboxed per test
     Config::nest();
     Injector::nest();
     $this->originalReadingMode = Versioned::get_reading_mode();
     // We cannot run the tests on this abstract class.
     if (get_class($this) == __CLASS__) {
         $this->markTestSkipped(sprintf('Skipping %s ', get_class($this)));
         return;
     }
     // Mark test as being run
     $this->originalIsRunningTest = self::$is_running_test;
     self::$is_running_test = true;
     // i18n needs to be set to the defaults or tests fail
     i18n::set_locale(i18n::config()->get('default_locale'));
     i18n::config()->date_format = null;
     i18n::config()->time_format = null;
     // Set default timezone consistently to avoid NZ-specific dependencies
     date_default_timezone_set('UTC');
     // Remove password validation
     $this->originalMemberPasswordValidator = Member::password_validator();
     $this->originalRequirements = Requirements::backend();
     Member::set_password_validator(null);
     Cookie::config()->update('report_errors', false);
     if (class_exists('SilverStripe\\CMS\\Controllers\\RootURLController')) {
         RootURLController::reset();
     }
     if (class_exists('Translatable')) {
         Translatable::reset();
     }
     Versioned::reset();
     DataObject::reset();
     if (class_exists('SilverStripe\\CMS\\Model\\SiteTree')) {
         SiteTree::reset();
     }
     Hierarchy::reset();
     if (Controller::has_curr()) {
         Controller::curr()->setSession(Session::create(array()));
     }
     Security::$database_is_ready = null;
     // Add controller-name auto-routing
     // @todo Fix to work with namespaced controllers
     Director::config()->update('rules', array('$Controller//$Action/$ID/$OtherID' => '*'));
     $fixtureFiles = $this->getFixturePaths();
     // Todo: this could be a special test model
     $this->model = DataModel::inst();
     // Set up fixture
     if ($fixtureFiles || $this->usesDatabase) {
         if (!self::using_temp_db()) {
             self::create_temp_db();
         }
         DataObject::singleton()->flushCache();
         self::empty_temp_db();
         foreach ($this->requireDefaultRecordsFrom as $className) {
             $instance = singleton($className);
             if (method_exists($instance, 'requireDefaultRecords')) {
                 $instance->requireDefaultRecords();
             }
             if (method_exists($instance, 'augmentDefaultRecords')) {
                 $instance->augmentDefaultRecords();
             }
         }
         foreach ($fixtureFiles as $fixtureFilePath) {
             $fixture = YamlFixture::create($fixtureFilePath);
             $fixture->writeInto($this->getFixtureFactory());
         }
         $this->logInWithPermission("ADMIN");
     }
     // Preserve memory settings
     $this->originalMemoryLimit = ini_get('memory_limit');
     // turn off template debugging
     SSViewer::config()->update('source_file_comments', false);
     // Clear requirements
     Requirements::clear();
     // Set up email
     $this->mailer = new TestMailer();
     Injector::inst()->registerService($this->mailer, 'SilverStripe\\Control\\Email\\Mailer');
     Email::config()->remove('send_all_emails_to');
 }
 public function setUp()
 {
     //nest config and injector for each test so they are effectively sandboxed per test
     Config::nest();
     Injector::nest();
     $this->originalReadingMode = Versioned::get_reading_mode();
     // We cannot run the tests on this abstract class.
     if (get_class($this) == "SapphireTest") {
         $this->markTestSkipped(sprintf('Skipping %s ', get_class($this)));
         return;
     }
     // Mark test as being run
     $this->originalIsRunningTest = self::$is_running_test;
     self::$is_running_test = true;
     // i18n needs to be set to the defaults or tests fail
     i18n::set_locale(Config::inst()->get('i18n', 'default_locale'));
     i18n::config()->date_format = null;
     i18n::config()->time_format = null;
     // Set default timezone consistently to avoid NZ-specific dependencies
     date_default_timezone_set('UTC');
     // Remove password validation
     $this->originalMemberPasswordValidator = Member::password_validator();
     $this->originalRequirements = Requirements::backend();
     Member::set_password_validator(null);
     Config::inst()->update('Cookie', 'report_errors', false);
     if (class_exists('SilverStripe\\CMS\\Controllers\\RootURLController')) {
         RootURLController::reset();
     }
     if (class_exists('Translatable')) {
         Translatable::reset();
     }
     Versioned::reset();
     DataObject::reset();
     if (class_exists('SilverStripe\\CMS\\Model\\SiteTree')) {
         SiteTree::reset();
     }
     Hierarchy::reset();
     if (Controller::has_curr()) {
         Controller::curr()->setSession(Injector::inst()->create('Session', array()));
     }
     Security::$database_is_ready = null;
     // Add controller-name auto-routing
     Config::inst()->update('Director', 'rules', array('$Controller//$Action/$ID/$OtherID' => '*'));
     $fixtureFile = static::get_fixture_file();
     $prefix = defined('SS_DATABASE_PREFIX') ? SS_DATABASE_PREFIX : 'ss_';
     // Todo: this could be a special test model
     $this->model = DataModel::inst();
     // Set up fixture
     if ($fixtureFile || $this->usesDatabase) {
         if (!self::using_temp_db()) {
             self::create_temp_db();
         }
         singleton('SilverStripe\\ORM\\DataObject')->flushCache();
         self::empty_temp_db();
         foreach ($this->requireDefaultRecordsFrom as $className) {
             $instance = singleton($className);
             if (method_exists($instance, 'requireDefaultRecords')) {
                 $instance->requireDefaultRecords();
             }
             if (method_exists($instance, 'augmentDefaultRecords')) {
                 $instance->augmentDefaultRecords();
             }
         }
         if ($fixtureFile) {
             $pathForClass = $this->getCurrentAbsolutePath();
             $fixtureFiles = is_array($fixtureFile) ? $fixtureFile : array($fixtureFile);
             $i = 0;
             foreach ($fixtureFiles as $fixtureFilePath) {
                 // Support fixture paths relative to the test class, rather than relative to webroot
                 // String checking is faster than file_exists() calls.
                 $isRelativeToFile = strpos('/', $fixtureFilePath) === false || preg_match('/^\\.\\./', $fixtureFilePath);
                 if ($isRelativeToFile) {
                     $resolvedPath = realpath($pathForClass . '/' . $fixtureFilePath);
                     if ($resolvedPath) {
                         $fixtureFilePath = $resolvedPath;
                     }
                 }
                 $fixture = Injector::inst()->create('YamlFixture', $fixtureFilePath);
                 $fixture->writeInto($this->getFixtureFactory());
                 $this->fixtures[] = $fixture;
                 // backwards compatibility: Load first fixture into $this->fixture
                 if ($i == 0) {
                     $this->fixture = $fixture;
                 }
                 $i++;
             }
         }
         $this->logInWithPermission("ADMIN");
     }
     // Preserve memory settings
     $this->originalMemoryLimit = ini_get('memory_limit');
     // turn off template debugging
     Config::inst()->update('SSViewer', 'source_file_comments', false);
     // Clear requirements
     Requirements::clear();
     // Set up email
     $this->originalMailer = Email::mailer();
     $this->mailer = new TestMailer();
     Injector::inst()->registerService($this->mailer, 'Mailer');
     Config::inst()->remove('Email', 'send_all_emails_to');
 }
 /**
  * This allows templates to create a new `DataList` from a known
  * DataObject class name, and call methods such as aggregates.
  *
  * The common use case is for partial caching:
  * <code>
  *    <% cached List(Member).max(LastEdited) %>
  *        loop members here
  *    <% end_cached %>
  * </code>
  *
  * @param string $className
  * @return DataList
  */
 public static function getDataList($className)
 {
     $list = new DataList($className);
     $list->setDataModel(DataModel::inst());
     return $list;
 }
 function testFieldMessageEscapeHtml()
 {
     $form = $this->getStubForm();
     $form->getController()->handleRequest(new HTTPRequest('GET', '/'), DataModel::inst());
     // stub out request
     $form->addErrorMessage('key1', '<em>Escaped HTML</em>', 'good', true);
     $form->setupFormErrors();
     $parser = new CSSContentParser($result = $form->forTemplate());
     $messageEls = $parser->getBySelector('#Form_Form_key1_Holder .message');
     $this->assertContains('&lt;em&gt;Escaped HTML&lt;/em&gt;', $messageEls[0]->asXML());
     $form = $this->getStubForm();
     $form->getController()->handleRequest(new HTTPRequest('GET', '/'), DataModel::inst());
     // stub out request
     $form->addErrorMessage('key1', '<em>Unescaped HTML</em>', 'good', false);
     $form->setupFormErrors();
     $parser = new CSSContentParser($form->forTemplate());
     $messageEls = $parser->getBySelector('#Form_Form_key1_Holder .message');
     $this->assertContains('<em>Unescaped HTML</em>', $messageEls[0]->asXML());
 }
 /**
  *
  * @param GridField $gridField
  * @param HTTPRequest $request
  * @return GridFieldDetailForm_ItemRequest
  */
 public function handleItem($gridField, $request)
 {
     // Our getController could either give us a true Controller, if this is the top-level GridField.
     // It could also give us a RequestHandler in the form of GridFieldDetailForm_ItemRequest if this is a
     // nested GridField.
     $requestHandler = $gridField->getForm()->getController();
     /** @var DataObject $record */
     if (is_numeric($request->param('ID'))) {
         $record = $gridField->getList()->byID($request->param("ID"));
     } else {
         $record = Object::create($gridField->getModelClass());
     }
     $handler = $this->getItemRequestHandler($gridField, $record, $requestHandler);
     // if no validator has been set on the GridField and the record has a
     // CMS validator, use that.
     if (!$this->getValidator() && (method_exists($record, 'getCMSValidator') || $record instanceof Object && $record->hasMethod('getCMSValidator'))) {
         $this->setValidator($record->getCMSValidator());
     }
     return $handler->handleRequest($request, DataModel::inst());
 }
 public function testSubActions()
 {
     /* If a controller action returns another controller, ensure that the $action variable is correctly forwarded */
     $response = $this->get("ControllerTest_ContainerController/subcontroller/subaction");
     $this->assertEquals('subaction', $response->getBody());
     $request = new SS_HTTPRequest('GET', 'ControllerTest_ContainerController/subcontroller/substring/subvieweraction');
     /* Shift to emulate the director selecting the controller */
     $request->shift();
     /* Handle the request to create conditions where improperly passing the action to the viewer might fail */
     $controller = new ControllerTest_ContainerController();
     try {
         $controller->handleRequest($request, DataModel::inst());
     } catch (ControllerTest_SubController_Exception $e) {
         $this->fail($e->getMessage());
     }
 }
 public function __construct()
 {
     $this->brokenOnConstruct = false;
     $this->setRequest(new NullHTTPRequest());
     // This will prevent bugs if setDataModel() isn't called.
     $this->model = DataModel::inst();
     parent::__construct();
 }