mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Various deprecations and a few features (#11365)
* API Deprecate DatabaselessKernel * ENH Add functionality to ArrayLib * ENH Add functionality to DBDateTime * API Deprecate various APIs
This commit is contained in:
parent
be18059d11
commit
6a3659d69d
@ -6,7 +6,6 @@ use SilverStripe\Control\HTTPApplication;
|
||||
use SilverStripe\Core\CoreKernel;
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\ORM\Connect\NullDatabase;
|
||||
use SilverStripe\Core\DatabaselessKernel;
|
||||
|
||||
require __DIR__ . '/src/includes/autoload.php';
|
||||
|
||||
@ -25,9 +24,10 @@ if ($skipDatabase) {
|
||||
DB::set_conn(new NullDatabase());
|
||||
}
|
||||
// Default application
|
||||
$kernel = $skipDatabase
|
||||
? new DatabaselessKernel(BASE_PATH)
|
||||
: new CoreKernel(BASE_PATH);
|
||||
$kernel = new CoreKernel(BASE_PATH);
|
||||
if ($skipDatabase) {
|
||||
$kernel->setBootDatabase(false);
|
||||
}
|
||||
|
||||
$app = new HTTPApplication($kernel);
|
||||
$response = $app->handle($request);
|
||||
|
@ -4,6 +4,7 @@ namespace SilverStripe\Control;
|
||||
|
||||
use SilverStripe\Core\ClassInfo;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\Dev\Deprecation;
|
||||
use SilverStripe\Security\Permission;
|
||||
use SilverStripe\Security\Security;
|
||||
|
||||
@ -13,9 +14,16 @@ use SilverStripe\Security\Security;
|
||||
* call to {@link process()} on every sub-subclass. For instance, calling
|
||||
* "sake DailyTask" from the commandline will call {@link process()} on every subclass
|
||||
* of DailyTask.
|
||||
*
|
||||
* @deprecated 5.4.0 Will be replaced with symfony/console commands
|
||||
*/
|
||||
abstract class CliController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
Deprecation::notice('5.4.0', 'Will be replaced with symfony/console commands', Deprecation::SCOPE_CLASS);
|
||||
}
|
||||
|
||||
private static $allowed_actions = [
|
||||
'index'
|
||||
|
@ -5,12 +5,26 @@ namespace SilverStripe\Control\Middleware\ConfirmationMiddleware;
|
||||
use SilverStripe\Control\Director;
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
use SilverStripe\Core\Kernel;
|
||||
use SilverStripe\Dev\Deprecation;
|
||||
|
||||
/**
|
||||
* Allows a bypass when the request has been run in CLI mode
|
||||
*
|
||||
* @deprecated 5.4.0 Will be removed without equivalent functionality to replace it
|
||||
*/
|
||||
class CliBypass implements Bypass
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
Deprecation::withNoReplacement(function () {
|
||||
Deprecation::notice(
|
||||
'5.4.0',
|
||||
'Will be removed without equivalent functionality to replace it',
|
||||
Deprecation::SCOPE_CLASS
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the current process is running in CLI mode
|
||||
*
|
||||
|
@ -357,6 +357,14 @@ abstract class BaseKernel implements Kernel
|
||||
$this->booted = $bool;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the kernel has booted or not
|
||||
*/
|
||||
public function getBooted(): bool
|
||||
{
|
||||
return $this->booted;
|
||||
}
|
||||
|
||||
public function shutdown()
|
||||
{
|
||||
}
|
||||
|
@ -8,18 +8,29 @@ use SilverStripe\ORM\DB;
|
||||
use Exception;
|
||||
use LogicException;
|
||||
use SilverStripe\Dev\Deprecation;
|
||||
use SilverStripe\ORM\Connect\NullDatabase;
|
||||
|
||||
/**
|
||||
* Simple Kernel container
|
||||
*/
|
||||
class CoreKernel extends BaseKernel
|
||||
{
|
||||
protected bool $bootDatabase = true;
|
||||
|
||||
/**
|
||||
* Indicates whether the Kernel has been flushed on boot
|
||||
*/
|
||||
private ?bool $flush = null;
|
||||
|
||||
/**
|
||||
* Set whether the database should boot or not.
|
||||
*/
|
||||
public function setBootDatabase(bool $bool): static
|
||||
{
|
||||
$this->bootDatabase = $bool;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param false $flush
|
||||
* @throws HTTPResponse_Exception
|
||||
@ -29,6 +40,10 @@ class CoreKernel extends BaseKernel
|
||||
{
|
||||
$this->flush = $flush;
|
||||
|
||||
if (!$this->bootDatabase) {
|
||||
DB::set_conn(new NullDatabase());
|
||||
}
|
||||
|
||||
$this->bootPHP();
|
||||
$this->bootManifests($flush);
|
||||
$this->bootErrorHandling();
|
||||
@ -47,6 +62,9 @@ class CoreKernel extends BaseKernel
|
||||
*/
|
||||
protected function validateDatabase()
|
||||
{
|
||||
if (!$this->bootDatabase) {
|
||||
return;
|
||||
}
|
||||
$databaseConfig = DB::getConfig();
|
||||
// Gracefully fail if no DB is configured
|
||||
if (empty($databaseConfig['database'])) {
|
||||
@ -62,6 +80,9 @@ class CoreKernel extends BaseKernel
|
||||
*/
|
||||
protected function bootDatabaseGlobals()
|
||||
{
|
||||
if (!$this->bootDatabase) {
|
||||
return;
|
||||
}
|
||||
// Now that configs have been loaded, we can check global for database config
|
||||
global $databaseConfig;
|
||||
global $database;
|
||||
@ -94,6 +115,9 @@ class CoreKernel extends BaseKernel
|
||||
*/
|
||||
protected function bootDatabaseEnvVars()
|
||||
{
|
||||
if (!$this->bootDatabase) {
|
||||
return;
|
||||
}
|
||||
// Set default database config
|
||||
$databaseConfig = $this->getDatabaseConfig();
|
||||
$databaseConfig['database'] = $this->getDatabaseName();
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace SilverStripe\Core;
|
||||
|
||||
use Exception;
|
||||
use SilverStripe\Dev\Deprecation;
|
||||
|
||||
/**
|
||||
* Boot a kernel without requiring a database connection.
|
||||
@ -11,6 +12,7 @@ use Exception;
|
||||
* around the availability of a database for every execution path.
|
||||
*
|
||||
* @internal
|
||||
* @deprecated 5.4.0 Use SilverStripe\Core\CoreKernel::setBootDatabase() instead
|
||||
*/
|
||||
class DatabaselessKernel extends BaseKernel
|
||||
{
|
||||
@ -29,6 +31,16 @@ class DatabaselessKernel extends BaseKernel
|
||||
*/
|
||||
protected $bootErrorHandling = true;
|
||||
|
||||
public function __construct($basePath)
|
||||
{
|
||||
parent::__construct($basePath);
|
||||
Deprecation::notice(
|
||||
'5.4.0',
|
||||
'Use ' . CoreKernel::class . '::setBootDatabase() instead',
|
||||
Deprecation::SCOPE_CLASS
|
||||
);
|
||||
}
|
||||
|
||||
public function setBootErrorHandling(bool $bool)
|
||||
{
|
||||
$this->bootErrorHandling = $bool;
|
||||
|
@ -30,6 +30,7 @@ abstract class BuildTask
|
||||
*
|
||||
* @config
|
||||
* @var string
|
||||
* @deprecated 5.4.0 Will be replaced with $commandName
|
||||
*/
|
||||
private static $segment = null;
|
||||
|
||||
@ -55,6 +56,7 @@ abstract class BuildTask
|
||||
/**
|
||||
* @var string $description Describe the implications the task has,
|
||||
* and the changes it makes. Accepts HTML formatting.
|
||||
* @deprecated 5.4.0 Will be replaced with a static property with the same name
|
||||
*/
|
||||
protected $description = 'No description available';
|
||||
|
||||
@ -90,9 +92,13 @@ abstract class BuildTask
|
||||
|
||||
/**
|
||||
* @return string HTML formatted description
|
||||
* @deprecated 5.4.0 Will be replaced with a static method with the same name
|
||||
*/
|
||||
public function getDescription()
|
||||
{
|
||||
Deprecation::withNoReplacement(
|
||||
fn() => Deprecation::notice('5.4.0', 'Will be replaced with a static method with the same name')
|
||||
);
|
||||
return $this->description;
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,9 @@ use SilverStripe\Security\Permission;
|
||||
use SilverStripe\Security\PermissionProvider;
|
||||
use SilverStripe\Security\Security;
|
||||
|
||||
/**
|
||||
* @deprecated 5.4.0 Will be replaced with SilverStripe\Dev\Command\DbBuild
|
||||
*/
|
||||
class DevBuildController extends Controller implements PermissionProvider
|
||||
{
|
||||
|
||||
@ -28,6 +31,18 @@ class DevBuildController extends Controller implements PermissionProvider
|
||||
'CAN_DEV_BUILD',
|
||||
];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
Deprecation::withNoReplacement(function () {
|
||||
Deprecation::notice(
|
||||
'5.4.0',
|
||||
'Will be replaced with SilverStripe\Dev\Command\DbBuild',
|
||||
Deprecation::SCOPE_CLASS
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
protected function init(): void
|
||||
{
|
||||
parent::init();
|
||||
@ -68,7 +83,7 @@ class DevBuildController extends Controller implements PermissionProvider
|
||||
|| Permission::check(static::config()->get('init_permissions'))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function providePermissions(): array
|
||||
{
|
||||
return [
|
||||
|
@ -15,6 +15,8 @@ use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
/**
|
||||
* Outputs the full configuration.
|
||||
*
|
||||
* @deprecated 5.4.0 Will be replaced with SilverStripe\Dev\Command\ConfigDump
|
||||
*/
|
||||
class DevConfigController extends Controller implements PermissionProvider
|
||||
{
|
||||
@ -41,6 +43,19 @@ class DevConfigController extends Controller implements PermissionProvider
|
||||
'CAN_DEV_CONFIG',
|
||||
];
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
Deprecation::withNoReplacement(function () {
|
||||
Deprecation::notice(
|
||||
'5.4.0',
|
||||
'Will be replaced with SilverStripe\Dev\Command\ConfigDump',
|
||||
Deprecation::SCOPE_CLASS
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
protected function init(): void
|
||||
{
|
||||
parent::init();
|
||||
@ -157,7 +172,7 @@ class DevConfigController extends Controller implements PermissionProvider
|
||||
|| Permission::check(static::config()->get('init_permissions'))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function providePermissions(): array
|
||||
{
|
||||
return [
|
||||
|
@ -54,6 +54,7 @@ class DevelopmentAdmin extends Controller implements PermissionProvider
|
||||
* ]
|
||||
*
|
||||
* @var array
|
||||
* @deprecated 5.4.0 Will be replaced with "controllers" and "commands" configuration properties
|
||||
*/
|
||||
private static $registered_controllers = [];
|
||||
|
||||
@ -82,7 +83,7 @@ class DevelopmentAdmin extends Controller implements PermissionProvider
|
||||
if (static::config()->get('deny_non_cli') && !Director::is_cli()) {
|
||||
return $this->httpError(404);
|
||||
}
|
||||
|
||||
|
||||
if (!$this->canViewAll() && empty($this->getLinks())) {
|
||||
Security::permissionFailure($this);
|
||||
return;
|
||||
@ -201,8 +202,12 @@ class DevelopmentAdmin extends Controller implements PermissionProvider
|
||||
return $links;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 5.4.0 Will be removed without equivalent functionality to replace it
|
||||
*/
|
||||
protected function getRegisteredController($baseUrlPart)
|
||||
{
|
||||
Deprecation::notice('5.4.0', 'Will be removed without equivalent functionality to replace it');
|
||||
$reg = Config::inst()->get(static::class, 'registered_controllers');
|
||||
|
||||
if (isset($reg[$baseUrlPart])) {
|
||||
@ -223,9 +228,18 @@ class DevelopmentAdmin extends Controller implements PermissionProvider
|
||||
* DataObject classes
|
||||
* Should match the $url_handlers rule:
|
||||
* 'build/defaults' => 'buildDefaults',
|
||||
*
|
||||
* @deprecated 5.4.0 Will be replaced with SilverStripe\Dev\Commands\DbDefaults
|
||||
*/
|
||||
public function buildDefaults()
|
||||
{
|
||||
Deprecation::withNoReplacement(function () {
|
||||
Deprecation::notice(
|
||||
'5.4.0',
|
||||
'Will be replaced with SilverStripe\Dev\Command\DbDefaults'
|
||||
);
|
||||
});
|
||||
|
||||
$da = DatabaseAdmin::create();
|
||||
|
||||
$renderer = null;
|
||||
@ -247,9 +261,18 @@ class DevelopmentAdmin extends Controller implements PermissionProvider
|
||||
/**
|
||||
* Generate a secure token which can be used as a crypto key.
|
||||
* Returns the token and suggests PHP configuration to set it.
|
||||
*
|
||||
* @deprecated 5.4.0 Will be replaced with SilverStripe\Dev\Commands\GenerateSecureToken
|
||||
*/
|
||||
public function generatesecuretoken()
|
||||
{
|
||||
Deprecation::withNoReplacement(function () {
|
||||
Deprecation::notice(
|
||||
'5.4.0',
|
||||
'Will be replaced with SilverStripe\Dev\Command\GenerateSecureToken'
|
||||
);
|
||||
});
|
||||
|
||||
$generator = Injector::inst()->create('SilverStripe\\Security\\RandomGenerator');
|
||||
$token = $generator->randomToken('sha1');
|
||||
$body = <<<TXT
|
||||
|
@ -4,6 +4,7 @@ namespace SilverStripe\Dev\Tasks;
|
||||
|
||||
use SilverStripe\Control\Director;
|
||||
use SilverStripe\Dev\BuildTask;
|
||||
use SilverStripe\Dev\Deprecation;
|
||||
use SilverStripe\ORM\Connect\TempDatabase;
|
||||
use SilverStripe\Security\Permission;
|
||||
use SilverStripe\Security\Security;
|
||||
@ -35,6 +36,12 @@ class CleanupTestDatabasesTask extends BuildTask
|
||||
|
||||
public function canView(): bool
|
||||
{
|
||||
Deprecation::withNoReplacement(function () {
|
||||
Deprecation::notice(
|
||||
'5.4.0',
|
||||
'Will be replaced with canRunInBrowser()'
|
||||
);
|
||||
});
|
||||
return Permission::check('ADMIN') || Director::is_cli();
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,8 @@ use SilverStripe\Dev\Deprecation;
|
||||
/**
|
||||
* Output the error to the browser, with the given HTTP status code.
|
||||
* We recommend that you use a formatter that generates HTML with this.
|
||||
*
|
||||
* @deprecated 5.4.0 Will be renamed to ErrorOutputHandler
|
||||
*/
|
||||
class HTTPOutputHandler extends AbstractProcessingHandler
|
||||
{
|
||||
@ -32,6 +34,18 @@ class HTTPOutputHandler extends AbstractProcessingHandler
|
||||
*/
|
||||
private $cliFormatter = null;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
Deprecation::withNoReplacement(function () {
|
||||
Deprecation::notice(
|
||||
'5.4.0',
|
||||
'Will be renamed to ErrorOutputHandler',
|
||||
Deprecation::SCOPE_CLASS
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mime type to use when displaying this error.
|
||||
*
|
||||
@ -146,7 +160,7 @@ class HTTPOutputHandler extends AbstractProcessingHandler
|
||||
// or our deprecations when the relevant shouldShow method returns true
|
||||
return $errorCode !== E_USER_DEPRECATED
|
||||
|| !Deprecation::isTriggeringError()
|
||||
|| ($this->isCli() ? Deprecation::shouldShowForCli() : Deprecation::shouldShowForHttp());
|
||||
|| (Director::is_cli() ? Deprecation::shouldShowForCli() : Deprecation::shouldShowForHttp());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -185,10 +199,12 @@ class HTTPOutputHandler extends AbstractProcessingHandler
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is required and must be protected for unit testing, since we can't mock static or private methods
|
||||
* This method used to be used for unit testing but is no longer required.
|
||||
* @deprecated 5.4.0 Use SilverStripe\Control\Director::is_cli() instead
|
||||
*/
|
||||
protected function isCli(): bool
|
||||
{
|
||||
Deprecation::notice('5.4.0', 'Use ' . Director::class . '::is_cli() instead');
|
||||
return Director::is_cli();
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ namespace SilverStripe\ORM;
|
||||
|
||||
use Generator;
|
||||
use SilverStripe\Dev\Deprecation;
|
||||
use InvalidArgumentException;
|
||||
|
||||
/**
|
||||
* Library of static methods for manipulating arrays.
|
||||
@ -354,4 +355,65 @@ class ArrayLib
|
||||
|
||||
$array = $shuffledArray;
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a value into an array before another given value.
|
||||
* Does not preserve keys.
|
||||
*
|
||||
* @param mixed $before The value to check for. If this value isn't in the source array, $insert will be put at the end.
|
||||
* @param boolean $strict If true then this will perform a strict type comparison to look for the $before value in the source array.
|
||||
* @param boolean $splatInsertArray If true, $insert must be an array.
|
||||
* Its values will be splatted into the source array.
|
||||
*/
|
||||
public static function insertBefore(array $array, mixed $insert, mixed $before, bool $strict = false, bool $splatInsertArray = false): array
|
||||
{
|
||||
if ($splatInsertArray && !is_array($insert)) {
|
||||
throw new InvalidArgumentException('$insert must be an array when $splatInsertArray is true. Got ' . gettype($insert));
|
||||
}
|
||||
$array = array_values($array);
|
||||
$pos = array_search($before, $array, $strict);
|
||||
if ($pos === false) {
|
||||
return static::insertIntoArray($array, $insert, $splatInsertArray);
|
||||
}
|
||||
return static::insertAtPosition($array, $insert, $pos, $splatInsertArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert a value into an array after another given value.
|
||||
* Does not preserve keys.
|
||||
*
|
||||
* @param mixed $after The value to check for. If this value isn't in the source array, $insert will be put at the end.
|
||||
* @param boolean $strict If true then this will perform a strict type comparison to look for the $before value in the source array.
|
||||
* @param boolean $splatInsertArray If true, $insert must be an array.
|
||||
* Its values will be splatted into the source array.
|
||||
*/
|
||||
public static function insertAfter(array $array, mixed $insert, mixed $after, bool $strict = false, bool $splatInsertArray = false): array
|
||||
{
|
||||
if ($splatInsertArray && !is_array($insert)) {
|
||||
throw new InvalidArgumentException('$insert must be an array when $splatInsertArray is true. Got ' . gettype($insert));
|
||||
}
|
||||
$array = array_values($array);
|
||||
$pos = array_search($after, $array, $strict);
|
||||
if ($pos === false) {
|
||||
return static::insertIntoArray($array, $insert, $splatInsertArray);
|
||||
}
|
||||
return static::insertAtPosition($array, $insert, $pos + 1, $splatInsertArray);
|
||||
}
|
||||
|
||||
private static function insertAtPosition(array $array, mixed $insert, int $pos, bool $splatInsertArray): array
|
||||
{
|
||||
$result = array_slice($array, 0, $pos);
|
||||
$result = static::insertIntoArray($result, $insert, $splatInsertArray);
|
||||
return array_merge($result, array_slice($array, $pos));
|
||||
}
|
||||
|
||||
private static function insertIntoArray(array $array, mixed $insert, bool $splatInsertArray): array
|
||||
{
|
||||
if ($splatInsertArray) {
|
||||
$array = array_merge($array, $insert);
|
||||
} else {
|
||||
$array[] = $insert;
|
||||
}
|
||||
return $array;
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ use SilverStripe\Core\ClassInfo;
|
||||
use SilverStripe\Core\Environment;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\Core\Manifest\ClassLoader;
|
||||
use SilverStripe\Dev\Deprecation;
|
||||
use SilverStripe\Dev\DevBuildController;
|
||||
use SilverStripe\Dev\DevelopmentAdmin;
|
||||
use SilverStripe\ORM\Connect\DatabaseException;
|
||||
@ -25,6 +26,8 @@ use SilverStripe\Versioned\Versioned;
|
||||
*
|
||||
* Utility functions for administrating the database. These can be accessed
|
||||
* via URL, e.g. http://www.yourdomain.com/db/build.
|
||||
*
|
||||
* @deprecated 5.4.0 Will be replaced with SilverStripe\Dev\Command\DbBuild
|
||||
*/
|
||||
class DatabaseAdmin extends Controller
|
||||
{
|
||||
@ -39,6 +42,7 @@ class DatabaseAdmin extends Controller
|
||||
|
||||
/**
|
||||
* Obsolete classname values that should be remapped in dev/build
|
||||
* @deprecated 5.4.0 Will be replaced with SilverStripe\Dev\Command\DbBuild.classname_value_remapping
|
||||
*/
|
||||
private static $classname_value_remapping = [
|
||||
'File' => 'SilverStripe\\Assets\\File',
|
||||
@ -56,9 +60,22 @@ class DatabaseAdmin extends Controller
|
||||
|
||||
/**
|
||||
* Config setting to enabled/disable the display of record counts on the dev/build output
|
||||
* @deprecated 5.4.0 Will be replaced with SilverStripe\Dev\Command\DbBuild.show_record_counts
|
||||
*/
|
||||
private static $show_record_counts = true;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
Deprecation::withNoReplacement(function () {
|
||||
Deprecation::notice(
|
||||
'5.4.0',
|
||||
'Will be replaced with SilverStripe\Dev\Command\DbBuild',
|
||||
Deprecation::SCOPE_CLASS
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
protected function init()
|
||||
{
|
||||
parent::init();
|
||||
@ -191,9 +208,18 @@ class DatabaseAdmin extends Controller
|
||||
*
|
||||
* @return string Returns the timestamp of the time that the database was
|
||||
* last built
|
||||
*
|
||||
* @deprecated 5.4.0 Will be replaced with SilverStripe\Dev\Command\DbBuild::lastBuilt()
|
||||
*/
|
||||
public static function lastBuilt()
|
||||
{
|
||||
Deprecation::withNoReplacement(function () {
|
||||
Deprecation::notice(
|
||||
'5.4.0',
|
||||
'Will be replaced with SilverStripe\Dev\Command\DbBuild::lastBuilt()'
|
||||
);
|
||||
});
|
||||
|
||||
$file = TEMP_PATH
|
||||
. DIRECTORY_SEPARATOR
|
||||
. 'database-last-generated-'
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace SilverStripe\ORM\FieldType;
|
||||
|
||||
use DateTime;
|
||||
use Exception;
|
||||
use IntlDateFormatter;
|
||||
use InvalidArgumentException;
|
||||
@ -195,6 +196,69 @@ class DBDatetime extends DBDate implements TemplateGlobalProvider
|
||||
return $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the amount of time inbetween two datetimes.
|
||||
*/
|
||||
public static function getTimeBetween(DBDateTime $from, DBDateTime $to): string
|
||||
{
|
||||
$fromRaw = new DateTime();
|
||||
$fromRaw->setTimestamp((int) $from->getTimestamp());
|
||||
$toRaw = new DateTime();
|
||||
$toRaw->setTimestamp((int) $to->getTimestamp());
|
||||
$diff = $fromRaw->diff($toRaw);
|
||||
$result = [];
|
||||
if ($diff->y) {
|
||||
$result[] = _t(
|
||||
__CLASS__ . '.nYears',
|
||||
'one year|{count} years',
|
||||
['count' => $diff->y]
|
||||
);
|
||||
}
|
||||
if ($diff->m) {
|
||||
$result[] = _t(
|
||||
__CLASS__ . '.nMonths',
|
||||
'one month|{count} months',
|
||||
['count' => $diff->m]
|
||||
);
|
||||
}
|
||||
if ($diff->d) {
|
||||
$result[] = _t(
|
||||
__CLASS__ . '.nDays',
|
||||
'one day|{count} days',
|
||||
['count' => $diff->d]
|
||||
);
|
||||
}
|
||||
if ($diff->h) {
|
||||
$result[] = _t(
|
||||
__CLASS__ . '.nHours',
|
||||
'one hour|{count} hours',
|
||||
['count' => $diff->h]
|
||||
);
|
||||
}
|
||||
if ($diff->i) {
|
||||
$result[] = _t(
|
||||
__CLASS__ . '.nMinutes',
|
||||
'one minute|{count} minutes',
|
||||
['count' => $diff->i]
|
||||
);
|
||||
}
|
||||
if ($diff->s) {
|
||||
$result[] = _t(
|
||||
__CLASS__ . '.nSeconds',
|
||||
'one second|{count} seconds',
|
||||
['count' => $diff->s]
|
||||
);
|
||||
}
|
||||
if (empty($result)) {
|
||||
return _t(
|
||||
__CLASS__ . '.nSeconds',
|
||||
'{count} seconds',
|
||||
['count' => 0]
|
||||
);
|
||||
}
|
||||
return implode(', ', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -6,6 +6,7 @@ use Monolog\Handler\HandlerInterface;
|
||||
use ReflectionClass;
|
||||
use ReflectionMethod;
|
||||
use SilverStripe\Control\Director;
|
||||
use SilverStripe\Core\Environment;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\Dev\Deprecation;
|
||||
use SilverStripe\Dev\SapphireTest;
|
||||
@ -172,14 +173,20 @@ class HTTPOutputHandlerTest extends SapphireTest
|
||||
}
|
||||
$reflectionDeprecation->setStaticPropertyValue('isTriggeringError', $triggeringError);
|
||||
|
||||
$mockHandler = $this->getMockBuilder(HTTPOutputHandler::class)->onlyMethods(['isCli'])->getMock();
|
||||
$mockHandler->method('isCli')->willReturn($isCli);
|
||||
$reflectionDirector = new ReflectionClass(Environment::class);
|
||||
$origIsCli = $reflectionDirector->getStaticPropertyValue('isCliOverride');
|
||||
$reflectionDirector->setStaticPropertyValue('isCliOverride', $isCli);
|
||||
|
||||
$result = $reflectionShouldShow->invoke($mockHandler, $errorCode);
|
||||
$this->assertSame($expected, $result);
|
||||
try {
|
||||
$handler = new HTTPOutputHandler();
|
||||
$result = $reflectionShouldShow->invoke($handler, $errorCode);
|
||||
$this->assertSame($expected, $result);
|
||||
|
||||
Deprecation::setShouldShowForCli($cliShouldShowOrig);
|
||||
Deprecation::setShouldShowForHttp($httpShouldShowOrig);
|
||||
$reflectionDeprecation->setStaticPropertyValue('isTriggeringError', $triggeringErrorOrig);
|
||||
Deprecation::setShouldShowForCli($cliShouldShowOrig);
|
||||
Deprecation::setShouldShowForHttp($httpShouldShowOrig);
|
||||
$reflectionDeprecation->setStaticPropertyValue('isTriggeringError', $triggeringErrorOrig);
|
||||
} finally {
|
||||
$reflectionDirector->setStaticPropertyValue('isCliOverride', $origIsCli);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -368,4 +368,176 @@ class ArrayLibTest extends SapphireTest
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function provideInsertBefore(): array
|
||||
{
|
||||
return [
|
||||
'simple insertion' => [
|
||||
'insert' => 'new',
|
||||
'before' => 'def',
|
||||
'strict' => true,
|
||||
'splat' => false,
|
||||
'expected' => ['abc', '', [1,2,3], 'new', 'def', '0', null, true, 0, 'last']
|
||||
],
|
||||
'insert before first' => [
|
||||
'insert' => 'new',
|
||||
'before' => 'abc',
|
||||
'strict' => true,
|
||||
'splat' => false,
|
||||
'expected' => ['new', 'abc', '', [1,2,3], 'def', '0', null, true, 0, 'last']
|
||||
],
|
||||
'insert before last' => [
|
||||
'insert' => 'new',
|
||||
'before' => 'last',
|
||||
'strict' => true,
|
||||
'splat' => false,
|
||||
'expected' => ['abc', '', [1,2,3], 'def', '0', null, true, 0, 'new', 'last']
|
||||
],
|
||||
'insert before missing' => [
|
||||
'insert' => 'new',
|
||||
'before' => 'this value isnt there',
|
||||
'strict' => true,
|
||||
'splat' => false,
|
||||
'expected' => ['abc', '', [1,2,3], 'def', '0', null, true, 0, 'last', 'new']
|
||||
],
|
||||
'strict' => [
|
||||
'insert' => 'new',
|
||||
'before' => 0,
|
||||
'strict' => true,
|
||||
'splat' => false,
|
||||
'expected' => ['abc', '', [1,2,3], 'def', '0', null, true, 'new', 0, 'last']
|
||||
],
|
||||
'not strict' => [
|
||||
'insert' => 'new',
|
||||
'before' => 0,
|
||||
'strict' => false,
|
||||
'splat' => false,
|
||||
'expected' => ['abc', '', [1,2,3], 'def', 'new', '0', null, true, 0, 'last']
|
||||
],
|
||||
'before array' => [
|
||||
'insert' => 'new',
|
||||
'before' => [1,2,3],
|
||||
'strict' => true,
|
||||
'splat' => false,
|
||||
'expected' => ['abc', '', 'new', [1,2,3], 'def', '0', null, true, 0, 'last']
|
||||
],
|
||||
'before missing array' => [
|
||||
'insert' => 'new',
|
||||
'before' => ['a', 'b', 'c'],
|
||||
'strict' => true,
|
||||
'splat' => false,
|
||||
'expected' => ['abc', '', [1,2,3], 'def', '0', null, true, 0, 'last', 'new']
|
||||
],
|
||||
'splat array' => [
|
||||
'insert' => ['a', 'b', 'c'],
|
||||
'before' => 'def',
|
||||
'strict' => true,
|
||||
'splat' => true,
|
||||
'expected' => ['abc', '', [1,2,3], 'a', 'b', 'c', 'def', '0', null, true, 0, 'last']
|
||||
],
|
||||
'no splat array' => [
|
||||
'insert' => ['a', 'b', 'c'],
|
||||
'before' => 'def',
|
||||
'strict' => true,
|
||||
'splat' => false,
|
||||
'expected' => ['abc', '', [1,2,3], ['a', 'b', 'c'], 'def', '0', null, true, 0, 'last']
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideInsertBefore
|
||||
*/
|
||||
public function testInsertBefore(mixed $insert, mixed $before, bool $strict, bool $splat, array $expected): void
|
||||
{
|
||||
$array = ['abc', '', [1,2,3], 'def', '0', null, true, 0, 'last'];
|
||||
$final = ArrayLib::insertBefore($array, $insert, $before, $strict, $splat);
|
||||
$this->assertSame($expected, $final);
|
||||
}
|
||||
|
||||
public function provideInsertAfter(): array
|
||||
{
|
||||
return [
|
||||
'simple insertion' => [
|
||||
'insert' => 'new',
|
||||
'before' => 'def',
|
||||
'strict' => true,
|
||||
'splat' => false,
|
||||
'expected' => ['abc', '', [1,2,3], 'def', 'new', '0', null, true, 0, 'last']
|
||||
],
|
||||
'insert after first' => [
|
||||
'insert' => 'new',
|
||||
'before' => 'abc',
|
||||
'strict' => true,
|
||||
'splat' => false,
|
||||
'expected' => ['abc', 'new', '', [1,2,3], 'def', '0', null, true, 0, 'last']
|
||||
],
|
||||
'insert after last' => [
|
||||
'insert' => 'new',
|
||||
'before' => 'last',
|
||||
'strict' => true,
|
||||
'splat' => false,
|
||||
'expected' => ['abc', '', [1,2,3], 'def', '0', null, true, 0, 'last', 'new']
|
||||
],
|
||||
'insert after missing' => [
|
||||
'insert' => 'new',
|
||||
'before' => 'this value isnt there',
|
||||
'strict' => true,
|
||||
'splat' => false,
|
||||
'expected' => ['abc', '', [1,2,3], 'def', '0', null, true, 0, 'last', 'new']
|
||||
],
|
||||
'strict' => [
|
||||
'insert' => 'new',
|
||||
'before' => 0,
|
||||
'strict' => true,
|
||||
'splat' => false,
|
||||
'expected' => ['abc', '', [1,2,3], 'def', '0', null, true, 0, 'new', 'last']
|
||||
],
|
||||
'not strict' => [
|
||||
'insert' => 'new',
|
||||
'before' => 0,
|
||||
'strict' => false,
|
||||
'splat' => false,
|
||||
'expected' => ['abc', '', [1,2,3], 'def', '0', 'new', null, true, 0, 'last']
|
||||
],
|
||||
'after array' => [
|
||||
'insert' => 'new',
|
||||
'before' => [1,2,3],
|
||||
'strict' => true,
|
||||
'splat' => false,
|
||||
'expected' => ['abc', '', [1,2,3], 'new', 'def', '0', null, true, 0, 'last']
|
||||
],
|
||||
'after missing array' => [
|
||||
'insert' => 'new',
|
||||
'before' => ['a', 'b', 'c'],
|
||||
'strict' => true,
|
||||
'splat' => false,
|
||||
'expected' => ['abc', '', [1,2,3], 'def', '0', null, true, 0, 'last', 'new']
|
||||
],
|
||||
'splat array' => [
|
||||
'insert' => ['a', 'b', 'c'],
|
||||
'before' => 'def',
|
||||
'strict' => true,
|
||||
'splat' => true,
|
||||
'expected' => ['abc', '', [1,2,3], 'def', 'a', 'b', 'c', '0', null, true, 0, 'last']
|
||||
],
|
||||
'no splat array' => [
|
||||
'insert' => ['a', 'b', 'c'],
|
||||
'before' => 'def',
|
||||
'strict' => true,
|
||||
'splat' => false,
|
||||
'expected' => ['abc', '', [1,2,3], 'def', ['a', 'b', 'c'], '0', null, true, 0, 'last']
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideInsertAfter
|
||||
*/
|
||||
public function testInsertAfter(mixed $insert, mixed $after, bool $strict, bool $splat, array $expected): void
|
||||
{
|
||||
$array = ['abc', '', [1,2,3], 'def', '0', null, true, 0, 'last'];
|
||||
$final = ArrayLib::insertAfter($array, $insert, $after, $strict, $splat);
|
||||
$this->assertSame($expected, $final);
|
||||
}
|
||||
}
|
||||
|
@ -302,4 +302,50 @@ class DBDatetimeTest extends SapphireTest
|
||||
['-59 seconds', '2019-03-03 11:59:01'],
|
||||
];
|
||||
}
|
||||
|
||||
public function provideGetTimeBetween(): array
|
||||
{
|
||||
return [
|
||||
'no time between' => [
|
||||
'timeBefore' => '2019-03-03 12:00:00',
|
||||
'timeAfter' => '2019-03-03 12:00:00',
|
||||
'expected' => '0 seconds',
|
||||
],
|
||||
'one second between' => [
|
||||
'timeBefore' => '2019-03-03 12:00:00',
|
||||
'timeAfter' => '2019-03-03 12:00:01',
|
||||
'expected' => 'one second',
|
||||
],
|
||||
'some seconds between' => [
|
||||
'timeBefore' => '2019-03-03 12:00:00',
|
||||
'timeAfter' => '2019-03-03 12:00:15',
|
||||
'expected' => '15 seconds',
|
||||
],
|
||||
'days and minutes between' => [
|
||||
'timeBefore' => '2019-03-03 12:00:00',
|
||||
'timeAfter' => '2019-03-15 12:05:00',
|
||||
'expected' => '12 days, 5 minutes',
|
||||
],
|
||||
'years, months, and hours between' => [
|
||||
'timeBefore' => '2019-03-03 12:00:00',
|
||||
'timeAfter' => '2028-01-03 17:00:00',
|
||||
'expected' => '8 years, 10 months, 5 hours',
|
||||
],
|
||||
'backwards in time doesnt say "negative" or "-"' => [
|
||||
'timeBefore' => '2019-03-03 12:00:00',
|
||||
'timeAfter' => '2018-01-06 12:01:12',
|
||||
'expected' => 'one year, one month, 27 days, 23 hours, 58 minutes, 48 seconds',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideGetTimeBetween
|
||||
*/
|
||||
public function testGetTimeBetween(string $timeBefore, string $timeAfter, string $expected): void
|
||||
{
|
||||
$before = (new DBDateTime())->setValue($timeBefore);
|
||||
$after = (new DBDateTime())->setValue($timeAfter);
|
||||
$this->assertSame($expected, DBDatetime::getTimeBetween($before, $after));
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user