Compare commits

...

92 Commits
3.2.2 ... 3

Author SHA1 Message Date
Guy Sartorelli d851ce562c
Merge pull request #395 from creative-commoners/pulls/3/manual-workflows
MNT Upaded scheduled workflows on default branch
2024-05-23 11:56:27 +12:00
Steve Boyd 018ab87515 MNT Upaded scheduled workflows on default branch 2024-05-22 16:36:45 +12:00
Guy Sartorelli d34c92dba7
Merge branch '3.6' into 3 2024-02-27 13:44:19 +13:00
Guy Sartorelli c84d8afa7a
TLN Update translations (#381) 2024-02-07 16:15:40 +13:00
Tom Oude Rengerink 78fa8ba747
ENH Make toast message "Records reordered." localisable (#321)
Co-authored-by: Tom Oude Rengerink <tom@cube.nl>
2024-01-24 11:41:14 +13:00
Guy Sartorelli 62734535a0
MNT Run module-standardiser (#377) 2023-12-21 16:33:13 +13:00
Guy Sartorelli 5ed8c95fda
Merge branch '3.6' into 3 2023-12-19 13:58:41 +13:00
Guy Sartorelli 377dc1ef93
Merge pull request #358 from Sitetools/link_color_fix
Make link color white.
2023-12-19 13:57:29 +13:00
Robin 1637e78ea1
Make link color white. 2023-12-19 13:54:08 +13:00
Guy Sartorelli 9c70b0175b
Merge branch '3.6' into 3 2023-08-30 10:18:58 +12:00
Loz Calver e7d7178719
Merge pull request #372 from creative-commoners/pulls/3.6/manymanythrough-editablecolumns
FIX Allow editing extra fields from ManyManyThroughList.
2023-08-21 09:06:49 +01:00
Guy Sartorelli 1e5a1e8056
ENH Update translations (#373) 2023-08-21 13:21:15 +12:00
Guy Sartorelli 47171ee4c2
FIX Allow editing extra fields from ManyManyThroughList. 2023-08-21 09:02:42 +12:00
Sabina Talipova a2ea473369
MNT Replaced SearchContext::getQuery limit param with null (#367) 2023-07-05 17:20:56 +12:00
Steve Boyd 829cacff0b Merge branch '3.6' into 3 2023-06-16 12:22:25 +12:00
Guy Sartorelli 1284046e10
Merge pull request #365 from creative-commoners/pulls/3.6/tx-1686725015
ENH Update translations
2023-06-15 10:06:20 +12:00
Steve Boyd 665d23170b ENH Update translations 2023-06-14 18:43:35 +12:00
Steve Boyd f2adec35d3 Merge branch '3.6' into 3 2023-05-31 14:31:33 +12:00
Sabina Talipova 504b3bd822
Merge pull request #364 from creative-commoners/pulls/3.6/tx-1685417567
ENH Update translations
2023-05-31 11:29:33 +12:00
Steve Boyd 89a7301b67 ENH Update translations 2023-05-30 15:32:47 +12:00
Guy Sartorelli 6d46483e32
Merge branch '3.6' into 3 2023-04-06 10:41:11 +12:00
Guy Sartorelli bb6c0396f1
Merge branch '3.5' into 3.6 2023-04-06 10:40:35 +12:00
Guy Sartorelli bd783a4a24
Merge pull request #361 from creative-commoners/pulls/3.5/arrays
FIX Handle arrays in default_sort
2023-04-06 10:39:18 +12:00
Steve Boyd 17f92d08ba FIX Handle arrays in default_sort 2023-04-06 10:30:12 +12:00
Maxime Rainville 49a607d747
Merge pull request #360 from creative-commoners/pulls/3/dispatch-ci
MNT Use gha-dispatch-ci
2023-03-23 12:04:25 +13:00
Steve Boyd 5566b05c9d MNT Use gha-dispatch-ci 2023-03-21 12:05:45 +13:00
Guy Sartorelli b0addcb5bd
ENH Update translations (#359) 2023-03-09 14:53:24 +13:00
Maxime Rainville d5d438c5cc
Merge pull request #334 from josephlewisnz/feature/republish-live-records-3
Feature/republish live records 3
2022-11-18 15:38:05 +13:00
Sabina Talipova e9f202f003
Merge pull request #351 from creative-commoners/pulls/3/stop-depr
API Stop using deprecated API
2022-11-11 12:06:57 +13:00
Steve Boyd aa6ac7a1a2 API Stop using deprecated API 2022-11-03 11:45:10 +13:00
Chris Penny 23a5154c97
ENH: Update reorderItems() to use ORM where possible (#336)
* ENH: Update reorderItems() to use ORM where possible

* Increase test coverage of orderable rows
2022-08-04 10:51:40 +12:00
Steve Boyd 7a8f244df0 Merge branch '3.4' into 3 2022-08-03 14:26:22 +12:00
Steve Boyd 378b3af799 Merge branch '3.3' into 3.4 2022-08-03 14:26:18 +12:00
Guy Sartorelli 77e811459e
Merge pull request #346 from creative-commoners/pulls/3.3/standardise-modules
MNT Standardise modules
2022-08-03 14:19:05 +12:00
Steve Boyd aec306bae2 MNT Standardise modules 2022-08-03 13:54:28 +12:00
Guy Sartorelli 4d99f83bbf
Merge pull request #347 from creative-commoners/pulls/3.4/remove-travis
MNT Remove travis
2022-08-03 12:30:03 +12:00
Steve Boyd 2cfe6db9a7 MNT Remove travis 2022-08-03 12:12:02 +12:00
bumbus f56bf67e40
FIX Fixes GridFieldEditableColumns::isChanged method for non-string values (e.g. arrays for has_many / many_many relations) (#343)
* fixes GridFieldEditableColumns::isChanged method for non-string values (e.g. arrays for has_many / many_many relations)

* revert formatting

Co-authored-by: Bumbus <sf@arillo.ch>
2022-08-01 13:22:09 +12:00
Guy Sartorelli acacac2563
Merge pull request #329 from creative-commoners/pulls/3/default-sort-unit-test
MNT Add unit tests for default sort
2022-08-01 11:25:29 +12:00
Steve Boyd dc99a8e04d Merge branch '3.4' into 3 2022-07-25 11:51:34 +12:00
Steve Boyd 7f90426987 Merge branch '3.3' into 3.4 2022-07-25 11:51:30 +12:00
Guy Sartorelli c6dfea0598
Merge pull request #345 from creative-commoners/pulls/3.3/module-standards
MNT Use GitHub Actions CI
2022-07-15 13:59:06 +12:00
Steve Boyd cfc764e3b5 MNT Use GitHub Actions CI 2022-07-15 13:57:33 +12:00
Steve Boyd 1574be36db Merge branch '3.4' into 3 2022-06-16 13:37:02 +12:00
Steve Boyd 0405d919fc
Merge pull request #341 from silverstripeltd/pull/performance-fixes
ENH: Add performance fixes on saving editable columns
2022-06-16 13:35:24 +12:00
Mo Alsharaf 547ec8aa50 ENH: Add performance fixes on saving editable columns
- Use one query to fetch all items needed to be saved.
- Only save items that are changed.
2022-06-16 13:02:16 +12:00
Steve Boyd 71d60b0734
Merge pull request #338 from creative-commoners/pulls/3/php81
ENH PHP 8.1 compatibility
2022-04-22 16:48:56 +12:00
Steve Boyd 93e4379c3d ENH PHP 8.1 compatibility 2022-04-13 17:44:44 +12:00
Guy Sartorelli ec93c994f8
NEW Extend new AbstractGridFieldComponent class (#332)
This makes this module's `GridFieldComponent` classes `Injectable`, and allows any future enhancements in the new abstract class to automatically apply without requiring additional changes in this module.

The class is introduced in silverstripe/framework 4.11.0 so the dependency constraint needs to be updated.

Also update docs to encourage use of dependency injection.
2022-03-04 10:12:24 +13:00
Guy Sartorelli 8c4e924bfa
ENH: Prefer dependency injection over use of `new` keyword. (#333)
* ENH: Prefer dependency injection over use of `new` keyword.

* MNT Fix phpcs linting error.
2022-02-18 16:44:54 +13:00
josephlewisnz 2928504b3c removed param 2022-02-18 08:39:59 +13:00
josephlewisnz 8e77095de0 updated to create syntax 2022-02-17 13:10:44 +13:00
josephlewisnz 07c97e45b2 Added the ability to autopublish items that are already live 2022-02-17 12:53:13 +13:00
Daniel Hensby 8e9ee0bace
Merge pull request #330 from creative-commoners/pulls/3/php74
DEP Set PHP 7.4 as the minimum version
2022-02-10 11:36:30 +00:00
Steve Boyd 78da0c31fe DEP Set PHP 7.4 as the minimum version 2022-02-10 17:59:26 +13:00
Steve Boyd 607a9bcdf9 MNT Add unit tests for default sort 2022-02-02 15:36:25 +13:00
David Toews 6d6cf4a225
ENH applies default sort order to CMS ordering (#325)
* (cms interface) applies default sort order to CMS ordering

This allows secondary sort ordering to be applied when it exists and when the objects have not been sorted manually

* (sort logic) adds additional checks for non DataList or unsorted cases

* Update src/GridFieldOrderableRows.php

Co-authored-by: Michal Kleiner <mk@011.nz>

Co-authored-by: Michal Kleiner <mk@011.nz>
2022-02-02 15:29:57 +13:00
Maxime Rainville baa6a8d147
Merge pull request #327 from creative-commoners/pulls/3/sapphire-test-nine
API phpunit 9 support
2021-11-09 13:14:44 +13:00
Steve Boyd 5e3037bd2f API phpunit 9 support 2021-11-09 11:43:41 +13:00
Steve Boyd b52fd75f0e
Update README.md 2021-06-18 14:03:25 +12:00
Marcus 7738a0b89b
Merge pull request #319 from ntd/inline-row-with-defaults
FIX: use default values in new inline rows (#64)
2021-05-13 10:11:36 +10:00
Marcus 719c0ed547
Merge pull request #302 from lpostiglione/patch-1
Fix support for dot notation in GridFieldOrderableRows
2021-05-13 10:09:52 +10:00
Nicola Fontana 3d4986432c FIX: use default values in new inline rows (#64) 2021-03-24 20:32:02 +01:00
Steve Boyd 74126ed6a7 Merge branch '3.2' into 3 2021-03-20 14:14:24 +13:00
Steve Boyd 6ee8d6ccb2
Merge pull request #316 from chromos33/patch-1
Update index.md
2021-03-19 12:30:45 +13:00
Serge Latyntsev acd1a37122
Merge pull request #318 from creative-commoners/pulls/3.2/travis-shared
MNT Travis shared config
2021-02-11 16:57:59 +13:00
Steve Boyd 700e5adf53 MNT Travis shared config 2021-01-20 14:52:20 +13:00
chromos33 d6357ec187
Update index.md
Updated doc to use "::class" instead of Literals to reflect SS4 changes
2020-12-23 11:26:38 +01:00
Robbie Averill 3a9fd3c928
Merge pull request #314 from sminnee/pulls/312-fix-editable-readonly
FIX: Fixed handling of uneditable records in GridFieldEditableColumns
2020-09-10 14:08:29 -07:00
Sam Minnee 6becfc2f89 NEW: Add test for GridFieldEditableColumns
Also adds a .gitignore to ignore files created by in-module testing.
2020-09-08 14:57:59 +12:00
Sam Minnee 229a23a2f4 FIX: Transfrom editable columns to readonly on a readonly gridfield also. 2020-09-08 14:57:59 +12:00
Sam Minnee 08f89ea4b5 FIX: Fixed handling of uneditable records in GridFieldEditableColumns
Fixes #312
2020-08-07 12:30:21 +12:00
Garion Herman c77d9d1de3
Merge pull request #313 from creative-commoners/pulls/3.2/column-content-fallback
FIX Reinstate previous field fetch logic as fallback
2020-07-30 16:46:06 +12:00
Garion Herman 4105d6330f FIX Reinstate previous field fetch logic as fallback
Fixes some cases where a field is not retrievable via dataFieldByName()
2020-07-30 10:54:53 +12:00
Marcus d671788b19
Merge pull request #301 from oilee80/3
Add Multi Class to inline add button
2020-06-17 16:44:15 +10:00
Marcus 2fc085bbd0
Merge pull request #294 from sminnee/allow-inline-dot-syntax
FIX: Let GridFieldEditableColumns edit relations via dot syntax
2020-06-17 16:42:26 +10:00
Nathan 306ad52a28
Merge pull request #310 from symbiote/nglasl-patch-1
PHP 7.4
2020-06-10 11:38:10 +10:00
Nathan 3aaf4479ce PHP 7.4 2020-06-10 11:31:21 +10:00
Steve Boyd 5024b93f1d
Merge pull request #306 from sunnysideup/patch-1
MINOR: better composer keywords
2020-06-02 13:25:05 +12:00
Nicolaas f8439f1b67
MINOR: better composer keywords 2020-05-29 12:47:16 +12:00
Serge Latyntsev 66d5e043ed
Merge pull request #296 from chrometoasters/manymanythrough_ploymorphic_support
FIX to make GridFieldOrderableRows support polymorphic ManyManyThroughList
2020-05-18 15:38:49 +12:00
Michal Kleiner 9944b67632 FIX GridFieldOrderableRows to support polymorphic ManyManyThroughList 2020-05-18 15:33:43 +12:00
Luca Postiglione 4d94b2748d
Added support for dot notation in GridField name
When you want to have a GridField for a sub-relation on a relation of your DataObject you use dot notation, this breaks the functionality of GridFieldOrderableRows because in the POST request the dot is replaced by an underscore.
2020-01-29 12:57:30 +01:00
Lee Bradley 4afe5dcfd3 Tweaks to pass tests 2019-12-12 16:18:09 +00:00
Lee Bradley 04c42273cf Add Multi Class to inline add button
Raised in Issue #300
2019-12-12 16:10:11 +00:00
Garion Herman 8e37021317
Merge pull request #299 from creative-commoners/pulls/3/travis-ci
Travis config update
2019-11-25 17:10:34 +13:00
Serge Latyntcev a710c81941 Travis config update 2019-11-25 16:58:44 +13:00
Serge Latyntcev d0cf736174 Travis config update 2019-11-25 16:48:52 +13:00
Serge Latyntcev 0dc0c5614d Merge branch '3.2' into 3 2019-11-25 16:02:34 +13:00
Sam Minnee 0b37e97b42 FIX: Fix insertion of new records in many-many-through list.
This change is specially important when using dot-syntax fieldnames to
access the join record of a many-many-through.
2019-08-26 18:11:36 +12:00
Sam Minnee d357479421 FIX: Let GridFieldEditableColumns edit relations via dot syntax
This is a companion to https://github.com/silverstripe/silverstripe-framework/pull/9192 to provide the same functionality for inline
editing in GridFields

A valuable use of this is editing fields in the join-object of
a many-many-through relation.
2019-08-26 12:37:19 +12:00
Robbie Averill a88ac60033
Update branch alias for 3.3.x-dev 2018-09-28 17:34:58 +02:00
74 changed files with 1381 additions and 218 deletions

1
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1 @@
<!-- Blank templates are for use by maintainers only! If you aren't a maintainer, please go back and pick one of the issue templates. -->

72
.github/ISSUE_TEMPLATE/1_bug_report.yml vendored Normal file
View File

@ -0,0 +1,72 @@
name: 🪳 Bug Report
description: Tell us if something isn't working the way it's supposed to
body:
- type: markdown
attributes:
value: |
We strongly encourage you to [submit a pull request](https://docs.silverstripe.org/en/contributing/code/) which fixes the issue.
Bug reports which are accompanied with a pull request are a lot more likely to be resolved quickly.
- type: input
id: affected-versions
attributes:
label: Module version(s) affected
description: |
What version of _this module_ have you reproduced this bug on?
Run `composer info` to see the specific version of each module installed in your project.
If you don't have access to that, check inside the help menu in the bottom left of the CMS.
placeholder: x.y.z
validations:
required: true
- type: textarea
id: description
attributes:
label: Description
description: A clear and concise description of the problem
validations:
required: true
- type: textarea
id: how-to-reproduce
attributes:
label: How to reproduce
description: |
⚠️ This is the most important part of the report ⚠️
Without a way to easily reproduce your issue, there is little chance we will be able to help you and work on a fix.
- Please, take the time to show us some code and/or configuration that is needed for others to reproduce the problem easily.
- If the bug is too complex to reproduce with some short code samples, please reproduce it in a public repository and provide a link to the repository along with steps for setting up and reproducing the bug using that repository.
- If part of the bug includes an error or exception, please provide a full stack trace.
- If any user interaction is required to reproduce the bug, please add an ordered list of steps that are required to reproduce it.
- Be as clear as you can, but don't miss any steps out. Simply saying "create a page" is less useful than guiding us through the steps you're taking to create a page, for example.
placeholder: |
#### Code sample
```php
```
#### Reproduction steps
1.
validations:
required: true
- type: textarea
id: possible-solution
attributes:
label: Possible Solution
description: |
*Optional: only if you have suggestions on a fix/reason for the bug*
Please consider [submitting a pull request](https://docs.silverstripe.org/en/contributing/code/) with your solution! It helps get faster feedback and greatly increases the chance of the bug being fixed.
- type: textarea
id: additional-context
attributes:
label: Additional Context
description: "*Optional: any other context about the problem: log messages, screenshots, etc.*"
- type: checkboxes
id: validations
attributes:
label: Validations
description: "Before submitting the issue, please make sure you do the following:"
options:
- label: Check that there isn't already an issue that reports the same bug
required: true
- label: Double check that your reproduction steps work in a fresh installation of [`silverstripe/installer`](https://github.com/silverstripe/silverstripe-installer) (with any code examples you've provided)
required: true

View File

@ -0,0 +1,35 @@
name: 🚀 Feature Request
description: Submit a feature request (but only if you're planning on implementing it)
body:
- type: markdown
attributes:
value: |
Please only submit feature requests if you plan on implementing the feature yourself.
See the [contributing code documentation](https://docs.silverstripe.org/en/contributing/code/#make-or-find-a-github-issue) for more guidelines about submitting feature requests.
- type: textarea
id: description
attributes:
label: Description
description: A clear and concise description of the new feature, and why it belongs in core
validations:
required: true
- type: textarea
id: more-info
attributes:
label: Additional context or points of discussion
description: |
*Optional: Any additional context, points of discussion, etc that might help validate and refine your idea*
- type: checkboxes
id: validations
attributes:
label: Validations
description: "Before submitting the issue, please confirm the following:"
options:
- label: You intend to implement the feature yourself
required: true
- label: You have read the [contributing guide](https://docs.silverstripe.org/en/contributing/code/)
required: true
- label: You strongly believe this feature should be in core, rather than being its own community module
required: true
- label: You have checked for existing issues or pull requests related to this feature (and didn't find any)
required: true

8
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@ -0,0 +1,8 @@
blank_issues_enabled: true
contact_links:
- name: Security Vulnerability
url: https://docs.silverstripe.org/en/contributing/issues_and_bugs/#reporting-security-issues
about: ⚠️ We do not use GitHub issues to track security vulnerability reports. Click "open" on the right to see how to report security vulnerabilities.
- name: Support Question
url: https://www.silverstripe.org/community/
about: We use GitHub issues only to discuss bugs and new features. For support questions, please use one of the support options available in our community channels.

39
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,39 @@
<!--
Thanks for contributing, you're awesome! ⭐
Please read https://docs.silverstripe.org/en/contributing/code/ if you haven't contributed to this project recently.
-->
## Description
<!--
Please describe expected and observed behaviour, and what you're fixing.
For visual fixes, please include tested browsers and screenshots.
-->
## Manual testing steps
<!--
Include any manual testing steps here which a reviewer can perform to validate your pull request works correctly.
Note that this DOES NOT replace unit or end-to-end tests.
-->
## Issues
<!--
List all issues here that this pull request fixes/resolves.
If there is no issue already, create a new one! You must link your pull request to at least one issue.
-->
- #
## Pull request checklist
<!--
PLEASE check each of these to ensure you have done everything you need to do!
If there's something in this list you need help with, please ask so that we can assist you.
-->
- [ ] The target branch is correct
- See [picking the right version](https://docs.silverstripe.org/en/contributing/code/#picking-the-right-version)
- [ ] All commits are relevant to the purpose of the PR (e.g. no debug statements, unrelated refactoring, or arbitrary linting)
- Small amounts of additional linting are usually okay, but if it makes it hard to concentrate on the relevant changes, ask for the unrelated changes to be reverted, and submitted as a separate PR.
- [ ] The commit messages follow our [commit message guidelines](https://docs.silverstripe.org/en/contributing/code/#commit-messages)
- [ ] The PR follows our [contribution guidelines](https://docs.silverstripe.org/en/contributing/code/)
- [ ] Code changes follow our [coding conventions](https://docs.silverstripe.org/en/contributing/coding_conventions/)
- [ ] This change is covered with tests (or tests aren't necessary for this change)
- [ ] Any relevant User Help/Developer documentation is updated; for impactful changes, information is added to the changelog for the intended release
- [ ] CI is green

11
.github/workflows/ci.yml vendored Normal file
View File

@ -0,0 +1,11 @@
name: CI
on:
push:
pull_request:
workflow_dispatch:
jobs:
ci:
name: CI
uses: silverstripe/gha-ci/.github/workflows/ci.yml@v1

21
.github/workflows/dispatch-ci.yml vendored Normal file
View File

@ -0,0 +1,21 @@
name: Dispatch CI
on:
# At 8:40 PM UTC, only on Sunday and Monday
schedule:
- cron: '40 20 * * 0,1'
permissions: {}
jobs:
dispatch-ci:
name: Dispatch CI
# Only run cron on the symbiote account
if: (github.event_name == 'schedule' && github.repository_owner == 'symbiote') || (github.event_name != 'schedule')
runs-on: ubuntu-latest
permissions:
contents: read
actions: write
steps:
- name: Dispatch CI
uses: silverstripe/gha-dispatch-ci@v1

17
.github/workflows/keepalive.yml vendored Normal file
View File

@ -0,0 +1,17 @@
name: Keepalive
on:
workflow_dispatch:
# The 7th of every month at 12:50pm UTC
schedule:
- cron: '50 12 7 * *'
jobs:
keepalive:
name: Keepalive
# Only run cron on the symbiote account
if: (github.event_name == 'schedule' && github.repository_owner == 'symbiote') || (github.event_name != 'schedule')
runs-on: ubuntu-latest
steps:
- name: Keepalive
uses: silverstripe/gha-keepalive@v1

22
.github/workflows/merge-up.yml vendored Normal file
View File

@ -0,0 +1,22 @@
name: Merge-up
on:
# At 8:40 PM UTC, only on Thursday
schedule:
- cron: '40 20 * * 4'
workflow_dispatch:
permissions: {}
jobs:
merge-up:
name: Merge-up
# Only run cron on the symbiote account
if: (github.event_name == 'schedule' && github.repository_owner == 'symbiote') || (github.event_name != 'schedule')
runs-on: ubuntu-latest
permissions:
contents: write
actions: write
steps:
- name: Merge-up
uses: silverstripe/gha-merge-up@v1

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
vendor/
resources/
composer.lock
assets/

View File

@ -1,31 +0,0 @@
language: php
matrix:
include:
- php: 5.6
env: DB=MYSQL RECIPE_VERSION=1.0.x-dev PHPCS_TEST=1 PHPUNIT_TEST=1
- php: 7.0
env: DB=MYSQL RECIPE_VERSION=1.1.x-dev PHPUNIT_TEST=1
- php: 7.1
env: DB=PGSQL RECIPE_VERSION=4.2.x-dev PHPUNIT_COVERAGE_TEST=1
- php: 7.2
env: DB=MYSQL RECIPE_VERSION=4.3.x-dev PHPUNIT_TEST=1
- php: 7.3
env: DB=MYSQL RECIPE_VERSION=4.x-dev PHPUNIT_TEST=1
before_script:
- phpenv rehash
- phpenv config-rm xdebug.ini
- composer validate
- composer require silverstripe/recipe-cms:"$RECIPE_VERSION" --no-update
- if [[ $DB == PGSQL ]]; then composer require silverstripe/postgresql:2.1.x-dev --no-update; fi
- composer install --prefer-dist --no-interaction --no-progress --no-suggest --optimize-autoloader --verbose --profile
script:
- if [[ $PHPUNIT_TEST ]]; then vendor/bin/phpunit tests/; fi
- if [[ $PHPUNIT_COVERAGE_TEST ]]; then phpdbg -qrr vendor/bin/phpunit --coverage-clover=coverage.xml; fi
- if [[ $PHPCS_TEST ]]; then vendor/bin/phpcs src/ tests/ *.php; fi
after_success:
- if [[ $PHPUNIT_COVERAGE_TEST ]]; then bash <(curl -s https://codecov.io/bash) -f coverage.xml; fi

15
.tx/config Normal file
View File

@ -0,0 +1,15 @@
[main]
host = https://www.transifex.com
[o:silverstripe:p:silverstripe-gridfieldextensions:r:master]
file_filter = lang/<lang>.yml
source_file = lang/en.yml
source_lang = en
type = YML
[o:silverstripe:p:silverstripe-gridfieldextensions:r:master-js]
file_filter = client/lang/src/<lang>.json
source_file = client/lang/src/en.json
source_lang = en
type = KEYVALUEJSON

View File

@ -1,11 +1,7 @@
# SilverStripe Grid Field Extensions Module
# Silverstripe Grid Field Extensions Module
[![Build Status](https://travis-ci.org/symbiote/silverstripe-gridfieldextensions.svg?branch=master)](https://travis-ci.org/symbiote/silverstripe-gridfieldextensions)
[![SilverStripe supported module](https://img.shields.io/badge/silverstripe-supported-0071C4.svg)](https://www.silverstripe.org/software/addons/silverstripe-commercially-supported-module-list/)
[![Latest Stable Version](https://poser.pugx.org/symbiote/silverstripe-gridfieldextensions/version.svg)](https://github.com/symbiote/silverstripe-gridfieldextensions/releases)
[![Latest Unstable Version](https://poser.pugx.org/symbiote/silverstripe-gridfieldextensions/v/unstable.svg)](https://packagist.org/packages/symbiote/silverstripe-gridfieldextensions)
[![Total Downloads](https://poser.pugx.org/symbiote/silverstripe-gridfieldextensions/downloads.svg)](https://packagist.org/packages/symbiote/silverstripe-gridfieldextensions)
[![License](https://poser.pugx.org/symbiote/silverstripe-gridfieldextensions/license.svg)](https://github.com/symbiote/silverstripe-gridfieldextensions/blob/master/LICENSE.md)
[![CI](https://github.com/symbiote/silverstripe-gridfieldextensions/actions/workflows/ci.yml/badge.svg)](https://github.com/symbiote/silverstripe-gridfieldextensions/actions/workflows/ci.yml)
[![Silverstripe supported module](https://img.shields.io/badge/silverstripe-supported-0071C4.svg)](https://www.silverstripe.org/software/addons/silverstripe-commercially-supported-module-list/)
This module provides a number of useful grid field components:
@ -23,14 +19,13 @@ This module provides a number of useful grid field components:
* `GridFieldTitleHeader` - a simple header which displays column titles.
* `GridFieldConfigurablePaginator` - a paginator for GridField that allows customisable page sizes.
This branch will aim for compatibility with SilverStripe 4.x.
This branch will aim for compatibility with Silverstripe 4.x.
## Installation
```bash
composer require symbiote/silverstripe-gridfieldextensions "^3"
composer require symbiote/silverstripe-gridfieldextensions:^3
```
For SilverStripe 3.x, please see the [compatible branch](https://github.com/symbiote/silverstripe-gridfieldextensions/tree/2).
For Silverstripe 3.x, please see the [compatible branch](https://github.com/symbiote/silverstripe-gridfieldextensions/tree/2).
See [docs/en/index.md](docs/en/index.md) for documentation and examples.

View File

@ -2,4 +2,8 @@
name: gridfieldextensions
---
GridFieldAddNewMultiClass:
showEmptyString: true
showEmptyString: true
SilverStripe\Forms\GridField\GridFieldDetailForm_ItemRequest:
extensions:
- Symbiote\GridFieldExtensions\Extensions\GridFieldDetailFormItemRequestExtension

14
client/lang/en.js Normal file
View File

@ -0,0 +1,14 @@
// This file was generated by silverstripe/tx-translator from client/lang/src/en.json.
// See https://github.com/silverstripe/silverstripe-tx-translator for details
if (typeof(ss) === 'undefined' || typeof(ss.i18n) === 'undefined') {
if (typeof(console) !== 'undefined') { // eslint-disable-line no-console
console.error('Class ss.i18n not defined'); // eslint-disable-line no-console
}
} else {
ss.i18n.addDictionary('en', {
"GridFieldExtensions.ADD_CLASS": "Add: <i>{classname}</i>",
"GridFieldExtensions.CONFIRMDEL": "Are you sure you want to delete this?",
"GridFieldExtensions.OPEN_SEARCH_FILTER": "Open search and filter",
"GridFieldExtensions.SAVE_PUBLISH": "Save & publish"
});
}

14
client/lang/eo.js Normal file
View File

@ -0,0 +1,14 @@
// This file was generated by silverstripe/tx-translator from client/lang/src/eo.json.
// See https://github.com/silverstripe/silverstripe-tx-translator for details
if (typeof(ss) === 'undefined' || typeof(ss.i18n) === 'undefined') {
if (typeof(console) !== 'undefined') { // eslint-disable-line no-console
console.error('Class ss.i18n not defined'); // eslint-disable-line no-console
}
} else {
ss.i18n.addDictionary('eo', {
"GridFieldExtensions.ADD_CLASS": "Aldoni: <i>{classname}</i>",
"GridFieldExtensions.CONFIRMDEL": "Ĉu vi certas ke vi volas forigi tion?",
"GridFieldExtensions.OPEN_SEARCH_FILTER": "Malfermi serĉon kaj filtrilon",
"GridFieldExtensions.SAVE_PUBLISH": "Konservi kaj publikigi"
});
}

14
client/lang/nl_NL.js Normal file
View File

@ -0,0 +1,14 @@
// This file was generated by silverstripe/tx-translator from client/lang/src/nl_NL.json.
// See https://github.com/silverstripe/silverstripe-tx-translator for details
if (typeof(ss) === 'undefined' || typeof(ss.i18n) === 'undefined') {
if (typeof(console) !== 'undefined') { // eslint-disable-line no-console
console.error('Class ss.i18n not defined'); // eslint-disable-line no-console
}
} else {
ss.i18n.addDictionary('nl_NL', {
"GridFieldExtensions.ADD_CLASS": "Toevoegen: <i>{classname}</i>",
"GridFieldExtensions.CONFIRMDEL": "Weet je zeker dat je dit wil verwijderen?",
"GridFieldExtensions.OPEN_SEARCH_FILTER": "Open zoeken en filteren",
"GridFieldExtensions.SAVE_PUBLISH": "Opslaan & Publiceren"
});
}

14
client/lang/sk.js Normal file
View File

@ -0,0 +1,14 @@
// This file was generated by silverstripe/tx-translator from client/lang/src/sk.json.
// See https://github.com/silverstripe/silverstripe-tx-translator for details
if (typeof(ss) === 'undefined' || typeof(ss.i18n) === 'undefined') {
if (typeof(console) !== 'undefined') { // eslint-disable-line no-console
console.error('Class ss.i18n not defined'); // eslint-disable-line no-console
}
} else {
ss.i18n.addDictionary('sk', {
"GridFieldExtensions.ADD_CLASS": "Pridať: <i>{classname}</i>",
"GridFieldExtensions.CONFIRMDEL": "Naozaj to chcete odstrániť?",
"GridFieldExtensions.OPEN_SEARCH_FILTER": "Otvorte vyhľadávanie a filter",
"GridFieldExtensions.SAVE_PUBLISH": "Uložiť a zverejniť"
});
}

14
client/lang/sl.js Normal file
View File

@ -0,0 +1,14 @@
// This file was generated by silverstripe/tx-translator from client/lang/src/sl.json.
// See https://github.com/silverstripe/silverstripe-tx-translator for details
if (typeof(ss) === 'undefined' || typeof(ss.i18n) === 'undefined') {
if (typeof(console) !== 'undefined') { // eslint-disable-line no-console
console.error('Class ss.i18n not defined'); // eslint-disable-line no-console
}
} else {
ss.i18n.addDictionary('sl', {
"GridFieldExtensions.ADD_CLASS": "Dodaj: <i>{classname}</i>",
"GridFieldExtensions.CONFIRMDEL": "Res želite to izbrisati?",
"GridFieldExtensions.OPEN_SEARCH_FILTER": "Prikaži iskalnik in filtre",
"GridFieldExtensions.SAVE_PUBLISH": "Shrani in objavi"
});
}

6
client/lang/src/en.json Normal file
View File

@ -0,0 +1,6 @@
{
"GridFieldExtensions.ADD_CLASS": "Add: <i>{classname}</i>",
"GridFieldExtensions.CONFIRMDEL": "Are you sure you want to delete this?",
"GridFieldExtensions.OPEN_SEARCH_FILTER": "Open search and filter",
"GridFieldExtensions.SAVE_PUBLISH": "Save & publish"
}

6
client/lang/src/eo.json Normal file
View File

@ -0,0 +1,6 @@
{
"GridFieldExtensions.ADD_CLASS": "Aldoni: <i>{classname}</i>",
"GridFieldExtensions.CONFIRMDEL": "Ĉu vi certas ke vi volas forigi tion?",
"GridFieldExtensions.OPEN_SEARCH_FILTER": "Malfermi serĉon kaj filtrilon",
"GridFieldExtensions.SAVE_PUBLISH": "Konservi kaj publikigi"
}

View File

@ -0,0 +1,6 @@
{
"GridFieldExtensions.ADD_CLASS": "Toevoegen: <i>{classname}</i>",
"GridFieldExtensions.CONFIRMDEL": "Weet je zeker dat je dit wil verwijderen?",
"GridFieldExtensions.OPEN_SEARCH_FILTER": "Open zoeken en filteren",
"GridFieldExtensions.SAVE_PUBLISH": "Opslaan & Publiceren"
}

6
client/lang/src/sk.json Normal file
View File

@ -0,0 +1,6 @@
{
"GridFieldExtensions.ADD_CLASS": "Pridať: <i>{classname}</i>",
"GridFieldExtensions.CONFIRMDEL": "Naozaj to chcete odstrániť?",
"GridFieldExtensions.OPEN_SEARCH_FILTER": "Otvorte vyhľadávanie a filter",
"GridFieldExtensions.SAVE_PUBLISH": "Uložiť a zverejniť"
}

6
client/lang/src/sl.json Normal file
View File

@ -0,0 +1,6 @@
{
"GridFieldExtensions.ADD_CLASS": "Dodaj: <i>{classname}</i>",
"GridFieldExtensions.CONFIRMDEL": "Res želite to izbrisati?",
"GridFieldExtensions.OPEN_SEARCH_FILTER": "Prikaži iskalnik in filtre",
"GridFieldExtensions.SAVE_PUBLISH": "Shrani in objavi"
}

View File

@ -3,7 +3,7 @@
"description": "A collection of useful grid field components",
"type": "silverstripe-vendormodule",
"homepage": "http://github.com/symbiote/silverstripe-gridfieldextensions",
"keywords": ["silverstripe", "gridfield"],
"keywords": ["silverstripe", "gridfield", "sortable", "sort", "sort field"],
"license": "BSD-3-Clause",
"authors": [
{
@ -19,11 +19,12 @@
"issues": "http://github.com/symbiote/silverstripe-gridfieldextensions/issues"
},
"require": {
"php": "^7.4 || ^8.0",
"silverstripe/vendor-plugin": "^1.0",
"silverstripe/framework": "~4.0"
"silverstripe/framework": "^4.11"
},
"require-dev": {
"phpunit/phpunit": "^5.7",
"phpunit/phpunit": "^9.5",
"squizlabs/php_codesniffer": "^3.0",
"silverstripe/versioned": "^1"
},
@ -34,7 +35,8 @@
],
"expose": [
"css",
"javascript"
"javascript",
"client/lang"
]
},
"replace": {

View File

@ -201,3 +201,25 @@
.ss-gridfield-configurable-paginator .pagination-page-number input {
text-align: center;
}
.grid-field-inline-new--multi-class-list {
display: none;
background-color: #008a00;
border-radius: 5px;
bottom: 3em;
list-style: none;
margin: 0;
right: 3em;
padding: 10px;
position: fixed;
}
.grid-field-inline-new--multi-class-list a {
color: #FFF !important;
display: block;
margin: 5px -10px;
padding: 0 10px;
}
.grid-field-inline-new--multi-class-list__visible {
display: block;
}

View File

@ -9,7 +9,7 @@ existing records than a basic autocomplete. It uses the search context construct
class to provide the search form.
```php
$grid->getConfig()->addComponent(new GridFieldAddExistingSearchButton());
$grid->getConfig()->addComponent(GridFieldAddExistingSearchButton::create());
```
Inline Editing
@ -19,17 +19,17 @@ This example replaces the default data columns component with an inline editable
default add new button with one that adds new records inline.
```php
$grid = new GridField(
$grid = GridField::create(
'ExampleGrid',
'Example Grid',
$this->Items(),
GridFieldConfig::create()
->addComponent(new GridFieldButtonRow('before'))
->addComponent(new GridFieldToolbarHeader())
->addComponent(new GridFieldTitleHeader())
->addComponent(new GridFieldEditableColumns())
->addComponent(new GridFieldDeleteAction())
->addComponent(new GridFieldAddNewInlineButton())
->addComponent(GridFieldButtonRow::create('before'))
->addComponent(GridFieldToolbarHeader::create())
->addComponent(GridFieldTitleHeader::create())
->addComponent(GridFieldEditableColumns::create())
->addComponent(GridFieldDeleteAction::create())
->addComponent(GridFieldAddNewInlineButton::create())
);
```
@ -37,13 +37,13 @@ You can customise the form fields that are used in the grid by calling `setDispl
inline editing component. By default field scaffolding will be used.
```php
$grid->getConfig()->getComponentByType('GridFieldEditableColumns')->setDisplayFields(array(
$grid->getConfig()->getComponentByType(GridFieldEditableColumns::class)->setDisplayFields(array(
'FirstField' => function($record, $column, $grid) {
return new TextField($column);
return TextField::create($column);
},
'SecondField' => array(
'title' => 'Custom Title',
'field' => 'ReadonlyField'
'field' => ReadonlyField::class
),
'ThirdField' => array(
'title' => 'Custom Title Two',
@ -69,7 +69,7 @@ use SilverStripe\Forms\GridField\GridFieldAddNewButton;
$grid->getConfig()
->removeComponentsByType(GridFieldAddNewButton::class)
->addComponent(new GridFieldAddNewMultiClass());
->addComponent(GridFieldAddNewMultiClass::create());
```
Orderable Rows
@ -82,10 +82,10 @@ the relationship.
```php
// Basic usage, defaults to "Sort" for the sort field.
$grid->getConfig()->addComponent(new GridFieldOrderableRows());
$grid->getConfig()->addComponent(GridFieldOrderableRows::create());
// Specifying the sort field.
$grid->getConfig()->addComponent(new GridFieldOrderableRows('SortField'));
$grid->getConfig()->addComponent(GridFieldOrderableRows::create('SortField'));
```
By default, when you create a new item, it is created with a sort order of "0" - that is, it is added
@ -106,6 +106,17 @@ class Item extends DataObject {
}
```
### Versioning
By default `GridFieldOrderableRows` will handle versioning but won't automatically publish any records. The user will need to go into each record and publish them manually which could get cumbersome for large lists.
You can configure the list to automatically publish a record if the record is the latest version and is already published. This won't publish any records which have draft changes.
```php
$orderable = GridFieldOrderableRows::create()->setRepublishLiveRecords(true);
```
There are caveats with both approaches so consideration should be made for which approach best suits the requirements.
**Please NOTE:** There is a limitation when using `GridFieldOrderableRows` on unsaved data objects; namely, that it doesn't work as without data being saved, the list of related objects has no context. Please check `$this->ID` before adding the `GridFieldOrderableRows` component to the grid field config (or even, before adding the gridfield at all).
Configurable Paginator
@ -118,7 +129,7 @@ To use this component you should remove the original paginator component first:
```php
$gridField->getConfig()
->removeComponentsByType('GridFieldPaginator')
->addComponent(new GridFieldConfigurablePaginator());
->addComponent(GridFieldConfigurablePaginator::create());
```
You can configure the page sizes with the configuration system. Note that merging is the default strategy, so to replace
@ -133,7 +144,7 @@ Config::inst()->update('GridFieldConfigurablePaginator', 'default_page_sizes', a
You can also override these at call time:
```php
$paginator = new GridFieldConfigurablePaginator(100, array(100, 200, 500));
$paginator = GridFieldConfigurablePaginator::create(100, array(100, 200, 500));
$paginator->setPageSizes(array(200, 500, 1000));
$paginator->setItemsPerPage(500);

View File

@ -237,6 +237,28 @@
}
});
$(".action--new__multi-class").entwine({
onmatch: function () {
const hrefTemplate = this.data('hrefTemplate');
const classes = this.data('classes');
const liHtml = Object.keys(classes).map(className => {
const link = hrefTemplate.replace('{class}', className);
const linkText = ss.i18n.inject(
ss.i18n._t('GridFieldExtensions.ADD_CLASS', 'Add: <i>{classname}</i>'),
{classname: classes[className]}
);
return `<li><a href="${link}">${linkText}</a></li>`;
});
const listElement = $(`<ul class="grid-field-inline-new--multi-class-list">${liHtml.join('')}</ul>`);
listElement.insertBefore(this);
this.on('click', function () {
listElement.toggleClass('grid-field-inline-new--multi-class-list__visible');
});
},
});
$(".ss-gridfield-add-new-multi-class select").entwine({
onadd: function() {
this.update();
@ -318,7 +340,8 @@
content = '<span class="non-sortable"></span>';
self.addClass('show-filter').find('.grid-field__filter-header').show();
} else {
content = '<button type="button" title="Open search and filter" name="showFilter" class="btn btn-secondary font-icon-search btn--no-text btn--icon-large grid-field__filter-open"></button>';
const contentTitle = ss.i18n._t('GridFieldExtensions.OPEN_SEARCH_FILTER', 'Open search and filter');
content = `<button type="button" title="${contentTitle}" name="showFilter" class="btn btn-secondary font-icon-search btn--no-text btn--icon-large grid-field__filter-open"></button>`;
self.removeClass('show-filter').find('.grid-field__filter-header').hide();
}
@ -346,7 +369,7 @@
publish.removeClass('font-icon-tick');
publish.addClass('btn-primary');
publish.addClass('font-icon-rocket');
publish.find('.btn__title').html('Save & publish');
publish.find('.btn__title').html(ss.i18n._t('GridFieldExtensions.SAVE_PUBLISH', 'Save & publish'));
}
},
error: function (e) {

View File

@ -1,9 +1,9 @@
de_DE:
GridFieldAddExistingSearchHandler.ss:
NOITEMS: 'Kein Ergebnis'
RESULTS: 'Ergebnisse'
RESULTS: Ergebnisse
GridFieldExtensions:
ADD: 'Hinzufügen'
ADD: Hinzufügen
ADDEXISTING: 'Bestehenden Eintrag hinzufügen'
SEARCH: 'Suche'
SEARCH: Suche
SELECTTYPETOCREATE: '(Bitte Typ auswählen)'

View File

@ -10,5 +10,7 @@ en:
RESULTS: Results
SEARCH: Search
SELECTTYPETOCREATE: '(Select type to create)'
Symbiote\GridFieldExtensions\Extensions\GridFieldDetailFormItemRequestExtension:
NEW: 'Add new record'
Symbiote\GridFieldExtensions\GridFieldConfigurablePaginator:
SHOW: Show

16
lang/eo.yml Normal file
View File

@ -0,0 +1,16 @@
eo:
GridFieldExtensions:
ADD: Aldoni
ADDEXISTING: 'Aldoni ekzistantan'
BACK: Antaŭa
CURRENT: (aktuala)
NOITEMS: 'Mankas elementoj'
Next: Sekva
PREVIOUS: Antaŭa
RESULTS: Rezultoj
SEARCH: Serĉi
SELECTTYPETOCREATE: '(Elektu tipon kreotan)'
Symbiote\GridFieldExtensions\Extensions\GridFieldDetailFormItemRequestExtension:
NEW: 'Aldoni novan rikordon'
Symbiote\GridFieldExtensions\GridFieldConfigurablePaginator:
SHOW: Vidigi

View File

@ -1,9 +1,9 @@
es_ES:
GridFieldAddExistingSearchHandler.ss:
NOITEMS: 'No hay items.'
RESULTS: 'Resultados'
RESULTS: Resultados
GridFieldExtensions:
ADD: 'Agregar'
ADD: Agregar
ADDEXISTING: 'Agregar existente'
SEARCH: 'Buscar'
SEARCH: Buscar
SELECTTYPETOCREATE: '(Seleccionar tipo para crear)'

View File

@ -1,7 +1,7 @@
et_EE:
GridFieldAddExistingSearchHandler.ss:
NOITEMS: 'Kirjed puuduvad.'
RESULTS: 'Tulemused'
RESULTS: Tulemused
GridFieldExtensions:
ADD: Lisa
ADDEXISTING: 'Lisa olemasolev'

View File

@ -1,9 +1,9 @@
fi_FI:
GridFieldAddExistingSearchHandler.ss:
NOITEMS: 'Ei kohteita'
RESULTS: 'Tulokset'
RESULTS: Tulokset
GridFieldExtensions:
ADD: 'Lisää'
ADD: Lisää
ADDEXISTING: 'Lisää olemassa oleva'
SEARCH: 'Etsi'
SEARCH: Etsi
SELECTTYPETOCREATE: 'Valitse lisättävä tyyppi'

View File

@ -1,9 +1,9 @@
it_IT:
GridFieldAddExistingSearchHandler.ss:
NOITEMS: 'Nessun elemento.'
RESULTS: 'Risultati'
RESULTS: Risultati
GridFieldExtensions:
ADD: 'Aggiungi'
ADD: Aggiungi
ADDEXISTING: 'Aggiungi esistente'
SEARCH: 'Cerca'
SEARCH: Cerca
SELECTTYPETOCREATE: '(Seleziona tipo per creare)'

View File

@ -1,9 +1,19 @@
nl_NL:
GridFieldAddExistingSearchHandler.ss:
NOITEMS: 'Geen resultaten gevonden.'
RESULTS: 'Resultaten'
RESULTS: Resultaten
GridFieldExtensions:
ADD: 'Toevoegen'
ADD: Toevoegen
ADDEXISTING: 'Bestaande toevoegen'
SEARCH: 'Zoeken'
BACK: Terug
CURRENT: (huidige)
NOITEMS: 'Er zijn geen items.'
Next: Volgende
PREVIOUS: Vorige
RESULTS: Resultaten
SEARCH: Zoeken
SELECTTYPETOCREATE: '(Selecteer type om te creeën)'
Symbiote\GridFieldExtensions\Extensions\GridFieldDetailFormItemRequestExtension:
NEW: 'Nieuw item maken'
Symbiote\GridFieldExtensions\GridFieldConfigurablePaginator:
SHOW: Toon

View File

@ -1,9 +1,9 @@
ru_RU:
GridFieldAddExistingSearchHandler.ss:
NOITEMS: 'Нет элементов.'
RESULTS: 'Результаты'
RESULTS: Результаты
GridFieldExtensions:
ADD: 'Добавить'
ADD: Добавить
ADDEXISTING: 'Добавить существующий'
SEARCH: 'Поиск'
SEARCH: Поиск
SELECTTYPETOCREATE: '(Выберите тип для создания)'

View File

@ -1,9 +1,19 @@
sk:
GridFieldAddExistingSearchHandler.ss:
NOITEMS: 'Nie sú tu žiadne položky.'
RESULTS: 'Výsledky'
RESULTS: Výsledky
GridFieldExtensions:
ADD: Pridať
ADDEXISTING: Pridať existujúci
ADDEXISTING: 'Pridať existujúci'
BACK: Späť
CURRENT: (aktuálny)
NOITEMS: 'Nie sú k dispozícii žiadne položky.'
Next: Ďalší
PREVIOUS: Predchádzajúci
RESULTS: Výsledky
SEARCH: Hľadať
SELECTTYPETOCREATE: '(Prosím, vyberte typ)'
SELECTTYPETOCREATE: '(Vyberte typ na vytvorenie)'
Symbiote\GridFieldExtensions\Extensions\GridFieldDetailFormItemRequestExtension:
NEW: 'Pridať nový záznam'
Symbiote\GridFieldExtensions\GridFieldConfigurablePaginator:
SHOW: Zobraziť

16
lang/sl.yml Normal file
View File

@ -0,0 +1,16 @@
sl:
GridFieldExtensions:
ADD: Dodaj
ADDEXISTING: 'Dodaj obstoječe'
BACK: Nazaj
CURRENT: (trenutno)
NOITEMS: 'Ni nobenih elementov.'
Next: Naslednja
PREVIOUS: Prejšnja
RESULTS: Rezultati
SEARCH: Iskanje
SELECTTYPETOCREATE: '(Izberite tip, ki ga želite ustvariti)'
Symbiote\GridFieldExtensions\Extensions\GridFieldDetailFormItemRequestExtension:
NEW: 'Dodaj zapis'
Symbiote\GridFieldExtensions\GridFieldConfigurablePaginator:
SHOW: Prikaži

16
lang/sv.yml Normal file
View File

@ -0,0 +1,16 @@
sv:
GridFieldExtensions:
ADD: 'Lägg till'
ADDEXISTING: 'Lägg till existerande'
BACK: Tillbaka
CURRENT: (befintliga)
NOITEMS: 'Hittade ingen data.'
Next: Nästa
PREVIOUS: Föregående
RESULTS: Resultat
SEARCH: Sök
SELECTTYPETOCREATE: '(Välj för att skapa)'
Symbiote\GridFieldExtensions\Extensions\GridFieldDetailFormItemRequestExtension:
NEW: 'Lägg till ny rad'
Symbiote\GridFieldExtensions\GridFieldConfigurablePaginator:
SHOW: Visa

View File

@ -2,6 +2,9 @@
<ruleset name="SilverStripe">
<description>CodeSniffer ruleset for SilverStripe coding conventions.</description>
<file>src</file>
<file>tests</file>
<rule ref="PSR2" >
<!-- Current exclusions -->
<exclude name="PSR1.Methods.CamelCapsMethodName" />

View File

@ -1,3 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="vendor/silverstripe/framework/tests/bootstrap.php" colors="true">
<testsuite name="Default">
<directory>tests</directory>

View File

@ -0,0 +1,83 @@
<?php
namespace Symbiote\GridFieldExtensions\Extensions;
use SilverStripe\Control\Controller;
use SilverStripe\Core\Convert;
use SilverStripe\Core\Extension;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\GridField\GridFieldDetailForm_ItemRequest as CoreGridFieldDetailForm_ItemRequest;
use SilverStripe\Forms\LiteralField;
use SilverStripe\View\ArrayData;
use SilverStripe\View\HTML;
use Symbiote\GridFieldExtensions\GridFieldAddNewMultiClass;
use Symbiote\GridFieldExtensions\GridFieldExtensions;
/**
* @property CoreGridFieldDetailForm_ItemRequest $owner
*/
class GridFieldDetailFormItemRequestExtension extends Extension
{
/**
* @param FieldList $actions
*/
public function updateFormActions(FieldList &$actions)
{
$grid = $this->owner->getGridField();
$gridFieldConfig = $grid->getConfig();
$addMultiClassComponent = $gridFieldConfig->getComponentByType(GridFieldAddNewMultiClass::class);
if ($addMultiClassComponent) {
$newRecordField = static::get_new_record_field_from_actions($actions);
if ($newRecordField) {
$newRecordField->getContainerFieldList()->removeByName('new-record');
$newRecordField->getContainerFieldList()->push(
LiteralField::create('new-record', $this->getHTMLFragment($addMultiClassComponent))
);
GridFieldExtensions::include_requirements();
}
}
}
/**
* {@inheritDoc}
*/
private function getHTMLFragment(GridFieldAddNewMultiClass $component)
{
$grid = $this->owner->getGridField();
$classes = $component->getClasses($grid);
if (!count($classes ?? [])) {
return false;
}
return HTML::createTag('a', [
'data-href-template' => Controller::join_links($grid->Link(), 'add-multi-class', '{class}'),
'title' => _t(__CLASS__ . '.NEW', 'Add new record'),
'aria-label' => _t(__CLASS__ . '.NEW', 'Add new record'),
'class' => implode(' ', array(
'btn',
'btn-primary',
'font-icon-plus-thin',
'btn--circular',
'action--new',
'discard-confirmation',
'action--new__multi-class',
)),
'data-classes' => json_encode($classes),
]);
}
/**
* @param FieldList $actions
* @return LiteralField OR NULL
*/
private static function get_new_record_field_from_actions(FieldList &$actions)
{
$rightGroup = $actions->fieldByName('RightGroup');
if (!$rightGroup) {
return null;
}
return $rightGroup->getChildren()->fieldByName('new-record');
}
}

View File

@ -2,6 +2,7 @@
namespace Symbiote\GridFieldExtensions;
use SilverStripe\Forms\GridField\AbstractGridFieldComponent;
use SilverStripe\Forms\GridField\GridField_HTMLProvider;
use SilverStripe\Forms\GridField\GridField_URLHandler;
use SilverStripe\ORM\SS_List;
@ -11,7 +12,9 @@ use SilverStripe\View\ArrayData;
* A modal search dialog which uses search context to search for and add
* existing records to a grid field.
*/
class GridFieldAddExistingSearchButton implements GridField_HTMLProvider, GridField_URLHandler
class GridFieldAddExistingSearchButton extends AbstractGridFieldComponent implements
GridField_HTMLProvider,
GridField_URLHandler
{
private static $allowed_actions = array(
@ -111,6 +114,6 @@ class GridFieldAddExistingSearchButton implements GridField_HTMLProvider, GridFi
public function handleSearch($grid, $request)
{
return new GridFieldAddExistingSearchHandler($grid, $this);
return GridFieldAddExistingSearchHandler::create($grid, $this);
}
}

View File

@ -94,9 +94,9 @@ class GridFieldAddExistingSearchHandler extends RequestHandler
public function doSearch($data, $form)
{
$list = $this->context->getQuery($data, false, false, $this->getSearchList());
$list = $this->context->getQuery($data, false, null, $this->getSearchList());
$list = $list->subtract($this->grid->getList());
$list = new PaginatedList($list, $this->request);
$list = PaginatedList::create($list, $this->request);
$data = $this->customise(array(
'SearchForm' => $form,
@ -109,7 +109,7 @@ class GridFieldAddExistingSearchHandler extends RequestHandler
{
$list = $this->getSearchList();
$list = $list->subtract($this->grid->getList());
$list = new PaginatedList($list, $this->request);
$list = PaginatedList::create($list, $this->request);
return $list;
}

View File

@ -5,6 +5,7 @@ namespace Symbiote\GridFieldExtensions;
use SilverStripe\Core\Convert;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Forms\Form;
use SilverStripe\Forms\GridField\AbstractGridFieldComponent;
use SilverStripe\Forms\GridField\GridField;
use SilverStripe\Forms\GridField\GridField_HTMLProvider;
use SilverStripe\Forms\GridField\GridField_SaveHandler;
@ -13,6 +14,7 @@ use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\DataObjectInterface;
use SilverStripe\ORM\FieldType\DBField;
use SilverStripe\ORM\ManyManyList;
use SilverStripe\ORM\ManyManyThroughList;
use SilverStripe\View\ArrayData;
use SilverStripe\View\Requirements;
use Exception;
@ -20,7 +22,9 @@ use Exception;
/**
* Builds on the {@link GridFieldEditableColumns} component to allow creating new records.
*/
class GridFieldAddNewInlineButton implements GridField_HTMLProvider, GridField_SaveHandler
class GridFieldAddNewInlineButton extends AbstractGridFieldComponent implements
GridField_HTMLProvider,
GridField_SaveHandler
{
/**
* @skipUpgrade
@ -101,7 +105,7 @@ class GridFieldAddNewInlineButton implements GridField_HTMLProvider, GridField_S
Requirements::javascript('symbiote/silverstripe-gridfieldextensions:javascript/tmpl.js');
GridFieldExtensions::include_requirements();
$data = new ArrayData(array(
$data = ArrayData::create(array(
'Title' => $this->getTitle(),
));
@ -113,8 +117,8 @@ class GridFieldAddNewInlineButton implements GridField_HTMLProvider, GridField_S
private function getRowTemplate(GridField $grid, GridFieldEditableColumns $editable)
{
$columns = new ArrayList();
$handled = array_keys($editable->getDisplayFields($grid));
$columns = ArrayList::create();
$handled = array_keys($editable->getDisplayFields($grid) ?? []);
if ($grid->getList()) {
$record = Injector::inst()->create($grid->getModelClass());
@ -125,7 +129,7 @@ class GridFieldAddNewInlineButton implements GridField_HTMLProvider, GridField_S
$fields = $editable->getFields($grid, $record);
foreach ($grid->getColumns() as $column) {
if (in_array($column, $handled)) {
if (in_array($column, $handled ?? [])) {
$field = $fields->dataFieldByName($column);
$field->setName(sprintf(
'%s[%s][{%%=o.num%%}][%s]',
@ -134,6 +138,9 @@ class GridFieldAddNewInlineButton implements GridField_HTMLProvider, GridField_S
$field->getName()
));
if ($record && $record->hasField($column)) {
$field->setValue($record->getField($column));
}
$content = $field->Field();
} else {
$content = $grid->getColumnContent($record, $column);
@ -142,7 +149,7 @@ class GridFieldAddNewInlineButton implements GridField_HTMLProvider, GridField_S
$content = str_replace(
sprintf('[%s][0]', GridFieldEditableColumns::POST_KEY),
sprintf('[%s][{%%=o.num%%}]', self::POST_KEY),
$content
$content ?? ''
);
}
@ -157,7 +164,7 @@ class GridFieldAddNewInlineButton implements GridField_HTMLProvider, GridField_S
$attrs .= sprintf(' %s="%s"', $attr, Convert::raw2att($val));
}
$columns->push(new ArrayData(array(
$columns->push(ArrayData::create(array(
'Content' => $content,
'Attributes' => DBField::create_field('HTMLFragment', $attrs),
'IsActions' => $column == 'Actions'
@ -189,9 +196,15 @@ class GridFieldAddNewInlineButton implements GridField_HTMLProvider, GridField_S
foreach ($value[self::POST_KEY] as $fields) {
/** @var DataObject $item */
$item = $class::create();
// Add the item before the form is loaded so that the join-object is available
if ($list instanceof ManyManyThroughList) {
$list->add($item);
}
$extra = array();
$form = $editable->getForm($grid, $record);
$form = $editable->getForm($grid, $item);
$form->loadDataFrom($fields, Form::MERGE_CLEAR_MISSING);
$form->saveInto($item);
@ -202,11 +215,15 @@ class GridFieldAddNewInlineButton implements GridField_HTMLProvider, GridField_S
}
if ($list instanceof ManyManyList) {
$extra = array_intersect_key($form->getData(), (array) $list->getExtraFields());
$extra = array_intersect_key($form->getData() ?? [], (array) $list->getExtraFields());
}
$item->write();
$list->add($item, $extra);
$item->write(false, false, false, true);
// Add non-through lists after the write. many_many_extraFields are added there too
if (!($list instanceof ManyManyThroughList)) {
$list->add($item, $extra);
}
}
}
}

View File

@ -9,6 +9,7 @@ use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Forms\DropdownField;
use SilverStripe\Forms\GridField\AbstractGridFieldComponent;
use SilverStripe\Forms\GridField\GridField;
use SilverStripe\Forms\GridField\GridField_HTMLProvider;
use SilverStripe\Forms\GridField\GridField_URLHandler;
@ -23,7 +24,9 @@ use Exception;
* By default the list of classes that are createable is the grid field's model class, and any
* subclasses. This can be customised using {@link setClasses()}.
*/
class GridFieldAddNewMultiClass implements GridField_HTMLProvider, GridField_URLHandler
class GridFieldAddNewMultiClass extends AbstractGridFieldComponent implements
GridField_HTMLProvider,
GridField_URLHandler
{
/**
* @skipUpgrade
@ -121,7 +124,7 @@ class GridFieldAddNewMultiClass implements GridField_HTMLProvider, GridField_URL
$result = array();
if (is_null($this->classes)) {
$classes = array_values(ClassInfo::subclassesFor($grid->getModelClass()));
$classes = array_values(ClassInfo::subclassesFor($grid->getModelClass()) ?? []);
sort($classes);
} else {
$classes = $this->classes;
@ -132,7 +135,7 @@ class GridFieldAddNewMultiClass implements GridField_HTMLProvider, GridField_URL
if (!is_string($class)) {
$class = $title;
}
if (!class_exists($class)) {
if (!class_exists($class ?? '')) {
continue;
}
$is_abstract = (($reflection = new ReflectionClass($class)) && $reflection->isAbstract());
@ -213,7 +216,7 @@ class GridFieldAddNewMultiClass implements GridField_HTMLProvider, GridField_URL
throw new Exception('The add new multi class component requires the detail form component.');
}
if (!$class || !array_key_exists($class, $classes)) {
if (!$class || !array_key_exists($class, $classes ?? [])) {
throw new HTTPResponse_Exception(400);
}
@ -238,19 +241,24 @@ class GridFieldAddNewMultiClass implements GridField_HTMLProvider, GridField_URL
{
$classes = $this->getClasses($grid);
if (!count($classes)) {
if (!count($classes ?? [])) {
return array();
}
GridFieldExtensions::include_requirements();
$field = new DropdownField(sprintf('%s[%s]', __CLASS__, $grid->getName()), '', $classes, $this->defaultClass);
$field = DropdownField::create(
sprintf('%s[%s]', __CLASS__, $grid->getName()),
'',
$classes,
$this->defaultClass
);
if (Config::inst()->get(__CLASS__, 'showEmptyString')) {
$field->setEmptyString(_t('GridFieldExtensions.SELECTTYPETOCREATE', '(Select type to create)'));
}
$field->addExtraClass('no-change-track');
$data = new ArrayData(array(
$data = ArrayData::create(array(
'Title' => $this->getTitle(),
'Link' => Controller::join_links($grid->Link(), 'add-multi-class', '{class}'),
'ClassField' => $field
@ -285,7 +293,7 @@ class GridFieldAddNewMultiClass implements GridField_HTMLProvider, GridField_URL
*/
protected function sanitiseClassName($class)
{
return str_replace('\\', '-', $class);
return str_replace('\\', '-', $class ?? '');
}
/**
@ -296,6 +304,6 @@ class GridFieldAddNewMultiClass implements GridField_HTMLProvider, GridField_URL
*/
protected function unsanitiseClassName($class)
{
return str_replace('-', '\\', $class);
return str_replace('-', '\\', $class ?? '');
}
}

View File

@ -31,6 +31,6 @@ class GridFieldAddNewMultiClassHandler extends GridFieldDetailForm_ItemRequest
*/
protected function sanitiseClassName($class)
{
return str_replace('\\', '-', $class);
return str_replace('\\', '-', $class ?? '');
}
}

View File

@ -171,7 +171,7 @@ class GridFieldConfigurablePaginator extends GridFieldPaginator
$this->pageSizes = $pageSizes;
// Reset items per page
$this->setItemsPerPage(current($pageSizes));
$this->setItemsPerPage(current($pageSizes ?? []));
return $this;
}
@ -356,7 +356,7 @@ class GridFieldConfigurablePaginator extends GridFieldPaginator
return array(
'footer' => $forTemplate->renderWith(
__CLASS__,
array('Colspan' => count($gridField->getColumns()))
array('Colspan' => count($gridField->getColumns() ?? []))
)
);
}

View File

@ -19,11 +19,12 @@ use SilverStripe\Forms\GridField\GridField_URLHandler;
use SilverStripe\Forms\HTMLEditor\HTMLEditorField;
use SilverStripe\Forms\LiteralField;
use SilverStripe\Forms\ReadonlyField;
use SilverStripe\ORM\ArrayList;
use SilverStripe\ORM\DataList;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\DataObjectInterface;
use SilverStripe\ORM\FieldType\DBField;
use SilverStripe\ORM\ManyManyList;
use SilverStripe\ORM\ManyManyThroughList;
/**
* Allows inline editing of grid field records without having to load a separate
@ -56,16 +57,12 @@ class GridFieldEditableColumns extends GridFieldDataColumns implements
public function getColumnContent($grid, $record, $col)
{
if (!$record->canEdit()) {
return parent::getColumnContent($grid, $record, $col);
}
$fields = $this->getForm($grid, $record)->Fields();
if (!$this->displayFields) {
// If setDisplayFields() not used, utilize $summary_fields
// in a way similar to base class
$colRelation = explode('.', $col);
$colRelation = explode('.', $col ?? '');
$value = $grid->getDataFieldValue($record, $colRelation[0]);
$field = $fields->fieldByName($colRelation[0]);
if (!$field || $field->isReadonly() || $field->isDisabled()) {
@ -82,15 +79,20 @@ class GridFieldEditableColumns extends GridFieldDataColumns implements
$field = clone $field;
} else {
$value = $grid->getDataFieldValue($record, $col);
$rel = (strpos($col, '.') === false); // field references a relation value
$field = ($rel) ? clone $fields->fieldByName($col) : new ReadonlyField($col);
$field = $fields->dataFieldByName($col);
// Fall back to previous logic
if (!$field) {
$rel = (strpos($col ?? '', '.') === false); // field references a relation value
$field = ($rel) ? clone $fields->fieldByName($col) : ReadonlyField::create($col);
}
if (!$field) {
throw new Exception("Could not find the field '$col'");
}
}
if (array_key_exists($col, $this->fieldCasting)) {
if (array_key_exists($col, $this->fieldCasting ?? [])) {
$value = $grid->getCastedValue($value, $this->fieldCasting[$col]);
}
@ -99,6 +101,10 @@ class GridFieldEditableColumns extends GridFieldDataColumns implements
$field->setName($this->getFieldName($field->getName(), $grid, $record));
$field->setValue($value);
if ($grid->isReadonly() || !$record->canEdit()) {
$field = $field->performReadonlyTransformation();
}
if ($field instanceof HtmlEditorField) {
return $field->FieldHolder();
}
@ -125,23 +131,33 @@ class GridFieldEditableColumns extends GridFieldDataColumns implements
/** @var GridFieldOrderableRows $sortable */
$sortable = $grid->getConfig()->getComponentByType(GridFieldOrderableRows::class);
// Fetch the items before processing them
$ids = array_keys($value[self::POST_KEY]);
if (empty($ids)) {
return;
}
$itemsCollection = ArrayList::create($list->filter('ID', $ids)->toArray());
foreach ($value[self::POST_KEY] as $id => $fields) {
if (!is_numeric($id) || !is_array($fields)) {
continue;
}
$item = $list->byID($id);
// Find the item from the fetched collection of items
$item = $itemsCollection->find('ID', $id);
if (!$item || !$item->canEdit()) {
// Skip not found item, or don't have any changed fields, or current user can't edit
if (!$item || !$this->isChanged($item, $fields) || !$item->canEdit()) {
continue;
}
$extra = array();
$form = $this->getForm($grid, $record);
$form = $this->getForm($grid, $item);
$form->loadDataFrom($fields, Form::MERGE_CLEAR_MISSING);
$form->saveInto($item);
// Check if we are also sorting these records
if ($sortable) {
$sortField = $sortable->getSortField();
@ -150,11 +166,11 @@ class GridFieldEditableColumns extends GridFieldDataColumns implements
}
}
if ($list instanceof ManyManyList) {
$extra = array_intersect_key($form->getData(), (array) $list->getExtraFields());
if ($list instanceof ManyManyList || $list instanceof ManyManyThroughList) {
$extra = array_intersect_key($form->getData() ?? [], (array) $list->getExtraFields());
}
$item->write();
$item->write(false, false, false, true);
$list->add($item, $extra);
}
}
@ -205,7 +221,7 @@ class GridFieldEditableColumns extends GridFieldDataColumns implements
public function getFields(GridField $grid, DataObjectInterface $record)
{
$cols = $this->getDisplayFields($grid);
$fields = new FieldList();
$fields = FieldList::create();
/** @var DataList $list */
$list = $grid->getList();
@ -235,10 +251,10 @@ class GridFieldEditableColumns extends GridFieldDataColumns implements
}
}
if (!$field && $list instanceof ManyManyList) {
if (!$field && ($list instanceof ManyManyList || $list instanceof ManyManyThroughList)) {
$extra = $list->getExtraFields();
if ($extra && array_key_exists($col, $extra)) {
if ($extra && array_key_exists($col, $extra ?? [])) {
$field = Injector::inst()->create($extra[$col], $col)->scaffoldFormField();
}
}
@ -253,16 +269,16 @@ class GridFieldEditableColumns extends GridFieldDataColumns implements
// revert to looking good in cases where the field isn't
// available or is readonly
//
$colRelation = explode('.', $col);
$colRelation = explode('.', $col ?? '');
if ($class && $obj = DataObject::singleton($class)->dbObject($colRelation[0])) {
$field = $obj->scaffoldFormField();
} else {
$field = new ReadonlyField($colRelation[0]);
$field = ReadonlyField::create($colRelation[0]);
}
} elseif ($class && $obj = DataObject::singleton($class)->dbObject($col)) {
$field = $obj->scaffoldFormField();
} else {
$field = new ReadonlyField($col);
$field = ReadonlyField::create($col);
}
}
@ -295,7 +311,7 @@ class GridFieldEditableColumns extends GridFieldDataColumns implements
{
$fields = $this->getFields($grid, $record);
$form = new Form($grid, null, $fields, new FieldList());
$form = Form::create($grid, null, $fields, FieldList::create());
$form->loadDataFrom($record);
$form->setFormAction(Controller::join_links(
@ -317,4 +333,18 @@ class GridFieldEditableColumns extends GridFieldDataColumns implements
$name
);
}
/**
* Whether or not an object in the grid field has changed data.
*/
private function isChanged(DataObject $item, array $fields): bool
{
foreach ($fields as $name => $value) {
if ($item->getField($name) !== $value) {
return true;
}
}
return false;
}
}

View File

@ -19,7 +19,7 @@ class GridFieldExternalLink extends GridFieldDataColumns
*/
public function augmentColumns($gridField, &$columns)
{
if (!in_array('Actions', $columns)) {
if (!in_array('Actions', $columns ?? [])) {
$columns[] = 'Actions';
}
}
@ -72,7 +72,7 @@ class GridFieldExternalLink extends GridFieldDataColumns
*/
public function getColumnContent($gridField, $record, $columnName)
{
$data = new ArrayData(array(
$data = ArrayData::create(array(
'Link' => $record->hasMethod('getExternalLink') ? $record->getExternalLink() : $record->ExternalLink,
'Text' => $record->hasMethod('getExternalLinkText') ? $record->getExternalLinkText() : 'External Link'
));

View File

@ -8,6 +8,7 @@ use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\HTTPResponse_Exception;
use SilverStripe\Control\RequestHandler;
use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Config\Config;
use SilverStripe\Forms\GridField\GridField;
use SilverStripe\Forms\GridField\GridField_ColumnProvider;
use SilverStripe\Forms\GridField\GridField_DataManipulator;
@ -81,6 +82,15 @@ class GridFieldOrderableRows extends RequestHandler implements
*/
protected $extraSortFields = null;
/**
* If the items in the list are versioned and this is set to true, then
* we will check to see if the version we're sorting is the latest published
* version and if so then we will re-publish the item.
*
* @var boolean
*/
protected $republishLiveRecords = false;
/**
* The number of the column containing the reorder handles
*
@ -146,6 +156,28 @@ class GridFieldOrderableRows extends RequestHandler implements
return $this->extraSortFields;
}
/**
* @see $republishLiveRecords
*
* @return boolean
*/
public function getRepublishLiveRecords()
{
return $this->republishLiveRecords;
}
/**
* @see $republishLiveRecords
*
* @param boolean $bool
* @return GridFieldOrderableRows $this
*/
public function setRepublishLiveRecords($bool)
{
$this->republishLiveRecords = $bool;
return $this;
}
/**
* Checks to see if the relationship list is for a type of many_many
*
@ -204,7 +236,7 @@ class GridFieldOrderableRows extends RequestHandler implements
if ($list instanceof ManyManyList) {
$extra = $list->getExtraFields();
if ($extra && array_key_exists($field, $extra)) {
if ($extra && array_key_exists($field, $extra ?? [])) {
return;
}
} elseif ($list instanceof ManyManyThroughList) {
@ -238,7 +270,7 @@ class GridFieldOrderableRows extends RequestHandler implements
if ($list instanceof ManyManyList) {
$extra = $list->getExtraFields();
$table = $list->getJoinTable();
if ($extra && array_key_exists($field, $extra)) {
if ($extra && array_key_exists($field, $extra ?? [])) {
return $table;
}
} elseif ($list instanceof ManyManyThroughList) {
@ -276,8 +308,8 @@ class GridFieldOrderableRows extends RequestHandler implements
public function augmentColumns($grid, &$cols)
{
if (!in_array('Reorder', $cols) && $grid->getState()->GridFieldOrderableRows->enabled) {
array_splice($cols, $this->reorderColumnNumber, 0, 'Reorder');
if (!in_array('Reorder', $cols ?? []) && $grid->getState()->GridFieldOrderableRows->enabled) {
array_splice($cols, $this->reorderColumnNumber ?? 0, 0, 'Reorder');
}
}
@ -307,7 +339,7 @@ class GridFieldOrderableRows extends RequestHandler implements
// if it exists, not directly from the record
$throughListSorts = $this->getSortValuesFromManyManyThroughList($list, $this->getSortField());
if (array_key_exists($record->ID, $throughListSorts)) {
if (array_key_exists($record->ID, $throughListSorts ?? [])) {
$currentSortValue = $throughListSorts[$record->ID];
}
}
@ -360,7 +392,24 @@ class GridFieldOrderableRows extends RequestHandler implements
$sortterm .= $this->getSortTable($list).'.'.$this->getSortField();
} else {
$sortterm .= '"'.$this->getSortTable($list).'"."'.$this->getSortField().'"';
if ($list instanceof DataList) {
$classname = $list->dataClass();
if ($defaultSort = Config::inst()->get($classname, 'default_sort')) {
if (is_array($defaultSort)) {
$defaultSortArray = [];
foreach ($defaultSort as $column => $direction) {
$defaultSortArray[] = "\"$column\" $direction";
}
$defaultSort = implode(', ', $defaultSortArray);
}
// Append the default sort to the end of the sort string
// This may result in redundancy... but it seems to work
$sortterm .= ($sortterm ? ', ' : '') . $defaultSort;
}
}
}
return $list->sort($sortterm);
}
@ -396,13 +445,21 @@ class GridFieldOrderableRows extends RequestHandler implements
}
// Get records from the `GridFieldEditableColumns` column
$data = $request->postVar($grid->getName());
$gridFieldName = $grid->getName();
if (strpos($gridFieldName ?? '', '.') !== false) {
$gridFieldName = str_replace('.', '_', $gridFieldName ?? '');
}
$data = $request->postVar($gridFieldName);
$sortedIDs = $this->getSortedIDs($data);
if (!$this->executeReorder($grid, $sortedIDs)) {
$this->httpError(400);
}
Controller::curr()->getResponse()->addHeader('X-Status', rawurlencode('Records reordered.'));
Controller::curr()->getResponse()->addHeader(
'X-Status',
rawurlencode(_t(__CLASS__ . '.REORDERED', 'Records reordered.'))
);
return $grid->FieldHolder();
}
@ -533,7 +590,7 @@ class GridFieldOrderableRows extends RequestHandler implements
$items = $list->filter('ID', $sortedIDs)->sort($sortterm);
// Ensure that each provided ID corresponded to an actual object.
if (count($items) != count($sortedIDs)) {
if (count($items ?? []) != count($sortedIDs ?? [])) {
return false;
}
@ -571,9 +628,10 @@ class GridFieldOrderableRows extends RequestHandler implements
*/
protected function reorderItems($list, array $values, array $sortedIDs)
{
$this->extend('onBeforeReorderItems', $list, $values, $sortedIDs);
// setup
$sortField = $this->getSortField();
$class = $list->dataClass();
// The problem is that $sortedIDs is a list of the _related_ item IDs, which causes trouble
// with ManyManyThrough, where we need the ID of the _join_ item in order to set the value.
$itemToSortReference = ($list instanceof ManyManyThroughList) ? 'getJoin' : 'Me';
@ -582,53 +640,21 @@ class GridFieldOrderableRows extends RequestHandler implements
// sanity check.
$this->validateSortField($list);
$isVersioned = false;
// check if sort column is present on the model provided by dataClass() and if it's versioned
// cases:
// Model has sort column and is versioned - handle as versioned
// Model has sort column and is NOT versioned - handle as NOT versioned
// Model doesn't have sort column because sort column is on ManyManyList - handle as NOT versioned
// Model doesn't have sort column because sort column is on ManyManyThroughList - inspect through object
if ($list instanceof ManyManyThroughList) {
// We'll be updating the join class, not the relation class.
$class = $this->getManyManyInspector($list)->getJoinClass();
$isVersioned = $class::create()->hasExtension(Versioned::class);
} elseif (!$this->isManyMany($list)) {
$isVersioned = $class::create()->hasExtension(Versioned::class);
}
// Loop through each item, and update the sort values which do not
// match to order the objects.
if (!$isVersioned) {
// ManyManyList extra fields aren't easily updated via the ORM, and so they need to be updated through an SQL
// Query
if ($list instanceof ManyManyList) {
$sortTable = $this->getSortTable($list);
$now = DBDatetime::now()->Rfc2822();
$additionalSQL = '';
$baseTable = DataObject::getSchema()->baseDataTable($class);
$isBaseTable = ($baseTable == $sortTable);
if (!$list instanceof ManyManyList && $isBaseTable) {
$additionalSQL = ", \"LastEdited\" = '$now'";
}
// Loop through each item, and update the sort values which do not match to order the objects.
foreach ($sortedIDs as $newSortValue => $targetRecordID) {
if ($currentSortList[$targetRecordID]->$sortField != $newSortValue) {
DB::query(sprintf(
'UPDATE "%s" SET "%s" = %d%s WHERE %s',
'UPDATE "%s" SET "%s" = %d WHERE %s',
$sortTable,
$sortField,
$newSortValue,
$additionalSQL,
$this->getSortTableClauseForIds($list, $targetRecordID)
));
if (!$isBaseTable && !$list instanceof ManyManyList) {
DB::query(sprintf(
'UPDATE "%s" SET "LastEdited" = \'%s\' WHERE %s',
$baseTable,
$now,
$this->getSortTableClauseForIds($list, $targetRecordID)
));
}
}
}
} else {
@ -640,9 +666,18 @@ class GridFieldOrderableRows extends RequestHandler implements
// either the list data class (has_many, (belongs_)many_many)
// or the intermediary join class (many_many through)
$record = $currentSortList[$targetRecordID];
if ($record->$sortField != $newSortValue) {
$record->$sortField = $newSortValue;
// We need to do this before writing otherwith isLiveVersion() will always be false
$shouldRepublish = $this->getRepublishLiveRecords() && $record->isLiveVersion();
// Write our staged record and publish if required
$record->write();
if ($shouldRepublish) {
$record->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE, true);
}
}
}
}
@ -704,7 +739,7 @@ class GridFieldOrderableRows extends RequestHandler implements
protected function getSortTableClauseForIds(DataList $list, $ids)
{
if (is_array($ids)) {
$value = 'IN (' . implode(', ', array_map('intval', $ids)) . ')';
$value = 'IN (' . implode(', ', array_map('intval', $ids ?? [])) . ')';
} else {
$value = '= ' . (int) $ids;
}
@ -715,10 +750,10 @@ class GridFieldOrderableRows extends RequestHandler implements
$introspector->getExtraFields() :
DataObjectSchema::create()->fieldSpecs($introspector->getJoinClass(), DataObjectSchema::DB_ONLY);
$key = $introspector->getLocalKey();
$foreignKey = $introspector->getForeignKey();
$foreignKey = $this->getManyManyInspectorForeignKey($introspector);
$foreignID = (int) $list->getForeignID();
if ($extra && array_key_exists($this->getSortField(), $extra)) {
if ($extra && array_key_exists($this->getSortField(), $extra ?? [])) {
return sprintf(
'"%s" %s AND "%s" = %d',
$key,
@ -755,6 +790,24 @@ class GridFieldOrderableRows extends RequestHandler implements
return $inspector;
}
/**
* Depending on the list inspector and the list itself (ManyMany vs ManyManyThrough), the method to obtain
* the foreign key may be different.
*
* @param $inspector
* @return string
*/
private function getManyManyInspectorForeignKey($inspector)
{
if (($inspector instanceof ManyManyThroughQueryManipulator) && (method_exists($inspector, 'getForeignIDKey'))) {
// This method has been introduced in framework 4.1
return $inspector->getForeignIDKey();
}
return $inspector->getForeignKey();
}
/**
* Used to get sort orders from a many many through list relationship record, rather than the current
* record itself.
@ -768,7 +821,7 @@ class GridFieldOrderableRows extends RequestHandler implements
// Find the foreign key name, ID and class to look up
$joinClass = $manipulator->getJoinClass();
$fromRelationName = $manipulator->getForeignKey();
$fromRelationName = $this->getManyManyInspectorForeignKey($manipulator);
$toRelationName = $manipulator->getLocalKey();
// Create a list of the MMTL relations

View File

@ -83,11 +83,11 @@ abstract class GridFieldRequestHandler extends RequestHandler
*/
public function Form()
{
$form = new Form(
$form = Form::create(
$this,
'SilverStripe\\Forms\\Form',
new FieldList($root = new TabSet('Root', new Tab('Main'))),
new FieldList()
FieldList::create($root = TabSet::create('Root', Tab::create('Main'))),
FieldList::create()
);
if ($this->getTopLevelController() instanceof LeftAndMain) {
@ -136,7 +136,7 @@ abstract class GridFieldRequestHandler extends RequestHandler
if ($controller->hasMethod('Breadcrumbs')) {
return $controller->Breadcrumbs();
} else {
return new ArrayList();
return ArrayList::create();
}
}

View File

@ -2,6 +2,7 @@
namespace Symbiote\GridFieldExtensions;
use SilverStripe\Forms\GridField\AbstractGridFieldComponent;
use SilverStripe\Forms\GridField\GridField_HTMLProvider;
use SilverStripe\ORM\ArrayList;
use SilverStripe\View\ArrayData;
@ -9,17 +10,17 @@ use SilverStripe\View\ArrayData;
/**
* A simple header which displays column titles.
*/
class GridFieldTitleHeader implements GridField_HTMLProvider
class GridFieldTitleHeader extends AbstractGridFieldComponent implements GridField_HTMLProvider
{
public function getHTMLFragments($grid)
{
$cols = new ArrayList();
$cols = ArrayList::create();
foreach ($grid->getColumns() as $name) {
$meta = $grid->getColumnMetadata($name);
$cols->push(new ArrayData(array(
$cols->push(ArrayData::create(array(
'Name' => $name,
'Title' => $meta['title']
)));

View File

@ -16,7 +16,7 @@ class GridFieldConfigurablePaginatorTest extends SapphireTest
*/
protected $gridField;
public function setUp()
protected function setUp(): void
{
parent::setUp();
@ -172,12 +172,10 @@ class GridFieldConfigurablePaginatorTest extends SapphireTest
), $paginator->getPageSizesAsList());
}
/**
* @expectedException Exception
* @expectedExceptionMessage No GridField available yet for this request!
*/
public function testGetGridFieldThrowsExceptionWhenNotSet()
{
$this->expectException(\Exception::class);
$this->expectExceptionMessage('No GridField available yet for this request!');
$paginator = new GridFieldConfigurablePaginator;
$paginator->getGridField();
}
@ -205,9 +203,9 @@ class GridFieldConfigurablePaginatorTest extends SapphireTest
)
);
$gridField = $this->getMockBuilder(GridField::class)->disableOriginalConstructor()->getMock();
$paginator = new GridFieldConfigurablePaginator;
$result = $paginator->getPagerActions($controls, $gridField);
$paginator->setGridField($this->gridField);
$result = $paginator->getPagerActions($controls, $this->gridField);
$this->assertCount(2, $result);
$this->assertArrayHasKey('next', $result);

View File

@ -0,0 +1,94 @@
<?php
namespace Symbiote\GridFieldExtensions\Tests;
use Symbiote\GridFieldExtensions\Tests\Stub\TestController;
use Symbiote\GridFieldExtensions\Tests\Stub\StubUnorderable;
use Symbiote\GridFieldExtensions\GridFieldEditableColumns;
use SilverStripe\ORM\FieldType\DBHTMLText;
use SilverStripe\Forms\TextField;
use SilverStripe\Forms\GridField\GridField;
use SilverStripe\Forms\Form;
use SilverStripe\Forms\FieldList;
use SilverStripe\Dev\SapphireTest;
class GridFieldEditableColumnsTest extends SapphireTest
{
private function getMockGrid()
{
$controller = new TestController('Test');
$form = new Form($controller, 'TestForm', new FieldList(
$grid = new GridField('TestGridField')
), new FieldList());
$grid->setModelClass(StubUnorderable::class);
$grid->setList(StubUnorderable::get());
return $grid;
}
private function getMockRecord($id, $title)
{
$record = new StubUnorderable();
$record->ID = $id;
$record->Title = $title;
return $record;
}
public function testProvidesEditableFieldsInColumns()
{
$grid = $this->getMockGrid();
$component = new GridFieldEditableColumns();
$record = $this->getMockRecord(100, "foo");
$this->assertEquals(
[ 'Title' ],
$component->getColumnsHandled($grid)
);
$record->setCanEdit(true);
$column = $component->getColumnContent($grid, $record, 'Title');
$this->assertInstanceOf(DBHTMLText::class, $column);
$this->assertMatchesRegularExpression(
'/<input type="text" name="TestGridField\[GridFieldEditableColumns\]\[100\]\[Title\]" value="foo"[^>]*>/',
$column->getValue()
);
}
public function testProvidesReadonlyColumnsForNoneditableRecords()
{
$grid = $this->getMockGrid();
$component = new GridFieldEditableColumns();
$record = $this->getMockRecord(100, "testval");
$record->setCanEdit(false);
$column = $component->getColumnContent($grid, $record, 'Title');
$this->assertInstanceOf(DBHTMLText::class, $column);
$this->assertMatchesRegularExpression(
'/<span[^>]*>\s*testval\s*<\/span>/',
$column->getValue()
);
}
public function testProvidesReadonlyColumnsForReadonlyGrids()
{
$grid = $this->getMockGrid();
$component = new GridFieldEditableColumns();
$record = $this->getMockRecord(100, "testval");
$record->setCanEdit(true);
$grid = $grid->performReadonlyTransformation();
if (!$grid instanceof GridField) {
$this->markTestSkipped('silverstripe/framework <4.2.2 doesn\'t support readonly GridFields');
}
$column = $component->getColumnContent($grid, $record, 'Title');
$this->assertInstanceOf(DBHTMLText::class, $column);
$this->assertMatchesRegularExpression(
'/<span[^>]*>\s*testval\s*<\/span>/',
$column->getValue()
);
}
}

View File

@ -6,7 +6,10 @@ use ReflectionMethod;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\Forms\GridField\GridField;
use SilverStripe\Forms\GridField\GridFieldConfig_RelationEditor;
use SilverStripe\ORM\DataList;
use Symbiote\GridFieldExtensions\GridFieldOrderableRows;
use Symbiote\GridFieldExtensions\Tests\Stub\PolymorphM2MMapper;
use Symbiote\GridFieldExtensions\Tests\Stub\PolymorphM2MParent;
use Symbiote\GridFieldExtensions\Tests\Stub\StubOrderableChild;
use Symbiote\GridFieldExtensions\Tests\Stub\StubOrdered;
use Symbiote\GridFieldExtensions\Tests\Stub\StubOrderedVersioned;
@ -14,9 +17,15 @@ use Symbiote\GridFieldExtensions\Tests\Stub\StubParent;
use Symbiote\GridFieldExtensions\Tests\Stub\StubSubclass;
use Symbiote\GridFieldExtensions\Tests\Stub\StubSubclassOrderedVersioned;
use Symbiote\GridFieldExtensions\Tests\Stub\StubUnorderable;
use Symbiote\GridFieldExtensions\Tests\Stub\ThroughDefiner;
use Symbiote\GridFieldExtensions\Tests\Stub\ThroughIntermediary;
use Symbiote\GridFieldExtensions\Tests\Stub\ThroughBelongs;
use Symbiote\GridFieldExtensions\Tests\Stub\ThroughBelongsVersioned;
use Symbiote\GridFieldExtensions\Tests\Stub\ThroughDefiner;
use Symbiote\GridFieldExtensions\Tests\Stub\ThroughDefinerVersioned;
use Symbiote\GridFieldExtensions\Tests\Stub\ThroughIntermediary;
use Symbiote\GridFieldExtensions\Tests\Stub\TitleObject;
use Symbiote\GridFieldExtensions\Tests\Stub\TitleSortedObject;
use Symbiote\GridFieldExtensions\Tests\Stub\TitleArraySortedObject;
use Symbiote\GridFieldExtensions\Tests\Stub\ThroughIntermediaryVersioned;
/**
* Tests for the {@link GridFieldOrderableRows} component.
@ -25,10 +34,14 @@ class GridFieldOrderableRowsTest extends SapphireTest
{
protected static $fixture_file = [
'GridFieldOrderableRowsTest.yml',
'OrderableRowsThroughTest.yml'
'OrderableRowsThroughTest.yml',
// 'OrderablePolymorphicManyToMany.yml' // TODO: introduce this tests in the next minor release
];
protected static $extra_dataobjects = [
// PolymorphM2MChild::class,
// PolymorphM2MMapper::class,
// PolymorphM2MParent::class,
StubParent::class,
StubOrdered::class,
StubSubclass::class,
@ -39,13 +52,25 @@ class GridFieldOrderableRowsTest extends SapphireTest
ThroughDefiner::class,
ThroughIntermediary::class,
ThroughBelongs::class,
TitleObject::class,
TitleSortedObject::class,
TitleArraySortedObject::class,
ThroughDefinerVersioned::class,
ThroughIntermediaryVersioned::class,
ThroughBelongsVersioned::class,
];
public function reorderItemsProvider()
{
return [
[StubParent::class . '.parent', 'MyHasMany', 'Sort'],
[StubParent::class . '.parent', 'MyHasManySubclass', 'Sort'],
[StubParent::class . '.parent-subclass-ordered-versioned', 'MyHasManySubclassOrderedVersioned', 'Sort'],
[StubParent::class . '.parent', 'MyManyMany', 'ManyManySort'],
[StubParent::class . '.parent', 'MyManyManyVersioned', 'ManyManySort'],
[ThroughDefiner::class . '.DefinerOne', 'Belongings', 'Sort'],
[ThroughDefinerVersioned::class . '.DefinerOne', 'Belongings', 'Sort'],
// [PolymorphM2MParent::class . '.ParentOne', 'Children', 'Sort']
];
}
@ -61,7 +86,7 @@ class GridFieldOrderableRowsTest extends SapphireTest
$config = new GridFieldConfig_RelationEditor();
$config->addComponent($orderable);
list($parentClass, $parentInstanceID) = explode('.', $fixtureID);
list($parentClass, $parentInstanceID) = explode('.', $fixtureID ?? '');
$parent = $this->objFromFixture($parentClass, $parentInstanceID);
$grid = new GridField(
@ -75,7 +100,7 @@ class GridFieldOrderableRowsTest extends SapphireTest
$desiredOrder = [];
// Make order non-contiguous, and 1-based
foreach (array_reverse($originalOrder) as $index => $id) {
foreach (array_reverse($originalOrder ?? []) as $index => $id) {
$desiredOrder[$index * 2 + 1] = $id;
}
@ -110,12 +135,46 @@ class GridFieldOrderableRowsTest extends SapphireTest
$result = $orderable->getColumnContent($grid, $record, 'irrelevant');
$this->assertContains(
$this->assertStringContainsString(
'Belongings[GridFieldEditableColumns][' . $record->ID . '][Sort]',
$result,
'The field name is indexed under the record\'s ID'
);
$this->assertContains(
$this->assertStringContainsString(
'value="' . $intermediary->Sort . '"',
$result,
'The value comes from the MMTL intermediary Sort value'
);
}
public function testPolymorphicManyManyListSortOrdersAreUsedForInitialRender()
{
$this->markTestSkipped('TODO: Introduce this test in the next minor release (3.3)');
$record = $this->objFromFixture(PolymorphM2MParent::class, 'ParentOne');
$orderable = new GridFieldOrderableRows('Sort');
$config = new GridFieldConfig_RelationEditor();
$config->addComponent($orderable);
$grid = new GridField(
'Children',
'Testing Polymorphic Many Many',
$record->Children()->sort('Sort'),
$config
);
// Get the first record, which would be the first one to have column contents generated
$intermediary = $this->objFromFixture(PolymorphM2MMapper::class, 'MapP1ToC1');
$result = $orderable->getColumnContent($grid, $record, 'irrelevant');
$this->assertStringContainsString(
'Children[GridFieldEditableColumns][' . $record->ID . '][Sort]',
$result,
'The field name is indexed under the record\'s ID'
);
$this->assertStringContainsString(
'value="' . $intermediary->Sort . '"',
$result,
'The value comes from the MMTL intermediary Sort value'
@ -141,7 +200,7 @@ class GridFieldOrderableRowsTest extends SapphireTest
);
$originalOrder = $parent->Children()->column('ID');
$desiredOrder = array_reverse($originalOrder);
$desiredOrder = array_reverse($originalOrder ?? []);
$this->assertNotEquals($originalOrder, $desiredOrder);
@ -228,7 +287,7 @@ class GridFieldOrderableRowsTest extends SapphireTest
$desiredOrder = [];
// Make order non-contiguous, and 1-based
foreach (array_reverse($originalOrder) as $index => $id) {
foreach (array_reverse($originalOrder ?? []) as $index => $id) {
$desiredOrder[$index * 2 + 1] = $id;
}
@ -254,4 +313,52 @@ class GridFieldOrderableRowsTest extends SapphireTest
$this->assertTrue($differenceFound);
}
public function testGetManipulatedDataWithoutDefaultSort()
{
$sortedList = $this->getTitleSortedListForManipuatedData(TitleObject::class, [
['Title' => 'C'],
['Title' => 'A'],
['Title' => 'B'],
]);
$this->assertSame(['A', 'B', 'C'], $sortedList->column('Title'));
}
public function testGetManipulatedDataWithDefaultSort()
{
$sortedList = $this->getTitleSortedListForManipuatedData(TitleSortedObject::class, [
['Title' => 'Z', 'Iden' => 'C', 'DefaultSort' => 3],
['Title' => 'Z', 'Iden' => 'A', 'DefaultSort' => 2],
['Title' => 'Z', 'Iden' => 'B', 'DefaultSort' => 1],
]);
$this->assertSame(['B', 'A', 'C'], $sortedList->column('Iden'));
}
public function testGetManipulatedDataWithDefaultSortArray()
{
$sortedList = $this->getTitleSortedListForManipuatedData(TitleArraySortedObject::class, [
['Title' => 'X', 'Iden' => 'C', 'OtherSort' => 3],
['Title' => 'Z', 'Iden' => 'A', 'OtherSort' => 2],
['Title' => 'Z', 'Iden' => 'B', 'OtherSort' => 1],
]);
$this->assertSame(['C', 'B', 'A'], $sortedList->column('Iden'));
}
private function getTitleSortedListForManipuatedData(string $dataClass, array $data): DataList
{
$list = new DataList($dataClass);
foreach ($data as $values) {
$item = new $dataClass();
$item->update($values);
$item->write();
$list->add($item);
}
$orderable = new GridFieldOrderableRows('Title');
$config = new GridFieldConfig_RelationEditor();
$config->addComponent($orderable);
$grid = new GridField('MyName', 'MyTitle', $list, $config);
$sortedList = $orderable->getManipulatedData($grid, $list);
return $sortedList;
}
}

View File

@ -7,6 +7,7 @@ Symbiote\GridFieldExtensions\Tests\Stub\StubOrderableChild:
Sort: 3
item4:
Sort: 4
Symbiote\GridFieldExtensions\Tests\Stub\StubOrdered:
item1:
Sort: 1
@ -27,6 +28,20 @@ Symbiote\GridFieldExtensions\Tests\Stub\StubOrdered:
- =>Symbiote\GridFieldExtensions\Tests\Stub\StubOrderableChild.item3
- =>Symbiote\GridFieldExtensions\Tests\Stub\StubOrderableChild.item4
Symbiote\GridFieldExtensions\Tests\Stub\StubSubclass:
item1:
Sort: 1
item2:
Sort: 2
item3:
Sort: 3
item4:
Sort: 4
item5:
Sort: 5
item6:
Sort: 6
Symbiote\GridFieldExtensions\Tests\Stub\StubSubclassOrderedVersioned:
item1:
ExtraField: 1
@ -56,6 +71,29 @@ Symbiote\GridFieldExtensions\Tests\Stub\StubParent:
ManyManySort: 108
- =>Symbiote\GridFieldExtensions\Tests\Stub\StubOrdered.item6:
ManyManySort: 108
MyManyManyVersioned:
- =>Symbiote\GridFieldExtensions\Tests\Stub\StubSubclassOrderedVersioned.item1:
ManyManySort: 1
- =>Symbiote\GridFieldExtensions\Tests\Stub\StubSubclassOrderedVersioned.item2:
ManyManySort: 1
- =>Symbiote\GridFieldExtensions\Tests\Stub\StubSubclassOrderedVersioned.item3:
ManyManySort: 108
- =>Symbiote\GridFieldExtensions\Tests\Stub\StubSubclassOrderedVersioned.item4:
ManyManySort: 108
MyHasMany:
- =>Symbiote\GridFieldExtensions\Tests\Stub\StubOrdered.item1
- =>Symbiote\GridFieldExtensions\Tests\Stub\StubOrdered.item2
- =>Symbiote\GridFieldExtensions\Tests\Stub\StubOrdered.item3
- =>Symbiote\GridFieldExtensions\Tests\Stub\StubOrdered.item4
- =>Symbiote\GridFieldExtensions\Tests\Stub\StubOrdered.item5
- =>Symbiote\GridFieldExtensions\Tests\Stub\StubOrdered.item6
MyHasManySubclass:
- =>Symbiote\GridFieldExtensions\Tests\Stub\StubSubclass.item1
- =>Symbiote\GridFieldExtensions\Tests\Stub\StubSubclass.item2
- =>Symbiote\GridFieldExtensions\Tests\Stub\StubSubclass.item3
- =>Symbiote\GridFieldExtensions\Tests\Stub\StubSubclass.item4
- =>Symbiote\GridFieldExtensions\Tests\Stub\StubSubclass.item5
- =>Symbiote\GridFieldExtensions\Tests\Stub\StubSubclass.item6
parent-subclass-ordered-versioned:
MyHasManySubclassOrderedVersioned:
- =>Symbiote\GridFieldExtensions\Tests\Stub\StubSubclassOrderedVersioned.item1

View File

@ -0,0 +1,28 @@
Symbiote\GridFieldExtensions\Tests\Stub\PolymorphM2MParent:
ParentOne:
ParentTwo:
Symbiote\GridFieldExtensions\Tests\Stub\PolymorphM2MChild:
ChildOne:
ChildTwo:
Symbiote\GridFieldExtensions\Tests\Stub\PolymorphM2MMapper:
MapP1ToC1:
Parent: '=>Symbiote\GridFieldExtensions\Tests\Stub\PolymorphM2MParent.ParentOne'
Child: '=>Symbiote\GridFieldExtensions\Tests\Stub\PolymorphM2MChild.ChildOne'
Sort: 1
MapP1ToC2:
Parent: '=>Symbiote\GridFieldExtensions\Tests\Stub\PolymorphM2MParent.ParentOne'
Child: '=>Symbiote\GridFieldExtensions\Tests\Stub\PolymorphM2MChild.ChildTwo'
Sort: 2
MapP2ToC1:
Parent: '=>Symbiote\GridFieldExtensions\Tests\Stub\PolymorphM2MParent.ParentTwo'
Child: '=>Symbiote\GridFieldExtensions\Tests\Stub\PolymorphM2MChild.ChildOne'
Sort: 2
MapP2ToC2:
Parent: '=>Symbiote\GridFieldExtensions\Tests\Stub\PolymorphM2MParent.ParentTwo'
Child: '=>Symbiote\GridFieldExtensions\Tests\Stub\PolymorphM2MChild.ChildTwo'
Sort: 1

View File

@ -28,3 +28,34 @@ Symbiote\GridFieldExtensions\Tests\Stub\ThroughIntermediary:
Defining: =>Symbiote\GridFieldExtensions\Tests\Stub\ThroughDefiner.DefinerTwo
Belonging: =>Symbiote\GridFieldExtensions\Tests\Stub\ThroughBelongs.BelongsThree
Sort: 2
Symbiote\GridFieldExtensions\Tests\Stub\ThroughDefinerVersioned:
DefinerOne:
DefinerTwo:
Symbiote\GridFieldExtensions\Tests\Stub\ThroughBelongsVersioned:
BelongsOne:
BelongsTwo:
BelongsThree:
Symbiote\GridFieldExtensions\Tests\Stub\ThroughIntermediaryVersioned:
One:
Defining: =>Symbiote\GridFieldExtensions\Tests\Stub\ThroughDefinerVersioned.DefinerOne
Belonging: =>Symbiote\GridFieldExtensions\Tests\Stub\ThroughBelongsVersioned.BelongsOne
Sort: 3
Two:
Defining: =>Symbiote\GridFieldExtensions\Tests\Stub\ThroughDefinerVersioned.DefinerOne
Belonging: =>Symbiote\GridFieldExtensions\Tests\Stub\ThroughBelongsVersioned.BelongsTwo
Sort: 2
Three:
Defining: =>Symbiote\GridFieldExtensions\Tests\Stub\ThroughDefinerVersioned.DefinerOne
Belonging: =>Symbiote\GridFieldExtensions\Tests\Stub\ThroughBelongsVersioned.BelongsThree
Sort: 1
Four:
Defining: =>Symbiote\GridFieldExtensions\Tests\Stub\ThroughDefinerVersioned.DefinerTwo
Belonging: =>Symbiote\GridFieldExtensions\Tests\Stub\ThroughBelongsVersioned.BelongsTwo
Sort: 1
Five:
Defining: =>Symbiote\GridFieldExtensions\Tests\Stub\ThroughDefinerVersioned.DefinerTwo
Belonging: =>Symbiote\GridFieldExtensions\Tests\Stub\ThroughBelongsVersioned.BelongsThree
Sort: 2

View File

@ -30,13 +30,13 @@ class OrderableRowsThroughVersionedTest extends SapphireTest
protected $originalReadingMode;
protected function setUp()
protected function setUp(): void
{
parent::setUp();
$this->orignalReadingMode = Versioned::get_reading_mode();
}
protected function tearDown()
protected function tearDown(): void
{
Versioned::set_reading_mode($this->originalReadingMode);
unset($this->originalReadingMode);
@ -80,11 +80,11 @@ class OrderableRowsThroughVersionedTest extends SapphireTest
$originalOrder = $parent->$relationName()->sort($sortName)->column('ID');
// Ring (un)shift by one, e.g. 3,2,1 becomes 1,3,2.
// then string key our new order starting at 1
$desiredOrder = array_values($originalOrder);
$desiredOrder = array_values($originalOrder ?? []);
array_unshift($desiredOrder, array_pop($desiredOrder));
$desiredOrder = array_combine(
range('1', count($desiredOrder)),
$desiredOrder
range('1', count($desiredOrder ?? [])),
$desiredOrder ?? []
);
$this->assertNotEquals($originalOrder, $desiredOrder);

View File

@ -0,0 +1,15 @@
<?php
namespace Symbiote\GridFieldExtensions\Tests\Stub;
use SilverStripe\Dev\TestOnly;
use SilverStripe\ORM\DataObject;
class PolymorphM2MChild extends DataObject implements TestOnly
{
private static $table_name = 'TestOnly_PolymorphM2MChild';
private static $has_many = [
'Parents' => PolymorphM2MMapper::class
];
}

View File

@ -0,0 +1,22 @@
<?php
namespace Symbiote\GridFieldExtensions\Tests\Stub;
use SilverStripe\Dev\TestOnly;
use SilverStripe\ORM\DataObject;
class PolymorphM2MMapper extends DataObject implements TestOnly
{
private static $table_name = 'TestOnly_PolymorphM2MMapper';
private static $db = [
'Sort' => 'Int'
];
private static $has_one = [
'Parent' => DataObject::class, // PolymorphM2MParent
'Child' => PolymorphM2MChild::class,
];
private static $default_sort = '"Sort" ASC';
}

View File

@ -0,0 +1,19 @@
<?php
namespace Symbiote\GridFieldExtensions\Tests\Stub;
use SilverStripe\Dev\TestOnly;
use SilverStripe\ORM\DataObject;
class PolymorphM2MParent extends DataObject implements TestOnly
{
private static $table_name = 'TableOnly_PolymorphM2MParent';
private static $many_many = [
'Children' => [
'through' => PolymorphM2MMapper::class,
'from' => 'Parent',
'to' => 'Child',
]
];
}

View File

@ -9,7 +9,7 @@ class StubA implements TestOnly
public function i18n_singular_name()
{
$class = get_class($this);
return substr($class, -1);
return substr($class ?? '', -1);
}
public function canCreate()

View File

@ -15,10 +15,12 @@ class StubParent extends DataObject implements TestOnly
private static $many_many = [
'MyManyMany' => StubOrdered::class,
'MyManyManyVersioned' => StubSubclassOrderedVersioned::class,
];
private static $many_many_extraFields = [
'MyManyMany' => ['ManyManySort' => 'Int'],
'MyManyManyVersioned' => ['ManyManySort' => 'Int'],
];
private static $table_name = 'StubParent';

View File

@ -12,4 +12,16 @@ class StubUnorderable extends DataObject implements TestOnly
];
private static $table_name = 'StubUnorderable';
private $canEdit = false;
public function setCanEdit($canEdit)
{
$this->canEdit = $canEdit;
}
public function canEdit($member = null)
{
return $this->canEdit;
}
}

View File

@ -0,0 +1,10 @@
<?php
namespace Symbiote\GridFieldExtensions\Tests\Stub;
use SilverStripe\Control\Controller;
class TestController extends Controller
{
private static $url_segment = 'test';
}

View File

@ -0,0 +1,25 @@
<?php
namespace Symbiote\GridFieldExtensions\Tests\Stub;
use SilverStripe\Dev\TestOnly;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\ManyManyList;
use SilverStripe\Versioned\Versioned;
/**
* @method ManyManyList|ThroughDefinerVersioned[] Definers()
* @mixin Versioned
*/
class ThroughBelongsVersioned extends DataObject implements TestOnly
{
private static string $table_name = 'ThroughBelongsVersioned';
private static array $belongs_many_many = [
'Definers' => ThroughDefinerVersioned::class,
];
private static array $extensions = [
Versioned::class,
];
}

View File

@ -0,0 +1,33 @@
<?php
namespace Symbiote\GridFieldExtensions\Tests\Stub;
use SilverStripe\Dev\TestOnly;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\ManyManyThroughList;
use SilverStripe\Versioned\Versioned;
/**
* @method ManyManyThroughList|ThroughIntermediaryVersioned Belongings()
* @mixin Versioned
*/
class ThroughDefinerVersioned extends DataObject implements TestOnly
{
private static string $table_name = 'ThroughDefinerVersioned';
private static array $many_many = [
'Belongings' => [
'through' => ThroughIntermediaryVersioned::class,
'from' => 'Defining',
'to' => 'Belonging',
]
];
private static array $owns = [
'Belongings'
];
private static array $extensions = [
Versioned::class,
];
}

View File

@ -0,0 +1,32 @@
<?php
namespace Symbiote\GridFieldExtensions\Tests\Stub;
use SilverStripe\Dev\TestOnly;
use SilverStripe\ORM\DataObject;
use SilverStripe\Versioned\Versioned;
/**
* @property int $DefiningID
* @property int $BelongingID
* @method ThroughDefinerVersioned Defining()
* @method ThroughBelongsVersioned Belonging()
* @mixin Versioned
*/
class ThroughIntermediaryVersioned extends DataObject implements TestOnly
{
private static string $table_name = 'ThroughIntermediaryVersioned';
private static array $db = [
'Sort' => 'Int',
];
private static array $has_one = [
'Defining' => ThroughDefinerVersioned::class,
'Belonging' => ThroughBelongsVersioned::class,
];
private static array $extensions = [
Versioned::class,
];
}

View File

@ -0,0 +1,22 @@
<?php
namespace Symbiote\GridFieldExtensions\Tests\Stub;
use SilverStripe\Dev\TestOnly;
use SilverStripe\ORM\DataObject;
class TitleArraySortedObject extends DataObject implements TestOnly
{
private static $db = [
'Title' => 'Varchar',
'Iden' => 'Varchar',
'OtherSort' => 'Int'
];
private static array $default_sort = [
'Title' => 'ASC',
'OtherSort' => 'ASC',
];
private static $table_name = 'TitleArraySortedObject';
}

View File

@ -0,0 +1,15 @@
<?php
namespace Symbiote\GridFieldExtensions\Tests\Stub;
use SilverStripe\Dev\TestOnly;
use SilverStripe\ORM\DataObject;
class TitleObject extends DataObject implements TestOnly
{
private static $db = [
'Title' => 'Varchar',
];
private static $table_name = 'TitleObject';
}

View File

@ -0,0 +1,19 @@
<?php
namespace Symbiote\GridFieldExtensions\Tests\Stub;
use SilverStripe\Dev\TestOnly;
use SilverStripe\ORM\DataObject;
class TitleSortedObject extends DataObject implements TestOnly
{
private static $db = [
'Title' => 'Varchar',
'Iden' => 'Varchar',
'DefaultSort' => 'Int'
];
private static $default_sort = '"DefaultSort" ASC';
private static $table_name = 'TitleSortedObject';
}