Merge branch '4.0' into 4

This commit is contained in:
Sam Minnee 2017-10-20 18:45:16 +13:00
commit 4bec62ba51
39 changed files with 652 additions and 220 deletions

View File

@ -58,7 +58,7 @@ matrix:
before_script: before_script:
# Init PHP # Init PHP
- pecl channel-update pecl.php.net - pecl channel-update pecl.php.net
- printf "\n" | pecl install imagick - travis_retry printf "\n" | pecl install imagick
- phpenv rehash - phpenv rehash
- phpenv config-rm xdebug.ini || true - phpenv config-rm xdebug.ini || true
- echo 'memory_limit = 2048M' >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini - echo 'memory_limit = 2048M' >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini

View File

@ -35,7 +35,7 @@
"symfony/config": "^3.2", "symfony/config": "^3.2",
"symfony/translation": "^2.8", "symfony/translation": "^2.8",
"symfony/yaml": "~3.2", "symfony/yaml": "~3.2",
"vlucas/phpdotenv": "^2.4", "m1/env": "^2.1",
"php": ">=5.6.0", "php": ">=5.6.0",
"ext-intl": "*", "ext-intl": "*",
"ext-mbstring": "*", "ext-mbstring": "*",

View File

@ -90,9 +90,10 @@ If you are running on a server instance where users other than the webserver use
read / write access to files in the assets folder, then you will need to adjust the read / write access to files in the assets folder, then you will need to adjust the
permissions of the filesystem to a more permissive setting. permissions of the filesystem to a more permissive setting.
By default private files and `.htaccess` are written with permission `0600`. By default private files and `.htaccess` are written with permission `0644`.
You could enable other users to access these files with the below config. You could enable other users to access these files with the below config.
Note: Please adjust the values below to those appropriate for your server configuration: Note: Please adjust the values below to those appropriate for your server configuration.
You may require `0666` for combined files generated during requests where they are cleared or refreshed only during a flush.
*mysite/_config/assetperms.yml* *mysite/_config/assetperms.yml*

View File

@ -30,7 +30,7 @@ But enough of the disclaimer, on to the actual configuration — typically in `n
} }
location / { location / {
try_files $uri index.php?$query_string; try_files $uri /index.php?$query_string;
} }
error_page 404 /assets/error-404.html; error_page 404 /assets/error-404.html;

View File

@ -7,8 +7,8 @@ server.
For each of these environments we may require slightly different configurations for our servers. This could be our debug For each of these environments we may require slightly different configurations for our servers. This could be our debug
level, caching backends, or - of course - sensitive information such as database credentials. level, caching backends, or - of course - sensitive information such as database credentials.
To solve this problem of setting variables per environment we use environment variables with the help of the To manage environment variables, as well as other server globals, the [api:SilverStripe\Core\Environment] class
[PHPDotEnv](https://github.com/vlucas/phpdotenv) library by Vance Lucas. provides a set of APIs and helpers.
## Security considerations ## Security considerations
@ -32,13 +32,18 @@ You can set "real" environment variables using Apache. Please
## How to access the environment variables ## How to access the environment variables
Accessing the environment varaibles is easy and can be done using the `getenv` method or in the `$_ENV` and `$_SERVER` Accessing the environment varaibles should be done via the `Environment::getEnv()` method
super-globals:
```php ```php
getenv('SS_DATABASE_CLASS'); use SilverStripe\Core\Environment;
$_ENV['SS_DATABASE_CLASS']; Environment::getEnv('SS_DATABASE_CLASS');
$_SERVER['SS_DATABASE_CLASS']; ```
Individual settings can be assigned via `Environment::setEnv()` or `Environment::putEnv()` methods.
```php
use SilverStripe\Core\Environment;
Environment::setEnv('API_KEY', 'AABBCCDDEEFF012345');
``` ```
## Including an extra `.env` file ## Including an extra `.env` file
@ -46,12 +51,14 @@ $_SERVER['SS_DATABASE_CLASS'];
Sometimes it may be useful to include an extra `.env` file - on a shared local development environment where all Sometimes it may be useful to include an extra `.env` file - on a shared local development environment where all
database credentials could be the same. To do this, you can add this snippet to your `mysite/_config.php` file: database credentials could be the same. To do this, you can add this snippet to your `mysite/_config.php` file:
Note that by default variables cannot be overloaded from this file; Existing values will be preferred
over values in this file.
```php ```php
try { use SilverStripe\Core\EnvironmentLoader;
(new \Dotenv\Dotenv('/path/to/env/'))->load(); $env = BASE_PATH . '/mysite/.env';
} catch (\Dotenv\Exception\InvalidPathException $e) { $loader = new EnvironmentLoader();
// no file found $loader->loadFile($env);
}
``` ```
## Core environment variables ## Core environment variables

View File

@ -300,6 +300,20 @@ $themesFilePath = ThemeResourceLoader::inst()->findThemedResource('css/styles.cs
$themeFolderPath = ThemeResourceLoader::inst()->getPath('simple'); $themeFolderPath = ThemeResourceLoader::inst()->getPath('simple');
``` ```
Usage for Page and ModelAdmin:
```php
class ListingPage extends \Page {
private static $icon = 'mycompany/silverstripe-mymodule: client/images/sitetree_icon.png';
}
```
```php
class MyCustomModelAdmin extends \SilverStripe\Admin\ModelAdmin {
private static $menu_icon = 'mycompany/silverstripe-mymodule: client/images/modeladmin_icon.png';
}
```
To ensure consistency, we've also deprecated support for path constants: To ensure consistency, we've also deprecated support for path constants:
* `FRAMEWORK_DIR` and `FRAMEWORK_PATH` * `FRAMEWORK_DIR` and `FRAMEWORK_PATH`
@ -486,6 +500,8 @@ SS_BASE_URL="//localhost/"
The global values `$database` and `$databaseConfig` have been deprecated, as has `ConfigureFromEnv.php` The global values `$database` and `$databaseConfig` have been deprecated, as has `ConfigureFromEnv.php`
which is no longer necessary. which is no longer necessary.
To access environment variables you can use the `SilverStripe\Core\Environment::getEnv()` method.
See [Environment Management docs](/getting-started/environment_management/) for full details. See [Environment Management docs](/getting-started/environment_management/) for full details.
#### Replace usages of Object class #### Replace usages of Object class
@ -1943,7 +1959,7 @@ that it belongs to, e.g. `themes/mytheme/templates/MyVendor/Foobar/Model/MyModel
All static methods have been removed, and the `inst_` prefix removed from all instance members. All static methods have been removed, and the `inst_` prefix removed from all instance members.
Please see the upgrading section on Session object for more details. Please see the upgrading section on Session object for more details.
* `Director.rules` config no longer support `redirect:<url>` directly via config. * `Director.rules` config no longer support `redirect:<url>` directly via config.
* `Director::get_environment_type()` and `Director::set_environment_type()` are removed. * `Director::set_environment_type()` has been removed.
Get the `Kernel` instance via injector and query `getEnvironment()` instead. Get the `Kernel` instance via injector and query `getEnvironment()` instead.
E.g. `$type = Injector::inst()->get(Kernel::class)->getEnvironment();`. E.g. `$type = Injector::inst()->get(Kernel::class)->getEnvironment();`.
* The environment can no longer be configured via YAML (`Director.environment_type`). * The environment can no longer be configured via YAML (`Director.environment_type`).
@ -2254,6 +2270,7 @@ The below methods have been added or had their functionality updated to `DBDate`
* `AssetControlExtension` is applied by default to all DataObjects, in order to support the management * `AssetControlExtension` is applied by default to all DataObjects, in order to support the management
of linked assets and file protection. of linked assets and file protection.
* `ProtectedFileController` class is used to serve up protected assets. * `ProtectedFileController` class is used to serve up protected assets.
* `AssetAdaptor` has a new config `default_server` which helps tell the code which server type to use if no matching type was found by scanning the server software - defaults to `apache`
#### <a name="overview-filesystem-removed"></a>Filesystem removed API #### <a name="overview-filesystem-removed"></a>Filesystem removed API

60
sake
View File

@ -9,39 +9,29 @@ Executes a SilverStripe command"
exit 1 exit 1
fi fi
# find the silverstripe installation # find the silverstripe installation, looking first at sake
# bin location, but falling back to current directory
sakedir=`dirname $0` sakedir=`dirname $0`
directory="$PWD"
if [ -f "$sakedir/cli-script.php" ]; then if [ -f "$sakedir/cli-script.php" ]; then
# Calling sake from vendor/silverstripe/framework/sake
framework="$sakedir" framework="$sakedir"
base=`dirname $sakedir` base="$sakedir/../../.."
elif [ -f ./cli-script.php ]; then elif [ -f "$sakedir/../silverstripe/framework/cli-script.php" ]; then
framework=. # Calling sake from vendor/bin/sake
base=.. framework="$sakedir/../silverstripe/framework"
base="$sakedir/../.."
elif [ -f "$directory/vendor/silverstripe/framework/cli-script.php" ]; then
# Vendor framework (from base) if sake installed globally
framework="$directory/vendor/silverstripe/framework"
base=.
elif [ -f "$directory/framework/cli-script.php" ]; then
# Legacy directory (from base) if sake installed globally
framework="$directory/framework"
base=.
else else
# look up the tree for the first parent folder that has a framework echo "Can't find cli-script.php in $sakedir"
# installation exit 1
slashes=${PWD//[^\/]/}
directory="$PWD"
base=.
for (( n=${#slashes}; n>0; --n )) do
if [ -d "$directory/framework" ]; then
framework="$directory/framework"
break
elif [ -d "$directory/sapphire" ]; then
framework="$directory/sapphire"
break
fi
directory=`dirname $directory`
base="$base."
done
if [ ! -f "$framework/cli-script.php" ]; then
echo "Can't find cli-script.php in $framework"
exit 1
fi
fi fi
# Find the PHP binary # Find the PHP binary
@ -74,20 +64,20 @@ if [ "$1" = "-start" ]; then
echo "You need to install the 'daemon' tool. In debian, go 'sudo apt-get install daemon'" echo "You need to install the 'daemon' tool. In debian, go 'sudo apt-get install daemon'"
exit 1 exit 1
fi fi
if [ ! -f $base/$2.pid ]; then if [ ! -f $base/$2.pid ]; then
echo "Starting service $2 $3" echo "Starting service $2 $3"
touch $base/$2.pid touch $base/$2.pid
pidfile=`realpath $base/$2.pid` pidfile=`realpath $base/$2.pid`
outlog=$base/$2.log outlog=$base/$2.log
errlog=$base/$2.err errlog=$base/$2.err
echo "Logging to $outlog" echo "Logging to $outlog"
sake=`realpath $0` sake=`realpath $0`
base=`realpath $base` base=`realpath $base`
# if third argument is not explicitly given, copy from second argument # if third argument is not explicitly given, copy from second argument
if [ "$3" = "" ]; then if [ "$3" = "" ]; then
url=$2 url=$2
@ -95,7 +85,7 @@ if [ "$1" = "-start" ]; then
url=$3 url=$3
fi fi
# TODO: Give a globally unique processname by including the projectname as well # TODO: Give a globally unique processname by including the projectname as well
processname=$2 processname=$2
daemon -n $processname -r -D $base --pidfile=$pidfile --stdout=$outlog --stderr=$errlog $sake $url daemon -n $processname -r -D $base --pidfile=$pidfile --stdout=$outlog --stderr=$errlog $sake $url
@ -109,7 +99,7 @@ if [ "$1" = "-stop" ]; then
pidfile=$base/$2.pid pidfile=$base/$2.pid
if [ -f $pidfile ]; then if [ -f $pidfile ]; then
echo "Stopping service $2" echo "Stopping service $2"
# TODO: This is a bad way of killing the process # TODO: This is a bad way of killing the process
kill -KILL `cat $pidfile` kill -KILL `cat $pidfile`
unlink $pidfile unlink $pidfile

View File

@ -5,9 +5,14 @@ namespace SilverStripe\Control\Email;
use SilverStripe\Control\Director; use SilverStripe\Control\Director;
use SilverStripe\Control\HTTP; use SilverStripe\Control\HTTP;
use SilverStripe\Core\Convert; use SilverStripe\Core\Convert;
use SilverStripe\Core\Environment;
use SilverStripe\Core\Injector\Injector; use SilverStripe\Core\Injector\Injector;
use SilverStripe\ORM\FieldType\DBDatetime; use SilverStripe\ORM\FieldType\DBDatetime;
use SilverStripe\ORM\FieldType\DBField;
use SilverStripe\ORM\FieldType\DBHTMLText;
use SilverStripe\View\Requirements; use SilverStripe\View\Requirements;
use SilverStripe\View\SSViewer;
use SilverStripe\View\ThemeResourceLoader;
use SilverStripe\View\ViewableData; use SilverStripe\View\ViewableData;
use Swift_Message; use Swift_Message;
use Swift_MimePart; use Swift_MimePart;
@ -58,12 +63,12 @@ class Email extends ViewableData
/** /**
* @var string The name of the HTML template to render the email with (without *.ss extension) * @var string The name of the HTML template to render the email with (without *.ss extension)
*/ */
private $HTMLTemplate = self::class; private $HTMLTemplate = null;
/** /**
* @var string The name of the plain text template to render the plain part of the email with * @var string The name of the plain text template to render the plain part of the email with
*/ */
private $plainTemplate = ''; private $plainTemplate = null;
/** /**
* @var Swift_MimePart * @var Swift_MimePart
@ -155,7 +160,7 @@ class Email extends ViewableData
$normalised[$name] = null; $normalised[$name] = null;
} }
} }
$extra = getenv($env); $extra = Environment::getEnv($env);
if ($extra) { if ($extra) {
$normalised[$extra] = null; $normalised[$extra] = null;
} }
@ -648,7 +653,14 @@ class Email extends ViewableData
*/ */
public function getHTMLTemplate() public function getHTMLTemplate()
{ {
return $this->HTMLTemplate; if ($this->HTMLTemplate) {
return $this->HTMLTemplate;
}
return ThemeResourceLoader::inst()->findTemplate(
SSViewer::get_templates_by_class(static::class, '', self::class),
SSViewer::get_themes()
);
} }
/** /**
@ -760,30 +772,49 @@ class Email extends ViewableData
$this->getSwiftMessage()->detach($existingPlainPart); $this->getSwiftMessage()->detach($existingPlainPart);
} }
unset($existingPlainPart); unset($existingPlainPart);
if (!$this->getHTMLTemplate() && !$this->getPlainTemplate()) {
// Respect explicitly set body
$htmlPart = $plainOnly ? null : $this->getBody();
$plainPart = $plainOnly ? $this->getBody() : null;
// Ensure we can at least render something
$htmlTemplate = $this->getHTMLTemplate();
$plainTemplate = $this->getPlainTemplate();
if (!$htmlTemplate && !$plainTemplate && !$plainPart && !$htmlPart) {
return $this; return $this;
} }
$HTMLPart = '';
$plainPart = '';
if ($this->getHTMLTemplate()) { // Render plain part
$HTMLPart = $this->renderWith($this->getHTMLTemplate(), $this->getData()); if ($plainTemplate && !$plainPart) {
$plainPart = $this->renderWith($plainTemplate, $this->getData());
} }
if ($this->getPlainTemplate()) { // Render HTML part, either if sending html email, or a plain part is lacking
$plainPart = $this->renderWith($this->getPlainTemplate(), $this->getData()); if (!$htmlPart && $htmlTemplate && (!$plainOnly || empty($plainPart))) {
} elseif ($HTMLPart) { $htmlPart = $this->renderWith($htmlTemplate, $this->getData());
$plainPart = Convert::xml2raw($HTMLPart);
} }
if ($HTMLPart && !$plainOnly) { // Plain part fails over to generated from html
$this->setBody($HTMLPart); if (!$plainPart && $htmlPart) {
/** @var DBHTMLText $htmlPartObject */
$htmlPartObject = DBField::create_field('HTMLFragment', $htmlPart);
$plainPart = $htmlPartObject->Plain();
}
// Fail if no email to send
if (!$plainPart && !$htmlPart) {
return $this;
}
// Build HTML / Plain components
if ($htmlPart && !$plainOnly) {
$this->setBody($htmlPart);
$this->getSwiftMessage()->setContentType('text/html'); $this->getSwiftMessage()->setContentType('text/html');
$this->getSwiftMessage()->setCharset('utf-8'); $this->getSwiftMessage()->setCharset('utf-8');
if ($plainPart) { if ($plainPart) {
$this->getSwiftMessage()->addPart($plainPart, 'text/plain', 'utf-8'); $this->getSwiftMessage()->addPart($plainPart, 'text/plain', 'utf-8');
} }
} elseif ($plainPart || $plainOnly) { } else {
if ($plainPart) { if ($plainPart) {
$this->setBody($plainPart); $this->setBody($plainPart);
} }
@ -812,7 +843,7 @@ class Email extends ViewableData
*/ */
public function hasPlainPart() public function hasPlainPart()
{ {
if ($this->getSwiftMessage()->getContentType() == 'text/plain') { if ($this->getSwiftMessage()->getContentType() === 'text/plain') {
return true; return true;
} }
return (bool) $this->findPlainPart(); return (bool) $this->findPlainPart();

View File

@ -35,6 +35,7 @@ class HTTPResponse
304 => 'Not Modified', 304 => 'Not Modified',
305 => 'Use Proxy', 305 => 'Use Proxy',
307 => 'Temporary Redirect', 307 => 'Temporary Redirect',
308 => 'Permanent Redirect',
400 => 'Bad Request', 400 => 'Bad Request',
401 => 'Unauthorized', 401 => 'Unauthorized',
403 => 'Forbidden', 403 => 'Forbidden',
@ -71,7 +72,8 @@ class HTTPResponse
303, 303,
304, 304,
305, 305,
307 307,
308
); );
/** /**

View File

@ -11,6 +11,7 @@ use Psr\Log\LoggerInterface;
use Psr\SimpleCache\CacheInterface; use Psr\SimpleCache\CacheInterface;
use ReflectionClass; use ReflectionClass;
use SilverStripe\Control\Director; use SilverStripe\Control\Director;
use SilverStripe\Core\Environment;
/** /**
* Assists with building of manifest cache prior to config being available * Assists with building of manifest cache prior to config being available
@ -43,7 +44,7 @@ class ManifestCacheFactory extends DefaultCacheFactory
public function create($service, array $params = array()) public function create($service, array $params = array())
{ {
// Override default cache generation with SS_MANIFESTCACHE // Override default cache generation with SS_MANIFESTCACHE
$cacheClass = getenv('SS_MANIFESTCACHE'); $cacheClass = Environment::getEnv('SS_MANIFESTCACHE');
if (!$cacheClass) { if (!$cacheClass) {
return parent::create($service, $params); return parent::create($service, $params);
} }

View File

@ -11,6 +11,7 @@ use SilverStripe\Config\Transformer\YamlTransformer;
use SilverStripe\Core\Cache\CacheFactory; use SilverStripe\Core\Cache\CacheFactory;
use SilverStripe\Core\Config\Middleware\ExtensionMiddleware; use SilverStripe\Core\Config\Middleware\ExtensionMiddleware;
use SilverStripe\Core\Config\Middleware\InheritanceMiddleware; use SilverStripe\Core\Config\Middleware\InheritanceMiddleware;
use SilverStripe\Core\Environment;
use SilverStripe\Core\Injector\Injector; use SilverStripe\Core\Injector\Injector;
use SilverStripe\Core\Kernel; use SilverStripe\Core\Kernel;
use SilverStripe\Core\Manifest\ClassLoader; use SilverStripe\Core\Manifest\ClassLoader;
@ -141,11 +142,12 @@ class CoreConfigFactory
// Add default rules // Add default rules
$envvarset = function ($var, $value = null) { $envvarset = function ($var, $value = null) {
if (getenv($var) === false) { $actual = Environment::getEnv($var);
if ($actual === false) {
return false; return false;
} }
if ($value) { if ($value) {
return getenv($var) === $value; return $actual === $value;
} }
return true; return true;
}; };

View File

@ -137,7 +137,7 @@ class CoreKernel implements Kernel
} }
// Check getenv // Check getenv
if ($env = getenv('SS_ENVIRONMENT_TYPE')) { if ($env = Environment::getEnv('SS_ENVIRONMENT_TYPE')) {
return $env; return $env;
} }
@ -328,32 +328,32 @@ class CoreKernel implements Kernel
{ {
/** @skipUpgrade */ /** @skipUpgrade */
$databaseConfig = [ $databaseConfig = [
"type" => getenv('SS_DATABASE_CLASS') ?: 'MySQLDatabase', "type" => Environment::getEnv('SS_DATABASE_CLASS') ?: 'MySQLDatabase',
"server" => getenv('SS_DATABASE_SERVER') ?: 'localhost', "server" => Environment::getEnv('SS_DATABASE_SERVER') ?: 'localhost',
"username" => getenv('SS_DATABASE_USERNAME') ?: null, "username" => Environment::getEnv('SS_DATABASE_USERNAME') ?: null,
"password" => getenv('SS_DATABASE_PASSWORD') ?: null, "password" => Environment::getEnv('SS_DATABASE_PASSWORD') ?: null,
]; ];
// Set the port if called for // Set the port if called for
$dbPort = getenv('SS_DATABASE_PORT'); $dbPort = Environment::getEnv('SS_DATABASE_PORT');
if ($dbPort) { if ($dbPort) {
$databaseConfig['port'] = $dbPort; $databaseConfig['port'] = $dbPort;
} }
// Set the timezone if called for // Set the timezone if called for
$dbTZ = getenv('SS_DATABASE_TIMEZONE'); $dbTZ = Environment::getEnv('SS_DATABASE_TIMEZONE');
if ($dbTZ) { if ($dbTZ) {
$databaseConfig['timezone'] = $dbTZ; $databaseConfig['timezone'] = $dbTZ;
} }
// For schema enabled drivers: // For schema enabled drivers:
$dbSchema = getenv('SS_DATABASE_SCHEMA'); $dbSchema = Environment::getEnv('SS_DATABASE_SCHEMA');
if ($dbSchema) { if ($dbSchema) {
$databaseConfig["schema"] = $dbSchema; $databaseConfig["schema"] = $dbSchema;
} }
// For SQlite3 memory databases (mainly for testing purposes) // For SQlite3 memory databases (mainly for testing purposes)
$dbMemory = getenv('SS_DATABASE_MEMORY'); $dbMemory = Environment::getEnv('SS_DATABASE_MEMORY');
if ($dbMemory) { if ($dbMemory) {
$databaseConfig["memory"] = $dbMemory; $databaseConfig["memory"] = $dbMemory;
} }
@ -368,7 +368,7 @@ class CoreKernel implements Kernel
*/ */
protected function getDatabasePrefix() protected function getDatabasePrefix()
{ {
return getenv('SS_DATABASE_PREFIX') ?: ''; return Environment::getEnv('SS_DATABASE_PREFIX') ?: '';
} }
/** /**
@ -392,14 +392,14 @@ class CoreKernel implements Kernel
} }
// Check environment // Check environment
$database = getenv('SS_DATABASE_NAME'); $database = Environment::getEnv('SS_DATABASE_NAME');
if ($database) { if ($database) {
return $this->getDatabasePrefix() . $database; return $this->getDatabasePrefix() . $database;
} }
// Auto-detect name // Auto-detect name
$chooseName = getenv('SS_DATABASE_CHOOSE_NAME'); $chooseName = Environment::getEnv('SS_DATABASE_CHOOSE_NAME');
if ($chooseName) { if ($chooseName) {
// Find directory to build name from // Find directory to build name from
@ -529,7 +529,7 @@ class CoreKernel implements Kernel
$errorHandler->start(); $errorHandler->start();
// Register error log file // Register error log file
$errorLog = getenv('SS_ERROR_LOG'); $errorLog = Environment::getEnv('SS_ERROR_LOG');
if ($errorLog) { if ($errorLog) {
$logger = Injector::inst()->get(LoggerInterface::class); $logger = Injector::inst()->get(LoggerInterface::class);
if ($logger instanceof Logger) { if ($logger instanceof Logger) {

View File

@ -6,6 +6,11 @@ namespace SilverStripe\Core;
* Consolidates access and modification of PHP global variables and settings. * Consolidates access and modification of PHP global variables and settings.
* This class should be used sparingly, and only if information cannot be obtained * This class should be used sparingly, and only if information cannot be obtained
* from a current {@link HTTPRequest} object. * from a current {@link HTTPRequest} object.
*
* Acts as the primary store for environment variables, including those loaded
* from .env files. Applications should use Environment::getEnv() instead of php's
* `getenv` in order to include `.env` configuration, as the system's actual
* environment variables are treated immutably.
*/ */
class Environment class Environment
{ {
@ -23,6 +28,13 @@ class Environment
*/ */
protected static $timeLimitMax = null; protected static $timeLimitMax = null;
/**
* Local overrides for all $_ENV var protected from cross-process operations
*
* @var array
*/
protected static $env = [];
/** /**
* Extract env vars prior to modification * Extract env vars prior to modification
* *
@ -31,7 +43,7 @@ class Environment
public static function getVariables() public static function getVariables()
{ {
// Suppress return by-ref // Suppress return by-ref
return array_merge($GLOBALS, []); return array_merge($GLOBALS, [ 'env' => static::$env ]);
} }
/** /**
@ -41,8 +53,14 @@ class Environment
*/ */
public static function setVariables(array $vars) public static function setVariables(array $vars)
{ {
foreach ($vars as $key => $value) { foreach ($vars as $varName => $varValue) {
$GLOBALS[$key] = $value; if ($varName === 'env') {
continue;
}
$GLOBALS[$varName] = $varValue;
}
if (array_key_exists('env', $vars)) {
static::$env = $vars['env'];
} }
} }
@ -151,4 +169,51 @@ class Environment
{ {
return static::$timeLimitMax; return static::$timeLimitMax;
} }
/**
* Get value of environment variable
*
* @param string $name
* @return mixed Value of the environment variable, or false if not set
*/
public static function getEnv($name)
{
switch (true) {
case array_key_exists($name, static::$env):
return static::$env[$name];
case array_key_exists($name, $_ENV):
return $_ENV[$name];
case array_key_exists($name, $_SERVER):
return $_SERVER[$name];
default:
return getenv($name);
}
}
/**
* Set environment variable using php.ini syntax.
* Acts as a process-isolated version of putenv()
* Note: This will be parsed via parse_ini_string() which handles quoted values
*
* @param string $string Setting to assign in KEY=VALUE or KEY="VALUE" syntax
*/
public static function putEnv($string)
{
// Parse name-value pairs
$envVars = parse_ini_string($string) ?: [];
foreach ($envVars as $name => $value) {
self::setEnv($name, $value);
}
}
/**
* Set environment variable via $name / $value pair
*
* @param string $name
* @param string $value
*/
public static function setEnv($name, $value)
{
static::$env[$name] = $value;
}
} }

View File

@ -0,0 +1,47 @@
<?php
namespace SilverStripe\Core;
use M1\Env\Parser;
/**
* Loads environment variables from .env files
* Loosely based on https://github.com/vlucas/phpdotenv/blob/master/src/Loader.php
*/
class EnvironmentLoader
{
/**
* Load environment variables from .env file
*
* @param string $path Path to the file
* @param bool $overload Set to true to allow vars to overload. Recommended to leave false.
* @return array|null List of values parsed as an associative array, or null if not loaded
* If overloading, this list will reflect the final state for all variables
*/
public function loadFile($path, $overload = false)
{
// Not readable
if (!file_exists($path) || !is_readable($path)) {
return null;
}
// Parse and cleanup content
$result = [];
$variables = Parser::parse(file_get_contents($path));
foreach ($variables as $name => $value) {
// Conditionally prevent overloading
if (!$overload) {
$existing = Environment::getEnv($name);
if ($existing !== false) {
$result[$name] = $existing;
continue;
}
}
// Overload or create var
Environment::setEnv($name, $value);
$result[$name] = $value;
}
return $result;
}
}

View File

@ -11,6 +11,7 @@ use ReflectionObject;
use ReflectionProperty; use ReflectionProperty;
use SilverStripe\Core\ClassInfo; use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Config\Config; use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Environment;
use SilverStripe\Dev\Deprecation; use SilverStripe\Dev\Deprecation;
/** /**
@ -523,8 +524,9 @@ class Injector implements ContainerInterface
// Evaluate constants surrounded by back ticks // Evaluate constants surrounded by back ticks
if (preg_match('/^`(?<name>[^`]+)`$/', $value, $matches)) { if (preg_match('/^`(?<name>[^`]+)`$/', $value, $matches)) {
if (getenv($matches['name']) !== false) { $envValue = Environment::getEnv($matches['name']);
$value = getenv($matches['name']); if ($envValue !== false) {
$value = $envValue;
} elseif (defined($matches['name'])) { } elseif (defined($matches['name'])) {
$value = constant($matches['name']); $value = constant($matches['name']);
} else { } else {

View File

@ -36,12 +36,12 @@ class TempFolder
*/ */
public static function getTempFolderUsername() public static function getTempFolderUsername()
{ {
$user = getenv('APACHE_RUN_USER'); $user = Environment::getEnv('APACHE_RUN_USER');
if (!$user) { if (!$user) {
$user = getenv('USER'); $user = Environment::getEnv('USER');
} }
if (!$user) { if (!$user) {
$user = getenv('USERNAME'); $user = Environment::getEnv('USERNAME');
} }
if (!$user && function_exists('posix_getpwuid') && function_exists('posix_getuid')) { if (!$user && function_exists('posix_getpwuid') && function_exists('posix_getuid')) {
$userDetails = posix_getpwuid(posix_getuid()); $userDetails = posix_getpwuid(posix_getuid());

View File

@ -2,6 +2,8 @@
namespace SilverStripe\Dev\Install; namespace SilverStripe\Dev\Install;
use SilverStripe\Core\Environment;
/** /**
* Provides environment settings from the current request + environment * Provides environment settings from the current request + environment
* *
@ -42,10 +44,10 @@ class InstallConfig
// Guess database config // Guess database config
return [ return [
'type' => $this->getDatabaseClass($databaseClasses), 'type' => $this->getDatabaseClass($databaseClasses),
'server' => getenv('SS_DATABASE_SERVER') ?: 'localhost', 'server' => Environment::getEnv('SS_DATABASE_SERVER') ?: 'localhost',
'username' => getenv('SS_DATABASE_USERNAME') ?: 'root', 'username' => Environment::getEnv('SS_DATABASE_USERNAME') ?: 'root',
'password' => getenv('SS_DATABASE_PASSWORD') ?: '', 'password' => Environment::getEnv('SS_DATABASE_PASSWORD') ?: '',
'database' => getenv('SS_DATABASE_NAME') ?: 'SS_mysite', 'database' => Environment::getEnv('SS_DATABASE_NAME') ?: 'SS_mysite',
]; ];
} }
@ -62,8 +64,8 @@ class InstallConfig
} }
return [ return [
'username' => getenv('SS_DEFAULT_ADMIN_USERNAME') ?: 'admin', 'username' => Environment::getEnv('SS_DEFAULT_ADMIN_USERNAME') ?: 'admin',
'password' => getenv('SS_DEFAULT_ADMIN_PASSWORD') ?: '', 'password' => Environment::getEnv('SS_DEFAULT_ADMIN_PASSWORD') ?: '',
]; ];
} }
@ -114,8 +116,9 @@ class InstallConfig
*/ */
protected function getDatabaseClass($databaseClasses) protected function getDatabaseClass($databaseClasses)
{ {
if (getenv('SS_DATABASE_CLASS')) { $envDatabase = Environment::getEnv('SS_DATABASE_CLASS');
return getenv('SS_DATABASE_CLASS'); if ($envDatabase) {
return $envDatabase;
} }
// Check supported versions // Check supported versions

View File

@ -978,12 +978,12 @@ class FormField extends RequestHandler
{ {
$context = $this; $context = $this;
$this->extend('onBeforeRender', $context, $properties);
if (count($properties)) { if (count($properties)) {
$context = $context->customise($properties); $context = $context->customise($properties);
} }
$this->extend('onBeforeRender', $this);
$result = $context->renderWith($this->getTemplates()); $result = $context->renderWith($this->getTemplates());
// Trim whitespace from the result, so that trailing newlines are supressed. Works for strings and HTMLText values // Trim whitespace from the result, so that trailing newlines are supressed. Works for strings and HTMLText values

View File

@ -8,6 +8,7 @@ use SilverStripe\Control\HTTPResponse;
use SilverStripe\Core\Convert; use SilverStripe\Core\Convert;
use SilverStripe\ORM\DataList; use SilverStripe\ORM\DataList;
use SilverStripe\ORM\DataObject; use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\FieldType\DBDatetime;
use SilverStripe\ORM\Hierarchy\Hierarchy; use SilverStripe\ORM\Hierarchy\Hierarchy;
use SilverStripe\ORM\Hierarchy\MarkedSet; use SilverStripe\ORM\Hierarchy\MarkedSet;
use SilverStripe\View\ViewableData; use SilverStripe\View\ViewableData;
@ -195,13 +196,18 @@ class TreeDropdownField extends FormField
* @var array * @var array
*/ */
protected $searchExpanded = []; protected $searchExpanded = [];
/** /**
* Show full path for selected options, only applies for single select * Show full path for selected options, only applies for single select
* @var bool * @var bool
*/ */
protected $showSelectedPath = false; protected $showSelectedPath = false;
/**
* @var array
*/
protected static $cacheKeyCache = [];
/** /**
* CAVEAT: for search to work properly $labelField must be a database field, * CAVEAT: for search to work properly $labelField must be a database field,
* or you need to setSearchFunction. * or you need to setSearchFunction.
@ -605,7 +611,7 @@ class TreeDropdownField extends FormField
$callback = $this->getDisableFunction(); $callback = $this->getDisableFunction();
return $callback && call_user_func($callback, $node); return $callback && call_user_func($callback, $node);
} }
/** /**
* Attributes to be given for this field type * Attributes to be given for this field type
* @return array * @return array
@ -618,11 +624,11 @@ class TreeDropdownField extends FormField
'data-schema' => json_encode($this->getSchemaData()), 'data-schema' => json_encode($this->getSchemaData()),
'data-state' => json_encode($this->getSchemaState()), 'data-state' => json_encode($this->getSchemaState()),
); );
$attributes = array_merge($attributes, $this->attributes); $attributes = array_merge($attributes, $this->attributes);
$this->extend('updateAttributes', $attributes); $this->extend('updateAttributes', $attributes);
return $attributes; return $attributes;
} }
@ -858,15 +864,14 @@ class TreeDropdownField extends FormField
/** @var Hierarchy|DataObject $record */ /** @var Hierarchy|DataObject $record */
$record = $this->Value() ? $this->objectForKey($this->Value()) : null; $record = $this->Value() ? $this->objectForKey($this->Value()) : null;
// Ensure cache is keyed by last modified date of the underlying list $data['data']['cacheKey'] = $this->getCacheKey();
$data['data']['cacheKey'] = DataList::create($this->getSourceObject())->max('LastEdited');
$data['data']['showSelectedPath'] = $this->getShowSelectedPath(); $data['data']['showSelectedPath'] = $this->getShowSelectedPath();
if ($record) { if ($record) {
$titlePath = ''; $titlePath = '';
if ($this->getShowSelectedPath()) { if ($this->getShowSelectedPath()) {
$ancestors = $record->getAncestors(true)->reverse(); $ancestors = $record->getAncestors(true)->reverse();
foreach ($ancestors as $parent) { foreach ($ancestors as $parent) {
$title = $parent->obj($this->getTitleField())->getValue(); $title = $parent->obj($this->getTitleField())->getValue();
$titlePath .= $title .'/'; $titlePath .= $title .'/';
@ -883,6 +888,21 @@ class TreeDropdownField extends FormField
return $data; return $data;
} }
/**
* Ensure cache is keyed by last modified datetime of the underlying list.
* Caches the key for the respective underlying list types, since it doesn't need to query again.
*
* @return DBDatetime
*/
protected function getCacheKey()
{
$target = $this->getSourceObject();
if (!isset(self::$cacheKeyCache[$target])) {
self::$cacheKeyCache[$target] = DataList::create($target)->max('LastEdited');
}
return self::$cacheKeyCache[$target];
}
public function getSchemaDataDefaults() public function getSchemaDataDefaults()
{ {
$data = parent::getSchemaDataDefaults(); $data = parent::getSchemaDataDefaults();
@ -947,7 +967,7 @@ class TreeDropdownField extends FormField
); );
return $emptyString; return $emptyString;
} }
/** /**
* @return bool * @return bool
*/ */
@ -955,7 +975,7 @@ class TreeDropdownField extends FormField
{ {
return $this->showSelectedPath; return $this->showSelectedPath;
} }
/** /**
* @param bool $showSelectedPath * @param bool $showSelectedPath
* @return TreeDropdownField * @return TreeDropdownField

View File

@ -4,6 +4,7 @@ namespace SilverStripe\ORM\Connect;
use Exception; use Exception;
use SilverStripe\Core\ClassInfo; use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Environment;
use SilverStripe\Core\Injector\Injectable; use SilverStripe\Core\Injector\Injectable;
use SilverStripe\Core\Injector\Injector; use SilverStripe\Core\Injector\Injector;
use SilverStripe\Dev\TestOnly; use SilverStripe\Dev\TestOnly;
@ -40,7 +41,7 @@ class TempDatabase
*/ */
protected function isDBTemp($name) protected function isDBTemp($name)
{ {
$prefix = getenv('SS_DATABASE_PREFIX') ?: 'ss_'; $prefix = Environment::getEnv('SS_DATABASE_PREFIX') ?: 'ss_';
$result = preg_match( $result = preg_match(
sprintf('/^%stmpdb_[0-9]+_[0-9]+$/i', preg_quote($prefix, '/')), sprintf('/^%stmpdb_[0-9]+_[0-9]+$/i', preg_quote($prefix, '/')),
$name $name
@ -133,7 +134,7 @@ class TempDatabase
// Create a temporary database, and force the connection to use UTC for time // Create a temporary database, and force the connection to use UTC for time
$dbConn = $this->getConn(); $dbConn = $this->getConn();
$prefix = getenv('SS_DATABASE_PREFIX') ?: 'ss_'; $prefix = Environment::getEnv('SS_DATABASE_PREFIX') ?: 'ss_';
do { do {
$dbname = strtolower(sprintf('%stmpdb_%s_%s', $prefix, time(), rand(1000000, 9999999))); $dbname = strtolower(sprintf('%stmpdb_%s_%s', $prefix, time(), rand(1000000, 9999999)));
} while ($dbConn->databaseExists($dbname)); } while ($dbConn->databaseExists($dbname));

View File

@ -8,6 +8,7 @@ use SilverStripe\Control\Director;
use SilverStripe\Control\HTTPRequest; use SilverStripe\Control\HTTPRequest;
use SilverStripe\Core\Config\Config; use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Convert; use SilverStripe\Core\Convert;
use SilverStripe\Core\Environment;
use SilverStripe\Core\Injector\Injector; use SilverStripe\Core\Injector\Injector;
use SilverStripe\Dev\Deprecation; use SilverStripe\Dev\Deprecation;
use SilverStripe\ORM\Connect\Database; use SilverStripe\ORM\Connect\Database;
@ -265,7 +266,7 @@ class DB
return false; return false;
} }
$prefix = getenv('SS_DATABASE_PREFIX') ?: 'ss_'; $prefix = Environment::getEnv('SS_DATABASE_PREFIX') ?: 'ss_';
$pattern = strtolower(sprintf('/^%stmpdb\d{7}$/', $prefix)); $pattern = strtolower(sprintf('/^%stmpdb\d{7}$/', $prefix));
return (bool)preg_match($pattern, $name); return (bool)preg_match($pattern, $name);
} }

View File

@ -1453,8 +1453,11 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
->filter('ID', $this->ID) ->filter('ID', $this->ID)
->dataQuery() ->dataQuery()
->query(); ->query();
foreach ($srcQuery->queriedTables() as $table) { $queriedTables = $srcQuery->queriedTables();
$delete = new SQLDelete("\"$table\"", array('"ID"' => $this->ID)); $this->extend('updateDeleteTables', $queriedTables, $srcQuery);
foreach ($queriedTables as $table) {
$delete = SQLDelete::create("\"$table\"", array('"ID"' => $this->ID));
$this->extend('updateDeleteTable', $delete, $table, $queriedTables, $srcQuery);
$delete->execute(); $delete->execute();
} }
// Remove this item out of any caches // Remove this item out of any caches

View File

@ -8,6 +8,7 @@ use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\HTTPResponse; use SilverStripe\Control\HTTPResponse;
use SilverStripe\Control\HTTPResponse_Exception; use SilverStripe\Control\HTTPResponse_Exception;
use SilverStripe\Core\Config\Configurable; use SilverStripe\Core\Config\Configurable;
use SilverStripe\Core\Environment;
use SilverStripe\ORM\Connect\DatabaseException; use SilverStripe\ORM\Connect\DatabaseException;
use SilverStripe\Security\MemberAuthenticator\MemberAuthenticator; use SilverStripe\Security\MemberAuthenticator\MemberAuthenticator;
@ -224,9 +225,9 @@ class BasicAuth
// Check if site is protected // Check if site is protected
if ($config->get('entire_site_protected')) { if ($config->get('entire_site_protected')) {
$permissionCode = $config->get('entire_site_protected_code'); $permissionCode = $config->get('entire_site_protected_code');
} elseif (getenv(self::USE_BASIC_AUTH)) { } elseif (Environment::getEnv(self::USE_BASIC_AUTH)) {
// Convert legacy 1 / true to ADMIN permissions // Convert legacy 1 / true to ADMIN permissions
$permissionCode = getenv(self::USE_BASIC_AUTH); $permissionCode = Environment::getEnv(self::USE_BASIC_AUTH);
if (!is_string($permissionCode) || is_numeric($permissionCode)) { if (!is_string($permissionCode) || is_numeric($permissionCode)) {
$permissionCode = self::AUTH_PERMISSION; $permissionCode = self::AUTH_PERMISSION;
} }

View File

@ -5,6 +5,7 @@ namespace SilverStripe\Security;
use BadMethodCallException; use BadMethodCallException;
use InvalidArgumentException; use InvalidArgumentException;
use SilverStripe\Core\Config\Configurable; use SilverStripe\Core\Config\Configurable;
use SilverStripe\Core\Environment;
use SilverStripe\Core\Extensible; use SilverStripe\Core\Extensible;
use SilverStripe\Core\Injector\Injectable; use SilverStripe\Core\Injector\Injectable;
@ -74,7 +75,7 @@ class DefaultAdminService
"No default admin configured. Please call hasDefaultAdmin() before getting default admin username" "No default admin configured. Please call hasDefaultAdmin() before getting default admin username"
); );
} }
return static::$default_username ?: getenv('SS_DEFAULT_ADMIN_USERNAME'); return static::$default_username ?: Environment::getEnv('SS_DEFAULT_ADMIN_USERNAME');
} }
/** /**
@ -88,7 +89,7 @@ class DefaultAdminService
"No default admin configured. Please call hasDefaultAdmin() before getting default admin password" "No default admin configured. Please call hasDefaultAdmin() before getting default admin password"
); );
} }
return static::$default_password ?: getenv('SS_DEFAULT_ADMIN_PASSWORD'); return static::$default_password ?: Environment::getEnv('SS_DEFAULT_ADMIN_PASSWORD');
} }
/** /**
@ -100,8 +101,8 @@ class DefaultAdminService
{ {
// Check environment if not explicitly set // Check environment if not explicitly set
if (!isset(static::$has_default_admin)) { if (!isset(static::$has_default_admin)) {
return !empty(getenv('SS_DEFAULT_ADMIN_USERNAME')) return !empty(Environment::getEnv('SS_DEFAULT_ADMIN_USERNAME'))
&& !empty(getenv('SS_DEFAULT_ADMIN_PASSWORD')); && !empty(Environment::getEnv('SS_DEFAULT_ADMIN_PASSWORD'));
} }
return static::$has_default_admin; return static::$has_default_admin;
} }

View File

@ -99,7 +99,10 @@ class LostPasswordHandler extends RequestHandler
public function passwordsent() public function passwordsent()
{ {
$request = $this->getRequest(); $request = $this->getRequest();
$email = Convert::raw2xml(rawurldecode($request->param('EmailAddress')) . '.' . $request->getExtension()); $email = Convert::raw2xml(rawurldecode($request->param('EmailAddress')));
if ($request->getExtension()) {
$email = $email . '.' . Convert::raw2xml($request->getExtension());
}
$message = _t( $message = _t(
'SilverStripe\\Security\\Security.PASSWORDSENTTEXT', 'SilverStripe\\Security\\Security.PASSWORDSENTTEXT',

View File

@ -103,7 +103,7 @@ class ThemeResourceLoader
if (count($parts) > 1) { if (count($parts) > 1) {
throw new InvalidArgumentException("Invalid theme identifier {$identifier}"); throw new InvalidArgumentException("Invalid theme identifier {$identifier}");
} }
return substr($identifier, 1); return ltrim($identifier, '/');
} }
// If there is no slash / colon it's a legacy theme // If there is no slash / colon it's a legacy theme
@ -148,7 +148,7 @@ class ThemeResourceLoader
} }
// Join module with subpath // Join module with subpath
return $modulePath . $subpath; return ltrim($modulePath . $subpath, '/');
} }
/** /**

View File

@ -1,7 +1,7 @@
<?php <?php
use Dotenv\Dotenv; use SilverStripe\Core\Environment;
use Dotenv\Exception\InvalidPathException; use SilverStripe\Core\EnvironmentLoader;
use SilverStripe\Core\TempFolder; use SilverStripe\Core\TempFolder;
/** /**
@ -58,24 +58,23 @@ if (!defined('BASE_PATH')) {
} }
// Allow a first class env var to be set that disables .env file loading // Allow a first class env var to be set that disables .env file loading
if (!getenv('SS_IGNORE_DOT_ENV')) { if (!Environment::getEnv('SS_IGNORE_DOT_ENV')) {
call_user_func(function () { call_user_func(function () {
$loader = new EnvironmentLoader();
foreach ([BASE_PATH, dirname(BASE_PATH)] as $path) { foreach ([BASE_PATH, dirname(BASE_PATH)] as $path) {
try { // Stop searching after first `.env` file is loaded
(new Dotenv($path))->load(); $dotEnvFile = $path . DIRECTORY_SEPARATOR . '.env';
} catch (InvalidPathException $e) { if ($loader->loadFile($dotEnvFile)) {
// no .env found - no big deal break;
continue;
} }
break;
} }
}); });
} }
// Validate SS_BASE_URL is absolute // Validate SS_BASE_URL is absolute
if (getenv('SS_BASE_URL') && !preg_match('#^(\w+:)?//.*#', getenv('SS_BASE_URL'))) { if (Environment::getEnv('SS_BASE_URL') && !preg_match('#^(\w+:)?//.*#', Environment::getEnv('SS_BASE_URL'))) {
call_user_func(function () { call_user_func(function () {
$base = getenv('SS_BASE_URL'); $base = Environment::getEnv('SS_BASE_URL');
user_error( user_error(
"SS_BASE_URL should be an absolute url with protocol " "SS_BASE_URL should be an absolute url with protocol "
. "(http://$base) or without protocol (//$base)", . "(http://$base) or without protocol (//$base)",
@ -83,14 +82,14 @@ if (getenv('SS_BASE_URL') && !preg_match('#^(\w+:)?//.*#', getenv('SS_BASE_URL')
); );
// Treat as protocol-less absolute url // Treat as protocol-less absolute url
$base = '//' . $base; $base = '//' . $base;
putenv("SS_BASE_URL=$base"); Environment::setEnv('SS_BASE_URL', $base);
}); });
} }
if (!defined('BASE_URL')) { if (!defined('BASE_URL')) {
define('BASE_URL', call_user_func(function () { define('BASE_URL', call_user_func(function () {
// Prefer explicitly provided SS_BASE_URL // Prefer explicitly provided SS_BASE_URL
$base = getenv('SS_BASE_URL'); $base = Environment::getEnv('SS_BASE_URL');
if ($base) { if ($base) {
// Strip relative path from SS_BASE_URL // Strip relative path from SS_BASE_URL
return rtrim(parse_url($base, PHP_URL_PATH), '/'); return rtrim(parse_url($base, PHP_URL_PATH), '/');
@ -100,7 +99,7 @@ if (!defined('BASE_URL')) {
// This tends not to work on CLI // This tends not to work on CLI
$path = realpath($_SERVER['SCRIPT_FILENAME']); $path = realpath($_SERVER['SCRIPT_FILENAME']);
if (substr($path, 0, strlen(BASE_PATH)) == BASE_PATH) { if (substr($path, 0, strlen(BASE_PATH)) == BASE_PATH) {
$urlSegmentToRemove = substr($path, strlen(BASE_PATH)); $urlSegmentToRemove = str_replace('\\', '/', substr($path, strlen(BASE_PATH)));
if (substr($_SERVER['SCRIPT_NAME'], -strlen($urlSegmentToRemove)) == $urlSegmentToRemove) { if (substr($_SERVER['SCRIPT_NAME'], -strlen($urlSegmentToRemove)) == $urlSegmentToRemove) {
$baseURL = substr($_SERVER['SCRIPT_NAME'], 0, -strlen($urlSegmentToRemove)); $baseURL = substr($_SERVER['SCRIPT_NAME'], 0, -strlen($urlSegmentToRemove));
// ltrim('.'), normalise slashes to '/', and rtrim('/') // ltrim('.'), normalise slashes to '/', and rtrim('/')

View File

@ -24,17 +24,18 @@
<ol> <ol>
<li>Create a <code>Controller</code> subclass (<a href="https://docs.silverstripe.org/en/developer_guides/controllers">docs.silverstripe.org/en/developer_guides/controllers/</a>)</li> <li>Create a <code>Controller</code> subclass (<a href="https://docs.silverstripe.org/en/developer_guides/controllers">docs.silverstripe.org/en/developer_guides/controllers/</a>)</li>
<li>Setup the routes.yml to your <code>Controller</code> (<a href="https://docs.silverstripe.org/en/developer_guides/controllers/routing">docs.silverstripe.org/en/developer_guides/controllers/routing</a>).</li> <li>Setup the routes.yml to your <code>Controller</code> (<a href="https://docs.silverstripe.org/en/developer_guides/controllers/routing">docs.silverstripe.org/en/developer_guides/controllers/routing</a>).</li>
<li>Create a template for your <code>Controller</code> (<a href="https://docs.silverstripe.org/en/3/developer_guides/templates">docs.silverstripe.org/en/developer_guides/templates/</a>)</li> <li>Create a template for your <code>Controller</code> (<a href="https://docs.silverstripe.org/en/developer_guides/templates">docs.silverstripe.org/en/developer_guides/templates/</a>)</li>
</ol> </ol>
<h3>Community resources</h3> <h3>Community resources</h3>
<ul> <ul>
<li> <li>
<p><a href="http://silverstripe.org/forum">silverstripe.org/forum</a> Discussion forums for the development community.</p> <p><a href="http://silverstripe.org/slack">silverstripe.org/slack</a> Join other SilverStripe developers in the community Slack channel.</p>
</li> </li>
<li><p><a href="http://silverstripe.org/irc">silverstripe.org/irc</a> IRC channel for realtime support and discussions.</p></li> <li>
<p><a href="https://stackoverflow.com/questions/tagged/silverstripe">stackoverflow.com/questions/tagged/silverstripe</a> Ask SilverStripe questions on Stack Overflow.</p>
</li>
<li><p><a href="http://docs.silverstripe.org">docs.silverstripe.org</a> Searchable developer documentation, how-tos, tutorials, and reference.</p></li> <li><p><a href="http://docs.silverstripe.org">docs.silverstripe.org</a> Searchable developer documentation, how-tos, tutorials, and reference.</p></li>
<li><p><a href="http://api.silverstripe.org">api.silverstripe.org</a> API documentation for PHP classes, methods and properties.</p></li> <li><p><a href="http://api.silverstripe.org">api.silverstripe.org</a> API documentation for PHP classes, methods and properties.</p></li>

View File

@ -2,34 +2,35 @@
// Bootstrap environment variables // Bootstrap environment variables
use Dotenv\Loader; use SilverStripe\Core\Environment;
/** @skipUpgrade */ /** @skipUpgrade */
if (!getenv('SS_DATABASE_CLASS') && !getenv('SS_DATABASE_USERNAME')) { if (!Environment::getEnv('SS_DATABASE_CLASS') && !Environment::getEnv('SS_DATABASE_USERNAME')) {
$loader = new Loader(null);
// The default settings let us define the database config via environment vars // The default settings let us define the database config via environment vars
// Database connection, including PDO and legacy ORM support // Database connection, including PDO and legacy ORM support
switch (getenv('DB')) { switch (Environment::getEnv('DB')) {
case "PGSQL"; case "PGSQL";
$loader->setEnvironmentVariable('SS_DATABASE_CLASS', getenv('PDO') ? 'PostgrePDODatabase' : 'PostgreSQLDatabase'); $pgDatabaseClass = Environment::getEnv('PDO') ? 'PostgrePDODatabase' : 'PostgreSQLDatabase';
$loader->setEnvironmentVariable('SS_DATABASE_USERNAME', 'postgres'); Environment::setEnv('SS_DATABASE_CLASS', $pgDatabaseClass);
$loader->setEnvironmentVariable('SS_DATABASE_PASSWORD', ''); Environment::setEnv('SS_DATABASE_USERNAME', 'postgres');
Environment::setEnv('SS_DATABASE_PASSWORD', '');
break; break;
case "SQLITE": case "SQLITE":
$loader->setEnvironmentVariable('SS_DATABASE_CLASS', getenv('PDO') ? 'SQLite3PDODatabase' : 'SQLite3Database'); $sqliteDatabaseClass = Environment::getEnv('PDO') ? 'SQLite3PDODatabase' : 'SQLite3Database';
$loader->setEnvironmentVariable('SS_DATABASE_USERNAME', 'root'); Environment::setEnv('SS_DATABASE_CLASS', $sqliteDatabaseClass);
$loader->setEnvironmentVariable('SS_DATABASE_PASSWORD', ''); Environment::setEnv('SS_DATABASE_USERNAME', 'root');
$loader->setEnvironmentVariable('SS_SQLITE_DATABASE_PATH', ':memory:'); Environment::setEnv('SS_DATABASE_PASSWORD', '');
Environment::setEnv('SS_SQLITE_DATABASE_PATH', ':memory:');
break; break;
default: default:
$loader->setEnvironmentVariable('SS_DATABASE_CLASS', getenv('PDO') ? 'MySQLPDODatabase' : 'MySQLDatabase'); $mysqlDatabaseClass = Environment::getEnv('PDO') ? 'MySQLPDODatabase' : 'MySQLDatabase';
$loader->setEnvironmentVariable('SS_DATABASE_USERNAME', 'root'); Environment::setEnv('SS_DATABASE_CLASS', $mysqlDatabaseClass);
$loader->setEnvironmentVariable('SS_DATABASE_PASSWORD', ''); Environment::setEnv('SS_DATABASE_USERNAME', 'root');
Environment::setEnv('SS_DATABASE_PASSWORD', '');
} }
$loader->setEnvironmentVariable('SS_DATABASE_SERVER', '127.0.0.1'); Environment::setEnv('SS_DATABASE_CHOOSE_NAME', 'true');
$loader->setEnvironmentVariable('SS_DATABASE_CHOOSE_NAME', true); Environment::setEnv('SS_DATABASE_SERVER', '127.0.0.1');
} }

View File

@ -4,10 +4,16 @@ namespace SilverStripe\Control\Tests\Email;
use PHPUnit_Framework_MockObject_MockObject; use PHPUnit_Framework_MockObject_MockObject;
use SilverStripe\Control\Email\Email; use SilverStripe\Control\Email\Email;
use SilverStripe\Control\Email\Mailer;
use SilverStripe\Control\Email\SwiftMailer; use SilverStripe\Control\Email\SwiftMailer;
use SilverStripe\Control\Tests\Email\EmailTest\EmailSubClass;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Core\Manifest\ModuleResourceLoader;
use SilverStripe\Dev\SapphireTest; use SilverStripe\Dev\SapphireTest;
use SilverStripe\Dev\TestMailer;
use SilverStripe\ORM\FieldType\DBDatetime; use SilverStripe\ORM\FieldType\DBDatetime;
use SilverStripe\Security\Member; use SilverStripe\Security\Member;
use SilverStripe\View\SSViewer;
use Swift_Attachment; use Swift_Attachment;
use Swift_Mailer; use Swift_Mailer;
use Swift_Message; use Swift_Message;
@ -84,37 +90,25 @@ class EmailTest extends SapphireTest
public function testSendPlain() public function testSendPlain()
{ {
/** @var Email|PHPUnit_Framework_MockObject_MockObject $email */ $email = $this->makeEmailMock('Test send plain');
$email = $this->getMockBuilder(Email::class)
->enableProxyingToOriginalMethods()
->disableOriginalConstructor()
->setConstructorArgs(array(
'from@example.com',
'to@example.com',
'Test send plain',
'Testing Email->sendPlain()',
'cc@example.com',
'bcc@example.com',
))
->getMock();
// email should not call render if a body is supplied // email should not call render if a body is supplied
$email->expects($this->never())->method('render'); $email->expects($this->never())->method('renderWith');
$email->addAttachment(__DIR__ . '/EmailTest/attachment.txt', null, 'text/plain');
$successful = $email->sendPlain(); $successful = $email->sendPlain();
$this->assertTrue($successful); $this->assertTrue($successful);
$this->assertEmpty($email->getFailedRecipients()); $this->assertEmpty($email->getFailedRecipients());
$sentMail = $this->mailer->findEmail('to@example.com'); /** @var TestMailer $mailer */
$mailer = Injector::inst()->get(Mailer::class);
$sentMail = $mailer->findEmail('to@example.com');
$this->assertTrue(is_array($sentMail)); $this->assertTrue(is_array($sentMail));
$this->assertEquals('to@example.com', $sentMail['To']); $this->assertEquals('to@example.com', $sentMail['To']);
$this->assertEquals('from@example.com', $sentMail['From']); $this->assertEquals('from@example.com', $sentMail['From']);
$this->assertEquals('Test send plain', $sentMail['Subject']); $this->assertEquals('Test send plain', $sentMail['Subject']);
$this->assertEquals('Testing Email->sendPlain()', $sentMail['Content']); $this->assertEquals('Body for Test send plain', $sentMail['Content']);
$this->assertCount(1, $sentMail['AttachedFiles']); $this->assertCount(1, $sentMail['AttachedFiles']);
$child = reset($sentMail['AttachedFiles']); $child = reset($sentMail['AttachedFiles']);
@ -126,36 +120,25 @@ class EmailTest extends SapphireTest
public function testSend() public function testSend()
{ {
/** @var Email|PHPUnit_Framework_MockObject_MockObject $email */ /** @var Email|PHPUnit_Framework_MockObject_MockObject $email */
$email = $this->getMockBuilder(Email::class) $email = $this->makeEmailMock('Test send HTML');
->enableProxyingToOriginalMethods()
->disableOriginalConstructor()
->setConstructorArgs(array(
'from@example.com',
'to@example.com',
'Test send HTML',
'Testing Email->send()',
'cc@example.com',
'bcc@example.com',
))
->getMock();
// email should not call render if a body is supplied // email should not call render if a body is supplied
$email->expects($this->never())->method('render'); $email->expects($this->never())->method('renderWith');
$email->addAttachment(__DIR__ . '/EmailTest/attachment.txt', null, 'text/plain');
$successful = $email->send(); $successful = $email->send();
$this->assertTrue($successful); $this->assertTrue($successful);
$this->assertEmpty($email->getFailedRecipients()); $this->assertEmpty($email->getFailedRecipients());
$sentMail = $this->mailer->findEmail('to@example.com'); /** @var TestMailer $mailer */
$mailer = Injector::inst()->get(Mailer::class);
$sentMail = $mailer->findEmail('to@example.com');
$this->assertTrue(is_array($sentMail)); $this->assertTrue(is_array($sentMail));
$this->assertEquals('to@example.com', $sentMail['To']); $this->assertEquals('to@example.com', $sentMail['To']);
$this->assertEquals('from@example.com', $sentMail['From']); $this->assertEquals('from@example.com', $sentMail['From']);
$this->assertEquals('Test send HTML', $sentMail['Subject']); $this->assertEquals('Test send HTML', $sentMail['Subject']);
$this->assertEquals('Testing Email->send()', $sentMail['Content']); $this->assertEquals('Body for Test send HTML', $sentMail['Content']);
$this->assertCount(1, $sentMail['AttachedFiles']); $this->assertCount(1, $sentMail['AttachedFiles']);
$child = reset($sentMail['AttachedFiles']); $child = reset($sentMail['AttachedFiles']);
@ -169,12 +152,9 @@ class EmailTest extends SapphireTest
/** @var Email|PHPUnit_Framework_MockObject_MockObject $email */ /** @var Email|PHPUnit_Framework_MockObject_MockObject $email */
$email = $this->getMockBuilder(Email::class) $email = $this->getMockBuilder(Email::class)
->enableProxyingToOriginalMethods() ->enableProxyingToOriginalMethods()
->disableOriginalConstructor()
->setConstructorArgs(array(
'from@example.com',
'to@example.com',
))
->getMock(); ->getMock();
$email->setFrom('from@example.com');
$email->setTo('to@example.com');
$email->setData(array( $email->setData(array(
'EmailContent' => 'test', 'EmailContent' => 'test',
)); ));
@ -188,6 +168,31 @@ class EmailTest extends SapphireTest
$this->assertNotEmpty($email->getBody()); $this->assertNotEmpty($email->getBody());
} }
public function testRenderedSendSubclass()
{
// Include dev theme
SSViewer::set_themes([
'silverstripe/framework:/tests/php/Control/Email/EmailTest',
'$default',
]);
/** @var Email|PHPUnit_Framework_MockObject_MockObject $email */
$email = $this->getMockBuilder(EmailSubClass::class)
->enableProxyingToOriginalMethods()
->getMock();
$email->setFrom('from@example.com');
$email->setTo('to@example.com');
$email->setData(array(
'EmailContent' => 'test',
));
$this->assertFalse($email->hasPlainPart());
$this->assertEmpty($email->getBody());
$email->send();
$this->assertTrue($email->hasPlainPart());
$this->assertNotEmpty($email->getBody());
$this->assertContains('<h1>Email Sub-class</h1>', $email->getBody());
}
public function testConsturctor() public function testConsturctor()
{ {
$email = new Email( $email = new Email(
@ -460,8 +465,33 @@ class EmailTest extends SapphireTest
public function testHTMLTemplate() public function testHTMLTemplate()
{ {
// Include dev theme
SSViewer::set_themes([
'silverstripe/framework:/tests/php/Control/Email/EmailTest',
'$default',
]);
// Find template on disk
$emailTemplate = ModuleResourceLoader::singleton()->resolveResource(
'silverstripe/framework:templates/SilverStripe/Control/Email/Email.ss'
);
$subClassTemplate = ModuleResourceLoader::singleton()->resolveResource(
'silverstripe/framework:tests/php/Control/Email/EmailTest/templates/'
. str_replace('\\', '/', EmailSubClass::class)
.'.ss'
);
$this->assertTrue($emailTemplate->exists());
$this->assertTrue($subClassTemplate->exists());
// Check template is auto-found
$email = new Email(); $email = new Email();
$this->assertEquals(Email::class, $email->getHTMLTemplate()); $this->assertEquals($emailTemplate->getPath(), $email->getHTMLTemplate());
$email->setHTMLTemplate('MyTemplate');
$this->assertEquals('MyTemplate', $email->getHTMLTemplate());
// Check subclass template is found
$email2 = new EmailSubClass();
$this->assertEquals($subClassTemplate->getPath(), $email2->getHTMLTemplate());
$email->setHTMLTemplate('MyTemplate'); $email->setHTMLTemplate('MyTemplate');
$this->assertEquals('MyTemplate', $email->getHTMLTemplate()); $this->assertEquals('MyTemplate', $email->getHTMLTemplate());
} }
@ -480,8 +510,8 @@ class EmailTest extends SapphireTest
/** @var Swift_NullTransport|PHPUnit_Framework_MockObject_MockObject $transport */ /** @var Swift_NullTransport|PHPUnit_Framework_MockObject_MockObject $transport */
$transport = $this->getMockBuilder(Swift_NullTransport::class)->getMock(); $transport = $this->getMockBuilder(Swift_NullTransport::class)->getMock();
$transport->expects($this->once()) $transport->expects($this->once())
->method('send') ->method('send')
->willThrowException(new Swift_RfcComplianceException('Bad email')); ->willThrowException(new Swift_RfcComplianceException('Bad email'));
$mailer->setSwiftMailer(new Swift_Mailer($transport)); $mailer->setSwiftMailer(new Swift_Mailer($transport));
$email = new Email(); $email = new Email();
$email->setTo('to@example.com'); $email->setTo('to@example.com');
@ -495,7 +525,7 @@ class EmailTest extends SapphireTest
$this->assertTrue((new Email)->IsEmail()); $this->assertTrue((new Email)->IsEmail());
} }
public function testRender() public function testRenderAgain()
{ {
$email = new Email(); $email = new Email();
$email->setData(array( $email->setData(array(
@ -578,4 +608,24 @@ class EmailTest extends SapphireTest
$plainPart = reset($children); $plainPart = reset($children);
$this->assertContains('Test', $plainPart->getBody()); $this->assertContains('Test', $plainPart->getBody());
} }
/**
* @return PHPUnit_Framework_MockObject_MockObject|Email
*/
protected function makeEmailMock($subject)
{
/** @var Email|PHPUnit_Framework_MockObject_MockObject $email */
$email = $this->getMockBuilder(Email::class)
->enableProxyingToOriginalMethods()
->getMock();
$email->setFrom('from@example.com');
$email->setTo('to@example.com');
$email->setSubject($subject);
$email->setBody("Body for {$subject}");
$email->setCC('cc@example.com');
$email->setBCC('bcc@example.com');
$email->addAttachment(__DIR__ . '/EmailTest/attachment.txt', null, 'text/plain');
return $email;
}
} }

View File

@ -0,0 +1,11 @@
<?php
namespace SilverStripe\Control\Tests\Email\EmailTest;
use SilverStripe\Control\Email\Email;
use SilverStripe\Dev\TestOnly;
class EmailSubClass extends Email implements TestOnly
{
}

View File

@ -0,0 +1,14 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<% base_tag %>
</head>
<body>
<div class="body">
<h1>Email Sub-class</h1>
$EmailContent
</div>
</body>
</html>

View File

@ -0,0 +1,83 @@
<?php
namespace SilverStripe\Core\Tests;
use SilverStripe\Core\Environment;
use SilverStripe\Core\EnvironmentLoader;
use SilverStripe\Dev\SapphireTest;
class EnvironmentLoaderTest extends SapphireTest
{
public function testStripComments()
{
$loader = new EnvironmentLoader();
// No file
$this->assertNull($loader->loadFile(__DIR__ . '/EnvironmentTest/nofile.env'));
// Initial load
$vars = $loader->loadFile(__DIR__ . '/EnvironmentTest/test.env');
$this->assertCount(7, $vars);
$this->assertEquals('first', $vars['TEST_ENV_FIRST']);
$this->assertEquals('first', Environment::getEnv('TEST_ENV_FIRST'));
$this->assertEquals('start "#notcomment end', $vars['TEST_ENV_SECOND']);
$this->assertEquals('start "#notcomment end', Environment::getEnv('TEST_ENV_SECOND'));
$this->assertEquals(3, $vars['TEST_ENV_THIRD']);
$this->assertEquals(3, Environment::getEnv('TEST_ENV_THIRD'));
$this->assertEquals(true, $vars['TEST_ENV_FOURTH']);
$this->assertEquals(true, Environment::getEnv('TEST_ENV_FOURTH'));
$this->assertEquals('not#comment', $vars['TEST_ENV_FIFTH']);
$this->assertEquals('not#comment', Environment::getEnv('TEST_ENV_FIFTH'));
$this->assertEquals('not#comment', $vars['TEST_ENV_SIXTH']);
$this->assertEquals('not#comment', Environment::getEnv('TEST_ENV_SIXTH'));
$this->assertEquals('', $vars['TEST_ENV_SEVENTH']);
$this->assertEquals('', Environment::getEnv('TEST_ENV_SEVENTH'));
}
public function testOverloading()
{
$loader = new EnvironmentLoader();
// No file
$loader->loadFile(__DIR__ . '/EnvironmentTest/test.env');
// Ensure default behaviour doesn't overload
$vars2 = $loader->loadFile(__DIR__ . '/EnvironmentTest/test2.env');
$this->assertEquals(
[
'TEST_ENV_FIRST' => 'first',
'TEST_ENV_SECOND' => 'start "#notcomment end',
'TEST_ENV_NEWVAR' => 'first-overloaded',
'TEST_ENV_NEWVAR2' => 'second-file',
],
$vars2
);
$this->assertEquals('first', Environment::getEnv('TEST_ENV_FIRST'));
// Test overload = true
$vars2 = $loader->loadFile(__DIR__ . '/EnvironmentTest/test2.env', true);
$this->assertEquals(
[
'TEST_ENV_FIRST' => 'first-overloaded',
'TEST_ENV_SECOND' => 'first-overloaded',
'TEST_ENV_NEWVAR' => 'first-overloaded',
'TEST_ENV_NEWVAR2' => 'second-file',
],
$vars2
);
$this->assertEquals('first-overloaded', Environment::getEnv('TEST_ENV_FIRST'));
}
public function testInterpolation()
{
$loader = new EnvironmentLoader();
$vars = $loader->loadFile(__DIR__ . '/EnvironmentTest/test3.env');
$this->assertEquals(
[
'TEST_ENV_INT_ONE' => 'some var',
'TEST_ENV_INT_TWO' => 'some var',
],
$vars
);
}
}

View File

@ -0,0 +1,56 @@
<?php
namespace SilverStripe\Core\Tests;
use SilverStripe\Core\Environment;
use SilverStripe\Dev\SapphireTest;
class EnvironmentTest extends SapphireTest
{
public function providerTestPutEnv()
{
return [
['_ENVTEST_BOOL=true', '_ENVTEST_BOOL', true],
['_ENVTEST_BOOL_QUOTED="true"', '_ENVTEST_BOOL_QUOTED', 'true'],
['_ENVTEST_NUMBER=1', '_ENVTEST_NUMBER', 1],
['_ENVTEST_NUMBER_QUOTED="1"', '_ENVTEST_NUMBER_QUOTED', '1'],
['_ENVTEST_NUMBER_SPECIAL="value=4"', '_ENVTEST_NUMBER_SPECIAL', 'value=4'],
['_ENVTEST_BLANK', '_ENVTEST_BLANK', false],
];
}
/**
* @dataProvider providerTestPutenv
*/
public function testPutEnv($put, $var, $value)
{
Environment::putEnv($put);
$this->assertEquals($value, Environment::getEnv($var));
}
/**
* @dataProvider providerTestPutEnv
*/
public function testSetEnv($put, $var, $value)
{
Environment::setEnv($var, $value);
$this->assertEquals($value, Environment::getEnv($var));
}
public function testRestoreEnv()
{
// Set and backup original vars
Environment::putEnv('_ENVTEST_RESTORED=initial');
$vars = Environment::getVariables();
$this->assertEquals('initial', Environment::getEnv('_ENVTEST_RESTORED'));
// Modify enironment
Environment::putEnv('_ENVTEST_RESTORED=new');
$this->assertEquals('initial', $vars['env']['_ENVTEST_RESTORED']);
$this->assertEquals('new', Environment::getEnv('_ENVTEST_RESTORED'));
// Restore
Environment::setVariables($vars);
$this->assertEquals('initial', Environment::getEnv('_ENVTEST_RESTORED'));
}
}

View File

@ -0,0 +1,13 @@
# Test file
TEST_ENV_FIRST="first"
TEST_ENV_SECOND="start \"#notcomment end"#Comment
#Comment
TEST_ENV_THIRD = 3 #comment
TEST_ENV_FOURTH=true #comment
TEST_ENV_FIFTH = "not#comment"#comment
TEST_ENV_SIXTH="not#comment"
TEST_ENV_SEVENTH="" #comment

View File

@ -0,0 +1,6 @@
# Test file
TEST_ENV_FIRST="first-overloaded"
TEST_ENV_SECOND="${TEST_ENV_FIRST}"
TEST_ENV_NEWVAR="${TEST_ENV_FIRST}"
TEST_ENV_NEWVAR2="second-file"

View File

@ -0,0 +1,4 @@
# Test file
TEST_ENV_INT_ONE="some var"
TEST_ENV_INT_TWO="${TEST_ENV_INT_ONE}"

View File

@ -2,9 +2,9 @@
namespace SilverStripe\Core\Tests\Manifest; namespace SilverStripe\Core\Tests\Manifest;
use Dotenv\Loader;
use SilverStripe\Config\Collections\MemoryConfigCollection; use SilverStripe\Config\Collections\MemoryConfigCollection;
use SilverStripe\Core\Config\CoreConfigFactory; use SilverStripe\Core\Config\CoreConfigFactory;
use SilverStripe\Core\Environment;
use SilverStripe\Core\Injector\Injector; use SilverStripe\Core\Injector\Injector;
use SilverStripe\Core\Kernel; use SilverStripe\Core\Kernel;
use SilverStripe\Core\Manifest\ModuleLoader; use SilverStripe\Core\Manifest\ModuleLoader;
@ -100,8 +100,7 @@ class ConfigManifestTest extends SapphireTest
public function testEnvVarSetRules() public function testEnvVarSetRules()
{ {
$loader = new Loader(null); Environment::setEnv('ENVVARSET_FOO', '1');
$loader->setEnvironmentVariable('ENVVARSET_FOO', 1);
$config = $this->getConfigFixtureValue('EnvVarSet'); $config = $this->getConfigFixtureValue('EnvVarSet');
$this->assertEquals( $this->assertEquals(
@ -137,9 +136,7 @@ class ConfigManifestTest extends SapphireTest
public function testEnvOrConstantMatchesValueRules() public function testEnvOrConstantMatchesValueRules()
{ {
$loader = new Loader(null); Environment::setEnv('CONSTANTMATCHESVALUE_FOO', 'Foo');
$loader->setEnvironmentVariable('CONSTANTMATCHESVALUE_FOO', 'Foo');
define('CONSTANTMATCHESVALUE_BAR', 'Bar'); define('CONSTANTMATCHESVALUE_BAR', 'Bar');
$config = $this->getConfigFixtureValue('EnvOrConstantMatchesValue'); $config = $this->getConfigFixtureValue('EnvOrConstantMatchesValue');
@ -194,9 +191,7 @@ class ConfigManifestTest extends SapphireTest
public function testMultipleRules() public function testMultipleRules()
{ {
$loader = new Loader(null); Environment::setEnv('MULTIPLERULES_ENVVARIABLESET', '1');
$loader->setEnvironmentVariable('MULTIPLERULES_ENVVARIABLESET', 1);
define('MULTIPLERULES_DEFINEDCONSTANT', 'defined'); define('MULTIPLERULES_DEFINEDCONSTANT', 'defined');
$config = $this->getConfigFixtureValue('MultipleRules'); $config = $this->getConfigFixtureValue('MultipleRules');

View File

@ -3,6 +3,7 @@
namespace SilverStripe\ORM\Tests; namespace SilverStripe\ORM\Tests;
use SilverStripe\Control\Director; use SilverStripe\Control\Director;
use SilverStripe\Core\Environment;
use SilverStripe\Core\Injector\Injector; use SilverStripe\Core\Injector\Injector;
use SilverStripe\Core\Kernel; use SilverStripe\Core\Kernel;
use SilverStripe\ORM\DB; use SilverStripe\ORM\DB;
@ -15,7 +16,7 @@ class DBTest extends SapphireTest
{ {
/** @var Kernel $kernel */ /** @var Kernel $kernel */
$kernel = Injector::inst()->get(Kernel::class); $kernel = Injector::inst()->get(Kernel::class);
$prefix = getenv('SS_DATABASE_PREFIX') ?: 'ss_'; $prefix = Environment::getEnv('SS_DATABASE_PREFIX') ?: 'ss_';
$kernel->setEnvironment(Kernel::DEV); $kernel->setEnvironment(Kernel::DEV);
$this->assertTrue(DB::valid_alternative_database_name($prefix.'tmpdb1234567')); $this->assertTrue(DB::valid_alternative_database_name($prefix.'tmpdb1234567'));