@@ -88,52 +88,8 @@ You can also add individual column to your table::
8888When invoking addColumn, you have a great control over the field properties and decoration. The format
8989of addColumn() is very similar to :php:meth: `Form::addField `.
9090
91- Calculations
92- ============
93-
94- Apart from adding columns that reflect currrent values of your database, there are several ways
95- how you can calculate additional values. You must know the capabilities of your database server
96- if you want to execute some calculation there. (See http://agile-data.readthedocs.io/en/develop/expressions.html)
97-
98- It's always a good idea to calculate column inside datababase. Lets create "total" column which will
99- multiply "price" and "amount" values. Use ``addExpression `` to provide in-line definition for this
100- field if it's not alrady defined in ``Order::init() ``::
101-
102- $table = $app->add('Table');
103- $order = new Order($db);
104-
105- $order->addExpression('total', '[price]*[amount]')->type = 'money';
106-
107- $table->setModel($order, ['name', 'price', 'amount', 'total', 'status']);
108-
109- The type of the Model Field determines the way how value is presented in the table. I've specified
110- value to be 'money' which makes column align values to the right, format it with 2 decimal signs
111- and possibly add a currency sign.
112-
113- To learn about value formatting, read documentation on :ref: `ui_persistence `.
114-
115- Table object does not contain any information about your fields (such as captions) but instead it will
116- consult your Model for the necessary field information. If you are willing to define the type but also
117- specify the caption, you can use code like this::
118-
119- $table = $app->add('Table');
120- $order = new Order($db);
121-
122- $order->addExpression('total', [
123- '[price]*[amount]',
124- 'type'=>'money',
125- 'caption'=>'Total Price'
126- ]);
127-
128- $table->setModel($order, ['name', 'price', 'amount', 'total', 'status']);
129-
130- Column Objects
131- --------------
132-
133- To read more about column objects, see :ref: `tablecolumn `
134-
135- Advanced Column Denifitions
136- ---------------------------
91+ Column Definition
92+ =================
13793
13894Table defines a method `columnFactory `, which returns Column object which is to be used to
13995display values of specific model Field.
@@ -226,6 +182,66 @@ As a final note in this section - you can re-use column objects multiple times::
226182
227183This will result in 3 gap columns rendered to the left, middle and right of your Table.
228184
185+ Calculated Fields
186+ =================
187+
188+ Apart from adding columns that reflect currrent values of your database, there are several ways
189+ how you can calculate additional values. You must know the capabilities of your database server
190+ if you want to execute some calculation there. (See http://agile-data.readthedocs.io/en/develop/expressions.html)
191+
192+ In the database - best performance
193+ ----------------------------------
194+
195+ It's always a good idea to calculate column inside datababase. Lets create "total" column which will
196+ multiply "price" and "amount" values. Use ``addExpression `` to provide in-line definition for this
197+ field if it's not alrady defined in ``Order::init() ``::
198+
199+ $table = $app->add('Table');
200+ $order = new Order($db);
201+
202+ $order->addExpression('total', [
203+ '[price]*[amount]',
204+ 'type'=>'money'
205+ ]);
206+
207+ $table->setModel($order, ['name', 'price', 'amount', 'total', 'status']);
208+
209+ In the model - best compatibility
210+ ---------------------------------
211+
212+ If your database does not have the capacity to perform calculations, e.g. you are using NoSQL with
213+ no support for expressions, the solution is to calculate value in the PHP::
214+
215+ $table = $app->add('Table');
216+ $order = new Order($db);
217+
218+ $model->addField('total', [
219+ 'Callback',
220+ function($m) {
221+ return $m['price'] * $m['amount'];
222+ },
223+ 'type'=>'money'
224+ ]);
225+
226+ $table->setModel($order, ['name', 'price', 'amount', 'total', 'status']);
227+
228+ Alternative approaches
229+ ----------------------
230+
231+ .. warning :: Those alternatives are for special cases, when you are unable to perform calcualtion
232+ in the database or in the model. Please use with caution.
233+
234+ You can add add a custom code that performs formatting within the table through a hook::
235+
236+ $table->addField('no');
237+
238+ $table->addHook('beforeRow', function($table)) {
239+ $table->model['no'] = @++$t->npk;
240+ }
241+
242+ To read more about column objects, see :ref: `tablecolumn `
243+
244+
229245Table sorting
230246=============
231247
@@ -321,7 +337,7 @@ For most applications, however, you would be probably using internally defined m
321337data stored inside your own database. Either way, several principles apply to the way how Table works.
322338
323339Table Rendering Steps
324- --------------------
340+ ---------------------
325341
326342Once model is specified to the Table it will keep the object until render process will begin. Table
327343columns can be defined anytime and will be stored in the :php:attr: `Table::columns ` property. Columns
@@ -430,6 +446,71 @@ getDataCellHTML can be left as-is and will be handled correctly. If you have ove
430446getDataCellHTML only, then your column will still work OK provided that it's used as a
431447last decorator.
432448
449+ Table Totals
450+ ============
451+
452+ .. php :attr :: totals_plan
453+ .. php :attr :: totals
454+ .. php :method :: addTotals()
455+
456+
457+ Table implements a built-in handling for the "Totals" row. Simple usage would be::
458+
459+ $table->addTotals();
460+
461+ but here is what actually happens:
462+
463+ 1. when calling addTotals() - you define a total calculation plan.
464+ 2. while iterating through table, totals are accumulated / modified according to plan.
465+ 3. when table finishes with the rows, it adds yet another row with the accumulated values.
466+
467+ .. important :: addTotals() will only calculate based on rendered rows. If your table has limit
468+ or uses :php:class: `Paginator ` you should calculate totals differently. See :php:meth: `Grid::addGrandTotals `
469+
470+ Definition of a "totals plan"
471+ -----------------------------
472+
473+ Each column may have a different plan, which consists of stages:
474+
475+ - init: defines the initial value
476+ - update: defines how value is updated
477+ - format: defines how value is formatted before outputting
478+
479+ Here is the plan to calculate number of records::
480+
481+ $table->addTotals(['client' => [
482+ 'init'=>0,
483+ 'update'=>'increment',
484+ 'format'=>'Totals for {$client} client(s)'
485+ ]);
486+
487+ To make things easier to define, each stage has a reasonable default:
488+
489+ - init: set to 0
490+ - update: 'sum' for numeric/money type and 'increment' otherwise
491+ - format: will output '-' by default
492+
493+ Also when calling addTotals() the column plan value does not have to be array, in which case the 'format'
494+ is set. The above example can therefore be shortened::
495+
496+ $table->addTotals(['client' => 'Totals for {$clients} client(s)']);
497+
498+ Possible values for total plan stages
499+ -------------------------------------
500+
501+ `init ` value is typically a number, but can be any value, especially if you are going to control it's
502+ increment / formatting.
503+
504+ `update ` can be string - either "sum" or "increment". Other values are not supported. You can also pass
505+ a callable which gives you an option to perform update yourself.
506+
507+ `format ` uses a template in a format suitable for :php:class: `Template `. Within the template you can
508+ reference other fields too. A benefit for using template is that type formatting is done automatically
509+ for you.
510+
511+
512+
513+
433514Advanced Usage
434515==============
435516
0 commit comments