mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
API Moving tests to use transactions
This commit is contained in:
parent
77a45c0dbc
commit
ec956a682d
@ -8,6 +8,7 @@ SilverStripe\Core\Injector\Injector:
|
|||||||
globals: '%$SilverStripe\Dev\State\GlobalsTestState'
|
globals: '%$SilverStripe\Dev\State\GlobalsTestState'
|
||||||
extensions: '%$SilverStripe\Dev\State\ExtensionTestState'
|
extensions: '%$SilverStripe\Dev\State\ExtensionTestState'
|
||||||
flushable: '%$SilverStripe\Dev\State\FlushableTestState'
|
flushable: '%$SilverStripe\Dev\State\FlushableTestState'
|
||||||
|
fixtures: '%$SilverStripe\Dev\State\FixtureTestState'
|
||||||
requirements: '%$SilverStripe\View\Dev\RequirementsTestState'
|
requirements: '%$SilverStripe\View\Dev\RequirementsTestState'
|
||||||
ssviewer: '%$SilverStripe\View\Dev\SSViewerTestState'
|
ssviewer: '%$SilverStripe\View\Dev\SSViewerTestState'
|
||||||
---
|
---
|
||||||
|
@ -41,7 +41,7 @@ class FixtureFactory
|
|||||||
protected $fixtures = array();
|
protected $fixtures = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array Callbacks
|
* @var FixtureBlueprint[] Callbacks
|
||||||
*/
|
*/
|
||||||
protected $blueprints = array();
|
protected $blueprints = array();
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ use SilverStripe\Core\Manifest\ClassLoader;
|
|||||||
use SilverStripe\Dev\Constraint\SSListContains;
|
use SilverStripe\Dev\Constraint\SSListContains;
|
||||||
use SilverStripe\Dev\Constraint\SSListContainsOnly;
|
use SilverStripe\Dev\Constraint\SSListContainsOnly;
|
||||||
use SilverStripe\Dev\Constraint\SSListContainsOnlyMatchingItems;
|
use SilverStripe\Dev\Constraint\SSListContainsOnlyMatchingItems;
|
||||||
|
use SilverStripe\Dev\State\FixtureTestState;
|
||||||
use SilverStripe\Dev\State\SapphireTestState;
|
use SilverStripe\Dev\State\SapphireTestState;
|
||||||
use SilverStripe\Dev\State\TestState;
|
use SilverStripe\Dev\State\TestState;
|
||||||
use SilverStripe\i18n\i18n;
|
use SilverStripe\i18n\i18n;
|
||||||
@ -148,7 +149,7 @@ class SapphireTest extends PHPUnit_Framework_TestCase implements TestOnly
|
|||||||
/**
|
/**
|
||||||
* State management container for SapphireTest
|
* State management container for SapphireTest
|
||||||
*
|
*
|
||||||
* @var TestState
|
* @var SapphireTestState
|
||||||
*/
|
*/
|
||||||
protected static $state = null;
|
protected static $state = null;
|
||||||
|
|
||||||
@ -159,6 +160,17 @@ class SapphireTest extends PHPUnit_Framework_TestCase implements TestOnly
|
|||||||
*/
|
*/
|
||||||
protected static $tempDB = null;
|
protected static $tempDB = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return TempDatabase
|
||||||
|
*/
|
||||||
|
public static function tempDB()
|
||||||
|
{
|
||||||
|
if (!static::$tempDB) {
|
||||||
|
static::$tempDB = TempDatabase::create();
|
||||||
|
}
|
||||||
|
return static::$tempDB;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets illegal extensions for this class
|
* Gets illegal extensions for this class
|
||||||
*
|
*
|
||||||
@ -208,6 +220,22 @@ class SapphireTest extends PHPUnit_Framework_TestCase implements TestOnly
|
|||||||
return static::$fixture_file;
|
return static::$fixture_file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function getUsesDatabase()
|
||||||
|
{
|
||||||
|
return $this->usesDatabase;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getRequireDefaultRecordsFrom()
|
||||||
|
{
|
||||||
|
return $this->requireDefaultRecordsFrom;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup the test.
|
* Setup the test.
|
||||||
* Always sets up in order:
|
* Always sets up in order:
|
||||||
@ -254,31 +282,10 @@ class SapphireTest extends PHPUnit_Framework_TestCase implements TestOnly
|
|||||||
|
|
||||||
$fixtureFiles = $this->getFixturePaths();
|
$fixtureFiles = $this->getFixturePaths();
|
||||||
|
|
||||||
// Set up fixture
|
|
||||||
if ($this->shouldSetupDatabaseForCurrentTest($fixtureFiles)) {
|
if ($this->shouldSetupDatabaseForCurrentTest($fixtureFiles)) {
|
||||||
if (!static::$tempDB->isUsed()) {
|
/** @var FixtureTestState $fixtureState */
|
||||||
static::$tempDB->build();
|
$fixtureState = static::$state->getStateByName('fixtures');
|
||||||
}
|
$this->setFixtureFactory($fixtureState->getFixtureFactory(static::class));
|
||||||
|
|
||||||
DataObject::singleton()->flushCache();
|
|
||||||
|
|
||||||
static::$tempDB->clearAllData();
|
|
||||||
|
|
||||||
foreach ($this->requireDefaultRecordsFrom as $className) {
|
|
||||||
$instance = singleton($className);
|
|
||||||
if (method_exists($instance, 'requireDefaultRecords')) {
|
|
||||||
$instance->requireDefaultRecords();
|
|
||||||
}
|
|
||||||
if (method_exists($instance, 'augmentDefaultRecords')) {
|
|
||||||
$instance->augmentDefaultRecords();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($fixtureFiles as $fixtureFilePath) {
|
|
||||||
$fixture = YamlFixture::create($fixtureFilePath);
|
|
||||||
$fixture->writeInto($this->getFixtureFactory());
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->logInWithPermission('ADMIN');
|
$this->logInWithPermission('ADMIN');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -393,24 +400,29 @@ class SapphireTest extends PHPUnit_Framework_TestCase implements TestOnly
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return FixtureFactory
|
* @deprecated 4.0..5.0
|
||||||
|
* @return FixtureFactory|false
|
||||||
*/
|
*/
|
||||||
public function getFixtureFactory()
|
public function getFixtureFactory()
|
||||||
{
|
{
|
||||||
if (!$this->fixtureFactory) {
|
Deprecation::notice('5.0', __FUNCTION__ . ' is deprecated, use ' . FixtureTestState::class . ' instead');
|
||||||
$this->fixtureFactory = Injector::inst()->create(FixtureFactory::class);
|
/** @var FixtureTestState $state */
|
||||||
}
|
$state = static::$state->getStateByName('fixtures');
|
||||||
return $this->fixtureFactory;
|
return $state->getFixtureFactory(static::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a new fixture factory
|
* Sets a new fixture factory
|
||||||
*
|
* @deprecated 4.0..5.0
|
||||||
* @param FixtureFactory $factory
|
* @param FixtureFactory $factory
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setFixtureFactory(FixtureFactory $factory)
|
public function setFixtureFactory(FixtureFactory $factory)
|
||||||
{
|
{
|
||||||
|
Deprecation::notice('5.0', __FUNCTION__ . ' is deprecated, use ' . FixtureTestState::class . ' instead');
|
||||||
|
/** @var FixtureTestState $state */
|
||||||
|
$state = static::$state->getStateByName('fixtures');
|
||||||
|
$state->setFixtureFactory($factory, static::class);
|
||||||
$this->fixtureFactory = $factory;
|
$this->fixtureFactory = $factory;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@ -476,11 +488,13 @@ class SapphireTest extends PHPUnit_Framework_TestCase implements TestOnly
|
|||||||
* Load a YAML fixture file into the database.
|
* Load a YAML fixture file into the database.
|
||||||
* Once loaded, you can use idFromFixture() and objFromFixture() to get items from the fixture.
|
* Once loaded, you can use idFromFixture() and objFromFixture() to get items from the fixture.
|
||||||
* Doesn't clear existing fixtures.
|
* Doesn't clear existing fixtures.
|
||||||
|
* @deprecated 4.0...5.0
|
||||||
*
|
*
|
||||||
* @param string $fixtureFile The location of the .yml fixture file, relative to the site base dir
|
* @param string $fixtureFile The location of the .yml fixture file, relative to the site base dir
|
||||||
*/
|
*/
|
||||||
public function loadFixture($fixtureFile)
|
public function loadFixture($fixtureFile)
|
||||||
{
|
{
|
||||||
|
Deprecation::notice('5.0', __FUNCTION__ . ' is deprecated, use ' . FixtureTestState::class . ' instead');
|
||||||
$fixture = Injector::inst()->create(YamlFixture::class, $fixtureFile);
|
$fixture = Injector::inst()->create(YamlFixture::class, $fixtureFile);
|
||||||
$fixture->writeInto($this->getFixtureFactory());
|
$fixture->writeInto($this->getFixtureFactory());
|
||||||
}
|
}
|
||||||
@ -973,7 +987,7 @@ class SapphireTest extends PHPUnit_Framework_TestCase implements TestOnly
|
|||||||
// Register state
|
// Register state
|
||||||
static::$state = SapphireTestState::singleton();
|
static::$state = SapphireTestState::singleton();
|
||||||
// Register temp DB holder
|
// Register temp DB holder
|
||||||
static::$tempDB = TempDatabase::create();
|
static::tempDB();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
229
src/Dev/State/FixtureTestState.php
Normal file
229
src/Dev/State/FixtureTestState.php
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\Dev\State;
|
||||||
|
|
||||||
|
use LogicException;
|
||||||
|
use SilverStripe\Control\Director;
|
||||||
|
use SilverStripe\Core\Injector\Injector;
|
||||||
|
use SilverStripe\Core\Manifest\ClassLoader;
|
||||||
|
use SilverStripe\Dev\FixtureFactory;
|
||||||
|
use SilverStripe\Dev\SapphireTest;
|
||||||
|
use SilverStripe\Dev\YamlFixture;
|
||||||
|
use SilverStripe\ORM\DataObject;
|
||||||
|
|
||||||
|
class FixtureTestState implements TestState
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var FixtureFactory[]
|
||||||
|
*/
|
||||||
|
private $fixtureFactories = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called on setup
|
||||||
|
*
|
||||||
|
* @param SapphireTest $test
|
||||||
|
*/
|
||||||
|
public function setUp(SapphireTest $test)
|
||||||
|
{
|
||||||
|
if ($this->testNeedsDB($test)) {
|
||||||
|
$tmpDB = $test::tempDB();
|
||||||
|
if (!$tmpDB->isUsed()) {
|
||||||
|
$tmpDB->build();
|
||||||
|
}
|
||||||
|
DataObject::singleton()->flushCache();
|
||||||
|
|
||||||
|
if (!$tmpDB->hasStarted()) {
|
||||||
|
foreach ($test->getRequireDefaultRecordsFrom() as $className) {
|
||||||
|
$instance = singleton($className);
|
||||||
|
if (method_exists($instance, 'requireDefaultRecords')) {
|
||||||
|
$instance->requireDefaultRecords();
|
||||||
|
}
|
||||||
|
if (method_exists($instance, 'augmentDefaultRecords')) {
|
||||||
|
$instance->augmentDefaultRecords();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->loadFixtures($test);
|
||||||
|
}
|
||||||
|
$tmpDB->startTransaction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called on tear down
|
||||||
|
*
|
||||||
|
* @param SapphireTest $test
|
||||||
|
*/
|
||||||
|
public function tearDown(SapphireTest $test)
|
||||||
|
{
|
||||||
|
if ($this->testNeedsDB($test)) {
|
||||||
|
$test::tempDB()->rollbackTransaction();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called once on setup
|
||||||
|
*
|
||||||
|
* @param string $class Class being setup
|
||||||
|
*/
|
||||||
|
public function setUpOnce($class)
|
||||||
|
{
|
||||||
|
$this->fixtureFactories[strtolower($class)] = Injector::inst()->create(FixtureFactory::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called once on tear down
|
||||||
|
*
|
||||||
|
* @param string $class Class being torn down
|
||||||
|
*/
|
||||||
|
public function tearDownOnce($class)
|
||||||
|
{
|
||||||
|
unset($this->fixtureFactories[strtolower($class)]);
|
||||||
|
$class::tempDB()->clearAllData();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $class
|
||||||
|
*
|
||||||
|
* @return bool|FixtureFactory
|
||||||
|
*/
|
||||||
|
public function getFixtureFactory($class)
|
||||||
|
{
|
||||||
|
$testClass = strtolower($class);
|
||||||
|
if (array_key_exists($testClass, $this->fixtureFactories)) {
|
||||||
|
return $this->fixtureFactories[$testClass];
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param FixtureFactory $factory
|
||||||
|
* @param string $class
|
||||||
|
*/
|
||||||
|
public function setFixtureFactory(FixtureFactory $factory, $class)
|
||||||
|
{
|
||||||
|
$this->fixtureFactories[strtolower($class)] = $factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param array $fixtures
|
||||||
|
*
|
||||||
|
* @param SapphireTest $test
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function getFixturePaths($fixtures, SapphireTest $test)
|
||||||
|
{
|
||||||
|
return array_map(function ($fixtureFilePath) use ($test) {
|
||||||
|
return $this->resolveFixturePath($fixtureFilePath, $test);
|
||||||
|
}, $fixtures);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param SapphireTest $test
|
||||||
|
*/
|
||||||
|
protected function loadFixtures(SapphireTest $test)
|
||||||
|
{
|
||||||
|
$fixtures = $test::get_fixture_file();
|
||||||
|
$fixtures = is_array($fixtures) ? $fixtures : [$fixtures];
|
||||||
|
$paths = $this->getFixturePaths($fixtures, $test);
|
||||||
|
foreach ($paths as $fixtureFile) {
|
||||||
|
$this->loadFixture($fixtureFile, $test);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $fixtureFile
|
||||||
|
* @param SapphireTest $test
|
||||||
|
*/
|
||||||
|
protected function loadFixture($fixtureFile, SapphireTest $test)
|
||||||
|
{
|
||||||
|
/** @var YamlFixture $fixture */
|
||||||
|
$fixture = Injector::inst()->create(YamlFixture::class, $fixtureFile);
|
||||||
|
$fixture->writeInto($this->getFixtureFactory(get_class($test)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map a fixture path to a physical file
|
||||||
|
*
|
||||||
|
* @param string $fixtureFilePath
|
||||||
|
* @param SapphireTest $test
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function resolveFixturePath($fixtureFilePath, SapphireTest $test)
|
||||||
|
{
|
||||||
|
// Support fixture paths relative to the test class, rather than relative to webroot
|
||||||
|
// String checking is faster than file_exists() calls.
|
||||||
|
$isRelativeToFile
|
||||||
|
= (strpos($fixtureFilePath, '/') === false)
|
||||||
|
|| preg_match('/^(\.){1,2}/', $fixtureFilePath);
|
||||||
|
|
||||||
|
if ($isRelativeToFile) {
|
||||||
|
$resolvedPath = realpath($this->getTestAbsolutePath($test) . '/' . $fixtureFilePath);
|
||||||
|
if ($resolvedPath) {
|
||||||
|
return $resolvedPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if file exists relative to base dir
|
||||||
|
$resolvedPath = realpath(Director::baseFolder() . '/' . $fixtureFilePath);
|
||||||
|
if ($resolvedPath) {
|
||||||
|
return $resolvedPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $fixtureFilePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Useful for writing unit tests without hardcoding folder structures.
|
||||||
|
*
|
||||||
|
* @param SapphireTest $test
|
||||||
|
*
|
||||||
|
* @return string Absolute path to current class.
|
||||||
|
*/
|
||||||
|
protected function getTestAbsolutePath(SapphireTest $test)
|
||||||
|
{
|
||||||
|
$filename = ClassLoader::inst()->getItemPath(get_class($test));
|
||||||
|
if (!$filename) {
|
||||||
|
throw new LogicException('getItemPath returned null for ' . static::class
|
||||||
|
. '. Try adding flush=1 to the test run.');
|
||||||
|
}
|
||||||
|
return dirname($filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param SapphireTest $test
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function testNeedsDB(SapphireTest $test)
|
||||||
|
{
|
||||||
|
$annotations = $test->getAnnotations();
|
||||||
|
|
||||||
|
// annotation explicitly disables the DB
|
||||||
|
if (array_key_exists('useDatabase', $annotations['method'])
|
||||||
|
&& $annotations['method']['useDatabase'][0] === 'false') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// annotation explicitly enables the DB
|
||||||
|
if (array_key_exists('useDatabase', $annotations['method'])
|
||||||
|
&& $annotations['method']['useDatabase'][0] !== 'false') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// test class explicitly enables DB
|
||||||
|
if ($test->getUsesDatabase()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// presence of fixture file implicitly enables DB
|
||||||
|
$fixtures = $test::get_fixture_file();
|
||||||
|
if (!empty($fixtures)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
@ -22,6 +22,36 @@ class SapphireTestState implements TestState
|
|||||||
return $this->states;
|
return $this->states;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $name
|
||||||
|
*
|
||||||
|
* @return bool|TestState
|
||||||
|
*/
|
||||||
|
public function getStateByName($name)
|
||||||
|
{
|
||||||
|
$states = $this->getStates();
|
||||||
|
if (array_key_exists($name, $states)) {
|
||||||
|
return $states[$name];
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $class
|
||||||
|
*
|
||||||
|
* @return bool|TestState
|
||||||
|
*/
|
||||||
|
public function getStateByClass($class)
|
||||||
|
{
|
||||||
|
$lClass = strtolower($class);
|
||||||
|
foreach ($this->getStates() as $state) {
|
||||||
|
if ($lClass === strtolower(get_class($state))) {
|
||||||
|
return $state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param TestState[] $states
|
* @param TestState[] $states
|
||||||
* @return $this
|
* @return $this
|
||||||
|
@ -23,6 +23,11 @@ class TempDatabase
|
|||||||
*/
|
*/
|
||||||
protected $name = null;
|
protected $name = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool If a transaction has been started
|
||||||
|
*/
|
||||||
|
protected $hasStarted = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new temp database
|
* Create a new temp database
|
||||||
*
|
*
|
||||||
@ -68,6 +73,46 @@ class TempDatabase
|
|||||||
return $this->isDBTemp($selected);
|
return $this->isDBTemp($selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function hasStarted()
|
||||||
|
{
|
||||||
|
return $this->hasStarted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function supportsTransactions()
|
||||||
|
{
|
||||||
|
return static::getConn()->supportsTransactions();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start a transaction for easy rollback after tests
|
||||||
|
*/
|
||||||
|
public function startTransaction()
|
||||||
|
{
|
||||||
|
$this->hasStarted = true;
|
||||||
|
if (static::getConn()->supportsTransactions()) {
|
||||||
|
static::getConn()->transactionStart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rollback a transaction (or trash all data if the DB doesn't support databases
|
||||||
|
*/
|
||||||
|
public function rollbackTransaction()
|
||||||
|
{
|
||||||
|
if (static::getConn()->supportsTransactions()) {
|
||||||
|
static::getConn()->transactionRollback();
|
||||||
|
} else {
|
||||||
|
$this->hasStarted = false;
|
||||||
|
static::clearAllData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy the current temp database
|
* Destroy the current temp database
|
||||||
*/
|
*/
|
||||||
@ -102,6 +147,7 @@ class TempDatabase
|
|||||||
*/
|
*/
|
||||||
public function clearAllData()
|
public function clearAllData()
|
||||||
{
|
{
|
||||||
|
$this->hasStarted = false;
|
||||||
if (!$this->isUsed()) {
|
if (!$this->isUsed()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -183,6 +229,11 @@ class TempDatabase
|
|||||||
*/
|
*/
|
||||||
public function resetDBSchema(array $extraDataObjects = [])
|
public function resetDBSchema(array $extraDataObjects = [])
|
||||||
{
|
{
|
||||||
|
// pgsql doesn't allow schema updates inside transactions
|
||||||
|
// so we need to rollback any transactions before commencing a schema reset
|
||||||
|
if ($this->hasStarted()) {
|
||||||
|
$this->rollbackTransaction();
|
||||||
|
}
|
||||||
if (!$this->isUsed()) {
|
if (!$this->isUsed()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -100,6 +100,7 @@ class DataObjectSchema
|
|||||||
* @param string $class Class name (not a table).
|
* @param string $class Class name (not a table).
|
||||||
* @param string $field Name of field that belongs to this class (or a parent class)
|
* @param string $field Name of field that belongs to this class (or a parent class)
|
||||||
* @param string $tablePrefix Optional prefix for table (alias)
|
* @param string $tablePrefix Optional prefix for table (alias)
|
||||||
|
*
|
||||||
* @return string The SQL identifier string for the corresponding column for this field
|
* @return string The SQL identifier string for the corresponding column for this field
|
||||||
*/
|
*/
|
||||||
public function sqlColumnForField($class, $field, $tablePrefix = null)
|
public function sqlColumnForField($class, $field, $tablePrefix = null)
|
||||||
@ -118,6 +119,7 @@ class DataObjectSchema
|
|||||||
* the name that would be used if this table did exist.
|
* the name that would be used if this table did exist.
|
||||||
*
|
*
|
||||||
* @param string $class
|
* @param string $class
|
||||||
|
*
|
||||||
* @return string Returns the table name, or null if there is no table
|
* @return string Returns the table name, or null if there is no table
|
||||||
*/
|
*/
|
||||||
public function tableName($class)
|
public function tableName($class)
|
||||||
@ -135,6 +137,7 @@ class DataObjectSchema
|
|||||||
* passed class.
|
* passed class.
|
||||||
*
|
*
|
||||||
* @param string|object $class
|
* @param string|object $class
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
* @throws InvalidArgumentException
|
* @throws InvalidArgumentException
|
||||||
*/
|
*/
|
||||||
@ -155,6 +158,7 @@ class DataObjectSchema
|
|||||||
* Get the base table
|
* Get the base table
|
||||||
*
|
*
|
||||||
* @param string|object $class
|
* @param string|object $class
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function baseDataTable($class)
|
public function baseDataTable($class)
|
||||||
@ -185,6 +189,7 @@ class DataObjectSchema
|
|||||||
* - UNINHERITED Limit to only this table
|
* - UNINHERITED Limit to only this table
|
||||||
* - DB_ONLY Exclude virtual fields (such as composite fields), and only include fields with a db column.
|
* - DB_ONLY Exclude virtual fields (such as composite fields), and only include fields with a db column.
|
||||||
* - INCLUDE_CLASS Prefix the field specification with the class name in RecordClass.Column(spec) format.
|
* - INCLUDE_CLASS Prefix the field specification with the class name in RecordClass.Column(spec) format.
|
||||||
|
*
|
||||||
* @return array List of fields, where the key is the field name and the value is the field specification.
|
* @return array List of fields, where the key is the field name and the value is the field specification.
|
||||||
*/
|
*/
|
||||||
public function fieldSpecs($classOrInstance, $options = 0)
|
public function fieldSpecs($classOrInstance, $options = 0)
|
||||||
@ -235,6 +240,7 @@ class DataObjectSchema
|
|||||||
* - UNINHERITED Limit to only this table
|
* - UNINHERITED Limit to only this table
|
||||||
* - DB_ONLY Exclude virtual fields (such as composite fields), and only include fields with a db column.
|
* - DB_ONLY Exclude virtual fields (such as composite fields), and only include fields with a db column.
|
||||||
* - INCLUDE_CLASS Prefix the field specification with the class name in RecordClass.Column(spec) format.
|
* - INCLUDE_CLASS Prefix the field specification with the class name in RecordClass.Column(spec) format.
|
||||||
|
*
|
||||||
* @return string|null Field will be a string in FieldClass(args) format, or
|
* @return string|null Field will be a string in FieldClass(args) format, or
|
||||||
* RecordClass.FieldClass(args) format if using INCLUDE_CLASS. Will be null if no field is found.
|
* RecordClass.FieldClass(args) format if using INCLUDE_CLASS. Will be null if no field is found.
|
||||||
*/
|
*/
|
||||||
@ -248,6 +254,7 @@ class DataObjectSchema
|
|||||||
* Find the class for the given table
|
* Find the class for the given table
|
||||||
*
|
*
|
||||||
* @param string $table
|
* @param string $table
|
||||||
|
*
|
||||||
* @return string|null The FQN of the class, or null if not found
|
* @return string|null The FQN of the class, or null if not found
|
||||||
*/
|
*/
|
||||||
public function tableClass($table)
|
public function tableClass($table)
|
||||||
@ -303,6 +310,7 @@ class DataObjectSchema
|
|||||||
* See dev/build errors for details in case of table name violation.
|
* See dev/build errors for details in case of table name violation.
|
||||||
*
|
*
|
||||||
* @param string $class
|
* @param string $class
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected function buildTableName($class)
|
protected function buildTableName($class)
|
||||||
@ -334,6 +342,7 @@ class DataObjectSchema
|
|||||||
*
|
*
|
||||||
* @param string $class Class name to query from
|
* @param string $class Class name to query from
|
||||||
* @param bool $aggregated Include fields in entire hierarchy, rather than just on this table
|
* @param bool $aggregated Include fields in entire hierarchy, rather than just on this table
|
||||||
|
*
|
||||||
* @return array Map of fieldname to specification, similiar to {@link DataObject::$db}.
|
* @return array Map of fieldname to specification, similiar to {@link DataObject::$db}.
|
||||||
*/
|
*/
|
||||||
public function databaseFields($class, $aggregated = true)
|
public function databaseFields($class, $aggregated = true)
|
||||||
@ -360,6 +369,7 @@ class DataObjectSchema
|
|||||||
* @param string $class Class name to query from
|
* @param string $class Class name to query from
|
||||||
* @param string $field Field name
|
* @param string $field Field name
|
||||||
* @param bool $aggregated Include fields in entire hierarchy, rather than just on this table
|
* @param bool $aggregated Include fields in entire hierarchy, rather than just on this table
|
||||||
|
*
|
||||||
* @return string|null Field specification, or null if not a field
|
* @return string|null Field specification, or null if not a field
|
||||||
*/
|
*/
|
||||||
public function databaseField($class, $field, $aggregated = true)
|
public function databaseField($class, $field, $aggregated = true)
|
||||||
@ -392,6 +402,7 @@ class DataObjectSchema
|
|||||||
* Check if the given class has a table
|
* Check if the given class has a table
|
||||||
*
|
*
|
||||||
* @param string $class
|
* @param string $class
|
||||||
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function classHasTable($class)
|
public function classHasTable($class)
|
||||||
@ -415,6 +426,7 @@ class DataObjectSchema
|
|||||||
*
|
*
|
||||||
* @param string $class Name of class to check
|
* @param string $class Name of class to check
|
||||||
* @param bool $aggregated Include fields in entire hierarchy, rather than just on this table
|
* @param bool $aggregated Include fields in entire hierarchy, rather than just on this table
|
||||||
|
*
|
||||||
* @return array List of composite fields and their class spec
|
* @return array List of composite fields and their class spec
|
||||||
*/
|
*/
|
||||||
public function compositeFields($class, $aggregated = true)
|
public function compositeFields($class, $aggregated = true)
|
||||||
@ -442,6 +454,7 @@ class DataObjectSchema
|
|||||||
* @param string $class Class name to query from
|
* @param string $class Class name to query from
|
||||||
* @param string $field Field name
|
* @param string $field Field name
|
||||||
* @param bool $aggregated Include fields in entire hierarchy, rather than just on this table
|
* @param bool $aggregated Include fields in entire hierarchy, rather than just on this table
|
||||||
|
*
|
||||||
* @return string|null Field specification, or null if not a field
|
* @return string|null Field specification, or null if not a field
|
||||||
*/
|
*/
|
||||||
public function compositeField($class, $field, $aggregated = true)
|
public function compositeField($class, $field, $aggregated = true)
|
||||||
@ -535,6 +548,7 @@ class DataObjectSchema
|
|||||||
* Get "default" database indexable field types
|
* Get "default" database indexable field types
|
||||||
*
|
*
|
||||||
* @param string $class
|
* @param string $class
|
||||||
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
protected function cacheDefaultDatabaseIndexes($class)
|
protected function cacheDefaultDatabaseIndexes($class)
|
||||||
@ -559,6 +573,7 @@ class DataObjectSchema
|
|||||||
* Look for custom indexes declared on the class
|
* Look for custom indexes declared on the class
|
||||||
*
|
*
|
||||||
* @param string $class
|
* @param string $class
|
||||||
|
*
|
||||||
* @return array
|
* @return array
|
||||||
* @throws InvalidArgumentException If an index already exists on the class
|
* @throws InvalidArgumentException If an index already exists on the class
|
||||||
* @throws InvalidArgumentException If a custom index format is not valid
|
* @throws InvalidArgumentException If a custom index format is not valid
|
||||||
@ -637,6 +652,7 @@ class DataObjectSchema
|
|||||||
* Parses a specified column into a sort field and direction
|
* Parses a specified column into a sort field and direction
|
||||||
*
|
*
|
||||||
* @param string $column String to parse containing the column name
|
* @param string $column String to parse containing the column name
|
||||||
|
*
|
||||||
* @return array Resolved table and column.
|
* @return array Resolved table and column.
|
||||||
*/
|
*/
|
||||||
protected function parseSortColumn($column)
|
protected function parseSortColumn($column)
|
||||||
@ -659,6 +675,7 @@ class DataObjectSchema
|
|||||||
*
|
*
|
||||||
* @param string $candidateClass
|
* @param string $candidateClass
|
||||||
* @param string $fieldName
|
* @param string $fieldName
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function tableForField($candidateClass, $fieldName)
|
public function tableForField($candidateClass, $fieldName)
|
||||||
@ -677,6 +694,7 @@ class DataObjectSchema
|
|||||||
*
|
*
|
||||||
* @param string $candidateClass
|
* @param string $candidateClass
|
||||||
* @param string $fieldName
|
* @param string $fieldName
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function classForField($candidateClass, $fieldName)
|
public function classForField($candidateClass, $fieldName)
|
||||||
@ -720,8 +738,10 @@ class DataObjectSchema
|
|||||||
* If the class name is 'ManyManyThroughList' then this is the name of the
|
* If the class name is 'ManyManyThroughList' then this is the name of the
|
||||||
* has_many relation.
|
* has_many relation.
|
||||||
* )
|
* )
|
||||||
|
*
|
||||||
* @param string $class Name of class to get component for
|
* @param string $class Name of class to get component for
|
||||||
* @param string $component The component name
|
* @param string $component The component name
|
||||||
|
*
|
||||||
* @return array|null
|
* @return array|null
|
||||||
*/
|
*/
|
||||||
public function manyManyComponent($class, $component)
|
public function manyManyComponent($class, $component)
|
||||||
@ -768,6 +788,7 @@ class DataObjectSchema
|
|||||||
* @param string $parentClass Name of class
|
* @param string $parentClass Name of class
|
||||||
* @param string $component Name of relation on class
|
* @param string $component Name of relation on class
|
||||||
* @param string $specification specification for this belongs_many_many
|
* @param string $specification specification for this belongs_many_many
|
||||||
|
*
|
||||||
* @return array Array with child class and relation name
|
* @return array Array with child class and relation name
|
||||||
*/
|
*/
|
||||||
protected function parseBelongsManyManyComponent($parentClass, $component, $specification)
|
protected function parseBelongsManyManyComponent($parentClass, $component, $specification)
|
||||||
@ -802,7 +823,7 @@ class DataObjectSchema
|
|||||||
// Return relatios
|
// Return relatios
|
||||||
return [
|
return [
|
||||||
'childClass' => $childClass,
|
'childClass' => $childClass,
|
||||||
'relationName' => $relationName
|
'relationName' => $relationName,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -811,6 +832,7 @@ class DataObjectSchema
|
|||||||
*
|
*
|
||||||
* @param string $class
|
* @param string $class
|
||||||
* @param string $component
|
* @param string $component
|
||||||
|
*
|
||||||
* @return array|null
|
* @return array|null
|
||||||
*/
|
*/
|
||||||
public function manyManyExtraFieldsForComponent($class, $component)
|
public function manyManyExtraFieldsForComponent($class, $component)
|
||||||
@ -845,6 +867,7 @@ class DataObjectSchema
|
|||||||
* @param string $component
|
* @param string $component
|
||||||
* @param bool $classOnly If this is TRUE, than any has_many relationships in the form
|
* @param bool $classOnly If this is TRUE, than any has_many relationships in the form
|
||||||
* "ClassName.Field" will have the field data stripped off. It defaults to TRUE.
|
* "ClassName.Field" will have the field data stripped off. It defaults to TRUE.
|
||||||
|
*
|
||||||
* @return string|null
|
* @return string|null
|
||||||
*/
|
*/
|
||||||
public function hasManyComponent($class, $component, $classOnly = true)
|
public function hasManyComponent($class, $component, $classOnly = true)
|
||||||
@ -868,6 +891,7 @@ class DataObjectSchema
|
|||||||
*
|
*
|
||||||
* @param string $class
|
* @param string $class
|
||||||
* @param string $component
|
* @param string $component
|
||||||
|
*
|
||||||
* @return string|null
|
* @return string|null
|
||||||
*/
|
*/
|
||||||
public function hasOneComponent($class, $component)
|
public function hasOneComponent($class, $component)
|
||||||
@ -890,6 +914,7 @@ class DataObjectSchema
|
|||||||
* @param string $component
|
* @param string $component
|
||||||
* @param bool $classOnly If this is TRUE, than any has_many relationships in the
|
* @param bool $classOnly If this is TRUE, than any has_many relationships in the
|
||||||
* form "ClassName.Field" will have the field data stripped off. It defaults to TRUE.
|
* form "ClassName.Field" will have the field data stripped off. It defaults to TRUE.
|
||||||
|
*
|
||||||
* @return string|null
|
* @return string|null
|
||||||
*/
|
*/
|
||||||
public function belongsToComponent($class, $component, $classOnly = true)
|
public function belongsToComponent($class, $component, $classOnly = true)
|
||||||
@ -912,8 +937,10 @@ class DataObjectSchema
|
|||||||
* Check class for any unary component
|
* Check class for any unary component
|
||||||
*
|
*
|
||||||
* Alias for hasOneComponent() ?: belongsToComponent()
|
* Alias for hasOneComponent() ?: belongsToComponent()
|
||||||
|
*
|
||||||
* @param string $class
|
* @param string $class
|
||||||
* @param string $component
|
* @param string $component
|
||||||
|
*
|
||||||
* @return string|null
|
* @return string|null
|
||||||
*/
|
*/
|
||||||
public function unaryComponent($class, $component)
|
public function unaryComponent($class, $component)
|
||||||
@ -926,6 +953,7 @@ class DataObjectSchema
|
|||||||
* @param string $parentClass Parent class name
|
* @param string $parentClass Parent class name
|
||||||
* @param string $component ManyMany name
|
* @param string $component ManyMany name
|
||||||
* @param string|array $specification Declaration of many_many relation type
|
* @param string|array $specification Declaration of many_many relation type
|
||||||
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
protected function parseManyManyComponent($parentClass, $component, $specification)
|
protected function parseManyManyComponent($parentClass, $component, $specification)
|
||||||
@ -975,6 +1003,7 @@ class DataObjectSchema
|
|||||||
*
|
*
|
||||||
* @param string $childClass
|
* @param string $childClass
|
||||||
* @param string $parentClass
|
* @param string $parentClass
|
||||||
|
*
|
||||||
* @return string|null
|
* @return string|null
|
||||||
*/
|
*/
|
||||||
protected function getManyManyInverseRelationship($childClass, $parentClass)
|
protected function getManyManyInverseRelationship($childClass, $parentClass)
|
||||||
@ -992,10 +1021,10 @@ class DataObjectSchema
|
|||||||
if (is_array($manyManySpec)) {
|
if (is_array($manyManySpec)) {
|
||||||
$toClass = $this->hasOneComponent($manyManySpec['through'], $manyManySpec['to']);
|
$toClass = $this->hasOneComponent($manyManySpec['through'], $manyManySpec['to']);
|
||||||
if ($toClass === $parentClass) {
|
if ($toClass === $parentClass) {
|
||||||
return $inverseComponentName;
|
return $inverseComponentName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1011,6 +1040,7 @@ class DataObjectSchema
|
|||||||
* remote object.
|
* remote object.
|
||||||
* @param string $type the join type - either 'has_many' or 'belongs_to'
|
* @param string $type the join type - either 'has_many' or 'belongs_to'
|
||||||
* @param boolean $polymorphic Flag set to true if the remote join field is polymorphic.
|
* @param boolean $polymorphic Flag set to true if the remote join field is polymorphic.
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
@ -1091,6 +1121,7 @@ class DataObjectSchema
|
|||||||
* @param string $joinClass Class for the joined table
|
* @param string $joinClass Class for the joined table
|
||||||
* @param array $specification Complete many_many specification
|
* @param array $specification Complete many_many specification
|
||||||
* @param string $key Name of key to check ('from' or 'to')
|
* @param string $key Name of key to check ('from' or 'to')
|
||||||
|
*
|
||||||
* @return string Class that matches the given relation
|
* @return string Class that matches the given relation
|
||||||
* @throws InvalidArgumentException
|
* @throws InvalidArgumentException
|
||||||
*/
|
*/
|
||||||
@ -1152,6 +1183,7 @@ class DataObjectSchema
|
|||||||
* @param string $parentClass Name of parent class
|
* @param string $parentClass Name of parent class
|
||||||
* @param string $component Name of many_many component
|
* @param string $component Name of many_many component
|
||||||
* @param array $specification Complete many_many specification
|
* @param array $specification Complete many_many specification
|
||||||
|
*
|
||||||
* @return string Name of join class
|
* @return string Name of join class
|
||||||
*/
|
*/
|
||||||
protected function checkManyManyJoinClass($parentClass, $component, $specification)
|
protected function checkManyManyJoinClass($parentClass, $component, $specification)
|
||||||
|
Loading…
Reference in New Issue
Block a user