Motivation
DataField->items is a public array, so consumers can reorder children directly — but it's clunky:
```php
// Move 'phone' to the front
$items = array_filter($df->items, fn ($i) => $i->key !== 'phone');
$df->items = [$df->phone, ...array_values($items)];
```
A helper would read much better. Tracking as an issue rather than implementing now because the right shape depends on real-world usage.
Design options
Numeric position only
```php
$df->moveField('phone', 0); // to index 0
$df->moveField('phone', -1); // to end (Python-style)
```
Simple. Doesn't cover the common "after another sibling" intent without an extra indexOf() lookup.
Sibling-relative
```php
$df->moveField('phone', before: 'email');
$df->moveField('phone', after: 'address');
```
Reads well at the call site. Both keyword args (before / after) are mutually exclusive — needs validation. Doesn't cover "move to absolute position".
Hybrid
```php
$df->moveField('phone', 0); // by index
$df->moveField('phone', before: 'email'); // by sibling
$df->moveField('phone', after: 'address'); // by sibling
```
Most flexible. Slight API surface bloat.
Error semantics
- Missing target key (
moveField('phone', before: 'no_such_key')): throw InvalidArgumentException.
- Missing moved key (
moveField('no_such_key', 0)): throw InvalidArgumentException.
- Container vs leaf: throw
LogicException on leaves (consistent with addField / removeField).
- Container in cast mode only — row mode reorders via the
sort_order column.
Open questions
- Should this only operate on direct children, or also accept dotted paths (
moveField('appearance.dark_mode', 0))?
- Worth a fluent return (
$df->moveField(...)->moveField(...)) — probably yes, matches addField / removeField.
When to do it
Defer until at least one consumer hits the friction so we know what shape they actually need. Until then, direct \$df->items manipulation works.
Related
Surfaced during 0.4.0 review as a nice-to-have. Not blocking.
Motivation
DataField->itemsis a public array, so consumers can reorder children directly — but it's clunky:```php
// Move 'phone' to the front
$items = array_filter($df->items, fn ($i) => $i->key !== 'phone');
$df->items = [$df->phone, ...array_values($items)];
```
A helper would read much better. Tracking as an issue rather than implementing now because the right shape depends on real-world usage.
Design options
Numeric position only
```php
$df->moveField('phone', 0); // to index 0
$df->moveField('phone', -1); // to end (Python-style)
```
Simple. Doesn't cover the common "after another sibling" intent without an extra
indexOf()lookup.Sibling-relative
```php
$df->moveField('phone', before: 'email');
$df->moveField('phone', after: 'address');
```
Reads well at the call site. Both keyword args (before / after) are mutually exclusive — needs validation. Doesn't cover "move to absolute position".
Hybrid
```php
$df->moveField('phone', 0); // by index
$df->moveField('phone', before: 'email'); // by sibling
$df->moveField('phone', after: 'address'); // by sibling
```
Most flexible. Slight API surface bloat.
Error semantics
moveField('phone', before: 'no_such_key')): throwInvalidArgumentException.moveField('no_such_key', 0)): throwInvalidArgumentException.LogicExceptionon leaves (consistent withaddField/removeField).sort_ordercolumn.Open questions
moveField('appearance.dark_mode', 0))?$df->moveField(...)->moveField(...)) — probably yes, matchesaddField/removeField.When to do it
Defer until at least one consumer hits the friction so we know what shape they actually need. Until then, direct
\$df->itemsmanipulation works.Related
Surfaced during 0.4.0 review as a nice-to-have. Not blocking.