Merge branch '5' into 6

# Conflicts:
#	src/Core/CoreKernel.php
#	src/ORM/FieldType/DBDatetime.php
This commit is contained in:
Guy Sartorelli 2024-09-17 18:13:59 +12:00
commit 68fb4b0cf6
No known key found for this signature in database
18 changed files with 541 additions and 17 deletions

View File

@ -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);

View File

@ -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'

View File

@ -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
*

View File

@ -331,6 +331,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()
{
}

View File

@ -4,21 +4,31 @@ namespace SilverStripe\Core;
use SilverStripe\Control\HTTPResponse_Exception;
use SilverStripe\Dev\Install\DatabaseAdapterRegistry;
use SilverStripe\ORM\Connect\NullDatabase;
use SilverStripe\ORM\DB;
use Exception;
use LogicException;
/**
* 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
@ -28,6 +38,10 @@ class CoreKernel extends BaseKernel
{
$this->flush = $flush;
if (!$this->bootDatabase) {
DB::set_conn(new NullDatabase());
}
$this->bootPHP();
$this->bootManifests($flush);
$this->bootErrorHandling();
@ -46,6 +60,9 @@ class CoreKernel extends BaseKernel
*/
protected function validateDatabase()
{
if (!$this->bootDatabase) {
return;
}
$databaseConfig = DB::getConfig();
// Fail if no DB is configured
if (empty($databaseConfig['database'])) {
@ -61,6 +78,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;
@ -93,6 +113,9 @@ class CoreKernel extends BaseKernel
*/
protected function bootDatabaseEnvVars()
{
if (!$this->bootDatabase) {
return;
}
// Set default database config
$databaseConfig = $this->getDatabaseConfig();
$databaseConfig['database'] = $this->getDatabaseName();

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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();

View File

@ -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();

View File

@ -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 = [];
@ -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

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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-'

View File

@ -2,6 +2,7 @@
namespace SilverStripe\ORM\FieldType;
use DateTime;
use Exception;
use IntlDateFormatter;
use InvalidArgumentException;
@ -187,6 +188,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);
}
/**
* Returns either the current system date as determined
* by date(), or a mocked date through {@link set_mock_now()}.

View File

@ -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);
}
}
}

View File

@ -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);
}
}

View File

@ -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));
}
}