Skip to content

Commit e0a40e4

Browse files
committed
Added sorting of options and weight property. Fixes #18.
1 parent 76d43e7 commit e0a40e4

File tree

6 files changed

+149
-18
lines changed

6 files changed

+149
-18
lines changed

Definition/DataDefinition.php

Lines changed: 52 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ class DataDefinition implements PropertyListInterface {
9292

9393
protected $options = NULL;
9494

95+
protected ?OptionsSortOrder $optionsOrder = NULL;
96+
9597
protected $validators = [];
9698

9799
/**
@@ -698,6 +700,11 @@ public function setOptionsArray(array $options_array): self {
698700
return $this;
699701
}
700702

703+
public function setOptionsSorting(OptionsSortOrder $order): self {
704+
$this->optionsOrder = $order;
705+
return $this;
706+
}
707+
701708
public function hasOptions(): bool {
702709
return !empty($this->options) || !empty($this->optionSet);
703710
}
@@ -708,19 +715,61 @@ public function hasOptions(): bool {
708715
* These can be either the options set directly on this definition, or
709716
* obtained dynamically from an option set definition.
710717
*
718+
* The options are returned sorted by option weight, and then the sort order
719+
* set on this definition. If not specified, this defaults to the order in
720+
* which the options were added to the definition.
721+
*
711722
* @return \MutableTypedData\Definition\OptionDefinition[]
712723
* An array of option definitions, keyed by the option values.
713724
*/
714725
public function getOptions(): array {
715726
if ($this->optionSet) {
716-
return $this->optionSet->getOptions();
727+
$options = $this->optionSet->getOptions();
717728
}
718729
elseif ($this->options) {
719-
return $this->options;
730+
$options = $this->options;
720731
}
721732
else {
722-
return [];
733+
$options = [];
734+
}
735+
736+
$options_sorting = $this->getOptionsSorting() ?? OptionsSortOrder::Original;
737+
738+
if ($options_sorting == OptionsSortOrder::Original) {
739+
// Get the order in which the items were added to the options array in the
740+
// definition (or in which they're returned from the option set definition).
741+
// This is an array of all option values, keyed by the option value, whose
742+
// values are increasing integers.
743+
$added_order = array_flip(array_keys($options));
744+
745+
uasort($options, function ($a, $b) use ($added_order) {
746+
// Options with the same weight are sorted by the order they were added
747+
// to the options array.
748+
if ($a->getWeight() == $b->getWeight()) {
749+
return $added_order[$a->getValue()] <=> $added_order[$b->getValue()];
750+
}
751+
else {
752+
return $a->getWeight() <=> $b->getWeight();
753+
}
754+
});
723755
}
756+
elseif ($options_sorting == OptionsSortOrder::Label) {
757+
uasort($options, function ($a, $b) {
758+
// Options with the same weight are sorted by label.
759+
if ($a->getWeight() == $b->getWeight()) {
760+
return strcmp($a->getLabel(), $b->getLabel());
761+
}
762+
else {
763+
return $a->getWeight() <=> $b->getWeight();
764+
}
765+
});
766+
}
767+
768+
return $options;
769+
}
770+
771+
public function getOptionsSorting(): ?OptionsSortOrder {
772+
return $this->optionsOrder;
724773
}
725774

726775
public function setValidators(string ...$validators): self {

Definition/OptionDefinition.php

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,22 @@ class OptionDefinition {
2828
*/
2929
protected $description = '';
3030

31-
public function __construct($value, $label, $description = NULL) {
31+
/**
32+
* An optional weight for sorting the option.
33+
*
34+
* @var int
35+
*/
36+
protected $weight = 0;
37+
38+
public function __construct($value, $label, $description = NULL, int $weight = 0) {
3239
$this->value = $value;
3340
$this->label = $label;
3441
if ($description) {
3542
$this->description = $description;
3643
}
44+
if ($weight) {
45+
$this->weight = $weight;
46+
}
3747
}
3848

3949
/**
@@ -45,11 +55,15 @@ public function __construct($value, $label, $description = NULL) {
4555
* The label that is shown by UIs to the user.
4656
* @param string $description
4757
* (optional) Additional text to show to the user in UIs.
58+
* @param int $weight
59+
* (optional) The weight for sorting the option in the list. Larger numbers
60+
* are heavier and sink to the bottom. Options with identical weights are
61+
* shown in the sort order defined by the data definition.
4862
*
4963
* @return static
5064
*/
51-
public static function create($value, string $label, string $description = NULL): self {
52-
return new static($value, $label, $description);
65+
public static function create($value, string $label, string $description = NULL, int $weight = 0): self {
66+
return new static($value, $label, $description, $weight);
5367
}
5468

5569
public function getValue() {
@@ -64,4 +78,8 @@ public function getDescription() {
6478
return $this->description;
6579
}
6680

81+
public function getWeight(): int {
82+
return $this->weight;
83+
}
84+
6785
}

Definition/OptionsSortOrder.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
namespace MutableTypedData\Definition;
4+
5+
/**
6+
* Defines the possible values for options sort order.
7+
*
8+
* Option weight always overrides this order. In other words, the order defined
9+
* with this value only applies to options of the same weight.
10+
*/
11+
enum OptionsSortOrder {
12+
13+
/**
14+
* Options are sorted in the order in which they were added to the definition.
15+
*/
16+
case Original;
17+
18+
/**
19+
* Options are sorted by their label.
20+
*/
21+
case Label;
22+
23+
}

README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ $definition = \MutableTypedData\Definition\DataDefinition::create('complex')
227227
### Options
228228

229229
Options can be defined with an array, or with objects, which allow options to
230-
have descriptions as well as labels:
230+
have descriptions and weights as well as labels:
231231

232232
```
233233
$definition = \MutableTypedData\Definition\DataDefinition::create('string')
@@ -243,10 +243,13 @@ $definition = \MutableTypedData\Definition\DataDefinition::create('string')
243243
->setOptions(
244244
\MutableTypedData\Definition\OptionDefinition::create('green', 'Emerald', 'A lovely shade of green'),
245245
\MutableTypedData\Definition\OptionDefinition::create('red', 'Magenta', 'A deep red'),
246-
\MutableTypedData\Definition\OptionDefinition::create('grey', 'Grey', 'Not very colourful')
246+
\MutableTypedData\Definition\OptionDefinition::create('grey', 'Grey', 'Not very colourful but shows at the top', -10)
247247
);
248248
```
249249

250+
Higher-valued weights 'sink' to the bottom of a list of options; lower-valued
251+
weights are lighter and 'rise' up.
252+
250253
### Mutable data
251254

252255
Mutable data needs a single property to control the variants, and then a

Test/fixtures/Definition/SerializationTestDefinition.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use MutableTypedData\Definition\DefaultDefinition;
77
use MutableTypedData\Definition\DefinitionProviderInterface;
88
use MutableTypedData\Definition\OptionDefinition;
9+
use MutableTypedData\Definition\OptionsSortOrder;
910
use MutableTypedData\Definition\DataDefinition;
1011
use MutableTypedData\Definition\VariantDefinition;
1112

@@ -15,6 +16,12 @@ public static function getDefinition(): DataDefinition {
1516
$definition = DataDefinition::create('complex')
1617
->setProperties([
1718
'one' => DataDefinition::create('string'),
19+
'string_with_options' => DataDefinition::create('string')
20+
->setOptionsArray([
21+
'option_one' => 'One',
22+
'option_two' => 'Two',
23+
])
24+
->setOptionsSorting(OptionsSortOrder::Label),
1825
'two' => DataDefinition::create('complex')
1926
->setProperties([
2027
'alpha' => DataDefinition::create('string'),

Test/src/DataDefinitionTest.php

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use MutableTypedData\DataItemFactory;
66
use MutableTypedData\Definition\DataDefinition;
7+
use MutableTypedData\Definition\OptionsSortOrder;
78
use PHPUnit\Framework\TestCase;
89

910
/**
@@ -84,16 +85,16 @@ public function testExceptions(callable $call) {
8485
*/
8586
public function testDefineChildProperties() {
8687
$definition = DataDefinition::create('complex')
87-
->setLabel('Label')
88-
->setRequired(TRUE)
89-
->setProperties([
90-
'alpha' => DataDefinition::create('string')
91-
->setLabel('Label')
92-
->setRequired(TRUE),
93-
'beta' => DataDefinition::create('string')
94-
->setLabel('Label')
95-
->setRequired(TRUE),
96-
]);
88+
->setLabel('Label')
89+
->setRequired(TRUE)
90+
->setProperties([
91+
'alpha' => DataDefinition::create('string')
92+
->setLabel('Label')
93+
->setRequired(TRUE),
94+
'beta' => DataDefinition::create('string')
95+
->setLabel('Label')
96+
->setRequired(TRUE),
97+
]);
9798

9899
$this->assertEquals(['alpha', 'beta'], array_keys($definition->getProperties()));
99100

@@ -112,4 +113,34 @@ public function testDefineChildProperties() {
112113
);
113114
}
114115

116+
/**
117+
* Test sorting of options.
118+
*/
119+
public function testOptionsOrder() {
120+
$definition = DataDefinition::create('string')
121+
->setOptions(
122+
\MutableTypedData\Definition\OptionDefinition::create('dull', 'Dull', weight: 10),
123+
\MutableTypedData\Definition\OptionDefinition::create('normal_zulu', 'Normal Zulu'),
124+
\MutableTypedData\Definition\OptionDefinition::create('normal_alpha', 'Normal Alpha'),
125+
\MutableTypedData\Definition\OptionDefinition::create('important', 'Important', weight: -10),
126+
);
127+
128+
$data = DataItemFactory::createFromDefinition($definition);
129+
$this->assertEquals([
130+
'important',
131+
'normal_zulu',
132+
'normal_alpha',
133+
'dull',
134+
], array_keys($data->getOptions()));
135+
136+
// Change the options to be sorted by label.
137+
$definition->setOptionsSorting(OptionsSortOrder::Label);
138+
$this->assertEquals([
139+
'important',
140+
'normal_alpha',
141+
'normal_zulu',
142+
'dull',
143+
], array_keys($data->getOptions()));
144+
}
145+
115146
}

0 commit comments

Comments
 (0)