diff --git a/dev/SapphireTest.php b/dev/SapphireTest.php index b91286929..9c80ad2ba 100644 --- a/dev/SapphireTest.php +++ b/dev/SapphireTest.php @@ -47,7 +47,7 @@ class SapphireTest extends PHPUnit_Framework_TestCase { * @deprecated since version 4.0 */ protected $originalMailer; - + protected $originalMemberPasswordValidator; protected $originalRequirements; protected $originalIsRunningTest; @@ -191,9 +191,9 @@ class SapphireTest extends PHPUnit_Framework_TestCase { self::$is_running_test = true; // i18n needs to be set to the defaults or tests fail - i18n::set_locale(i18n::default_locale()); - i18n::config()->date_format = null; - i18n::config()->time_format = null; + i18n::set_locale(i18n::config()->default_locale); + i18n::config()->date_format = 'yyyy-MM-dd'; + i18n::config()->time_format = 'H:mm'; // Set default timezone consistently to avoid NZ-specific dependencies date_default_timezone_set('UTC'); @@ -217,7 +217,7 @@ class SapphireTest extends PHPUnit_Framework_TestCase { Config::inst()->update('Director', 'rules', array( '$Controller//$Action/$ID/$OtherID' => '*' )); - + $fixtureFile = static::get_fixture_file(); $prefix = defined('SS_DATABASE_PREFIX') ? SS_DATABASE_PREFIX : 'ss_'; @@ -367,7 +367,7 @@ class SapphireTest extends PHPUnit_Framework_TestCase { } } } - + //unnest injector / config now that the test suite is over // this will reset all the extensions on the object too (see setUpOnce) Injector::unnest(); @@ -719,22 +719,22 @@ class SapphireTest extends PHPUnit_Framework_TestCase { . var_export($match, true) . ": " . var_export($item, true) ); } - } + } /** * Removes sequences of repeated whitespace characters from SQL queries * making them suitable for string comparison - * + * * @param string $sql * @return string The cleaned and normalised SQL string */ protected function normaliseSQL($sql) { return trim(preg_replace('/\s+/m', ' ', $sql)); } - + /** * Asserts that two SQL queries are equivalent - * + * * @param string $expectedSQL * @param string $actualSQL * @param string $message @@ -749,7 +749,7 @@ class SapphireTest extends PHPUnit_Framework_TestCase { // Normalise SQL queries to remove patterns of repeating whitespace $expectedSQL = $this->normaliseSQL($expectedSQL); $actualSQL = $this->normaliseSQL($actualSQL); - + $this->assertEquals($expectedSQL, $actualSQL, $message, $delta, $maxDepth, $canonicalize, $ignoreCase); } @@ -813,7 +813,7 @@ class SapphireTest extends PHPUnit_Framework_TestCase { public static function using_temp_db() { $dbConn = DB::get_conn(); $prefix = defined('SS_DATABASE_PREFIX') ? SS_DATABASE_PREFIX : 'ss_'; - return $dbConn && (substr($dbConn->getSelectedDatabase(), 0, strlen($prefix) + 5) + return $dbConn && (substr($dbConn->getSelectedDatabase(), 0, strlen($prefix) + 5) == strtolower(sprintf('%stmpdb', $prefix))); } @@ -919,7 +919,7 @@ class SapphireTest extends PHPUnit_Framework_TestCase { if(!($SNG instanceof TestOnly)) $SNG->requireTable(); } } - + // If we have additional dataobjects which need schema, do so here: if($extraDataObjects) { foreach($extraDataObjects as $dataClass) { @@ -997,7 +997,7 @@ class SapphireTest extends PHPUnit_Framework_TestCase { // Remove all the test themes we created SS_TemplateLoader::instance()->popManifest(); - + Config::unnest(); if ($e) throw $e; diff --git a/forms/FieldList.php b/forms/FieldList.php index 68a1f9922..8af71a384 100644 --- a/forms/FieldList.php +++ b/forms/FieldList.php @@ -47,14 +47,23 @@ class FieldList extends ArrayList { /** * Return a sequential set of all fields that have data. This excludes wrapper composite fields * as well as heading / help text fields. + * + * @return array */ public function dataFields() { - if(!$this->sequentialSet) $this->collateDataFields($this->sequentialSet); + if(!$this->sequentialSet) { + $this->collateDataFields($this->sequentialSet); + } return $this->sequentialSet; } + /** + * @return array + */ public function saveableFields() { - if(!$this->sequentialSaveableSet) $this->collateDataFields($this->sequentialSaveableSet, true); + if(!$this->sequentialSaveableSet) { + $this->collateDataFields($this->sequentialSaveableSet, true); + } return $this->sequentialSaveableSet; } @@ -64,13 +73,20 @@ class FieldList extends ArrayList { } protected function collateDataFields(&$list, $saveableOnly = false) { + // Initialise list + if (!isset($list)) { + $list = array(); + } + /** @var FormField $field */ foreach($this as $field) { - if($field->isComposite()) $field->collateDataFields($list, $saveableOnly); + if($field->isComposite()) { + $field->collateDataFields($list, $saveableOnly); + } if($saveableOnly) { - $isIncluded = ($field->hasData() && !$field->isReadonly() && !$field->isDisabled()); + $isIncluded = $field->canSubmitValue(); } else { - $isIncluded = ($field->hasData()); + $isIncluded = $field->hasData(); } if($isIncluded) { $name = $field->getName(); diff --git a/forms/Form.php b/forms/Form.php index b40c36333..9d4385fba 100644 --- a/forms/Form.php +++ b/forms/Form.php @@ -355,18 +355,8 @@ class Form extends RequestHandler { $vars = $request->requestVars(); } - // construct an array of allowed fields that can be populated from request data. - // readonly or disabled fields should not be loading data from requests - $allowedFields = array(); - $dataFields = $this->Fields()->dataFields(); - if ($dataFields) { - /** @var FormField $field */ - foreach ($this->Fields()->dataFields() as $name => $field) { - if (!$field->isReadonly() && !$field->isDisabled()) { - $allowedFields[] = $name; - } - } - } + // Ensure we only process saveable fields (non structural, readonly, or disabled) + $allowedFields = array_keys($this->Fields()->saveableFields()); // Populate the form $this->loadDataFrom($vars, true, $allowedFields); @@ -1392,7 +1382,7 @@ class Form extends RequestHandler { * For backwards compatibility reasons, this parameter can also be set to === true, which is the same as passing * CLEAR_MISSING * - * @param FieldList $fieldList An optional list of fields to process. This can be useful when you have a + * @param array $fieldList An optional list of fields to process. This can be useful when you have a * form that has some fields that save to one object, and some that save to another. * @return Form */ @@ -1669,7 +1659,7 @@ class Form extends RequestHandler { /** * Get a list of all actions, including those in the main "fields" FieldList - * + * * @return array */ protected function getAllActions() { diff --git a/forms/FormField.php b/forms/FormField.php index 6e70e80fa..d04991e02 100644 --- a/forms/FormField.php +++ b/forms/FormField.php @@ -1277,4 +1277,13 @@ class FormField extends RequestHandler { return $field; } + /** + * Determine if the value of this formfield accepts front-end submitted values and is saveable. + * + * @return bool + */ + public function canSubmitValue() { + return $this->hasData() && !$this->isReadonly() && !$this->isDisabled(); + } + } diff --git a/forms/HtmlEditorField.php b/forms/HtmlEditorField.php index 725464114..e088b8401 100644 --- a/forms/HtmlEditorField.php +++ b/forms/HtmlEditorField.php @@ -26,14 +26,6 @@ class HtmlEditorField extends TextareaField { */ private static $sanitise_server_side = false; - /** - * @config - * @var array - */ - private static $casting = array( - 'Value' => 'HTMLText', - ); - protected $rows = 30; /** diff --git a/forms/TextareaField.php b/forms/TextareaField.php index 7b9df32a6..b44a4cb35 100644 --- a/forms/TextareaField.php +++ b/forms/TextareaField.php @@ -19,8 +19,13 @@ */ class TextareaField extends FormField { + /** + * Value should be XML + * + * @var array + */ private static $casting = array( - 'Value' => 'HTMLText', + 'Value' => 'HTMLText(array(\'shortcodes\' => false))', ); /** @@ -93,7 +98,9 @@ class TextareaField extends FormField { } /** - * @return string + * Return value with all values encoded in html entities + * + * @return string Raw HTML */ public function Value() { return htmlentities($this->value, ENT_COMPAT, 'UTF-8'); diff --git a/model/fieldtypes/HTMLText.php b/model/fieldtypes/HTMLText.php index 17107e62d..a93be690f 100644 --- a/model/fieldtypes/HTMLText.php +++ b/model/fieldtypes/HTMLText.php @@ -34,6 +34,26 @@ class HTMLText extends Text { protected $processShortcodes = true; + /** + * Check if shortcodes are enabled + * + * @return bool + */ + public function getProcessShortcodes() { + return $this->processShortcodes; + } + + /** + * Set shortcodes on or off by default + * + * @param bool $process + * @return $this + */ + public function setProcessShortcodes($process) { + $this->processShortcodes = (bool)$process; + return $this; + } + protected $whitelist = false; public function __construct($name = null, $options = array()) { diff --git a/tests/forms/TextareaFieldTest.php b/tests/forms/TextareaFieldTest.php index d635574c1..7d52da04d 100644 --- a/tests/forms/TextareaFieldTest.php +++ b/tests/forms/TextareaFieldTest.php @@ -16,7 +16,7 @@ class TextareaFieldTest extends SapphireTest { /** * Quick smoke test to ensure that text with special html chars is being displayed properly in readonly fields. */ - public function testReadonlyDisplaySepcialHTML() { + public function testReadonlyDisplaySpecialHTML() { $inputText = "These are some special chars including 'single' & \"double\" quotations"; $field = new TextareaField("Test", "Test"); $field = $field->performReadonlyTransformation(); @@ -25,4 +25,22 @@ class TextareaFieldTest extends SapphireTest { . ' "double" quotations', $field->Field()); } + public function testValueEntities() { + $inputText = "These are some unicodes: äöü"; + $field = new TextareaField("Test", "Test"); + $field->setValue($inputText); + + // Value should be safe-encoding only, but ValueEntities should be more aggressive + $this->assertEquals( + "These <b>are</b> some unicodes: äöü", + $field->obj('Value')->forTemplate() + ); + + // Shortcodes are disabled + $this->assertEquals( + false, + $field->obj('Value')->getProcessShortcodes() + ); + } + }