SubForeachMapper
Applies its inner mappers to each element of an array (or Traversable) bindable value. Mappers::subForeach() takes Mapper or Validator arguments — the same arguments Mappers::pipe() accepts — and runs them as a pipe on every element individually. Each element is exposed as its own bindable, keyed by the array key.
It is applied with ->prop(...) (or ->props(...)). Only the elements present in the array are mapped; the array shape itself is preserved.
Mappers::subForeach()is the per-element companion toMappers::subProps()(which maps the named children of a structure). It is typically followed byMappers::subMerge()to reassemble the mapped elements into an array — the combinationsubForeach+subMerge+Mappers::value()is whatTypedArrayUnmarshalTraituses to build typed arrays of value objects. See UnmarshalMapper.
Example: transforming each element
$src = new DataMap(['huii' => ['key1' => 'value1', 'key2' => 'value2']]);
$target = new DataMap();
Bind::attrs($src)->toAttrs($target)
->prop('huii', Mappers::subForeach(Mappers::value(fn (string $v) => $v . '-m')))
->exec();
echo $target->req('huii/key1'); // value1-m
echo $target->req('huii/key2'); // value2-m
Example: validating each element
$result = Bind::attrs(['emails' => ['bad1', 'bad2']])
->prop('emails', Mappers::subForeach(Mappers::email()))
->toArray()
->exec();
// result is invalid with an error for each array element.
var_dump($result->isValid()); // false
var_dump($result->getErrorMap()->getChild('emails')->isEmpty()); // false
var_dump($result->getErrorMap()->getChild('emails')->getChild(0)->isEmpty()); // false
var_dump($result->getErrorMap()->getChild('emails')->getChild(1)->isEmpty()); // false