diff --git a/cli-script.php b/cli-script.php
index cb88be8e5be..879b2de6546 100755
--- a/cli-script.php
+++ b/cli-script.php
@@ -4,6 +4,9 @@
use SilverStripe\Control\CLIRequestBuilder;
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';
@@ -16,8 +19,17 @@
// Build request and detect flush
$request = CLIRequestBuilder::createFromEnvironment();
+
+$skipDatabase = in_array('--no-database', $argv);
+if ($skipDatabase) {
+ DB::set_conn(new NullDatabase());
+}
// Default application
-$kernel = new CoreKernel(BASE_PATH);
+$kernel = $skipDatabase
+ ? new DatabaselessKernel(BASE_PATH)
+ : new CoreKernel(BASE_PATH);
+
$app = new HTTPApplication($kernel);
$response = $app->handle($request);
+
$response->output();
diff --git a/src/Core/BaseKernel.php b/src/Core/BaseKernel.php
new file mode 100644
index 00000000000..2265cc1b02a
--- /dev/null
+++ b/src/Core/BaseKernel.php
@@ -0,0 +1,507 @@
+basePath = $basePath;
+
+ // Initialise the dependency injector as soon as possible, as it is
+ // subsequently used by some of the following code
+ $injectorLoader = InjectorLoader::inst();
+ $injector = new Injector(['locator' => SilverStripeServiceConfigurationLocator::class]);
+ $injectorLoader->pushManifest($injector);
+ $this->setInjectorLoader($injectorLoader);
+
+ // Manifest cache factory
+ $manifestCacheFactory = $this->buildManifestCacheFactory();
+
+ // Class loader
+ $classLoader = ClassLoader::inst();
+ $classLoader->pushManifest(new ClassManifest($basePath, $manifestCacheFactory));
+ $this->setClassLoader($classLoader);
+
+ // Module loader
+ $moduleLoader = ModuleLoader::inst();
+ $moduleManifest = new ModuleManifest($basePath, $manifestCacheFactory);
+ $moduleLoader->pushManifest($moduleManifest);
+ $this->setModuleLoader($moduleLoader);
+
+ // Config loader
+ // @todo refactor CoreConfigFactory
+ $configFactory = new CoreConfigFactory($manifestCacheFactory);
+ $configManifest = $configFactory->createRoot();
+ $configLoader = ConfigLoader::inst();
+ $configLoader->pushManifest($configManifest);
+ $this->setConfigLoader($configLoader);
+
+ // Load template manifest
+ $themeResourceLoader = ThemeResourceLoader::inst();
+ $themeResourceLoader->addSet(SSViewer::PUBLIC_THEME, new PublicThemes());
+ $themeResourceLoader->addSet(SSViewer::DEFAULT_THEME, new ThemeManifest(
+ $basePath,
+ null, // project is defined in config, and this argument is deprecated
+ $manifestCacheFactory
+ ));
+ $this->setThemeResourceLoader($themeResourceLoader);
+ }
+
+ /**
+ * Initialise PHP with default variables
+ */
+ protected function bootPHP()
+ {
+ if ($this->getEnvironment() === self::LIVE) {
+ // limited to fatal errors and warnings in live mode
+ error_reporting(E_ALL & ~(E_DEPRECATED | E_STRICT | E_NOTICE));
+ } else {
+ // Report all errors in dev / test mode
+ error_reporting(E_ALL | E_STRICT);
+ }
+
+ /**
+ * Ensure we have enough memory
+ */
+ Environment::increaseMemoryLimitTo('64M');
+
+ // Ensure we don't run into xdebug's fairly conservative infinite recursion protection limit
+ if (function_exists('xdebug_enable')) {
+ $current = ini_get('xdebug.max_nesting_level');
+ if ((int)$current < 200) {
+ ini_set('xdebug.max_nesting_level', 200);
+ }
+ }
+
+ /**
+ * Set default encoding
+ */
+ mb_http_output('UTF-8');
+ mb_internal_encoding('UTF-8');
+ mb_regex_encoding('UTF-8');
+
+ /**
+ * Enable better garbage collection
+ */
+ gc_enable();
+ }
+
+ /**
+ * Boot all manifests
+ *
+ * @param bool $flush
+ */
+ protected function bootManifests($flush)
+ {
+ // Setup autoloader
+ $this->getClassLoader()->init(
+ $this->getIncludeTests(),
+ $flush,
+ $this->getIgnoredCIConfigs()
+ );
+
+ // Find modules
+ $this->getModuleLoader()->init(
+ $this->getIncludeTests(),
+ $flush,
+ $this->getIgnoredCIConfigs()
+ );
+
+ // Flush config
+ if ($flush) {
+ $config = $this->getConfigLoader()->getManifest();
+ if ($config instanceof CachedConfigCollection) {
+ $config->setFlush(true);
+ }
+ }
+ // tell modules to sort, now that config is available
+ $this->getModuleLoader()->getManifest()->sort();
+
+ // Find default templates
+ $defaultSet = $this->getThemeResourceLoader()->getSet('$default');
+ if ($defaultSet instanceof ThemeManifest) {
+ $defaultSet->setProject(
+ ModuleManifest::config()->get('project')
+ );
+ $defaultSet->init(
+ $this->getIncludeTests(),
+ $flush,
+ $this->getIgnoredCIConfigs()
+ );
+ }
+ }
+
+ /**
+ * Include all _config.php files
+ */
+ protected function bootConfigs()
+ {
+ global $project;
+ $projectBefore = $project;
+ $config = ModuleManifest::config();
+ // After loading all other app manifests, include _config.php files
+ $this->getModuleLoader()->getManifest()->activateConfig();
+ if ($project && $project !== $projectBefore) {
+ Deprecation::notice('5.0', '$project global is deprecated');
+ $config->set('project', $project);
+ }
+ }
+
+ /**
+ * Turn on error handling
+ * @throws Exception
+ */
+ protected function bootErrorHandling()
+ {
+ // Register error handler
+ $errorHandler = Injector::inst()->get(ErrorHandler::class);
+ $errorHandler->start();
+
+ // Register error log file
+ $errorLog = Environment::getEnv('SS_ERROR_LOG');
+ if ($errorLog) {
+ $logger = Injector::inst()->get(LoggerInterface::class);
+ if ($logger instanceof Logger) {
+ $logger->pushHandler(new StreamHandler($this->basePath . '/' . $errorLog, Logger::WARNING));
+ } else {
+ user_error("SS_ERROR_LOG setting only works with Monolog, you are using another logger", E_USER_WARNING);
+ }
+ }
+ }
+
+ /**
+ * Get the environment type
+ *
+ * @return string
+ *
+ * @deprecated 5.0 use Director::get_environment_type() instead. Since 5.0 it should return only if kernel overrides. No checking SESSION or Environment.
+ */
+ public function getEnvironment()
+ {
+ // Check set
+ if ($this->enviroment) {
+ return $this->enviroment;
+ }
+
+ // Check saved session
+ $env = $this->sessionEnvironment();
+ if ($env) {
+ return $env;
+ }
+
+ // Check getenv
+ if ($env = Environment::getEnv('SS_ENVIRONMENT_TYPE')) {
+ return $env;
+ }
+
+ return self::LIVE;
+ }
+
+ /**
+ * Check or update any temporary environment specified in the session.
+ *
+ * @return null|string
+ *
+ * @deprecated 5.0 Use Director::get_session_environment_type() instead
+ */
+ protected function sessionEnvironment()
+ {
+ if (!$this->booted) {
+ // session is not initialyzed yet, neither is manifest
+ return null;
+ }
+
+ return Director::get_session_environment_type();
+ }
+
+ abstract public function boot($flush = false);
+
+ abstract public function isFlushed();
+
+ /**
+ * Check if there's a legacy _ss_environment.php file
+ *
+ * @throws HTTPResponse_Exception
+ */
+ protected function detectLegacyEnvironment()
+ {
+ // Is there an _ss_environment.php file?
+ if (!file_exists($this->basePath . '/_ss_environment.php') &&
+ !file_exists(dirname($this->basePath) . '/_ss_environment.php')
+ ) {
+ return;
+ }
+
+ // Build error response
+ $dv = new DebugView();
+ $body = implode([
+ $dv->renderHeader(),
+ $dv->renderInfo(
+ "Configuration Error",
+ Director::absoluteBaseURL()
+ ),
+ $dv->renderParagraph(
+ 'You need to replace your _ss_environment.php file with a .env file, or with environment variables.
'
+ . 'See the '
+ . 'Environment Management docs for more information.'
+ ),
+ $dv->renderFooter()
+ ]);
+
+ // Raise error
+ $response = new HTTPResponse($body, 500);
+ throw new HTTPResponse_Exception($response);
+ }
+
+ /**
+ * If missing configuration, redirect to install.php if it exists.
+ * Otherwise show a server error to the user.
+ *
+ * @param string $msg Optional message to show to the user on an installed project (install.php missing).
+ */
+ protected function redirectToInstaller($msg = '')
+ {
+ // Error if installer not available
+ if (!file_exists(Director::publicFolder() . '/install.php')) {
+ throw new HTTPResponse_Exception(
+ $msg,
+ 500
+ );
+ }
+
+ // Redirect to installer
+ $response = new HTTPResponse();
+ $response->redirect(Director::absoluteURL('install.php'));
+ throw new HTTPResponse_Exception($response);
+ }
+
+ /**
+ * @return ManifestCacheFactory
+ */
+ protected function buildManifestCacheFactory()
+ {
+ return new ManifestCacheFactory([
+ 'namespace' => 'manifestcache',
+ 'directory' => TEMP_PATH,
+ ]);
+ }
+
+ /**
+ * When manifests are discovering files, tests files in modules using the following CI library type will be ignored.
+ *
+ * The purpose of this method is to avoid loading PHPUnit test files with incompatible definitions.
+ *
+ * @return string[] List of CI types to ignore as defined by `Module`.
+ */
+ protected function getIgnoredCIConfigs(): array
+ {
+ return [];
+ }
+
+ /**
+ * @return bool
+ */
+ protected function getIncludeTests()
+ {
+ return false;
+ }
+
+ /**
+ * @param bool $bool
+ */
+ protected function setBooted(bool $bool): void
+ {
+ $this->booted = $bool;
+ }
+
+ public function shutdown()
+ {
+ }
+
+ public function nest()
+ {
+ // Clone this kernel, nesting config / injector manifest containers
+ $kernel = clone $this;
+ $kernel->setConfigLoader($this->configLoader->nest());
+ $kernel->setInjectorLoader($this->injectorLoader->nest());
+ $kernel->nestedFrom = $this;
+ return $kernel;
+ }
+
+ public function activate()
+ {
+ $this->configLoader->activate();
+ $this->injectorLoader->activate();
+
+ // Self register
+ $this->getInjectorLoader()
+ ->getManifest()
+ ->registerService($this, Kernel::class);
+ return $this;
+ }
+
+ public function getNestedFrom()
+ {
+ return $this->nestedFrom;
+ }
+
+ public function getContainer()
+ {
+ return $this->getInjectorLoader()->getManifest();
+ }
+
+ public function setInjectorLoader(InjectorLoader $injectorLoader)
+ {
+ $this->injectorLoader = $injectorLoader;
+ $injectorLoader
+ ->getManifest()
+ ->registerService($this, Kernel::class);
+ return $this;
+ }
+
+ public function getInjectorLoader()
+ {
+ return $this->injectorLoader;
+ }
+
+ public function getClassLoader()
+ {
+ return $this->classLoader;
+ }
+
+ public function setClassLoader(ClassLoader $classLoader)
+ {
+ $this->classLoader = $classLoader;
+ return $this;
+ }
+
+ public function getModuleLoader()
+ {
+ return $this->moduleLoader;
+ }
+
+ public function setModuleLoader(ModuleLoader $moduleLoader)
+ {
+ $this->moduleLoader = $moduleLoader;
+ return $this;
+ }
+
+ public function setEnvironment($environment)
+ {
+ if (!in_array($environment, [self::DEV, self::TEST, self::LIVE, null])) {
+ throw new InvalidArgumentException(
+ "Director::set_environment_type passed '$environment'. It should be passed dev, test, or live"
+ );
+ }
+ $this->enviroment = $environment;
+ return $this;
+ }
+
+ public function getConfigLoader()
+ {
+ return $this->configLoader;
+ }
+
+ public function setConfigLoader($configLoader)
+ {
+ $this->configLoader = $configLoader;
+ return $this;
+ }
+
+ public function getThemeResourceLoader()
+ {
+ return $this->themeResourceLoader;
+ }
+
+ public function setThemeResourceLoader($themeResourceLoader)
+ {
+ $this->themeResourceLoader = $themeResourceLoader;
+ return $this;
+ }
+}
diff --git a/src/Core/CoreKernel.php b/src/Core/CoreKernel.php
index 89bbac01472..baa420f92de 100644
--- a/src/Core/CoreKernel.php
+++ b/src/Core/CoreKernel.php
@@ -2,190 +2,30 @@
namespace SilverStripe\Core;
-use InvalidArgumentException;
-use Monolog\Handler\StreamHandler;
-use Monolog\Logger;
-use Psr\Log\LoggerInterface;
-use SilverStripe\Config\Collections\CachedConfigCollection;
-use SilverStripe\Control\Director;
-use SilverStripe\Control\HTTPResponse;
use SilverStripe\Control\HTTPResponse_Exception;
-use SilverStripe\Core\Cache\ManifestCacheFactory;
-use SilverStripe\Core\Config\ConfigLoader;
-use SilverStripe\Core\Config\CoreConfigFactory;
-use SilverStripe\Core\Injector\Injector;
-use SilverStripe\Core\Injector\InjectorLoader;
-use SilverStripe\Core\Injector\SilverStripeServiceConfigurationLocator;
-use SilverStripe\Core\Manifest\ClassLoader;
-use SilverStripe\Core\Manifest\ClassManifest;
-use SilverStripe\Core\Manifest\ModuleLoader;
-use SilverStripe\Core\Manifest\ModuleManifest;
-use SilverStripe\Dev\DebugView;
use SilverStripe\Dev\Install\DatabaseAdapterRegistry;
-use SilverStripe\Logging\ErrorHandler;
use SilverStripe\ORM\DB;
-use SilverStripe\View\PublicThemes;
-use SilverStripe\View\SSViewer;
-use SilverStripe\View\ThemeManifest;
-use SilverStripe\View\ThemeResourceLoader;
-use SilverStripe\Dev\Deprecation;
+use Exception;
/**
* Simple Kernel container
*/
-class CoreKernel implements Kernel
+class CoreKernel extends BaseKernel
{
- /**
- * @var Kernel
- */
- protected $nestedFrom = null;
-
- /**
- * @var Injector
- */
- protected $container = null;
-
- /**
- * @var string
- */
- protected $environment = null;
-
- /**
- * @var ClassLoader
- */
- protected $classLoader = null;
-
- /**
- * @var ModuleLoader
- */
- protected $moduleLoader = null;
-
- /**
- * @var ConfigLoader
- */
- protected $configLoader = null;
-
- /**
- * @var InjectorLoader
- */
- protected $injectorLoader = null;
-
- /**
- * @var ThemeResourceLoader
- */
- protected $themeResourceLoader = null;
-
- protected $basePath = null;
-
- /**
- * Indicates whether the Kernel has been booted already
- *
- * @var bool
- */
- private $booted = false;
/**
* Indicates whether the Kernel has been flushed on boot
- * Uninitialized before boot
+ * Uninitialised before boot
*
* @var bool
*/
private $flush;
/**
- * Create a new kernel for this application
- *
- * @param string $basePath Path to base dir for this application
- */
- public function __construct($basePath)
- {
- $this->basePath = $basePath;
-
- // Initialise the dependency injector as soon as possible, as it is
- // subsequently used by some of the following code
- $injectorLoader = InjectorLoader::inst();
- $injector = new Injector(['locator' => SilverStripeServiceConfigurationLocator::class]);
- $injectorLoader->pushManifest($injector);
- $this->setInjectorLoader($injectorLoader);
-
- // Manifest cache factory
- $manifestCacheFactory = $this->buildManifestCacheFactory();
-
- // Class loader
- $classLoader = ClassLoader::inst();
- $classLoader->pushManifest(new ClassManifest($basePath, $manifestCacheFactory));
- $this->setClassLoader($classLoader);
-
- // Module loader
- $moduleLoader = ModuleLoader::inst();
- $moduleManifest = new ModuleManifest($basePath, $manifestCacheFactory);
- $moduleLoader->pushManifest($moduleManifest);
- $this->setModuleLoader($moduleLoader);
-
- // Config loader
- // @todo refactor CoreConfigFactory
- $configFactory = new CoreConfigFactory($manifestCacheFactory);
- $configManifest = $configFactory->createRoot();
- $configLoader = ConfigLoader::inst();
- $configLoader->pushManifest($configManifest);
- $this->setConfigLoader($configLoader);
-
- // Load template manifest
- $themeResourceLoader = ThemeResourceLoader::inst();
- $themeResourceLoader->addSet(SSViewer::PUBLIC_THEME, new PublicThemes());
- $themeResourceLoader->addSet(SSViewer::DEFAULT_THEME, new ThemeManifest(
- $basePath,
- null, // project is defined in config, and this argument is deprecated
- $manifestCacheFactory
- ));
- $this->setThemeResourceLoader($themeResourceLoader);
- }
-
- /**
- * Get the environment type
- *
- * @return string
- *
- * @deprecated 5.0 use Director::get_environment_type() instead. Since 5.0 it should return only if kernel overrides. No checking SESSION or Environment.
- */
- public function getEnvironment()
- {
- // Check set
- if ($this->environment) {
- return $this->environment;
- }
-
- // Check saved session
- $env = $this->sessionEnvironment();
- if ($env) {
- return $env;
- }
-
- // Check getenv
- if ($env = Environment::getEnv('SS_ENVIRONMENT_TYPE')) {
- return $env;
- }
-
- return self::LIVE;
- }
-
- /**
- * Check or update any temporary environment specified in the session.
- *
- * @return null|string
- *
- * @deprecated 5.0 Use Director::get_session_environment_type() instead
+ * @param false $flush
+ * @throws HTTPResponse_Exception
+ * @throws Exception
*/
- protected function sessionEnvironment()
- {
- if (!$this->booted) {
- // session is not initialized yet, neither is manifest
- return null;
- }
-
- return Director::get_session_environment_type();
- }
-
public function boot($flush = false)
{
$this->flush = $flush;
@@ -198,22 +38,23 @@ public function boot($flush = false)
$this->bootDatabaseGlobals();
$this->validateDatabase();
- $this->booted = true;
+ $this->setBooted(true);
}
/**
- * Include all _config.php files
+ * Check that the database configuration is valid, throwing an HTTPResponse_Exception if it's not
+ *
+ * @throws HTTPResponse_Exception
*/
- protected function bootConfigs()
+ protected function validateDatabase()
{
- global $project;
- $projectBefore = $project;
- $config = ModuleManifest::config();
- // After loading all other app manifests, include _config.php files
- $this->getModuleLoader()->getManifest()->activateConfig();
- if ($project && $project !== $projectBefore) {
- Deprecation::notice('5.0', '$project global is deprecated');
- $config->set('project', $project);
+ $databaseConfig = DB::getConfig();
+ // Gracefully fail if no DB is configured
+ if (empty($databaseConfig['database'])) {
+ $msg = 'Silverstripe Framework requires a "database" key in DB::getConfig(). ' .
+ 'Did you forget to set SS_DATABASE_NAME or SS_DATABASE_CHOOSE_NAME in your environment?';
+ $this->detectLegacyEnvironment();
+ $this->redirectToInstaller($msg);
}
}
@@ -260,80 +101,6 @@ protected function bootDatabaseEnvVars()
DB::setConfig($databaseConfig);
}
- /**
- * Check that the database configuration is valid, throwing an HTTPResponse_Exception if it's not
- *
- * @throws HTTPResponse_Exception
- */
- protected function validateDatabase()
- {
- $databaseConfig = DB::getConfig();
- // Gracefully fail if no DB is configured
- if (empty($databaseConfig['database'])) {
- $msg = 'Silverstripe Framework requires a "database" key in DB::getConfig(). ' .
- 'Did you forget to set SS_DATABASE_NAME or SS_DATABASE_CHOOSE_NAME in your environment?';
- $this->detectLegacyEnvironment();
- $this->redirectToInstaller($msg);
- }
- }
-
- /**
- * Check if there's a legacy _ss_environment.php file
- *
- * @throws HTTPResponse_Exception
- */
- protected function detectLegacyEnvironment()
- {
- // Is there an _ss_environment.php file?
- if (!file_exists($this->basePath . '/_ss_environment.php') &&
- !file_exists(dirname($this->basePath) . '/_ss_environment.php')
- ) {
- return;
- }
-
- // Build error response
- $dv = new DebugView();
- $body = implode([
- $dv->renderHeader(),
- $dv->renderInfo(
- "Configuration Error",
- Director::absoluteBaseURL()
- ),
- $dv->renderParagraph(
- 'You need to replace your _ss_environment.php file with a .env file, or with environment variables.
'
- . 'See the '
- . 'Environment Management docs for more information.'
- ),
- $dv->renderFooter()
- ]);
-
- // Raise error
- $response = new HTTPResponse($body, 500);
- throw new HTTPResponse_Exception($response);
- }
-
- /**
- * If missing configuration, redirect to install.php if it exists.
- * Otherwise show a server error to the user.
- *
- * @param string $msg Optional message to show to the user on an installed project (install.php missing).
- */
- protected function redirectToInstaller($msg = '')
- {
- // Error if installer not available
- if (!file_exists(Director::publicFolder() . '/install.php')) {
- throw new HTTPResponse_Exception(
- $msg,
- 500
- );
- }
-
- // Redirect to installer
- $response = new HTTPResponse();
- $response->redirect(Director::absoluteURL('install.php'));
- throw new HTTPResponse_Exception($response);
- }
-
/**
* Load database config from environment
*
@@ -451,247 +218,6 @@ protected function getDatabaseName()
return null;
}
- /**
- * Initialise PHP with default variables
- */
- protected function bootPHP()
- {
- if ($this->getEnvironment() === self::LIVE) {
- // limited to fatal errors and warnings in live mode
- error_reporting(E_ALL & ~(E_DEPRECATED | E_STRICT | E_NOTICE));
- } else {
- // Report all errors in dev / test mode
- error_reporting(E_ALL | E_STRICT);
- }
-
- /**
- * Ensure we have enough memory
- */
- Environment::increaseMemoryLimitTo('64M');
-
- // Ensure we don't run into xdebug's fairly conservative infinite recursion protection limit
- if (function_exists('xdebug_enable')) {
- $current = ini_get('xdebug.max_nesting_level');
- if ((int)$current < 200) {
- ini_set('xdebug.max_nesting_level', 200);
- }
- }
-
- /**
- * Set default encoding
- */
- mb_http_output('UTF-8');
- mb_internal_encoding('UTF-8');
- mb_regex_encoding('UTF-8');
-
- /**
- * Enable better garbage collection
- */
- gc_enable();
- }
-
- /**
- * @return ManifestCacheFactory
- */
- protected function buildManifestCacheFactory()
- {
- return new ManifestCacheFactory([
- 'namespace' => 'manifestcache',
- 'directory' => TEMP_PATH,
- ]);
- }
-
- /**
- * @return bool
- */
- protected function getIncludeTests()
- {
- return false;
- }
-
- /**
- * When manifests are discovering files, tests files in modules using the following CI library type will be ignored.
- *
- * The purpose of this method is to avoid loading PHPUnit test files with incompatible definitions.
- *
- * @return string[] List of CI types to ignore as defined by `Module`.
- */
- protected function getIgnoredCIConfigs(): array
- {
- return [];
- }
-
- /**
- * Boot all manifests
- *
- * @param bool $flush
- */
- protected function bootManifests($flush)
- {
- // Setup autoloader
- $this->getClassLoader()->init(
- $this->getIncludeTests(),
- $flush,
- $this->getIgnoredCIConfigs()
- );
-
- // Find modules
- $this->getModuleLoader()->init(
- $this->getIncludeTests(),
- $flush,
- $this->getIgnoredCIConfigs()
- );
-
- // Flush config
- if ($flush) {
- $config = $this->getConfigLoader()->getManifest();
- if ($config instanceof CachedConfigCollection) {
- $config->setFlush(true);
- }
- }
- // tell modules to sort, now that config is available
- $this->getModuleLoader()->getManifest()->sort();
-
- // Find default templates
- $defaultSet = $this->getThemeResourceLoader()->getSet('$default');
- if ($defaultSet instanceof ThemeManifest) {
- $defaultSet->setProject(
- ModuleManifest::config()->get('project')
- );
- $defaultSet->init(
- $this->getIncludeTests(),
- $flush,
- $this->getIgnoredCIConfigs()
- );
- }
- }
-
- /**
- * Turn on error handling
- */
- protected function bootErrorHandling()
- {
- // Register error handler
- $errorHandler = Injector::inst()->get(ErrorHandler::class);
- $errorHandler->start();
-
- // Register error log file
- $errorLog = Environment::getEnv('SS_ERROR_LOG');
- if ($errorLog) {
- $logger = Injector::inst()->get(LoggerInterface::class);
- if ($logger instanceof Logger) {
- $logger->pushHandler(new StreamHandler($this->basePath . '/' . $errorLog, Logger::WARNING));
- } else {
- user_error("SS_ERROR_LOG setting only works with Monolog, you are using another logger", E_USER_WARNING);
- }
- }
- }
-
- public function shutdown()
- {
- }
-
- public function nest()
- {
- // Clone this kernel, nesting config / injector manifest containers
- $kernel = clone $this;
- $kernel->setConfigLoader($this->configLoader->nest());
- $kernel->setInjectorLoader($this->injectorLoader->nest());
- $kernel->nestedFrom = $this;
- return $kernel;
- }
-
- public function activate()
- {
- $this->configLoader->activate();
- $this->injectorLoader->activate();
-
- // Self register
- $this->getInjectorLoader()
- ->getManifest()
- ->registerService($this, Kernel::class);
- return $this;
- }
-
- public function getNestedFrom()
- {
- return $this->nestedFrom;
- }
-
- public function getContainer()
- {
- return $this->getInjectorLoader()->getManifest();
- }
-
- public function setInjectorLoader(InjectorLoader $injectorLoader)
- {
- $this->injectorLoader = $injectorLoader;
- $injectorLoader
- ->getManifest()
- ->registerService($this, Kernel::class);
- return $this;
- }
-
- public function getInjectorLoader()
- {
- return $this->injectorLoader;
- }
-
- public function getClassLoader()
- {
- return $this->classLoader;
- }
-
- public function setClassLoader(ClassLoader $classLoader)
- {
- $this->classLoader = $classLoader;
- return $this;
- }
-
- public function getModuleLoader()
- {
- return $this->moduleLoader;
- }
-
- public function setModuleLoader(ModuleLoader $moduleLoader)
- {
- $this->moduleLoader = $moduleLoader;
- return $this;
- }
-
- public function setEnvironment($environment)
- {
- if (!in_array($environment, [self::DEV, self::TEST, self::LIVE, null])) {
- throw new InvalidArgumentException(
- "Director::set_environment_type passed '$environment'. It should be passed dev, test, or live"
- );
- }
- $this->environment = $environment;
- return $this;
- }
-
- public function getConfigLoader()
- {
- return $this->configLoader;
- }
-
- public function setConfigLoader($configLoader)
- {
- $this->configLoader = $configLoader;
- return $this;
- }
-
- public function getThemeResourceLoader()
- {
- return $this->themeResourceLoader;
- }
-
- public function setThemeResourceLoader($themeResourceLoader)
- {
- $this->themeResourceLoader = $themeResourceLoader;
- return $this;
- }
-
/**
* Returns whether the Kernel has been flushed on boot
*
diff --git a/src/Core/DatabaselessKernel.php b/src/Core/DatabaselessKernel.php
new file mode 100644
index 00000000000..d5c981ba462
--- /dev/null
+++ b/src/Core/DatabaselessKernel.php
@@ -0,0 +1,63 @@
+bootErrorHandling = $bool;
+ return $this;
+ }
+
+ /**
+ * @param false $flush
+ * @throws Exception
+ */
+ public function boot($flush = false)
+ {
+ $this->flush = $flush;
+
+ $this->bootPHP();
+ $this->bootManifests($flush);
+ $this->bootErrorHandling();
+ $this->bootConfigs();
+
+ $this->setBooted(true);
+ }
+
+ /**
+ * @return bool
+ */
+ public function isFlushed()
+ {
+ return $this->flush;
+ }
+}
diff --git a/src/ORM/Connect/NullDatabase.php b/src/ORM/Connect/NullDatabase.php
new file mode 100644
index 00000000000..73d2ab893a8
--- /dev/null
+++ b/src/ORM/Connect/NullDatabase.php
@@ -0,0 +1,336 @@
+errorMessage = $msg;
+ return $this;
+ }
+
+ /**
+ * @param string $msg
+ */
+ public function setQueryErrorMessage(string $msg): self
+ {
+ $this->queryErrorMessage = $msg;
+ return $this;
+ }
+
+ /**
+ * @throws NullDatabaseException
+ */
+ public function query($sql, $errorLevel = E_USER_ERROR)
+ {
+ throw new NullDatabaseException(sprintf($this->queryErrorMessage, $sql));
+ }
+
+ /**
+ * @throws NullDatabaseException
+ */
+ public function preparedQuery($sql, $parameters, $errorLevel = E_USER_ERROR)
+ {
+ throw new NullDatabaseException(sprintf($this->queryErrorMessage, $sql));
+ }
+
+ /**
+ * @throws NullDatabaseException
+ */
+ public function getConnector()
+ {
+ throw new NullDatabaseException($this->errorMessage);
+ }
+
+ /**
+ * @throws NullDatabaseException
+ */
+ public function getSchemaManager()
+ {
+ throw new NullDatabaseException($this->errorMessage);
+ }
+
+ /**
+ * @throws NullDatabaseException
+ */
+ public function getQueryBuilder()
+ {
+ throw new NullDatabaseException($this->errorMessage);
+ }
+
+
+ public function getGeneratedID($table)
+ {
+ // no-op
+ }
+
+ public function isActive()
+ {
+ return true;
+ }
+
+ public function escapeString($value)
+ {
+ return $value;
+ }
+
+ public function quoteString($value)
+ {
+ return $value;
+ }
+
+ public function escapeIdentifier($value, $separator = '.')
+ {
+ return $value;
+ }
+
+ protected function escapeColumnKeys($fieldValues)
+ {
+ return $fieldValues;
+ }
+
+ /**
+ * @throws NullDatabaseException
+ */
+ public function manipulate($manipulation)
+ {
+ throw new NullDatabaseException($this->errorMessage);
+ }
+
+ /**
+ * @throws NullDatabaseException
+ */
+ public function clearAllData()
+ {
+ throw new NullDatabaseException($this->errorMessage);
+ }
+
+ /**
+ * @throws NullDatabaseException
+ */
+ public function clearTable($table)
+ {
+ throw new NullDatabaseException($this->errorMessage);
+ }
+
+ public function nullCheckClause($field, $isNull)
+ {
+ return '';
+ }
+
+ public function comparisonClause(
+ $field,
+ $value,
+ $exact = false,
+ $negate = false,
+ $caseSensitive = null,
+ $parameterised = false
+ ) {
+ return '';
+ }
+
+ public function formattedDatetimeClause($date, $format)
+ {
+ return '';
+ }
+
+ public function datetimeIntervalClause($date, $interval)
+ {
+ return '';
+ }
+
+ public function datetimeDifferenceClause($date1, $date2)
+ {
+ return '';
+ }
+
+ public function concatOperator()
+ {
+ return '';
+ }
+
+ public function supportsCollations()
+ {
+ return false;
+ }
+
+ public function supportsTimezoneOverride()
+ {
+ return false;
+ }
+
+ public function getVersion()
+ {
+ return '';
+ }
+
+ public function getDatabaseServer()
+ {
+ return '';
+ }
+
+ public function affectedRows()
+ {
+ return 0;
+ }
+
+ public function searchEngine(
+ $classesToSearch,
+ $keywords,
+ $start,
+ $pageLength,
+ $sortBy = "Relevance DESC",
+ $extraFilter = "",
+ $booleanSearch = false,
+ $alternativeFileFilter = "",
+ $invertedMatch = false
+ ) {
+ // no-op
+ }
+
+ public function supportsTransactions()
+ {
+ return false;
+ }
+
+ public function supportsSavepoints()
+ {
+ return false;
+ }
+
+
+ public function supportsTransactionMode(string $mode): bool
+ {
+ return false;
+ }
+
+ public function withTransaction(
+ $callback,
+ $errorCallback = null,
+ $transactionMode = false,
+ $errorIfTransactionsUnsupported = false
+ ) {
+ // no-op
+ }
+
+ public function supportsExtensions($extensions)
+ {
+ return false;
+ }
+
+ public function transactionStart($transactionMode = false, $sessionCharacteristics = false)
+ {
+ // no-op
+ }
+
+ public function transactionSavepoint($savepoint)
+ {
+ // no-op
+ }
+
+ public function transactionRollback($savepoint = false)
+ {
+ // no-op
+ }
+
+ public function transactionEnd($chain = false)
+ {
+ // no-op
+ }
+
+ public function transactionDepth()
+ {
+ return 0;
+ }
+
+ public function supportsLocks()
+ {
+ return false;
+ }
+
+ public function canLock($name)
+ {
+ return false;
+ }
+
+ public function getLock($name, $timeout = 5)
+ {
+ return false;
+ }
+
+ public function releaseLock($name)
+ {
+ return false;
+ }
+
+ public function connect($parameters)
+ {
+ // no-op
+ }
+
+ public function databaseExists($name)
+ {
+ return false;
+ }
+
+ public function databaseList()
+ {
+ return [];
+ }
+
+ public function selectDatabase($name, $create = false, $errorLevel = E_USER_ERROR)
+ {
+ // no-op
+ }
+
+ public function dropSelectedDatabase()
+ {
+ // no-op
+ }
+
+ public function getSelectedDatabase()
+ {
+ // no-op
+ }
+
+ public function now()
+ {
+ return '';
+ }
+
+ public function random()
+ {
+ return '';
+ }
+}
diff --git a/src/ORM/Connect/NullDatabaseException.php b/src/ORM/Connect/NullDatabaseException.php
new file mode 100644
index 00000000000..68a7e6b621e
--- /dev/null
+++ b/src/ORM/Connect/NullDatabaseException.php
@@ -0,0 +1,12 @@
+