Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENH Scaffold TaxonomyTerm with searchable dropdown #119

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 61 additions & 23 deletions src/TaxonomyTerm.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,21 @@

namespace SilverStripe\Taxonomy;

use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\FormField;
use SilverStripe\Forms\GridField\GridField;
use SilverStripe\ORM\HasManyList;
use Symbiote\GridFieldExtensions\GridFieldOrderableRows;
use UndefinedOffset\SortableGridField\Forms\GridFieldSortableRows;
use SilverStripe\ORM\Hierarchy\Hierarchy;
use SilverStripe\Forms\GridField\GridFieldDeleteAction;
use SilverStripe\Forms\GridField\GridFieldAddExistingAutocompleter;
use SilverStripe\Forms\GridField\GridFieldConfig_RelationEditor;
use SilverStripe\Forms\NumericField;
use SilverStripe\Forms\SearchableMultiDropdownField;
use SilverStripe\Security\Permission;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\FieldType\DBForeignKey;
use SilverStripe\Security\PermissionProvider;

/**
Expand Down Expand Up @@ -63,33 +69,33 @@ class TaxonomyTerm extends DataObject implements PermissionProvider

public function getCMSFields()
{
$fields = parent::getCMSFields();
$this->beforeUpdateCMSFields(function (FieldList $fields) {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrapping the implementation in beforeUpdateCMSFields() is best practice. This is partially unrelated refactoring, but it also is necessary to make sure the Children field is a gridfield before extension hooks fire, which will keep those functioning the same before and after this change.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All other changes to this method (unless otherwise stated) are just explicitly using a GridField for the Children relation, instead of the auto-scaffolded searchable dropdown.

// For now moving taxonomy terms is not supported. We also want to entirely rebuild the Children field.
$fields->removeByName(['ParentID', 'Sort', 'Children']);

// For now moving taxonomy terms is not supported.
$fields->removeByName('ParentID');
$fields->removeByName('Sort');

// Child taxonomy terms don't need to choose a type, it is inherited
if ($this->config()->get('type_inheritance_enabled') && $this->getTaxonomy() !== $this) {
$fields->removeByName('TypeID');
}

$childrenGrid = $fields->dataFieldByName('Children');
if ($childrenGrid) {
$deleteAction = $childrenGrid->getConfig()->getComponentByType(GridFieldDeleteAction::class);
$addExistingAutocompleter = $childrenGrid
->getConfig()
->getComponentByType(GridFieldAddExistingAutocompleter::class);
// Child taxonomy terms don't need to choose a type, it is inherited
if ($this->config()->get('type_inheritance_enabled') && $this->getTaxonomy() !== $this) {
$fields->removeByName('TypeID');
}

$childrenGrid->getConfig()->removeComponent($addExistingAutocompleter);
$childrenGrid->getConfig()->removeComponent($deleteAction);
$childrenGrid->getConfig()->addComponent(new GridFieldDeleteAction(false));
$childrenConfig = GridFieldConfig_RelationEditor::create();
$childrenGrid = GridField::create(
'Children',
$this->fieldLabel('Children'),
$this->Children(),
$childrenConfig
);
$deleteAction = $childrenConfig->getComponentByType(GridFieldDeleteAction::class);
$addExistingAutocompleter = $childrenConfig->getComponentByType(GridFieldAddExistingAutocompleter::class);
$childrenConfig->removeComponent($addExistingAutocompleter);
$childrenConfig->removeComponent($deleteAction);
$childrenConfig->addComponent(GridFieldDeleteAction::create(false));

// Setup sorting of TaxonomyTerm siblings, and fall back to a manual NumericField if no sorting is possible
if (class_exists(GridFieldOrderableRows::class)) {
$childrenGrid->getConfig()->addComponent(GridFieldOrderableRows::create('Sort'));
$childrenConfig->addComponent(GridFieldOrderableRows::create('Sort'));
} elseif (class_exists(GridFieldSortableRows::class)) {
$childrenGrid->getConfig()->addComponent(new GridFieldSortableRows('Sort'));
$childrenConfig->addComponent(GridFieldSortableRows::create('Sort'));
} else {
$fields->addFieldToTab(
'Root.Main',
Expand All @@ -99,9 +105,41 @@ public function getCMSFields()
)
);
}
}
$fields->addFieldToTab('Root.Children', $childrenGrid);
});

return parent::getCMSFields();
}

public function scaffoldFormFieldForHasMany(
string $relationName,
?string $fieldTitle,
DataObject $ownerRecord,
bool &$includeInOwnTab
): FormField {
$includeInOwnTab = false;
return $this->scaffoldFormFieldForManyRelation($relationName, $fieldTitle);
}

return $fields;
public function scaffoldFormFieldForManyMany(
string $relationName,
?string $fieldTitle,
DataObject $ownerRecord,
bool &$includeInOwnTab
): FormField {
$includeInOwnTab = false;
return $this->scaffoldFormFieldForManyRelation($relationName, $fieldTitle);
}

private function scaffoldFormFieldForManyRelation(string $relationName, ?string $fieldTitle): FormField
{
$list = static::get();
$field = SearchableMultiDropdownField::create($relationName, $fieldTitle, $list, labelField: 'Name');
// Use the same lazyload threshold has_one relations use
$threshold = DBForeignKey::config()->get('dropdown_field_threshold');
$overThreshold = $list->count() > $threshold;
$field->setIsLazyLoaded($overThreshold)->setLazyLoadLimit($threshold);
return $field;
}

/**
Expand Down
Loading