Merge remote-tracking branch 'origin/3.1'

This commit is contained in:
Damian Mooyman 2014-05-12 11:32:22 +12:00
commit ec578e5c8a
70 changed files with 669 additions and 141 deletions

View File

@ -20,7 +20,7 @@
"composer/installers": "*"
},
"require-dev": {
"phpunit/PHPUnit": "~3.7"
"phpunit/PHPUnit": "~3.7@stable"
},
"extra": {
"branch-alias": {

View File

@ -165,13 +165,13 @@ class Director implements TemplateGlobalProvider {
DataModel::inst()
);
} else {
$response = new SS_HTTPResponse();
$response = new SS_HTTPResponse();
$response->redirect($url);
$res = Injector::inst()->get('RequestProcessor')->postRequest($req, $response, $model);
$res = Injector::inst()->get('RequestProcessor')->postRequest($req, $response, $model);
if ($res !== false) {
$response->output();
}
if ($res !== false) {
$response->output();
}
}
// Handle a controller
} else if($result) {

View File

@ -11,16 +11,24 @@
* @subpackage control
*/
interface RequestFilter {
/**
* Filter executed before a request processes
*
* @return boolean (optional)
* Whether to continue processing other filters
* @param SS_HTTPRequest $request Request container object
* @param Session $session Request session
* @param DataModel $model Current DataModel
* @return boolean Whether to continue processing other filters. Null or true will continue processing (optional)
*/
public function preRequest(SS_HTTPRequest $request, Session $session, DataModel $model);
/**
* Filter executed AFTER a request
*
* @param SS_HTTPRequest $request Request container object
* @param SS_HTTPResponse $response Response output object
* @param DataModel $model Current DataModel
* @return boolean Whether to continue processing other filters. Null or true will continue processing (optional)
*/
public function postRequest(SS_HTTPRequest $request, SS_HTTPResponse $response, DataModel $model);
}
}

View File

@ -1,17 +1,29 @@
<?php
/**
* Represents a request processer that delegates pre and post request handling to nested request filters
*
* @package framework
* @subpackage control
*/
class RequestProcessor {
class RequestProcessor implements RequestFilter {
/**
* List of currently assigned request filters
*
* @var array
*/
private $filters = array();
public function __construct($filters = array()) {
$this->filters = $filters;
}
/**
* Assign a list of request filters
*
* @param array $filters
*/
public function setFilters($filters) {
$this->filters = $filters;
}
@ -25,9 +37,6 @@ class RequestProcessor {
}
}
/**
* Filter executed AFTER a request
*/
public function postRequest(SS_HTTPRequest $request, SS_HTTPResponse $response, DataModel $model) {
foreach ($this->filters as $filter) {
$res = $filter->postRequest($request, $response, $model);

View File

@ -5,13 +5,15 @@
* @package framework
* @subpackage control
*/
class VersionedRequestFilter {
class VersionedRequestFilter implements RequestFilter {
public function preRequest() {
Versioned::choose_site_stage();
public function preRequest(SS_HTTPRequest $request, Session $session, DataModel $model) {
Versioned::choose_site_stage($session);
return true;
}
public function postRequest() {
public function postRequest(SS_HTTPRequest $request, SS_HTTPResponse $response, DataModel $model) {
return true;
}
}

View File

@ -210,6 +210,13 @@ class Injector {
}
}
/**
* The injector instance this one was copied from when Injector::nest() was called.
*
* @var Injector
*/
protected $nestedFrom = null;
/**
* If a user wants to use the injector as a static reference
*
@ -227,9 +234,38 @@ class Injector {
* Sets the default global injector instance.
*
* @param Injector $instance
* @return Injector Reference to new active Injector instance
*/
public static function set_inst(Injector $instance) {
self::$instance = $instance;
return self::$instance = $instance;
}
/**
* Make the newly active {@link Injector} be a copy of the current active
* {@link Injector} instance.
*
* You can then make changes to the injector with methods such as
* {@link Injector::inst()->registerService()} which will be discarded
* upon a subsequent call to {@link Injector::unnest()}
*
* @return Injector Reference to new active Injector instance
*/
public static function nest() {
$current = self::$instance;
$new = clone $current;
$new->nestedFrom = $current;
return self::set_inst($new);
}
/**
* Change the active Injector back to the Injector instance the current active
* Injector object was copied from.
*
* @return Injector Reference to restored active Injector instance
*/
public static function unnest() {
return self::set_inst(self::$instance->nestedFrom);
}
/**

View File

@ -201,13 +201,15 @@ class Config {
* A use case for replacing the active configuration set would be for
* creating an isolated environment for unit tests.
*
* @return Config
* @param Config $instance New instance of Config to assign
* @return Config Reference to new active Config instance
*/
public static function set_instance($instance) {
self::$instance = $instance;
global $_SINGLETONS;
$_SINGLETONS['Config'] = $instance;
return $instance;
}
/**
@ -215,23 +217,27 @@ class Config {
* {@link Config} instance.
*
* You can then make changes to the configuration by calling update and
* remove on the new value returned by Config::inst(), and then discard
* remove on the new value returned by {@link Config::inst()}, and then discard
* those changes later by calling unnest.
*
* @return Config Reference to new active Config instance
*/
public static function nest() {
$current = self::$instance;
$new = clone $current;
$new->nestedFrom = $current;
self::set_instance($new);
return self::set_instance($new);
}
/**
* Change the active Config back to the Config instance the current active
* Config object was copied from.
*
* @return Config Reference to new active Config instance
*/
public static function unnest() {
self::set_instance(self::$instance->nestedFrom);
return self::set_instance(self::$instance->nestedFrom);
}
/**

View File

@ -186,7 +186,7 @@ class SS_ConfigStaticManifest_Parser {
* Get the next token to process, incrementing the pointer
*
* @param bool $ignoreWhitespace - if true will skip any whitespace tokens & only return non-whitespace ones
* @return null | int - Either the next token or null if there isn't one
* @return null | mixed - Either the next token or null if there isn't one
*/
protected function next($ignoreWhitespace = true) {
do {
@ -198,6 +198,40 @@ class SS_ConfigStaticManifest_Parser {
return $next;
}
/**
* Get the next set of tokens that form a string to process,
* incrementing the pointer
*
* @param bool $ignoreWhitespace - if true will skip any whitespace tokens
* & only return non-whitespace ones
* @return null|string - Either the next string or null if there isn't one
*/
protected function nextString($ignoreWhitespace = true) {
static $stop = array('{', '}', '(', ')', '[', ']');
$string = '';
while ($this->pos < $this->length) {
$next = $this->tokens[$this->pos];
if (is_string($next)) {
if (!in_array($next, $stop)) {
$string .= $next;
} else {
break;
}
} else if ($next[0] == T_STRING) {
$string .= $next[1];
} else if ($next[0] != T_WHITESPACE || !$ignoreWhitespace) {
break;
}
$this->pos++;
}
if ($string === '') {
return null;
} else {
return $string;
}
}
/**
* Parse the given file to find the static variables declared in it, along with their access & values
*/
@ -208,12 +242,12 @@ class SS_ConfigStaticManifest_Parser {
$type = is_array($token) ? $token[0] : $token;
if($type == T_CLASS) {
$next = $this->next();
if($next[0] != T_STRING) {
$next = $this->nextString();
if($next === null) {
user_error("Couldn\'t parse {$this->path} when building config static manifest", E_USER_ERROR);
}
$class = $next[1];
$class = $next;
}
else if($type == T_NAMESPACE) {
$namespace = '';
@ -227,11 +261,11 @@ class SS_ConfigStaticManifest_Parser {
$next = $this->next();
}
if($next[0] != T_STRING) {
if(!is_string($next) && $next[0] != T_STRING) {
user_error("Couldn\'t parse {$this->path} when building config static manifest", E_USER_ERROR);
}
$namespace .= $next[1];
$namespace .= is_string($next) ? $next : $next[1];
}
}
else if($type == '{' || $type == T_CURLY_OPEN || $type == T_DOLLAR_OPEN_CURLY_BRACES){

View File

@ -181,25 +181,15 @@ class DevelopmentAdmin extends Controller {
public function generatesecuretoken() {
$generator = Injector::inst()->create('RandomGenerator');
$token = $generator->randomToken('sha1');
$body = <<<TXT
Generated new token. Please add the following code to your YAML configuration:
$path = $this->request->getVar('path');
if($path) {
if(file_exists(BASE_PATH . '/' . $path)) {
echo sprintf(
"Configuration file '%s' exists, can't merge. Please choose a new file.\n",
BASE_PATH . '/' . $path
);
exit(1);
}
$yml = "Security:\n token: $token";
Filesystem::makeFolder(dirname(BASE_PATH . '/' . $path));
file_put_contents(BASE_PATH . '/' . $path, $yml);
echo "Configured token in $path\n";
} else {
echo "Generated new token. Please add the following code to your YAML configuration:\n\n";
echo "Security:\n";
echo " token: $token\n";
}
Security:
token: $token
TXT;
$response = new SS_HTTPResponse($body);
return $response->addHeader('Content-Type', 'text/plain');
}
public function errors() {

View File

@ -7,3 +7,55 @@
user login name between sessions, and disable browser auto-completion on the username field.
Note that users of certain browsers who have previously autofilled and saved login credentials
will need to clear their password autofill history before this setting is properly respected.
* Test cases that rely on updating and restoring `[api:Injector]` services may now take advantage
of the new `Injector::nest()` and `Injector::unnest()` methods to sandbox their alterations.
* If errors could potentially be raised by any `[api:RequestHandler]` class such as a `[api:Form]` or
`[api:Controller]`, you may now add the new `[api:ErrorPageControllerExtension]` to this class to
transform plain text error messages into `ErrorPage` rendered HTML errors. In the past this
behaviour was limited to subclasses of `[api:ContentController]`. By default this extension is now
added to the `Security` controller, and if this is not desirable then it should be removed
explicitly via the Config system.
## Security
* 2014-04-16 [bde16f0](https://github.com/silverstripe/sapphire/commit/bde16f0) 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 [d9bc352](https://github.com/silverstripe/silverstripe-framework/commit/d9bc352) Injection / Filesystem vulnerability in generatesecuretoken - See [announcement SS-2014-010](http://www.silverstripe.org/ss-2014-010-injection-filesystem-vulnerability-in-generatesecuretoken/)
* 2014-05-02 [8e841cc](https://github.com/silverstripe/sapphire/commit/8e841cc) Folder filename injection - See [announcement SS-2014-011](http://www.silverstripe.org/ss-2014-011-folder-filename-injection/)
* 2014-05-05 [df28ccb](https://github.com/silverstripe/sapphire/commit/df28ccb) Upload fileexists vulnerability - See [announcement SS-2014-013](http://www.silverstripe.org/ss-2014-013-upload-fileexists-vulnerability/)
### API Changes
* 2014-05-02 [f9cb880](https://github.com/silverstripe/silverstripe-cms/commit/f9cb880) Error page support for Security controller errors (Damian Mooyman)
* 2014-05-01 [3162d0e](https://github.com/silverstripe/silverstripe-cms/commit/3162d0e) Update ErrorPage to respect new HTTP Error codes (Damian Mooyman)
* 2014-04-28 [0285322](https://github.com/silverstripe/silverstripe-cms/commit/0285322) Ability to configure paging for assets / pages (Damian Mooyman)
* 2014-04-22 [d06d5c1](https://github.com/silverstripe/sapphire/commit/d06d5c1) Injector supports nesting BUG Resolve issue with DirectorTest breaking RequestProcessor Injector::nest and Injector::unnest are introduced to better support sandboxing of testings. Injector and Config ::nest and ::unnest support chaining Test cases for both Injector::nest and Config::nest (Damian Mooyman)
* 2014-04-17 [a6017a0](https://github.com/silverstripe/sapphire/commit/a6017a0) HTTP 429 Allowed for use with rate limiting methods (Damian Mooyman)
* 2014-04-11 [892b440](https://github.com/silverstripe/sapphire/commit/892b440) Make default gridfield paging configurable Documentation improved (Damian Mooyman)
* 2014-04-09 [997077a](https://github.com/silverstripe/sapphire/commit/997077a) Security.remember_username to disable login form autocompletion (Damian Mooyman)
### Features and Enhancements
* 2014-03-28 [a502c9d](https://github.com/silverstripe/silverstripe-cms/commit/a502c9d) Fixes #966. Ability to filter pages on page status. - New filters for statuses normally found through SiteTree::getStatusFlags(). - Refactored menu sorting. Now alphabetical, as it wasn't previously. (Russell Michell)
* 2014-04-11 [3765030](https://github.com/silverstripe/silverstripe-cms/commit/3765030) Filter by date created for files Added test cases Do not merge before https://github.com/silverstripe-labs/silverstripe-behat-extension/pull/32 (Damian Mooyman)
### Bugfixes
* 2014-05-05 [c5d5d10](https://github.com/silverstripe/silverstripe-cms/commit/c5d5d10) Behat now uses explicit radio button behaviour (Damian Mooyman)
* 2014-05-01 [bd5abb6](https://github.com/silverstripe/sapphire/commit/bd5abb6) parent::init is not called first (Michael Parkhill)
* 2014-05-01 [4fd3015](https://github.com/silverstripe/sapphire/commit/4fd3015) corrected link to CMS Alternating Button Page (James Pluck)
* 2014-04-29 [8673b11](https://github.com/silverstripe/sapphire/commit/8673b11) Fix ImageTest Image test would erroneously reset the Image::$backend to null if the test was skipped, breaking subsequent test cases (Damian Mooyman)
* 2014-04-29 [89fbae2](https://github.com/silverstripe/silverstripe-cms/commit/89fbae2) Fix encoding of SiteTree.MetaTags (Damian Mooyman)
* 2014-04-25 [ff5f607](https://github.com/silverstripe/sapphire/commit/ff5f607) Docs for DataList::filter() (Daniel Hensby)
* 2014-04-24 [5e9ae57](https://github.com/silverstripe/sapphire/commit/5e9ae57) Fix edge case IE8 / dev / ssl / download file crash Prevents issue at http://support.microsoft.com/kb/323308 appearing on dev (Damian Mooyman)
* 2014-04-17 [bec8927](https://github.com/silverstripe/sapphire/commit/bec8927) Allow PHPUnit installation with composer / Fix travis (Will Morgan)
* 2014-04-16 [396fd9a](https://github.com/silverstripe/silverstripe-cms/commit/396fd9a) Broken file link tracking (fixes #996) (Loz Calver)
* 2014-04-14 [0b4f62d](https://github.com/silverstripe/sapphire/commit/0b4f62d) Fix jstree when duplicating subtrees (Damian Mooyman)
* 2014-04-11 [a261f22](https://github.com/silverstripe/sapphire/commit/a261f22) Delete Character \x01 (Stevie Mayhew)
* 2014-04-09 [91034d1](https://github.com/silverstripe/sapphire/commit/91034d1) HTMLText whitelist considers text nodes Minor improvement to #2853. If a list of whitelisted elements are specified, text nodes no longer evade the whitelist (Damian Mooyman)
* 2014-04-09 [a3c8a59](https://github.com/silverstripe/sapphire/commit/a3c8a59) Fix data query not always joining necessary tables Fixes #2846 (Damian Mooyman)
* 2014-04-08 [a060784](https://github.com/silverstripe/sapphire/commit/a060784) - missing link url for composer (camfindlay)
* 2014-04-07 [3204ab5](https://github.com/silverstripe/silverstripe-cms/commit/3204ab5) Fix orphaned pages reporting they can be viewed (Damian Mooyman)
* 2014-04-01 [84d8022](https://github.com/silverstripe/sapphire/commit/84d8022) Fix Date and SS_DateTime::FormatFromSettings This issue is caused by the odd default behaviour of Zend_Date, which attempts to parse yyyy-mm-dd format date and times as though they were yyyy-dd-mm. (Damian Mooyman)
* 2014-03-12 [b4a1aa4](https://github.com/silverstripe/silverstripe-cms/commit/b4a1aa4) Fixes #965. Allow user date-settings to show on GridField Page admin (Russell Michell)
* 2014-03-04 [ae573f8](https://github.com/silverstripe/sapphire/commit/ae573f8) Fix Versioned stage not persisting in Session. Fixes #962 BUG Disabled disruptive test case in DirectorTest API RequestProcessor and VersionedRequestFilter now both correctly implement RequestFilter Better PHPDoc on RequestFilter and implementations (Damian Mooyman)
* 2013-06-20 [f2c4a62](https://github.com/silverstripe/sapphire/commit/f2c4a62) ConfirmedPasswordField used to expose existing hash (Hamish Friedlander)

View File

@ -9,8 +9,10 @@ For information on how to upgrade to newer versions consult the [upgrading](/ins
## Stable Releases
* [3.1.4](3.1.4) - 8 April 2014
* [3.1.0](3.1.0) - 1 October 2013
* [3.0.10](3.0.10) - 8 April 2014
* [3.0.5](3.0.5) - 20 February 2013
* [3.0.4](3.0.4) - 19 February 2013
* [3.0.3](3.0.3) - 26 November 2012
@ -75,6 +77,9 @@ For information on how to upgrade to newer versions consult the [upgrading](/ins
## Alpha/beta/release candidate ##
* [3.1.5-rc1](rc/3.1.5-rc1) - 7 May 2014
* [3.1.4-rc1](rc/3.1.4-rc1) - 1 April 2014
* [3.0.10-rc1](rc/3.0.10-rc1) - 1 April 2014
* [3.0.6-rc1](rc/3.0.6-rc1) - 2013-08-08
* [3.0.3-rc1](rc/3.0.3-rc1) - 6 November 2012
* [3.0.2-rc2](rc/3.0.2-rc2) - 12 September 2012

View File

@ -0,0 +1,61 @@
# 3.1.5-rc1
## Upgrading
* If running an application in an environment where user security is critical, it may be necessary to
assign the config value `Security.remember_username` to false. This will disable persistence of
user login name between sessions, and disable browser auto-completion on the username field.
Note that users of certain browsers who have previously autofilled and saved login credentials
will need to clear their password autofill history before this setting is properly respected.
* Test cases that rely on updating and restoring `[api:Injector]` services may now take advantage
of the new `Injector::nest()` and `Injector::unnest()` methods to sandbox their alterations.
* If errors could potentially be raised by any `[api:RequestHandler]` class such as a `[api:Form]` or
`[api:Controller]`, you may now add the new `[api:ErrorPageControllerExtension]` to this class to
transform plain text error messages into `ErrorPage` rendered HTML errors. In the past this
behaviour was limited to subclasses of `[api:ContentController]`. By default this extension is now
added to the `Security` controller, and if this is not desirable then it should be removed
explicitly via the Config system.
## Security
* 2014-04-16 [bde16f0](https://github.com/silverstripe/sapphire/commit/bde16f0) 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 [d9bc352](https://github.com/silverstripe/silverstripe-framework/commit/d9bc352) Injection / Filesystem vulnerability in generatesecuretoken - See [announcement SS-2014-010](http://www.silverstripe.org/ss-2014-010-injection-filesystem-vulnerability-in-generatesecuretoken/)
* 2014-05-02 [8e841cc](https://github.com/silverstripe/sapphire/commit/8e841cc) Folder filename injection - See [announcement SS-2014-011](http://www.silverstripe.org/ss-2014-011-folder-filename-injection/)
* 2014-05-05 [df28ccb](https://github.com/silverstripe/sapphire/commit/df28ccb) Upload fileexists vulnerability - See [announcement SS-2014-013](http://www.silverstripe.org/ss-2014-013-upload-fileexists-vulnerability/)
### API Changes
* 2014-05-02 [f9cb880](https://github.com/silverstripe/silverstripe-cms/commit/f9cb880) Error page support for Security controller errors (Damian Mooyman)
* 2014-05-01 [3162d0e](https://github.com/silverstripe/silverstripe-cms/commit/3162d0e) Update ErrorPage to respect new HTTP Error codes (Damian Mooyman)
* 2014-04-28 [0285322](https://github.com/silverstripe/silverstripe-cms/commit/0285322) Ability to configure paging for assets / pages (Damian Mooyman)
* 2014-04-22 [d06d5c1](https://github.com/silverstripe/sapphire/commit/d06d5c1) Injector supports nesting BUG Resolve issue with DirectorTest breaking RequestProcessor Injector::nest and Injector::unnest are introduced to better support sandboxing of testings. Injector and Config ::nest and ::unnest support chaining Test cases for both Injector::nest and Config::nest (Damian Mooyman)
* 2014-04-17 [a6017a0](https://github.com/silverstripe/sapphire/commit/a6017a0) HTTP 429 Allowed for use with rate limiting methods (Damian Mooyman)
* 2014-04-11 [892b440](https://github.com/silverstripe/sapphire/commit/892b440) Make default gridfield paging configurable Documentation improved (Damian Mooyman)
* 2014-04-09 [997077a](https://github.com/silverstripe/sapphire/commit/997077a) Security.remember_username to disable login form autocompletion (Damian Mooyman)
### Features and Enhancements
* 2014-03-28 [a502c9d](https://github.com/silverstripe/silverstripe-cms/commit/a502c9d) Fixes #966. Ability to filter pages on page status. - New filters for statuses normally found through SiteTree::getStatusFlags(). - Refactored menu sorting. Now alphabetical, as it wasn't previously. (Russell Michell)
* 2014-04-11 [3765030](https://github.com/silverstripe/silverstripe-cms/commit/3765030) Filter by date created for files Added test cases Do not merge before https://github.com/silverstripe-labs/silverstripe-behat-extension/pull/32 (Damian Mooyman)
### Bugfixes
* 2014-05-05 [c5d5d10](https://github.com/silverstripe/silverstripe-cms/commit/c5d5d10) Behat now uses explicit radio button behaviour (Damian Mooyman)
* 2014-05-01 [bd5abb6](https://github.com/silverstripe/sapphire/commit/bd5abb6) parent::init is not called first (Michael Parkhill)
* 2014-05-01 [4fd3015](https://github.com/silverstripe/sapphire/commit/4fd3015) corrected link to CMS Alternating Button Page (James Pluck)
* 2014-04-29 [8673b11](https://github.com/silverstripe/sapphire/commit/8673b11) Fix ImageTest Image test would erroneously reset the Image::$backend to null if the test was skipped, breaking subsequent test cases (Damian Mooyman)
* 2014-04-29 [89fbae2](https://github.com/silverstripe/silverstripe-cms/commit/89fbae2) Fix encoding of SiteTree.MetaTags (Damian Mooyman)
* 2014-04-25 [ff5f607](https://github.com/silverstripe/sapphire/commit/ff5f607) Docs for DataList::filter() (Daniel Hensby)
* 2014-04-24 [5e9ae57](https://github.com/silverstripe/sapphire/commit/5e9ae57) Fix edge case IE8 / dev / ssl / download file crash Prevents issue at http://support.microsoft.com/kb/323308 appearing on dev (Damian Mooyman)
* 2014-04-17 [bec8927](https://github.com/silverstripe/sapphire/commit/bec8927) Allow PHPUnit installation with composer / Fix travis (Will Morgan)
* 2014-04-16 [396fd9a](https://github.com/silverstripe/silverstripe-cms/commit/396fd9a) Broken file link tracking (fixes #996) (Loz Calver)
* 2014-04-14 [0b4f62d](https://github.com/silverstripe/sapphire/commit/0b4f62d) Fix jstree when duplicating subtrees (Damian Mooyman)
* 2014-04-11 [a261f22](https://github.com/silverstripe/sapphire/commit/a261f22) Delete Character \x01 (Stevie Mayhew)
* 2014-04-09 [91034d1](https://github.com/silverstripe/sapphire/commit/91034d1) HTMLText whitelist considers text nodes Minor improvement to #2853. If a list of whitelisted elements are specified, text nodes no longer evade the whitelist (Damian Mooyman)
* 2014-04-09 [a3c8a59](https://github.com/silverstripe/sapphire/commit/a3c8a59) Fix data query not always joining necessary tables Fixes #2846 (Damian Mooyman)
* 2014-04-08 [a060784](https://github.com/silverstripe/sapphire/commit/a060784) - missing link url for composer (camfindlay)
* 2014-04-07 [3204ab5](https://github.com/silverstripe/silverstripe-cms/commit/3204ab5) Fix orphaned pages reporting they can be viewed (Damian Mooyman)
* 2014-04-01 [84d8022](https://github.com/silverstripe/sapphire/commit/84d8022) Fix Date and SS_DateTime::FormatFromSettings This issue is caused by the odd default behaviour of Zend_Date, which attempts to parse yyyy-mm-dd format date and times as though they were yyyy-dd-mm. (Damian Mooyman)
* 2014-03-12 [b4a1aa4](https://github.com/silverstripe/silverstripe-cms/commit/b4a1aa4) Fixes #965. Allow user date-settings to show on GridField Page admin (Russell Michell)
* 2014-03-04 [ae573f8](https://github.com/silverstripe/sapphire/commit/ae573f8) Fix Versioned stage not persisting in Session. Fixes #962 BUG Disabled disruptive test case in DirectorTest API RequestProcessor and VersionedRequestFilter now both correctly implement RequestFilter Better PHPDoc on RequestFilter and implementations (Damian Mooyman)
* 2013-06-20 [f2c4a62](https://github.com/silverstripe/sapphire/commit/f2c4a62) ConfirmedPasswordField used to expose existing hash (Hamish Friedlander)

View File

@ -87,7 +87,7 @@ To set the limit of items displayed in a paginated page use the `[api:PaginatedL
public function PaginatedPagesLimit() {
$paginatedItems = new PaginatedList(Page::get(), $this->request);
$paginatedItems->setPageLength(4);
return $pagination;
return $paginatedItems;
}
## Related

View File

@ -192,6 +192,30 @@ would
* Create a MySQLDatabase class, passing dbusername and dbpassword as the
parameters to the constructor
### Testing with Injector in a sandbox environment
In situations where injector states must be temporarily overridden, it is possible
to create nested Injector instances which may be later discarded, reverting the
application to the original state.
This is useful when writing test cases, as certain services may be necessary to
override for a single method call.
For instance, a temporary service can be registered and unregistered as below:
:::php
// Setup default service
Injector::inst()->registerService(new LiveService(), 'ServiceName');
// Test substitute service temporarily
Injector::nest();
Injector::inst()->registerService(new TestingService(), 'ServiceName');
$service = Injector::inst()->get('ServiceName');
// ... do something with $service
Injector::unnest();
// ... future requests for 'ServiceName' will return the LiveService instance
### What are Services?

View File

@ -1286,16 +1286,16 @@ class UploadField extends FileField {
}
/**
* Determines if a specified file exists
* Check if file exists, both checking filtered filename and exact filename
*
* @param SS_HTTPRequest $request
* @param string $originalFile Filename
* @return bool
*/
public function fileexists(SS_HTTPRequest $request) {
protected function checkFileExists($originalFile) {
// Check both original and safely filtered filename
$originalFile = $request->requestVar('filename');
$nameFilter = FileNameFilter::create();
$filteredFile = basename($nameFilter->filter($originalFile));
$filteredFile = $nameFilter->filter($originalFile);
// Resolve expected folder name
$folderName = $this->getFolderName();
@ -1305,17 +1305,32 @@ class UploadField extends FileField {
: ASSETS_PATH."/";
// check if either file exists
$exists = false;
foreach(array($originalFile, $filteredFile) as $file) {
if(file_exists($parentPath.$file)) {
$exists = true;
break;
}
return file_exists($parentPath.$originalFile)
|| file_exists($parentPath.$filteredFile);
}
/**
* Determines if a specified file exists
*
* @param SS_HTTPRequest $request
*/
public function fileexists(SS_HTTPRequest $request) {
// Assert that requested filename doesn't attempt to escape the directory
$originalFile = $request->requestVar('filename');
if($originalFile !== basename($originalFile)) {
$return = array(
'error' => _t('File.NOVALIDUPLOAD', 'File is not a valid upload')
);
} else {
$return = array(
'exists' => $this->checkFileExists($originalFile)
);
}
// Encode and present response
$response = new SS_HTTPResponse(Convert::raw2json(array('exists' => $exists)));
$response = new SS_HTTPResponse(Convert::raw2json($return));
$response->addHeader('Content-Type', 'application/json');
if (!empty($return['error'])) $response->setStatusCode(400);
return $response;
}

View File

@ -2512,8 +2512,7 @@ class i18n extends Object implements TemplateGlobalProvider {
*/
public static function include_by_locale($locale, $clean = false) {
if($clean) {
$cache = Zend_Translate::getCache();
if($cache) $cache->clean(Zend_Cache::CLEANING_MODE_ALL);
Zend_Translate::clearCache();
}
// Get list of module => path pairs, and then just the names

47
javascript/lang/nb.js Normal file
View File

@ -0,0 +1,47 @@
// This file was generated by GenerateJavaScriptI18nTask from javascript/lang/src/nb.js.
// See https://github.com/silverstripe/silverstripe-buildtools for details
if(typeof(ss) == 'undefined' || typeof(ss.i18n) == 'undefined') {
if(typeof(console) != 'undefined') console.error('Class ss.i18n not defined');
} else {
ss.i18n.addDictionary('nb', {
"VALIDATOR.FIELDREQUIRED": "Vennligst fyll ut det påkrevde feltet \"%s\"",
"HASMANYFILEFIELD.UPLOADING": "Laster opp ... %s",
"TABLEFIELD.DELETECONFIRMMESSAGE": "Er du sikker på at du vil slette denne oppføringen?",
"LOADING": "laster ...",
"UNIQUEFIELD.SUGGESTED": "Endret verdien til '%s': %s",
"UNIQUEFIELD.ENTERNEWVALUE": "Du må skrive inn en ny verdi for dette feltet",
"UNIQUEFIELD.CANNOTLEAVEEMPTY": "Dette feltet kan ikke stå tomt",
"RESTRICTEDTEXTFIELD.CHARCANTBEUSED": "Tegnet '%s' kan ikke brukes i dette feltet",
"UPDATEURL.CONFIRM": "Ønsker du å endre adressen til:\n\n%s/\n\nTrykk Ok for å endre adressen, trykk Avbryt for å beholde den som:\n\n%s",
"UPDATEURL.CONFIRMURLCHANGED": "Adressen har blitt endret til\n'%s'",
"FILEIFRAMEFIELD.DELETEFILE": "Slett fil",
"FILEIFRAMEFIELD.UNATTACHFILE": "Fjern vedlagt fil",
"FILEIFRAMEFIELD.DELETEIMAGE": "Slett bilde",
"FILEIFRAMEFIELD.CONFIRMDELETE": "Er du sikker på du vil slette denne filen?",
"LeftAndMain.IncompatBrowserWarning": "Nettleseren din er ikke kompatibel med publiseringsgrensesnittet. Vennligst bruk Internet Explorer 7+, Google Chrome 10+ eller Mozilla Firefox 3.5+.",
"GRIDFIELD.ERRORINTRANSACTION": "En feil oppstod ved lesing fra serveren\nVennligst prøv på nytt senere.",
"HtmlEditorField.SelectAnchor": "Velg et anker",
"UploadField.ConfirmDelete": "Er du sikker på at du vil fjerne denne filen fra serverens filsystem?",
"UploadField.PHP_MAXFILESIZE": "Filen er større enn upload_max_filesize (innstilling i php.ini)",
"UploadField.HTML_MAXFILESIZE": "Filen er større enn MAX_FILE_SIZE (HTML-direktiv)",
"UploadField.ONLYPARTIALUPLOADED": "Filen ble bare delvis lastet opp",
"UploadField.NOFILEUPLOADED": "Ingen filer ble lastet opp",
"UploadField.NOTMPFOLDER": "Mangler en midlertidig mappe",
"UploadField.WRITEFAILED": "Klarte ikke å lagre filen på harddisken",
"UploadField.STOPEDBYEXTENSION": "Filopplastingen ble stoppet av en utvidelse",
"UploadField.TOOLARGE": "Filen er for stor",
"UploadField.TOOSMALL": "Filen er for liten",
"UploadField.INVALIDEXTENSION": "Filtypen er ikke tillatt",
"UploadField.MAXNUMBEROFFILESSIMPLE": "For mange filer",
"UploadField.UPLOADEDBYTES": "Lastet opp flere bytes enn filstørrelsen tilsier",
"UploadField.EMPTYRESULT": "Filopplastingen ga et tomt resultat",
"UploadField.LOADING": "Laster ...",
"UploadField.Editing": "Redigerer ...",
"UploadField.Uploaded": "Lastet opp",
"UploadField.OVERWRITEWARNING": "En fil med samme navn eksisterer allerede",
"TreeDropdownField.ENTERTOSEARCH": "Trykk enter for å søke",
"TreeDropdownField.OpenLink": "Åpne",
"TreeDropdownField.FieldTitle": "Velg",
"TreeDropdownField.SearchFieldTitle": "Velg eller søk"
});
}

View File

@ -233,7 +233,6 @@ af:
PERMAGAIN: 'Jy is uit die IBS uitgeteken. As jy weer wil inteken, moet jy ''n gebruikersnaam en wagwoord onder in tik'
PERMALREADY: 'Ek is jammer, maar jy het nie toestemming om dié gedeelte van die IBS te besugtig nie. As jy as iemand anders wil inteken doen so hieronder'
PERMDEFAULT: 'Kies asseblief ''n kontroleer metode en sleutel jou sekuriteit''s besonderhede in'
PLEASESAVE: 'Stoor asseblief die bladsy: Die bladsy kon nie opgedateer word nie omdat dit nog nie gestoor is nie'
PreviewButton: Beskou
REORGANISATIONSUCCESSFUL: 'Die ''site tree'' is suksesvol geheorganiseer'
SAVEDUP: Gestoor

View File

@ -302,7 +302,6 @@ ar:
PERMAGAIN: 'تم خروجك من النظام بنجاح. للدخول مرة أخرى أدحل البريد الإلكتروني و الرقم السري بالأسفل'
PERMALREADY: 'عذراً , لكن لا يمكنك الوصول لهذا القسم من النظام. يتوجب عليك الدخول بصلاحية أخرى'
PERMDEFAULT: 'أدخل البريد الإلكتروني و الرقم السري للوصول إلى نظام إدارة المحتوى'
PLEASESAVE: 'فضلاً احفظ الصفحة: هذه الصفحة لا يمكن تحديثها لأنها لم تحفظ بعد'
PreviewButton: استعراض
REORGANISATIONSUCCESSFUL: 'تم إعادة تنظيم خريطة الموقع بنجاح'
SAVEDUP: تم الحفظ.

View File

@ -220,7 +220,6 @@ bg:
PERMAGAIN: 'Вие излязохте от CMS. Ако искате да влезете отново, моля, въведете потребителско име и парола.'
PERMALREADY: 'Съжалявам, но нямате достъп до тази част от CMS. Ако искате да влезете с друго потребителско име, моля, направете го по-долу'
PERMDEFAULT: 'Въведете имейл адреса и паролата си, за да влезете в CMS.'
PLEASESAVE: 'Съхрани страницата: Тази страница не може да бъде обновена, защото още не е записана.'
PreviewButton: Преглед
REORGANISATIONSUCCESSFUL: 'Реорганизацията на дървото на сайта беше успешна.'
SAVEDUP: Записано

View File

@ -104,7 +104,6 @@ bs:
PERMAGAIN: 'Odjavljeni ste sa CMS-a. Ukoliko se želite ponovo prijaviti, unesite korisničko ime i šifru ispod.'
PERMALREADY: 'Žao nam je ali ne možete pristupiti ovom dijelu CMS-a. Ako se želite prijaviti sa drugim korisnikom uradite to ispod'
PERMDEFAULT: 'Unesite vašu e-mail adresu i šifru kako biste pristupili CMS-u.'
PLEASESAVE: 'Molimo snimite stranicu: Ova stranica ne može biti ažurirana ako nije prethodno snimljena.'
Member:
BUTTONCHANGEPASSWORD: 'Promijeni šifru'
BUTTONLOGIN: 'Prijava'

View File

@ -123,7 +123,6 @@ ca:
PERMAGAIN: 'Heu estat desconnectat del SGC. Si voleu entrar de nou, introduïu un nom d''usuari i contrasenya a sota'
PERMALREADY: 'Lamentant-ho molt, no podeu accedir a aquesta part del SGC. Si voleu entrar com a algú altre, feu-ho a sota'
PERMDEFAULT: 'Introduïu la vostra adreça de correu electrònic i la contrasenya per a entrar al SGC.'
PLEASESAVE: 'Si us plau, deseu la pàgina: aquesta pàgina no s''ha pogut actualitzar perquè encara no s''ha desat.'
LoginAttempt:
Email: 'Adreça de correu'
IP: 'Adreça IP'

View File

@ -307,7 +307,7 @@ cs:
PERMAGAIN: 'Byli jste odhlášeni z CMS. Pokud se chcete znovu přihlásit, zadejte níže své uživatelské jméno a heslo.'
PERMALREADY: 'Je nám líto, ale nemůžete vstoupit do této části CMS. Pokud se chcete přihlásit jako někdo jiný, udělejte tak níže'
PERMDEFAULT: 'Pro přístup do CMS zadejte Vaši e-mailovou adresu a heslo.'
PLEASESAVE: 'Prosím uložte stránku: Tato stránka nemohla být aktualizována, protože ještě nebyla uložena.'
PLEASESAVE: 'Uložte stránku, prosím. Tato stránka nemůže být aktualizována, protože ještě nebyla uložena.'
PreviewButton: Náhled
REORGANISATIONSUCCESSFUL: 'Strom webu reorganizován úspěšně.'
SAVEDUP: Uloženo.

View File

@ -20,7 +20,6 @@ da:
PERMAGAIN: 'Du er blevet logget ud af CMS, hvis du vil logge ind igen, indtast brugernavn og kodeord nedenfor.'
PERMALREADY: 'Beklager, men du kan ikke få adgang til denne del af CMS, hvis du vil logge ind som en anden, kan du gøre det nedenfor'
PERMDEFAULT: 'Indtast din email adresse og kodeord for at få adgang til CMS systemet'
PLEASESAVE: 'Gem siden: Denne side kunne ikke blive opdateret, fordi den endnu ikke er gemt.'
ModelAdmin:
DELETE: Slet
IMPORT: 'Importer fra CSV'

View File

@ -309,7 +309,6 @@ de:
PERMAGAIN: 'Sie wurden aus dem System ausgeloggt. Falls Sie sich wieder einloggen möchten, geben Sie bitte Benutzernamen und Passwort im untenstehenden Formular an.'
PERMALREADY: 'Leider dürfen Sie diesen Teil des CMS nicht aufrufen. Wenn Sie sich als jemand anderes einloggen wollen, benutzen Sie bitte das nachstehende Formular.'
PERMDEFAULT: 'Bitte wählen Sie eine Authentifizierungsmethode und geben Sie Ihre Benutzerdaten für den Zugang zum CMS ein.'
PLEASESAVE: 'Diese Seite konnte nicht aktualisiert werden weil sie noch nicht gespeichert wurde - bitte speichern.'
PreviewButton: Vorschau
REORGANISATIONSUCCESSFUL: 'Der Seitenbaum wurde erfolgreich sortiert.'
SAVEDUP: Gespeichert.

View File

@ -18,7 +18,6 @@ en_GB:
PAGETYPE: 'Page type:'
PERMAGAIN: 'You have been logged out of the CMS. If you would like to log in again, enter a username and password below.'
PERMALREADY: 'I''m sorry, but you can''t access that part of the CMS. If you want to log in as someone else, do so below'
PLEASESAVE: 'Please Save Page: This page could not be updated because it hasn''t been saved yet.'
Member:
ERRORNEWPASSWORD: 'Your have entered your new password differently, try again'
Security:

View File

@ -137,7 +137,6 @@ eo:
PERMAGAIN: 'Vin adiaŭis la CMS. Se vi volas denove saluti, enigu salutnomon kaj pasvorton malsupre.'
PERMALREADY: 'Bedaŭrinde vi ne povas aliri tiun parton de la CMS. Se vi volas saluti kiel iu alia, tiel faru sube'
PERMDEFAULT: 'Enigi vian retadreson kaj pasvorton por aliri al la CMS.'
PLEASESAVE: 'Bonvolu konservi paĝon: Ne eblis ĝisdatigi ĉi tiun paĝon ĉar ĝi ankoraŭ ne estas konservita.'
LoginAttempt:
Email: 'Retadreso'
IP: 'IP-Adreso'

View File

@ -171,6 +171,7 @@ es:
TEXT2: 'enlace para restablecer contraseña'
TEXT3: para
Form:
CSRF_FAILED_MESSAGE: "Parece que hay un problema técnico. Por favor presionar el botón volver \n\n⇥⇥⇥⇥⇥refresca tu navegador e intenta nuevamente"
FIELDISREQUIRED: 'Se requiere este campo'
SubmitBtnLabel: Ir
VALIDATIONCREDITNUMBER: 'Por favor, asegúrese de que ha introducido el número de tarjeta de crédito correctamente {number}'
@ -180,6 +181,7 @@ es:
VALIDATIONSTRONGPASSWORD: 'Las contraseñas deben tener al menos un dígito y un carácter alfanumérico'
VALIDATOR: Validador
VALIDCURRENCY: 'Por favor, introduzca una moneda válida.'
CSRF_EXPIRED_MESSAGE: 'Tu sesión ha expirado. Por favor re envíe el formulario'
FormField:
Example: 'Ejemplo'
NONE: ninguna
@ -305,7 +307,7 @@ es:
PERMAGAIN: 'Ha sido desconectado del CMS. Si quiere volver a entrar, introduzca su nombre de usuario y contraseña a continuación.'
PERMALREADY: 'Lamentablemente no puede acceder a esta parte del CMS. Si quiere entrar como alguien distinto, hágalo a continuación'
PERMDEFAULT: 'Introduzca su correo electrónico y su contraseña para acceder al CMS.'
PLEASESAVE: 'Por favor Guarde la Página: Esta página no se ha podido actualizar porque aún no ha sido salvada.'
PLEASESAVE: 'Por favor guardar la página: Esta página no puede ser actualizada porque no ha sido guardada aún.'
PreviewButton: Vista previa
REORGANISATIONSUCCESSFUL: 'Reorganizado el árbol del sitio con éxito.'
SAVEDUP: Guardado
@ -473,6 +475,7 @@ es:
ERRORPASSWORDPERMISSION: 'Debe iniciar una sesión para poder cambiar su contraseña!'
LOGGEDOUT: 'Ha terminado su sesión. Si desea iniciar sesión nuevamente, introduzca sus datos de acreditación a continuación.'
LOGIN: 'Entrar'
LOSTPASSWORDHEADER: '¿Contraseña Perdida?'
NOTEPAGESECURED: 'Esa página está protegida. Introduzca sus datos de acreditación a continuación y lo enviaremos a ella en un momento.'
NOTERESETLINKINVALID: '<p>El enlace para restablecer la contraseña es inválido o ha expirado.</p><p>Usted puede solicitar uno nuevo <a href="{link1}">aqui</a> o cambiar su contraseña después de que se haya <a href="{link2}">conectado</a>.</p>'
NOTERESETPASSWORD: 'Introduzca su dirección de e-mail, y le enviaremos un enlace, con el cual podrá restaurar su contraseña'

View File

@ -136,7 +136,6 @@ es_AR:
PERMAGAIN: 'Haz sido desconectado del CMS. Si quieres volver a entrar, a continuación introduce tu nombre de usuario y contraseña.'
PERMALREADY: 'Lamentablemente no puedes ingresar a esta parte del CMS. Si quieres entrar como alguien distinto, haz eso a continuación'
PERMDEFAULT: 'Por favor elegir un método de autenticación e ingresar sus credenciales para acceder al CMS.'
PLEASESAVE: 'Por favor Guarda la Página: No se puede actualizar esta página porque aún no se ha guardado.'
LoginAttempt:
Email: 'Dirección Email'
IP: 'Dirección IP'

View File

@ -187,7 +187,6 @@ es_MX:
PERMAGAIN: 'Usted ha sido desconectado del CMS. Si quiere volver a entrar, introduzca su nombre de usuario y contraseña.'
PERMALREADY: 'Lamentablemente no puedes ingresar a esta parte del CMS. Si quieres entrar como alguien distinto, hazlo a continuación'
PERMDEFAULT: 'Por favor, elija un método de autenticación e introduzca sus credenciales para acceder al CMS.'
PLEASESAVE: 'Por favor Guarda la Página: No se puede actualizar esta página porque aún no se ha guardado.'
VersionUnknown: desconocido
LoginAttempt:
Email: 'Dirección de Correo Electrónico'

View File

@ -279,7 +279,6 @@ et_EE:
PERMAGAIN: 'Oled Sisuhaldusest välja logitud. Kui soovite uuesti sisse logida sisestage kasutajanimi ja parool.'
PERMALREADY: 'Vabandust, aga sul pole lubatud sisuhaldussüsteemi selle osa juurde pääseda. Kui soovid kellegi teisena sisse logida, tee seda allpool.'
PERMDEFAULT: 'Sisesta oma e-posti aadress ja parool sisuhaldussüsteemi ligipääsemiseks.'
PLEASESAVE: 'Palun Salvesta Lehekülg: Antud lehekülge ei uuendatud, kuna seda ei ole veel salvestatud.'
PreviewButton: Eelvaade
REORGANISATIONSUCCESSFUL: 'Saidipuu korraldati edukalt ümber.'
SAVEDUP: Salvestatud.

View File

@ -99,7 +99,6 @@ fa_IR:
PAGETYPE: 'نوع صفحه'
PERMAGAIN: 'شما از سیستم مدیریت محتوا خارج شده اید.اگر میخواهید دوباره وارد شوید نام کاربری و رمز عبور خود را در قسمت زیر وارد کنید'
PERMALREADY: 'من متاسفم، شما نمی توانید به آن قسمت از سیستم مدیریت محتوا دسترسی پیدا کنید. اگر میخواهید به عنوان شخص دیگری وارد شوید از قسمت زیر تلاش کنید'
PLEASESAVE: 'لطفاً صفحه را ذخیره کنید : این صفحه نمی تواند بروز شود چراکه هنوز ذخیره نشده است.'
LoginAttempt:
Email: 'آدرس های ایمیل'
Member:

View File

@ -309,7 +309,6 @@ fi:
PERMAGAIN: 'Olet kirjautunut ulos CMS:stä. Jos haluat kirjautua uudelleen sisään, syötä käyttäjätunnuksesi ja salasanasi alla.'
PERMALREADY: 'Paihoittelut, mutta et pääse tähän osaan CMS:ää. Jos haluat kirjautua jonain muuna, voit tehdä sen alla.'
PERMDEFAULT: 'Valitse tunnistustapa ja syötä tunnistetietosi CMS:ään.'
PLEASESAVE: 'Tätä sivua ei voitu päivittää, koska sitä ei ole vielä tallennettu. Tallenna sivu.'
PreviewButton: Esikatselu
REORGANISATIONSUCCESSFUL: 'Hakemistopuu järjestettiin uudelleen onnistuneesti.'
SAVEDUP: Tallennettu.

View File

@ -92,7 +92,6 @@ fo:
PERMAGAIN: 'Tú ert blivin útritaður av CMS skipanini. Um tú ynskir at innrita aftur, inntøppa so títt brúkaranavn og loyniorð niðanfyri:'
PERMALREADY: 'Tíanverri, tú hevur ikki atgongd til handan partin av CMS skipanini. Um tú ynskir at innrita sum onkur annar, so kann tú gera tað niðanfyri.'
PERMDEFAULT: 'Inntøppa tygara teldupost og loyniorð fyri at fáa atgongd til CMS skipanina.'
PLEASESAVE: 'Vinarliga goym síðuna: Hendan síðan kundi ikki blíva dagført, tí at hon er ikki goymd enn.'
LoginAttempt:
Email: 'Teldupostur'
IP: 'IP adressa'

View File

@ -301,7 +301,6 @@ fr:
PERMAGAIN: 'Vous avez été déconnecté du CMS. Si vous voulez vous reconnecter, entrez un nom d''utilisateur et un mot de passe ci-dessous.'
PERMALREADY: 'Désolé, mais vous ne pouvez pas accéder à cette partie du CMS. Si vous voulez changer d''identité, faites le ci-dessous'
PERMDEFAULT: 'Saisissez votre adresse de courriel et votre mot de passe pour accéder au CMS.'
PLEASESAVE: 'Enregistrez la page sil vous plaît&nbsp;: elle ne pouvait pas être mise à jour car elle navait pas encore été sauvegardée.'
PreviewButton: Aperçu
REORGANISATIONSUCCESSFUL: 'Larbre du site a été bien réorganisé.'
SAVEDUP: Enregistré.

View File

@ -162,7 +162,6 @@ gl_ES:
PERMAGAIN: 'Non tes unha sesión válida no CMS. Se queres volver entrar, insire o nome de usuario e contrasinal a continuación.'
PERMALREADY: 'Sintoo, pero non podes acceder a esta parte do CMS. Se queres iniciar sesión con outras credenciais, faino a continuación'
PERMDEFAULT: 'Escolle un método de autenticación e insire as túas credenciais para acceder o CMS.'
PLEASESAVE: 'Por favor Garda Páxina: Esta páxina podería non ser actualizada porque inda non foi gardada.'
VersionUnknown: descoñecido
LoginAttempt:
Email: 'Enderezo Correo-e'

View File

@ -67,7 +67,6 @@ he_IL:
PERMAGAIN: 'התנתקת מהמערכת. לחיבור מחדש נא להזין שם וסיסמה'
PERMALREADY: 'צר לנו, אך לא תוכל לגשת לחלק זה של מערכת ניהול התוכן. אם ברצונך להתחבר למערכת בתור משתמש אחר נא להשתמש בתיבה בעמוד זה'
PERMDEFAULT: 'נא לבחור בשיטת וידוא והזן פרטיך למערכת'
PLEASESAVE: 'נא לשמור עמוד זה. העמוד לא עודכן מכיוון ולא עודכן.'
Member:
BUTTONCHANGEPASSWORD: 'שנה סיסמא'
BUTTONLOGIN: 'התחבר'

View File

@ -75,7 +75,6 @@ hr:
PERMAGAIN: 'Odjavili ste se sa CMS-a. Želite li se ponovno prijaviti, upišite korisničko ime i lozinku'
PERMALREADY: 'Nažalost, ne možete pristupiti tom dijelu CMS-a. Želite li se prijaviti kao netko drugi, učinite to ispod'
PERMDEFAULT: 'Odaberite metodu autorizacije te upišite svoje podatke za pristup CMS-u.'
PLEASESAVE: 'Molim spremite stranicu: Nemože biti ažurirano dok nije spremljeno.'
Member:
BUTTONCHANGEPASSWORD: 'Promjeni lozinku'
BUTTONLOGIN: 'Prijavi'

View File

@ -71,7 +71,6 @@ hu:
PERMAGAIN: 'Kiléptetésre kerültél a CMS-ből. Ha újra be szeretnél lépni, add meg alább a felhasználóneved és jelszavad.'
PERMALREADY: 'Nincs jogosultságod a CMS ezen részének megtekintéséhez. Ha be szeretnél jelentkezni más felhasználóként, lejjebb megteheted.'
PERMDEFAULT: 'A CMS- be való belépéshez, kérünk válassz egy azonosítási módot, és írd be az azonosítási infomációkat.'
PLEASESAVE: 'Kérjük, mentsd el az oldalt: az oldalt nem lehetett frissíteni, mivel még nem került elmentésre.'
Member:
BUTTONCHANGEPASSWORD: 'Jelszó megváltoztatása'
BUTTONLOGIN: 'Bejelentkezés'

View File

@ -297,7 +297,6 @@ it:
PERMAGAIN: 'Sei stato disconnesso dal CMS. Se desideri autenticarti nuovamente, inserisci qui sotto nome utente e password.'
PERMALREADY: 'Siamo spiacenti, ma non puoi accedere a questa sezione del CMS. Se desideri autenticarti come qualcun altro, fallo qui sotto.'
PERMDEFAULT: 'Inserisci il tuo indirizzo email e password per accedere al CMS.'
PLEASESAVE: 'Per favore salva la pagina: La stessa potrebbe non venire aggiornata se non si provvede quanto prima a salvarla.'
PreviewButton: Anteprima
REORGANISATIONSUCCESSFUL: 'Albero del sito riorganizzato con successo.'
SAVEDUP: Salvato.

View File

@ -301,7 +301,6 @@ ja:
PERMAGAIN: 'ログアウトしました。再度ログインする場合は下にユーザー名とパスワードを入力してください。'
PERMALREADY: '申し訳ございません。ご指定になられたCMSの箇所にはアクセスいただけません。別ユーザーとしてログインをされたい場合は、下記より行えます。'
PERMDEFAULT: '認証方法を選択し、CMSにアクセスするために利用する認証情報を入力してください。'
PLEASESAVE: '保存してください: 保存してないため更新できません。'
PreviewButton: プレビュー
REORGANISATIONSUCCESSFUL: 'サイトツリーの再編集に成功しました。'
SAVEDUP: 保存済み

View File

@ -303,7 +303,6 @@ mi:
PERMAGAIN: 'Kua takiputaina atu koe i te CMS. Ki te pīrangi koe ki te takiuru atu anō, tāurutia tētahi ingoa kaiwhakamahi me te kupuhipa i raro.'
PERMALREADY: 'Aroha mai, kāore e taea te whakauru i tērā wāhanga o te CMS. Ki te pīrangi koe ki te takiuru atu mā tētahi atu ingoa, whakamahia ki raro nei.'
PERMDEFAULT: 'Whiriwhiria tētahi aratuka motuhēhēnga me te tāuru i ō taipitopito tuakiri ki te uru ki te CMS.'
PLEASESAVE: 'Tiaki Whārangi: Kāore i taea tēnei whārangi te whakahōu nā te mea kāore anō kia tiakina.'
PreviewButton: Arokite
REORGANISATIONSUCCESSFUL: 'Kua momoho te whakaraupapa anō i te rākau pae'
SAVEDUP: Kua Tiakina

View File

@ -123,6 +123,7 @@ nb:
INVALID_REQUEST: 'Ugyldig forespørsel'
DropdownField:
CHOOSE: (Velg)
CHOOSESEARCH: '(Velg eller søk)'
EmailField:
VALIDATION: 'Vennligst skriv inn en epostadresse'
Enum:
@ -170,6 +171,7 @@ nb:
TEXT2: 'lenke for nullstilling av passord'
TEXT3: for
Form:
CSRF_FAILED_MESSAGE: "Det ser ut til å ha oppstått et teknisk problem. Vennligst trykk på tilbakeknappen, oppdater nettsiden og prøv på nytt."
FIELDISREQUIRED: '{name} er påkrevet'
SubmitBtnLabel: Utfør
VALIDATIONCREDITNUMBER: 'Vennligst sjekk at du har skrevet inn {number} korrekt kortnummer'
@ -192,7 +194,7 @@ nb:
FilterBy: 'Filtrer på '
Find: Finn
LEVELUP: 'Opp ett nivå'
LinkExisting: 'Eksisterende lenke'
LinkExisting: 'Knytt til eksisterende'
NewRecord: 'Ny %s'
NoItemsFound: 'Ingen elementer ble funnet'
PRINTEDAT: 'Skrevet ut ved'
@ -264,6 +266,8 @@ nb:
FROMWEB: 'Fra internett'
FindInFolder: 'Finn i mappe'
IMAGEALT: 'Alternativ tekst (alt)'
IMAGEALTTEXT: 'Alternativ tekst (alt) - blir brukt hvis bildet ikke kan vises'
IMAGEALTTEXTDESC: 'Blir vist til skjermlesere eller hvis bildet ikke kan vises'
IMAGEDIMENSIONS: Dimensjoner
IMAGEHEIGHTPX: Høyde
IMAGETITLE: 'Titteltekst (tooltip) - for tilleggsinformasjon om bildet'
@ -465,6 +469,7 @@ nb:
ERRORPASSWORDPERMISSION: 'Du må logge inn for å bytte passord.'
LOGGEDOUT: 'Du har blitt logget ut. Hvis du vil logge inn igjen, så gjør du det under.'
LOGIN: 'Logg inn'
LOSTPASSWORDHEADER: 'Mistet passord'
NOTEPAGESECURED: 'Den siden er sikret. Skriv inn gyldig innloggingsinfo så kommer du inn.'
NOTERESETLINKINVALID: '<p>Lenken for å nullstille passordet er ugyldig eller utgått.</p><p>Du kan kreve en ny <a href="{link1}">her</a> eller endre passordet etter at du har <a href="{link2}">logget inn</a>.</p>'
NOTERESETPASSWORD: 'Skriv inn epostadressen din og vi vil sende deg en lenke som nullstiller passordet.'

View File

@ -307,7 +307,6 @@ nl:
PERMAGAIN: 'U bent uitgelogd uit het CMS. Als U weer wilt inloggen vul dan uw gebruikersnaam en wachtwoord hier beneden in.'
PERMALREADY: 'Helaas, dat deel van het CMS is niet toegankelijk voor U. Hieronder kunt U als iemand anders inloggen.'
PERMDEFAULT: 'Geef uw e-mailadres en wachtwoord voor toegang tot het CMS.'
PLEASESAVE: 'Deze pagina kon niet bijgewerkt worden, omdat deze nog niet is bewaard.'
PreviewButton: Voorbeeld
REORGANISATIONSUCCESSFUL: 'Menu-indeling is aangepast'
SAVEDUP: Opgeslagen

View File

@ -305,7 +305,6 @@ pl:
PERMAGAIN: 'Zostałeś wylogowany z CMSa. Jeśli chcesz zalogować się ponownie, wpisz login i hasło poniżej.'
PERMALREADY: 'Niestety nie masz dostępu do tej części CMS. Jeśli chcesz zalogować się jako ktoś inny, zrób to poniżej'
PERMDEFAULT: 'Proszę wybrać metodę identyfikacji i wpisać swoje dane, aby uruchomić CMSa.'
PLEASESAVE: 'Proszę zapisać stronę. Ta strona nie mogła zostać uaktualniona, ponieważ nie została jeszcze zapisana.'
PreviewButton: Podgląd
REORGANISATIONSUCCESSFUL: 'Pomyślnie zreorganizowano drzewo serwisu.'
SAVEDUP: Zapisano.

View File

@ -123,7 +123,6 @@ pt_BR:
PERMAGAIN: 'Você foi desconectado do CMS. Se você quiser entrar novamente, digite um nome de usuário e senha abaixo.'
PERMALREADY: 'Sinto muito, mas você não pode acessar essa parte do CMS. Se você quiser entrar como outra pessoa, faça-o abaixo.'
PERMDEFAULT: 'Por favor, entre com seu e-mail e senha para entrar no sistema.'
PLEASESAVE: 'Por favor salve a página: Esta página não pode ser atulizada porque ainda não foi salva.'
LoginAttempt:
Email: 'Endereço de E-mail'
IP: 'Endereço IP'

View File

@ -306,7 +306,6 @@ ru:
PERMAGAIN: 'Вы вышли из Системы Управления Сайтом. Если Вы хотите войти снова, введите внизу имя пользователя и пароль.'
PERMALREADY: 'Извините, у вас нет доступа к этому разделу Системы Управления. Если Вы хотите войти под другой учетной записью, сделайте это ниже'
PERMDEFAULT: 'Введите ваши адрес электр. почты и пароль для доступа к системе.'
PLEASESAVE: 'Пожалуйста, сохраните страницу: ее нельзя обновить, т.к. она еще не была сохранена.'
PreviewButton: Просмотр
REORGANISATIONSUCCESSFUL: 'Древесная структура сайта успешно реорганизована.'
SAVEDUP: Сохранено.

View File

@ -82,7 +82,6 @@ si:
PERMAGAIN: 'ඹබ CMS ඵකෙන් ඉවත් වී ඇත. නැවත ඇතුල් වීමට නම හා මුරපදය යොදන්න'
PERMALREADY: 'සමාවන්න ඔබට මෙම කොටස පරිශීලනය කල නොහැක. පහතින් වෙනත් නමකින් ඇතුල් වන්න'
PERMDEFAULT: 'හදුනාගැනීමේ ක්රමයක් තෝරා ඹබගේ දත්ත ඇතුල් කරන්න'
PLEASESAVE: 'පිටුව සේව් කරන්න, නැතිනම් මෙම පිටුව යාවත්කාලීන කල නොහැක'
Member:
BUTTONCHANGEPASSWORD: 'මුර පදය අලුත් කරන්න'
BUTTONLOGIN: 'ඇතුල්වන්න'

View File

@ -307,7 +307,7 @@ sk:
PERMAGAIN: 'Boli ste odhlásený'
PERMALREADY: 'Je mi ľúto, ale nemáte prístup k tejto časti CMS. Ak sa chcete prihlásiť ako niekto iný, urobte tak nižšie'
PERMDEFAULT: 'Vyberte si prosím metódu autentifikácie a zadajte svoje prístupové údaje k CMS.'
PLEASESAVE: 'Prosím uložte stránku: Táto stránka nemôže byť aktualizovaná, lebo ešte nebola uložená.'
PLEASESAVE: 'Uložte stránku, prosím. Táto stránka nemôže byť aktualizovaná, pretože eště nebola uložená.'
PreviewButton: Náhľad
REORGANISATIONSUCCESSFUL: 'Strom webu bol reorganizovaný úspešne.'
SAVEDUP: Uložené.

View File

@ -238,7 +238,6 @@ sl:
PERMAGAIN: 'Odjavili ste se iz CMS-vmesnika. Če se želite ponovno prijaviti, vpišite uporabniško ime in geslo.'
PERMALREADY: 'Do tega dela CMS-vmesnika nimate dostopa. Če se želite vpisati z drugim uporabniškim imenom, lahko to storite spodaj'
PERMDEFAULT: 'Izberite način avtentikacije in vpišite svoje podatke za dostop do CMS-vmesnika.'
PLEASESAVE: 'Shranite stran: te strani ne morete posodobiti, ker še ni bila shranjena.'
PreviewButton: Predogled
REORGANISATIONSUCCESSFUL: 'Struktura spletnega mesta je bila uspešno spremenjena.'
SAVEDUP: Shranjeno.

View File

@ -305,7 +305,6 @@ sr:
PERMAGAIN: 'Одјављени сте са CMS-а. Уколико желите да се поново пријавите, унесите корисничко име и лозинку.'
PERMALREADY: 'Не можете да приступите овом делу CMS-а. Ако желите да се пријавите као неко други, урадите то испод'
PERMDEFAULT: 'Изаберите методу аутентификације и унесите податке за приступ CMS-у.'
PLEASESAVE: 'Сачувајте страну: ова страна не може да буде ажурирана јер још увек није сачувана.'
PreviewButton: Претходни преглед
REORGANISATIONSUCCESSFUL: 'Стабло сајта је успешно реорганизовано.'
SAVEDUP: Сачувано.

View File

@ -305,7 +305,6 @@ sr_RS:
PERMAGAIN: 'Одјављени сте са CMS-а. Уколико желите да се поново пријавите, унесите корисничко име и лозинку.'
PERMALREADY: 'Не можете да приступите овом делу CMS-а. Ако желите да се пријавите као неко други, урадите то испод'
PERMDEFAULT: 'Изаберите методу аутентификације и унесите податке за приступ CMS-у.'
PLEASESAVE: 'Сачувајте страну: ова страна не може да буде ажурирана јер још увек није сачувана.'
PreviewButton: Претходни преглед
REORGANISATIONSUCCESSFUL: 'Стабло сајта је успешно реорганизовано.'
SAVEDUP: Сачувано.

View File

@ -259,7 +259,6 @@ sv:
PERMAGAIN: 'Du har blivit utloggad. Om du vill logga in igen anger du dina uppgifter nedan.'
PERMALREADY: 'Tyvärr så har du inte tillträde till den delen av CMSet. Om du vill logga in med en annan användare kan du göra det nedan'
PERMDEFAULT: 'Var god välj en inloggningsmetod och fyll i dina uppgifter för att logga in i CMSet.'
PLEASESAVE: 'Var god spara sidan. Den kan inte uppdateras för att den har inte sparats ännu.'
PreviewButton: Förhandsgranska
REORGANISATIONSUCCESSFUL: 'Omorganisationen av sidträdet luyckades.'
SAVEDUP: Sparad.

View File

@ -209,7 +209,6 @@ th:
PERMAGAIN: 'คุณได้ออกจากระบบของ CMS แล้ว หากคุณต้องการเข้าสู่ระบบอีกครั้ง กรุณากรอกชื่อผู้ใช้งานและรหัสผ่านของคุณด้านล่าง'
PERMALREADY: 'ขออภัย, คุณไม่สามารถเข้าใช้งานในส่วนนี้ของ CMS ได้ หากคุณต้องการเข้าสู่ระบบในชื่ออื่นได้จากด้านล่าง'
PERMDEFAULT: 'กรุณาเลือกวิธีการยืนยันตัวบุคคลและกรอกข้อมูลประจำตัวเพื่อเข้าใช้งาน CMS'
PLEASESAVE: 'กรุณาบันทึกหน้าเว็บ หน้าเว็บนี้ยังไม่สามรถอัพเดทข้อมูลได้ เนื่องจากยังไม่ได้ถูกบันทึกข้อมูล'
LeftAndMain_Menu_ss:
Hello: สวัสดีค่ะ
LOGOUT: 'ออกจากระบบ'

View File

@ -137,7 +137,6 @@ tr:
PERMAGAIN: 'İYS yönetiminden çıkış yaptınız. Eğer tekrar giriş yapmak isterseniz, aşağıya kullanıcı adı ve şifrenizi giriniz.'
PERMALREADY: 'Üzgünüm ama İYS''nin bu bölümüne erişim hakkınız yok. Başka bir kullanıcı olarak giriş yapmak istiyorsanız aşağıdan bunu yapabilirsiniz'
PERMDEFAULT: 'İYS erişimi için eposta adresinizi ve parolanızı giriniz.e kolaylık sağlama'
PLEASESAVE: 'Lütfen Sayfayı Kaydedin: Bu sayfa henüz kaydedilmediği için güncellenemedi.'
PreviewButton: Önizleme
SAVEDUP: Kaydedilmiş.
LoginAttempt:

View File

@ -142,7 +142,6 @@ uk:
PERMAGAIN: 'Ви вийшли з системи. Якщо Ви хочете повторно ідентифікуватися, введіть дані нижче.'
PERMALREADY: 'Вибачте, та Ви не маєте доступу до цієї чатини системи. Якщо Ви хочете ідентифікуватися як хтось інший, зробіть це нижче '
PERMDEFAULT: 'Будь ласка, оберіть метод ідентифікації та введіть дані доступу до системи.'
PLEASESAVE: 'Будь ласка, збережіть сторінку: Ця сторінка не може бути оновлена, бо вона ще не була збережена.'
LeftAndMain_Menu_ss:
Hello: Привіт
LOGOUT: 'Вилогуватися'

View File

@ -305,7 +305,6 @@ zh:
PERMAGAIN: '您已经退出 CMS。如果您想再次登录请在下面输入用户名和密码。'
PERMALREADY: '抱歉,您不能访问 CMS 的这一部分。如果您想以不同的身份登录,请在下面进行操作'
PERMDEFAULT: '请选择一种认证方法并输入您的凭据以访问 CMS。'
PLEASESAVE: '请保存页面:不能更新该页面因为它还没有被保存。'
PreviewButton: 预览
REORGANISATIONSUCCESSFUL: '重新组织网站地图已成功'
SAVEDUP: 已保存。

View File

@ -73,7 +73,6 @@ zh_CN:
PERMAGAIN: '您于CMS的登录已被注销请在下面输入用户名和密码重新登录。'
PERMALREADY: '对不起您无权登录CMS的这一部分。如果您要用另外的帐号请在下面登录。'
PERMDEFAULT: '请先选择一种验证方法并输入您的权限信息以登录CMS。'
PLEASESAVE: '请先保存:因为该网页还未保存,所以该页无法更新。'
Member:
BUTTONCHANGEPASSWORD: '更改密码'
BUTTONLOGIN: '登录'

View File

@ -59,7 +59,6 @@ zh_TW:
PERMAGAIN: '您已被登出,請在下面重新登入。'
PERMALREADY: '抱歉,您沒有權力使用這個部分。您可以用別的帳號登入。'
PERMDEFAULT: '請選擇一個認證方法並登入。'
PLEASESAVE: '請儲存:這個網頁沒有被更新因為尚未被儲存。'
Member:
BUTTONCHANGEPASSWORD: '更改密碼'
BUTTONLOGIN: '登入'

View File

@ -149,11 +149,13 @@ class DataQuery {
}
$query = clone $this->query;
$ancestorTables = ClassInfo::ancestry($this->dataClass, true);
// Generate the list of tables to iterate over and the list of columns required by any existing where clauses.
// This second step is skipped if we're fetching the whole dataobject as any required columns will get selected
// regardless.
// Generate the list of tables to iterate over and the list of columns required
// by any existing where clauses. This second step is skipped if we're fetching
// the whole dataobject as any required columns will get selected regardless.
if($queriedColumns) {
// Specifying certain columns allows joining of child tables
$tableClasses = ClassInfo::dataClassesFor($this->dataClass);
foreach ($query->getWhere() as $where) {
@ -163,8 +165,9 @@ class DataQuery {
if (!in_array($matches[1], $queriedColumns)) $queriedColumns[] = $matches[1];
}
}
} else {
$tableClasses = $ancestorTables;
}
else $tableClasses = ClassInfo::ancestry($this->dataClass, true);
$tableNames = array_keys($tableClasses);
$baseClass = $tableNames[0];
@ -172,30 +175,26 @@ class DataQuery {
// Iterate over the tables and check what we need to select from them. If any selects are made (or the table is
// required for a select)
foreach($tableClasses as $tableClass) {
$joinTable = false;
// If queriedColumns is set, then check if any of the fields are in this table.
// Determine explicit columns to select
$selectColumns = null;
if ($queriedColumns) {
// Restrict queried columns to that on the selected table
$tableFields = DataObject::database_fields($tableClass);
$selectColumns = array();
// Look through columns specifically requested in query (or where clause)
foreach ($queriedColumns as $queriedColumn) {
if (array_key_exists($queriedColumn, $tableFields)) {
$selectColumns[] = $queriedColumn;
}
}
$selectColumns = array_intersect($queriedColumns, array_keys($tableFields));
}
// If this is a subclass without any explicitly requested columns, omit this from the query
if(!in_array($tableClass, $ancestorTables) && empty($selectColumns)) continue;
// Select necessary columns (unless an explicitly empty array)
if($selectColumns !== array()) {
$this->selectColumnsFromTable($query, $tableClass, $selectColumns);
if ($selectColumns && $tableClass != $baseClass) {
$joinTable = true;
}
} else {
$this->selectColumnsFromTable($query, $tableClass);
if ($tableClass != $baseClass) $joinTable = true;
}
if ($joinTable) {
$query->addLeftJoin($tableClass, "\"$tableClass\".\"ID\" = \"$baseClass\".\"ID\"", $tableClass, 10) ;
// Join if not the base table
if($tableClass !== $baseClass) {
$query->addLeftJoin($tableClass, "\"$tableClass\".\"ID\" = \"$baseClass\".\"ID\"", $tableClass, 10);
}
}
@ -687,7 +686,8 @@ class DataQuery {
/**
* Query the given field column from the database and return as an array.
*
* @param String $field See {@link expressionForField()}.
* @param string $field See {@link expressionForField()}.
* @return array List of column values for the specified column
*/
public function column($field = 'ID') {
$fieldExpression = $this->expressionForField($field);

View File

@ -954,20 +954,24 @@ class Versioned extends DataExtension implements TemplateGlobalProvider {
*
* If neither of these are set, it checks the session, otherwise the stage
* is set to 'Live'.
*
* @param Session $session Optional session within which to store the resulting stage
*/
public static function choose_site_stage() {
public static function choose_site_stage($session = null) {
if(!$session) $session = Session::current_session();
if(isset($_GET['stage'])) {
$stage = ucfirst(strtolower($_GET['stage']));
if(!in_array($stage, array('Stage', 'Live'))) $stage = 'Live';
Session::set('readingMode', 'Stage.' . $stage);
$session->inst_set('readingMode', 'Stage.' . $stage);
}
if(isset($_GET['archiveDate']) && strtotime($_GET['archiveDate'])) {
Session::set('readingMode', 'Archive.' . $_GET['archiveDate']);
$session->inst_set('readingMode', 'Archive.' . $_GET['archiveDate']);
}
if($mode = Session::get('readingMode')) {
if($mode = $session->inst_get('readingMode')) {
Versioned::set_reading_mode($mode);
} else {
Versioned::reading_stage("Live");

View File

@ -13,6 +13,9 @@ class DirectorTest extends SapphireTest {
public function setUp() {
parent::setUp();
// Required for testRequestFilterInDirectorTest
Injector::nest();
// Hold the original request URI once so it doesn't get overwritten
if(!self::$originalRequestURI) {
@ -52,6 +55,8 @@ class DirectorTest extends SapphireTest {
$_SERVER[$header] = $value;
}
}
Injector::unnest();
parent::tearDown();
}
@ -404,8 +409,6 @@ class DirectorTest extends SapphireTest {
$processor = new RequestProcessor(array($filter));
$currentProcessor = Injector::inst()->get('RequestProcessor');
Injector::inst()->registerService($processor, 'RequestProcessor');
$response = Director::test('some-dummy-url');
@ -430,9 +433,6 @@ class DirectorTest extends SapphireTest {
// preCall 'false' will trigger an exception and prevent post call execution
$this->assertEquals(2, $filter->postCalls);
// swap back otherwise our wrapping test execution request may fail in the post processing later
Injector::inst()->registerService($currentProcessor, 'RequestProcessor');
}
}

View File

@ -1,6 +1,6 @@
<?php
class ConfigTest_DefinesFoo extends Object {
class ConfigTest_DefinesFoo extends Object implements TestOnly {
protected static $foo = 1;
}
@ -13,11 +13,11 @@ class ConfigTest_DefinesFooAndBar extends ConfigTest_DefinesFoo {
public static $bar = 3;
}
class ConfigTest_DefinesFooDoesntExtendObject {
class ConfigTest_DefinesFooDoesntExtendObject implements TestOnly {
protected static $foo = 4;
}
class ConfigStaticTest_First extends Config {
class ConfigStaticTest_First extends Config implements TestOnly {
/** @config */
private static $first = array('test_1');
/** @config */
@ -57,7 +57,7 @@ class ConfigStaticTest_Fourth extends ConfigStaticTest_Third {
public static $fourth = array('test_4');
}
class ConfigStaticTest_Combined1 extends Config {
class ConfigStaticTest_Combined1 extends Config implements TestOnly {
/** @config */
private static $first = array('test_1');
/** @config */
@ -74,7 +74,36 @@ class ConfigStaticTest_Combined3 extends ConfigStaticTest_Combined2 {
private static $second = array('test_3');
}
class ConfigTest_TestNest extends Object implements TestOnly {
/** @config */
private static $foo = 3;
/** @config */
private static $bar = 5;
}
class ConfigTest extends SapphireTest {
public function testNest() {
// Check basic config
$this->assertEquals(3, Config::inst()->get('ConfigTest_TestNest', 'foo'));
$this->assertEquals(5, Config::inst()->get('ConfigTest_TestNest', 'bar'));
// Test nest copies data
Config::nest();
$this->assertEquals(3, Config::inst()->get('ConfigTest_TestNest', 'foo'));
$this->assertEquals(5, Config::inst()->get('ConfigTest_TestNest', 'bar'));
// Test nested data can be updated
Config::inst()->update('ConfigTest_TestNest', 'foo', 4);
$this->assertEquals(4, Config::inst()->get('ConfigTest_TestNest', 'foo'));
$this->assertEquals(5, Config::inst()->get('ConfigTest_TestNest', 'bar'));
// Test unnest restores data
Config::unnest();
$this->assertEquals(3, Config::inst()->get('ConfigTest_TestNest', 'foo'));
$this->assertEquals(5, Config::inst()->get('ConfigTest_TestNest', 'bar'));
}
public function testUpdateStatic() {
$this->assertEquals(Config::inst()->get('ConfigStaticTest_First', 'first', Config::FIRST_SET),
@ -270,7 +299,7 @@ class ConfigTest extends SapphireTest {
}
}
class ConfigTest_Config_LRU extends Config_LRU {
class ConfigTest_Config_LRU extends Config_LRU implements TestOnly {
public $cache;
public $indexing;

View File

@ -200,4 +200,70 @@ DOC;
$this->assertEquals($expectedValue, $statics['config\staticmanifest\NamespaceTest']['db']['value']);
}
public function testParsingMultyStringClass() {
static $tokens = array(
array(T_OPEN_TAG, "<?php\n", 1),
array(T_WHITESPACE, "\n", 2),
array(T_CLASS, 'class', 3),
array(T_WHITESPACE, ' ', 3),
':',
array(T_STRING, 'ss', 3),
':',
array(T_STRING, 'test2', 3),
array(T_WHITESPACE, ' ', 3),
array(T_EXTENDS, 'extends', 3),
array(T_WHITESPACE, ' ', 3),
':',
array(T_STRING, 'ss', 3),
':',
array(T_STRING, 'test', 3),
array(T_WHITESPACE, ' ', 3),
array(T_IMPLEMENTS, 'implements', 3),
array(T_WHITESPACE, ' ', 3),
array(T_STRING, 'TestOnly', 3),
array(T_WHITESPACE, ' ', 3),
'{',
array(T_WHITESPACE, "\n\t", 3),
array(T_PRIVATE, 'private', 4),
array(T_WHITESPACE, ' ', 4),
array(T_STATIC, 'static', 4),
array(T_WHITESPACE, ' ', 4),
array(T_VARIABLE, '$test', 4),
array(T_WHITESPACE, ' ', 4),
'=',
array(T_WHITESPACE, ' ', 4),
array(T_ARRAY, 'array', 4),
'(',
array(T_LNUMBER, '3', 4),
')',
';',
array(T_WHITESPACE, "\n", 4),
'}',
array(T_WHITESPACE, "\n", 5),
);
$parser = new ConfigStaticManifestTest_Parser($tokens);
$parser->parse();
$statics = $parser->getStatics();
$expected = array(
'test' => array(
'access' => T_PRIVATE,
'value' => array(3)
)
);
$this->assertEquals($expected, $statics[':ss:test2']);
}
}
class ConfigStaticManifestTest_Parser extends SS_ConfigStaticManifest_Parser implements TestOnly {
public function __construct($tokens) {
$this->path = __FILE__;
$this->tokens = $tokens;
$this->length = count($this->tokens);
$this->pos = 0;
}
}

View File

@ -730,6 +730,30 @@ class UploadFieldTest extends FunctionalTest {
$responseExistsData = json_decode($responseExists->getBody());
$this->assertFalse($responseExists->isError());
$this->assertTrue($responseExistsData->exists);
// Test that files with invalid characters are rewritten safely and both report exists
// Check that uploaded files can be detected in the root
$tmpFileName = '_test___Upload___Bad.txt';
$tmpFileNameExpected = 'test-Upload-Bad.txt';
$response = $this->mockFileUpload('NoRelationField', $tmpFileName);
$this->assertFalse($response->isError());
$this->assertFileExists(ASSETS_PATH . "/UploadFieldTest/$tmpFileNameExpected");
// With original file
$responseExists = $this->mockFileExists('NoRelationField', $tmpFileName);
$responseExistsData = json_decode($responseExists->getBody());
$this->assertFalse($responseExists->isError());
$this->assertTrue($responseExistsData->exists);
// With rewritten file
$responseExists = $this->mockFileExists('NoRelationField', $tmpFileNameExpected);
$responseExistsData = json_decode($responseExists->getBody());
$this->assertFalse($responseExists->isError());
$this->assertTrue($responseExistsData->exists);
// Test that attempts to navigate outside of the directory return false
$responseExists = $this->mockFileExists('NoRelationField', "../../../../var/private/$tmpFileName");
$responseExistsData = json_decode($responseExists->getBody());
$this->assertTrue($responseExists->isError());
$this->assertContains('File is not a valid upload', $responseExists->getBody());
}
protected function getMockForm() {

View File

@ -12,6 +12,24 @@ define('TEST_SERVICES', dirname(__FILE__) . '/testservices');
*/
class InjectorTest extends SapphireTest {
protected $nestingLevel = 0;
public function setUp() {
parent::setUp();
$this->nestingLevel = 0;
}
public function tearDown() {
while($this->nestingLevel > 0) {
$this->nestingLevel--;
Config::unnest();
}
parent::tearDown();
}
public function testCorrectlyInitialised() {
$injector = Injector::inst();
$this->assertTrue($injector->getConfigLocator() instanceof SilverStripeServiceConfigurationLocator,
@ -562,6 +580,64 @@ class InjectorTest extends SapphireTest {
$this->assertInstanceOf('TestObject', $injector->get('service'));
}
/**
* Test nesting of injector
*/
public function testNest() {
// Outer nest to avoid interference with other
Injector::nest();
$this->nestingLevel++;
// Test services
$config = array(
'NewRequirementsBackend',
);
Injector::inst()->load($config);
$si = Injector::inst()->get('TestStaticInjections');
$this->assertInstanceOf('TestStaticInjections', $si);
$this->assertInstanceOf('NewRequirementsBackend', $si->backend);
$this->assertInstanceOf('MyParentClass', Injector::inst()->get('MyParentClass'));
$this->assertInstanceOf('MyChildClass', Injector::inst()->get('MyChildClass'));
// Test that nested injector values can be overridden
Injector::nest();
$this->nestingLevel++;
Injector::inst()->unregisterAllObjects();
$newsi = Injector::inst()->get('TestStaticInjections');
$newsi->backend = new OriginalRequirementsBackend();
Injector::inst()->registerService($newsi, 'TestStaticInjections');
Injector::inst()->registerService(new MyChildClass(), 'MyParentClass');
// Check that these overridden values are retrievable
$si = Injector::inst()->get('TestStaticInjections');
$this->assertInstanceOf('TestStaticInjections', $si);
$this->assertInstanceOf('OriginalRequirementsBackend', $si->backend);
$this->assertInstanceOf('MyParentClass', Injector::inst()->get('MyParentClass'));
$this->assertInstanceOf('MyParentClass', Injector::inst()->get('MyChildClass'));
// Test that unnesting restores expected behaviour
Injector::unnest();
$this->nestingLevel--;
$si = Injector::inst()->get('TestStaticInjections');
$this->assertInstanceOf('TestStaticInjections', $si);
$this->assertInstanceOf('NewRequirementsBackend', $si->backend);
$this->assertInstanceOf('MyParentClass', Injector::inst()->get('MyParentClass'));
$this->assertInstanceOf('MyChildClass', Injector::inst()->get('MyChildClass'));
// Test reset of cache
Injector::inst()->unregisterAllObjects();
$si = Injector::inst()->get('TestStaticInjections');
$this->assertInstanceOf('TestStaticInjections', $si);
$this->assertInstanceOf('NewRequirementsBackend', $si->backend);
$this->assertInstanceOf('MyParentClass', Injector::inst()->get('MyParentClass'));
$this->assertInstanceOf('MyChildClass', Injector::inst()->get('MyChildClass'));
// Return to nestingLevel 0
Injector::unnest();
$this->nestingLevel--;
}
}

View File

@ -35,6 +35,7 @@ class DataObjectLazyLoadingTest extends SapphireTest {
'"DataObjectTest_Team"."ClassName" IS NOT NULL THEN "DataObjectTest_Team"."ClassName" ELSE ' .
$db->prepStringForDB('DataObjectTest_Team').' END AS "RecordClassName", "DataObjectTest_Team"."Title" '.
'FROM "DataObjectTest_Team" ' .
'LEFT JOIN "DataObjectTest_SubTeam" ON "DataObjectTest_SubTeam"."ID" = "DataObjectTest_Team"."ID" ' .
'WHERE ("DataObjectTest_Team"."ClassName" IN ('.$db->prepStringForDB('DataObjectTest_SubTeam').'))' .
' ORDER BY "DataObjectTest_Team"."Title" ASC';
$this->assertEquals($expected, $playerList->sql());
@ -62,7 +63,8 @@ class DataObjectLazyLoadingTest extends SapphireTest {
$expected = 'SELECT DISTINCT "DataObjectTest_Team"."ClassName", "DataObjectTest_Team"."Created", ' .
'"DataObjectTest_Team"."LastEdited", "DataObjectTest_Team"."Title", "DataObjectTest_Team"."ID", ' .
'CASE WHEN "DataObjectTest_Team"."ClassName" IS NOT NULL THEN "DataObjectTest_Team"."ClassName" ELSE ' .
$db->prepStringForDB('DataObjectTest_Team').' END AS "RecordClassName" FROM "DataObjectTest_Team" WHERE ' .
$db->prepStringForDB('DataObjectTest_Team').' END AS "RecordClassName" FROM "DataObjectTest_Team" ' .
'LEFT JOIN "DataObjectTest_SubTeam" ON "DataObjectTest_SubTeam"."ID" = "DataObjectTest_Team"."ID" WHERE ' .
'("DataObjectTest_Team"."ClassName" IN ('.$db->prepStringForDB('DataObjectTest_SubTeam').')) ' .
'ORDER BY "DataObjectTest_Team"."Title" ASC';
$this->assertEquals($expected, $playerList->sql());

View File

@ -1,11 +1,15 @@
<?php
class DataQueryTest extends SapphireTest {
protected static $fixture_file = 'DataQueryTest.yml';
protected $extraDataObjects = array(
'DataQueryTest_A',
'DataQueryTest_B',
'DataQueryTest_C',
'DataQueryTest_D',
'DataQueryTest_E',
);
/**
@ -124,6 +128,12 @@ class DataQueryTest extends SapphireTest {
$dq->sql()
);
}
public function testDefaultSort() {
$query = new DataQuery('DataQueryTest_E');
$result = $query->column('Title');
$this->assertEquals(array('First', 'Second', 'Last'), $result);
}
}
@ -148,6 +158,10 @@ class DataQueryTest_B extends DataQueryTest_A {
}
class DataQueryTest_C extends DataObject implements TestOnly {
private static $db = array(
'Title' => 'Varchar'
);
private static $has_one = array(
'TestA' => 'DataQueryTest_A',
@ -171,3 +185,12 @@ class DataQueryTest_D extends DataObject implements TestOnly {
'Relation' => 'DataQueryTest_B',
);
}
class DataQueryTest_E extends DataQueryTest_C implements TestOnly {
private static $db = array(
'SortOrder' => 'Int'
);
private static $default_sort = '"DataQueryTest_E"."SortOrder" ASC';
}

View File

@ -0,0 +1,10 @@
DataQueryTest_E:
query1:
Title: 'Last'
SortOrder: 3
query2:
Title: 'First'
SortOrder: 1
query3:
Title: 'Second'
SortOrder: 2

View File

@ -590,6 +590,42 @@ class VersionedTest extends SapphireTest {
Versioned::set_reading_mode($originalMode);
}
/**
* Tests that reading mode persists between requests
*/
public function testReadingPersistent() {
$session = new Session(array());
// Set to stage
Director::test('/?stage=Stage', null, $session);
$this->assertEquals(
'Stage.Stage',
$session->inst_get('readingMode'),
'Check querystring changes reading mode to Stage'
);
Director::test('/', null, $session);
$this->assertEquals(
'Stage.Stage',
$session->inst_get('readingMode'),
'Check that subsequent requests in the same session remain in Stage mode'
);
// Test live persists
Director::test('/?stage=Live', null, $session);
$this->assertEquals(
'Stage.Live',
$session->inst_get('readingMode'),
'Check querystring changes reading mode to Live'
);
Director::test('/', null, $session);
$this->assertEquals(
'Stage.Live',
$session->inst_get('readingMode'),
'Check that subsequent requests in the same session remain in Live mode'
);
}
}