diff --git a/core/Extension.php b/core/Extension.php index c3fd9e134..89e0b17a7 100644 --- a/core/Extension.php +++ b/core/Extension.php @@ -26,6 +26,15 @@ abstract class Extension extends Object { function setOwner(Object $owner) { $this->owner = $owner; } + + /** + * Returns the owner of this decorator + * + * @return Object + */ + public function getOwner() { + return $this->owner; + } } ?> \ No newline at end of file diff --git a/core/ManifestBuilder.php b/core/ManifestBuilder.php index cf4e1aca2..16a92069f 100644 --- a/core/ManifestBuilder.php +++ b/core/ManifestBuilder.php @@ -40,7 +40,6 @@ class ManifestBuilder { 'cli-script.php', 'install.php', 'index.php', - 'check-php.php', 'rewritetest.php', ); diff --git a/core/Object.php b/core/Object.php index caf7b119a..a08a6c294 100755 --- a/core/Object.php +++ b/core/Object.php @@ -460,12 +460,15 @@ class Object { * @param string $funcName The name of the function. * @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) { $returnArr = array(); foreach($this->extension_instances as $extension) { if($extension->hasMethod($funcName)) { - $return = $extension->$funcName($arg); + $return = $extension->$funcName($arg1, $arg2, $arg3, $arg4, $arg5, $arg6, $arg7); if($return !== NULL) $returnArr[] = $return; } } diff --git a/core/control/ContentController.php b/core/control/ContentController.php index 319f59847..6f9498863 100644 --- a/core/control/ContentController.php +++ b/core/control/ContentController.php @@ -377,7 +377,6 @@ HTML 'index.php', 'install.php', 'rewritetest.php', - 'check-php.php', 'config-form.css', 'config-form.html', 'index.html' diff --git a/core/control/Director.php b/core/control/Director.php index e75c713da..b52adbfad 100644 --- a/core/control/Director.php +++ b/core/control/Director.php @@ -287,11 +287,8 @@ class Director { static function currentPage() { if(isset(Director::$urlParams['URLSegment'])) { $SQL_urlSegment = Convert::raw2sql(Director::$urlParams['URLSegment']); - if (Translatable::is_enabled()) { - return Translatable::get_one("SiteTree", "\"URLSegment\" = '$SQL_urlSegment'"); - } else { - return DataObject::get_one("SiteTree", "\"URLSegment\" = '$SQL_urlSegment'"); - } + + return SiteTree::get_by_url($SQL_urlSegment); } else { return Controller::curr(); } diff --git a/core/control/ModelAsController.php b/core/control/ModelAsController.php index fc543fc37..11cd4b7dc 100644 --- a/core/control/ModelAsController.php +++ b/core/control/ModelAsController.php @@ -32,11 +32,8 @@ class ModelAsController extends Controller implements NestedController { public function getNestedController() { if($this->urlParams['URLSegment']) { $SQL_URLSegment = Convert::raw2sql($this->urlParams['URLSegment']); - if (Translatable::is_enabled()) { - $child = Translatable::get_one("SiteTree", "\"SiteTree\".\"URLSegment\" = '$SQL_URLSegment'", false); - } else { - $child = DataObject::get_one("SiteTree", "\"SiteTree\".\"URLSegment\" = '$SQL_URLSegment'", false); - } + $child = SiteTree::get_by_url($SQL_URLSegment); + if(!$child) { if($child = $this->findOldPage($SQL_URLSegment)) { $url = Controller::join_links( diff --git a/core/i18n.php b/core/i18n.php index 377a068ac..8f37ab0b6 100755 --- a/core/i18n.php +++ b/core/i18n.php @@ -853,26 +853,6 @@ class i18n extends Object { 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 * (identified by having a _config.php on their first directory-level). diff --git a/core/model/DataObject.php b/core/model/DataObject.php index 3d2ec7ae4..97bdbe332 100644 --- a/core/model/DataObject.php +++ b/core/model/DataObject.php @@ -302,8 +302,7 @@ class DataObject extends ViewableData implements DataObjectInterface,i18nEntityP * @return string User friendly translated singular name of this DataObject */ function i18n_singular_name() { - $name = (!empty($this->add_action)) ? $this->add_action : $this->singular_name(); - return _t($this->class.'.SINGULARNAME', $name); + return _t($this->class.'.SINGULARNAME', $this->singular_name()); } /** @@ -2245,6 +2244,9 @@ class DataObject extends ViewableData implements DataObjectInterface,i18nEntityP } $query = $this->extendedSQL($filter, $sort, $limit, $join); + + $this->extend('augmentSQL', $query); + $records = $query->execute(); $ret = $this->buildDataObjectSet($records, $containerClass, $query, $this->class); diff --git a/core/model/DataObjectSet.php b/core/model/DataObjectSet.php index d9aa75ee9..3385fc91d 100644 --- a/core/model/DataObjectSet.php +++ b/core/model/DataObjectSet.php @@ -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. * @param DataObjectSet $anotherSet Set to mege onto this set. diff --git a/core/model/Hierarchy.php b/core/model/Hierarchy.php index 8765e4b48..c5238d14f 100644 --- a/core/model/Hierarchy.php +++ b/core/model/Hierarchy.php @@ -33,7 +33,7 @@ class Hierarchy extends DataObjectDecorator { $this->markingFinished(); } - $children = $this->owner->AllChildrenIncludingDeleted(); + $children = $this->owner->AllChildrenIncludingDeleted($extraArg); if($children) { if($attributes) { @@ -69,13 +69,13 @@ class Hierarchy extends DataObjectDecorator { * @param int $minCount The minimum amount of nodes to mark. * @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->owner->markUnexpanded(); // foreach can't handle an ever-growing $nodes list while(list($id, $node) = each($this->markedNodes)) { - $this->markChildren($node); + $this->markChildren($node, $context); if($minCount && sizeof($this->markedNodes) >= $minCount) { break; @@ -139,8 +139,8 @@ class Hierarchy extends DataObjectDecorator { * Mark all children of the given node that match the marking filter. * @param DataObject $node Parent node. */ - public function markChildren($node) { - $children = $node->AllChildrenIncludingDeleted(); + public function markChildren($node, $context = null) { + $children = $node->AllChildrenIncludingDeleted($context); $node->markExpanded(); if($children) { 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. * @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 // object. This allows the mark..() system to work appropriately. @@ -391,6 +401,8 @@ class Hierarchy extends DataObjectDecorator { $stageChildren = $this->owner->stageChildren(true); $this->allChildrenIncludingDeleted = $stageChildren; + $this->owner->extend("augmentAllChildrenIncludingDeleted", $stageChildren, $context); + // Add live site content, if required. if($this->owner->hasExtension('Versioned')) { // 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. $query = new SQLQuery("COUNT(*)","\"$baseClass\"","\"ParentID\" = " . (int)$this->owner->ID); $this->owner->extend('augmentSQL', $query); + $this->owner->extend('augmentNumChildrenCountQuery', $query); return $query->execute()->value(); } @@ -478,7 +491,11 @@ class Hierarchy extends DataObjectDecorator { public function stageChildren($showAll = false) { $extraFilter = $showAll ? '' : " AND \"ShowInMenus\""; $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; } /** diff --git a/core/model/Image.php b/core/model/Image.php index 71fa4785d..c92e0e6ab 100755 --- a/core/model/Image.php +++ b/core/model/Image.php @@ -6,6 +6,10 @@ */ class Image extends File { + const ORIENTATION_SQUARE = 0; + const ORIENTATION_PORTRAIT = 1; + const ORIENTATION_LANDSCAPE = 2; + static $casting = array( 'Tag' => 'HTMLText', ); @@ -383,6 +387,21 @@ class Image extends File { 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 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(); diff --git a/core/model/SQLQuery.php b/core/model/SQLQuery.php index 20185c05b..0835668d8 100755 --- a/core/model/SQLQuery.php +++ b/core/model/SQLQuery.php @@ -398,12 +398,30 @@ class SQLQuery extends Object { /** * 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 */ function filtersOnID() { - return ($this->where && - (strpos($this->where[0], ".\"ID\" = ") || strpos($this->where[0], ".`ID` = ") || strpos($this->where[0], ".ID = ") || strpos($this->where[0], "ID = ") ) + return ( + $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]) ); } diff --git a/core/model/SiteTree.php b/core/model/SiteTree.php index b4fcd22f5..63ab4466f 100644 --- a/core/model/SiteTree.php +++ b/core/model/SiteTree.php @@ -138,6 +138,8 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid /** * The text shown in the create page dropdown. If * this is not set, default to "Create a ClassName". + * + * @deprecated 2.3 Use ".TITLE" in the i18n language tables instead * @var string */ static $add_action = null; @@ -956,14 +958,12 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid DataObject::set_context_obj($this); // Ensure URLSegment is unique - $idFilter = ($this->ID) - ? " AND \"SiteTree\".\"ID\" <> '$this->ID'" : - ''; + $idFilter = ($this->ID) ? "\"SiteTree\".\"ID\" <> '$this->ID'" : ''; $count = 1; while ( (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++; $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. * * @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 */ - public static function get_by_url($urlSegment) { - return DataObject::get_one("SiteTree", "\"URLSegment\" = '" . addslashes((string) $urlSegment) . "'"); + public static function get_by_url($urlSegment, $extraFilter = "", $cache = true, $orderby = "") { + $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 */ 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); $liveVersion = Versioned::get_versionnumber_by_stage('SiteTree', 'Live', $this->ID); @@ -1735,6 +1742,9 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid * @return boolean */ 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); $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 * located in custom code, hence textcollector picks it up for the wrong folder. diff --git a/core/model/Translatable.php b/core/model/Translatable.php index 0c074227c..1160b4da3 100755 --- a/core/model/Translatable.php +++ b/core/model/Translatable.php @@ -758,6 +758,27 @@ class Translatable extends DataObjectDecorator { } 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; + } } ?> diff --git a/filesystem/Folder.php b/filesystem/Folder.php index efeb40167..3e82f1423 100755 --- a/filesystem/Folder.php +++ b/filesystem/Folder.php @@ -210,7 +210,7 @@ class Folder extends File { function onBeforeDelete() { - if($children = $this->AllChildren()) { + if($this->ID && ($children = $this->AllChildren())) { foreach($children as $child) { if(!$this->Filename || !$this->Name || !file_exists($this->getFullPath())) { $child->setField('Name',null); @@ -260,7 +260,7 @@ class Folder extends File { * Returns true if this folder has children */ 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() { parent::autosetFilename(); - if($children = $this->AllChildren()) { + if($this->ID && ($children = $this->AllChildren())) { $this->write(); foreach($children as $child) { @@ -286,7 +286,7 @@ class Folder extends File { protected function resetFilename($renamePhysicalFile = true) { parent::resetFilename($renamePhysicalFile); - if($children = $this->AllChildren()) { + if($this->ID && ($children = $this->AllChildren())) { $this->write(); foreach($children as $child) { diff --git a/forms/ComplexTableField.php b/forms/ComplexTableField.php index 4bb4f9d2d..104f30621 100755 --- a/forms/ComplexTableField.php +++ b/forms/ComplexTableField.php @@ -35,6 +35,9 @@ class ComplexTableField extends TableListField { * - A FieldSet object: Use that field set directly. * - A method name, eg, 'getCMSFields': Call that method on the child object to get the fields. */ + + protected $addTitle; + protected $detailFormFields; protected $viewAction, $sourceJoin, $sourceItems, $unpagedSourceItems; @@ -302,6 +305,15 @@ JS; function setDetailFormValidator( Validator $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 @@ -982,4 +994,4 @@ class ComplexTableField_Popup extends Form { } } -?> \ No newline at end of file +?> diff --git a/forms/Form.php b/forms/Form.php index 1ac29afcb..6448ffb0a 100644 --- a/forms/Form.php +++ b/forms/Form.php @@ -127,29 +127,7 @@ class Form extends RequestHandler { $this->validator->setForm($this); // Form error controls - $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']); - } + $this->setupFormErrors(); $this->security = self::$default_security; } @@ -161,6 +139,34 @@ class Form extends RequestHandler { '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. * Populates the form with {@link loadDataFrom()}, calls {@link validate()}, diff --git a/forms/HtmlEditorField.php b/forms/HtmlEditorField.php index 80358ddc0..5e950b710 100755 --- a/forms/HtmlEditorField.php +++ b/forms/HtmlEditorField.php @@ -445,8 +445,7 @@ class HtmlEditorField_Toolbar extends RequestHandler { ) ), new FieldSet( - new FormAction('insertimage', _t('HtmlEditorField.BUTTONINSERTIMAGE', 'Insert image')), - new FormAction('editimage', _t('HtmlEditorField.BUTTONEDITIMAGE', 'Edit image')) + new FormAction('insertimage', _t('HtmlEditorField.BUTTONINSERTIMAGE', 'Insert image')) ) ); diff --git a/forms/LanguageDropdownField.php b/forms/LanguageDropdownField.php index 0f9efecea..de361e74d 100755 --- a/forms/LanguageDropdownField.php +++ b/forms/LanguageDropdownField.php @@ -17,7 +17,7 @@ class LanguageDropdownField extends GroupedDropdownField { */ function __construct($name, $title, $dontInclude = array(), $translatingClass = 'SiteTree', $list = 'Common-English' ) { $usedlangs = array_diff( - i18n::get_existing_content_languages($translatingClass), + Translatable::get_existing_content_languages($translatingClass), $dontInclude ); // we accept in dontInclude both language codes and names, so another diff is required diff --git a/forms/TableField.php b/forms/TableField.php index 9859b1482..e8383e94e 100644 --- a/forms/TableField.php +++ b/forms/TableField.php @@ -233,7 +233,7 @@ class TableField extends TableListField { foreach($newitems as $k => $newitem){ $fieldset = $this->FieldSetForRow(); if($fieldset){ - $newitem[ID] = "new".$k; + $newitem['ID'] = "new".$k; foreach($newitem as $k => $v){ if($this->extraData && array_key_exists($k, $this->extraData)){ unset($newitem[$k]); @@ -563,7 +563,8 @@ JS; } } - function validate($validator){ + function validate($validator) { + $errorMessage = ''; $valid = true; $fields = $this->SubmittedFieldSet($sourceItemsNew); $fields = new FieldSet($fields); diff --git a/security/MemberLoginForm.php b/security/MemberLoginForm.php index e5d08f013..bdb40dc91 100644 --- a/security/MemberLoginForm.php +++ b/security/MemberLoginForm.php @@ -50,23 +50,23 @@ class MemberLoginForm extends LoginForm { if(!$fields) { $fields = new FieldSet( new HiddenField("AuthenticationMethod", null, $this->authenticator_class, $this), - new TextField("Email", _t('Member.EMAIL'), - Session::get('SessionForms.MemberLoginForm.Email'), null, $this), + new TextField("Email", _t('Member.EMAIL'), Session::get('SessionForms.MemberLoginForm.Email'), null, $this), new PasswordField("Password", _t('Member.PASSWORD'), null, $this) ); if(Security::$autologin_enabled) { $fields->push(new CheckboxField( "Remember", - _t('Member.REMEMBERME', "Remember me next time?"), - Session::get('SessionForms.MemberLoginForm.Remember'), - $this + _t('Member.REMEMBERME', "Remember me next time?") )); } } if(!$actions) { $actions = new FieldSet( new FormAction('dologin', _t('Member.BUTTONLOGIN', "Log in")), - new LiteralField('forgotPassword', '

' . _t('Member.BUTTONLOSTPASSWORD', "I've lost my password") . '

') + new LiteralField( + 'forgotPassword', + '

' . _t('Member.BUTTONLOSTPASSWORD', "I've lost my password") . '

' + ) ); } } @@ -78,7 +78,6 @@ class MemberLoginForm extends LoginForm { parent::__construct($controller, $name, $fields, $actions); } - /** * Get message from session */ @@ -113,8 +112,6 @@ class MemberLoginForm extends LoginForm { $cp->sessionMessage('Your password has expired. Please choose a new one.', 'good'); Director::redirect('Security/changepassword'); - - } elseif(isset($_REQUEST['BackURL']) && $backURL = $_REQUEST['BackURL']) { Session::clear("BackURL"); Director::redirect($backURL); @@ -122,6 +119,14 @@ class MemberLoginForm extends LoginForm { $member = Member::currentUser(); if($member) { $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', sprintf(_t('Member.WELCOMEBACK', "Welcome Back, %s"), $firstname) ); diff --git a/tests/SQLQueryTest.php b/tests/SQLQueryTest.php index 39fee8c5f..8a869a80c 100644 --- a/tests/SQLQueryTest.php +++ b/tests/SQLQueryTest.php @@ -112,6 +112,88 @@ class SQLQueryTest extends SapphireTest { function testSelectWithComplexOrderbyClause() { // @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 {