mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 12:05:37 +00:00
#3927 ENHANCEMENT Added support for many-many auto-setting relations with a standard ComplexTableField
MINOR Added tests for ComplexTableField - ComplexTableFieldTest git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/branches/2.3@75738 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
parent
7861a8f740
commit
faeed904dc
@ -60,6 +60,35 @@ class ComponentSet extends DataObjectSet {
|
||||
$this->joinField = $joinField;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the extra field data for a single row of the relationship
|
||||
* join table, given the known child ID.
|
||||
*
|
||||
* @param string $componentName The name of the component
|
||||
* @param int $childID The ID of the child for the relationship
|
||||
* @return array Map of fieldName => fieldValue
|
||||
*/
|
||||
function getExtraData($componentName, $childID) {
|
||||
$ownerObj = $this->ownerObj;
|
||||
$parentField = $this->ownerClass . 'ID';
|
||||
$childField = ($this->childClass == $this->ownerClass) ? 'ChildID' : ($this->childClass . 'ID');
|
||||
$result = array();
|
||||
|
||||
if(!$componentName) return false;
|
||||
|
||||
// @todo Optimize into a single query instead of one per extra field
|
||||
$extraFields = $ownerObj->many_many_extraFields($componentName);
|
||||
if($extraFields) {
|
||||
foreach($extraFields as $fieldName => $dbFieldSpec) {
|
||||
$query = DB::query("SELECT $fieldName FROM {$this->tableName} WHERE $parentField = '{$this->ownerObj->ID}' AND $childField = '{$childID}'");
|
||||
$value = $query->value();
|
||||
$result[$fieldName] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of all the IDs in this component set, where the keys are the same as the
|
||||
* values.
|
||||
@ -95,7 +124,6 @@ class ComponentSet extends DataObjectSet {
|
||||
}
|
||||
|
||||
$item = DataObject::get_by_id($this->childClass, $item);
|
||||
|
||||
if(!$item) return;
|
||||
}
|
||||
|
||||
@ -292,4 +320,4 @@ OUT;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
||||
|
@ -1421,6 +1421,90 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
||||
return isset($items) ? $items : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the many-to-many extra fields specification.
|
||||
*
|
||||
* If you don't specify a component name, it returns all
|
||||
* extra fields for all components available.
|
||||
*
|
||||
* @param string $component Name of component
|
||||
* @return array
|
||||
*/
|
||||
public function many_many_extraFields($component = null) {
|
||||
$classes = ClassInfo::ancestry($this);
|
||||
|
||||
foreach($classes as $class) {
|
||||
if(in_array($class, array('ViewableData', 'Object', 'DataObject'))) continue;
|
||||
|
||||
// Find extra fields for one component
|
||||
if($component) {
|
||||
$SNG_class = singleton($class);
|
||||
$extraFields = $SNG_class->stat('many_many_extraFields');
|
||||
|
||||
// Extra fields are immediately available on this class
|
||||
if(isset($extraFields[$component])) {
|
||||
return $extraFields[$component];
|
||||
}
|
||||
|
||||
$manyMany = $SNG_class->stat('many_many');
|
||||
$candidate = (isset($manyMany[$component])) ? $manyMany[$component] : null;
|
||||
if($candidate) {
|
||||
$SNG_candidate = singleton($candidate);
|
||||
$candidateManyMany = $SNG_candidate->stat('belongs_many_many');
|
||||
|
||||
// Find the relation given the class
|
||||
if($candidateManyMany) foreach($candidateManyMany as $relation => $relatedClass) {
|
||||
if($relatedClass == $class) {
|
||||
$relationName = $relation;
|
||||
}
|
||||
}
|
||||
|
||||
$extraFields = $SNG_candidate->stat('many_many_extraFields');
|
||||
if(isset($extraFields[$relationName])) {
|
||||
return $extraFields[$relationName];
|
||||
}
|
||||
}
|
||||
|
||||
$manyMany = $SNG_class->stat('belongs_many_many');
|
||||
$candidate = (isset($manyMany[$component])) ? $manyMany[$component] : null;
|
||||
if($candidate) {
|
||||
$SNG_candidate = singleton($candidate);
|
||||
$candidateManyMany = $SNG_candidate->stat('many_many');
|
||||
|
||||
// Find the relation given the class
|
||||
if($candidateManyMany) foreach($candidateManyMany as $relation => $relatedClass) {
|
||||
if($relatedClass == $class) {
|
||||
$relationName = $relation;
|
||||
}
|
||||
}
|
||||
|
||||
$extraFields = $SNG_candidate->stat('many_many_extraFields');
|
||||
if(isset($extraFields[$relationName])) {
|
||||
return $extraFields[$relationName];
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// Find all the extra fields for all components
|
||||
$newItems = eval("return (array){$class}::\$many_many_extraFields;");
|
||||
|
||||
foreach($newItems as $k => $v) {
|
||||
if(!is_array($v)) {
|
||||
user_error(
|
||||
"$class::\$many_many_extraFields has a bad entry: "
|
||||
. var_export($k, true) . " => " . var_export($v, true)
|
||||
. ". Each many_many_extraFields entry should map to a field specification array.",
|
||||
E_USER_ERROR
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return isset($items) ? array_merge($newItems, $items) : $newItems;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return information about a many-to-many component.
|
||||
* The return value is an array of (parentclass, childclass). If $component is null, then all many-many
|
||||
|
@ -455,61 +455,109 @@ JS;
|
||||
* this method.
|
||||
*/
|
||||
function getCustomFieldsFor($childData) {
|
||||
// If the fieldset is passed, use it
|
||||
if(is_a($this->detailFormFields,"Fieldset")) {
|
||||
if($this->detailFormFields instanceof Fieldset) {
|
||||
return $this->detailFormFields;
|
||||
|
||||
// Else use the formfields returned from the object via a string method call.
|
||||
} else {
|
||||
if(!is_string($this->detailFormFields)) $this->detailFormFields = "getCMSFields";
|
||||
$functioncall = $this->detailFormFields;
|
||||
if(!$childData->hasMethod($functioncall)) $functioncall = "getCMSFields";
|
||||
|
||||
return $childData->$functioncall();
|
||||
}
|
||||
}
|
||||
$fieldsMethod = $this->detailFormFields;
|
||||
|
||||
if(!is_string($fieldsMethod)) {
|
||||
$this->detailFormFields = 'getCMSFields';
|
||||
$fieldsMethod = 'getCMSFields';
|
||||
}
|
||||
|
||||
if(!$childData->hasMethod($fieldsMethod)) {
|
||||
$fieldsMethod = 'getCMSFields';
|
||||
}
|
||||
|
||||
$fields = $childData->$fieldsMethod();
|
||||
}
|
||||
|
||||
if(!$this->relationAutoSetting) {
|
||||
return $fields;
|
||||
}
|
||||
|
||||
if($this->sourceID()) {
|
||||
$parentClass = DataObject::get_by_id($this->getParentClass(), $this->sourceID());
|
||||
} else {
|
||||
$parentClass = singleton($this->getParentClass());
|
||||
}
|
||||
|
||||
$manyManyExtraFields = $parentClass->many_many_extraFields($this->name);
|
||||
if($manyManyExtraFields) {
|
||||
foreach($manyManyExtraFields as $fieldName => $fieldSpec) {
|
||||
$dbField = new Varchar('ctf[extraFields][' . $fieldName . ']');
|
||||
$fields->addFieldToTab('Root.Main', $dbField->scaffoldFormField($fieldName));
|
||||
}
|
||||
}
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
function getFieldsFor($childData) {
|
||||
// See if our parent class has any many_many relations by this source class
|
||||
if($this->sourceID()) {
|
||||
$parentClass = DataObject::get_by_id($this->getParentClass(), $this->sourceID());
|
||||
} else {
|
||||
$parentClass = singleton($this->getParentClass());
|
||||
}
|
||||
|
||||
$manyManyRelations = $parentClass->many_many();
|
||||
$manyManyRelationName = null;
|
||||
$manyManyComponentSet = null;
|
||||
|
||||
if($manyManyRelations) foreach($manyManyRelations as $relation => $class) {
|
||||
if($class == $this->sourceClass()) {
|
||||
$manyManyRelationName = $relation;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the relation value to related records
|
||||
if(!$childData->ID && $this->getParentClass()) {
|
||||
// make sure the relation-link is existing, even if we just add the sourceClass and didn't save it
|
||||
$parentIDName = $this->getParentIdName( $this->getParentClass(), $this->sourceClass() );
|
||||
$childData->$parentIDName = $this->sourceID();
|
||||
}
|
||||
|
||||
|
||||
$detailFields = $this->getCustomFieldsFor($childData);
|
||||
|
||||
// Loading of extra field values for editing an existing record
|
||||
if($manyManyRelationName && $childData->ID) {
|
||||
$manyManyComponentSet = $parentClass->getManyManyComponents($manyManyRelationName);
|
||||
$extraData = $manyManyComponentSet->getExtraData($manyManyRelationName, $childData->ID);
|
||||
|
||||
if($extraData) foreach($extraData as $fieldName => $fieldValue) {
|
||||
$field = $detailFields->dataFieldByName('ctf[extraFields][' . $fieldName . ']');
|
||||
$field->setValue($fieldValue);
|
||||
}
|
||||
}
|
||||
|
||||
// the ID field confuses the Controller-logic in finding the right view for ReferencedField
|
||||
$detailFields->removeByName('ID');
|
||||
|
||||
|
||||
// only add childID if we're not adding a record
|
||||
if($childData->ID) {
|
||||
$detailFields->push(new HiddenField("ctf[childID]","",$childData->ID));
|
||||
$detailFields->push(new HiddenField('ctf[childID]', '', $childData->ID));
|
||||
}
|
||||
|
||||
// add a namespaced ID instead thats "converted" by saveComplexTableField()
|
||||
$detailFields->push(new HiddenField("ctf[ClassName]","",$this->sourceClass()));
|
||||
$detailFields->push(new HiddenField('ctf[ClassName]', '', $this->sourceClass()));
|
||||
|
||||
if($this->getParentClass()) {
|
||||
$parentIdName = $this->getParentIdName($this->getParentClass(), $this->sourceClass());
|
||||
/*
|
||||
if(!$parentIdName) {
|
||||
user_error("ComplexTableField::DetailForm() Cannot automatically
|
||||
determine 'has-one'-relationship to parent class " . $this->ctf->getParentClass() . ",
|
||||
please use setParentClass() to set it manually",
|
||||
E_USER_WARNING);
|
||||
return;
|
||||
if($manyManyRelationName && $this->relationAutoSetting) {
|
||||
$detailFields->push(new HiddenField('ctf[manyManyRelation]', '', $manyManyRelationName));
|
||||
$detailFields->push(new HiddenField('ctf[parentClass]', '', $this->getParentClass()));
|
||||
$detailFields->push(new HiddenField('ctf[sourceID]', '', $this->sourceID()));
|
||||
}
|
||||
*/
|
||||
|
||||
$parentIdName = $this->getParentIdName($this->getParentClass(), $this->sourceClass());
|
||||
if($parentIdName) {
|
||||
// add relational fields
|
||||
$detailFields->push(new HiddenField("ctf[parentClass]"," ",$this->getParentClass()));
|
||||
|
||||
if( $this->relationAutoSetting ) {
|
||||
$detailFields->push(new HiddenField('ctf[parentClass]', '', $this->getParentClass()));
|
||||
|
||||
if($this->relationAutoSetting) {
|
||||
// Hack for model admin: model admin will have included a dropdown for the relation itself
|
||||
$detailFields->removeByName($parentIdName);
|
||||
$detailFields->push(new HiddenField("$parentIdName"," ",$this->sourceID()));
|
||||
$detailFields->push(new HiddenField($parentIdName, '', $this->sourceID()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -574,6 +622,8 @@ JS;
|
||||
* even if there is no action relevant for the main controller (to provide the instance of ComplexTableField
|
||||
* which in turn saves the record.
|
||||
*
|
||||
* This is for adding new item records. {@link ComplexTableField_ItemRequest::saveComplexTableField()}
|
||||
*
|
||||
* @see Form::ReferencedField
|
||||
*/
|
||||
function saveComplexTableField($data, $form, $params) {
|
||||
@ -581,17 +631,38 @@ JS;
|
||||
$childData = new $className();
|
||||
$form->saveInto($childData);
|
||||
$childData->write();
|
||||
|
||||
// Save the many many relationship if it's available
|
||||
if(isset($data['ctf']['manyManyRelation'])) {
|
||||
|
||||
$parentRecord = DataObject::get_by_id($data['ctf']['parentClass'], (int) $data['ctf']['sourceID']);
|
||||
$relationName = $data['ctf']['manyManyRelation'];
|
||||
$extraFields = array();
|
||||
|
||||
if(isset($data['ctf']['extraFields'])) {
|
||||
foreach($data['ctf']['extraFields'] as $field => $value) {
|
||||
$extraFields[$field] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$componentSet = $parentRecord->getManyManyComponents($relationName);
|
||||
$componentSet->add($childData, $extraFields);
|
||||
}
|
||||
|
||||
$referrer = isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null;
|
||||
|
||||
$closeLink = sprintf(
|
||||
'<small><a href="' . $_SERVER['HTTP_REFERER'] . '" onclick="javascript:window.top.GB_hide(); return false;">(%s)</a></small>',
|
||||
'<small><a href="' . $referrer . '" onclick="javascript:window.top.GB_hide(); return false;">(%s)</a></small>',
|
||||
_t('ComplexTableField.CLOSEPOPUP', 'Close Popup')
|
||||
);
|
||||
|
||||
$message = sprintf(
|
||||
_t('ComplexTableField.SUCCESSADD', 'Added %s %s %s'),
|
||||
$childData->singular_name(),
|
||||
'<a href="' . $this->Link() . '/item/' . $childData->ID . '/edit">' . $childData->Title . '</a>',
|
||||
$closeLink
|
||||
);
|
||||
|
||||
$form->sessionMessage($message, 'good');
|
||||
|
||||
Director::redirectBack();
|
||||
@ -724,14 +795,31 @@ class ComplexTableField_ItemRequest extends RequestHandler {
|
||||
* even if there is no action relevant for the main controller (to provide the instance of ComplexTableField
|
||||
* which in turn saves the record.
|
||||
*
|
||||
* This is for editing existing item records. {@link ComplexTableField::saveComplexTableField()}
|
||||
*
|
||||
* @see Form::ReferencedField
|
||||
*/
|
||||
function saveComplexTableField($data, $form, $request) {
|
||||
$dataObject = $this->dataObj();
|
||||
|
||||
$form->saveInto($dataObject);
|
||||
$dataObject->write();
|
||||
|
||||
// Save the many many relationship if it's available
|
||||
if(isset($data['ctf']['manyManyRelation'])) {
|
||||
$parentRecord = DataObject::get_by_id($data['ctf']['parentClass'], (int) $data['ctf']['sourceID']);
|
||||
$relationName = $data['ctf']['manyManyRelation'];
|
||||
$extraFields = array();
|
||||
|
||||
if(isset($data['ctf']['extraFields'])) {
|
||||
foreach($data['ctf']['extraFields'] as $field => $value) {
|
||||
$extraFields[$field] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$componentSet = $parentRecord->getManyManyComponents($relationName);
|
||||
$componentSet->add($dataObject, $extraFields);
|
||||
}
|
||||
|
||||
$closeLink = sprintf(
|
||||
'<small><a href="' . $_SERVER['HTTP_REFERER'] . '" onclick="javascript:window.top.GB_hide(); return false;">(%s)</a></small>',
|
||||
_t('ComplexTableField.CLOSEPOPUP', 'Close Popup')
|
||||
@ -742,6 +830,7 @@ class ComplexTableField_ItemRequest extends RequestHandler {
|
||||
'<a href="' . $this->Link() . '">"' . $dataObject->Title . '"</a>',
|
||||
$closeLink
|
||||
);
|
||||
|
||||
$form->sessionMessage($message, 'good');
|
||||
|
||||
Director::redirectBack();
|
||||
|
@ -187,6 +187,7 @@ class Form extends RequestHandler {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Protection against CSRF attacks
|
||||
if($this->securityTokenEnabled()) {
|
||||
$securityID = Session::get('SecurityID');
|
||||
|
@ -553,6 +553,23 @@ class DataObjectTest extends SapphireTest {
|
||||
$this->assertType('RedirectorPage', $changedPage);
|
||||
$this->assertEquals($changedPage->ClassName, 'RedirectorPage');
|
||||
}
|
||||
|
||||
function testManyManyExtraFields() {
|
||||
$player = $this->fixture->objFromFixture('DataObjectTest_Player', 'player1');
|
||||
$team = $this->fixture->objFromFixture('DataObjectTest_Team', 'team1');
|
||||
|
||||
// Extra fields are immediately available on the Team class (defined in $many_many_extraFields)
|
||||
$teamExtraFields = $team->many_many_extraFields('Players');
|
||||
$this->assertEquals($teamExtraFields, array(
|
||||
'Position' => 'Varchar(100)'
|
||||
));
|
||||
|
||||
// We'll have to go through the relation to get the extra fields on Player
|
||||
$playerExtraFields = $player->many_many_extraFields('Teams');
|
||||
$this->assertEquals($playerExtraFields, array(
|
||||
'Position' => 'Varchar(100)'
|
||||
));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -583,6 +600,12 @@ class DataObjectTest_Team extends DataObject implements TestOnly {
|
||||
'Players' => 'DataObjectTest_Player'
|
||||
);
|
||||
|
||||
static $many_many_extraFields = array(
|
||||
'Players' => array(
|
||||
'Position' => 'Varchar(100)'
|
||||
)
|
||||
);
|
||||
|
||||
function getDynamicField() {
|
||||
return 'dynamicfield';
|
||||
}
|
||||
|
155
tests/forms/ComplexTableFieldTest.php
Normal file
155
tests/forms/ComplexTableFieldTest.php
Normal file
@ -0,0 +1,155 @@
|
||||
<?php
|
||||
/**
|
||||
* @package sapphire
|
||||
* @subpackage tests
|
||||
*/
|
||||
class ComplexTableFieldTest extends FunctionalTest {
|
||||
|
||||
static $fixture_file = 'sapphire/tests/forms/ComplexTableFieldTest.yml';
|
||||
|
||||
/**
|
||||
* An instance of {@link Controller} used for
|
||||
* running tests against.
|
||||
*
|
||||
* @var Controller object
|
||||
*/
|
||||
protected $controller;
|
||||
|
||||
/**
|
||||
* An instance of {@link Form} that is taken
|
||||
* from the test controller, used for testing.
|
||||
*
|
||||
* @var Form object
|
||||
*/
|
||||
protected $form;
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->controller = new ComplexTableFieldTest_Controller();
|
||||
$this->form = $this->controller->Form();
|
||||
}
|
||||
|
||||
function testCorrectNumberOfRowsInTable() {
|
||||
$field = $this->form->dataFieldByName('Players');
|
||||
$parser = new CSSContentParser($field->FieldHolder());
|
||||
|
||||
/* There are 2 players (rows) in the table */
|
||||
$this->assertEquals(count($parser->getBySelector('tbody tr')), 2, 'There are 2 players (rows) in the table');
|
||||
|
||||
/* There are 2 CTF items in the DataObjectSet */
|
||||
$this->assertEquals($field->Items()->Count(), 2, 'There are 2 CTF items in the DataObjectSet');
|
||||
}
|
||||
|
||||
function testDetailFormDisplaysWithCorrectFields() {
|
||||
$field = $this->form->dataFieldByName('Players');
|
||||
$detailForm = $field->add();
|
||||
$parser = new CSSContentParser($detailForm);
|
||||
|
||||
/* There is a field called "Name", which is a text input */
|
||||
$this->assertNotNull($parser->getBySelector('#Name input'), 'There is a field called "Name", which is a text input');
|
||||
|
||||
/* There is a field called "Role" - this field is the extra field for $many_many_extraFields */
|
||||
$this->assertNotNull($parser->getBySelector('#Role input'), 'There is a field called "Role" - this field is the extra field for $many_many_extraFields');
|
||||
}
|
||||
|
||||
function testAddingNewPlayerWithExtraData() {
|
||||
$team = DataObject::get_one('ComplexTableFieldTest_Team', "Name = 'The Awesome People'");
|
||||
|
||||
$this->post('ComplexTableFieldTest_Controller/Form/field/Players/AddForm', array(
|
||||
'Name' => 'Bobby Joe',
|
||||
'ctf' => array(
|
||||
'extraFields' => array(
|
||||
'Role' => 'Goalie'
|
||||
),
|
||||
'ClassName' => 'ComplexTableFieldTest_Player',
|
||||
'manyManyRelation' => 'Players',
|
||||
'parentClass' => 'ComplexTableFieldTest_Team',
|
||||
'sourceID' => $team->ID
|
||||
)
|
||||
));
|
||||
|
||||
/* Retrieve the new player record we created */
|
||||
$newPlayer = DataObject::get_one('ComplexTableFieldTest_Player', "Name = 'Bobby Joe'");
|
||||
|
||||
/* A new ComplexTableFieldTest_Player record was created, Name = "Bobby Joe" */
|
||||
$this->assertNotNull($newPlayer, 'A new ComplexTableFieldTest_Player record was created, Name = "Bobby Joe"');
|
||||
|
||||
/* Get the many-many related Teams to the new player that were automatically linked by CTF */
|
||||
$teams = $newPlayer->getManyManyComponents('Teams');
|
||||
|
||||
/* Automatic many-many relation was set correctly on the new player */
|
||||
$this->assertEquals($teams->Count(), 1, 'Automatic many-many relation was set correctly on the new player');
|
||||
|
||||
/* The extra fields have the correct value */
|
||||
$extraFields = $teams->getExtraData('Teams', $team->ID);
|
||||
$this->assertEquals($extraFields['Role'], 'Goalie', 'The extra fields have the correct value');
|
||||
}
|
||||
|
||||
}
|
||||
class ComplexTableFieldTest_Controller extends Controller {
|
||||
|
||||
function Link($action = null) {
|
||||
return "ComplexTableFieldTest_Controller/$action";
|
||||
}
|
||||
|
||||
function Form() {
|
||||
$team = DataObject::get_one('ComplexTableFieldTest_Team', "Name = 'The Awesome People'");
|
||||
|
||||
$playersField = new ComplexTableField(
|
||||
$this,
|
||||
'Players',
|
||||
'ComplexTableFieldTest_Player',
|
||||
ComplexTableFieldTest_Player::$summary_fields,
|
||||
'getCMSFields'
|
||||
);
|
||||
|
||||
$playersField->setParentClass('ComplexTableFieldTest_Team');
|
||||
|
||||
$form = new Form(
|
||||
$this,
|
||||
'Form',
|
||||
new FieldSet(
|
||||
new HiddenField('ID', '', $team->ID),
|
||||
$playersField
|
||||
),
|
||||
new FieldSet(
|
||||
new FormAction('doSubmit', 'Submit')
|
||||
)
|
||||
);
|
||||
|
||||
$form->disableSecurityToken();
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
}
|
||||
class ComplexTableFieldTest_Player extends DataObject implements TestOnly {
|
||||
|
||||
public static $db = array(
|
||||
'Name' => 'Varchar(100)'
|
||||
);
|
||||
|
||||
public static $many_many = array(
|
||||
'Teams' => 'ComplexTableFieldTest_Team'
|
||||
);
|
||||
|
||||
public static $many_many_extraFields = array(
|
||||
'Teams' => array(
|
||||
'Role' => 'Varchar(100)'
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
class ComplexTableFieldTest_Team extends DataObject implements TestOnly {
|
||||
|
||||
public static $db = array(
|
||||
'Name' => 'Varchar(100)'
|
||||
);
|
||||
|
||||
public static $belongs_many_many = array(
|
||||
'Players' => 'ComplexTableFieldTest_Player'
|
||||
);
|
||||
|
||||
}
|
||||
?>
|
10
tests/forms/ComplexTableFieldTest.yml
Normal file
10
tests/forms/ComplexTableFieldTest.yml
Normal file
@ -0,0 +1,10 @@
|
||||
ComplexTableFieldTest_Player:
|
||||
p1:
|
||||
Name: Joe Bloggs
|
||||
p2:
|
||||
Name: Some Guy
|
||||
ComplexTableFieldTest_Team:
|
||||
t1:
|
||||
Name: The Awesome People
|
||||
t2:
|
||||
Name: Incredible Four
|
Loading…
x
Reference in New Issue
Block a user