diff --git a/api/SapphireSoapServer.php b/api/SapphireSoapServer.php index 9efb216a6..0ada4e7aa 100755 --- a/api/SapphireSoapServer.php +++ b/api/SapphireSoapServer.php @@ -54,10 +54,16 @@ class SapphireSoapServer extends Controller { } function index() { - $s = new SoapServer($this->getWSDLURL()); - $s->setClass($this->class); - $s->handle(); + $wsdl = $this->getViewer('wsdl')->process($this); + $wsdlFile = TEMP_FOLDER . '/sapphire-wsdl-' . $this->class; + $fh = fopen($wsdlFile, 'w'); + fwrite($fh, $wsdl); + fclose($fh); + + $s = new SoapServer($wsdlFile); + $s->setClass($this->class); + $s->handle(); } } -?> \ No newline at end of file +?> diff --git a/conf/ConfigureFromEnv.php b/conf/ConfigureFromEnv.php index 53c26a330..2dac47b30 100644 --- a/conf/ConfigureFromEnv.php +++ b/conf/ConfigureFromEnv.php @@ -26,6 +26,7 @@ * You can configure the default admin with these defines * - SS_DEFAULT_ADMIN_USERNAME: The username of the default admin - this is a non-database user with administrative privileges. * - SS_DEFAULT_ADMIN_PASSWORD: The password of the default admin. + * - SS_USE_BASIC_AUTH: Protect the site with basic auth (good for test sites) * * Email: * - SS_SEND_ALL_EMAILS_TO: If you set this define, all emails will be redirected to this address. @@ -82,7 +83,10 @@ if(defined('SS_DEFAULT_ADMIN_USERNAME')) { if(!defined('SS_DEFAULT_ADMIN_PASSWORD')) user_error("SS_DEFAULT_ADMIN_PASSWORD must be defined in your _ss_environment.php, if SS_DEFAULT_ADMIN_USERNAME is defined. See http://doc.silverstripe.com/doku.php?id=environment-management for more infomration", E_USER_ERROR); Security::setDefaultAdmin(SS_DEFAULT_ADMIN_USERNAME, SS_DEFAULT_ADMIN_PASSWORD); } +if(defined('SS_USE_BASIC_AUTH') && SS_USE_BASIC_AUTH) { + BasicAuth::enable(); +} if(defined('SS_ERROR_LOG')) { Debug::log_errors_to(SS_ERROR_LOG); -} \ No newline at end of file +} diff --git a/core/ArrayData.php b/core/ArrayData.php index 6c06eb0b8..f2528b81b 100755 --- a/core/ArrayData.php +++ b/core/ArrayData.php @@ -32,6 +32,7 @@ class ArrayData extends ViewableData { E_USER_WARNING ); } + parent::__construct(); } public function getField($f) { diff --git a/core/ClassInfo.php b/core/ClassInfo.php index 747be4339..bc7208e25 100755 --- a/core/ClassInfo.php +++ b/core/ClassInfo.php @@ -24,12 +24,23 @@ class ClassInfo { return isset($_ALL_CLASSES['exists'][$class]) ? $_ALL_CLASSES['exists'][$class] : null; } + /** + * Cache for {@link hasTable()} + */ + private static $_cache_all_tables = null; + /** * @todo Move this to Database or DB */ static function hasTable($class) { if(DB::isActive()) { - return DB::getConn()->hasTable($class); + // Cache the list of all table names to reduce on DB traffic + if(self::$_cache_all_tables === null) { + self::$_cache_all_tables = array(); + $tables = DB::query("SHOW TABLES")->column(); + foreach($tables as $table) self::$_cache_all_tables[strtolower($table)] = true; + } + return isset(self::$_cache_all_tables[strtolower($class)]); } else { return false; } @@ -191,4 +202,4 @@ class ClassInfo { } } -?> \ No newline at end of file +?> diff --git a/core/Requirements.php b/core/Requirements.php index 9d16f0647..88f1daba7 100644 --- a/core/Requirements.php +++ b/core/Requirements.php @@ -7,6 +7,20 @@ * @subpackage view */ class Requirements { + /** + * Enable combining of css/javascript files. + * + * @var boolean + */ + private static $combined_files_enabled = true; + public static function set_combined_files_enabled($enable) { + self::$combined_files_enabled = (bool) $enable; + } + + public static function get_combined_files_enabled() { + return self::$combined_files_enabled; + } + /** * Instance of requirements for storage * @@ -777,7 +791,7 @@ class Requirements_Backend { */ function process_combined_files() { - if(Director::isDev() && !SapphireTest::is_running_test()) { + if((Director::isDev() && !SapphireTest::is_running_test()) || !Requirements::get_combined_files_enabled()) { return; } diff --git a/core/SSViewer.php b/core/SSViewer.php index 41ac4470f..739d06ecb 100644 --- a/core/SSViewer.php +++ b/core/SSViewer.php @@ -369,7 +369,7 @@ class SSViewer extends Object { static function parseTemplateContent($content, $template="") { // Add template filename comments on dev sites - if(Director::isDev() && self::$source_file_comments && $template) { + if(Director::isDev() && self::$source_file_comments && $template && stripos($content, "]*>)/i', "\\1", $content); diff --git a/core/control/ContentController.php b/core/control/ContentController.php index 50f2b6d84..5f17f87b8 100644 --- a/core/control/ContentController.php +++ b/core/control/ContentController.php @@ -244,17 +244,17 @@ JS $archiveLink = "". _t('ContentController.ARCHIVEDSITE', 'Archived Site') .""; $liveLink = "". _t('ContentController.PUBLISHEDSITE', 'Published Site') .""; $stageLink = "". _t('ContentController.DRAFTSITE', 'Draft Site') .""; - $message = "
". _t('ContentController.ARCHIVEDSITEFROM', 'Archived site from') ."
" . $dateObj->Nice() . "
"; + $message = "
". _t('ContentController.ARCHIVEDSITEFROM', 'Archived site from') ."
" . $dateObj->Nice() . "
"; } else if(Versioned::current_stage() == 'Stage') { $stageLink = "". _t('ContentController.DRAFTSITE', 'Draft Site') .""; $liveLink = "". _t('ContentController.PUBLISHEDSITE', 'Published Site') .""; - $message = "
". _t('ContentController.DRAFTSITE', 'Draft Site') ."
"; + $message = "
". _t('ContentController.DRAFTSITE', 'Draft Site') ."
"; } else { $liveLink = "". _t('ContentController.PUBLISHEDSITE', 'Published Site') .""; $stageLink = "". _t('ContentController.DRAFTSITE', 'Draft Site') .""; - $message = "
". _t('ContentController.PUBLISHEDSITE', 'Published Site') ."
"; + $message = "
". _t('ContentController.PUBLISHEDSITE', 'Published Site') ."
"; } if($member) { diff --git a/core/control/ModelAsController.php b/core/control/ModelAsController.php index 13428ef12..88f74e9c7 100644 --- a/core/control/ModelAsController.php +++ b/core/control/ModelAsController.php @@ -38,11 +38,11 @@ class ModelAsController extends Controller implements NestedController { $url = Controller::join_links( Director::baseURL(), $child->URLSegment, - (isset($this->urlParams['Action'])) ? $this->urlParams['Action'] : null, - (isset($this->urlParams['ID'])) ? $this->urlParams['ID'] : null, - (isset($this->urlParams['OtherID'])) ? $this->urlParams['OtherID'] : null + isset($this->urlParams['Action']) ? $this->urlParams['Action'] : null, + isset($this->urlParams['ID']) ? $this->urlParams['ID'] : null, + isset($this->urlParams['OtherID']) ? $this->urlParams['OtherID'] : null ); - + $response = new HTTPResponse(); $response->redirect($url, 301); return $response; @@ -80,17 +80,32 @@ class ModelAsController extends Controller implements NestedController { } protected function findOldPage($urlSegment) { - $versionedQuery = new SQLQuery ( - '"RecordID"', '"SiteTree_versions"', - "\"WasPublished\" AND \"URLSegment\" = '$urlSegment'", - '"LastEdited" DESC, "WasPublished"', - null, null, 1 - ); + // Build the query by replacing `SiteTree` with `SiteTree_versions` in a regular query. + // Note that this should *really* be handled by a more full-featured data mapper; as it stands + // this is a bit of a hack. + $origStage = Versioned::current_stage(); + Versioned::reading_stage('Stage'); + $versionedQuery = singleton('SiteTree')->extendedSQL(''); + Versioned::reading_stage($origStage); + foreach($versionedQuery->from as $k => $v) { + $versionedQuery->renameTable($k, $k . '_versions'); + } + $versionedQuery->select = array("`SiteTree_versions`.RecordID"); + $versionedQuery->where[] = "`SiteTree_versions`.`WasPublished` = 1 AND `URLSegment` = '$urlSegment'"; + $versionedQuery->orderby = '`LastEdited` DESC, `SiteTree_versions`.`WasPublished`'; + $versionedQuery->limit = 1; + $result = $versionedQuery->execute(); if($result->numRecords() == 1 && $redirectPage = $result->nextRecord()) { - if($redirectObj = DataObject::get_by_id('SiteTree', $redirectPage['RecordID'])) return $redirectObj; + $redirectObj = DataObject::get_by_id('SiteTree', $redirectPage['RecordID']); + if($redirectObj) { + // Double-check by querying this page in the same way that getNestedController() does. This + // will prevent query muck-ups from modules such as subsites + $doubleCheck = SiteTree::get_by_url($redirectObj->URLSegment); + if($doubleCheck) return $redirectObj; + } } return false; @@ -102,4 +117,4 @@ class ModelAsController extends Controller implements NestedController { } } -?> \ No newline at end of file +?> diff --git a/core/i18n.php b/core/i18n.php index 96924f7e4..9268cdcea 100755 --- a/core/i18n.php +++ b/core/i18n.php @@ -1103,6 +1103,9 @@ class i18n extends Object { static function include_by_locale($locale) { $topLevel = scandir(Director::baseFolder()); foreach($topLevel as $module) { + //$topLevel is the website root, some server is configurated not to allow excess website root's parent level + //and we don't need to check website root's parent level and websit root level for its lang folder, so we skip these 2 levels checking. + if($module == ".." || $module == ".") continue; if (file_exists(Director::getAbsFile("$module/_config.php")) && file_exists($file = Director::getAbsFile("$module/lang/$locale.php"))) { include_once($file); diff --git a/core/i18nTextCollector.php b/core/i18nTextCollector.php index e0cddd508..b6485afc1 100644 --- a/core/i18nTextCollector.php +++ b/core/i18nTextCollector.php @@ -206,7 +206,7 @@ class i18nTextCollector extends Object { $entitiesArr = array_merge($entitiesArr,(array)$this->collectFromTemplate($includeContent, $module, $includeFileName)); } - // @todo respect template tags (<% _t() %> instead of _t()) + // @todo respect template tags (< % _t() % > instead of _t()) $regexRule = '_t[[:space:]]*\(' . '[[:space:]]*("[^"]*"|\\\'[^\']*\\\')[[:space:]]*,' . # namespace.entity '[[:space:]]*("([^"]|\\\")*"|\'([^\']|\\\\\')*\')([[:space:]]*,' . # value @@ -366,7 +366,7 @@ class i18nTextCollector extends Object { user_error('i18nTextCollector->writeMasterStringFile(): Invalid PHP language file. Error: ' . $e->toString(), E_USER_ERROR); } - fwrite($fh, ""); + fwrite($fh, "<"."?php\n\nglobal \$lang;\n\n" . $php . "\n?".">"); fclose($fh); //Debug::message("Created file: $langFolder/" . $this->defaultLocale . ".php", false); diff --git a/core/model/DataObject.php b/core/model/DataObject.php index 7b2fbd395..6bf9a6751 100644 --- a/core/model/DataObject.php +++ b/core/model/DataObject.php @@ -105,6 +105,29 @@ class DataObject extends ViewableData implements DataObjectInterface,i18nEntityP * @todo Define the options that can be set here */ static $api_access = false; + + /** + * Should dataobjects be validated before they are written? + */ + private static $validation_enabled = true; + + /** + * Returns when validation on DataObjects is enabled. + * @return bool + */ + static function get_validation_enabled() { + return self::$validation_enabled; + } + + /** + * Set whether DataObjects should be validated before they are written. + * @param $enable bool + * @see DataObject::validate() + */ + static function set_validation_enabled($enable) { + self::$validation_enabled = (bool) $enable; + } + /** * Construct a new DataObject. @@ -165,6 +188,9 @@ class DataObject extends ViewableData implements DataObjectInterface,i18nEntityP $this->extension_instances = null; $this->components = null; $this->destroyed = true; + $this->record = null; + $this->orignal = null; + $this->changed = null; $this->flushCache(); } @@ -692,12 +718,14 @@ class DataObject extends ViewableData implements DataObjectInterface,i18nEntityP $this->brokenOnWrite = true; $isNewRecord = false; - $valid = $this->validate(); - if(!$valid->valid()) { - throw new ValidationException($valid, "Validation error writing a $this->class object: " . $valid->message() . ". Object not written.", E_USER_WARNING); - return false; + if(self::get_validation_enabled()) { + $valid = $this->validate(); + if(!$valid->valid()) { + throw new ValidationException($valid, "Validation error writing a $this->class object: " . $valid->message() . ". Object not written.", E_USER_WARNING); + return false; + } } - + $this->onBeforeWrite(); if($this->brokenOnWrite) { user_error("$this->class has a broken onBeforeWrite() function. Make sure that you call parent::onBeforeWrite().", E_USER_ERROR); diff --git a/core/model/DatabaseAdmin.php b/core/model/DatabaseAdmin.php index 9ec29e76d..6abb62a8f 100644 --- a/core/model/DatabaseAdmin.php +++ b/core/model/DatabaseAdmin.php @@ -158,13 +158,16 @@ class DatabaseAdmin extends Controller { $conn = DB::getConn(); $conn->beginSchemaUpdate(); foreach($dataClasses as $dataClass) { - $SNG = singleton($dataClass); - if($testMode || !($SNG instanceof TestOnly)) { - if(!$quiet) { - if(Director::is_cli()) echo " * $dataClass\n"; - else echo "
  • $dataClass
  • \n"; + // Check if class exists before trying to instantiate - this sidesteps any manifest weirdness + if(class_exists($dataClass)) { + $SNG = singleton($dataClass); + if($testMode || !($SNG instanceof TestOnly)) { + if(!$quiet) { + if(Director::is_cli()) echo " * $dataClass\n"; + else echo "
  • $dataClass
  • \n"; + } + $SNG->requireTable(); } - $SNG->requireTable(); } } $conn->endSchemaUpdate(); @@ -176,9 +179,9 @@ class DatabaseAdmin extends Controller { } foreach($dataClasses as $dataClass) { + // Check if class exists before trying to instantiate - this sidesteps any manifest weirdness // Test_ indicates that it's the data class is part of testing system - - if(strpos($dataClass,'Test_') === false) { + if(strpos($dataClass,'Test_') === false && class_exists($dataClass)) { if(!$quiet) { if(Director::is_cli()) echo " * $dataClass\n"; else echo "
  • $dataClass
  • \n"; @@ -266,4 +269,4 @@ class DatabaseAdmin extends Controller { } -?> \ No newline at end of file +?> diff --git a/core/model/MySQLDatabase.php b/core/model/MySQLDatabase.php index 03cdd2012..c9f1c07f9 100644 --- a/core/model/MySQLDatabase.php +++ b/core/model/MySQLDatabase.php @@ -272,6 +272,8 @@ class MySQLDatabase extends Database { } } + private static $_cache_collation_info = array(); + public function fieldList($table) { $fields = DB::query("SHOW FULL FIELDS IN \"$table\""); foreach($fields as $field) { @@ -281,7 +283,11 @@ class MySQLDatabase extends Database { } if($field['Collation'] && $field['Collation'] != 'NULL') { - $collInfo = DB::query("SHOW COLLATION LIKE '$field[Collation]'")->record(); + // Cache collation info to cut down on database traffic + if(!isset(self::$_cache_collation_info[$field['Collation']])) { + self::$_cache_collation_info[$field['Collation']] = DB::query("SHOW COLLATION LIKE '$field[Collation]'")->record(); + } + $collInfo = self::$_cache_collation_info[$field['Collation']]; $fieldSpec .= " character set $collInfo[Charset] collate $field[Collation]"; } diff --git a/core/model/fieldtypes/Date.php b/core/model/fieldtypes/Date.php index 4ac2a51b4..9212583b7 100644 --- a/core/model/fieldtypes/Date.php +++ b/core/model/fieldtypes/Date.php @@ -74,6 +74,16 @@ class Date extends DBField { if($this->value) return date($formattingString, strtotime($this->value)); } + /** + * Return the date formatted using the given strftime formatting string. + * + * strftime obeyes the current LC_TIME/LC_ALL when printing lexical values + * like day- and month-names + */ + function FormatI18N($formattingString) { + if($this->value) return strftime($formattingString, strtotime($this->value)); + } + /* * Return a string in the form "12 - 16 Sept" or "12 Aug - 16 Sept" */ diff --git a/css/TableListField.css b/css/TableListField.css index c6f42d80c..742061e48 100644 --- a/css/TableListField.css +++ b/css/TableListField.css @@ -40,7 +40,7 @@ table.CMSList thead th { height : 24px; border-right : 1px solid #aca899; border-left : 1px solid #ffffff; - padding-left : 5px; + padding-left : 0 5px; } table.TableField thead th span, @@ -75,8 +75,8 @@ table.TableField tfoot td, .TableListField table.data tfoot td, table.CMSList tbody td, table.CMSList tfoot td { - border : 1px solid #f1efe2; - padding-left : 5px; + border: 1px solid #f1efe2; + padding: 5px; } .TableListField table.data tfoot tr.addtogrouprow td { diff --git a/dev/BulkLoader.php b/dev/BulkLoader.php index 261f433a6..6059f48f8 100644 --- a/dev/BulkLoader.php +++ b/dev/BulkLoader.php @@ -128,9 +128,9 @@ abstract class BulkLoader extends ViewableData { * * @return BulkLoader_Result See {@link self::processAll()} */ - public function load($filepath) { + public function load($filepath, $memory_limit='512M') { ini_set('max_execution_time', 3600); - ini_set('memory_limit', '512M'); + ini_set('memory_limit', $memory_limit); return $this->processAll($filepath); } diff --git a/dev/CsvBulkLoader.php b/dev/CsvBulkLoader.php index 3f4ca2405..e1347be8e 100644 --- a/dev/CsvBulkLoader.php +++ b/dev/CsvBulkLoader.php @@ -86,6 +86,7 @@ class CsvBulkLoader extends BulkLoader { $obj->setComponent($relationName, $relationObj); $obj->{"{$relationName}ID"} = $relationObj->ID; $obj->write(); + $obj->flushCache(); // avoid relation caching confusion } elseif(strpos($fieldName, '.') !== false) { // we have a relation column with dot notation @@ -95,11 +96,10 @@ class CsvBulkLoader extends BulkLoader { $relationObj->write(); $obj->{"{$relationName}ID"} = $relationObj->ID; $obj->write(); + $obj->flushCache(); // avoid relation caching confusion } - $obj->flushCache(); // avoid relation caching confusion } - $id = ($preview) ? 0 : $obj->write(); // second run: save data foreach($record as $fieldName => $val) { @@ -127,9 +127,15 @@ class CsvBulkLoader extends BulkLoader { $results->addCreated($obj, $message); } + $objID = $obj->ID; + + $obj->destroy(); + // memory usage unset($existingObj); unset($obj); + + return $objID; } /** diff --git a/dev/SapphireTest.php b/dev/SapphireTest.php index 4a290a69d..1dc66de96 100644 --- a/dev/SapphireTest.php +++ b/dev/SapphireTest.php @@ -66,9 +66,15 @@ class SapphireTest extends PHPUnit_Framework_TestCase { $dbadmin = new DatabaseAdmin(); $dbadmin->clearAllData(); - + + // We have to disable validation while we import the fixtures, as the order in + // which they are imported doesnt guarantee valid relations until after the + // import is complete. + $validationenabled = DataObject::get_validation_enabled(); + DataObject::set_validation_enabled(false); $this->fixture = new YamlFixture($fixtureFile); $this->fixture->saveIntoDatabase(); + DataObject::set_validation_enabled($validationenabled); } // Set up email @@ -236,4 +242,4 @@ class SapphireTest extends PHPUnit_Framework_TestCase { } } -?> \ No newline at end of file +?> diff --git a/dev/TestRunner.php b/dev/TestRunner.php index fcccbd533..8ae7d6082 100644 --- a/dev/TestRunner.php +++ b/dev/TestRunner.php @@ -133,6 +133,9 @@ class TestRunner extends Controller { } function runTests($classList, $coverage = false) { + // XDEBUG seem to cause problems with test execution :-( + if(function_exists('xdebug_disable')) xdebug_disable(); + ini_set('max_execution_time', 0); $this->setUp(); diff --git a/email/Email.php b/email/Email.php index 257e63e09..ee3821e08 100755 --- a/email/Email.php +++ b/email/Email.php @@ -238,8 +238,8 @@ class Email extends ViewableData { if($headerName == 'Cc') $this->cc = $headerValue; else if($headerName == 'Bcc') $this->bcc = $headerValue; else { - if($this->customHeaders[$headerName]) $this->customHeaders[$headerName] .= ", "; - $this->customHeaders[$headerName] .= $headerValue; + if(isset($this->customHeaders[$headerName])) $this->customHeaders[$headerName] .= ", " . $headerValue; + else $this->customHeaders[$headerName] = $headerValue; } } @@ -746,6 +746,8 @@ class Email_BounceRecord extends DataObject { static $defaults = array(); + static $singular_name = 'Email Bounce Record'; + /** * a record of Email_BounceRecord can't be created manually. Instead, it should be diff --git a/forms/ComplexTableField.php b/forms/ComplexTableField.php index c0fcf12e4..0242b6d4e 100755 --- a/forms/ComplexTableField.php +++ b/forms/ComplexTableField.php @@ -40,7 +40,7 @@ class ComplexTableField extends TableListField { protected $detailFormFields; - protected $viewAction, $sourceJoin, $sourceItems, $unpagedSourceItems; + protected $viewAction, $sourceJoin, $sourceItems; /** * @var Controller @@ -825,9 +825,7 @@ class ComplexTableField_ItemRequest extends RequestHandler { if(!isset($_REQUEST['ctf']['start']) || !is_numeric($_REQUEST['ctf']['start']) || $_REQUEST['ctf']['start'] == 0) { return null; } - - // We never use $item afterwards in the function, where we have it here? disable it! - //$item = $this->unpagedSourceItems->First(); + $start = 0; return Controller::join_links($this->Link(), "$this->methodName?ctf[start]={$start}"); } @@ -837,8 +835,6 @@ class ComplexTableField_ItemRequest extends RequestHandler { return null; } - // We never use $item afterwards in the function, where we have it here? disable it! - // $item = $this->unpagedSourceItems->Last(); $start = $this->totalCount - 1; return Controller::join_links($this->Link(), "$this->methodName?ctf[start]={$start}"); } @@ -848,9 +844,6 @@ class ComplexTableField_ItemRequest extends RequestHandler { return null; } - // We never use $item afterwards in the function, where we have it here? disable it! - //$item = $this->unpagedSourceItems->getIterator()->getOffset($_REQUEST['ctf']['start'] + 1); - $start = $_REQUEST['ctf']['start'] + 1; return Controller::join_links($this->Link(), "$this->methodName?ctf[start]={$start}"); } @@ -860,9 +853,6 @@ class ComplexTableField_ItemRequest extends RequestHandler { return null; } - // We never use $item afterwards in the function, where we have it here? disable it! - //$item = $this->unpagedSourceItems->getIterator()->getOffset($_REQUEST['ctf']['start'] - 1); - $start = $_REQUEST['ctf']['start'] - 1; return Controller::join_links($this->Link(), "$this->methodName?ctf[start]={$start}"); } @@ -887,7 +877,6 @@ class ComplexTableField_ItemRequest extends RequestHandler { } for($i = $offset;$i <= $offset + $this->pageSize && $i <= $this->totalCount;$i++) { $start = $i - 1; - $item = $this->unpagedSourceItems->getIterator()->getOffset($i-1); $links['link'] = Controller::join_links($this->Link() . "$this->methodName?ctf[start]={$start}"); $links['number'] = $i; $links['active'] = $i == $currentItem ? false : true; diff --git a/forms/HtmlEditorField.php b/forms/HtmlEditorField.php index daef011d2..1c2f0fd85 100755 --- a/forms/HtmlEditorField.php +++ b/forms/HtmlEditorField.php @@ -54,6 +54,8 @@ class HtmlEditorField extends TextareaField { } else if($link[0] == '/') { $broken = true; } else if(ereg('^assets/',$link)) { + $link = str_replace(array('%20', '%5C', '%27'), array(' ', '\\', '\''), $link); + $link = Convert::raw2sql($link); if(!DataObject::get_one("File", "\"Filename\" = '$link'", false)) { $broken = true; } diff --git a/forms/RequiredFields.php b/forms/RequiredFields.php index e4500e8fa..f87acbc45 100755 --- a/forms/RequiredFields.php +++ b/forms/RequiredFields.php @@ -54,13 +54,14 @@ class RequiredFields extends Validator{ function javascript() { $js = ""; $fields = $this->form->Fields(); - - foreach($this->form->Fields()->dataFields() as $field) { - //if the field type has some special specific specification for validation of itself - $validationFunc = $field->jsValidation(); - if($validationFunc) $js .= $validationFunc . "\n"; + $dataFields = $this->form->Fields()->dataFields(); + if($dataFields) { + foreach($dataFields as $field) { + // if the field type has some special specific specification for validation of itself + $validationFunc = $field->jsValidation(); + if($validationFunc) $js .= $validationFunc . "\n"; + } } - $useLabels = $this->useLabels ? 'true' : 'false'; if($this->required) { diff --git a/javascript/RelationComplexTableField.js b/javascript/RelationComplexTableField.js index 78c3bcc6d..e58bdc968 100644 --- a/javascript/RelationComplexTableField.js +++ b/javascript/RelationComplexTableField.js @@ -1,7 +1,4 @@ -var checkedListNameArray = null; -var checkedListEndName = 'CheckedList'; -var checkedListField = 'selected'; -var checkedArray = null; + Event.observe( window, 'load', function() { if($('sitetree')){ @@ -15,9 +12,12 @@ Event.observe( window, 'load', function() { } ); RelationComplexTableField = Class.create(); -RelationComplexTableField.prototype = { - +RelationComplexTableField.prototype = { initialize: function() { + var checkedListNameArray = null; + var checkedListEndName = 'CheckedList'; + var checkedListField = 'selected'; + var checkedArray = null; // 1) Find The Hidden Field Where The IDs Will Be Stored diff --git a/javascript/core/jquery.ondemand.js b/javascript/core/jquery.ondemand.js index d946d3d62..1f7de99e9 100644 --- a/javascript/core/jquery.ondemand.js +++ b/javascript/core/jquery.ondemand.js @@ -173,7 +173,7 @@ processOnDemandHeaders(xml, _ondemandComplete); } - _originalAjax(s); + return _originalAjax(s); } })(jQuery); diff --git a/search/SearchContext.php b/search/SearchContext.php index 4135b082d..17fb2c3bc 100644 --- a/search/SearchContext.php +++ b/search/SearchContext.php @@ -105,16 +105,12 @@ class SearchContext extends Object { public function getQuery($searchParams, $sort = false, $limit = false, $existingQuery = null) { $model = singleton($this->modelClass); - $fields = $this->applyBaseTableFields($model); - if($existingQuery) { $query = $existingQuery; } else { $query = $model->buildSQL(); } - $query->select = array_merge($query->select,$fields); - $SQL_limit = Convert::raw2sql($limit); $query->limit($SQL_limit); diff --git a/security/Member.php b/security/Member.php index 8484ee65c..3ef8ea144 100644 --- a/security/Member.php +++ b/security/Member.php @@ -64,9 +64,9 @@ class Member extends DataObject { ); static $summary_fields = array( - 'FirstName', - 'Surname', - 'Email', + 'FirstName' => 'First Name', + 'Surname' => 'Last Name', + 'Email' => 'Email', ); /** @@ -453,7 +453,6 @@ class Member extends DataObject { */ function onBeforeWrite() { if($this->SetPassword) $this->Password = $this->SetPassword; - $identifierField = self::$unique_identifier_field; if($this->$identifierField) { $idClause = ($this->ID) ? " AND \"Member\".\"ID\" <> $this->ID" : ''; @@ -471,6 +470,7 @@ class Member extends DataObject { foreach($existingRecord->getAllFields() as $k => $v) { if(!isset($this->changed[$k]) || !$this->changed[$k]) $this->record[$k] = $v; } + $existingRecord->destroy(); } } diff --git a/security/Security.php b/security/Security.php index 9f67f8436..b0d4f1f36 100644 --- a/security/Security.php +++ b/security/Security.php @@ -273,6 +273,18 @@ class Security extends Controller { * @return string Returns the "login" page as HTML code. */ public function login() { + // Event handler for pre-login, with an option to let it break you out of the login form + $eventResults = $this->extend('onBeforeSecurityLogin'); + // If there was a redirection, return + if(Director::redirected_to()) return; + // If there was an HTTPResponse object returned, then return that + else if($eventResults) { + foreach($eventResults as $result) { + if($result instanceof HTTPResponse) return $result; + } + } + + $customCSS = project() . '/css/tabs.css'; if(Director::fileExists($customCSS)) { Requirements::css($customCSS); diff --git a/templates/RSSFeed.ss b/templates/RSSFeed.ss index c95af9330..dab956a9e 100755 --- a/templates/RSSFeed.ss +++ b/templates/RSSFeed.ss @@ -1,9 +1,10 @@ - + $Title $Link - <% if Description %>$Description.XML<% end_if %> + + $Description.XML <% control Entries %> @@ -12,10 +13,10 @@ <% if Description %>$Description.AbsoluteLinks.EscapeXML<% end_if %> <% if Date %>$Date.Rfc822 <% else %>$Created.Rfc822<% end_if %> - <% if Author %>$Author.XML<% end_if %> + <% if Author %>$Author.XML<% end_if %> $AbsoluteLink <% end_control %> - + \ No newline at end of file diff --git a/tests/DataObjectTest.php b/tests/DataObjectTest.php index 5b435cb91..a7daa02a6 100644 --- a/tests/DataObjectTest.php +++ b/tests/DataObjectTest.php @@ -5,7 +5,7 @@ */ class DataObjectTest extends SapphireTest { static $fixture_file = 'sapphire/tests/DataObjectTest.yml'; - + /** * Test deletion of DataObjects * - Deleting using delete() on the DataObject @@ -479,29 +479,20 @@ class DataObjectTest extends SapphireTest { $reloadedTeam1 = $this->objFromFixture('DataObjectTest_Team', 'team1'); $this->assertEquals('New and improved team 1', $reloadedTeam1->Title); } - - public function testDataObjectValidation() { + + public function testWritingInvalidDataObjectThrowsException() { + $validatedObject = new DataObjectTest_ValidatedObject(); + + $this->setExpectedException('ValidationException'); + $validatedObject->write(); + } + + public function testWritingValidDataObjectDoesntThrowException() { $validatedObject = new DataObjectTest_ValidatedObject(); - - try { - $validatedObject->write(); - - // If write doesn't throw an exception, this line is executed and the test fails. - $this->assertTrue(false, "Validated object did not throw a ValidationException when saving with DataObject::write"); - - } catch (ValidationException $validationException) { - // ValidationException wraps a ValidationResult. This result should be invalid - $this->assertFalse($validationException->getResult()->valid(), "ValidationException thrown by DataObject::write contains a valid ValidationResult. The result should be invalid."); - } - $validatedObject->Name = "Mr. Jones"; - try { - $validatedObject->write(); - $this->assertTrue($validatedObject->isInDB(), "Validated object was not saved to database"); - } catch (Exception $exception) { - $this->assertTrue(false, "Validated object threw an unexpected exception of type " . get_class($exception) . " from DataObject::write: " . $exception->getMessage()); - } + $validatedObject->write(); + $this->assertTrue($validatedObject->isInDB(), "Validated object was not saved to database"); } public function testSubclassCreation() {