Skip to content

Commit 78938ff

Browse files
committed
New interfaces for collector classes
1 parent 346c3b9 commit 78938ff

20 files changed

+285
-257
lines changed

composer.json

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "gpoehl/phpreport",
3-
"description": "PHP library solving almost all common tasks for applications working with data groups. It manages group changes, provides aggregate functions and can even join data from different sources.",
3+
"description": "PHP library solving almost all common tasks for applications working with data sets. It manages group changes, provides aggregate functions and can even join data from different sources.",
44
"license": "LGPL-3.0-or-later",
55
"authors": [
66
{
@@ -10,18 +10,17 @@
1010
"keywords": [
1111
"php",
1212
"report",
13+
"reporting"
1314
"grouping",
14-
"group change",
1515
"totals",
1616
"subtotals",
17-
"sheets",
18-
"join"
17+
"sheets"
1918
],
2019
"archive": {
2120
"exclude": ["/docs", "/docs/build"]
2221
},
2322
"require": {
24-
"php": "^7.4"
23+
"php": ">=7.4"
2524
},
2625
"autoload": {
2726
"classmap": [

docs/source/collector.rst

Lines changed: 123 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,145 @@
11
Collector
22
=========
33

4-
phpReport has a very powerful feature to aggregate values and increment counters.
5-
Each value and counter is implemented as a calculator object. These objects
6-
will be assigned to one collector.
4+
A collector class is designed to hold and manage multiple items. An item can
5+
be an other collector or an calculator object.
76

8-
phpReport instantiates the following collectors.
7+
The main responsibilty of an collector is to call methods in assigned items.
8+
To make sure that the cumputation of calculated values works correct calculator
9+
objects must be registered to the **total** collector or to one of his child collectors.
910

10-
.. note::
11-
All entities assigned to one of those collectors are cumulated to
12-
higher group levels.
11+
The collector class has the ArrayAccess interface and the magic __get method
12+
implemented which allows a broad range of access options.
1313

14+
The visibility of the $items array is public. This allows maximum speed when accessing
15+
an item and gives the opportunity to apply all php array methods.
1416

15-
Row counter collector
16-
----------------------
1717

18-
The row counter collector is named **rc**. For each data dimension one CalculatorXS
19-
object will be instantiated.
18+
Add items
19+
---------
2020

21-
Group counter collector
22-
-----------------------
21+
Items will be added (or registered) to an collector usually by calling the calculate()
22+
or sheet() methods of the **phpReport** class.
2323

24-
The group counter collector is named **gc**. For each defined group one CalculatorXS
25-
object will be instantiated.
24+
You may can also add items by the addItem() method. This is especially desired when
25+
you want to group multiple item objects.
2626

27-
Total collector
28-
---------------
27+
Adding items to a sheet collector is hidden and will be
28+
internally handled based on key values of the add() method.
29+
30+
31+
Alternate item keys
32+
-------------------
33+
Items are stored in the $item array indexed by the name given when calling the
34+
addItem() method. You can also apply an alternate key to allow accessing an item
35+
by the alternate key as well.
2936

30-
The total collector is named **total**. The collector is used to hold all calculator
31-
objects instantiated by the aggregate() method and the sheet objects instantiated
32-
by the sheet() method.
37+
The setAltKeys() method will set many alternate keys while the setAltKey()
38+
method one alternate key.
3339

34-
You can assign further collectors, sheets or calculators to this total collector
35-
or any other collector in this tree.
36-
So it's possible to build a hirachichal structure of aggregated values.
40+
The group conter collecor uses alternate keys to allow accessing the counters
41+
by the group level and by the group name.
3742

3843

39-
Accessing values
40-
----------------
44+
Get items
45+
---------
4146

42-
There are multiple options to access a calculater object. The long version looks
43-
like
47+
To access an item you can use the getItems() method for all items or the getItem()
48+
method to get one item.
4449

45-
$this->rep->*collectorName*->items[*itemName*].
50+
The magic __get() and the array access get methods calls the getItem() method.
51+
The item will returned when it exist either by the item array key or by the alternate
52+
key.
4653

4754
.. code-block:: php
4855
49-
$rep = $this->report;
50-
$rep->t->*name*;
51-
$rep->t['*name*'];
52-
$rep->rc;
53-
$rep->rc->{0};
54-
$rep->rc->[0];
55-
56-
.. include:: rowCounter.rst
57-
.. include:: groupCounter.rst
56+
$this->rep = new phpReport($this);
57+
$this->rep->compute('sales');
58+
// All of the following statements will return the same item.
59+
$item = $this->report->total->getItem('sales');
60+
$item = $this->report->total->items['sales']);
61+
$item = $this->report->total->sales;
62+
$item = $this->report->total['sales'];
63+
64+
65+
Aggregate methods
66+
-----------------
5867

59-
Range of values
68+
All aggregate methods implemented in the calculator classes have their counterpart
69+
it the collector classes.
70+
71+
The collector aggregate methods calls the same methods for each assigned item.
72+
Returned results will be returned either as an array indexed by the item key or
73+
as an scalar aggregated value.
74+
75+
76+
Subset of items
6077
---------------
61-
To apply aggregate funcions only to a subset of collected items use the range method.
78+
79+
To apply aggregate methods only on some items you can build a subset by calling the
80+
following filter methods. Each of them will return a cloned collector object with
81+
just the filtered items.
82+
83+
To use the cloned collector multiple times hold the reference to the cloned collector in
84+
a variable.
85+
86+
.. php:method:: range(...$ranges): AbstractCollecotor
87+
88+
Extract ranges of items.
89+
90+
Returns ranges of items located between start and end keys.
91+
92+
When a range is an array value1 is the start and value2 the end key.
93+
When one of the keys don't exist the value of the altKey will be used instead.
94+
When the items still doesn't exist an error will be thrown.
95+
96+
If start key equals Null the range begins at the first item.
97+
When the end key equals Null the range ends at the last item.
98+
99+
When a range is not an array then the item with the corresponding key or
100+
altKey is returned if it exist. If this doesn't exist php raise a notice.
101+
102+
Item keys are preserved. Sort order within ranges are preserved. Ranges
103+
are returned in given order. When items belong to multiple ranges only
104+
the first occurence will returned.
105+
106+
:param array|int|string[] $ranges Ranges or item keys for items to be filtered.
107+
:return AbstractCollector Cloned collector with items in ranges.
108+
:throws InvalidArgumentException When start or end item doesn't exist.
109+
110+
.. php:method:: between(...$ranges): AbstractCollecotor
111+
112+
Filters items where key is between values.
113+
114+
Iterates over each collector item. If a range is an array and the item key
115+
is between value1 and value2 of this range (inclusive) the item is returned.
116+
117+
If the range isn't an the item with the corresponding key is returned.
118+
119+
If a range matches the key of a named range then the named range value will
120+
be used to filter the items.
121+
122+
Item keys and sort order are preserved.
123+
124+
:param array|int|string[]: $ranges Ranges or item keys for items to be filtered.
125+
:returns: AbstractCollector Cloned collector with items in ranges.
126+
127+
.. php:method:: filter(callable $callable):
128+
129+
Filters items using a callback function.
130+
Iterates over each item in the array passing key and value to the callback
131+
function. If the callback function returns TRUE, the current item is returned
132+
into the cloned collector. Item keys are preserved.
133+
134+
:param callable $callable: The callback function to use.
135+
:returns: AbstractCollector Clone of current collector with filtered items
136+
137+
.. php:method:: cmd(callable $command, ...$params): AbstractCollector
138+
139+
Alter item collection by executing a php array command.
140+
141+
:param callable $command: Any php array command which accepts an
142+
array as the first parameter.
143+
:param mixed[] $params: Additional parameters passed to the php command.
144+
:returns: AbstractCollector Clone of current collector with applied command
145+
on the items array.

docs/source/conf.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
3333
# ones.
3434
extensions = [
35-
'sphinx.ext.todo',
35+
'sphinx.ext.todo',
3636
'sphinx_rtd_theme',
3737
'sphinxcontrib.phpdomain',
3838
]
@@ -68,7 +68,7 @@
6868
# Add any paths that contain custom static files (such as style sheets) here,
6969
# relative to this directory. They are copied after the builtin static files,
7070
# so a file named "default.css" will overwrite the builtin "default.css".
71-
html_static_path = ['_static']
71+
# html_static_path = ['_static']
7272

7373
html_context = {
7474
# Enable the "Edit in GitHub link within the header of each page.

docs/source/defaultCollectors.rst

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
Default Collectors
2+
==================
3+
4+
phpReport has a very powerful feature to aggregate values and increment counters.
5+
Each value and counter is implemented as a calculator object. These objects
6+
will be assigned to one collector.
7+
8+
phpReport instantiates the following collectors.
9+
10+
.. note::
11+
All entities assigned to one of those collectors are cumulated to
12+
higher group levels.
13+
14+
15+
Row counter collector
16+
----------------------
17+
18+
The row counter collector is named **rc**. For each data dimension one CalculatorXS
19+
object will be instantiated.
20+
21+
Group counter collector
22+
-----------------------
23+
24+
The group counter collector is named **gc**. For each defined group one CalculatorXS
25+
object will be instantiated.
26+
27+
Total collector
28+
---------------
29+
30+
The total collector is named **total**. The collector is used to hold all calculator
31+
objects instantiated by the compute() method and the sheet objects instantiated
32+
by the sheet() method.
33+
34+
You can assign further collectors, sheets or calculators to this total collector
35+
or any other collector in this tree.
36+
So it's possible to build a hirachichal structure of aggregated values.
37+
38+
.. include:: rowCounter.rst
39+
.. include:: groupCounter.rst

src/AbstractCalculator.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
namespace gpoehl\phpReport;
1515

16+
1617
/**
1718
* Base class for calculator classes.
1819
*/

src/AbstractCollector.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,15 @@ public function setAltKey($key, $itemKey): void {
5353

5454
/**
5555
* Magic get method to access item via arrow notation.
56+
* Note: A magic setter method is not implemented. Use the addItem method instead.
5657
* Example: $collector->itemKey
5758
* @param int|string $key the item key
5859
* @return AbstractCollector|AbstractCalculator Returns the requested item
5960
*/
6061
public function __get($key): object {
6162
return $this->getItem($key);
6263
}
64+
6365

6466
/* -------------------------------------------------------------------------
6567
* Implementation of the arrayAccess interface
@@ -167,7 +169,7 @@ public function cumulateToNextLevel(): void {
167169
* @return AbstractCollector Clone of current collector with selected items.
168170
* @throws InvalidArgumentException When start or end item doesn't exist.
169171
*/
170-
public function range(... $ranges): AbstractCollector {
172+
public function range(...$ranges): AbstractCollector {
171173
$collector = clone $this;
172174
$collector->items = [];
173175
$keyOffsets = array_flip(array_keys($this->items));
@@ -234,7 +236,7 @@ private function findItemKey($key) {
234236
* @param array|int|string[] $ranges Ranges or item keys for items to be filtered.
235237
* @return AbstractCollector Clone of current collector with filtered items.
236238
*/
237-
public function between(... $ranges): AbstractCollector {
239+
public function between(...$ranges): AbstractCollector {
238240
$collector = clone $this;
239241
$collector->items = [];
240242
foreach ($this->items as $key => $item) {

src/Calculator.php

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,12 @@
1212

1313
namespace gpoehl\phpReport;
1414

15+
1516
/**
1617
* Summarize values and count how often not null and not zero values are given
1718
* to the add() method.
1819
*/
19-
class Calculator extends AbstractCalculator {
20+
class Calculator extends AbstractCalculator implements NnAndNzCounterIF{
2021

2122
/** @var int[] not null counter. How many added values had a value not equal to zero. */
2223
protected $nn = [];
@@ -32,22 +33,6 @@ public function __construct(MajorProperties $mp, int $maxLevel) {
3233
$this->total = $this->nz = $this->nn = array_fill(0, $maxLevel + 1, 0);
3334
}
3435

35-
/**
36-
* Returns always true. Counters for notNull and notZero values are implemented.
37-
* @return true
38-
*/
39-
public function hasCounter(): bool {
40-
return true;
41-
}
42-
43-
/**
44-
* Returns always false. Methods to handle min and max values are not implemented.
45-
* @return false
46-
*/
47-
public function hasMinMax(): bool {
48-
return false;
49-
}
50-
5136
/**
5237
* Add given $value to $maxLevel and increment counters.
5338
* @param numeric|null $value The numeric data value which will be added
@@ -88,7 +73,7 @@ public function cumulateToNextLevel(): void {
8873
* @return numeric The running total of added values from the requested level down
8974
* to the lowest level
9075
*/
91-
public function sum($level = null) {
76+
public function sum(int $level = null) {
9277
return array_sum(array_slice($this->total, $this->mp->getLevel($level)));
9378
}
9479

@@ -97,7 +82,7 @@ public function sum($level = null) {
9782
* @param int|null $level The requested level. Defaults to the current level.
9883
* @return int The total number of added not null values for the requested level.
9984
*/
100-
public function nn($level = null): int {
85+
public function nn(int $level = null): int {
10186
// To calculate the total number all values from requested level down
10287
// to lowest level must be included.
10388
return array_sum(array_slice($this->nn, $this->mp->getLevel($level)));
@@ -109,7 +94,7 @@ public function nn($level = null): int {
10994
* @return int The total number of added not null and not zero values for
11095
* the requested level.
11196
*/
112-
public function nz($level = null): int {
97+
public function nz(int $level = null): int {
11398
// To calculate the total number all values from requested level down
11499
// to lowest level must be included.
115100
return array_sum(array_slice($this->nz, $this->mp->getLevel($level)));

0 commit comments

Comments
 (0)