You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: architecture/using-composer.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -185,7 +185,7 @@ Laravel packages will often provide configuration files, and they will usually c
185
185
186
186
However, this can create problems with Winter's plugin oriented design, since there would now be random config files in the core `/config` directory. In order to solve this problem, it is recommended that you proxy the included package's configuration through your plugin instead.
187
187
188
-
You may place this code in your Plugin registration file and call it from the the `boot()` method.
188
+
You may place this code in your Plugin registration file and call it from the `boot()` method.
Copy file name to clipboardExpand all lines: backend/controllers-ajax.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,7 +4,7 @@
4
4
5
5
The Winter CMS backend implements the MVC pattern. Controllers manage backend pages and implement various features like forms and lists. This article describes how to develop backend controllers and how to configure controller behaviors.
6
6
7
-
Each controller consists of a PHP file which resides in the the **/controllers** subdirectory of a Plugin directory. Controller views are `.php` files that reside in the controller view directory. The controller view directory name matches the controller class name written in lowercase. The view directory can also contain controller configuration files. An example of a controller directory structure:
7
+
Each controller consists of a PHP file which resides in the **/controllers** subdirectory of a Plugin directory. Controller views are `.php` files that reside in the controller view directory. The controller view directory name matches the controller class name written in lowercase. The view directory can also contain controller configuration files. An example of a controller directory structure:
8
8
9
9
```treeview
10
10
plugins/
@@ -44,7 +44,7 @@ The backend controller base class defines a number of properties that allow to c
44
44
Property | Description
45
45
------------- | -------------
46
46
`$fatalError` | allows to store a fatal exception generated in an action method in order to display it in the view.
47
-
`$user` | contains a reference to the the backend user object.
47
+
`$user` | contains a reference to the backend user object.
48
48
`$suppressView` | allows to prevent the view display. Can be updated in the action method or in the controller constructor.
49
49
`$params` | an array of the routed parameters.
50
50
`$action` | a name of the action method being executed in the current request.
- `options`will be rendered in a `<datalist>` element, enabling autocomplete suggestions.
710
+
- If an option's value and label are identical, the label is omitted for brevity.
711
+
712
+
See [Defining field options](#defining-field-options) for the different methods to specify the options.
713
+
684
714
### Text
685
715
686
716
`text`- renders a single line text box. This is the default type used if none is specified.
@@ -1816,7 +1846,7 @@ Sometimes you may wish to modify the default form behavior and there are several
1816
1846
1817
1847
Several controller methods can called at various points during the lifecycle of the `FormController` to provide injection points for custom logic. See the [API docs](/docs/v1.2/api/Backend/Behaviors/FormController#method-formbeforesave) for a full reference of what they are. Generally speaking any method in the API docs prefixed with `form` can be overridden in your controller to change the default behaviour or act as an injection point for custom logic.
1818
1848
1819
-
> **NOTE:** It may be more desirable to use [model events](/docs/v1.2/api/events/model/beforeSave) to implement your logic instead as those are always run when applicable if the model is being affected, no matter where the interaction with the model is occuring.
1849
+
> **NOTE:** It may be more desirable to use [model events](/docs/v1.2/api/events/model/beforeSave) to implement your logic instead as those are always run when applicable if the model is being affected, no matter where the interaction with the model is occurring.
Copy file name to clipboardExpand all lines: backend/lists.md
+15Lines changed: 15 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -76,6 +76,21 @@ Option | Description
76
76
`showTotals` | displays the summed values for the columns in the form of `totalOnPage (totalForQuery)` in the list header and footer. Default: `true`.
77
77
`treeExpanded` | if tree nodes should be expanded by default. Default: `false`.
78
78
`customViewPath`| specify a custom view path to override partials used by the list, optional.
79
+
`sortable`| enables drag-and-drop reordering of records directly in the list, see [reordering records](#reordering-records). Default: `false`.
80
+
81
+
### Reordering records
82
+
83
+
Set `sortable` to `true` to let backend users reorder the list with drag-and-drop. The list model must use the [`Sortable` trait](../database/traits#sortable) so it has a `sort_order` column.
84
+
85
+
```yaml
86
+
sortable: true
87
+
```
88
+
89
+
When enabled, a drag handle is shown on each row, column header sorting is disabled, the list is shown in its stored order without pagination, and dropping a row persists the new order to the model's sort order column via AJAX.
90
+
91
+
Because the whole list must be visible in a single fixed order, `sortable` cannot be combined with searching, filtering, pagination, or a custom `defaultSort` — configuring any of these alongside it raises a configuration error.
92
+
93
+
> **NOTE:** Reordering applies to flat lists. For reordering tree structures, or for a dedicated standalone reordering page, use the [Reorder behavior](reorder).
Copy file name to clipboardExpand all lines: backend/relations.md
+18Lines changed: 18 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -114,6 +114,7 @@ Option | Type | Description
114
114
`recordUrl` | List | link each list record to another page. Eg: **users/update/:id**. The `:id` part is replaced with the record identifier.
115
115
`customViewPath`| List | specify a custom view path to override partials used by the list.
116
116
`recordOnClick`| List | custom JavaScript code to execute when clicking on a record.
117
+
`sortable`| List | enables drag-and-drop reordering of the related records, see [reordering relations](#reordering-relations). Requires the parent model to use the [`HasSortableRelations` trait](../database/traits#hassortablerelations). Default: `false`.
117
118
`toolbarPartial` | Both | a reference to a controller partial file with the toolbar buttons. Eg: **_relation_toolbar.htm**. This option overrides the *toolbarButtons* option.
118
119
`toolbarButtons` | Both | the set of buttons to display. This can be formatted as an array or a pipe separated string, or set to `false` to show no buttons. Available options are: `create`, `update`, `delete`, `add`, `remove`, `refresh`, `link`, & `unlink`. Example: `add\|remove`. <br/> Additionally, you can customize the text inside these buttons by setting this property to an associative array, with the key being the button type and the value being the text for that button. Example: `create: 'Assign User'`. The value also supports translation.
119
120
@@ -289,6 +290,23 @@ phone:
289
290
list: $/acme/user/models/phone/columns.yaml
290
291
```
291
292
293
+
### Reordering relations
294
+
295
+
Pivot-based relations (`belongsToMany`, `morphToMany`, `morphedByMany`) can be reordered with drag-and-drop directly in the relation manager. The parent model must use the [`HasSortableRelations` trait](../database/traits#hassortablerelations) and declare the relation in its `$sortableRelations` property, and the pivot table must have a sort order column. Then set `sortable: true` on the relation's `view` configuration:
296
+
297
+
```yaml
298
+
authors:
299
+
label: Author
300
+
view:
301
+
list: $/acme/blog/models/author/columns.yaml
302
+
toolbarButtons: link|unlink
303
+
sortable: true
304
+
```
305
+
306
+
A drag handle is shown on each related record; dropping persists the new order to the pivot's sort order column. Reordering also works while the parent record is being created, before it is saved — the order is stored against the [deferred binding](../database/relations#deferred-binding) and committed together with the record.
307
+
308
+
As with sortable lists, the related records are shown as a single unpaginated set in their stored order, so `sortable` cannot be combined with searching, filtering, pagination, or a custom `defaultSort` on the relation's `view` configuration.
309
+
292
310
## Displaying a relation manager
293
311
294
312
Before relations can be managed on any page, the target model must first be initialized in the controller by calling the `initRelation` method.
Copy file name to clipboardExpand all lines: backend/reorder.md
+2Lines changed: 2 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,6 +4,8 @@
4
4
5
5
The **Reorder behavior** is a controller [behavior](../services/behaviors) that provides features for sorting and reordering database records. The behavior provides a page called Reorder using the controller action `reorder`. This page displays a list of records with a drag handle allowing them to be sorted and in some cases restructured.
6
6
7
+
> **NOTE:** To let users reorder records inline with drag-and-drop without a dedicated page — directly in a [list](lists#reordering-records) or a [relation manager](relations#reordering-relations) — see those sections. The Reorder behavior documented here provides a dedicated standalone page, which is best suited to models with deep tree structures.
8
+
7
9
The behavior depends on a [model class](../database/model) which must implement one of the following [model traits](../database/traits):
Copy file name to clipboardExpand all lines: database/traits.md
+38-5Lines changed: 38 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -838,16 +838,49 @@ class ApiData extends Model
838
838
839
839
## HasSortableRelations
840
840
841
-
Add this trait to your model in order to allow its relations to be sorted/reordered.
841
+
Sorted relations store a sort order value in the pivot table of a `belongsToMany`, `morphToMany`, or `morphedByMany` relation, so the related records keep a custom order for each parent record. Apply the `Winter\Storm\Database\Traits\HasSortableRelations` trait and define a `$sortableRelations` property that maps each relation name to its pivot sort order column.
842
842
843
843
```php
844
-
class MyModel extends model
844
+
class Article extends \Winter\Storm\Database\Model
845
845
{
846
846
use \Winter\Storm\Database\Traits\HasSortableRelations;
847
847
848
848
/**
849
-
* @var array Relations that can be sorted/reordered and the column name to use for sorting/reordering.
849
+
* @var array Relations that can be reordered and the pivot column used for sorting.
850
850
*/
851
-
public $sortableRelations = ['relation_name' => 'sort_order_column'];
852
-
...
851
+
public $sortableRelations = ['authors' => 'sort_order'];
852
+
853
+
public $belongsToMany = [
854
+
'authors' => [
855
+
\Acme\Blog\Models\Author::class,
856
+
'table' => 'acme_blog_articles_authors',
857
+
],
858
+
];
853
859
}
860
+
```
861
+
862
+
Ensure the pivot table has the sort order column, for example in a migration:
863
+
864
+
```php
865
+
$table->integer('sort_order')->default(0);
866
+
```
867
+
868
+
You must create the column yourself (as in the migration above) — the trait does not create it. When the model boots, the trait includes that column in the relation's pivot data, so its value is loaded onto each record's `pivot`, and applies an `order by {pivot_table}.{column} asc` clause so the relation is always returned in its stored order. The trait also assigns the next sort order value to newly attached records, appending them to the end of the relation.
869
+
870
+
Use the `setRelationOrder` method to reorder a relation programmatically. The second argument is the related record ids in their new order; the optional third argument provides the sort order value to assign to each (when omitted, a sequential `1..N` order is assigned in the given order):
871
+
872
+
```php
873
+
// Reorder by ids only — assigns sort orders 1, 2, 3 in the given order
You can check whether a relation is configured as sortable with `isSortableRelation`:
881
+
882
+
```php
883
+
$article->isSortableRelation('authors'); // true
884
+
```
885
+
886
+
> **NOTE:** To let backend users reorder a relation with drag-and-drop directly in a form, see [reordering relations](../backend/relations#reordering-relations) in the RelationController documentation.
Copy file name to clipboardExpand all lines: snowboard/extras.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -413,7 +413,7 @@ class Gallery extends Snowboard.PluginBase {
413
413
}
414
414
```
415
415
416
-
In the example above, even if the gallery element defines a `data-num-images` data attribute, this will be overriden by the `userNumImages` parameter that is used in constructing the gallery. This `userNumImages` parameter could be populated by a user configuration source.
416
+
In the example above, even if the gallery element defines a `data-num-images` data attribute, this will be overridden by the `userNumImages` parameter that is used in constructing the gallery. This `userNumImages` parameter could be populated by a user configuration source.
417
417
418
418
### Methods
419
419
@@ -429,7 +429,7 @@ this.config.get(); // Returns an object of all configuration options and their v
429
429
430
430
#### `get(configName: string)`
431
431
432
-
Gets the configuration value for the given configuration name. This will be retrieved from the local configuration first, then the data attribute of the element providing the configuration then finally from the the defaults if not specified on the element.
432
+
Gets the configuration value for the given configuration name. This will be retrieved from the local configuration first, then the data attribute of the element providing the configuration then finally from the defaults if not specified on the element.
433
433
434
434
If the configuration has been provided a local configuration value for the config name, it will be returned over all other sources.
Copy file name to clipboardExpand all lines: snowboard/request.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -71,7 +71,7 @@ Finally, the following option parameters define override functionality for vario
71
71
Option | Parameters | Description
72
72
------ | ---------- | -----------
73
73
`handleConfirmMessage` | `(string) confirmationMessage` | Handles any confirmations requested of the user.
74
-
`handleErrorMessage` | `(string) errorMessage` | Handles any errors occuring during the request
74
+
`handleErrorMessage` | `(string) errorMessage` | Handles any errors occurring during the request
75
75
`handleValidationMessage` | `(string) message, (Object) fieldMessages` | Handles validation errors occurring during the request. `fieldMessages` has field names as the key and messages as the value.
0 commit comments