mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 12:05:37 +00:00
(merged from branches/roa. use "svn log -c <changeset> -g <module-svn-path>" for detailed commit message)
git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@60231 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
parent
0362276b67
commit
4ec93162a0
@ -1061,7 +1061,7 @@ class DataObject extends ViewableData implements DataObjectInterface {
|
|||||||
* Add the scaffold-generated relation fields to the given field set
|
* Add the scaffold-generated relation fields to the given field set
|
||||||
*/
|
*/
|
||||||
protected function addScaffoldRelationFields($fieldSet) {
|
protected function addScaffoldRelationFields($fieldSet) {
|
||||||
if ($this->has_many() || $this->_many_many()) {
|
if ($this->has_many() || $this->many_many()) {
|
||||||
$oldFields = $fieldSet;
|
$oldFields = $fieldSet;
|
||||||
$fieldSet = new FieldSet(
|
$fieldSet = new FieldSet(
|
||||||
new TabSet("Root", new Tab("Main"))
|
new TabSet("Root", new Tab("Main"))
|
||||||
@ -1070,22 +1070,42 @@ class DataObject extends ViewableData implements DataObjectInterface {
|
|||||||
$fieldSet->addFieldToTab("Root.Main", $field);
|
$fieldSet->addFieldToTab("Root.Main", $field);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if($this->has_many()) {
|
if($this->has_many()) {
|
||||||
// Add each relation as a separate tab
|
// Add each relation as a separate tab
|
||||||
foreach($this->has_many() as $relationship => $component) {
|
foreach($this->has_many() as $relationship => $component) {
|
||||||
$relationshipFields = singleton($component)->summary_fields();
|
$relationshipFields = singleton($component)->summaryFields();
|
||||||
$foreignKey = $this->getComponentJoinField($relationship);
|
$foreignKey = $this->getComponentJoinField($relationship);
|
||||||
$fieldSet->addFieldToTab("Root.$relationship", new ComplexTableField($this, $relationship, $component, $relationshipFields, "getCMSFields", "$foreignKey = $this->ID"));
|
$ctf = new ComplexTableField(
|
||||||
|
$this,
|
||||||
|
$relationship,
|
||||||
|
$component,
|
||||||
|
$relationshipFields,
|
||||||
|
"getCMSFields",
|
||||||
|
"$foreignKey = $this->ID"
|
||||||
|
);
|
||||||
|
$ctf->setPermissions(TableListField::permissions_for_object($component));
|
||||||
|
$fieldSet->addFieldToTab("Root.$relationship", $ctf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ($this->many_many()) {
|
if ($this->many_many()) {
|
||||||
foreach($this->many_many() as $relationship => $component) {
|
foreach($this->many_many() as $relationship => $component) {
|
||||||
$relationshipFields = singleton($component)->summary_fields();
|
$relationshipFields = singleton($component)->summaryFields();
|
||||||
$filterWhere = $this->getManyManyFilter($relationship, $component);
|
$filterWhere = $this->getManyManyFilter($relationship, $component);
|
||||||
$filterJoin = $this->getManyManyJoin($relationship, $component);
|
$filterJoin = $this->getManyManyJoin($relationship, $component);
|
||||||
$tableField = new ComplexTableField($this, $relationship, $component, $relationshipFields, "getCMSFields", $filterWhere, '', $filterJoin);
|
$ctf = new ComplexTableField(
|
||||||
$tableField->popupClass = "ScaffoldingComplexTableField_Popup";
|
$this,
|
||||||
$fieldSet->addFieldToTab("Root.$relationship", $tableField);
|
$relationship,
|
||||||
|
$component,
|
||||||
|
$relationshipFields,
|
||||||
|
"getCMSFields",
|
||||||
|
$filterWhere,
|
||||||
|
'',
|
||||||
|
$filterJoin
|
||||||
|
);
|
||||||
|
$ctf->setPermissions(TableListField::permissions_for_object($component));
|
||||||
|
$ctf->popupClass = "ScaffoldingComplexTableField_Popup";
|
||||||
|
$fieldSet->addFieldToTab("Root.$relationship", $ctf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $fieldSet;
|
return $fieldSet;
|
||||||
@ -1319,21 +1339,28 @@ class DataObject extends ViewableData implements DataObjectInterface {
|
|||||||
* based on default {@link FormField} mapping in {@link DBField::scaffoldFormField()}
|
* based on default {@link FormField} mapping in {@link DBField::scaffoldFormField()}
|
||||||
*
|
*
|
||||||
* @uses {@link DBField::scaffoldFormField()}
|
* @uses {@link DBField::scaffoldFormField()}
|
||||||
|
* @param array $fieldClasses Optional mapping of fieldnames to subclasses of {@link DBField}
|
||||||
* @return FieldSet
|
* @return FieldSet
|
||||||
*/
|
*/
|
||||||
public function scaffoldFormFields() {
|
public function scaffoldFormFields($fieldClasses = null) {
|
||||||
$fields = new FieldSet();
|
$fields = new FieldSet();
|
||||||
$fields->push(new HeaderField($this->singular_name()));
|
$fields->push(new HeaderField($this->singular_name()));
|
||||||
foreach($this->db() as $fieldName => $fieldType) {
|
foreach($this->db() as $fieldName => $fieldType) {
|
||||||
// @todo Pass localized title
|
// @todo Pass localized title
|
||||||
// commented out, to be less of a pain in the ass
|
// commented out, to be less of a pain in the ass
|
||||||
//$fields->addFieldToTab('Root.Main', $this->dbObject($fieldName)->scaffoldFormField());
|
//$fields->addFieldToTab('Root.Main', $this->dbObject($fieldName)->scaffoldFormField());
|
||||||
$fields->push($this->dbObject($fieldName)->scaffoldFormField());
|
if(isset($fieldClasses[$fieldName])) {
|
||||||
|
$fieldClass = $fieldClasses[$fieldName];
|
||||||
|
$fieldObject = new $fieldClass($fieldName);
|
||||||
|
} else {
|
||||||
|
$fieldObject = $this->dbObject($fieldName)->scaffoldFormField();
|
||||||
|
}
|
||||||
|
$fields->push($fieldObject);
|
||||||
}
|
}
|
||||||
foreach($this->has_one() as $relationship => $component) {
|
foreach($this->has_one() as $relationship => $component) {
|
||||||
$model = singleton($component);
|
$model = singleton($component);
|
||||||
$records = DataObject::get($component);
|
$records = DataObject::get($component);
|
||||||
$collect = ($model->hasMethod('customSelectOption')) ? 'customSelectOption' : current($model->summary_fields());
|
$collect = ($model->hasMethod('customSelectOption')) ? 'customSelectOption' : current($model->summaryFields());
|
||||||
$options = $records ? $records->filter_map('ID', $collect) : array();
|
$options = $records ? $records->filter_map('ID', $collect) : array();
|
||||||
$fields->push(new DropdownField($relationship.'ID', $relationship, $options));
|
$fields->push(new DropdownField($relationship.'ID', $relationship, $options));
|
||||||
}
|
}
|
||||||
@ -2227,7 +2254,7 @@ class DataObject extends ViewableData implements DataObjectInterface {
|
|||||||
public function searchable_fields() {
|
public function searchable_fields() {
|
||||||
$fields = $this->stat('searchable_fields');
|
$fields = $this->stat('searchable_fields');
|
||||||
if (!$fields) {
|
if (!$fields) {
|
||||||
$fields = array_fill_keys(array_keys($this->summary_fields()), 'TextField');
|
$fields = array_fill_keys(array_keys($this->summaryFields()), 'TextField');
|
||||||
}
|
}
|
||||||
return $fields;
|
return $fields;
|
||||||
}
|
}
|
||||||
@ -2239,10 +2266,18 @@ class DataObject extends ViewableData implements DataObjectInterface {
|
|||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function summary_fields() {
|
public function summaryFields() {
|
||||||
$fields = $this->stat('summary_fields');
|
$fields = $this->stat('summary_fields');
|
||||||
|
|
||||||
|
// if fields were passed in numeric array,
|
||||||
|
// convert to an associative array
|
||||||
|
if($fields && array_key_exists(0, $fields)) {
|
||||||
|
$fields = array_combine(array_values($fields), array_values($fields));
|
||||||
|
}
|
||||||
|
|
||||||
if (!$fields) {
|
if (!$fields) {
|
||||||
$fields = array();
|
$fields = array();
|
||||||
|
// try to scaffold a couple of usual suspects
|
||||||
if ($this->hasField('Name')) $fields['Name'] = 'Name';
|
if ($this->hasField('Name')) $fields['Name'] = 'Name';
|
||||||
if ($this->hasField('Title')) $fields['Title'] = 'Title';
|
if ($this->hasField('Title')) $fields['Title'] = 'Title';
|
||||||
if ($this->hasField('Description')) $fields['Description'] = 'Description';
|
if ($this->hasField('Description')) $fields['Description'] = 'Description';
|
||||||
|
@ -66,7 +66,7 @@ class HTMLText extends Text {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function scaffoldFormField($title = null) {
|
public function scaffoldFormField($title = null) {
|
||||||
return new HTMLEditorField($this->name, $title);
|
return new HtmlEditorField($this->name, $title);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function scaffoldSearchField($title = null) {
|
public function scaffoldSearchField($title = null) {
|
||||||
|
@ -12,6 +12,7 @@ class Varchar extends DBField {
|
|||||||
$this->size = $size ? $size : 50;
|
$this->size = $size ? $size : 50;
|
||||||
parent::__construct($name);
|
parent::__construct($name);
|
||||||
}
|
}
|
||||||
|
|
||||||
function requireField() {
|
function requireField() {
|
||||||
DB::requireField($this->tableName, $this->name, "varchar($this->size) character set utf8 collate utf8_general_ci");
|
DB::requireField($this->tableName, $this->name, "varchar($this->size) character set utf8 collate utf8_general_ci");
|
||||||
}
|
}
|
||||||
|
@ -561,12 +561,12 @@ interface DebugReporter {
|
|||||||
/**
|
/**
|
||||||
* Render HTML markup for the header/top segment of debug report.
|
* Render HTML markup for the header/top segment of debug report.
|
||||||
*/
|
*/
|
||||||
abstract function writeHeader();
|
function writeHeader();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render HTML markup for the footer and closing tags of debug report.
|
* Render HTML markup for the footer and closing tags of debug report.
|
||||||
*/
|
*/
|
||||||
abstract function writeFooter();
|
function writeFooter();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -576,7 +576,7 @@ interface DebugReporter {
|
|||||||
*/
|
*/
|
||||||
class SapphireDebugReporter implements DebugReporter {
|
class SapphireDebugReporter implements DebugReporter {
|
||||||
|
|
||||||
function writeHeader() {
|
public function writeHeader() {
|
||||||
echo '<!DOCTYPE html><html><head><title>'. $_SERVER['REQUEST_METHOD'] . ' ' .$_SERVER['REQUEST_URI'] .'</title>';
|
echo '<!DOCTYPE html><html><head><title>'. $_SERVER['REQUEST_METHOD'] . ' ' .$_SERVER['REQUEST_URI'] .'</title>';
|
||||||
echo '<style type="text/css">';
|
echo '<style type="text/css">';
|
||||||
echo 'body { background-color:#eee; margin:0; padding:0; font-family:Helvetica,Arial,sans-serif; }';
|
echo 'body { background-color:#eee; margin:0; padding:0; font-family:Helvetica,Arial,sans-serif; }';
|
||||||
@ -595,7 +595,7 @@ class SapphireDebugReporter implements DebugReporter {
|
|||||||
echo '<div class="header"><img src="'. Director::absoluteBaseURL() .'cms/images/mainmenu/logo.gif" width="26" height="23"></div>';
|
echo '<div class="header"><img src="'. Director::absoluteBaseURL() .'cms/images/mainmenu/logo.gif" width="26" height="23"></div>';
|
||||||
}
|
}
|
||||||
|
|
||||||
function writeFooter() {
|
public function writeFooter() {
|
||||||
echo "</body></html>";
|
echo "</body></html>";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ class TestRunner extends Controller {
|
|||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
parent::init();
|
parent::init();
|
||||||
if (!self::$default_reporter) self::set_reporter('DebugView');
|
if (!self::$default_reporter) self::set_reporter('SapphireDebugReporter');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -896,7 +896,7 @@ class ScaffoldingComplexTableField_Popup extends Form {
|
|||||||
protected $dataObject;
|
protected $dataObject;
|
||||||
|
|
||||||
public static $allowed_actions = array(
|
public static $allowed_actions = array(
|
||||||
'filter', 'record', 'httpSubmission', 'handleAction'
|
'filter', 'record', 'httpSubmission', 'handleAction', 'handleField'
|
||||||
);
|
);
|
||||||
|
|
||||||
function __construct($controller, $name, $fields, $validator, $readonly, $dataObject) {
|
function __construct($controller, $name, $fields, $validator, $readonly, $dataObject) {
|
||||||
|
@ -291,6 +291,8 @@ JS
|
|||||||
$SQL_limit = ($this->pageSize) ? "{$this->pageSize}" : "0";
|
$SQL_limit = ($this->pageSize) ? "{$this->pageSize}" : "0";
|
||||||
if(isset($_REQUEST['ctf'][$this->Name()]['start']) && is_numeric($_REQUEST['ctf'][$this->Name()]['start'])) {
|
if(isset($_REQUEST['ctf'][$this->Name()]['start']) && is_numeric($_REQUEST['ctf'][$this->Name()]['start'])) {
|
||||||
$SQL_start = (isset($_REQUEST['ctf'][$this->Name()]['start'])) ? intval($_REQUEST['ctf'][$this->Name()]['start']) : "0";
|
$SQL_start = (isset($_REQUEST['ctf'][$this->Name()]['start'])) ? intval($_REQUEST['ctf'][$this->Name()]['start']) : "0";
|
||||||
|
} else {
|
||||||
|
$SQL_start = 0;
|
||||||
}
|
}
|
||||||
if(isset($this->customSourceItems)) {
|
if(isset($this->customSourceItems)) {
|
||||||
if($this->customSourceItems) {
|
if($this->customSourceItems) {
|
||||||
@ -929,6 +931,29 @@ JS
|
|||||||
}
|
}
|
||||||
return $idField->Value();
|
return $idField->Value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method to determine permissions for a scaffolded
|
||||||
|
* TableListField (or subclasses) - currently used in {@link ModelAdmin} and {@link DataObject->scaffoldFormFields()}.
|
||||||
|
* Returns true for each permission that doesn't have an explicit getter.
|
||||||
|
*
|
||||||
|
* @todo Temporary method, implement directly in FormField subclasses with object-level permissions.
|
||||||
|
*
|
||||||
|
* @param string $class
|
||||||
|
* @param numeric $id
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function permissions_for_object($class, $id = null) {
|
||||||
|
$permissions = array();
|
||||||
|
$obj = ($id) ? DataObject::get_by_id($class, $id) : singleton($class);
|
||||||
|
|
||||||
|
if(!$obj->hasMethod('canView') || $obj->canView()) $permissions[] = 'show';
|
||||||
|
if(!$obj->hasMethod('canEdit') || $obj->canEdit()) $permissions[] = 'edit';
|
||||||
|
if(!$obj->hasMethod('canDelete') || $obj->canDelete()) $permissions[] = 'delete';
|
||||||
|
if(!$obj->hasMethod('canCreate') || $obj->canCreate()) $permissions[] = 'add';
|
||||||
|
|
||||||
|
return $permissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1075,6 +1100,7 @@ class TableListField_Item extends ViewableData {
|
|||||||
function IsReadOnly() {
|
function IsReadOnly() {
|
||||||
return $this->parent->Can('delete');
|
return $this->parent->Can('delete');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
@ -17,6 +17,9 @@ ComplexTableField.prototype = {
|
|||||||
rules['#'+this.id+' table.data tbody td'] = {onclick: this.openPopup.bind(this)};
|
rules['#'+this.id+' table.data tbody td'] = {onclick: this.openPopup.bind(this)};
|
||||||
|
|
||||||
Behaviour.register(rules);
|
Behaviour.register(rules);
|
||||||
|
|
||||||
|
// HACK If already in a popup, we can't allow add (doesn't save existing relation correctly)
|
||||||
|
if(window != top) $$('#'+this.id+' table.data a.addlink').each(function(el) {Element.hide(el);});
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -66,6 +69,10 @@ ComplexTableField.prototype = {
|
|||||||
* @param href, table Optional dom object (use for external triggering without an event)
|
* @param href, table Optional dom object (use for external triggering without an event)
|
||||||
*/
|
*/
|
||||||
openPopup: function(e, _popupLink, _table) {
|
openPopup: function(e, _popupLink, _table) {
|
||||||
|
// If already in a popup, simply open the link instead
|
||||||
|
// of opening a nested lightwindow
|
||||||
|
if(window != top) return true;
|
||||||
|
|
||||||
var el,type;
|
var el,type;
|
||||||
var popupLink = "";
|
var popupLink = "";
|
||||||
if(_popupLink) {
|
if(_popupLink) {
|
||||||
|
@ -19,15 +19,15 @@ class SearchContextTest extends SapphireTest {
|
|||||||
|
|
||||||
function testSummaryIncludesDefaultFieldsIfNotDefined() {
|
function testSummaryIncludesDefaultFieldsIfNotDefined() {
|
||||||
$person = singleton('SearchContextTest_Person');
|
$person = singleton('SearchContextTest_Person');
|
||||||
$this->assertContains('Name', $person->summary_fields());
|
$this->assertContains('Name', $person->summaryFields());
|
||||||
|
|
||||||
$book = singleton('SearchContextTest_Book');
|
$book = singleton('SearchContextTest_Book');
|
||||||
$this->assertContains('Title', $book->summary_fields());
|
$this->assertContains('Title', $book->summaryFields());
|
||||||
}
|
}
|
||||||
|
|
||||||
function testAccessDefinedSummaryFields() {
|
function testAccessDefinedSummaryFields() {
|
||||||
$company = singleton('SearchContextTest_Company');
|
$company = singleton('SearchContextTest_Company');
|
||||||
$this->assertContains('Industry', $company->summary_fields());
|
$this->assertContains('Industry', $company->summaryFields());
|
||||||
}
|
}
|
||||||
|
|
||||||
function testPartialMatchUsedByDefaultWhenNotExplicitlySet() {
|
function testPartialMatchUsedByDefaultWhenNotExplicitlySet() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user