Merge branch '4.0' into 4

This commit is contained in:
Daniel Hensby 2017-12-05 12:14:22 +00:00
commit eb55c27124
No known key found for this signature in database
GPG Key ID: B00D1E9767F0B06E
49 changed files with 321 additions and 75 deletions

View File

@ -1,7 +1,17 @@
inherit: true inherit: true
build:
environment:
variables:
# Must match actual branch, not alias. E.g. 4.x-dev rather than 4.1.x-dev for 4 branch, but 4.0.x-dev for 4.0 branch
COMPOSER_ROOT_VERSION: 4.x-dev
nodes:
analysis:
tests:
override: [php-scrutinizer-run]
filter: filter:
excluded_paths: paths:
- thirdparty/* - src/*
- parsers/* - tests/*
- docs/*
- images/*

View File

@ -42,6 +42,11 @@ matrix:
- DB=MYSQL - DB=MYSQL
- PDO=1 - PDO=1
- PHPUNIT_TEST=framework - PHPUNIT_TEST=framework
- php: nightly
env:
- DB=MYSQL
- PDO=1
- PHPUNIT_TEST=framework
- php: 7.0 - php: 7.0
env: env:
- DB=MYSQL - DB=MYSQL
@ -54,6 +59,12 @@ matrix:
env: env:
- DB=MYSQL - DB=MYSQL
- BEHAT_TEST=cms - BEHAT_TEST=cms
allow_failures:
- php: nightly
env:
- DB=MYSQL
- PDO=1
- PHPUNIT_TEST=framework
before_script: before_script:
# Init PHP # Init PHP

View File

@ -22,3 +22,6 @@ SilverStripe ships with default rewriting rules specific to your web server. Apa
routing requests to the framework, they also prevent access to sensitive files in the webroot, routing requests to the framework, they also prevent access to sensitive files in the webroot,
for example YAML configuration files. Please refer to the [secure coding](/developer_guides/security/secure_coding/#filesystem) documentation for details. for example YAML configuration files. Please refer to the [secure coding](/developer_guides/security/secure_coding/#filesystem) documentation for details.
</div> </div>
## Related Lessons
* [Up and running: Setting up a local SilverStripe dev environment](https://www.silverstripe.org/learn/lessons/v4/up-and-running-setting-up-a-local-silverstripe-dev-environment-1)

View File

@ -100,4 +100,4 @@ by using a `flush=1` query parameter. See the ["Manifests" documentation](/devel
## Best Practices ## Best Practices
### Making /assets readonly ### Making /assets readonly
See [Secure coding](/developer_guides/security/secure_coding#filesystem) See [Secure coding](/developer_guides/security/secure_coding#filesystem)

View File

@ -64,6 +64,15 @@ ready for download or installation on a cloud platform.
If you run into trouble, see [common-problems](installation/common_problems) or post to the If you run into trouble, see [common-problems](installation/common_problems) or post to the
[SilverStripe forums](http://silverstripe.org/community/forums/). [SilverStripe forums](http://silverstripe.org/community/forums/).
## Related
## Related Lessons
* [Up and running](https://www.silverstripe.org/learn/lessons/v4/up-and-running-setting-up-a-local-silverstripe-dev-environment-1)
* [Creating your first theme](https://www.silverstripe.org/learn/lessons/v4/creating-your-first-theme-1)
* [Migrating static templates into your theme](https://www.silverstripe.org/learn/lessons/v4/migrating-static-templates-into-your-theme-1)
* [Working with multiple templates](https://www.silverstripe.org/learn/lessons/v4/working-with-multiple-templates-1)
## Related Documentation
* [Module installation](/developer_guides/extending/modules) * [Module installation](/developer_guides/extending/modules)

View File

@ -403,4 +403,4 @@ We use the normal tactic of putting the data into an unordered list and using CS
In this tutorial we have explored custom php forms, and displayed result sets through Grouped Lists. We have briefly covered the different approaches to creating and using forms. Whether you decide to use the [userforms module](http://addons.silverstripe.org/add-ons/silverstripe/userforms) or create a form in PHP depends on the situation and flexibility required. In this tutorial we have explored custom php forms, and displayed result sets through Grouped Lists. We have briefly covered the different approaches to creating and using forms. Whether you decide to use the [userforms module](http://addons.silverstripe.org/add-ons/silverstripe/userforms) or create a form in PHP depends on the situation and flexibility required.
[Next Tutorial >>](/tutorials/site_search) [Next Tutorial >>](/tutorials/site_search)

View File

@ -744,6 +744,11 @@ record #2 in Page refers to the same object as record #2 in [SiteTree](api:Silve
To retrieve a news article, SilverStripe joins the [SiteTree](api:SilverStripe\CMS\Model\SiteTree), [Page](api:SilverStripe\CMS\Model\SiteTree\Page) and NewsPage tables by their ID fields. To retrieve a news article, SilverStripe joins the [SiteTree](api:SilverStripe\CMS\Model\SiteTree), [Page](api:SilverStripe\CMS\Model\SiteTree\Page) and NewsPage tables by their ID fields.
## Related Lessons
* [Introduction to the ORM](https://www.silverstripe.org/learn/lessons/v4/introduction-to-the-orm-1)
* [Adding custom fields to a page](https://www.silverstripe.org/learn/lessons/v4/adding-custom-fields-to-a-page-1)
## Related Documentation ## Related Documentation
* [Data Types and Casting](/developer_guides/model/data_types_and_casting) * [Data Types and Casting](/developer_guides/model/data_types_and_casting)

View File

@ -479,6 +479,10 @@ As these lists are not backed by the database, most of the filtering methods on
this type. As such, an `UnsavedRelationList` should only be used for setting a relation before saving an object, not this type. As such, an `UnsavedRelationList` should only be used for setting a relation before saving an object, not
for displaying the objects contained in the relation. for displaying the objects contained in the relation.
## Related Lessons
* [Working with data relationships -- has_many](https://www.silverstripe.org/learn/lessons/v4/working-with-data-relationships-has-many-1)
* [Working with data relationships -- many_many](https://www.silverstripe.org/learn/lessons/v4/working-with-data-relationships-many-many-1)
## Related Documentation ## Related Documentation
* [Introduction to the Data Model and ORM](data_model_and_orm) * [Introduction to the Data Model and ORM](data_model_and_orm)

View File

@ -92,6 +92,9 @@ echo $list->Count();
// returns '2' // returns '2'
``` ```
## Related Lessons
* [Lists and pagination](https://www.silverstripe.org/learn/lessons/v4/lists-and-pagination-1)
## API Documentation ## API Documentation
* [SS_List](api:SilverStripe\ORM\SS_List) * [SS_List](api:SilverStripe\ORM\SS_List)

View File

@ -89,3 +89,6 @@ class Player extends DataObject
Note: There are no separate methods for *onBeforeCreate* and *onBeforeUpdate*. Please check `$this->isInDb()` to toggle Note: There are no separate methods for *onBeforeCreate* and *onBeforeUpdate*. Please check `$this->isInDb()` to toggle
these two modes, as shown in the example above. these two modes, as shown in the example above.
</div> </div>
## Related Lessons
* [Working with data relationships - $has_many](https://www.silverstripe.org/learn/lessons/v4/working-with-data-relationships-has-many-1)

View File

@ -61,6 +61,10 @@ $players = Player::get()->filter([
]); ]);
``` ```
## Related Lessons
* [Introduction to ModelAdmin](https://www.silverstripe.org/learn/lessons/v4/introduction-to-modeladmin-1)
* [Building a search form](https://www.silverstripe.org/learn/lessons/v4/building-a-search-form-1)
## API Documentation ## API Documentation
* [SearchFilter](api:SilverStripe\ORM\Filters\SearchFilter) * [SearchFilter](api:SilverStripe\ORM\Filters\SearchFilter)

View File

@ -291,7 +291,11 @@ $players = Player::get();
$map = $players->map('Name', 'NameWithBirthyear'); $map = $players->map('Name', 'NameWithBirthyear');
``` ```
## Related ## Related Lessons
* [Building custom SQL](https://www.silverstripe.org/learn/lessons/v4/beyond-the-orm-building-custom-sql-1)
## Related Documentation
* [Introduction to the Data Model and ORM](data_model_and_orm) * [Introduction to the Data Model and ORM](data_model_and_orm)

View File

@ -551,7 +551,10 @@ for adding notes for other developers but for things you don't want published in
$EditForm <%-- Some hidden comment about the form --%> $EditForm <%-- Some hidden comment about the form --%>
``` ```
## Related ## Related Lessons
* [Creating your first theme](https://www.silverstripe.org/learn/lessons/v4/creating-your-first-theme-1)
## Related Documentation
[CHILDREN] [CHILDREN]
@ -563,3 +566,5 @@ $EditForm <%-- Some hidden comment about the form --%>
* [SSViewer](api:SilverStripe\View\SSViewer) * [SSViewer](api:SilverStripe\View\SSViewer)
* [ThemeManifest](api:SilverStripe\View\ThemeManifest) * [ThemeManifest](api:SilverStripe\View\ThemeManifest)

View File

@ -365,7 +365,10 @@ Placing it just below `$Content` is a good default.
You can add your own forms by implementing new form instances (see the [Forms tutorial](/tutorials/forms)). You can add your own forms by implementing new form instances (see the [Forms tutorial](/tutorials/forms)).
## Related ## Related Lessons
* [Adding dynamic content](https://www.silverstripe.org/learn/lessons/v4/adding-dynamic-content-1)
## Related Documentation
* [Casting and Formating Variables](casting) * [Casting and Formating Variables](casting)
* [Template Inheritance](template_inheritance) * [Template Inheritance](template_inheritance)

View File

@ -392,6 +392,10 @@ $file = ModuleResourceLoader::singleton()
->resolveURL('silverstripe/admin:client/dist/images/spinner.gif'); ->resolveURL('silverstripe/admin:client/dist/images/spinner.gif');
``` ```
## Related Lessons
* [Creating your first theme](https://www.silverstripe.org/learn/lessons/v4/creating-your-first-theme-1)
* [AJAX behaviour and ViewableData](https://www.silverstripe.org/learn/lessons/v4/ajax-behaviour-and-viewabledata-1)
## API Documentation ## API Documentation
* [Requirements](api:SilverStripe\View\Requirements) * [Requirements](api:SilverStripe\View\Requirements)

View File

@ -99,3 +99,9 @@ class PageController extends ContentController
} }
``` ```
## Related Lessons
* [Controller actions/DataObjects as pages](https://www.silverstripe.org/learn/lessons/v4/controller-actions-dataobjects-as-pages-1)
* [AJAX behaviour and ViewableData](https://www.silverstripe.org/learn/lessons/v4/ajax-behaviour-and-viewabledata-1)
* [Dealing with arbitrary template data](https://www.silverstripe.org/learn/lessons/v4/dealing-with-arbitrary-template-data-1)
* [Creating filtered views](https://www.silverstripe.org/learn/lessons/v4/creating-filtered-views-1)

View File

@ -180,3 +180,6 @@ Module names are derived their local `composer.json` files using the following p
* The value of the `name` attribute in `composer.json` * The value of the `name` attribute in `composer.json`
* The value of `extras.installer_name` in `composer.json` * The value of `extras.installer_name` in `composer.json`
* The basename of the directory that contains the module * The basename of the directory that contains the module
## Related Lessons
* [Working with multiple templates](https://www.silverstripe.org/learn/lessons/v4/working-with-multiple-templates-1)

View File

@ -103,3 +103,7 @@ The final step is to [submit your theme to Packagist](https://packagist.org/abou
* [Themes Listing on silverstripe.org](http://addons.silverstripe.org/add-ons?search=&type=theme) * [Themes Listing on silverstripe.org](http://addons.silverstripe.org/add-ons?search=&type=theme)
* [Themes Forum on silverstripe.org](https://www.silverstripe.org/community/forums/themes-2/) * [Themes Forum on silverstripe.org](https://www.silverstripe.org/community/forums/themes-2/)
* [Themes repositories on github.com](http://github.com/silverstripe-themes) * [Themes repositories on github.com](http://github.com/silverstripe-themes)
## Related Lessons
* [Creating your first theme](https://www.silverstripe.org/learn/lessons/v4/creating-your-first-theme-1)
* [Migrating static templates into your theme](https://www.silverstripe.org/learn/lessons/v4/migrating-static-templates-into-your-theme-1)

View File

@ -167,3 +167,7 @@ Text / HTMLText methods:
version of emails. version of emails.
* `$LimitSentences(<num>)` Will limit to the first `<num>` sentences in the content. If called on * `$LimitSentences(<num>)` Will limit to the first `<num>` sentences in the content. If called on
HTML content this will have all HTML stripped and converted to plain text. HTML content this will have all HTML stripped and converted to plain text.
## Related Lessons
* [Dealing with arbitrary template data](https://www.silverstripe.org/learn/lessons/v4/dealing-with-arbitrary-template-data-1)

View File

@ -113,6 +113,8 @@ list.
| `$Link` | Links to the current controller URL, setting this page as current via a GET parameter | | `$Link` | Links to the current controller URL, setting this page as current via a GET parameter |
| `$CurrentBool` | Returns true if you're currently on that page | | `$CurrentBool` | Returns true if you're currently on that page |
## Related Lessons
* [Lists and pagination](https://www.silverstripe.org/learn/lessons/v4/lists-and-pagination-1)
## API Documentation ## API Documentation

View File

@ -15,3 +15,6 @@ templates from your controllers.
## How to's ## How to's
[CHILDREN Folder=How_Tos] [CHILDREN Folder=How_Tos]
## Related Lessons
* [Migrating static templates into your theme](https://www.silverstripe.org/learn/lessons/v4/migrating-static-templates-into-your-theme-1)

View File

@ -174,6 +174,10 @@ public function Link($action = null)
The [Controller::join_links()](api:SilverStripe\Control\Controller::join_links()) is optional, but makes `Link()` more flexible by allowing an `$action` argument, and concatenates the path segments with slashes. The action should map to a method on your controller. The [Controller::join_links()](api:SilverStripe\Control\Controller::join_links()) is optional, but makes `Link()` more flexible by allowing an `$action` argument, and concatenates the path segments with slashes. The action should map to a method on your controller.
</div> </div>
## Related Lessons
* [Controller actions/DataObjects as pages](https://www.silverstripe.org/learn/lessons/v4/controller-actions-dataobjects-as-pages-1)
* [Creating filtered views](https://www.silverstripe.org/learn/lessons/v4/creating-filtered-views-1)
## Related Documentation ## Related Documentation
* [Execution Pipeline](../execution_pipeline) * [Execution Pipeline](../execution_pipeline)

View File

@ -213,6 +213,9 @@ Director:
'feed': 'FeedController' 'feed': 'FeedController'
``` ```
## Related Lessons
* [Creating filtered views](https://www.silverstripe.org/learn/lessons/v4/creating-filtered-views-1)
* [Controller actions / DataObjects as pages](https://www.silverstripe.org/learn/lessons/v4/controller-actions-dataobjects-as-pages-1)
## Links ## Links
* [Controller](api:SilverStripe\Control\Controller) API documentation * [Controller](api:SilverStripe\Control\Controller) API documentation

View File

@ -346,6 +346,9 @@ $validator = new SilverStripe\Forms\RequiredFields([
$form = new Form($this, 'MyForm', $fields, $actions, $validator); $form = new Form($this, 'MyForm', $fields, $actions, $validator);
``` ```
## Related Lessons
* [Intoduction to frontend forms](https://www.silverstripe.org/learn/lessons/v4/introduction-to-frontend-forms-1)
## API Documentation ## API Documentation
* [Form](api:SilverStripe\Forms\Form) * [Form](api:SilverStripe\Forms\Form)

View File

@ -307,6 +307,10 @@ class Page extends SiteTree
``` ```
## Related Lessons
* [Intoduction to frontend forms](https://www.silverstripe.org/learn/lessons/v4/introduction-to-frontend-forms-1)
## API Documentation ## API Documentation
* [RequiredFields](api:SilverStripe\Forms\RequiredFields) * [RequiredFields](api:SilverStripe\Forms\RequiredFields)

View File

@ -351,3 +351,6 @@ That is, the fragment will be included if all Only rules match, except if all Ex
## API Documentation ## API Documentation
* [Config](api:SilverStripe\Core\Config\Config) * [Config](api:SilverStripe\Core\Config\Config)
## Related Lessons
* [DataExtensions and SiteConfig](https://www.silverstripe.org/learn/lessons/v4/data-extensions-and-siteconfig-1)

View File

@ -81,3 +81,7 @@ provide the users a place to configure settings then the `SiteConfig` panel is t
## API Documentation ## API Documentation
* [SiteConfig](api:SilverStripe\SiteConfig\SiteConfig) * [SiteConfig](api:SilverStripe\SiteConfig\SiteConfig)
## Related Lessons
* [DataExtensions and SiteConfig](https://www.silverstripe.org/learn/lessons/v4/data-extensions-and-siteconfig-1)

View File

@ -11,3 +11,7 @@ For more information see our docs on [Environment Management](../../getting_star
Data which isn't sensitive that can be in version control but is mostly static such as constants is best suited to be Data which isn't sensitive that can be in version control but is mostly static such as constants is best suited to be
included through the [Configuration API](configuration) based on the standard environment types (dev / test / live). included through the [Configuration API](configuration) based on the standard environment types (dev / test / live).
## Related Lessons
* [Up and running](https://www.silverstripe.org/learn/lessons/v4/up-and-running-setting-up-a-local-silverstripe-dev-environment-1)
* [Advanced environment configuration](https://www.silverstripe.org/learn/lessons/v4/advanced-environment-configuration-1)

View File

@ -311,6 +311,10 @@ public function getCMSFields()
} }
``` ```
## Related Lessons
* [DataExtensions and SiteConfig](https://www.silverstripe.org/learn/lessons/v4/data-extensions-and-siteconfig-1)
## Related Documentaion ## Related Documentaion
* [Injector](injector/) * [Injector](injector/)

View File

@ -81,4 +81,5 @@ if (Director::isLive()) {
} }
``` ```
## Related Lessons
* [Advanced environment configuration](https://www.silverstripe.org/learn/lessons/v4/advanced-environment-configuration-1)

View File

@ -265,3 +265,6 @@ In SilverStripe 3, logging was based on the Zend Log module. Customisations were
This function no longer works, and any Zend Log writers will need to be replaced with Monolog handlers. Fortunately, This function no longer works, and any Zend Log writers will need to be replaced with Monolog handlers. Fortunately,
a range of handlers are available, both in the core package and in add-ons. See the a range of handlers are available, both in the core package and in add-ons. See the
[Monolog documentation](https://github.com/Seldaek/monolog/blob/master/doc/01-usage.md) for more information. [Monolog documentation](https://github.com/Seldaek/monolog/blob/master/doc/01-usage.md) for more information.
## Related Lessons
* [Advanced environment configuration](https://www.silverstripe.org/learn/lessons/v4/advanced-environment-configuration-1)

View File

@ -202,3 +202,6 @@ storage.
SilverStripe\Assets\File: SilverStripe\Assets\File:
keep_archived_assets: true keep_archived_assets: true
``` ```
## Related Lessons
* [Working with files and images](https://www.silverstripe.org/learn/lessons/v4/working-with-files-and-images-1)

View File

@ -214,3 +214,7 @@ SilverStripe\Core\Injector\Injector:
* [Image](api:SilverStripe\Assets\Image) * [Image](api:SilverStripe\Assets\Image)
* [DBFile](api:SilverStripe\Assets\Storage\DBFile) * [DBFile](api:SilverStripe\Assets\Storage\DBFile)
* [ImageManipulation](api:SilverStripe\Assets\ImageManipulation) * [ImageManipulation](api:SilverStripe\Assets\ImageManipulation)
## Related Lessons
* [Working with files and images](https://www.silverstripe.org/learn/lessons/v4/working-with-files-and-images-1)

View File

@ -360,6 +360,9 @@ class MyAdmin extends ModelAdmin
} }
``` ```
## Related Lessons
* [Intoduction to ModelAdmin](https://www.silverstripe.org/learn/lessons/v4/introduction-to-modeladmin-1)
## Related Documentation ## Related Documentation
* [GridField](../forms/field_types/gridfield) * [GridField](../forms/field_types/gridfield)

View File

@ -359,7 +359,7 @@ class CoreKernel implements Kernel
} }
// Allow database adapters to handle their own configuration // Allow database adapters to handle their own configuration
DatabaseAdapterRegistry::autoconfigure(); DatabaseAdapterRegistry::autoconfigure($databaseConfig);
return $databaseConfig; return $databaseConfig;
} }

View File

@ -3,6 +3,7 @@
namespace SilverStripe\Dev\Install; namespace SilverStripe\Dev\Install;
use InvalidArgumentException; use InvalidArgumentException;
use SilverStripe\Dev\Deprecation;
/** /**
* This class keeps track of the available database adapters * This class keeps track of the available database adapters
@ -111,7 +112,7 @@ class DatabaseAdapterRegistry
/** /**
* Detects all _register_database.php files and invokes them. * Detects all _register_database.php files and invokes them.
* Searches through vendor/ folder only, * Searches through vendor/*\/* folders only,
* does not support "legacy" folder location in webroot * does not support "legacy" folder location in webroot
*/ */
public static function autodiscover() public static function autodiscover()
@ -131,10 +132,19 @@ class DatabaseAdapterRegistry
* Called by ConfigureFromEnv.php. * Called by ConfigureFromEnv.php.
* Searches through vendor/ folder only, * Searches through vendor/ folder only,
* does not support "legacy" folder location in webroot * does not support "legacy" folder location in webroot
*
* @param array $config Config to update. If not provided fall back to global $databaseConfig.
* In 5.0.0 this will be mandatory and the global will be removed.
*/ */
public static function autoconfigure() public static function autoconfigure(&$config = null)
{ {
// Search through all composer packages in vendor if (!isset($config)) {
Deprecation::notice('5.0', 'Configuration via global is deprecated');
global $databaseConfig;
} else {
$databaseConfig = $config;
}
// Search through all composer packages in vendor, updating $databaseConfig
foreach (glob(BASE_PATH . '/vendor/*', GLOB_ONLYDIR) as $vendor) { foreach (glob(BASE_PATH . '/vendor/*', GLOB_ONLYDIR) as $vendor) {
foreach (glob($vendor . '/*', GLOB_ONLYDIR) as $directory) { foreach (glob($vendor . '/*', GLOB_ONLYDIR) as $directory) {
if (file_exists($directory . '/_configure_database.php')) { if (file_exists($directory . '/_configure_database.php')) {
@ -142,6 +152,8 @@ class DatabaseAdapterRegistry
} }
} }
} }
// Update modified variable
$config = $databaseConfig;
} }
/** /**

View File

@ -227,8 +227,9 @@ class InstallRequirements
/** /**
* Check everything except the database * Check everything except the database
*/ */
public function check() public function check($originalIni)
{ {
$this->originalIni = $originalIni;
$this->errors = []; $this->errors = [];
$isApache = $this->isApache(); $isApache = $this->isApache();
$isIIS = $this->isIIS(); $isIIS = $this->isIIS();

View File

@ -66,7 +66,7 @@ $theme = $config->getTheme($_REQUEST);
// Check requirements // Check requirements
$req = new InstallRequirements(); $req = new InstallRequirements();
$req->check(); $req->check($originalIni);
if ($req->isIIS()) { if ($req->isIIS()) {
$webserverConfigFile = 'web.config'; $webserverConfigFile = 'web.config';

View File

@ -74,49 +74,49 @@ class TinyMCEConfig extends HTMLEditorConfig
'fa_PK' => 'fa', 'fa_PK' => 'fa',
'fi_FI' => 'fi', 'fi_FI' => 'fi',
'fi_SE' => 'fi', 'fi_SE' => 'fi',
'fr_BE' => 'fr', 'fr_BE' => 'fr_FR',
'fr_BF' => 'fr', 'fr_BF' => 'fr_FR',
'fr_BI' => 'fr', 'fr_BI' => 'fr_FR',
'fr_BJ' => 'fr', 'fr_BJ' => 'fr_FR',
'fr_CA' => 'fr_ca', 'fr_CA' => 'fr_FR',
'fr_CF' => 'fr', 'fr_CF' => 'fr_FR',
'fr_CG' => 'fr', 'fr_CG' => 'fr_FR',
'fr_CH' => 'fr', 'fr_CH' => 'fr_FR',
'fr_CI' => 'fr', 'fr_CI' => 'fr_FR',
'fr_CM' => 'fr', 'fr_CM' => 'fr_FR',
'fr_DJ' => 'fr', 'fr_DJ' => 'fr_FR',
'fr_DZ' => 'fr', 'fr_DZ' => 'fr_FR',
'fr_FR' => 'fr', 'fr_FR' => 'fr_FR',
'fr_GA' => 'fr', 'fr_GA' => 'fr_FR',
'fr_GF' => 'fr', 'fr_GF' => 'fr_FR',
'fr_GN' => 'fr', 'fr_GN' => 'fr_FR',
'fr_GP' => 'fr', 'fr_GP' => 'fr_FR',
'fr_HT' => 'fr', 'fr_HT' => 'fr_FR',
'fr_KM' => 'fr', 'fr_KM' => 'fr_FR',
'fr_LU' => 'fr', 'fr_LU' => 'fr_FR',
'fr_MA' => 'fr', 'fr_MA' => 'fr_FR',
'fr_MC' => 'fr', 'fr_MC' => 'fr_FR',
'fr_MG' => 'fr', 'fr_MG' => 'fr_FR',
'fr_ML' => 'fr', 'fr_ML' => 'fr_FR',
'fr_MQ' => 'fr', 'fr_MQ' => 'fr_FR',
'fr_MU' => 'fr', 'fr_MU' => 'fr_FR',
'fr_NC' => 'fr', 'fr_NC' => 'fr_FR',
'fr_NE' => 'fr', 'fr_NE' => 'fr_FR',
'fr_PF' => 'fr', 'fr_PF' => 'fr_FR',
'fr_PM' => 'fr', 'fr_PM' => 'fr_FR',
'fr_RE' => 'fr', 'fr_RE' => 'fr_FR',
'fr_RW' => 'fr', 'fr_RW' => 'fr_FR',
'fr_SC' => 'fr', 'fr_SC' => 'fr_FR',
'fr_SN' => 'fr', 'fr_SN' => 'fr_FR',
'fr_SY' => 'fr', 'fr_SY' => 'fr_FR',
'fr_TD' => 'fr', 'fr_TD' => 'fr_FR',
'fr_TG' => 'fr', 'fr_TG' => 'fr_FR',
'fr_TN' => 'fr', 'fr_TN' => 'fr_FR',
'fr_VU' => 'fr', 'fr_VU' => 'fr_FR',
'fr_WF' => 'fr', 'fr_WF' => 'fr_FR',
'fr_YT' => 'fr', 'fr_YT' => 'fr_FR',
'fr_GB' => 'fr', 'fr_GB' => 'fr_FR',
'fr_US' => 'fr', 'fr_US' => 'fr_FR',
'he_IL' => 'he', 'he_IL' => 'he',
'hu_HU' => 'hu', 'hu_HU' => 'hu',
'hu_AT' => 'hu', 'hu_AT' => 'hu',

View File

@ -899,8 +899,7 @@ abstract class DBSchemaManager
* *
* @param string $tableName The name of the table. * @param string $tableName The name of the table.
* @param string $indexName The name of the index. * @param string $indexName The name of the index.
* @param string $indexSpec The specification of the index, see {@link SS_Database::requireIndex()} * @param array $indexSpec The specification of the index, see Database::requireIndex() for more details.
* for more details.
* @todo Find out where this is called from - Is it even used? Aren't indexes always dropped and re-added? * @todo Find out where this is called from - Is it even used? Aren't indexes always dropped and re-added?
*/ */
abstract public function alterIndex($tableName, $indexName, $indexSpec); abstract public function alterIndex($tableName, $indexName, $indexSpec);

View File

@ -6,6 +6,7 @@ use Exception;
use SilverStripe\Core\Injector\Injectable; use SilverStripe\Core\Injector\Injectable;
use SilverStripe\Core\Config\Configurable; use SilverStripe\Core\Config\Configurable;
use SilverStripe\Core\Injector\Injector; use SilverStripe\Core\Injector\Injector;
use SilverStripe\Dev\TestOnly;
use SilverStripe\ORM\FieldType\DBComposite; use SilverStripe\ORM\FieldType\DBComposite;
use SilverStripe\Core\ClassInfo; use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Config\Config; use SilverStripe\Core\Config\Config;
@ -126,6 +127,7 @@ class DataObjectSchema
} }
return null; return null;
} }
/** /**
* Returns the root class (the first to extend from DataObject) for the * Returns the root class (the first to extend from DataObject) for the
* passed class. * passed class.
@ -301,11 +303,26 @@ class DataObjectSchema
$table = Config::inst()->get($class, 'table_name', Config::UNINHERITED); $table = Config::inst()->get($class, 'table_name', Config::UNINHERITED);
// Generate default table name // Generate default table name
if (!$table) { if ($table) {
$separator = DataObjectSchema::config()->uninherited('table_namespace_separator'); return $table;
$table = str_replace('\\', $separator, trim($class, '\\'));
} }
if (strpos($class, '\\') === false) {
return $class;
}
if (!ClassInfo::classImplements($class, TestOnly::class)) {
trigger_error(
"It is recommended to define a table_name for your '$class'." .
' Not defining a table_name may cause subsequent table names to be too long and may not be supported' .
' by your current database engine, the generated naming scheme will also change when upgrading to' .
' SilverStripe 5.0 and potentially break.',
E_USER_WARNING
);
}
$separator = DataObjectSchema::config()->uninherited('table_namespace_separator');
$table = str_replace('\\', $separator, trim($class, '\\'));
return $table; return $table;
} }

View File

@ -2,6 +2,7 @@
namespace SilverStripe\Security\MemberAuthenticator; namespace SilverStripe\Security\MemberAuthenticator;
use SilverStripe\Control\Controller;
use SilverStripe\Control\Director; use SilverStripe\Control\Director;
use SilverStripe\Control\HTTPResponse; use SilverStripe\Control\HTTPResponse;
use SilverStripe\Control\RequestHandler; use SilverStripe\Control\RequestHandler;
@ -109,6 +110,14 @@ class LogoutHandler extends RequestHandler
return $this->redirect($backURL); return $this->redirect($backURL);
} }
return $this->redirect(Security::config()->get('login_url')); $link = Security::config()->get('login_url');
$referer = $this->getReturnReferer();
if ($referer) {
$link = Controller::join_links($link, '?' . http_build_query([
'BackURL' => Director::makeRelative($referer)
]));
}
return $this->redirect($link);
} }
} }

View File

@ -3,9 +3,12 @@
namespace SilverStripe\View; namespace SilverStripe\View;
use Exception; use Exception;
use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Config\Configurable; use SilverStripe\Core\Config\Configurable;
use SilverStripe\Core\Extensible; use SilverStripe\Core\Extensible;
use SilverStripe\Core\Injector\Injectable; use SilverStripe\Core\Injector\Injectable;
use SilverStripe\Core\Manifest\ModuleResourceLoader;
use SilverStripe\Dev\Deprecation;
use SilverStripe\ORM\ArrayLib; use SilverStripe\ORM\ArrayLib;
use SilverStripe\ORM\FieldType\DBField; use SilverStripe\ORM\FieldType\DBField;
use SilverStripe\ORM\FieldType\DBHTMLText; use SilverStripe\ORM\FieldType\DBHTMLText;
@ -586,6 +589,35 @@ class ViewableData implements IteratorAggregate
return $this; return $this;
} }
/**
* Return the directory if the current active theme (relative to the site root).
*
* This method is useful for things such as accessing theme images from your template without hardcoding the theme
* page - e.g. <img src="$ThemeDir/images/something.gif">.
*
* This method should only be used when a theme is currently active. However, it will fall over to the current
* project directory.
*
* @return string URL to the current theme
* @deprecated 4.0.0..5.0.0 Use $resourcePath or $resourceURL template helpers instead
*/
public function ThemeDir()
{
Deprecation::notice('5.0', 'Use $resourcePath or $resourceURL template helpers instead');
$themes = SSViewer::get_themes();
foreach ($themes as $theme) {
// Skip theme sets
if (strpos($theme, '$') === 0) {
continue;
}
// Map theme path to url
$themePath = ThemeResourceLoader::inst()->getPath($theme);
return ModuleResourceLoader::resourceURL($themePath);
}
return project();
}
/** /**
* Get part of the current classes ancestry to be used as a CSS class. * Get part of the current classes ancestry to be used as a CSS class.
* *

View File

@ -793,7 +793,7 @@ class IntlLocales implements Locales, Resettable
'pl' => 'pl_PL', 'pl' => 'pl_PL',
'pon' => 'pon_FM', 'pon' => 'pon_FM',
'ps' => 'ps_AF', 'ps' => 'ps_AF',
'pt' => 'pt_BR', 'pt' => 'pt_PT',
'qu' => 'qu_PE', 'qu' => 'qu_PE',
'rm' => 'rm_CH', 'rm' => 'rm_CH',
'rn' => 'rn_BI', 'rn' => 'rn_BI',

View File

@ -558,6 +558,7 @@ class i18nTextCollector
$inNamespace = false; $inNamespace = false;
$inClass = false; // after `class` but before `{` $inClass = false; // after `class` but before `{`
$inArrayClosedBy = false; // Set to the expected closing token, or false if not in array $inArrayClosedBy = false; // Set to the expected closing token, or false if not in array
$inSelf = false; // Tracks progress of collecting self::class
$currentEntity = array(); $currentEntity = array();
$currentClass = []; // Class components $currentClass = []; // Class components
$previousToken = null; $previousToken = null;
@ -584,10 +585,20 @@ class i18nTextCollector
if ($id === T_CLASS) { if ($id === T_CLASS) {
// Skip if previous token was '::'. E.g. 'Object::class' // Skip if previous token was '::'. E.g. 'Object::class'
if (is_array($previousToken) && $previousToken[0] === T_DOUBLE_COLON) { if (is_array($previousToken) && $previousToken[0] === T_DOUBLE_COLON) {
if ($inSelf) {
// Handle self::class by allowing logic further down
// for __CLASS__ to handle an array of class parts
$id = T_CLASS_C;
$inSelf = false;
} else {
// Don't handle other ::class definitions. We can't determine which
// class was invoked, so parent::class is not possible at this point.
continue;
}
} else {
$inClass = true;
continue; continue;
} }
$inClass = true;
continue;
} }
if ($inClass && $id === T_STRING) { if ($inClass && $id === T_STRING) {
$currentClass[] = $text; $currentClass[] = $text;
@ -614,7 +625,7 @@ class i18nTextCollector
// If inside this translation, some elements might be unreachable // If inside this translation, some elements might be unreachable
if (in_array($id, [T_VARIABLE, T_STATIC]) || if (in_array($id, [T_VARIABLE, T_STATIC]) ||
($id === T_STRING && in_array($text, ['self', 'static', 'parent'])) ($id === T_STRING && in_array($text, ['static', 'parent']))
) { ) {
// Un-collectable strings such as _t(static::class.'.KEY'). // Un-collectable strings such as _t(static::class.'.KEY').
// Should be provided by i18nEntityProvider instead // Should be provided by i18nEntityProvider instead
@ -625,6 +636,12 @@ class i18nTextCollector
continue; continue;
} }
// Start collecting self::class declarations
if ($id === T_STRING && $text === 'self') {
$inSelf = true;
continue;
}
// Check text // Check text
if ($id == T_CONSTANT_ENCAPSED_STRING) { if ($id == T_CONSTANT_ENCAPSED_STRING) {
// Fixed quoting escapes, and remove leading/trailing quotes // Fixed quoting escapes, and remove leading/trailing quotes
@ -648,7 +665,7 @@ class i18nTextCollector
throw new LogicException("Invalid string escape: " .$text); throw new LogicException("Invalid string escape: " .$text);
} }
} elseif ($id === T_CLASS_C) { } elseif ($id === T_CLASS_C) {
// Evaluate __CLASS__ . '.KEY' concatenation // Evaluate __CLASS__ . '.KEY' and self::class concatenation
$text = implode('\\', $currentClass); $text = implode('\\', $currentClass);
} else { } else {
continue; continue;

View File

@ -2,7 +2,9 @@
namespace SilverStripe\Core\Tests\ClassInfoTest; namespace SilverStripe\Core\Tests\ClassInfoTest;
class ChildClass extends BaseClass use SilverStripe\Dev\TestOnly;
class ChildClass extends BaseClass implements TestOnly
{ {
} }

View File

@ -5,6 +5,7 @@ namespace SilverStripe\View\Tests;
use SilverStripe\ORM\FieldType\DBField; use SilverStripe\ORM\FieldType\DBField;
use SilverStripe\Dev\SapphireTest; use SilverStripe\Dev\SapphireTest;
use SilverStripe\View\ArrayData; use SilverStripe\View\ArrayData;
use SilverStripe\View\SSViewer;
use SilverStripe\View\ViewableData; use SilverStripe\View\ViewableData;
/** /**
@ -204,4 +205,19 @@ class ViewableDataTest extends SapphireTest
$this->assertSame($failover, $container->getFailover(), 'getFailover() returned a different object'); $this->assertSame($failover, $container->getFailover(), 'getFailover() returned a different object');
$this->assertFalse($container->hasMethod('testMethod'), 'testMethod() incorrectly reported as existing'); $this->assertFalse($container->hasMethod('testMethod'), 'testMethod() incorrectly reported as existing');
} }
public function testThemeDir()
{
$themes = [
"silverstripe/framework:/tests/php/View/ViewableDataTest/testtheme",
SSViewer::DEFAULT_THEME
];
SSViewer::set_themes($themes);
$data = new ViewableData();
$this->assertContains(
'tests/php/View/ViewableDataTest/testtheme',
$data->ThemeDir()
);
}
} }

View File

@ -323,13 +323,21 @@ class MyClass extends Base implements SomeService {
"Slash=\\\\, Quote=\\"" "Slash=\\\\, Quote=\\""
); );
} }
public function getMagicConstantStringFromSelf()
{
return _t(
self::class . '.SELF_CLASS',
'Self Class'
);
}
} }
PHP; PHP;
$this->assertEquals( $this->assertEquals(
[ [
'SilverStripe\\Framework\\Core\\MyClass.NEWLINES' => "New Lines", 'SilverStripe\\Framework\\Core\\MyClass.NEWLINES' => "New Lines",
'SilverStripe\\Framework\\MyClass.ANOTHER_STRING' => 'Slash=\\, Quote=\'', 'SilverStripe\\Framework\\MyClass.ANOTHER_STRING' => 'Slash=\\, Quote=\'',
'SilverStripe\\Framework\\MyClass.DOUBLE_STRING' => 'Slash=\\, Quote="' 'SilverStripe\\Framework\\MyClass.DOUBLE_STRING' => 'Slash=\\, Quote="',
'SilverStripe\\Framework\\Core\\MyClass.SELF_CLASS' => 'Self Class',
], ],
$c->collectFromCode($php, null, $mymodule) $c->collectFromCode($php, null, $mymodule)
); );
@ -434,7 +442,7 @@ PHP;
$php = <<<PHP $php = <<<PHP
_t(static::class.'.KEY1', 'Default'); _t(static::class.'.KEY1', 'Default');
_t(self::class.'.KEY2', 'Default'); _t(parent::class.'.KEY1', 'Default');
_t('Collectable.KEY4', 'Default'); _t('Collectable.KEY4', 'Default');
PHP; PHP;