mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merge branch '3.0'
This commit is contained in:
commit
824afffd2e
@ -285,7 +285,8 @@
|
||||
}
|
||||
|
||||
// Replace inner content
|
||||
node.addClass(origClasses).html(newNode.html());
|
||||
var origChildren = node.children('ul').detach();
|
||||
node.addClass(origClasses).html(newNode.html()).append(origChildren);
|
||||
|
||||
if (nextNode && nextNode.length) {
|
||||
this.jstree('move_node', node, nextNode, 'before');
|
||||
@ -354,23 +355,25 @@
|
||||
return;
|
||||
}
|
||||
|
||||
var correctStateFn = function(node) {
|
||||
self.jstree('deselect_all');
|
||||
self.jstree('select_node', node);
|
||||
// Similar to jstree's correct_state, but doesn't remove children
|
||||
var hasChildren = (node.children('ul').length > 0);
|
||||
node.toggleClass('jstree-leaf', !hasChildren);
|
||||
if(!hasChildren) node.removeClass('jstree-closed jstree-open');
|
||||
};
|
||||
|
||||
// Check if node exists, create if necessary
|
||||
if(node.length) {
|
||||
self.updateNode(node, nodeData.html, nodeData);
|
||||
setTimeout(function() {
|
||||
self.jstree('deselect_all');
|
||||
self.jstree('select_node', node);
|
||||
// Manually correct state, which checks for children and
|
||||
// removes toggle arrow (should really be done by jstree internally)
|
||||
self.jstree('correct_state', node);
|
||||
correctStateFn(node) ;
|
||||
}, 500);
|
||||
} else {
|
||||
includesNewNode = true;
|
||||
self.createNode(nodeData.html, nodeData, function(newNode) {
|
||||
self.jstree('deselect_all');
|
||||
self.jstree('select_node', newNode);
|
||||
// Manually remove toggle node, see above
|
||||
self.jstree('correct_state', newNode);
|
||||
correctStateFn(newNode);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
|
||||
<!doctype html>
|
||||
<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7" lang="en"> <![endif]-->
|
||||
<!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8" lang="en"> <![endif]-->
|
||||
<!--[if IE 8]> <html class="no-js lt-ie9" lang="en"> <![endif]-->
|
||||
@ -244,8 +244,8 @@
|
||||
<h3 class="sectionHeading">Theme selection <small>Step 4 of 5</small></h3>
|
||||
<p class="helpText">You can change the theme or <a href="http://silverstripe.org/themes">download</a> another from the SilverStripe website after installation.</p>
|
||||
<ul id="Themes">
|
||||
<li><input type="radio" name="template" value="simple" id="Simple" <?php if(!isset($_POST['template']) || $_POST['template'] == 'simple') {?>checked="checked"<?php }?>><label for="Simple"><a href="https://github.com/silverstripe-themes/silverstripe-simple">Simple</a> - our default theme ready to use.</label></li>
|
||||
<li><input type="radio" name="template" value="tutorial" id="EmptyTemplate" <?php if(isset($_POST['template']) && $_POST['template'] == 'tutorial') {?>checked="checked"<?php }?>><label for="EmptyTemplate">Empty template - ready to begin the <a href="http://doc.silverstripe.org/sapphire/en/tutorials" target="_blank">tutorial</a>.</label></li>
|
||||
<li><input type="radio" name="template" value="simple" id="Simple" <?php if(!isset($_POST['template']) || $_POST['template'] == 'simple') {?>checked="checked"<?php }?>><label for="Simple"><a href="https://github.com/silverstripe-themes/silverstripe-simple">Simple</a> - our default theme ready to use, or begin the <a href="http://doc.silverstripe.org/sapphire/en/tutorials" target="_blank">tutorial</a>.</label></li>
|
||||
<li><input type="radio" name="template" value="tutorial" id="EmptyTemplate" <?php if(isset($_POST['template']) && $_POST['template'] == 'tutorial') {?>checked="checked"<?php }?>><label for="EmptyTemplate">Empty template</label></li>
|
||||
</ul>
|
||||
<h3 class="sectionHeading" id="install">Confirm Install <small>Step 5 of 5</small></h3>
|
||||
|
||||
|
@ -246,44 +246,6 @@ use case could be when you want to find all the members that does not exist in a
|
||||
// ... Finding all members that does not belong to $group.
|
||||
$otherMembers = Member::get()->subtract($group->Members());
|
||||
|
||||
|
||||
### Relation filters
|
||||
|
||||
So far we have only filtered a data list by fields on the object that you're requesting. For simple cases, this might
|
||||
be okay, but often, a data model is made up of a number of related objects. For example, in SilverStripe each member
|
||||
can be placed in a number of groups, and each group has a number of permissions.
|
||||
|
||||
For this, the SilverStripe ORM supports **Relation Filters**. Any ORM request can be filtered by fields on a related
|
||||
object by specifying the filter key as `<relation-name>.<field-in-related-object>`. You can chain relations together
|
||||
as many times as is necessary.
|
||||
|
||||
For example, this will return all members assigned to a group that has a permission record with the code "ADMIN". In
|
||||
other words, it will return all administrators.
|
||||
|
||||
:::php
|
||||
$members = Member::get()->filter(array(
|
||||
'Groups.Permissions.Code:ExactMatch' => 'ADMIN',
|
||||
));
|
||||
|
||||
Note that we are just joining these tables to filter the records. Even if a member is in more than 1 administrator
|
||||
group, unique members will still be returned by this query.
|
||||
|
||||
The other features of filters can be applied to relation filters as well. This will return all members in groups whose
|
||||
names start with 'A' or 'B'.
|
||||
|
||||
:::php
|
||||
$members = Member::get()->filter(array(
|
||||
'Groups.Title:StartsWith' => array('A', 'B'),
|
||||
));
|
||||
|
||||
You can even follow a relation back to the original model class! This will return all members are in at least 1 group
|
||||
that also has a member called Sam.
|
||||
|
||||
:::php
|
||||
$members = Member::get()->filter(array(
|
||||
'Groups.Members.FirstName' => 'Sam'
|
||||
));
|
||||
|
||||
### Raw SQL options for advanced users
|
||||
|
||||
Occasionally, the system described above won't let you do exactly what you need to do. In these situtations, we have
|
||||
|
@ -133,7 +133,11 @@ class GridFieldDeleteAction implements GridField_ColumnProvider, GridField_Actio
|
||||
if($actionName == 'deleterecord' && !$item->canDelete()) {
|
||||
throw new ValidationException(_t('GridFieldAction_Delete.DeletePermissionsFailure',"No delete permissions"),0);
|
||||
}
|
||||
$gridField->getList()->remove($item);
|
||||
if($actionName == 'deleterecord') {
|
||||
$item->delete();
|
||||
} else {
|
||||
$gridField->getList()->remove($item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -656,6 +656,7 @@ function max($field) {
|
||||
$fieldExpression = $this->expressionForField($field, $subSelect);
|
||||
$subSelect->setSelect(array());
|
||||
$subSelect->selectField($fieldExpression, $field);
|
||||
$subSelect->setOrderBy(null);
|
||||
$this->where($this->expressionForField($field, $this).' NOT IN ('.$subSelect->sql().')');
|
||||
|
||||
return $this;
|
||||
|
@ -575,22 +575,9 @@ class Hierarchy extends DataExtension {
|
||||
if(!$showAll) $children = $children->where('"ShowInMenus" = 1');
|
||||
|
||||
// Query the live site
|
||||
$children->dataQuery()->setQueryParam('Versioned.mode', 'stage');
|
||||
$children->dataQuery()->setQueryParam('Versioned.mode', $onlyDeletedFromStage ? 'stage_unique' : 'stage');
|
||||
$children->dataQuery()->setQueryParam('Versioned.stage', 'Live');
|
||||
|
||||
if($onlyDeletedFromStage) {
|
||||
// Note that this makes a second query, and could be optimised to be a join
|
||||
$stageChildren = DataObject::get($baseClass)
|
||||
->where("\"{$baseClass}\".\"ID\" != $id");
|
||||
$stageChildren->dataQuery()->setQueryParam('Versioned.mode', 'stage');
|
||||
$stageChildren->dataQuery()->setQueryParam('Versioned.stage', '');
|
||||
|
||||
$ids = $stageChildren->column("ID");
|
||||
if($ids) {
|
||||
$children = $children->where("\"$baseClass\".\"ID\" NOT IN (" . implode(',',$ids) . ")");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return $children;
|
||||
}
|
||||
|
||||
|
@ -191,8 +191,28 @@ class Versioned extends DataExtension {
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
|
||||
// Reading a specific stage, but only return items that aren't in any other stage
|
||||
case 'stage_unique':
|
||||
$stage = $dataQuery->getQueryParam('Versioned.stage');
|
||||
|
||||
// Recurse to do the default stage behavior (must be first, we rely on stage renaming happening before below)
|
||||
$dataQuery->setQueryParam('Versioned.mode', 'stage');
|
||||
$this->augmentSQL($query, $dataQuery);
|
||||
|
||||
// Now exclude any ID from any other stage. Note that we double rename to avoid the regular stage rename
|
||||
// renaming all subquery references to be Versioned.stage
|
||||
foreach($this->stages as $excluding) {
|
||||
if ($excluding == $stage) continue;
|
||||
|
||||
$tempName = 'ExclusionarySource_'.$excluding;
|
||||
$excludingTable = $baseTable . ($excluding && $excluding != $this->defaultStage ? "_$excluding" : '');
|
||||
|
||||
$query->addWhere('"'.$baseTable.'"."ID" NOT IN (SELECT ID FROM "'.$tempName.'")');
|
||||
$query->renameTable($tempName, $excludingTable);
|
||||
}
|
||||
break;
|
||||
|
||||
// Return all version instances
|
||||
case 'all_versions':
|
||||
case 'latest_versions':
|
||||
@ -208,6 +228,7 @@ class Versioned extends DataExtension {
|
||||
$query->selectField(sprintf('"%s_versions"."%s"', $baseTable, $name), $name);
|
||||
}
|
||||
$query->selectField(sprintf('"%s_versions"."%s"', $baseTable, 'RecordID'), "ID");
|
||||
$query->addOrderBy(sprintf('"%s_versions"."%s"', $baseTable, 'Version'));
|
||||
|
||||
// latest_version has one more step
|
||||
// Return latest version instances, regardless of whether they are on a particular stage
|
||||
@ -363,7 +384,7 @@ class Versioned extends DataExtension {
|
||||
|
||||
$versionIndexes = array_merge(
|
||||
array(
|
||||
'RecordID_Version' => array('type' => 'unique', 'value' => 'RecordID,Version'),
|
||||
'RecordID_Version' => array('type' => 'unique', 'value' => '"RecordID","Version"'),
|
||||
'RecordID' => true,
|
||||
'Version' => true,
|
||||
),
|
||||
|
@ -14,11 +14,12 @@ class GreaterThanFilter extends SearchFilter {
|
||||
*/
|
||||
public function apply(DataQuery $query) {
|
||||
$this->model = $query->applyRelation($this->relation);
|
||||
return $query->where(sprintf(
|
||||
"%s > '%s'",
|
||||
$this->getDbName(),
|
||||
Convert::raw2sql($this->getDbFormattedValue())
|
||||
));
|
||||
$value = $this->getDbFormattedValue();
|
||||
|
||||
if(is_numeric($value)) $filter = sprintf("%s > %s", $this->getDbName(), Convert::raw2sql($value));
|
||||
else $filter = sprintf("%s > '%s'", $this->getDbName(), Convert::raw2sql($value));
|
||||
|
||||
return $query->where($filter);
|
||||
}
|
||||
|
||||
public function isEmpty() {
|
||||
|
@ -18,8 +18,10 @@ class RequirementsTest extends SapphireTest {
|
||||
|
||||
$backend->javascript('http://www.mydomain.com/test.js');
|
||||
$backend->javascript('https://www.mysecuredomain.com/test.js');
|
||||
$backend->javascript('//scheme-relative.example.com/test.js');
|
||||
$backend->css('http://www.mydomain.com/test.css');
|
||||
$backend->css('https://www.mysecuredomain.com/test.css');
|
||||
$backend->css('//scheme-relative.example.com/test.css');
|
||||
|
||||
$html = $backend->includeInHTML(false, self::$html_template);
|
||||
|
||||
@ -31,6 +33,10 @@ class RequirementsTest extends SapphireTest {
|
||||
(strpos($html, 'https://www.mysecuredomain.com/test.js') !== false),
|
||||
'Load external secure javascript URL'
|
||||
);
|
||||
$this->assertTrue(
|
||||
(strpos($html, '//scheme-relative.example.com/test.js') !== false),
|
||||
'Load external scheme-relative javascript URL'
|
||||
);
|
||||
$this->assertTrue(
|
||||
(strpos($html, 'http://www.mydomain.com/test.css') !== false),
|
||||
'Load external CSS URL'
|
||||
@ -39,6 +45,10 @@ class RequirementsTest extends SapphireTest {
|
||||
(strpos($html, 'https://www.mysecuredomain.com/test.css') !== false),
|
||||
'Load external secure CSS URL'
|
||||
);
|
||||
$this->assertTrue(
|
||||
(strpos($html, '//scheme-relative.example.com/test.css') !== false),
|
||||
'Load scheme-relative CSS URL'
|
||||
);
|
||||
}
|
||||
|
||||
protected function setupCombinedRequirements($backend) {
|
||||
|
@ -28,8 +28,10 @@ class DataObjectLazyLoadingTest extends SapphireTest {
|
||||
$expected = 'SELECT DISTINCT "DataObjectTest_Team"."ClassName", "DataObjectTest_Team"."Created", ' .
|
||||
'"DataObjectTest_Team"."LastEdited", "DataObjectTest_Team"."ID", CASE WHEN '.
|
||||
'"DataObjectTest_Team"."ClassName" IS NOT NULL THEN "DataObjectTest_Team"."ClassName" ELSE ' .
|
||||
$db->prepStringForDB('DataObjectTest_Team').' END AS "RecordClassName" FROM "DataObjectTest_Team" WHERE ' .
|
||||
'("DataObjectTest_Team"."ClassName" IN ('.$db->prepStringForDB('DataObjectTest_SubTeam').'))';
|
||||
$db->prepStringForDB('DataObjectTest_Team').' END AS "RecordClassName", "DataObjectTest_Team"."Title" '.
|
||||
'FROM "DataObjectTest_Team" ' .
|
||||
'WHERE ("DataObjectTest_Team"."ClassName" IN ('.$db->prepStringForDB('DataObjectTest_SubTeam').'))' .
|
||||
' ORDER BY "DataObjectTest_Team"."Title" ASC';
|
||||
$this->assertEquals($expected, $playerList->sql());
|
||||
}
|
||||
|
||||
@ -43,7 +45,8 @@ class DataObjectLazyLoadingTest extends SapphireTest {
|
||||
'"DataObjectTest_Team"."ClassName" IS NOT NULL THEN "DataObjectTest_Team"."ClassName" ELSE ' .
|
||||
$db->prepStringForDB('DataObjectTest_Team').' END AS "RecordClassName" FROM "DataObjectTest_Team" LEFT JOIN ' .
|
||||
'"DataObjectTest_SubTeam" ON "DataObjectTest_SubTeam"."ID" = "DataObjectTest_Team"."ID" WHERE ' .
|
||||
'("DataObjectTest_Team"."ClassName" IN ('.$db->prepStringForDB('DataObjectTest_SubTeam').'))';
|
||||
'("DataObjectTest_Team"."ClassName" IN ('.$db->prepStringForDB('DataObjectTest_SubTeam').')) ' .
|
||||
'ORDER BY "DataObjectTest_Team"."Title" ASC';
|
||||
$this->assertEquals($expected, $playerList->sql());
|
||||
}
|
||||
|
||||
@ -55,7 +58,8 @@ class DataObjectLazyLoadingTest extends SapphireTest {
|
||||
'"DataObjectTest_Team"."LastEdited", "DataObjectTest_Team"."Title", "DataObjectTest_Team"."ID", ' .
|
||||
'CASE WHEN "DataObjectTest_Team"."ClassName" IS NOT NULL THEN "DataObjectTest_Team"."ClassName" ELSE ' .
|
||||
$db->prepStringForDB('DataObjectTest_Team').' END AS "RecordClassName" FROM "DataObjectTest_Team" WHERE ' .
|
||||
'("DataObjectTest_Team"."ClassName" IN ('.$db->prepStringForDB('DataObjectTest_SubTeam').'))';
|
||||
'("DataObjectTest_Team"."ClassName" IN ('.$db->prepStringForDB('DataObjectTest_SubTeam').')) ' .
|
||||
'ORDER BY "DataObjectTest_Team"."Title" ASC';
|
||||
$this->assertEquals($expected, $playerList->sql());
|
||||
}
|
||||
|
||||
@ -66,9 +70,10 @@ class DataObjectLazyLoadingTest extends SapphireTest {
|
||||
$expected = 'SELECT DISTINCT "DataObjectTest_Team"."ClassName", "DataObjectTest_Team"."Created", ' .
|
||||
'"DataObjectTest_Team"."LastEdited", "DataObjectTest_SubTeam"."SubclassDatabaseField", ' .
|
||||
'"DataObjectTest_Team"."ID", CASE WHEN "DataObjectTest_Team"."ClassName" IS NOT NULL THEN ' .
|
||||
'"DataObjectTest_Team"."ClassName" ELSE '.$db->prepStringForDB('DataObjectTest_Team').' END AS "RecordClassName" FROM ' .
|
||||
'"DataObjectTest_Team"."ClassName" ELSE '.$db->prepStringForDB('DataObjectTest_Team').' END AS "RecordClassName", "DataObjectTest_Team"."Title" FROM ' .
|
||||
'"DataObjectTest_Team" LEFT JOIN "DataObjectTest_SubTeam" ON "DataObjectTest_SubTeam"."ID" = ' .
|
||||
'"DataObjectTest_Team"."ID" WHERE ("DataObjectTest_Team"."ClassName" IN ('.$db->prepStringForDB('DataObjectTest_SubTeam').'))';
|
||||
'"DataObjectTest_Team"."ID" WHERE ("DataObjectTest_Team"."ClassName" IN ('.$db->prepStringForDB('DataObjectTest_SubTeam').')) ' .
|
||||
'ORDER BY "DataObjectTest_Team"."Title" ASC';
|
||||
$this->assertEquals($expected, $playerList->sql());
|
||||
}
|
||||
|
||||
|
@ -1111,6 +1111,8 @@ class DataObjectTest_Team extends DataObject implements TestOnly {
|
||||
)
|
||||
);
|
||||
|
||||
static $default_sort = "Title";
|
||||
|
||||
function MyTitle() {
|
||||
return 'Team ' . $this->Title;
|
||||
}
|
||||
|
@ -781,7 +781,7 @@ class Requirements_Backend {
|
||||
* @return string|boolean
|
||||
*/
|
||||
protected function path_for_file($fileOrUrl) {
|
||||
if(preg_match('/^http[s]?/', $fileOrUrl)) {
|
||||
if(preg_match('{^//|http[s]?}', $fileOrUrl)) {
|
||||
return $fileOrUrl;
|
||||
} elseif(Director::fileExists($fileOrUrl)) {
|
||||
$prefix = Director::baseURL();
|
||||
|
Loading…
Reference in New Issue
Block a user