diff --git a/docs/en/02_Developer_Guides/05_Extending/How_Tos/03_Track_member_logins.md b/docs/en/02_Developer_Guides/05_Extending/How_Tos/03_Track_member_logins.md index cf2eaa688..c3a00d601 100644 --- a/docs/en/02_Developer_Guides/05_Extending/How_Tos/03_Track_member_logins.md +++ b/docs/en/02_Developer_Guides/05_Extending/How_Tos/03_Track_member_logins.md @@ -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 )); } diff --git a/docs/en/02_Developer_Guides/09_Security/04_Secure_Coding.md b/docs/en/02_Developer_Guides/09_Security/04_Secure_Coding.md index 29bb57bd5..974791c93 100644 --- a/docs/en/02_Developer_Guides/09_Security/04_Secure_Coding.md +++ b/docs/en/02_Developer_Guides/09_Security/04_Secure_Coding.md @@ -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 diff --git a/docs/en/04_Changelogs/3.2.0.md b/docs/en/04_Changelogs/3.2.0.md index 1ff719cfd..93daa8943 100644 --- a/docs/en/04_Changelogs/3.2.0.md +++ b/docs/en/04_Changelogs/3.2.0.md @@ -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 `
` 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 `` 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 +