Compare commits
83 Commits
Author | SHA1 | Date |
---|---|---|
UndefinedOffset | f6ce5741ab | |
UndefinedOffset | b1febae3d8 | |
UndefinedOffset | 9e5908c4ef | |
UndefinedOffset | 09f7be61ae | |
UndefinedOffset | 402dab8faa | |
UndefinedOffset | bb65d01748 | |
UndefinedOffset | e3d92e774a | |
UndefinedOffset | 237716571f | |
UndefinedOffset | 3940a7475f | |
UndefinedOffset | 29957be873 | |
UndefinedOffset | c3915cc2b8 | |
UndefinedOffset | 255347b755 | |
UndefinedOffset | eabbe33342 | |
Ed Chipman | f5a5346349 | |
UndefinedOffset | 66dfcc25ad | |
UndefinedOffset | 6f44c555cd | |
UndefinedOffset | 8ed1621f8b | |
UndefinedOffset | 5f37c8a0b4 | |
UndefinedOffset | e1b1bbf8b3 | |
UndefinedOffset | c965eb0c2e | |
Guy Sartorelli | e374c93ae3 | |
UndefinedOffset | fff3f08901 | |
Robbie Averill | 7bdeebb6cd | |
Samuel Mulliss | 6a14bfbcc1 | |
Ed Chipman | 51c43642ff | |
Steve Boyd | c3d202d4a0 | |
Ed Chipman | ee5f10e1e7 | |
Nicolaas | 902fe50c96 | |
Nicolaas | a0d1272238 | |
Nicolaas | f1a9c92784 | |
UndefinedOffset | 74756cad52 | |
UndefinedOffset | dd955ff1bb | |
Robbie Averill | 30b50a0597 | |
Nicolaas | 2e9d0e6b33 | |
UndefinedOffset | af492d0267 | |
UndefinedOffset | 35775ad2ce | |
UndefinedOffset | aef0a8acc1 | |
UndefinedOffset | 3ab5aadf45 | |
UndefinedOffset | a622fd4d6f | |
UndefinedOffset | cd86fe2fd4 | |
UndefinedOffset | fc83d6813e | |
UndefinedOffset | 8a2417a750 | |
UndefinedOffset | 504387d711 | |
UndefinedOffset | bc633e151d | |
UndefinedOffset | ae12e74aa8 | |
UndefinedOffset | 97b526ea87 | |
ChrissiQ | 118838fb79 | |
UndefinedOffset | 5e3e5cac3f | |
UndefinedOffset | dc11841e11 | |
UndefinedOffset | 6cfc1b7338 | |
UndefinedOffset | 20da27f7dd | |
UndefinedOffset | e53e3622a4 | |
UndefinedOffset | ecbe9b904a | |
UndefinedOffset | 12cd5776c1 | |
UndefinedOffset | e6eefdffd3 | |
Daniel Hensby | d8c379879f | |
UndefinedOffset | 8254ce7fe7 | |
UndefinedOffset | f0110c11e2 | |
UndefinedOffset | 0c66fa0ec6 | |
UndefinedOffset | fe104efad8 | |
UndefinedOffset | 21289b42f5 | |
UndefinedOffset | 2bde7362cd | |
UndefinedOffset | b70ec00945 | |
UndefinedOffset | 386fa1053d | |
UndefinedOffset | 710b94e25b | |
UndefinedOffset | 7e8cdd9c2b | |
UndefinedOffset | 9ea5caa91c | |
UndefinedOffset | b38d7f6f04 | |
UndefinedOffset | c537c86567 | |
UndefinedOffset | bf1f27e075 | |
UndefinedOffset | fc150881f2 | |
UndefinedOffset | c0c0518ae9 | |
UndefinedOffset | 1925d5151e | |
UndefinedOffset | 5dc5bbc908 | |
UndefinedOffset | d3fd38e54c | |
UndefinedOffset | 08a0781d56 | |
UndefinedOffset | 21a6f3c8e8 | |
UndefinedOffset | e5d442cabe | |
UndefinedOffset | f0fbbd5650 | |
UndefinedOffset | 72d458c819 | |
Reece | 23da810b19 | |
Reece | 1862700761 | |
Reece | d88af0c513 |
|
@ -2,3 +2,4 @@
|
|||
/docs export-ignore
|
||||
/.gitignore export-ignore
|
||||
/.travis.yml export-ignore
|
||||
/.github export-ignore
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
## Affected Version
|
||||
|
||||
Show version numbers by pasting the output of `composer info --direct`.
|
||||
Alternatively, hover over the SilverStripe logo in the CMS to basic version information.
|
||||
|
||||
## Description
|
||||
|
||||
Describe expected and observed behaviour.
|
||||
For visual issues, please include browser version and screenshots.
|
||||
Please read https://docs.silverstripe.org/en/contributing/issues_and_bugs/
|
||||
|
||||
## Steps to Reproduce
|
||||
|
||||
Help us with step-by-step instructions.
|
|
@ -0,0 +1,5 @@
|
|||
Thanks for contributing, you're awesome! :star:
|
||||
Please describe expected and observed behaviour, and what you're fixing.
|
||||
For visual fixes, please include tested browsers and screenshots.
|
||||
Search for related existing issues and link to them if possible.
|
||||
Please read https://github.com/UndefinedOffset/SortableGridField/blob/master/CONTRIBUTING.md
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"problemMatcher": [
|
||||
{
|
||||
"owner": "phpcs",
|
||||
"severity": "error",
|
||||
"pattern": [
|
||||
{
|
||||
"regexp": "^<file name=\"(?:\\/github\\/workspace\\/)?(.*)\">$",
|
||||
"file": 1
|
||||
},
|
||||
{
|
||||
"regexp": "<error line=\"(\\d*)\" column=\"(\\d*)\" severity=\"(error|warning)\" message=\"(.*)\" source=\"(.*)(\"\\/>+)$",
|
||||
"line": 1,
|
||||
"column": 2,
|
||||
"severity": 3,
|
||||
"message": 4,
|
||||
"code": 5,
|
||||
"loop": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,241 @@
|
|||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ '**' ]
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '*.md'
|
||||
pull_request:
|
||||
branches: [ '**' ]
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '*.md'
|
||||
|
||||
|
||||
|
||||
jobs:
|
||||
silverstripe_5_php81:
|
||||
name: "Silverstripe 5.0 | PHP 8.1"
|
||||
runs-on: ubuntu-latest
|
||||
if: "!contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '[ci skip]')"
|
||||
env:
|
||||
php_version: 8.1
|
||||
php_extensions: ctype, dom, fileinfo, hash, intl, mbstring, session, simplexml, tokenizer, xml, pdo, mysqli, gd, zip
|
||||
services:
|
||||
mysql:
|
||||
image: mysql:5.7
|
||||
env:
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: false
|
||||
MYSQL_ROOT_PASSWORD: testpassword
|
||||
MYSQL_DATABASE: test_db
|
||||
ports:
|
||||
- 3306/tcp
|
||||
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup PHP Extension Cache
|
||||
id: cache-env
|
||||
uses: shivammathur/cache-extensions@v1
|
||||
with:
|
||||
php-version: ${{ env.php_version }}
|
||||
extensions: ${{ env.php_extensions }}
|
||||
key: php74-ext-cache-${{ hashFiles('.github/workflows/ci.yml') }}
|
||||
|
||||
- name: Cache PHP Extensions
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ steps.cache-env.outputs.dir }}
|
||||
key: ${{ steps.cache-env.outputs.key }}
|
||||
restore-keys: ${{ steps.cache-env.outputs.key }}
|
||||
|
||||
- name: Setup PHP, with composer and extensions
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ env.php_version }}
|
||||
extensions: ${{ env.php_extensions }}
|
||||
ini-values: log_errors=On, error_log="${{github.workspace}}/artifacts/php_errors.log"
|
||||
coverage: none
|
||||
tools: composer:v2
|
||||
|
||||
- name: Get composer cache directory
|
||||
id: composer-cache
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
key: ${{ runner.os }}-composer-ss5-php81-${{ hashFiles('**/composer.json') }}-${{ hashFiles('.github/workflows/ci.yml') }}
|
||||
restore-keys: ${{ runner.os }}-composer-ss5-php81-
|
||||
|
||||
- name: Install Composer dependencies
|
||||
env:
|
||||
GITHUB_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
composer self-update --ansi || true
|
||||
if [[ $GITHUB_ACCESS_TOKEN ]]; then composer config --ansi -g github-oauth.github.com $GITHUB_ACCESS_TOKEN; fi
|
||||
composer config allow-plugins.composer/installers true
|
||||
composer config allow-plugins.silverstripe/recipe-plugin true
|
||||
composer config allow-plugins.silverstripe/vendor-plugin true
|
||||
composer require silverstripe/admin 2.0.* --no-update
|
||||
composer require silverstripe/versioned 2.0.*
|
||||
composer install --verbose --no-interaction --no-progress --no-suggest --optimize-autoloader --ansi
|
||||
|
||||
- name: Configure Environment
|
||||
run: |
|
||||
cp tests/utils/actions.env.template .env
|
||||
mkdir artifacts
|
||||
|
||||
- name: Perform PHPUnit Tests
|
||||
env:
|
||||
SS_DATABASE_PORT: ${{ job.services.mysql.ports['3306'] }}
|
||||
run: vendor/bin/phpunit --colors=always --printer UndefinedOffset\\SortableGridField\\Tests\\PHPUnit\\Bootstrap\\GitHubActionsAnnotatorPrinter
|
||||
|
||||
silverstripe_411_php80:
|
||||
name: "Silverstripe 4.11 | PHP 8.0"
|
||||
runs-on: ubuntu-latest
|
||||
if: "!contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '[ci skip]')"
|
||||
env:
|
||||
php_version: 8.0
|
||||
php_extensions: ctype, dom, fileinfo, hash, intl, mbstring, session, simplexml, tokenizer, xml, pdo, mysqli, gd, zip
|
||||
services:
|
||||
mysql:
|
||||
image: mysql:5.7
|
||||
env:
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: false
|
||||
MYSQL_ROOT_PASSWORD: testpassword
|
||||
MYSQL_DATABASE: test_db
|
||||
ports:
|
||||
- 3306/tcp
|
||||
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup PHP Extension Cache
|
||||
id: cache-env
|
||||
uses: shivammathur/cache-extensions@v1
|
||||
with:
|
||||
php-version: ${{ env.php_version }}
|
||||
extensions: ${{ env.php_extensions }}
|
||||
key: php80-ext-cache-${{ hashFiles('.github/workflows/ci.yml') }}
|
||||
|
||||
- name: Cache PHP Extensions
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ steps.cache-env.outputs.dir }}
|
||||
key: ${{ steps.cache-env.outputs.key }}
|
||||
restore-keys: ${{ steps.cache-env.outputs.key }}
|
||||
|
||||
- name: Setup PHP, with composer and extensions
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ env.php_version }}
|
||||
extensions: ${{ env.php_extensions }}
|
||||
ini-values: log_errors=On, error_log="${{github.workspace}}/artifacts/php_errors.log"
|
||||
coverage: none
|
||||
tools: composer:v2
|
||||
|
||||
- name: Get composer cache directory
|
||||
id: composer-cache
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
key: ${{ runner.os }}-composer-ss411-php80-${{ hashFiles('**/composer.json') }}-${{ hashFiles('.github/workflows/ci.yml') }}
|
||||
restore-keys: ${{ runner.os }}-composer-ss411-php80-
|
||||
|
||||
- name: Install Composer dependencies
|
||||
env:
|
||||
GITHUB_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
composer self-update --ansi || true
|
||||
if [[ $GITHUB_ACCESS_TOKEN ]]; then composer config --ansi -g github-oauth.github.com $GITHUB_ACCESS_TOKEN; fi
|
||||
composer config allow-plugins.composer/installers true
|
||||
composer config allow-plugins.silverstripe/recipe-plugin true
|
||||
composer config allow-plugins.silverstripe/vendor-plugin true
|
||||
composer require silverstripe/admin 1.11.* --no-update
|
||||
composer require silverstripe/versioned 1.11.*
|
||||
composer install --verbose --no-interaction --no-progress --no-suggest --optimize-autoloader --ansi
|
||||
|
||||
- name: Configure Environment
|
||||
run: |
|
||||
cp tests/utils/actions.env.template .env
|
||||
mkdir artifacts
|
||||
|
||||
- name: Perform PHPUnit Tests
|
||||
env:
|
||||
SS_DATABASE_PORT: ${{ job.services.mysql.ports['3306'] }}
|
||||
run: vendor/bin/phpunit --colors=always --printer UndefinedOffset\\SortableGridField\\Tests\\PHPUnit\\Bootstrap\\GitHubActionsAnnotatorPrinter
|
||||
|
||||
phpcs:
|
||||
name: "PHP_CodeSniffer"
|
||||
runs-on: ubuntu-latest
|
||||
if: "!contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '[ci skip]')"
|
||||
env:
|
||||
php_version: 8.0
|
||||
php_extensions: ctype, dom, fileinfo, hash, intl, mbstring, session, simplexml, tokenizer, xml, pdo, mysqli, gd, zip
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup PHP Extension Cache
|
||||
id: cache-env
|
||||
uses: shivammathur/cache-extensions@v1
|
||||
with:
|
||||
php-version: ${{ env.php_version }}
|
||||
extensions: ${{ env.php_extensions }}
|
||||
key: php74-ext-cache-${{ hashFiles('.github/workflows/ci.yml') }}
|
||||
|
||||
- name: Cache PHP Extensions
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ steps.cache-env.outputs.dir }}
|
||||
key: ${{ steps.cache-env.outputs.key }}
|
||||
restore-keys: ${{ steps.cache-env.outputs.key }}
|
||||
|
||||
- name: Setup PHP, with composer and extensions
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ env.php_version }}
|
||||
extensions: ${{ env.php_extensions }}
|
||||
ini-values: log_errors=On, error_log="${{github.workspace}}/artifacts/php_errors.log"
|
||||
coverage: none
|
||||
tools: composer:v2
|
||||
|
||||
- name: Get composer cache directory
|
||||
id: composer-cache
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
key: ${{ runner.os }}-composer-phpcs-${{ hashFiles('.github/workflows/ci.yml') }}
|
||||
restore-keys: ${{ runner.os }}-composer-phpcs-
|
||||
|
||||
- name: Install Composer dependencies
|
||||
env:
|
||||
GITHUB_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
rm composer.json
|
||||
composer self-update --ansi || true
|
||||
if [[ $GITHUB_ACCESS_TOKEN ]]; then composer config --ansi -g github-oauth.github.com $GITHUB_ACCESS_TOKEN; fi
|
||||
composer require squizlabs/php_codesniffer ~3.4
|
||||
composer install --verbose --no-interaction --no-progress --no-suggest --optimize-autoloader --ansi
|
||||
mkdir artifacts
|
||||
|
||||
- name: Validate Code Style
|
||||
run: vendor/bin/phpcs --colors --report=full --report-checkstyle=artifacts/phpcs.xml
|
||||
|
||||
- name: Annotate Code Style Issues
|
||||
if: failure()
|
||||
run: (test -f artifacts/phpcs.xml && echo "::add-matcher::.github/matchers/phpcs.json" && cat artifacts/phpcs.xml && echo "::remove-matcher owner=phpcs::")
|
|
@ -2,4 +2,5 @@
|
|||
/.buildpath
|
||||
/.project
|
||||
/.settings
|
||||
/.settings/*
|
||||
/.settings/*
|
||||
.phpunit.result.cache
|
||||
|
|
|
@ -66,4 +66,4 @@ checks:
|
|||
argument_type_checks: true
|
||||
|
||||
filter:
|
||||
paths: [code/*, tests/*]
|
||||
paths: [src/*, tests/*]
|
||||
|
|
45
.travis.yml
45
.travis.yml
|
@ -1,23 +1,42 @@
|
|||
language: php
|
||||
|
||||
sudo: false
|
||||
dist: xenial
|
||||
|
||||
services:
|
||||
- mysql
|
||||
- postgresql
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.composer/cache/files
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- php: 5.6
|
||||
env: DB=PGSQL CORE_RELEASE=3.6
|
||||
- php: 5.6
|
||||
env: DB=SQLITE3 CORE_RELEASE=3.6
|
||||
- php: 5.6
|
||||
env: DB=MYSQL CORE_RELEASE=3.6
|
||||
- php: 5.6
|
||||
env: DB=MYSQL CORE_RELEASE=3.5
|
||||
env: DB=MYSQL CORE_RELEASE=4.4.x-dev PHPUNIT_TEST=1
|
||||
- php: 7.1
|
||||
env: DB=MYSQL CORE_RELEASE=4.5.x-dev PHPUNIT_TEST=1 PDO=1
|
||||
- php: 7.2
|
||||
env: DB=PGSQL CORE_RELEASE=4.6.x-dev PHPUNIT_TEST=1
|
||||
- php: 7.3
|
||||
env: DB=MYSQL CORE_RELEASE=4.6.x-dev PHPUNIT_TEST=1
|
||||
- php: 7.4
|
||||
env: DB=MYSQL CORE_RELEASE=4.x-dev PHPUNIT_TEST=1
|
||||
|
||||
before_script:
|
||||
- phpenv rehash
|
||||
- git clone git://github.com/silverstripe-labs/silverstripe-travis-support.git ~/travis-support
|
||||
- php ~/travis-support/travis_setup.php --source `pwd` --target ~/builds/ss
|
||||
- cd ~/builds/ss
|
||||
# Init PHP
|
||||
- composer self-update || true
|
||||
- phpenv rehash
|
||||
- phpenv config-rm xdebug.ini
|
||||
|
||||
# Install composer dependencies
|
||||
- composer validate
|
||||
- composer require --no-update silverstripe/recipe-core:$CORE_RELEASE
|
||||
- composer require --no-update phpunit/phpunit:^5.7
|
||||
# Fix for running phpunit 5 on php 7.4+
|
||||
- composer require --no-update sminnee/phpunit-mock-objects:^3
|
||||
- if [[ $DB == PGSQL ]]; then composer require silverstripe/postgresql:^2 --prefer-dist --no-update; fi
|
||||
- composer install --prefer-dist --no-interaction --no-progress --no-suggest --optimize-autoloader --verbose --profile
|
||||
|
||||
script:
|
||||
- phpunit sortablegridfield/tests/
|
||||
- vendor/bin/phpunit
|
||||
|
|
69
CHANGELOG.md
69
CHANGELOG.md
|
@ -1,5 +1,70 @@
|
|||
# Change Log
|
||||
|
||||
## [2.2.0](https://github.com/UndefinedOffset/SortableGridField/tree/2.2.0) (2023-05-08)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/2.1.0...2.2.0)
|
||||
|
||||
## [2.1.0](https://github.com/UndefinedOffset/SortableGridField/tree/2.1.0) (2022-07-06)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/2.0.9...2.1.0)
|
||||
|
||||
## [2.0.9](https://github.com/UndefinedOffset/SortableGridField/tree/2.0.9) (2021-07-19)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/2.0.8...2.0.9)
|
||||
|
||||
## [2.0.8](https://github.com/UndefinedOffset/SortableGridField/tree/2.0.8) (2019-01-08)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/2.0.7...2.0.8)
|
||||
|
||||
## [2.0.7](https://github.com/UndefinedOffset/SortableGridField/tree/2.0.7) (2018-12-13)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/2.0.6...2.0.7)
|
||||
|
||||
## [2.0.6](https://github.com/UndefinedOffset/SortableGridField/tree/2.0.6) (2018-07-04)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/2.0.5...2.0.6)
|
||||
|
||||
## [2.0.5](https://github.com/UndefinedOffset/SortableGridField/tree/2.0.5) (2018-06-07)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/2.0.4...2.0.5)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Int to DBInt [\#120](https://github.com/UndefinedOffset/SortableGridField/issues/120)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Fixes "undefined offset" error when moving a many\_many item to previous page [\#121](https://github.com/UndefinedOffset/SortableGridField/pull/121) ([ChrissiQ](https://github.com/ChrissiQ))
|
||||
|
||||
## [2.0.4](https://github.com/UndefinedOffset/SortableGridField/tree/2.0.4) (2018-03-07)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/2.0.3...2.0.4)
|
||||
|
||||
## [2.0.3](https://github.com/UndefinedOffset/SortableGridField/tree/2.0.3) (2018-03-01)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/2.0.2...2.0.3)
|
||||
|
||||
## [2.0.2](https://github.com/UndefinedOffset/SortableGridField/tree/2.0.2) (2017-12-11)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/2.0.1...2.0.2)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- many\_many ss 3.6 GridFieldAddNewMultiClass Column 'SortOrder' in field list is ambiguous [\#114](https://github.com/UndefinedOffset/SortableGridField/issues/114)
|
||||
- mapTableNameAndReturn can't parse namespace+classname into mysql tablename [\#113](https://github.com/UndefinedOffset/SortableGridField/issues/113)
|
||||
|
||||
## [2.0.1](https://github.com/UndefinedOffset/SortableGridField/tree/2.0.1) (2017-11-29)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/2.0.0...2.0.1)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Many Many relationships are broken due to renaming of many\_many and many\_many\_extraFields to manyMany and manyManyExtraFields [\#110](https://github.com/UndefinedOffset/SortableGridField/issues/110)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Merge 1.0.x into master [\#112](https://github.com/UndefinedOffset/SortableGridField/pull/112) ([dhensby](https://github.com/dhensby))
|
||||
- DOCS Update docs examples to be 3.1+ relevant [\#111](https://github.com/UndefinedOffset/SortableGridField/pull/111) ([dhensby](https://github.com/dhensby))
|
||||
|
||||
## [2.0.0](https://github.com/UndefinedOffset/SortableGridField/tree/2.0.0) (2017-11-24)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/2.0.0-beta2...2.0.0)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- SilverStripe 4 Compatibility [\#103](https://github.com/UndefinedOffset/SortableGridField/issues/103)
|
||||
|
||||
## [2.0.0-beta2](https://github.com/UndefinedOffset/SortableGridField/tree/2.0.0-beta2) (2017-11-01)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/1.0.0...2.0.0-beta2)
|
||||
|
||||
## [1.0.0](https://github.com/UndefinedOffset/SortableGridField/tree/1.0.0) (2017-10-27)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/0.6.10...1.0.0)
|
||||
|
||||
|
@ -303,7 +368,3 @@
|
|||
- German Translation [\#9](https://github.com/UndefinedOffset/SortableGridField/pull/9) ([PatrickElsing](https://github.com/PatrickElsing))
|
||||
- Update lang/en.yml [\#8](https://github.com/UndefinedOffset/SortableGridField/pull/8) ([PatrickElsing](https://github.com/PatrickElsing))
|
||||
- Renamed the Items array that is sent in post [\#7](https://github.com/UndefinedOffset/SortableGridField/pull/7) ([sheadawson](https://github.com/sheadawson))
|
||||
|
||||
|
||||
|
||||
\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
|
2
LICENSE
2
LICENSE
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2017, Ed Chipman
|
||||
Copyright (c) 2024, Ed Chipman
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
|
|
135
README.md
135
README.md
|
@ -1,27 +1,42 @@
|
|||
SortableGridField
|
||||
=================
|
||||
[![Build Status](https://travis-ci.org/UndefinedOffset/SortableGridField.png)](https://travis-ci.org/UndefinedOffset/SortableGridField) ![helpfulrobot](https://helpfulrobot.io/undefinedoffset/sortablegridfield/badge)
|
||||
|
||||
Adds drag and drop functionality to SilverStripe 3's GridField
|
||||
[![CI](https://github.com/UndefinedOffset/SortableGridField/actions/workflows/ci.yml/badge.svg)](https://github.com/UndefinedOffset/SortableGridField/actions/workflows/ci.yml)
|
||||
[![Latest Stable Version](https://poser.pugx.org/undefinedoffset/sortablegridfield/version.svg)](http://www.silverstripe.org/stable-download/)
|
||||
[![Latest Unstable Version](https://poser.pugx.org/undefinedoffset/sortablegridfield/v/unstable.svg)](https://packagist.org/packages/undefinedoffset/sortablegridfield)
|
||||
[![Total Downloads](https://poser.pugx.org/undefinedoffset/sortablegridfield/downloads.svg)](https://packagist.org/packages/undefinedoffset/sortablegridfield)
|
||||
[![License](https://poser.pugx.org/undefinedoffset/sortablegridfield/license.svg)](https://github.com/UndefinedOffset/SortableGridField/blob/master/LICENSE)
|
||||
|
||||
Adds drag and drop functionality to Silverstripe's GridField
|
||||
|
||||
## Requirements
|
||||
* SilverStripe 3.x
|
||||
|
||||
* Silverstripe 4.11+ or 5.0+
|
||||
|
||||
## Installation
|
||||
__Composer (recommended):__
|
||||
```
|
||||
|
||||
Installation is supported via composer only
|
||||
|
||||
```sh
|
||||
composer require undefinedoffset/sortablegridfield
|
||||
```
|
||||
|
||||
If you prefer you may also install manually:
|
||||
* Download the module from here https://github.com/UndefinedOffset/SortableGridField/archive/master.zip
|
||||
* Extract the downloaded archive into your site root so that the destination folder is called SortableGridField, opening the extracted folder should contain _config.php in the root along with other files/folders
|
||||
* Run dev/build?flush=all to regenerate the manifest
|
||||
* Upon entering the cms and using GridFieldSortableRows component for the first time you make need to add ?flush=all to the end of the address to force the templates to regenerate
|
||||
|
||||
* Run `dev/build?flush=all` to regenerate the manifest
|
||||
* Upon entering the cms and using `GridFieldSortableRows` component for the first time you make need to add `?flush=all`
|
||||
to the end of the address to force the templates to regenerate
|
||||
|
||||
## Usage
|
||||
To enable sorting on a has_many relationship set up an integer field on your data object. Also for has_many relationships make sure to set the $default_sort on the dataobject to this new integer field to ensure that the sort order is applied when the relationship is requested. For many_many relationships you must add a $many_many_extraFields static to the data object defining the relationship, see the SilverStripe documentation for more information on this. If you are using a many_many relationship you will need to do a custom getter to set the sort order of this relationship for use on the front end see below for an example. As well for many_many relationships the name of the GridField *must* be the same as the relationship name other wise error's will occur. For new DataObjects you do not need to increment the Sort order yourself in your DataObject GridFieldSortableRows will automatically do this the next time the grid is displayed.
|
||||
|
||||
To enable sorting on a `has_many` relationship set up an integer field on your data object. Also for `has_many`
|
||||
relationships make sure to set the `$default_sort` on the `DataObject` to this new integer field to ensure that the sort
|
||||
order is applied when the relationship is requested. For `many_many` relationships you must add a
|
||||
`$many_many_extraFields` static to the `DataObject` defining the relationship, see the
|
||||
[SilverStripe documentation](https://docs.silverstripe.org/en/3/developer_guides/model/relations/#many-many)
|
||||
for more information on this. If you are using a `many_many` relationship you will need to do a custom getter to set the
|
||||
sort order of this relationship for use on the front end see below for an example. As well for `many_many` relationships
|
||||
the name of the GridField *must* be the same as the relationship name other wise error's will occur. For new
|
||||
`DataObject`s you do not need to increment the sort order yourself in your `DataObject`, `GridFieldSortableRows` will
|
||||
automatically do this the next time the grid is displayed.
|
||||
|
||||
```php
|
||||
public function getMyManyManyRelationship() {
|
||||
|
@ -29,68 +44,104 @@ public function getMyManyManyRelationship() {
|
|||
}
|
||||
```
|
||||
|
||||
|
||||
To enable drag and drop sorting on the grid field add the following to your grid field's config
|
||||
*Grid Field Config*
|
||||
To enable drag and drop sorting on the `GridField` add the following to your `GridField`'s config, also make sure you add
|
||||
the namespace `UndefinedOffset\SortableGridField\Forms` to your file.
|
||||
|
||||
```php
|
||||
//Namespace imports should be added to the top of your file
|
||||
use UndefinedOffset\SortableGridField\Forms\GridFieldSortableRows;
|
||||
|
||||
$myGridConfig->addComponent(new GridFieldSortableRows('{Column to store sort}'));
|
||||
```
|
||||
|
||||
To move an item to another page drag the row over the respective move to page button which appear on the left and right of the GridField and release.
|
||||
To move an item to another page drag the row over the respective move to page button which appear on the left and right
|
||||
of the GridField and release.
|
||||
|
||||
#### Full code Examples
|
||||
* [has_many relationship] (https://github.com/UndefinedOffset/SortableGridField/blob/master/docs/HasManyExample.md)
|
||||
* [many_many relationship] (https://github.com/UndefinedOffset/SortableGridField/blob/master/docs/ManyManyExample.md)
|
||||
* [ModelAdmin implementation] (https://github.com/UndefinedOffset/SortableGridField/blob/master/docs/ModelAdminExample.md)
|
||||
|
||||
* [has_many relationship](https://github.com/UndefinedOffset/SortableGridField/blob/master/docs/HasManyExample.md)
|
||||
* [many_many relationship](https://github.com/UndefinedOffset/SortableGridField/blob/master/docs/ManyManyExample.md)
|
||||
* [ModelAdmin implementation](https://github.com/UndefinedOffset/SortableGridField/blob/master/docs/ModelAdminExample.md)
|
||||
|
||||
#### Events
|
||||
GridFieldSortableRows provides 4 "events" onBeforeGridFieldRowSort(), onAfterGridFieldRowSort(), onBeforeGridFieldPageSort() and onAfterGridFieldPageSort(). These "events" are passed a clone of the DataList used in GridFieldSortableRows, in the case of page sorting this list has a limit that shows you the current page plus/minus one object. For GridFieldSortableRows that are on ModelAdmin decendents these events are called on the ModelAdmin if they do not have a owner DataObject, if you are using GridFieldSortableRows on a GridField for a DataObject's relationship the events are called on that DataObject.
|
||||
|
||||
`GridFieldSortableRows` provides 4 "events" `onBeforeGridFieldRowSort()`, `onAfterGridFieldRowSort()`,
|
||||
`onBeforeGridFieldPageSort()` and `onAfterGridFieldPageSort()`. These "events" are passed a clone of the `DataList`
|
||||
used in `GridFieldSortableRows`, in the case of page sorting this list has a limit that shows you the current page
|
||||
plus/minus one object. For `GridFieldSortableRows` that are on `ModelAdmin` descendants these events are called on the
|
||||
`ModelAdmin` if they do not have an owner `DataObject`, if you are using `GridFieldSortableRows` on a `GridField` for a
|
||||
`DataObject`'s relationship the events are called on that `DataObject`.
|
||||
|
||||
#### Appending to the top instead of the bottom
|
||||
By default GridFieldSortableRows appends to the bottom of the list for performance on large data sets, however you can set new records to append new records to the top by calling setAppendToTop(true) on your GridFieldSortableRows instance.
|
||||
|
||||
By default `GridFieldSortableRows` appends to the bottom of the list for performance on large data sets, however you can
|
||||
set new records to append new records to the top by calling `setAppendToTop(true)` on your `GridFieldSortableRows`
|
||||
instance.
|
||||
|
||||
```php
|
||||
$myGridConfig->addComponent($sortable=new GridFieldSortableRows('SortOrder'));
|
||||
//Namespace imports should be added to the top of your file
|
||||
use UndefinedOffset\SortableGridField\Forms\GridFieldSortableRows;
|
||||
|
||||
$myGridConfig->addComponent($sortable = new GridFieldSortableRows('SortOrder'));
|
||||
$sortable->setAppendToTop(true);
|
||||
```
|
||||
|
||||
#### Working with versioned records
|
||||
By default GridFieldSortableRows does not update any other stage for versioned than the base stage. However you can enable this by calling setUpdateVersionedStage() and passing in the name of the stage you want to update along with the base stage. For example passing in "Live" will also update the "Live" stage when any sort happens.
|
||||
|
||||
By default `GridFieldSortableRows` does not update any other stage for versioned than the base stage. However you can
|
||||
enable this by calling `setUpdateVersionedStage()` and passing in the name of the stage you want to update along with
|
||||
the base stage. For example passing in "Live" will also update the "Live" stage when any sort happens.
|
||||
|
||||
```php
|
||||
$myGridConfig->addComponent($sortable=new GridFieldSortableRows('SortOrder'));
|
||||
//Namespace imports should be added to the top of your file
|
||||
use UndefinedOffset\SortableGridField\Forms\GridFieldSortableRows;
|
||||
|
||||
$myGridConfig->addComponent($sortable = new GridFieldSortableRows('SortOrder'));
|
||||
$sortable->setUpdateVersionedStage('Live');
|
||||
```
|
||||
|
||||
#### Overriding the default relationship name
|
||||
By default the relationship name comes from the name of the GridField, however you can override this lookup by calling setCustomRelationName() and passing in the name of the relationship. This allows for you to have multiple GridFields on the same form interacting with the same many_many list maybe filtered slightly differently.
|
||||
|
||||
By default the relationship name comes from the name of the `GridField`, however you can override this lookup by
|
||||
calling `setCustomRelationName()` and passing in the name of the relationship. This allows for you to have multiple
|
||||
`GridFields` on the same form interacting with the same `many_many` list maybe filtered slightly differently.
|
||||
|
||||
```php
|
||||
$myGridConfig->addComponent($sortable=new GridFieldSortableRows('SortOrder'));
|
||||
//Namespace imports should be added to the top of your file
|
||||
use UndefinedOffset\SortableGridField\Forms\GridFieldSortableRows;
|
||||
|
||||
$myGridConfig->addComponent($sortable = new GridFieldSortableRows('SortOrder'));
|
||||
$sortable->setCustomRelationName('MyRelationship');
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Migrating from SilverStripe 2.4 and Data Object Manager's SortableDataObject
|
||||
SortableGridField is not the same as SortableDataObject, since it is only a component of GridField it does not have the ability to catch the object when it is saved for the first time. So SortableGridField uses 1 as the first sort index because 0 is the default for an integer field/column in the database. For migrations from 2.4 with SortableDataObject you need to setup your DataObject based on the instructions above however you must name your sort column "SortOrder" to maintain your sort indexes defined by SortableDataObject. Then you need to run the following query on the table containing your sort field, for many_many relationships this will be something like {RelationshipClass}_{RelationshipName}. This query will maintain your sort order from SortableDataObject but increment the index by 1 giving it a starting number of 1.
|
||||
|
||||
```sql
|
||||
UPDATE YourTable SET SortOrder=SortOrder+1;
|
||||
```
|
||||
|
||||
## Reporting an issue
|
||||
When you're reporting an issue please ensure you specify what version of SilverStripe you are using i.e. 3.0.5, 3.1beta3, 3.0-master etc. Also be sure to include any JavaScript or PHP errors you receive, for PHP errors please ensure you include the full stack trace. Also please include your implementation code (where your setting up your grid field) as well as how you produced the issue. You may also be asked to provide some of the classes to aid in re-producing the issue. Stick with the issue, remember that you seen the issue not the maintainer of the module so it may take allot of questions to arrive at a fix or answer.
|
||||
|
||||
When you're reporting an issue please ensure you specify what version of SilverStripe you are using i.e. 3.0.5,
|
||||
3.1beta3, 3.0-master etc. Also be sure to include any JavaScript or PHP errors you receive, for PHP errors please ensure
|
||||
you include the full stack trace. Also please include your implementation code (where your setting up your grid field)
|
||||
as well as how you produced the issue. You may also be asked to provide some of the classes to aid in re-producing the
|
||||
issue. Stick with the issue, remember that you seen the issue not the maintainer of the module so it may take a lot of
|
||||
questions to arrive at a fix or answer.
|
||||
|
||||
### Notes
|
||||
* When using with GridFieldManyRelationHandler make sure that you add GridFieldSortableRows to your config before for example GridFieldManyRelationHandler:
|
||||
|
||||
```php
|
||||
$config->addComponent(new GridFieldSortableRows('SortOrder'), 'GridFieldManyRelationHandler');
|
||||
```
|
||||
* When using with GridFieldManyRelationHandler make sure that you add GridFieldSortableRows to your config before for
|
||||
example `GridFieldManyRelationHandler`:
|
||||
|
||||
```php
|
||||
//Namespace imports should be added to the top of your file
|
||||
use UndefinedOffset\SortableGridField\Forms\GridFieldSortableRows;
|
||||
|
||||
$config->addComponent(new GridFieldSortableRows('SortOrder'), 'GridFieldManyRelationHandler');
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
### Translations
|
||||
|
||||
Translations of the natural language strings are managed through a third party translation interface, transifex.com. Newly added strings will be periodically uploaded there for translation, and any new translations will be merged back to the project source code.
|
||||
Translations of the natural language strings are managed through a third party translation interface, transifex.com.
|
||||
Newly added strings will be periodically uploaded there for translation, and any new translations will be merged back to
|
||||
the project source code.
|
||||
|
||||
Please use [https://www.transifex.com/projects/p/silverstripe-sortablegridfield](https://www.transifex.com/projects/p/silverstripe-sortablegridfield) to contribute translations, rather than sending pull requests with YAML files.
|
||||
Please use [https://www.transifex.com/projects/p/silverstripe-sortablegridfield](https://www.transifex.com/projects/p/silverstripe-sortablegridfield)
|
||||
to contribute translations, rather than sending pull requests with YAML files.
|
||||
|
|
|
@ -1,3 +1 @@
|
|||
<?php
|
||||
define('SORTABLE_GRIDFIELD_BASE', basename(dirname(__FILE__)));
|
||||
?>
|
|
@ -1,680 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* This component provides a checkbox which when checked enables drag-and-drop re-ordering of elements displayed in a {@link GridField}
|
||||
*
|
||||
* @package forms
|
||||
*/
|
||||
class GridFieldSortableRows implements GridField_HTMLProvider, GridField_ActionProvider, GridField_DataManipulator {
|
||||
protected $sortColumn;
|
||||
protected $disable_selection=true;
|
||||
protected $append_to_top=false;
|
||||
protected $update_versioned_stage=null;
|
||||
protected $custom_relation_name=null;
|
||||
|
||||
/**
|
||||
* @param string $sortColumn Column that should be used to update the sort information
|
||||
* @param bool $disableSelection Disable selection on the GridField when dragging
|
||||
* @param string $updateVersionStage Name of the versioned stage to update this disabled by default unless this is set
|
||||
* @param string $customRelationName Name of the relationship to use, if left null the name is determined from the GridField's name
|
||||
*/
|
||||
public function __construct($sortColumn, $disableSelection = true, $updateVersionStage = null, $customRelationName = null) {
|
||||
$this->sortColumn = $sortColumn;
|
||||
$this->disable_selection = $disableSelection;
|
||||
$this->update_versioned_stage = $updateVersionStage;
|
||||
$this->custom_relation_name = $customRelationName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a map where the keys are fragment names and the values are pieces of HTML to add to these fragments.
|
||||
* @param GridField $gridField Grid Field Reference
|
||||
* @return Array Map where the keys are fragment names and the values are pieces of HTML to add to these fragments.
|
||||
*/
|
||||
public function getHTMLFragments($gridField) {
|
||||
$dataList = $gridField->getList();
|
||||
|
||||
if(class_exists('UnsavedRelationList') && $dataList instanceof UnsavedRelationList) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$state = $gridField->State->GridFieldSortableRows;
|
||||
if(!is_bool($state->sortableToggle)) {
|
||||
$state->sortableToggle = false;
|
||||
}
|
||||
|
||||
//Ensure user can edit
|
||||
if(!singleton($gridField->getModelClass())->canEdit()){
|
||||
return array();
|
||||
}
|
||||
|
||||
|
||||
//Sort order toggle
|
||||
$sortOrderToggle = GridField_FormAction::create(
|
||||
$gridField,
|
||||
'sortablerows-toggle',
|
||||
'sorttoggle',
|
||||
'sortableRowsToggle',
|
||||
null
|
||||
)->addExtraClass('sortablerows-toggle');
|
||||
|
||||
|
||||
$sortOrderSave = GridField_FormAction::create(
|
||||
$gridField,
|
||||
'sortablerows-savesort',
|
||||
'savesort',
|
||||
'saveGridRowSort',
|
||||
null
|
||||
)->addExtraClass('sortablerows-savesort');
|
||||
|
||||
|
||||
//Sort to Page Action
|
||||
$sortToPage = GridField_FormAction::create(
|
||||
$gridField,
|
||||
'sortablerows-sorttopage',
|
||||
'sorttopage',
|
||||
'sortToPage',
|
||||
null
|
||||
)->addExtraClass('sortablerows-sorttopage');
|
||||
|
||||
|
||||
$data = array('SortableToggle' => $sortOrderToggle,
|
||||
'SortOrderSave' => $sortOrderSave,
|
||||
'SortToPage' => $sortToPage,
|
||||
'Checked' => ($state->sortableToggle == true ? ' checked = "checked"':''),
|
||||
'List' => $dataList);
|
||||
|
||||
$forTemplate = new ArrayData($data);
|
||||
|
||||
|
||||
//Inject Requirements
|
||||
$custom = Config::inst()->get('GridFieldSortableRows', 'Base');
|
||||
$base = $custom ?: SORTABLE_GRIDFIELD_BASE;
|
||||
|
||||
Requirements::css($base . '/css/GridFieldSortableRows.css');
|
||||
Requirements::javascript($base . '/javascript/GridFieldSortableRows.js');
|
||||
|
||||
|
||||
$args = array('Colspan' => count($gridField->getColumns()), 'ID' => $gridField->ID(), 'DisableSelection' => $this->disable_selection);
|
||||
|
||||
|
||||
$fragments=array('header' => $forTemplate->renderWith('GridFieldSortableRows', $args));
|
||||
|
||||
if($gridField->getConfig()->getComponentByType('GridFieldPaginator')) {
|
||||
$fragments['after']=$forTemplate->renderWith('GridFieldSortableRows_paginator');
|
||||
}
|
||||
|
||||
return $fragments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Manipulate the datalist as needed by this grid modifier.
|
||||
* @param GridField $gridField Grid Field Reference
|
||||
* @param SS_List $dataList Data List to adjust
|
||||
* @return DataList Modified Data List
|
||||
*/
|
||||
public function getManipulatedData(GridField $gridField, SS_List $dataList) {
|
||||
//Detect and correct items with a sort column value of 0 (push to bottom)
|
||||
$this->fixSortColumn($gridField, $dataList);
|
||||
|
||||
|
||||
$headerState = $gridField->State->GridFieldSortableHeader;
|
||||
$state = $gridField->State->GridFieldSortableRows;
|
||||
if ((!is_bool($state->sortableToggle) || $state->sortableToggle===false) && $headerState && is_string($headerState->SortColumn) && is_string($headerState->SortDirection)) {
|
||||
return $dataList->sort($headerState->SortColumn, $headerState->SortDirection);
|
||||
}
|
||||
|
||||
if ($state->sortableToggle === true) {
|
||||
$gridField->getConfig()->removeComponentsByType('GridFieldFilterHeader');
|
||||
$gridField->getConfig()->removeComponentsByType('GridFieldSortableHeader');
|
||||
}
|
||||
|
||||
return $dataList->sort($this->sortColumn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if new records should be appended to the top or the bottom of the list
|
||||
* @param bool $value Boolean true to append to the top false to append to the bottom
|
||||
* @return GridFieldSortableRows Returns the current instance
|
||||
*/
|
||||
public function setAppendToTop($value) {
|
||||
$this->append_to_top=$value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $value Boolean true to disable selection of table contents false to enable selection
|
||||
* @return GridFieldSortableRows Returns the current instance
|
||||
*/
|
||||
public function setDisableSelection($value){
|
||||
$this->disable_selection = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the suffix of the versioned stage that should be updated along side the default stage
|
||||
* @param string $value Versioned Stage to update this is disabled by default unless this is set
|
||||
* @return GridFieldSortableRows Returns the current instance
|
||||
*/
|
||||
public function setUpdateVersionedStage($value) {
|
||||
$this->update_versioned_stage=$value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the relationship to use, by default the name is determined from the GridField's name
|
||||
* @param string $value Name of the relationship to use, by default the name is determined from the GridField's name
|
||||
* @return GridFieldSortableRows Returns the current instance
|
||||
*/
|
||||
public function setCustomRelationName($value) {
|
||||
$this->custom_relation_name=$value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects and corrects items with a sort column value of 0, by appending them to the bottom of the list
|
||||
* @param GridField $gridField Grid Field Reference
|
||||
* @param SS_List $dataList Data List of items to be checked
|
||||
*/
|
||||
protected function fixSortColumn($gridField, SS_List $dataList) {
|
||||
if(class_exists('UnsavedRelationList') && $dataList instanceof UnsavedRelationList) {
|
||||
return;
|
||||
}
|
||||
|
||||
$list=clone $dataList;
|
||||
$list=$list->alterDataQuery(function($query, SS_List $tmplist) {
|
||||
$query->limit(array());
|
||||
return $query;
|
||||
});
|
||||
|
||||
$many_many = ($list instanceof ManyManyList);
|
||||
if (!$many_many) {
|
||||
$sng=singleton($gridField->getModelClass());
|
||||
$fieldType=$sng->db($this->sortColumn);
|
||||
if(!$fieldType || !(strtolower($fieldType) == 'int' || is_subclass_of($fieldType, 'Int'))) {
|
||||
if(is_array($fieldType)) {
|
||||
user_error('Sort column '.$this->sortColumn.' could not be found in '.$gridField->getModelClass().'\'s ancestry', E_USER_ERROR);
|
||||
}else {
|
||||
user_error('Sort column '.$this->sortColumn.' must be an Int, column is of type '.$fieldType, E_USER_ERROR);
|
||||
}
|
||||
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$max = $list->Max($this->sortColumn);
|
||||
$list=$list->filter($this->sortColumn, 0)->sort("Created,ID");
|
||||
if($list->Count()>0) {
|
||||
$owner = $gridField->Form->getRecord();
|
||||
$sortColumn = $this->sortColumn;
|
||||
$i = 1;
|
||||
|
||||
if ($many_many) {
|
||||
list($parentClass, $componentClass, $parentField, $componentField, $table) = $owner->many_many((!empty($this->custom_relation_name) ? $this->custom_relation_name:$gridField->getName()));
|
||||
$extraFields=$owner->many_many_extraFields((!empty($this->custom_relation_name) ? $this->custom_relation_name:$gridField->getName()));
|
||||
|
||||
if(!$extraFields || !array_key_exists($this->sortColumn, $extraFields) || !($extraFields[$this->sortColumn]=='Int' || is_subclass_of('Int', $extraFields[$this->sortColumn]))) {
|
||||
user_error('Sort column '.$this->sortColumn.' must be an Int, column is of type '.$extraFields[$this->sortColumn], E_USER_ERROR);
|
||||
exit;
|
||||
}
|
||||
}else {
|
||||
//Find table containing the sort column
|
||||
$table=false;
|
||||
$class=$gridField->getModelClass();
|
||||
|
||||
$db = Config::inst()->get($class, "db", CONFIG::UNINHERITED);
|
||||
if(!empty($db) && array_key_exists($sortColumn, $db)) {
|
||||
$table=$class;
|
||||
}else {
|
||||
$classes=ClassInfo::ancestry($class, true);
|
||||
foreach($classes as $class) {
|
||||
$db = Config::inst()->get($class, "db", CONFIG::UNINHERITED);
|
||||
if(!empty($db) && array_key_exists($sortColumn, $db)) {
|
||||
$table=$class;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($table===false) {
|
||||
user_error('Sort column '.$this->sortColumn.' could not be found in '.$gridField->getModelClass().'\'s ancestry', E_USER_ERROR);
|
||||
exit;
|
||||
}
|
||||
|
||||
$baseDataClass=ClassInfo::baseDataClass($gridField->getModelClass());
|
||||
}
|
||||
|
||||
|
||||
//Start transaction if supported
|
||||
if(DB::getConn()->supportsTransactions()) {
|
||||
DB::getConn()->transactionStart();
|
||||
}
|
||||
|
||||
$idCondition=null;
|
||||
if($this->append_to_top && !($list instanceof RelationList)) {
|
||||
$idCondition='"ID" IN(\''.implode("','", $dataList->getIDList()).'\')';
|
||||
}
|
||||
|
||||
if($this->append_to_top) {
|
||||
$topIncremented=array();
|
||||
}
|
||||
|
||||
foreach($list as $obj) {
|
||||
if($many_many) {
|
||||
if($this->append_to_top) {
|
||||
//Upgrade all the records (including the last inserted from 0 to 1)
|
||||
DB::query('UPDATE "' . $table
|
||||
. '" SET "' . $sortColumn . '" = "' . $sortColumn .'"+1'
|
||||
. ' WHERE "' . $parentField . '" = ' . $owner->ID . (!empty($topIncremented) ? ' AND "' . $componentField . '" NOT IN(\''.implode('\',\'', $topIncremented).'\')':''));
|
||||
|
||||
$topIncremented[]=$obj->ID;
|
||||
}else {
|
||||
//Append the last record to the bottom
|
||||
DB::query('UPDATE "' . $table
|
||||
. '" SET "' . $sortColumn .'" = ' . ($max + $i)
|
||||
. ' WHERE "' . $componentField . '" = ' . $obj->ID . ' AND "' . $parentField . '" = ' . $owner->ID);
|
||||
}
|
||||
}else if($this->append_to_top) {
|
||||
//Upgrade all the records (including the last inserted from 0 to 1)
|
||||
DB::query('UPDATE "' . $table
|
||||
. '" SET "' . $sortColumn . '" = "' . $sortColumn .'"+1'
|
||||
. ' WHERE '.($list instanceof RelationList ? '"' . $list->foreignKey . '" = '. $owner->ID:$idCondition) . (!empty($topIncremented) ? ' AND "ID" NOT IN(\''.implode('\',\'', $topIncremented).'\')':''));
|
||||
|
||||
if($this->update_versioned_stage && class_exists($table) && Object::has_extension($table, 'Versioned')) {
|
||||
DB::query('UPDATE "' . $table . '_' . $this->update_versioned_stage
|
||||
. '" SET "' . $sortColumn . '" = "' . $sortColumn .'"+1'
|
||||
. ' WHERE '. ($list instanceof RelationList ? '"' . $list->foreignKey . '" = '. $owner->ID:$idCondition) . (!empty($topIncremented) ? ' AND "ID" NOT IN(\''.implode('\',\'', $topIncremented).'\')':''));
|
||||
}
|
||||
|
||||
$topIncremented[]=$obj->ID;
|
||||
}else {
|
||||
//Append the last record to the bottom
|
||||
DB::query('UPDATE "' . $table
|
||||
. '" SET "' . $sortColumn . '" = ' . ($max + $i)
|
||||
. ' WHERE "ID" = '. $obj->ID);
|
||||
//LastEdited
|
||||
DB::query('UPDATE "' . $baseDataClass
|
||||
. '" SET "LastEdited" = \'' . date('Y-m-d H:i:s') . '\''
|
||||
. ' WHERE "ID" = '. $obj->ID);
|
||||
|
||||
if($this->update_versioned_stage && class_exists($table) && Object::has_extension($table, 'Versioned')) {
|
||||
DB::query('UPDATE "' . $table . '_' . $this->update_versioned_stage
|
||||
. '" SET "' . $sortColumn . '" = ' . ($max + $i)
|
||||
. ' WHERE "ID" = '. $obj->ID);
|
||||
|
||||
if(Object::has_extension($baseDataClass, 'Versioned')) {
|
||||
DB::query('UPDATE "' . $baseDataClass . '_' . $this->update_versioned_stage
|
||||
. '" SET "LastEdited" = \'' . date('Y-m-d H:i:s') . '\''
|
||||
. ' WHERE "ID" = '. $obj->ID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$i++;
|
||||
}
|
||||
|
||||
//Update LastEdited for affected records when using append to top on a many_many relationship
|
||||
if(!$many_many && $this->append_to_top && count($topIncremented)>0) {
|
||||
DB::query('UPDATE "' . $baseDataClass
|
||||
. '" SET "LastEdited" = \'' . date('Y-m-d H:i:s') . '\''
|
||||
. ' WHERE "ID" IN(\''.implode('\',\'', $topIncremented).'\')');
|
||||
|
||||
if($this->update_versioned_stage && class_exists($table) && Object::has_extension($table, 'Versioned') && Object::has_extension($baseDataClass, 'Versioned')) {
|
||||
DB::query('UPDATE "' . $baseDataClass . '_' . $this->update_versioned_stage
|
||||
. '" SET "LastEdited" = \'' . date('Y-m-d H:i:s') . '\''
|
||||
. ' WHERE "ID" IN(\''.implode('\',\'', $topIncremented).'\')');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//End transaction if supported
|
||||
if(DB::getConn()->supportsTransactions()) {
|
||||
DB::getConn()->transactionEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of the actions handled by this action provider.
|
||||
* @param GridField $gridField Grid Field Reference
|
||||
* @return Array Array with action identifier strings.
|
||||
*/
|
||||
public function getActions($gridField) {
|
||||
return array('saveGridRowSort', 'sortableRowsToggle', 'sortToPage');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an action on the given grid field.
|
||||
* @param GridField $gridField Grid Field Reference
|
||||
* @param String $actionName Action identifier, see {@link getActions()}.
|
||||
* @param Array $arguments Arguments relevant for this
|
||||
* @param Array $data All form data
|
||||
*/
|
||||
public function handleAction(GridField $gridField, $actionName, $arguments, $data) {
|
||||
$state = $gridField->State->GridFieldSortableRows;
|
||||
if (!is_bool($state->sortableToggle)) {
|
||||
$state->sortableToggle = false;
|
||||
} else if ($state->sortableToggle == true) {
|
||||
$gridField->getConfig()->removeComponentsByType('GridFieldFilterHeader');
|
||||
$gridField->getConfig()->removeComponentsByType('GridFieldSortableHeader');
|
||||
}
|
||||
|
||||
|
||||
if ($actionName == 'savegridrowsort') {
|
||||
return $this->saveGridRowSort($gridField, $data);
|
||||
} else if ($actionName == 'sorttopage') {
|
||||
return $this->sortToPage($gridField, $data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles saving of the row sort order
|
||||
* @param GridField $gridField Grid Field Reference
|
||||
* @param Array $data Data submitted in the request
|
||||
*/
|
||||
protected function saveGridRowSort(GridField $gridField, $data) {
|
||||
$dataList = $gridField->getList();
|
||||
|
||||
if(class_exists('UnsavedRelationList') && $dataList instanceof UnsavedRelationList) {
|
||||
user_error('Cannot sort an UnsavedRelationList', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!singleton($gridField->getModelClass())->canEdit()){
|
||||
throw new ValidationException(_t('GridFieldSortableRows.EditPermissionsFailure', "No edit permissions"),0);
|
||||
}
|
||||
|
||||
if (empty($data['ItemIDs'])) {
|
||||
user_error('No items to sort', E_USER_ERROR);
|
||||
}
|
||||
|
||||
$className = $gridField->getModelClass();
|
||||
$owner = $gridField->Form->getRecord();
|
||||
$items = clone $gridField->getList();
|
||||
$many_many = ($items instanceof ManyManyList);
|
||||
$sortColumn = $this->sortColumn;
|
||||
$pageOffset = 0;
|
||||
|
||||
if ($paginator = $gridField->getConfig()->getComponentsByType('GridFieldPaginator')->First()) {
|
||||
$pageState = $gridField->State->GridFieldPaginator;
|
||||
|
||||
if($pageState->currentPage && is_int($pageState->currentPage) && $pageState->currentPage>1) {
|
||||
$pageOffset = $paginator->getItemsPerPage() * ($pageState->currentPage - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ($many_many) {
|
||||
list($parentClass, $componentClass, $parentField, $componentField, $table) = $owner->many_many((!empty($this->custom_relation_name) ? $this->custom_relation_name:$gridField->getName()));
|
||||
}else {
|
||||
//Find table containing the sort column
|
||||
$table=false;
|
||||
$class=$gridField->getModelClass();
|
||||
$db = Config::inst()->get($class, "db", CONFIG::UNINHERITED);
|
||||
if(!empty($db) && array_key_exists($sortColumn, $db)) {
|
||||
$table=$class;
|
||||
}else {
|
||||
$classes=ClassInfo::ancestry($class, true);
|
||||
foreach($classes as $class) {
|
||||
$db = Config::inst()->get($class, "db", CONFIG::UNINHERITED);
|
||||
if(!empty($db) && array_key_exists($sortColumn, $db)) {
|
||||
$table=$class;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($table===false) {
|
||||
user_error('Sort column '.$this->sortColumn.' could not be found in '.$gridField->getModelClass().'\'s ancestry', E_USER_ERROR);
|
||||
exit;
|
||||
}
|
||||
|
||||
$baseDataClass=ClassInfo::baseDataClass($gridField->getModelClass());
|
||||
}
|
||||
|
||||
|
||||
//Event to notify the Controller or owner DataObject before list sort
|
||||
if($owner && $owner instanceof DataObject && method_exists($owner, 'onBeforeGridFieldRowSort')) {
|
||||
$owner->onBeforeGridFieldRowSort(clone $items);
|
||||
}else if(Controller::has_curr() && Controller::curr() instanceof ModelAdmin && method_exists(Controller::curr(), 'onBeforeGridFieldRowSort')) {
|
||||
Controller::curr()->onBeforeGridFieldRowSort(clone $items);
|
||||
}
|
||||
|
||||
|
||||
//Start transaction if supported
|
||||
if(DB::getConn()->supportsTransactions()) {
|
||||
DB::getConn()->transactionStart();
|
||||
}
|
||||
|
||||
|
||||
//Perform sorting
|
||||
$ids = explode(',', $data['ItemIDs']);
|
||||
for($sort = 0;$sort<count($ids);$sort++) {
|
||||
$id = intval($ids[$sort]);
|
||||
if ($many_many) {
|
||||
DB::query('UPDATE "' . $table
|
||||
. '" SET "' . $sortColumn.'" = ' . (($sort + 1) + $pageOffset)
|
||||
. ' WHERE "' . $componentField . '" = ' . $id . ' AND "' . $parentField . '" = ' . $owner->ID);
|
||||
} else {
|
||||
DB::query('UPDATE "' . $table
|
||||
. '" SET "' . $sortColumn . '" = ' . (($sort + 1) + $pageOffset)
|
||||
. ' WHERE "ID" = '. $id);
|
||||
|
||||
DB::query('UPDATE "' . $baseDataClass
|
||||
. '" SET "LastEdited" = \'' . date('Y-m-d H:i:s') . '\''
|
||||
. ' WHERE "ID" = '. $id);
|
||||
|
||||
if($this->update_versioned_stage && class_exists($table) && Object::has_extension($table, 'Versioned')) {
|
||||
DB::query('UPDATE "' . $table . '_' . $this->update_versioned_stage
|
||||
. '" SET "' . $sortColumn . '" = ' . (($sort + 1) + $pageOffset)
|
||||
. ' WHERE "ID" = '. $id);
|
||||
|
||||
if(Object::has_extension($baseDataClass, 'Versioned')) {
|
||||
DB::query('UPDATE "' . $baseDataClass . '_' . $this->update_versioned_stage
|
||||
. '" SET "LastEdited" = \'' . date('Y-m-d H:i:s') . '\''
|
||||
. ' WHERE "ID" = '. $id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//End transaction if supported
|
||||
if(DB::getConn()->supportsTransactions()) {
|
||||
DB::getConn()->transactionEnd();
|
||||
}
|
||||
|
||||
|
||||
//Event to notify the Controller or owner DataObject after list sort
|
||||
if($owner && $owner instanceof DataObject && method_exists($owner, 'onAfterGridFieldRowSort')) {
|
||||
$owner->onAfterGridFieldRowSort(clone $items);
|
||||
}else if(Controller::has_curr() && Controller::curr() instanceof ModelAdmin && method_exists(Controller::curr(), 'onAfterGridFieldRowSort')) {
|
||||
Controller::curr()->onAfterGridFieldRowSort(clone $items);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles sorting across pages
|
||||
* @param GridField $gridField Grid Field Reference
|
||||
* @param Array $data Data submitted in the request
|
||||
*/
|
||||
protected function sortToPage(GridField $gridField, $data) {
|
||||
if (!$paginator = $gridField->getConfig()->getComponentsByType('GridFieldPaginator')->First()) {
|
||||
user_error('Paginator not detected', E_USER_ERROR);
|
||||
}
|
||||
|
||||
if (empty($data['ItemID'])) {
|
||||
user_error('No item to sort', E_USER_ERROR);
|
||||
}
|
||||
|
||||
if (empty($data['Target'])) {
|
||||
user_error('No target page', E_USER_ERROR);
|
||||
}
|
||||
|
||||
|
||||
$className = $gridField->getModelClass();
|
||||
$owner = $gridField->Form->getRecord();
|
||||
$items = clone $gridField->getList();
|
||||
$many_many = ($items instanceof ManyManyList);
|
||||
$sortColumn = $this->sortColumn;
|
||||
$targetItem = $items->byID(intval($data['ItemID']));
|
||||
|
||||
if (!$targetItem) {
|
||||
user_error('Target item not found', E_USER_ERROR);
|
||||
}
|
||||
|
||||
$currentPage = 1;
|
||||
|
||||
|
||||
$pageState = $gridField->State->GridFieldPaginator;
|
||||
if($pageState->currentPage && $pageState->currentPage>1) {
|
||||
$currentPage = $pageState->currentPage;
|
||||
}
|
||||
|
||||
|
||||
if ($many_many) {
|
||||
list($parentClass, $componentClass, $parentField, $componentField, $table) = $owner->many_many((!empty($this->custom_relation_name) ? $this->custom_relation_name:$gridField->getName()));
|
||||
}
|
||||
|
||||
|
||||
if ($data['Target'] == 'previouspage') {
|
||||
$items = $items->limit($paginator->getItemsPerPage() + 1, ($paginator->getItemsPerPage() * ($currentPage - 1)) - 1);
|
||||
} else if ($data['Target'] == 'nextpage') {
|
||||
$items = $items->limit($paginator->getItemsPerPage() + 1, $paginator->getItemsPerPage() * ($currentPage - 1));
|
||||
} else {
|
||||
user_error('Not implemented: '.$data['Target'], E_USER_ERROR);
|
||||
}
|
||||
|
||||
$sortPositions = $items->column($sortColumn);
|
||||
|
||||
|
||||
//Event to notify the Controller or owner DataObject before list sort
|
||||
if($owner && $owner instanceof DataObject && method_exists($owner, 'onBeforeGridFieldPageSort')) {
|
||||
$owner->onBeforeGridFieldPageSort(clone $items);
|
||||
}else if(Controller::has_curr() && Controller::curr() instanceof ModelAdmin && method_exists(Controller::curr(), 'onBeforeGridFieldPageSort')) {
|
||||
Controller::curr()->onBeforeGridFieldPageSort(clone $items);
|
||||
}
|
||||
|
||||
|
||||
//Find the sort column
|
||||
if($this->update_versioned_stage && Object::has_extension($className, 'Versioned')) {
|
||||
$table=false;
|
||||
$classes=ClassInfo::ancestry($className, true);
|
||||
foreach($classes as $class) {
|
||||
$db = Config::inst()->get($class, "db", CONFIG::UNINHERITED);
|
||||
if(!empty($db) && array_key_exists($sortColumn, $db)) {
|
||||
$table=$class;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if($table===false) {
|
||||
user_error('Sort column '.$this->sortColumn.' could not be found in '.$gridField->getModelClass().'\'s ancestry', E_USER_ERROR);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Start transaction if supported
|
||||
if(DB::getConn()->supportsTransactions()) {
|
||||
DB::getConn()->transactionStart();
|
||||
}
|
||||
|
||||
if($data['Target']=='previouspage') {
|
||||
if ($many_many) {
|
||||
DB::query('UPDATE "' . $table
|
||||
. '" SET "' . $sortColumn.'" = ' . $sortPositions[0]
|
||||
. ' WHERE "' . $componentField . '" = ' . $targetItem->ID . ' AND "' . $parentField . '" = ' . $owner->ID);
|
||||
} else {
|
||||
$targetItem->$sortColumn = $sortPositions[0];
|
||||
$targetItem->write();
|
||||
|
||||
if($this->update_versioned_stage && Object::has_extension($className, 'Versioned')) {
|
||||
DB::query('UPDATE "' . $table . '_' . $this->update_versioned_stage
|
||||
. '" SET "' . $sortColumn.'" = ' . $sortPositions[0]
|
||||
. ' WHERE "ID" = ' . $targetItem->ID);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$i = 1;
|
||||
foreach ($items as $obj) {
|
||||
if ($obj->ID == $targetItem->ID) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if ($many_many) {
|
||||
DB::query('UPDATE "' . $table
|
||||
. '" SET "' . $sortColumn.'" = ' . $sortPositions[$i]
|
||||
. ' WHERE "' . $componentField . '" = ' . $obj->ID . ' AND "' . $parentField . '" = ' . $owner->ID);
|
||||
} else {
|
||||
$obj->$sortColumn = $sortPositions[$i];
|
||||
$obj->write();
|
||||
|
||||
if($this->update_versioned_stage && Object::has_extension($className, 'Versioned')) {
|
||||
DB::query('UPDATE "' . $table . '_' . $this->update_versioned_stage
|
||||
. '" SET "' . $sortColumn.'" = ' . $sortPositions[$i]
|
||||
. ' WHERE "ID" = ' . $obj->ID);
|
||||
}
|
||||
}
|
||||
|
||||
$i++;
|
||||
}
|
||||
} else {
|
||||
if ($many_many) {
|
||||
DB::query('UPDATE "' . $table
|
||||
. '" SET "' . $sortColumn.'" = ' . $sortPositions[count($sortPositions) - 1]
|
||||
. ' WHERE "' . $componentField . '" = ' . $targetItem->ID . ' AND "' . $parentField . '" = ' . $owner->ID);
|
||||
} else {
|
||||
$targetItem->$sortColumn = $sortPositions[count($sortPositions) - 1];
|
||||
$targetItem->write();
|
||||
|
||||
if($this->update_versioned_stage && Object::has_extension($className, 'Versioned')) {
|
||||
DB::query('UPDATE "' . $table . '_' . $this->update_versioned_stage
|
||||
. '" SET "' . $sortColumn.'" = ' . $sortPositions[count($sortPositions) - 1]
|
||||
. ' WHERE "ID" = ' . $targetItem->ID);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$i = 0;
|
||||
foreach ($items as $obj) {
|
||||
if ($obj->ID == $targetItem->ID) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if ($many_many) {
|
||||
DB::query('UPDATE "' . $table
|
||||
. '" SET "' . $sortColumn.'" = ' . $sortPositions[$i]
|
||||
. ' WHERE "' . $componentField . '" = ' . $obj->ID . ' AND "' . $parentField . '" = ' . $owner->ID);
|
||||
} else {
|
||||
$obj->$sortColumn = $sortPositions[$i];
|
||||
$obj->write();
|
||||
|
||||
if($this->update_versioned_stage && Object::has_extension($className, 'Versioned')) {
|
||||
DB::query('UPDATE "' . $table . '_' . $this->update_versioned_stage
|
||||
. '" SET "' . $sortColumn.'" = ' . $sortPositions[$i]
|
||||
. ' WHERE "ID" = ' . $obj->ID);
|
||||
}
|
||||
}
|
||||
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//End transaction if supported
|
||||
if(DB::getConn()->supportsTransactions()) {
|
||||
DB::getConn()->transactionEnd();
|
||||
}
|
||||
|
||||
|
||||
//Event to notify the Controller or owner DataObject after list sort
|
||||
if($owner && $owner instanceof DataObject && method_exists($owner, 'onAfterGridFieldPageSort')) {
|
||||
$owner->onAfterGridFieldPageSort(clone $items);
|
||||
}else if(Controller::has_curr() && Controller::curr() instanceof ModelAdmin && method_exists(Controller::curr(), 'onAfterGridFieldPageSort')) {
|
||||
Controller::curr()->onAfterGridFieldPageSort(clone $items);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"name": "undefinedoffset/sortablegridfield",
|
||||
"description": "Adds drag and drop functionality to SilverStripe 3.0's GridField",
|
||||
"type": "silverstripe-module",
|
||||
"keywords": ["silverstripe", "gridfield"],
|
||||
"description": "Adds drag and drop functionality to Silverstripe's GridField",
|
||||
"type": "silverstripe-vendormodule",
|
||||
"keywords": ["silverstripe", "gridfield", "sortable", "sort"],
|
||||
"license": "BSD-3-Clause",
|
||||
"authors": [
|
||||
{
|
||||
|
@ -11,15 +11,33 @@
|
|||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"require":
|
||||
{
|
||||
"silverstripe/framework": ">=3.0.1 <4.0.0",
|
||||
"composer/installers": "*"
|
||||
"require": {
|
||||
"silverstripe/framework": "~4.11 | ^5",
|
||||
"silverstripe/versioned": "^1 | ^2"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"squizlabs/php_codesniffer": "~3.4"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"UndefinedOffset\\SortableGridField\\": "src/",
|
||||
"UndefinedOffset\\SortableGridField\\Tests\\": "tests/"
|
||||
}
|
||||
},
|
||||
"support": {
|
||||
"issues": "https://github.com/undefinedoffset/SortableGridField/issues"
|
||||
},
|
||||
"extra": {
|
||||
"installer-name": "sortablegridfield"
|
||||
}
|
||||
"installer-name": "sortablegridfield",
|
||||
"expose": [
|
||||
"css",
|
||||
"javascript"
|
||||
],
|
||||
"branch-alias": {
|
||||
"dev-master": "2.0.x-dev"
|
||||
}
|
||||
},
|
||||
"prefer-stable": true,
|
||||
"minimum-stability": "dev"
|
||||
}
|
||||
|
|
|
@ -1,16 +1,22 @@
|
|||
form table.ss-gridfield-table thead tr th.sortablerowsheading {
|
||||
form table.grid-field__table thead tr th.sortablerowsheading {
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
form table.ss-gridfield-table thead tr th.sortablerowsheading .gridfield-sortablerows input[type=checkbox] {
|
||||
form table.grid-field__table thead tr td.sortablerowsheading label {
|
||||
margin-bottom: 0;
|
||||
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
form table.grid-field__table thead tr td.sortablerowsheading .gridfield-sortablerows input[type=checkbox] {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
form table.ss-gridfield-table thead tr th.sortablerowsheading .gridfield-sortablerows {
|
||||
form table.grid-field__table thead tr td.sortablerowsheading .gridfield-sortablerows {
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
form table.ss-gridfield-table thead tr th.sortablerowsheading .gridfield-sortablerows button {
|
||||
form table.grid-field__table thead tr td.sortablerowsheading .gridfield-sortablerows button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
@ -19,7 +25,7 @@ form .ss-gridfield {
|
|||
}
|
||||
|
||||
form .ss-gridfield .gridfield-sortablerows-movepage .sortablerows-psort-arrow {
|
||||
background: #98AAB6;
|
||||
background: #5589A7;
|
||||
|
||||
display: none;
|
||||
|
||||
|
@ -30,7 +36,7 @@ form .ss-gridfield .gridfield-sortablerows-movepage .sortablerows-psort-arrow {
|
|||
|
||||
width: 40px;
|
||||
|
||||
opacity: 0.4;
|
||||
opacity: 0.6;
|
||||
|
||||
text-align: center;
|
||||
|
||||
|
@ -45,6 +51,8 @@ form .ss-gridfield .gridfield-sortablerows-movepage .sortablerows-psort-arrow i
|
|||
display: block;
|
||||
|
||||
position: relative;
|
||||
|
||||
font-style: normal;
|
||||
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
|
@ -72,13 +80,13 @@ form .ss-gridfield .gridfield-sortablerows-movepage .sortablerows-psort-arrow i:
|
|||
}
|
||||
|
||||
form .ss-gridfield .gridfield-sortablerows-movepage .sortablerows-psort-arrow:hover {
|
||||
opacity: 0.7;
|
||||
opacity: 0.8;
|
||||
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
form .ss-gridfield .gridfield-sortablerows-movepage .sortablerows-prev-page {
|
||||
left: 0;
|
||||
left: -20px;
|
||||
}
|
||||
|
||||
form .ss-gridfield .gridfield-sortablerows-movepage .sortablerows-prev-page i {
|
||||
|
@ -98,7 +106,7 @@ form .ss-gridfield .gridfield-sortablerows-movepage .sortablerows-prev-page i {
|
|||
}
|
||||
|
||||
form .ss-gridfield .gridfield-sortablerows-movepage .sortablerows-next-page {
|
||||
right: 0;
|
||||
right: -20px;
|
||||
}
|
||||
|
||||
form .ss-gridfield .gridfield-sortablerows-movepage .sortablerows-next-page i {
|
||||
|
@ -117,10 +125,10 @@ form .ss-gridfield .gridfield-sortablerows-movepage .sortablerows-next-page i {
|
|||
transform-origin: bottom right;
|
||||
}
|
||||
|
||||
form table.ss-gridfield-table.dragSorting tbody tr td {
|
||||
form table.grid-field__table.dragSorting tbody tr td {
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
form table.ss-gridfield-table.dragSorting .ui-sortable-helper {
|
||||
form table.grid-field__table.dragSorting .ui-sortable-helper {
|
||||
display: table;
|
||||
}
|
|
@ -1,37 +1,58 @@
|
|||
has_many Example
|
||||
=================
|
||||
Please note this example is written with 3.0.x in mind, if you are using 3.1.x make sure you scope all static properties to private not public.
|
||||
|
||||
```php
|
||||
|
||||
/*** TestPage.php ***/
|
||||
class TestPage extends Page {
|
||||
public static $has_many=array(
|
||||
'TestObjects'=>'TestObject'
|
||||
);
|
||||
|
||||
public function getCMSFields() {
|
||||
$fields=parent::getCMSFields();
|
||||
|
||||
$conf=GridFieldConfig_RelationEditor::create(10);
|
||||
$conf->addComponent(new GridFieldSortableRows('SortOrder'));
|
||||
|
||||
$fields->addFieldToTab('Root.TestObjects', new GridField('TestObjects', 'TestObjects', $this->TestObjects(), $conf));
|
||||
|
||||
return $fields;
|
||||
}
|
||||
use SilverStripe\Forms\GridField\GridField;
|
||||
use SilverStripe\Forms\GridField\GridFieldConfig_RelationEditor;
|
||||
use UndefinedOffset\SortableGridField\Forms\GridFieldSortableRows;
|
||||
|
||||
class TestPage extends Page
|
||||
{
|
||||
private static $has_many = [
|
||||
'TestObjects' => 'TestObject',
|
||||
];
|
||||
|
||||
public function getCMSFields()
|
||||
{
|
||||
$fields = parent::getCMSFields();
|
||||
|
||||
$conf = GridFieldConfig_RelationEditor::create(10);
|
||||
$conf->addComponent(GridFieldSortableRows::create('SortOrder'));
|
||||
|
||||
$fields->addFieldToTab(
|
||||
'Root.TestObjects',
|
||||
GridField::create(
|
||||
'TestObjects',
|
||||
'TestObjects',
|
||||
$this->TestObjects(),
|
||||
$conf
|
||||
)
|
||||
);
|
||||
|
||||
return $fields;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*** TestObject.php ***/
|
||||
class TestObject extends DataObject {
|
||||
public static $db=array(
|
||||
'Title'=>'Text',
|
||||
'SortOrder'=>'Int'
|
||||
);
|
||||
|
||||
public static $has_one=array(
|
||||
'Parent'=>'TestPage'
|
||||
);
|
||||
|
||||
public static $default_sort='SortOrder';
|
||||
use SilverStripe\ORM\DataObject;
|
||||
|
||||
class TestObject extends DataObject
|
||||
{
|
||||
private static $db = [
|
||||
'Title' => 'Text',
|
||||
'SortOrder' => 'Int',
|
||||
];
|
||||
|
||||
private static $indexes = [
|
||||
'SortOrder' => true,
|
||||
];
|
||||
private static $has_one = [
|
||||
'Parent' => 'TestPage',
|
||||
];
|
||||
|
||||
private static $default_sort = 'SortOrder';
|
||||
}
|
||||
```
|
||||
```
|
||||
|
|
|
@ -1,45 +1,55 @@
|
|||
many_many Example
|
||||
=================
|
||||
Please note this example is written with 3.0.x in mind, if you are using 3.1.x make sure you scope all static properties to private not public.
|
||||
|
||||
```php
|
||||
/*** TestPage.php ***/
|
||||
class TestPage extends Page {
|
||||
public static $many_many=array(
|
||||
'TestObjects'=>'TestObject'
|
||||
);
|
||||
|
||||
public static $many_many_extraFields=array(
|
||||
'TestObjects'=>array(
|
||||
'SortOrder'=>'Int'
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
public function getCMSFields() {
|
||||
$fields=parent::getCMSFields();
|
||||
|
||||
$conf=GridFieldConfig_RelationEditor::create(10);
|
||||
$conf->addComponent(new GridFieldSortableRows('SortOrder'));
|
||||
|
||||
$fields->addFieldToTab('Root.TestObjects', new GridField('TestObjects', 'TestObjects', $this->TestObjects(), $conf));
|
||||
|
||||
use SilverStripe\Forms\GridField\GridField;
|
||||
use SilverStripe\Forms\GridField\GridFieldConfig_RelationEditor;
|
||||
use UndefinedOffset\SortableGridField\Forms\GridFieldSortableRows;
|
||||
|
||||
class TestPage extends Page
|
||||
{
|
||||
private static $many_many = [
|
||||
'TestObjects' => 'TestObject',
|
||||
];
|
||||
|
||||
private static $many_many_extraFields = [
|
||||
'TestObjects' => [
|
||||
'SortOrder' => 'Int',
|
||||
]
|
||||
];
|
||||
|
||||
|
||||
public function getCMSFields()
|
||||
{
|
||||
$fields = parent::getCMSFields();
|
||||
|
||||
$conf = GridFieldConfig_RelationEditor::create(10);
|
||||
$conf->addComponent(GridFieldSortableRows::create('SortOrder'));
|
||||
|
||||
$fields->addFieldToTab('Root.TestObjects', GridField::create('TestObjects', 'TestObjects', $this->TestObjects(), $conf));
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
public function TestObjects() {
|
||||
|
||||
public function TestObjects()
|
||||
{
|
||||
return $this->getManyManyComponents('TestObjects')->sort('SortOrder');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*** TestObject.php ***/
|
||||
class TestObject extends DataObject {
|
||||
public static $db=array(
|
||||
'Title'=>'Text'
|
||||
);
|
||||
|
||||
public static $belongs_many_many=array(
|
||||
'TestPages'=>'TestPage'
|
||||
);
|
||||
use SilverStripe\ORM\DataObject;
|
||||
|
||||
class TestObject extends DataObject
|
||||
{
|
||||
private static $db = [
|
||||
'Title' => 'Text',
|
||||
];
|
||||
|
||||
private static $belongs_many_many = [
|
||||
'TestPages' => 'TestPage',
|
||||
];
|
||||
}
|
||||
```
|
||||
```
|
||||
|
|
|
@ -1,38 +1,54 @@
|
|||
ModelAdmin implementation Example
|
||||
=================
|
||||
Please note this example is written with 3.0.x in mind, if you are using 3.1.x make sure you scope all static properties to private not public.
|
||||
|
||||
```php
|
||||
/**** MyModelAdmin.php ****/
|
||||
class MyModelAdmin extends ModelAdmin {
|
||||
public static $menu_title='My Model Admin';
|
||||
public static $url_segment='my-model-admin';
|
||||
|
||||
public static $managed_models=array(
|
||||
'MATestObject'
|
||||
);
|
||||
|
||||
public function getEditForm($id = null, $fields = null) {
|
||||
$form=parent::getEditForm($id, $fields);
|
||||
|
||||
//This check is simply to ensure you are on the managed model you want adjust accordingly
|
||||
if($this->modelClass=='MATestObject' && $gridField=$form->Fields()->dataFieldByName($this->sanitiseClassName($this->modelClass))) {
|
||||
//This is just a precaution to ensure we got a GridField from dataFieldByName() which you should have
|
||||
if($gridField instanceof GridField) {
|
||||
$gridField->getConfig()->addComponent(new GridFieldSortableRows('SortOrder'));
|
||||
use SilverStripe\Admin\ModelAdmin;
|
||||
use SilverStripe\Forms\GridField\GridField;
|
||||
use UndefinedOffset\SortableGridField\Forms\GridFieldSortableRows;
|
||||
|
||||
class MyModelAdmin extends ModelAdmin
|
||||
{
|
||||
private static $menu_title = 'My Model Admin';
|
||||
|
||||
private static $url_segment = 'my-model-admin';
|
||||
|
||||
private static $managed_models = [
|
||||
MATestObject::class,
|
||||
];
|
||||
|
||||
public function getEditForm($id = null, $fields = null)
|
||||
{
|
||||
$form = parent::getEditForm($id, $fields);
|
||||
|
||||
// This check is simply to ensure you are on the managed model you want adjust accordingly
|
||||
if ($this->modelClass === MATestObject::class) {
|
||||
$gridField = $form->Fields()->dataFieldByName($this->sanitiseClassName($this->modelClass));
|
||||
|
||||
// This is just a precaution to ensure we got a GridField from dataFieldByName() which you should have
|
||||
if ($gridField instanceof GridField) {
|
||||
$gridField->getConfig()->addComponent(GridFieldSortableRows::create('SortOrder'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return $form;
|
||||
}
|
||||
}
|
||||
|
||||
/**** MATestObject.php ****/
|
||||
class MATestObject extends DataObject {
|
||||
public static $db=array(
|
||||
'Title'=>'Varchar',
|
||||
'SortOrder'=>'Int'
|
||||
);
|
||||
|
||||
public static $default_sort='SortOrder';
|
||||
use SilverStripe\ORM\DataObject;
|
||||
|
||||
class MATestObject extends DataObject
|
||||
{
|
||||
private static $db = [
|
||||
'Title' => 'Varchar',
|
||||
'SortOrder' => 'Int',
|
||||
];
|
||||
|
||||
private static $indexes = [
|
||||
'SortOrder' => true,
|
||||
];
|
||||
|
||||
private static $default_sort = 'SortOrder';
|
||||
}
|
||||
```
|
||||
```
|
||||
|
|
|
@ -1,202 +1,206 @@
|
|||
(function($) {
|
||||
$.entwine('ss', function($) {
|
||||
$('.ss-gridfield .gridfield-sortablerows input').entwine({
|
||||
PageSort: false,
|
||||
|
||||
onmatch: function() {
|
||||
var self=this;
|
||||
var refCheckbox=$(this);
|
||||
var gridField=this.getGridField();
|
||||
var form=gridField.closest('form');
|
||||
var pageArrows=gridField.find('.gridfield-sortablerows-movepage .sortablerows-psort-arrow');
|
||||
|
||||
if($(this).is(':checked')) {
|
||||
gridField.find('table').addClass('dragSorting');
|
||||
}else {
|
||||
gridField.find('table').removeClass('dragSorting');
|
||||
}
|
||||
|
||||
gridField.find('tbody').sortable({
|
||||
opacity: 0.6,
|
||||
disabled: ($(this).is(':checked')==false),
|
||||
start: function(event, ui) {
|
||||
pageArrows.show();
|
||||
pageArrows.redraw();
|
||||
pageArrows.startMoveTracking();
|
||||
},
|
||||
stop: function(event, ui) {
|
||||
pageArrows.stopMoveTracking();
|
||||
pageArrows.hide();
|
||||
},
|
||||
sort: function(event, ui) {
|
||||
pageArrows.moveTracking(event, ui);
|
||||
},
|
||||
update: function(event, ui) {
|
||||
if(self.getPageSort()) {
|
||||
self.setPageSort(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var gridItems=gridField.getItems();
|
||||
|
||||
gridItems.removeClass('first last odd even');
|
||||
gridItems.first().addClass('first');
|
||||
gridItems.last().addClass('last');
|
||||
gridItems.filter(':even').addClass('odd');
|
||||
gridItems.filter(':odd').addClass('even');
|
||||
|
||||
var dataRows=[];
|
||||
var button=refCheckbox.parent().find('.sortablerows-savesort');
|
||||
|
||||
|
||||
for(var i=0;i<gridItems.length;i++) {
|
||||
dataRows[i]=$(gridItems[i]).data('id');
|
||||
}
|
||||
|
||||
|
||||
self._makeRequest({data: [
|
||||
{
|
||||
name: button.attr('name'),
|
||||
value: button.val()
|
||||
},
|
||||
{
|
||||
name: 'ItemIDs',
|
||||
value: dataRows
|
||||
}
|
||||
]},function() {
|
||||
form.removeClass('loading');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if(refCheckbox.hasClass('gridfield-sortablerows-noselection') || $(this).is(':checked')) {
|
||||
gridField.find('tbody').disableSelection();
|
||||
}
|
||||
},
|
||||
|
||||
onchange: function(e) {
|
||||
var gridField=this.getGridField();
|
||||
gridField.find('tbody').sortable('option', 'disabled', ($(this).is(':checked')==false));
|
||||
gridField.setState('GridFieldSortableRows', {sortableToggle: $(this).is(':checked')});
|
||||
|
||||
|
||||
var button=$(this).parent().find('.sortablerows-toggle');
|
||||
gridField.reload({data: [{name: button.attr('name'), value: button.val()}]});
|
||||
},
|
||||
|
||||
_makeRequest: function(ajaxOpts, callback) {
|
||||
var gridField=this.getGridField();
|
||||
var form = gridField.closest('form');
|
||||
|
||||
form.addClass('loading');
|
||||
|
||||
ajaxOpts.data = ajaxOpts.data.concat(form.find(':input').serializeArray());
|
||||
|
||||
// Include any GET parameters from the current URL, as the view state might depend on it.
|
||||
// For example, a list prefiltered through external search criteria might be passed to GridField.
|
||||
if(window.location.search) {
|
||||
ajaxOpts.data = window.location.search.replace(/^\?/, '') + '&' + $.param(ajaxOpts.data);
|
||||
}
|
||||
|
||||
$.ajax($.extend({}, {
|
||||
headers: {"X-Pjax" : 'CurrentField'},
|
||||
type: "POST",
|
||||
url: gridField.data('url'),
|
||||
dataType: 'html',
|
||||
success: callback,
|
||||
error: function(e) {
|
||||
alert(ss.i18n._t('GRIDFIELD.ERRORINTRANSACTION'));
|
||||
}
|
||||
}, ajaxOpts));
|
||||
}
|
||||
});
|
||||
|
||||
$('.ss-gridfield .gridfield-sortablerows-movepage .sortablerows-psort-arrow').entwine({
|
||||
ArrowIcon: null,
|
||||
|
||||
onmatch: function() {
|
||||
var gridField=this.getGridField();
|
||||
var sortableCheckbox=gridField.find('.gridfield-sortablerows input');
|
||||
var self=$(this);
|
||||
|
||||
if($(this).hasClass('sortablerows-prev-page') && (gridField.find('.ss-gridfield-previouspage').length==0 || gridField.find('.ss-gridfield-previouspage').is(':disabled'))) {
|
||||
$(this).remove();
|
||||
return;
|
||||
}else if($(this).hasClass('sortablerows-next-page') && (gridField.find('.ss-gridfield-nextpage').length==0 || gridField.find('.ss-gridfield-nextpage').is(':disabled'))) {
|
||||
$(this).remove();
|
||||
return;
|
||||
}
|
||||
|
||||
$(this).droppable({
|
||||
disabled: $(this).is(':disabled'),
|
||||
accept: 'tr.ss-gridfield-item',
|
||||
activeClass: 'sortablerows-droptarget',
|
||||
tolerance: 'pointer',
|
||||
drop: function(event, ui) {
|
||||
self.stopMoveTracking();
|
||||
|
||||
sortableCheckbox.setPageSort(true);
|
||||
|
||||
var button=gridField.find('.gridfield-sortablerows .sortablerows-sorttopage');
|
||||
var itemID=$(ui.draggable).data('id');
|
||||
var target='';
|
||||
|
||||
if($(this).hasClass('sortablerows-prev-page')) {
|
||||
target='previouspage';
|
||||
}else if($(this).hasClass('sortablerows-next-page')) {
|
||||
target='nextpage';
|
||||
}
|
||||
|
||||
|
||||
//Move and Reload the grid
|
||||
gridField.reload({data: [
|
||||
{
|
||||
name: button.attr('name'),
|
||||
value: button.val()
|
||||
},
|
||||
{
|
||||
name: 'ItemID',
|
||||
value: itemID
|
||||
},
|
||||
{
|
||||
name: 'Target',
|
||||
value: target
|
||||
}
|
||||
]});
|
||||
}
|
||||
});
|
||||
|
||||
this.redraw();
|
||||
},
|
||||
redraw: function() {
|
||||
var gridField=this.getGridField();
|
||||
var tbody=gridField.find('tbody');
|
||||
var tbodyPos=tbody.position();
|
||||
|
||||
$(this).css('top', tbodyPos.top+'px').height(tbody.height());
|
||||
},
|
||||
startMoveTracking: function() {
|
||||
var self=$(this);
|
||||
self.setArrowIcon(self.find('i'));
|
||||
},
|
||||
stopMoveTracking: function() {
|
||||
$(this).setArrowIcon(null);
|
||||
},
|
||||
moveTracking: function(e, ui) {
|
||||
var self=$(this);
|
||||
var arrowIcon=self.getArrowIcon();
|
||||
if(arrowIcon) {
|
||||
var selfOffset=self.offset().top;
|
||||
var arrowIconHeight=arrowIcon.width()+10;
|
||||
var railHeight=self.height()-arrowIconHeight;
|
||||
var helperPos=ui.helper.offset().top;
|
||||
|
||||
if(helperPos>selfOffset+10 && helperPos<selfOffset+railHeight) {
|
||||
arrowIcon.css('top', ((helperPos-selfOffset)+arrowIconHeight/2)+'px');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
(function ($) {
|
||||
$.entwine('ss', function ($) {
|
||||
$('.ss-gridfield .gridfield-sortablerows input').entwine({
|
||||
PageSort: false,
|
||||
|
||||
onmatch: function () {
|
||||
var self = this;
|
||||
var refCheckbox = $(this);
|
||||
var gridField = this.getGridField();
|
||||
var form = gridField.closest('form');
|
||||
var pageArrows = gridField.find('.gridfield-sortablerows-movepage .sortablerows-psort-arrow');
|
||||
|
||||
if ($(this).is(':checked')) {
|
||||
gridField.find('table').addClass('dragSorting');
|
||||
} else {
|
||||
gridField.find('table').removeClass('dragSorting');
|
||||
}
|
||||
|
||||
gridField.find('tbody').sortable({
|
||||
opacity: 0.6,
|
||||
disabled: ($(this).is(':checked') == false),
|
||||
start: function (event, ui) {
|
||||
pageArrows.show();
|
||||
pageArrows.redraw();
|
||||
pageArrows.startMoveTracking();
|
||||
},
|
||||
stop: function (event, ui) {
|
||||
pageArrows.stopMoveTracking();
|
||||
pageArrows.hide();
|
||||
},
|
||||
sort: function (event, ui) {
|
||||
pageArrows.moveTracking(event, ui);
|
||||
},
|
||||
update: function (event, ui) {
|
||||
if (self.getPageSort()) {
|
||||
self.setPageSort(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var gridItems = gridField.getItems();
|
||||
|
||||
gridItems.removeClass('first last odd even');
|
||||
gridItems.first().addClass('first');
|
||||
gridItems.last().addClass('last');
|
||||
gridItems.filter(':even').addClass('odd');
|
||||
gridItems.filter(':odd').addClass('even');
|
||||
|
||||
var dataRows = [];
|
||||
var button = refCheckbox.parent().find('.sortablerows-savesort');
|
||||
|
||||
|
||||
for (var i = 0; i < gridItems.length; i++) {
|
||||
dataRows[i] = $(gridItems[i]).data('id');
|
||||
}
|
||||
|
||||
|
||||
self._makeRequest({
|
||||
data: [
|
||||
{
|
||||
name: button.attr('name'),
|
||||
value: button.val()
|
||||
},
|
||||
{
|
||||
name: 'ItemIDs',
|
||||
value: dataRows
|
||||
}
|
||||
]
|
||||
}, function () {
|
||||
form.removeClass('loading');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (refCheckbox.hasClass('gridfield-sortablerows-noselection') || $(this).is(':checked')) {
|
||||
gridField.find('tbody').disableSelection();
|
||||
}
|
||||
},
|
||||
|
||||
onchange: function (e) {
|
||||
var gridField = this.getGridField();
|
||||
gridField.find('tbody').sortable('option', 'disabled', ($(this).is(':checked') == false));
|
||||
gridField.setState('GridFieldSortableRows', {sortableToggle: $(this).is(':checked')});
|
||||
|
||||
|
||||
var button = $(this).parent().find('.sortablerows-toggle');
|
||||
gridField.reload({data: [{name: button.attr('name'), value: button.val()}]});
|
||||
},
|
||||
|
||||
_makeRequest: function (ajaxOpts, callback) {
|
||||
var gridField = this.getGridField();
|
||||
var form = gridField.closest('form');
|
||||
|
||||
form.addClass('loading');
|
||||
|
||||
ajaxOpts.data = ajaxOpts.data.concat(form.find(':input').serializeArray());
|
||||
|
||||
// Include any GET parameters from the current URL, as the view state might depend on it.
|
||||
// For example, a list prefiltered through external search criteria might be passed to GridField.
|
||||
if (window.location.search) {
|
||||
ajaxOpts.data = window.location.search.replace(/^\?/, '') + '&' + $.param(ajaxOpts.data);
|
||||
}
|
||||
|
||||
$.ajax($.extend({}, {
|
||||
headers: {"X-Pjax": 'CurrentField'},
|
||||
type: "POST",
|
||||
url: gridField.data('url'),
|
||||
dataType: 'html',
|
||||
success: callback,
|
||||
error: function (e) {
|
||||
alert(ss.i18n._t('Admin.ERRORINTRANSACTION', 'An error occured while fetching data from the server\n Please try again later.'));
|
||||
}
|
||||
}, ajaxOpts));
|
||||
}
|
||||
});
|
||||
|
||||
$('.ss-gridfield .gridfield-sortablerows-movepage .sortablerows-psort-arrow').entwine({
|
||||
ArrowIcon: null,
|
||||
|
||||
onmatch: function () {
|
||||
var gridField = this.getGridField();
|
||||
var sortableCheckbox = gridField.find('.gridfield-sortablerows input');
|
||||
var self = $(this);
|
||||
|
||||
if ($(this).hasClass('sortablerows-prev-page') && (gridField.find('.ss-gridfield-previouspage').length == 0 || gridField.find('.ss-gridfield-previouspage').is(':disabled'))) {
|
||||
$(this).remove();
|
||||
return;
|
||||
} else if ($(this).hasClass('sortablerows-next-page') && (gridField.find('.ss-gridfield-nextpage').length == 0 || gridField.find('.ss-gridfield-nextpage').is(':disabled'))) {
|
||||
$(this).remove();
|
||||
return;
|
||||
}
|
||||
|
||||
$(this).droppable({
|
||||
disabled: $(this).is(':disabled'),
|
||||
accept: 'tr.ss-gridfield-item',
|
||||
activeClass: 'sortablerows-droptarget',
|
||||
tolerance: 'pointer',
|
||||
drop: function (event, ui) {
|
||||
self.stopMoveTracking();
|
||||
|
||||
sortableCheckbox.setPageSort(true);
|
||||
|
||||
var button = gridField.find('.gridfield-sortablerows .sortablerows-sorttopage');
|
||||
var itemID = $(ui.draggable).data('id');
|
||||
var target = '';
|
||||
|
||||
if ($(this).hasClass('sortablerows-prev-page')) {
|
||||
target = 'previouspage';
|
||||
} else if ($(this).hasClass('sortablerows-next-page')) {
|
||||
target = 'nextpage';
|
||||
}
|
||||
|
||||
|
||||
//Move and Reload the grid
|
||||
gridField.reload({
|
||||
data: [
|
||||
{
|
||||
name: button.attr('name'),
|
||||
value: button.val()
|
||||
},
|
||||
{
|
||||
name: 'ItemID',
|
||||
value: itemID
|
||||
},
|
||||
{
|
||||
name: 'Target',
|
||||
value: target
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
this.redraw();
|
||||
},
|
||||
redraw: function () {
|
||||
var gridField = this.getGridField();
|
||||
var tbody = gridField.find('tbody');
|
||||
var tbodyPos = tbody.position();
|
||||
|
||||
$(this).css('top', tbodyPos.top + 'px').height(tbody.height());
|
||||
},
|
||||
startMoveTracking: function () {
|
||||
var self = $(this);
|
||||
self.setArrowIcon(self.find('i'));
|
||||
},
|
||||
stopMoveTracking: function () {
|
||||
$(this).setArrowIcon(null);
|
||||
},
|
||||
moveTracking: function (e, ui) {
|
||||
var self = $(this);
|
||||
var arrowIcon = self.getArrowIcon();
|
||||
if (arrowIcon) {
|
||||
var selfOffset = self.offset().top;
|
||||
var arrowIconHeight = arrowIcon.width() + 10;
|
||||
var railHeight = self.height() - arrowIconHeight;
|
||||
var helperPos = ui.helper.offset().top;
|
||||
|
||||
if (helperPos > selfOffset + 10 && helperPos < selfOffset + railHeight) {
|
||||
arrowIcon.css('top', ((helperPos - selfOffset) + arrowIconHeight / 2) + 'px');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
da:
|
||||
GridFieldSortableRows:
|
||||
ALLOW_DRAG_DROP: 'Tillad træk og slip sortering'
|
||||
EditPermissionsFailure: 'Manglende tilladelse til at redigere'
|
||||
NEXT: 'Flyt til næste side'
|
||||
PREVIOUS: 'Flyt til forrige side'
|
|
@ -2,3 +2,5 @@ fr:
|
|||
GridFieldSortableRows:
|
||||
ALLOW_DRAG_DROP: 'Activer le classement par glisser-déposer'
|
||||
EditPermissionsFailure: 'Vous n''avez pas les permissions pour éditer'
|
||||
NEXT: 'Aller à la page suivante'
|
||||
PREVIOUS: 'Aller à la page précédente'
|
||||
|
|
|
@ -2,5 +2,3 @@ lt:
|
|||
GridFieldSortableRows:
|
||||
ALLOW_DRAG_DROP: 'Įjungti tempimo ir įmetimo rėžimą rikiavimui'
|
||||
EditPermissionsFailure: 'Nėra leidimų redagavimui'
|
||||
NEXT: 'Perkelti į kitą puslapį'
|
||||
PREVIOUS: 'Perkelti į ankstesnį puslapį'
|
||||
|
|
|
@ -2,3 +2,5 @@ nl:
|
|||
GridFieldSortableRows:
|
||||
ALLOW_DRAG_DROP: 'Rangschikken met drag & drop toestaan'
|
||||
EditPermissionsFailure: 'Geen toegang'
|
||||
NEXT: 'Verplaats naar Volgende Pagina'
|
||||
PREVIOUS: 'Verplaats naar Vorige Pagina'
|
||||
|
|
|
@ -2,3 +2,5 @@ pl:
|
|||
GridFieldSortableRows:
|
||||
ALLOW_DRAG_DROP: 'Pozwól na reorganizację przez drag and drop'
|
||||
EditPermissionsFailure: 'Brak możliwości edycji'
|
||||
NEXT: 'Przenieś do następnej strony'
|
||||
PREVIOUS: 'Przenieś do poprzedniej strony'
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
sl:
|
||||
GridFieldSortableRows:
|
||||
ALLOW_DRAG_DROP: 'Omogoči razvrščanje s "povleci in spusti" '
|
||||
EditPermissionsFailure: 'Nimate pravic za urejanje'
|
||||
NEXT: 'Prestavi na naslednjo stran'
|
||||
PREVIOUS: 'Prestavi na prejšnjo stran'
|
|
@ -2,3 +2,5 @@ sv:
|
|||
GridFieldSortableRows:
|
||||
ALLOW_DRAG_DROP: 'Aktivera dra och släpp sortering'
|
||||
EditPermissionsFailure: 'Rättighet för att redigera saknas'
|
||||
NEXT: 'Gå till nästa sida'
|
||||
PREVIOUS: 'Gå till föregående sida'
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ruleset name="SilverStripe">
|
||||
<description>CodeSniffer ruleset for SilverStripe coding conventions.</description>
|
||||
|
||||
<!-- base rules are PSR-2 -->
|
||||
<rule ref="PSR2" >
|
||||
<!-- Current exclusions -->
|
||||
<exclude name="PSR1.Methods.CamelCapsMethodName" />
|
||||
<exclude name="PSR1.Files.SideEffects.FoundWithSymbols" />
|
||||
<exclude name="PSR2.Classes.PropertyDeclaration" />
|
||||
<exclude name="PSR2.Methods.MethodDeclaration.Underscore" />
|
||||
<exclude name="Squiz.Scope.MethodScope" />
|
||||
<exclude name="Squiz.Classes.ValidClassName.NotCamelCaps" />
|
||||
<exclude name="Generic.Files.LineLength.TooLong" />
|
||||
<exclude name="PEAR.Functions.ValidDefaultValue.NotAtEnd" />
|
||||
<exclude name="PSR2.ControlStructures.ElseIfDeclaration" />
|
||||
</rule>
|
||||
|
||||
<rule ref="Squiz.Strings.ConcatenationSpacing">
|
||||
<properties>
|
||||
<property name="spacing" value="1" />
|
||||
<property name="ignoreNewlines" value="true"/>
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
<rule ref="PEAR.ControlStructures.MultiLineCondition" />
|
||||
|
||||
<rule ref="Generic.Formatting.SpaceAfterCast" />
|
||||
<rule ref="Generic.Arrays.DisallowLongArraySyntax.Found">
|
||||
<type>warning</type>
|
||||
</rule>
|
||||
|
||||
<rule ref="Squiz.Arrays.ArrayDeclaration.NoComma" />
|
||||
<rule ref="Squiz.WhiteSpace.OperatorSpacing">
|
||||
<properties>
|
||||
<property name="ignoreNewlines" value="true" />
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
<rule ref="PSR12.Functions.ReturnTypeDeclaration" />
|
||||
|
||||
<!-- include php files only -->
|
||||
<arg name="extensions" value="php,lib,inc,php5"/>
|
||||
|
||||
<file>./src</file>
|
||||
<file>./tests</file>
|
||||
<file>./_config.php</file>
|
||||
</ruleset>
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="vendor/silverstripe/framework/tests/bootstrap.php" colors="true" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
|
||||
<testsuites>
|
||||
<testsuite name="Default">
|
||||
<directory suffix=".php">tests/PHPUnit</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<groups>
|
||||
<exclude>
|
||||
<group>sanitychecks</group>
|
||||
</exclude>
|
||||
</groups>
|
||||
|
||||
<coverage includeUncoveredFiles="true">
|
||||
<include>
|
||||
<directory suffix=".php">src/</directory>
|
||||
</include>
|
||||
<exclude>
|
||||
<directory suffix=".php">tests/</directory>
|
||||
</exclude>
|
||||
</coverage>
|
||||
|
||||
<php>
|
||||
<get name="flush" value="1"/>
|
||||
</php>
|
||||
</phpunit>
|
|
@ -0,0 +1,808 @@
|
|||
<?php
|
||||
namespace UndefinedOffset\SortableGridField\Forms;
|
||||
|
||||
use SilverStripe\Admin\ModelAdmin;
|
||||
use SilverStripe\Control\Controller;
|
||||
use SilverStripe\Core\ClassInfo;
|
||||
use SilverStripe\Core\Config\Config;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\Forms\GridField\AbstractGridFieldComponent;
|
||||
use SilverStripe\Forms\GridField\GridField;
|
||||
use SilverStripe\Forms\GridField\GridField_ActionProvider;
|
||||
use SilverStripe\Forms\GridField\GridField_DataManipulator;
|
||||
use SilverStripe\Forms\GridField\GridField_FormAction;
|
||||
use SilverStripe\Forms\GridField\GridField_HTMLProvider;
|
||||
use SilverStripe\Forms\GridField\GridFieldFilterHeader;
|
||||
use SilverStripe\Forms\GridField\GridFieldPaginator;
|
||||
use SilverStripe\Forms\GridField\GridFieldSortableHeader;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\ORM\DataObjectSchema;
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\ORM\ManyManyList;
|
||||
use SilverStripe\ORM\ManyManyThroughList;
|
||||
use SilverStripe\ORM\RelationList;
|
||||
use SilverStripe\ORM\SS_List;
|
||||
use SilverStripe\ORM\UnsavedRelationList;
|
||||
use SilverStripe\ORM\ValidationException;
|
||||
use SilverStripe\Versioned\Versioned;
|
||||
use SilverStripe\View\ArrayData;
|
||||
use SilverStripe\View\Requirements;
|
||||
|
||||
/**
|
||||
* This component provides a checkbox which when checked enables drag-and-drop re-ordering of elements displayed in a {@link GridField}
|
||||
*/
|
||||
class GridFieldSortableRows extends AbstractGridFieldComponent implements GridField_HTMLProvider, GridField_ActionProvider, GridField_DataManipulator
|
||||
{
|
||||
/** @var string */
|
||||
protected $sortColumn;
|
||||
|
||||
/** @var bool */
|
||||
protected $disable_selection = true;
|
||||
|
||||
/** @var bool */
|
||||
protected $append_to_top = false;
|
||||
|
||||
/** @var null|string */
|
||||
protected $update_versioned_stage = null;
|
||||
|
||||
/** @var null|string */
|
||||
protected $custom_relation_name = null;
|
||||
|
||||
/**
|
||||
* @param string $sortColumn Column that should be used to update the sort information
|
||||
* @param bool $disableSelection Disable selection on the GridField when dragging
|
||||
* @param string $updateVersionStage Name of the versioned stage to update this disabled by default unless this is set
|
||||
* @param string $customRelationName Name of the relationship to use, if left null the name is determined from the GridField's name
|
||||
*/
|
||||
public function __construct($sortColumn, $disableSelection = true, $updateVersionStage = null, $customRelationName = null)
|
||||
{
|
||||
$this->sortColumn = $sortColumn;
|
||||
$this->disable_selection = $disableSelection;
|
||||
$this->update_versioned_stage = $updateVersionStage;
|
||||
$this->custom_relation_name = $customRelationName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a map where the keys are fragment names and the values are pieces of HTML to add to these fragments.
|
||||
* @param GridField $gridField Grid Field Reference
|
||||
* @return array Map where the keys are fragment names and the values are pieces of HTML to add to these fragments.
|
||||
*/
|
||||
public function getHTMLFragments($gridField)
|
||||
{
|
||||
$dataList = $gridField->getList();
|
||||
|
||||
if (class_exists('UnsavedRelationList') && $dataList instanceof UnsavedRelationList) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$state = $gridField->State->GridFieldSortableRows;
|
||||
if (!is_bool($state->sortableToggle)) {
|
||||
$state->sortableToggle = false;
|
||||
}
|
||||
|
||||
//Ensure user can edit
|
||||
if (!singleton($gridField->getModelClass())->canEdit()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
//Sort order toggle
|
||||
$sortOrderToggle = GridField_FormAction::create(
|
||||
$gridField,
|
||||
'sortablerows-toggle',
|
||||
'sorttoggle',
|
||||
'sortableRowsToggle',
|
||||
null
|
||||
)->addExtraClass('sortablerows-toggle');
|
||||
|
||||
|
||||
$sortOrderSave = GridField_FormAction::create(
|
||||
$gridField,
|
||||
'sortablerows-savesort',
|
||||
'savesort',
|
||||
'saveGridRowSort',
|
||||
null
|
||||
)->addExtraClass('sortablerows-savesort');
|
||||
|
||||
|
||||
//Sort to Page Action
|
||||
$sortToPage = GridField_FormAction::create(
|
||||
$gridField,
|
||||
'sortablerows-sorttopage',
|
||||
'sorttopage',
|
||||
'sortToPage',
|
||||
null
|
||||
)->addExtraClass('sortablerows-sorttopage');
|
||||
|
||||
|
||||
$data = [
|
||||
'SortableToggle' => $sortOrderToggle,
|
||||
'SortOrderSave' => $sortOrderSave,
|
||||
'SortToPage' => $sortToPage,
|
||||
'Checked' => ($state->sortableToggle == true ? ' checked = "checked"' : ''),
|
||||
'List' => $dataList,
|
||||
];
|
||||
|
||||
$forTemplate = new ArrayData($data);
|
||||
|
||||
Requirements::css('undefinedoffset/sortablegridfield:css/GridFieldSortableRows.css');
|
||||
Requirements::javascript('undefinedoffset/sortablegridfield:javascript/GridFieldSortableRows.js');
|
||||
|
||||
$args = ['Colspan' => count($gridField->getColumns()), 'ID' => $gridField->ID(), 'DisableSelection' => $this->disable_selection];
|
||||
|
||||
$fragments = ['header' => $forTemplate->renderWith('SortableGridField\Forms\Includes\GridFieldSortableRows', $args)];
|
||||
|
||||
if ($gridField->getConfig()->getComponentByType(GridFieldPaginator::class)) {
|
||||
$fragments['after'] = $forTemplate->renderWith('SortableGridField\Forms\Includes\GridFieldSortableRows_paginator');
|
||||
}
|
||||
|
||||
return $fragments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Manipulate the datalist as needed by this grid modifier.
|
||||
* @param GridField $gridField Grid Field Reference
|
||||
* @param SS_List|\SilverStripe\ORM\DataList $dataList Data List to adjust
|
||||
* @return \SilverStripe\ORM\DataList Modified Data List
|
||||
*/
|
||||
public function getManipulatedData(GridField $gridField, SS_List $dataList)
|
||||
{
|
||||
//Detect and correct items with a sort column value of 0 (push to bottom)
|
||||
$this->fixSortColumn($gridField, $dataList);
|
||||
|
||||
|
||||
$headerState = $gridField->State->GridFieldSortableHeader;
|
||||
$state = $gridField->State->GridFieldSortableRows;
|
||||
if ((!is_bool($state->sortableToggle) || $state->sortableToggle === false) && $headerState && is_string($headerState->SortColumn) && is_string($headerState->SortDirection)) {
|
||||
return $dataList->sort($headerState->SortColumn, $headerState->SortDirection);
|
||||
}
|
||||
|
||||
if ($state->sortableToggle === true) {
|
||||
$gridField->getConfig()->removeComponentsByType(GridFieldFilterHeader::class);
|
||||
$gridField->getConfig()->removeComponentsByType(GridFieldSortableHeader::class);
|
||||
}
|
||||
|
||||
return $dataList->sort($this->sortColumn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if new records should be appended to the top or the bottom of the list
|
||||
* @param bool $value Boolean true to append to the top false to append to the bottom
|
||||
* @return GridFieldSortableRows Returns the current instance
|
||||
*/
|
||||
public function setAppendToTop($value)
|
||||
{
|
||||
$this->append_to_top = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $value Boolean true to disable selection of table contents false to enable selection
|
||||
* @return GridFieldSortableRows Returns the current instance
|
||||
*/
|
||||
public function setDisableSelection($value)
|
||||
{
|
||||
$this->disable_selection = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the suffix of the versioned stage that should be updated along side the default stage
|
||||
* @param string $value Versioned Stage to update this is disabled by default unless this is set
|
||||
* @return GridFieldSortableRows Returns the current instance
|
||||
*/
|
||||
public function setUpdateVersionedStage($value)
|
||||
{
|
||||
$this->update_versioned_stage = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the relationship to use, by default the name is determined from the GridField's name
|
||||
* @param string $value Name of the relationship to use, by default the name is determined from the GridField's name
|
||||
* @return GridFieldSortableRows Returns the current instance
|
||||
*/
|
||||
public function setCustomRelationName($value)
|
||||
{
|
||||
$this->custom_relation_name = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects and corrects items with a sort column value of 0, by appending them to the bottom of the list
|
||||
* @param GridField $gridField Grid Field Reference
|
||||
* @param SS_List|\SilverStripe\ORM\DataList $dataList Data List of items to be checked
|
||||
*/
|
||||
protected function fixSortColumn($gridField, SS_List $dataList)
|
||||
{
|
||||
if ($dataList instanceof UnsavedRelationList) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var SS_List|\SilverStripe\ORM\DataList $list */
|
||||
$list = clone $dataList;
|
||||
$list = $list->alterDataQuery(function ($query, SS_List $tmplist) {
|
||||
/** @var \SilverStripe\ORM\DataQuery $query */
|
||||
$query->limit(null);
|
||||
return $query;
|
||||
});
|
||||
|
||||
$many_many = ($list instanceof ManyManyList || $list instanceof ManyManyThroughList);
|
||||
if (!$many_many) {
|
||||
$sng = singleton($gridField->getModelClass());
|
||||
$fieldType = $sng->config()->db[$this->sortColumn];
|
||||
|
||||
if (!$fieldType || !($fieldType == 'Int' || $fieldType == 'SilverStripe\\ORM\\FieldType\\DBInt' || is_subclass_of($fieldType, 'SilverStripe\\ORM\\FieldType\\DBInt'))) {
|
||||
if (is_array($fieldType)) {
|
||||
user_error('Sort column ' . $this->sortColumn . ' could not be found in ' . $gridField->getModelClass() . '\'s ancestry', E_USER_ERROR);
|
||||
} else {
|
||||
user_error('Sort column ' . $this->sortColumn . ' must be an instance of SilverStripe\\ORM\\FieldType\\DBInt, column is of type ' . $fieldType, E_USER_ERROR);
|
||||
}
|
||||
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
$max = $list->Max($this->sortColumn);
|
||||
$list = $list->filter($this->sortColumn, 0)->sort("Created,ID");
|
||||
if ($list->Count() > 0) {
|
||||
$owner = $gridField->getForm()->getRecord();
|
||||
$sortColumn = $this->sortColumn;
|
||||
$i = 1;
|
||||
|
||||
if ($many_many) {
|
||||
$schema = Injector::inst()->get(DataObjectSchema::class);
|
||||
$componentDetails = $schema->manyManyComponent(get_class($owner), (!empty($this->custom_relation_name) ? $this->custom_relation_name : $gridField->getName()));
|
||||
if (empty($componentDetails)) {
|
||||
user_error('Could not find the relationship "' . (!empty($this->custom_relation_name) ? $this->custom_relation_name : $gridField->getName()) . '" on "' . get_class($owner) . '"', E_USER_ERROR);
|
||||
}
|
||||
|
||||
$parentField = $componentDetails['parentField'];
|
||||
$componentField = $componentDetails['childField'];
|
||||
$table = $componentDetails['join'];
|
||||
|
||||
//For ManyManyThroughLists get the right join table
|
||||
if ($list instanceof ManyManyThroughList && class_exists($table)) {
|
||||
$table = $schema->tableName($table);
|
||||
}
|
||||
|
||||
$extraFields = $list->getExtraFields();
|
||||
|
||||
if (!$extraFields || !array_key_exists($this->sortColumn, $extraFields) || !($extraFields[$this->sortColumn] == 'Int' || $extraFields[$this->sortColumn] == 'SilverStripe\\ORM\\FieldType\\DBInt' || is_subclass_of('SilverStripe\\ORM\\FieldType\\DBInt', $extraFields[$this->sortColumn]))) {
|
||||
user_error('Sort column ' . $this->sortColumn . ' must be an SilverStripe\\ORM\\FieldType\\DBInt, column is of type ' . $extraFields[$this->sortColumn], E_USER_ERROR);
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
//Find table containing the sort column
|
||||
$table = false;
|
||||
$class = $gridField->getModelClass();
|
||||
|
||||
$db = Config::inst()->get($class, "db", CONFIG::UNINHERITED);
|
||||
if (!empty($db) && array_key_exists($sortColumn, $db)) {
|
||||
$table = DataObject::getSchema()->tableName($class);
|
||||
} else {
|
||||
$classes = ClassInfo::ancestry($class, true);
|
||||
foreach ($classes as $class) {
|
||||
$db = Config::inst()->get($class, "db", CONFIG::UNINHERITED);
|
||||
if (!empty($db) && array_key_exists($sortColumn, $db)) {
|
||||
$table = DataObject::getSchema()->tableName($class);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($table === false) {
|
||||
user_error('Sort column ' . $this->sortColumn . ' could not be found in ' . $gridField->getModelClass() . '\'s ancestry', E_USER_ERROR);
|
||||
exit;
|
||||
}
|
||||
|
||||
$baseDataClass = DataObject::getSchema()->baseDataClass($gridField->getModelClass());
|
||||
$baseDataTable = DataObject::getSchema()->tableName($baseDataClass);
|
||||
}
|
||||
|
||||
|
||||
//Start transaction if supported
|
||||
if (DB::get_conn()->supportsTransactions()) {
|
||||
DB::get_conn()->transactionStart();
|
||||
}
|
||||
|
||||
$idCondition = null;
|
||||
if ($this->append_to_top && !($list instanceof RelationList)) {
|
||||
$idCondition = '"ID" IN(\'' . implode("','", $dataList->getIDList()) . '\')';
|
||||
}
|
||||
|
||||
if ($this->append_to_top) {
|
||||
$topIncremented = [];
|
||||
}
|
||||
|
||||
$modelClass = $gridField->getModelClass();
|
||||
$hasVersioned = $this->hasVersionedExtension($modelClass);
|
||||
foreach ($list as $obj) {
|
||||
if ($many_many) {
|
||||
if ($this->append_to_top) {
|
||||
//Upgrade all the records (including the last inserted from 0 to 1)
|
||||
DB::query('UPDATE "' . $table
|
||||
. '" SET "' . $sortColumn . '" = "' . $sortColumn . '"+1'
|
||||
. ' WHERE "' . $parentField . '" = ' . $owner->ID . (!empty($topIncremented) ? ' AND "' . $componentField . '" NOT IN(\'' . implode('\',\'', $topIncremented) . '\')' : ''));
|
||||
|
||||
$topIncremented[] = $obj->ID;
|
||||
} else {
|
||||
//Append the last record to the bottom
|
||||
DB::query('UPDATE "' . $table
|
||||
. '" SET "' . $sortColumn . '" = ' . ($max + $i)
|
||||
. ' WHERE "' . $componentField . '" = ' . $obj->ID . ' AND "' . $parentField . '" = ' . $owner->ID);
|
||||
}
|
||||
} else if ($this->append_to_top) {
|
||||
if ($hasVersioned) {
|
||||
// For versioned objects, modify them with the ORM so that the *_versions table is updated
|
||||
$itemsToUpdate = $modelClass::get()->where(($list instanceof RelationList ? '"' . $list->foreignKey . '" = ' . $owner->ID : $idCondition) . (!empty($topIncremented) ? ' AND "ID" NOT IN(\'' . implode('\',\'', $topIncremented) . '\')' : ''));
|
||||
if ($itemsToUpdate->exists()) {
|
||||
foreach ($itemsToUpdate as $item) {
|
||||
$item->$sortColumn = $item->$sortColumn + 1;
|
||||
$item->write();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//Upgrade all the records (including the last inserted from 0 to 1)
|
||||
DB::query('UPDATE "' . $table
|
||||
. '" SET "' . $sortColumn . '" = "' . $sortColumn . '"+1'
|
||||
. ' WHERE ' . ($list instanceof RelationList ? '"' . $list->foreignKey . '" = ' . $owner->ID : $idCondition) . (!empty($topIncremented) ? ' AND "ID" NOT IN(\'' . implode('\',\'', $topIncremented) . '\')' : ''));
|
||||
}
|
||||
|
||||
if ($this->update_versioned_stage && $this->hasVersionedExtension($gridField->getModelClass())) {
|
||||
DB::query('UPDATE "' . $table . '_' . $this->update_versioned_stage
|
||||
. '" SET "' . $sortColumn . '" = "' . $sortColumn . '"+1'
|
||||
. ' WHERE ' . ($list instanceof RelationList ? '"' . $list->foreignKey . '" = ' . $owner->ID : $idCondition) . (!empty($topIncremented) ? ' AND "ID" NOT IN(\'' . implode('\',\'', $topIncremented) . '\')' : ''));
|
||||
}
|
||||
|
||||
$topIncremented[] = $obj->ID;
|
||||
} else {
|
||||
if ($hasVersioned) {
|
||||
// For versioned objects, modify them with the ORM so that the *_versions table is updated
|
||||
$obj->$sortColumn = ($max + $i);
|
||||
$obj->write();
|
||||
} else {
|
||||
//Append the last record to the bottom
|
||||
DB::query('UPDATE "' . $table
|
||||
. '" SET "' . $sortColumn . '" = ' . ($max + $i)
|
||||
. ' WHERE "ID" = ' . $obj->ID);
|
||||
|
||||
//LastEdited
|
||||
DB::query('UPDATE "' . $baseDataTable
|
||||
. '" SET "LastEdited" = \'' . date('Y-m-d H:i:s') . '\''
|
||||
. ' WHERE "ID" = ' . $obj->ID);
|
||||
}
|
||||
|
||||
if ($this->update_versioned_stage && $this->hasVersionedExtension($gridField->getModelClass())) {
|
||||
DB::query('UPDATE "' . $table . '_' . $this->update_versioned_stage
|
||||
. '" SET "' . $sortColumn . '" = ' . ($max + $i)
|
||||
. ' WHERE "ID" = ' . $obj->ID);
|
||||
|
||||
if ($this->hasVersionedExtension($baseDataClass)) {
|
||||
DB::query('UPDATE "' . $baseDataTable . '_' . $this->update_versioned_stage
|
||||
. '" SET "LastEdited" = \'' . date('Y-m-d H:i:s') . '\''
|
||||
. ' WHERE "ID" = ' . $obj->ID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$i++;
|
||||
}
|
||||
|
||||
//Update LastEdited for affected records when using append to top on a many_many relationship
|
||||
if (!$many_many && $this->append_to_top && count($topIncremented) > 0) {
|
||||
DB::query('UPDATE "' . $baseDataTable
|
||||
. '" SET "LastEdited" = \'' . date('Y-m-d H:i:s') . '\''
|
||||
. ' WHERE "ID" IN(\'' . implode('\',\'', $topIncremented) . '\')');
|
||||
|
||||
if ($this->update_versioned_stage && $this->hasVersionedExtension($gridField->getModelClass()) && $this->hasVersionedExtension($baseDataClass)) {
|
||||
DB::query('UPDATE "' . $baseDataTable . '_' . $this->update_versioned_stage
|
||||
. '" SET "LastEdited" = \'' . date('Y-m-d H:i:s') . '\''
|
||||
. ' WHERE "ID" IN(\'' . implode('\',\'', $topIncremented) . '\')');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//End transaction if supported
|
||||
if (DB::get_conn()->supportsTransactions()) {
|
||||
DB::get_conn()->transactionEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of the actions handled by this action provider.
|
||||
* @param GridField $gridField Grid Field Reference
|
||||
* @return array array with action identifier strings.
|
||||
*/
|
||||
public function getActions($gridField)
|
||||
{
|
||||
return ['saveGridRowSort', 'sortableRowsToggle', 'sortToPage'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an action on the given grid field.
|
||||
* @param GridField $gridField Grid Field Reference
|
||||
* @param String $actionName Action identifier, see {@link getActions()}.
|
||||
* @param array $arguments Arguments relevant for this
|
||||
* @param array $data All form data
|
||||
*/
|
||||
public function handleAction(GridField $gridField, $actionName, $arguments, $data)
|
||||
{
|
||||
$state = $gridField->State->GridFieldSortableRows;
|
||||
if (!is_bool($state->sortableToggle)) {
|
||||
$state->sortableToggle = false;
|
||||
} else if ($state->sortableToggle == true) {
|
||||
$gridField->getConfig()->removeComponentsByType(GridFieldFilterHeader::class);
|
||||
$gridField->getConfig()->removeComponentsByType(GridFieldSortableHeader::class);
|
||||
}
|
||||
|
||||
|
||||
if ($actionName == 'savegridrowsort') {
|
||||
return $this->saveGridRowSort($gridField, $data);
|
||||
} else if ($actionName == 'sorttopage') {
|
||||
return $this->sortToPage($gridField, $data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles saving of the row sort order
|
||||
* @param GridField $gridField Grid Field Reference
|
||||
* @param array $data Data submitted in the request
|
||||
* @throws ValidationException If user has no edit permissions
|
||||
*/
|
||||
protected function saveGridRowSort(GridField $gridField, $data)
|
||||
{
|
||||
$dataList = $gridField->getList();
|
||||
|
||||
if ($dataList instanceof UnsavedRelationList) {
|
||||
user_error('Cannot sort an UnsavedRelationList', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!singleton($gridField->getModelClass())->canEdit()) {
|
||||
throw new ValidationException(_t('GridFieldSortableRows.EditPermissionsFailure', "No edit permissions"), 0);
|
||||
}
|
||||
|
||||
if (empty($data['ItemIDs'])) {
|
||||
user_error('No items to sort', E_USER_ERROR);
|
||||
}
|
||||
|
||||
$className = $gridField->getModelClass();
|
||||
$owner = $gridField->Form->getRecord();
|
||||
$items = clone $gridField->getList();
|
||||
$many_many = ($items instanceof ManyManyList || $items instanceof ManyManyThroughList);
|
||||
$sortColumn = $this->sortColumn;
|
||||
$pageOffset = 0;
|
||||
|
||||
if ($paginator = $gridField->getConfig()->getComponentsByType(GridFieldPaginator::class)->First()) {
|
||||
$pageState = $gridField->State->GridFieldPaginator;
|
||||
|
||||
if ($pageState->currentPage && is_int($pageState->currentPage) && $pageState->currentPage > 1) {
|
||||
$pageOffset = $paginator->getItemsPerPage() * ($pageState->currentPage - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ($many_many) {
|
||||
$schema = Injector::inst()->get(DataObjectSchema::class);
|
||||
$componentDetails = $schema->manyManyComponent(get_class($owner), (!empty($this->custom_relation_name) ? $this->custom_relation_name : $gridField->getName()));
|
||||
if (empty($componentDetails)) {
|
||||
user_error('Could not find the relationship "' . (!empty($this->custom_relation_name) ? $this->custom_relation_name : $gridField->getName()) . '" on "' . get_class($owner) . '"', E_USER_ERROR);
|
||||
}
|
||||
|
||||
$parentField = $componentDetails['parentField'];
|
||||
$componentField = $componentDetails['childField'];
|
||||
$table = $componentDetails['join'];
|
||||
|
||||
//For ManyManyThroughLists get the right join table
|
||||
if ($items instanceof ManyManyThroughList && class_exists($table)) {
|
||||
$table = $schema->tableName($table);
|
||||
}
|
||||
} else {
|
||||
//Find table containing the sort column
|
||||
$table = false;
|
||||
$class = $gridField->getModelClass();
|
||||
$db = Config::inst()->get($class, "db", CONFIG::UNINHERITED);
|
||||
if (!empty($db) && array_key_exists($sortColumn, $db)) {
|
||||
$table = DataObject::getSchema()->tableName($class);
|
||||
} else {
|
||||
$classes = ClassInfo::ancestry($class, true);
|
||||
foreach ($classes as $class) {
|
||||
$db = Config::inst()->get($class, "db", CONFIG::UNINHERITED);
|
||||
if (!empty($db) && array_key_exists($sortColumn, $db)) {
|
||||
$table = DataObject::getSchema()->tableName($class);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($table === false) {
|
||||
user_error('Sort column ' . $this->sortColumn . ' could not be found in ' . $gridField->getModelClass() . '\'s ancestry', E_USER_ERROR);
|
||||
exit;
|
||||
}
|
||||
|
||||
$baseDataClass = DataObject::getSchema()->baseDataClass($gridField->getModelClass());
|
||||
$baseDataTable = DataObject::getSchema()->tableName($baseDataClass);
|
||||
}
|
||||
|
||||
|
||||
//Event to notify the Controller or owner DataObject before list sort
|
||||
if ($owner && $owner instanceof DataObject && method_exists($owner, 'onBeforeGridFieldRowSort')) {
|
||||
$owner->onBeforeGridFieldRowSort(clone $items);
|
||||
} else if (Controller::has_curr() && Controller::curr() instanceof ModelAdmin && method_exists(Controller::curr(), 'onBeforeGridFieldRowSort')) {
|
||||
Controller::curr()->onBeforeGridFieldRowSort(clone $items);
|
||||
}
|
||||
|
||||
//Start transaction if supported
|
||||
if (DB::get_conn()->supportsTransactions()) {
|
||||
DB::get_conn()->transactionStart();
|
||||
}
|
||||
|
||||
//Perform sorting
|
||||
$ids = explode(',', $data['ItemIDs']);
|
||||
$modelClass = $gridField->getModelClass();
|
||||
$hasVersioned = $this->hasVersionedExtension($modelClass);
|
||||
for ($sort = 0; $sort < count($ids); $sort++) {
|
||||
$id = intval($ids[$sort]);
|
||||
if ($many_many) {
|
||||
DB::query('UPDATE "' . $table
|
||||
. '" SET "' . $sortColumn . '" = ' . (($sort + 1) + $pageOffset)
|
||||
. ' WHERE "' . $componentField . '" = ' . $id . ' AND "' . $parentField . '" = ' . $owner->ID);
|
||||
} else {
|
||||
if ($hasVersioned) {
|
||||
// For versioned objects, modify them with the ORM so that the *_versions table is updated
|
||||
$obj = $modelClass::get()->byID(intval($id));
|
||||
if (!empty($obj) && $obj !== false && $obj->exists()) {
|
||||
$obj->$sortColumn = (($sort + 1) + $pageOffset);
|
||||
$obj->write();
|
||||
}
|
||||
} else {
|
||||
DB::query('UPDATE "' . $table
|
||||
. '" SET "' . $sortColumn . '" = ' . (($sort + 1) + $pageOffset)
|
||||
. ' WHERE "ID" = ' . $id);
|
||||
|
||||
DB::query('UPDATE "' . $baseDataTable
|
||||
. '" SET "LastEdited" = \'' . date('Y-m-d H:i:s') . '\''
|
||||
. ' WHERE "ID" = ' . $id);
|
||||
}
|
||||
|
||||
if ($this->update_versioned_stage && $hasVersioned) {
|
||||
DB::query('UPDATE "' . $table . '_' . $this->update_versioned_stage
|
||||
. '" SET "' . $sortColumn . '" = ' . (($sort + 1) + $pageOffset)
|
||||
. ' WHERE "ID" = ' . $id);
|
||||
|
||||
if ($this->hasVersionedExtension($baseDataClass)) {
|
||||
DB::query('UPDATE "' . $baseDataTable . '_' . $this->update_versioned_stage
|
||||
. '" SET "LastEdited" = \'' . date('Y-m-d H:i:s') . '\''
|
||||
. ' WHERE "ID" = ' . $id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//End transaction if supported
|
||||
if (DB::get_conn()->supportsTransactions()) {
|
||||
DB::get_conn()->transactionEnd();
|
||||
}
|
||||
|
||||
|
||||
//Event to notify the Controller or owner DataObject after list sort
|
||||
if ($owner && $owner instanceof DataObject && method_exists($owner, 'onAfterGridFieldRowSort')) {
|
||||
$owner->onAfterGridFieldRowSort(clone $items);
|
||||
} else if (Controller::has_curr() && Controller::curr() instanceof ModelAdmin && method_exists(Controller::curr(), 'onAfterGridFieldRowSort')) {
|
||||
Controller::curr()->onAfterGridFieldRowSort(clone $items);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles sorting across pages
|
||||
* @param GridField $gridField Grid Field Reference
|
||||
* @param array $data Data submitted in the request
|
||||
*/
|
||||
protected function sortToPage(GridField $gridField, $data)
|
||||
{
|
||||
if (!$paginator = $gridField->getConfig()->getComponentsByType(GridFieldPaginator::class)->First()) {
|
||||
user_error('Paginator not detected', E_USER_ERROR);
|
||||
}
|
||||
|
||||
if (empty($data['ItemID'])) {
|
||||
user_error('No item to sort', E_USER_ERROR);
|
||||
}
|
||||
|
||||
if (empty($data['Target'])) {
|
||||
user_error('No target page', E_USER_ERROR);
|
||||
}
|
||||
|
||||
/** @var \SilverStripe\Core\Extensible $className */
|
||||
$className = $gridField->getModelClass();
|
||||
$owner = $gridField->Form->getRecord();
|
||||
|
||||
/** @var DataList $items */
|
||||
$items = clone $gridField->getList();
|
||||
|
||||
$many_many = ($items instanceof ManyManyList || $items instanceof ManyManyThroughList);
|
||||
$sortColumn = $this->sortColumn;
|
||||
$targetItem = $items->byID(intval($data['ItemID']));
|
||||
|
||||
if (!$targetItem) {
|
||||
user_error('Target item not found', E_USER_ERROR);
|
||||
}
|
||||
|
||||
$currentPage = 1;
|
||||
|
||||
$pageState = $gridField->State->GridFieldPaginator;
|
||||
if ($pageState->currentPage && $pageState->currentPage > 1) {
|
||||
$currentPage = $pageState->currentPage;
|
||||
}
|
||||
|
||||
if ($many_many) {
|
||||
$schema = Injector::inst()->get(DataObjectSchema::class);
|
||||
$componentDetails = $schema->manyManyComponent(get_class($owner), (!empty($this->custom_relation_name) ? $this->custom_relation_name : $gridField->getName()));
|
||||
$parentField = $componentDetails['parentField'];
|
||||
$componentField = $componentDetails['childField'];
|
||||
$table = $componentDetails['join'];
|
||||
|
||||
//For ManyManyThroughLists get the right join table
|
||||
if ($items instanceof ManyManyThroughList && class_exists($table)) {
|
||||
$table = $schema->tableName($table);
|
||||
}
|
||||
}
|
||||
|
||||
if ($data['Target'] == 'previouspage') {
|
||||
$items = $items->limit($paginator->getItemsPerPage() + 1, ($paginator->getItemsPerPage() * ($currentPage - 1)) - 1);
|
||||
} else if ($data['Target'] == 'nextpage') {
|
||||
$items = $items->limit($paginator->getItemsPerPage() + 1, $paginator->getItemsPerPage() * ($currentPage - 1));
|
||||
} else {
|
||||
user_error('Not implemented: ' . $data['Target'], E_USER_ERROR);
|
||||
}
|
||||
|
||||
$sortPositions = $items->column($sortColumn);
|
||||
|
||||
//Event to notify the Controller or owner DataObject before list sort
|
||||
if ($owner && $owner instanceof DataObject && method_exists($owner, 'onBeforeGridFieldPageSort')) {
|
||||
$owner->onBeforeGridFieldPageSort(clone $items);
|
||||
} else if (Controller::has_curr() && Controller::curr() instanceof ModelAdmin && method_exists(Controller::curr(), 'onBeforeGridFieldPageSort')) {
|
||||
Controller::curr()->onBeforeGridFieldPageSort(clone $items);
|
||||
}
|
||||
|
||||
//Find the sort column
|
||||
if ($this->update_versioned_stage && $this->hasVersionedExtension($className)) {
|
||||
$table = false;
|
||||
$classes = ClassInfo::ancestry($className, true);
|
||||
foreach ($classes as $class) {
|
||||
$db = Config::inst()->get($class, "db", CONFIG::UNINHERITED);
|
||||
if (!empty($db) && array_key_exists($sortColumn, $db)) {
|
||||
$table = DataObject::getSchema()->tableName($class);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($table === false) {
|
||||
user_error('Sort column ' . $this->sortColumn . ' could not be found in ' . $gridField->getModelClass() . '\'s ancestry', E_USER_ERROR);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
//Start transaction if supported
|
||||
if (DB::get_conn()->supportsTransactions()) {
|
||||
DB::get_conn()->transactionStart();
|
||||
}
|
||||
|
||||
if ($data['Target'] == 'previouspage') {
|
||||
if ($many_many) {
|
||||
DB::query('UPDATE "' . $table
|
||||
. '" SET "' . $sortColumn . '" = ' . $sortPositions[0]
|
||||
. ' WHERE "' . $componentField . '" = ' . $targetItem->ID . ' AND "' . $parentField . '" = ' . $owner->ID);
|
||||
} else {
|
||||
$targetItem->$sortColumn = $sortPositions[0];
|
||||
$targetItem->write();
|
||||
|
||||
if ($this->update_versioned_stage && $this->hasVersionedExtension($className)) {
|
||||
DB::query('UPDATE "' . $table . '_' . $this->update_versioned_stage
|
||||
. '" SET "' . $sortColumn . '" = ' . $sortPositions[0]
|
||||
. ' WHERE "ID" = ' . $targetItem->ID);
|
||||
}
|
||||
}
|
||||
|
||||
$i = 1;
|
||||
foreach ($items as $obj) {
|
||||
if ($obj->ID == $targetItem->ID || $i >= count($sortPositions)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if ($many_many) {
|
||||
DB::query('UPDATE "' . $table
|
||||
. '" SET "' . $sortColumn . '" = ' . $sortPositions[$i]
|
||||
. ' WHERE "' . $componentField . '" = ' . $obj->ID . ' AND "' . $parentField . '" = ' . $owner->ID);
|
||||
} else {
|
||||
$obj->$sortColumn = $sortPositions[$i];
|
||||
$obj->write();
|
||||
|
||||
if ($this->update_versioned_stage && $this->hasVersionedExtension($className)) {
|
||||
DB::query('UPDATE "' . $table . '_' . $this->update_versioned_stage
|
||||
. '" SET "' . $sortColumn . '" = ' . $sortPositions[$i]
|
||||
. ' WHERE "ID" = ' . $obj->ID);
|
||||
}
|
||||
}
|
||||
|
||||
$i++;
|
||||
}
|
||||
} else {
|
||||
if ($many_many) {
|
||||
DB::query('UPDATE "' . $table
|
||||
. '" SET "' . $sortColumn . '" = ' . $sortPositions[count($sortPositions) - 1]
|
||||
. ' WHERE "' . $componentField . '" = ' . $targetItem->ID . ' AND "' . $parentField . '" = ' . $owner->ID);
|
||||
} else {
|
||||
$targetItem->$sortColumn = $sortPositions[count($sortPositions) - 1];
|
||||
$targetItem->write();
|
||||
|
||||
if ($this->update_versioned_stage && $this->hasVersionedExtension($className)) {
|
||||
DB::query('UPDATE "' . $table . '_' . $this->update_versioned_stage
|
||||
. '" SET "' . $sortColumn . '" = ' . $sortPositions[count($sortPositions) - 1]
|
||||
. ' WHERE "ID" = ' . $targetItem->ID);
|
||||
}
|
||||
}
|
||||
|
||||
$i = 0;
|
||||
foreach ($items as $obj) {
|
||||
if ($obj->ID == $targetItem->ID) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if ($many_many) {
|
||||
DB::query('UPDATE "' . $table
|
||||
. '" SET "' . $sortColumn . '" = ' . $sortPositions[$i]
|
||||
. ' WHERE "' . $componentField . '" = ' . $obj->ID . ' AND "' . $parentField . '" = ' . $owner->ID);
|
||||
} else {
|
||||
$obj->$sortColumn = $sortPositions[$i];
|
||||
$obj->write();
|
||||
|
||||
if ($this->update_versioned_stage && $this->hasVersionedExtension($className)) {
|
||||
DB::query('UPDATE "' . $table . '_' . $this->update_versioned_stage
|
||||
. '" SET "' . $sortColumn . '" = ' . $sortPositions[$i]
|
||||
. ' WHERE "ID" = ' . $obj->ID);
|
||||
}
|
||||
}
|
||||
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
|
||||
//End transaction if supported
|
||||
if (DB::get_conn()->supportsTransactions()) {
|
||||
DB::get_conn()->transactionEnd();
|
||||
}
|
||||
|
||||
//Event to notify the Controller or owner DataObject after list sort
|
||||
if ($owner && $owner instanceof DataObject && method_exists($owner, 'onAfterGridFieldPageSort')) {
|
||||
$owner->onAfterGridFieldPageSort(clone $items);
|
||||
} else if (Controller::has_curr() && Controller::curr() instanceof ModelAdmin && method_exists(Controller::curr(), 'onAfterGridFieldPageSort')) {
|
||||
Controller::curr()->onAfterGridFieldPageSort(clone $items);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if the given class name has the Versioned extension
|
||||
* @param \SilverStripe\Core\Extensible|string $className
|
||||
* @return bool
|
||||
*/
|
||||
public function hasVersionedExtension($className)
|
||||
{
|
||||
return $className::has_extension(Versioned::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if $table_name is declared on the DataObject, if not returns string as given
|
||||
* @param $className
|
||||
* @return string
|
||||
* @deprecated Use DataObject::getSchema()->tableName() instead
|
||||
*/
|
||||
public function mapTableNameAndReturn($className)
|
||||
{
|
||||
return DataObject::getSchema()->tableName($className);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
<tr>
|
||||
<th class="extra sortablerowsheading" colspan="$Colspan">
|
||||
<td class="sortablerowsheading" colspan="$Colspan">
|
||||
<div class="gridfield-sortablerows">
|
||||
<input type="checkbox" id="{$ID}_AllowDragDropCheck" value="1" autocomplete="off" class="no-change-track<% if $DisableSelection %> gridfield-sortablerows-noselection<% end_if %>"$Checked/>
|
||||
<label for="{$ID}_AllowDragDropCheck"><%t GridFieldSortableRows.ALLOW_DRAG_DROP "Allow drag and drop re-ordering" %></label>
|
||||
|
@ -7,5 +7,5 @@
|
|||
$SortOrderSave
|
||||
$SortToPage
|
||||
</div>
|
||||
</th>
|
||||
</td>
|
||||
</tr>
|
|
@ -0,0 +1,112 @@
|
|||
<?php
|
||||
namespace UndefinedOffset\SortableGridField\Tests\PHPUnit\Bootstrap;
|
||||
|
||||
use PHPUnit\Framework\TestFailure;
|
||||
use PHPUnit\TextUI\DefaultResultPrinter;
|
||||
|
||||
class GitHubActionsAnnotatorPrinter extends DefaultResultPrinter
|
||||
{
|
||||
protected $currentType = null;
|
||||
|
||||
/**
|
||||
* Handles printing of the defects
|
||||
* @param array $defects Array of Test Failures
|
||||
* @param string $type Type of the failure
|
||||
*/
|
||||
protected function printDefects(array $defects, string $type): void
|
||||
{
|
||||
$this->currentType = $type;
|
||||
|
||||
parent::printDefects($defects, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles printing of a single defect
|
||||
* @param TestFailure $defect Test Failure Object
|
||||
* @param int $count Current position
|
||||
*/
|
||||
protected function printDefect(TestFailure $defect, int $count): void
|
||||
{
|
||||
parent::printDefect($defect, $count);
|
||||
|
||||
$this->printGitHubAnnotation($defect);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prints a GitHub Annotation Command
|
||||
* @param TestFailure $defect Defect to print
|
||||
*/
|
||||
protected function printGitHubAnnotation(TestFailure $defect)
|
||||
{
|
||||
$e = $defect->thrownException();
|
||||
|
||||
$errorLines = array_filter(
|
||||
explode("\n", (string) $e),
|
||||
function ($l) {
|
||||
return $l;
|
||||
}
|
||||
);
|
||||
|
||||
$error = end($errorLines);
|
||||
$lineIndex = strrpos($error, ":");
|
||||
$path = substr($error, 0, $lineIndex);
|
||||
$line = substr($error, $lineIndex + 1);
|
||||
|
||||
if (!$path) {
|
||||
list($path, $line) = $this->getReflectionFromTest(
|
||||
$defect->getTestName()
|
||||
);
|
||||
}
|
||||
|
||||
$message = explode("\n", trim($defect->getTestName() . "\n\n" . (string) $e));
|
||||
$message = implode('%0A', $message);
|
||||
|
||||
$type = $this->getCurrentType();
|
||||
$file = "file={$this->relativePath($path)}";
|
||||
$line = "line={$line}";
|
||||
$this->write("::{$type} $file,$line::{$message}\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current type of the defect
|
||||
* @return string
|
||||
*/
|
||||
protected function getCurrentType()
|
||||
{
|
||||
if (in_array($this->currentType, ['error', 'failure'])) {
|
||||
return 'error';
|
||||
}
|
||||
|
||||
return 'warning';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the relative path to the file
|
||||
* @param string $path Path to make relative
|
||||
* @return string
|
||||
*/
|
||||
protected function relativePath($path)
|
||||
{
|
||||
$relative = str_replace(getcwd() . DIRECTORY_SEPARATOR, '', $path);
|
||||
|
||||
//Normalize
|
||||
$relative = str_replace('\\', '/', $relative);
|
||||
|
||||
return $relative;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the file name and start line for the test
|
||||
* @param string $name Name of the test
|
||||
* @return array
|
||||
*/
|
||||
protected function getReflectionFromTest($name)
|
||||
{
|
||||
list($klass, $method) = explode('::', $name);
|
||||
$c = new \ReflectionClass($klass);
|
||||
$m = $c->getMethod($method);
|
||||
|
||||
return [$m->getFileName(), $m->getStartLine()];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,264 @@
|
|||
<?php
|
||||
namespace UndefinedOffset\SortableGridField\Tests\Forms;
|
||||
|
||||
use SilverStripe\Control\Controller;
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
use SilverStripe\Dev\SapphireTest;
|
||||
use SilverStripe\Forms\FieldList;
|
||||
use SilverStripe\Forms\Form;
|
||||
use SilverStripe\Forms\GridField\GridField;
|
||||
use SilverStripe\Forms\GridField\GridFieldConfig;
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\Security\Security;
|
||||
use SilverStripe\Versioned\Versioned;
|
||||
use UndefinedOffset\SortableGridField\Forms\GridFieldSortableRows;
|
||||
use UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\BaseObject;
|
||||
use UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\ChildObject;
|
||||
use UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\DummyController;
|
||||
use UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\Player;
|
||||
use UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\TestParent;
|
||||
use UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\VPlayer;
|
||||
|
||||
class AutoSortTest extends SapphireTest
|
||||
{
|
||||
/** @var string */
|
||||
public static $fixture_file = 'AutoSortTest.yml';
|
||||
|
||||
/** @var array */
|
||||
protected static $extra_dataobjects = [
|
||||
Player::class,
|
||||
VPlayer::class,
|
||||
TestParent::class,
|
||||
BaseObject::class,
|
||||
ChildObject::class
|
||||
];
|
||||
|
||||
public function testAutoSort()
|
||||
{
|
||||
if (Security::getCurrentUser()) {
|
||||
$this->logOut();
|
||||
}
|
||||
|
||||
$list = Player::get();
|
||||
$config = GridFieldConfig::create()->addComponent(new GridFieldSortableRows('SortOrder'));
|
||||
$gridField = new GridField('testfield', 'testfield', $list, $config);
|
||||
$form = new Form(new DummyController(), 'mockform', new FieldList([$gridField]), new FieldList());
|
||||
|
||||
$stateID = 'testGridStateActionField';
|
||||
$request = new HTTPRequest('POST', 'url', [], ['action_gridFieldAlterAction?StateID=' . $stateID => true, $form->getSecurityToken()->getName() => $form->getSecurityToken()->getValue()]);
|
||||
$session = Controller::curr()->getRequest()->getSession();
|
||||
$session->set($form->getSecurityToken()->getName(), $form->getSecurityToken()->getValue());
|
||||
$session->set($stateID, ['grid' => '', 'actionName' => 'sortableRowsToggle', 'args' => ['GridFieldSortableRows' => ['sortableToggle' => true]]]);
|
||||
$request->setSession($session);
|
||||
|
||||
$gridField->gridFieldAlterAction(['StateID' => $stateID], $form, $request);
|
||||
|
||||
//Insure sort ran
|
||||
$this->assertEquals(3, $list->last()->SortOrder, 'Auto sort should have run');
|
||||
|
||||
|
||||
//Check for duplicates (there shouldn't be any)
|
||||
$count = $list->Count();
|
||||
$indexes = count(array_unique($list->column('SortOrder')));
|
||||
$this->assertEquals(0, $count - $indexes, 'Duplicate indexes detected');
|
||||
}
|
||||
|
||||
public function testAppendToTopAutoSort()
|
||||
{
|
||||
if (Security::getCurrentUser()) {
|
||||
$this->logOut();
|
||||
}
|
||||
|
||||
$list = Player::get();
|
||||
$config = GridFieldConfig::create()->addComponent(new GridFieldSortableRows('SortOrder'));
|
||||
$gridField = new GridField('testfield', 'testfield', $list, $config);
|
||||
$form = new Form(new DummyController(), 'mockform', new FieldList([$gridField]), new FieldList());
|
||||
|
||||
/** @var GridFieldSortableRows $sortableRows */
|
||||
$sortableRows = $gridField->getConfig()->getComponentByType(GridFieldSortableRows::class);
|
||||
$sortableRows->setAppendToTop(true);
|
||||
|
||||
$this->assertEquals(0, $list->last()->SortOrder, 'Auto sort should not have run');
|
||||
|
||||
$stateID = 'testGridStateActionField';
|
||||
$request = new HTTPRequest('POST', 'url', [], ['action_gridFieldAlterAction?StateID=' . $stateID => true, $form->getSecurityToken()->getName() => $form->getSecurityToken()->getValue()]);
|
||||
$session = Controller::curr()->getRequest()->getSession();
|
||||
$session->set($form->getSecurityToken()->getName(), $form->getSecurityToken()->getValue());
|
||||
$session->set($stateID, ['grid' => '', 'actionName' => 'sortableRowsToggle', 'args' => ['GridFieldSortableRows' => ['sortableToggle' => true]]]);
|
||||
$request->setSession($session);
|
||||
$gridField->gridFieldAlterAction(['StateID' => $stateID], $form, $request);
|
||||
|
||||
//Insure sort ran
|
||||
$this->assertEquals(3, $list->last()->SortOrder, 'Auto sort should have run');
|
||||
|
||||
|
||||
//Check for duplicates (there shouldn't be any)
|
||||
$count = $list->Count();
|
||||
$indexes = count(array_unique($list->column('SortOrder')));
|
||||
$this->assertEquals(0, $count - $indexes, 'Duplicate indexes detected');
|
||||
}
|
||||
|
||||
public function testAutoSortVersioned()
|
||||
{
|
||||
if (Security::getCurrentUser()) {
|
||||
$this->logOut();
|
||||
}
|
||||
|
||||
//Force versioned to reset
|
||||
Versioned::reset();
|
||||
|
||||
$list = VPlayer::get();
|
||||
|
||||
//Publish all records
|
||||
foreach ($list as $item) {
|
||||
$item->publishSingle();
|
||||
}
|
||||
|
||||
|
||||
$config = GridFieldConfig::create()->addComponent(new GridFieldSortableRows('SortOrder', true, 'Live'));
|
||||
$gridField = new GridField('testfield', 'testfield', $list, $config);
|
||||
$form = new Form(new DummyController(), 'mockform', new FieldList([$gridField]), new FieldList());
|
||||
|
||||
$stateID = 'testGridStateActionField';
|
||||
$request = new HTTPRequest('POST', 'url', [], ['action_gridFieldAlterAction?StateID=' . $stateID => true, $form->getSecurityToken()->getName() => $form->getSecurityToken()->getValue()]);
|
||||
$session = Controller::curr()->getRequest()->getSession();
|
||||
$session->set($form->getSecurityToken()->getName(), $form->getSecurityToken()->getValue());
|
||||
$session->set($stateID, ['grid' => '', 'actionName' => 'sortableRowsToggle', 'args' => ['GridFieldSortableRows' => ['sortableToggle' => true]]]);
|
||||
$request->setSession($session);
|
||||
$gridField->gridFieldAlterAction(['StateID' => $stateID], $form, $request);
|
||||
|
||||
|
||||
//Insure sort ran
|
||||
$this->assertEquals(3, $list->last()->SortOrder, 'Auto sort should have run on Versioned stage "Stage"');
|
||||
|
||||
|
||||
//Check for duplicates (there shouldn't be any)
|
||||
$count = $list->Count();
|
||||
$indexes = count(array_unique($list->column('SortOrder')));
|
||||
$this->assertEquals(0, $count - $indexes, 'Duplicate indexes detected on Versioned stage "Stage"');
|
||||
|
||||
|
||||
//Force versioned over to Live stage
|
||||
Versioned::set_reading_mode('Live');
|
||||
|
||||
//Get live instance
|
||||
$obj = Versioned::get_one_by_stage(VPlayer::class, 'Live', '"ID"=' . $list->last()->ID);
|
||||
|
||||
//Insure sort ran
|
||||
$this->assertEquals(3, $obj->SortOrder, 'Auto sort should have run on Versioned stage "Live"');
|
||||
|
||||
|
||||
//Check for duplicates (there shouldn't be any)
|
||||
$list = Versioned::get_by_stage(VPlayer::class, 'Live');
|
||||
$count = $list->Count();
|
||||
$indexes = count(array_unique($list->column('SortOrder')));
|
||||
$this->assertEquals(0, $count - $indexes, 'Duplicate indexes detected on Versioned stage "Live"');
|
||||
}
|
||||
|
||||
public function testAppendToTopAutoSortVersioned()
|
||||
{
|
||||
if (Security::getCurrentUser()) {
|
||||
$this->logOut();
|
||||
}
|
||||
|
||||
//Force versioned to reset
|
||||
Versioned::reset();
|
||||
|
||||
$list = VPlayer::get();
|
||||
|
||||
//Publish all records
|
||||
foreach ($list as $item) {
|
||||
$item->publishSingle();
|
||||
}
|
||||
|
||||
|
||||
$config = GridFieldConfig::create()->addComponent(new GridFieldSortableRows('SortOrder', true, 'Live'));
|
||||
$gridField = new GridField('testfield', 'testfield', $list, $config);
|
||||
$form = new Form(new DummyController(), 'mockform', new FieldList([$gridField]), new FieldList());
|
||||
|
||||
/** @var GridFieldSortableRows $sortableRows */
|
||||
$sortableRows = $gridField->getConfig()->getComponentByType(GridFieldSortableRows::class);
|
||||
$sortableRows->setAppendToTop(true);
|
||||
|
||||
$this->assertEquals(0, $list->last()->SortOrder, 'Auto sort should not have run on Versioned stage "Stage"');
|
||||
|
||||
$stateID = 'testGridStateActionField';
|
||||
$request = new HTTPRequest('POST', 'url', [], ['action_gridFieldAlterAction?StateID=' . $stateID => true, $form->getSecurityToken()->getName() => $form->getSecurityToken()->getValue()]);
|
||||
$session = Controller::curr()->getRequest()->getSession();
|
||||
$session->set($form->getSecurityToken()->getName(), $form->getSecurityToken()->getValue());
|
||||
$session->set($stateID, ['grid' => '', 'actionName' => 'sortableRowsToggle', 'args' => ['GridFieldSortableRows' => ['sortableToggle' => true]]]);
|
||||
$request->setSession($session);
|
||||
$gridField->gridFieldAlterAction(['StateID' => $stateID], $form, $request);
|
||||
|
||||
|
||||
//Insure sort ran
|
||||
$this->assertEquals(3, $list->last()->SortOrder, 'Auto sort should have run on Versioned stage "Stage"');
|
||||
|
||||
|
||||
//Check for duplicates (there shouldn't be any)
|
||||
$count = $list->Count();
|
||||
$indexes = count(array_unique($list->column('SortOrder')));
|
||||
$this->assertEquals(0, $count - $indexes, 'Duplicate indexes detected on Versioned stage "Stage"');
|
||||
|
||||
|
||||
//Force versioned over to Live stage
|
||||
Versioned::set_reading_mode('Live');
|
||||
|
||||
//Insure sort ran
|
||||
$this->assertEquals(3, $list->last()->SortOrder, 'Auto sort should have run on Versioned stage "Live"');
|
||||
|
||||
|
||||
//Check for duplicates (there shouldn't be any)
|
||||
$count = $list->Count();
|
||||
$indexes = count(array_unique($list->column('SortOrder')));
|
||||
$this->assertEquals(0, $count - $indexes, 'Duplicate indexes detected on Versioned stage "Live"');
|
||||
}
|
||||
|
||||
public function testAppendToTopAutoSortChild()
|
||||
{
|
||||
if (Security::getCurrentUser()) {
|
||||
$this->logOut();
|
||||
}
|
||||
|
||||
//Push the edit date into the past, we're checking this later
|
||||
DB::query('UPDATE "GridFieldAction_SortOrder_BaseObject" SET "LastEdited"=\'' . date('Y-m-d 00:00:00', strtotime('yesterday')) . '\'');
|
||||
|
||||
/** @var TestParent $parent */
|
||||
$parent = TestParent::get()->first();
|
||||
|
||||
/** @var DataList $list */
|
||||
$list = $parent->TestRelation();
|
||||
|
||||
$config = GridFieldConfig::create()->addComponent(new GridFieldSortableRows('SortOrder'));
|
||||
$gridField = new GridField('testfield', 'testfield', $list, $config);
|
||||
$form = new Form(new DummyController(), 'mockform', new FieldList([$gridField]), new FieldList());
|
||||
$form->loadDataFrom($parent);
|
||||
|
||||
/** @var GridFieldSortableRows $sortableRows */
|
||||
$sortableRows = $gridField->getConfig()->getComponentByType(GridFieldSortableRows::class);
|
||||
$sortableRows->setAppendToTop(true);
|
||||
|
||||
$this->assertEquals(0, $list->last()->SortOrder, 'Auto sort should not have run');
|
||||
|
||||
$stateID = 'testGridStateActionField';
|
||||
$request = new HTTPRequest('POST', 'url', [], ['action_gridFieldAlterAction?StateID=' . $stateID => true, $form->getSecurityToken()->getName() => $form->getSecurityToken()->getValue()]);
|
||||
$session = Controller::curr()->getRequest()->getSession();
|
||||
$session->set($form->getSecurityToken()->getName(), $form->getSecurityToken()->getValue());
|
||||
$session->set($stateID, ['grid' => '', 'actionName' => 'sortableRowsToggle', 'args' => ['GridFieldSortableRows' => ['sortableToggle' => true]]]);
|
||||
$request->setSession($session);
|
||||
$gridField->gridFieldAlterAction(['StateID' => $stateID], $form, $request);
|
||||
|
||||
//Insure sort ran
|
||||
$this->assertEquals(3, $list->last()->SortOrder, 'Auto sort should have run');
|
||||
|
||||
|
||||
//Check for duplicates (there shouldn't be any)
|
||||
$count = $list->Count();
|
||||
$indexes = count(array_unique($list->column('SortOrder')));
|
||||
$this->assertEquals(0, $count - $indexes, 'Duplicate indexes detected');
|
||||
|
||||
|
||||
//Make sure the last edited is today for all records
|
||||
$this->assertEquals(3, $list->filter('LastEdited:GreaterThan', date('Y-m-d 00:00:00'))->count());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\Player:
|
||||
player1:
|
||||
Name: Player 1
|
||||
SortOrder: 0
|
||||
player2:
|
||||
Name: Player 2
|
||||
SortOrder: 0
|
||||
player3:
|
||||
Name: Player 3
|
||||
SortOrder: 0
|
||||
|
||||
UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\VPlayer:
|
||||
player1:
|
||||
Name: Player 1
|
||||
SortOrder: 0
|
||||
player2:
|
||||
Name: Player 2
|
||||
SortOrder: 0
|
||||
player3:
|
||||
Name: Player 3
|
||||
SortOrder: 0
|
||||
|
||||
UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\TestParent:
|
||||
testparent:
|
||||
Name: Test
|
||||
|
||||
UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\ChildObject:
|
||||
testitem1:
|
||||
Name: Test 1
|
||||
SortOrder: 0
|
||||
Parent: =>UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\TestParent.testparent
|
||||
testitem2:
|
||||
Name: Test 2
|
||||
SortOrder: 0
|
||||
Parent: =>UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\TestParent.testparent
|
||||
testitem3:
|
||||
Name: Test 3
|
||||
SortOrder: 0
|
||||
Parent: =>UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\TestParent.testparent
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
namespace UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest;
|
||||
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
|
||||
/**
|
||||
* Class \UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\BaseObject
|
||||
*
|
||||
* @property string Name
|
||||
*/
|
||||
class BaseObject extends DataObject implements TestOnly
|
||||
{
|
||||
private static $table_name = 'GridFieldAction_SortOrder_BaseObject';
|
||||
|
||||
private static $db = [
|
||||
'Name' => 'Varchar',
|
||||
];
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
namespace UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest;
|
||||
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\ORM\FieldType\DBInt;
|
||||
|
||||
/**
|
||||
* Class \UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\ChildObject
|
||||
*
|
||||
* @package SortableGridField\Tests
|
||||
* @property int SortOrder
|
||||
* @method TestParent Parent
|
||||
*/
|
||||
class ChildObject extends BaseObject implements TestOnly
|
||||
{
|
||||
private static $table_name = 'GridFieldAction_SortOrder_ChildObject';
|
||||
|
||||
private static $db = [
|
||||
'SortOrder' => DBInt::class,
|
||||
];
|
||||
|
||||
private static $has_one = [
|
||||
'Parent' => TestParent::class,
|
||||
];
|
||||
|
||||
private static $default_sort = 'SortOrder';
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
namespace UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest;
|
||||
|
||||
use SilverStripe\Control\Controller;
|
||||
|
||||
/**
|
||||
* Class \UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\DummyController
|
||||
*/
|
||||
class DummyController extends Controller
|
||||
{
|
||||
private static $url_segment = 'sortable-grid-field';
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
namespace UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest;
|
||||
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
|
||||
/**
|
||||
* Class \UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\Player
|
||||
*
|
||||
* @property string Name
|
||||
* @property int SortOrder
|
||||
*/
|
||||
class Player extends DataObject implements TestOnly
|
||||
{
|
||||
private static $table_name = 'GridFieldAction_SortOrder_Player';
|
||||
|
||||
private static $db = [
|
||||
'Name' => 'Varchar',
|
||||
'SortOrder' => 'Int',
|
||||
];
|
||||
|
||||
private static $default_sort = 'SortOrder';
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
namespace UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest;
|
||||
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
|
||||
/**
|
||||
* Class \UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\TestParent
|
||||
*
|
||||
* @package SortableGridField\Tests
|
||||
* @property string Name
|
||||
* @method ChildObject TestRelation
|
||||
*/
|
||||
class TestParent extends DataObject implements TestOnly
|
||||
{
|
||||
private static $table_name = 'GridFieldAction_SortOrder_TestParent';
|
||||
|
||||
private static $db = [
|
||||
'Name' => 'Varchar',
|
||||
];
|
||||
|
||||
private static $has_many = [
|
||||
'TestRelation' => ChildObject::class,
|
||||
];
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
namespace UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest;
|
||||
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\Versioned\Versioned;
|
||||
|
||||
/**
|
||||
* Class \UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\VPlayer
|
||||
*
|
||||
* @property string Name
|
||||
* @property int SortOrder
|
||||
*/
|
||||
class VPlayer extends DataObject implements TestOnly
|
||||
{
|
||||
private static $table_name = 'GridFieldAction_SortOrder_VPlayer';
|
||||
|
||||
private static $db = [
|
||||
'Name' => 'Varchar',
|
||||
'SortOrder' => 'Int',
|
||||
];
|
||||
|
||||
private static $default_sort = 'SortOrder';
|
||||
|
||||
private static $extensions = [
|
||||
Versioned::class,
|
||||
];
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
<?php
|
||||
namespace UndefinedOffset\SortableGridField\Tests;
|
||||
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\Control\Controller;
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
use SilverStripe\Dev\SapphireTest;
|
||||
use SilverStripe\Forms\FieldList;
|
||||
use SilverStripe\Forms\Form;
|
||||
use SilverStripe\Forms\GridField\GridField;
|
||||
use SilverStripe\Forms\GridField\GridFieldConfig;
|
||||
use SilverStripe\ORM\ValidationException;
|
||||
use SilverStripe\Security\IdentityStore;
|
||||
use SilverStripe\Security\Security;
|
||||
use SilverStripe\Versioned\Versioned;
|
||||
use UndefinedOffset\SortableGridField\Forms\GridFieldSortableRows;
|
||||
use UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\DummyController;
|
||||
use UndefinedOffset\SortableGridField\Tests\Forms\OrderingTest\Team;
|
||||
use UndefinedOffset\SortableGridField\Tests\Forms\OrderingTest\VTeam;
|
||||
|
||||
class OrderingTest extends SapphireTest
|
||||
{
|
||||
/** @var ArrayList */
|
||||
protected $list;
|
||||
|
||||
/** @var GridField */
|
||||
protected $gridField;
|
||||
|
||||
/** @var Form */
|
||||
protected $form;
|
||||
|
||||
/** @var string */
|
||||
public static $fixture_file = 'OrderingTest.yml';
|
||||
|
||||
/** @var array */
|
||||
protected static $extra_dataobjects = [
|
||||
Team::class,
|
||||
VTeam::class
|
||||
];
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->list = Team::get();
|
||||
$config = GridFieldConfig::create()->addComponent(new GridFieldSortableRows('SortOrder'));
|
||||
$this->gridField = new GridField('testfield', 'testfield', $this->list, $config);
|
||||
$this->form = new Form(new DummyController(), 'mockform', new FieldList([$this->gridField]), new FieldList());
|
||||
}
|
||||
|
||||
public function testSortActionWithoutCorrectPermission()
|
||||
{
|
||||
if (Security::getCurrentUser()) {
|
||||
Injector::inst()->get(IdentityStore::class)->logOut(Controller::curr()->getRequest());
|
||||
}
|
||||
|
||||
$this->expectException(ValidationException::class);
|
||||
$team1 = $this->objFromFixture(Team::class, 'team1');
|
||||
$team2 = $this->objFromFixture(Team::class, 'team2');
|
||||
$team3 = $this->objFromFixture(Team::class, 'team3');
|
||||
|
||||
$stateID = 'testGridStateActionField';
|
||||
$request = new HTTPRequest('POST', 'url', ['ItemIDs' => "$team1->ID, $team3->ID, $team2->ID"], ['action_gridFieldAlterAction?StateID=' . $stateID => true, $this->form->getSecurityToken()->getName() => $this->form->getSecurityToken()->getValue()]);
|
||||
$session = Controller::curr()->getRequest()->getSession();
|
||||
$session->set($this->form->getSecurityToken()->getName(), $this->form->getSecurityToken()->getValue());
|
||||
$session->set($stateID, ['grid' => '', 'actionName' => 'saveGridRowSort', 'args' => ['GridFieldSortableRows' => ['sortableToggle' => true]]]);
|
||||
$request->setSession($session);
|
||||
$this->gridField->gridFieldAlterAction(['StateID' => $stateID], $this->form, $request);
|
||||
$this->assertEquals($team3->ID, $this->list->last()->ID, 'User should\'t be able to sort records without correct permissions.');
|
||||
}
|
||||
|
||||
public function testSortActionWithAdminPermission()
|
||||
{
|
||||
$team1 = $this->objFromFixture(Team::class, 'team1');
|
||||
$team2 = $this->objFromFixture(Team::class, 'team2');
|
||||
$team3 = $this->objFromFixture(Team::class, 'team3');
|
||||
$this->logInWithPermission('ADMIN');
|
||||
$stateID = 'testGridStateActionField';
|
||||
$request = new HTTPRequest('POST', 'url', ['ItemIDs' => "$team1->ID, $team3->ID, $team2->ID"], ['action_gridFieldAlterAction?StateID=' . $stateID => true, $this->form->getSecurityToken()->getName() => $this->form->getSecurityToken()->getValue()]);
|
||||
$session = Controller::curr()->getRequest()->getSession();
|
||||
$session->set($this->form->getSecurityToken()->getName(), $this->form->getSecurityToken()->getValue());
|
||||
$session->set($stateID, ['grid' => '', 'actionName' => 'saveGridRowSort', 'args' => ['GridFieldSortableRows' => ['sortableToggle' => true]]]);
|
||||
$request->setSession($session);
|
||||
$this->gridField->gridFieldAlterAction(['StateID' => $stateID], $this->form, $request);
|
||||
$this->assertEquals($team2->ID, $this->list->last()->ID, 'User should be able to sort records with ADMIN permission.');
|
||||
}
|
||||
|
||||
public function testSortActionVersioned()
|
||||
{
|
||||
//Force versioned to reset
|
||||
Versioned::reset();
|
||||
|
||||
$list = VTeam::get();
|
||||
$this->gridField->setList($list);
|
||||
|
||||
/** @var GridFieldSortableRows $sortableGrid */
|
||||
$sortableGrid = $this->gridField->getConfig()->getComponentByType(GridFieldSortableRows::class);
|
||||
$sortableGrid->setUpdateVersionedStage('Live');
|
||||
|
||||
//Publish all records
|
||||
foreach ($list as $item) {
|
||||
$item->publishSingle();
|
||||
}
|
||||
|
||||
$team1 = $this->objFromFixture(VTeam::class, 'team1');
|
||||
$team2 = $this->objFromFixture(VTeam::class, 'team2');
|
||||
$team3 = $this->objFromFixture(VTeam::class, 'team3');
|
||||
|
||||
$this->logInWithPermission('ADMIN');
|
||||
$stateID = 'testGridStateActionField';
|
||||
$request = new HTTPRequest('POST', 'url', ['ItemIDs' => "$team1->ID, $team3->ID, $team2->ID"], ['action_gridFieldAlterAction?StateID=' . $stateID => true, $this->form->getSecurityToken()->getName() => $this->form->getSecurityToken()->getValue()]);
|
||||
$session = Controller::curr()->getRequest()->getSession();
|
||||
$session->set($this->form->getSecurityToken()->getName(), $this->form->getSecurityToken()->getValue());
|
||||
$session->set($stateID, ['grid' => '', 'actionName' => 'saveGridRowSort', 'args' => ['GridFieldSortableRows' => ['sortableToggle' => true]]]);
|
||||
$request->setSession($session);
|
||||
$this->gridField->gridFieldAlterAction(['StateID' => $stateID], $this->form, $request);
|
||||
|
||||
$this->assertEquals($team2->ID, $list->last()->ID, 'Sort should have happened on Versioned stage "Stage"');
|
||||
|
||||
$list = Versioned::get_by_stage(VTeam::class, 'Live');
|
||||
$this->assertEquals($team2->ID, $list->last()->ID, 'Sort should have happened on Versioned stage "Live"');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
UndefinedOffset\SortableGridField\Tests\Forms\OrderingTest\Team:
|
||||
team1:
|
||||
Name: Team 1
|
||||
City: Cologne
|
||||
SortOrder: 1
|
||||
team2:
|
||||
Name: Team 2
|
||||
City: Wellington
|
||||
SortOrder: 2
|
||||
team3:
|
||||
Name: Team 3
|
||||
City: Auckland
|
||||
SortOrder: 3
|
||||
|
||||
UndefinedOffset\SortableGridField\Tests\Forms\OrderingTest\VTeam:
|
||||
team1:
|
||||
Name: Team 1
|
||||
City: Cologne
|
||||
SortOrder: 1
|
||||
team2:
|
||||
Name: Team 2
|
||||
City: Wellington
|
||||
SortOrder: 2
|
||||
team3:
|
||||
Name: Team 3
|
||||
City: Auckland
|
||||
SortOrder: 3
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
namespace UndefinedOffset\SortableGridField\Tests\Forms\OrderingTest;
|
||||
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
|
||||
/**
|
||||
* Class \UndefinedOffset\SortableGridField\Tests\Forms\OrderingTest\Team
|
||||
*
|
||||
* @property string Name
|
||||
* @property string City
|
||||
* @property int SortOrder
|
||||
*/
|
||||
class Team extends DataObject implements TestOnly
|
||||
{
|
||||
private static $table_name = 'GridFieldAction_SortOrder_Team';
|
||||
|
||||
private static $db = [
|
||||
'Name' => 'Varchar',
|
||||
'City' => 'Varchar',
|
||||
'SortOrder' => 'Int',
|
||||
];
|
||||
|
||||
private static $default_sort = 'SortOrder';
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
namespace UndefinedOffset\SortableGridField\Tests\Forms\OrderingTest;
|
||||
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\Versioned\Versioned;
|
||||
|
||||
/**
|
||||
* Class \UndefinedOffset\SortableGridField\Tests\Forms\OrderingTest\VTeam
|
||||
*
|
||||
* @property string Name
|
||||
* @property string City
|
||||
* @property int SortOrder
|
||||
*/
|
||||
class VTeam extends DataObject implements TestOnly
|
||||
{
|
||||
private static $table_name = 'GridFieldAction_SortOrder_VTeam';
|
||||
|
||||
private static $db = [
|
||||
'Name' => 'Varchar',
|
||||
'City' => 'Varchar',
|
||||
'SortOrder' => 'Int',
|
||||
];
|
||||
private static $default_sort = 'SortOrder';
|
||||
|
||||
private static $extensions = [
|
||||
Versioned::class,
|
||||
];
|
||||
}
|
|
@ -0,0 +1,188 @@
|
|||
<?php
|
||||
namespace UndefinedOffset\SortableGridField\Tests;
|
||||
|
||||
use SilverStripe\Control\Controller;
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
use SilverStripe\Dev\SapphireTest;
|
||||
use SilverStripe\Forms\FieldList;
|
||||
use SilverStripe\Forms\Form;
|
||||
use SilverStripe\Forms\GridField\GridField;
|
||||
use SilverStripe\Forms\GridField\GridFieldConfig_Base;
|
||||
use SilverStripe\Versioned\Versioned;
|
||||
use UndefinedOffset\SortableGridField\Forms\GridFieldSortableRows;
|
||||
use UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\DummyController;
|
||||
use UndefinedOffset\SortableGridField\Tests\Forms\PageSortingTest\Team;
|
||||
use UndefinedOffset\SortableGridField\Tests\Forms\PageSortingTest\VTeam;
|
||||
|
||||
/**
|
||||
* Class \UndefinedOffset\SortableGridField\Tests\PageSortingTest
|
||||
*/
|
||||
class PageSortingTest extends SapphireTest
|
||||
{
|
||||
/** @var ArrayList */
|
||||
protected $list;
|
||||
|
||||
/** @var GridField */
|
||||
protected $gridField;
|
||||
|
||||
/** @var Form */
|
||||
protected $form;
|
||||
|
||||
/** @var string */
|
||||
public static $fixture_file = 'PageSortingTest.yml';
|
||||
|
||||
/** @var array */
|
||||
protected static $extra_dataobjects = [
|
||||
Team::class,
|
||||
VTeam::class
|
||||
];
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->list = Team::get();
|
||||
$config = GridFieldConfig_Base::create(5)->addComponent(new GridFieldSortableRows('SortOrder'));
|
||||
$this->gridField = new GridField('testfield', 'testfield', $this->list, $config);
|
||||
$this->form = new Form(new DummyController(), 'mockform', FieldList::create([$this->gridField]), FieldList::create());
|
||||
}
|
||||
|
||||
public function testSortToNextPage()
|
||||
{
|
||||
$this->gridField->State->GridFieldPaginator->currentPage = 1;
|
||||
|
||||
$team3 = $this->objFromFixture(Team::class, 'team3');
|
||||
|
||||
$this->logInWithPermission('ADMIN');
|
||||
$stateID = 'testGridStateActionField';
|
||||
$request = new HTTPRequest('POST', 'url', ['ItemID' => $team3->ID, 'Target' => 'nextpage'], ['action_gridFieldAlterAction?StateID=' . $stateID => true, $this->form->getSecurityToken()->getName() => $this->form->getSecurityToken()->getValue()]);
|
||||
$session = Controller::curr()->getRequest()->getSession();
|
||||
$session->set($this->form->getSecurityToken()->getName(), $this->form->getSecurityToken()->getValue());
|
||||
$session->set($stateID, ['grid' => '', 'actionName' => 'sortToPage', 'args' => ['GridFieldSortableRows' => ['sortableToggle' => true], 'GridFieldPaginator' => ['currentPage' => 1]]]);
|
||||
$request->setSession($session);
|
||||
$this->gridField->gridFieldAlterAction(['StateID' => $stateID], $this->form, $request);
|
||||
|
||||
$team6 = $this->objFromFixture(Team::class, 'team6');
|
||||
$this->assertEquals(5, $team6->SortOrder, 'Team 6 Should have moved to the bottom of the first page');
|
||||
|
||||
$team3 = $this->objFromFixture(Team::class, 'team3');
|
||||
$this->assertEquals(6, $team3->SortOrder, 'Team 3 Should have moved to the top of the second page');
|
||||
}
|
||||
|
||||
public function testSortToPrevPage()
|
||||
{
|
||||
$this->gridField->State->GridFieldPaginator->currentPage = 2;
|
||||
|
||||
$team7 = $this->objFromFixture(Team::class, 'team7');
|
||||
|
||||
$this->logInWithPermission('ADMIN');
|
||||
$stateID = 'testGridStateActionField';
|
||||
$request = new HTTPRequest('POST', 'url', ['ItemID' => $team7->ID, 'Target' => 'previouspage'], ['action_gridFieldAlterAction?StateID=' . $stateID => true, $this->form->getSecurityToken()->getName() => $this->form->getSecurityToken()->getValue()]);
|
||||
$session = Controller::curr()->getRequest()->getSession();
|
||||
$session->set($this->form->getSecurityToken()->getName(), $this->form->getSecurityToken()->getValue());
|
||||
$session->set($stateID, ['grid' => '', 'actionName' => 'sortToPage', 'args' => ['GridFieldSortableRows' => ['sortableToggle' => true], 'GridFieldPaginator' => ['currentPage' => 1]]]);
|
||||
$request->setSession($session);
|
||||
$this->gridField->gridFieldAlterAction(['StateID' => $stateID], $this->form, $request);
|
||||
|
||||
|
||||
$team7 = $this->objFromFixture(Team::class, 'team7');
|
||||
$this->assertEquals(5, $team7->SortOrder, 'Team 7 Should have moved to the bottom of the first page');
|
||||
|
||||
$team5 = $this->objFromFixture(Team::class, 'team5');
|
||||
$this->assertEquals(6, $team5->SortOrder, 'Team 5 Should have moved to the top of the second page');
|
||||
}
|
||||
|
||||
public function testSortToNextPageVersioned()
|
||||
{
|
||||
//Force versioned to reset
|
||||
Versioned::reset();
|
||||
|
||||
$list = VTeam::get();
|
||||
$this->gridField->setList($list);
|
||||
|
||||
/** @var GridFieldSortableRows $sortableGrid */
|
||||
$sortableGrid = $this->gridField->getConfig()->getComponentByType(GridFieldSortableRows::class);
|
||||
$sortableGrid->setUpdateVersionedStage('Live');
|
||||
$this->gridField->State->GridFieldPaginator->currentPage = 1;
|
||||
|
||||
//Publish all records
|
||||
foreach ($list as $item) {
|
||||
$item->publishSingle();
|
||||
}
|
||||
|
||||
|
||||
$team3 = $this->objFromFixture(VTeam::class, 'team3');
|
||||
|
||||
$this->logInWithPermission('ADMIN');
|
||||
$stateID = 'testGridStateActionField';
|
||||
$request = new HTTPRequest('POST', 'url', ['ItemID' => $team3->ID, 'Target' => 'nextpage'], ['action_gridFieldAlterAction?StateID=' . $stateID => true, $this->form->getSecurityToken()->getName() => $this->form->getSecurityToken()->getValue()]);
|
||||
$session = Controller::curr()->getRequest()->getSession();
|
||||
$session->set($this->form->getSecurityToken()->getName(), $this->form->getSecurityToken()->getValue());
|
||||
$session->set($stateID, ['grid' => '', 'actionName' => 'sortToPage', 'args' => ['GridFieldSortableRows' => ['sortableToggle' => true], 'GridFieldPaginator' => ['currentPage' => 1]]]);
|
||||
$request->setSession($session);
|
||||
$this->gridField->gridFieldAlterAction(['StateID' => $stateID], $this->form, $request);
|
||||
|
||||
|
||||
$team6 = $this->objFromFixture(VTeam::class, 'team6');
|
||||
$this->assertEquals(5, $team6->SortOrder, 'Team 6 Should have moved to the bottom of the first page on Versioned stage "Stage"');
|
||||
|
||||
$team3 = $this->objFromFixture(VTeam::class, 'team3');
|
||||
$this->assertEquals(6, $team3->SortOrder, 'Team 3 Should have moved to the top of the second page on Versioned stage "Stage"');
|
||||
|
||||
|
||||
$list = Versioned::get_by_stage(VTeam::class, 'Live');
|
||||
|
||||
$team6 = $list->byID($team6->ID);
|
||||
$this->assertEquals(5, $team6->SortOrder, 'Team 6 Should have moved to the bottom of the first page on Versioned stage "Live"');
|
||||
|
||||
$team3 = $list->byID($team3->ID);
|
||||
$this->assertEquals(6, $team3->SortOrder, 'Team 3 Should have moved to the top of the second page on Versioned stage "Live"');
|
||||
}
|
||||
|
||||
public function testSortToPrevPageVersioned()
|
||||
{
|
||||
//Force versioned to reset
|
||||
Versioned::reset();
|
||||
|
||||
$list = VTeam::get();
|
||||
$this->gridField->setList($list);
|
||||
|
||||
/** @var GridFieldSortableRows $sortableGrid */
|
||||
$sortableGrid = $this->gridField->getConfig()->getComponentByType(GridFieldSortableRows::class);
|
||||
$sortableGrid->setUpdateVersionedStage('Live');
|
||||
$this->gridField->State->GridFieldPaginator->currentPage = 2;
|
||||
|
||||
//Publish all records
|
||||
foreach ($list as $item) {
|
||||
$item->publishSingle();
|
||||
}
|
||||
|
||||
|
||||
$team7 = $this->objFromFixture(VTeam::class, 'team7');
|
||||
|
||||
$this->logInWithPermission('ADMIN');
|
||||
$stateID = 'testGridStateActionField';
|
||||
$request = new HTTPRequest('POST', 'url', ['ItemID' => $team7->ID, 'Target' => 'previouspage'], ['action_gridFieldAlterAction?StateID=' . $stateID => true, $this->form->getSecurityToken()->getName() => $this->form->getSecurityToken()->getValue()]);
|
||||
$session = Controller::curr()->getRequest()->getSession();
|
||||
$session->set($this->form->getSecurityToken()->getName(), $this->form->getSecurityToken()->getValue());
|
||||
$session->set($stateID, ['grid' => '', 'actionName' => 'sortToPage', 'args' => ['GridFieldSortableRows' => ['sortableToggle' => true], 'GridFieldPaginator' => ['currentPage' => 1]]]);
|
||||
$request->setSession($session);
|
||||
$this->gridField->gridFieldAlterAction(['StateID' => $stateID], $this->form, $request);
|
||||
|
||||
|
||||
$team7 = $this->objFromFixture(VTeam::class, 'team7');
|
||||
$this->assertEquals(5, $team7->SortOrder, 'Team 7 Should have moved to the bottom of the first page on Versioned stage "Stage"');
|
||||
|
||||
$team5 = $this->objFromFixture(VTeam::class, 'team5');
|
||||
$this->assertEquals(6, $team5->SortOrder, 'Team 5 Should have moved to the top of the second page on Versioned stage "Stage"');
|
||||
|
||||
|
||||
$list = Versioned::get_by_stage(VTeam::class, 'Live');
|
||||
|
||||
$team7 = $list->byID($team7->ID);
|
||||
$this->assertEquals(5, $team7->SortOrder, 'Team 7 Should have moved to the bottom of the first page on Versioned stage "Live"');
|
||||
|
||||
$team5 = $list->byID($team5->ID);
|
||||
$this->assertEquals(6, $team5->SortOrder, 'Team 5 Should have moved to the top of the second page on Versioned stage "Live"');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
UndefinedOffset\SortableGridField\Tests\Forms\PageSortingTest\Team:
|
||||
team1:
|
||||
Name: Team 1
|
||||
City: Cologne
|
||||
SortOrder: 1
|
||||
team2:
|
||||
Name: Team 2
|
||||
City: Wellington
|
||||
SortOrder: 2
|
||||
team3:
|
||||
Name: Team 3
|
||||
City: Auckland
|
||||
SortOrder: 3
|
||||
team4:
|
||||
Name: Team 4
|
||||
City: Cologne
|
||||
SortOrder: 4
|
||||
team5:
|
||||
Name: Team 5
|
||||
City: Wellington
|
||||
SortOrder: 5
|
||||
team6:
|
||||
Name: Team 6
|
||||
City: Auckland
|
||||
SortOrder: 6
|
||||
team7:
|
||||
Name: Team 7
|
||||
City: Cologne
|
||||
SortOrder: 7
|
||||
team8:
|
||||
Name: Team 8
|
||||
City: Wellington
|
||||
SortOrder: 8
|
||||
team9:
|
||||
Name: Team 9
|
||||
City: Auckland
|
||||
SortOrder: 9
|
||||
|
||||
UndefinedOffset\SortableGridField\Tests\Forms\PageSortingTest\VTeam:
|
||||
team1:
|
||||
Name: Team 1
|
||||
City: Cologne
|
||||
SortOrder: 1
|
||||
team2:
|
||||
Name: Team 2
|
||||
City: Wellington
|
||||
SortOrder: 2
|
||||
team3:
|
||||
Name: Team 3
|
||||
City: Auckland
|
||||
SortOrder: 3
|
||||
team4:
|
||||
Name: Team 4
|
||||
City: Cologne
|
||||
SortOrder: 4
|
||||
team5:
|
||||
Name: Team 5
|
||||
City: Wellington
|
||||
SortOrder: 5
|
||||
team6:
|
||||
Name: Team 6
|
||||
City: Auckland
|
||||
SortOrder: 6
|
||||
team7:
|
||||
Name: Team 7
|
||||
City: Cologne
|
||||
SortOrder: 7
|
||||
team8:
|
||||
Name: Team 8
|
||||
City: Wellington
|
||||
SortOrder: 8
|
||||
team9:
|
||||
Name: Team 9
|
||||
City: Auckland
|
||||
SortOrder: 9
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
namespace UndefinedOffset\SortableGridField\Tests\Forms\PageSortingTest;
|
||||
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
|
||||
/**
|
||||
* Class \UndefinedOffset\SortableGridField\Tests\Forms\PageSortingTest\Team
|
||||
*
|
||||
* @property string Name
|
||||
* @property string City
|
||||
* @property int SortOrder
|
||||
*/
|
||||
class Team extends DataObject implements TestOnly
|
||||
{
|
||||
private static $table_name = 'GridFieldAction_PageSortOrder_Team';
|
||||
|
||||
private static $db = [
|
||||
'Name' => 'Varchar',
|
||||
'City' => 'Varchar',
|
||||
'SortOrder' => 'Int',
|
||||
];
|
||||
|
||||
private static $default_sort = 'SortOrder';
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
namespace UndefinedOffset\SortableGridField\Tests\Forms\PageSortingTest;
|
||||
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\Versioned\Versioned;
|
||||
|
||||
/**
|
||||
* Class \UndefinedOffset\SortableGridField\Tests\Forms\PageSortingTest\VTeam
|
||||
*
|
||||
* @property string Name
|
||||
* @property string City
|
||||
* @property int SortOrder
|
||||
*/
|
||||
class VTeam extends DataObject implements TestOnly
|
||||
{
|
||||
private static $table_name = 'GridFieldAction_PageSortOrder_VTeam';
|
||||
|
||||
private static $db = [
|
||||
'Name' => 'Varchar',
|
||||
'City' => 'Varchar',
|
||||
'SortOrder' => 'Int',
|
||||
];
|
||||
|
||||
private static $default_sort = 'SortOrder';
|
||||
|
||||
private static $extensions = [
|
||||
Versioned::class,
|
||||
];
|
||||
}
|
|
@ -1,253 +0,0 @@
|
|||
<?php
|
||||
class GridFieldSortableRowsAutoSortTest extends SapphireTest {
|
||||
/** @var string */
|
||||
public static $fixture_file = 'GridFieldSortableRowsAutoSortTest.yml';
|
||||
|
||||
/** @var array */
|
||||
protected $extraDataObjects = array(
|
||||
'GridFieldAction_SortOrder_Player',
|
||||
'GridFieldAction_SortOrder_VPlayer',
|
||||
'GridFieldAction_SortOrder_TestParent',
|
||||
'GridFieldAction_SortOrder_BaseObject',
|
||||
'GridFieldAction_SortOrder_ChildObject'
|
||||
);
|
||||
|
||||
public function testAutoSort() {
|
||||
if(Member::currentUser()) { Member::currentUser()->logOut(); }
|
||||
|
||||
$list = GridFieldAction_SortOrder_Player::get();
|
||||
$config = GridFieldConfig::create()->addComponent(new GridFieldSortableRows('SortOrder'));
|
||||
$gridField = new GridField('testfield', 'testfield', $list, $config);
|
||||
$form = new Form(new Controller(), 'mockform', new FieldList(array($gridField)), new FieldList());
|
||||
|
||||
$stateID = 'testGridStateActionField';
|
||||
Session::set($stateID, array('grid'=>'', 'actionName'=>'sortableRowsToggle', 'args'=>array('GridFieldSortableRows'=>array('sortableToggle'=>true))));
|
||||
$request = new SS_HTTPRequest('POST', 'url', array(), array('action_gridFieldAlterAction?StateID='.$stateID=>true, $form->getSecurityToken()->getName()=>$form->getSecurityToken()->getValue()));
|
||||
$gridField->gridFieldAlterAction(array('StateID'=>$stateID), $form, $request);
|
||||
|
||||
//Insure sort ran
|
||||
$this->assertEquals(3, $list->last()->SortOrder, 'Auto sort should have run');
|
||||
|
||||
|
||||
//Check for duplicates (there shouldn't be any)
|
||||
$count=$list->Count();
|
||||
$indexes=count(array_unique($list->column('SortOrder')));
|
||||
$this->assertEquals(0, $count-$indexes, 'Duplicate indexes detected');
|
||||
}
|
||||
|
||||
public function testAppendToTopAutoSort() {
|
||||
if(Member::currentUser()) { Member::currentUser()->logOut(); }
|
||||
|
||||
$list = GridFieldAction_SortOrder_Player::get();
|
||||
$config = GridFieldConfig::create()->addComponent(new GridFieldSortableRows('SortOrder'));
|
||||
$gridField = new GridField('testfield', 'testfield', $list, $config);
|
||||
$form = new Form(new Controller(), 'mockform', new FieldList(array($gridField)), new FieldList());
|
||||
|
||||
$gridField->getConfig()->getComponentByType('GridFieldSortableRows')->setAppendToTop(true);
|
||||
|
||||
$this->assertEquals(0, $list->last()->SortOrder, 'Auto sort should not have run');
|
||||
|
||||
$stateID = 'testGridStateActionField';
|
||||
Session::set($stateID, array('grid'=>'', 'actionName'=>'sortableRowsToggle', 'args'=>array('GridFieldSortableRows'=>array('sortableToggle'=>true))));
|
||||
$request = new SS_HTTPRequest('POST', 'url', array(), array('action_gridFieldAlterAction?StateID='.$stateID=>true, $form->getSecurityToken()->getName()=>$form->getSecurityToken()->getValue()));
|
||||
$gridField->gridFieldAlterAction(array('StateID'=>$stateID), $form, $request);
|
||||
|
||||
//Insure sort ran
|
||||
$this->assertEquals(3, $list->last()->SortOrder, 'Auto sort should have run');
|
||||
|
||||
|
||||
//Check for duplicates (there shouldn't be any)
|
||||
$count=$list->Count();
|
||||
$indexes=count(array_unique($list->column('SortOrder')));
|
||||
$this->assertEquals(0, $count-$indexes, 'Duplicate indexes detected');
|
||||
}
|
||||
|
||||
public function testAutoSortVersioned() {
|
||||
if(Member::currentUser()) { Member::currentUser()->logOut(); }
|
||||
|
||||
//Force versioned to reset
|
||||
Versioned::reset();
|
||||
|
||||
$list = GridFieldAction_SortOrder_VPlayer::get();
|
||||
|
||||
//Publish all records
|
||||
foreach($list as $item) {
|
||||
$item->publish('Stage', 'Live');
|
||||
}
|
||||
|
||||
|
||||
$config = GridFieldConfig::create()->addComponent(new GridFieldSortableRows('SortOrder', true, 'Live'));
|
||||
$gridField = new GridField('testfield', 'testfield', $list, $config);
|
||||
$form = new Form(new Controller(), 'mockform', new FieldList(array($gridField)), new FieldList());
|
||||
|
||||
$stateID = 'testGridStateActionField';
|
||||
Session::set($stateID, array('grid'=>'', 'actionName'=>'sortableRowsToggle', 'args'=>array('GridFieldSortableRows'=>array('sortableToggle'=>true))));
|
||||
$request = new SS_HTTPRequest('POST', 'url', array(), array('action_gridFieldAlterAction?StateID='.$stateID=>true, $form->getSecurityToken()->getName()=>$form->getSecurityToken()->getValue()));
|
||||
$gridField->gridFieldAlterAction(array('StateID'=>$stateID), $form, $request);
|
||||
|
||||
|
||||
//Insure sort ran
|
||||
$this->assertEquals(3, $list->last()->SortOrder, 'Auto sort should have run on Versioned stage "Stage"');
|
||||
|
||||
|
||||
//Check for duplicates (there shouldn't be any)
|
||||
$count=$list->Count();
|
||||
$indexes=count(array_unique($list->column('SortOrder')));
|
||||
$this->assertEquals(0, $count-$indexes, 'Duplicate indexes detected on Versioned stage "Stage"');
|
||||
|
||||
|
||||
//Force versioned over to Live stage
|
||||
Versioned::reading_stage('Live');
|
||||
|
||||
//Get live instance
|
||||
$obj=Versioned::get_one_by_stage('GridFieldAction_SortOrder_VPlayer', 'Live', '"ID"='.$list->last()->ID);
|
||||
|
||||
//Insure sort ran
|
||||
$this->assertEquals(3, $obj->SortOrder, 'Auto sort should have run on Versioned stage "Live"');
|
||||
|
||||
|
||||
//Check for duplicates (there shouldn't be any)
|
||||
$list=Versioned::get_by_stage('GridFieldAction_SortOrder_VPlayer', 'Live');
|
||||
$count=$list->Count();
|
||||
$indexes=count(array_unique($list->column('SortOrder')));
|
||||
$this->assertEquals(0, $count-$indexes, 'Duplicate indexes detected on Versioned stage "Live"');
|
||||
}
|
||||
|
||||
public function testAppendToTopAutoSortVersioned() {
|
||||
if(Member::currentUser()) { Member::currentUser()->logOut(); }
|
||||
|
||||
//Force versioned to reset
|
||||
Versioned::reset();
|
||||
|
||||
$list = GridFieldAction_SortOrder_VPlayer::get();
|
||||
|
||||
//Publish all records
|
||||
foreach($list as $item) {
|
||||
$item->publish('Stage', 'Live');
|
||||
}
|
||||
|
||||
|
||||
$config = GridFieldConfig::create()->addComponent(new GridFieldSortableRows('SortOrder', true, 'Live'));
|
||||
$gridField = new GridField('testfield', 'testfield', $list, $config);
|
||||
$form = new Form(new Controller(), 'mockform', new FieldList(array($gridField)), new FieldList());
|
||||
|
||||
$gridField->getConfig()->getComponentByType('GridFieldSortableRows')->setAppendToTop(true);
|
||||
|
||||
$this->assertEquals(0, $list->last()->SortOrder, 'Auto sort should not have run on Versioned stage "Stage"');
|
||||
|
||||
$stateID = 'testGridStateActionField';
|
||||
Session::set($stateID, array('grid'=>'', 'actionName'=>'sortableRowsToggle', 'args'=>array('GridFieldSortableRows'=>array('sortableToggle'=>true))));
|
||||
$request = new SS_HTTPRequest('POST', 'url', array(), array('action_gridFieldAlterAction?StateID='.$stateID=>true, $form->getSecurityToken()->getName()=>$form->getSecurityToken()->getValue()));
|
||||
$gridField->gridFieldAlterAction(array('StateID'=>$stateID), $form, $request);
|
||||
|
||||
|
||||
//Insure sort ran
|
||||
$this->assertEquals(3, $list->last()->SortOrder, 'Auto sort should have run on Versioned stage "Stage"');
|
||||
|
||||
|
||||
//Check for duplicates (there shouldn't be any)
|
||||
$count=$list->Count();
|
||||
$indexes=count(array_unique($list->column('SortOrder')));
|
||||
$this->assertEquals(0, $count-$indexes, 'Duplicate indexes detected on Versioned stage "Stage"');
|
||||
|
||||
|
||||
//Force versioned over to Live stage
|
||||
Versioned::reading_stage('Live');
|
||||
|
||||
//Insure sort ran
|
||||
$this->assertEquals(3, $list->last()->SortOrder, 'Auto sort should have run on Versioned stage "Live"');
|
||||
|
||||
|
||||
//Check for duplicates (there shouldn't be any)
|
||||
$count=$list->Count();
|
||||
$indexes=count(array_unique($list->column('SortOrder')));
|
||||
$this->assertEquals(0, $count-$indexes, 'Duplicate indexes detected on Versioned stage "Live"');
|
||||
}
|
||||
|
||||
public function testAppendToTopAutoSortChild() {
|
||||
if(Member::currentUser()) { Member::currentUser()->logOut(); }
|
||||
|
||||
//Push the edit date into the past, we're checking this later
|
||||
DB::query('UPDATE "GridFieldAction_SortOrder_BaseObject" SET "LastEdited"=\''.date('Y-m-d 00:00:00', strtotime('yesterday')).'\'');
|
||||
|
||||
$parent = GridFieldAction_SortOrder_TestParent::get()->first();
|
||||
$list = $parent->TestRelation();
|
||||
$config = GridFieldConfig::create()->addComponent(new GridFieldSortableRows('SortOrder'));
|
||||
$gridField = new GridField('testfield', 'testfield', $list, $config);
|
||||
$form = new Form(new Controller(), 'mockform', new FieldList(array($gridField)), new FieldList());
|
||||
$form->loadDataFrom($parent);
|
||||
|
||||
$gridField->getConfig()->getComponentByType('GridFieldSortableRows')->setAppendToTop(true);
|
||||
|
||||
$this->assertEquals(0, $list->last()->SortOrder, 'Auto sort should not have run');
|
||||
|
||||
$stateID = 'testGridStateActionField';
|
||||
Session::set($stateID, array('grid'=>'', 'actionName'=>'sortableRowsToggle', 'args'=>array('GridFieldSortableRows'=>array('sortableToggle'=>true))));
|
||||
$request = new SS_HTTPRequest('POST', 'url', array(), array('action_gridFieldAlterAction?StateID='.$stateID=>true, $form->getSecurityToken()->getName()=>$form->getSecurityToken()->getValue()));
|
||||
$gridField->gridFieldAlterAction(array('StateID'=>$stateID), $form, $request);
|
||||
|
||||
//Insure sort ran
|
||||
$this->assertEquals(3, $list->last()->SortOrder, 'Auto sort should have run');
|
||||
|
||||
|
||||
//Check for duplicates (there shouldn't be any)
|
||||
$count=$list->Count();
|
||||
$indexes=count(array_unique($list->column('SortOrder')));
|
||||
$this->assertEquals(0, $count-$indexes, 'Duplicate indexes detected');
|
||||
|
||||
|
||||
//Make sure the last edited is today for all records
|
||||
$this->assertEquals(3, $list->filter('LastEdited:GreaterThan', date('Y-m-d 00:00:00'))->count());
|
||||
}
|
||||
}
|
||||
|
||||
class GridFieldAction_SortOrder_Player extends DataObject implements TestOnly {
|
||||
static $db = array(
|
||||
'Name' => 'Varchar',
|
||||
'SortOrder' => 'Int'
|
||||
);
|
||||
|
||||
static $default_sort='SortOrder';
|
||||
}
|
||||
|
||||
class GridFieldAction_SortOrder_VPlayer extends DataObject implements TestOnly {
|
||||
static $db = array(
|
||||
'Name' => 'Varchar',
|
||||
'SortOrder' => 'Int'
|
||||
);
|
||||
|
||||
static $default_sort = 'SortOrder';
|
||||
|
||||
static $extensions=array(
|
||||
"Versioned('Stage', 'Live')"
|
||||
);
|
||||
}
|
||||
|
||||
class GridFieldAction_SortOrder_TestParent extends DataObject implements TestOnly {
|
||||
static $db = array(
|
||||
'Name' => 'Varchar'
|
||||
);
|
||||
|
||||
static $has_many = array(
|
||||
'TestRelation' => 'GridFieldAction_SortOrder_ChildObject'
|
||||
);
|
||||
}
|
||||
|
||||
class GridFieldAction_SortOrder_BaseObject extends DataObject implements TestOnly {
|
||||
static $db = array(
|
||||
'Name' => 'Varchar'
|
||||
);
|
||||
}
|
||||
|
||||
class GridFieldAction_SortOrder_ChildObject extends GridFieldAction_SortOrder_BaseObject implements TestOnly {
|
||||
static $db = array(
|
||||
'SortOrder' => 'Int'
|
||||
);
|
||||
|
||||
static $has_one = array(
|
||||
'Parent'=>'GridFieldAction_SortOrder_TestParent'
|
||||
);
|
||||
|
||||
static $default_sort='SortOrder';
|
||||
}
|
||||
?>
|
|
@ -1,39 +0,0 @@
|
|||
GridFieldAction_SortOrder_Player:
|
||||
player1:
|
||||
Name: Player 1
|
||||
SortOrder: 0
|
||||
player2:
|
||||
Name: Player 2
|
||||
SortOrder: 0
|
||||
player3:
|
||||
Name: Player 3
|
||||
SortOrder: 0
|
||||
|
||||
GridFieldAction_SortOrder_VPlayer:
|
||||
player1:
|
||||
Name: Player 1
|
||||
SortOrder: 0
|
||||
player2:
|
||||
Name: Player 2
|
||||
SortOrder: 0
|
||||
player3:
|
||||
Name: Player 3
|
||||
SortOrder: 0
|
||||
|
||||
GridFieldAction_SortOrder_TestParent:
|
||||
testparent:
|
||||
Name: Test
|
||||
|
||||
GridFieldAction_SortOrder_ChildObject:
|
||||
testitem1:
|
||||
Name: Test 1
|
||||
SortOrder: 0
|
||||
Parent: =>GridFieldAction_SortOrder_TestParent.testparent
|
||||
testitem2:
|
||||
Name: Test 2
|
||||
SortOrder: 0
|
||||
Parent: =>GridFieldAction_SortOrder_TestParent.testparent
|
||||
testitem3:
|
||||
Name: Test 3
|
||||
SortOrder: 0
|
||||
Parent: =>GridFieldAction_SortOrder_TestParent.testparent
|
|
@ -1,171 +0,0 @@
|
|||
<?php
|
||||
class GridFieldSortableRowsPageTest extends SapphireTest {
|
||||
|
||||
/** @var ArrayList */
|
||||
protected $list;
|
||||
|
||||
/** @var GridField */
|
||||
protected $gridField;
|
||||
|
||||
/** @var Form */
|
||||
protected $form;
|
||||
|
||||
/** @var string */
|
||||
public static $fixture_file = 'GridFieldSortableRowsPageTest.yml';
|
||||
|
||||
/** @var array */
|
||||
protected $extraDataObjects = array('GridFieldAction_PageSortOrder_Team', 'GridFieldAction_PageSortOrder_VTeam');
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
$this->list = GridFieldAction_PageSortOrder_Team::get();
|
||||
$config = GridFieldConfig_Base::create(5)->addComponent(new GridFieldSortableRows('SortOrder'));
|
||||
$this->gridField = new GridField('testfield', 'testfield', $this->list, $config);
|
||||
$this->form = new Form(new Controller(), 'mockform', new FieldList(array($this->gridField)), new FieldList());
|
||||
}
|
||||
|
||||
public function testSortToNextPage() {
|
||||
$this->gridField->State->GridFieldPaginator->currentPage=1;
|
||||
|
||||
|
||||
$team3 = $this->objFromFixture('GridFieldAction_PageSortOrder_Team', 'team3');
|
||||
|
||||
$this->logInWithPermission('ADMIN');
|
||||
$stateID = 'testGridStateActionField';
|
||||
Session::set($stateID, array('grid'=>'', 'actionName'=>'sortToPage', 'args'=>array('GridFieldSortableRows'=>array('sortableToggle'=>true), 'GridFieldPaginator'=>array('currentPage'=>1))));
|
||||
$request = new SS_HTTPRequest('POST', 'url', array('ItemID'=>$team3->ID, 'Target'=>'nextpage'), array('action_gridFieldAlterAction?StateID='.$stateID=>true, $this->form->getSecurityToken()->getName()=>$this->form->getSecurityToken()->getValue()));
|
||||
$this->gridField->gridFieldAlterAction(array('StateID'=>$stateID), $this->form, $request);
|
||||
|
||||
|
||||
$team6 = $this->objFromFixture('GridFieldAction_PageSortOrder_Team', 'team6');
|
||||
$this->assertEquals(5, $team6->SortOrder, 'Team 6 Should have moved to the bottom of the first page');
|
||||
|
||||
$team3 = $this->objFromFixture('GridFieldAction_PageSortOrder_Team', 'team3');
|
||||
$this->assertEquals(6, $team3->SortOrder, 'Team 3 Should have moved to the top of the second page');
|
||||
}
|
||||
|
||||
public function testSortToPrevPage() {
|
||||
$this->gridField->State->GridFieldPaginator->currentPage=2;
|
||||
|
||||
|
||||
$team7 = $this->objFromFixture('GridFieldAction_PageSortOrder_Team', 'team7');
|
||||
|
||||
$this->logInWithPermission('ADMIN');
|
||||
$stateID = 'testGridStateActionField';
|
||||
Session::set($stateID, array('grid'=>'', 'actionName'=>'sortToPage', 'args'=>array('GridFieldSortableRows'=>array('sortableToggle'=>true), 'GridFieldPaginator'=>array('currentPage'=>1))));
|
||||
$request = new SS_HTTPRequest('POST', 'url', array('ItemID'=>$team7->ID, 'Target'=>'previouspage'), array('action_gridFieldAlterAction?StateID='.$stateID=>true, $this->form->getSecurityToken()->getName()=>$this->form->getSecurityToken()->getValue()));
|
||||
$this->gridField->gridFieldAlterAction(array('StateID'=>$stateID), $this->form, $request);
|
||||
|
||||
|
||||
$team7 = $this->objFromFixture('GridFieldAction_PageSortOrder_Team', 'team7');
|
||||
$this->assertEquals(5, $team7->SortOrder, 'Team 7 Should have moved to the bottom of the first page');
|
||||
|
||||
$team5 = $this->objFromFixture('GridFieldAction_PageSortOrder_Team', 'team5');
|
||||
$this->assertEquals(6, $team5->SortOrder, 'Team 5 Should have moved to the top of the second page');
|
||||
}
|
||||
|
||||
public function testSortToNextPageVersioned() {
|
||||
//Force versioned to reset
|
||||
Versioned::reset();
|
||||
|
||||
$list=GridFieldAction_PageSortOrder_VTeam::get();
|
||||
$this->gridField->setList($list);
|
||||
$this->gridField->getConfig()->getComponentByType('GridFieldSortableRows')->setUpdateVersionedStage('Live');
|
||||
$this->gridField->State->GridFieldPaginator->currentPage=1;
|
||||
|
||||
//Publish all records
|
||||
foreach($list as $item) {
|
||||
$item->publish('Stage', 'Live');
|
||||
}
|
||||
|
||||
|
||||
$team3 = $this->objFromFixture('GridFieldAction_PageSortOrder_VTeam', 'team3');
|
||||
|
||||
$this->logInWithPermission('ADMIN');
|
||||
$stateID = 'testGridStateActionField';
|
||||
Session::set($stateID, array('grid'=>'', 'actionName'=>'sortToPage', 'args'=>array('GridFieldSortableRows'=>array('sortableToggle'=>true), 'GridFieldPaginator'=>array('currentPage'=>1))));
|
||||
$request = new SS_HTTPRequest('POST', 'url', array('ItemID'=>$team3->ID, 'Target'=>'nextpage'), array('action_gridFieldAlterAction?StateID='.$stateID=>true, $this->form->getSecurityToken()->getName()=>$this->form->getSecurityToken()->getValue()));
|
||||
$this->gridField->gridFieldAlterAction(array('StateID'=>$stateID), $this->form, $request);
|
||||
|
||||
|
||||
$team6 = $this->objFromFixture('GridFieldAction_PageSortOrder_VTeam', 'team6');
|
||||
$this->assertEquals(5, $team6->SortOrder, 'Team 6 Should have moved to the bottom of the first page on Versioned stage "Stage"');
|
||||
|
||||
$team3 = $this->objFromFixture('GridFieldAction_PageSortOrder_VTeam', 'team3');
|
||||
$this->assertEquals(6, $team3->SortOrder, 'Team 3 Should have moved to the top of the second page on Versioned stage "Stage"');
|
||||
|
||||
|
||||
$list=Versioned::get_by_stage('GridFieldAction_PageSortOrder_VTeam', 'Live');
|
||||
|
||||
$team6 = $list->byID($team6->ID);
|
||||
$this->assertEquals(5, $team6->SortOrder, 'Team 6 Should have moved to the bottom of the first page on Versioned stage "Live"');
|
||||
|
||||
$team3 = $list->byID($team3->ID);
|
||||
$this->assertEquals(6, $team3->SortOrder, 'Team 3 Should have moved to the top of the second page on Versioned stage "Live"');
|
||||
}
|
||||
|
||||
public function testSortToPrevPageVersioned() {
|
||||
//Force versioned to reset
|
||||
Versioned::reset();
|
||||
|
||||
$list=GridFieldAction_PageSortOrder_VTeam::get();
|
||||
$this->gridField->setList($list);
|
||||
$this->gridField->getConfig()->getComponentByType('GridFieldSortableRows')->setUpdateVersionedStage('Live');
|
||||
$this->gridField->State->GridFieldPaginator->currentPage=2;
|
||||
|
||||
//Publish all records
|
||||
foreach($list as $item) {
|
||||
$item->publish('Stage', 'Live');
|
||||
}
|
||||
|
||||
|
||||
$team7 = $this->objFromFixture('GridFieldAction_PageSortOrder_VTeam', 'team7');
|
||||
|
||||
$this->logInWithPermission('ADMIN');
|
||||
$stateID = 'testGridStateActionField';
|
||||
Session::set($stateID, array('grid'=>'', 'actionName'=>'sortToPage', 'args'=>array('GridFieldSortableRows'=>array('sortableToggle'=>true), 'GridFieldPaginator'=>array('currentPage'=>1))));
|
||||
$request = new SS_HTTPRequest('POST', 'url', array('ItemID'=>$team7->ID, 'Target'=>'previouspage'), array('action_gridFieldAlterAction?StateID='.$stateID=>true, $this->form->getSecurityToken()->getName()=>$this->form->getSecurityToken()->getValue()));
|
||||
$this->gridField->gridFieldAlterAction(array('StateID'=>$stateID), $this->form, $request);
|
||||
|
||||
|
||||
$team7 = $this->objFromFixture('GridFieldAction_PageSortOrder_VTeam', 'team7');
|
||||
$this->assertEquals(5, $team7->SortOrder, 'Team 7 Should have moved to the bottom of the first page on Versioned stage "Stage"');
|
||||
|
||||
$team5 = $this->objFromFixture('GridFieldAction_PageSortOrder_VTeam', 'team5');
|
||||
$this->assertEquals(6, $team5->SortOrder, 'Team 5 Should have moved to the top of the second page on Versioned stage "Stage"');
|
||||
|
||||
|
||||
$list=Versioned::get_by_stage('GridFieldAction_PageSortOrder_VTeam', 'Live');
|
||||
|
||||
$team7 = $list->byID($team7->ID);
|
||||
$this->assertEquals(5, $team7->SortOrder, 'Team 7 Should have moved to the bottom of the first page on Versioned stage "Live"');
|
||||
|
||||
$team5 = $list->byID($team5->ID);
|
||||
$this->assertEquals(6, $team5->SortOrder, 'Team 5 Should have moved to the top of the second page on Versioned stage "Live"');
|
||||
}
|
||||
}
|
||||
|
||||
class GridFieldAction_PageSortOrder_Team extends DataObject implements TestOnly {
|
||||
static $db = array(
|
||||
'Name' => 'Varchar',
|
||||
'City' => 'Varchar',
|
||||
'SortOrder' => 'Int'
|
||||
);
|
||||
|
||||
static $default_sort='SortOrder';
|
||||
}
|
||||
|
||||
class GridFieldAction_PageSortOrder_VTeam extends DataObject implements TestOnly {
|
||||
static $db = array(
|
||||
'Name' => 'Varchar',
|
||||
'City' => 'Varchar',
|
||||
'SortOrder' => 'Int'
|
||||
);
|
||||
|
||||
static $default_sort='SortOrder';
|
||||
|
||||
static $extensions=array(
|
||||
"Versioned('Stage', 'Live')"
|
||||
);
|
||||
}
|
||||
?>
|
|
@ -1,75 +0,0 @@
|
|||
GridFieldAction_PageSortOrder_Team:
|
||||
team1:
|
||||
Name: Team 1
|
||||
City: Cologne
|
||||
SortOrder: 1
|
||||
team2:
|
||||
Name: Team 2
|
||||
City: Wellington
|
||||
SortOrder: 2
|
||||
team3:
|
||||
Name: Team 3
|
||||
City: Auckland
|
||||
SortOrder: 3
|
||||
team4:
|
||||
Name: Team 4
|
||||
City: Cologne
|
||||
SortOrder: 4
|
||||
team5:
|
||||
Name: Team 5
|
||||
City: Wellington
|
||||
SortOrder: 5
|
||||
team6:
|
||||
Name: Team 6
|
||||
City: Auckland
|
||||
SortOrder: 6
|
||||
team7:
|
||||
Name: Team 7
|
||||
City: Cologne
|
||||
SortOrder: 7
|
||||
team8:
|
||||
Name: Team 8
|
||||
City: Wellington
|
||||
SortOrder: 8
|
||||
team9:
|
||||
Name: Team 9
|
||||
City: Auckland
|
||||
SortOrder: 9
|
||||
|
||||
GridFieldAction_PageSortOrder_VTeam:
|
||||
team1:
|
||||
Name: Team 1
|
||||
City: Cologne
|
||||
SortOrder: 1
|
||||
team2:
|
||||
Name: Team 2
|
||||
City: Wellington
|
||||
SortOrder: 2
|
||||
team3:
|
||||
Name: Team 3
|
||||
City: Auckland
|
||||
SortOrder: 3
|
||||
team4:
|
||||
Name: Team 4
|
||||
City: Cologne
|
||||
SortOrder: 4
|
||||
team5:
|
||||
Name: Team 5
|
||||
City: Wellington
|
||||
SortOrder: 5
|
||||
team6:
|
||||
Name: Team 6
|
||||
City: Auckland
|
||||
SortOrder: 6
|
||||
team7:
|
||||
Name: Team 7
|
||||
City: Cologne
|
||||
SortOrder: 7
|
||||
team8:
|
||||
Name: Team 8
|
||||
City: Wellington
|
||||
SortOrder: 8
|
||||
team9:
|
||||
Name: Team 9
|
||||
City: Auckland
|
||||
SortOrder: 9
|
|
@ -1,106 +0,0 @@
|
|||
<?php
|
||||
class GridFieldSortableRowsTest extends SapphireTest {
|
||||
|
||||
/** @var ArrayList */
|
||||
protected $list;
|
||||
|
||||
/** @var GridField */
|
||||
protected $gridField;
|
||||
|
||||
/** @var Form */
|
||||
protected $form;
|
||||
|
||||
/** @var string */
|
||||
public static $fixture_file = 'GridFieldSortableRowsTest.yml';
|
||||
|
||||
/** @var array */
|
||||
protected $extraDataObjects = array('GridFieldAction_SortOrder_Team', 'GridFieldAction_SortOrder_VTeam');
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
$this->list = GridFieldAction_SortOrder_Team::get();
|
||||
$config = GridFieldConfig::create()->addComponent(new GridFieldSortableRows('SortOrder'));
|
||||
$this->gridField = new GridField('testfield', 'testfield', $this->list, $config);
|
||||
$this->form = new Form(new Controller(), 'mockform', new FieldList(array($this->gridField)), new FieldList());
|
||||
}
|
||||
|
||||
public function testSortActionWithoutCorrectPermission() {
|
||||
if(Member::currentUser()) { Member::currentUser()->logOut(); }
|
||||
$this->setExpectedException('ValidationException');
|
||||
$team1 = $this->objFromFixture('GridFieldAction_SortOrder_Team', 'team1');
|
||||
$team2 = $this->objFromFixture('GridFieldAction_SortOrder_Team', 'team2');
|
||||
$team3 = $this->objFromFixture('GridFieldAction_SortOrder_Team', 'team3');
|
||||
|
||||
$stateID = 'testGridStateActionField';
|
||||
Session::set($stateID, array('grid'=>'', 'actionName'=>'saveGridRowSort', 'args'=>array('GridFieldSortableRows'=>array('sortableToggle'=>true))));
|
||||
$request = new SS_HTTPRequest('POST', 'url', array('ItemIDs'=>"$team1->ID, $team3->ID, $team2->ID"), array('action_gridFieldAlterAction?StateID='.$stateID=>true, $this->form->getSecurityToken()->getName()=>$this->form->getSecurityToken()->getValue()));
|
||||
$this->gridField->gridFieldAlterAction(array('StateID'=>$stateID), $this->form, $request);
|
||||
$this->assertEquals($team3->ID, $this->list->last()->ID, 'User should\'t be able to sort records without correct permissions.');
|
||||
}
|
||||
|
||||
public function testSortActionWithAdminPermission() {
|
||||
$team1 = $this->objFromFixture('GridFieldAction_SortOrder_Team', 'team1');
|
||||
$team2 = $this->objFromFixture('GridFieldAction_SortOrder_Team', 'team2');
|
||||
$team3 = $this->objFromFixture('GridFieldAction_SortOrder_Team', 'team3');
|
||||
$this->logInWithPermission('ADMIN');
|
||||
$stateID = 'testGridStateActionField';
|
||||
Session::set($stateID, array('grid'=>'', 'actionName'=>'saveGridRowSort', 'args'=>array('GridFieldSortableRows'=>array('sortableToggle'=>true))));
|
||||
$request = new SS_HTTPRequest('POST', 'url', array('ItemIDs'=>"$team1->ID, $team3->ID, $team2->ID"), array('action_gridFieldAlterAction?StateID='.$stateID=>true, $this->form->getSecurityToken()->getName()=>$this->form->getSecurityToken()->getValue()));
|
||||
$this->gridField->gridFieldAlterAction(array('StateID'=>$stateID), $this->form, $request);
|
||||
$this->assertEquals($team2->ID, $this->list->last()->ID, 'User should be able to sort records with ADMIN permission.');
|
||||
}
|
||||
|
||||
public function testSortActionVersioned() {
|
||||
//Force versioned to reset
|
||||
Versioned::reset();
|
||||
|
||||
$list = GridFieldAction_SortOrder_VTeam::get();
|
||||
$this->gridField->setList($list);
|
||||
$this->gridField->getConfig()->getComponentByType('GridFieldSortableRows')->setUpdateVersionedStage('Live');
|
||||
|
||||
//Publish all records
|
||||
foreach($list as $item) {
|
||||
$item->publish('Stage', 'Live');
|
||||
}
|
||||
|
||||
$team1 = $this->objFromFixture('GridFieldAction_SortOrder_VTeam', 'team1');
|
||||
$team2 = $this->objFromFixture('GridFieldAction_SortOrder_VTeam', 'team2');
|
||||
$team3 = $this->objFromFixture('GridFieldAction_SortOrder_VTeam', 'team3');
|
||||
|
||||
$this->logInWithPermission('ADMIN');
|
||||
$stateID = 'testGridStateActionField';
|
||||
Session::set($stateID, array('grid'=>'', 'actionName'=>'saveGridRowSort', 'args'=>array('GridFieldSortableRows'=>array('sortableToggle'=>true))));
|
||||
$request = new SS_HTTPRequest('POST', 'url', array('ItemIDs'=>"$team1->ID, $team3->ID, $team2->ID"), array('action_gridFieldAlterAction?StateID='.$stateID=>true, $this->form->getSecurityToken()->getName()=>$this->form->getSecurityToken()->getValue()));
|
||||
$this->gridField->gridFieldAlterAction(array('StateID'=>$stateID), $this->form, $request);
|
||||
|
||||
$this->assertEquals($team2->ID, $list->last()->ID, 'Sort should have happened on Versioned stage "Stage"');
|
||||
|
||||
$list=Versioned::get_by_stage('GridFieldAction_SortOrder_VTeam', 'Live');
|
||||
$this->assertEquals($team2->ID, $list->last()->ID, 'Sort should have happened on Versioned stage "Live"');
|
||||
}
|
||||
}
|
||||
|
||||
class GridFieldAction_SortOrder_Team extends DataObject implements TestOnly {
|
||||
static $db = array(
|
||||
'Name' => 'Varchar',
|
||||
'City' => 'Varchar',
|
||||
'SortOrder' => 'Int'
|
||||
);
|
||||
|
||||
static $default_sort='SortOrder';
|
||||
}
|
||||
|
||||
class GridFieldAction_SortOrder_VTeam extends DataObject implements TestOnly {
|
||||
static $db = array(
|
||||
'Name' => 'Varchar',
|
||||
'City' => 'Varchar',
|
||||
'SortOrder' => 'Int'
|
||||
);
|
||||
|
||||
static $default_sort='SortOrder';
|
||||
|
||||
static $extensions=array(
|
||||
"Versioned('Stage', 'Live')"
|
||||
);
|
||||
}
|
||||
?>
|
|
@ -1,27 +0,0 @@
|
|||
GridFieldAction_SortOrder_Team:
|
||||
team1:
|
||||
Name: Team 1
|
||||
City: Cologne
|
||||
SortOrder: 1
|
||||
team2:
|
||||
Name: Team 2
|
||||
City: Wellington
|
||||
SortOrder: 2
|
||||
team3:
|
||||
Name: Team 3
|
||||
City: Auckland
|
||||
SortOrder: 3
|
||||
|
||||
GridFieldAction_SortOrder_VTeam:
|
||||
team1:
|
||||
Name: Team 1
|
||||
City: Cologne
|
||||
SortOrder: 1
|
||||
team2:
|
||||
Name: Team 2
|
||||
City: Wellington
|
||||
SortOrder: 2
|
||||
team3:
|
||||
Name: Team 3
|
||||
City: Auckland
|
||||
SortOrder: 3
|
|
@ -0,0 +1,15 @@
|
|||
SS_ENVIRONMENT_TYPE="dev"
|
||||
SS_TRUSTED_PROXY_IPS="*"
|
||||
|
||||
SS_DATABASE_CLASS="MySQLDatabase"
|
||||
SS_DATABASE_SERVER="127.0.0.1"
|
||||
SS_DATABASE_USERNAME="root"
|
||||
SS_DATABASE_PASSWORD="testpassword"
|
||||
SS_DATABASE_NAME="test_db"
|
||||
|
||||
SS_DEFAULT_ADMIN_USERNAME="username"
|
||||
SS_DEFAULT_ADMIN_PASSWORD="password"
|
||||
|
||||
SS_ERROR_LOG="artifacts/silverstripe-errors.log"
|
||||
|
||||
TRAVIS_TEST_SESSION="1"
|
Loading…
Reference in New Issue