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',