mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merge branch '3.4' into 3
This commit is contained in:
commit
058f57979b
@ -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(..));
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
|
@ -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');
|
||||
|
@ -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() {
|
||||
|
Loading…
Reference in New Issue
Block a user