forked from silverstripe/silverstripe-framework
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
NEW DatabaselessKernel to support operation without DB
This is required for GraphQL code generation in CI (without a working runtime database/webserver environment). Context: silverstripe/silverstripe-graphql#388
- Loading branch information
Showing
3 changed files
with
368 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
<?php | ||
|
||
namespace SilverStripe\Core; | ||
|
||
use SilverStripe\EventDispatcher\Dispatch\Dispatcher; | ||
use SilverStripe\EventDispatcher\Event\EventContextInterface; | ||
use SilverStripe\EventDispatcher\Event\EventHandlerInterface; | ||
use SilverStripe\ORM\Connect\NullDatabase; | ||
use SilverStripe\ORM\DB; | ||
|
||
/** | ||
* Boot a kernel without requiring a database connection. | ||
* This is a workaround for the lack of composition in the boot stages | ||
* of CoreKernel, as well as for the framework's misguided assumptions | ||
* around the availability of a database for every execution path. | ||
* | ||
* @internal | ||
*/ | ||
class DatabaselessKernel extends CoreKernel | ||
{ | ||
protected $queryErrorMessage = 'Booted with DatabaseLessKernel, cannot execute query: %s'; | ||
|
||
/** | ||
* Allows disabling of the configured error handling. | ||
* This can be useful to ensure the execution context (e.g. composer) | ||
* can consistently use its own error handling. | ||
* | ||
* @var boolean | ||
*/ | ||
protected $bootErrorHandling = true; | ||
|
||
public function setBootErrorHandling(bool $bool) | ||
{ | ||
$this->bootErrorHandling = $bool; | ||
return $this; | ||
} | ||
|
||
public function boot($flush = false) | ||
{ | ||
$this->flush = $flush; | ||
|
||
$this->bootPHP(); | ||
$this->bootManifests($flush); | ||
|
||
if ($this->bootErrorHandling) { | ||
$this->bootErrorHandling(); | ||
} | ||
|
||
$this->bootConfigs(); | ||
|
||
$this->booted = true; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,314 @@ | ||
<?php | ||
|
||
namespace SilverStripe\ORM\Connect; | ||
|
||
use BadMethodCallException; | ||
use Exception; | ||
|
||
/** | ||
* Utility class required due to bad coupling in framework. | ||
* Not every framework execution should require a working database connection. | ||
* For example, when generating class and config manifests for deployment bundles, | ||
* or when generating code in a silverstripe/graphql schema build. | ||
* | ||
* This class creates the required no-ops to fulfill the contract, | ||
* and create exceptions as required. | ||
* | ||
* It also avoids introducing new third party core dependencies that | ||
* would be required with https://github.com/tractorcow/silverstripe-proxy-db. | ||
* | ||
* @internal | ||
*/ | ||
class NullDatabase extends Database | ||
{ | ||
|
||
/** | ||
* @var string | ||
*/ | ||
protected $errorMessage = 'Using NullDatabase, cannot interact with database'; | ||
|
||
/** | ||
* @var string | ||
*/ | ||
protected $queryErrorMessage = 'Using NullDatabase, cannot execute query: %s'; | ||
|
||
/** | ||
* @param string $msg | ||
* @return self | ||
*/ | ||
public function setErrorMessage(string $msg) | ||
{ | ||
$this->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 ''; | ||
} | ||
} |