1<?php
2// (c) Copyright by authors of the Tiki Wiki CMS Groupware Project
3//
4// All Rights Reserved. See copyright.txt for details and a complete list of authors.
5// Licensed under the GNU LESSER GENERAL PUBLIC LICENSE. See license.txt for details.
6// $Id$
7
8class Math_Formula_Function_Subtotal extends Math_Formula_Function
9{
10	function evaluate($element)
11	{
12		$allowed = ['list', 'group', 'aggregate', 'separators', 'formula'];
13
14		if ($extra = $element->getExtraValues($allowed)) {
15			$this->error(tr('Unexpected values: %0', implode(', ', $extra)));
16		}
17
18		$list = $element->list;
19		if (! $list || count($list) != 1) {
20			$this->error(tra('Field must be provided and contain one argument: list'));
21		}
22		$list = $this->evaluateChild($list[0]);
23
24		$group = $element->group;
25		if (! $group || count($group) != 1) {
26			$this->error(tra('Field must be provided and contain one argument: group.'));
27		}
28		$group = $group[0];
29
30		$aggregate = $element->aggregate;
31		if (! $aggregate || count($aggregate) < 1) {
32			$this->error(tra('Field must be provided and contain at least one argument: aggregate.'));
33		}
34
35		$separators = $element->separators;
36		if (! $separators || count($separators) != 2) {
37			$separators = ["|", "\n"];
38		} else {
39			$separators = [$this->evaluateChild($separators[0]), $this->evaluateChild($separators[1])];
40		}
41
42		$formula = $element->formula;
43		if (! $formula) {
44			$formula = [];
45		}
46
47		$out = [];
48
49		// group values by field
50		if (is_array($list)) {
51			foreach ($list as $values) {
52				if (! isset($values[$group])) {
53					continue;
54				}
55				$group_value = trim($values[$group]);
56				if (! isset($out[$group_value])) {
57					$out[$group_value] = ['group' => $group_value];
58					foreach ($aggregate as $position => $field) {
59						$out[$group_value][$position] = [];
60					}
61				}
62				foreach ($aggregate as $position => $field) {
63					if (is_string($field) && !isset($values[$field])) {
64						$value = 0;
65					} else {
66						$value = $this->evaluateChild($field, $values);
67					}
68					$out[$group_value][$position][] = $value;
69				}
70			}
71		}
72
73		// evaluate aggregate function for each field
74		foreach ($out as $group_value => $rows) {
75			foreach ($aggregate as $position => $field) {
76				$function = str_replace(' ', '', ucwords(str_replace('-', ' ', $formula[$position] ?? 'add')));
77				$class = 'Math_Formula_Function_'.$function;
78				if (class_exists($class)) {
79					$op = new $class;
80					$out[$group_value][$position] = $op->evaluateTemplate($rows[$position], function($child) { return $child; });
81				}
82			}
83		}
84
85		return implode($separators[1], array_map(function($row) use ($separators) {
86			return implode($separators[0], $row);
87		}, $out));
88	}
89}
90