/**
  * Perform migration
  *
  * @param string $base Absolute base path (parent of assets folder). Will default to BASE_PATH
  * @return int Number of files successfully migrated
  */
 public function run($base = null)
 {
     if (empty($base)) {
         $base = BASE_PATH;
     }
     // Check if the File dataobject has a "Filename" field.
     // If not, cannot migrate
     /** @skipUpgrade */
     if (!DB::get_schema()->hasField('File', 'Filename')) {
         return 0;
     }
     // Set max time and memory limit
     increase_time_limit_to();
     increase_memory_limit_to();
     // Loop over all files
     $count = 0;
     $originalState = Versioned::get_reading_mode();
     Versioned::set_stage(Versioned::DRAFT);
     $filenameMap = $this->getFilenameArray();
     foreach ($this->getFileQuery() as $file) {
         // Get the name of the file to import
         $filename = $filenameMap[$file->ID];
         $success = $this->migrateFile($base, $file, $filename);
         if ($success) {
             $count++;
         }
     }
     Versioned::set_reading_mode($originalState);
     return $count;
 }
 public function tearDown()
 {
     AssetStoreTest_SpyStore::reset();
     if ($this->oldReadingMode) {
         Versioned::set_reading_mode($this->oldReadingMode);
     }
     parent::tearDown();
 }
 /**
  * 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;
 }
 public function tearDown()
 {
     // Preserve memory settings
     ini_set('memory_limit', $this->originalMemoryLimit ? $this->originalMemoryLimit : -1);
     // Restore email configuration
     $this->originalMailer = null;
     $this->mailer = null;
     // Restore password validation
     if ($this->originalMemberPasswordValidator) {
         Member::set_password_validator($this->originalMemberPasswordValidator);
     }
     // Restore requirements
     if ($this->originalRequirements) {
         Requirements::set_backend($this->originalRequirements);
     }
     // Mark test as no longer being run - we use originalIsRunningTest to allow for nested SapphireTest calls
     self::$is_running_test = $this->originalIsRunningTest;
     $this->originalIsRunningTest = null;
     // Reset mocked datetime
     DBDatetime::clear_mock_now();
     // Stop the redirection that might have been requested in the test.
     // Note: Ideally a clean Controller should be created for each test.
     // Now all tests executed in a batch share the same controller.
     $controller = Controller::has_curr() ? Controller::curr() : null;
     if ($controller && $controller->response && $controller->response->getHeader('Location')) {
         $controller->response->setStatusCode(200);
         $controller->response->removeHeader('Location');
     }
     Versioned::set_reading_mode($this->originalReadingMode);
     //unnest injector / config now that tests are over
     Injector::unnest();
     Config::unnest();
 }
 /**
  * Test that publishing processes respects lazy loaded fields
  */
 public function testLazyLoadFields()
 {
     $originalMode = Versioned::get_reading_mode();
     // Generate staging record and retrieve it from stage in live mode
     Versioned::set_stage(Versioned::DRAFT);
     $obj = new VersionedTest_Subclass();
     $obj->Name = 'bob';
     $obj->ExtraField = 'Field Value';
     $obj->write();
     $objID = $obj->ID;
     $filter = sprintf('"VersionedTest_DataObject"."ID" = \'%d\'', Convert::raw2sql($objID));
     Versioned::set_stage(Versioned::LIVE);
     // Check fields are unloaded prior to access
     $objLazy = Versioned::get_one_by_stage('VersionedTest_DataObject', 'Stage', $filter, false);
     $lazyFields = $objLazy->getQueriedDatabaseFields();
     $this->assertTrue(isset($lazyFields['ExtraField_Lazy']));
     $this->assertEquals('VersionedTest_Subclass', $lazyFields['ExtraField_Lazy']);
     // Check lazy loading works when viewing a Stage object in Live mode
     $this->assertEquals('Field Value', $objLazy->ExtraField);
     // Test that writeToStage respects lazy loaded fields
     $objLazy = Versioned::get_one_by_stage('VersionedTest_DataObject', 'Stage', $filter, false);
     $objLazy->writeToStage('Live');
     $objLive = Versioned::get_one_by_stage('VersionedTest_DataObject', 'Live', $filter, false);
     $liveLazyFields = $objLive->getQueriedDatabaseFields();
     // Check fields are unloaded prior to access
     $this->assertTrue(isset($liveLazyFields['ExtraField_Lazy']));
     $this->assertEquals('VersionedTest_Subclass', $liveLazyFields['ExtraField_Lazy']);
     // Check that live record has original value
     $this->assertEquals('Field Value', $objLive->ExtraField);
     Versioned::set_reading_mode($originalMode);
 }
 /**
  * Write the given record to the draft stage
  *
  * @param string $stage
  * @param boolean $forceInsert
  * @return int The ID of the record
  */
 public function writeToStage($stage, $forceInsert = false)
 {
     $oldMode = Versioned::get_reading_mode();
     Versioned::set_stage($stage);
     $owner = $this->owner;
     $owner->forceChange();
     $result = $owner->write(false, $forceInsert);
     Versioned::set_reading_mode($oldMode);
     return $result;
 }
 public function testVersionedCache()
 {
     $origReadingMode = Versioned::get_reading_mode();
     // Run without caching in stage to prove data is uncached
     $this->_reset(false);
     Versioned::set_stage(Versioned::DRAFT);
     $data = new SSViewerCacheBlockTest_VersionedModel();
     $data->setEntropy('default');
     $this->assertEquals('default Stage.Stage', SSViewer::execute_string('<% cached %>$Inspect<% end_cached %>', $data));
     $data = new SSViewerCacheBlockTest_VersionedModel();
     $data->setEntropy('first');
     $this->assertEquals('first Stage.Stage', SSViewer::execute_string('<% cached %>$Inspect<% end_cached %>', $data));
     // Run without caching in live to prove data is uncached
     $this->_reset(false);
     Versioned::set_stage(Versioned::LIVE);
     $data = new SSViewerCacheBlockTest_VersionedModel();
     $data->setEntropy('default');
     $this->assertEquals('default Stage.Live', $this->_runtemplate('<% cached %>$Inspect<% end_cached %>', $data));
     $data = new SSViewerCacheBlockTest_VersionedModel();
     $data->setEntropy('first');
     $this->assertEquals('first Stage.Live', $this->_runtemplate('<% cached %>$Inspect<% end_cached %>', $data));
     // Then with caching, initially in draft, and then in live, to prove that
     // changing the versioned reading mode doesn't cache between modes, but it does
     // within them
     $this->_reset(true);
     Versioned::set_stage(Versioned::DRAFT);
     $data = new SSViewerCacheBlockTest_VersionedModel();
     $data->setEntropy('default');
     $this->assertEquals('default Stage.Stage', $this->_runtemplate('<% cached %>$Inspect<% end_cached %>', $data));
     $data = new SSViewerCacheBlockTest_VersionedModel();
     $data->setEntropy('first');
     $this->assertEquals('default Stage.Stage', $this->_runtemplate('<% cached %>$Inspect<% end_cached %>', $data));
     Versioned::set_stage(Versioned::LIVE);
     $data = new SSViewerCacheBlockTest_VersionedModel();
     $data->setEntropy('first');
     $this->assertEquals('first Stage.Live', $this->_runtemplate('<% cached %>$Inspect<% end_cached %>', $data));
     $data = new SSViewerCacheBlockTest_VersionedModel();
     $data->setEntropy('second');
     $this->assertEquals('first Stage.Live', $this->_runtemplate('<% cached %>$Inspect<% end_cached %>', $data));
     Versioned::set_reading_mode($origReadingMode);
 }