From f823831a639c0b0aa6f7c15550dc011832ad601e Mon Sep 17 00:00:00 2001
From: Igor Nadj
Date: Mon, 25 Aug 2014 11:49:38 +1200
Subject: [PATCH 01/77] FIX making minify javascript fail-safe
---
tests/view/SSViewerTest.php | 51 +++++++++++++++++++++++++++++
tests/view/themes/javascript/bad.js | 1 +
view/Requirements.php | 8 ++++-
3 files changed, 59 insertions(+), 1 deletion(-)
create mode 100644 tests/view/themes/javascript/bad.js
diff --git a/tests/view/SSViewerTest.php b/tests/view/SSViewerTest.php
index 474ea1cf6..6fa2b6b2d 100644
--- a/tests/view/SSViewerTest.php
+++ b/tests/view/SSViewerTest.php
@@ -103,6 +103,57 @@ class SSViewerTest extends SapphireTest {
<% require css($cssFile) %>");
$this->assertFalse((bool)trim($template), "Should be no content in this return.");
}
+
+ public function testRequirementsCombine(){
+ $oldBackend = Requirements::backend();
+ $testBackend = new Requirements_Backend();
+ Requirements::set_backend($testBackend);
+ $combinedTestFilePath = BASE_PATH . '/' . $testBackend->getCombinedFilesFolder() . '/testRequirementsCombine.js';
+
+ $jsFile = FRAMEWORK_DIR . '/tests/view/themes/javascript/bad.js';
+ $jsFileContents = file_get_contents(BASE_PATH . '/' . $jsFile);
+ Requirements::combine_files('testRequirementsCombine.js', array($jsFile));
+ require_once('thirdparty/jsmin/jsmin.php');
+
+ // first make sure that our test js file causes an exception to be thrown
+ try{
+ $content = JSMin::minify($content);
+ $this->fail('JSMin did not throw exception on minify bad file: ');
+ Requirements::set_backend($oldBackend);
+ return;
+ }catch(Exception $e){
+ // exception thrown... good
+ }
+
+ // secondly, make sure that requirements combine can handle this and continue safely
+ @unlink($combinedTestFilePath);
+ try{
+ /*
+ * Use @ (ignore warning) because a warning would cause php unit to throw an exception and therefore change the execution
+ * process and mess up the next test.
+ */
+ @Requirements::process_combined_files();
+ }catch(Exception $e){
+ $this->fail('Requirements::process_combined_files did not catch exception caused by minifying bad js file: '.$e);
+ Requirements::set_backend($oldBackend);
+ return;
+ }
+
+ // and make sure the combined content matches the input content, i.e. no loss of functionality
+ if(!file_exists($combinedTestFilePath)){
+ $this->fail('No combined file was created at expected path: '.$combinedTestFilePath);
+ Requirements::set_backend($oldBackend);
+ return;
+ }
+ $combinedTestFileContents = file_get_contents($combinedTestFilePath);
+ $this->assertContains($jsFileContents, $combinedTestFileContents);
+
+
+ // reset
+ Requirements::set_backend($oldBackend);
+ }
+
+
public function testComments() {
$output = $this->render(<<blocked) as $file) {
$fileContent = file_get_contents($base . $file);
- $fileContent = $this->minifyFile($file, $fileContent);
+
+ try{
+ $fileContent = $this->minifyFile($file, $fileContent);
+ }catch(Exception $e){
+ // failed to minify, use unminified
+ user_error('Failed to minify '.$file.', exception: '.$e->getMessage(), E_USER_WARNING);
+ }
if ($this->write_header_comment) {
// write a header comment for each file for easier identification and debugging
From 657606e8c8a470139d1d997722fcd5cb3591d274 Mon Sep 17 00:00:00 2001
From: Igor Nadj
Date: Wed, 26 Nov 2014 15:27:54 +1300
Subject: [PATCH 02/77] Updating code to allow unit test to use try-catch block
to catch warning without stopping code execution inside try
---
tests/view/SSViewerTest.php | 17 +++++++++--------
view/Requirements.php | 10 ++++++++--
2 files changed, 17 insertions(+), 10 deletions(-)
diff --git a/tests/view/SSViewerTest.php b/tests/view/SSViewerTest.php
index 6fa2b6b2d..6fa92b795 100644
--- a/tests/view/SSViewerTest.php
+++ b/tests/view/SSViewerTest.php
@@ -125,20 +125,22 @@ class SSViewerTest extends SapphireTest {
// exception thrown... good
}
- // secondly, make sure that requirements combine can handle this and continue safely
+ // secondly, make sure that requirements combine throws the correct warning, and only that warning
@unlink($combinedTestFilePath);
try{
- /*
- * Use @ (ignore warning) because a warning would cause php unit to throw an exception and therefore change the execution
- * process and mess up the next test.
- */
- @Requirements::process_combined_files();
+ Requirements::process_combined_files();
+ }catch(PHPUnit_Framework_Error_Warning $e){
+ if(strstr($e->getMessage(), 'Failed to minify') === false){
+ $this->fail('Requirements::process_combined_files raised a warning, which is good, but this is not the expected warning ("Failed to minify..."): '.$e);
+ Requirements::set_backend($oldBackend);
+ return;
+ }
}catch(Exception $e){
$this->fail('Requirements::process_combined_files did not catch exception caused by minifying bad js file: '.$e);
Requirements::set_backend($oldBackend);
return;
}
-
+
// and make sure the combined content matches the input content, i.e. no loss of functionality
if(!file_exists($combinedTestFilePath)){
$this->fail('No combined file was created at expected path: '.$combinedTestFilePath);
@@ -147,7 +149,6 @@ class SSViewerTest extends SapphireTest {
}
$combinedTestFileContents = file_get_contents($combinedTestFilePath);
$this->assertContains($jsFileContents, $combinedTestFileContents);
-
// reset
Requirements::set_backend($oldBackend);
diff --git a/view/Requirements.php b/view/Requirements.php
index 8952edf0a..a607eb88e 100644
--- a/view/Requirements.php
+++ b/view/Requirements.php
@@ -1129,6 +1129,7 @@ class Requirements_Backend {
if(!$refresh) continue;
+ $failedToMinify = false;
$combinedData = "";
foreach(array_diff($fileList, $this->blocked) as $file) {
$fileContent = file_get_contents($base . $file);
@@ -1136,8 +1137,7 @@ class Requirements_Backend {
try{
$fileContent = $this->minifyFile($file, $fileContent);
}catch(Exception $e){
- // failed to minify, use unminified
- user_error('Failed to minify '.$file.', exception: '.$e->getMessage(), E_USER_WARNING);
+ $failedToMinify = true;
}
if ($this->write_header_comment) {
@@ -1156,6 +1156,12 @@ class Requirements_Backend {
fclose($fh);
unset($fh);
}
+
+ if($failedToMinify){
+ // Failed to minify, use unminified. This warning is raised at the end to allow code execution
+ // to complete in case this warning is caught inside a try-catch block.
+ user_error('Failed to minify '.$file.', exception: '.$e->getMessage(), E_USER_WARNING);
+ }
// Unsuccessful write - just include the regular JS files, rather than the combined one
if(!$successfulWrite) {
From 77e30d4524810948db262ca674f431338523a180 Mon Sep 17 00:00:00 2001
From: Igor Nadj
Date: Wed, 26 Nov 2014 15:31:07 +1300
Subject: [PATCH 03/77] Cleanup, removing redundant returns
---
tests/view/SSViewerTest.php | 14 +++++---------
1 file changed, 5 insertions(+), 9 deletions(-)
diff --git a/tests/view/SSViewerTest.php b/tests/view/SSViewerTest.php
index 6fa92b795..7511af1ca 100644
--- a/tests/view/SSViewerTest.php
+++ b/tests/view/SSViewerTest.php
@@ -114,13 +114,12 @@ class SSViewerTest extends SapphireTest {
$jsFileContents = file_get_contents(BASE_PATH . '/' . $jsFile);
Requirements::combine_files('testRequirementsCombine.js', array($jsFile));
require_once('thirdparty/jsmin/jsmin.php');
-
+
// first make sure that our test js file causes an exception to be thrown
try{
$content = JSMin::minify($content);
- $this->fail('JSMin did not throw exception on minify bad file: ');
Requirements::set_backend($oldBackend);
- return;
+ $this->fail('JSMin did not throw exception on minify bad file: ');
}catch(Exception $e){
// exception thrown... good
}
@@ -131,21 +130,18 @@ class SSViewerTest extends SapphireTest {
Requirements::process_combined_files();
}catch(PHPUnit_Framework_Error_Warning $e){
if(strstr($e->getMessage(), 'Failed to minify') === false){
- $this->fail('Requirements::process_combined_files raised a warning, which is good, but this is not the expected warning ("Failed to minify..."): '.$e);
Requirements::set_backend($oldBackend);
- return;
+ $this->fail('Requirements::process_combined_files raised a warning, which is good, but this is not the expected warning ("Failed to minify..."): '.$e);
}
}catch(Exception $e){
- $this->fail('Requirements::process_combined_files did not catch exception caused by minifying bad js file: '.$e);
Requirements::set_backend($oldBackend);
- return;
+ $this->fail('Requirements::process_combined_files did not catch exception caused by minifying bad js file: '.$e);
}
// and make sure the combined content matches the input content, i.e. no loss of functionality
if(!file_exists($combinedTestFilePath)){
- $this->fail('No combined file was created at expected path: '.$combinedTestFilePath);
Requirements::set_backend($oldBackend);
- return;
+ $this->fail('No combined file was created at expected path: '.$combinedTestFilePath);
}
$combinedTestFileContents = file_get_contents($combinedTestFilePath);
$this->assertContains($jsFileContents, $combinedTestFileContents);
From 6c6d2172737517a634f1740aa0167f6a8f798d32 Mon Sep 17 00:00:00 2001
From: Antony Thorpe
Date: Wed, 3 Dec 2014 16:56:53 +1300
Subject: [PATCH 04/77] Update error-handling.md
Add how to log notices (deprecation notifications can help with discovering problems caused by old code).
---
docs/en/topics/error-handling.md | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/docs/en/topics/error-handling.md b/docs/en/topics/error-handling.md
index c40650521..88ab7c975 100644
--- a/docs/en/topics/error-handling.md
+++ b/docs/en/topics/error-handling.md
@@ -58,9 +58,11 @@ added.
:::php
// log errors and warnings
- SS_Log::add_writer(new SS_LogFileWriter('/my/logfile/path'), SS_Log::WARN, '<=');
+ SS_Log::add_writer(new SS_LogFileWriter('../silverstripe-errors-warnings.log'), SS_Log::WARN, '<=');
// or just errors
- SS_Log::add_writer(new SS_LogFileWriter('/my/logfile/path'), SS_Log::ERR);
+ SS_Log::add_writer(new SS_LogFileWriter('../silverstripe-errors.log'), SS_Log::ERR);
+ // or notices (e.g. for Deprecation Notifications)
+ SS_Log::add_writer(new SS_LogFileWriter('../silverstripe-errors-notices.log'), SS_Log::NOTICE);
### From PHP
@@ -84,4 +86,4 @@ You can send both fatal errors and warnings in your code to a specified email-ad
// log errors and warnings
SS_Log::add_writer(new SS_LogEmailWriter('admin@domain.com'), SS_Log::WARN, '<=');
// or just errors
- SS_Log::add_writer(new SS_LogEmailWriter('admin@domain.com'), SS_Log::ERR);
\ No newline at end of file
+ SS_Log::add_writer(new SS_LogEmailWriter('admin@domain.com'), SS_Log::ERR);
From ab24ed3bea46c0d3c0a7b770236816753fcca97b Mon Sep 17 00:00:00 2001
From: "Elvinas L."
Date: Tue, 13 Jan 2015 15:31:17 +0200
Subject: [PATCH 05/77] FIX. Use i18n_plural_name() instead of plural_name()
---
admin/code/SecurityAdmin.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/admin/code/SecurityAdmin.php b/admin/code/SecurityAdmin.php
index 2e71de0bc..85c96ccf3 100755
--- a/admin/code/SecurityAdmin.php
+++ b/admin/code/SecurityAdmin.php
@@ -281,7 +281,7 @@ class SecurityAdmin extends LeftAndMain implements PermissionProvider {
$firstCrumb = $crumbs->shift();
if($params['FieldName'] == 'Groups') {
$crumbs->unshift(new ArrayData(array(
- 'Title' => singleton('Group')->plural_name(),
+ 'Title' => singleton('Group')->i18n_plural_name(),
'Link' => $this->Link('groups')
)));
} elseif($params['FieldName'] == 'Users') {
From d28edd09ce9223ede8d7bd30a981b972ce143df7 Mon Sep 17 00:00:00 2001
From: ProzacJellybeans
Date: Wed, 14 Jan 2015 15:34:20 +1300
Subject: [PATCH 06/77] Extending site - RSS correction
Instructions needed to be given on flushing more frequently, not just on template editing
---
docs/en/01_Tutorials/02_Extending_A_Basic_Site.md | 3 +++
1 file changed, 3 insertions(+)
diff --git a/docs/en/01_Tutorials/02_Extending_A_Basic_Site.md b/docs/en/01_Tutorials/02_Extending_A_Basic_Site.md
index 2eb6faaef..d7f9fefef 100644
--- a/docs/en/01_Tutorials/02_Extending_A_Basic_Site.md
+++ b/docs/en/01_Tutorials/02_Extending_A_Basic_Site.md
@@ -409,6 +409,9 @@ An RSS feed is something that no news section should be without. SilverStripe ma
}
+Ensure that when you have input the code to implement an RSS feed; flush the webpage afterwards
+(add ?flush=all on the end of your URL)
+
This function creates an RSS feed of all the news articles, and outputs it to the browser. If we go to [http://localhost/your_site_name/news/rss](http://localhost/your_site_name/news/rss) we should see our RSS feed. When there is more to a URL after a page's base URL, "rss" in this case, SilverStripe will call the function with that name on the controller if it exists.
Depending on your browser, you should see something like the picture below. If your browser doesn't support RSS, you will most likely see the XML output instead. For more on RSS, see `[api:RSSFeed]`
From 32ce85d9f4590ce56ee3a7979407acd3d23e8263 Mon Sep 17 00:00:00 2001
From: "Elvinas L."
Date: Thu, 15 Jan 2015 15:09:32 +0200
Subject: [PATCH 07/77] FIX. Summary fields can't be translated
fieldLabels() now can find these fields and translate them.
---
security/Member.php | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/security/Member.php b/security/Member.php
index fbe04dc8e..886cf783e 100644
--- a/security/Member.php
+++ b/security/Member.php
@@ -99,9 +99,9 @@ class Member extends DataObject implements TemplateGlobalProvider {
);
private static $summary_fields = array(
- 'FirstName' => 'First Name',
- 'Surname' => 'Last Name',
- 'Email' => 'Email',
+ 'FirstName',
+ 'Surname',
+ 'Email',
);
/**
From 8b1aa5f1d72dc9a6630601ac5f58b34b43def71c Mon Sep 17 00:00:00 2001
From: ProzacJellybeans
Date: Fri, 16 Jan 2015 11:45:44 +1300
Subject: [PATCH 08/77] Extending site - RSS correction
Rewrote the reason as to why the website needs to be flushed more frequently
---
docs/en/01_Tutorials/02_Extending_A_Basic_Site.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/docs/en/01_Tutorials/02_Extending_A_Basic_Site.md b/docs/en/01_Tutorials/02_Extending_A_Basic_Site.md
index d7f9fefef..3f78a8eee 100644
--- a/docs/en/01_Tutorials/02_Extending_A_Basic_Site.md
+++ b/docs/en/01_Tutorials/02_Extending_A_Basic_Site.md
@@ -246,7 +246,7 @@ page layout.
### ArticlePage Template
First, the template for displaying a single article:
-**themes/simple/templates/Layout/ArticlePage.ss**
+**themes/simple/templates/Layout/ArticlePage.ss**
:::ss
@@ -410,7 +410,7 @@ An RSS feed is something that no news section should be without. SilverStripe ma
Ensure that when you have input the code to implement an RSS feed; flush the webpage afterwards
-(add ?flush=all on the end of your URL)
+(add ?flush=all on the end of your URL). This is because allowed_actions has changed.
This function creates an RSS feed of all the news articles, and outputs it to the browser. If we go to [http://localhost/your_site_name/news/rss](http://localhost/your_site_name/news/rss) we should see our RSS feed. When there is more to a URL after a page's base URL, "rss" in this case, SilverStripe will call the function with that name on the controller if it exists.
From 77ebdc22fadc0d4b0daa887068c9b719f8ec617f Mon Sep 17 00:00:00 2001
From: Loz Calver
Date: Mon, 19 Jan 2015 20:38:08 +0000
Subject: [PATCH 09/77] FIX: DataObject::db returned fields in incorrect order,
with incorrect data types
fixes #3802
---
model/DataObject.php | 9 +++++++--
tests/model/DataObjectTest.php | 10 ++++++++++
2 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/model/DataObject.php b/model/DataObject.php
index 0bd7b19dd..4a666c91c 100644
--- a/model/DataObject.php
+++ b/model/DataObject.php
@@ -1666,9 +1666,14 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
*/
public function db($fieldName = null) {
$classes = ClassInfo::ancestry($this, true);
- $items = array();
- foreach(array_reverse($classes) as $class) {
+ // If we're looking for a specific field, we want to hit subclasses first as they may override field types
+ if($fieldName) {
+ $classes = array_reverse($classes);
+ }
+
+ $items = array();
+ foreach($classes as $class) {
if(isset(self::$_cache_db[$class])) {
$dbItems = self::$_cache_db[$class];
} else {
diff --git a/tests/model/DataObjectTest.php b/tests/model/DataObjectTest.php
index 275e643d6..8daffecce 100644
--- a/tests/model/DataObjectTest.php
+++ b/tests/model/DataObjectTest.php
@@ -38,9 +38,19 @@ class DataObjectTest extends SapphireTest {
$this->assertEquals('Text', $obj->db('Comment'));
$obj = new DataObjectTest_ExtendedTeamComment();
+ $dbFields = $obj->db();
// Assert overloaded fields have correct data type
$this->assertEquals('HTMLText', $obj->db('Comment'));
+ $this->assertEquals('HTMLText', $dbFields['Comment'],
+ 'Calls to DataObject::db without a field specified return correct data types');
+
+ // assertEquals doesn't verify the order of array elements, so access keys manually to check order:
+ // expected: array('Name' => 'Varchar', 'Comment' => 'HTMLText')
+ reset($dbFields);
+ $this->assertEquals('Name', key($dbFields), 'DataObject::db returns fields in correct order');
+ next($dbFields);
+ $this->assertEquals('Comment', key($dbFields), 'DataObject::db returns fields in correct order');
}
public function testValidObjectsForBaseFields() {
From 12621153592ab14abdc54c420098a66d0ea09331 Mon Sep 17 00:00:00 2001
From: Corey Sewell
Date: Tue, 20 Jan 2015 13:21:12 +1300
Subject: [PATCH 10/77] Fix #3794
Fix #3794
---
dev/install/install.php5 | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dev/install/install.php5 b/dev/install/install.php5
index d57431947..8b77230b5 100755
--- a/dev/install/install.php5
+++ b/dev/install/install.php5
@@ -1494,7 +1494,7 @@ HTML;
if($base != '.') $baseClause = "RewriteBase '$base'\n";
else $baseClause = "";
- if(strpos(strtolower(php_sapi_name()), "cgi") !== false) $cgiClause = "RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]\n";
+ if(strpos(strtolower(php_sapi_name()), "cgi") !== false) $cgiClause = "RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]\n";
else $cgiClause = "";
$modulePath = FRAMEWORK_NAME;
$rewrite = <<
Date: Tue, 20 Jan 2015 14:23:53 +0000
Subject: [PATCH 11/77] Update 01_Image.md
Ive added this to show you can change the color of the padding area
---
docs/en/02_Developer_Guides/14_Files/01_Image.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/en/02_Developer_Guides/14_Files/01_Image.md b/docs/en/02_Developer_Guides/14_Files/01_Image.md
index 682183362..bd3b4537a 100644
--- a/docs/en/02_Developer_Guides/14_Files/01_Image.md
+++ b/docs/en/02_Developer_Guides/14_Files/01_Image.md
@@ -97,7 +97,7 @@ For output of an image tag with the image automatically resized to 80px width, y
$Image.SetSize(80,80) // returns a 80x80px padded image
$Image.SetRatioSize(80,80) // Returns an image scaled proportional, with its greatest diameter scaled to 80px
$Image.CroppedImage(80,80) // Returns an 80x80 image cropped from the center.
- $Image.PaddedImage(80, 80) // Returns an 80x80 image. Unused space is padded white. No crop. No stretching
+ $Image.PaddedImage(80, 80, FFFFFF) // Returns an 80x80 image. Unused space is padded white. No crop. No stretching
$Image.Width // returns width of image
$Image.Height // returns height of image
$Image.Orientation // returns Orientation
From 3de82ce8dc6adc38936838c2537878a8926657f1 Mon Sep 17 00:00:00 2001
From: Cam Findlay
Date: Wed, 21 Jan 2015 15:27:22 +1300
Subject: [PATCH 12/77] DOCS Fixed link to yaml config docs.
---
docs/en/02_Developer_Guides/09_Security/00_Member.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/en/02_Developer_Guides/09_Security/00_Member.md b/docs/en/02_Developer_Guides/09_Security/00_Member.md
index 93e03d334..e30a3112d 100644
--- a/docs/en/02_Developer_Guides/09_Security/00_Member.md
+++ b/docs/en/02_Developer_Guides/09_Security/00_Member.md
@@ -91,7 +91,7 @@ and another subclass for the same email-address in the address-database.
Using inheritance to add extra behaviour or data fields to a member is limiting, because you can only inherit from 1
class. A better way is to use role extensions to add this behaviour. Add the following to your
-`[config.yml](/topics/configuration)`.
+`[config.yml](/developer_guides/configuration/configuration/#configuration-yaml-syntax-and-rules)`.
:::yml
Member:
From 037c3a1847b6470f5a1badd58f114dff10715b5c Mon Sep 17 00:00:00 2001
From: Cam Findlay
Date: Thu, 22 Jan 2015 08:40:33 +1300
Subject: [PATCH 13/77] DOCS Fix missing changelogs
---
docs/en/04_Changelogs/3.0.10.md | 26 ++++++++++
docs/en/04_Changelogs/3.0.11.md | 19 ++++++++
docs/en/04_Changelogs/3.1.3.md | 29 +++++++++++
docs/en/04_Changelogs/3.1.4.md | 46 ++++++++++++++++++
docs/en/04_Changelogs/3.1.5.md | 67 ++++++++++++++++++++++++++
docs/en/04_Changelogs/rc/3.0.10-rc1.md | 25 ++++++++++
docs/en/04_Changelogs/rc/3.0.11-rc1.md | 19 ++++++++
docs/en/04_Changelogs/rc/3.0.9-rc1.md | 12 +++++
docs/en/04_Changelogs/rc/3.1.3-rc1.md | 29 +++++++++++
docs/en/04_Changelogs/rc/3.1.3-rc2.md | 12 +++++
docs/en/04_Changelogs/rc/3.1.4-rc1.md | 44 +++++++++++++++++
docs/en/04_Changelogs/rc/3.1.5-rc1.md | 67 ++++++++++++++++++++++++++
12 files changed, 395 insertions(+)
create mode 100644 docs/en/04_Changelogs/3.0.10.md
create mode 100644 docs/en/04_Changelogs/3.0.11.md
create mode 100644 docs/en/04_Changelogs/3.1.3.md
create mode 100644 docs/en/04_Changelogs/3.1.4.md
create mode 100644 docs/en/04_Changelogs/3.1.5.md
create mode 100644 docs/en/04_Changelogs/rc/3.0.10-rc1.md
create mode 100644 docs/en/04_Changelogs/rc/3.0.11-rc1.md
create mode 100644 docs/en/04_Changelogs/rc/3.0.9-rc1.md
create mode 100644 docs/en/04_Changelogs/rc/3.1.3-rc1.md
create mode 100644 docs/en/04_Changelogs/rc/3.1.3-rc2.md
create mode 100644 docs/en/04_Changelogs/rc/3.1.4-rc1.md
create mode 100644 docs/en/04_Changelogs/rc/3.1.5-rc1.md
diff --git a/docs/en/04_Changelogs/3.0.10.md b/docs/en/04_Changelogs/3.0.10.md
new file mode 100644
index 000000000..8e06089aa
--- /dev/null
+++ b/docs/en/04_Changelogs/3.0.10.md
@@ -0,0 +1,26 @@
+# 3.0.10
+
+## Upgrading
+
+ * If relying on partial caching of content between logged in users, be aware that the cache is now automatically
+ segmented based on both the current member ID, and the versioned reading mode. If this is not an appropriate
+ method (such as if the same content is served to logged in users within partial caching) then it is necessary
+ to adjust the config value of `SSViewer.global_key` to something more or less sensitive.
+
+## Security
+
+ * [BUG Fix issue with versioned dataobjects being cached between stages](https://github.com/silverstripe/silverstripe-framework/commit/4415a75d9304a3930b9c28763fc092299640c685) - See [announcement SS-2014-007](http://www.silverstripe.org/ss-2014-007-confidentiality-breach-can-occur-between-draft-and-live-modes/)
+ * [BUG Fix encoding of JS redirection script](https://github.com/silverstripe/silverstripe-framework/commit/f8e3bbe3ae3f29f22d85abb73cea033659511168) - See [announcement SS-2014-006](http://www.silverstripe.org/ss-2014-006-xss-in-returnurl-redirection/)
+ * [Amends solution to SS-2014-006](https://github.com/silverstripe/silverstripe-framework/commit/5b0a96979484fad12e11ce69aef98feda57b321f)
+ * [FIX Prevent SQLi when no URL filters are applied](https://github.com/silverstripe/silverstripe-cms/commit/114df8a3a5e4800ef7586c5d9c8d79798fd2a11d) - See [announcement SS-2014-004](http://www.silverstripe.org/ss-2014-004-sql-injection-in-sitetree-with-custom-urlsegmentfilter-rules/)
+ * [FIX Do now allow arbitary class creation in CMS](https://github.com/silverstripe/silverstripe-cms/commit/bf9b22fd4331a6f78cec12a75262f570b025ec2d) - See [announcement SS-2014-005](http://www.silverstripe.org/ss-2014-005-arbitrary-class-creation-in-cms-backend/)
+
+## General
+
+ * [Rewrote usages of error suppression operator](https://github.com/silverstripe/silverstripe-framework/commit/6d5d3d8cb7e69e0b37471b1e34077211b0f631fe)
+
+## Changelog
+
+ * [framework](https://github.com/silverstripe/silverstripe-framework/releases/tag/3.0.10)
+ * [cms](https://github.com/silverstripe/silverstripe-cms/releases/tag/3.0.10)
+ * [installer](https://github.com/silverstripe/silverstripe-installer/releases/tag/3.0.10)
diff --git a/docs/en/04_Changelogs/3.0.11.md b/docs/en/04_Changelogs/3.0.11.md
new file mode 100644
index 000000000..71191bd7e
--- /dev/null
+++ b/docs/en/04_Changelogs/3.0.11.md
@@ -0,0 +1,19 @@
+# 3.0.11
+
+Minor security release
+
+## Security
+
+ * 2014-04-16 [9d74bc4](https://github.com/silverstripe/sapphire/commit/9d74bc4) Potential DoS exploit in TinyMCE - See [announcement SS-2014-009](http://www.silverstripe.org/ss-2014-009-potential-dos-exploit-in-tinymce/)
+ * 2014-05-05 [9bfeffd](https://github.com/silverstripe/silverstripe-framework/commit/9bfeffd) Injection / Filesystem vulnerability in generatesecuretoken - See [announcement SS-2014-010](http://www.silverstripe.org/ss-2014-010-injection-filesystem-vulnerability-in-generatesecuretoken/)
+ * 2014-05-07 [0099a18](https://github.com/silverstripe/silverstripe-framework/commit/0099a18) Folder filename injection - See [announcement SS-2014-011](http://www.silverstripe.org/ss-2014-011-folder-filename-injection/)
+
+### Bugfixes
+
+ * 2013-06-20 [f2c4a62](https://github.com/silverstripe/sapphire/commit/f2c4a62) ConfirmedPasswordField used to expose existing hash (Hamish Friedlander)
+
+## Changelog
+
+ * [framework](https://github.com/silverstripe/silverstripe-framework/releases/tag/3.0.11)
+ * [cms](https://github.com/silverstripe/silverstripe-cms/releases/tag/3.0.11)
+ * [installer](https://github.com/silverstripe/silverstripe-installer/releases/tag/3.0.11)
diff --git a/docs/en/04_Changelogs/3.1.3.md b/docs/en/04_Changelogs/3.1.3.md
new file mode 100644
index 000000000..d43eb42fb
--- /dev/null
+++ b/docs/en/04_Changelogs/3.1.3.md
@@ -0,0 +1,29 @@
+# 3.1.3
+
+## Overview
+
+ * Security: Require ADMIN for ?flush=1&isDev=1 ([SS-2014-001](http://www.silverstripe.org/ss-2014-001-require-admin-for-flush1-and-isdev1))
+ * Security: XSS in third party library (SWFUpload) ([SS-2014-002](http://www.silverstripe.org/ss-2014-002-xss-in-third-party-library-swfupload/))
+ * Security: SiteTree.ExtraMeta allows JavaScript for malicious CMS authors ([SS-2014-003](http://www.silverstripe.org/ss-2014-003-extrameta-allows-javascript-for-malicious-cms-authors-/))
+ * Better loading performance when using multiple `UploadField` instances
+ * Option for `force_js_to_bottom` on `Requirements` class (ignoring inline `";
+ $title = Director::isDev()
+ ? "{$urlATT}... (output started on {$file}, line {$line})"
+ : "{$urlATT}...";
+ echo <<Redirecting to {$title}
+
+";
+EOT
+ ;
} else {
$line = $file = null;
if(!headers_sent($file, $line)) {
From 647f921c0826d62af263dad4daf2d5425c12ace1 Mon Sep 17 00:00:00 2001
From: unclecheese
Date: Thu, 5 Feb 2015 16:25:07 +1300
Subject: [PATCH 39/77] MINOR: Add lesson 8
---
docs/en/01_Tutorials/index.md | 1 +
1 file changed, 1 insertion(+)
diff --git a/docs/en/01_Tutorials/index.md b/docs/en/01_Tutorials/index.md
index 0065d7bd2..395174b9b 100644
--- a/docs/en/01_Tutorials/index.md
+++ b/docs/en/01_Tutorials/index.md
@@ -16,6 +16,7 @@ These include video screencasts, written tutorials and code examples to get you
* [Lesson 5: The holder/page pattern](http://www.silverstripe.org/learn/lessons/lesson-5-the-holderpage-pattern/)
* [Lesson 6: Adding Custom Fields to a Page](http://www.silverstripe.org/learn/lessons/lesson-6-adding-custom-fields-to-a-page/)
* [Lesson 7: Working with Files and Images](http://www.silverstripe.org/learn/lessons/lesson-7-working-with-files-and-images/)
+* [Lesson 8: Introduction to the ORM](http://www.silverstripe.org/learn/lessons/lesson-8-introduction-to-the-orm)
## Help: If you get stuck
From 9720b4939d144f865581ae4675884a28fe0486f2 Mon Sep 17 00:00:00 2001
From: Cam Findlay
Date: Fri, 6 Feb 2015 20:37:50 +1300
Subject: [PATCH 40/77] DOCS Fixed link on issues and bugs
---
docs/en/05_Contributing/00_Issues_and_Bugs.md | 26 +++++++++----------
1 file changed, 13 insertions(+), 13 deletions(-)
diff --git a/docs/en/05_Contributing/00_Issues_and_Bugs.md b/docs/en/05_Contributing/00_Issues_and_Bugs.md
index 3ce05e953..a5d45cdf9 100644
--- a/docs/en/05_Contributing/00_Issues_and_Bugs.md
+++ b/docs/en/05_Contributing/00_Issues_and_Bugs.md
@@ -16,11 +16,11 @@ well written bug reports can be half of the solution already!
Before submitting a bug:
- * Ask for assistance on the [forums](http://silverstripe.org/forums), [core mailinglist](http://groups.google.com/group/silverstripe-dev) or on [IRC](http://silverstripe.org/irc) if you're unsure if its really a bug.
+ * Ask for assistance on the [forums](http://www.silverstripe.org/community/forums/), [core mailinglist](http://groups.google.com/group/silverstripe-dev) or on [IRC](http://irc.silverstripe.org/) if you're unsure if its really a bug.
* Search for similar, existing tickets
* Is this a security issue? Please follow our separate reporting guidelines below.
- * Is this a issue with the core framework or cms? Modules have their own issue trackers (see [silverstripe.org/modules](http://www.silverstripe.org/modules))
- * Try to reproduce your issue on a [clean installation](http://doc.silverstripe.org/framework/en/installation/composer#using-development-versions), maybe the bug has already been fixed on an unreleased branch?
+ * Is this a issue with the core framework or cms? Modules have their own issue trackers (see [silverstripe.org/modules](http://www.silverstripe.org/modules/))
+ * Try to reproduce your issue on a [clean installation](/getting_started/composer#using-development-versions), maybe the bug has already been fixed on an unreleased branch?
* The bugtracker is not the place to discuss enhancements, please use the forums or mailinglist.
Only log enhancement tickets if they gather a large interest in the community
and the enhancement is likely to be implemented in the next couple of months.
@@ -30,7 +30,7 @@ If the issue does look like a new bug:
* [Create a new ticket](https://github.com/silverstripe/silverstripe-framework/issues/new)
* Describe the steps required to reproduce your issue, and the expected outcome. Unit tests, screenshots and screencasts can help here.
* Describe your environment as detailed as possible: SilverStripe version, Browser, PHP version, Operating System, any installed SilverStripe modules.
- * *(optional)* [Submit a pull request](/misc/contributing/code) which fixes the issue.
+ * *(optional)* [Submit a pull request](/contributing/code/#step-by-step-from-forking-to-sending-the-pull-request) which fixes the issue.
Lastly, don't get your hopes up too high. Unless your issue is a blocker
affecting a large number of users, don't expect SilverStripe developers to jump
@@ -42,24 +42,24 @@ problem can collaborate with you to develop a fix.
Please don't file "feature requests" as Github issues. If there's a new feature
you'd like to see in SilverStripe, you either need to write it yourself (and
-[submit a pull request](/misc/contributing/code)) or convince somebody else to
+[submit a pull request](/contributing/code/#step-by-step-from-forking-to-sending-the-pull-request) or convince somebody else to
write it for you. Any "wishlist" type issues without code attached can be
expected to be closed as soon as they're reviewed.
In order to gain interest and feedback in your feature, we encourage you to
-present it to the community through the [forums](http://silverstripe.org/forums),
+present it to the community through the [forums](http://www.silverstripe.org/community/forums),
[core mailinglist](http://groups.google.com/group/silverstripe-dev) or on
-[IRC](http://silverstripe.org/irc).
+[IRC](http://irc.silverstripe.org/).
## Reporting Security Issues
-Report security issues to [security@silverstripe.com](mailto:security@silverstripe.com).
-See our "[Release Process](release-process)" documentation for more info, and
-read our guide on [how to write secure code](/topics/security).
+Report security issues to [security@silverstripe.org](mailto:security@silverstripe.org).
+See our "[Release Process](/contributing/release_process/#security-releases)" documentation for more info, and
+read our guide on [how to write secure code](/developer_guides/security/secure_coding/).
## Sharing your Opinion
-* [silverstripe.org/forums](http://silverstripe.org/forums): Forums on silverstripe.org
-* [silverstripe-dev](http://groups.google.com/group/silverstripe-dev): Core development mailinglist
-* [silverstripe-documentation](http://groups.google.com/group/silverstripe-translators): Translation team mailing list
+* [silverstripe.org/forums](http://www.silverstripe.org/community/forums/): Forums on silverstripe.org
+* [silverstripe-dev](http://groups.google.com/group/silverstripe-dev/): Core development mailinglist
+* [silverstripe-documentation](http://groups.google.com/group/silverstripe-translators/): Translation team mailing list
From a0f9535dd42d9085c2c84800c77f1ddb47a4ef08 Mon Sep 17 00:00:00 2001
From: Daniel Hensby
Date: Fri, 6 Feb 2015 10:58:01 +0000
Subject: [PATCH 41/77] FIX issue where empty composite fields created a
fieldlist with empty items
---
forms/CompositeField.php | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/forms/CompositeField.php b/forms/CompositeField.php
index f47d3aa2e..3bd6e9d34 100644
--- a/forms/CompositeField.php
+++ b/forms/CompositeField.php
@@ -47,13 +47,14 @@ class CompositeField extends FormField {
if($children instanceof FieldList) {
$this->children = $children;
} elseif(is_array($children)) {
- $this->children = new FieldList($children);
+ $this->children = new FieldList($children);
} else {
- $children = is_array(func_get_args()) ? func_get_args() : array();
- $this->children = new FieldList($children);
+ //filter out null/empty items
+ $children = array_filter(func_get_args());
+ $this->children = new FieldList($children);
}
$this->children->setContainerField($this);
-
+
// Skipping FormField::__construct(), but we have to make sure this
// doesn't count as a broken constructor
$this->brokenOnConstruct = false;
From d68435e97858dfcb96742fd0b6597a381f33ca62 Mon Sep 17 00:00:00 2001
From: Daniel Hensby
Date: Fri, 6 Feb 2015 11:00:00 +0000
Subject: [PATCH 42/77] FIX SelectionGroup no longer shows empty FieldLists
---
templates/forms/SelectionGroup.ss | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/templates/forms/SelectionGroup.ss b/templates/forms/SelectionGroup.ss
index 14737897c..8201cf936 100644
--- a/templates/forms/SelectionGroup.ss
+++ b/templates/forms/SelectionGroup.ss
@@ -13,7 +13,10 @@
From 74ec7e413f343e1f1cda4fa13a6dc1ce35183b9b Mon Sep 17 00:00:00 2001
From: Daniel Hensby
Date: Sat, 7 Feb 2015 14:33:12 +0000
Subject: [PATCH 43/77] DOCS Updating contributing version
---
docs/en/05_Contributing/01_Code.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/en/05_Contributing/01_Code.md b/docs/en/05_Contributing/01_Code.md
index 4b6438a38..4d3e26091 100644
--- a/docs/en/05_Contributing/01_Code.md
+++ b/docs/en/05_Contributing/01_Code.md
@@ -18,7 +18,7 @@ We ask for this so that the ownership in the license is clear and unambiguous, a
1. Install the project through composer. The process is described in detail in "[Installation through Composer](../../installation/composer#contributing)".
- composer create-project --keep-vcs --dev silverstripe/installer ./my/website/folder 3.0.x-dev
+ composer create-project --keep-vcs --dev silverstripe/installer ./my/website/folder 3.1.x-dev
2. Edit the `composer.json`. Remove the `@stable` markers from the core modules in there.
Add your fork URLs, in this example a fork of the `cms` module on the `sminnee` github account
From a7be8003e066bfb80bb6e281cf421a7f7fe8d268 Mon Sep 17 00:00:00 2001
From: Nick
Date: Mon, 9 Feb 2015 22:55:59 +1300
Subject: [PATCH 44/77] Fix some broken links for flushable and errors in the
caching code examples
---
docs/en/02_Developer_Guides/08_Performance/01_Caching.md | 4 ++--
.../02_Developer_Guides/16_Execution_Pipeline/01_Flushable.md | 2 +-
.../02_Developer_Guides/16_Execution_Pipeline/02_Manifests.md | 2 +-
docs/en/02_Developer_Guides/16_Execution_Pipeline/index.md | 2 +-
4 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/docs/en/02_Developer_Guides/08_Performance/01_Caching.md b/docs/en/02_Developer_Guides/08_Performance/01_Caching.md
index 91a08140d..578d895ac 100644
--- a/docs/en/02_Developer_Guides/08_Performance/01_Caching.md
+++ b/docs/en/02_Developer_Guides/08_Performance/01_Caching.md
@@ -51,7 +51,7 @@ The returned object is of type `Zend_Cache`.
$cache = SS_Cache::factory('foo');
if (!($result = $cache->load($cachekey))) {
$result = caluate some how;
- $cache->save($result);
+ $cache->save($result, $cachekey);
}
return $result;
@@ -103,7 +103,7 @@ which can provide better performance, including APC, Xcache, ZendServer, Memcach
If `?flush=1` is requested in the URL, e.g. http://mysite.com?flush=1, this will trigger a call to `flush()` on
any classes that implement the `Flushable` interface. Using this, you can trigger your caches to clean.
-See [reference documentation on Flushable](/reference/flushable) for implementation details.
+See [reference documentation on Flushable](/developer_guides/execution_pipeline/flushable/) for implementation details.
### Memcached
diff --git a/docs/en/02_Developer_Guides/16_Execution_Pipeline/01_Flushable.md b/docs/en/02_Developer_Guides/16_Execution_Pipeline/01_Flushable.md
index 9872257eb..e46ef19b5 100644
--- a/docs/en/02_Developer_Guides/16_Execution_Pipeline/01_Flushable.md
+++ b/docs/en/02_Developer_Guides/16_Execution_Pipeline/01_Flushable.md
@@ -31,7 +31,7 @@ This example uses `[api:SS_Cache]` in some custom code, and the same cache is cl
$something = $cache->load('mykey');
if(!$something) {
$something = 'value to be cached';
- $cache->save($something);
+ $cache->save($something, 'mykey');
}
return $something;
}
diff --git a/docs/en/02_Developer_Guides/16_Execution_Pipeline/02_Manifests.md b/docs/en/02_Developer_Guides/16_Execution_Pipeline/02_Manifests.md
index 269382e26..694d5190a 100644
--- a/docs/en/02_Developer_Guides/16_Execution_Pipeline/02_Manifests.md
+++ b/docs/en/02_Developer_Guides/16_Execution_Pipeline/02_Manifests.md
@@ -76,7 +76,7 @@ The chapter on [configuration](/topics/configuration) has more details.
## Flushing
If a `?flush=1` query parameter is added to a URL, a call to `flush()` will be triggered
-on any classes that implement the [Flushable](/reference/flushable) interface.
+on any classes that implement the [Flushable](flushable) interface.
This enables developers to clear [manifest caches](manifests),
for example when adding new templates or PHP classes.
Note that you need to be in [dev mode](/getting_started/environment_management)
diff --git a/docs/en/02_Developer_Guides/16_Execution_Pipeline/index.md b/docs/en/02_Developer_Guides/16_Execution_Pipeline/index.md
index e250b8b9b..45310ae44 100644
--- a/docs/en/02_Developer_Guides/16_Execution_Pipeline/index.md
+++ b/docs/en/02_Developer_Guides/16_Execution_Pipeline/index.md
@@ -130,7 +130,7 @@ The ["Request Filters" documentation](../controller/request_filters) shows you h
## Flushing Manifests
If a `?flush=1` query parameter is added to a URL, a call to `flush()` will be triggered
-on any classes that implement the [Flushable](/reference/flushable) interface.
+on any classes that implement the [Flushable](flushable) interface.
This enables developers to clear [manifest caches](manifests),
for example when adding new templates or PHP classes.
Note that you need to be in [dev mode](/getting_started/environment_management)
From 9fd57ea4f61c387906622330e28638d1c300927a Mon Sep 17 00:00:00 2001
From: Daniel Hensby
Date: Mon, 9 Feb 2015 16:24:25 +0000
Subject: [PATCH 45/77] MINOR SS_Query properties now protected
---
model/Query.php | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/model/Query.php b/model/Query.php
index 7765775e7..9a1067afc 100644
--- a/model/Query.php
+++ b/model/Query.php
@@ -23,22 +23,22 @@ abstract class SS_Query implements Iterator {
*
* @var array
*/
- private $currentRecord = null;
-
+ protected $currentRecord = null;
+
/**
* The number of the current row in the interator.
*
* @var int
*/
- private $rowNum = -1;
-
+ protected $rowNum = -1;
+
/**
* Flag to keep track of whether iteration has begun, to prevent unnecessary
* seeks.
*
* @var boolean
*/
- private $queryHasBegun = false;
+ protected $queryHasBegun = false;
/**
* Return an array containing all the values from a specific column. If no
From 0a19d882d3ffc0a9762872d8ef04fea936064e47 Mon Sep 17 00:00:00 2001
From: Christopher Pitt
Date: Tue, 10 Feb 2015 09:16:18 +1300
Subject: [PATCH 46/77] Update index.md
404 fix
---
docs/en/01_Tutorials/index.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/en/01_Tutorials/index.md b/docs/en/01_Tutorials/index.md
index 395174b9b..1cf924ecb 100644
--- a/docs/en/01_Tutorials/index.md
+++ b/docs/en/01_Tutorials/index.md
@@ -11,7 +11,7 @@ These include video screencasts, written tutorials and code examples to get you
* [How to set up a local development environment in SilverStripe](https://vimeo.com/108861537)
* [Lesson 1: Creating your first theme](http://www.silverstripe.org/learn/lessons/lesson-1-creating-your-first-theme/)
* [Lesson 2: Migrating static templates into your theme](http://www.silverstripe.org/learn/lessons/lesson-2-migrating-static-templates-into-your-theme/)
-* [Lesson 3: Adding dynamic content](http://www.silverstripe.org/learn/lessons/lesson-3/)
+* [Lesson 3: Adding dynamic content](http://www.silverstripe.org/learn/lessons/lesson-3-adding-dynamic-content/)
* [Lesson 4: Working with multiple templates](http://www.silverstripe.org/learn/lessons/lesson-4-working-with-multiple-templates/)
* [Lesson 5: The holder/page pattern](http://www.silverstripe.org/learn/lessons/lesson-5-the-holderpage-pattern/)
* [Lesson 6: Adding Custom Fields to a Page](http://www.silverstripe.org/learn/lessons/lesson-6-adding-custom-fields-to-a-page/)
From e96d40d391e433eba5ea2627624c2679ad1e5dd4 Mon Sep 17 00:00:00 2001
From: gavin bruce
Date: Tue, 10 Feb 2015 14:30:29 +1000
Subject: [PATCH 47/77] Update 00_Partial_Caching.md
Spelling mistake fix.
---
.../02_Developer_Guides/08_Performance/00_Partial_Caching.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/docs/en/02_Developer_Guides/08_Performance/00_Partial_Caching.md b/docs/en/02_Developer_Guides/08_Performance/00_Partial_Caching.md
index c2836e24e..e50d3c1be 100644
--- a/docs/en/02_Developer_Guides/08_Performance/00_Partial_Caching.md
+++ b/docs/en/02_Developer_Guides/08_Performance/00_Partial_Caching.md
@@ -159,7 +159,7 @@ To cache the contents of a page for all anonymous users, but dynamically calcula
## Uncached
-Yhe template tag 'uncached' can be used - it is the exact equivalent of a cached block with an if condition that always
+The template tag 'uncached' can be used - it is the exact equivalent of a cached block with an if condition that always
returns false. The key and conditionals in an uncached tag are ignored, so you can easily temporarily disable a
particular cache block by changing just the tag, leaving the key and conditional intact.
@@ -235,4 +235,4 @@ Can be re-written as:
<% end_loop %>
<% end_cached %>
- <% end_cached %>
\ No newline at end of file
+ <% end_cached %>
From d555b5b26ee97f574c862e62c040d33a965a8736 Mon Sep 17 00:00:00 2001
From: Aden Fraser
Date: Wed, 11 Feb 2015 15:19:08 +0000
Subject: [PATCH 48/77] Fixed JS error in lib.js (fixes #3481)
---
admin/javascript/lib.js | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/admin/javascript/lib.js b/admin/javascript/lib.js
index a8ad7b6d2..3524c9724 100644
--- a/admin/javascript/lib.js
+++ b/admin/javascript/lib.js
@@ -194,8 +194,8 @@
// For embedded pages, remove the dialog hash key as in getFilePath(),
// otherwise the Data Url won't match the id of the embedded Page.
return u.hash.split( dialogHashKey )[0].replace( /^#/, "" );
- } else if ( path.isSameDomain( u, documentBase ) ) {
- return u.hrefNoHash.replace( documentBase.domain, "" );
+ } else if ( path.isSameDomain( u, document ) ) {
+ return u.hrefNoHash.replace( document.domain, "" );
}
return absUrl;
},
@@ -227,7 +227,7 @@
//return a url path with the window's location protocol/hostname/pathname removed
clean: function( url ) {
- return url.replace( documentBase.domain, "" );
+ return url.replace( document.domain, "" );
},
//just return the url without an initial #
@@ -244,7 +244,7 @@
//could be mailto, etc
isExternal: function( url ) {
var u = path.parseUrl( url );
- return u.protocol && u.domain !== documentUrl.domain ? true : false;
+ return u.protocol && u.domain !== document.domain ? true : false;
},
hasProtocol: function( url ) {
From eed709384d4791d3467dcc79809d6f66a7de21e0 Mon Sep 17 00:00:00 2001
From: Loz Calver
Date: Thu, 22 Jan 2015 10:33:38 +0000
Subject: [PATCH 49/77] FIX: dev/build not flushing manifests if site is in a
subfolder
---
core/Core.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/core/Core.php b/core/Core.php
index df2c7f802..7a5158d8b 100644
--- a/core/Core.php
+++ b/core/Core.php
@@ -96,7 +96,7 @@ Injector::set_inst($injector);
// The coupling is a hack, but it removes an annoying bug where new classes
// referenced in _config.php files can be referenced during the build process.
$requestURL = isset($_REQUEST['url']) ? trim($_REQUEST['url'], '/') : false;
-$flush = (isset($_GET['flush']) || $requestURL == 'dev/build' || $requestURL == BASE_URL . '/dev/build');
+$flush = (isset($_GET['flush']) || $requestURL === trim(BASE_URL . '/dev/build', '/'));
global $manifest;
$manifest = new SS_ClassManifest(BASE_PATH, false, $flush);
From 0ec53d8fdd7a895014d5deb7819faa9c22966d11 Mon Sep 17 00:00:00 2001
From: 3Dgoo
Date: Thu, 12 Feb 2015 14:39:54 +1030
Subject: [PATCH 50/77] sort method comments fixed missing single quote
---
model/DataList.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/model/DataList.php b/model/DataList.php
index 0f7b387af..3e2408ef1 100644
--- a/model/DataList.php
+++ b/model/DataList.php
@@ -244,7 +244,7 @@ class DataList extends ViewableData implements SS_List, SS_Filterable, SS_Sortab
* @example $list = $list->sort('Name'); // default ASC sorting
* @example $list = $list->sort('Name DESC'); // DESC sorting
* @example $list = $list->sort('Name', 'ASC');
- * @example $list = $list->sort(array('Name'=>'ASC,'Age'=>'DESC'));
+ * @example $list = $list->sort(array('Name'=>'ASC', 'Age'=>'DESC'));
*
* @param String|array Escaped SQL statement. If passed as array, all keys and values are assumed to be escaped.
* @return DataList
From 921891943775b0a78ae223afde5bca218ad8dea8 Mon Sep 17 00:00:00 2001
From: Uncle Cheese
Date: Thu, 12 Feb 2015 17:15:53 +1300
Subject: [PATCH 51/77] Several changes to deprecate old tutorials
---
docs/en/01_Tutorials/01_Building_A_Basic_Site.md | 3 +++
docs/en/01_Tutorials/02_Extending_A_Basic_Site.md | 4 ++++
docs/en/01_Tutorials/05_Dataobject_Relationship_Management.md | 4 ++++
docs/en/01_Tutorials/index.md | 2 --
docs/en/index.md | 2 +-
5 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/docs/en/01_Tutorials/01_Building_A_Basic_Site.md b/docs/en/01_Tutorials/01_Building_A_Basic_Site.md
index 1317de48c..4c8b84819 100644
--- a/docs/en/01_Tutorials/01_Building_A_Basic_Site.md
+++ b/docs/en/01_Tutorials/01_Building_A_Basic_Site.md
@@ -1,6 +1,9 @@
title: Building a basic site
summary: An overview of the SilverStripe installation and an introduction to creating a web page.
+
+This tutorial is deprecated, and has been replaced by Lessons 1, 2, 3, and 4 in the [Lessons section](http://www.silverstripe.org/learn/lessons)
+
# Tutorial 1 - Building a Basic Site
## Overview
diff --git a/docs/en/01_Tutorials/02_Extending_A_Basic_Site.md b/docs/en/01_Tutorials/02_Extending_A_Basic_Site.md
index 87775f2f8..5a7fb60cd 100644
--- a/docs/en/01_Tutorials/02_Extending_A_Basic_Site.md
+++ b/docs/en/01_Tutorials/02_Extending_A_Basic_Site.md
@@ -1,6 +1,10 @@
title: Extending a basic site
summary: Building on tutorial 1, a look at storing data in SilverStripe and creating a latest news feed.
+
+This tutorial is deprecated, and has been replaced by Lessons 4, 5, and 6 in the [Lessons section](http://www.silverstripe.org/learn/lessons)
+
+
# Tutorial 2 - Extending a basic site
## Overview
diff --git a/docs/en/01_Tutorials/05_Dataobject_Relationship_Management.md b/docs/en/01_Tutorials/05_Dataobject_Relationship_Management.md
index cac565c1b..1696369ec 100644
--- a/docs/en/01_Tutorials/05_Dataobject_Relationship_Management.md
+++ b/docs/en/01_Tutorials/05_Dataobject_Relationship_Management.md
@@ -1,6 +1,10 @@
title: DataObject Relationship Management
summary: Learn how to create custom DataObjects and how to build interfaces for managing that data.
+
+This tutorial is deprecated, and has been replaced by Lessons 7, 8, 9, and 10 in the [Lessons section](http://www.silverstripe.org/learn/lessons)
+
+
# Tutorial 5 - Dataobject Relationship Management
## Overview
diff --git a/docs/en/01_Tutorials/index.md b/docs/en/01_Tutorials/index.md
index 1cf924ecb..daa53cc5b 100644
--- a/docs/en/01_Tutorials/index.md
+++ b/docs/en/01_Tutorials/index.md
@@ -3,8 +3,6 @@ introduction: The tutorials below take a step by step look at how to build a Sil
## Written Tutorials
-[CHILDREN]
-
## Video lessons
These include video screencasts, written tutorials and code examples to get you started working with SilverStripe websites.
diff --git a/docs/en/index.md b/docs/en/index.md
index 635283d56..20c777d41 100644
--- a/docs/en/index.md
+++ b/docs/en/index.md
@@ -28,7 +28,7 @@ discussed on the [core mailinglist](https://groups.google.com/forum/#!forum/silv
## Building your first SilverStripe Web application
Once you have completed the [Getting Started](/getting_started) guide and have got SilverStripe
-installed and running, the following [Tutorials](/tutorials) will lead through the basics and core concepts of
+installed and running, the following [Tutorials](http://silverstripe.org/learn/lessons) will lead through the basics and core concepts of
SilverStripe.
Make sure you know the basic concepts of PHP5 before attempting to follow the tutorials. If you have not programmed with PHP5 be sure to read the [Introduction to PHP5 (zend.com)](http://devzone.zend.com/6/php-101--php-for-the-absolute-beginner).
From 047fe3a410624f34d617e4577669c4c7db52613b Mon Sep 17 00:00:00 2001
From: JorisDebonnet
Date: Thu, 12 Feb 2015 02:20:54 +0100
Subject: [PATCH 52/77] BUG Include php version in default cache folder name
Update CoreTest.php
---
core/TempPath.php | 5 +++--
tests/core/CoreTest.php | 28 ++++++++++++++++------------
2 files changed, 19 insertions(+), 14 deletions(-)
diff --git a/core/TempPath.php b/core/TempPath.php
index b64f2609d..93ae274db 100644
--- a/core/TempPath.php
+++ b/core/TempPath.php
@@ -64,8 +64,9 @@ function getTempParentFolder($base = null) {
}
// failing the above, try finding a namespaced silverstripe-cache dir in the system temp
- $cacheFolder = DIRECTORY_SEPARATOR . 'silverstripe-cache' . str_replace(array(' ', '/', ':', '\\'), '-', $base);
- $tempPath = sys_get_temp_dir() . $cacheFolder;
+ $tempPath = sys_get_temp_dir() . DIRECTORY_SEPARATOR .
+ 'silverstripe-cache-php' . preg_replace('/[^\w-\.+]+/', '-', PHP_VERSION) .
+ str_replace(array(' ', '/', ':', '\\'), '-', $base);
if(!@file_exists($tempPath)) {
$oldUMask = umask(0);
$worked = @mkdir($tempPath, 0777);
diff --git a/tests/core/CoreTest.php b/tests/core/CoreTest.php
index a6e6df99c..3fa928cbb 100644
--- a/tests/core/CoreTest.php
+++ b/tests/core/CoreTest.php
@@ -22,20 +22,22 @@ class CoreTest extends SapphireTest {
$this->assertEquals(getTempFolder(BASE_PATH), $this->tempPath . DIRECTORY_SEPARATOR . $user);
} else {
$user = getTempFolderUsername();
+ $base = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'silverstripe-cache-php' .
+ preg_replace('/[^\w-\.+]+/', '-', PHP_VERSION);
// A typical Windows location for where sites are stored on IIS
- $this->assertEquals(sys_get_temp_dir() . DIRECTORY_SEPARATOR .
- 'silverstripe-cacheC--inetpub-wwwroot-silverstripe-test-project' . DIRECTORY_SEPARATOR . $user,
+ $this->assertEquals(
+ $base . 'C--inetpub-wwwroot-silverstripe-test-project' . DIRECTORY_SEPARATOR . $user,
getTempFolder('C:\\inetpub\\wwwroot\\silverstripe-test-project'));
// A typical Mac OS X location for where sites are stored
- $this->assertEquals(sys_get_temp_dir() . DIRECTORY_SEPARATOR .
- 'silverstripe-cache-Users-joebloggs-Sites-silverstripe-test-project' . DIRECTORY_SEPARATOR . $user,
+ $this->assertEquals(
+ $base . '-Users-joebloggs-Sites-silverstripe-test-project' . DIRECTORY_SEPARATOR . $user,
getTempFolder('/Users/joebloggs/Sites/silverstripe-test-project'));
// A typical Linux location for where sites are stored
- $this->assertEquals(sys_get_temp_dir() . DIRECTORY_SEPARATOR .
- 'silverstripe-cache-var-www-silverstripe-test-project' . DIRECTORY_SEPARATOR . $user,
+ $this->assertEquals(
+ $base . '-var-www-silverstripe-test-project' . DIRECTORY_SEPARATOR . $user,
getTempFolder('/var/www/silverstripe-test-project'));
}
}
@@ -43,17 +45,19 @@ class CoreTest extends SapphireTest {
public function tearDown() {
parent::tearDown();
$user = getTempFolderUsername();
+ $base = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'silverstripe-cache-php' .
+ preg_replace('/[^\w-\.+]+/', '-', PHP_VERSION);
foreach(array(
- 'silverstripe-cacheC--inetpub-wwwroot-silverstripe-test-project',
- 'silverstripe-cache-Users-joebloggs-Sites-silverstripe-test-project',
- 'silverstripe-cache-var-www-silverstripe-test-project'
+ 'C--inetpub-wwwroot-silverstripe-test-project',
+ '-Users-joebloggs-Sites-silverstripe-test-project',
+ '-cache-var-www-silverstripe-test-project'
) as $dir) {
- $path = sys_get_temp_dir().DIRECTORY_SEPARATOR.$dir;
+ $path = $base . $dir;
if(file_exists($path)) {
rmdir($path . DIRECTORY_SEPARATOR . $user);
rmdir($path);
+ }
}
- }
- }
+ }
}
From c88ddef477f7581e4c2134242021481e8d995885 Mon Sep 17 00:00:00 2001
From: Uncle Cheese
Date: Fri, 13 Feb 2015 00:41:29 +1300
Subject: [PATCH 53/77] add new lessons 9, 10
remove tutorials from home page
---
docs/en/01_Tutorials/index.md | 7 ++++++-
docs/en/index.md | 1 -
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/docs/en/01_Tutorials/index.md b/docs/en/01_Tutorials/index.md
index daa53cc5b..c2b4be94e 100644
--- a/docs/en/01_Tutorials/index.md
+++ b/docs/en/01_Tutorials/index.md
@@ -2,7 +2,10 @@ title: Tutorials
introduction: The tutorials below take a step by step look at how to build a SilverStripe application.
## Written Tutorials
-
+
+These tutorials are deprecated, and have been replaced by the new [Lessons](http://silverstripe.org/learn/lessons) section.
+
+[CHIDLREN]
## Video lessons
These include video screencasts, written tutorials and code examples to get you started working with SilverStripe websites.
@@ -15,6 +18,8 @@ These include video screencasts, written tutorials and code examples to get you
* [Lesson 6: Adding Custom Fields to a Page](http://www.silverstripe.org/learn/lessons/lesson-6-adding-custom-fields-to-a-page/)
* [Lesson 7: Working with Files and Images](http://www.silverstripe.org/learn/lessons/lesson-7-working-with-files-and-images/)
* [Lesson 8: Introduction to the ORM](http://www.silverstripe.org/learn/lessons/lesson-8-introduction-to-the-orm)
+* [Lesson 9: Data Relationships - $has_many](http://www.silverstripe.org/learn/lessons/lesson-9-working-with-data-relationships-has-many)
+* [Lesson 10: Introduction to the ORM](http://www.silverstripe.org/learn/lessons/lesson-10-working-with-data-relationships-many-many)
## Help: If you get stuck
diff --git a/docs/en/index.md b/docs/en/index.md
index 20c777d41..b72d3add5 100644
--- a/docs/en/index.md
+++ b/docs/en/index.md
@@ -33,7 +33,6 @@ SilverStripe.
Make sure you know the basic concepts of PHP5 before attempting to follow the tutorials. If you have not programmed with PHP5 be sure to read the [Introduction to PHP5 (zend.com)](http://devzone.zend.com/6/php-101--php-for-the-absolute-beginner).
-[CHILDREN Folder=01_Tutorials]
## SilverStripe Concepts
From 96962a92cfa64eeb65f412cdddf3aa7110dd96bf Mon Sep 17 00:00:00 2001
From: Stephan Bauer
Date: Thu, 12 Feb 2015 15:21:55 +0100
Subject: [PATCH 54/77] Changed cache_dir to respect TEMP_FOLDER
---
thirdparty/tinymce/tiny_mce_gzip.php | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/thirdparty/tinymce/tiny_mce_gzip.php b/thirdparty/tinymce/tiny_mce_gzip.php
index d07fe1b5f..c93571522 100755
--- a/thirdparty/tinymce/tiny_mce_gzip.php
+++ b/thirdparty/tinymce/tiny_mce_gzip.php
@@ -12,14 +12,14 @@
$frameworkPath = rtrim(dirname(dirname(dirname(__FILE__))), DIRECTORY_SEPARATOR);
$basePath = rtrim(dirname($frameworkPath), DIRECTORY_SEPARATOR);
-require_once $frameworkPath . '/core/TempPath.php';
+require_once $frameworkPath . '/core/Constants.php';
// Handle incoming request if it's a script call
if (TinyMCE_Compressor::getParam("js")) {
// Default settings
$tinyMCECompressor = new TinyMCE_Compressor(array(
// CUSTOM SilverStripe
- 'cache_dir' => getTempFolder($basePath)
+ 'cache_dir' => TEMP_FOLDER
// CUSTOM END
));
From 36dbd4f8a10ac2e35d378d4635178b2ec9794844 Mon Sep 17 00:00:00 2001
From: LiamW
Date: Thu, 12 Feb 2015 14:16:05 -0500
Subject: [PATCH 55/77] Update 11_Scaffolding.md
Noticed the call to the tab is wrong.
---
docs/en/02_Developer_Guides/00_Model/11_Scaffolding.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/en/02_Developer_Guides/00_Model/11_Scaffolding.md b/docs/en/02_Developer_Guides/00_Model/11_Scaffolding.md
index f0d64e644..f66d57d15 100644
--- a/docs/en/02_Developer_Guides/00_Model/11_Scaffolding.md
+++ b/docs/en/02_Developer_Guides/00_Model/11_Scaffolding.md
@@ -39,7 +39,7 @@ To fully customise your form fields, start with an empty FieldList.
public function getCMSFields() {
$fields = FieldList::create(
- TabSet::create("Root",
+ TabSet::create("Root.Main",
CheckboxSetField::create('IsActive','Is active?'),
TextField::create('Title'),
TextareaField::create('Content')
From 518045257e32be90781a853ab187428ff4c00948 Mon Sep 17 00:00:00 2001
From: Damian Mooyman
Date: Thu, 3 Apr 2014 09:33:18 +1300
Subject: [PATCH 56/77] BUG Fixed handling of numbers in certain locales. Fixes
#2161
---
forms/FormField.php | 3 +-
forms/NumericField.php | 116 +++++++++++++----
tests/forms/NumericFieldTest.php | 210 ++++++++++++++++++++++++++++---
3 files changed, 290 insertions(+), 39 deletions(-)
diff --git a/forms/FormField.php b/forms/FormField.php
index 40fdba1c2..693c50253 100644
--- a/forms/FormField.php
+++ b/forms/FormField.php
@@ -423,6 +423,7 @@ class FormField extends RequestHandler {
* Set the field value.
*
* @param mixed $value
+ * @param mixed $data Optional data source passed in by {@see Form::loadDataFrom}
* @return FormField Self reference
*/
public function setValue($value) {
@@ -444,7 +445,7 @@ class FormField extends RequestHandler {
* have to worry about linking the two.
*/
public function setForm($form) {
- $this->form = $form;
+ $this->form = $form;
return $this;
}
diff --git a/forms/NumericField.php b/forms/NumericField.php
index d6219074b..4fd615b2a 100644
--- a/forms/NumericField.php
+++ b/forms/NumericField.php
@@ -2,13 +2,63 @@
/**
* Text input field with validation for numeric values. Supports validating
- * the numeric value as to the {@link i18n::get_locale()} value.
+ * the numeric value as to the {@link i18n::get_locale()} value, or an
+ * overridden locale specific to this field.
*
* @package forms
* @subpackage fields-formattedinput
*/
class NumericField extends TextField {
+ /**
+ * Override locale for this field
+ *
+ * @var string
+ */
+ protected $locale = null;
+
+ public function setValue($value, $data = array()) {
+ require_once "Zend/Locale/Format.php";
+
+ // If passing in a non-string number, or a value
+ // directly from a dataobject then localise this number
+ if ((is_numeric($value) && !is_string($value)) ||
+ ($value && $data instanceof DataObject)
+ ){
+ $locale = new Zend_Locale($this->getLocale());
+ $this->value = Zend_Locale_Format::toNumber($value, array('locale' => $locale));
+ } else {
+ // If an invalid number, store it anyway, but validate() will fail
+ $this->value = $this->clean($value);
+ }
+ return $this;
+ }
+
+ /**
+ * In some cases and locales, validation expects non-breaking spaces
+ *
+ * @param string $input
+ * @return string The input value, with all spaces replaced with non-breaking spaces
+ */
+ protected function clean($input) {
+ $nbsp = html_entity_decode(' ', null, 'UTF-8');
+ return str_replace(' ', $nbsp, trim($input));
+ }
+
+ /**
+ * Determine if the current value is a valid number in the current locale
+ *
+ * @return bool
+ */
+ protected function isNumeric() {
+ require_once "Zend/Locale/Format.php";
+ $locale = new Zend_Locale($this->getLocale());
+ return Zend_Locale_Format::isNumber(
+ $this->clean($this->value),
+ array('locale' => $locale)
+ );
+ }
+
public function Type() {
return 'numeric text';
}
@@ -18,31 +68,33 @@ class NumericField extends TextField {
return true;
}
- require_once THIRDPARTY_PATH."/Zend/Locale/Format.php";
+ if($this->isNumeric()) return true;
- $valid = Zend_Locale_Format::isNumber(
- trim($this->value),
- array('locale' => i18n::get_locale())
+ $validator->validationError(
+ $this->name,
+ _t(
+ 'NumericField.VALIDATION', "'{value}' is not a number, only numbers can be accepted for this field",
+ array('value' => $this->value)
+ ),
+ "validation"
);
-
- if(!$valid) {
- $validator->validationError(
- $this->name,
- _t(
- 'NumericField.VALIDATION', "'{value}' is not a number, only numbers can be accepted for this field",
- array('value' => $this->value)
- ),
- "validation"
- );
-
- return false;
- }
-
- return true;
+ return false;
}
-
+
+ /**
+ * Extracts the number value from the localised string value
+ *
+ * @return string number value
+ */
public function dataValue() {
- return (is_numeric($this->value)) ? $this->value : 0;
+ require_once "Zend/Locale/Format.php";
+ if(!$this->isNumeric()) return 0;
+ $locale = new Zend_Locale($this->getLocale());
+ $number = Zend_Locale_Format::getNumber(
+ $this->clean($this->value),
+ array('locale' => $locale)
+ );
+ return $number;
}
/**
@@ -54,6 +106,26 @@ class NumericField extends TextField {
return $field;
}
+ /**
+ * Gets the current locale this field is set to
+ *
+ * @return string
+ */
+ public function getLocale() {
+ return $this->locale ?: i18n::get_locale();
+ }
+
+ /**
+ * Override the locale for this field
+ *
+ * @param string $locale
+ * @return $this
+ */
+ public function setLocale($locale) {
+ $this->locale = $locale;
+ return $this;
+ }
+
}
class NumericField_Readonly extends ReadonlyField {
diff --git a/tests/forms/NumericFieldTest.php b/tests/forms/NumericFieldTest.php
index a7fd5ad27..c7c549107 100644
--- a/tests/forms/NumericFieldTest.php
+++ b/tests/forms/NumericFieldTest.php
@@ -8,34 +8,212 @@ class NumericFieldTest extends SapphireTest {
protected $usesDatabase = false;
- public function testValidator() {
- i18n::set_locale('en_US');
+ /**
+ * In some cases and locales, validation expects non-breaking spaces.
+ *
+ * Duplicates non-public NumericField::clean method
+ *
+ * @param string $input
+ * @return string The input value, with all spaces replaced with non-breaking spaces
+ */
+ protected function clean($input) {
+ $nbsp = html_entity_decode(' ', null, 'UTF-8');
+ return str_replace(' ', $nbsp, trim($input));
+ }
+ protected function checkInputValidation($locale, $tests) {
+ i18n::set_locale($locale);
$field = new NumericField('Number');
- $field->setValue('12.00');
-
$validator = new RequiredFields('Number');
- $this->assertTrue($field->validate($validator));
- $field->setValue('12,00');
- $this->assertFalse($field->validate($validator));
+ foreach($tests as $input => $output) {
+ // Both decimal and thousands B
+ $field->setValue($input);
+ if($output === false) {
+ $this->assertFalse(
+ $field->validate($validator),
+ "Expect validation to fail for input $input in locale $locale"
+ );
+ $this->assertEquals(
+ 0,
+ $field->dataValue(),
+ "Expect invalid value to be rewritten to 0 in locale $locale"
+ );
+
+ // Even invalid values shouldn't be rewritten
+ $this->assertEquals(
+ $this->clean($input),
+ $field->Value(),
+ "Expected input $input to be saved in the field in locale $locale"
+ );
+ } else {
+ $this->assertTrue(
+ $field->validate($validator),
+ "Expect validation to succeed for $input in locale $locale"
+ );
+ $this->assertEquals(
+ $output,
+ $field->dataValue(),
+ "Expect value $input to be mapped to $output in locale $locale"
+ );
+ }
+ }
+ }
+
+ /**
+ * Test that data loaded in via Form::loadDataFrom(DataObject) will populate the field correctly,
+ * and can format the database value appropriately for the frontend
+ *
+ * @param string $locale
+ * @param array $tests
+ */
+ public function checkDataFormatting($locale, $tests) {
+ i18n::set_locale($locale);
+ $field = new NumericField('Number');
+ $form = new Form(new Controller(), 'Form', new FieldList($field), new FieldList());
+ $dataObject = new NumericFieldTest_Object();
+
+ foreach($tests as $input => $output) {
+ // Given a dataobject as a context, the field should assume the field value is not localised
+ $dataObject->Number = (string)$input;
+ $form->loadDataFrom($dataObject, Form::MERGE_CLEAR_MISSING);
+
+ // Test value
+ $this->assertEquals(
+ $input,
+ $field->dataValue(),
+ "Expected $input loaded via dataobject to be left intact in locale $locale"
+ );
+
+ // Test expected formatted value (Substitute nbsp for spaces)
+ $this->assertEquals(
+ $this->clean($output),
+ $field->Value(),
+ "Expected $input to be formatted as $output in locale $locale"
+ );
+ }
+ }
+
+ /**
+ * German locale values (same as dutch)
+ */
+ public function testGermanLocales() {
+ $this->checkDataFormatting('de_DE', $formatting = array(
+ '13000' => "13.000",
+ '15' => '15',
+ '12.0' => '12,0',
+ '12.1' => '12,1',
+ '14000.5' => "14.000,5",
+ ));
+
+ $this->checkDataFormatting('nl_NL', $formatting);
+
+ $this->checkInputValidation('de_DE', $validation = array(
+ '13000' => 13000,
+ '12,00' => 12.00,
+ '12.00' => false,
+ '11 000' => false,
+ '11.000' => 11000,
+ '11,000' => 11.0,
+ '15 000,5' => false,
+ '15 000.5' => false,
+ '15.000,5' => 15000.5,
+ '15,000.5' => false,
+ ));
+
+ $this->checkInputValidation('nl_NL', $validation);
+ }
+
+ /**
+ * French locale values
+ */
+ public function testFrenchLocales() {
+ $this->checkDataFormatting('fr_FR', array(
+ '13000' => "13 000",
+ '15' => '15',
+ '12.0' => '12,0',
+ '12.1' => '12,1',
+ '14000.5' => "14 000,5",
+ ));
+
+ $this->checkInputValidation('fr_FR', array(
+ '13000' => 13000,
+ '12,00' => 12.00,
+ '12.00' => false,
+ '11 000' => 11000,
+ '11.000' => false,
+ '11,000' => 11.000,
+ '15 000,5' => 15000.5,
+ '15 000.5' => false,
+ '15.000,5' => false,
+ '15,000.5' => false,
+ ));
+ }
+
+ /**
+ * US locale values
+ */
+ public function testUSLocales() {
+ $this->checkDataFormatting('en_US', array(
+ '13000' => "13,000",
+ '15' => '15',
+ '12.0' => '12.0',
+ '12.1' => '12.1',
+ '14000.5' => "14,000.5",
+ ));
+
+ $this->checkInputValidation('en_US', array(
+ '13000' => 13000,
+ '12,00' => false,
+ '12.00' => 12.00,
+ '11 000' => false,
+ '11.000' => 11.0,
+ '11,000' => 11000,
+ '15 000,5' => false,
+ '15 000.5' => false,
+ '15.000,5' => false,
+ '15,000.5' => 15000.5,
+ ));
+ }
+
+ /**
+ * Test empty values
+ */
+ public function testEmptyValidator() {
+ i18n::set_locale('en_US');
+ $field = new NumericField('Number');
+ $validator = new RequiredFields('Number');
+
+ // Treats '0' as given for the sake of required fields
$field->setValue('0');
$this->assertTrue($field->validate($validator));
+ $this->assertEquals(0, $field->dataValue());
+
+ // Treat literal 0
+ $field->setValue(0);
+ $this->assertTrue($field->validate($validator));
+ $this->assertEquals(0, $field->dataValue());
+
+ // Should fail the 'required but not given' test
+ $field->setValue('');
+ $this->assertFalse($field->validate($validator));
$field->setValue(false);
$this->assertFalse($field->validate($validator));
+ }
- i18n::set_locale('de_DE');
- $field->setValue('12,00');
- $validator = new RequiredFields();
- $this->assertTrue($field->validate($validator));
-
- $field->setValue('12.00');
- $this->assertFalse($field->validate($validator));
-
- $field->setValue(0);
+ public function testReadonly() {
+ i18n::set_locale('en_US');
+ $field = new NumericField('Number');
$this->assertRegExp("#]+>\s*0\s*<\/span>#", "".$field->performReadonlyTransformation()->Field()."");
}
}
+
+class NumericFieldTest_Object extends DataObject implements TestOnly {
+
+ private static $db = array(
+ 'Number' => 'Float'
+ );
+}
\ No newline at end of file
From 89c14d079d3a130d6c4029af596262528ce53925 Mon Sep 17 00:00:00 2001
From: Daniel Hensby
Date: Sat, 7 Feb 2015 23:00:36 +0000
Subject: [PATCH 57/77] Making TreeMultiSelectField consistent with parent
class NEW TreeDropdownField sanatiser helper added Use config for
default_cast of objects FIX Determine if Diffed value should be escaped
Forcing casting for core DB fields Fixing permissions labels
---
forms/TreeDropdownField.php | 26 +++++++++++++++---
forms/TreeMultiselectField.php | 34 ++++++++++--------------
forms/gridfield/GridFieldPrintButton.php | 4 +++
javascript/TreeDropdownField.js | 8 +++---
model/DataDifferencer.php | 9 +++++--
model/DataObject.php | 2 ++
security/PermissionCheckboxSetField.php | 8 +++---
templates/forms/TreeDropdownField.ss | 3 ++-
view/ViewableData.php | 6 ++---
9 files changed, 64 insertions(+), 36 deletions(-)
diff --git a/forms/TreeDropdownField.php b/forms/TreeDropdownField.php
index 2f9f5d623..8cf46c78b 100644
--- a/forms/TreeDropdownField.php
+++ b/forms/TreeDropdownField.php
@@ -94,12 +94,32 @@ class TreeDropdownField extends FormField {
$this->keyField = $keyField;
$this->labelField = $labelField;
$this->showSearch = $showSearch;
-
+
+ $this->addExtraClass('single');
+
parent::__construct($name, $title);
}
-
+
/**
- * Set the ID of the root node of the tree. This defaults to 0 - i.e.
+ * Helper for the front end to know if we should escape the label value
+ *
+ * @return bool Whether the label field should be escaped
+ */
+ public function getEscapeLabelField() {
+ // be defensive
+ $escape = true;
+ $sourceClass = $this->getSourceObject();
+ //if it's an array, then it's an explicit set of values and we have to assume they've escaped their values already
+ //if the field is cast as XML, then we don't need to escape
+ if (is_array($sourceClass) || (is_a($sourceClass, 'ViewableData', true) && singleton($sourceClass)->escapeTypeForField($this->getLabelField()) == 'xml')) {
+ $escape = false;
+ }
+
+ return $escape;
+ }
+
+ /**
+ * Set the ID of the root node of the tree. This defaults to 0 - i.e.
* displays the whole tree.
*
* @param int $ID
diff --git a/forms/TreeMultiselectField.php b/forms/TreeMultiselectField.php
index 029ac84ce..1757f7b55 100644
--- a/forms/TreeMultiselectField.php
+++ b/forms/TreeMultiselectField.php
@@ -46,6 +46,8 @@
class TreeMultiselectField extends TreeDropdownField {
public function __construct($name, $title=null, $sourceObject="Group", $keyField="ID", $labelField="Title") {
parent::__construct($name, $title, $sourceObject, $keyField, $labelField);
+ $this->removeExtraClass('single');
+ $this->addExtraClass('multiple');
$this->value = 'unchanged';
}
@@ -103,7 +105,11 @@ class TreeMultiselectField extends TreeDropdownField {
if($items && count($items)) {
foreach($items as $id => $item) {
- $titleArray[] = $item->Title;
+ $title = $item->Title;
+ if ($item instanceof ViewableData && $item->escapeTypeForField('Title') != 'xml') {
+ $title = Convert::raw2xml($title);
+ }
+ $titleArray[] = $title;
$idArray[] = $item->ID;
}
@@ -118,30 +124,18 @@ class TreeMultiselectField extends TreeDropdownField {
$dataUrlTree = '';
if ($this->form){
$dataUrlTree = $this->Link('tree');
- if (isset($idArray) && count($idArray)){
+ if (!empty($idArray)){
$dataUrlTree = Controller::join_links($dataUrlTree, '?forceValue='.implode(',',$idArray));
}
}
- return FormField::create_tag(
- 'div',
- array (
- 'id' => "TreeDropdownField_{$this->id()}",
- 'class' => 'TreeDropdownField multiple' . ($this->extraClass() ? " {$this->extraClass()}" : '')
- . ($this->showSearch ? " searchable" : ''),
- 'data-url-tree' => $dataUrlTree,
- 'data-title' => $title,
- 'title' => $this->getDescription()
- ),
- FormField::create_tag(
- 'input',
- array (
- 'id' => $this->id(),
- 'type' => 'hidden',
- 'name' => $this->name,
- 'value' => $value
- )
+ $properties = array_merge(
+ $properties,
+ array(
+ 'Title' => $title,
+ 'Link' => $dataUrlTree,
)
);
+ return $this->customise($properties)->renderWith('TreeDropdownField');
}
/**
diff --git a/forms/gridfield/GridFieldPrintButton.php b/forms/gridfield/GridFieldPrintButton.php
index 217ea09cb..653620b11 100644
--- a/forms/gridfield/GridFieldPrintButton.php
+++ b/forms/gridfield/GridFieldPrintButton.php
@@ -192,6 +192,10 @@ class GridFieldPrintButton implements GridField_HTMLProvider, GridField_ActionPr
foreach($printColumns as $field => $label) {
$value = $gridField->getDataFieldValue($item, $field);
+ if ($item->escapeTypeForField('Title') != 'xml') {
+ $value = Convert::raw2xml($value);
+ }
+
$itemRow->push(new ArrayData(array(
"CellString" => $value,
)));
diff --git a/javascript/TreeDropdownField.js b/javascript/TreeDropdownField.js
index c30e67a2c..b3d1bca59 100644
--- a/javascript/TreeDropdownField.js
+++ b/javascript/TreeDropdownField.js
@@ -139,9 +139,11 @@
},
setTitle: function(title) {
title = title || this.data('title') || strings.fieldTitle;
-
- this.find('.treedropdownfield-title').html(title);
- this.data('title', title); // separate view from storage (important for search cancellation)
+
+ var func = this.data('escape-label-field') ? 'text' : 'html';
+
+ this.find('.treedropdownfield-title')[func](title);
+ this.data('title', title); // separate view from storage (important for search cancellation)
},
getTitle: function() {
return this.find('.treedropdownfield-title').text();
diff --git a/model/DataDifferencer.php b/model/DataDifferencer.php
index 36c0b4643..a69216c69 100644
--- a/model/DataDifferencer.php
+++ b/model/DataDifferencer.php
@@ -85,10 +85,15 @@ class DataDifferencer extends ViewableData {
if(in_array($field, $this->ignoredFields)) continue;
if(in_array($field, array_keys($hasOnes))) continue;
+ $escape = false;
+ if ($this->toRecord->escapeTypeForField($field) != 'xml') {
+ $escape = true;
+ }
if(!$this->fromRecord) {
- $diffed->setField($field, "" . $this->toRecord->$field . "");
+ $val = $escape ? Convert::raw2xml($this->toRecord->$field) : $this->toRecord->$field;
+ $diffed->setField($field, "" . $val . "");
} else if($this->fromRecord->$field != $this->toRecord->$field) {
- $diffed->setField($field, Diff::compareHTML($this->fromRecord->$field, $this->toRecord->$field));
+ $diffed->setField($field, Diff::compareHTML($this->fromRecord->$field, $this->toRecord->$field, $escape));
}
}
diff --git a/model/DataObject.php b/model/DataObject.php
index 4a666c91c..cea18d6ed 100644
--- a/model/DataObject.php
+++ b/model/DataObject.php
@@ -3435,6 +3435,8 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
* @var array
*/
private static $casting = array(
+ "ID" => 'Int',
+ "ClassName" => 'Varchar',
"LastEdited" => "SS_Datetime",
"Created" => "SS_Datetime",
"Title" => 'Text',
diff --git a/security/PermissionCheckboxSetField.php b/security/PermissionCheckboxSetField.php
index d3b7ab151..c4ade0bb0 100644
--- a/security/PermissionCheckboxSetField.php
+++ b/security/PermissionCheckboxSetField.php
@@ -99,7 +99,7 @@ class PermissionCheckboxSetField extends FormField {
if(!isset($uninheritedCodes[$permission->Code])) $uninheritedCodes[$permission->Code] = array();
$uninheritedCodes[$permission->Code][] = _t(
'PermissionCheckboxSetField.AssignedTo', 'assigned to "{title}"',
- array('title' => $record->Title)
+ array('title' => $record->dbObject('Title')->forTemplate())
);
}
@@ -115,7 +115,7 @@ class PermissionCheckboxSetField extends FormField {
'PermissionCheckboxSetField.FromRole',
'inherited from role "{title}"',
'A permission inherited from a certain permission role',
- array('title' => $role->Title)
+ array('title' => $role->dbObject('Title')->forTemplate())
);
}
}
@@ -134,7 +134,7 @@ class PermissionCheckboxSetField extends FormField {
'PermissionCheckboxSetField.FromRoleOnGroup',
'inherited from role "%s" on group "%s"',
'A permission inherited from a role on a certain group',
- array('roletitle' => $role->Title, 'grouptitle' => $parent->Title)
+ array('roletitle' => $role->dbObject('Title')->forTemplate(), 'grouptitle' => $parent->dbObject('Title')->forTemplate())
);
}
}
@@ -149,7 +149,7 @@ class PermissionCheckboxSetField extends FormField {
'PermissionCheckboxSetField.FromGroup',
'inherited from group "{title}"',
'A permission inherited from a certain group',
- array('title' => $parent->Title)
+ array('title' => $parent->dbObject('Title')->forTemplate())
);
}
}
diff --git a/templates/forms/TreeDropdownField.ss b/templates/forms/TreeDropdownField.ss
index 8b37d2f2b..f8d84a67a 100644
--- a/templates/forms/TreeDropdownField.ss
+++ b/templates/forms/TreeDropdownField.ss
@@ -1,7 +1,8 @@