From d25e0fa38eba433932ed901cb14271958cd981e9 Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Mon, 12 Jul 2021 21:24:26 +1200 Subject: [PATCH] NEW DatabaselessKernel to support operation without DB This is required for GraphQL code generation in CI (without a working runtime database/webserver environment). Context: https://github.com/silverstripe/silverstripe-graphql/issues/388 --- composer.json | 1 + src/Core/DatabaselessKernel.php | 35 ++++ src/ORM/Connect/Database.php | 17 ++ src/ORM/Connect/NullDatabase.php | 314 +++++++++++++++++++++++++++++++ 4 files changed, 367 insertions(+) create mode 100644 src/Core/DatabaselessKernel.php create mode 100644 src/ORM/Connect/NullDatabase.php diff --git a/composer.json b/composer.json index 520853c7292..d0010388653 100644 --- a/composer.json +++ b/composer.json @@ -32,6 +32,7 @@ "psr/container": "1.0.0", "silverstripe/config": "^1@dev", "silverstripe/assets": "^1@dev", + "silverstripe/event-dispatcher": "^0.1.0", "silverstripe/vendor-plugin": "^1.4", "sminnee/callbacklist": "^0.1", "swiftmailer/swiftmailer": "~5.4", diff --git a/src/Core/DatabaselessKernel.php b/src/Core/DatabaselessKernel.php new file mode 100644 index 00000000000..5d4ec4d2541 --- /dev/null +++ b/src/Core/DatabaselessKernel.php @@ -0,0 +1,35 @@ +flush = $flush; + + $this->bootPHP(); + $this->bootManifests($flush); + $this->bootErrorHandling(); + $this->bootConfigs(); + + $this->booted = true; + } + +} diff --git a/src/ORM/Connect/Database.php b/src/ORM/Connect/Database.php index 0eba456329f..82fe134ec21 100644 --- a/src/ORM/Connect/Database.php +++ b/src/ORM/Connect/Database.php @@ -9,6 +9,8 @@ use SilverStripe\ORM\PaginatedList; use SilverStripe\ORM\Queries\SQLUpdate; use SilverStripe\ORM\Queries\SQLInsert; +use SilverStripe\EventDispatcher\Dispatch\Dispatcher; +use SilverStripe\EventDispatcher\Symfony\Event; use BadMethodCallException; use Exception; use SilverStripe\Dev\Backtrace; @@ -151,6 +153,13 @@ public function query($sql, $errorLevel = E_USER_ERROR) return null; } + Dispatcher::singleton()->trigger('database.query', Event::create( + null, + [ + 'sql' => $sql + ] + )); + // Benchmark query $connector = $this->connector; return $this->benchmarkQuery( @@ -177,6 +186,14 @@ public function preparedQuery($sql, $parameters, $errorLevel = E_USER_ERROR) return null; } + Dispatcher::singleton()->trigger('database.preparedQuery', Event::create( + null, + [ + 'sql' => $sql, + 'parameters' => $parameters + ] + )); + // Benchmark query $connector = $this->connector; return $this->benchmarkQuery( diff --git a/src/ORM/Connect/NullDatabase.php b/src/ORM/Connect/NullDatabase.php new file mode 100644 index 00000000000..eed77578e63 --- /dev/null +++ b/src/ORM/Connect/NullDatabase.php @@ -0,0 +1,314 @@ +errorMessage = $msg; + return $this; + } + + /** + * @param string $msg + * @return self + */ + public function setQueryErrorMessage(string $msg) + { + $this->queryErrorMessage = $msg; + return $this; + } + + public function query($sql, $errorLevel = E_USER_ERROR) + { + throw new \LogicException(sprintf($this->queryErrorMessage, $sql)); + } + + public function preparedQuery($sql, $parameters, $errorLevel = E_USER_ERROR) + { + throw new \LogicException(sprintf($this->queryErrorMessage, $sql)); + } + + public function getConnector() + { + throw new \LogicException($this->errorMessage); + } + + public function getSchemaManager() + { + throw new \LogicException($this->errorMessage); + } + + public function getQueryBuilder() + { + throw new \LogicException($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; + } + + public function manipulate($manipulation) + { + throw new \LogicException($this->errorMessage); + } + + public function clearAllData() + { + throw new \LogicException($this->errorMessage); + } + + public function clearTable($table) + { + throw new \LogicException($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 ''; + } +}