mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merge branch '3.3' into 3.4
This commit is contained in:
commit
4e392a4d43
@ -46,7 +46,7 @@
|
||||
ChangeTrackerOptions: {
|
||||
ignoreFieldSelector: '.no-change-track, .ss-upload :input, .cms-navigator :input'
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Variable: ValidationErrorShown
|
||||
* Boolean for tracking whether a validation error has been already been shown. Used because tabs can
|
||||
@ -94,16 +94,16 @@
|
||||
//
|
||||
// // Rewrite iframe links (for IE)
|
||||
// html = html.replace(/(<iframe[^>]*src=")([^"]+)("[^>]*>)/g, '$1' + $('base').attr('href') + '$2$3');
|
||||
|
||||
|
||||
this._super();
|
||||
},
|
||||
'from .cms-tabset': {
|
||||
onafterredrawtabs: function () {
|
||||
// Show validation errors if necessary
|
||||
if(this.hasClass('validationerror')) {
|
||||
// Ensure the first validation error is visible
|
||||
var tabError = this.find('.message.validation, .message.required').first().closest('.tab');
|
||||
$('.cms-container').clearCurrentTabState(); // clear state to avoid override later on
|
||||
// Show validation errors if necessary
|
||||
if(this.hasClass('validationerror')) {
|
||||
// Ensure the first validation error is visible
|
||||
var tabError = this.find('.message.validation, .message.required').first().closest('.tab');
|
||||
$('.cms-container').clearCurrentTabState(); // clear state to avoid override later on
|
||||
|
||||
// Attempt #1: Look for nearest .ss-tabset (usually nested deeper underneath a .cms-tabset).
|
||||
var $tabSet = tabError.closest('.ss-tabset');
|
||||
@ -111,7 +111,7 @@
|
||||
// Attempt #2: Next level in tab-ception, try to select the tab within this higher level .cms-tabset if possible
|
||||
if (!$tabSet.length) {
|
||||
$tabSet = tabError.closest('.cms-tabset');
|
||||
}
|
||||
}
|
||||
|
||||
if ($tabSet.length) {
|
||||
$tabSet.tabs('option', 'active', tabError.index('.tab'));
|
||||
@ -347,7 +347,7 @@
|
||||
|
||||
//Fall back to nearest visible element if hidden (for select type fields)
|
||||
if(!$(elementID).is(':visible')){
|
||||
elementID = '#' + $(elementID).closest('.field').attr('id');
|
||||
elementID = '#' + $(elementID).closest('.field:visible').attr('id');
|
||||
scrollY = $(elementID).position().top;
|
||||
}
|
||||
|
||||
|
@ -343,7 +343,11 @@ class BulkLoader_Result extends Object {
|
||||
* @return ArrayList
|
||||
*/
|
||||
public function Deleted() {
|
||||
return $this->mapToArrayList($this->deleted);
|
||||
$set = new ArrayList();
|
||||
foreach ($this->deleted as $arrItem) {
|
||||
$set->push(ArrayData::create($arrItem));
|
||||
}
|
||||
return $set;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -386,11 +390,9 @@ class BulkLoader_Result extends Object {
|
||||
* @param $message string
|
||||
*/
|
||||
public function addDeleted($obj, $message = null) {
|
||||
$this->deleted[] = $this->lastChange = array(
|
||||
'ID' => $obj->ID,
|
||||
'ClassName' => $obj->class,
|
||||
'Message' => $message
|
||||
);
|
||||
$data = $obj->toMap();
|
||||
$data['_BulkLoaderMessage'] = $message;
|
||||
$this->deleted[] = $this->lastChange = $data;
|
||||
$this->lastChange['ChangeType'] = 'deleted';
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,7 @@ and `MyDate`. The attribute `HiddenProperty` should not be searchable, and `MyDa
|
||||
'MyDate' => 'Date'
|
||||
);
|
||||
|
||||
public function getCustomSearchContext() {
|
||||
public function getDefaultSearchContext() {
|
||||
$fields = $this->scaffoldSearchFields(array(
|
||||
'restrictFields' => array('PublicProperty','MyDate')
|
||||
));
|
||||
|
@ -170,7 +170,9 @@ class DataQuery {
|
||||
* @return SQLQuery The finalised sql query
|
||||
*/
|
||||
public function getFinalisedQuery($queriedColumns = null) {
|
||||
if(!$queriedColumns) $queriedColumns = $this->queriedColumns;
|
||||
if(!$queriedColumns) {
|
||||
$queriedColumns = $this->queriedColumns;
|
||||
}
|
||||
if($queriedColumns) {
|
||||
$queriedColumns = array_merge($queriedColumns, array('Created', 'LastEdited', 'ClassName'));
|
||||
}
|
||||
@ -185,11 +187,19 @@ class DataQuery {
|
||||
// Specifying certain columns allows joining of child tables
|
||||
$tableClasses = ClassInfo::dataClassesFor($this->dataClass);
|
||||
|
||||
// Ensure that any filtered columns are included in the selected columns
|
||||
foreach ($query->getWhereParameterised($parameters) as $where) {
|
||||
// Check for just the column, in the form '"Column" = ?' and the form '"Table"."Column"' = ?
|
||||
if (preg_match('/^"([^"]+)"/', $where, $matches) ||
|
||||
preg_match('/^"([^"]+)"\."[^"]+"/', $where, $matches)) {
|
||||
if (!in_array($matches[1], $queriedColumns)) $queriedColumns[] = $matches[1];
|
||||
// Check for any columns in the form '"Column" = ?' or '"Table"."Column"' = ?
|
||||
if(preg_match_all(
|
||||
'/(?:"(?<table>[^"]+)"\.)?"(?<column>[^"]+)"(?:[^\.]|$)/',
|
||||
$where, $matches, PREG_SET_ORDER
|
||||
)) {
|
||||
foreach($matches as $match) {
|
||||
$column = $match['column'];
|
||||
if (!in_array($column, $queriedColumns)) {
|
||||
$queriedColumns[] = $column;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
94
tests/dev/BulkLoaderResultTest.php
Normal file
94
tests/dev/BulkLoaderResultTest.php
Normal file
@ -0,0 +1,94 @@
|
||||
<?php
|
||||
/**
|
||||
* @package framework
|
||||
* @subpackage tests
|
||||
*/
|
||||
class BulkLoaderResultTest extends SapphireTest
|
||||
{
|
||||
protected $extraDataObjects = array('BulkLoaderTestPlayer');
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
BulkLoaderTestPlayer::create(array('Name' => 'Vincent', 'Status' => 'Available'))->write();
|
||||
}
|
||||
|
||||
public function testBulkLoaderResultCreated()
|
||||
{
|
||||
$results = BulkLoader_Result::create();
|
||||
$player = BulkLoaderTestPlayer::create(array('Name' => 'Rangi', 'Status' => 'Possible'));
|
||||
$player->write();
|
||||
$results->addCreated($player, 'Speedster');
|
||||
|
||||
$this->assertEquals($results->CreatedCount(), 1);
|
||||
$this->assertSame(
|
||||
'Rangi',
|
||||
$results->Created()->find('Name', 'Rangi')->Name,
|
||||
'The player Rangi should be recorded as created in $results'
|
||||
);
|
||||
$this->assertSame(
|
||||
'Possible',
|
||||
$results->Created()->find('Name', 'Rangi')->Status,
|
||||
'The player Rangi should have Status of "Possible" in $results'
|
||||
);
|
||||
$this->assertSame(
|
||||
'Speedster',
|
||||
$results->Created()->find('Name', 'Rangi')->_BulkLoaderMessage,
|
||||
'Rangi should have _BulkLoaderMessage of Speedster'
|
||||
);
|
||||
}
|
||||
|
||||
public function testBulkLoaderResultDeleted()
|
||||
{
|
||||
$results = BulkLoader_Result::create();
|
||||
$player = BulkLoaderTestPlayer::get()->find('Name', 'Vincent');
|
||||
$results->addDeleted($player, 'Retired');
|
||||
$player->delete();
|
||||
|
||||
$this->assertEquals($results->DeletedCount(), 1);
|
||||
$this->assertSame(
|
||||
'Vincent',
|
||||
$results->Deleted()->find('Name', 'Vincent')->Name,
|
||||
'The player Vincent should be recorded as deleted'
|
||||
);
|
||||
$this->assertSame(
|
||||
'Retired',
|
||||
$results->Deleted()->find('Name', 'Vincent')->_BulkLoaderMessage,
|
||||
'Vincent should have a _BulkLoaderMessage of Retired'
|
||||
);
|
||||
}
|
||||
|
||||
public function testBulkLoaderResultUpdated()
|
||||
{
|
||||
$results = BulkLoader_Result::create();
|
||||
$player = BulkLoaderTestPlayer::get()->find('Name', 'Vincent');
|
||||
$player->Status = 'Unavailable';
|
||||
$player->write();
|
||||
$results->addUpdated($player, 'Injured');
|
||||
|
||||
$this->assertEquals($results->UpdatedCount(), 1);
|
||||
$this->assertSame(
|
||||
'Vincent',
|
||||
$results->Updated()->find('Name', 'Vincent')->Name,
|
||||
'The player Vincent should be recorded as updated'
|
||||
);
|
||||
$this->assertSame(
|
||||
'Unavailable',
|
||||
$results->Updated()->find('Name', 'Vincent')->Status,
|
||||
'The player Vincent should have a Status of Unavailable'
|
||||
);
|
||||
$this->assertSame(
|
||||
'Injured',
|
||||
$results->Updated()->find('Name', 'Vincent')->_BulkLoaderMessage,
|
||||
'Vincent is injured'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class BulkLoaderTestPlayer extends DataObject implements TestOnly
|
||||
{
|
||||
private static $db = array(
|
||||
'Name' => 'Varchar',
|
||||
'Status' => 'Varchar',
|
||||
);
|
||||
}
|
@ -224,7 +224,7 @@ class DataQueryTest extends SapphireTest {
|
||||
$query = $query->distinct(true);
|
||||
$this->assertContains('SELECT DISTINCT', $query->sql($params), 'Query contains distinct');
|
||||
}
|
||||
|
||||
|
||||
public function testComparisonClauseInt() {
|
||||
DB::query("INSERT INTO \"DataQueryTest_F\" (\"SortOrder\") VALUES (2)");
|
||||
$query = new DataQuery('DataQueryTest_F');
|
||||
@ -232,7 +232,7 @@ class DataQueryTest extends SapphireTest {
|
||||
$this->assertGreaterThan(0, $query->count(), "Couldn't find SortOrder");
|
||||
$this->resetDBSchema(true);
|
||||
}
|
||||
|
||||
|
||||
public function testComparisonClauseDateFull() {
|
||||
DB::query("INSERT INTO \"DataQueryTest_F\" (\"MyDate\") VALUES ('1988-03-04 06:30')");
|
||||
$query = new DataQuery('DataQueryTest_F');
|
||||
@ -240,7 +240,7 @@ class DataQueryTest extends SapphireTest {
|
||||
$this->assertGreaterThan(0, $query->count(), "Couldn't find MyDate");
|
||||
$this->resetDBSchema(true);
|
||||
}
|
||||
|
||||
|
||||
public function testComparisonClauseDateStartsWith() {
|
||||
DB::query("INSERT INTO \"DataQueryTest_F\" (\"MyDate\") VALUES ('1988-03-04 06:30')");
|
||||
$query = new DataQuery('DataQueryTest_F');
|
||||
@ -248,7 +248,7 @@ class DataQueryTest extends SapphireTest {
|
||||
$this->assertGreaterThan(0, $query->count(), "Couldn't find MyDate");
|
||||
$this->resetDBSchema(true);
|
||||
}
|
||||
|
||||
|
||||
public function testComparisonClauseDateStartsPartial() {
|
||||
DB::query("INSERT INTO \"DataQueryTest_F\" (\"MyDate\") VALUES ('1988-03-04 06:30')");
|
||||
$query = new DataQuery('DataQueryTest_F');
|
||||
@ -256,7 +256,7 @@ class DataQueryTest extends SapphireTest {
|
||||
$this->assertGreaterThan(0, $query->count(), "Couldn't find MyDate");
|
||||
$this->resetDBSchema(true);
|
||||
}
|
||||
|
||||
|
||||
public function testComparisonClauseTextCaseInsensitive() {
|
||||
DB::query("INSERT INTO \"DataQueryTest_F\" (\"MyString\") VALUES ('HelloWorld')");
|
||||
$query = new DataQuery('DataQueryTest_F');
|
||||
@ -264,19 +264,58 @@ class DataQueryTest extends SapphireTest {
|
||||
$this->assertGreaterThan(0, $query->count(), "Couldn't find MyString");
|
||||
$this->resetDBSchema(true);
|
||||
}
|
||||
|
||||
|
||||
public function testComparisonClauseTextCaseSensitive() {
|
||||
DB::query("INSERT INTO \"DataQueryTest_F\" (\"MyString\") VALUES ('HelloWorld')");
|
||||
$query = new DataQuery('DataQueryTest_F');
|
||||
$query->where(DB::get_conn()->comparisonClause('"MyString"', 'HelloWorld', false, false, true));
|
||||
$this->assertGreaterThan(0, $query->count(), "Couldn't find MyString");
|
||||
|
||||
|
||||
$query2 = new DataQuery('DataQueryTest_F');
|
||||
$query2->where(DB::get_conn()->comparisonClause('"MyString"', 'helloworld', false, false, true));
|
||||
$this->assertEquals(0, $query2->count(), "Found mystring. Shouldn't be able too.");
|
||||
$this->resetDBSchema(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that getFinalisedQuery can include all tables
|
||||
*/
|
||||
public function testConditionsIncludeTables() {
|
||||
// Including filter on parent table only doesn't pull in second
|
||||
$query = new DataQuery('DataQueryTest_C');
|
||||
$query->sort('"SortOrder"');
|
||||
$query->where(array(
|
||||
'"DataQueryTest_C"."Title" = ?' => array('First')
|
||||
));
|
||||
$result = $query->getFinalisedQuery(array('Title'));
|
||||
$from = $result->getFrom();
|
||||
$this->assertContains('DataQueryTest_C', array_keys($from));
|
||||
$this->assertNotContains('DataQueryTest_E', array_keys($from));
|
||||
|
||||
// Including filter on sub-table requires it
|
||||
$query = new DataQuery('DataQueryTest_C');
|
||||
$query->sort('"SortOrder"');
|
||||
$query->where(array(
|
||||
'"DataQueryTest_C"."Title" = ? OR "DataQueryTest_E"."SortOrder" > ?' => array(
|
||||
'First', 2
|
||||
)
|
||||
));
|
||||
$result = $query->getFinalisedQuery(array('Title'));
|
||||
$from = $result->getFrom();
|
||||
|
||||
// Check that including "SortOrder" prompted inclusion of DataQueryTest_E table
|
||||
$this->assertContains('DataQueryTest_C', array_keys($from));
|
||||
$this->assertContains('DataQueryTest_E', array_keys($from));
|
||||
$arrayResult = iterator_to_array($result->execute());
|
||||
$first = array_shift($arrayResult);
|
||||
$this->assertNotNull($first);
|
||||
$this->assertEquals('First', $first['Title']);
|
||||
$second = array_shift($arrayResult);
|
||||
$this->assertNotNull($second);
|
||||
$this->assertEquals('Last', $second['Title']);
|
||||
$this->assertEmpty(array_shift($arrayResult));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user