October CMS 3.6 - Enhanced Forms Release

Release Note 37

Version 3.6 of October CMS contains some major improvements to the platform. Some of these features were scheduled to be released in v4.0 of October CMS, however, since Laravel 11 includes some compatibility changes, we need to wait for those changes to mature. This means we've included the new features in the v3.6 as a backwards compatible release.

Table of Contents

How to Upgrade to v3.6

There are two ways to upgrade, by clicking the Check for Updates button in the admin panel, or via console commands. For command line interface, please use the following commands:

composer update
php artisan october:migrate
php artisan october:util set build

Using the october:update command, you may encounter an error Target class [system.cacher] does not exist.. If this occurs, run the command a second time to fix it.

In the event that you find some incompatibilities with your plugins due to this release, lock your composer file to the previous version (v3.5) by modifying your composer file below and then run composer update.

"require": {
    "october/all": "3.5.*",
    "october/rain": "3.5.*",
}

Relation Controller Support in Tailor

Nested Items Tailor Content Field

The entries field type in Tailor supports managing records using a more advanced interface, including create, update and delete. When setting the display mode to controller, the records can be managed using the Relation Controller behavior. For example:

guests:
    type: entries
    source: Event\Guest
    displayMode: controller

The new nesteditems content field supports the Relation Controller behavior natively. It is used when the related items are exclusive to the parent record, and supports inline form fields, including tabs and secondary tabs.

items:
    label: Menu Items
    type: nesteditems
    form:
        fields: [...]
        tabs:
            fields: [...]

Design Modes for Form Controller

The FormController behavior has been improved to include different design modes. A design property can be specified inside the form configuration YAML file. For example, the following displays a basic form design with a size of 750 wide.

# ===================================
#  Form Behavior Config
# ===================================

# ...

design:
    displayMode: basic
    size: 750

Now, the form can be rendered in the controller view using the formRenderDesign method, as a single line of code.

<?= $this->formRenderDesign() ?>

A popup display mode is also available that removes the need to create any form view files (update, create, preview).

design:
    displayMode: popup

Now, the following recordOnClick value can be used in the ListController list configuration YAML file. This will manage the form records using popups, as a single line of code.

# ===================================
#  List Behavior Config
# ===================================

# ...

recordOnClick: popup

When the design property is omitted, the custom design mode is used with the standard formRender method. We anticipate there will be several new design modes coming in later releases, in addition to different design modes for the list controller.

Nested Relation Controllers

The Relation Controller has been improved to support nesting relations, in other words, managing relations through relations. A nested relationship uses the standard field nesting syntax. For example, the countries[cities] relation definition makes the cities relationship available to manage through the countries relationship.

countries:
    label: Country
    form: $/october/test/models/country/fields.yaml
    list: $/october/test/models/country/columns.yaml

countries[cities]:
    label: City
    form: $/october/test/models/city/fields.yaml
    list: $/october/test/models/city/columns.yaml

This concept has been taken further with self-registration using the relation field type. This makes it effortless to manage complex relations. You may now define the controller property on the form field with the relation controller configuration directly on the field.

For example, a product model can specify a related_products field that registers itself with the Relation Controller automatically, including nested and recursive structures.

related_products:
    label: Related Products
    type: relation
    controller:
        label: Related Product
        list: $/october/test/models/product/columns.yaml
        form: $/october/test/models/product/fields.yaml
        view:
            toolbarButtons: add|remove

Masking Author Name in Admin URLs

It is now possible to customize the admin panel URLs introduced by plugins. By default, the URL of an admin page is made up of the author name, plugin name, controller name and action name.

admin/[author name]/[plugin name]/[controller name]/[action name]

To use a custom URL segment, specify the hint property in the pluginDetails method when registering the plugin. The hint should be a unique code that does not conflict with other plugins.

public function pluginDetails()
{
    return [
        // ...
        'hint' => 'user'
    ];
}

A shorter URL structure becomes available, which is useful for masking the author name in URLs.

admin/[hint name]/[controller name]/[action name]

More Multisite Improvements

Synchronization for multisite has been improved to allow sync between all sites, sites within the same group (default) or within the same locale. These values are available within Tailor Blueprints to control this behavior.

multisite: sync | all | locale | group

Deleted records are also propagated across multisite-enabled models, so when a record is deleted, any linked records will also be deleted. This is the new default, however, it can be disabled using the array format for configuration, and setting the delete property to false.

multisite:
    sync: group
    delete: false

Shorter Mail Templates

It is now possible to register shorter mail template codes, instead of using the fully qualified view path. This feature is optional but may cause some misconfigured plugins to throw an error. Check the registerMailTemplates method of your plugins. Some older plugins were using this format:

// Invalid syntax from v3.6
[
    'vendor.plugin::mail.view-one' => 'vendor.plugin::lang.string_one',
    'vendor.plugin::mail.view-two' => 'vendor.plugin::lang.string_two',
    // ...
]

The language string (array value) was never used for anything or documented anywhere, however, we noticed some plugins were using this format, including official ones, and it may have replicated from these examples. If you find the mail templates page throws an exception, update the plugin to remove the language strings and return a list array of view paths instead. See the example below:

// Valid syntax (backward compatible)
[
    'vendor.plugin::mail.view-one',
    'vendor.plugin::mail.view-two',
    // ...
]

Or, if you wish to use the newer v3.6 syntax, with shorter mail codes:

// Newer syntax
[
    'plugin:message-one' => 'vendor.plugin::mail.view-one',
    'plugin:message-two' => 'vendor.plugin::mail.view-two',
    // ...
]

Phosphor Icon Library

The admin panel now includes Phosphor icons -- a flexible icon family containing 7,488 icons that are now available for use in plugins.

A phosphorIcons preset is available to use in your form fields:

icon:
    label: Icon
    type: dropdown
    optionsPreset: phosphorIcons

The preset can also be used in list columns with the selectable type.

icon:
    label: Icon
    type: selectable
    optionsPreset: phosphorIcons

A new documentation page has been created to list all the available icons.

Notable Minor Changes

Flash Progress Messages

The AJAX framework now supports a message option that contains text to display while the request loads, which is displayed using a flash message. It can be implemented using the data attributes API or the JavaScript interface.

<button
    data-request="onSave"
    data-request-message="Please wait while we process your request...">
    Save
</button>

Partial Types Now Support The Model Directory

The partial type for form fields and list columns will now check the model directory in addition to the controller directory. This makes it easier to couple your view files with the YAML definition that implements it.

For example, if a model fields.yaml file defines a partial field called foobar with a generic path called field_foobar. The partial will be loaded from models/mymodel/_field_foobar.php first, and then controllers/mycontroller/_field_foobar.php as a fallback.

Default Path of Partial Types Changed

The partial type for form fields and list columns previously used a default path value set as the field name. This created a naming collision between list columns and form fields using the same name. When the path is omitted, the default value is now prefixed with field_ and column_ respectively.

For backward compatibility, plugin developers should check that YAML definitions containing type: partial also have a path specified as the field name.

myfield:
    type: partial
    path: myfield # ← Add this line

Module Load Order Changed

The load order of service providers (modules, plugins, app) has been changed in this version. This has a low likelihood of impact, however, plugin developers should be aware of this difference.

  • In v3.5 and earlier, the load order was: (1) System module, (2) All plugins, (3) All other modules, (4) App provider

  • In v3.6 and later, the load order is: (1) All modules, (2) All plugins, (3) App provider

Disable Backend Password Resets

By default, administrators can reset their own password using the password reset feature found administrator area. In some cases you may wish to restrict this ability. A new backend.password_policy.allow_reset configuration item is included to allow disabling the reset password feature via self service. When disabled, administrators will need to request a password reset from another administrator or via the october:passwd artisan command.

'password_policy' => [
    'allow_reset' => false,
],

Deferred Binding Support for Sortable Relations

The October\Rain\Database\Traits\SortableRelation trait now supports deferred binding. The sort order is stored in the deferred bindings table until it is committed and applied to the pivot table. When deferred models are co-mingled with existing models, the results are sorted by a unified sort order column to produce a seamless result.

This implementation has improved the withDeferred method so pivot and binding data is now available as part of the query. Previously, pivot data was not available since whereExists sub-queries were used internally, and special consideration had to be given since the pivot data was not always available. Now, the new internals use a leftJoin query so the pivot columns are always available, although they appear empty for deferred records, they can now be queried normally without any special workarounds.


This is the end of the document, you may read the announcement blog post or visit the changelog for more information.

comments powered by Disqus