mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merge remote-tracking branch 'origin/3.0'
This commit is contained in:
commit
6571c17992
267
dev/FixtureBlueprint.php
Normal file
267
dev/FixtureBlueprint.php
Normal file
@ -0,0 +1,267 @@
|
||||
<?php
|
||||
/**
|
||||
* A blueprint on how to create instances of a certain {@link DataObject} subclass.
|
||||
*
|
||||
* Relies on a {@link FixtureFactory} to manage database relationships between instances,
|
||||
* and manage the mappings between fixture identifiers and their database IDs.
|
||||
*
|
||||
* @package framework
|
||||
* @subpackage core
|
||||
*/
|
||||
class FixtureBlueprint {
|
||||
|
||||
/**
|
||||
* @var array Map of field names to values. Supersedes {@link DataObject::$defaults}.
|
||||
*/
|
||||
protected $defaults = array();
|
||||
|
||||
/**
|
||||
* @var String Arbitrary name by which this fixture type can be referenced.
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* @var String Subclass of {@link DataObject}
|
||||
*/
|
||||
protected $class;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $callbacks = array(
|
||||
'beforeCreate' => array(),
|
||||
'afterCreate' => array(),
|
||||
);
|
||||
|
||||
static $dependencies = array(
|
||||
'factory' => '%$FixtureFactory'
|
||||
);
|
||||
|
||||
/**
|
||||
* @param String $name
|
||||
* @param String $class Defaults to $name
|
||||
* @param array $defaults
|
||||
*/
|
||||
public function __construct($name, $class = null, $defaults = array()) {
|
||||
if(!$class) $class = $name;
|
||||
|
||||
if(!is_subclass_of($class, 'DataObject')) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'Class "%s" is not a valid subclass of DataObject',
|
||||
$class
|
||||
));
|
||||
}
|
||||
|
||||
$this->name = $name;
|
||||
$this->class = $class;
|
||||
$this->defaults = $defaults;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param String $identifier Unique identifier for this fixture type
|
||||
* @param Array $data Map of property names to their values.
|
||||
* @param Array $fixtures Map of fixture names to an associative array of their in-memory
|
||||
* identifiers mapped to their database IDs. Used to look up
|
||||
* existing fixtures which might be referenced in the $data attribute
|
||||
* via the => notation.
|
||||
* @return DataObject
|
||||
*/
|
||||
public function createObject($identifier, $data = null, $fixtures = null) {
|
||||
// We have to disable validation while we import the fixtures, as the order in
|
||||
// which they are imported doesnt guarantee valid relations until after the import is complete.
|
||||
$validationenabled = DataObject::get_validation_enabled();
|
||||
DataObject::set_validation_enabled(false);
|
||||
|
||||
$this->invokeCallbacks('beforeCreate', array($identifier, &$data, &$fixtures));
|
||||
|
||||
try {
|
||||
$class = $this->class;
|
||||
$obj = DataModel::inst()->$class->newObject();
|
||||
|
||||
// If an ID is explicitly passed, then we'll sort out the initial write straight away
|
||||
// This is just in case field setters triggered by the population code in the next block
|
||||
// Call $this->write(). (For example, in FileTest)
|
||||
if(isset($data['ID'])) {
|
||||
$obj->ID = $data['ID'];
|
||||
|
||||
// The database needs to allow inserting values into the foreign key column (ID in our case)
|
||||
$conn = DB::getConn();
|
||||
if(method_exists($conn, 'allowPrimaryKeyEditing')) {
|
||||
$conn->allowPrimaryKeyEditing(ClassInfo::baseDataClass($class), true);
|
||||
}
|
||||
$obj->write(false, true);
|
||||
if(method_exists($conn, 'allowPrimaryKeyEditing')) {
|
||||
$conn->allowPrimaryKeyEditing(ClassInfo::baseDataClass($class), false);
|
||||
}
|
||||
}
|
||||
|
||||
// Populate defaults
|
||||
if($this->defaults) foreach($this->defaults as $fieldName => $fieldVal) {
|
||||
if(isset($data[$fieldName]) && $data[$fieldName] !== false) continue;
|
||||
|
||||
if(is_callable($fieldVal)) {
|
||||
$obj->$fieldName = $fieldVal($obj, $data, $fixtures);
|
||||
} else {
|
||||
$obj->$fieldName = $fieldVal;
|
||||
}
|
||||
}
|
||||
|
||||
// Populate overrides
|
||||
if($data) foreach($data as $fieldName => $fieldVal) {
|
||||
// Defer relationship processing
|
||||
if($obj->many_many($fieldName) || $obj->has_many($fieldName) || $obj->has_one($fieldName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->setValue($obj, $fieldName, $fieldVal, $fixtures);
|
||||
}
|
||||
$obj->write();
|
||||
|
||||
// Save to fixture before relationship processing in case of reflexive relationships
|
||||
if(!isset($fixtures[$class])) {
|
||||
$fixtures[$class] = array();
|
||||
}
|
||||
$fixtures[$class][$identifier] = $obj->ID;
|
||||
|
||||
// Populate all relations
|
||||
if($data) foreach($data as $fieldName => $fieldVal) {
|
||||
if($obj->many_many($fieldName) || $obj->has_many($fieldName)) {
|
||||
$parsedItems = array();
|
||||
$items = preg_split('/ *, */',trim($fieldVal));
|
||||
foreach($items as $item) {
|
||||
// Check for correct format: =><relationname>.<identifier>
|
||||
if(!preg_match('/^=>[^\.]+\.[^\.]+/', $item)) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'Invalid format for relation "%s" on class "%s" ("%s")',
|
||||
$fieldName,
|
||||
$class,
|
||||
$item
|
||||
));
|
||||
}
|
||||
|
||||
$parsedItems[] = $this->parseValue($item, $fixtures);
|
||||
}
|
||||
$obj->write();
|
||||
if($obj->has_many($fieldName)) {
|
||||
$obj->getComponents($fieldName)->setByIDList($parsedItems);
|
||||
} elseif($obj->many_many($fieldName)) {
|
||||
$obj->getManyManyComponents($fieldName)->setByIDList($parsedItems);
|
||||
}
|
||||
} elseif($obj->has_one($fieldName)) {
|
||||
// Sets has_one with relation name
|
||||
$obj->{$fieldName . 'ID'} = $this->parseValue($fieldVal, $fixtures);
|
||||
} elseif($obj->has_one(preg_replace('/ID$/', '', $fieldName))) {
|
||||
// Sets has_one with database field
|
||||
$obj->$fieldName = $this->parseValue($fieldVal, $fixtures);
|
||||
}
|
||||
}
|
||||
$obj->write();
|
||||
|
||||
// If LastEdited was set in the fixture, set it here
|
||||
if($data && array_key_exists('LastEdited', $data)) {
|
||||
$edited = $this->parseValue($data['LastEdited'], $fixtures);
|
||||
DB::manipulate(array(
|
||||
$class => array(
|
||||
"command" => "update", "id" => $obj->id,
|
||||
"fields" => array("LastEdited" => "'".$edited."'")
|
||||
)
|
||||
));
|
||||
}
|
||||
} catch(Exception $e) {
|
||||
DataObject::set_validation_enabled($validationenabled);
|
||||
throw $e;
|
||||
}
|
||||
|
||||
DataObject::set_validation_enabled($validationenabled);
|
||||
|
||||
$this->invokeCallbacks('afterCreate', array($obj, $identifier, &$data, &$fixtures));
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Array $defaults
|
||||
*/
|
||||
public function setDefaults($defaults) {
|
||||
$this->defaults = $defaults;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Array
|
||||
*/
|
||||
public function getDefaults() {
|
||||
return $this->defaults;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return String
|
||||
*/
|
||||
public function getClass() {
|
||||
return $this->class;
|
||||
}
|
||||
|
||||
/**
|
||||
* See class documentation.
|
||||
*
|
||||
* @param String $type
|
||||
* @param callable $callback
|
||||
*/
|
||||
public function addCallback($type, $callback) {
|
||||
if(!array_key_exists($type, $this->callbacks)) {
|
||||
throw new InvalidArgumentException(sprintf('Invalid type "%s"', $type));
|
||||
}
|
||||
|
||||
$this->callbacks[$type][] = $callback;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param String $type
|
||||
* @param callable $callback
|
||||
*/
|
||||
public function removeCallback($type, $callback) {
|
||||
$pos = array_search($callback, $this->callbacks[$type]);
|
||||
if($pos !== false) unset($this->callbacks[$type][$pos]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function invokeCallbacks($type, $args = array()) {
|
||||
foreach($this->callbacks[$type] as $callback) {
|
||||
call_user_func_array($callback, $args);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a value from a fixture file. If it starts with =>
|
||||
* it will get an ID from the fixture dictionary
|
||||
*
|
||||
* @param String $fieldVal
|
||||
* @param Array $fixtures See {@link createObject()}
|
||||
* @return String Fixture database ID, or the original value
|
||||
*/
|
||||
protected function parseValue($value, $fixtures = null) {
|
||||
if(substr($value,0,2) == '=>') {
|
||||
// Parse a dictionary reference - used to set foreign keys
|
||||
list($class, $identifier) = explode('.', substr($value,2), 2);
|
||||
|
||||
if($fixtures && !isset($fixtures[$class][$identifier])) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'No fixture definitions found for "%s"',
|
||||
$value
|
||||
));
|
||||
}
|
||||
|
||||
return $fixtures[$class][$identifier];
|
||||
} else {
|
||||
// Regular field value setting
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
protected function setValue($obj, $name, $value, $fixtures = null) {
|
||||
$obj->$name = $this->parseValue($value, $fixtures);
|
||||
}
|
||||
|
||||
}
|
226
dev/FixtureFactory.php
Normal file
226
dev/FixtureFactory.php
Normal file
@ -0,0 +1,226 @@
|
||||
<?php
|
||||
/**
|
||||
* Manages a set of database fixtures for {@link DataObject} records
|
||||
* as well as raw database table rows.
|
||||
*
|
||||
* Delegates creation of objects to {@link FixtureBlueprint},
|
||||
* which can implement class- and use-case specific fixture setup.
|
||||
*
|
||||
* Supports referencing model relations through a specialized syntax:
|
||||
* <code>
|
||||
* $factory = new FixtureFactory();
|
||||
* $relatedObj = $factory->createObject(
|
||||
* 'MyRelatedClass',
|
||||
* 'relation1'
|
||||
* );
|
||||
* $obj = $factory->createObject(
|
||||
* 'MyClass',
|
||||
* 'object1'
|
||||
* array('MyRelationName' => '=>MyRelatedClass.relation1')
|
||||
* );
|
||||
* </code>
|
||||
* Relation loading is order dependant.
|
||||
*
|
||||
* @package framework
|
||||
* @subpackage core
|
||||
*/
|
||||
class FixtureFactory {
|
||||
|
||||
/**
|
||||
* @var array Array of fixture items, keyed by class and unique identifier,
|
||||
* with values being the generated database ID. Does not store object instances.
|
||||
*/
|
||||
protected $fixtures = array();
|
||||
|
||||
/**
|
||||
* @var array Callbacks
|
||||
*/
|
||||
protected $blueprints = array();
|
||||
|
||||
/**
|
||||
* @param String $name Unique name for this blueprint
|
||||
* @param array|FixtureBlueprint $defaults Array of default values, or a blueprint instance
|
||||
*/
|
||||
public function define($name, $defaults = array()) {
|
||||
if($defaults instanceof FixtureBlueprint) {
|
||||
$this->blueprints[$name] = $defaults;
|
||||
} else {
|
||||
$class = $name;
|
||||
$this->blueprints[$name] = Injector::inst()->create(
|
||||
'FixtureBlueprint', $name, $class, $defaults
|
||||
);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the fixture into the database using DataObjects
|
||||
*
|
||||
* @param String $name Name of the {@link FixtureBlueprint} to use,
|
||||
* usually a DataObject subclass.
|
||||
* @param String $identifier Unique identifier for this fixture type
|
||||
* @param Array $data Map of properties. Overrides default data.
|
||||
* @return DataObject
|
||||
*/
|
||||
public function createObject($name, $identifier, $data = null) {
|
||||
if(!isset($this->blueprints[$name])) {
|
||||
$this->blueprints[$name] = new FixtureBlueprint($name);
|
||||
}
|
||||
$blueprint = $this->blueprints[$name];
|
||||
$obj = $blueprint->createObject($identifier, $data, $this->fixtures);
|
||||
$class = $blueprint->getClass();
|
||||
|
||||
if(!isset($this->fixtures[$class])) {
|
||||
$this->fixtures[$class] = array();
|
||||
}
|
||||
$this->fixtures[$class][$identifier] = $obj->ID;
|
||||
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the fixture into the database directly using a database manipulation.
|
||||
* Does not use blueprints. Only supports tables with a primary key.
|
||||
*
|
||||
* @param String $table Existing database table name
|
||||
* @param String $identifier Unique identifier for this fixture type
|
||||
* @param Array $data Map of properties
|
||||
* @return Int Database identifier
|
||||
*/
|
||||
public function createRaw($table, $identifier, $data) {
|
||||
$manipulation = array($table => array("fields" => array(), "command" => "insert"));
|
||||
foreach($data as $fieldName => $fieldVal) {
|
||||
$manipulation[$table]["fields"][$fieldName] = "'" . $this->parseValue($fieldVal) . "'";
|
||||
}
|
||||
DB::manipulate($manipulation);
|
||||
$id = DB::getGeneratedID($table);
|
||||
$this->fixtures[$table][$identifier] = $id;
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ID of an object from the fixture.
|
||||
* @param $className The data class, as specified in your fixture file. Parent classes won't work
|
||||
* @param $identifier The identifier string, as provided in your fixture file
|
||||
*/
|
||||
public function getId($class, $identifier) {
|
||||
if(isset($this->fixtures[$class][$identifier])) {
|
||||
return $this->fixtures[$class][$identifier];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all of the IDs in the fixture of a particular class name.
|
||||
*
|
||||
* @return A map of fixture-identifier => object-id
|
||||
*/
|
||||
public function getIds($class) {
|
||||
if(isset($this->fixtures[$class])) {
|
||||
return $this->fixtures[$class];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param String
|
||||
* @param String $identifier
|
||||
* @param Int $databaseId
|
||||
*/
|
||||
public function setId($class, $identifier, $databaseId) {
|
||||
$this->fixtures[$class][$identifier] = $databaseId;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an object from the fixture.
|
||||
*
|
||||
* @param $class The data class, as specified in your fixture file. Parent classes won't work
|
||||
* @param $identifier The identifier string, as provided in your fixture file
|
||||
*/
|
||||
public function get($class, $identifier) {
|
||||
$id = $this->getId($class, $identifier);
|
||||
if($id) return DataObject::get_by_id($class, $id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Array Map of class names, containing a map of in-memory identifiers
|
||||
* mapped to database identifiers.
|
||||
*/
|
||||
public function getFixtures() {
|
||||
return $this->fixtures;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all fixtures previously defined through {@link createObject()}
|
||||
* or {@link createRaw()}, both from the internal fixture mapping and the database.
|
||||
* If the $class argument is set, limit clearing to items of this class.
|
||||
*
|
||||
* @param String $class
|
||||
*/
|
||||
public function clear($limitToClass = null) {
|
||||
$classes = ($limitToClass) ? array($limitToClass) : array_keys($this->fixtures);
|
||||
foreach($classes as $class) {
|
||||
$ids = $this->fixtures[$class];
|
||||
foreach($ids as $id => $dbId) {
|
||||
if(class_exists($class)) {
|
||||
$class::get()->byId($dbId)->delete();
|
||||
} else {
|
||||
$table = $class;
|
||||
DB::manipulate(array(
|
||||
$table => array("fields" => array('ID' => $dbId),
|
||||
"command" => "delete")
|
||||
));
|
||||
}
|
||||
|
||||
unset($this->fixtures[$class][$id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Array Of {@link FixtureBlueprint} instances
|
||||
*/
|
||||
public function getBlueprints() {
|
||||
return $this->blueprints;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param String $name
|
||||
* @return FixtureBlueprint
|
||||
*/
|
||||
public function getBlueprint($name) {
|
||||
return (isset($this->blueprints[$name])) ? $this->blueprints[$name] : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a value from a fixture file. If it starts with =>
|
||||
* it will get an ID from the fixture dictionary
|
||||
*
|
||||
* @param String $fieldVal
|
||||
* @return String Fixture database ID, or the original value
|
||||
*/
|
||||
protected function parseValue($value) {
|
||||
if(substr($value,0,2) == '=>') {
|
||||
// Parse a dictionary reference - used to set foreign keys
|
||||
list($class, $identifier) = explode('.', substr($value,2), 2);
|
||||
|
||||
if($this->fixtures && !isset($this->fixtures[$class][$identifier])) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'No fixture definitions found for "%s"',
|
||||
$value
|
||||
));
|
||||
}
|
||||
|
||||
return $this->fixtures[$class][$identifier];
|
||||
} else {
|
||||
// Regular field value setting
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -10,6 +10,11 @@ require_once 'TestRunner.php';
|
||||
* @subpackage testing
|
||||
*/
|
||||
class SapphireTest extends PHPUnit_Framework_TestCase {
|
||||
|
||||
static $dependencies = array(
|
||||
'fixtureFactory' => '%$FixtureFactory',
|
||||
);
|
||||
|
||||
/**
|
||||
* Path to fixture data for this test run.
|
||||
* If passed as an array, multiple fixture files will be loaded.
|
||||
@ -21,9 +26,12 @@ class SapphireTest extends PHPUnit_Framework_TestCase {
|
||||
static $fixture_file = null;
|
||||
|
||||
/**
|
||||
* Set whether to include this test in the TestRunner or to skip this.
|
||||
*
|
||||
* @var bool
|
||||
* @var FixtureFactory
|
||||
*/
|
||||
protected $fixtureFactory;
|
||||
|
||||
/**
|
||||
* @var bool Set whether to include this test in the TestRunner or to skip this.
|
||||
*/
|
||||
protected $skipTest = false;
|
||||
|
||||
@ -140,8 +148,9 @@ class SapphireTest extends PHPUnit_Framework_TestCase {
|
||||
|
||||
/**
|
||||
* @var array $fixtures Array of {@link YamlFixture} instances
|
||||
* @deprecated 3.1 Use $fixtureFactory instad
|
||||
*/
|
||||
protected $fixtures;
|
||||
protected $fixtures = array();
|
||||
|
||||
protected $model;
|
||||
|
||||
@ -234,8 +243,8 @@ class SapphireTest extends PHPUnit_Framework_TestCase {
|
||||
if($resolvedPath) $fixtureFilePath = $resolvedPath;
|
||||
}
|
||||
|
||||
$fixture = new YamlFixture($fixtureFilePath);
|
||||
$fixture->saveIntoDatabase($this->model);
|
||||
$fixture = Injector::inst()->create('YamlFixture', $fixtureFilePath);
|
||||
$fixture->writeInto($this->getFixtureFactory());
|
||||
$this->fixtures[] = $fixture;
|
||||
|
||||
// backwards compatibility: Load first fixture into $this->fixture
|
||||
@ -339,38 +348,37 @@ class SapphireTest extends PHPUnit_Framework_TestCase {
|
||||
}
|
||||
|
||||
/**
|
||||
* Array
|
||||
* @return FixtureFactory
|
||||
*/
|
||||
protected $fixtureDictionary;
|
||||
public function getFixtureFactory() {
|
||||
if(!$this->fixtureFactory) $this->fixtureFactory = Injector::inst()->create('FixtureFactory');
|
||||
return $this->fixtureFactory;
|
||||
}
|
||||
|
||||
public function setFixtureFactory(FixtureFactory $factory) {
|
||||
$this->fixtureFactory = $factory;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ID of an object from the fixture.
|
||||
*
|
||||
* @param $className The data class, as specified in your fixture file. Parent classes won't work
|
||||
* @param $identifier The identifier string, as provided in your fixture file
|
||||
* @return int
|
||||
*/
|
||||
protected function idFromFixture($className, $identifier) {
|
||||
if(!$this->fixtures) {
|
||||
user_error("You've called idFromFixture() but you haven't specified static \$fixture_file.\n",
|
||||
E_USER_WARNING);
|
||||
return;
|
||||
$id = $this->getFixtureFactory()->getId($className, $identifier);
|
||||
|
||||
if(!$id) {
|
||||
user_error(sprintf(
|
||||
"Couldn't find object '%s' (class: %s)",
|
||||
$identifier,
|
||||
$className
|
||||
), E_USER_ERROR);
|
||||
}
|
||||
|
||||
foreach($this->fixtures as $fixture) {
|
||||
$match = $fixture->idFromFixture($className, $identifier);
|
||||
if($match) return $match;
|
||||
}
|
||||
|
||||
$fixtureFiles = Config::inst()->get(get_class($this), 'fixture_file', Config::FIRST_SET);
|
||||
user_error(sprintf(
|
||||
"Couldn't find object '%s' (class: %s) in files %s",
|
||||
$identifier,
|
||||
$className,
|
||||
(is_array($fixtureFiles)) ? implode(',', $fixtureFiles) : $fixtureFiles
|
||||
), E_USER_ERROR);
|
||||
|
||||
return false;
|
||||
return $id;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -381,46 +389,27 @@ class SapphireTest extends PHPUnit_Framework_TestCase {
|
||||
* @return A map of fixture-identifier => object-id
|
||||
*/
|
||||
protected function allFixtureIDs($className) {
|
||||
if(!$this->fixtures) {
|
||||
user_error("You've called allFixtureIDs() but you haven't specified static \$fixture_file.\n",
|
||||
E_USER_WARNING);
|
||||
return;
|
||||
}
|
||||
|
||||
$ids = array();
|
||||
foreach($this->fixtures as $fixture) {
|
||||
$ids += $fixture->allFixtureIDs($className);
|
||||
}
|
||||
|
||||
return $ids;
|
||||
return $this->getFixtureFactory()->getIds($className);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an object from the fixture.
|
||||
*
|
||||
* @param $className The data class, as specified in your fixture file. Parent classes won't work
|
||||
* @param $identifier The identifier string, as provided in your fixture file
|
||||
*/
|
||||
protected function objFromFixture($className, $identifier) {
|
||||
if(!$this->fixtures) {
|
||||
user_error("You've called objFromFixture() but you haven't specified static \$fixture_file.\n",
|
||||
E_USER_WARNING);
|
||||
return;
|
||||
$obj = $this->getFixtureFactory()->get($className, $identifier);
|
||||
|
||||
if(!$obj) {
|
||||
user_error(sprintf(
|
||||
"Couldn't find object '%s' (class: %s)",
|
||||
$identifier,
|
||||
$className
|
||||
), E_USER_ERROR);
|
||||
}
|
||||
|
||||
foreach($this->fixtures as $fixture) {
|
||||
$match = $fixture->objFromFixture($className, $identifier);
|
||||
if($match) return $match;
|
||||
}
|
||||
|
||||
$fixtureFiles = Config::inst()->get(get_class($this), 'fixture_file', Config::FIRST_SET);
|
||||
user_error(sprintf(
|
||||
"Couldn't find object '%s' (class: %s) in files %s",
|
||||
$identifier,
|
||||
$className,
|
||||
(is_array($fixtureFiles)) ? implode(',', $fixtureFiles) : $fixtureFiles
|
||||
), E_USER_ERROR);
|
||||
|
||||
return false;
|
||||
return $obj;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -431,20 +420,18 @@ class SapphireTest extends PHPUnit_Framework_TestCase {
|
||||
* @param $fixtureFile The location of the .yml fixture file, relative to the site base dir
|
||||
*/
|
||||
public function loadFixture($fixtureFile) {
|
||||
$parser = new Spyc();
|
||||
$fixtureContent = $parser->load(Director::baseFolder().'/'.$fixtureFile);
|
||||
|
||||
$fixture = new YamlFixture($fixtureFile);
|
||||
$fixture->saveIntoDatabase($this->model);
|
||||
$fixture = Injector::inst()->create('YamlFixture', $fixtureFile);
|
||||
$fixture->writeInto($this->getFixtureFactory());
|
||||
$this->fixtures[] = $fixture;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all fixtures which were previously loaded through
|
||||
* {@link loadFixture()}.
|
||||
* {@link loadFixture()}
|
||||
*/
|
||||
public function clearFixtures() {
|
||||
$this->fixtures = array();
|
||||
$this->getFixtureFactory()->clear();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -765,7 +752,7 @@ class SapphireTest extends PHPUnit_Framework_TestCase {
|
||||
$dbConn->selectDatabase($dbname);
|
||||
$dbConn->createDatabase();
|
||||
|
||||
$st = new SapphireTest();
|
||||
$st = Injector::inst()->create('SapphireTest');
|
||||
$st->resetDBSchema();
|
||||
|
||||
// Reinstate PHPUnit error handling
|
||||
|
@ -392,7 +392,7 @@ HTML;
|
||||
|
||||
// Fixture
|
||||
if($fixtureFile) {
|
||||
$fixture = new YamlFixture($fixtureFile);
|
||||
$fixture = Injector::inst()->create('YamlFixture', $fixtureFile);
|
||||
$fixture->saveIntoDatabase();
|
||||
|
||||
// If no fixture, then use defaults
|
||||
@ -466,7 +466,7 @@ HTML;
|
||||
SapphireTest::empty_temp_db();
|
||||
|
||||
if(isset($_GET['fixture']) && ($fixtureFile = $_GET['fixture'])) {
|
||||
$fixture = new YamlFixture($fixtureFile);
|
||||
$fixture = Injector::inst()->create('YamlFixture', $fixtureFile);
|
||||
$fixture->saveIntoDatabase();
|
||||
return "<p>Re-test the test database with fixture '$fixtureFile'. Time to start testing; where would"
|
||||
. " you like to start?</p>";
|
||||
@ -530,7 +530,7 @@ HTML;
|
||||
}
|
||||
|
||||
// Fixture
|
||||
$fixture = new YamlFixture($fixtureFile);
|
||||
$fixture = Injector::inst()->create('YamlFixture', $fixtureFile);
|
||||
$fixture->saveIntoDatabase();
|
||||
|
||||
return "<p>Loaded fixture '$fixtureFile' into session</p>";
|
||||
|
@ -66,8 +66,6 @@ require_once 'thirdparty/spyc/spyc.php';
|
||||
* @subpackage core
|
||||
*
|
||||
* @see http://code.google.com/p/spyc/
|
||||
*
|
||||
* @todo Write unit test for YamlFixture
|
||||
*/
|
||||
class YamlFixture extends Object {
|
||||
|
||||
@ -78,13 +76,6 @@ class YamlFixture extends Object {
|
||||
*/
|
||||
protected $fixtureFile;
|
||||
|
||||
/**
|
||||
* Array of fixture items
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fixtureDictionary;
|
||||
|
||||
/**
|
||||
* String containing fixture
|
||||
*
|
||||
@ -92,6 +83,12 @@ class YamlFixture extends Object {
|
||||
*/
|
||||
protected $fixtureString;
|
||||
|
||||
/**
|
||||
* @var FixtureFactory
|
||||
* @deprecated 3.1 Use writeInto() and FixtureFactory instead
|
||||
*/
|
||||
protected $factory;
|
||||
|
||||
/**
|
||||
* @param String Absolute file path, or relative path to {@link Director::baseFolder()}
|
||||
*/
|
||||
@ -128,41 +125,47 @@ class YamlFixture extends Object {
|
||||
|
||||
/**
|
||||
* Get the ID of an object from the fixture.
|
||||
*
|
||||
* @deprecated 3.1 Use writeInto() and FixtureFactory accessors instead
|
||||
*
|
||||
* @param $className The data class, as specified in your fixture file. Parent classes won't work
|
||||
* @param $identifier The identifier string, as provided in your fixture file
|
||||
*/
|
||||
public function idFromFixture($className, $identifier) {
|
||||
if(isset($this->fixtureDictionary[$className][$identifier])) {
|
||||
return $this->fixtureDictionary[$className][$identifier];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
Deprecation::notice('3.1', 'Use writeInto() and FixtureFactory accessors instead');
|
||||
|
||||
if(!$this->factory) $this->factory = Injector::inst()->create('FixtureFactory');
|
||||
return $this->factory->getId($className, $identifier);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all of the IDs in the fixture of a particular class name.
|
||||
*
|
||||
* @deprecated 3.1 Use writeInto() and FixtureFactory accessors instead
|
||||
*
|
||||
* @return A map of fixture-identifier => object-id
|
||||
*/
|
||||
public function allFixtureIDs($className) {
|
||||
if(isset($this->fixtureDictionary[$className])) {
|
||||
return $this->fixtureDictionary[$className];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
Deprecation::notice('3.1', 'Use writeInto() and FixtureFactory accessors instead');
|
||||
|
||||
if(!$this->factory) $this->factory = Injector::inst()->create('FixtureFactory');
|
||||
return $this->factory->getIds($className);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an object from the fixture.
|
||||
*
|
||||
* @deprecated 3.1 Use writeInto() and FixtureFactory accessors instead
|
||||
*
|
||||
* @param $className The data class, as specified in your fixture file. Parent classes won't work
|
||||
* @param $identifier The identifier string, as provided in your fixture file
|
||||
*/
|
||||
public function objFromFixture($className, $identifier) {
|
||||
$id = $this->idFromFixture($className, $identifier);
|
||||
if($id) return DataObject::get_by_id($className, $id);
|
||||
Deprecation::notice('3.1', 'Use writeInto() and FixtureFactory accessors instead');
|
||||
|
||||
if(!$this->factory) $this->factory = Injector::inst()->create('FixtureFactory');
|
||||
return $this->factory->get($className, $identifier);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -172,14 +175,24 @@ class YamlFixture extends Object {
|
||||
* Caution: In order to support reflexive relations which need a valid object ID,
|
||||
* the record is written twice: first after populating all non-relational fields,
|
||||
* then again after populating all relations (has_one, has_many, many_many).
|
||||
*
|
||||
* @deprecated 3.1 Use writeInto() and FixtureFactory instance instead
|
||||
*/
|
||||
public function saveIntoDatabase(DataModel $model) {
|
||||
// We have to disable validation while we import the fixtures, as the order in
|
||||
// which they are imported doesnt guarantee valid relations until after the
|
||||
// import is complete.
|
||||
$validationenabled = DataObject::get_validation_enabled();
|
||||
DataObject::set_validation_enabled(false);
|
||||
Deprecation::notice('3.1', 'Use writeInto() and FixtureFactory instance instead');
|
||||
|
||||
if(!$this->factory) $this->factory = Injector::inst()->create('FixtureFactory');
|
||||
$this->writeInto($this->factory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Persists the YAML data in a FixtureFactory,
|
||||
* which in turn saves them into the database.
|
||||
* Please use the passed in factory to access the fixtures afterwards.
|
||||
*
|
||||
* @param FixtureFactory $factory
|
||||
*/
|
||||
public function writeInto(FixtureFactory $factory) {
|
||||
$parser = new Spyc();
|
||||
if (isset($this->fixtureString)) {
|
||||
$fixtureContent = $parser->load($this->fixtureString);
|
||||
@ -187,112 +200,15 @@ class YamlFixture extends Object {
|
||||
$fixtureContent = $parser->loadFile($this->fixtureFile);
|
||||
}
|
||||
|
||||
$this->fixtureDictionary = array();
|
||||
foreach($fixtureContent as $dataClass => $items) {
|
||||
if(ClassInfo::exists($dataClass)) {
|
||||
$this->writeDataObject($model, $dataClass, $items);
|
||||
} else {
|
||||
$this->writeSQL($dataClass, $items);
|
||||
}
|
||||
}
|
||||
|
||||
DataObject::set_validation_enabled($validationenabled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the fixture into the database using DataObjects
|
||||
*
|
||||
* @param string $dataClass
|
||||
* @param array $items
|
||||
*/
|
||||
protected function writeDataObject($model, $dataClass, $items) {
|
||||
foreach($items as $identifier => $fields) {
|
||||
$obj = $model->$dataClass->newObject();
|
||||
|
||||
// If an ID is explicitly passed, then we'll sort out the initial write straight away
|
||||
// This is just in case field setters triggered by the population code in the next block
|
||||
// Call $this->write(). (For example, in FileTest)
|
||||
if(isset($fields['ID'])) {
|
||||
$obj->ID = $fields['ID'];
|
||||
|
||||
// The database needs to allow inserting values into the foreign key column (ID in our case)
|
||||
$conn = DB::getConn();
|
||||
if(method_exists($conn, 'allowPrimaryKeyEditing')) {
|
||||
$conn->allowPrimaryKeyEditing(ClassInfo::baseDataClass($dataClass), true);
|
||||
}
|
||||
$obj->write(false, true);
|
||||
if(method_exists($conn, 'allowPrimaryKeyEditing')) {
|
||||
$conn->allowPrimaryKeyEditing(ClassInfo::baseDataClass($dataClass), false);
|
||||
foreach($fixtureContent as $class => $items) {
|
||||
foreach($items as $identifier => $data) {
|
||||
if(ClassInfo::exists($class)) {
|
||||
$factory->createObject($class, $identifier, $data);
|
||||
} else {
|
||||
$factory->createRaw($class, $identifier, $data);
|
||||
}
|
||||
}
|
||||
|
||||
// Populate the dictionary with the ID
|
||||
if($fields) foreach($fields as $fieldName => $fieldVal) {
|
||||
if($obj->many_many($fieldName) || $obj->has_many($fieldName) || $obj->has_one($fieldName)) continue;
|
||||
$obj->$fieldName = $this->parseFixtureVal($fieldVal);
|
||||
}
|
||||
$obj->write();
|
||||
|
||||
// has to happen before relations in case a class is referring to itself
|
||||
$this->fixtureDictionary[$dataClass][$identifier] = $obj->ID;
|
||||
|
||||
// Populate all relations
|
||||
if($fields) foreach($fields as $fieldName => $fieldVal) {
|
||||
if($obj->many_many($fieldName) || $obj->has_many($fieldName)) {
|
||||
$parsedItems = array();
|
||||
$items = preg_split('/ *, */',trim($fieldVal));
|
||||
foreach($items as $item) {
|
||||
$parsedItems[] = $this->parseFixtureVal($item);
|
||||
}
|
||||
$obj->write();
|
||||
if($obj->has_many($fieldName)) {
|
||||
$obj->getComponents($fieldName)->setByIDList($parsedItems);
|
||||
} elseif($obj->many_many($fieldName)) {
|
||||
$obj->getManyManyComponents($fieldName)->setByIDList($parsedItems);
|
||||
}
|
||||
} elseif($obj->has_one($fieldName)) {
|
||||
$obj->{$fieldName . 'ID'} = $this->parseFixtureVal($fieldVal);
|
||||
}
|
||||
}
|
||||
$obj->write();
|
||||
//If LastEdited was set in the fixture, set it here
|
||||
if (array_key_exists('LastEdited', $fields)) {
|
||||
$manip = array($dataClass => array("command" => "update", "id" => $obj->id,
|
||||
"fields" => array("LastEdited" => "'".$this->parseFixtureVal($fields['LastEdited'])."'")));
|
||||
DB::manipulate($manip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the fixture into the database directly using a database manipulation
|
||||
*
|
||||
* @param string $table
|
||||
* @param array $items
|
||||
*/
|
||||
protected function writeSQL($table, $items) {
|
||||
foreach($items as $identifier => $fields) {
|
||||
$manipulation = array($table => array("fields" => array(), "command" => "insert"));
|
||||
foreach($fields as $fieldName=> $fieldVal) {
|
||||
$manipulation[$table]["fields"][$fieldName] = "'".$this->parseFixtureVal($fieldVal)."'";
|
||||
}
|
||||
DB::manipulate($manipulation);
|
||||
$this->fixtureDictionary[$table][$identifier] = DB::getGeneratedID($table);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a value from a fixture file. If it starts with => it will get an ID from the fixture dictionary
|
||||
*/
|
||||
protected function parseFixtureVal($fieldVal) {
|
||||
// Parse a dictionary reference - used to set foreign keys
|
||||
if(substr($fieldVal,0,2) == '=>') {
|
||||
list($a, $b) = explode('.', substr($fieldVal,2), 2);
|
||||
return $this->fixtureDictionary[$a][$b];
|
||||
|
||||
// Regular field value setting
|
||||
} else {
|
||||
return $fieldVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ To install Composer, run the following commands from your command-line.
|
||||
curl -s https://getcomposer.org/installer | php
|
||||
|
||||
# Move to your path
|
||||
sudo mv composer.phar /usr/bin/composer
|
||||
sudo mv composer.phar /usr/local/bin/composer
|
||||
|
||||
Or [download composer.phar](http://getcomposer.org/composer.phar) manually, and rename `composer.phar` as `composer`, and put it in your path. On Windows, you should call the file `composer.bat`.
|
||||
|
||||
|
@ -62,76 +62,8 @@ specific to the framework, e.g. `[assertEmailSent](api:SapphireTest->assertEmail
|
||||
which can simulate sending emails through the `Email->send()` API without actually
|
||||
using a mail server (see the [testing emails](email-sending)) guide.
|
||||
|
||||
## The Database YAML file
|
||||
## Fixtures
|
||||
|
||||
The main feature of `[api:SapphireTest]` over the raw PHPUnit classes is that SapphireTest will prepare a temporary database for
|
||||
you. The content of that database is provided in a special YAML file. YAML is a simple markup languages that uses tabs
|
||||
and colons instead of the more verbose XML tags, and because of this much better for developers creating files by hand.
|
||||
|
||||
We will begin with a sample file and talk our way through it.
|
||||
|
||||
Page:
|
||||
home:
|
||||
Title: Home
|
||||
about:
|
||||
Title: About Us
|
||||
staff:
|
||||
Title: Staff
|
||||
URLSegment: my-staff
|
||||
Parent: =>Page.about
|
||||
staffduplicate:
|
||||
Title: Staff
|
||||
URLSegment: my-staff
|
||||
Parent: =>Page.about
|
||||
products:
|
||||
Title: Products
|
||||
product1:
|
||||
Title: 1.1 Test Product
|
||||
product2:
|
||||
Title: Another Product
|
||||
product3:
|
||||
Title: Another Product
|
||||
product4:
|
||||
Title: Another Product
|
||||
contact:
|
||||
Title: Contact Us
|
||||
|
||||
ErrorPage:
|
||||
404:
|
||||
Title: Page not Found
|
||||
ErrorCode: 404
|
||||
|
||||
|
||||
The contents of the YAML file are broken into three levels.
|
||||
|
||||
* **Top level: class names** - Page and ErrorPage. This is the name of the dataobject class that should be created.
|
||||
The fact that ErrorPage is actually a subclass is irrelevant to the system populating the database. It just
|
||||
instantiates the object you specify.
|
||||
* **Second level: identifiers** - home, about, staff, staffduplicate, etc. These are the identifiers that you pass as
|
||||
the second argument of SapphireTest::objFromFixture(). Each identifier you specify delimits a new database record.
|
||||
This means that every record needs to have an identifier, whether you use it or not.
|
||||
* **Third level: fields** - each field for the record is listed as a 3rd level entry. In most cases, the field's raw
|
||||
content is provided. However, if you want to define a relationship, you can do so using "=>".
|
||||
|
||||
There are a couple of lines like this:
|
||||
|
||||
Parent: =>Page.about
|
||||
|
||||
This will tell the system to set the ParentID database field to the ID of the Page object with the identifier "about".
|
||||
This can be used on any has-one or many-many relationship. Note that we use the name of the relationship (Parent), and
|
||||
not the name of the database field (ParentID)
|
||||
|
||||
On many-many relationships, you should specify a comma separated list of values.
|
||||
|
||||
MyRelation: =>Class.inst1,=>Class.inst2,=>Class.inst3
|
||||
|
||||
An crucial thing to note is that **the YAML file specifies DataObjects, not database records**. The database is
|
||||
populated by instantiating DataObject objects, setting the fields listed, and calling write(). This means that any
|
||||
onBeforeWrite() or default value logic will be executed as part of the test. This forms the basis of our
|
||||
testURLGeneration() test above.
|
||||
|
||||
For example, the URLSegment value of Page.staffduplicate is the same as the URLSegment value of Page.staff. When the
|
||||
fixture is set up, the URLSegment value of Page.staffduplicate will actually be my-staff-2.
|
||||
|
||||
Finally, be aware that requireDefaultRecords() is **not** called by the database populator - so you will need to specify
|
||||
standard pages such as 404 and home in your YAML file.
|
||||
Often you need to test your functionality with some existing data, so called "fixtures".
|
||||
These records are inserted on a fresh test database automatically.
|
||||
[Read more about fixtures](fixtures).
|
228
docs/en/topics/testing/fixtures.md
Normal file
228
docs/en/topics/testing/fixtures.md
Normal file
@ -0,0 +1,228 @@
|
||||
# Fixtures
|
||||
|
||||
## Overview
|
||||
|
||||
Often you need to test your functionality with some existing data, so called "fixtures".
|
||||
The `[api:SapphireTest]` class already prepares an empty database for you,
|
||||
and you have various ways to define those fixtures.
|
||||
|
||||
## YAML Fixtures
|
||||
|
||||
YAML is a markup language which is deliberately simple and easy to read,
|
||||
so ideal for our fixture generation.
|
||||
|
||||
We will begin with a sample file and talk our way through it.
|
||||
|
||||
Page:
|
||||
home:
|
||||
Title: Home
|
||||
about:
|
||||
Title: About Us
|
||||
staff:
|
||||
Title: Staff
|
||||
URLSegment: my-staff
|
||||
Parent: =>Page.about
|
||||
|
||||
RedirectorPage:
|
||||
redirect_home:
|
||||
RedirectionType: Internal
|
||||
LinkTo: =>Page.home
|
||||
|
||||
|
||||
The contents of the YAML file are broken into three levels.
|
||||
|
||||
* **Top level: class names** - `Page` and `RedirectorPage`. This is the name of the dataobject class that should be created.
|
||||
The fact that `RedirectorPage` is actually a subclass is irrelevant to the system populating the database. It just
|
||||
instantiates the object you specify.
|
||||
* **Second level: identifiers** - `home`, `about`, etc. These are the identifiers that you pass as
|
||||
the second argument of SapphireTest::objFromFixture(). Each identifier you specify delimits a new database record.
|
||||
This means that every record needs to have an identifier, whether you use it or not.
|
||||
* **Third level: fields** - each field for the record is listed as a 3rd level entry. In most cases, the field's raw
|
||||
content is provided. However, if you want to define a relationship, you can do so using "=>".
|
||||
|
||||
There are a couple of lines like this:
|
||||
|
||||
Parent: =>Page.about
|
||||
|
||||
This will tell the system to set the ParentID database field to the ID of the Page object with the identifier "about".
|
||||
This can be used on any has-one or many-many relationship. Note that we use the name of the relationship (Parent), and
|
||||
not the name of the database field (ParentID)
|
||||
|
||||
On many-many relationships, you should specify a comma separated list of values.
|
||||
|
||||
MyRelation: =>Class.inst1,=>Class.inst2,=>Class.inst3
|
||||
|
||||
An crucial thing to note is that **the YAML file specifies DataObjects, not database records**. The database is
|
||||
populated by instantiating DataObject objects, setting the fields listed, and calling write(). This means that any
|
||||
onBeforeWrite() or default value logic will be executed as part of the test. This forms the basis of our
|
||||
testURLGeneration() test above.
|
||||
|
||||
For example, the URLSegment value of Page.staffduplicate is the same as the URLSegment value of Page.staff. When the
|
||||
fixture is set up, the URLSegment value of Page.staffduplicate will actually be my-staff-2.
|
||||
|
||||
Finally, be aware that requireDefaultRecords() is **not** called by the database populator - so you will need to specify
|
||||
standard pages such as 404 and home in your YAML file.
|
||||
|
||||
## Test Class Definition
|
||||
|
||||
|
||||
|
||||
## Manual Object Creation
|
||||
|
||||
Sometimes statically defined fixtures don't suffice, because of the complexity of the tested model,
|
||||
or because the YAML format doesn't allow you to modify all model state.
|
||||
One common example here is publishing pages (page fixtures aren't published by default).
|
||||
|
||||
You can always resort to creating objects manually in the test setup phase.
|
||||
Since the test database is cleared on every test method, you'll get a fresh
|
||||
set of test instances every time.
|
||||
|
||||
:::php
|
||||
class SiteTreeTest extends SapphireTest {
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
for($i=0; $i<100; $i++) {
|
||||
$page = new Page(array('Title' => "Page $i"));
|
||||
$page->write();
|
||||
$page->publish('Stage', 'Live');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
## Fixture Factories
|
||||
|
||||
### Why Factories?
|
||||
|
||||
Manually defined fixture provide full flexibility, but very little in terms of structure and convention.
|
||||
Alternatively, you can use the `[api:FixtureFactory]` class, which allows you
|
||||
to set default values, callbacks on object creation, and dynamic/lazy value setting.
|
||||
By the way, the `SapphireTest` YAML fixtures rely on internally on this class as well.
|
||||
|
||||
The idea is that rather than instanciating objects directly, we'll have a factory class for them.
|
||||
This factory can have so called "blueprints" defined on it, which tells the factory
|
||||
how to instanciate an object of a specific type. Blueprints need a name,
|
||||
which is usually set to the class it creates.
|
||||
|
||||
### Usage
|
||||
|
||||
Since blueprints are auto-created for all available DataObject subclasses,
|
||||
you only need to instanciate a factory to start using it.
|
||||
|
||||
:::php
|
||||
$factory = Injector::inst()->create('FixtureFactory');
|
||||
$obj = $factory->createObject('MyClass', 'myobj1');
|
||||
|
||||
It is important to remember that fixtures are referenced by arbitrary
|
||||
identifiers ('myobj1'). These are internally mapped to their database identifiers.
|
||||
|
||||
:::
|
||||
$databaseId = $factory->getId('MyClass', 'myobj1');
|
||||
|
||||
In order to create an object with certain properties, just add a second argument:
|
||||
|
||||
:::php
|
||||
$obj = $factory->createObject('MyClass', 'myobj1', array('MyProperty' => 'My Value'));
|
||||
|
||||
### Default Properties
|
||||
|
||||
Blueprints can be overwritten in order to customize their behaviour,
|
||||
for example with default properties in case none are passed into `createObject()`.
|
||||
|
||||
:::php
|
||||
$factory->define('MyObject', array(
|
||||
'MyProperty' => 'My Default Value'
|
||||
));
|
||||
|
||||
### Dependent Properties
|
||||
|
||||
Values can be set on demand through anonymous functions,
|
||||
which can either generate random defaults, or create
|
||||
composite values based on other fixture data.
|
||||
|
||||
:::php
|
||||
$factory->define('Member', array(
|
||||
'Email' => function($obj, $data, $fixtures) {
|
||||
if(isset($data['FirstName']) {
|
||||
$obj->Email = strtolower($data['FirstName']) . '@example.org';
|
||||
}
|
||||
},
|
||||
'Score' => function($obj, $data, $fixtures) {
|
||||
$obj->Score = rand(0,10);
|
||||
}
|
||||
));
|
||||
|
||||
### Relations
|
||||
|
||||
Model relations can be expressed through the same notation as in the YAML fixture format
|
||||
described earlier, through the `=>` prefix on data values.
|
||||
|
||||
:::php
|
||||
$obj = $factory->createObject('MyObject', array(
|
||||
'MyHasManyRelation' => '=>MyOtherObject.obj1,=>MyOtherObject.obj2'
|
||||
));
|
||||
|
||||
### Callbacks
|
||||
|
||||
Sometimes new model instances need to be modified in ways which can't be expressed
|
||||
in their properties, for example to publish a page, which requires a method call.
|
||||
|
||||
:::php
|
||||
$blueprint = Injector::inst()->create('FixtureBlueprint', 'Member');
|
||||
$blueprint->addCallback('afterCreate', function($obj, $identifier, $data, $fixtures) {
|
||||
$obj->publish('Stage', 'Live');
|
||||
});
|
||||
$page = $factory->define('Page', $blueprint);
|
||||
|
||||
Available callbacks:
|
||||
|
||||
* `beforeCreate($identifier, $data, $fixtures)`
|
||||
* `afterCreate($obj, $identifier, $data, $fixtures)`
|
||||
|
||||
### Multiple Blueprints
|
||||
|
||||
Data of the same type can have variations, for example forum members vs.
|
||||
CMS admins could both inherit from the `Member` class, but have completely
|
||||
different properties. This is where named blueprints come in.
|
||||
By default, blueprint names equal the class names they manage.
|
||||
|
||||
:::php
|
||||
$memberBlueprint = Injector::inst()->create('FixtureBlueprint', 'Member', 'Member');
|
||||
$adminBlueprint = Injector::inst()->create('FixtureBlueprint', 'AdminMember', 'Member');
|
||||
$adminBlueprint->addCallback('afterCreate', function($obj, $identifier, $data, $fixtures) {
|
||||
if(isset($fixtures['Group']['admin'])) {
|
||||
$adminGroup = Group::get()->byId($fixtures['Group']['admin']);
|
||||
$obj->Groups()->add($adminGroup);
|
||||
}
|
||||
});
|
||||
|
||||
$member = $factory->createObject('Member'); // not in admin group
|
||||
$admin = $factory->createObject('AdminMember'); // in admin group
|
||||
|
||||
### Full Test Example
|
||||
|
||||
:::php
|
||||
class MyObjectTest extends SapphireTest {
|
||||
|
||||
protected $factory;
|
||||
|
||||
function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
$factory = Injector::inst()->create('FixtureFactory');
|
||||
// Defines a "blueprint" for new objects
|
||||
$factory->define('MyObject', array(
|
||||
'MyProperty' => 'My Default Value'
|
||||
));
|
||||
$this->factory = $factory;
|
||||
}
|
||||
|
||||
function testSomething() {
|
||||
$MyObjectObj = $this->factory->createObject(
|
||||
'MyObject',
|
||||
array('MyOtherProperty' => 'My Custom Value')
|
||||
);
|
||||
// $myPageObj->MyProperty = My Default Value
|
||||
// $myPageObj->MyOtherProperty = My Custom Value
|
||||
}
|
||||
}
|
181
tests/dev/FixtureBlueprintTest.php
Normal file
181
tests/dev/FixtureBlueprintTest.php
Normal file
@ -0,0 +1,181 @@
|
||||
<?php
|
||||
/**
|
||||
* @package framework
|
||||
* @subpackage tests
|
||||
*/
|
||||
class FixtureBlueprintTest extends SapphireTest {
|
||||
|
||||
protected $usesDatabase = true;
|
||||
|
||||
protected $extraDataObjects = array(
|
||||
'FixtureFactoryTest_DataObject',
|
||||
'FixtureFactoryTest_DataObjectRelation'
|
||||
);
|
||||
|
||||
public function testCreateWithoutData() {
|
||||
$blueprint = new FixtureBlueprint('FixtureFactoryTest_DataObject');
|
||||
$obj = $blueprint->createObject('one');
|
||||
$this->assertNotNull($obj);
|
||||
$this->assertGreaterThan(0, $obj->ID);
|
||||
$this->assertEquals('', $obj->Name);
|
||||
}
|
||||
|
||||
public function testCreateWithData() {
|
||||
$blueprint = new FixtureBlueprint('FixtureFactoryTest_DataObject');
|
||||
$obj = $blueprint->createObject('one', array('Name' => 'My Name'));
|
||||
$this->assertNotNull($obj);
|
||||
$this->assertGreaterThan(0, $obj->ID);
|
||||
$this->assertEquals('My Name', $obj->Name);
|
||||
}
|
||||
|
||||
public function testCreateWithRelationship() {
|
||||
$blueprint = new FixtureBlueprint('FixtureFactoryTest_DataObject');
|
||||
|
||||
$relation1 = new FixtureFactoryTest_DataObjectRelation();
|
||||
$relation1->write();
|
||||
$relation2 = new FixtureFactoryTest_DataObjectRelation();
|
||||
$relation2->write();
|
||||
|
||||
$obj = $blueprint->createObject(
|
||||
'one',
|
||||
array(
|
||||
'ManyMany' =>
|
||||
'=>FixtureFactoryTest_DataObjectRelation.relation1,' .
|
||||
'=>FixtureFactoryTest_DataObjectRelation.relation2'
|
||||
),
|
||||
array(
|
||||
'FixtureFactoryTest_DataObjectRelation' => array(
|
||||
'relation1' => $relation1->ID,
|
||||
'relation2' => $relation2->ID
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$this->assertEquals(2, $obj->ManyMany()->Count());
|
||||
$this->assertNotNull($obj->ManyMany()->find('ID', $relation1->ID));
|
||||
$this->assertNotNull($obj->ManyMany()->find('ID', $relation2->ID));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException InvalidArgumentException
|
||||
* @expectedExceptionMessage No fixture definitions found
|
||||
*/
|
||||
public function testCreateWithInvalidRelationName() {
|
||||
$blueprint = new FixtureBlueprint('FixtureFactoryTest_DataObject');
|
||||
|
||||
$obj = $blueprint->createObject(
|
||||
'one',
|
||||
array(
|
||||
'ManyMany' => '=>UnknownClass.relation1'
|
||||
),
|
||||
array(
|
||||
'FixtureFactoryTest_DataObjectRelation' => array(
|
||||
'relation1' => 99
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException InvalidArgumentException
|
||||
* @expectedExceptionMessage No fixture definitions found
|
||||
*/
|
||||
public function testCreateWithInvalidRelationIdentifier() {
|
||||
$blueprint = new FixtureBlueprint('FixtureFactoryTest_DataObject');
|
||||
|
||||
$obj = $blueprint->createObject(
|
||||
'one',
|
||||
array(
|
||||
'ManyMany' => '=>FixtureFactoryTest_DataObjectRelation.unknown_identifier'
|
||||
),
|
||||
array(
|
||||
'FixtureFactoryTest_DataObjectRelation' => array(
|
||||
'relation1' => 99
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException InvalidArgumentException
|
||||
* @expectedExceptionMessage Invalid format
|
||||
*/
|
||||
public function testCreateWithInvalidRelationFormat() {
|
||||
$factory = new FixtureFactory();
|
||||
$blueprint = new FixtureBlueprint('FixtureFactoryTest_DataObject');
|
||||
|
||||
$relation1 = new FixtureFactoryTest_DataObjectRelation();
|
||||
$relation1->write();
|
||||
|
||||
$obj = $blueprint->createObject(
|
||||
'one',
|
||||
array(
|
||||
'ManyMany' => 'FixtureFactoryTest_DataObjectRelation.relation1'
|
||||
),
|
||||
array(
|
||||
'FixtureFactoryTest_DataObjectRelation' => array(
|
||||
'relation1' => $relation1->ID
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public function testCreateWithId() {
|
||||
$blueprint = new FixtureBlueprint('FixtureFactoryTest_DataObject');
|
||||
$obj = $blueprint->createObject('ninetynine', array('ID' => 99));
|
||||
$this->assertNotNull($obj);
|
||||
$this->assertEquals(99, $obj->ID);
|
||||
}
|
||||
|
||||
function testCallbackOnBeforeCreate() {
|
||||
$blueprint = new FixtureBlueprint('FixtureFactoryTest_DataObject');
|
||||
$this->_called = 0;
|
||||
$self = $this;
|
||||
$cb = function($identifier, $data, $fixtures) use($self) {
|
||||
$self->_called = $self->_called + 1;
|
||||
};
|
||||
$blueprint->addCallback('beforeCreate', $cb);
|
||||
$this->assertEquals(0, $this->_called);
|
||||
$obj1 = $blueprint->createObject('one');
|
||||
$this->assertEquals(1, $this->_called);
|
||||
$obj2 = $blueprint->createObject('two');
|
||||
$this->assertEquals(2, $this->_called);
|
||||
|
||||
$this->_called = 0;
|
||||
}
|
||||
|
||||
function testCallbackOnAfterCreate() {
|
||||
$blueprint = new FixtureBlueprint('FixtureFactoryTest_DataObject');
|
||||
$this->_called = 0;
|
||||
$self = $this;
|
||||
$cb = function($obj, $identifier, $data, $fixtures) use($self) {
|
||||
$self->_called = $self->_called + 1;
|
||||
};
|
||||
$blueprint->addCallback('afterCreate', $cb);
|
||||
$this->assertEquals(0, $this->_called);
|
||||
$obj1 = $blueprint->createObject('one');
|
||||
$this->assertEquals(1, $this->_called);
|
||||
$obj2 = $blueprint->createObject('two');
|
||||
$this->assertEquals(2, $this->_called);
|
||||
|
||||
$this->_called = 0;
|
||||
}
|
||||
|
||||
function testDefineWithDefaultCustomSetters() {
|
||||
$blueprint = new FixtureBlueprint(
|
||||
'FixtureFactoryTest_DataObject',
|
||||
null,
|
||||
array(
|
||||
'Name' => function($obj, $data, $fixtures) {
|
||||
return 'Default Name';
|
||||
}
|
||||
));
|
||||
|
||||
$obj1 = $blueprint->createObject('one');
|
||||
$this->assertEquals('Default Name', $obj1->Name);
|
||||
|
||||
$obj2 = $blueprint->createObject('one', array('Name' => 'Override Name'));
|
||||
$this->assertEquals('Override Name', $obj2->Name);
|
||||
}
|
||||
|
||||
}
|
170
tests/dev/FixtureFactoryTest.php
Normal file
170
tests/dev/FixtureFactoryTest.php
Normal file
@ -0,0 +1,170 @@
|
||||
<?php
|
||||
/**
|
||||
* @package framework
|
||||
* @subpackage tests
|
||||
*/
|
||||
class FixtureFactoryTest extends SapphireTest {
|
||||
|
||||
protected $usesDatabase = true;
|
||||
|
||||
protected $extraDataObjects = array(
|
||||
'FixtureFactoryTest_DataObject',
|
||||
'FixtureFactoryTest_DataObjectRelation'
|
||||
);
|
||||
|
||||
public function testCreateRaw() {
|
||||
$factory = new FixtureFactory();
|
||||
$id = $factory->createRaw('FixtureFactoryTest_DataObject', 'one', array('Name' => 'My Name'));
|
||||
$this->assertNotNull($id);
|
||||
$this->assertGreaterThan(0, $id);
|
||||
$obj = FixtureFactoryTest_DataObject::get()->find('ID', $id);
|
||||
$this->assertNotNull($obj);
|
||||
$this->assertEquals('My Name', $obj->Name);
|
||||
}
|
||||
|
||||
public function testSetId() {
|
||||
$factory = new FixtureFactory();
|
||||
$obj = new FixtureFactoryTest_DataObject();
|
||||
$obj->write();
|
||||
$factory->setId('FixtureFactoryTest_DataObject', 'one', $obj->ID);
|
||||
$this->assertEquals(
|
||||
$obj->ID,
|
||||
$factory->getId('FixtureFactoryTest_DataObject', 'one')
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetId() {
|
||||
$factory = new FixtureFactory();
|
||||
$obj = $factory->createObject('FixtureFactoryTest_DataObject', 'one');
|
||||
$this->assertEquals(
|
||||
$obj->ID,
|
||||
$factory->getId('FixtureFactoryTest_DataObject', 'one')
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetIds() {
|
||||
$factory = new FixtureFactory();
|
||||
$obj = $factory->createObject('FixtureFactoryTest_DataObject', 'one');
|
||||
$this->assertEquals(
|
||||
array('one' => $obj->ID),
|
||||
$factory->getIds('FixtureFactoryTest_DataObject')
|
||||
);
|
||||
}
|
||||
|
||||
public function testDefine() {
|
||||
$factory = new FixtureFactory();
|
||||
$this->assertFalse($factory->getBlueprint('FixtureFactoryTest_DataObject'));
|
||||
$factory->define('FixtureFactoryTest_DataObject');
|
||||
$this->assertInstanceOf(
|
||||
'FixtureBluePrint',
|
||||
$factory->getBlueprint('FixtureFactoryTest_DataObject')
|
||||
);
|
||||
}
|
||||
|
||||
public function testDefineWithCustomBlueprint() {
|
||||
$blueprint = new FixtureBlueprint('FixtureFactoryTest_DataObject');
|
||||
$factory = new FixtureFactory();
|
||||
$this->assertFalse($factory->getBlueprint('FixtureFactoryTest_DataObject'));
|
||||
$factory->define('FixtureFactoryTest_DataObject', $blueprint);
|
||||
$this->assertInstanceOf(
|
||||
'FixtureBluePrint',
|
||||
$factory->getBlueprint('FixtureFactoryTest_DataObject')
|
||||
);
|
||||
$this->assertEquals(
|
||||
$blueprint,
|
||||
$factory->getBlueprint('FixtureFactoryTest_DataObject')
|
||||
);
|
||||
}
|
||||
|
||||
public function testDefineWithDefaults() {
|
||||
$factory = new FixtureFactory();
|
||||
$factory->define('FixtureFactoryTest_DataObject', array('Name' => 'Default'));
|
||||
$obj = $factory->createObject('FixtureFactoryTest_DataObject', 'one');
|
||||
$this->assertEquals('Default', $obj->Name);
|
||||
}
|
||||
|
||||
public function testDefineMultipleBlueprintsForClass() {
|
||||
$factory = new FixtureFactory();
|
||||
$factory->define(
|
||||
'FixtureFactoryTest_DataObject',
|
||||
new FixtureBlueprint('FixtureFactoryTest_DataObject')
|
||||
);
|
||||
$factory->define(
|
||||
'FixtureFactoryTest_DataObjectWithDefaults',
|
||||
new FixtureBlueprint(
|
||||
'FixtureFactoryTest_DataObjectWithDefaults',
|
||||
'FixtureFactoryTest_DataObject',
|
||||
array('Name' => 'Default')
|
||||
)
|
||||
);
|
||||
|
||||
$obj = $factory->createObject('FixtureFactoryTest_DataObject', 'one');
|
||||
$this->assertNull($obj->Name);
|
||||
|
||||
$objWithDefaults = $factory->createObject('FixtureFactoryTest_DataObjectWithDefaults', 'two');
|
||||
$this->assertEquals('Default', $objWithDefaults->Name);
|
||||
|
||||
$this->assertEquals(
|
||||
$obj->ID,
|
||||
$factory->getId('FixtureFactoryTest_DataObject', 'one')
|
||||
);
|
||||
$this->assertEquals(
|
||||
$objWithDefaults->ID,
|
||||
$factory->getId('FixtureFactoryTest_DataObject', 'two'),
|
||||
'Can access fixtures under class name, not blueprint name'
|
||||
);
|
||||
}
|
||||
|
||||
public function testClear() {
|
||||
$factory = new FixtureFactory();
|
||||
$obj1Id = $factory->createRaw('FixtureFactoryTest_DataObject', 'one', array('Name' => 'My Name'));
|
||||
$obj2 = $factory->createObject('FixtureFactoryTest_DataObject', 'two');
|
||||
|
||||
$factory->clear();
|
||||
|
||||
$this->assertFalse($factory->getId('FixtureFactoryTest_DataObject', 'one'));
|
||||
$this->assertNull(FixtureFactoryTest_DataObject::get()->byId($obj1Id));
|
||||
$this->assertFalse($factory->getId('FixtureFactoryTest_DataObject', 'two'));
|
||||
$this->assertNull(FixtureFactoryTest_DataObject::get()->byId($obj2->ID));
|
||||
}
|
||||
|
||||
public function testClearWithClass() {
|
||||
$factory = new FixtureFactory();
|
||||
$obj1 = $factory->createObject('FixtureFactoryTest_DataObject', 'object-one');
|
||||
$relation1 = $factory->createObject('FixtureFactoryTest_DataObjectRelation', 'relation-one');
|
||||
|
||||
$factory->clear('FixtureFactoryTest_DataObject');
|
||||
|
||||
$this->assertFalse(
|
||||
$factory->getId('FixtureFactoryTest_DataObject', 'one')
|
||||
);
|
||||
$this->assertNull(FixtureFactoryTest_DataObject::get()->byId($obj1->ID));
|
||||
$this->assertEquals(
|
||||
$relation1->ID,
|
||||
$factory->getId('FixtureFactoryTest_DataObjectRelation', 'relation-one')
|
||||
);
|
||||
$this->assertInstanceOf(
|
||||
'FixtureFactoryTest_DataObjectRelation',
|
||||
FixtureFactoryTest_DataObjectRelation::get()->byId($relation1->ID)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class FixtureFactoryTest_DataObject extends DataObject implements TestOnly {
|
||||
static $db = array(
|
||||
"Name" => "Varchar"
|
||||
);
|
||||
static $many_many = array(
|
||||
"ManyMany" => "FixtureFactoryTest_DataObjectRelation"
|
||||
);
|
||||
}
|
||||
|
||||
class FixtureFactoryTest_DataObjectRelation extends DataObject implements TestOnly {
|
||||
static $db = array(
|
||||
"Name" => "Varchar"
|
||||
);
|
||||
static $belongs_many_many = array(
|
||||
"TestParent" => "FixtureFactoryTest_DataObject"
|
||||
);
|
||||
}
|
@ -241,8 +241,8 @@ class DataObjectTest extends SapphireTest {
|
||||
$team->Comments()->add($newComment);
|
||||
$this->assertEquals($team->ID, $newComment->TeamID);
|
||||
|
||||
$comment1 = $this->fixture->objFromFixture('DataObjectTest_TeamComment', 'comment1');
|
||||
$comment2 = $this->fixture->objFromFixture('DataObjectTest_TeamComment', 'comment2');
|
||||
$comment1 = $this->objFromFixture('DataObjectTest_TeamComment', 'comment1');
|
||||
$comment2 = $this->objFromFixture('DataObjectTest_TeamComment', 'comment2');
|
||||
$team->Comments()->remove($comment2);
|
||||
|
||||
$commentIDs = $team->Comments()->sort('ID')->column('ID');
|
||||
|
@ -2,8 +2,6 @@
|
||||
|
||||
class YamlFixtureTest extends SapphireTest {
|
||||
|
||||
static $fixture_file = 'YamlFixtureTest.yml';
|
||||
|
||||
protected $extraDataObjects = array(
|
||||
'YamlFixtureTest_DataObject',
|
||||
'YamlFixtureTest_DataObjectRelation',
|
||||
@ -11,14 +9,14 @@ class YamlFixtureTest extends SapphireTest {
|
||||
|
||||
public function testAbsoluteFixturePath() {
|
||||
$absPath = FRAMEWORK_PATH . '/tests/testing/YamlFixtureTest.yml';
|
||||
$obj = new YamlFixture($absPath);
|
||||
$obj = Injector::inst()->create('YamlFixture', $absPath);
|
||||
$this->assertEquals($absPath, $obj->getFixtureFile());
|
||||
$this->assertNull($obj->getFixtureString());
|
||||
}
|
||||
|
||||
public function testRelativeFixturePath() {
|
||||
$relPath = FRAMEWORK_DIR . '/tests/testing/YamlFixtureTest.yml';
|
||||
$obj = new YamlFixture($relPath);
|
||||
$obj = Injector::inst()->create('YamlFixture', $relPath);
|
||||
$this->assertEquals(Director::baseFolder() . '/' . $relPath, $obj->getFixtureFile());
|
||||
$this->assertNull($obj->getFixtureString());
|
||||
}
|
||||
@ -26,7 +24,7 @@ class YamlFixtureTest extends SapphireTest {
|
||||
public function testStringFixture() {
|
||||
$absPath = FRAMEWORK_PATH . '/tests/testing/YamlFixtureTest.yml';
|
||||
$string = file_get_contents($absPath);
|
||||
$obj = new YamlFixture($string);
|
||||
$obj = Injector::inst()->create('YamlFixture', $string);
|
||||
$this->assertEquals($string, $obj->getFixtureString());
|
||||
$this->assertNull($obj->getFixtureFile());
|
||||
}
|
||||
@ -36,16 +34,42 @@ class YamlFixtureTest extends SapphireTest {
|
||||
*/
|
||||
public function testFailsWithInvalidFixturePath() {
|
||||
$invalidPath = FRAMEWORK_DIR . '/tests/testing/invalid.yml';
|
||||
$obj = new YamlFixture($invalidPath);
|
||||
$obj = Injector::inst()->create('YamlFixture', $invalidPath);
|
||||
}
|
||||
|
||||
public function testSQLInsert() {
|
||||
$object1 = DataObject::get_by_id("YamlFixtureTest_DataObject",
|
||||
$this->idFromFixture("YamlFixtureTest_DataObject", "testobject1"));
|
||||
$this->assertTrue($object1->ManyMany()->Count() == 2, "Should be 2 items in this manymany relationship");
|
||||
$object2 = DataObject::get_by_id("YamlFixtureTest_DataObject",
|
||||
$this->idFromFixture("YamlFixtureTest_DataObject", "testobject2"));
|
||||
$this->assertTrue($object2->ManyMany()->Count() == 2, "Should be 2 items in this manymany relationship");
|
||||
$relPath = FRAMEWORK_DIR . '/tests/testing/YamlFixtureTest.yml';
|
||||
$fixture = Injector::inst()->create('YamlFixture', $relPath);
|
||||
$fixture->saveIntoDatabase(DataModel::inst());
|
||||
|
||||
$this->assertGreaterThan(0, $fixture->idFromFixture("YamlFixtureTest_DataObject", "testobject1"));
|
||||
$object1 = DataObject::get_by_id(
|
||||
"YamlFixtureTest_DataObject",
|
||||
$fixture->idFromFixture("YamlFixtureTest_DataObject", "testobject1")
|
||||
);
|
||||
$this->assertTrue(
|
||||
$object1->ManyMany()->Count() == 2,
|
||||
"Should be two items in this relationship"
|
||||
);
|
||||
$this->assertGreaterThan(0, $fixture->idFromFixture("YamlFixtureTest_DataObject", "testobject2"));
|
||||
$object2 = DataObject::get_by_id(
|
||||
"YamlFixtureTest_DataObject",
|
||||
$fixture->idFromFixture("YamlFixtureTest_DataObject", "testobject2")
|
||||
);
|
||||
$this->assertTrue(
|
||||
$object2->ManyMany()->Count() == 1,
|
||||
"Should be one item in this relationship"
|
||||
);
|
||||
}
|
||||
|
||||
public function testWriteInto() {
|
||||
$factory = Injector::inst()->create('FixtureFactory');
|
||||
|
||||
$relPath = FRAMEWORK_DIR . '/tests/testing/YamlFixtureTest.yml';
|
||||
$fixture = Injector::inst()->create('YamlFixture', $relPath);
|
||||
$fixture->writeInto($factory);
|
||||
|
||||
$this->assertGreaterThan(0, $factory->getId("YamlFixtureTest_DataObject", "testobject1"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,23 +1,12 @@
|
||||
YamlFixtureTest_DataObject:
|
||||
testobject1:
|
||||
Name: TestObject1
|
||||
testobject2:
|
||||
Name: TestObject2
|
||||
YamlFixtureTest_DataObjectRelation:
|
||||
relation1:
|
||||
Name: Relation1
|
||||
relation2:
|
||||
Name: Relation2
|
||||
YamlFixtureTest_DataObject_ManyMany:
|
||||
manymany1:
|
||||
YamlFixtureTest_DataObjectID: =>YamlFixtureTest_DataObject.testobject1
|
||||
YamlFixtureTest_DataObjectRelationID: =>YamlFixtureTest_DataObjectRelation.relation1
|
||||
manymany2:
|
||||
YamlFixtureTest_DataObjectID: =>YamlFixtureTest_DataObject.testobject1
|
||||
YamlFixtureTest_DataObjectRelationID: =>YamlFixtureTest_DataObjectRelation.relation2
|
||||
manymany3:
|
||||
YamlFixtureTest_DataObjectID: =>YamlFixtureTest_DataObject.testobject2
|
||||
YamlFixtureTest_DataObjectRelationID: =>YamlFixtureTest_DataObjectRelation.relation1
|
||||
manymany4:
|
||||
YamlFixtureTest_DataObjectID: =>YamlFixtureTest_DataObject.testobject2
|
||||
YamlFixtureTest_DataObjectRelationID: =>YamlFixtureTest_DataObjectRelation.relation2
|
||||
YamlFixtureTest_DataObject:
|
||||
testobject1:
|
||||
Name: TestObject1
|
||||
ManyMany: =>YamlFixtureTest_DataObjectRelation.relation1,=>YamlFixtureTest_DataObjectRelation.relation2
|
||||
testobject2:
|
||||
Name: TestObject2
|
||||
ManyMany: =>YamlFixtureTest_DataObjectRelation.relation1
|
Loading…
Reference in New Issue
Block a user