diff --git a/CHANGELOG.md b/CHANGELOG.md
index 645eea1..20727ee 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,11 @@
# (MODX)EvolutionCMS.snippets.ddGetDocuments changelog
+## Version 1.5 (2022-06-03)
+* \+ Parameters → `providerParams->groupBy`: The new parameter. Allows to group items that have the same field values into summary item (like SQL `GROUP BY`). See README.
+* \* README → Examples: HJSON is used for all examples.
+
+
## Version 1.4 (2021-07-27)
* \* Attention! PHP >= 5.6 is required.
* \* Attention! (MODX)EvolutionCMS.libraries.ddTools >= 0.50 is required.
diff --git a/CHANGELOG_ru.md b/CHANGELOG_ru.md
index d9c52de..708470a 100644
--- a/CHANGELOG_ru.md
+++ b/CHANGELOG_ru.md
@@ -1,6 +1,11 @@
# (MODX)EvolutionCMS.snippets.ddGetDocuments changelog
+## Version 1.5 (2022-06-03)
+* \+ Параметры → `providerParams->groupBy`: Новый параметр. Позволяет сгруппировать элементы, имеющие одинаковые значения полей, в один сводный элемент (как SQL `GROUP BY`). См. README.
+* \* README → Примеры: HJSON используется для всех примеров.
+
+
## Версия 1.4 (2021-07-27)
* \* Внимание! Требуется PHP >= 5.6.
* \* Внимание! Требуется (MODX)EvolutionCMS.libraries.ddTools >= 0.50.
diff --git a/README.md b/README.md
index 5ad500d..1fe8224 100644
--- a/README.md
+++ b/README.md
@@ -11,31 +11,28 @@ A snippet for fetching and parsing resources from the document tree or custom DB
* [(MODX)EvolutionCMS.libraries.ddTools](https://code.divandesign.biz/modx/ddtools) >= 0.50
-## Documentation
+## Installation
-### Installation
+### Manually
-#### Manually
-
-
-##### 1. Elements → Snippets: Create a new snippet with the following data
+#### 1. Elements → Snippets: Create a new snippet with the following data
1. Snippet name: `ddGetDocuments`.
-2. Description: `1.4 A snippet for fetching and parsing resources from the document tree or custom DB table by a custom rule.`.
+2. Description: `1.5 A snippet for fetching and parsing resources from the document tree or custom DB table by a custom rule.`.
3. Category: `Core`.
4. Parse DocBlock: `no`.
5. Snippet code (php): Insert content of the `ddGetDocuments_snippet.php` file from the archive.
-##### 2. Elements → Manage Files:
+#### 2. Elements → Manage Files:
1. Create a new folder `assets/snippets/ddGetDocuments/`.
2. Extract the archive to the folder (except `ddGetDocuments_snippet.php`).
-#### Using [(MODX)EvolutionCMS.libraries.ddInstaller](https://github.com/DivanDesign/EvolutionCMS.libraries.ddInstaller)
+### Using [(MODX)EvolutionCMS.libraries.ddInstaller](https://github.com/DivanDesign/EvolutionCMS.libraries.ddInstaller)
Just run the following PHP code in your sources or [Console](https://github.com/vanchelo/MODX-Evolution-Ajax-Console):
@@ -57,18 +54,18 @@ require_once(
* If `ddGetDocuments` is already exist on your site, `ddInstaller` will check it version and update it if needed.
-### Parameters description
+## Parameters description
-#### Core parameters
+### Core parameters
* `fieldDelimiter`
- * Desctription: The field delimiter to be used in order to distinct data base column names in those parameters which can contain SQL queries directly, e. g. `providerParams->orderBy` and `providerParams->filter`.
+ * Desctription: The field delimiter to be used in order to distinct data base column names in those parameters which can contain SQL queries directly, e. g. `providerParams->groupBy`, `providerParams->orderBy` and `providerParams->filter`.
* Valid values: `string`
* Default value: ``'`'``
-#### Data provider parameters
+### Data provider parameters
* `provider`
* Desctription: Name of the provider that will be used to fetch documents.
@@ -105,6 +102,16 @@ require_once(
* Valid values: `integer`
* Default value: `0`
+* `providerParams->groupBy`
+ * Desctription: Group items that have the same values into summary item (like SQL `GROUP BY`).
+ * Valid values: `stringCommaSeparated`
+ * Default value: —
+
+* `providerParams->groupBy[$i]`
+ * Desctription: Document field or TV by which the items will be grouped.
+ * Valid values: `string`
+ * **Required**
+
* `providerParams->orderBy`
* Desctription: A string representing the sorting rule.
TV names also can be used.
@@ -112,7 +119,7 @@ require_once(
* Default value: —
-##### Providers → Parent (``&provider=`parent` ``)
+#### Providers → Parent (``&provider=`parent` ``)
* `providerParams->parentIds`
* Desctription: Parent ID(s).
@@ -144,7 +151,7 @@ require_once(
* **Required**
-##### Providers → Select (``&provider=`select` ``)
+#### Providers → Select (``&provider=`select` ``)
* `providerParams->ids`
* Desctription: Document IDs to output.
@@ -159,7 +166,7 @@ require_once(
* **Required**
-##### Providers → Customdbtable (``&provider=`customdbtable` ``)
+#### Providers → Customdbtable (``&provider=`customdbtable` ``)
Get resources from custom DB table.
@@ -169,7 +176,7 @@ Get resources from custom DB table.
* **Required**
-#### Output format parameters
+### Output format parameters
* `outputter`
* Desctription: Format of the output.
@@ -199,7 +206,7 @@ Get resources from custom DB table.
* Default value: —
-##### Outputter → String (``&outputter=`string` ``)
+#### Outputter → String (``&outputter=`string` ``)
* `outputterParams->templates->item`
* Desctription: Item template.
@@ -266,7 +273,7 @@ Get resources from custom DB table.
* Default value: `''`
-##### Outputter → Json (``&outputter=`json` ``)
+#### Outputter → Json (``&outputter=`json` ``)
* `outputterParams->docFields`
* Desctription: Document fields to output (including TVs).
@@ -297,7 +304,7 @@ Get resources from custom DB table.
* **Required**
-##### Outputter → Sitemap (``&outputter=`sitemap` ``)
+#### Outputter → Sitemap (``&outputter=`sitemap` ``)
Output in [Sitemap XML format](https://en.wikipedia.org/wiki/Sitemaps).
@@ -348,7 +355,7 @@ Output in [Sitemap XML format](https://en.wikipedia.org/wiki/Sitemaps).
```
-##### Outputter → Yandexmarket (``&outputter=`yandexmarket` ``)
+#### Outputter → Yandexmarket (``&outputter=`yandexmarket` ``)
Output in [YML format](https://yandex.ru/support/partnermarket/export/yml.html).
@@ -630,7 +637,7 @@ Output in [YML format](https://yandex.ru/support/partnermarket/export/yml.html).
* Default: —
-#### Extenders parameters
+### Extenders parameters
* `extenders`
* Desctription: Comma-separated string determining which extenders should be applied to the snippet.
@@ -667,7 +674,7 @@ Output in [YML format](https://yandex.ru/support/partnermarket/export/yml.html).
* Default value: —
-##### Extenders → Pagination (``&extenders=`pagination` ``)
+#### Extenders → Pagination (``&extenders=`pagination` ``)
* `extendersParams->pagination->wrapperTpl`
* Desctription: Chunk to be used to output the pagination.
@@ -771,7 +778,7 @@ Output in [YML format](https://yandex.ru/support/partnermarket/export/yml.html).
```
-##### Extenders → Tagging (``&extenders=`tagging` ``)
+#### Extenders → Tagging (``&extenders=`tagging` ``)
* `extendersParams->tagging->tagsDocumentField`
* Desctription: The document field (TV) contains tags.
@@ -789,7 +796,7 @@ Output in [YML format](https://yandex.ru/support/partnermarket/export/yml.html).
* Default value: `'tags'`
-##### Extenders → Search (``&extenders=`search` ``)
+#### Extenders → Search (``&extenders=`search` ``)
* `extendersParams->search->docFieldsToSearch`
* Desctription: Document fields to search in (including TVs).
@@ -806,7 +813,7 @@ Output in [YML format](https://yandex.ru/support/partnermarket/export/yml.html).
* **Required**
-##### Extenders → SortFromURL (``&extenders=`sortFromURL` ``)
+#### Extenders → SortFromURL (``&extenders=`sortFromURL` ``)
* `$_GET['orderBy']`
* Desctription: A string representing the sorting rule similar to `providerParams->orderBy`.
@@ -814,27 +821,36 @@ Output in [YML format](https://yandex.ru/support/partnermarket/export/yml.html).
* Default value: —
-### Examples
+## Examples
+
+All examples are written using [HJSON](https://hjson.github.io/), but if you want you can use vanilla JSON instead.
-#### Simple fetching child documents from a parent with ID = `1`
+### Simple fetching child documents from a parent with ID = `1`
```html
[[ddGetDocuments?
&providerParams=`{
- "parentIds": "1",
- "depth": 1
+ parentIds: 1
+ depth: 1
}`
&outputterParams=`{
- "templates": {
- "item": "@CODE:
[+pagetitle+]
[+introtext+]
[+someTV+]
"
+ templates: {
+ item:
+ '''
+ @CODE:
+
[+pagetitle+]
+
[+introtext+]
+ [+someTV+]
+
+ '''
}
}`
]]
```
-#### Simple fetching child documents from a parent with ID = `1` with the `providerParams->filter`
+### Simple fetching child documents from a parent with ID = `1` with the `providerParams->filter`
Add a filter that would not output everything. Let's say we need only published documents.
@@ -844,13 +860,13 @@ _Don't forget about `fieldDelimiter`._
[[ddGetDocuments?
&fieldDelimiter=`#`
&providerParams=`{
- "parentIds": "1",
- "depth": 1,
- "filter": "#published# = 1"
+ parentIds: 1
+ depth: 1
+ filter: "#published# = 1"
}`
&outputterParams=`{
- "templates": {
- "item": "documents_item"
+ templates: {
+ item: documents_item
}
}`
]]
@@ -862,27 +878,32 @@ So we can filter as much as we like (we can use `AND` and `OR`, doucument fields
[[ddGetDocuments?
&fieldDelimiter=`#`
&providerParams=`{
- "parentIds": "1",
- "depth": 1,
- "filter": "#published# = 1 AND #hidemenu# = 0 OR #SomeTVName# = 1"
+ parentIds: 1
+ depth: 1
+ filter:
+ '''
+ #published# = 1 AND
+ #hidemenu# = 0 OR
+ #SomeTVName# = 1
+ '''
}`
&outputterParams=`{
- "templates: {
- "item": "documents_item"
+ templates: {
+ item: documents_item
}
}`
]]
```
-#### Sorting by TV with the `date` type (`providerParams->orderBy`)
+### Sorting by TV with the `date` type (`providerParams->orderBy`)
Dates in DB stored in specific format (`01-02-2017 08:59:45`) and sorting works unexpectedly at first sight.
So, we can't just type:
```
&providerParams=`{
- "orderBy": "#TVName# DESC"
+ orderBy: "#TVName# DESC"
}`
```
@@ -890,18 +911,18 @@ For correct working we need to convert date from DB to Unixtime for sorting:
```
&providerParams=`{
- "orderBy": "STR_TO_DATE(#TVName#, '%d-%m-%Y %H:%i:%s') DESC"
+ orderBy: "STR_TO_DATE(#TVName#, '%d-%m-%Y %H:%i:%s') DESC"
}`
```
When `TVName` — TV name for sorting by.
-#### Outputters → JSON (``&outputter=`json` ``): Fetch documents and output in JSON
+### Outputters → JSON (``&outputter=`json` ``): Fetch documents and output in JSON
```
[[ddGetDocuments?
- &providerParams=`{"parentIds": "1"}`
+ &providerParams=`{parentIds: 1}`
&outputter=`json`
]]
```
@@ -917,14 +938,14 @@ Returns:
```
-#### Outputters → JSON (``&outputter=`json` ``): Set documents fields to output
+### Outputters → JSON (``&outputter=`json` ``): Set documents fields to output
```
[[ddGetDocuments?
- &providerParams=`{"parentIds": "1"}`
+ &providerParams=`{parentIds: 1}`
&outputter=`json`
&outputterParams=`{
- "docFields": "id,pagetitle,menuindex,someTV"
+ docFields: id,pagetitle,menuindex,someTV
}`
]]
```
@@ -955,50 +976,93 @@ Returns:
```
-#### Extenders → Pagination (``&extenders=`pagination` ``)
+### Group items that have the same field values into summary item (`providerParams->orderBy`)
+
+For example we have the following documents with TV `gender`:
+
+* Mary Teresa, female
+* Mahatma Gandhi, male
+* Tenzin Gyatso, male
+* Dmitry Muratov, male
+* ICAN, none
+
+And we want to make a gender list with unique items:
+
+```
+[[ddGetDocuments?
+ &fieldDelimiter=`#`
+ &providerParams=`{
+ //The parent of our documents
+ parentIds: 42
+ //The field by which the items will be grouped
+ groupBy: "#gender#"
+ }`
+ &outputter=`json`
+ &outputterParams=`{
+ docFields: gender
+ }`
+]]
+```
+
+Returns:
+
+```json
+[
+ {"gender": "female"},
+ {"gender": "male"},
+ {"gender": "none"}
+]
+```
+
+
+### Extenders → Pagination (``&extenders=`pagination` ``)
```
[[ddGetDocuments?
&fieldDelimiter=`#`
&providerParams=`{
- "parentIds": "[*id*]",
- "filter": "#published# = 1",
- "total": 3,
- "orderBy": "#pub_date# DESC`"
+ parentIds: "[*id*]"
+ filter: "#published# = 1"
+ total: 3
+ orderBy: "#pub_date# DESC`"
}`
&outputterParams=`{
- "templates": {
- "item": "documents_item",
- "wrapper": "@CODE:[+ddGetDocuments_items+][+extenders.pagination+]",
- "noResults": "@CODE:"
+ templates: {
+ item: documents_item
+ wrapper:
+ ''''
+ @CODE:[+ddGetDocuments_items+]
+ [+extenders.pagination+]
+ '''
+ noResults: "@CODE:"
}
}`
&extenders=`pagination`
&extendersParams=`{
- "pagination": {
- "wrapperTpl": "general_pagination",
- "nextTpl": "general_pagination_next",
- "previousTpl": "general_pagination_prev",
- "nextOffTpl": "general_pagination_nextOff",
- "previousOffTpl": "general_pagination_prevOff",
- "pageTpl": "general_pagination_page",
- "currentPageTpl": "general_pagination_pageCurrent"
+ pagination: {
+ wrapperTpl: general_pagination
+ nextTpl: general_pagination_next
+ previousTpl: general_pagination_prev
+ nextOffTpl: general_pagination_nextOff
+ previousOffTpl: general_pagination_prevOff
+ pageTpl: general_pagination_page
+ currentPageTpl: general_pagination_pageCurrent
}
}`
]]
```
-* ``&providerParams=`{"parentIds": "[*id*]"}` `` — fetch current doc children.
-* ``&providerParams=`{"filter": "#published# = 1"}` `` — only published.
-* ``&providerParams=`{"total": 3}` `` — items per page.
-* ``&providerParams=`{"orderBy": "#pub_date# DESC"} `` — sort by publish date, new first.
-* ``&outputterParams=`{"templates": {"item": "documents_item"}}` `` — item template (chunk name).
-* ``&outputterParams=`{"templates": {"wrapper": "@CODE:[+ddGetDocuments_items+][+extenders.pagination+]"}}` `` — we need set where pagination will being outputted.
-* ``&outputterParams=`{"templates": {"noResults": "@CODE:"}}` `` — return nothing if nothing found.
-* ``&extendersParams=`{"pagination": {}}` `` — pagination templates (see the parameters description).
+* ``&providerParams=`{parentIds: "[*id*]"}` `` — fetch current doc children.
+* ``&providerParams=`{filter: "#published# = 1"}` `` — only published.
+* ``&providerParams=`{total: 3}` `` — items per page.
+* ``&providerParams=`{orderBy: "#pub_date# DESC"} `` — sort by publish date, new first.
+* ``&outputterParams=`{templates: {item: documents_item}}` `` — item template (chunk name).
+* ``&outputterParams=`{templates: {wrapper: "@CODE:[+ddGetDocuments_items+][+extenders.pagination+]"}}` `` — we need set where pagination will being outputted.
+* ``&outputterParams=`{templates: {noResults: "@CODE:"}}` `` — return nothing if nothing found.
+* ``&extendersParams=`{pagination: {}}` `` — pagination templates (see the parameters description).
-#### Extenders → Search (``&extenders=`search` ``)
+### Extenders → Search (``&extenders=`search` ``)
Call the snippet at the page with search results.
Let's specify where and how deep we will search.
@@ -1008,17 +1072,22 @@ Set up filter to get only necessary documets.
[[ddGetDocuments?
&fieldDelimiter=`#`
&providerParams=`{
- "parentIds": 1,
- "depth": 3,
- "filter": "#published# = 1 AND #deleted# = 0 AND #template# = 11"
+ parentIds: 1
+ depth: 3
+ filter:
+ '''
+ #published# = 1 AND
+ #deleted# = 0 AND
+ #template# = 11
+ '''
}`
&extenders=`search`
&extendersParams=`{
- "docFieldsToSearch": "pagetitle,content,someTv"
+ docFieldsToSearch: pagetitle,content,someTv
}`
&outputterParams=`{
- "templates": {
- "item": "documents_item"
+ templates: {
+ item: documents_item
}
}
]]
@@ -1029,7 +1098,7 @@ Then just add to the page URL `?query=Some query text` and the snippet returns o
We recommend to use cashed snippet calls and turn on document caching type with $_GET parameters in CMS configuration.
-#### Run the snippet through `\DDTools\Snippet::runSnippet` without DB and eval
+### Run the snippet through `\DDTools\Snippet::runSnippet` without DB and eval
```php
//Include (MODX)EvolutionCMS.libraries.ddTools
diff --git a/composer.json b/composer.json
index ece41da..b4d95b3 100644
--- a/composer.json
+++ b/composer.json
@@ -1,7 +1,7 @@
{
"name": "dd/evolutioncms-snippets-ddgetdocuments",
"type": "modxevo-snippet",
- "version": "1.4.0",
+ "version": "1.5.0",
"description": "A snippet for fetching and parsing resources from the document tree or custom DB table by a custom rule.",
"keywords": [
"modx",
diff --git a/ddGetDocuments_snippet.php b/ddGetDocuments_snippet.php
index ec4e49a..806834f 100644
--- a/ddGetDocuments_snippet.php
+++ b/ddGetDocuments_snippet.php
@@ -1,13 +1,13 @@
from {string}
* @return $result->where {string}
+ * @return $result->groupBy {string}
* @return $result->orderBy {string}
* @return $result->limit {string}
*/
@@ -479,10 +481,18 @@ protected final function prepareQueryData($params = []){
$result = (object) [
'from' => $fromAndFilterQueries->from,
'where' => '',
+ 'groupBy' => '',
'orderBy' => '',
'limit' => '',
];
+ if(!empty($this->groupBy)){
+ $result->groupBy =
+ 'GROUP BY ' .
+ $this->groupBy
+ ;
+ }
+
if(!empty($this->orderBy)){
$result->orderBy =
'ORDER BY ' .
@@ -543,7 +553,7 @@ protected final function prepareQueryData($params = []){
/**
* prepareQuery
- * @version 1.3 (2020-05-20)
+ * @version 1.4 (2022-06-03)
*
* @param $params {arrayAssociative|stdClass}
* @param $params['resourcesIds'] — Document IDs to get ($this->filter will be used). Default: ''.
@@ -601,6 +611,8 @@ protected function prepareQuery($params = []){
' AS `resources` ' .
$queryData->where .
' ' .
+ $queryData->groupBy .
+ ' ' .
$queryData->orderBy .
' ' .
$queryData->limit .
diff --git a/src/Input.php b/src/Input.php
index b114b1d..0d63029 100644
--- a/src/Input.php
+++ b/src/Input.php
@@ -40,7 +40,7 @@ class Input extends \DDTools\BaseClass {
/**
* __construct
- * @version 4.4.2 (2021-07-18)
+ * @version 4.5 (2022-06-03)
*
* @param $snippetParams {stdClass} — The object of parameters. @required
* @param $snippetParams->providerParams {stdClass|arrayAssociative|stringJsonObject}
@@ -99,10 +99,11 @@ public function __construct($snippetParams){
$this->setExistingProps($snippetParams);
- //Make sure orderBy and filter looks like SQL
+ //Make sure groupBy, orderBy and filter looks like SQL
foreach (
[
'filter',
+ 'groupBy',
'orderBy'
] as
$paramName
diff --git a/src/Snippet.php b/src/Snippet.php
index 91d876a..4d12352 100644
--- a/src/Snippet.php
+++ b/src/Snippet.php
@@ -3,7 +3,7 @@
class Snippet extends \DDTools\Snippet {
protected
- $version = '1.4.0',
+ $version = '1.5.0',
$renamedParamsCompliance = [
'outputter' => 'outputFormat',