|
|
@ -2,17 +2,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
## Overview ##
|
|
|
|
## Overview ##
|
|
|
|
|
|
|
|
|
|
|
|
* New template engine
|
|
|
|
### CMS
|
|
|
|
* New CMS interface design
|
|
|
|
|
|
|
|
* Image/Link insertion moved into a modal dialog instead of a sidebar
|
|
|
|
* New CMS interface design more geared towards complex content solutions
|
|
|
|
|
|
|
|
* List view for pages (sortable and filterable)
|
|
|
|
|
|
|
|
* More powerful media and link insertion (including auto-embedding of external sources)
|
|
|
|
* Batch actions on site tree moved to an "Edit Tree" view
|
|
|
|
* Batch actions on site tree moved to an "Edit Tree" view
|
|
|
|
* "Add pages" dropdown now an "Add new" button which goes to a more descriptive page
|
|
|
|
* "Add pages" shows a dedicated interface with more info about the page type
|
|
|
|
* Renaming of sapphire to SilverStripe framework
|
|
|
|
|
|
|
|
* FormField classes now have their own HTML templates
|
|
|
|
|
|
|
|
* Allow usage of SilverStripe framework without the "cms" module
|
|
|
|
|
|
|
|
* CMS JavaScript moved to [jQuery.entwine](https://github.com/hafriedlander/jquery.entwine)
|
|
|
|
* CMS JavaScript moved to [jQuery.entwine](https://github.com/hafriedlander/jquery.entwine)
|
|
|
|
* CMS stylesheets are generated by SCSS to provide more flexible and robust styling
|
|
|
|
* CMS stylesheets are generated by SCSS to provide more flexible and robust styling
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Framework
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* Renaming of "sapphire" to SilverStripe "framework"
|
|
|
|
|
|
|
|
* Allow usage of SilverStripe framework without the "cms" module
|
|
|
|
|
|
|
|
* New template engine with more powerful syntax
|
|
|
|
|
|
|
|
* New ORM layer with expressive and fluent syntax
|
|
|
|
|
|
|
|
* New GridField component to replace ComplexTableField
|
|
|
|
|
|
|
|
* FormField classes now have their own HTML templates
|
|
|
|
|
|
|
|
* Moved functionality to modules: Widget, RestfulServer, SapphireSoapServer, Translatable, IPRestrictions, PageComment, HomepageForDomain
|
|
|
|
|
|
|
|
|
|
|
|
## Detailed change logs ##
|
|
|
|
## Detailed change logs ##
|
|
|
|
|
|
|
|
|
|
|
|
The detailed change logs are broken down by pre-release:
|
|
|
|
The detailed change logs are broken down by pre-release:
|
|
|
@ -29,19 +38,67 @@ The detailed change logs are broken down by pre-release:
|
|
|
|
|
|
|
|
|
|
|
|
## Upgrading ##
|
|
|
|
## Upgrading ##
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Common Upgrade Tasks
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* Rename foder from `sapphire/`to `framework/`, replace own paths with `FRAMEWORK_DIR` (in PHP) or `$ModulePath(framework)` (in templates). Update paths in `.htaccess` or `web.config` ([more](#sapphire-rename))
|
|
|
|
|
|
|
|
* Replace `<% control %>` in your templates with `<% loop %>` and `<% with %>` ([more](/reference/templates-upgrading-guide#control))
|
|
|
|
|
|
|
|
* Replace `DataObjectSet` with `DataList` or `ArrayList` ([more](#deprecated-classes))
|
|
|
|
|
|
|
|
* Rewrite `ComplexTableField` and `DataObjectManager` instances to `GridField`
|
|
|
|
|
|
|
|
* Rewrite `Director::redirect()` and `Director::redirectBack()` calls ([more] (#director-static-functions-deprecated-director-redirect-and-director-redirectback-in-particular)
|
|
|
|
|
|
|
|
* Use `<MyModel>::get()` rather than `DataObject::get()` ([more](#new-orm-datalist))
|
|
|
|
|
|
|
|
* Use new syntax for `DataObjectDecorator::extraStatics` ([more](#extensions))
|
|
|
|
|
|
|
|
* Change CMS tab paths from `Root.Content.Main` to `Root.Main`, move some field changes to new `SiteTree->getSettingsFields()` method ([more](#tab-paths))
|
|
|
|
|
|
|
|
* Add new modules if using specific core features like Widget, RestfulServer, PageComment or Translatable
|
|
|
|
|
|
|
|
|
|
|
|
### sapphire renamed to framework {#sapphire-rename}
|
|
|
|
### sapphire renamed to framework {#sapphire-rename}
|
|
|
|
|
|
|
|
|
|
|
|
`sapphire` has been renamed to `framework`.
|
|
|
|
The `sapphire` module has been renamed to `framework`. Please ensure the framework now resides in the new folder when upgrading. Here's a list of steps to check:
|
|
|
|
|
|
|
|
|
|
|
|
Please ensure the framework now resides in the new folder when upgrading.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Here's a list of steps to check:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* Remove your existing `sapphire` directory, and replace with `framework` from the new SilverStripe 3.0 package
|
|
|
|
* Remove your existing `sapphire` directory, and replace with `framework` from the new SilverStripe 3.0 package
|
|
|
|
* Rename references of `sapphire` to `framework` in `.htaccess`, `web.config` and `/usr/bin/sake` (the last is only necessary if you use `sake`)
|
|
|
|
* Rename references of `sapphire` to `framework` in `.htaccess`, `web.config` and `/usr/bin/sake` (the last is only necessary if you use `sake`)
|
|
|
|
* Find and replace any references to `sapphire` in your custom code to `framework`. In your PHP code, you can use the constant `FRAMEWORK_DIR`,
|
|
|
|
* Find and replace any references to `sapphire` in your custom code to `framework`. In your PHP code, you can use the constant `FRAMEWORK_DIR`,
|
|
|
|
which points to the framework directory, and in the templates you can use `$ModulePath(framework)`
|
|
|
|
which points to the framework directory, and in the templates you can use `$ModulePath(framework)`
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### GridField: Replacement for TableListField and ComplexTableField [gridfield]###
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
We have a new component for managing lists of objects: The `[GridField](/topics/grid-field)`.
|
|
|
|
|
|
|
|
It's a substantial rewrite of the features previously captured by `TableListField`,
|
|
|
|
|
|
|
|
`ComplexTableField`, `HasManyComplexTableField` and `ManyManyComplexTableField`.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The legacy fields remain operational for now, although a switch to `GridField` is strongly encouraged,
|
|
|
|
|
|
|
|
for stability, interface and performance reasons. The `HasManyComplexTableField` and `ManyManyComplexTableField`
|
|
|
|
|
|
|
|
are no longer maintained, for those you do have to make the switch.
|
|
|
|
|
|
|
|
The `TableField` class will be deprecated soon, but we don't have an adequate replacement for it yet.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Upgrade example: Record listing
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
:::php
|
|
|
|
|
|
|
|
// before
|
|
|
|
|
|
|
|
$field = new TableListField('Companies', 'Company');
|
|
|
|
|
|
|
|
$field->setPageSize(20);
|
|
|
|
|
|
|
|
// after
|
|
|
|
|
|
|
|
$field = new GridField('Companies', null, Company::get());
|
|
|
|
|
|
|
|
$field->getConfig()->getComponentByType('GridFieldPaginator')->setItemsPerPage(20);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Upgrade example: Record listing with view/edit interface
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
:::php
|
|
|
|
|
|
|
|
// before
|
|
|
|
|
|
|
|
$field = new ComplexTableField($myController, 'Companies', 'Company');
|
|
|
|
|
|
|
|
// after
|
|
|
|
|
|
|
|
$field = new GridField('Companies', null, Company::get(), GridFieldConfig_RecordEditor::create());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Upgrade example: Relationship editing
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
:::php
|
|
|
|
|
|
|
|
// before
|
|
|
|
|
|
|
|
$field = new HasManyComplexTableField($myController, 'MyRelation', 'MyRelationObject');
|
|
|
|
|
|
|
|
// after
|
|
|
|
|
|
|
|
$field = new GridField('MyRelation', null, $myRecord->MyRelation(), GridFieldConfig_RelationEditor::create());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
More information is available in the [GridField documentation](/topics/grid-field).
|
|
|
|
|
|
|
|
|
|
|
|
### Object static functions replaced with new Config class {#new-config}
|
|
|
|
### Object static functions replaced with new Config class {#new-config}
|
|
|
|
Static functions for getting a static variable on the `Object` class have been deprecated,
|
|
|
|
Static functions for getting a static variable on the `Object` class have been deprecated,
|
|
|
|
in favour of using the new `Config` class instead.
|
|
|
|
in favour of using the new `Config` class instead.
|
|
|
@ -66,21 +123,17 @@ Note the different options for the third parameter of `get()`:
|
|
|
|
If you don't set an option, it will get all the values for the static, including inherited ones.
|
|
|
|
If you don't set an option, it will get all the values for the static, including inherited ones.
|
|
|
|
This was previously known as `Object::combined_static()`.
|
|
|
|
This was previously known as `Object::combined_static()`.
|
|
|
|
|
|
|
|
|
|
|
|
### Director static functions deprecated, Director::redirect() and Director::redirectBack() in particular
|
|
|
|
### Director static functions deprecated (e.g. redirect() and redirectBack())
|
|
|
|
|
|
|
|
|
|
|
|
`Director::redirect()` and `Director::redirectBack()` are now marked as deprecated.
|
|
|
|
`Director::redirect()` and `Director::redirectBack()` are now marked as deprecated. If you have a `Controller` instance and need to redirect, call `redirect()` or `redirectBack()` on the instance
|
|
|
|
|
|
|
|
instead, e.g. `$controller->redirect()` or `$controller->redirectBack()`. Most of the time, form action handler methods on a controller need only call `$this->redirect()` or `$this->redirectBack()`.
|
|
|
|
|
|
|
|
|
|
|
|
If you have a `Controller` instance and need to redirect, call `redirect()` or `redirectBack()` on the instance
|
|
|
|
Use `Controller::curr()->redirect()` and `Controller::curr()->redirectBack()` if you need to redirect in contexts where a controller might not be immediately available.
|
|
|
|
instead, e.g. `$controller->redirect()` or `$controller->redirectBack()`. Most of the time, form action handler
|
|
|
|
|
|
|
|
methods on a controller need only call `$this->redirect()` or `$this->redirectBack()`.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Use `Controller::curr()->redirect()` and `Controller::curr()->redirectBack()` if you need to redirect in contexts
|
|
|
|
|
|
|
|
where a controller might not be immediately available.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### DataExtension and deprecated extraStatics on extension classes {#extensions}
|
|
|
|
### DataExtension and deprecated extraStatics on extension classes {#extensions}
|
|
|
|
|
|
|
|
|
|
|
|
`DataObjectDecorator` has been renamed to `DataExtension`. Any classes that extend `DataObjectDecorator`
|
|
|
|
`DataObjectDecorator` has been renamed to `DataExtension`. Please extend this class in case you
|
|
|
|
should now extend `DataExtension` instead.
|
|
|
|
have written your own extensions.
|
|
|
|
|
|
|
|
|
|
|
|
`extraStatics()` on extensions is now deprecated.
|
|
|
|
`extraStatics()` on extensions is now deprecated.
|
|
|
|
|
|
|
|
|
|
|
@ -89,41 +142,36 @@ Instead of using `extraStatics()`, you can simply define static variables on you
|
|
|
|
If you need custom logic, e.g. checking for a class before applying the statics on the extension,
|
|
|
|
If you need custom logic, e.g. checking for a class before applying the statics on the extension,
|
|
|
|
you can use `add_to_class()` as a replacement to `extraStatics()`.
|
|
|
|
you can use `add_to_class()` as a replacement to `extraStatics()`.
|
|
|
|
|
|
|
|
|
|
|
|
Given the original `extraStatics` function:
|
|
|
|
:::php
|
|
|
|
|
|
|
|
class MyExtension extends Extension {
|
|
|
|
<?php
|
|
|
|
|
|
|
|
//...
|
|
|
|
// before
|
|
|
|
function extraStatics($class, $extensionClass) {
|
|
|
|
function extraStatics($class, $extensionClass) {
|
|
|
|
if($class == 'MyClass') {
|
|
|
|
if($class == 'MyClass') {
|
|
|
|
return array(
|
|
|
|
return array(
|
|
|
|
'db' => array(
|
|
|
|
'db' => array(
|
|
|
|
'Title' => 'Varchar'
|
|
|
|
'Title' => 'Varchar'
|
|
|
|
|
|
|
|
);
|
|
|
|
);
|
|
|
|
);
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// after
|
|
|
|
|
|
|
|
static $db = array(
|
|
|
|
|
|
|
|
'Title' => 'Varchar'
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// advanced syntax
|
|
|
|
|
|
|
|
static function add_to_class($class, $extensionClass, $args = null) {
|
|
|
|
|
|
|
|
if($class == 'MyClass') {
|
|
|
|
|
|
|
|
Config::inst()->update($class, 'db', array(
|
|
|
|
|
|
|
|
'Title' => 'Varchar'
|
|
|
|
|
|
|
|
));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
parent::add_to_class($class, $extensionClass, $args);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
This would now become a static function `add_to_class`, and calls `update()` with an array
|
|
|
|
|
|
|
|
instead of returning it. It also needs to call `parent::add_to_class()`:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<?php
|
|
|
|
|
|
|
|
//...
|
|
|
|
|
|
|
|
static function add_to_class($class, $extensionClass, $args = null) {
|
|
|
|
|
|
|
|
if($class == 'MyClass') {
|
|
|
|
|
|
|
|
Config::inst()->update($class, 'db', array(
|
|
|
|
|
|
|
|
'Title' => 'Varchar'
|
|
|
|
|
|
|
|
));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
parent::add_to_class($class, $extensionClass, $args);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Alternatively, you can define statics on the extension directly, like this:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<?php
|
|
|
|
|
|
|
|
//...
|
|
|
|
|
|
|
|
static $db = array(
|
|
|
|
|
|
|
|
'Title' => 'Varchar'
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### New ORM: More flexible and expressive querying via `DataList` {#new-orm-datalist}
|
|
|
|
### New ORM: More flexible and expressive querying via `DataList` {#new-orm-datalist}
|
|
|
|
|
|
|
|
|
|
|
@ -166,6 +214,7 @@ for the presence of records, please call the count() method on the `DataList`:
|
|
|
|
// after
|
|
|
|
// after
|
|
|
|
if(!DataObject::get('SiteTree', '"ParentID" = 5')->count()) echo "Page 5 has no children";
|
|
|
|
if(!DataObject::get('SiteTree', '"ParentID" = 5')->count()) echo "Page 5 has no children";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Beware that `DataList->remove()` will delete an entry from the database.
|
|
|
|
See the ["datamodel" documentation](../../topics/datamodel) for more details.
|
|
|
|
See the ["datamodel" documentation](../../topics/datamodel) for more details.
|
|
|
|
|
|
|
|
|
|
|
|
### New ORM: Changes to manipulation of SQL queries {#new-orm-sql-queries}
|
|
|
|
### New ORM: Changes to manipulation of SQL queries {#new-orm-sql-queries}
|
|
|
@ -207,32 +256,10 @@ The abstract `RelationList` class and its implementations `ManyManyList` and `Ha
|
|
|
|
are replacing the `ComponentSet` API, which is only relevant if you have instanciated these manually.
|
|
|
|
are replacing the `ComponentSet` API, which is only relevant if you have instanciated these manually.
|
|
|
|
Relations are retrieved through the same way (e.g. `$myMember->Groups()`).
|
|
|
|
Relations are retrieved through the same way (e.g. `$myMember->Groups()`).
|
|
|
|
|
|
|
|
|
|
|
|
### New ORM: DataObjectSet->groupBy() changed to GroupedList decorator
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
:::php
|
|
|
|
|
|
|
|
$members = Member::get();
|
|
|
|
|
|
|
|
// before
|
|
|
|
|
|
|
|
$grouped = $members->groupBy('Surname');
|
|
|
|
|
|
|
|
// after
|
|
|
|
|
|
|
|
$grouped = GroupedList::create($members)->groupBy('Surname');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Aggregate changes for partial caching in templates ###
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
`DataObject::Aggregate()` and `DataObject::RelationshipAggregate()` are now deprecated. To replace your deprecated aggregate calls
|
|
|
|
|
|
|
|
in PHP code, you should query with something like `Member::get()->max('LastEdited')`, that is, calling the aggregate on the `DataList` directly.
|
|
|
|
|
|
|
|
The same concept applies for replacing `RelationshipAggregate()`, just call the aggregate method on the relationship instead,
|
|
|
|
|
|
|
|
so something like `Member::get()->Groups()->max('LastEdited')`.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
For partial caching in templates, the syntax `<% cached Aggregate(Page).Max(LastEdited) %>` has been deprecated. The new syntax is similar,
|
|
|
|
|
|
|
|
except you use `List()` instead of `Aggregate()`, and the aggregate call `Max()` is now lowercase, as in `max()`.
|
|
|
|
|
|
|
|
An example of the new syntax is `<% cached List(Page).max(LastEdited) %>`. Check `DataList` class for more aggregate methods to use.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### `SQLQuery` changes ###
|
|
|
|
### `SQLQuery` changes ###
|
|
|
|
|
|
|
|
|
|
|
|
`SQLQuery` has been changed so direct access to internal properties `$from`, `$select`, `$orderby` is
|
|
|
|
`SQLQuery` has been changed so direct access to internal properties `$from`, `$select`, `$orderby` is
|
|
|
|
now deprecated.
|
|
|
|
now deprecated. Instead, there are now methods you can call which allow you to get and set SQL clauses instead.
|
|
|
|
|
|
|
|
|
|
|
|
Instead, there are now methods you can call which allow you to get and set SQL clauses instead.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* `$from` getter is `getFrom()` and setters `setFrom()` and `addFrom()`
|
|
|
|
* `$from` getter is `getFrom()` and setters `setFrom()` and `addFrom()`
|
|
|
|
* `$select` getter is `getSelect()` and setters `setSelect()` and `addSelect()`
|
|
|
|
* `$select` getter is `getSelect()` and setters `setSelect()` and `addSelect()`
|
|
|
@ -244,23 +271,19 @@ Instead, there are now methods you can call which allow you to get and set SQL c
|
|
|
|
* `$distinct` getter is `getDistinct()` and setter `setDistinct()`
|
|
|
|
* `$distinct` getter is `getDistinct()` and setter `setDistinct()`
|
|
|
|
* `$delete` getter is `getDelete()` and setter `setDelete()`
|
|
|
|
* `$delete` getter is `getDelete()` and setter `setDelete()`
|
|
|
|
* `$connective` getter is `getConnective()` and settter `setConnective()`
|
|
|
|
* `$connective` getter is `getConnective()` and settter `setConnective()`
|
|
|
|
|
|
|
|
|
|
|
|
* `innerJoin()` has been renamed to `addInnerJoin()`
|
|
|
|
* `innerJoin()` has been renamed to `addInnerJoin()`
|
|
|
|
* `leftJoin()` has been renamed to `addLeftJoin()`
|
|
|
|
* `leftJoin()` has been renamed to `addLeftJoin()`
|
|
|
|
|
|
|
|
|
|
|
|
### TinyMCE upgraded to 3.5 ###
|
|
|
|
### Aggregate changes for partial caching in templates ###
|
|
|
|
|
|
|
|
|
|
|
|
TinyMCE has been upgraded to version 3.5.
|
|
|
|
`DataObject::Aggregate()` and `DataObject::RelationshipAggregate()` are now deprecated. To replace your deprecated aggregate calls
|
|
|
|
|
|
|
|
in PHP code, you should query with something like `Member::get()->max('LastEdited')`, that is, calling the aggregate on the `DataList` directly.
|
|
|
|
|
|
|
|
The same concept applies for replacing `RelationshipAggregate()`, just call the aggregate method on the relationship instead,
|
|
|
|
|
|
|
|
so something like `Member::get()->Groups()->max('LastEdited')`.
|
|
|
|
|
|
|
|
|
|
|
|
This change should be transparent to most people upgrading, but if you're using custom plugins for TinyMCE,
|
|
|
|
For partial caching in templates, the syntax `<% cached Aggregate(Page).Max(LastEdited) %>` has been deprecated. The new syntax is similar,
|
|
|
|
please ensure they are still working correctly with the new version.
|
|
|
|
except you use `List()` instead of `Aggregate()`, and the aggregate call `Max()` is now lowercase, as in `max()`.
|
|
|
|
|
|
|
|
An example of the new syntax is `<% cached List(Page).max(LastEdited) %>`. Check `DataList` class for more aggregate methods to use.
|
|
|
|
If you're upgrading from an SS 3.0 beta, TinyMCE HTML source editor and other popups might be blank.
|
|
|
|
|
|
|
|
This is caused by the TinyMCE compressor leaving stale cache files in the system temp folder from an earlier
|
|
|
|
|
|
|
|
version.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
To resolve this problem, simply delete the `{hash}.gz` files within your temp location (defined by `sys_get_temp_dir()` in PHP.)
|
|
|
|
|
|
|
|
These cache files will be regenerated next time the CMS is opened.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### InnoDB driver for existing and new tables on MySQL (instead of MyISAM) [innodb]###
|
|
|
|
### InnoDB driver for existing and new tables on MySQL (instead of MyISAM) [innodb]###
|
|
|
|
|
|
|
|
|
|
|
@ -282,12 +305,9 @@ Note: MySQL has made InnoDB the default engine in its [5.5 release](http://dev.m
|
|
|
|
|
|
|
|
|
|
|
|
### Convert::json2array() changes [raw2json]###
|
|
|
|
### Convert::json2array() changes [raw2json]###
|
|
|
|
|
|
|
|
|
|
|
|
Convert JSON functions have been changed to use built-in json PHP functions `json_decode()` and `json_encode()`
|
|
|
|
Convert JSON functions have been changed to use built-in json PHP functions `json_decode()` and `json_encode()`.
|
|
|
|
|
|
|
|
|
|
|
|
Because `json_decode()` will convert nested JSON structures to arrays as well, this has changed the way it worked,
|
|
|
|
Because `json_decode()` will convert nested JSON structures to arrays as well, this has changed the way it worked,
|
|
|
|
as before nested structures would be converted to an object instead.
|
|
|
|
as before nested structures would be converted to an object instead. So, given the following JSON input to `Convert::json2array()`:
|
|
|
|
|
|
|
|
|
|
|
|
So, given the following JSON input to `Convert::json2array()`:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{"Joe":"Bloggs","Tom":"Jones","My":{"Complicated":"Structure"}}
|
|
|
|
{"Joe":"Bloggs","Tom":"Jones","My":{"Complicated":"Structure"}}
|
|
|
|
|
|
|
|
|
|
|
@ -311,47 +331,6 @@ Now in SilverStripe 3.x, nested structures are arrays:
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### GridField: Replacement for TableListField and ComplexTableField [gridfield]###
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
We have a new component for managing lists of objects: The `[GridField](/topics/grid-field)`.
|
|
|
|
|
|
|
|
It's a substantial rewrite of the features previously captured by `TableListField`,
|
|
|
|
|
|
|
|
`ComplexTableField`, `HasManyComplexTableField` and `ManyManyComplexTableField`.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The legacy fields remain operational for now, although a switch to `GridField` is strongly encouraged,
|
|
|
|
|
|
|
|
for stability, interface and performance reasons. The `HasManyComplexTableField` and `ManyManyComplexTableField`
|
|
|
|
|
|
|
|
are no longer maintained, for those you do have to make the switch.
|
|
|
|
|
|
|
|
The `TableField` class will be deprecated soon, but we don't have an adequate replacement for it yet.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Upgrade example: Record listing
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
:::php
|
|
|
|
|
|
|
|
// before
|
|
|
|
|
|
|
|
$field = new TableListField('Companies', 'Company');
|
|
|
|
|
|
|
|
$field->setPageSize(20);
|
|
|
|
|
|
|
|
// after
|
|
|
|
|
|
|
|
$field = new GridField('Companies', null, Company::get());
|
|
|
|
|
|
|
|
$field->getConfig()->getComponentByType('GridFieldPaginator')->setItemsPerPage(20);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Upgrade example: Record listing with view/edit interface
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
:::php
|
|
|
|
|
|
|
|
// before
|
|
|
|
|
|
|
|
$field = new ComplexTableField($myController, 'Companies', 'Company');
|
|
|
|
|
|
|
|
// after
|
|
|
|
|
|
|
|
$field = new GridField('Companies', null, Company::get(), GridFieldConfig_RecordEditor::create());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Upgrade example: Relationship editing
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
:::php
|
|
|
|
|
|
|
|
// before
|
|
|
|
|
|
|
|
$field = new HasManyComplexTableField($myController, 'MyRelation', 'MyRelationObject');
|
|
|
|
|
|
|
|
// after
|
|
|
|
|
|
|
|
$field = new GridField('MyRelation', null, $myRecord->MyRelation(), GridFieldConfig_RelationEditor::create());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
More information is available in the [GridField documentation](/topics/grid-field).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### New template engine [templates]###
|
|
|
|
### New template engine [templates]###
|
|
|
|
|
|
|
|
|
|
|
|
The template engine has been completely rewritten, and although it is generally backward compatible, there are new features
|
|
|
|
The template engine has been completely rewritten, and although it is generally backward compatible, there are new features
|
|
|
@ -385,6 +364,18 @@ The page tree moved from a bespoke tree library to [JSTree](http://jstree.com),
|
|
|
|
which required changes to markup of the tree and its JavaScript architecture.
|
|
|
|
which required changes to markup of the tree and its JavaScript architecture.
|
|
|
|
This includes changes to `TreeDropdownField` and `TreeMultiSelectField`.
|
|
|
|
This includes changes to `TreeDropdownField` and `TreeMultiSelectField`.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### TinyMCE upgraded to 3.5 ###
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TinyMCE has been upgraded to version 3.5.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
This change should be transparent to most people upgrading, but if you're using custom plugins for TinyMCE,
|
|
|
|
|
|
|
|
please ensure they are still working correctly with the new version.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
If you're upgrading from an SS 3.0 beta, TinyMCE HTML source editor and other popups might be blank.
|
|
|
|
|
|
|
|
This is caused by the TinyMCE compressor leaving stale cache files in the system temp folder from an earlier
|
|
|
|
|
|
|
|
version. To resolve this problem, simply delete the `{hash}.gz` files within your temp location (defined by `sys_get_temp_dir()` in PHP.)
|
|
|
|
|
|
|
|
These cache files will be regenerated next time the CMS is opened.
|
|
|
|
|
|
|
|
|
|
|
|
### Settings-related fields move from SiteTree->getCMSFields() to new SiteTree->getSettingsFields() [getcmsfields]###
|
|
|
|
### Settings-related fields move from SiteTree->getCMSFields() to new SiteTree->getSettingsFields() [getcmsfields]###
|
|
|
|
|
|
|
|
|
|
|
|
The fields and tabs are now split into two separate forms, which required a structural
|
|
|
|
The fields and tabs are now split into two separate forms, which required a structural
|
|
|
@ -503,10 +494,9 @@ Please use the appropriate setters on the form field instance instead.
|
|
|
|
### EmailField now uses type "email" instead of type "text" {#email-form-field}
|
|
|
|
### EmailField now uses type "email" instead of type "text" {#email-form-field}
|
|
|
|
|
|
|
|
|
|
|
|
EmailField now uses "email" for the `type` attribute, which integrates better with HTML5 features like
|
|
|
|
EmailField now uses "email" for the `type` attribute, which integrates better with HTML5 features like
|
|
|
|
form validation in the browser.
|
|
|
|
form validation in the browser. If you want to change this back to "text", use `setAttribute()` when constructing the field:
|
|
|
|
|
|
|
|
|
|
|
|
If you want to change this back to "text", use `setAttribute()` when constructing the field:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
:::php
|
|
|
|
$field = new EmailField('Email');
|
|
|
|
$field = new EmailField('Email');
|
|
|
|
$field->setAttribute('type', 'text');
|
|
|
|
$field->setAttribute('type', 'text');
|
|
|
|
|
|
|
|
|
|
|
@ -514,7 +504,6 @@ If you want to change this back to "text", use `setAttribute()` when constructin
|
|
|
|
|
|
|
|
|
|
|
|
In order to make the SilverStripe framework useable without the `cms` module,
|
|
|
|
In order to make the SilverStripe framework useable without the `cms` module,
|
|
|
|
we've moved some files around.
|
|
|
|
we've moved some files around.
|
|
|
|
|
|
|
|
|
|
|
|
CMS base functionality which is not directly related to content pages (`SiteTree`)
|
|
|
|
CMS base functionality which is not directly related to content pages (`SiteTree`)
|
|
|
|
has been moved from the `cms` module into a new "sub-module" located in `framework/admin`.
|
|
|
|
has been moved from the `cms` module into a new "sub-module" located in `framework/admin`.
|
|
|
|
This includes generic management interfaces like "Files & Images" (`AssetAdmin`),
|
|
|
|
This includes generic management interfaces like "Files & Images" (`AssetAdmin`),
|
|
|
|