From b221134ce19419d372399540f350a477751afe38 Mon Sep 17 00:00:00 2001 From: Robbie Averill Date: Fri, 28 Sep 2018 17:38:38 +0200 Subject: [PATCH 1/7] FIX Orderable rows now respects actual MMTL sort orders instead of incrementing from SiteTree --- src/GridFieldOrderableRows.php | 67 ++++++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 16 deletions(-) diff --git a/src/GridFieldOrderableRows.php b/src/GridFieldOrderableRows.php index 57bb4fb..d8c5e0c 100755 --- a/src/GridFieldOrderableRows.php +++ b/src/GridFieldOrderableRows.php @@ -4,6 +4,8 @@ namespace Symbiote\GridFieldExtensions; use Exception; use SilverStripe\Control\Controller; +use SilverStripe\Control\HTTPRequest; +use SilverStripe\Control\HTTPResponse_Exception; use SilverStripe\Control\RequestHandler; use SilverStripe\Core\ClassInfo; use SilverStripe\Forms\GridField\GridField; @@ -20,11 +22,11 @@ use SilverStripe\ORM\DataObject; use SilverStripe\ORM\DataObjectInterface; use SilverStripe\ORM\DataObjectSchema; use SilverStripe\ORM\DB; +use SilverStripe\ORM\FieldType\DBDatetime; use SilverStripe\ORM\ManyManyList; use SilverStripe\ORM\ManyManyThroughList; use SilverStripe\ORM\ManyManyThroughQueryManipulator; use SilverStripe\ORM\SS_List; -use SilverStripe\ORM\FieldType\DBDatetime; use SilverStripe\Versioned\Versioned; use SilverStripe\View\ViewableData; @@ -295,7 +297,22 @@ class GridFieldOrderableRows extends RequestHandler implements $record->ID, $this->getSortField() ); - $sortField = new HiddenField($sortFieldName, false, $record->getField($this->getSortField())); + + // Default: Get the sort field directly from the current record + $currentSortValue = $record->getField($this->getSortField()); + + $list = $grid->getList(); + if ($list instanceof ManyManyThroughList) { + // In a many many through list we should get the current sort order from the relationship + // if it exists, not directly from the record + $throughListSorts = $this->getSortValuesFromManyManyThroughList($list, $this->getSortField()); + + if (array_key_exists($record->ID, $throughListSorts)) { + $currentSortValue = $throughListSorts[$record->ID]; + } + } + + $sortField = HiddenField::create($sortFieldName, false, $currentSortValue); $sortField->addExtraClass('ss-orderable-hidden-sort'); $sortField->setForm($grid->getForm()); @@ -345,17 +362,18 @@ class GridFieldOrderableRows extends RequestHandler implements $sortterm .= '"'.$this->getSortTable($list).'"."'.$this->getSortField().'"'; } return $list->sort($sortterm); - } else { - return $list; } + + return $list; } /** * Handles requests to reorder a set of IDs in a specific order. * * @param GridField $grid - * @param SS_HTTPRequest $request - * @return SS_HTTPResponse + * @param HTTPRequest $request + * @return string + * @throws HTTPResponse_Exception */ public function handleReorder($grid, $request) { @@ -536,16 +554,7 @@ class GridFieldOrderableRows extends RequestHandler implements } } } elseif ($items instanceof ManyManyThroughList) { - $manipulator = $this->getManyManyInspector($list); - $joinClass = $manipulator->getJoinClass(); - $fromRelationName = $manipulator->getForeignKey(); - $toRelationName = $manipulator->getLocalKey(); - $sortlist = DataList::create($joinClass)->filter([ - $toRelationName => $items->column('ID'), - // first() is safe as there are earlier checks to ensure our list to sort is valid - $fromRelationName => $items->first()->getJoin()->$fromRelationName, - ]); - $current = $sortlist->map($toRelationName, $sortField)->toArray(); + $current = $this->getSortValuesFromManyManyThroughList($list, $sortField); } else { $current = $items->map('ID', $sortField)->toArray(); } @@ -759,4 +768,30 @@ class GridFieldOrderableRows extends RequestHandler implements } return $inspector; } + + /** + * Used to get sort orders from a many many through list relationship record, rather than the current + * record itself. + * + * @param ManyManyList|ManyManyThroughList $list + * @return int[] Sort orders for the + */ + protected function getSortValuesFromManyManyThroughList($list, $sortField) + { + $manipulator = $this->getManyManyInspector($list); + + // Find the foreign key name, ID and class to look up + $joinClass = $manipulator->getJoinClass(); + $fromRelationName = $manipulator->getForeignKey(); + $toRelationName = $manipulator->getLocalKey(); + + // Create a list of the MMTL relations + $sortlist = DataList::create($joinClass)->filter([ + $toRelationName => $list->column('ID'), + // first() is safe as there are earlier checks to ensure our list to sort is valid + $fromRelationName => $list->first()->getJoin()->$fromRelationName, + ]); + + return $sortlist->map($toRelationName, $sortField)->toArray(); + } } From 78c63c6725cca07882b720a5c9581da45b04d769 Mon Sep 17 00:00:00 2001 From: Robbie Averill Date: Fri, 28 Sep 2018 17:59:44 +0200 Subject: [PATCH 2/7] Add test for getting the correct Sort order from MMTL items, fix incorrect test class name --- tests/GridFieldOrderableRowsTest.php | 34 +++++++++++++++++++++ tests/OrderableRowsThroughVersionedTest.php | 4 +-- tests/Stub/ThroughIntermediary.php | 7 ++--- 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/tests/GridFieldOrderableRowsTest.php b/tests/GridFieldOrderableRowsTest.php index 2ca98a9..dd71b07 100644 --- a/tests/GridFieldOrderableRowsTest.php +++ b/tests/GridFieldOrderableRowsTest.php @@ -88,6 +88,40 @@ class GridFieldOrderableRowsTest extends SapphireTest $this->assertEquals($desiredOrder, $newOrder); } + public function testManyManyThroughListSortOrdersAreUsedForInitialRender() + { + /** @var ThroughDefiner $record */ + $record = $this->objFromFixture(ThroughDefiner::class, 'DefinerOne'); + + $orderable = new GridFieldOrderableRows('Sort'); + $config = new GridFieldConfig_RelationEditor(); + $config->addComponent($orderable); + + $grid = new GridField( + 'Belongings', + 'Testing Many Many', + $record->Belongings()->sort('Sort'), + $config + ); + + // Get the first record, which would be the first one to have column contents generated + /** @var ThroughIntermediary $expected */ + $intermediary = $this->objFromFixture(ThroughIntermediary::class, 'One'); + + $result = $orderable->getColumnContent($grid, $record, 'irrelevant'); + + $this->assertContains( + 'Belongings[GridFieldEditableColumns][' . $record->ID . '][Sort]', + $result, + 'The field name is indexed under the record\'s ID' + ); + $this->assertContains( + 'value="' . $intermediary->Sort . '"', + $result, + 'The value comes from the MMTL intermediary Sort value' + ); + } + public function testSortableChildClass() { $orderable = new GridFieldOrderableRows('Sort'); diff --git a/tests/OrderableRowsThroughVersionedTest.php b/tests/OrderableRowsThroughVersionedTest.php index 694da01..e7e3cb1 100644 --- a/tests/OrderableRowsThroughVersionedTest.php +++ b/tests/OrderableRowsThroughVersionedTest.php @@ -12,7 +12,7 @@ use Symbiote\GridFieldExtensions\Tests\Stub\ThroughIntermediary; use Symbiote\GridFieldExtensions\Tests\Stub\ThroughBelongs; use Symbiote\GridFieldExtensions\GridFieldOrderableRows; -class OrderableRowsThroughTest extends SapphireTest +class OrderableRowsThroughVersionedTest extends SapphireTest { protected static $fixture_file = 'OrderableRowsThroughTest.yml'; @@ -105,7 +105,7 @@ class OrderableRowsThroughTest extends SapphireTest } } $this->assertTrue($differenceFound, 'All records should have changes in draft'); - + // Verify live stage has NOT reordered Versioned::set_stage(Versioned::LIVE); $sameOrder = $parent->$relationName()->sort($sortName)->column('ID'); diff --git a/tests/Stub/ThroughIntermediary.php b/tests/Stub/ThroughIntermediary.php index 12a48e1..9477d61 100644 --- a/tests/Stub/ThroughIntermediary.php +++ b/tests/Stub/ThroughIntermediary.php @@ -2,18 +2,17 @@ namespace Symbiote\GridFieldExtensions\Tests\Stub; -use SilverStripe\ORM\DataObject; -use SilverStripe\ORM\FieldType\DBInt; use SilverStripe\Dev\TestOnly; +use SilverStripe\ORM\DataObject; class ThroughIntermediary extends DataObject implements TestOnly { private static $table_name = 'IntermediaryThrough'; private static $db = [ - 'Sort' => DBInt::class, + 'Sort' => 'Int', ]; - + private static $has_one = [ 'Defining' => ThroughDefiner::class, 'Belonging' => ThroughBelongs::class, From 968b80791834cfbac0163e77f4362161ef2b51e8 Mon Sep 17 00:00:00 2001 From: Robbie Averill Date: Fri, 28 Sep 2018 18:24:50 +0200 Subject: [PATCH 3/7] Add SS 4.3.x to Travis matrix and move Postgres to 2.1.x-dev with SS 4.2 or newer --- .travis.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 74cc970..f0fbdb3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,9 +9,11 @@ matrix: - php: 5.6 env: DB=MYSQL RECIPE_VERSION=1.0.x-dev PHPCS_TEST=1 PHPUNIT_TEST=1 - php: 7.0 - env: DB=PGSQL RECIPE_VERSION=1.1.x-dev PHPUNIT_TEST=1 + env: DB=MYSQL RECIPE_VERSION=1.1.x-dev PHPUNIT_TEST=1 - php: 7.1 - env: DB=MYSQL RECIPE_VERSION=4.2.x-dev PHPUNIT_COVERAGE_TEST=1 + env: DB=PGSQL RECIPE_VERSION=4.2.x-dev PHPUNIT_COVERAGE_TEST=1 + - php: 7.2 + env: DB=MYSQL RECIPE_VERSION=4.3.x-dev PHPUNIT_TEST=1 - php: 7.2 env: DB=MYSQL RECIPE_VERSION=4.x-dev PHPUNIT_TEST=1 @@ -21,7 +23,7 @@ before_script: - composer validate - composer require silverstripe/recipe-core "$RECIPE_VERSION" --no-update - - if [[ $DB == PGSQL ]]; then composer require silverstripe/postgresql:2.0.x-dev --no-update; fi + - if [[ $DB == PGSQL ]]; then composer require silverstripe/postgresql:2.1.x-dev --no-update; fi - composer install --prefer-dist --no-interaction --no-progress --no-suggest --optimize-autoloader --verbose --profile script: From 4263c9d9700ef74745362f9cf1afa0dd506f210f Mon Sep 17 00:00:00 2001 From: Robbie Averill Date: Wed, 17 Oct 2018 11:36:45 +0200 Subject: [PATCH 4/7] FIX Disable change tracking on configurable paginator inputs See https://github.com/silverstripe/silverstripe-framework/pull/8486 --- .../GridFieldExtensions/GridFieldConfigurablePaginator.ss | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/Symbiote/GridFieldExtensions/GridFieldConfigurablePaginator.ss b/templates/Symbiote/GridFieldExtensions/GridFieldConfigurablePaginator.ss index 488c40f..17e3de0 100644 --- a/templates/Symbiote/GridFieldExtensions/GridFieldConfigurablePaginator.ss +++ b/templates/Symbiote/GridFieldExtensions/GridFieldConfigurablePaginator.ss @@ -2,7 +2,7 @@ <%t Symbiote\\GridFieldExtensions\\GridFieldConfigurablePaginator.SHOW 'Show' is 'Verb. Example: Show 1 of 2' %> - <% loop $PageSizes %> <% end_loop %> @@ -14,7 +14,7 @@ $FirstPage $PreviousPage <%t SilverStripe\\Forms\\GridField\\GridFieldPaginator.Page 'Page' %> - + <%t SilverStripe\\Forms\\GridField\\GridFieldPaginator.OF 'of' is 'Example: View 1 of 2' %> $NumPages From 3876527913a6f63750e9cf3beecc3349c60cee33 Mon Sep 17 00:00:00 2001 From: Robbie Averill Date: Fri, 19 Oct 2018 21:38:19 +0200 Subject: [PATCH 5/7] FIX Position inline editable checkbox fields relative rather than absolute --- css/GridFieldExtensions.css | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/css/GridFieldExtensions.css b/css/GridFieldExtensions.css index 498d478..f56db7e 100644 --- a/css/GridFieldExtensions.css +++ b/css/GridFieldExtensions.css @@ -42,6 +42,11 @@ background: #DFD; } +.grid-field__table .form-check-input.editable-column-field { + margin-top: .9rem; + position: relative; +} + /** * GridFieldAddNewMultiClass */ From 76541b27f238da3a069778514ea0c939b2c31019 Mon Sep 17 00:00:00 2001 From: Robbie Averill Date: Fri, 1 Mar 2019 15:38:49 +1300 Subject: [PATCH 6/7] Add PHP 7.3 to Travis builds and use recipe-cms instead of recipe-core Fixes the version incompatibility with silverstripe/versioned and its new interfaces --- .travis.yml | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index f0fbdb3..7140b49 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,5 @@ language: php -env: - global: - - COMPOSER_ROOT_VERSION="3.1.x-dev" - matrix: include: - php: 5.6 @@ -14,7 +10,7 @@ matrix: env: DB=PGSQL RECIPE_VERSION=4.2.x-dev PHPUNIT_COVERAGE_TEST=1 - php: 7.2 env: DB=MYSQL RECIPE_VERSION=4.3.x-dev PHPUNIT_TEST=1 - - php: 7.2 + - php: 7.3 env: DB=MYSQL RECIPE_VERSION=4.x-dev PHPUNIT_TEST=1 before_script: @@ -22,7 +18,7 @@ before_script: - phpenv config-rm xdebug.ini - composer validate - - composer require silverstripe/recipe-core "$RECIPE_VERSION" --no-update + - composer require silverstripe/recipe-cms:"$RECIPE_VERSION" --no-update - if [[ $DB == PGSQL ]]; then composer require silverstripe/postgresql:2.1.x-dev --no-update; fi - composer install --prefer-dist --no-interaction --no-progress --no-suggest --optimize-autoloader --verbose --profile From 088e7f16a81fb07d789f665958dcfec1336398dd Mon Sep 17 00:00:00 2001 From: Ivo Bathke Date: Tue, 26 Feb 2019 08:37:12 +0100 Subject: [PATCH 7/7] FIX Fixed unload modal in GridFieldConfigurablePaginator --- src/GridFieldConfigurablePaginator.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/GridFieldConfigurablePaginator.php b/src/GridFieldConfigurablePaginator.php index 3655ae9..54e5c7d 100644 --- a/src/GridFieldConfigurablePaginator.php +++ b/src/GridFieldConfigurablePaginator.php @@ -290,33 +290,34 @@ class GridFieldConfigurablePaginator extends GridFieldPaginator 'title' => 'First', 'args' => array('first-shown' => 1), 'extra-class' => 'btn btn-secondary btn--hide-text btn-sm font-icon-angle-double-left ' - . 'ss-gridfield-firstpage', + . 'ss-gridfield-pagination-action ss-gridfield-firstpage', 'disable-previous' => ($this->getCurrentPage() == 1) ), 'prev' => array( 'title' => 'Previous', 'args' => array('first-shown' => $arguments['first-shown'] - $this->getItemsPerPage()), 'extra-class' => 'btn btn-secondary btn--hide-text btn-sm font-icon-angle-left ' - . 'ss-gridfield-previouspage', + . 'ss-gridfield-pagination-action ss-gridfield-previouspage', 'disable-previous' => ($this->getCurrentPage() == 1) ), 'next' => array( 'title' => 'Next', 'args' => array('first-shown' => $arguments['first-shown'] + $this->getItemsPerPage()), - 'extra-class' => 'btn btn-secondary btn--hide-text btn-sm font-icon-angle-right ss-gridfield-nextpage', + 'extra-class' => 'btn btn-secondary btn--hide-text btn-sm font-icon-angle-right ' + .'ss-gridfield-pagination-action ss-gridfield-nextpage', 'disable-next' => ($this->getCurrentPage() == $arguments['total-pages']) ), 'last' => array( 'title' => 'Last', 'args' => array('first-shown' => ($this->getTotalPages() - 1) * $this->getItemsPerPage() + 1), 'extra-class' => 'btn btn-secondary btn--hide-text btn-sm font-icon-angle-double-right ' - . 'ss-gridfield-lastpage', + . 'ss-gridfield-pagination-action ss-gridfield-lastpage', 'disable-next' => ($this->getCurrentPage() == $arguments['total-pages']) ), 'pagesize' => array( 'title' => 'Page Size', 'args' => array('first-shown' => $arguments['first-shown']), - 'extra-class' => 'ss-gridfield-pagesize-submit' + 'extra-class' => 'ss-gridfield-pagination-action ss-gridfield-pagesize-submit' ), );