From 610bd7771253428bb13c796f35eb87d72d3d3730 Mon Sep 17 00:00:00 2001 From: Guy Sartorelli <36352093+GuySartorelli@users.noreply.github.com> Date: Thu, 9 Mar 2023 10:39:43 +1300 Subject: [PATCH] DOC Add upgrade guide for tractorcow/silverstripe-fluent (#175) --- en/03_Upgrading/07_Upgrading_Fluent.md | 252 ++++++++++++++++++++ en/_images/fluent/batch_actions_enabled.png | Bin 0 -> 27680 bytes 2 files changed, 252 insertions(+) create mode 100644 en/03_Upgrading/07_Upgrading_Fluent.md create mode 100644 en/_images/fluent/batch_actions_enabled.png diff --git a/en/03_Upgrading/07_Upgrading_Fluent.md b/en/03_Upgrading/07_Upgrading_Fluent.md new file mode 100644 index 000000000..b18bf1df1 --- /dev/null +++ b/en/03_Upgrading/07_Upgrading_Fluent.md @@ -0,0 +1,252 @@ +--- +title: Upgrading Fluent +summary: Upgrade your Silverstripe CMS project to use the latest version of tractorcow/silverstripe-fluent +--- + +Silverstripe only commercially supports version 4.x of [tractorcow/silverstripe-fluent](https://github.com/tractorcow-farm/silverstripe-fluent) with the 4.x major release line of Silverstripe CMS - however, the fluent module also has versions 5.x and 6.x which are compatible with Silverstripe CMS 4.x. + +This documents some of the breaking and functional changes across these three major release lines of the fluent module, as well as some key things to look out for and general guidelines on how to adapt your code to be compatible with the latest version. + +- [Breaking API changes](#breaking-api-changes) +- [Localisation settings](#localisation-settings) + - [Locale fallback](#locale-fallback) + - [User permissions](#user-permissions) + - [Enhanced CMS UI](#enhanced-cms-ui) +- [Localised versioned history](#localised-versioned-history) + - [Standard Versioned methods](#standard-versioned-methods) +- [Localised relations](#localised-relations) +- [Quality of life changes](#quality-of-life-changes) +- [Unit tests](#unit-tests) +- [Further reading](#further-reading) + +## Breaking API changes + +Fluent v5 and v6 both introduced some breaking API changes. + +### Fluent v5 {#breaking-api-changes-v5} + +- `TractorCow\Fluent\Extension\FluentBadgeExtension` class was removed (use `TractorCow\Fluent\Extension\Traits\FluentBadgeTrait` instead) +- `TractorCow\Fluent\Extension\FluentExtension::LocaleInformation()` returns `RecordLocale` (used to be `ArrayData`) +- `TractorCow\Fluent\Extension\FluentExtension::getSelectedLanguage()` returns `RecordLocale` (used to be `ArrayData`) +- `TractorCow\Fluent\Model\CachableModel::getCached()` (this is a trait so by extension everything which uses it) returns `ArrayList|static[]` (used to be `ArrayList`) +- `TractorCow\Fluent\Model\Domain::getLocales()` returns `ArrayList|Locale[]` (used to be just `ArrayList`) +- `TractorCow\Fluent\Model\Locale::getLocales()` returns `ArrayList|Locale[]` (used to be just `ArrayList`) + +#### Deprecated {#deprecated-v5} + +- `TractorCow\Fluent\Extension\FluentExtension::getLinkingMode()` (Use `LocaleInformation()` instead) +- `TractorCow\Fluent\Extension\FluentExtension::LocaleLink()` (Use `LocaleInformation()` instead) + +### Fluent v6 {#breaking-api-changes-v6} + +- `TractorCow\Fluent\Extension\FluentExtension::requireSavedInLocale()` method was removed (use `getInheritanceMode()` instead) +- `TractorCow\Fluent\Extension\Traits\FluentObjectTrait::LinkedLocales()` now returns `ArrayList|Locale[]` (used to be `DataList|Locale[]`) +- `TractorCow\Fluent\Model\Locale::getCurrentLocale()` now explicitly returns `?Locale` (used to be dynamic) +- `TractorCow\Fluent\Model\Locale::getByLocale()` now explicitly returns `?Locale` (used to be dynamic) +- `TractorCow\Fluent\Extension\FluentExtension::updateLocalisationTabConfig()` no longer does permissions checks - it expects those checks to be handled by the relevant `GridField` components +- `TractorCow\Fluent\Forms\GroupActionMenu::getColumnContent()` no longer includes disabled actions in the returned markup + +## Localisation settings + +Changes to various localisation settings. + +### Locale fallback + +Locale fallback logic and options have changed significantly. + +In Fluent v5, the `DataObject.cms_publish_required` configuration property was renamed to `DataObject.cms_localisation_required`. + +[info] +If you have set `cms_publish_required` configuration in your yaml configuration files, `Extension` class, or `DataObject` models, change these to `cms_localisation_required` instead. +[/info] + +#### Fallback changes in Fluent v6 {#locale-fallback-v6} + +The values for the `DataObject.frontend_publish_required` and `DataObject.cms_localisation_required` config properties changed from boolean to the strings "any", "fallback", and "exact". + +If you had set either property to `true` in previous versions, this is the equivalent of the new "exact" value, where `false` is the equivalent of "any". + +[hint] +If you're setting these values in an extension or model with the private static properties, you can use the constants from `FluentExtension` (e.g. `FluentExtension::INHERITANCE_MODE_EXACT`). +[/hint] + +| | `frontend_publish_required` | `cms_localisation_required` | +|-------------|--------------------------------|-------------------------------| +| Old default | `true` (equivalent of "exact") | `false` (equivalent of "any") | +| New default | "fallback" | "any" | + +Here's what the new values actually mean: + +| "any" | "fallback" | "exact" +|-----|-----|-----| +| Content for this record must exist in any locale _or the base (unlocalised) record_. | Content for this record must exist in the current locale _or_ a specific fallback locale, as defined through the Locales admin section. | Content for this record _must_ exist in the current locale to be used. | + +[notice] +Review localisation settings on all of your models and migrate to the correct value. _Do not_ just swap to the new equivalent of your old value unless you explicitly want to keep that behaviour. Instead, consider whether the new functionality warrants a change to a different option. +[/notice] + +### User permissions + +Fluent v5 introduced more granular permission management. + +| | **Fluent 4** | **Fluent 5** | **Fluent 6** | +|---------------------------|--------------|--------------|--------------| +| Locale permission support | No | Yes | Yes | + +[hint] +If you're upgrading from Fluent v4, review your requirements for user permissions in the context of locales and update the permissions as needed. For example you may have content authors who should only be allowed to edit content for specific locales. +[/hint] + +### Enhanced CMS UI + +Fluent 5 introduced some new configurable UI actions, including a new `Localisation` tab in the edit form for localised models where you see and manage the localisation status of each record. The `Localisation` tab is referred to in documentation as the "localisation manager". + +| | `localise_actions_enabled` | `batch_actions_enabled` | `copy_from_locale_enabled` | `copy_to_locale_enabled` | +|---------------|--------|--------|--------|--------| +| Default value | `true` | `true` | `true` | `true` | +| Functionality | Enable localise actions for records which are not available in the current locale (copy to draft, copy & publish and Localise actions) | Enable "Localisation" actions in the edit form. More about this below. | Enable "copy from locale" action in the localisation manager | Enable "copy to locale" action in the localisation manager | + +As mentioned in the table above, the `batch_actions_enabled` configuration value controls whether a new "Localisation" action group appears in the edit form. This is not to be confused with the "batch actions" menu in the site tree. + +![The "Localisation" action group, expanded to show all the actions available in it](../_images/fluent/batch_actions_enabled.png) + +[hint] +Review available CMS UI components and enable those that you need. +[/hint] + +## Localised versioned history + +One of the major improvements in Fluent v6 is that version history actually works correctly _out of the box_ now. For example, you can see all of the version history for a record _for each locale_, and rollback changes _per locale_. This wasn't possible in version 4 and 5. + +The following actions in the history tab in the CMS are affected: + +- view version +- compare version +- rollback to version + +| | **Fluent v4** | **Fluent v5** | **Fluent v6** | +|-------|--------------|--------------|--------------| +| Versioned history support | No | No | Yes | +| Out of the box support of [Versioned snapshots module](https://github.com/silverstripe/silverstripe-versioned-snapshot-admin) | No | No | Yes | +| Data source of standard Versioned methods | Base record | Base record | Localised record | + +### Standard Versioned methods + +Fluent 6 alters how many of the [`Versioned`](api:SilverStripe/Versioned/Versioned) methods work as the data source is changed to use the localised tables. This has a large impact on the CMS UI and behaviour (as mentioned in the previous section). + +Examples of impacted methods: + +- [`isOnDraft()`](api:SilverStripe/Versioned/Versioned::isOnDraft()) +- [`isPublished()`](api:SilverStripe/Versioned/Versioned::isPublished()) +- [`isArchived()`](api:SilverStripe/Versioned/Versioned::isArchived()) +- [`stagesDiffer()`](api:SilverStripe/Versioned/Versioned::stagesDiffer()) + +Simply put, any code you have checking the versioned state of a record used to return results for the base (unlocalised) record. To get the result for the localised record, specialised methods had to be called. + +Now the result for the _localised_ record is returned instead. To get the result for the unlocalised record, you must wrap the call with `FluentState::singleton()->withState()` and set the temporary state to null. For example: + +#### Code examples {#fluent-versioned-examples} + +##### Fluent v4 and v5 {#fluent-versioned-example-v4-v5} + +```php +// Data source: base (unlocalised) record +$model->isPublished(); + +// Data source: localised record +$model->isPublishedInLocale(); +``` + +##### Fluent v6 {#fluent-versioned-example-v6} + +```php +// Data source: base (unlocalised) record +FluentState::singleton()->withState(function (FluentState $state): bool { + $state->setLocale(null); + return $model->isPublished(); +}); + +// Data source: localised record (both give the same result) +$model->isPublished(); +$model->isPublishedInLocale(); +``` + +[/warning] +It's common for Fluent 4 projects to have a lot of custom code to +achieve the same result as this feature. Any such custom code needs to be +identified and removed as a part of the upgrade as it's likely going to +clash with this feature. +[/warning] + +## Localised relations + +This feature allows relations to be localised without having to add custom functionality to support it. + +| | **Fluent 4** | **Fluent 5** | **Fluent 6** | +|-----------------------------|--------------|--------------|--------------| +| Localised relations support | No | Yes | Yes | + +If you have implemented custom functionality to support localising relations, you will need to remove that code. There are a couple of different strategies available for localising relations, and your specific localisation requirements will help you decide which is more appropriate. + +Regardless of which strategy you choose, you will need to apply `FluentExtension` (or `FluentVersionedExtension` for versioned models) to both classes. + +If the locales you support in your project all have the same structure (i.e. you want to keep all the same related objects in the same places) then this is all you need to do. This strategy is called "localise by content" AKA "direct localisation". + +If your locales have a different structure (i.e. you may want different related objects in different locales), you will need to set the `$localised_copy` configuration for the relation. This works very similarly to [`$cascade_duplicates`](/developer_guides/model/relations/#cascading-duplications), except it is explicitly for when you copy content across locales. + +```php +class HomePage extends Page +{ + private static $db = [ + 'Title' => 'Varchar', + ]; + + private static $has_one = [ + 'Banner' => Banner::class, + ]; + + private static $localised_copy = [ + 'Banner', + ]; +} +``` + +[note] +You cannot simply localise the `BannerID` field and expect the relation to be localised, as that won't copy the `Banner` object to the new locale. +[/note] + +This strategy is called "localise by relation" AKA "indirect localisation". We recommend this approach in most cases. + +See [localised copy](https://github.com/tractorcow-farm/silverstripe-fluent/blob/6/docs/en/localised-copy.md) for more details. + +## Quality of life changes + +These changes aren't likely to break anything in your project, but we recommend you review them as you may be implementing some of these features in custom code. If that's the case, you can now remove that custom code in favour of the new API, which reduces your maintenance burden. + +| | **Fluent 4** | **Fluent 5** | **Fluent 6** | +|-----------------------|--------------|--------------|--------------| +| Record locale | No | Yes | Yes | +| Current locale object | No | Yes | Yes | +| Copy to locale | No | No | Yes | + +- **Record locale** - Object that represents details of a specific `DataObject` record in a specific locale + - returned from the `LocaleInformation()` method on every localised model + - you can also get the `RecordLocale` for _all locales_ available for a record by calling `Locales()` +- **Current locale object** - The current locale model available as a global template provider + - use `$CurrentLocaleObject` in a template + - provides all the information about the current locale, not just the locale code or title +- **Copy to locale** - The ability to copy a record to another locale via a single method call + - available via the `copyToLocale()` method on every localised model + +## Unit tests + +Some unit tests may break. There's no one solution for problems you may encounter, but some general recommendations that might help are: + +- avoid localised tables in yaml fixtures + - localise models in your PHP code instead, either in the `setUp()` method or via ORM calls (for example explicitly calling [`$obj->write()`](api:SilverStripe/ORM/DataObject::write()) after fetching the fixture object) +- avoid including version history in your yaml fixtures + - use ORM methods like [`$obj->publishRecursive()`](api:SilverStripe/Versioned/RecursivePublishable:publishRecursive()) after fetching the fixture objects instead + +## Further reading + +- [Fluent 6 documentation](https://github.com/tractorcow-farm/silverstripe-fluent/tree/6/docs) diff --git a/en/_images/fluent/batch_actions_enabled.png b/en/_images/fluent/batch_actions_enabled.png new file mode 100644 index 0000000000000000000000000000000000000000..562cfb1a37058f043c9203ebd86d9a8715b1816c GIT binary patch literal 27680 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