Calculated property

public function calculateAge(): ?float
{
    // calculation of age (today - month of manufacture)
    $manufacturemonth = $this->getProperty('manufacture_month'); // DateProperty object
    $manufacturemonth_year_month = $manufacturemonth->getValue(); // "2026-01"
    if (!$manufacturemonth_year_month)
        return null;
    $temp = new DateTime($manufacturemonth_year_month); // DateTime object. Let's take the 1st or that month.
    $today = new \Datetime(); // DateTime object / today by default
    $diff = $today->diff($temp); // calculate the difference between manu-date and today

    // for leasing contracts we usually calculate months like 48.
    return $diff->y * 12 + $diff->m; // let's forget about the days. We don't even know exact manuf-date, only month.
}

Now, in getAdditionalProperties() we can create a new property which automatically calculates its' value:

(new NumericPropertyCalculated('age', fn() => $this->calculateAge()))
    ->label("Vehicle age in months"),

This is the complete getAdditionalProperties() function

protected function getAdditionalProperties(): array
{
    return [
        (new StringProperty("licenseplate"))->required(),
        (new StringProperty("chassisnumber"))->required(),

        // simple lookup list for now (array or models) 
        (new SelectProperty("model", [
            'Audi A4',
            'Audi A6',
            'Audi A8',
        ]))->required(),
        (new MonthProperty("manufacture_month")),
        (new NumericPropertyCalculated('age', fn() => $this->calculateAge()))->label("Vehicle age in months"),
        (new MonthProperty("purchase_month")),
        (new NumericWithUnitProperty("purchase_mileage", ['km', 'ml'], 'km', 1, false)),
    ];
}

Save the file and reload your page:

alt text

We care for layout later. For the moment, let us concentrate on the model.

Now that we have a calculated age field, we can use the result in list view label. We can evaluate the age-property for each Vehicle object.

1
2
3
4
5
/**
 * @var NumericPropertyCalculated
 */
$age = $this->getProperty('age');
$age_value = $age ? $age->calculate($this) : null;

This is the complete function:

public function getLabelHtml(): string
{
    $diff_months = $this->calculateAge();
    // gather our data
    $model = $this->getProperty('model');
    $month = $this->getProperty('manufacture_month');

    /**
     * @var NumericPropertyCalculated
     */
    $age = $this->getProperty('age');
    $age_value = $age ? $age->calculate($this) : null;

    $details = [
        $model?->toDisplayValue(),
        $month?->toDisplayValue(),
        ($age_value ? "{$age_value} months" : ''),
    ];
    $details = array_filter($details);// remove empty entries

    // create a tile
    \System\UI\Output::use(); // important for autoloading
    $tile = new \System\UI\Output\Elements\Tile('car', $this->licenseplate);
    if ($details)
        $tile->subtitle = implode(' • ', $details);
    return $tile;
}

And still we see the calculated age in list view:

alt text