public function updateTotals()
    {
        foreach ($this->totals_plan as $key => $val) {

            // if value is array, then we treat it as built-in or callable aggregate method
            if (is_array($val)) {
                $f = $val[0]; // shortcut

                // initial value is always 0
                if (!isset($this->totals[$key])) {
                    $this->totals[$key] = 0;
                }

                // closure support
                // arguments - current value, key, \atk4\ui\Table object
                if ($f instanceof \Closure) {
                    $this->totals[$key] += ($f($this->model[$key], $key, $this) ?: 0);
                }
                // built-in methods
                elseif (is_string($f)) {
                    switch ($f) {
                        case 'sum':
                            $this->totals[$key] += $this->model[$key];
                            break;
                        case 'count':
                            $this->totals[$key] += 1;
                            break;
                        case 'min':
                            if ($this->model[$key] < $this->totals[$key]) {
                                $this->totals[$key] = $this->model[$key];
                            }
                            break;
                        case 'max':
                            if ($this->model[$key] > $this->totals[$key]) {
                                $this->totals[$key] = $this->model[$key];
                            }
                            break;
                        default:
                            throw new Exception(['Aggregation method does not exist', 'method' => $f]);
                    }
                }
            }
        }
    }