How to approach input and output conversion in Expressive?

Say your end-point middleware action receives input in English unit system (via POST), but all your internal computations are written with the Metric system in mind. So, you need to convert the input into Metric for for the computational engine to work correctly. And the results received from that engine need to be converted back into English system for the view template, to display back to the user.

How would you approach that in Expressive?

This question is probably more of general OO than Expressive but I am curious if Expressive has any provisions for this. Or I wonder if Zend Form has some facilities for this as well.

My naive approach is to create a service that contains conversion methods, and inject that service into my end-point middleware. And I have a choice of either making that service task-specific (convert my business-specific Form data explicitly), or more general (a library of conversion methods to which I pass the values I wish to convert).

You’re onto something with the zend-form idea. Also take a look at zend-inputfilter and zend-filter.

While slightly different, zend-validator is certainly worth mentioning as well.

Looking at zend-inputfilter and zend-filter, how would I make it conditional?

I have created a ConversionFilter, that will convert a given value from one system to the other, but if I specify it as part of the form, it will do so all the time, and I only need to convert when my form unit_system element is set to English, and do nothing when it’s in Metric.

zend-validator may not exactly help here as I need conversion and actual modification of value. I do not see validation helping in that regard.

For example, consider form code below. How can I engage the InputFilter to engage ConversionFilter ONLY when unit_system element value equals to English?

//main form
class RequestForm extends Form
{
    public function __construct()
    {
        parent::__construct("request_form");
        $this->setHydrator(new ClassMethods(false));
        $this->setInputFilter(new InputFilter());
        
        $this->add(array(
            'type' => RequestFieldset::class,
            'name' => 'request_fieldset'
        ));
    }
}

//fieldset with unit_system select and flow_rate to be converted
class RequestFieldset extends Fieldset implements InputFilterProviderInterface
{
    public function __construct()
    {
        parent::__construct("request_fieldset");
        $this->add(array(
            'type' => Element\Select::class,
            'name' => 'unit_system',
            'options' => array(
                'value_options' => array(
                    'English' => 'English',
                    'Metric' => 'Metric'
                )
            )
        ));
        
        $this->add(array(
            'type' => Element\Number::class,
            'name' => 'flow_rate'
        ));
    }

    public function getInputFilterSpecification()
    {
        return [
            'flow_rate' => [
                'required' => true,
                'filters' => [
                    [
                        'name' => GallonsPerMinuteFilter::class
                    ]
                ]
            ]
        ];
    }
}

//my conversion filter which I want to use ONLY when English system is selected
class GallonsPerMinuteFilter implements FilterInterface
{
    public function filter($value)
    {
         //converts value from assumed from gallons per minute to m^3/h
        return $value * 0.22712470704;
    }
}