MINOR Merged from branches/2.3

git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@69957 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
Ingo Schommer 2009-01-10 11:35:50 +00:00
parent c8200f67ac
commit b7d394008e
22 changed files with 292 additions and 95 deletions

View File

@ -26,6 +26,15 @@ abstract class Extension extends Object {
function setOwner(Object $owner) { function setOwner(Object $owner) {
$this->owner = $owner; $this->owner = $owner;
} }
/**
* Returns the owner of this decorator
*
* @return Object
*/
public function getOwner() {
return $this->owner;
}
} }
?> ?>

View File

@ -40,7 +40,6 @@ class ManifestBuilder {
'cli-script.php', 'cli-script.php',
'install.php', 'install.php',
'index.php', 'index.php',
'check-php.php',
'rewritetest.php', 'rewritetest.php',
); );

View File

@ -460,12 +460,15 @@ class Object {
* @param string $funcName The name of the function. * @param string $funcName The name of the function.
* @param mixed $arg An Argument to be passed to each of the extension functions. * @param mixed $arg An Argument to be passed to each of the extension functions.
*/ */
public function extend($funcName, &$arg=null) { public function extend($funcName, &$arg1=null, &$arg2=null, &$arg3=null, &$arg4=null, &$arg5=null, &$arg6=null, &$arg7=null) {
$arguments = func_get_args();
array_shift($arguments);
if($this->extension_instances) { if($this->extension_instances) {
$returnArr = array(); $returnArr = array();
foreach($this->extension_instances as $extension) { foreach($this->extension_instances as $extension) {
if($extension->hasMethod($funcName)) { if($extension->hasMethod($funcName)) {
$return = $extension->$funcName($arg); $return = $extension->$funcName($arg1, $arg2, $arg3, $arg4, $arg5, $arg6, $arg7);
if($return !== NULL) $returnArr[] = $return; if($return !== NULL) $returnArr[] = $return;
} }
} }

View File

@ -377,7 +377,6 @@ HTML
'index.php', 'index.php',
'install.php', 'install.php',
'rewritetest.php', 'rewritetest.php',
'check-php.php',
'config-form.css', 'config-form.css',
'config-form.html', 'config-form.html',
'index.html' 'index.html'

View File

@ -287,11 +287,8 @@ class Director {
static function currentPage() { static function currentPage() {
if(isset(Director::$urlParams['URLSegment'])) { if(isset(Director::$urlParams['URLSegment'])) {
$SQL_urlSegment = Convert::raw2sql(Director::$urlParams['URLSegment']); $SQL_urlSegment = Convert::raw2sql(Director::$urlParams['URLSegment']);
if (Translatable::is_enabled()) {
return Translatable::get_one("SiteTree", "\"URLSegment\" = '$SQL_urlSegment'"); return SiteTree::get_by_url($SQL_urlSegment);
} else {
return DataObject::get_one("SiteTree", "\"URLSegment\" = '$SQL_urlSegment'");
}
} else { } else {
return Controller::curr(); return Controller::curr();
} }

View File

@ -32,11 +32,8 @@ class ModelAsController extends Controller implements NestedController {
public function getNestedController() { public function getNestedController() {
if($this->urlParams['URLSegment']) { if($this->urlParams['URLSegment']) {
$SQL_URLSegment = Convert::raw2sql($this->urlParams['URLSegment']); $SQL_URLSegment = Convert::raw2sql($this->urlParams['URLSegment']);
if (Translatable::is_enabled()) { $child = SiteTree::get_by_url($SQL_URLSegment);
$child = Translatable::get_one("SiteTree", "\"SiteTree\".\"URLSegment\" = '$SQL_URLSegment'", false);
} else {
$child = DataObject::get_one("SiteTree", "\"SiteTree\".\"URLSegment\" = '$SQL_URLSegment'", false);
}
if(!$child) { if(!$child) {
if($child = $this->findOldPage($SQL_URLSegment)) { if($child = $this->findOldPage($SQL_URLSegment)) {
$url = Controller::join_links( $url = Controller::join_links(

View File

@ -853,26 +853,6 @@ class i18n extends Object {
return self::$all_locales; return self::$all_locales;
} }
/**
* Get a list of languages with at least one element translated in (including the default language)
*
* @param string $className Look for languages in elements of this class
* @return array Map of languages in the form langCode => langName
*/
static function get_existing_content_languages($className = 'SiteTree', $where = '') {
if(!Translatable::is_enabled()) return false;
$query = new SQLQuery('Lang',$className.'_lang',$where,"",'Lang');
$dbLangs = $query->execute()->column();
$langlist = array_merge((array)Translatable::default_lang(), (array)$dbLangs);
$returnMap = array();
$allCodes = array_merge(self::$all_locales, self::$common_languages);
foreach ($langlist as $langCode) {
$returnMap[$langCode] = (is_array($allCodes[$langCode]) ? $allCodes[$langCode][0] : $allCodes[$langCode]);
}
return $returnMap;
}
/** /**
* Searches the root-directory for module-directories * Searches the root-directory for module-directories
* (identified by having a _config.php on their first directory-level). * (identified by having a _config.php on their first directory-level).

View File

@ -302,8 +302,7 @@ class DataObject extends ViewableData implements DataObjectInterface,i18nEntityP
* @return string User friendly translated singular name of this DataObject * @return string User friendly translated singular name of this DataObject
*/ */
function i18n_singular_name() { function i18n_singular_name() {
$name = (!empty($this->add_action)) ? $this->add_action : $this->singular_name(); return _t($this->class.'.SINGULARNAME', $this->singular_name());
return _t($this->class.'.SINGULARNAME', $name);
} }
/** /**
@ -2245,6 +2244,9 @@ class DataObject extends ViewableData implements DataObjectInterface,i18nEntityP
} }
$query = $this->extendedSQL($filter, $sort, $limit, $join); $query = $this->extendedSQL($filter, $sort, $limit, $join);
$this->extend('augmentSQL', $query);
$records = $query->execute(); $records = $query->execute();
$ret = $this->buildDataObjectSet($records, $containerClass, $query, $this->class); $ret = $this->buildDataObjectSet($records, $containerClass, $query, $this->class);

View File

@ -381,6 +381,21 @@ class DataObjectSet extends ViewableData implements IteratorAggregate {
} }
} }
/**
* Replaces $itemOld with $itemNew
*
* @param DataObject $itemOld
* @param DataObject $itemNew
*/
public function replace($itemOld, $itemNew) {
foreach($this->items as $key => $item) {
if($item === $itemOld) {
$this->items[$key] = $itemNew;
return;
}
}
}
/** /**
* Merge another set onto the end of this set. * Merge another set onto the end of this set.
* @param DataObjectSet $anotherSet Set to mege onto this set. * @param DataObjectSet $anotherSet Set to mege onto this set.

View File

@ -33,7 +33,7 @@ class Hierarchy extends DataObjectDecorator {
$this->markingFinished(); $this->markingFinished();
} }
$children = $this->owner->AllChildrenIncludingDeleted(); $children = $this->owner->AllChildrenIncludingDeleted($extraArg);
if($children) { if($children) {
if($attributes) { if($attributes) {
@ -69,13 +69,13 @@ class Hierarchy extends DataObjectDecorator {
* @param int $minCount The minimum amount of nodes to mark. * @param int $minCount The minimum amount of nodes to mark.
* @return int The actual number of nodes marked. * @return int The actual number of nodes marked.
*/ */
public function markPartialTree($minCount = 30) { public function markPartialTree($minCount = 30, $context = null) {
$this->markedNodes = array($this->owner->ID => $this->owner); $this->markedNodes = array($this->owner->ID => $this->owner);
$this->owner->markUnexpanded(); $this->owner->markUnexpanded();
// foreach can't handle an ever-growing $nodes list // foreach can't handle an ever-growing $nodes list
while(list($id, $node) = each($this->markedNodes)) { while(list($id, $node) = each($this->markedNodes)) {
$this->markChildren($node); $this->markChildren($node, $context);
if($minCount && sizeof($this->markedNodes) >= $minCount) { if($minCount && sizeof($this->markedNodes) >= $minCount) {
break; break;
@ -139,8 +139,8 @@ class Hierarchy extends DataObjectDecorator {
* Mark all children of the given node that match the marking filter. * Mark all children of the given node that match the marking filter.
* @param DataObject $node Parent node. * @param DataObject $node Parent node.
*/ */
public function markChildren($node) { public function markChildren($node, $context = null) {
$children = $node->AllChildrenIncludingDeleted(); $children = $node->AllChildrenIncludingDeleted($context);
$node->markExpanded(); $node->markExpanded();
if($children) { if($children) {
foreach($children as $child) { foreach($children as $child) {
@ -381,7 +381,17 @@ class Hierarchy extends DataObjectDecorator {
* Everything else has "SameOnStage" set, as an indicator that this information has been looked up. * Everything else has "SameOnStage" set, as an indicator that this information has been looked up.
* @return DataObjectSet * @return DataObjectSet
*/ */
public function AllChildrenIncludingDeleted() { public function AllChildrenIncludingDeleted($context = null) {
return $this->doAllChildrenIncludingDeleted($context);
}
/**
* @see AllChildrenIncludingDeleted
*
* @param unknown_type $context
* @return DataObjectSet
*/
public function doAllChildrenIncludingDeleted($context = null) {
// Cache the allChildren data, so that future requests will return the references to the same // Cache the allChildren data, so that future requests will return the references to the same
// object. This allows the mark..() system to work appropriately. // object. This allows the mark..() system to work appropriately.
@ -391,6 +401,8 @@ class Hierarchy extends DataObjectDecorator {
$stageChildren = $this->owner->stageChildren(true); $stageChildren = $this->owner->stageChildren(true);
$this->allChildrenIncludingDeleted = $stageChildren; $this->allChildrenIncludingDeleted = $stageChildren;
$this->owner->extend("augmentAllChildrenIncludingDeleted", $stageChildren, $context);
// Add live site content, if required. // Add live site content, if required.
if($this->owner->hasExtension('Versioned')) { if($this->owner->hasExtension('Versioned')) {
// Get all the requisite data, and index it // Get all the requisite data, and index it
@ -467,6 +479,7 @@ class Hierarchy extends DataObjectDecorator {
// We build the query in an extension-friendly way. // We build the query in an extension-friendly way.
$query = new SQLQuery("COUNT(*)","\"$baseClass\"","\"ParentID\" = " . (int)$this->owner->ID); $query = new SQLQuery("COUNT(*)","\"$baseClass\"","\"ParentID\" = " . (int)$this->owner->ID);
$this->owner->extend('augmentSQL', $query); $this->owner->extend('augmentSQL', $query);
$this->owner->extend('augmentNumChildrenCountQuery', $query);
return $query->execute()->value(); return $query->execute()->value();
} }
@ -478,7 +491,11 @@ class Hierarchy extends DataObjectDecorator {
public function stageChildren($showAll = false) { public function stageChildren($showAll = false) {
$extraFilter = $showAll ? '' : " AND \"ShowInMenus\""; $extraFilter = $showAll ? '' : " AND \"ShowInMenus\"";
$baseClass = ClassInfo::baseDataClass($this->owner->class); $baseClass = ClassInfo::baseDataClass($this->owner->class);
return DataObject::get($baseClass, "\"{$baseClass}\".\"ParentID\" = " . (int)$this->owner->ID . " AND \"{$baseClass}\".\"ID\" != " . (int)$this->owner->ID . $extraFilter, "");
$staged = DataObject::get($baseClass, "\"{$baseClass}\".\"ParentID\" = " . (int)$this->owner->ID . " AND \"{$baseClass}\".\"ID\" != " . (int)$this->owner->ID . $extraFilter, "");
if(!$staged) $staged = new DataObjectSet();
$this->owner->extend("augmentStageChildren", $staged, $showAll);
return $staged;
} }
/** /**

View File

@ -6,6 +6,10 @@
*/ */
class Image extends File { class Image extends File {
const ORIENTATION_SQUARE = 0;
const ORIENTATION_PORTRAIT = 1;
const ORIENTATION_LANDSCAPE = 2;
static $casting = array( static $casting = array(
'Tag' => 'HTMLText', 'Tag' => 'HTMLText',
); );
@ -383,6 +387,21 @@ class Image extends File {
return $this->getDimensions(1); return $this->getDimensions(1);
} }
/**
* Get the orientation of this image.
* @return ORIENTATION_SQUARE | ORIENTATION_PORTRAIT | ORIENTATION_LANDSCAPE
*/
function getOrienation() {
$width = $this->getWidth();
$height = $this->getHeight();
if($width > $height) {
return self::ORIENTATION_LANDSCAPE;
} elseif($height > $width) {
return self::ORIENTATION_PORTRAIT;
} else {
return self::ORIENTATION_SQUARE;
}
}
@ -467,7 +486,7 @@ class Image_Uploader extends Controller {
// set reading lang // set reading lang
if(Translatable::is_enabled() && !Director::is_ajax()) { if(Translatable::is_enabled() && !Director::is_ajax()) {
Translatable::choose_site_lang(array_keys(i18n::get_existing_content_languages('SiteTree'))); Translatable::choose_site_lang(array_keys(Translatable::get_existing_content_languages('SiteTree')));
} }
parent::init(); parent::init();

View File

@ -399,11 +399,29 @@ class SQLQuery extends Object {
/** /**
* Checks whether this query is for a specific ID in a table * Checks whether this query is for a specific ID in a table
* *
* @todo Doesn't work with combined statements (e.g. "Foo='bar' AND ID=5")
*
* @return boolean * @return boolean
*/ */
function filtersOnID() { function filtersOnID() {
return ($this->where && return (
(strpos($this->where[0], ".\"ID\" = ") || strpos($this->where[0], ".`ID` = ") || strpos($this->where[0], ".ID = ") || strpos($this->where[0], "ID = ") ) $this->where
&& count($this->where) == 1
&& preg_match('/^(.*\.)?("|`)?ID("|`)?\s?=/', $this->where[0])
);
}
/**
* Checks whether this query is filtering on a foreign key, ie finding a has_many relationship
*
* @todo Doesn't work with combined statements (e.g. "Foo='bar' AND ParentID=5")
*
* @return boolean
*/
function filtersOnFK() {
return (
$this->where
&& preg_match('/^(.*\.)?("|`)?[a-zA-Z]+ID("|`)?\s?=/', $this->where[0])
); );
} }

View File

@ -138,6 +138,8 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
/** /**
* The text shown in the create page dropdown. If * The text shown in the create page dropdown. If
* this is not set, default to "Create a ClassName". * this is not set, default to "Create a ClassName".
*
* @deprecated 2.3 Use "<myclassname>.TITLE" in the i18n language tables instead
* @var string * @var string
*/ */
static $add_action = null; static $add_action = null;
@ -956,14 +958,12 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
DataObject::set_context_obj($this); DataObject::set_context_obj($this);
// Ensure URLSegment is unique // Ensure URLSegment is unique
$idFilter = ($this->ID) $idFilter = ($this->ID) ? "\"SiteTree\".\"ID\" <> '$this->ID'" : '';
? " AND \"SiteTree\".\"ID\" <> '$this->ID'" :
'';
$count = 1; $count = 1;
while ( while (
(class_exists($this->URLSegment) && is_subclass_of($this->URLSegment, 'RequestHandler')) || (class_exists($this->URLSegment) && is_subclass_of($this->URLSegment, 'RequestHandler')) ||
DataObject::get_one("SiteTree", "\"URLSegment\" = '$this->URLSegment' $idFilter") SiteTree::get_by_url($this->URLSegment, $idFilter)
) { ) {
$count++; $count++;
$this->URLSegment = ereg_replace('-[0-9]+$','', $this->URLSegment) . "-$count"; $this->URLSegment = ereg_replace('-[0-9]+$','', $this->URLSegment) . "-$count";
@ -1024,11 +1024,15 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
* Return the SiteTree object with the given URL segment. * Return the SiteTree object with the given URL segment.
* *
* @param string $urlSegment The URL segment, eg 'home' * @param string $urlSegment The URL segment, eg 'home'
* * @param string $extraFilter
* @param boolean $cache
* @param string $orderby
* @return SiteTree The object with the given URL segment * @return SiteTree The object with the given URL segment
*/ */
public static function get_by_url($urlSegment) { public static function get_by_url($urlSegment, $extraFilter = "", $cache = true, $orderby = "") {
return DataObject::get_one("SiteTree", "\"URLSegment\" = '" . addslashes((string) $urlSegment) . "'"); $filter = sprintf("\"URLSegment\" = '%s'", Convert::raw2sql($urlSegment));
if($extraFilter) $filter .= " AND $extraFilter";
return DataObject::get_one("SiteTree", $filter, $cache, $orderby);
} }
/** /**
@ -1721,6 +1725,9 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
* @return boolean * @return boolean
*/ */
public function getIsModifiedOnStage() { public function getIsModifiedOnStage() {
// new unsaved pages could be never be published
if($this->isNew()) return false;
$stageVersion = Versioned::get_versionnumber_by_stage('SiteTree', 'Stage', $this->ID); $stageVersion = Versioned::get_versionnumber_by_stage('SiteTree', 'Stage', $this->ID);
$liveVersion = Versioned::get_versionnumber_by_stage('SiteTree', 'Live', $this->ID); $liveVersion = Versioned::get_versionnumber_by_stage('SiteTree', 'Live', $this->ID);
@ -1735,6 +1742,9 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
* @return boolean * @return boolean
*/ */
public function getIsAddedToStage() { public function getIsAddedToStage() {
// new unsaved pages could be never be published
if($this->isNew()) return false;
$stageVersion = Versioned::get_versionnumber_by_stage('SiteTree', 'Stage', $this->ID); $stageVersion = Versioned::get_versionnumber_by_stage('SiteTree', 'Stage', $this->ID);
$liveVersion = Versioned::get_versionnumber_by_stage('SiteTree', 'Live', $this->ID); $liveVersion = Versioned::get_versionnumber_by_stage('SiteTree', 'Live', $this->ID);
@ -1768,6 +1778,12 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
); );
} }
function i18n_singular_name() {
$addAction = $this->stat('add_action');
$name = (!empty($addAction)) ? $addAction : $this->singular_name();
return _t($this->class.'.SINGULARNAME', $name);
}
/** /**
* Overloaded to also provide entities for 'Page' class which is usually * Overloaded to also provide entities for 'Page' class which is usually
* located in custom code, hence textcollector picks it up for the wrong folder. * located in custom code, hence textcollector picks it up for the wrong folder.

View File

@ -759,5 +759,26 @@ class Translatable extends DataObjectDecorator {
return $table; return $table;
} }
/**
* Get a list of languages with at least one element translated in (including the default language)
*
* @param string $className Look for languages in elements of this class
* @return array Map of languages in the form langCode => langName
*/
static function get_existing_content_languages($className = 'SiteTree', $where = '') {
if(!Translatable::is_enabled()) return false;
$baseTable = ClassInfo::baseDataClass($className);
$query = new SQLQuery('Lang',$baseTable.'_lang',$where,"",'Lang');
$dbLangs = $query->execute()->column();
$langlist = array_merge((array)Translatable::default_lang(), (array)$dbLangs);
$returnMap = array();
$allCodes = array_merge(i18n::$all_locales, i18n::$common_languages);
foreach ($langlist as $langCode) {
if($langCode)
$returnMap[$langCode] = (is_array($allCodes[$langCode]) ? $allCodes[$langCode][0] : $allCodes[$langCode]);
}
return $returnMap;
}
} }
?> ?>

View File

@ -210,7 +210,7 @@ class Folder extends File {
function onBeforeDelete() { function onBeforeDelete() {
if($children = $this->AllChildren()) { if($this->ID && ($children = $this->AllChildren())) {
foreach($children as $child) { foreach($children as $child) {
if(!$this->Filename || !$this->Name || !file_exists($this->getFullPath())) { if(!$this->Filename || !$this->Name || !file_exists($this->getFullPath())) {
$child->setField('Name',null); $child->setField('Name',null);
@ -260,7 +260,7 @@ class Folder extends File {
* Returns true if this folder has children * Returns true if this folder has children
*/ */
public function hasChildren() { public function hasChildren() {
return $this->myChildren() && $this->myChildren()->Count() > 0; return $this->ID && $this->myChildren() && $this->myChildren()->Count() > 0;
} }
/** /**
@ -269,7 +269,7 @@ class Folder extends File {
public function autosetFilename() { public function autosetFilename() {
parent::autosetFilename(); parent::autosetFilename();
if($children = $this->AllChildren()) { if($this->ID && ($children = $this->AllChildren())) {
$this->write(); $this->write();
foreach($children as $child) { foreach($children as $child) {
@ -286,7 +286,7 @@ class Folder extends File {
protected function resetFilename($renamePhysicalFile = true) { protected function resetFilename($renamePhysicalFile = true) {
parent::resetFilename($renamePhysicalFile); parent::resetFilename($renamePhysicalFile);
if($children = $this->AllChildren()) { if($this->ID && ($children = $this->AllChildren())) {
$this->write(); $this->write();
foreach($children as $child) { foreach($children as $child) {

View File

@ -35,6 +35,9 @@ class ComplexTableField extends TableListField {
* - A FieldSet object: Use that field set directly. * - A FieldSet object: Use that field set directly.
* - A method name, eg, 'getCMSFields': Call that method on the child object to get the fields. * - A method name, eg, 'getCMSFields': Call that method on the child object to get the fields.
*/ */
protected $addTitle;
protected $detailFormFields; protected $detailFormFields;
protected $viewAction, $sourceJoin, $sourceItems, $unpagedSourceItems; protected $viewAction, $sourceJoin, $sourceItems, $unpagedSourceItems;
@ -303,6 +306,15 @@ JS;
$this->detailFormValidator = $validator; $this->detailFormValidator = $validator;
} }
function setAddTitle($addTitle) {
if(is_string($addTitle))
$this->addTitle = $addTitle;
}
function Title() {
return $this->addTitle ? $this->addTitle : parent::Title();
}
/** /**
* Returns the content of this formfield without surrounding layout. Triggered by Javascript * Returns the content of this formfield without surrounding layout. Triggered by Javascript
* to update content after a DetailForm-save-action. * to update content after a DetailForm-save-action.

View File

@ -127,29 +127,7 @@ class Form extends RequestHandler {
$this->validator->setForm($this); $this->validator->setForm($this);
// Form error controls // Form error controls
$errorInfo = Session::get("FormInfo.{$this->FormName()}"); $this->setupFormErrors();
if(isset($errorInfo['errors']) && is_array($errorInfo['errors'])){
foreach($errorInfo['errors'] as $error){
$field = $this->fields->dataFieldByName($error['fieldName']);
if(!$field){
$errorInfo['message'] = $error['message'];
$errorInfo['type'] = $error['messageType'];
} else {
$field->setError($error['message'],$error['messageType']);
}
}
// load data in from previous submission upon error
if(isset($errorInfo['data']))
$this->loadDataFrom($errorInfo['data']);
}
if(isset($errorInfo['message']) && isset($errorInfo['type'])) {
$this->setMessage($errorInfo['message'],$errorInfo['type']);
}
$this->security = self::$default_security; $this->security = self::$default_security;
} }
@ -161,6 +139,34 @@ class Form extends RequestHandler {
'GET ' => 'httpSubmission', 'GET ' => 'httpSubmission',
); );
/**
* Set up current form errors in session to
* the current form if appropriate.
*/
function setupFormErrors() {
$errorInfo = Session::get("FormInfo.{$this->FormName()}");
if(isset($errorInfo['errors']) && is_array($errorInfo['errors'])) {
foreach($errorInfo['errors'] as $error) {
$field = $this->fields->dataFieldByName($error['fieldName']);
if(!$field) {
$errorInfo['message'] = $error['message'];
$errorInfo['type'] = $error['messageType'];
} else {
$field->setError($error['message'], $error['messageType']);
}
}
// load data in from previous submission upon error
if(isset($errorInfo['data'])) $this->loadDataFrom($errorInfo['data']);
}
if(isset($errorInfo['message']) && isset($errorInfo['type'])) {
$this->setMessage($errorInfo['message'], $errorInfo['type']);
}
}
/** /**
* Handle a form submission. GET and POST requests behave identically. * Handle a form submission. GET and POST requests behave identically.
* Populates the form with {@link loadDataFrom()}, calls {@link validate()}, * Populates the form with {@link loadDataFrom()}, calls {@link validate()},

View File

@ -445,8 +445,7 @@ class HtmlEditorField_Toolbar extends RequestHandler {
) )
), ),
new FieldSet( new FieldSet(
new FormAction('insertimage', _t('HtmlEditorField.BUTTONINSERTIMAGE', 'Insert image')), new FormAction('insertimage', _t('HtmlEditorField.BUTTONINSERTIMAGE', 'Insert image'))
new FormAction('editimage', _t('HtmlEditorField.BUTTONEDITIMAGE', 'Edit image'))
) )
); );

View File

@ -17,7 +17,7 @@ class LanguageDropdownField extends GroupedDropdownField {
*/ */
function __construct($name, $title, $dontInclude = array(), $translatingClass = 'SiteTree', $list = 'Common-English' ) { function __construct($name, $title, $dontInclude = array(), $translatingClass = 'SiteTree', $list = 'Common-English' ) {
$usedlangs = array_diff( $usedlangs = array_diff(
i18n::get_existing_content_languages($translatingClass), Translatable::get_existing_content_languages($translatingClass),
$dontInclude $dontInclude
); );
// we accept in dontInclude both language codes and names, so another diff is required // we accept in dontInclude both language codes and names, so another diff is required

View File

@ -233,7 +233,7 @@ class TableField extends TableListField {
foreach($newitems as $k => $newitem){ foreach($newitems as $k => $newitem){
$fieldset = $this->FieldSetForRow(); $fieldset = $this->FieldSetForRow();
if($fieldset){ if($fieldset){
$newitem[ID] = "new".$k; $newitem['ID'] = "new".$k;
foreach($newitem as $k => $v){ foreach($newitem as $k => $v){
if($this->extraData && array_key_exists($k, $this->extraData)){ if($this->extraData && array_key_exists($k, $this->extraData)){
unset($newitem[$k]); unset($newitem[$k]);
@ -563,7 +563,8 @@ JS;
} }
} }
function validate($validator){ function validate($validator) {
$errorMessage = '';
$valid = true; $valid = true;
$fields = $this->SubmittedFieldSet($sourceItemsNew); $fields = $this->SubmittedFieldSet($sourceItemsNew);
$fields = new FieldSet($fields); $fields = new FieldSet($fields);

View File

@ -50,23 +50,23 @@ class MemberLoginForm extends LoginForm {
if(!$fields) { if(!$fields) {
$fields = new FieldSet( $fields = new FieldSet(
new HiddenField("AuthenticationMethod", null, $this->authenticator_class, $this), new HiddenField("AuthenticationMethod", null, $this->authenticator_class, $this),
new TextField("Email", _t('Member.EMAIL'), new TextField("Email", _t('Member.EMAIL'), Session::get('SessionForms.MemberLoginForm.Email'), null, $this),
Session::get('SessionForms.MemberLoginForm.Email'), null, $this),
new PasswordField("Password", _t('Member.PASSWORD'), null, $this) new PasswordField("Password", _t('Member.PASSWORD'), null, $this)
); );
if(Security::$autologin_enabled) { if(Security::$autologin_enabled) {
$fields->push(new CheckboxField( $fields->push(new CheckboxField(
"Remember", "Remember",
_t('Member.REMEMBERME', "Remember me next time?"), _t('Member.REMEMBERME', "Remember me next time?")
Session::get('SessionForms.MemberLoginForm.Remember'),
$this
)); ));
} }
} }
if(!$actions) { if(!$actions) {
$actions = new FieldSet( $actions = new FieldSet(
new FormAction('dologin', _t('Member.BUTTONLOGIN', "Log in")), new FormAction('dologin', _t('Member.BUTTONLOGIN', "Log in")),
new LiteralField('forgotPassword', '<p id="ForgotPassword"><a href="Security/lostpassword">' . _t('Member.BUTTONLOSTPASSWORD', "I've lost my password") . '</a></p>') new LiteralField(
'forgotPassword',
'<p id="ForgotPassword"><a href="Security/lostpassword">' . _t('Member.BUTTONLOSTPASSWORD', "I've lost my password") . '</a></p>'
)
); );
} }
} }
@ -78,7 +78,6 @@ class MemberLoginForm extends LoginForm {
parent::__construct($controller, $name, $fields, $actions); parent::__construct($controller, $name, $fields, $actions);
} }
/** /**
* Get message from session * Get message from session
*/ */
@ -113,8 +112,6 @@ class MemberLoginForm extends LoginForm {
$cp->sessionMessage('Your password has expired. Please choose a new one.', 'good'); $cp->sessionMessage('Your password has expired. Please choose a new one.', 'good');
Director::redirect('Security/changepassword'); Director::redirect('Security/changepassword');
} elseif(isset($_REQUEST['BackURL']) && $backURL = $_REQUEST['BackURL']) { } elseif(isset($_REQUEST['BackURL']) && $backURL = $_REQUEST['BackURL']) {
Session::clear("BackURL"); Session::clear("BackURL");
Director::redirect($backURL); Director::redirect($backURL);
@ -122,6 +119,14 @@ class MemberLoginForm extends LoginForm {
$member = Member::currentUser(); $member = Member::currentUser();
if($member) { if($member) {
$firstname = Convert::raw2xml($member->FirstName); $firstname = Convert::raw2xml($member->FirstName);
if(!empty($data['Remember'])) {
Session::set('SessionForms.MemberLoginForm.Remember', '1');
$member->logIn(true);
} else {
$member->logIn();
}
Session::set('Security.Message.message', Session::set('Security.Message.message',
sprintf(_t('Member.WELCOMEBACK', "Welcome Back, %s"), $firstname) sprintf(_t('Member.WELCOMEBACK', "Welcome Back, %s"), $firstname)
); );

View File

@ -112,6 +112,88 @@ class SQLQueryTest extends SapphireTest {
function testSelectWithComplexOrderbyClause() { function testSelectWithComplexOrderbyClause() {
// @todo Test "ORDER BY RANDOM() ASC,MyName DESC" etc. // @todo Test "ORDER BY RANDOM() ASC,MyName DESC" etc.
} }
function testFiltersOnID() {
$query = new SQLQuery();
$query->where[] = "ID = 5";
$this->assertTrue(
$query->filtersOnID(),
"filtersOnID() is true with simple unquoted column name"
);
$query = new SQLQuery();
$query->where[] = "ID=5";
$this->assertTrue(
$query->filtersOnID(),
"filtersOnID() is true with simple unquoted column name and no spaces in equals sign"
);
/*
$query = new SQLQuery();
$query->where[] = "Foo='Bar' AND ID=5";
$this->assertTrue(
$query->filtersOnID(),
"filtersOnID() is true with combined SQL statements"
);
*/
$query = new SQLQuery();
$query->where[] = "Identifier = 5";
$this->assertFalse(
$query->filtersOnID(),
"filtersOnID() is false with custom column name (starting with 'id')"
);
$query = new SQLQuery();
$query->where[] = "ParentID = 5";
$this->assertFalse(
$query->filtersOnID(),
"filtersOnID() is false with column name ending in 'ID'"
);
$query = new SQLQuery();
$query->where[] = "MyTable.ID = 5";
$this->assertTrue(
$query->filtersOnID(),
"filtersOnID() is true with table and column name"
);
$query = new SQLQuery();
$query->where[] = "MyTable.`ID`= 5";
$this->assertTrue(
$query->filtersOnID(),
"filtersOnID() is true with table and quoted column name "
);
}
function testFiltersOnFK() {
$query = new SQLQuery();
$query->where[] = "ID = 5";
$this->assertFalse(
$query->filtersOnFK(),
"filtersOnFK() is true with simple unquoted column name"
);
$query = new SQLQuery();
$query->where[] = "Identifier = 5";
$this->assertFalse(
$query->filtersOnFK(),
"filtersOnFK() is false with custom column name (starting with 'id')"
);
$query = new SQLQuery();
$query->where[] = "MyTable.ParentID = 5";
$this->assertTrue(
$query->filtersOnFK(),
"filtersOnFK() is true with table and column name"
);
$query = new SQLQuery();
$query->where[] = "MyTable.`ParentID`= 5";
$this->assertTrue(
$query->filtersOnFK(),
"filtersOnFK() is true with table and quoted column name "
);
}
} }
class SQLQueryTest_DO extends DataObject implements TestOnly { class SQLQueryTest_DO extends DataObject implements TestOnly {