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
|
||||
*/
|
||||
protected function addScaffoldRelationFields($fieldSet) {
|
||||
if ($this->has_many() || $this->_many_many()) {
|
||||
if ($this->has_many() || $this->many_many()) {
|
||||
$oldFields = $fieldSet;
|
||||
$fieldSet = new FieldSet(
|
||||
new TabSet("Root", new Tab("Main"))
|
||||
@ -1070,22 +1070,42 @@ class DataObject extends ViewableData implements DataObjectInterface {
|
||||
$fieldSet->addFieldToTab("Root.Main", $field);
|
||||
}
|
||||
}
|
||||
|
||||
if($this->has_many()) {
|
||||
// Add each relation as a separate tab
|
||||
foreach($this->has_many() as $relationship => $component) {
|
||||
$relationshipFields = singleton($component)->summary_fields();
|
||||
$relationshipFields = singleton($component)->summaryFields();
|
||||
$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()) {
|
||||
foreach($this->many_many() as $relationship => $component) {
|
||||
$relationshipFields = singleton($component)->summary_fields();
|
||||
$relationshipFields = singleton($component)->summaryFields();
|
||||
$filterWhere = $this->getManyManyFilter($relationship, $component);
|
||||
$filterJoin = $this->getManyManyJoin($relationship, $component);
|
||||
$tableField = new ComplexTableField($this, $relationship, $component, $relationshipFields, "getCMSFields", $filterWhere, '', $filterJoin);
|
||||
$tableField->popupClass = "ScaffoldingComplexTableField_Popup";
|
||||
$fieldSet->addFieldToTab("Root.$relationship", $tableField);
|
||||
$ctf = new ComplexTableField(
|
||||
$this,
|
||||
$relationship,
|
||||
$component,
|
||||
$relationshipFields,
|
||||
"getCMSFields",
|
||||
$filterWhere,
|
||||
'',
|
||||
$filterJoin
|
||||
);
|
||||
$ctf->setPermissions(TableListField::permissions_for_object($component));
|
||||
$ctf->popupClass = "ScaffoldingComplexTableField_Popup";
|
||||
$fieldSet->addFieldToTab("Root.$relationship", $ctf);
|
||||
}
|
||||
}
|
||||
return $fieldSet;
|
||||
@ -1319,21 +1339,28 @@ class DataObject extends ViewableData implements DataObjectInterface {
|
||||
* based on default {@link FormField} mapping in {@link DBField::scaffoldFormField()}
|
||||
*
|
||||
* @uses {@link DBField::scaffoldFormField()}
|
||||
* @param array $fieldClasses Optional mapping of fieldnames to subclasses of {@link DBField}
|
||||
* @return FieldSet
|
||||
*/
|
||||
public function scaffoldFormFields() {
|
||||
public function scaffoldFormFields($fieldClasses = null) {
|
||||
$fields = new FieldSet();
|
||||
$fields->push(new HeaderField($this->singular_name()));
|
||||
foreach($this->db() as $fieldName => $fieldType) {
|
||||
// @todo Pass localized title
|
||||
// commented out, to be less of a pain in the ass
|
||||
//$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) {
|
||||
$model = singleton($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();
|
||||
$fields->push(new DropdownField($relationship.'ID', $relationship, $options));
|
||||
}
|
||||
@ -2227,7 +2254,7 @@ class DataObject extends ViewableData implements DataObjectInterface {
|
||||
public function searchable_fields() {
|
||||
$fields = $this->stat('searchable_fields');
|
||||
if (!$fields) {
|
||||
$fields = array_fill_keys(array_keys($this->summary_fields()), 'TextField');
|
||||
$fields = array_fill_keys(array_keys($this->summaryFields()), 'TextField');
|
||||
}
|
||||
return $fields;
|
||||
}
|
||||
@ -2239,10 +2266,18 @@ class DataObject extends ViewableData implements DataObjectInterface {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function summary_fields() {
|
||||
public function summaryFields() {
|
||||
$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) {
|
||||
$fields = array();
|
||||
// try to scaffold a couple of usual suspects
|
||||
if ($this->hasField('Name')) $fields['Name'] = 'Name';
|
||||
if ($this->hasField('Title')) $fields['Title'] = 'Title';
|
||||
if ($this->hasField('Description')) $fields['Description'] = 'Description';
|
||||
|
@ -66,7 +66,7 @@ class HTMLText extends Text {
|
||||
}
|
||||
|
||||
public function scaffoldFormField($title = null) {
|
||||
return new HTMLEditorField($this->name, $title);
|
||||
return new HtmlEditorField($this->name, $title);
|
||||
}
|
||||
|
||||
public function scaffoldSearchField($title = null) {
|
||||
|
@ -12,6 +12,7 @@ class Varchar extends DBField {
|
||||
$this->size = $size ? $size : 50;
|
||||
parent::__construct($name);
|
||||
}
|
||||
|
||||
function requireField() {
|
||||
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.
|
||||
*/
|
||||
abstract function writeHeader();
|
||||
function writeHeader();
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
|
||||
function writeHeader() {
|
||||
public function writeHeader() {
|
||||
echo '<!DOCTYPE html><html><head><title>'. $_SERVER['REQUEST_METHOD'] . ' ' .$_SERVER['REQUEST_URI'] .'</title>';
|
||||
echo '<style type="text/css">';
|
||||
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>';
|
||||
}
|
||||
|
||||
function writeFooter() {
|
||||
public function writeFooter() {
|
||||
echo "</body></html>";
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,7 @@ class TestRunner extends Controller {
|
||||
|
||||
function 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;
|
||||
|
||||
public static $allowed_actions = array(
|
||||
'filter', 'record', 'httpSubmission', 'handleAction'
|
||||
'filter', 'record', 'httpSubmission', 'handleAction', 'handleField'
|
||||
);
|
||||
|
||||
function __construct($controller, $name, $fields, $validator, $readonly, $dataObject) {
|
||||
|
@ -291,6 +291,8 @@ JS
|
||||
$SQL_limit = ($this->pageSize) ? "{$this->pageSize}" : "0";
|
||||
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";
|
||||
} else {
|
||||
$SQL_start = 0;
|
||||
}
|
||||
if(isset($this->customSourceItems)) {
|
||||
if($this->customSourceItems) {
|
||||
@ -929,6 +931,29 @@ JS
|
||||
}
|
||||
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() {
|
||||
return $this->parent->Can('delete');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
|
@ -17,6 +17,9 @@ ComplexTableField.prototype = {
|
||||
rules['#'+this.id+' table.data tbody td'] = {onclick: this.openPopup.bind(this)};
|
||||
|
||||
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)
|
||||
*/
|
||||
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 popupLink = "";
|
||||
if(_popupLink) {
|
||||
|
@ -19,15 +19,15 @@ class SearchContextTest extends SapphireTest {
|
||||
|
||||
function testSummaryIncludesDefaultFieldsIfNotDefined() {
|
||||
$person = singleton('SearchContextTest_Person');
|
||||
$this->assertContains('Name', $person->summary_fields());
|
||||
$this->assertContains('Name', $person->summaryFields());
|
||||
|
||||
$book = singleton('SearchContextTest_Book');
|
||||
$this->assertContains('Title', $book->summary_fields());
|
||||
$this->assertContains('Title', $book->summaryFields());
|
||||
}
|
||||
|
||||
function testAccessDefinedSummaryFields() {
|
||||
$company = singleton('SearchContextTest_Company');
|
||||
$this->assertContains('Industry', $company->summary_fields());
|
||||
$this->assertContains('Industry', $company->summaryFields());
|
||||
}
|
||||
|
||||
function testPartialMatchUsedByDefaultWhenNotExplicitlySet() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user