diff --git a/docs/en/04_Changelogs/4.0.0.md b/docs/en/04_Changelogs/4.0.0.md
index a150386a9..bda5bd454 100644
--- a/docs/en/04_Changelogs/4.0.0.md
+++ b/docs/en/04_Changelogs/4.0.0.md
@@ -1295,6 +1295,9 @@ After (`mysite/_config/config.yml`):
* `Configurable` Provides Config API helper methods
* `Injectable` Provides Injector API helper methods
* `Extensible` Allows extensions to be applied
+* `Convert` class has extra methods for formatting file sizes in php_ini compatible format
+ * `Convert::memstring2bytes()` will parse a php_ini memory size.
+ * `Convert::bytes2memstring()` will format the memory size with the appropriate scale.
* `SiteTree.alternatePreviewLink` is deprecated. Use `updatePreviewLink` instead.
* `Injector` dependencies no longer automatically inherit from parent classes.
* `$action` parameter to `Controller::Link()` method is standardised.
@@ -1545,6 +1548,17 @@ A very small number of methods were chosen for deprecation, and will be removed
* `DBMoney` values are now treated as empty only if `Amount` field is null. If an `Amount` value
is provided without a `Currency` specified, it will be formatted as per the current locale.
* Removed `DatabaseAdmin#clearAllData()`. Use `DB::get_conn()->clearAllData()` instead
+* `SapphireTest` temp DB methods have been removed and put into a new `TempDatabase` class.
+ This allows applications to create temp databases when not running tests.
+ This class now takes a connection name as a constructor class, and no longer
+ has static methods.
+ The following methods have been moved to this new class and renamed as non-static:
+ * `using_temp_db` -> `isUsed()`
+ * `kill_temp_db` -> `kill()`
+ * `empty_temp_db` _> `clearAllData()`
+ * `create_temp_db` -> `build()`
+ * `delete_all_temp_dbs` -> `deleteAll()`
+ * `resetDBSchema` -> `resetSchema()`
The below methods have been added or had their functionality updated to `DBDate`, `DBTime` and `DBDatetime`
* `getTimestamp()` added to get the respective date / time as unix timestamp (seconds since 1970-01-01)
diff --git a/src/Control/HTTP.php b/src/Control/HTTP.php
index e691edb3e..1cff05eb2 100644
--- a/src/Control/HTTP.php
+++ b/src/Control/HTTP.php
@@ -163,15 +163,17 @@ class HTTP
*
* @param string $varname
* @param string $varvalue
- * @param string $currentURL Relative or absolute URL.
+ * @param string|null $currentURL Relative or absolute URL, or HTTPRequest to get url from
* @param string $separator Separator for http_build_query().
- *
* @return string
*/
public static function setGetVar($varname, $varvalue, $currentURL = null, $separator = '&')
{
- $request = Controller::curr()->getRequest();
- $uri = $currentURL ?: $request->getURL();
+ if (!isset($currentURL)) {
+ $request = Controller::curr()->getRequest();
+ $currentURL = $request->getURL(true);
+ }
+ $uri = $currentURL;
$isRelative = false;
// We need absolute URLs for parse_url()
diff --git a/src/Control/HTTPRequestBuilder.php b/src/Control/HTTPRequestBuilder.php
index 53903b3fa..a30657c72 100644
--- a/src/Control/HTTPRequestBuilder.php
+++ b/src/Control/HTTPRequestBuilder.php
@@ -65,7 +65,7 @@ class HTTPRequestBuilder
*
* @return array
*/
- protected static function extractRequestHeaders(array $server)
+ public static function extractRequestHeaders(array $server)
{
$headers = array();
foreach ($server as $key => $value) {
diff --git a/src/Core/Convert.php b/src/Core/Convert.php
index c8a1a2475..4b167434a 100644
--- a/src/Core/Convert.php
+++ b/src/Core/Convert.php
@@ -582,7 +582,7 @@ class Convert
*/
public static function bytes2memstring($bytes, $decimal = 0)
{
- $scales = ['b','k','m','g'];
+ $scales = ['B','K','M','G'];
// Get scale
$scale = (int)floor(log($bytes, 1024));
if (!isset($scales[$scale])) {
diff --git a/src/Core/Environment.php b/src/Core/Environment.php
index c32b9a0f5..5f46afa12 100644
--- a/src/Core/Environment.php
+++ b/src/Core/Environment.php
@@ -67,7 +67,7 @@ class Environment
// Check hard maximums
$max = static::getMemoryLimitMax();
if ($max > 0 && ($memoryLimit < 0 || $memoryLimit > $max)) {
- return false;
+ $memoryLimit = $max;
}
// Increase the memory limit if it's too low
diff --git a/src/Core/HTTPApplication.php b/src/Core/HTTPApplication.php
index 1e7a327d0..ba60fbeeb 100644
--- a/src/Core/HTTPApplication.php
+++ b/src/Core/HTTPApplication.php
@@ -5,6 +5,7 @@ namespace SilverStripe\Core;
use SilverStripe\Control\Director;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\HTTPResponse;
+use SilverStripe\Control\HTTPResponse_Exception;
/**
* Invokes the HTTP application within an ErrorControlChain
@@ -118,6 +119,8 @@ class HTTPApplication implements Application
$this->getKernel()->boot($flush);
return call_user_func($callback, $request);
});
+ } catch (HTTPResponse_Exception $ex) {
+ return $ex->getResponse();
} finally {
$this->getKernel()->shutdown();
}
diff --git a/src/Dev/SapphireTest.php b/src/Dev/SapphireTest.php
index 254a860ed..9273944a2 100644
--- a/src/Dev/SapphireTest.php
+++ b/src/Dev/SapphireTest.php
@@ -13,20 +13,16 @@ use SilverStripe\Control\Director;
use SilverStripe\Control\Email\Email;
use SilverStripe\Control\Email\Mailer;
use SilverStripe\Control\HTTPRequest;
-use SilverStripe\Control\Session;
-use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Config\Config;
use SilverStripe\Core\HTTPApplication;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Core\Injector\InjectorLoader;
use SilverStripe\Core\Manifest\ClassLoader;
-use SilverStripe\Dev\TestKernel;
use SilverStripe\Dev\State\SapphireTestState;
use SilverStripe\Dev\State\TestState;
use SilverStripe\i18n\i18n;
-use SilverStripe\ORM\DataExtension;
+use SilverStripe\ORM\Connect\TempDatabase;
use SilverStripe\ORM\DataObject;
-use SilverStripe\ORM\DB;
use SilverStripe\ORM\FieldType\DBDatetime;
use SilverStripe\ORM\FieldType\DBField;
use SilverStripe\ORM\SS_List;
@@ -45,6 +41,9 @@ if (!class_exists(PHPUnit_Framework_TestCase::class)) {
* Test case class for the Sapphire framework.
* Sapphire unit testing is based on PHPUnit, but provides a number of hooks into our data model that make it easier
* to work with.
+ *
+ * This class should not be used anywhere outside of unit tests, as phpunit may not be installed
+ * in production sites.
*/
class SapphireTest extends PHPUnit_Framework_TestCase
{
@@ -67,6 +66,8 @@ class SapphireTest extends PHPUnit_Framework_TestCase
* @var Boolean If set to TRUE, this will force a test database to be generated
* in {@link setUp()}. Note that this flag is overruled by the presence of a
* {@link $fixture_file}, which always forces a database build.
+ *
+ * @var bool
*/
protected $usesDatabase = null;
@@ -92,6 +93,8 @@ class SapphireTest extends PHPUnit_Framework_TestCase
* the values are an array of illegal extensions on that class.
*
* Set a class to `*` to remove all extensions (unadvised)
+ *
+ * @var array
*/
protected static $illegal_extensions = [];
@@ -106,6 +109,8 @@ class SapphireTest extends PHPUnit_Framework_TestCase
*
* array("MyTreeDataObject" => array("Versioned", "Hierarchy"))
*
+ *
+ * @var array
*/
protected static $required_extensions = [];
@@ -113,6 +118,8 @@ class SapphireTest extends PHPUnit_Framework_TestCase
* By default, the test database won't contain any DataObjects that have the interface TestOnly.
* This variable lets you define additional TestOnly DataObjects to set up for this test.
* Set it to an array of DataObject subclass names.
+ *
+ * @var array
*/
protected static $extra_dataobjects = [];
@@ -139,6 +146,13 @@ class SapphireTest extends PHPUnit_Framework_TestCase
*/
protected static $state = null;
+ /**
+ * Temp database helper
+ *
+ * @var TempDatabase
+ */
+ protected static $tempDB = null;
+
/**
* Gets illegal extensions for this class
*
@@ -229,13 +243,13 @@ class SapphireTest extends PHPUnit_Framework_TestCase
// Set up fixture
if ($fixtureFiles || $this->usesDatabase) {
- if (!self::using_temp_db()) {
- self::create_temp_db();
+ if (!static::$tempDB->isUsed()) {
+ static::$tempDB->build();
}
DataObject::singleton()->flushCache();
- self::empty_temp_db();
+ static::$tempDB->clearAllData();
foreach ($this->requireDefaultRecordsFrom as $className) {
$instance = singleton($className);
@@ -292,10 +306,7 @@ class SapphireTest extends PHPUnit_Framework_TestCase
// Build DB if we have objects
if (static::getExtraDataObjects()) {
DataObject::reset();
- if (!self::using_temp_db()) {
- self::create_temp_db();
- }
- static::resetDBSchema(true);
+ static::resetDBSchema(true, true);
}
}
@@ -915,159 +926,26 @@ class SapphireTest extends PHPUnit_Framework_TestCase
// Register state
static::$state = SapphireTestState::singleton();
+ // Register temp DB holder
+ static::$tempDB = TempDatabase::create();
}
/**
- * Returns true if we are currently using a temporary database
- *
- * @return bool
- */
- public static function using_temp_db()
- {
- $dbConn = DB::get_conn();
- $prefix = getenv('SS_DATABASE_PREFIX') ?: 'ss_';
- return 1 === preg_match(sprintf('/^%stmpdb_[0-9]+_[0-9]+$/i', preg_quote($prefix, '/')), $dbConn->getSelectedDatabase());
- }
-
- /**
- * Destroy all temp databases
- */
- public static function kill_temp_db()
- {
- // Delete our temporary database
- if (self::using_temp_db()) {
- $dbConn = DB::get_conn();
- $dbName = $dbConn->getSelectedDatabase();
- if ($dbName && DB::get_conn()->databaseExists($dbName)) {
- // Some DataExtensions keep a static cache of information that needs to
- // be reset whenever the database is killed
- foreach (ClassInfo::subclassesFor(DataExtension::class) as $class) {
- $toCall = array($class, 'on_db_reset');
- if (is_callable($toCall)) {
- call_user_func($toCall);
- }
- }
-
- // echo "Deleted temp database " . $dbConn->currentDatabase() . "\n";
- $dbConn->dropSelectedDatabase();
- }
- }
- }
-
- /**
- * Remove all content from the temporary database.
- */
- public static function empty_temp_db()
- {
- if (self::using_temp_db()) {
- DB::get_conn()->clearAllData();
-
- // Some DataExtensions keep a static cache of information that needs to
- // be reset whenever the database is cleaned out
- $classes = array_merge(ClassInfo::subclassesFor(DataExtension::class), ClassInfo::subclassesFor(DataObject::class));
- foreach ($classes as $class) {
- $toCall = array($class, 'on_db_reset');
- if (is_callable($toCall)) {
- call_user_func($toCall);
- }
- }
- }
- }
-
- /**
- * Create temp DB without creating extra objects
- *
- * @return string
- */
- public static function create_temp_db()
- {
- // Disable PHPUnit error handling
- $oldErrorHandler = set_error_handler(null);
-
- // Create a temporary database, and force the connection to use UTC for time
- global $databaseConfig;
- $databaseConfig['timezone'] = '+0:00';
- DB::connect($databaseConfig);
- $dbConn = DB::get_conn();
- $prefix = getenv('SS_DATABASE_PREFIX') ?: 'ss_';
- do {
- $dbname = strtolower(sprintf('%stmpdb_%s_%s', $prefix, time(), rand(1000000, 9999999)));
- } while ($dbConn->databaseExists($dbname));
-
- $dbConn->selectDatabase($dbname, true);
-
- static::resetDBSchema();
-
- // Reinstate PHPUnit error handling
- set_error_handler($oldErrorHandler);
-
- // Ensure test db is killed on exit
- register_shutdown_function(function () {
- static::kill_temp_db();
- });
-
- return $dbname;
- }
-
- public static function delete_all_temp_dbs()
- {
- $prefix = getenv('SS_DATABASE_PREFIX') ?: 'ss_';
- foreach (DB::get_schema()->databaseList() as $dbName) {
- if (1 === preg_match(sprintf('/^%stmpdb_[0-9]+_[0-9]+$/i', preg_quote($prefix, '/')), $dbName)) {
- DB::get_schema()->dropDatabase($dbName);
- if (Director::is_cli()) {
- echo "Dropped database \"$dbName\"" . PHP_EOL;
- } else {
- echo "