Merge branch '3.4' into 3

This commit is contained in:
Daniel Hensby 2016-08-22 16:23:22 +01:00
commit 058f57979b
No known key found for this signature in database
GPG Key ID: B00D1E9767F0B06E
8 changed files with 154 additions and 45 deletions

View File

@ -19,7 +19,7 @@ name, and normally they all exist under the `Root` [api:TabSet].
display up to two levels of tabs in the interface. If you want to group data further than that, try [api:ToggleField].
</div>
## Adding a field from a tab.
## Adding a field to a tab
:::php
$fields->addFieldToTab('Root.Main', new TextField(..));

View File

@ -59,7 +59,7 @@ class GridFieldAddExistingAutocompleter
* 'Team.Name'
* )
*
* @var Array
* @var array
*/
protected $searchFields = array();
@ -69,7 +69,7 @@ class GridFieldAddExistingAutocompleter
protected $resultsFormat = '$Title';
/**
* @var String Text shown on the search field, instructing what to search for.
* @var string Text shown on the search field, instructing what to search for.
*/
protected $placeholderText;
@ -90,7 +90,7 @@ class GridFieldAddExistingAutocompleter
/**
*
* @param GridField $gridField
* @return string - HTML
* @return string[] - HTML
*/
public function getHTMLFragments($gridField) {
$dataClass = $gridField->getList()->dataClass();
@ -220,17 +220,20 @@ class GridFieldAddExistingAutocompleter
->limit($this->getResultsLimit());
$json = array();
$originalSourceFileComments = Config::inst()->get('SSViewer', 'source_file_comments');
Config::nest();
Config::inst()->update('SSViewer', 'source_file_comments', false);
$viewer = SSViewer::fromString($this->resultsFormat);
foreach($results as $result) {
$json[$result->ID] = html_entity_decode(SSViewer::fromString($this->resultsFormat)->process($result));
$json[$result->ID] = html_entity_decode($viewer->process($result));
}
Config::inst()->update('SSViewer', 'source_file_comments', $originalSourceFileComments);
Config::unnest();
return Convert::array2json($json);
}
/**
* @param String
* @param string $format
*
* @return $this
*/
public function setResultsFormat($format) {
$this->resultsFormat = $format;
@ -238,7 +241,7 @@ class GridFieldAddExistingAutocompleter
}
/**
* @return String
* @return string
*/
public function getResultsFormat() {
return $this->resultsFormat;
@ -252,10 +255,11 @@ class GridFieldAddExistingAutocompleter
*/
public function setSearchList(SS_List $list) {
$this->searchList = $list;
return $this;
}
/**
* @param Array
* @param array $fields
*/
public function setSearchFields($fields) {
$this->searchFields = $fields;
@ -263,7 +267,7 @@ class GridFieldAddExistingAutocompleter
}
/**
* @return Array
* @return array
*/
public function getSearchFields() {
return $this->searchFields;
@ -274,8 +278,8 @@ class GridFieldAddExistingAutocompleter
* Falls back to {@link DataObject->summaryFields()} if
* no custom search fields are defined.
*
* @param String the class name
* @return Array|null names of the searchable fields
* @param string $dataClass the class name
* @return array|null names of the searchable fields
*/
public function scaffoldSearchFields($dataClass) {
$obj = singleton($dataClass);
@ -311,8 +315,9 @@ class GridFieldAddExistingAutocompleter
}
/**
* @param String The class of the object being searched for
* @return String
* @param string $dataClass The class of the object being searched for
*
* @return string
*/
public function getPlaceholderText($dataClass) {
$searchFields = ($this->getSearchFields())
@ -344,10 +349,13 @@ class GridFieldAddExistingAutocompleter
}
/**
* @param String
* @param string $text
*
* @return $this
*/
public function setPlaceholderText($text) {
$this->placeholderText = $text;
return $this;
}
/**
@ -361,8 +369,11 @@ class GridFieldAddExistingAutocompleter
/**
* @param int $limit
*
* @return $this
*/
public function setResultsLimit($limit) {
$this->resultsLimit = $limit;
return $this;
}
}

View File

@ -431,6 +431,7 @@ class ArrayList extends ViewableData implements SS_List, SS_Filterable, SS_Sorta
// This the main sorting algorithm that supports infinite sorting params
$multisortArgs = array();
$values = array();
$firstRun = true;
foreach($columnsToSort as $column => $direction) {
// The reason these are added to columns is of the references, otherwise when the foreach
// is done, all $values and $direction look the same
@ -438,7 +439,7 @@ class ArrayList extends ViewableData implements SS_List, SS_Filterable, SS_Sorta
$sortDirection[$column] = $direction;
// We need to subtract every value into a temporary array for sorting
foreach($this->items as $index => $item) {
$values[$column][] = $this->extractValue($item, $column);
$values[$column][] = strtolower($this->extractValue($item, $column));
}
// PHP 5.3 requires below arguments to be reference when using array_multisort together
// with call_user_func_array
@ -446,6 +447,10 @@ class ArrayList extends ViewableData implements SS_List, SS_Filterable, SS_Sorta
$multisortArgs[] = &$values[$column];
// First argument is the direction to be sorted,
$multisortArgs[] = &$sortDirection[$column];
if ($firstRun) {
$multisortArgs[] = defined('SORT_NATURAL') ? SORT_NATURAL : SORT_STRING;
}
$firstRun = false;
}
$multisortArgs[] = &$originalKeys;

View File

@ -8,6 +8,9 @@
*/
class HasManyList extends RelationList {
/**
* @var string
*/
protected $foreignKey;
/**
@ -34,6 +37,10 @@ class HasManyList extends RelationList {
return $this->foreignKey;
}
/**
* @param null|int $id
* @return array
*/
protected function foreignIDFilter($id = null) {
if ($id === null) $id = $this->getForeignID();
@ -51,7 +58,7 @@ class HasManyList extends RelationList {
*
* It does so by setting the relationFilters.
*
* @param $item The DataObject to be added, or its ID
* @param DataObject|int $item The DataObject to be added, or its ID
*/
public function add($item) {
if(is_numeric($item)) {
@ -83,7 +90,7 @@ class HasManyList extends RelationList {
*
* Doesn't actually remove the item, it just clears the foreign key value.
*
* @param $itemID The ID of the item to be removed.
* @param int $itemID The ID of the item to be removed.
*/
public function removeByID($itemID) {
$item = $this->byID($itemID);
@ -95,7 +102,7 @@ class HasManyList extends RelationList {
* Remove an item from this relation.
* Doesn't actually remove the item, it just clears the foreign key value.
*
* @param $item The DataObject to be removed
* @param DataObject $item The DataObject to be removed
* @todo Maybe we should delete the object instead?
*/
public function remove($item) {

View File

@ -47,7 +47,7 @@ class ManyManyList extends RelationList {
* @param string $joinTable The name of the table whose entries define the content of this many_many relation.
* @param string $localKey The key in the join table that maps to the dataClass' PK.
* @param string $foreignKey The key in the join table that maps to joined class' PK.
* @param string $extraFields A map of field => fieldtype of extra fields on the join table.
* @param array $extraFields A map of field => fieldtype of extra fields on the join table.
*
* @example new ManyManyList('Group','Group_Members', 'GroupID', 'MemberID');
*/
@ -151,9 +151,9 @@ class ManyManyList extends RelationList {
* Return a filter expression for when getting the contents of the
* relationship for some foreign ID
*
* @param int $id
* @param int|null $id
*
* @return string
* @return array
*/
protected function foreignIDFilter($id = null) {
if ($id === null) {
@ -176,7 +176,7 @@ class ManyManyList extends RelationList {
* entries. However some subclasses of ManyManyList (Member_GroupSet) modify foreignIDFilter to
* include additional calculated entries, so we need different filters when reading and when writing
*
* @param array|integer $id (optional) An ID or an array of IDs - if not provided, will use the current ids
* @param array|int|null $id (optional) An ID or an array of IDs - if not provided, will use the current ids
* as per getForeignID
* @return array Condition In array(SQL => parameters format)
*/
@ -188,7 +188,10 @@ class ManyManyList extends RelationList {
* Add an item to this many_many relationship
* Does so by adding an entry to the joinTable.
*
* @param mixed $item
* @throws InvalidArgumentException
* @throws Exception
*
* @param DataObject|int $item
* @param array $extraFields A map of additional columns to insert into the joinTable.
* Column names should be ANSI quoted.
*/
@ -349,7 +352,7 @@ class ManyManyList extends RelationList {
*/
public function getExtraData($componentName, $itemID) {
$result = array();
// Skip if no extrafields or unsaved record
if(empty($this->extraFields) || empty($itemID)) {
return $result;

View File

@ -10,6 +10,9 @@
*/
abstract class RelationList extends DataList {
/**
* @return string|null
*/
public function getForeignID() {
return $this->dataQuery->getQueryParam('Foreign.ID');
}
@ -19,6 +22,8 @@ abstract class RelationList extends DataList {
* the given foreign ID.
*
* @param int|array $id An ID or an array of IDs.
*
* @return DataList
*/
public function forForeignID($id) {
// Turn a 1-element array into a simple value
@ -27,7 +32,8 @@ abstract class RelationList extends DataList {
// Calculate the new filter
$filter = $this->foreignIDFilter($id);
$list = $this->alterDataQuery(function($query, $list) use ($id, $filter){
$list = $this->alterDataQuery(function($query) use ($id, $filter){
/** @var DataQuery $query */
// Check if there is an existing filter, remove if there is
$currentFilter = $query->getQueryParam('Foreign.Filter');
if($currentFilter) {

View File

@ -1417,7 +1417,12 @@ class Member extends DataObject implements TemplateGlobalProvider {
));
$mainFields->removeByName($self->config()->hidden_fields);
// make sure that the "LastVisited" field exists
// it may have been removed using $self->config()->hidden_fields
if($mainFields->fieldByName("LastVisited")){
$mainFields->makeFieldReadonly('LastVisited');
}
if( ! $self->config()->lock_out_after_incorrect_logins) {
$mainFields->removeByName('FailedLoginCount');

View File

@ -247,63 +247,135 @@ class ArrayListTest extends SapphireTest {
$list = new ArrayList(array(
array('Name' => 'Steve'),
(object) array('Name' => 'Bob'),
array('Name' => 'John')
array('Name' => 'John'),
array('Name' => 'bonny'),
));
// Unquoted name
$list1 = $list->sort('Name');
$this->assertEquals($list1->toArray(), array(
$this->assertEquals(array(
(object) array('Name' => 'Bob'),
array('Name' => 'bonny'),
array('Name' => 'John'),
array('Name' => 'Steve')
));
array('Name' => 'Steve'),
), $list1->toArray());
// Quoted name name
$list2 = $list->sort('"Name"');
$this->assertEquals($list2->toArray(), array(
$this->assertEquals(array(
(object) array('Name' => 'Bob'),
array('Name' => 'bonny'),
array('Name' => 'John'),
array('Name' => 'Steve')
));
array('Name' => 'Steve'),
), $list2->toArray());
// Array (non-associative)
$list3 = $list->sort(array('"Name"'));
$this->assertEquals($list3->toArray(), array(
$this->assertEquals(array(
(object) array('Name' => 'Bob'),
array('Name' => 'bonny'),
array('Name' => 'John'),
array('Name' => 'Steve')
));
array('Name' => 'Steve'),
), $list3->toArray());
// Quoted name name with table
$list4 = $list->sort('"Record"."Name"');
$this->assertEquals($list4->toArray(), array(
$this->assertEquals(array(
(object) array('Name' => 'Bob'),
array('Name' => 'bonny'),
array('Name' => 'John'),
array('Name' => 'Steve')
));
), $list4->toArray());
// Quoted name name with table (desc)
$list5 = $list->sort('"Record"."Name" DESC');
$this->assertEquals($list5->toArray(), array(
$this->assertEquals(array(
array('Name' => 'Steve'),
array('Name' => 'John'),
array('Name' => 'bonny'),
(object) array('Name' => 'Bob')
));
), $list5->toArray());
// Table without quotes
$list6 = $list->sort('Record.Name');
$this->assertEquals($list6->toArray(), array(
$this->assertEquals(array(
(object) array('Name' => 'Bob'),
array('Name' => 'bonny'),
array('Name' => 'John'),
array('Name' => 'Steve')
));
), $list6->toArray());
// Check original list isn't altered
$this->assertEquals($list->toArray(), array(
$this->assertEquals(array(
array('Name' => 'Steve'),
(object) array('Name' => 'Bob'),
array('Name' => 'John')
array('Name' => 'John'),
array('Name' => 'bonny'),
), $list->toArray());
}
public function testNaturalSort() {
//natural sort is only available in 5.4+
if (version_compare(phpversion(), '5.4.0', '<')) {
$this->markTestSkipped();
}
$list = new ArrayList(array(
array('Name' => 'Steve'),
(object) array('Name' => 'Bob'),
array('Name' => 'John'),
array('Name' => 'bonny'),
array('Name' => 'bonny1'),
array('Name' => 'bonny10'),
array('Name' => 'bonny2'),
));
// Unquoted name
$list1 = $list->sort('Name');
$this->assertEquals(array(
(object) array('Name' => 'Bob'),
array('Name' => 'bonny'),
array('Name' => 'bonny1'),
array('Name' => 'bonny2'),
array('Name' => 'bonny10'),
array('Name' => 'John'),
array('Name' => 'Steve'),
), $list1->toArray());
// Quoted name name
$list2 = $list->sort('"Name"');
$this->assertEquals(array(
(object) array('Name' => 'Bob'),
array('Name' => 'bonny'),
array('Name' => 'bonny1'),
array('Name' => 'bonny2'),
array('Name' => 'bonny10'),
array('Name' => 'John'),
array('Name' => 'Steve'),
), $list2->toArray());
// Array (non-associative)
$list3 = $list->sort(array('"Name"'));
$this->assertEquals(array(
(object) array('Name' => 'Bob'),
array('Name' => 'bonny'),
array('Name' => 'bonny1'),
array('Name' => 'bonny2'),
array('Name' => 'bonny10'),
array('Name' => 'John'),
array('Name' => 'Steve'),
), $list3->toArray());
// Check original list isn't altered
$this->assertEquals(array(
array('Name' => 'Steve'),
(object) array('Name' => 'Bob'),
array('Name' => 'John'),
array('Name' => 'bonny'),
array('Name' => 'bonny1'),
array('Name' => 'bonny10'),
array('Name' => 'bonny2'),
), $list->toArray());
}
public function testSortSimpleASCOrder() {