Cleanup 3.2 changelog for release

This commit is contained in:
Damian Mooyman 2015-06-11 16:12:59 +12:00
parent 78a3f703f2
commit 4d37e21bc6
4 changed files with 533 additions and 404 deletions

View File

@ -37,7 +37,7 @@ explicitly logging in or by invoking the "remember me" functionality.
DB::query(sprintf(
'UPDATE "Member" SET "LastVisited" = %s, "NumVisit" = "NumVisit" + 1 WHERE "ID" = %d',
DB::getConn()->now(),
DB::get_conn()->now(),
$this->owner->ID
));
}

View File

@ -27,7 +27,7 @@ come from user input.
Example:
:::php
$records = DB::preparedQuery('SELECT * FROM "MyClass" WHERE "ID" = ?', array(3));
$records = DB::prepared_query('SELECT * FROM "MyClass" WHERE "ID" = ?', array(3));
$records = MyClass::get()->where(array('"ID" = ?' => 3));
$records = MyClass::get()->where(array('"ID"' => 3));
$records = DataObject::get_by_id('MyClass', 3);
@ -48,7 +48,7 @@ Parameterised updates and inserts are also supported, but the syntax is a little
))
->assignSQL('"Created"', 'NOW()')
->execute();
DB::preparedQuery(
DB::prepared_query(
'INSERT INTO "MyClass" ("Name", "Position", "Age", "Created") VALUES(?, ?, GREATEST(0,?,?), NOW())'
array('Daniel', 'Accountant', 24, 28)
);
@ -100,7 +100,7 @@ and [datamodel](/developer_guides/model) for ways to parameterise, cast, and con
* `SQLQuery`
* `DB::query()`
* `DB::preparedQuery()`
* `DB::prepared_query()`
* `Director::urlParams()`
* `Controller->requestParams`, `Controller->urlParams`
* `SS_HTTPRequest` data

View File

@ -1,60 +1,200 @@
# 3.2.0 (unreleased)
# 3.2.0
## Overview
## Contents
### Framework
* [Major Changes](#major-changes)
* [Removed API](#deprecated-classesmethods-removed)
* [New API](#new-and-changed-api)
* [Bugfixes](#bugfixes)
* [Upgrading Notes](#upgrading-notes)
* Minimum PHP version raised to 5.3.3
* `DataObject::validate()` method visibility changed to public
* `NumericField` now uses HTML5 "number" type instead of "text"
* `UploadField` "Select from files" shows files in all folders by default
* `UploadField` won't display an overwrite warning unless `Upload::replaceFile` is true
* `HtmlEditorField` no longer substitutes `<blockquote />` for indented text
* `ClassInfo::dataClassesFor` now returns classes which should have tables, regardless of whether those
tables actually exist.
* `SS_Filterable`, `SS_Limitable` and `SS_Sortable` now explicitly extend `SS_List`
* `Convert::html2raw` no longer wraps text by default and can decode single quotes.
* `Mailer` no longer calls `xml2raw` on all email subject line, and now must be passed in via plain text.
* `ErrorControlChain` now supports reload on exceptions
* `FormField::validate` now requires an instance of `Validator`
* Implementation of new "Archive" concept for page removal, which supercedes "delete". Where deletion removed
pages only from draft, archiving removes from both draft and live simultaneously.
* Support for multiple HtmlEditorConfigs on the same page.
* Most of the `Image` manipulation methods have been renamed
* New `Image` methods `CropWidth` and `CropHeight` added
* 'Max' versions of `Image` methods introduced to prevent up-sampling
## Major changes
#### Deprecated classes/methods removed
* Minimum PHP version raised to 5.3.3
* Introduction of new parameterised ORM
* Default support for PDO
* Moved SS_Report and ReportAdmin out to a separate module. If you're using
composer or downloading a release, this module should be included for you.
Otherwise, you'll need to include the module yourself
(https://github.com/silverstripe-labs/silverstripe-reports)
* Moved SiteConfig also out to its own module. This will be included by
default if you include the CMS module.
(https://github.com/silverstripe/silverstripe-siteconfig)
* Implementation of new "Archive" concept for page removal, which supercedes
"delete from draft". Where deletion removed pages only from draft, archiving
removes from both draft and live simultaneously.
* Most of the `Image` manipulation methods have been renamed
* `ToggleField` was deprecated in 3.1, and has been removed. Use custom Javascript with `ReadonlyField` instead.
* `ExactMatchMultiFilter` was deprecated in 3.1, and has been removed. Use `ExactMatchFilter` instead.
* `NegationFilter` was deprecated in 3.1, and has been removed. Use `ExactMatchFilter:not` instead.
* `StartsWithMultiFilter` was deprecated in 3.1, and has been removed. Use `StartsWithFilter` instead.
* `ScheduledTask` and subclasses like `DailyTask` were deprecated in 3.1, and have been removed.
## Deprecated classes/methods removed
* `ToggleField` was deprecated in 3.1, and has been removed. Use custom Javascript with `ReadonlyField` instead.
* `ExactMatchMultiFilter` was deprecated in 3.1, and has been removed. Use `ExactMatchFilter` instead.
* `NegationFilter` was deprecated in 3.1, and has been removed. Use `ExactMatchFilter:not` instead.
* `StartsWithMultiFilter` was deprecated in 3.1, and has been removed. Use `StartsWithFilter` instead.
* `ScheduledTask` and subclasses like `DailyTask` were deprecated in 3.1, and have been removed.
Use custom code instead, or a module like silverstripe-crontask: https://github.com/silverstripe-labs/silverstripe-crontask
* `Cookie::forceExpiry()` was removed. Use `Cookie::force_expiry()` instead
* `Object` statics removal: `get_static()`, `set_static()`, `uninherited_static()`, `combined_static()`,
* `Cookie::forceExpiry()` was removed. Use `Cookie::force_expiry()` instead
* `Object` statics removal: `get_static()`, `set_static()`, `uninherited_static()`, `combined_static()`,
`addStaticVars()` and `add_static_var()` removed. Use the Config methods instead.
* `GD` methods removed: `setGD()`, `getGD()`, `hasGD()`. Use `setImageResource()`, `getImageResource()`, and `hasImageResource()` instead
* `DataExtension::get_extra_config()` removed, no longer supports `extraStatics` or `extraDBFields`. Define your
* `GD` methods removed: `setGD()`, `getGD()`, `hasGD()`. Use `setImageResource()`, `getImageResource()`, and `hasImageResource()` instead
* `DataExtension::get_extra_config()` removed, no longer supports `extraStatics` or `extraDBFields`. Define your
statics on the class directly.
* `DataList::getRange()` removed. Use `limit()` instead.
* `SQLMap` removed. Call `map()` on a `DataList` or use `SS_Map` directly instead.
* `Profiler` removed. Use xhprof or xdebug for profiling instead.
* `Aggregate` removed. Call aggregate methods on a `DataList` instead e.g. `Member::get()->max('LastEdited')`
* `MySQLDatabase::set_connection_charset()` removed. Use `MySQLDatabase.connection_charset` config setting instead
* `SQLConditionalExpression/SQLQuery` `select()`, `limit()`, `orderby()`, `groupby()`, `having()`, `from()`, `leftjoin()`, `innerjoin()`, `where()` and `whereAny()` removed.
* `DataList::getRange()` removed. Use `limit()` instead.
* `SQLMap` removed. Call `map()` on a `DataList` or use `SS_Map` directly instead.
* `Profiler` removed. Use xhprof or xdebug for profiling instead.
* `Aggregate` removed. Call aggregate methods on a `DataList` instead e.g. `Member::get()->max('LastEdited')`
* `MySQLDatabase::set_connection_charset()` removed. Use `MySQLDatabase.connection_charset` config setting instead
* `SQLConditionalExpression/SQLQuery` `select()`, `limit()`, `orderby()`, `groupby()`, `having()`, `from()`, `leftjoin()`, `innerjoin()`, `where()` and `whereAny()` removed.
Use `set*()` and `add*()` methods instead.
* Template `<% control $MyList %>` syntax removed. Use `<% loop $MyList %>` instead.
* Object::singleton() method for better type-friendly singleton generation
* Template `<% control $MyList %>` syntax removed. Use `<% loop $MyList %>` instead.
* Removed `Member.LastVisited` and `Member.NumVisits` properties, see
[Howto: Track Member Logins](/extending/how_tos/track_member_logins) to restore functionality as custom code
### CMS
## New and changed API
* `SearchForm::getSearchQuery` no longer pre-escapes search keywords and must be cast in your template
* Implementation of a parameterised query framework eliminating the need to manually escape variables for
use in SQL queries. This has been integrated into nearly every level of the database ORM.
* Refactor of database connectivity classes into separate components linked together through dependency injection
* Refactor of `SQLQuery` into separate objects for each query type: `SQLQuery`, `SQLDelete`, `SQLUpdate` and `SQLInsert`
* PDO is now a standard connector, and is available for all database interfaces
* `DataObject::validate()` method visibility changed to public
* `NumericField` now uses HTML5 "number" type instead of "text"
* `UploadField` "Select from files" shows files in all folders by default
* `UploadField` won't display an overwrite warning unless `Upload::replaceFile` is true
* `HtmlEditorField` no longer substitutes `<blockquote />` for indented text
* `ClassInfo::dataClassesFor` now returns classes which should have tables, regardless of whether those
tables actually exist.
* `SS_Filterable`, `SS_Limitable` and `SS_Sortable` now explicitly extend `SS_List`
* `Convert::html2raw` no longer wraps text by default and can decode single quotes.
* `Mailer` no longer calls `xml2raw` on all email subject line, and now must be passed in via plain text.
* `ErrorControlChain` now supports reload on exceptions
* `FormField::validate` now requires an instance of `Validator`
* API: Removed URL routing by controller name
* Security: The multiple authenticator login page should now be styled manually - i.e. without the default jQuery
UI layout. A new template, Security_MultiAuthenticatorLogin.ss is available.
* Security: This controller's templates can be customised by overriding the `getTemplatesFor` function.
* API: Form and FormField ID attributes rewritten.
* `SearchForm::getSearchQuery` no longer pre-escapes search keywords and must
be cast in your template
* Helper function `DB::placeholders` can be used to generate a comma separated list of placeholders
useful for creating "WHERE ... IN (?,...)" SQL fragments
* Implemented Convert::symbol2sql to safely encode database and table names and identifiers.
E.g. `Convert::symbol2sql('table.column') => '"table"."column"';`
* `Convert::raw2sql` may now quote the escaped value, as well as safely escape it, according to the current
database adaptor's preference.
* `DB` class has been updated and many static methods have been renamed to conform to coding convention.
* Renamed API:
* `affectedRows` -> `affected_rows`
* `checkAndRepairTable` -> `check_and_repair_table`
* `createDatabase` -> `create_database`
* `createField` -> `create_field`
* `createTable` -> `create_table`
* `dontRequireField` -> `dont_require_field`
* `dontRequireTable` -> `dont_require_table`
* `fieldList` -> `field_list`
* `getConn` -> `get_conn`
* `getGeneratedID` -> `get_generated_id`
* `isActive` -> `is_active`
* `requireField` -> `require_field`
* `requireIndex` -> `require_index`
* `requireTable` -> `require_table`
* `setConn` -> `set_conn`
* `tableList` -> `table_list`
* Deprecated API:
* `getConnect` (Was placeholder for PDO connection string building code, but is made
redundant after the PDOConnector being fully abstracted)
* New API:
* `build_sql` - Hook into new SQL generation code
* `get_connector` (Nothing to do with getConnect)
* `get_schema`
* `placeholders`
* `prepared_query`
* `SS_Database` class has been updated and many functions have been deprecated, or refactored into
the various other database classes. Most of the database management classes remain in the database
controller, due to individual databases (changing, creating of, etc) varying quite a lot from
API to API, but schema updates within a database itself is managed by an attached DBSchemaManager
* Refactored into DBSchemaManager:
* `createTable`
* `alterTable`
* `renameTable`
* `createField`
* `renameField`
* `fieldList`
* `tableList`
* `hasTable`
* `enumValuesForField`
* `beginSchemaUpdate` and `endSchemaUpdate` -> Use `schemaUpdate` with a callback
* `cancelSchemaUpdate`
* `isSchemaUpdating`
* `doesSchemaNeedUpdating`
* `transCreateTable`
* `transAlterTable`
* `transCreateField`
* `transCreateField`
* `transCreateIndex`
* `transAlterField`
* `transAlterIndex`
* `requireTable`
* `dontRequireTable`
* `requireIndex`
* `hasField`
* `requireField`
* `dontRequireField`
* Refactored into DBQueryBuilder
* `sqlQueryToString`
* Deprecated:
* `getConnect` - Was intended for use with PDO, but was never implemented, and is now
redundant, now that there is a stand-alone `PDOConnector`
* `prepStringForDB` - Use `quoteString` instead
* `dropDatabase` - Use `dropSelectedDatabase`
* `createDatabase` - Use `selectDatabase` with the second parameter set to true instead
* `allDatabaseNames` - Use `databaseList` instead
* `currentDatabase` - Use `getSelectedDatabase` instead
* `addslashes` - Use `escapeString` instead
* `LogErrorEmailFormatter` now better displays SQL queries in errors by respecting line breaks
* Installer has been majorly upgraded to handle the new database configuration options
and additional PDO functionality.
* Created `SS_DatabaseException` to emit database errors. Query information such as SQL
and any relevant parameters may be used by error handling user code that catches
this exception.
* The `SQLConditionGroup` interface has been created to represent dynamically
evaluated SQL conditions. This may be used to wrap a class that generates
a custom SQL clause(s) to be evaluated at the time of execution.
* `DataObject` constants CHANGE_NONE, CHANGE_STRICT, and CHANGE_VALUE have been created
to provide more verbosity to field modification detection. This replaces the use of
various magic numbers with the same meaning.
* create_table_options now uses constants as API specific filters rather than strings.
This is in order to promote better referencing of elements across the codebase.
See `FulltextSearchable->enable` for example.
* `$FromEnd` iterator variable now available in templates.
* Support for multiple HtmlEditorConfigs on the same page.
* Object::singleton() method for better type-friendly singleton generation
* New `Image` methods `CropWidth` and `CropHeight` added
* 'Max' versions of `Image` methods introduced to prevent up-sampling
* Update Image method names in PHP code and templates
* `SetRatioSize` -> `Fit`
* `CroppedImage` -> `Fill`
* `PaddedImage` -> `Pad`
* `SetSize` -> `Pad`
* `SetWidth` -> `ScaleWidth`
* `SetHeight` -> `ScaleHeight`
## Changelog
## Bugfixes
### CMS
* Reduced database regeneration chances on subsequent rebuilds after the initial dev/build
* Elimination of various SQL injection vulnerability points
* `DataObject::writeComponents()` now called correctly during `DataObject::write()`
* Fixed missing theme declaration in installer
* Fixed incorrect use of non-existing exception classes (e.g. `HTTPResponse_exception`)
* `GridState` fixed to distinguish between check for missing values, and creation of
nested state values, in order to prevent non-empty values being returned for
missing keys. This was breaking `DataObject::get_by_id` by passing in an object
for the ID.
* Fixed order of `File` fulltext searchable fields to use same order as actual fields.
This is required to prevent unnecessary rebuild of MS SQL databases when fulltext
searching is enabled.
## Upgrading Notes
### DataObject::validate() method visibility changed to public
@ -63,6 +203,7 @@ The visibility of `DataObject::validate()` has been changed from `protected` to
Any existing classes that currently set this as `protected` should be changed like in
this example:
::php
class MyDataClass extends DataObject {
...
@ -72,13 +213,17 @@ this example:
...
}
### UploadField "Select from files" shows files in all folders by default
In order to list files in a single folder by default (previous default behaviour),
use `setDisplayFolderName()` with a folder path relative to `assets/`:
:::php
UploadField::create('MyField')->setDisplayFolderName('Uploads');
### UploadField won't display an overwrite warning unless Upload:replaceFile is true
The configuration setting `UploadField:overwriteWarning` is dependent on `Upload:replaceFile`
@ -88,6 +233,7 @@ To display a warning before overwriting a file:
Via config:
::yaml
Upload:
# Replace an existing file rather than renaming the new one.
@ -96,12 +242,15 @@ Via config:
# Warning before overwriting existing file (only relevant when Upload: replaceFile is true)
overwriteWarning: true
Or per instance:
::php
$uploadField->getUpload()->setReplaceFile(true);
$uploadField->setOverwriteWarning(true);
### File.allowed_extensions restrictions
Certain file types such as swf, html, htm, xhtml and xml have been removed from the list
@ -130,35 +279,160 @@ languages like JavaScript won't be able to read them.
To set it back to be non-HTTP only, you need to set the `$httpOnly` argument to false when calling
`Cookie::set()`.
### Bugfixes
* Migration of code to use new parameterised framework
### API: Removed URL routing by controller name
### Framework
The auto-routing of controller class names to URL endpoints
has been removed (rule: `'$Controller//$Action/$ID/$OtherID': '*'`).
This increases clarity in routing since it makes URL entpoints explicit,
and thereby simplifies system and security reviews.
* Implementation of a parameterised query framework eliminating the need to manually escape variables for
use in SQL queries. This has been integrated into nearly every level of the database ORM.
* Refactor of database connectivity classes into separate components linked together through dependency injection
* Refactor of `SQLQuery` into separate objects for each query type: `SQLQuery`, `SQLDelete`, `SQLUpdate` and `SQLInsert`
* Rename of API methods to conform to coding conventions
* PDO is now a standard connector, and is available for all database interfaces
* Additional database and query generation tools
Please access any custom controllers exclusively through self-defined
[routes](/reference/director). For controllers extending `Page_Controller`,
simply use the provided page URLs.
## Bugfixes
* Reduced database regeneration chances on subsequent rebuilds after the initial dev/build
* Elimination of various SQL injection vulnerability points
* `DataObject::writeComponents()` now called correctly during `DataObject::write()`
* Fixed missing theme declaration in installer
* Fixed incorrect use of non-existing exception classes (e.g. `HTTPResponse_exception`)
* `GridState` fixed to distinguish between check for missing values, and creation of
nested state values, in order to prevent non-empty values being returned for
missing keys. This was breaking `DataObject::get_by_id` by passing in an object
for the ID.
* Fixed order of `File` fulltext searchable fields to use same order as actual fields.
This is required to prevent unnecessary rebuild of MS SQL databases when fulltext
searching is enabled.
:::php
class MyController extends Controller {
static $allowed_actions = array('myaction');
public function myaction($request) {
// ...
}
}
Create a new file `mysite/_config/routes.yml`
(read more about the [config format](/topics/configuration)).
Your controller is now available on `http://yourdomain.com/my-controller-endpoint`,
after refreshing the configuration cache through `?flush=all`.
:::yaml
---
Name: my-routes
After: framework/routes#coreroutes
---
Director:
rules:
'my-controller-endpoint//$Action' : 'MyController'
The auto-routing is still in place for unit tests,
since its a frequently used feature there. Although we advise against it,
you can reinstate the old behaviour through a director rule:
:::yaml
---
Name: my-routes
After: framework/routes#coreroutes
---
Director:
rules:
'$Controller//$Action/$ID/$OtherID': '*'
### API: Default Form and FormField ID attributes rewritten.
Previously the automatic generation of ID attributes throughout the Form API
could generate invalid ID values such as Password[ConfirmedPassword] as well
as duplicate ID values between forms on the same page. For example, if you
created a field called `Email` on more than one form on the page, the resulting
HTML would have multiple instances of `#Email`. ID should be a unique
identifier for a single element within the document.
This rewrite has several angles, each of which is described below. If you rely
on ID values in your CSS files, Javascript code or application unit tests *you
will need to update your code*.
#### Conversion of invalid form ID values
ID attributes on Form and Form Fields will now follow the
[HTML specification](http://www.w3.org/TR/REC-html40/types.html#type-cdata).
Generating ID attributes is now handled by the new `FormTemplateHelper` class.
Please test each of your existing site forms to ensure that they work
correctly in particular, javascript and css styles which rely on specific ID
values.
#### Invalid ID attributes stripped
ID attributes will now be run through `Convert::raw2htmlid`. Invalid characters
are replaced with a single underscore character. Duplicate, leading and trailing
underscores are removed. Custom ID attributes (set through `setHTMLID`) will not
be altered.
Before:
:::html
<form id="MyForm[Form]"
<div id="MyForm[Form][ID]">
Now:
:::html
<form id="MyForm_Form">
<div id="MyForm_Form_ID">
#### Namespaced FormField ID's
Form Field ID values will now be namespaced with the parent form ID.
Before:
:::html
<div id="Email">
Now:
:::html
<div id="MyForm_Email">
#### FormField wrapper containers suffixed with `_Holder`
Previously both the container div and FormField tag shared the same ID in
certain cases. Now, the wrapper div in the default `FormField` template will be
suffixed with `_Holder`.
Before:
:::html
<div id="Email">
<input id="Email" />
After:
:::html
<div id="MyForm_Email_Holder"
<input id="MyForm_Email" />
#### Reverting to the old specification
If upgrading existing forms is not feasible, developers can opt out of the new
specifications by using the `FormTemplateHelper_Pre32` class rules instead of
the default ones.
`mysite/config/_config.yml`:
:::yaml
Injector:
FormTemplateHelper:
class: FormTemplateHelper_Pre32
## Upgrading
### Update code that uses SQLQuery
@ -177,6 +451,7 @@ although now a new SQLDelete object should be created from the original SQLQuery
Before:
:::php
<?php
$query = new SQLQuery('*');
@ -185,8 +460,10 @@ Before:
$query->setDelete(true);
$query->execute();
After:
:::php
<?php
$query = SQLDelete::create()
@ -194,8 +471,10 @@ After:
->setWhere(array('"SiteTree"."ShowInMenus"' => 0));
$query->execute();
Alternatively:
:::php
<?php
$query = SQLQuery::create()
@ -204,6 +483,7 @@ Alternatively:
->toDelete();
$query->execute();
### Update code that interacts with SQL strings to use parameters
The Silverstripe ORM (object relation model) has moved from using escaped SQL strings
@ -225,121 +505,214 @@ As a result of this upgrade there are now very few cases where `Convert::raw2sql
Examples of areas where queries should be upgraded are below:
1. #### Querying the database directly through DB, including non-SELECT queries
#### 1. Querying the database directly through DB, including non-SELECT queries
Before:
Before:
:::php
<?php
// Note: No deprecation notices will be caused here
DB::query("UPDATE \"SiteTree\" SET \"Title\" LIKE '%" . Convert::raw2sql($myTitle) . "%' WHERE \"ID\" = 1");
$myPages = DB::query(sprintf('SELECT "ID" FROM "MyObject" WHERE "Title" = \'%s\'', Convert::raw2sql($parentTitle)));
:::php
<?php
After:
// Note: No deprecation notices will be caused here
DB::query("UPDATE \"SiteTree\" SET \"Title\" LIKE '%" . Convert::raw2sql($myTitle) . "%' WHERE \"ID\" = 1");
$myPages = DB::query(sprintf('SELECT "ID" FROM "MyObject" WHERE "Title" = \'%s\'', Convert::raw2sql($parentTitle)));
:::php
<?php
DB::prepared_query(
'UPDATE "SiteTree" SET "Title" LIKE ? WHERE "ID" = ?',
array("%{$myTitle}%", 1)
);
$myPages = DB::prepared_query(
'SELECT "ID" FROM "MyObject" WHERE "Title" = ?',
array($parentTitle)
);
After:
2. #### Querying the database through `DataList`, `DataQuery`, `SQLQuery`, and `DataObject`
Before:
:::php
<?php
:::php
<?php
DB::prepared_query(
'UPDATE "SiteTree" SET "Title" LIKE ? WHERE "ID" = ?',
array("%{$myTitle}%", 1)
);
$myPages = DB::prepared_query(
'SELECT "ID" FROM "MyObject" WHERE "Title" = ?',
array($parentTitle)
);
$items = DataObject::get_one('MyObject', '"Details" = \''.Convert::raw2sql($details).'\'');
$things = MyObject::get()->where('"Name" = \''.Convert::raw2sql($name).'\'');
$list = DataList::create('Banner')->where(array(
'"ParentID" IS NOT NULL',
'"Title" = \'' . Convert::raw2sql($title) . '\''
);
After:
#### 2. Querying the database through `DataList`, `DataQuery`, `SQLQuery`, and `DataObject`
:::php
<?php
Before:
$items = DataObject::get_one('MyObject', array('"MyObject"."Details"' => $details));
$things = MyObject::get()->where(array('"MyObject"."Name" = ?' => $name));
$list = DataList::create('Banner')->where(array(
'"ParentID" IS NOT NULL',
'"Title" = ?', $title
);
3. #### Interaction with `DataList::sql()`, `DataQuery::sql()`, `SQLQuery::sql()`, or `SQLQuery::getJoins()` methods
:::php
<?php
The place where legacy code would almost certainly fail is any code that calls
DataList::sql`, `DataQuery::sql`, `SQLQuery::sql` or `SQLQuery::getJoins()`, as the api requires that user
code passes in an argument here to retrieve SQL parameters by value.
$items = DataObject::get_one('MyObject', '"Details" = \''.Convert::raw2sql($details).'\'');
$things = MyObject::get()->where('"Name" = \''.Convert::raw2sql($name).'\'');
$list = DataList::create('Banner')->where(array(
'"ParentID" IS NOT NULL',
'"Title" = \'' . Convert::raw2sql($title) . '\''
);
User code that assumes parameterless queries will likely fail, and need to be
updated to handle this case properly.
Before:
After:
:::php
<?php
// Generate query
$argument = 'whatever';
$query = SQLQuery::create()
->setFrom('"SiteTree"')
->setWhere(array("\"SiteTree\".\"Title\" LIKE '" . Convert::raw2sql($argument) . "'"));
:::php
<?php
// Inspect elements of the query
$sql = $query->sql();
$sql = preg_replace('/LIKE \'(.+)\'/', 'LIKE \'%${1}%\'', $sql); // Adds %% around the argument
$items = DataObject::get_one('MyObject', array('"MyObject"."Details"' => $details));
$things = MyObject::get()->where(array('"MyObject"."Name" = ?' => $name));
$list = DataList::create('Banner')->where(array(
'"ParentID" IS NOT NULL',
'"Title" = ?', $title
);
// Pass new query to database connector
DB::query($sql);
After:
#### 3. Interaction with `DataList::sql()`, `DataQuery::sql()`, `SQLQuery::sql()`, or `SQLQuery::getJoins()` methods
:::php
<?php
The place where legacy code would almost certainly fail is any code that calls
DataList::sql`, `DataQuery::sql`, `SQLQuery::sql` or `SQLQuery::getJoins()`, as the api requires that user
code passes in an argument here to retrieve SQL parameters by value.
// Generate query
$argument = 'whatever';
$query = SQLQuery::create()
->setFrom('"SiteTree"')
->setWhere(array('"SiteTree"."Title" LIKE ?' => $argument));
User code that assumes parameterless queries will likely fail, and need to be
updated to handle this case properly.
// Inspect elements of the query
$sql = $query->sql($parameters);
foreach($parameters as $key => $value) {
// Adds %% around arguments
$parameters[$key] = "%{$value}%";
Before:
:::php
<?php
// Generate query
$argument = 'whatever';
$query = SQLQuery::create()
->setFrom('"SiteTree"')
->setWhere(array("\"SiteTree\".\"Title\" LIKE '" . Convert::raw2sql($argument) . "'"));
// Inspect elements of the query
$sql = $query->sql();
$sql = preg_replace('/LIKE \'(.+)\'/', 'LIKE \'%${1}%\'', $sql); // Adds %% around the argument
// Pass new query to database connector
DB::query($sql);
After:
:::php
<?php
// Generate query
$argument = 'whatever';
$query = SQLQuery::create()
->setFrom('"SiteTree"')
->setWhere(array('"SiteTree"."Title" LIKE ?' => $argument));
// Inspect elements of the query
$sql = $query->sql($parameters);
foreach($parameters as $key => $value) {
// Adds %% around arguments
$parameters[$key] = "%{$value}%";
}
// Pass new query to database connector
// Note that DB::query($sql) would fail, as it would contain ? with missing parameters
DB::prepared_query($sql, $parameters);
Also note that the parameters may not be a single level array, as certain values
may be forced to be cast as a certain type (where supported by the current API).
E.g.
:::php
<?php
$parameters = array(
10,
array('value' => 0, 'type' => 'boolean') // May also contain other database API specific options
)
DB::prepared_query('DELETE FROM "MyObject" WHERE ParentID = ? OR IsValid = ?', $parameters);
#### 4. Interaction with `SQLQuery::getWhere()` method
As all where conditions are now parameterised, the format of the results returned by `SQLQuery::getWhere()`
will not always equate with that in FrameWork 3.1. Once this would be a list of strings, what will
now be returned is a list of conditions, each of which is an associative array mapping the
condition string to a list of parameters provided.
Before:
:::php
<?php
// Increment value of a single condition
$conditions = $query->getWhere();
$new = array();
foreach($conditions as $condition) {
if(preg_match('/\"Count\" = (?<count>\d+)/', $condition, $matches)) {
$condition = '"Count" = '.($matches['count'] + 1);
}
$new[] = $condition;
}
$query->setWhere($new);
// Pass new query to database connector
// Note that DB::query($sql) would fail, as it would contain ? with missing parameters
DB::prepared_query($sql, $parameters);
Also note that the parameters may not be a single level array, as certain values
may be forced to be cast as a certain type (where supported by the current API).
After:
E.g.
:::php
<?php
:::php
// Increment value of a single condition
$conditions = $query->getWhere();
$new = array();
foreach($conditions as $condition) {
// $condition will be a single length array
foreach($condition as $predicate => $parameters) {
if('"Count" = ?' === $predicate) {
$parameters[0] = $parameters[0] + 1;
}
$new[] = array($predicate => $parameters);
}
}
$query->setWhere($new);
$parameters = array(
10,
array('value' => 0, 'type' => 'boolean') // May also contain other database API specific options
)
DB::prepared_query('DELETE FROM "MyObject" WHERE ParentID = ? OR IsValid = ?', $parameters);
4. ### Update code that interacts with the DB schema
In cases where user code will manipulate the results of this value, it may be useful to
replace this method call with the new `getWhereParameterised($parameters)` method, where
applicable.
This method returns a manipulated form of the where conditions stored by the query, so
that it matches the list of strings consistent with the old 3.1 `SQLQuery::getWhere()` behaviour.
Additionally, the list of parameters is safely extracted, flattened, and can be passed out
through the `$parameters` argument which is passed by reference.
Before:
:::php
public function filtersOnColumn($query, $column) {
$regexp = '/^(.*\.)?("|`)?' . $column . ' ("|`)?\s?=/';
foreach($this->getWhere() as $predicate) {
if(preg_match($regexp, $predicate)) return true;
}
return false;
}
After:
:::php
public function filtersOnColumn($query, $column) {
$regexp = '/^(.*\.)?("|`)?' . $column . ' ("|`)?\s?=/';
foreach($this->getWhereParameterised($parameters) as $predicate) {
if(preg_match($regexp, $predicate)) return true;
}
return false;
}
#### 5. Update code that interacts with the DB schema
Updating database schema is now done by `updateSchema` with a callback, rather than relying
on user code to call `beginSchemaUpdate` and `endSchemaUpdate` around the call.
@ -350,6 +723,7 @@ interact with it via `DB::get_schema` instead of `DB::get_conn` (previously name
Before:
:::php
<?php
$conn = DB::getConn();
@ -359,8 +733,10 @@ Before:
}
$conn->endSchemaUpdate();
After:
:::php
<?php
$schema = DB::get_schema();
@ -370,6 +746,7 @@ After:
}
});
Also should be noted is that many functions have been renamed to conform better with
coding conventions. E.g. `DB::requireTable` is now `DB::require_table`
@ -381,6 +758,7 @@ feature which performs both unpublish and deletion simultaneously.
To restore "delete from live" add the following config to your site's config.yml.
:::yml
CMSMain:
enabled_legacy_actions:
@ -395,106 +773,3 @@ In order to remove the new "archive" action and restore the old "delete" action
enabled_legacy_actions:
- CMSBatchAction_Delete
### Update Image method names in PHP code and templates
* `SetRatioSize` -> `Fit`
* `CroppedImage` -> `Fill`
* `PaddedImage` -> `Pad`
* `SetSize` -> `Pad`
* `SetWidth` -> `ScaleWidth`
* `SetHeight` -> `ScaleHeight`
### Other
* Helper function `DB::placeholders` can be used to generate a comma separated list of placeholders
useful for creating "WHERE ... IN (?,...)" SQL fragments
* Implemented Convert::symbol2sql to safely encode database and table names and identifiers.
E.g. `Convert::symbol2sql('table.column') => '"table"."column"';`
* `Convert::raw2sql` may now quote the escaped value, as well as safely escape it, according to the current
database adaptor's preference.
* `DB` class has been updated and many static methods have been renamed to conform to coding convention.
* Renamed API:
- `affectedRows` -> `affected_rows`
- `checkAndRepairTable` -> `check_and_repair_table`
- `createDatabase` -> `create_database`
- `createField` -> `createField`
- `createTable` -> `createTable`
- `dontRequireField` -> `dont_require_field`
- `dontRequireTable` -> `dont_require_table`
- `fieldList` -> `field_list`
- `getConn` -> `get_conn`
- `getGeneratedID` -> `get_generated_id`
- `isActive` -> `is_active`
- `requireField` -> `require_field`
- `requireIndex` -> `require_index`
- `requireTable` -> `require_table`
- `setConn` -> `set_conn`
- `tableList` -> `table_list`
* Deprecated API:
- `getConnect` (Was placeholder for PDO connection string building code, but is made
redundant after the PDOConnector being fully abstracted)
* New API:
- `build_sql` - Hook into new SQL generation code
- `get_connector` (Nothing to do with getConnect)
- `get_schema`
- `placeholders`
- `prepared_query`
* `SS_Database` class has been updated and many functions have been deprecated, or refactored into
the various other database classes. Most of the database management classes remain in the database
controller, due to individual databases (changing, creating of, etc) varying quite a lot from
API to API, but schema updates within a database itself is managed by an attached DBSchemaManager
* Refactored into DBSchemaManager:
- `createTable`
- `alterTable`
- `renameTable`
- `createField`
- `renameField`
- `fieldList`
- `tableList`
- `hasTable`
- `enumValuesForField`
- `beginSchemaUpdate` and `endSchemaUpdate` -> Use `schemaUpdate` with a callback
- `cancelSchemaUpdate`
- `isSchemaUpdating`
- `doesSchemaNeedUpdating`
- `transCreateTable`
- `transAlterTable`
- `transCreateField`
- `transCreateField`
- `transCreateIndex`
- `transAlterField`
- `transAlterIndex`
- `requireTable`
- `dontRequireTable`
- `requireIndex`
- `hasField`
- `requireField`
- `dontRequireField`
* Refactored into DBQueryBuilder
- `sqlQueryToString`
* Deprecated:
- `getConnect` - Was intended for use with PDO, but was never implemented, and is now
redundant, now that there is a stand-alone `PDOConnector`
- `prepStringForDB` - Use `quoteString` instead
- `dropDatabase` - Use `dropSelectedDatabase`
- `createDatabase` - Use `selectDatabase` with the second parameter set to true instead
- `allDatabaseNames` - Use `databaseList` instead
- `currentDatabase` - Use `getSelectedDatabase` instead
- `addslashes` - Use `escapeString` instead
* LogErrorEmailFormatter now better displays SQL queries in errors by respecting line breaks
* Installer has been majorly upgraded to handle the new database configuration options
and additional PDO functionality.
* Created SS_DatabaseException to emit database errors. Query information such as SQL
and any relevant parameters may be used by error handling user code that catches
this exception.
* The SQLConditionGroup interface has been created to represent dynamically
evaluated SQL conditions. This may be used to wrap a class that generates
a custom SQL clause(s) to be evaluated at the time of execution.
* DataObject constants CHANGE_NONE, CHANGE_STRICT, and CHANGE_VALUE have been created
to provide more verbosity to field modification detection. This replaces the use of
various magic numbers with the same meaning.
* create_table_options now uses constants as API specific filters rather than strings.
This is in order to promote better referencing of elements across the codebase.
See `FulltextSearchable->enable` for example.
* `$FromEnd` iterator variable now available in templates.

View File

@ -1,146 +0,0 @@
# 3.2.0 (unreleased)
## Overview
### CMS
* Moved SS_Report and ReportAdmin out to a separate module. If you're using
composer or downloading a release, this module should be included for you.
Otherwise, you'll need to include the module yourself
(https://github.com/silverstripe-labs/silverstripe-reports)
### Framework
* API: Removed URL routing by controller name
* Security: The multiple authenticator login page should now be styled manually - i.e. without the default jQuery
UI layout. A new template, Security_MultiAuthenticatorLogin.ss is available.
* Security: This controller's templates can be customised by overriding the `getTemplatesFor` function.
* API: Form and FormField ID attributes rewritten.
## Details
### API: Removed URL routing by controller name
The auto-routing of controller class names to URL endpoints
has been removed (rule: `'$Controller//$Action/$ID/$OtherID': '*'`).
This increases clarity in routing since it makes URL entpoints explicit,
and thereby simplifies system and security reviews.
Please access any custom controllers exclusively through self-defined
[routes](/reference/director). For controllers extending `Page_Controller`,
simply use the provided page URLs.
:::php
class MyController extends Controller {
static $allowed_actions = array('myaction');
public function myaction($request) {
// ...
}
}
Create a new file `mysite/_config/routes.yml`
(read more about the [config format](/topics/configuration)).
Your controller is now available on `http://yourdomain.com/my-controller-endpoint`,
after refreshing the configuration cache through `?flush=all`.
:::yaml
---
Name: my-routes
After: framework/routes#coreroutes
---
Director:
rules:
'my-controller-endpoint//$Action' : 'MyController'
The auto-routing is still in place for unit tests,
since its a frequently used feature there. Although we advise against it,
you can reinstate the old behaviour through a director rule:
:::yaml
---
Name: my-routes
After: framework/routes#coreroutes
---
Director:
rules:
'$Controller//$Action/$ID/$OtherID': '*'
### API: Default Form and FormField ID attributes rewritten.
Previously the automatic generation of ID attributes throughout the Form API
could generate invalid ID values such as Password[ConfirmedPassword] as well
as duplicate ID values between forms on the same page. For example, if you
created a field called `Email` on more than one form on the page, the resulting
HTML would have multiple instances of `#Email`. ID should be a unique
identifier for a single element within the document.
This rewrite has several angles, each of which is described below. If you rely
on ID values in your CSS files, Javascript code or application unit tests *you
will need to update your code*.
#### Conversion of invalid form ID values
ID attributes on Form and Form Fields will now follow the
[HTML specification](http://www.w3.org/TR/REC-html40/types.html#type-cdata).
Generating ID attributes is now handled by the new `FormTemplateHelper` class.
Please test each of your existing site forms to ensure that they work
correctly in particular, javascript and css styles which rely on specific ID
values.
#### Invalid ID attributes stripped
ID attributes will now be run through `Convert::raw2htmlid`. Invalid characters
are replaced with a single underscore character. Duplicate, leading and trailing
underscores are removed. Custom ID attributes (set through `setHTMLID`) will not
be altered.
Before:
<form id="MyForm[Form]"
<div id="MyForm[Form][ID]">
Now:
<form id="MyForm_Form">
<div id="MyForm_Form_ID">
#### Namespaced FormField ID's
Form Field ID values will now be namespaced with the parent form ID.
Before:
<div id="Email">
Now:
<div id="MyForm_Email">
#### FormField wrapper containers suffixed with `_Holder`
Previously both the container div and FormField tag shared the same ID in
certain cases. Now, the wrapper div in the default `FormField` template will be
suffixed with `_Holder`.
Before:
<div id="Email">
<input id="Email" />
After:
<div id="MyForm_Email_Holder"
<input id="MyForm_Email" />
#### Reverting to the old specification
If upgrading existing forms is not feasible, developers can opt out of the new
specifications by using the `FormTemplateHelper_Pre32` class rules instead of
the default ones.
:::yaml
# mysite/config/_config.yml
Injector:
FormTemplateHelper:
class: FormTemplateHelper_Pre32
### Further Changes
* Removed `Member.LastVisited` and `Member.NumVisits` properties, see [Howto: Track Member Logins](doc.silverstripe.org/framework/en/trunk/howto/track-member-logins) to restore functionality as custom code