@@ -98,53 +98,7 @@ $table->addColumn('price');
9898When invoking addColumn, you have a great control over the field properties and decoration. The format
9999of addColumn() is very similar to {php: meth }` Form::addControl ` .
100100
101- ## Calculations
102-
103- Apart from adding columns that reflect current values of your database, there are several ways
104- how you can calculate additional values. You must know the capabilities of your database server
105- if you want to execute some calculation there. (See https://atk4-data.readthedocs.io/en/develop/expressions.html )
106-
107- It's always a good idea to calculate column inside database. Lets create "total" column which will
108- multiply "price" and "amount" values. Use ` addExpression ` to provide in-line definition for this
109- field if it's not already defined in ` Order::init() ` :
110-
111- ```
112- $table = Table::addTo($app);
113- $order = new Order($db);
114-
115- $order->addExpression('total', '[price] * [amount]')->type = 'atk4_money';
116-
117- $table->setModel($order, ['name', 'price', 'amount', 'total', 'status']);
118- ```
119-
120- The type of the Model Field determines the way how value is presented in the table. I've specified
121- value to be 'atk4_money' which makes column align values to the right, format it with 2 decimal signs
122- and possibly add a currency sign.
123-
124- To learn about value formatting, read documentation on {ref}` uiPersistence ` .
125-
126- Table object does not contain any information about your fields (such as captions) but instead it will
127- consult your Model for the necessary field information. If you are willing to define the type but also
128- specify the caption, you can use code like this:
129-
130- ```
131- $table = Table::addTo($app);
132- $order = new Order($db);
133-
134- $order->addExpression('total', [
135- '[price]*[amount]',
136- 'type' => 'atk4_money',
137- 'caption' => 'Total Price',
138- ]);
139-
140- $table->setModel($order, ['name', 'price', 'amount', 'total', 'status']);
141- ```
142-
143- ### Column Objects
144-
145- To read more about column objects, see {ref}` tablecolumn `
146-
147- ### Advanced Column Denifitions
101+ ### Column Denifition
148102
149103Table defines a method ` columnFactory ` , which returns Column object which is to be used to
150104display values of specific model Field.
@@ -235,6 +189,68 @@ $table->addColumn($colGap);
235189
236190This will result in 3 gap columns rendered to the left, middle and right of your Table.
237191
192+ ## Calculated Fields
193+
194+ Apart from adding columns that reflect current values of your database, there are several ways
195+ how you can calculate additional values. You must know the capabilities of your database server
196+ if you want to execute some calculation there. (See https://atk4-data.readthedocs.io/en/develop/expressions.html )
197+
198+ ### In the database - best performance
199+
200+ It's always a good idea to calculate column inside database. Lets create "total" column which will
201+ multiply "price" and "amount" values. Use ` addExpression ` to provide in-line definition for this
202+ field if it's not alrady defined in ` Order::init() ` :
203+
204+ ```
205+ $table = $app->add('Table');
206+ $order = new Order($db);
207+
208+ $order->addExpression('total', [
209+ '[price] * [amount]',
210+ 'type' => 'money',
211+ ]);
212+
213+ $table->setModel($order, ['name', 'price', 'amount', 'total', 'status']);
214+ ```
215+
216+ ### In the model - best compatibility
217+
218+ If your database does not have the capacity to perform calculations, e.g. you are using NoSQL with
219+ no support for expressions, the solution is to calculate value in the PHP:
220+
221+ ```
222+ $table = $app->add('Table');
223+ $order = new Order($db);
224+
225+ $model->addField('total', [
226+ 'Callback',
227+ function ($m) {
228+ return $m['price'] * $m['amount'];
229+ },
230+ 'type' => 'money',
231+ ]);
232+
233+ $table->setModel($order, ['name', 'price', 'amount', 'total', 'status']);
234+ ```
235+
236+ ### Alternative approaches
237+
238+ :::{warning} Those alternatives are for special cases, when you are unable to perform calculation
239+ in the database or in the model. Please use with caution.
240+ ::
241+
242+ You can add add a custom code that performs formatting within the table through a hook:
243+
244+ ```
245+ $table->addField('no');
246+
247+ $table->addHook('beforeRow', function($table)) {
248+ $table->model['no'] = @++$t->npk;
249+ }
250+ ```
251+
252+ To read more about column objects, see {ref}` tablecolumn `
253+
238254## Table sorting
239255
240256:::{php: attr } sortable
@@ -453,6 +469,75 @@ getDataCellHtml can be left as-is and will be handled correctly. If you have ove
453469getDataCellHtml only, then your column will still work OK provided that it's used as a
454470last decorator.
455471
472+ ## Table Totals
473+
474+ :::{php: attr } totals_plan
475+ :::
476+ :::{php: attr } totals
477+ :::
478+ :::{php: method } addTotals()
479+ :::
480+
481+
482+ Table implements a built-in handling for the "Totals" row. Simple usage would be:
483+
484+ ```
485+ $table->addTotals();
486+ ```
487+
488+ but here is what actually happens:
489+
490+ 1 . when calling addTotals() - you define a total calculation plan.
491+ 2 . while iterating through table, totals are accumulated / modified according to plan.
492+ 3 . when table finishes with the rows, it adds yet another row with the accumulated values.
493+
494+ :::{important} addTotals() will only calculate based on rendered rows. If your table has limit
495+ or uses {php: class }` Paginator ` you should calculate totals differently. See {php: meth }` Grid::addGrandTotals `
496+ ::
497+
498+ ### Definition of a "totals plan"
499+
500+ Each column may have a different plan, which consists of stages:
501+
502+ - init: defines the initial value
503+ - update: defines how value is updated
504+ - format: defines how value is formatted before outputting
505+
506+ Here is the plan to calculate number of records:
507+
508+ ```
509+ $table->addTotals(['client' => [
510+ 'init' => 0,
511+ 'update' => 'increment',
512+ 'format' => 'Totals for {$client} client(s)',
513+ ]);
514+ ```
515+
516+ To make things easier to define, each stage has a reasonable default:
517+
518+ - init: set to 0
519+ - update: 'sum' for numeric/money type and 'increment' otherwise
520+ - format: will output '-' by default
521+
522+ Also when calling addTotals() the column plan value does not have to be array, in which case the 'format'
523+ is set. The above example can therefore be shortened:
524+
525+ ```
526+ $table->addTotals(['client' => 'Totals for {$clients} client(s)']);
527+ ```
528+
529+ ### Possible values for total plan stages
530+
531+ ` init ` value is typically a number, but can be any value, especially if you are going to control it's
532+ increment / formatting.
533+
534+ ` update ` can be string - either "sum" or "increment". Other values are not supported. You can also pass
535+ a callable which gives you an option to perform update yourself.
536+
537+ ` format ` uses a template in a format suitable for {php: class }` Template ` . Within the template you can
538+ reference other fields too. A benefit for using template is that type formatting is done automatically
539+ for you.
540+
456541## Advanced Usage
457542
458543Table is a very flexible object and can be extended through various means. This chapter will focus
0 commit comments