1
0
Fork 0
mirror of synced 2025-04-05 14:53:40 +03:00

Compare commits

...

112 commits

Author SHA1 Message Date
fc78e5897b
Merge pull request #221 from opheugene/offer-site
Added site field to ProductOffer
2025-03-20 16:41:04 +03:00
Opheugene
0a862dd86b Added site field to ProductOffer 2025-03-19 17:51:25 +01:00
5a3547894a
Merge pull request #219 from Neur0toxine/fix-cache-action
fix github workflows (cache action)
2025-03-04 20:00:39 +03:00
1d05f3efeb fix github workflows (cache action) 2025-03-04 19:52:24 +03:00
831ed64871
Merge pull request #218 from Neur0toxine/fix-github-workflows
fix github workflows (checkout action)
2025-03-04 19:48:31 +03:00
502a0c8641 fix github workflows (checkout action) 2025-03-04 19:45:09 +03:00
4a99094294
Merge pull request #217 from curse89/master
Add calling setEventDispatcher method in ClientFactory
2025-03-04 19:42:56 +03:00
Сергей Кривич
c379815f76 Upd GH actions config && add calling setEventDispatcher method in CLientFactory 2025-03-04 19:19:35 +03:00
27e9e8eaa5
Merge pull request #216 from retailcrm/integration-embed-js
Add embedJs field to integrations/edit method
2025-01-14 09:23:27 +03:00
Ilyas Salikhov
c21a89c761 Add embedJs field to integrations/edit method 2025-01-13 22:28:31 +03:00
068a9d0e0b
Add customerSubscriptions to Customer entity 2024-12-20 16:34:11 +03:00
Alex Komarichev
1881dd3499 Add customerSubscriptions to Customer entity. Add subscriptions filter to CustomerFilter filter. 2024-12-18 14:42:35 +03:00
Uryvskiy Dima
47edbda927
Add discount amount for update payment request
Add discount amount for update payment request
2024-12-10 15:07:42 +03:00
ellynoize
91c3ca8ce5 add discount in test 2024-12-10 11:46:19 +03:00
ellynoize
6d05a1af3f add for update payment request 2024-12-09 19:43:10 +06:00
Andrey Belikin
16cdc6ce49
Add contact to store reference model (#213) 2024-10-18 10:08:15 +03:00
cdca2b6d6d
Support for urlLike filter in GET /api/v5/store/products 2024-09-25 11:30:20 +03:00
Vlasov
ecaac435cc Added support for urlLike filter in GET /api/v5/store/products 2024-09-24 17:59:01 +03:00
GrishaginEvgeny
e3cc485873
add customFields in CustomerCorporateFilter.php (#210)
Co-authored-by: Евгений Гришагин <grishagin@retailcrm.ru>
2024-09-10 15:00:32 +03:00
4880ed9930
Resolves #206: /api/v5/loyalty/account/{id}/bonus/charge method support 2024-09-04 13:37:32 +03:00
7b393e961b Resolves #206: /api/v5/loyalty/account/{id}/bonus/charge method support 2024-09-04 13:19:20 +03:00
3a3d00aeb8
update version constraint for symfony/console 2024-09-04 13:04:28 +03:00
60624dad9b
Add support for new filters of GET /api/v5/store/offers method 2024-09-04 12:58:19 +03:00
121dcebb32
Replace abandoned php-http/message-factory with psr/http-factory 2024-09-04 12:57:30 +03:00
Viacheslav Akulov
80396691dd
Update composer.json 2024-09-04 10:29:51 +03:00
Viacheslav Akulov
3d5e3e92e6
Update composer.json 2024-09-04 10:27:30 +03:00
RenCurs
6130b265fe
Add support for new filters of GET /api/v5/store/offers method (#205)
* Add support for new filters of GET /api/v5/store/offers method

- filter[min/maxPrice]
- filter[priceType]
- filter[min/maxQuantity]
- filter[catalogs][]

---------

Co-authored-by: Kirill Sukhorukov <suhorukov@retailcrm.ru>
2024-08-27 09:33:04 +03:00
Kirill Sukhorukov
da8ce13736 Add support for new filters of GET /api/v5/store/offers method
- filter[min/maxPrice]
- filter[priceType]
- filter[min/maxQuantity]
2024-08-22 17:15:24 +03:00
Kirill
1c6ebd819f
Add support for GET /api/v5/store/offers method (#203)
Co-authored-by: Kirill Sukhorukov <suhorukov@retailcrm.ru>
2024-08-19 16:01:35 +03:00
Nikolay Parshakov
a7d071af28 Replace abandoned php-http/message-factory to psr/http-factory 2024-08-12 07:26:15 +03:00
544d16186f
Add support for GET "/api/v5/store/products/properties/values" method 2024-08-09 12:46:31 +03:00
Kirill Sukhorukov
dc9e0a5b39 Add support for GET /api/v5/properties/values method 2024-08-07 17:50:13 +03:00
5b04bd9d8a
Support for filtering product properties by groups and sorting by usage in offers 2024-08-06 12:38:45 +03:00
Kirill Sukhorukov
ca1650d8d9 Add filter by ProductGroups and sort by popular for ProductProperties 2024-08-06 10:08:30 +03:00
54ce958c76
Add customer-interaction 2024-08-01 15:14:15 +03:00
Alex Komarichev
be71f22c65 Change params, add matchPath to test 2024-08-01 12:26:50 +03:00
Alex Komarichev
a7cffe45da Add customer-interaction 2024-07-31 18:24:22 +03:00
8b677de616
Fixed ProductFilter types 2024-07-19 12:06:13 +03:00
Opheugene
0ef461e504 fixed array of string 2024-07-18 18:24:03 +02:00
Opheugene
7d65407c7c fixes for tests 2024-07-18 18:20:25 +02:00
Opheugene
ccbff3aba3 Fixed ProductFilter types 2024-07-18 17:33:02 +02:00
71a3a66724
Add support for MG settings 2024-07-09 11:18:34 +03:00
Kirill Sukhorukov
36bf34b511 Add support for MG settings 2024-07-09 11:13:53 +03:00
ca955cd49f
Support for ProductGroup level in filter and response 2024-07-09 09:44:39 +03:00
Kirill Sukhorukov
a2bac7dcd0 Support for ProductGroup level in filter and response 2024-07-09 09:25:01 +03:00
bc5d044282
Customer subscriptions support 2024-06-20 18:05:04 +03:00
Opheugene
0298a1ad58 new fields 2024-06-20 16:47:02 +02:00
Opheugene
b7ae093cc4 Support for working with customer subscriptions 2024-06-20 14:03:20 +02:00
f04a352126
fixed LegalEntity certificateDate format 2024-04-17 15:39:21 +03:00
Владимир Колчин
e3877587bb fixed LegalEntity certificateDate format 2024-04-16 10:40:35 +03:00
fda9208de2
Compatibility with newer Symfony skeleton versions (with Doctrine 3.x) 2024-04-02 11:50:22 +03:00
5bb006588b add explanation for DateTime lexer behavior backport 2024-03-12 13:05:57 +03:00
759c1ee5a8 restore php 7.3 support 2024-03-12 09:59:53 +03:00
18f5b8c196 update phpcs command & composer-compile-plugin 2024-03-12 09:30:21 +03:00
312dfeffd7 better php 7.4 support 2024-03-11 20:45:58 +03:00
7a4d755f83 update phpstan baseline 2024-03-11 20:36:12 +03:00
f53f545c22 WIP: php 7.4 support 2024-03-11 20:31:56 +03:00
8ced4dc8a1 update README.md 2024-03-11 18:39:46 +03:00
49844e50d6 update php test matrix 2024-03-11 18:39:25 +03:00
0d747fa1e7 cq tools fixes 2024-03-11 18:37:34 +03:00
232c22a557 fix customer tags support 2024-03-11 18:24:44 +03:00
4de6a3b798 fix contracts support 2024-03-11 18:18:01 +03:00
82f110d0d0 update liip/serializer 2024-03-11 18:09:10 +03:00
curse89
7cf7cbf467
add allolwed version of psr/http-message (#189)
Co-authored-by: Сергей Кривич <krivich@retailcrm.ru>
2024-03-11 13:00:53 +03:00
Uryvskiy Dima
3927344dde
Add new method for get task comments (#188) 2024-02-08 12:52:58 +03:00
72636563ff
added type property to Product and ProductBatchModel 2024-01-18 16:08:45 +03:00
angelina pehova
37e9ca0110 type fix in Store and StoreTest 2024-01-18 10:20:28 +03:00
af8a79379b
Add history method for tasks 2024-01-17 16:32:18 +03:00
Uryvskiy Dima
a2d7035655 Add description 2024-01-17 00:44:40 +03:00
Uryvskiy Dima
0fce4a49db Fix tests 2024-01-17 00:38:29 +03:00
Uryvskiy Dima
f37434af17 Add test 2024-01-16 18:16:36 +03:00
angelina pehova
2310b3b825 added type var to Product and ProductBatchModel 2024-01-16 14:46:33 +03:00
Uryvskiy Dima
f926b59e36 Add history method for task 2024-01-16 14:00:43 +03:00
fe18dce66a
update resource group list in docs 2024-01-09 12:00:39 +03:00
3054974756
Add feature check method 2023-12-20 15:53:22 +03:00
Alex Komarichev
a7bb610a0a Fix example 2023-12-20 15:48:45 +03:00
725209296c
Add visitsUpload method 2023-12-20 12:53:28 +03:00
Alex Komarichev
a682ce606a Some refactor 2023-12-19 15:55:23 +03:00
Alex Komarichev
5223d0e9f6 Add feature/check method 2023-12-19 15:27:34 +03:00
Artem Osipov
2d0ed4c149 Добавлен метод загрузки визитов веб-аналитики 2023-12-14 19:25:46 +03:00
454a5fac26
Merge pull request #183 from Neur0toxine/phpdocumentor-fix
fix phpDocumentor pipeline & pin phar version
2023-11-27 15:37:16 +03:00
c10f2d3d47 fix phpDocumentor pipeline & pin phar version 2023-11-27 15:32:27 +03:00
Opheugene
37069e8cdd
Updated doctrine/annotations version (#180) 2023-11-15 16:10:03 +03:00
curse89
ef7d5cba25
Fix bonus details response data 2023-10-12 16:57:34 +03:00
b497e37c8e
API client updates 2023-10-03 11:09:27 +03:00
19f2b3dcd1 fix for phpstan 2023-10-03 10:02:39 +03:00
974b0cc8ef update ubuntu version for phpstan 2023-10-03 10:00:01 +03:00
Danila
b6afd33906 Add functionality from recent updates to the library 2023-10-03 10:00:01 +03:00
Danila
2b02c0e116 Add functionality from recent updates to the library 2023-10-03 10:00:00 +03:00
Vladimir Kolchin
6515e39144
Added currency methods + properties (#174)
Added currency methods + properties
2023-08-02 08:32:24 +03:00
curse89
a68705055c
Fix costs upload request model (#175) 2023-08-01 10:00:53 +03:00
Andrey
bb5a205cd1
Merge pull request #173 from oxy-coach/master
Fixed files/upload issue
2023-07-26 10:21:04 +03:00
Владимир Колчин
8476f8946e Fixed files/upload issue 2023-07-24 17:57:42 +03:00
fa0e8a7075
Added non_working_days field to settings. Added attachedTag field to customer 2023-06-27 11:33:07 +03:00
a87630a72b
Добавлены методы загрузки данных веб-аналитики 2023-06-27 11:32:40 +03:00
Vitaly Bormotov
06e34486ac Добавлены методы загрузки данных веб-аналитики 2023-06-27 09:35:39 +05:00
Max Baranikov
aa3c99fa6d Added attachedTag field to customer 2023-06-23 16:30:08 +04:00
Max Baranikov
86d280ba47 Added non_working_days field to settings. 2023-06-23 13:35:40 +04:00
curse89
a42ddcc337
Add field 'sites' to delivery and payment types (#167)
Add field sites to delivery and payment types
2023-05-23 10:50:33 +03:00
azgalot
847fbd0bd0
Merge pull request #166 from ilyavlasoff/add_multiselect_custom_field_support
Added multi dictionary custom field support
2023-05-05 14:23:35 +03:00
Vlasov
47741acd28 Added multi dictionary support 2023-05-03 12:01:58 +03:00
Andrey
bc820d0a69
Merge pull request #164 from AndreyMuriy/master
Add itemDeclaredValues field to deliveryData
2023-04-27 16:36:04 +03:00
Andrey Muriy
12d8381b80 Add itemDeclaredValues field to deliveryData 2023-04-27 16:05:24 +03:00
azgalot
5e2c947f27
Merge pull request #160 from oxy-coach/master
add notifications/send method support
2023-03-31 15:03:35 +03:00
Vladimir Kolchin
b0080ff23c add notifications/send method support 2023-03-31 14:09:58 +03:00
curse89
186b44b0d4
PHP 8.2 support 2023-02-27 16:08:34 +03:00
f75a653a7d
update documentation & update compile:prompt command 2022-11-18 12:17:42 +03:00
c47b6d2bb4 update documentation & update compile:prompt command 2022-11-17 12:21:47 +03:00
9a56566a7f
remove mgCustomerIds filter from /api/v5/customers request 2022-11-08 13:47:48 +03:00
ccd3c07872
add new methods & fix wrong URL bug 2022-11-08 13:47:32 +03:00
d960d43053 remove mgCustomerIds filter from /api/v5/customers request 2022-11-07 17:28:25 +03:00
Кривич Сергей
bbb9af3ac0 Update api-client 2022-10-28 18:01:44 +03:00
184 changed files with 8956 additions and 5806 deletions

View file

@ -14,27 +14,33 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
php-version: ['7.3', '7.4', '8.0', '8.1']
php-version: ['7.3', '7.4', '8.0', '8.1', '8.2', '8.3']
steps:
- name: Check out code into the workspace
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Setup PHP ${{ matrix.php-version }}
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-version }}
coverage: pcov
- name: Composer cache
uses: actions/cache@v2
uses: actions/cache@v4
with:
path: ${{ env.HOME }}/.composer/cache
key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }}
- name: Install dependencies
run: composer install -o
- name: Configure matchers
uses: mheap/phpunit-matcher-action@v1
- name: Run tests
run: composer run-script phpunit-ci
- name: Coverage
uses: codecov/codecov-action@v2
uses: codecov/codecov-action@v4
with:
verbose: true

View file

@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code into the workspace
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Run PHPCS
uses: chekalsky/phpcs-action@v1
phpmd:
@ -21,7 +21,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code into the workspace
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Run PHPMD
uses: GeneaLabs/action-reviewdog-phpmd@1.0.0
with:
@ -32,11 +32,11 @@ jobs:
target_directory: 'src'
phpstan:
name: PHPStan
runs-on: ubuntu-18.04
runs-on: ubuntu-latest
steps:
- name: Check out code into the workspace
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Run PHPStan
uses: docker://oskarstark/phpstan-ga:1.0.1
uses: docker://oskarstark/phpstan-ga:1.8.0
with:
args: analyse src -c phpstan.neon --memory-limit=1G --no-progress

View file

@ -8,7 +8,7 @@ on:
- 'v*'
jobs:
test:
documentation:
name: "phpDocumentor"
runs-on: ubuntu-latest
steps:
@ -19,21 +19,21 @@ jobs:
pages_threshold: major_outage
- name: Check out code into the workspace
if: success() && ${{ github.ref != 'refs/heads/master' }}
uses: actions/checkout@v2
- name: Setup PHP 7.4
uses: actions/checkout@v4
- name: Setup PHP 8.3
if: ${{ github.ref != 'refs/heads/master' }}
uses: shivammathur/setup-php@v2
with:
php-version: "7.4"
php-version: "8.3"
- name: Cache phpDocumentor
id: cache-phpdocumentor
uses: actions/cache@v2
uses: actions/cache@v4
with:
path: phpDocumentor.phar
key: phpdocumentor
- name: Download latest phpDocumentor
if: steps.cache-phpdocumentor.outputs.cache-hit != 'true'
run: curl -O -L https://phpdoc.org/phpDocumentor.phar
run: curl -O -L https://github.com/phpDocumentor/phpDocumentor/releases/download/v3.4.3/phpDocumentor.phar
- name: Generate documentation
if: ${{ github.ref != 'refs/heads/master' }}
run: php phpDocumentor.phar

View file

@ -37,31 +37,27 @@ Follow those steps to install the library:
```bash
composer require retailcrm/api-client-php:"~6.0"
```
During the installation, you'll see a message which will look like this:
During the installation you will see this message. Press `'y'` when you do:
```sh
civicrm/composer-compile-plugin contains a Composer plugin which is currently not in your allow-plugins config. See https://getcomposer.org/allow-plugins
Do you trust "civicrm/composer-compile-plugin" to execute code and wish to enable it now? (writes "allow-plugins" to composer.json) [y,n,d,?]
```
After that, you may see a message which will look like this:
```sh
The following packages have new compilation tasks:
- retailcrm/api-client-php has 1 task
Allow these packages to compile? ([y]es, [a]lways, [n]o, [l]ist, [h]elp)
```
That's because the Client uses code generation to speed up serialization and deserialization of models in production. This code should be generated during installation or update. Without that code, the library itself will not work at all.
Choose `[a]lways` by typing `a` and pressing Enter if you don't want to see this message anymore. If you want to approve the compilation task every time - use `[y]es` option. The DTO cache will be generated after that.
Choose `[a]lways` by typing `a` and pressing Enter.
**Note:** You should choose `[a]lways` if your application is using CI/CD pipeline because the interactive terminal is not available
**Note:** You should choose `'y'` and `[a]lways` if your application is using CI/CD pipeline because the interactive terminal is not available
in that environment which will result in failure during the dependencies installation.
If you skipped the compilation task - don't worry, it can be executed manually at any time with this command:
```sh
composer compile --all
```
If you chose something else during the installation and API client doesn't work properly - please follow [these instructions](doc/compilation_prompt.md#ive-chosen-something-else-now-api-client-doesnt-work) to fix the problem.
3. **Optional.** Disable compilation prompt that you have seen in the previous step.
If you wish to disable the compilation prompt but didn't do that at the previous step - you can disable the prompt manually.
Read the [documentation](doc/compilation_prompt.md) to learn how to do that.
4. Include the autoloader if it's not included, or you didn't use Composer before.
3. Include the autoloader if it's not included, or you didn't use Composer before.
```php
require 'path/to/vendor/autoload.php';
```

View file

@ -16,33 +16,33 @@
}
],
"require": {
"php": ">=7.3.0",
"php": ">=7.3",
"ext-json": "*",
"psr/log": "^1|^2|^3",
"psr/http-client": "^1.0",
"psr/http-message": "^1.0",
"psr/http-message": "^1.0 || ^2.0",
"psr/http-message-implementation": "^1.0",
"php-http/client-implementation": "^1.0",
"php-http/message-factory": "^1.0",
"php-http/discovery": "^1.13",
"doctrine/annotations": "^1.13",
"liip/serializer": "2.0.*",
"doctrine/annotations": "^1.13|^2.0",
"liip/serializer": "2.2.* || 2.6.*",
"php-http/httplug": "^2.2",
"civicrm/composer-compile-plugin": "^0.18.0",
"symfony/console": "^4.0|^5.0|^6.0",
"civicrm/composer-compile-plugin": "^0.20",
"symfony/console": "^4.0|^5.0|^6.0|^7.0",
"psr/event-dispatcher": "^1.0",
"neur0toxine/psr.http-client-implementation.php-http-curl": "*",
"neur0toxine/psr.http-factory-implementation.nyholm": "*",
"neur0toxine/psr.http-message-implementation.nyholm": "*",
"psr/cache": "^1.0 || ^2.0 || ^3.0",
"symfony/cache": ">=v3.1.0"
"symfony/cache": ">=v3.1.0",
"psr/http-factory": "^1.1"
},
"require-dev": {
"squizlabs/php_codesniffer": "^3.5",
"phpmd/phpmd": "^2.10",
"dealerdirect/phpcodesniffer-composer-installer": "^0.7.1",
"phpcompatibility/php-compatibility": "^9.3",
"phpstan/phpstan": "1.0.1",
"phpstan/phpstan": "1.9.14",
"vlucas/phpdotenv": "^5.3",
"phpunit/phpunit": "^9.5",
"php-http/curl-client": "^2.2",
@ -67,7 +67,7 @@
"phpunit": "./vendor/bin/phpunit -c phpunit.xml.dist --coverage-text",
"phpunit-ci": "@php -dpcov.enabled=1 -dpcov.directory=. -dpcov.exclude=\"~vendor~\" ./vendor/bin/phpunit --teamcity -c phpunit.xml.dist",
"phpmd": "./vendor/bin/phpmd src text ./phpmd.xml",
"phpcs": "./vendor/bin/phpcs -p src --runtime-set testVersion 7.3-8.0 && ./vendor/bin/phpcs -p tests --runtime-set testVersion 7.3-8.0 --warning-severity=0",
"phpcs": "./vendor/bin/phpcs -p src --runtime-set testVersion 7.3-8.3 && ./vendor/bin/phpcs -p tests --runtime-set testVersion 7.3-8.3 --warning-severity=0",
"phpstan": "./vendor/bin/phpstan analyse -c phpstan.neon src --memory-limit=-1",
"phpstan-dockerized-ci": "docker run --rm -it -w=/app -v ${PWD}:/app oskarstark/phpstan-ga:1.0.1 analyse src -c phpstan.neon --memory-limit=1G --no-progress",
"lint:fix": "./vendor/bin/phpcbf src",
@ -114,7 +114,8 @@
"process-timeout": 600,
"allow-plugins": {
"civicrm/composer-compile-plugin": true,
"dealerdirect/phpcodesniffer-composer-installer": true
"dealerdirect/phpcodesniffer-composer-installer": true,
"php-http/discovery": true
}
}
}

View file

@ -1,6 +1,12 @@
## Compilation prompt
## Dealing with `civicrm/composer-compile-plugin` prompts
After almost every Composer operation you will see this prompt:
During installation you will see this prompt:
```sh
civicrm/composer-compile-plugin contains a Composer plugin which is currently not in your allow-plugins config. See https://getcomposer.org/allow-plugins
Do you trust "civicrm/composer-compile-plugin" to execute code and wish to enable it now? (writes "allow-plugins" to composer.json) [y,n,d,?]
```
And after almost any Composer operation you will see this prompt:
```sh
The following packages have new compilation tasks:
- retailcrm/api-client-php has 1 task
@ -9,7 +15,7 @@ Allow these packages to compile? ([y]es, [a]lways, [n]o, [l]ist, [h]elp)
```
That's because the API client utilizes code generation to speed up the serialization and deserialization of the requests. However,
this prompt may be annoying and sometimes can even break the application lifecycle pipeline (in the CI/CD environment). We can't just
these prompts may be annoying and sometimes can even break the application lifecycle pipeline (in the CI/CD environment). We can't just
disable it for everyone [because of security concerns](https://github.com/composer/composer/issues/1193). But you can disable it for your project.
There are three ways of disabling this prompt:
@ -17,54 +23,65 @@ There are three ways of disabling this prompt:
2. Automated way.
3. Manual way.
### Disable compilation prompt during the installation
### Disable compilation prompts during the installation
Just choose `[a]lways` option by pressing `a` followed by Enter. This will automatically edit your `composer.json` and will disable
the compilation prompt for you. No additional steps are needed.
Press `'y'` when you see this message:
```sh
civicrm/composer-compile-plugin contains a Composer plugin which is currently not in your allow-plugins config. See https://getcomposer.org/allow-plugins
Do you trust "civicrm/composer-compile-plugin" to execute code and wish to enable it now? (writes "allow-plugins" to composer.json) [y,n,d,?]
```
### Disable or enable compilation prompt via CLI
And when you see this prompt, press `'a'`:
```sh
The following packages have new compilation tasks:
- retailcrm/api-client-php has 1 task
Alternatively, you can use `retailcrm-client` CLI utility. It will be in your binary directory. By default, it'll be in the
`vendor/bin` directory if not defined otherwise in the composer.json `config.bin-dir` entry.
Allow these packages to compile? ([y]es, [a]lways, [n]o, [l]ist, [h]elp)
```
The only benefit of this utility is the fact that it also can enable the prompt again.
That's it. Code generation is now enabled.
#### Disabling compilation prompt
You can disable the compiler prompt by running this command:
### I've chosen something else, now API client doesn't work!
That happens. We provide special CLI utility which will automatically configure your `composer.json` to enable code generation.
Just run this command inside your project after API client installation:
```sh
./vendor/bin/retailcrm-client compiler:prompt
```
Replace `vendor/bin` with your bin directory path if it's different from the default.
You should see this message after that:
You should see this message after running the command:
```sh
✓ Done, generator prompt is now enabled.
✓ Done, code generation has been enabled.
```
You may also want to run code generation manually once. It can be achieved by running this command:
```sh
composer compile --all
```
#### Enabling compilation prompt
**Note:** `retailcrm-client` should be in your binary directory. By default it is set to `vendor/bin`. You can check `config.bin-dir`
value in your `composer.json` and update paths in the commands above accordingly.
**Note (2):** `compiler:prompt` command has `--revert` flag. You can use it if you want to disable automatic code generation for some reason.
If you want to revert this change and enable the compilation prompt then just run this command again with the `--activate` flag:
### Disabling compilation prompts manually
```sh
./vendor/bin/retailcrm-client compiler:prompt --activate
It is possible to replicate the same actions manually. First, you will need to enable compiler plugin. Add the plugin
to the `config.allow-plugins` segment of your `composer.json` file:
```json
"allow-plugins": {
"civicrm/composer-compile-plugin": true
}
```
### Disable or enable compilation prompt manually
#### Enabling compilation prompt
It is possible to replicate the same actions manually. Add these params into the `extra` segment of your `composer.json` if
you want to execute code generation automatically after library installation or update.
After that add these params into the `extra` segment of your `composer.json`:
```json
"compile-mode": "whitelist",
"compile-whitelist": ["retailcrm/api-client-php"]
```
Your `composer.json` file will look like this:
Your `composer.json` file should look like this:
```json
{
"name": "author/some-project",
@ -77,6 +94,11 @@ Your `composer.json` file will look like this:
"nyholm/psr7": "^1.4",
"retailcrm/api-client-php": "~6.0"
},
"config": {
"allow-plugins": {
"civicrm/composer-compile-plugin": true
}
},
"extra": {
"compile-mode": "whitelist",
"compile-whitelist": ["retailcrm/api-client-php"]
@ -85,7 +107,3 @@ Your `composer.json` file will look like this:
```
Voilà! You won't see the annoying prompt again.
#### Enabling compilation prompt
Just remove `extra.compile-mode` and `extra.compile-whitelist` params from your `composer.json`.

View file

@ -1,8 +1,9 @@
# Documentation
* [Compilation prompt](compilation_prompt.md)
+ [Disable or enable compilation prompt via CLI](compilation_prompt.md#disable-or-enable-compilation-prompt-via-cli)
+ [Disable or enable compilation prompt manually](compilation_prompt.md#disable-or-enable-compilation-prompt-manually)
* [Dealing with `civicrm/composer-compile-plugin` prompts](compilation_prompt.md)
+ [Disable compilation prompts during the installation](compilation_prompt.md#disable-compilation-prompts-during-the-installation)
+ [I've chosen something else, now API client doesn't work!](compilation_prompt.md#ive-chosen-something-else-now-api-client-doesnt-work)
+ [Disabling compilation prompts manually](compilation_prompt.md#disabling-compilation-prompts-manually)
* [Client structure](structure.md)
+ [Design principles](structure.md#design-principles)
+ [Resource groups](structure.md#resource-groups)

View file

@ -24,9 +24,11 @@ The resource groups list into which client is separated:
* `customers`
* `customersCorporate`
* `delivery`
* `features`
* `files`
* `integration`
* `loyalty`
* `notifications`
* `orders`
* `packs`
* `payments`
@ -39,7 +41,8 @@ The resource groups list into which client is separated:
* `users`
* `verification`
* `statistics`
* `webAnalytics`
Every group implements corresponding API documentation block:
There is also a special `customMethods` group that is used for custom API methods. Each group except this one implements corresponding API documentation block:
* [English](https://docs.retailcrm.pro/Developers/API/APIVersions/APIv5)
* [Русский](https://docs.retailcrm.ru/Developers/API/APIVersions/APIv5)

View file

@ -10,4 +10,8 @@
<file>src/</file>
<file>tests/</file>
<exclude-pattern>src/Component/Serializer/Generator/*</exclude-pattern>
<exclude-pattern>src/Component/Serializer/Parser/*</exclude-pattern>
<exclude-pattern>src/Component/Serializer/ArraySupportDecorator.php</exclude-pattern>
</ruleset>

View file

@ -44,4 +44,6 @@
</rule>
<exclude-pattern>tests/*</exclude-pattern>
<exclude-pattern>src/Component/Serializer/Generator/*</exclude-pattern>
<exclude-pattern>src/Component/Serializer/Parser/*</exclude-pattern>
</ruleset>

View file

@ -0,0 +1,246 @@
parameters:
ignoreErrors:
-
message: "#^Parameter \\#1 \\$config of static method Liip\\\\Serializer\\\\Configuration\\\\GeneratorConfiguration\\:\\:createFomArray\\(\\) expects array\\{default_group_combinations\\?\\: array\\<int, array\\<int, string\\>\\>\\|null, default_versions\\?\\: array\\<int, string\\>\\|null, classes\\?\\: array\\<class\\-string, array\\<string, mixed\\>\\>\\|null, options\\?\\: array\\<string, mixed\\>\\}, array\\{default_group_combinations\\: array\\{\\}, default_versions\\: array\\{\\}, classes\\: non\\-empty\\-array\\<string, array\\{\\}\\>\\} given\\.$#"
count: 1
path: src/Component/ModelsGenerator.php
-
message: "#^Parameter \\#3 \\$classesToGenerate of class RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Generator\\\\DeserializerGenerator constructor expects array\\<int, class\\-string\\>, array\\<string\\> given\\.$#"
count: 1
path: src/Component/ModelsGenerator.php
-
message: "#^Parameter \\#2 \\$method of method Liip\\\\Serializer\\\\Template\\\\Deserialization\\:\\:renderSetter\\(\\) expects string, string\\|null given\\.$#"
count: 1
path: src/Component/Serializer/Generator/DeserializerGenerator.php
-
message: "#^Parameter \\#4 \\$stack of method RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Generator\\\\DeserializerGenerator\\:\\:generateCodeForClass\\(\\) expects array\\<string, int\\<1, max\\>\\>, array given\\.$#"
count: 2
path: src/Component/Serializer/Generator/DeserializerGenerator.php
-
message: "#^Method RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Generator\\\\SerializerGenerator\\:\\:buildSerializerFunctionName\\(\\) should return string but returns string\\|null\\.$#"
count: 1
path: src/Component/Serializer/Generator/SerializerGenerator.php
-
message: "#^Parameter \\#2 \\$method of method Liip\\\\Serializer\\\\Template\\\\Serialization\\:\\:renderGetter\\(\\) expects string, string\\|null given\\.$#"
count: 1
path: src/Component/Serializer/Generator/SerializerGenerator.php
-
message: "#^Parameter \\#3 \\$serializerGroups of method RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Generator\\\\SerializerGenerator\\:\\:generateCodeForClass\\(\\) expects array\\<int, string\\>, array given\\.$#"
count: 4
path: src/Component/Serializer/Generator/SerializerGenerator.php
-
message: "#^Class RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Parser\\\\JMSCore\\\\Type\\\\Lexer extends generic class Doctrine\\\\Common\\\\Lexer\\\\AbstractLexer but does not specify its types\\: T, V$#"
count: 1
path: src/Component/Serializer/Parser/JMSCore/Type/Lexer.php
-
message: "#^Method RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Parser\\\\JMSCore\\\\Type\\\\Lexer\\:\\:getType\\(\\) has parameter \\$value with no type specified\\.$#"
count: 1
path: src/Component/Serializer/Parser/JMSCore/Type/Lexer.php
-
message: "#^Method RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Parser\\\\JMSCore\\\\Type\\\\Lexer\\:\\:parse\\(\\) has no return type specified\\.$#"
count: 1
path: src/Component/Serializer/Parser/JMSCore/Type/Lexer.php
-
message: "#^Parameter \\#1 \\$haystack of function stripos expects string, float\\|int\\|string given\\.$#"
count: 1
path: src/Component/Serializer/Parser/JMSCore/Type/Lexer.php
-
message: "#^Parameter \\#1 \\$haystack of function strpos expects string, float\\|int\\|string given\\.$#"
count: 1
path: src/Component/Serializer/Parser/JMSCore/Type/Lexer.php
-
message: "#^Method RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Parser\\\\JMSCore\\\\Type\\\\Parser\\:\\:getConstant\\(\\) should return string but returns string\\|false\\.$#"
count: 1
path: src/Component/Serializer/Parser/JMSCore/Type/Parser.php
-
message: "#^Method RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Parser\\\\JMSCore\\\\Type\\\\Parser\\:\\:parse\\(\\) return type has no value type specified in iterable type array\\.$#"
count: 1
path: src/Component/Serializer/Parser/JMSCore/Type/Parser.php
-
message: "#^Method RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Parser\\\\JMSCore\\\\Type\\\\Parser\\:\\:parse\\(\\) should return array but returns mixed\\.$#"
count: 1
path: src/Component/Serializer/Parser/JMSCore/Type/Parser.php
-
message: "#^Method RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Parser\\\\JMSCore\\\\Type\\\\Parser\\:\\:visitArrayType\\(\\) return type has no value type specified in iterable type array\\.$#"
count: 1
path: src/Component/Serializer/Parser/JMSCore/Type/Parser.php
-
message: "#^Method RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Parser\\\\JMSCore\\\\Type\\\\Parser\\:\\:visitCompoundType\\(\\) return type has no value type specified in iterable type array\\.$#"
count: 1
path: src/Component/Serializer/Parser/JMSCore/Type/Parser.php
-
message: "#^Method RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Parser\\\\JMSCore\\\\Type\\\\Parser\\:\\:visitSimpleType\\(\\) never returns string so it can be removed from the return type\\.$#"
count: 1
path: src/Component/Serializer/Parser/JMSCore/Type/Parser.php
-
message: "#^Method RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Parser\\\\JMSCore\\\\Type\\\\ParserInterface\\:\\:parse\\(\\) return type has no value type specified in iterable type array\\.$#"
count: 1
path: src/Component/Serializer/Parser/JMSCore/Type/ParserInterface.php
-
message: "#^Method RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Parser\\\\JMSParser\\:\\:gatherClassAnnotations\\(\\) has parameter \\$reflectionClass with generic class ReflectionClass but does not specify its types\\: T$#"
count: 1
path: src/Component/Serializer/Parser/JMSParser.php
-
message: "#^Method RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Parser\\\\JMSParser\\:\\:getMethodName\\(\\) has parameter \\$annotations with no value type specified in iterable type array\\.$#"
count: 1
path: src/Component/Serializer/Parser/JMSParser.php
-
message: "#^Method RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Parser\\\\JMSParser\\:\\:getProperty\\(\\) has parameter \\$annotations with no value type specified in iterable type array\\.$#"
count: 1
path: src/Component/Serializer/Parser/JMSParser.php
-
message: "#^Method RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Parser\\\\JMSParser\\:\\:getReturnType\\(\\) has parameter \\$reflClass with generic class ReflectionClass but does not specify its types\\: T$#"
count: 1
path: src/Component/Serializer/Parser/JMSParser.php
-
message: "#^Method RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Parser\\\\JMSParser\\:\\:getSerializedName\\(\\) has parameter \\$annotations with no value type specified in iterable type array\\.$#"
count: 1
path: src/Component/Serializer/Parser/JMSParser.php
-
message: "#^Method RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Parser\\\\JMSParser\\:\\:isPostDeserializeMethod\\(\\) has parameter \\$annotations with no value type specified in iterable type array\\.$#"
count: 1
path: src/Component/Serializer/Parser/JMSParser.php
-
message: "#^Method RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Parser\\\\JMSParser\\:\\:isVirtualProperty\\(\\) has parameter \\$annotations with no value type specified in iterable type array\\.$#"
count: 1
path: src/Component/Serializer/Parser/JMSParser.php
-
message: "#^Method RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Parser\\\\JMSParser\\:\\:parseClass\\(\\) has parameter \\$reflClass with generic class ReflectionClass but does not specify its types\\: T$#"
count: 1
path: src/Component/Serializer/Parser/JMSParser.php
-
message: "#^Method RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Parser\\\\JMSParser\\:\\:parseMethods\\(\\) has parameter \\$reflClass with generic class ReflectionClass but does not specify its types\\: T$#"
count: 1
path: src/Component/Serializer/Parser/JMSParser.php
-
message: "#^Method RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Parser\\\\JMSParser\\:\\:parseProperties\\(\\) has parameter \\$reflClass with generic class ReflectionClass but does not specify its types\\: T$#"
count: 1
path: src/Component/Serializer/Parser/JMSParser.php
-
message: "#^Method RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Parser\\\\JMSParser\\:\\:parsePropertyAnnotations\\(\\) has parameter \\$annotations with no value type specified in iterable type array\\.$#"
count: 1
path: src/Component/Serializer/Parser/JMSParser.php
-
message: "#^Parameter \\#1 \\$objectOrClass of class ReflectionClass constructor expects class\\-string\\<T of object\\>\\|T of object, string given\\.$#"
count: 1
path: src/Component/Serializer/Parser/JMSParser.php
-
message: "#^Class Doctrine\\\\Common\\\\Collections\\\\ArrayCollection not found\\.$#"
count: 1
path: src/Component/Serializer/Parser/JMSTypeParser.php
-
message: "#^Class Doctrine\\\\Common\\\\Collections\\\\Collection not found\\.$#"
count: 1
path: src/Component/Serializer/Parser/JMSTypeParser.php
-
message: "#^Method RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Parser\\\\JMSTypeParser\\:\\:parseType\\(\\) has parameter \\$typeInfo with no value type specified in iterable type array\\.$#"
count: 1
path: src/Component/Serializer/Parser/JMSTypeParser.php
-
message: "#^Parameter \\#4 \\$traversableClass of class Liip\\\\MetadataParser\\\\Metadata\\\\PropertyTypeIterable constructor expects class\\-string\\<Traversable\\>\\|null, string\\|null given\\.$#"
count: 1
path: src/Component/Serializer/Parser/JMSTypeParser.php
-
message: "#^Cannot access property \\$value on RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Parser\\\\JMSCore\\\\Type\\\\Token\\|null\\.$#"
count: 2
path: src/Component/Serializer/Parser/JMSCore/Type/Parser.php
-
message: "#^Parameter \\#1 \\$string of function strlen expects string, int\\|string given\\.$#"
count: 1
path: src/Component/Serializer/Parser/JMSCore/Type/Parser.php
-
message: "#^Parameter \\#1 \\$value of method RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Parser\\\\JMSCore\\\\Type\\\\Parser\\:\\:getConstant\\(\\) expects int, int\\<min, 0\\>\\|int\\<4, 8\\>\\|int\\<11, max\\>\\|string\\|null given\\.$#"
count: 1
path: src/Component/Serializer/Parser/JMSCore/Type/Parser.php
-
message: "#^Parameter \\#1 \\$value of method RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Parser\\\\JMSCore\\\\Type\\\\Parser\\:\\:getConstant\\(\\) expects int, int\\|string\\|null given\\.$#"
count: 1
path: src/Component/Serializer/Parser/JMSCore/Type/Parser.php
-
message: "#^Property RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Parser\\\\JMSCore\\\\Type\\\\Parser\\:\\:\\$token with generic class RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Parser\\\\JMSCore\\\\Type\\\\Token does not specify its types\\: T, V$#"
count: 1
path: src/Component/Serializer/Parser/JMSCore/Type/Parser.php
-
message: "#^Access to an undefined property object\\:\\:\\$position\\.$#"
count: 1
path: src/Component/Serializer/Parser/JMSCore/Type/Token.php
-
message: "#^Access to an undefined property object\\:\\:\\$type\\.$#"
count: 1
path: src/Component/Serializer/Parser/JMSCore/Type/Token.php
-
message: "#^Access to an undefined property object\\:\\:\\$value\\.$#"
count: 1
path: src/Component/Serializer/Parser/JMSCore/Type/Token.php
-
message: "#^Method RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Parser\\\\JMSCore\\\\Type\\\\Token\\:\\:fromArray\\(\\) has parameter \\$source with no value type specified in iterable type array\\.$#"
count: 1
path: src/Component/Serializer/Parser/JMSCore/Type/Token.php
-
message: "#^Method RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Parser\\\\JMSCore\\\\Type\\\\Token\\:\\:fromArray\\(\\) return type with generic class RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Parser\\\\JMSCore\\\\Type\\\\Token does not specify its types\\: T, V$#"
count: 1
path: src/Component/Serializer/Parser/JMSCore/Type/Token.php
-
message: "#^Method RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Parser\\\\JMSCore\\\\Type\\\\Token\\:\\:fromObject\\(\\) return type with generic class RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Parser\\\\JMSCore\\\\Type\\\\Token does not specify its types\\: T, V$#"
count: 1
path: src/Component/Serializer/Parser/JMSCore/Type/Token.php
-
message: "#^Property RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Parser\\\\JMSCore\\\\Type\\\\Token\\<T of int\\|string,V of int\\|string\\>\\:\\:\\$type \\(\\(T of int\\|string\\)\\|null\\) does not accept int\\|string\\.$#"
count: 1
path: src/Component/Serializer/Parser/JMSCore/Type/Token.php
-
message: "#^Cannot call method getParameters\\(\\) on ReflectionMethod\\|null\\.$#"
count: 1
path: src/Component/Serializer/Parser/JMSTypeParser.php
-
message: "#^Property RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Parser\\\\JMSTypeParser\\:\\:\\$useArrayDateFormat has no type specified\\.$#"
count: 1
path: src/Component/Serializer/Parser/JMSTypeParser.php

View file

@ -1,4 +1,6 @@
parameters:
excludePaths:
- src/Component/Serializer/ArraySupportDecorator.php
ignoreErrors:
-
message: "#^Unsafe call to private method RetailCrm\\\\Api\\\\Builder\\\\ClientBuilder\\:\\:buildHandlersChain\\(\\) through static\\:\\:\\.$#"
@ -16,37 +18,37 @@ parameters:
path: src/Client.php
-
message: "#^Cannot access offset 'compile\\-mode' on mixed\\.$#"
count: 2
path: src/Command/CompilerPromptCommand.php
-
message: "#^Cannot access offset 'compile\\-whitelist' on mixed\\.$#"
count: 2
path: src/Command/CompilerPromptCommand.php
-
message: "#^Parameter \\#1 \\$value of function count expects array\\|Countable, mixed given\\.$#"
message: "#^Cannot assign new offset to array\\<string\\>\\|string\\.$#"
count: 1
path: src/Command/CompilerPromptCommand.php
-
message: "#^Parameter \\#2 \\$array of function array_key_exists expects array, mixed given\\.$#"
message: "#^Parameter \\#1 \\$array of function array_filter expects array, string given\\.$#"
count: 1
path: src/Command/CompilerPromptCommand.php
-
message: "#^Parameter \\#2 \\$haystack of function in_array expects array, array\\<string\\>\\|string given\\.$#"
count: 1
path: src/Command/CompilerPromptCommand.php
-
message: "#^Unsafe access to private constant RetailCrm\\\\Api\\\\Command\\\\CompilerPromptCommand\\:\\:COMPILER_PLUGIN through static\\:\\:\\.$#"
count: 3
path: src/Command/CompilerPromptCommand.php
-
message: "#^Unsafe access to private constant RetailCrm\\\\Api\\\\Command\\\\CompilerPromptCommand\\:\\:PACKAGE_NAME through static\\:\\:\\.$#"
count: 5
path: src/Command/CompilerPromptCommand.php
-
message: "#^Unsafe call to private method RetailCrm\\\\Api\\\\Command\\\\CompilerPromptCommand\\:\\:activatePrompt\\(\\) through static\\:\\:\\.$#"
message: "#^Unsafe call to private method RetailCrm\\\\Api\\\\Command\\\\CompilerPromptCommand\\:\\:activateAutoCompiler\\(\\) through static\\:\\:\\.$#"
count: 1
path: src/Command/CompilerPromptCommand.php
-
message: "#^Unsafe call to private method RetailCrm\\\\Api\\\\Command\\\\CompilerPromptCommand\\:\\:deactivatePrompt\\(\\) through static\\:\\:\\.$#"
message: "#^Unsafe call to private method RetailCrm\\\\Api\\\\Command\\\\CompilerPromptCommand\\:\\:activatePlugin\\(\\) through static\\:\\:\\.$#"
count: 1
path: src/Command/CompilerPromptCommand.php
-
message: "#^Unsafe call to private method RetailCrm\\\\Api\\\\Command\\\\CompilerPromptCommand\\:\\:deactivateAutoCompiler\\(\\) through static\\:\\:\\.$#"
count: 1
path: src/Command/CompilerPromptCommand.php
@ -95,11 +97,6 @@ parameters:
count: 1
path: src/Component/FormData/FormEncoder.php
-
message: "#^Parameter \\#2 \\$result of method RetailCrm\\\\Api\\\\Component\\\\FormData\\\\FormEncoder\\:\\:processPostSerialize\\(\\) expects array, array given\\.$#"
count: 1
path: src/Component/FormData/FormEncoder.php
-
message: "#^Parameter \\#1 \\$object of function get_class expects object, mixed given\\.$#"
count: 1
@ -117,16 +114,11 @@ parameters:
-
message: "#^Cannot cast mixed to float\\.$#"
count: 2
path: src/Component/FormData/Strategy/Encode/SimpleTypeStrategy.php
-
message: "#^Cannot cast mixed to int\\.$#"
count: 1
path: src/Component/FormData/Strategy/Encode/SimpleTypeStrategy.php
-
message: "#^Cannot cast mixed to string\\.$#"
message: "#^Cannot cast mixed to int\\.$#"
count: 1
path: src/Component/FormData/Strategy/Encode/SimpleTypeStrategy.php
@ -180,6 +172,11 @@ parameters:
count: 1
path: src/Component/ModelsGenerator.php
-
message: "#^Property RetailCrm\\\\Api\\\\Component\\\\PhpFilesIterator\\:\\:\\$parent \\(Iterator\\<int\\|string, array\\|string\\>\\) does not accept RegexIterator\\<mixed, mixed, Traversable\\<TKey, TValue\\>\\>\\.$#"
count: 1
path: src/Component/PhpFilesIterator.php
-
message: "#^Property RetailCrm\\\\Api\\\\Component\\\\PhpFilesIterator\\:\\:\\$parent type has no value type specified in iterable type array\\.$#"
count: 1
@ -196,12 +193,12 @@ parameters:
path: src/Component/Serializer/ArraySupportDecorator.php
-
message: "#^Parameter \\#1 \\$data of method RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\ArraySupportDecorator\\:\\:decodeArray\\(\\) expects array, mixed given\\.$#"
count: 1
message: "#^Method RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\ArraySupportDecorator\\:\\:getArrayValueType\\(\\) should return string but returns array\\<string\\>\\.$#"
count: 2
path: src/Component/Serializer/ArraySupportDecorator.php
-
message: "#^Parameter \\#1 \\$data of method RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\ArraySupportDecorator\\:\\:encodeArray\\(\\) expects array, mixed given\\.$#"
message: "#^Parameter \\#1 \\$data of method RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\ArraySupportDecorator\\:\\:decodeArray\\(\\) expects array, mixed given\\.$#"
count: 1
path: src/Component/Serializer/ArraySupportDecorator.php
@ -215,61 +212,16 @@ parameters:
count: 2
path: src/Component/Serializer/ArraySupportDecorator.php
-
message: "#^Unsafe access to private constant RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Generator\\\\DeserializerGenerator\\:\\:FILENAME_PREFIX through static\\:\\:\\.$#"
count: 1
path: src/Component/Serializer/Generator/DeserializerGenerator.php
-
message: "#^Argument of an invalid type mixed supplied for foreach, only iterables are supported\\.$#"
count: 1
path: src/Component/Serializer/Generator/SerializerGenerator.php
-
message: "#^Cannot call method getClassName\\(\\) on mixed\\.$#"
count: 1
path: src/Component/Serializer/Generator/SerializerGenerator.php
-
message: "#^Cannot call method getGroups\\(\\) on mixed\\.$#"
count: 3
path: src/Component/Serializer/Generator/SerializerGenerator.php
-
message: "#^Cannot call method getVersions\\(\\) on mixed\\.$#"
count: 1
path: src/Component/Serializer/Generator/SerializerGenerator.php
-
message: "#^Unsafe access to private constant RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Generator\\\\SerializerGenerator\\:\\:FILENAME_PREFIX through static\\:\\:\\.$#"
count: 1
path: src/Component/Serializer/Generator/SerializerGenerator.php
-
message: "#^Method RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\ModelsChecksumGenerator\\:\\:getStoredChecksums\\(\\) should return array\\<string, string\\> but returns mixed\\.$#"
count: 1
path: src/Component/Serializer/ModelsChecksumGenerator.php
-
message: "#^Parameter \\#1 \\$iterator of class RetailCrm\\\\Api\\\\Component\\\\FilesIteratorChecksumGenerator constructor expects Iterator\\<mixed, mixed\\>, RetailCrm\\\\Api\\\\Component\\\\PhpFilesIterator given\\.$#"
count: 1
path: src/Component/Serializer/ModelsChecksumGenerator.php
-
message: "#^Unsafe call to private method RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\ModelsChecksumGenerator\\:\\:getChecksumFileName\\(\\) through static\\:\\:\\.$#"
count: 4
path: src/Component/Serializer/ModelsChecksumGenerator.php
-
message: "#^Method RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Parser\\\\BaseJMSParser\\:\\:parse\\(\\) should return array but returns mixed\\.$#"
count: 1
path: src/Component/Serializer/Parser/BaseJMSParser.php
-
message: "#^Parameter \\#1 \\$object of function get_class expects object, mixed given\\.$#"
count: 2
path: src/Component/Serializer/Parser/JMSParser.php
-
message: "#^Parameter \\#2 \\$string2 of function strncmp expects string, class\\-string\\|false given\\.$#"
count: 1
@ -280,86 +232,26 @@ parameters:
count: 1
path: src/Component/Serializer/Parser/JMSParser.php
-
message: "#^Cannot access offset 0 on mixed\\.$#"
count: 2
path: src/Component/Serializer/Parser/JMSTypeParser.php
-
message: "#^Cannot access offset 1 on mixed\\.$#"
count: 2
path: src/Component/Serializer/Parser/JMSTypeParser.php
-
message: "#^Cannot access offset 2 on mixed\\.$#"
count: 1
path: src/Component/Serializer/Parser/JMSTypeParser.php
-
message: "#^Parameter \\#1 \\$className of class Liip\\\\MetadataParser\\\\Metadata\\\\PropertyTypeClass constructor expects string, mixed given\\.$#"
count: 1
path: src/Component/Serializer/Parser/JMSTypeParser.php
-
message: "#^Parameter \\#1 \\$className of static method Liip\\\\MetadataParser\\\\Metadata\\\\PropertyTypeDateTime\\:\\:fromDateTimeClass\\(\\) expects string, mixed given\\.$#"
count: 2
path: src/Component/Serializer/Parser/JMSTypeParser.php
-
message: "#^Parameter \\#1 \\$format of class Liip\\\\MetadataParser\\\\Metadata\\\\DateTimeOptions constructor expects string\\|null, mixed given\\.$#"
count: 1
path: src/Component/Serializer/Parser/JMSTypeParser.php
-
message: "#^Parameter \\#1 \\$typeInfo of method RetailCrm\\\\Api\\\\Component\\\\Serializer\\\\Parser\\\\JMSTypeParser\\:\\:parseType\\(\\) expects array, mixed given\\.$#"
count: 2
path: src/Component/Serializer/Parser/JMSTypeParser.php
-
message: "#^Parameter \\#1 \\$typeName of class Liip\\\\MetadataParser\\\\Metadata\\\\PropertyTypePrimitive constructor expects string, mixed given\\.$#"
count: 1
path: src/Component/Serializer/Parser/JMSTypeParser.php
-
message: "#^Parameter \\#1 \\$typeName of static method Liip\\\\MetadataParser\\\\Metadata\\\\PropertyTypeDateTime\\:\\:isTypeDateTime\\(\\) expects string, mixed given\\.$#"
count: 2
path: src/Component/Serializer/Parser/JMSTypeParser.php
-
message: "#^Parameter \\#1 \\$typeName of static method Liip\\\\MetadataParser\\\\Metadata\\\\PropertyTypePrimitive\\:\\:isTypePrimitive\\(\\) expects string, mixed given\\.$#"
count: 1
path: src/Component/Serializer/Parser/JMSTypeParser.php
-
message: "#^Parameter \\#1 \\$value of function count expects array\\|Countable, mixed given\\.$#"
count: 3
path: src/Component/Serializer/Parser/JMSTypeParser.php
-
message: "#^Parameter \\#2 \\$zone of class Liip\\\\MetadataParser\\\\Metadata\\\\DateTimeOptions constructor expects string\\|null, mixed given\\.$#"
count: 1
path: src/Component/Serializer/Parser/JMSTypeParser.php
-
message: "#^Parameter \\#3 \\$deserializeFormat of class Liip\\\\MetadataParser\\\\Metadata\\\\DateTimeOptions constructor expects string\\|null, mixed given\\.$#"
count: 1
path: src/Component/Serializer/Parser/JMSTypeParser.php
-
message: "#^Unsafe call to private method RetailCrm\\\\Api\\\\Component\\\\Transformer\\\\DateTimeTransformer\\:\\:createFromFormat\\(\\) through static\\:\\:\\.$#"
count: 3
path: src/Component/Transformer/DateTimeTransformer.php
-
message: "#^Method RetailCrm\\\\Api\\\\Event\\\\AbstractRequestEvent\\:\\:getApiKey\\(\\) should return string but returns array\\|string\\.$#"
count: 1
path: src/Event/AbstractRequestEvent.php
-
message: "#^Property RetailCrm\\\\Api\\\\Event\\\\AbstractRequestEvent\\:\\:\\$apiKey \\(string\\) does not accept array\\|string\\.$#"
count: 1
path: src/Event/AbstractRequestEvent.php
-
message: "#^Unsafe call to private method RetailCrm\\\\Api\\\\Exception\\\\ApiException\\:\\:getErrorMessage\\(\\) through static\\:\\:\\.$#"
count: 1
path: src/Exception/ApiException.php
-
message: "#^Parameter \\#3 \\.\\.\\.\\$values of function sprintf expects bool\\|float\\|int\\|string\\|null, mixed given\\.$#"
count: 1
path: src/Exception/ClientException.php
-
message: "#^Property RetailCrm\\\\Api\\\\Model\\\\Response\\\\ErrorResponse\\:\\:\\$errorMsg \\(string\\) on left side of \\?\\? is not nullable\\.$#"
count: 2
@ -375,11 +267,6 @@ parameters:
count: 1
path: src/Handler/Request/PsrRequestHandler.php
-
message: "#^Parameter \\#2 \\$code of class RetailCrm\\\\Api\\\\Exception\\\\Client\\\\HandlerException constructor expects int, mixed given\\.$#"
count: 1
path: src/Handler/Request/RequestDataHandler.php
-
message: "#^Unsafe call to private method RetailCrm\\\\Api\\\\Handler\\\\Request\\\\RequestDataHandler\\:\\:queryShouldBeUsed\\(\\) through static\\:\\:\\.$#"
count: 1
@ -420,6 +307,11 @@ parameters:
count: 1
path: src/Handler/Response/FilesDownloadResponseHandler.php
-
message: "#^Unsafe call to private method RetailCrm\\\\Api\\\\Handler\\\\Response\\\\FilesDownloadResponseHandler\\:\\:isFileRequest\\(\\) through static\\:\\:\\.$#"
count: 1
path: src/Handler/Response/FilesDownloadResponseHandler.php
-
message: "#^Property RetailCrm\\\\Api\\\\Model\\\\ResponseData\\:\\:\\$responseArray \\(array\\<int\\|string, mixed\\>\\) on left side of \\?\\? is not nullable\\.$#"
count: 1
@ -435,8 +327,3 @@ parameters:
count: 1
path: src/ResourceGroup/AbstractApiResourceGroup.php
-
message: "#^Parameter \\#2 \\$code of class RetailCrm\\\\Api\\\\Exception\\\\Client\\\\HttpClientException constructor expects int, mixed given\\.$#"
count: 1
path: src/ResourceGroup/AbstractApiResourceGroup.php

View file

@ -1,4 +1,5 @@
includes:
- phpstan-baseline-serializer.neon
- phpstan-baseline.neon # TODO: This should be removed eventually.
parameters:

View file

@ -18,15 +18,18 @@ use RetailCrm\Api\Interfaces\RequestTransformerInterface;
use RetailCrm\Api\Interfaces\ResponseTransformerInterface;
use RetailCrm\Api\ResourceGroup\Api;
use RetailCrm\Api\ResourceGroup\Costs;
use RetailCrm\Api\ResourceGroup\CustomerInteraction;
use RetailCrm\Api\ResourceGroup\Customers;
use RetailCrm\Api\ResourceGroup\CustomersCorporate;
use RetailCrm\Api\ResourceGroup\CustomFields;
use RetailCrm\Api\ResourceGroup\CustomMethods;
use RetailCrm\Api\ResourceGroup\Delivery;
use RetailCrm\Api\ResourceGroup\Features;
use RetailCrm\Api\ResourceGroup\Files;
use RetailCrm\Api\ResourceGroup\Integration;
use RetailCrm\Api\ResourceGroup\Inventories;
use RetailCrm\Api\ResourceGroup\Loyalty;
use RetailCrm\Api\ResourceGroup\Notifications;
use RetailCrm\Api\ResourceGroup\Orders;
use RetailCrm\Api\ResourceGroup\Packs;
use RetailCrm\Api\ResourceGroup\Payments;
@ -39,6 +42,7 @@ use RetailCrm\Api\ResourceGroup\Tasks;
use RetailCrm\Api\ResourceGroup\Telephony;
use RetailCrm\Api\ResourceGroup\Users;
use RetailCrm\Api\ResourceGroup\Verification;
use RetailCrm\Api\ResourceGroup\WebAnalytics;
/**
* Class Client
@ -64,6 +68,9 @@ class Client
/** @var \RetailCrm\Api\ResourceGroup\CustomFields */
public $customFields;
/** @var \RetailCrm\Api\ResourceGroup\CustomerInteraction */
public $customerInteraction;
/** @var \RetailCrm\Api\ResourceGroup\Customers */
public $customers;
@ -73,6 +80,9 @@ class Client
/** @var \RetailCrm\Api\ResourceGroup\Delivery */
public $delivery;
/** @var \RetailCrm\Api\ResourceGroup\Features */
public $features;
/** @var \RetailCrm\Api\ResourceGroup\Files */
public $files;
@ -82,6 +92,9 @@ class Client
/** @var \RetailCrm\Api\ResourceGroup\Loyalty */
public $loyalty;
/** @var \RetailCrm\Api\ResourceGroup\Notifications */
public $notifications;
/** @var \RetailCrm\Api\ResourceGroup\Orders */
public $orders;
@ -121,6 +134,9 @@ class Client
/** @var \RetailCrm\Api\ResourceGroup\CustomMethods */
public $customMethods;
/** @var \RetailCrm\Api\ResourceGroup\WebAnalytics */
public $webAnalytics;
/** @var StreamFactoryInterface */
private $streamFactory;
@ -175,6 +191,14 @@ class Client
$eventDispatcher,
$logger
);
$this->customerInteraction = new CustomerInteraction(
$url,
$httpClient,
$requestTransformer,
$responseTransformer,
$eventDispatcher,
$logger
);
$this->customers = new Customers(
$url,
$httpClient,
@ -199,6 +223,14 @@ class Client
$eventDispatcher,
$logger
);
$this->features = new Features(
$url,
$httpClient,
$requestTransformer,
$responseTransformer,
$eventDispatcher,
$logger
);
$this->files = new Files(
$url,
$httpClient,
@ -223,6 +255,14 @@ class Client
$eventDispatcher,
$logger
);
$this->notifications = new Notifications(
$url,
$httpClient,
$requestTransformer,
$responseTransformer,
$eventDispatcher,
$logger
);
$this->orders = new Orders(
$url,
$httpClient,
@ -327,6 +367,14 @@ class Client
$eventDispatcher,
$logger
);
$this->webAnalytics = new WebAnalytics(
$url,
$httpClient,
$requestTransformer,
$responseTransformer,
$eventDispatcher,
$logger
);
}
/**

View file

@ -25,6 +25,7 @@ use Symfony\Component\Console\Output\OutputInterface;
class CompilerPromptCommand extends Command
{
private const PACKAGE_NAME = 'retailcrm/api-client-php';
private const COMPILER_PLUGIN = 'civicrm/composer-compile-plugin';
/**
* Sets description and help for a command.
@ -32,20 +33,14 @@ class CompilerPromptCommand extends Command
protected function configure(): void
{
$this->setName('compiler:prompt')
->setDescription('Enable or disable composer compiler prompt.')
->setHelp('Use this command to suppress the compiler message and enable automatic compilation.')
->addOption(
'deactivate',
'd',
->setDescription('Enable or disable code generation during client installation & update.')
->setHelp(
'Use this command to enable or disable automatic code generation.'
)->addOption(
'revert',
'r',
InputOption::VALUE_OPTIONAL,
'Hide compiler prompt and run compiler task automatically. This mode is used by default.',
false
)
->addOption(
'activate',
'a',
InputOption::VALUE_OPTIONAL,
'Show compiler prompt and only run compiler task if user allows it.',
'You will need to run ./vendor/bin/retailcrm-client models:generate -a after each update.',
false
);
}
@ -78,12 +73,13 @@ class CompilerPromptCommand extends Command
return -1;
}
$activatePrompt = false !== $input->getOption('activate');
$revert = false !== $input->getOption('revert');
if ($activatePrompt) {
static::activatePrompt($json);
if ($revert) {
static::deactivateAutoCompiler($json);
} else {
static::deactivatePrompt($json);
static::activateAutoCompiler($json);
static::activatePlugin($json);
}
try {
@ -101,73 +97,110 @@ class CompilerPromptCommand extends Command
}
$output->writeln(sprintf(
'<fg=black;bg=green> ✓ Done, generator prompt is now %s.</>',
$activatePrompt ? 'enabled' : 'disabled'
'<fg=black;bg=green> ✓ Done, code generation has been %s.</>',
$revert ? 'disabled' : 'enabled'
));
return 0;
}
/**
* Activate prompt in the provided composer.json
* Activate plugin in the provided composer.json
*
* @param array<string, mixed> $composerJson
* @param array<string, array<string, array<string>|string>> $composerJson
*/
private static function activatePrompt(array &$composerJson): void
private static function activatePlugin(array &$composerJson): void
{
if (!array_key_exists('config', $composerJson)) {
$composerJson['config'] = [
'allow-plugins' => [
static::COMPILER_PLUGIN => true
]
];
return;
}
if (!array_key_exists('allow-plugins', $composerJson['config'])) {
$composerJson['config']['allow-plugins'] = [
static::COMPILER_PLUGIN => true
];
return;
}
$composerJson['config']['allow-plugins'][static::COMPILER_PLUGIN] = true;
}
/**
* Activate auto compiler in the provided composer.json
*
* @param array<string, array<string, array<string>|string>> $composerJson
*/
private static function activateAutoCompiler(array &$composerJson): void
{
if (!array_key_exists('extra', $composerJson)) {
$composerJson['extra'] = [];
$composerJson['extra'] = [
'compile-mode' => 'whitelist',
'compile-whitelist' => [self::PACKAGE_NAME]
];
return;
}
if (
array_key_exists('compile-whitelist', $composerJson['extra']) &&
is_array($composerJson['extra']['compile-whitelist']) &&
in_array(static::PACKAGE_NAME, $composerJson['extra']['compile-whitelist'], true)
) {
$composerJson['extra']['compile-whitelist'] = array_filter(
$composerJson['extra']['compile-whitelist'],
static function ($value) {
return static::PACKAGE_NAME !== $value;
}
);
if (array_key_exists('compile-mode', $composerJson['extra'])) {
if (
'prompt' === $composerJson['extra']['compile-mode'] ||
'none' === $composerJson['extra']['compile-mode']
) {
$composerJson['extra']['compile-mode'] = 'whitelist';
}
if ('all' === $composerJson['extra']['compile-mode']) {
return;
}
}
if (
empty($composerJson['extra']['compile-whitelist']) &&
array_key_exists('compile-mode', $composerJson['extra']) &&
'whitelist' === $composerJson['extra']['compile-mode']
) {
unset($composerJson['extra']['compile-whitelist'], $composerJson['extra']['compile-mode']);
$composerJson['extra']['compile-mode'] = 'whitelist';
if (!array_key_exists('compile-whitelist', $composerJson['extra'])) {
$composerJson['extra']['compile-whitelist'] = [self::PACKAGE_NAME];
return;
}
if (1 === count($composerJson['extra'])) {
unset($composerJson['extra']);
if (!in_array(self::PACKAGE_NAME, $composerJson['extra']['compile-whitelist'])) {
$composerJson['extra']['compile-whitelist'][] = self::PACKAGE_NAME;
}
}
/**
* Deactivate prompt in the provided composer.json
*
* @param array<string, mixed> $composerJson
* @param array<string, array<string>> $composerJson
*
* @SuppressWarnings(PHPMD.ElseExpression)
*/
private static function deactivatePrompt(array &$composerJson): void
private static function deactivateAutoCompiler(array &$composerJson): void
{
if (!array_key_exists('extra', $composerJson)) {
$composerJson['extra'] = [];
return;
}
if (
array_key_exists('compile-whitelist', $composerJson['extra']) &&
is_array($composerJson['extra']['compile-whitelist']) &&
!in_array(static::PACKAGE_NAME, $composerJson['extra']['compile-whitelist'], true)
null !== $composerJson['extra']['compile-whitelist']
) {
$composerJson['extra']['compile-whitelist'][] = static::PACKAGE_NAME;
} else {
$composerJson['extra']['compile-whitelist'] = [static::PACKAGE_NAME];
}
$composerJson['extra']['compile-whitelist'] = array_filter(
$composerJson['extra']['compile-whitelist'],
static function (string $item) {
return $item !== self::PACKAGE_NAME;
}
);
$composerJson['extra']['compile-mode'] = 'whitelist';
if (0 === count($composerJson['extra']['compile-whitelist'])) {
unset($composerJson['extra']['compile-whitelist']);
}
}
}
}

View file

@ -13,6 +13,7 @@ use RetailCrm\Api\Component\ModelsGenerator;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
/**
* Class GenerateModelsCommand
@ -82,7 +83,15 @@ class GenerateModelsCommand extends AbstractModelsProcessorCommand
$output->writeln('');
}
$generator->generate();
try {
$generator->generate();
} catch (\Throwable $throwable) {
$styled = new SymfonyStyle($input, $output);
$styled->error($throwable->getMessage());
$styled->writeln($throwable->getTraceAsString());
return -1;
}
$output->writeln(sprintf(
'<fg=black;bg=green> ✓ Done, generated code for %d models.</>',

View file

@ -67,7 +67,7 @@ class ComposerLocator
$counter++;
$dir = dirname($dir);
if (5 < $counter) {
if (2 < $counter) {
break;
}
}
@ -80,7 +80,9 @@ class ComposerLocator
*/
private static function getBaseDirectory(): string
{
return (string) realpath(implode(DIRECTORY_SEPARATOR, [__DIR__, '..', '..']));
$cwd = getcwd();
return false === $cwd ? (string) realpath(implode(DIRECTORY_SEPARATOR, [__DIR__, '..', '..'])) : $cwd;
}
/**

View file

@ -11,12 +11,12 @@ namespace RetailCrm\Api\Component;
use Doctrine\Common\Annotations\AnnotationReader;
use Liip\MetadataParser\Builder;
use Liip\MetadataParser\ModelParser\RawMetadata\PropertyCollection;
use Liip\MetadataParser\Parser;
use Liip\MetadataParser\RecursionChecker;
use Liip\Serializer\Configuration\GeneratorConfiguration;
use Liip\Serializer\Template\Deserialization;
use Liip\Serializer\Template\Serialization;
use RetailCrm\Api\Component\Utils;
use RetailCrm\Api\Component\Serializer\Generator\DeserializerGenerator;
use RetailCrm\Api\Component\Serializer\Generator\SerializerGenerator;
use RetailCrm\Api\Component\Serializer\ModelsChecksumGenerator;
@ -177,6 +177,7 @@ class ModelsGenerator
$configurationArray['classes'][$class] = [];
}
PropertyCollection::useIdenticalNamingStrategy();
$configuration = GeneratorConfiguration::createFomArray($configurationArray);
$parsers = [new JMSParser(new AnnotationReader())];
$builder = new Builder(new Parser($parsers), new RecursionChecker(null, []));

View file

@ -86,6 +86,7 @@ class PhpFilesIterator implements Iterator
*
* @return int|string
*/
#[\ReturnTypeWillChange]
public function key()
{
return $this->parent->key();

View file

@ -16,212 +16,424 @@ use Liip\Serializer\Exception\UnsupportedFormatException;
use Liip\Serializer\SerializerInterface;
use Pnz\JsonException\Json;
/**
* Class ArraySupportDecorator
*
* @category ArraySupportDecorator
* @package RetailCrm\Api\Component\Serializer
*/
class ArraySupportDecorator implements SerializerInterface
{
/** @var \Liip\Serializer\SerializerInterface */
private $serializer;
if (PHP_VERSION_ID >= 80000) {
/**
* ArraySupportDecorator constructor.
* Class ArraySupportDecorator
*
* @param \Liip\Serializer\SerializerInterface $serializer
* @category ArraySupportDecorator
* @package RetailCrm\Api\Component\Serializer
*/
public function __construct(SerializerInterface $serializer)
class ArraySupportDecorator implements SerializerInterface
{
$this->serializer = $serializer;
}
/** @var \Liip\Serializer\SerializerInterface */
private $serializer;
/**
* @inheritDoc
* @throws \JsonException
*/
public function serialize($data, string $format, ?Context $context = null): string
{
if ('json' !== $format) {
throw new UnsupportedFormatException('Liip serializer only supports JSON for now');
/**
* ArraySupportDecorator constructor.
*
* @param \Liip\Serializer\SerializerInterface $serializer
*/
public function __construct(SerializerInterface $serializer)
{
$this->serializer = $serializer;
}
if (is_array($data)) {
try {
return Json::encode($this->encodeArray($data, $context), JSON_UNESCAPED_SLASHES);
} catch (JsonException $exception) {
throw new Exception(
sprintf(
'Failed to JSON encode data for %s. This is not supposed to happen.',
// @phpstan-ignore-next-line
is_object($data) ? get_class($data) : gettype($data)
),
0,
$exception
);
}
}
return $this->serializer->serialize($data, $format, $context);
}
/**
* @inheritDoc
*/
public function deserialize(string $data, string $type, string $format, ?Context $context = null)
{
if ('json' !== $format) {
throw new UnsupportedFormatException('Liip serializer only supports JSON for now');
}
if (static::isArrayType($type)) {
try {
$array = Json::decode($data, true);
} catch (JsonException $exception) {
throw new Exception('Failed to JSON decode data. This is not supposed to happen.', 0, $exception);
/**
* @inheritDoc
* @throws \JsonException
*/
public function serialize($data, string $format, ?Context $context = null): string
{
if ('json' !== $format) {
throw new UnsupportedFormatException('Liip serializer only supports JSON for now');
}
return $this->serializer->fromArray($this->decodeArray($array, $type, $context), $type, $context);
}
return $this->serializer->deserialize($data, $type, $format, $context);
}
/**
* @inheritDoc
*
* @return array<int|string, mixed>
*/
public function toArray($data, ?Context $context = null): array
{
if (is_array($data)) {
return $this->encodeArray($data, $context);
}
return $this->serializer->toArray($data, $context);
}
/**
* @inheritDoc
*
* @param array<int|string, mixed> $data
*
* @return array<int|string, mixed>|object
*/
public function fromArray(array $data, string $type, ?Context $context = null)
{
if (static::isArrayType($type)) {
return $this->decodeArray($data, $type, $context);
}
return $this->serializer->fromArray($data, $type, $context);
}
/**
* Encodes array of objects into simple multidimensional array.
*
* @param mixed[] $data
* @param \Liip\Serializer\Context|null $context
*
* @return mixed[]
* @throws \Liip\Serializer\Exception\Exception
* @throws \Liip\Serializer\Exception\UnsupportedTypeException
*/
private function encodeArray(array $data, ?Context $context = null): array
{
$result = [];
foreach ($data as $key => $value) {
switch (gettype($value)) {
case 'array':
$result[$key] = $this->encodeArray($value, $context);
break;
case 'object':
$result[$key] = $this->serializer->toArray($value, $context);
break;
default:
$result[$key] = $value;
break;
if (is_array($data)) {
try {
return Json::encode($this->encodeArray($data, $context), JSON_UNESCAPED_SLASHES);
} catch (JsonException $exception) {
throw new Exception(
sprintf(
'Failed to JSON encode data for %s. This is not supposed to happen.',
// @phpstan-ignore-next-line
is_object($data) ? get_class($data) : gettype($data)
),
0,
$exception
);
}
}
return $this->serializer->serialize($data, $format, $context);
}
return $result;
}
/**
* @inheritDoc
*/
public function deserialize(string $data, string $type, string $format, ?Context $context = null): mixed
{
if ('json' !== $format) {
throw new UnsupportedFormatException('Liip serializer only supports JSON for now');
}
/**
* Decodes array of arrays to array of objects.
*
* @param mixed[] $data
* @param string $type
* @param \Liip\Serializer\Context|null $context
*
* @return array<int|string, mixed>
* @throws \Liip\Serializer\Exception\Exception
* @throws \Liip\Serializer\Exception\UnsupportedTypeException
*/
private function decodeArray(array $data, string $type, ?Context $context = null): array
{
$result = [];
$subtype = static::getArrayValueType($type);
if (class_exists($subtype)) {
foreach ($data as $key => $item) {
if (is_array($item)) {
$result[$key] = $this->decodeArray($item, $subtype, $context);
continue;
if (static::isArrayType($type)) {
try {
$array = Json::decode($data, true);
} catch (JsonException $exception) {
throw new Exception('Failed to JSON decode data. This is not supposed to happen.', 0, $exception);
}
$result[$key] = $item;
return $this->serializer->fromArray($this->decodeArray($array, $type, $context), $type, $context);
}
return $this->serializer->deserialize($data, $type, $format, $context);
}
/**
* @inheritDoc
*
* @return array<int|string, mixed>
*/
public function toArray($data, ?Context $context = null): array
{
if (is_array($data)) {
return $this->encodeArray($data, $context);
}
return $this->serializer->toArray($data, $context);
}
/**
* @inheritDoc
*
* @param array<int|string, mixed> $data
*
* @return array<int|string, mixed>|object
*/
public function fromArray(array $data, string $type, ?Context $context = null): mixed
{
if (static::isArrayType($type)) {
return $this->decodeArray($data, $type, $context);
}
return $this->serializer->fromArray($data, $type, $context);
}
/**
* Encodes array of objects into simple multidimensional array.
*
* @param mixed[] $data
* @param \Liip\Serializer\Context|null $context
*
* @return mixed[]
* @throws \Liip\Serializer\Exception\Exception
* @throws \Liip\Serializer\Exception\UnsupportedTypeException
*/
private function encodeArray(array $data, ?Context $context = null): array
{
$result = [];
foreach ($data as $key => $value) {
switch (gettype($value)) {
case 'array':
$result[$key] = $this->encodeArray($value, $context);
break;
case 'object':
$result[$key] = $this->serializer->toArray($value, $context);
break;
default:
$result[$key] = $value;
break;
}
}
return $result;
}
return $data;
}
/**
* Decodes array of arrays to array of objects.
*
* @param mixed[] $data
* @param string $type
* @param \Liip\Serializer\Context|null $context
*
* @return array<int|string, mixed>
* @throws \Liip\Serializer\Exception\Exception
* @throws \Liip\Serializer\Exception\UnsupportedTypeException
*/
private function decodeArray(array $data, string $type, ?Context $context = null): array
{
$result = [];
$subtype = static::getArrayValueType($type);
/**
* Returns true if provided type is an array.
*
* @param string $type
*
* @return bool
*/
private static function isArrayType(string $type): bool
{
return false !== strpos($type, 'array');
}
if (class_exists($subtype)) {
foreach ($data as $key => $item) {
if (is_array($item)) {
$result[$key] = $this->decodeArray($item, $subtype, $context);
continue;
}
/**
* Returns array value type from types like 'array<string|int, Class\Name>' or 'array<string>'.
*
* @param string $type
*
* @return string
*/
private static function getArrayValueType(string $type): string
{
$matches = [];
$result[$key] = $item;
}
preg_match_all(
'/array(\s+)?\<([\w\|\\\\]+)\s+\,\s+([\w\|\\\\]+)\>/m',
$type,
$matches,
PREG_SET_ORDER,
0
);
return $result;
}
if (count($matches) > 0) {
return $matches[count($matches) - 1];
return $data;
}
preg_match_all('/array(\s+)?\<([\w\|\\\\]+)\>/m', $type, $matches, PREG_SET_ORDER, 0);
if (count($matches) > 0) {
return $matches[count($matches) - 1];
/**
* Returns true if provided type is an array.
*
* @param string $type
*
* @return bool
*/
private static function isArrayType(string $type): bool
{
return false !== strpos($type, 'array');
}
return 'mixed';
/**
* Returns array value type from types like 'array<string|int, Class\Name>' or 'array<string>'.
*
* @param string $type
*
* @return string
*/
private static function getArrayValueType(string $type): string
{
$matches = [];
preg_match_all(
'/array(\s+)?\<([\w\|\\\\]+)\s+\,\s+([\w\|\\\\]+)\>/m',
$type,
$matches,
PREG_SET_ORDER,
0
);
if (count($matches) > 0) {
return $matches[count($matches) - 1];
}
preg_match_all('/array(\s+)?\<([\w\|\\\\]+)\>/m', $type, $matches, PREG_SET_ORDER, 0);
if (count($matches) > 0) {
return $matches[count($matches) - 1];
}
return 'mixed';
}
}
} else {
/**
* Class ArraySupportDecorator
*
* @category ArraySupportDecorator
* @package RetailCrm\Api\Component\Serializer
*/
class ArraySupportDecorator implements SerializerInterface
{
/** @var \Liip\Serializer\SerializerInterface */
private $serializer;
/**
* ArraySupportDecorator constructor.
*
* @param \Liip\Serializer\SerializerInterface $serializer
*/
public function __construct(SerializerInterface $serializer)
{
$this->serializer = $serializer;
}
/**
* @inheritDoc
* @throws \JsonException
*/
public function serialize($data, string $format, ?Context $context = null): string
{
if ('json' !== $format) {
throw new UnsupportedFormatException('Liip serializer only supports JSON for now');
}
if (is_array($data)) {
try {
return Json::encode($this->encodeArray($data, $context), JSON_UNESCAPED_SLASHES);
} catch (JsonException $exception) {
throw new Exception(
sprintf(
'Failed to JSON encode data for %s. This is not supposed to happen.',
// @phpstan-ignore-next-line
is_object($data) ? get_class($data) : gettype($data)
),
0,
$exception
);
}
}
return $this->serializer->serialize($data, $format, $context);
}
/**
* @inheritDoc
*/
public function deserialize(string $data, string $type, string $format, ?Context $context = null)
{
if ('json' !== $format) {
throw new UnsupportedFormatException('Liip serializer only supports JSON for now');
}
if (static::isArrayType($type)) {
try {
$array = Json::decode($data, true);
} catch (JsonException $exception) {
throw new Exception('Failed to JSON decode data. This is not supposed to happen.', 0, $exception);
}
return $this->serializer->fromArray($this->decodeArray($array, $type, $context), $type, $context);
}
return $this->serializer->deserialize($data, $type, $format, $context);
}
/**
* @inheritDoc
*
* @return array<int|string, mixed>
*/
public function toArray($data, ?Context $context = null): array
{
if (is_array($data)) {
return $this->encodeArray($data, $context);
}
return $this->serializer->toArray($data, $context);
}
/**
* @inheritDoc
*
* @param array<int|string, mixed> $data
*
* @return array<int|string, mixed>|object
*/
public function fromArray(array $data, string $type, ?Context $context = null)
{
if (static::isArrayType($type)) {
return $this->decodeArray($data, $type, $context);
}
return $this->serializer->fromArray($data, $type, $context);
}
/**
* Encodes array of objects into simple multidimensional array.
*
* @param mixed[] $data
* @param \Liip\Serializer\Context|null $context
*
* @return mixed[]
* @throws \Liip\Serializer\Exception\Exception
* @throws \Liip\Serializer\Exception\UnsupportedTypeException
*/
private function encodeArray(array $data, ?Context $context = null): array
{
$result = [];
foreach ($data as $key => $value) {
switch (gettype($value)) {
case 'array':
$result[$key] = $this->encodeArray($value, $context);
break;
case 'object':
$result[$key] = $this->serializer->toArray($value, $context);
break;
default:
$result[$key] = $value;
break;
}
}
return $result;
}
/**
* Decodes array of arrays to array of objects.
*
* @param mixed[] $data
* @param string $type
* @param \Liip\Serializer\Context|null $context
*
* @return array<int|string, mixed>
* @throws \Liip\Serializer\Exception\Exception
* @throws \Liip\Serializer\Exception\UnsupportedTypeException
*/
private function decodeArray(array $data, string $type, ?Context $context = null): array
{
$result = [];
$subtype = static::getArrayValueType($type);
if (class_exists($subtype)) {
foreach ($data as $key => $item) {
if (is_array($item)) {
$result[$key] = $this->decodeArray($item, $subtype, $context);
continue;
}
$result[$key] = $item;
}
return $result;
}
return $data;
}
/**
* Returns true if provided type is an array.
*
* @param string $type
*
* @return bool
*/
private static function isArrayType(string $type): bool
{
return false !== strpos($type, 'array');
}
/**
* Returns array value type from types like 'array<string|int, Class\Name>' or 'array<string>'.
*
* @param string $type
*
* @return string
*/
private static function getArrayValueType(string $type): string
{
$matches = [];
preg_match_all(
'/array(\s+)?\<([\w\|\\\\]+)\s+\,\s+([\w\|\\\\]+)\>/m',
$type,
$matches,
PREG_SET_ORDER,
0
);
if (count($matches) > 0) {
return $matches[count($matches) - 1];
}
preg_match_all('/array(\s+)?\<([\w\|\\\\]+)\>/m', $type, $matches, PREG_SET_ORDER, 0);
if (count($matches) > 0) {
return $matches[count($matches) - 1];
}
return 'mixed';
}
}
}

View file

@ -1,11 +1,6 @@
<?php
/**
* PHP version 7.3
*
* @category DeserializerGenerator
* @package RetailCrm\Api\Component\Serializer\Generator
*/
declare(strict_types=1);
namespace RetailCrm\Api\Component\Serializer\Generator;
@ -18,6 +13,8 @@ use Liip\MetadataParser\Metadata\PropertyTypeDateTime;
use Liip\MetadataParser\Metadata\PropertyTypePrimitive;
use Liip\MetadataParser\Metadata\PropertyTypeUnknown;
use Liip\MetadataParser\Reducer\TakeBestReducer;
use Liip\Serializer\Configuration\ClassToGenerate;
use Liip\Serializer\Configuration\GeneratorConfiguration;
use Liip\Serializer\Path\ArrayPath;
use Liip\Serializer\Path\ModelPath;
use Liip\Serializer\Template\Deserialization;
@ -26,129 +23,75 @@ use RetailCrm\Api\Component\Serializer\Type\PropertyTypeMixed;
use RetailCrm\Api\Interfaces\Orders\CustomerInterface;
use RetailCrm\Api\Model\Entity\Customers\Customer;
use RetailCrm\Api\Model\Entity\CustomersCorporate\CustomerCorporate;
use RuntimeException;
use Symfony\Component\Filesystem\Filesystem;
/**
* Class DeserializerGenerator
*
* @category DeserializerGenerator
* @package RetailCrm\Api\Component\Serializer\Generator
* @license https://github.com/liip/serializer/blob/master/LICENSE MIT License
* @author Liip <https://github.com/liip>
* @author Pavel Kovalenko
* @see https://github.com/liip/serializer
* @internal
*
* @SuppressWarnings(PHPMD)
*/
class DeserializerGenerator
final class DeserializerGenerator
{
private const FILENAME_PREFIX = 'deserialize';
/**
* @var Deserialization
*/
private $templating;
/**
* @var \RetailCrm\Api\Component\Serializer\Template\CustomDeserialization
*/
private $customTemplating;
/**
* @var Filesystem
*/
/** @var \Symfony\Component\Filesystem\Filesystem */
private $filesystem;
/**
* @var Builder
*/
/** @var \Liip\Serializer\Configuration\GeneratorConfiguration */
private $configuration;
/** @var \Liip\Serializer\Template\Deserialization */
private $templating;
/** @var \RetailCrm\Api\Component\Serializer\Template\CustomDeserialization */
private $customTemplating;
/** @var string */
private $cacheDirectory;
/** @var \Liip\MetadataParser\Builder */
private $metadataBuilder;
/**
* This is a list of fqn classnames
*
* I.e.
*
* [
* Product::class,
* ];
*
* @var string[]
*/
private $classesToGenerate;
/**
* @var string
*/
private $cacheDirectory;
/**
* @param \Liip\Serializer\Template\Deserialization $templating
* @param \RetailCrm\Api\Component\Serializer\Template\CustomDeserialization $customTemplating
* @param string[] $classesToGenerate
* @param string $cacheDirectory
* @param list<class-string> $classesToGenerate This is a list of FQCN classnames
*/
public function __construct(
Deserialization $templating,
CustomDeserialization $customTemplating,
array $classesToGenerate,
string $cacheDirectory
string $cacheDirectory,
GeneratorConfiguration $configuration = null
) {
$this->cacheDirectory = $cacheDirectory;
$this->templating = $templating;
$this->customTemplating = $customTemplating;
$this->classesToGenerate = $classesToGenerate;
$this->cacheDirectory = $cacheDirectory;
$this->filesystem = new Filesystem();
$this->configuration = $this->createGeneratorConfiguration($configuration, $classesToGenerate);
}
/**
* @param string $className
*
* @return string
*/
public static function buildDeserializerFunctionName(string $className): string
{
return static::FILENAME_PREFIX . '_' . str_replace('\\', '_', $className);
return self::FILENAME_PREFIX.'_'.str_replace('\\', '_', $className);
}
/**
* @param \Liip\MetadataParser\Builder $metadataBuilder
*
* @throws \Exception
*/
public function generate(Builder $metadataBuilder): void
{
$this->metadataBuilder = $metadataBuilder;
$this->filesystem->mkdir($this->cacheDirectory);
foreach ($this->classesToGenerate as $className) {
/** @var ClassToGenerate $classToGenerate */
foreach ($this->configuration as $classToGenerate) {
// we do not use the oldest version reducer here and hope for the best
// otherwise we end up with generated property names for accessor methods
$classMetadata = $metadataBuilder->build($className, [
$classMetadata = $metadataBuilder->build($classToGenerate->getClassName(), [
new TakeBestReducer(),
]);
$this->writeFile($classMetadata);
}
}
/**
* @param \Liip\MetadataParser\Metadata\ClassMetadata $classMetadata
*
* @throws \Exception
*/
private function writeFile(ClassMetadata $classMetadata): void
{
if (count($classMetadata->getConstructorParameters())) {
throw new RuntimeException(sprintf(
'We currently do not support deserializing when the root class has a non-empty constructor. Class %s',
$classMetadata->getClassName()
));
if (\count($classMetadata->getConstructorParameters())) {
throw new \Exception(sprintf('We currently do not support deserializing when the root class has a non-empty constructor. Class %s', $classMetadata->getClassName()));
}
$functionName = static::buildDeserializerFunctionName($classMetadata->getClassName());
$functionName = self::buildDeserializerFunctionName($classMetadata->getClassName());
$arrayPath = new ArrayPath('jsonData');
$code = $this->templating->renderFunction(
@ -162,13 +105,7 @@ class DeserializerGenerator
}
/**
* @param \Liip\MetadataParser\Metadata\ClassMetadata $classMetadata
* @param \Liip\Serializer\Path\ArrayPath $arrayPath
* @param \Liip\Serializer\Path\ModelPath $modelPath
* @param mixed[] $stack
*
* @return string
* @throws \Exception
* @param array<string, positive-int> $stack
*/
private function generateCodeForClass(
ClassMetadata $classMetadata,
@ -179,9 +116,9 @@ class DeserializerGenerator
$stack[$classMetadata->getClassName()] = ($stack[$classMetadata->getClassName()] ?? 0) + 1;
$constructorArgumentNames = [];
$overwrittenNames = [];
$initCode = '';
$code = '';
foreach ($classMetadata->getProperties() as $propertyMetadata) {
$propertyArrayPath = $arrayPath->withFieldName($propertyMetadata->getSerializedName());
@ -189,6 +126,9 @@ class DeserializerGenerator
$argument = $classMetadata->getConstructorParameter($propertyMetadata->getName());
$default = var_export($argument->isRequired() ? null : $argument->getDefaultValue(), true);
$tempVariable = ModelPath::tempVariable([(string) $modelPath, $propertyMetadata->getName()]);
if (\array_key_exists($propertyMetadata->getName(), $constructorArgumentNames)) {
$overwrittenNames[$propertyMetadata->getName()] = true;
}
$constructorArgumentNames[$propertyMetadata->getName()] = (string) $tempVariable;
$initCode .= $this->templating->renderArgument(
@ -206,26 +146,21 @@ class DeserializerGenerator
}
$constructorArguments = [];
foreach ($classMetadata->getConstructorParameters() as $definition) {
if (array_key_exists($definition->getName(), $constructorArgumentNames)) {
if (\array_key_exists($definition->getName(), $constructorArgumentNames)) {
$constructorArguments[] = $constructorArgumentNames[$definition->getName()];
continue;
}
if ($definition->isRequired()) {
throw new RuntimeException(sprintf(
'Unknown constructor argument "%s" in "%s(%s)"',
$definition->getName(),
$classMetadata->getClassName(),
implode(', ', array_keys($constructorArgumentNames))
));
$msg = sprintf('Unknown constructor argument "%s". Class %s only has properties that tell how to handle %s.', $definition->getName(), $classMetadata->getClassName(), implode(', ', array_keys($constructorArgumentNames)));
if ($overwrittenNames) {
$msg .= sprintf(' Multiple definitions for fields %s seen - the last one overwrites previous ones.', implode(', ', array_keys($overwrittenNames)));
}
throw new \Exception($msg);
}
$constructorArguments[] = var_export($definition->getDefaultValue(), true);
}
if (count($constructorArgumentNames) > 0) {
if (\count($constructorArgumentNames) > 0) {
$code .= $this->templating->renderUnset(array_values($constructorArgumentNames));
}
@ -233,13 +168,7 @@ class DeserializerGenerator
return $this->generateCustomerInterface($classMetadata, $arrayPath, $modelPath, $initCode, $stack);
}
return $this->templating->renderClass(
(string) $modelPath,
$classMetadata->getClassName(),
$constructorArguments,
$code,
$initCode
);
return $this->templating->renderClass((string) $modelPath, $classMetadata->getClassName(), $constructorArguments, $code, $initCode);
}
/**
@ -282,13 +211,7 @@ class DeserializerGenerator
}
/**
* @param \Liip\MetadataParser\Metadata\PropertyMetadata $propertyMetadata
* @param \Liip\Serializer\Path\ArrayPath $arrayPath
* @param \Liip\Serializer\Path\ModelPath $modelPath
* @param mixed[] $stack
*
* @return string
* @throws \Exception
* @param array<string, positive-int> $stack
*/
private function generateCodeForProperty(
PropertyMetadata $propertyMetadata,
@ -300,16 +223,16 @@ class DeserializerGenerator
return '';
}
if (Recursion::hasMaxDepthReached($propertyMetadata, $stack)) {
return '';
}
if ($propertyMetadata->getAccessor()->hasSetterMethod()) {
$tempVariable = ModelPath::tempVariable([(string) $modelPath, $propertyMetadata->getName()]);
$code = $this->generateCodeForField($propertyMetadata, $arrayPath, $tempVariable, $stack);
$code .= $this->templating->renderConditional(
(string) $tempVariable,
$this->templating->renderSetter(
(string) $modelPath,
(string) $propertyMetadata->getAccessor()->getSetterMethod(),
(string) $tempVariable
)
$this->templating->renderSetter((string) $modelPath, $propertyMetadata->getAccessor()->getSetterMethod(), (string) $tempVariable)
);
$code .= $this->templating->renderUnset([(string) $tempVariable]);
@ -322,13 +245,7 @@ class DeserializerGenerator
}
/**
* @param \Liip\MetadataParser\Metadata\PropertyMetadata $propertyMetadata
* @param \Liip\Serializer\Path\ArrayPath $arrayPath
* @param \Liip\Serializer\Path\ModelPath $modelPath
* @param mixed[] $stack
*
* @return string
* @throws \Exception
* @param array<string, positive-int> $stack
*/
private function generateCodeForField(
PropertyMetadata $propertyMetadata,
@ -342,14 +259,17 @@ class DeserializerGenerator
);
}
private function isArrayTraversable(PropertyTypeArray $array): bool
{
if (method_exists($array, 'isCollection')) {
return $array->isCollection();
}
return $array->isTraversable();
}
/**
* @param \Liip\MetadataParser\Metadata\PropertyMetadata $propertyMetadata
* @param \Liip\Serializer\Path\ArrayPath $arrayPath
* @param \Liip\Serializer\Path\ModelPath $modelPropertyPath
* @param mixed[] $stack
*
* @return string
* @throws \Exception
* @param array<string, positive-int> $stack
*/
private function generateInnerCodeForFieldType(
PropertyMetadata $propertyMetadata,
@ -359,64 +279,50 @@ class DeserializerGenerator
): string {
$type = $propertyMetadata->getType();
if ($type instanceof PropertyTypeArray) {
if ($type->getSubType() instanceof PropertyTypePrimitive) {
// for arrays of scalars, copy the field even when its an empty array
return $this->templating->renderAssignJsonDataToField((string) $modelPropertyPath, (string) $arrayPath);
}
// either array or hashmap with second param the type of values
// the index works the same whether its numeric or hashmap
return $this->generateCodeForArray($type, $arrayPath, $modelPropertyPath, $stack);
}
switch ($type) {
case $type instanceof PropertyTypeArray:
if ($this->isArrayTraversable($type)) {
return $this->generateCodeForArrayCollection($propertyMetadata, $type, $arrayPath, $modelPropertyPath, $stack);
}
return $this->generateCodeForArray($type, $arrayPath, $modelPropertyPath, $stack);
case $type instanceof PropertyTypeDateTime:
if (null !== $type->getZone()) {
throw new RuntimeException('Timezone support is not implemented');
if (method_exists($type, 'getDeserializeFormat')) {
$format = $type->getDeserializeFormat();
if (null !== $format) {
return $this->templating->renderAssignDateTimeFromFormat($type->isImmutable(), (string) $modelPropertyPath, (string) $arrayPath, $format, $type->getZone());
}
return $this->templating->renderAssignDateTimeToField($type->isImmutable(), (string) $modelPropertyPath, (string) $arrayPath);
}
$format = $type->getDeserializeFormat() ?: $type->getFormat();
if (null !== $format) {
return $this->templating->renderAssignDateTimeFromFormat(
$type->isImmutable(),
(string) $modelPropertyPath,
(string) $arrayPath,
$format
);
$formats = $type->getDeserializeFormats() ?: (\is_string($type->getFormat()) ? [$type->getFormat()] : $type->getFormat());
if (null !== $formats) {
return $this->templating->renderAssignDateTimeFromFormat($type->isImmutable(), (string) $modelPropertyPath, (string) $arrayPath, $formats, $type->getZone());
}
return $this->templating->renderAssignDateTimeToField(
$type->isImmutable(),
(string) $modelPropertyPath,
(string) $arrayPath
);
return $this->templating->renderAssignDateTimeToField($type->isImmutable(), (string) $modelPropertyPath, (string) $arrayPath);
case $type instanceof PropertyTypePrimitive && 'float' === $type->getTypeName():
return $this->templating->renderAssignJsonDataToFieldWithCasting(
(string) $modelPropertyPath,
(string) $arrayPath,
'float'
);
return $this->templating->renderAssignJsonDataToFieldWithCasting((string) $modelPropertyPath, (string) $arrayPath, 'float');
case $type instanceof PropertyTypePrimitive:
case $type instanceof PropertyTypeUnknown:
case $type instanceof PropertyTypeMixed:
return $this->templating->renderAssignJsonDataToField((string) $modelPropertyPath, (string) $arrayPath);
case $type instanceof PropertyTypeClass:
return $this->generateCodeForClass($type->getClassMetadata(), $arrayPath, $modelPropertyPath, $stack);
default:
throw new RuntimeException('Unexpected type ' . get_class($type) . ' at ' . $modelPropertyPath);
throw new \Exception('Unexpected type '. get_class($type) .' at '.$modelPropertyPath);
}
}
/**
* @param \Liip\MetadataParser\Metadata\PropertyTypeArray $type
* @param \Liip\Serializer\Path\ArrayPath $arrayPath
* @param \Liip\Serializer\Path\ModelPath $modelPath
* @param mixed[] $stack
*
* @return string
* @throws \Exception
* @param array<string, positive-int> $stack
*/
private function generateCodeForArray(
PropertyTypeArray $type,
@ -424,6 +330,11 @@ class DeserializerGenerator
ModelPath $modelPath,
array $stack
): string {
if ($type->getSubType() instanceof PropertyTypePrimitive) {
// for arrays of scalars, copy the field even when its an empty array
return $this->templating->renderAssignJsonDataToField((string) $modelPath, (string) $arrayPath);
}
$index = ModelPath::indexVariable((string) $arrayPath);
$arrayPropertyPath = $arrayPath->withVariable((string) $index);
$modelPropertyPath = $modelPath->withArray((string) $index);
@ -433,22 +344,16 @@ class DeserializerGenerator
case $subType instanceof PropertyTypeArray:
$innerCode = $this->generateCodeForArray($subType, $arrayPropertyPath, $modelPropertyPath, $stack);
break;
case $subType instanceof PropertyTypeClass:
$innerCode = $this->generateCodeForClass(
$subType->getClassMetadata(),
$arrayPropertyPath,
$modelPropertyPath,
$stack
);
$innerCode = $this->generateCodeForClass($subType->getClassMetadata(), $arrayPropertyPath, $modelPropertyPath, $stack);
break;
case $subType instanceof PropertyTypeUnknown:
$innerCode = $this->templating->renderAssignJsonDataToField(
$modelPropertyPath,
$arrayPropertyPath
);
break;
return $this->templating->renderAssignJsonDataToField((string) $modelPath, (string) $arrayPath);
default:
throw new RuntimeException('Unexpected array subtype ' . get_class($subType));
throw new \Exception('Unexpected array subtype '. get_class($subType));
}
if ('' === $innerCode) {
@ -460,4 +365,42 @@ class DeserializerGenerator
return $code;
}
/**
* @param array<string, positive-int> $stack
*/
private function generateCodeForArrayCollection(
PropertyMetadata $propertyMetadata,
PropertyTypeArray $type,
ArrayPath $arrayPath,
ModelPath $modelPath,
array $stack
): string {
$tmpVariable = ModelPath::tempVariable([(string) $modelPath, $propertyMetadata->getName()]);
$innerCode = $this->generateCodeForArray($type, $arrayPath, $tmpVariable, $stack);
if ('' === $innerCode) {
return '';
}
return $innerCode.$this->templating->renderArrayCollection((string) $modelPath, (string) $tmpVariable);
}
/**
* @param list<class-string> $classesToGenerate
*/
private function createGeneratorConfiguration(
?GeneratorConfiguration $configuration,
array $classesToGenerate
): GeneratorConfiguration {
if (null === $configuration) {
$configuration = new GeneratorConfiguration([], []);
}
foreach ($classesToGenerate as $className) {
$configuration->addClassToGenerate(new ClassToGenerate($configuration, $className));
}
return $configuration;
}
}

View file

@ -0,0 +1,57 @@
<?php
declare(strict_types=1);
namespace RetailCrm\Api\Component\Serializer\Generator;
use Liip\MetadataParser\Metadata\PropertyMetadata;
use Liip\MetadataParser\Metadata\PropertyTypeArray;
use Liip\MetadataParser\Metadata\PropertyTypeClass;
abstract class Recursion
{
/**
* @param array<string, positive-int> $stack
*/
public static function check(string $className, array $stack, string $modelPath): bool
{
if (\array_key_exists($className, $stack) && $stack[$className] > 1) {
throw new \Exception(sprintf('recursion for %s at %s', key($stack), $modelPath));
}
return false;
}
/**
* @param array<string, positive-int> $stack
*/
public static function hasMaxDepthReached(PropertyMetadata $propertyMetadata, array $stack): bool
{
if (null === $propertyMetadata->getMaxDepth()) {
return false;
}
$className = self::getClassNameFromProperty($propertyMetadata);
if (null === $className) {
return false;
}
$classStackCount = $stack[$className] ?? 0;
return $classStackCount > $propertyMetadata->getMaxDepth();
}
private static function getClassNameFromProperty(PropertyMetadata $propertyMetadata): ?string
{
$type = $propertyMetadata->getType();
if ($type instanceof PropertyTypeArray) {
$type = $type->getLeafType();
}
if (!($type instanceof PropertyTypeClass)) {
return null;
}
return $type->getClassName();
}
}

View file

@ -1,17 +1,9 @@
<?php
/**
* PHP version 7.3
*
* @category SerializerGenerator
* @package RetailCrm\Api\Component\Serializer\Generator
*/
declare(strict_types=1);
namespace RetailCrm\Api\Component\Serializer\Generator;
use DateTime;
use Liip\MetadataParser\Builder;
use Liip\MetadataParser\Metadata\ClassMetadata;
use Liip\MetadataParser\Metadata\PropertyMetadata;
@ -27,140 +19,99 @@ use Liip\MetadataParser\Reducer\TakeBestReducer;
use Liip\MetadataParser\Reducer\VersionReducer;
use Liip\Serializer\Configuration\GeneratorConfiguration;
use Liip\Serializer\Template\Serialization;
use RetailCrm\Api\Component\Serializer\Template\CustomSerialization;
use RetailCrm\Api\Component\Serializer\Type\PropertyTypeMixed;
use RetailCrm\Api\Interfaces\Orders\CustomerInterface;
use RetailCrm\Api\Model\Entity\Customers\Customer;
use RetailCrm\Api\Model\Entity\Customers\CustomerTag;
use RetailCrm\Api\Model\Entity\CustomersCorporate\CustomerCorporate;
use RetailCrm\Api\Component\Serializer\Template\CustomSerialization;
use RetailCrm\Api\Component\Serializer\Type\PropertyTypeMixed;
use RetailCrm\Api\Model\Entity\CustomersCorporate\SerializedRelationAbstractCustomer;
use RetailCrm\Api\Model\Entity\Orders\SerializedRelationCustomer;
use RuntimeException;
use Symfony\Component\Filesystem\Filesystem;
/**
* Class SerializerGenerator
*
* @category SerializerGenerator
* @package RetailCrm\Api\Component\Serializer\Generator
* @license https://github.com/liip/serializer/blob/master/LICENSE MIT License
* @author Liip <https://github.com/liip>
* @author Pavel Kovalenko
* @see https://github.com/liip/serializer
* @internal
*
* @SuppressWarnings(PHPMD)
*/
class SerializerGenerator
final class SerializerGenerator
{
private const FILENAME_PREFIX = 'serialize';
/**
* @var Serialization
*/
private $templating;
/**
* @var \RetailCrm\Api\Component\Serializer\Template\CustomSerialization
*/
private $customTemplating;
/**
* @var Builder
*/
private $metadataBuilder;
/**
* @var GeneratorConfiguration<mixed>
*/
private $configuration;
/**
* @var string
*/
private $cacheDirectory;
/**
* @var Filesystem
*/
/** @var \Symfony\Component\Filesystem\Filesystem */
private $filesystem;
/**
* SerializerGenerator constructor.
*
* @param \Liip\Serializer\Template\Serialization $templating
* @param \RetailCrm\Api\Component\Serializer\Template\CustomSerialization $customTemplating
* @param \Liip\Serializer\Configuration\GeneratorConfiguration<mixed> $configuration
* @param string $cacheDirectory
*/
/** @var \Liip\Serializer\Template\Serialization */
private $templating;
/** @var \Liip\Serializer\Configuration\GeneratorConfiguration */
private $configuration;
/** @var string */
private $cacheDirectory;
/** @var \RetailCrm\Api\Component\Serializer\Template\CustomSerialization */
private $customTemplating;
/** @var \Liip\MetadataParser\Builder */
private $metadataBuilder;
public function __construct(
Serialization $templating,
CustomSerialization $customTemplating,
GeneratorConfiguration $configuration,
string $cacheDirectory
) {
$this->templating = $templating;
$this->cacheDirectory = $cacheDirectory;
$this->configuration = $configuration;
$this->templating = $templating;
$this->customTemplating = $customTemplating;
$this->configuration = $configuration;
$this->cacheDirectory = $cacheDirectory;
$this->filesystem = new Filesystem();
}
/**
* @param string $className
* @param string|null $apiVersion
* @param array<mixed> $serializerGroups
*
* @return string
* @param list<string> $serializerGroups
*/
public static function buildSerializerFunctionName(
string $className,
?string $apiVersion,
array $serializerGroups
): string {
$functionName = static::FILENAME_PREFIX . '_' . $className;
if (count($serializerGroups)) {
$functionName .= '_' . implode('_', $serializerGroups);
public static function buildSerializerFunctionName(string $className, ?string $apiVersion, array $serializerGroups): string
{
$functionName = self::FILENAME_PREFIX.'_'.$className;
if (\count($serializerGroups)) {
$functionName .= '_'.implode('_', $serializerGroups);
}
if (null !== $apiVersion) {
$functionName .= '_' . $apiVersion;
$functionName .= '_'.$apiVersion;
}
return (string) preg_replace('/[^a-zA-Z0-9_]/', '_', $functionName);
return preg_replace('/[^a-zA-Z0-9_]/', '_', $functionName);
}
/**
* @param \Liip\MetadataParser\Builder $metadataBuilder
*/
public function generate(Builder $metadataBuilder): void
{
$this->metadataBuilder = $metadataBuilder;
$this->filesystem->mkdir($this->cacheDirectory);
foreach ($this->configuration as $classToGenerate) {
foreach ($classToGenerate as $groupCombination) {
$className = $classToGenerate->getClassName();
foreach ($groupCombination->getVersions() as $version) {
$groups = $groupCombination->getGroups();
if ('' === $version) {
$metadata = $metadataBuilder->build($className, [
new PreferredReducer(),
new TakeBestReducer(),
]);
$this->writeFile($className, null, $groupCombination->getGroups(), $metadata);
if ([] === $groups) {
$metadata = $metadataBuilder->build($className, [
new PreferredReducer(),
new TakeBestReducer(),
]);
$this->writeFile($className, null, [], $metadata);
} else {
$metadata = $metadataBuilder->build($className, [
new GroupReducer($groups),
new PreferredReducer(),
new TakeBestReducer(),
]);
$this->writeFile($className, null, $groups, $metadata);
}
} else {
$metadata = $metadataBuilder->build($className, [
new VersionReducer($version),
new GroupReducer($groupCombination->getGroups()),
new GroupReducer($groups),
new TakeBestReducer(),
]);
$this->writeFile($className, $version, $groupCombination->getGroups(), $metadata);
$this->writeFile($className, $version, $groups, $metadata);
}
}
}
@ -168,10 +119,7 @@ class SerializerGenerator
}
/**
* @param string $className
* @param string|null $apiVersion
* @param array<mixed> $serializerGroups
* @param \Liip\MetadataParser\Metadata\ClassMetadata $classMetadata
* @param list<string> $serializerGroups
*/
private function writeFile(
string $className,
@ -179,8 +127,7 @@ class SerializerGenerator
array $serializerGroups,
ClassMetadata $classMetadata
): void {
sort($serializerGroups);
$functionName = static::buildSerializerFunctionName($className, $apiVersion, $serializerGroups);
$functionName = self::buildSerializerFunctionName($className, $apiVersion, $serializerGroups);
$code = $this->templating->renderFunction(
$functionName,
@ -192,15 +139,8 @@ class SerializerGenerator
}
/**
* @param \Liip\MetadataParser\Metadata\ClassMetadata $classMetadata
* @param string|null $apiVersion
* @param array<mixed> $serializerGroups
* @param string $arrayPath
* @param string $modelPath
* @param array<mixed> $stack
*
* @return string
* @throws \Exception
* @param list<string> $serializerGroups
* @param array<string, positive-int> $stack
*/
private function generateCodeForClass(
ClassMetadata $classMetadata,
@ -226,17 +166,10 @@ class SerializerGenerator
}
$stack[$classMetadata->getClassName()] = ($stack[$classMetadata->getClassName()] ?? 0) + 1;
$code = '';
$code = '';
foreach ($classMetadata->getProperties() as $propertyMetadata) {
$code .= $this->generateCodeForField(
$propertyMetadata,
$apiVersion,
$serializerGroups,
$arrayPath,
$modelPath,
$stack
);
$code .= $this->generateCodeForField($propertyMetadata, $apiVersion, $serializerGroups, $arrayPath, $modelPath, $stack);
}
return $this->templating->renderClass($arrayPath, $code);
@ -334,15 +267,8 @@ class SerializerGenerator
}
/**
* @param \Liip\MetadataParser\Metadata\PropertyMetadata $propertyMetadata
* @param string|null $apiVersion
* @param array<mixed> $serializerGroups
* @param string $arrayPath
* @param string $modelPath
* @param array<mixed> $stack
*
* @return string
* @throws \Exception
* @param list<string> $serializerGroups
* @param array<string, positive-int> $stack
*/
private function generateCodeForField(
PropertyMetadata $propertyMetadata,
@ -352,61 +278,34 @@ class SerializerGenerator
string $modelPath,
array $stack
): string {
$modelPropertyPath = $modelPath . '->' . $propertyMetadata->getName();
$fieldPath = $arrayPath . '["' . $propertyMetadata->getSerializedName() . '"]';
if (Recursion::hasMaxDepthReached($propertyMetadata, $stack)) {
return '';
}
$modelPropertyPath = $modelPath.'->'.$propertyMetadata->getName();
$fieldPath = $arrayPath.'["'.$propertyMetadata->getSerializedName().'"]';
if ($propertyMetadata->getAccessor()->hasGetterMethod()) {
$tempVariable = str_replace(['->', '[', ']', '$'], '', $modelPath) . ucfirst($propertyMetadata->getName());
$tempVariable = str_replace(['->', '[', ']', '$'], '', $modelPath).ucfirst($propertyMetadata->getName());
return $this->templating->renderConditional(
$this->templating->renderTempVariable(
$tempVariable,
$this->templating->renderGetter(
$modelPath,
(string) $propertyMetadata->getAccessor()->getGetterMethod()
)
),
$this->generateCodeForFieldType(
$propertyMetadata->getType(),
$apiVersion,
$serializerGroups,
$fieldPath,
'$' . $tempVariable,
$stack
)
$this->templating->renderTempVariable($tempVariable, $this->templating->renderGetter($modelPath, $propertyMetadata->getAccessor()->getGetterMethod())),
$this->generateCodeForFieldType($propertyMetadata->getType(), $apiVersion, $serializerGroups, $fieldPath, '$'.$tempVariable, $stack)
);
}
if (!$propertyMetadata->isPublic()) {
throw new RuntimeException(sprintf(
'Property %s is not public and no getter has been defined. Stack %s',
$modelPropertyPath,
var_export($stack, true)
));
throw new \Exception(sprintf('Property %s is not public and no getter has been defined. Stack %s', $modelPropertyPath, var_export($stack, true)));
}
return $this->templating->renderConditional(
$modelPropertyPath,
$this->generateCodeForFieldType(
$propertyMetadata->getType(),
$apiVersion,
$serializerGroups,
$fieldPath,
$modelPropertyPath,
$stack
)
$this->generateCodeForFieldType($propertyMetadata->getType(), $apiVersion, $serializerGroups, $fieldPath, $modelPropertyPath, $stack)
);
}
/**
* @param \Liip\MetadataParser\Metadata\PropertyType $type
* @param string|null $apiVersion
* @param array<mixed> $serializerGroups
* @param string $fieldPath
* @param string $modelPropertyPath
* @param array<mixed> $stack
*
* @return string
* @throws \Exception
* @param list<string> $serializerGroups
* @param array<string, positive-int> $stack
*/
private function generateCodeForFieldType(
PropertyType $type,
@ -416,31 +315,9 @@ class SerializerGenerator
string $modelPropertyPath,
array $stack
): string {
if ($type instanceof PropertyTypeArray) {
if ($type->getSubType() instanceof PropertyTypePrimitive) {
// for arrays of scalars, copy the field even when its an empty array
return $this->templating->renderAssign($fieldPath, $modelPropertyPath);
}
// either array or hashmap with second param the type of values
// the index works the same whether its numeric or hashmap
return $this->generateCodeForArray(
$type,
$apiVersion,
$serializerGroups,
$fieldPath,
$modelPropertyPath,
$stack
);
}
switch ($type) {
case $type instanceof PropertyTypeDateTime:
if (null !== $type->getZone()) {
throw new \RuntimeException('Timezone support is not implemented');
}
$dateFormat = $type->getFormat() ?: DateTime::ATOM;
$dateFormat = $type->getFormat() ?: \DateTimeInterface::ISO8601;
return $this->templating->renderAssign(
$fieldPath,
@ -454,30 +331,19 @@ class SerializerGenerator
return $this->templating->renderAssign($fieldPath, $modelPropertyPath);
case $type instanceof PropertyTypeClass:
return $this->generateCodeForClass(
$type->getClassMetadata(),
$apiVersion,
$serializerGroups,
$fieldPath,
$modelPropertyPath,
$stack
);
return $this->generateCodeForClass($type->getClassMetadata(), $apiVersion, $serializerGroups, $fieldPath, $modelPropertyPath, $stack);
case $type instanceof PropertyTypeArray:
return $this->generateCodeForArray($type, $apiVersion, $serializerGroups, $fieldPath, $modelPropertyPath, $stack);
default:
throw new RuntimeException('Unexpected type ' . \get_class($type) . ' at ' . $modelPropertyPath);
throw new \Exception('Unexpected type '. get_class($type) .' at '.$modelPropertyPath);
}
}
/**
* @param \Liip\MetadataParser\Metadata\PropertyTypeArray $type
* @param string|null $apiVersion
* @param array<mixed> $serializerGroups
* @param string $arrayPath
* @param string $modelPath
* @param array<mixed> $stack
*
* @return string
* @throws \Exception
* @param list<string> $serializerGroups
* @param array<string, positive-int> $stack
*/
private function generateCodeForArray(
PropertyTypeArray $type,
@ -487,35 +353,25 @@ class SerializerGenerator
string $modelPath,
array $stack
): string {
$index = '$index' . \mb_strlen($arrayPath);
$index = '$index'.mb_strlen($arrayPath);
$subType = $type->getSubType();
switch ($subType) {
case $subType instanceof PropertyTypeArray:
$innerCode = $this->generateCodeForArray(
$subType,
$apiVersion,
$serializerGroups,
$arrayPath . '[' . $index . ']',
$modelPath . '[' . $index . ']',
$stack
);
break;
case $subType instanceof PropertyTypeClass:
$innerCode = $this->generateCodeForClass(
$subType->getClassMetadata(),
$apiVersion,
$serializerGroups,
$arrayPath . '[' . $index . ']',
$modelPath . '[' . $index . ']',
$stack
);
break;
case $subType instanceof PropertyTypePrimitive:
case $subType instanceof PropertyTypeArray && self::isArrayForPrimitive($subType):
case $subType instanceof PropertyTypeUnknown:
$innerCode = $this->templating->renderAssign($arrayPath, $modelPath);
return $this->templating->renderArrayAssign($arrayPath, $modelPath);
case $subType instanceof PropertyTypeArray:
$innerCode = $this->generateCodeForArray($subType, $apiVersion, $serializerGroups, $arrayPath.'['.$index.']', $modelPath.'['.$index.']', $stack);
break;
case $subType instanceof PropertyTypeClass:
$innerCode = $this->generateCodeForClass($subType->getClassMetadata(), $apiVersion, $serializerGroups, $arrayPath.'['.$index.']', $modelPath.'['.$index.']', $stack);
break;
default:
throw new RuntimeException('Unexpected array subtype ' . get_class($subType));
throw new \Exception('Unexpected array subtype '. get_class($subType));
}
if ('' === $innerCode) {
@ -532,4 +388,16 @@ class SerializerGenerator
return $this->templating->renderLoopArray($arrayPath, $modelPath, $index, $innerCode);
}
private static function isArrayForPrimitive(PropertyTypeArray $type): bool
{
do {
$type = $type->getSubType();
if ($type instanceof PropertyTypePrimitive) {
return true;
}
} while ($type instanceof PropertyTypeArray);
return false;
}
}

View file

@ -1,197 +0,0 @@
<?php
/**
* PHP version 7.3
*
* @category BaseJMSParser
* @package RetailCrm\Api\Component\Serializer\Parser
*/
declare(strict_types=1);
namespace RetailCrm\Api\Component\Serializer\Parser;
use ReflectionClass;
use RetailCrm\Api\Component\Serializer\Exception\SyntaxError;
/**
* Class Parser
*
* @package RetailCrm\Api\Component\Serializer\Parser
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
* @internal
*/
final class BaseJMSParser
{
/**
* @var \RetailCrm\Api\Component\Serializer\Parser\JMSLexer
*/
private $lexer;
/**
* @var bool
*/
private $root = true;
/**
* @param string $string
*
* @return array|mixed[]
*/
public function parse(string $string): array
{
$this->lexer = new JMSLexer();
$this->lexer->setInput($string);
$this->lexer->moveNext();
return $this->visit();
}
/**
* @return mixed
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
*/
private function visit()
{
$this->lexer->moveNext();
if (!$this->lexer->token) {
throw new SyntaxError(
'Syntax error, unexpected end of stream'
);
}
if (JMSLexer::T_FLOAT === $this->lexer->token['type']) {
return (float)$this->lexer->token['value'];
} elseif (JMSLexer::T_INTEGER === $this->lexer->token['type']) {
return (int)$this->lexer->token['value'];
} elseif (JMSLexer::T_NULL === $this->lexer->token['type']) {
return null;
} elseif (JMSLexer::T_STRING === $this->lexer->token['type']) {
return $this->lexer->token['value'];
} elseif (JMSLexer::T_IDENTIFIER === $this->lexer->token['type']) {
if ($this->lexer->isNextToken(JMSLexer::T_TYPE_START)) {
return $this->visitCompoundType();
} elseif ($this->lexer->isNextToken(JMSLexer::T_ARRAY_START)) {
return $this->visitArrayType();
}
return $this->visitSimpleType();
} elseif (!$this->root && JMSLexer::T_ARRAY_START === $this->lexer->token['type']) {
return $this->visitArrayType();
}
throw new SyntaxError(sprintf(
'Syntax error, unexpected "%s" (%s)',
$this->lexer->token['value'],
// @phpstan-ignore-next-line
$this->getConstant($this->lexer->token['type'])
));
}
/**
* @return mixed[]
*/
private function visitSimpleType(): array
{
$value = $this->lexer->token['value']; // @phpstan-ignore-line
return ['name' => $value, 'params' => []];
}
/**
* @return array<string, mixed>
*/
private function visitCompoundType(): array
{
$this->root = false;
$name = $this->lexer->token['value']; // @phpstan-ignore-line
$this->match(JMSLexer::T_TYPE_START);
$params = [];
if (!$this->lexer->isNextToken(JMSLexer::T_TYPE_END)) {
while (true) {
$params[] = $this->visit();
if ($this->lexer->isNextToken(JMSLexer::T_TYPE_END)) {
break;
}
$this->match(JMSLexer::T_COMMA);
}
}
$this->match(JMSLexer::T_TYPE_END);
return [
'name' => $name,
'params' => $params,
];
}
/**
* @return array<int, mixed>
*/
private function visitArrayType(): array
{
/*
* Here we should call $this->match(JMSLexer::T_ARRAY_START); to make it clean
* but the token has already been consumed by moveNext() in visit()
*/
$params = [];
if (!$this->lexer->isNextToken(JMSLexer::T_ARRAY_END)) {
while (true) {
$params[] = $this->visit();
if ($this->lexer->isNextToken(JMSLexer::T_ARRAY_END)) {
break;
}
$this->match(JMSLexer::T_COMMA);
}
}
$this->match(JMSLexer::T_ARRAY_END);
return $params;
}
/**
* @param int $token
*/
private function match(int $token): void
{
if (!$this->lexer->lookahead) {
throw new SyntaxError(
sprintf('Syntax error, unexpected end of stream, expected %s', $this->getConstant($token))
);
}
if ($this->lexer->lookahead['type'] === $token) {
$this->lexer->moveNext();
return;
}
throw new SyntaxError(sprintf(
'Syntax error, unexpected "%s" (%s), expected was %s',
$this->lexer->lookahead['value'],
$this->getConstant($this->lexer->lookahead['type']), // @phpstan-ignore-line
$this->getConstant($token)
));
}
/**
* @param int $value
*
* @return string
*/
private function getConstant(int $value): string
{
$oClass = new ReflectionClass(JMSLexer::class);
return (string) array_search($value, $oClass->getConstants());
}
}

View file

@ -0,0 +1,14 @@
<?php
declare(strict_types=1);
namespace RetailCrm\Api\Component\Serializer\Parser\JMSCore\Exception;
/**
* Base exception for the Serializer.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
interface Exception extends \Throwable
{
}

View file

@ -0,0 +1,11 @@
<?php
declare(strict_types=1);
namespace RetailCrm\Api\Component\Serializer\Parser\JMSCore\Type\Exception;
use RetailCrm\Api\Component\Serializer\Parser\JMSCore\Exception\Exception as BaseException;
interface Exception extends BaseException
{
}

View file

@ -0,0 +1,9 @@
<?php
declare(strict_types=1);
namespace RetailCrm\Api\Component\Serializer\Parser\JMSCore\Type\Exception;
final class InvalidNode extends \LogicException implements Exception
{
}

View file

@ -0,0 +1,9 @@
<?php
declare(strict_types=1);
namespace RetailCrm\Api\Component\Serializer\Parser\JMSCore\Type\Exception;
final class SyntaxError extends \RuntimeException implements Exception
{
}

View file

@ -1,24 +1,16 @@
<?php
/**
* PHP version 7.3
*
* @category BaseJMSParser
* @package RetailCrm\Api\Component\Serializer\Parser
*/
declare(strict_types=1);
namespace RetailCrm\Api\Component\Serializer\Parser;
namespace RetailCrm\Api\Component\Serializer\Parser\JMSCore\Type;
use Doctrine\Common\Lexer\AbstractLexer;
use RetailCrm\Api\Component\Serializer\Exception\SyntaxError;
use Throwable;
use RetailCrm\Api\Component\Serializer\Parser\JMSCore\Type\Exception\SyntaxError;
/**
* @internal
*/
final class JMSLexer extends AbstractLexer
final class Lexer extends AbstractLexer
{
public const T_UNKNOWN = 0;
public const T_INTEGER = 1;
@ -32,23 +24,15 @@ final class JMSLexer extends AbstractLexer
public const T_IDENTIFIER = 9;
public const T_NULL = 10;
/**
* @param string $type
*
* @return int|string|null
*/
public function parse(string $type)
{
try {
return $this->getType($type);
} catch (Throwable $e) {
} catch (\Throwable $e) {
throw new SyntaxError($e->getMessage(), 0, $e);
}
}
/**
* @return string[]
*/
protected function getCatchablePatterns(): array
{
return [
@ -63,18 +47,15 @@ final class JMSLexer extends AbstractLexer
];
}
/**
* @return string[]
*/
protected function getNonCatchablePatterns(): array
{
return ['\s+'];
}
/**
* {{@inheritDoc}}
* {@inheritDoc}
*
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
* @return int|string|null
*/
protected function getType(&$value)
{

View file

@ -0,0 +1,220 @@
<?php
declare(strict_types=1);
namespace RetailCrm\Api\Component\Serializer\Parser\JMSCore\Type;
use RetailCrm\Api\Component\Serializer\Parser\JMSCore\Type\Exception\SyntaxError;
/**
* @internal
*/
final class Parser implements ParserInterface
{
/** @var \RetailCrm\Api\Component\Serializer\Parser\JMSCore\Type\Lexer */
private $lexer;
/** @var \RetailCrm\Api\Component\Serializer\Parser\JMSCore\Type\Token|null */
private $token = null;
/** @var string */
private $input;
/** @var bool */
private $root = true;
public function parse(string $type): array
{
$this->input = $type;
$this->lexer = new Lexer();
$this->lexer->setInput($type);
$this->lexer->moveNext();
return $this->visit();
}
/**
* @return mixed
*/
private function visit(bool $fetchingParam = false)
{
$this->lexer->moveNext();
if (!$this->lexer->token) {
throw new SyntaxError(
'Syntax error, unexpected end of stream',
);
}
if (is_array($this->lexer->token)) {
$this->token = Token::fromArray($this->lexer->token);
} else {
$this->token = Token::fromObject($this->lexer->token);
}
/*
* There is a difference in the behavior of the tokenizer depending on the version of the lexer. This affects
* how the lexer interprets date formats for compound date types. In our case it has a huge impact because
* we're using `DateTime<'Y-m-d H:i:s'>` in the API. Newer lexer versions will treat the whole format
* (`Y-m-d H:i:s`) as a token of string type. Older lexer versions will treat each symbol of the format as
* a single token, and this will inevitably break type parsing during model compilation (it will say something
* about unexpected token).
*
* The condition below is used to work around this, albeit in a very hacky way. The token it tries to detect is
* actually a single quote ('). After detecting this token and determining that this time parser has been
* called recursively for a compound type, it will try to determine the parameter length and extract it as
* a single token. In other words, we're trying to mimic newer lexer behavior while using an older version.
*
* This implementation is very limited, as it may fail abruptly with more complex compound types, also it
* may fail to extract the type correctly if it has different whitespace symbols / multiple whitespace symbols.
* It was tested only with the compound date type mentioned above.
*
* A special fallback parser would be a better solution, but it would take much more time and effort to create.
*/
if ("" === $this->token->value && $fetchingParam) {
$len = 0;
$this->lexer->moveNext();
while (true) {
if (is_array($this->lexer->token)) {
$this->token = Token::fromArray($this->lexer->token);
} else {
$this->token = Token::fromObject($this->lexer->token);
}
if ("" === $this->token->value) {
$len++;
break;
}
$len += strlen($this->token->value);
$this->lexer->moveNext();
}
return substr($this->input, 9, $len + substr_count($this->input, ' '));
}
if (Lexer::T_FLOAT === $this->token->type) {
return floatval($this->token->value);
} elseif (Lexer::T_INTEGER === $this->token->type) {
return intval($this->token->value);
} elseif (Lexer::T_NULL === $this->token->type) {
return null;
} elseif (Lexer::T_STRING === $this->token->type) {
return $this->token->value;
} elseif (Lexer::T_IDENTIFIER === $this->token->type) {
if ($this->lexer->isNextToken(Lexer::T_TYPE_START)) {
return $this->visitCompoundType();
} elseif ($this->lexer->isNextToken(Lexer::T_ARRAY_START)) {
return $this->visitArrayType();
}
return $this->visitSimpleType();
} elseif (!$this->root && Lexer::T_ARRAY_START === $this->token->type) {
return $this->visitArrayType();
}
throw new SyntaxError(sprintf(
'Syntax error, unexpected "%s" (%s)',
$this->token->value,
$this->getConstant($this->token->type),
));
}
/**
* @return string|mixed[]
*/
private function visitSimpleType()
{
$value = $this->token->value;
return ['name' => $value, 'params' => []];
}
private function visitCompoundType(): array
{
$this->root = false;
$name = $this->token->value;
$this->match(Lexer::T_TYPE_START);
$params = [];
if (!$this->lexer->isNextToken(Lexer::T_TYPE_END)) {
while (true) {
$params[] = $this->visit(true);
if ($this->lexer->isNextToken(Lexer::T_TYPE_END)) {
break;
}
$this->match(Lexer::T_COMMA);
}
}
$this->match(Lexer::T_TYPE_END);
return [
'name' => $name,
'params' => $params,
];
}
private function visitArrayType(): array
{
/*
* Here we should call $this->match(Lexer::T_ARRAY_START); to make it clean
* but the token has already been consumed by moveNext() in visit()
*/
$params = [];
if (!$this->lexer->isNextToken(Lexer::T_ARRAY_END)) {
while (true) {
$params[] = $this->visit();
if ($this->lexer->isNextToken(Lexer::T_ARRAY_END)) {
break;
}
$this->match(Lexer::T_COMMA);
}
}
$this->match(Lexer::T_ARRAY_END);
return $params;
}
private function match(int $token): void
{
if (!$this->lexer->lookahead) {
throw new SyntaxError(
sprintf('Syntax error, unexpected end of stream, expected %s', $this->getConstant($token)),
);
}
if (is_array($this->lexer->lookahead)) {
$lookahead = Token::fromArray($this->lexer->lookahead);
} else {
$lookahead = Token::fromObject($this->lexer->lookahead);
}
if ($lookahead->type === $token) {
$this->lexer->moveNext();
return;
}
throw new SyntaxError(sprintf(
'Syntax error, unexpected "%s" (%s), expected was %s',
$lookahead->value,
$this->getConstant($lookahead->type),
$this->getConstant($token),
));
}
private function getConstant(int $value): string
{
$oClass = new \ReflectionClass(Lexer::class);
return array_search($value, $oClass->getConstants());
}
}

View file

@ -0,0 +1,10 @@
<?php
declare(strict_types=1);
namespace RetailCrm\Api\Component\Serializer\Parser\JMSCore\Type;
interface ParserInterface
{
public function parse(string $type): array;
}

View file

@ -0,0 +1,66 @@
<?php
declare(strict_types=1);
namespace RetailCrm\Api\Component\Serializer\Parser\JMSCore\Type;
use function in_array;
/**
* @template T of string|int
* @template V of string|int
*/
final class Token
{
public static function fromArray(array $source): Token
{
return new self($source['value'] ?? '', $source['type'] ?? '', $source['position'] ?? '');
}
public static function fromObject(object $source): Token
{
return new self($source->value, $source->type, $source->position);
}
/**
* The string value of the token in the input string
*
* @readonly
* @var string|int
*/
public $value;
/**
* The type of the token (identifier, numeric, string, input parameter, none)
*
* @readonly
* @var T|null
*/
public $type;
/**
* The position of the token in the input string
*
* @var int
*
* @readonly
*/
public $position;
/**
* @param string|int $value
* @param string|int $type
*/
public function __construct($value, $type, int $position)
{
$this->value = $value;
$this->type = $type;
$this->position = $position;
}
/** @param T ...$types */
public function isA(...$types): bool
{
return in_array($this->type, $types, true);
}
}

View file

@ -1,21 +1,18 @@
<?php
/**
* PHP version 7.3
*
* @category JMSParser
* @package RetailCrm\Api\Component\Serializer\Parser
*/
declare(strict_types=1);
namespace RetailCrm\Api\Component\Serializer\Parser;
use Doctrine\Common\Annotations\AnnotationException;
use Doctrine\Common\Annotations\Reader;
use Liip\MetadataParser\ModelParser\ModelParserInterface;
use RetailCrm\Api\Component\Serializer\Annotation\Accessor;
use RetailCrm\Api\Component\Serializer\Annotation\AccessorOrder;
use RetailCrm\Api\Component\Serializer\Annotation\Exclude;
use RetailCrm\Api\Component\Serializer\Annotation\ExclusionPolicy;
use RetailCrm\Api\Component\Serializer\Annotation\Groups;
use RetailCrm\Api\Component\Serializer\Annotation\MaxDepth;
use RetailCrm\Api\Component\Serializer\Annotation\PostDeserialize;
use RetailCrm\Api\Component\Serializer\Annotation\SerializedName;
use RetailCrm\Api\Component\Serializer\Annotation\Since;
@ -27,54 +24,32 @@ use Liip\MetadataParser\Exception\ParseException;
use Liip\MetadataParser\Metadata\PropertyAccessor;
use Liip\MetadataParser\Metadata\PropertyType;
use Liip\MetadataParser\Metadata\PropertyTypeUnknown;
use Liip\MetadataParser\ModelParser\ModelParserInterface;
use Liip\MetadataParser\ModelParser\RawMetadata\PropertyCollection;
use Liip\MetadataParser\ModelParser\RawMetadata\PropertyVariationMetadata;
use Liip\MetadataParser\ModelParser\RawMetadata\RawClassMetadata;
use Liip\MetadataParser\TypeParser\PhpTypeParser;
use ReflectionClass;
use ReflectionException;
use ReflectionMethod;
use ReflectionProperty;
use UnexpectedValueException;
use RetailCrm\Api\Component\Serializer\Parser\JMSCore\Type\Exception\SyntaxError;
/**
* Class JMSParser
* Parse JMSSerializer annotations.
*
* Run this parser *after* the PHPDoc parser as JMS annotations are more precise.
*
* @category JMSParser
* @package RetailCrm\Api\Component\Serializer\Parser
* @license https://github.com/liip/metadata-parser/blob/master/LICENSE MIT License
* @author Liip <https://github.com/liip>
* @author Pavel Kovalenko
* @see https://github.com/liip/metadata-parser
* @internal
*
* @SuppressWarnings(PHPMD)
*/
class JMSParser implements ModelParserInterface
{
private const ACCESS_ORDER_CUSTOM = 'custom';
/**
* @var Reader
*/
/** @var \Doctrine\Common\Annotations\Reader */
private $annotationsReader;
/**
* @var PhpTypeParser
*/
/** @var \Liip\MetadataParser\TypeParser\PhpTypeParser */
private $phpTypeParser;
/**
* @var JMSTypeParser
*/
private $jmsTypeParser;
/** @var \RetailCrm\Api\Component\Serializer\Parser\JMSTypeParser */
protected $jmsTypeParser;
/**
* JMSParser constructor.
*
* @param \Doctrine\Common\Annotations\Reader $annotationsReader
*/
public function __construct(Reader $annotationsReader)
{
$this->annotationsReader = $annotationsReader;
@ -82,124 +57,99 @@ class JMSParser implements ModelParserInterface
$this->jmsTypeParser = new JMSTypeParser();
}
/**
* @param \Liip\MetadataParser\ModelParser\RawMetadata\RawClassMetadata $classMetadata
*/
public function parse(RawClassMetadata $classMetadata): void
{
try {
$refClass = new ReflectionClass($classMetadata->getClassName()); // @phpstan-ignore-line
} catch (ReflectionException $exception) {
throw ParseException::classNotFound($classMetadata->getClassName(), $exception);
$reflClass = new \ReflectionClass($classMetadata->getClassName());
} catch (\ReflectionException $e) {
throw ParseException::classNotFound($classMetadata->getClassName(), $e);
}
$this->parseProperties($refClass, $classMetadata);
$this->parseMethods($refClass, $classMetadata);
$this->parseClass($refClass, $classMetadata);
try {
$this->parseProperties($reflClass, $classMetadata);
$this->parseMethods($reflClass, $classMetadata);
$this->parseClass($reflClass, $classMetadata);
} catch (SyntaxError $exception) {
throw new ParseException($exception->getMessage(), $exception->getCode(), $exception);
}
}
/**
* @param \ReflectionClass $refClass
* @param \Liip\MetadataParser\ModelParser\RawMetadata\RawClassMetadata $classMetadata
*
* @phpstan-ignore-next-line
*/
private function parseProperties(ReflectionClass $refClass, RawClassMetadata $classMetadata): void
private function parseProperties(\ReflectionClass $reflClass, RawClassMetadata $classMetadata): void
{
if ($refParentClass = $refClass->getParentClass()) {
$this->parseProperties($refParentClass, $classMetadata);
if ($reflParentClass = $reflClass->getParentClass()) {
$this->parseProperties($reflParentClass, $classMetadata);
}
foreach ($refClass->getProperties() as $refProperty) {
foreach ($reflClass->getProperties() as $reflProperty) {
try {
$annotations = $this->annotationsReader->getPropertyAnnotations($refProperty);
} catch (AnnotationException $exception) {
throw ParseException::propertyError((string) $classMetadata, $refProperty->getName(), $exception);
$annotations = $this->annotationsReader->getPropertyAnnotations($reflProperty);
} catch (AnnotationException $e) {
throw ParseException::propertyError((string) $classMetadata, $reflProperty->getName(), $e);
}
$property = $this->getProperty($classMetadata, $refProperty, $annotations);
$property = $this->getProperty($classMetadata, $reflProperty, $annotations);
$this->parsePropertyAnnotations($classMetadata, $property, $annotations);
}
}
/**
* @param \ReflectionClass $refClass
* @param \Liip\MetadataParser\ModelParser\RawMetadata\RawClassMetadata $classMetadata
*
* @phpstan-ignore-next-line
*/
private function parseMethods(ReflectionClass $refClass, RawClassMetadata $classMetadata): void
private function parseMethods(\ReflectionClass $reflClass, RawClassMetadata $classMetadata): void
{
if ($refParentClass = $refClass->getParentClass()) {
$this->parseMethods($refParentClass, $classMetadata);
if ($reflParentClass = $reflClass->getParentClass()) {
$this->parseMethods($reflParentClass, $classMetadata);
}
foreach ($refClass->getMethods() as $refMethod) {
if (false === $refMethod->getDocComment()) {
continue;
}
foreach ($reflClass->getMethods() as $reflMethod) {
try {
$annotations = $this->annotationsReader->getMethodAnnotations($refMethod);
} catch (AnnotationException $exception) {
throw ParseException::propertyError((string) $classMetadata, $refMethod->getName(), $exception);
$annotations = $this->annotationsReader->getMethodAnnotations($reflMethod);
} catch (AnnotationException $e) {
throw ParseException::propertyError((string) $classMetadata, $reflMethod->getName(), $e);
}
if ($this->isVirtualProperty($annotations)) {
if (!$refMethod->isPublic()) {
throw ParseException::nonPublicMethod((string) $classMetadata, $refMethod->getName());
if (!$reflMethod->isPublic()) {
throw ParseException::nonPublicMethod((string) $classMetadata, $reflMethod->getName());
}
$methodName = $this->getMethodName($annotations, $refMethod);
$methodName = $this->getMethodName($annotations, $reflMethod);
$name = $this->getSerializedName($annotations) ?: $methodName;
$property = new PropertyVariationMetadata($methodName, true, true);
$classMetadata->addPropertyVariation($name, $property);
$property->setType($this->getReturnType($property, $refMethod, $refClass));
$property->setAccessor(new PropertyAccessor($refMethod->getName(), null));
$property->setType($this->getReturnType($property, $reflMethod, $reflClass));
$property->setAccessor(new PropertyAccessor($reflMethod->getName(), null));
$this->parsePropertyAnnotations($classMetadata, $property, $annotations);
}
if ($this->isPostDeserializeMethod($annotations)) {
if (!$refMethod->isPublic()) {
throw ParseException::nonPublicMethod((string) $classMetadata, $refMethod->getName());
if (!$reflMethod->isPublic()) {
throw ParseException::nonPublicMethod((string) $classMetadata, $reflMethod->getName());
}
$classMetadata->addPostDeserializeMethod($refMethod->getName());
$classMetadata->addPostDeserializeMethod($reflMethod->getName());
}
}
}
/**
* @param \ReflectionClass $refClass
* @param \Liip\MetadataParser\ModelParser\RawMetadata\RawClassMetadata $classMetadata
*
* @phpstan-ignore-next-line
*/
private function parseClass(ReflectionClass $refClass, RawClassMetadata $classMetadata): void
private function parseClass(\ReflectionClass $reflClass, RawClassMetadata $classMetadata): void
{
try {
$annotations = $this->gatherClassAnnotations($refClass);
$annotations = $this->gatherClassAnnotations($reflClass);
} catch (AnnotationException $e) {
throw ParseException::classError($refClass->getName(), $e);
throw ParseException::classError($reflClass->getName(), $e);
}
foreach ($annotations as $annotation) {
switch (true) {
case $annotation instanceof AccessorOrder:
if (self::ACCESS_ORDER_CUSTOM !== $annotation->order) {
throw ParseException::unsupportedClassAnnotation(
(string) $classMetadata,
'AccessorOrder::' . $annotation->order
);
throw ParseException::unsupportedClassAnnotation((string) $classMetadata, 'AccessorOrder::'.$annotation->order);
}
// usort is not stable for the same result. we want to preserve order of
// the fields that are not explicitly mentioned
// usort is not stable for the same result. we want to preserve order of the fields that are not explicitly mentioned
$order = [];
$init = count($annotation->custom);
$init = \count($annotation->custom);
foreach ($classMetadata->getPropertyCollections() as $property) {
$position = $property->getPosition($annotation->custom);
if (null === $position) {
@ -208,21 +158,17 @@ class JMSParser implements ModelParserInterface
$order[$property->getSerializedName()] = $position;
}
$classMetadata->sortProperties(static function (
PropertyCollection $propA,
PropertyCollection $propB
) use ($order): int {
$classMetadata->sortProperties(static function (PropertyCollection $propA, PropertyCollection $propB) use ($order): int {
return $order[$propA->getSerializedName()] <=> $order[$propB->getSerializedName()];
});
break;
case $annotation instanceof ExclusionPolicy:
if (ExclusionPolicy::NONE !== $annotation->policy) {
throw ParseException::unsupportedClassAnnotation(
(string) $classMetadata,
'ExclusionPolicy::' . $annotation->policy
);
throw ParseException::unsupportedClassAnnotation((string) $classMetadata, 'ExclusionPolicy::'.$annotation->policy);
}
break;
default:
if (
0 === strncmp(
@ -232,10 +178,7 @@ class JMSParser implements ModelParserInterface
)
) {
// if there are annotations we can safely ignore, we need to explicitly ignore them
throw ParseException::unsupportedClassAnnotation(
(string) $classMetadata,
get_class($annotation)
);
throw ParseException::unsupportedClassAnnotation((string) $classMetadata, \get_class($annotation));
}
}
}
@ -244,51 +187,36 @@ class JMSParser implements ModelParserInterface
/**
* Find the annotations we care about by looking through all ancestors of $reflectionClass.
*
* @param \ReflectionClass $reflectionClass
*
* @return object[] Hashmap of annotation class => annotation object
* @throws \Doctrine\Common\Annotations\AnnotationException
*
* @phpstan-ignore-next-line
* @throws AnnotationException
*/
private function gatherClassAnnotations(ReflectionClass $reflectionClass): array
private function gatherClassAnnotations(\ReflectionClass $reflectionClass): array
{
$map = [];
if ($parent = $reflectionClass->getParentClass()) {
$map = $this->gatherClassAnnotations($parent);
}
$annotations = $this->annotationsReader->getClassAnnotations($reflectionClass);
foreach ($annotations as $annotation) {
$map[get_class($annotation)] = $annotation;
$map[\get_class($annotation)] = $annotation;
}
return $map;
}
/**
* @param \Liip\MetadataParser\ModelParser\RawMetadata\RawClassMetadata $classMetadata
* @param \Liip\MetadataParser\ModelParser\RawMetadata\PropertyVariationMetadata $property
* @param array<mixed> $annotations
*/
private function parsePropertyAnnotations(
RawClassMetadata $classMetadata,
PropertyVariationMetadata $property,
array $annotations
): void {
private function parsePropertyAnnotations(RawClassMetadata $classMetadata, PropertyVariationMetadata $property, array $annotations): void
{
foreach ($annotations as $annotation) {
switch (true) {
case $annotation instanceof Type:
if (null === $annotation->name) {
throw ParseException::propertyTypeNameNull((string) $classMetadata, (string) $property);
}
try {
$type = $this->jmsTypeParser->parse($annotation->name);
} catch (InvalidTypeException $exception) {
throw ParseException::propertyTypeError(
(string) $classMetadata,
(string) $property,
$exception
);
} catch (InvalidTypeException $e) {
throw ParseException::propertyTypeError((string) $classMetadata, (string) $property, $e);
}
if ($property->getType() instanceof PropertyTypeUnknown) {
@ -296,52 +224,49 @@ class JMSParser implements ModelParserInterface
} else {
try {
$property->setType($property->getType()->merge($type));
} catch (UnexpectedValueException $exception) {
throw ParseException::propertyTypeConflict(
(string) $classMetadata,
(string) $property,
(string) $property->getType(),
(string) $type,
$exception
);
} catch (\UnexpectedValueException $e) {
throw ParseException::propertyTypeConflict((string) $classMetadata, (string) $property, (string) $property->getType(), (string) $type, $e);
}
}
break;
case $annotation instanceof Exclude:
if (null !== $annotation->if) {
throw ParseException::unsupportedPropertyAnnotation(
(string) $classMetadata,
(string) $property,
'Exclude::if'
);
throw ParseException::unsupportedPropertyAnnotation((string) $classMetadata, (string) $property, 'Exclude::if');
}
$classMetadata->removePropertyVariation((string) $property);
break;
case $annotation instanceof Groups:
$property->setGroups($annotation->groups);
break;
case $annotation instanceof Accessor:
$property->setAccessor(new PropertyAccessor($annotation->getter, $annotation->setter));
break;
case $annotation instanceof Since:
$property->setVersionRange($property->getVersionRange()->withSince($annotation->version));
break;
case $annotation instanceof Until:
$property->setVersionRange($property->getVersionRange()->withUntil($annotation->version));
break;
case $annotation instanceof SerializedName:
// we handle this separately
case $annotation instanceof MaxDepth:
$property->setMaxDepth($annotation->depth);
break;
case $annotation instanceof VirtualProperty:
// we handle this separately
case $annotation instanceof SerializedName:
// we handle this separately
break;
default:
if (0 === strncmp('JMS\Serializer\\', get_class($annotation), mb_strlen('JMS\Serializer\\'))) {
if (0 === strncmp('JMS\Serializer\\', \get_class($annotation), mb_strlen('JMS\Serializer\\'))) {
// if there are annotations we can safely ignore, we need to explicitly ignore them
throw ParseException::unsupportedPropertyAnnotation(
(string) $classMetadata,
(string) $property,
get_class($annotation)
);
throw ParseException::unsupportedPropertyAnnotation((string) $classMetadata, (string) $property, \get_class($annotation));
}
break;
}
@ -352,96 +277,38 @@ class JMSParser implements ModelParserInterface
* Returns the property metadata for the specified property.
*
* If the property already exists on the class metadata this is returned.
* If the property has a serialized name that overrides the name of an existing property,
* it will be renamed and merged.
*
* @param \Liip\MetadataParser\ModelParser\RawMetadata\RawClassMetadata $classMetadata
* @param \ReflectionProperty $refProperty
* @param array<mixed> $annotations
*
* @return \Liip\MetadataParser\ModelParser\RawMetadata\PropertyVariationMetadata
* @throws \ReflectionException
* If the property has a serialized name that overrides the name of an existing property, it will be renamed and merged.
*/
private function getProperty(
RawClassMetadata $classMetadata,
ReflectionProperty $refProperty,
array $annotations
): PropertyVariationMetadata {
$defaultName = PropertyCollection::serializedName($refProperty->getName());
private function getProperty(RawClassMetadata $classMetadata, \ReflectionProperty $reflProperty, array $annotations): PropertyVariationMetadata
{
$defaultName = PropertyCollection::serializedName($reflProperty->getName());
$name = $this->getSerializedName($annotations) ?: $defaultName;
if ($classMetadata->hasPropertyVariation($refProperty->getName())) {
$property = $classMetadata->getPropertyVariation($refProperty->getName());
if ($classMetadata->hasPropertyVariation($reflProperty->getName())) {
$property = $classMetadata->getPropertyVariation($reflProperty->getName());
if ($defaultName !== $name && $classMetadata->hasPropertyCollection($defaultName)) {
$classMetadata->removePropertyVariation($defaultName);
$this->addPropertyVariation($defaultName, $name, $property, $classMetadata);
$classMetadata->renameProperty($defaultName, $name);
}
} else {
$property = PropertyVariationMetadata::fromReflection($refProperty);
$this->addPropertyVariation($defaultName, $name, $property, $classMetadata);
$property = PropertyVariationMetadata::fromReflection($reflProperty);
$classMetadata->addPropertyVariation($name, $property);
}
return $property;
}
/**
* This workaround helps to avoid unnecessary camelCase to snake_case conversion while
* using default property metadata classes. This allows us to produce code we expect
* without rewriting the whole metadata parsing library.
*
* @param string $defaultName
* @param string $name
* @param \Liip\MetadataParser\ModelParser\RawMetadata\PropertyVariationMetadata $property
* @param \Liip\MetadataParser\ModelParser\RawMetadata\RawClassMetadata $classMetadata
*
* @throws \ReflectionException
*/
private function addPropertyVariation(
string $defaultName,
string $name,
PropertyVariationMetadata $property,
RawClassMetadata $classMetadata
): void {
if ($classMetadata->hasPropertyCollection($defaultName)) {
$prop = $classMetadata->getPropertyCollection($defaultName);
} else {
$prop = new PropertyCollection($name);
$classMetadata->addPropertyCollection($prop);
}
$propName = new ReflectionProperty(get_class($prop), 'serializedName');
$propName->setAccessible(true);
$propName->setValue($prop, $name);
$prop->addVariation($property);
}
/**
* @param \Liip\MetadataParser\ModelParser\RawMetadata\PropertyVariationMetadata $property
* @param \ReflectionMethod $refMethod
* @param \ReflectionClass $refClass
*
* @return \Liip\MetadataParser\Metadata\PropertyType
*
* @phpstan-ignore-next-line
*/
private function getReturnType(
PropertyVariationMetadata $property,
ReflectionMethod $refMethod,
ReflectionClass $refClass
): PropertyType {
private function getReturnType(PropertyVariationMetadata $property, \ReflectionMethod $reflMethod, \ReflectionClass $reflClass): PropertyType
{
$type = new PropertyTypeUnknown(true);
$refType = $refMethod->getReturnType();
if (null !== $refType) {
$type = $this->phpTypeParser->parseReflectionType($refType);
$reflType = $reflMethod->getReturnType();
if (null !== $reflType) {
$type = $this->phpTypeParser->parseReflectionType($reflType);
}
try {
$docBlockType = $this->getReturnTypeOfMethod($refMethod, $refClass);
} catch (InvalidTypeException $exception) {
throw ParseException::propertyTypeError($refClass->getName(), (string) $property, $exception);
$docBlockType = $this->getReturnTypeOfMethod($reflMethod);
} catch (InvalidTypeException $e) {
throw ParseException::propertyTypeError($reflClass->getName(), (string) $property, $e);
}
if (null === $docBlockType) {
@ -450,47 +317,27 @@ class JMSParser implements ModelParserInterface
try {
return $type->merge($docBlockType);
} catch (UnexpectedValueException $exception) {
throw ParseException::propertyTypeConflict(
$refClass->getName(),
(string) $property,
(string) $type,
(string) $docBlockType,
$exception
);
} catch (\UnexpectedValueException $e) {
throw ParseException::propertyTypeConflict($reflClass->getName(), (string) $property, (string) $type, (string) $docBlockType, $e);
}
}
/**
* @param \ReflectionMethod $refMethod
* @param \ReflectionClass $refClass
*
* @return \Liip\MetadataParser\Metadata\PropertyType|null
*
* @phpstan-ignore-next-line
*/
private function getReturnTypeOfMethod(ReflectionMethod $refMethod, ReflectionClass $refClass): ?PropertyType
private function getReturnTypeOfMethod(\ReflectionMethod $reflMethod): ?PropertyType
{
$docComment = $refMethod->getDocComment();
$docComment = $reflMethod->getDocComment();
if (false === $docComment) {
return null;
}
foreach (explode("\n", $docComment) as $line) {
if (1 === preg_match('/@return ([^ ]+)/', $line, $matches)) {
return $this->phpTypeParser->parseAnnotationType($matches[1], $refClass);
return $this->phpTypeParser->parseAnnotationType($matches[1], $reflMethod->getDeclaringClass());
}
}
return null;
}
/**
* @param array<mixed> $annotations
*
* @return string|null
*/
private function getSerializedName(array $annotations): ?string
{
foreach ($annotations as $annotation) {
@ -502,11 +349,6 @@ class JMSParser implements ModelParserInterface
return null;
}
/**
* @param array<mixed> $annotations
*
* @return bool
*/
private function isVirtualProperty(array $annotations): bool
{
foreach ($annotations as $annotation) {
@ -518,11 +360,6 @@ class JMSParser implements ModelParserInterface
return false;
}
/**
* @param array<mixed> $annotations
*
* @return bool
*/
private function isPostDeserializeMethod(array $annotations): bool
{
foreach ($annotations as $annotation) {
@ -534,16 +371,9 @@ class JMSParser implements ModelParserInterface
return false;
}
/**
* @param array<mixed> $annotations
* @param \ReflectionMethod $refMethod
*
* @return string
*/
private function getMethodName(array $annotations, ReflectionMethod $refMethod): string
private function getMethodName(array $annotations, \ReflectionMethod $reflMethod): string
{
$name = $refMethod->getName();
$name = $reflMethod->getName();
foreach ($annotations as $annotation) {
if ($annotation instanceof VirtualProperty && null !== $annotation->name) {
$name = $annotation->name;

View file

@ -1,59 +1,42 @@
<?php
/**
* PHP version 7.3
*
* @category JMSTypeParser
* @package RetailCrm\Api\Component\Serializer\Parser
*/
declare(strict_types=1);
namespace RetailCrm\Api\Component\Serializer\Parser;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Liip\MetadataParser\Exception\InvalidTypeException;
use Liip\MetadataParser\Metadata\AbstractPropertyType;
use Liip\MetadataParser\Metadata\DateTimeOptions;
use Liip\MetadataParser\Metadata\PropertyType;
use Liip\MetadataParser\Metadata\PropertyTypeArray;
use Liip\MetadataParser\Metadata\PropertyTypeClass;
use Liip\MetadataParser\Metadata\PropertyTypeDateTime;
use Liip\MetadataParser\Metadata\PropertyTypeIterable;
use Liip\MetadataParser\Metadata\PropertyTypeArray;
use Liip\MetadataParser\Metadata\PropertyTypePrimitive;
use Liip\MetadataParser\Metadata\PropertyTypeUnknown;
use RetailCrm\Api\Component\Serializer\Parser\JMSCore\Type\Parser;
use RetailCrm\Api\Component\Serializer\Type\PropertyTypeMixed;
/**
* Class JMSTypeParser
*
* @category JMSTypeParser
* @package RetailCrm\Api\Component\Serializer\Parser
* @license https://github.com/liip/metadata-parser/blob/master/LICENSE MIT License
* @author Liip <https://github.com/liip>
* @author Pavel Kovalenko
* @see https://github.com/liip/metadata-parser
* @internal
*
* @SuppressWarnings(PHPMD)
*/
class JMSTypeParser
final class JMSTypeParser
{
private const TYPE_ARRAY = 'array';
private const TYPE_ARRAY_COLLECTION = 'ArrayCollection';
private const TYPE_DATETIME_INTERFACE = 'DateTimeInterface';
/**
* @var \RetailCrm\Api\Component\Serializer\Parser\BaseJMSParser
*/
/** @var \RetailCrm\Api\Component\Serializer\Parser\JMSCore\Type\Parser */
private $jmsTypeParser;
/**
* JMSTypeParser constructor.
*/
private $useArrayDateFormat;
public function __construct()
{
$this->jmsTypeParser = new BaseJMSParser();
$this->jmsTypeParser = new Parser();
$this->useArrayDateFormat = null === (new \ReflectionClass(DateTimeOptions::class))
->getConstructor()->getParameters()[2]->getType();
}
/**
* @param string $rawType
*
* @return \Liip\MetadataParser\Metadata\PropertyType
*/
public function parse(string $rawType): PropertyType
{
if ('' === $rawType) {
@ -63,12 +46,6 @@ class JMSTypeParser
return $this->parseType($this->jmsTypeParser->parse($rawType));
}
/**
* @param array<mixed> $typeInfo
* @param bool $isSubType
*
* @return \Liip\MetadataParser\Metadata\PropertyType
*/
private function parseType(array $typeInfo, bool $isSubType = false): PropertyType
{
$typeInfo = array_merge(
@ -84,13 +61,12 @@ class JMSTypeParser
if (0 === \count($typeInfo['params'])) {
if (self::TYPE_ARRAY === $typeInfo['name']) {
return new PropertyTypeArray(new PropertyTypeUnknown(false), false, $nullable);
return self::iterableType(new PropertyTypeUnknown(false), false, $nullable);
}
if (PropertyTypePrimitive::isTypePrimitive($typeInfo['name'])) {
return new PropertyTypePrimitive($typeInfo['name'], $nullable);
}
if (PropertyTypeDateTime::isTypeDateTime($typeInfo['name'])) {
return PropertyTypeDateTime::fromDateTimeClass($typeInfo['name'], $nullable);
}
@ -102,41 +78,62 @@ class JMSTypeParser
return new PropertyTypeClass($typeInfo['name'], $nullable);
}
if (self::TYPE_ARRAY === $typeInfo['name']) {
$collectionClass = $this->getCollectionClass($typeInfo['name']);
if (self::TYPE_ARRAY === $typeInfo['name'] || $collectionClass) {
if (1 === \count($typeInfo['params'])) {
return new PropertyTypeArray(
$this->parseType($typeInfo['params'][0], true),
false,
$nullable
);
return self::iterableType($this->parseType($typeInfo['params'][0], true), false, $nullable, $collectionClass);
}
if (2 === \count($typeInfo['params'])) {
return new PropertyTypeArray(
$this->parseType($typeInfo['params'][1], true),
true,
$nullable
);
return self::iterableType($this->parseType($typeInfo['params'][1], true), true, $nullable, $collectionClass);
}
throw new InvalidTypeException(sprintf(
'JMS property type array can\'t have more than 2 parameters (%s)',
var_export($typeInfo, true)
));
throw new InvalidTypeException(sprintf('JMS property type array can\'t have more than 2 parameters (%s)', var_export($typeInfo, true)));
}
if (PropertyTypeDateTime::isTypeDateTime($typeInfo['name'])) {
if (PropertyTypeDateTime::isTypeDateTime($typeInfo['name']) || (self::TYPE_DATETIME_INTERFACE === $typeInfo['name'])) {
// the case of datetime without params is already handled above, we know we have params
$serializeFormat = $typeInfo['params'][0] ?: null;
// {@link \JMS\Serializer\Handler\DateHandler} of jms/serializer defaults to using the serialization format as a deserialization format if none was supplied...
$deserializeFormats = ($typeInfo['params'][2] ?? null) ?: $serializeFormat;
// ... and always converts single strings to arrays
$deserializeFormats = \is_string($deserializeFormats) ? [$deserializeFormats] : $deserializeFormats;
// Jms defaults to DateTime when given DateTimeInterface despite the documentation saying DateTimeImmutable, {@see \JMS\Serializer\Handler\DateHandler} in jms/serializer
$className = (self::TYPE_DATETIME_INTERFACE === $typeInfo['name']) ? \DateTime::class : $typeInfo['name'];
return PropertyTypeDateTime::fromDateTimeClass(
$typeInfo['name'],
$className,
$nullable,
new DateTimeOptions(
$typeInfo['params'][0] ?: null,
$serializeFormat,
($typeInfo['params'][1] ?? null) ?: null,
($typeInfo['params'][2] ?? null) ?: null
$this->useArrayDateFormat ? $deserializeFormats : $deserializeFormats[0],
)
);
}
throw new InvalidTypeException(sprintf('Unknown JMS property found (%s)', var_export($typeInfo, true)));
}
private function getCollectionClass(string $name): ?string
{
switch ($name) {
case self::TYPE_ARRAY_COLLECTION:
return ArrayCollection::class;
default:
return is_a($name, Collection::class, true) ? $name : null;
}
}
private static function iterableType(
PropertyType $subType,
bool $hashmap,
bool $nullable,
?string $collectionClass = null
): AbstractPropertyType {
if (class_exists('Liip\MetadataParser\Metadata\PropertyTypeIterable')) {
return new PropertyTypeIterable($subType, $hashmap, $nullable, $collectionClass);
}
return new PropertyTypeArray($subType, $hashmap, $nullable, $collectionClass !== null);
}
}

22
src/Enum/BySite.php Normal file
View file

@ -0,0 +1,22 @@
<?php
/**
* PHP version 7.3
*
* @category BySite
* @package RetailCrm\Api\Enum
*/
namespace RetailCrm\Api\Enum;
/**
* Class BySite
*
* @category BySite
* @package RetailCrm\Api\Enum
*/
final class BySite
{
public const ID = 'id';
public const CODE = 'code';
}

View file

@ -0,0 +1,23 @@
<?php
/**
* PHP 7.3
*
* @category PaymentInvoiceType
* @package RetailCrm\Api\Enum\Payments
*/
namespace RetailCrm\Api\Enum\Payments;
/**
* Class PaymentInvoiceType
*
* @category PaymentInvoiceType
* @package RetailCrm\Api\Enum\Payments
*/
final class PaymentObjectType
{
public const COMMODITY = 'commodity';
public const SERVICE = 'service';
public const PAYMENT = 'payment';
}

View file

@ -0,0 +1,22 @@
<?php
/**
* PHP version 7.3
*
* @category CallEventType
* @package RetailCrm\Api\Enum\Telephony
*/
namespace RetailCrm\Api\Enum\Product;
/**
* Class CallEventType
*
* @category CallEventType
* @package RetailCrm\Api\Enum\Telephony
*/
final class ProductType
{
public const PRODUCT = 'product';
public const SERVICE = 'service';
}

View file

@ -285,6 +285,7 @@ class ClientFactory implements ClientFactoryInterface, EventDispatcherAwareInter
->setStreamFactory($this->streamFactory)
->setRequestFactory($this->requestFactory)
->setUriFactory($this->uriFactory)
->setEventDispatcher($this->eventDispatcher)
->appendRequestHandlers($this->requestHandlers)
->appendResponseHandlers($this->responseHandlers)
->build();

View file

@ -15,6 +15,7 @@ use RetailCrm\Api\Enum\RequestMethod;
use RetailCrm\Api\Exception\Client\HandlerException;
use RetailCrm\Api\Handler\AbstractHandler;
use RetailCrm\Api\Interfaces\FormEncoderInterface;
use RetailCrm\Api\Model\Request\Files\FilesUploadRequest;
use RetailCrm\Api\Model\RequestData;
use Throwable;
@ -76,7 +77,9 @@ class RequestDataHandler extends AbstractHandler
}
if ('' !== $formData) {
if (static::queryShouldBeUsed($item->request->getMethod())) {
if ($item->requestModel instanceof FilesUploadRequest) {
$item->request = $item->request->withBody($item->requestModel->file);
} elseif (static::queryShouldBeUsed($item->request->getMethod())) {
$item->request = $item->request->withUri(
$item->request->getUri()->withQuery($formData)
);

View file

@ -26,7 +26,7 @@ class FilesDownloadResponseHandler extends AbstractResponseHandler
*/
protected function handleResponse(ResponseData $responseData)
{
if (!preg_match('/^\/api\/v5\/files\/\d+\/download$/', $responseData->request->getUri()->getPath())) {
if (!static::isFileRequest($responseData->request->getUri()->getPath())) {
$this->next($responseData);
return;
@ -44,6 +44,29 @@ class FilesDownloadResponseHandler extends AbstractResponseHandler
));
}
/**
* Checking the request path to determine a file request
*
* @param string $path
*
* @return bool
*/
private static function isFileRequest(string $path): bool
{
$filePatterns = [
'#^/api/v5/files/\d+/download$#',
'#^/api/v5/orders/\S+/plates/\d+/print$#',
];
foreach ($filePatterns as $pattern) {
if (preg_match($pattern, $path)) {
return true;
}
}
return false;
}
/**
* Parses filename from a Content-Disposition header value.
*

View file

@ -0,0 +1,38 @@
<?php
/**
* PHP version 7.3
*
* @category ShipmentPointList
* @package RetailCrm\Api\Model\Callback\Entity\Delivery
*/
namespace RetailCrm\Api\Model\Callback\Entity\Delivery;
use RetailCrm\Api\Component\Serializer\Annotation as JMS;
use RetailCrm\Api\Model\Entity\References\GeoHierarchyRow;
/**
* Class ShipmentPointList
*
* @category ShipmentPointList
* @package RetailCrm\Api\Model\Callback\Entity\Delivery
*/
class ShipmentPointList extends GeoHierarchyRow
{
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("clientId")
*/
public $clientId;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("code")
*/
public $code;
}

View file

@ -0,0 +1,37 @@
<?php
/**
* PHP version 7.3
*
* @category Settings
* @package RetailCrm\Api\Model\Callback\Entity\Integration
*/
namespace RetailCrm\Api\Model\Callback\Entity\Integration;
use RetailCrm\Api\Component\Serializer\Annotation as JMS;
/**
* Class Settings
*
* @category Settings
* @package RetailCrm\Api\Model\Callback\Entity\Integration
*/
class Settings
{
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("clientId")
*/
public $clientId;
/**
* @var \RetailCrm\Api\Model\Entity\Settings\Settings
*
* @JMS\Type("RetailCrm\Api\Model\Entity\Settings\Settings")
* @JMS\SerializedName("settings")
*/
public $settings;
}

View file

@ -84,6 +84,7 @@ class CustomField
public $entity;
/**
* @deprecated Please use $defaultTyped instead.
* @var string
*
* @JMS\Type("string")
@ -122,4 +123,12 @@ class CustomField
* @JMS\SerializedName("dictionary")
*/
public $dictionary;
/**
* @var mixed
*
* @JMS\Type("mixed")
* @JMS\SerializedName("defaultTyped")
*/
public $defaultTyped;
}

View file

@ -0,0 +1,86 @@
<?php
/**
* PHP version 7.3
*
* @category Cart
* @package RetailCrm\Api\Model\Entity\CustomerInteraction
*/
namespace RetailCrm\Api\Model\Entity\CustomerInteraction;
use DateTime;
use RetailCrm\Api\Component\Serializer\Annotation as JMS;
/**
* Class Cart
*
* @category Cart
* @package RetailCrm\Api\Model\Entity\CustomerInteraction
*/
class Cart
{
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("currency")
*/
public $currency;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("externalId")
*/
public $externalId;
/**
* @var DateTime
*
* @JMS\Type("DateTime<'Y-m-d H:i:sP'>")
* @JMS\SerializedName("droppedAt")
*/
public $droppedAt;
/**
* @var DateTime
*
* @JMS\Type("DateTime<'Y-m-d H:i:sP'>")
* @JMS\SerializedName("clearedAt")
*/
public $clearedAt;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("link")
*/
public $link;
/**
* @var \RetailCrm\Api\Model\Entity\CustomerInteraction\CartCustomer
*
* @JMS\Type("RetailCrm\Api\Model\Entity\CustomerInteraction\CartCustomer")
* @JMS\SerializedName("customer")
*/
public $customer;
/**
* @var \RetailCrm\Api\Model\Entity\CustomerInteraction\CartItem[]
*
* @JMS\Type("array<RetailCrm\Api\Model\Entity\CustomerInteraction\CartItem>")
* @JMS\SerializedName("items")
*/
public $items;
/**
* @var \RetailCrm\Api\Model\Entity\CustomerInteraction\CartOrder
*
* @JMS\Type("RetailCrm\Api\Model\Entity\CustomerInteraction\CartOrder")
* @JMS\SerializedName("order")
*/
public $order;
}

View file

@ -0,0 +1,61 @@
<?php
/**
* PHP version 7.3
*
* @category CartCustomer
* @package RetailCrm\Api\Model\Entity\CustomerInteraction
*/
namespace RetailCrm\Api\Model\Entity\CustomerInteraction;
use RetailCrm\Api\Component\Serializer\Annotation as JMS;
/**
* Class CartCustomer
*
* @category CartCustomer
* @package RetailCrm\Api\Model\Entity\CustomerInteraction
*/
class CartCustomer
{
/**
* @var int
*
* @JMS\Type("int")
* @JMS\SerializedName("id")
*/
public $id;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("externalId")
*/
public $externalId;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("browserId")
*/
public $browserId;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("site")
*/
public $site;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("gaClientId")
*/
public $gaClientId;
}

View file

@ -0,0 +1,53 @@
<?php
/**
* PHP version 7.3
*
* @category CartItem
* @package RetailCrm\Api\Model\Entity\CustomerInteraction
*/
namespace RetailCrm\Api\Model\Entity\CustomerInteraction;
use RetailCrm\Api\Component\Serializer\Annotation as JMS;
/**
* Class CartItem
*
* @category CartItem
* @package RetailCrm\Api\Model\Entity\CustomerInteraction
*/
class CartItem
{
/**
* @var int
*
* @JMS\Type("int")
* @JMS\SerializedName("id")
*/
public $id;
/**
* @var \RetailCrm\Api\Model\Entity\Orders\Items\Offer
*
* @JMS\Type("RetailCrm\Api\Model\Entity\Orders\Items\Offer")
* @JMS\SerializedName("offer")
*/
public $offer;
/**
* @var float
*
* @JMS\Type("float")
* @JMS\SerializedName("quantity")
*/
public $quantity;
/**
* @var float
*
* @JMS\Type("float")
* @JMS\SerializedName("price")
*/
public $price;
}

View file

@ -0,0 +1,45 @@
<?php
/**
* PHP version 7.3
*
* @category CartOrder
* @package RetailCrm\Api\Model\Entity\CustomerInteraction
*/
namespace RetailCrm\Api\Model\Entity\CustomerInteraction;
use RetailCrm\Api\Component\Serializer\Annotation as JMS;
/**
* Class CartOrder
*
* @category CartOrder
* @package RetailCrm\Api\Model\Entity\CustomerInteraction
*/
class CartOrder
{
/**
* @var int
*
* @JMS\Type("int")
* @JMS\SerializedName("id")
*/
public $id;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("externalId")
*/
public $externalId;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("number")
*/
public $number;
}

View file

@ -120,6 +120,15 @@ class Customer implements CustomerInterface
*/
public $tags;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("attachedTag")
*/
public $attachedTag;
/**
* @var string[]
*
@ -359,4 +368,20 @@ class Customer implements CustomerInterface
* @JMS\SerializedName("subscribed")
*/
public $subscribed;
/**
* @var \RetailCrm\Api\Model\Entity\Customers\CustomerSubscription[]
*
* @JMS\Type("array<RetailCrm\Api\Model\Entity\Customers\CustomerSubscription>")
* @JMS\SerializedName("customerSubscriptions")
*/
public $customerSubscriptions;
/**
* @var \RetailCrm\Api\Model\Entity\Customers\MGCustomer[]
*
* @JMS\Type("array<RetailCrm\Api\Model\Entity\Customers\MGCustomer>")
* @JMS\SerializedName("mgCustomers")
*/
public $mgCustomers;
}

View file

@ -0,0 +1,46 @@
<?php
/**
* PHP version 7.3
*
* @category CustomerSubscription
* @package RetailCrm\Api\Model\Entity\Customers
*/
namespace RetailCrm\Api\Model\Entity\Customers;
use DateTime;
use RetailCrm\Api\Component\Serializer\Annotation as JMS;
/**
* Class CustomerSubscription
*
* @category CustomerSubscription
* @package RetailCrm\Api\Model\Entity\Customers
*/
class CustomerSubscription
{
/**
* @var \RetailCrm\Api\Model\Entity\Customers\SubscriptionCategory
*
* @JMS\Type("RetailCrm\Api\Model\Entity\Customers\SubscriptionCategory")
* @JMS\SerializedName("subscription")
*/
public $subscription;
/**
* @var bool
*
* @JMS\Type("bool")
* @JMS\SerializedName("subscribed")
*/
public $subscribed;
/**
* @var DateTime
*
* @JMS\Type("DateTime<'Y-m-d H:i:s'>")
* @JMS\SerializedName("changedAt")
*/
public $changedAt;
}

View file

@ -0,0 +1,69 @@
<?php
/**
* PHP version 7.3
*
* @category MGChannel
* @package RetailCrm\Api\Model\Entity\Customers
*/
namespace RetailCrm\Api\Model\Entity\Customers;
use RetailCrm\Api\Component\Serializer\Annotation as JMS;
/**
* Class MGChannel
*
* @category MGChannel
* @package RetailCrm\Api\Model\Entity\Customers
*/
class MGChannel
{
/**
* @var int
*
* @JMS\Type("int")
* @JMS\SerializedName("id")
*/
public $id;
/**
* @var int
*
* @JMS\Type("int")
* @JMS\SerializedName("externalId")
*/
public $externalId;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("type")
*/
public $type;
/**
* @var bool
*
* @JMS\Type("bool")
* @JMS\SerializedName("active")
*/
public $active;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("name")
*/
public $name;
/**
* @var bool
*
* @JMS\Type("bool")
* @JMS\SerializedName("allowedSendByPhone")
*/
public $allowedSendByPhone;
}

View file

@ -0,0 +1,45 @@
<?php
/**
* PHP version 7.3
*
* @category MGCustomer
* @package RetailCrm\Api\Model\Entity\Customers
*/
namespace RetailCrm\Api\Model\Entity\Customers;
use RetailCrm\Api\Component\Serializer\Annotation as JMS;
/**
* Class MGCustomer
*
* @category MGCustomer
* @package RetailCrm\Api\Model\Entity\Customers
*/
class MGCustomer
{
/**
* @var int
*
* @JMS\Type("int")
* @JMS\SerializedName("id")
*/
public $id;
/**
* @var int
*
* @JMS\Type("int")
* @JMS\SerializedName("externalId")
*/
public $externalId;
/**
* @var \RetailCrm\Api\Model\Entity\Customers\MGChannel
*
* @JMS\Type("RetailCrm\Api\Model\Entity\Customers\MGChannel")
* @JMS\SerializedName("mgChannel")
*/
public $mgChannel;
}

View file

@ -0,0 +1,53 @@
<?php
/**
* PHP version 7.3
*
* @category Subscription
* @package RetailCrm\Api\Model\Entity\Customers
*/
namespace RetailCrm\Api\Model\Entity\Customers;
use RetailCrm\Api\Component\Serializer\Annotation as JMS;
/**
* Class Subscription
*
* @category Subscription
* @package RetailCrm\Api\Model\Entity\Customers
*/
class Subscription
{
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("channel")
*/
public $channel;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("subscription")
*/
public $subscription;
/**
* @var bool
*
* @JMS\Type("bool")
* @JMS\SerializedName("active")
*/
public $active;
/**
* @var int
*
* @JMS\Type("int")
* @JMS\SerializedName("messageId")
*/
public $messageId;
}

View file

@ -0,0 +1,77 @@
<?php
/**
* PHP version 7.3
*
* @category SubscriptionCategory
* @package RetailCrm\Api\Model\Entity\Customers
*/
namespace RetailCrm\Api\Model\Entity\Customers;
use RetailCrm\Api\Component\Serializer\Annotation as JMS;
/**
* Class SubscriptionCategory
*
* @category SubscriptionCategory
* @package RetailCrm\Api\Model\Entity\Customers
*/
class SubscriptionCategory
{
/**
* @var int
*
* @JMS\Type("int")
* @JMS\SerializedName("id")
*/
public $id;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("channel")
*/
public $channel;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("name")
*/
public $name;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("code")
*/
public $code;
/**
* @var bool
*
* @JMS\Type("bool")
* @JMS\SerializedName("active")
*/
public $active;
/**
* @var bool
*
* @JMS\Type("bool")
* @JMS\SerializedName("autoSubscribe")
*/
public $autoSubscribe;
/**
* @var int
*
* @JMS\Type("int")
* @JMS\SerializedName("ordering")
*/
public $ordering;
}

View file

@ -0,0 +1,29 @@
<?php
/**
* PHP version 7.3
*
* @category EntityWithExternalId
* @package RetailCrm\Api\Model\Entity
*/
namespace RetailCrm\Api\Model\Entity;
use RetailCrm\Api\Component\Serializer\Annotation as JMS;
/**
* Class EntityWithExternalId
*
* @category EntityWithExternalId
* @package RetailCrm\Api\Model\Entity
*/
class EntityWithExternalId
{
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("externalId")
*/
public $externalId;
}

View file

@ -0,0 +1,45 @@
<?php
/**
* PHP version 7.3
*
* @category EmbedJsConfiguration
* @package RetailCrm\Api\Model\Entity\Integration\EmbedJs
*/
namespace RetailCrm\Api\Model\Entity\Integration\EmbedJs;
use RetailCrm\Api\Component\Serializer\Annotation as JMS;
/**
* Class EmbedJsConfiguration
*
* @category EmbedJsConfiguration
* @package RetailCrm\Api\Model\Entity\Integration\EmbedJs
*/
class EmbedJsConfiguration
{
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("entrypoint")
*/
public $entrypoint;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("stylesheet")
*/
public $stylesheet;
/**
* @var string[]
*
* @JMS\Type("array<string>")
* @JMS\SerializedName("targets")
*/
public $targets;
}

View file

@ -74,4 +74,12 @@ class Integrations
* @JMS\SerializedName("mgBot")
*/
public $mgBot;
/**
* @var \RetailCrm\Api\Model\Entity\Integration\EmbedJs\EmbedJsConfiguration
*
* @JMS\Type("RetailCrm\Api\Model\Entity\Integration\EmbedJs\EmbedJsConfiguration")
* @JMS\SerializedName("embedJs")
*/
public $embedJs;
}

View file

@ -22,7 +22,7 @@ class BonusDetail
/**
* @var \DateTime
*
* @JMS\Type("DateTime<'Y-m-d H:i:s'>")
* @JMS\Type("DateTime<'Y-m-d'>")
* @JMS\SerializedName("date")
*/
public $date;

View file

@ -46,6 +46,14 @@ class Loyalty
*/
public $blocked;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("currency")
*/
public $currency;
/**
* @var int
*

View file

@ -116,4 +116,12 @@ class SerializedLoyaltyOrder
* @JMS\SerializedName("items")
*/
public $items;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("currency")
*/
public $currency;
}

View file

@ -0,0 +1,57 @@
<?php
/**
* PHP version 7.3
*
* @category Notification
* @package RetailCrm\Api\Model\Entity\Notifications
*/
namespace RetailCrm\Api\Model\Entity\Notifications;
use RetailCrm\Api\Component\Serializer\Annotation as JMS;
/**
* Class Notification
*
* @category Notification
* @package RetailCrm\Api\Model\Entity\Notifications
*
* @SuppressWarnings(PHPMD.LongVariables)
* @SuppressWarnings(PHPMD.TooManyFields)
* @SuppressWarnings(PHPMD.ExcessivePublicCount)
*/
class Notification
{
/**
* @var string[]
*
* @JMS\Type("array<string>")
* @JMS\SerializedName("userGroups")
*/
public $userGroups;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("type")
*/
public $type;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("message")
*/
public $message;
/**
* @var int[]
*
* @JMS\Type("array<int>")
* @JMS\SerializedName("userIds")
*/
public $userIds;
}

View file

@ -671,4 +671,12 @@ class DeliveryData
* @JMS\SerializedName("service")
*/
public $service;
/**
* @var ItemDeclaredValue[]
*
* @JMS\Type("array<RetailCrm\Api\Model\Entity\Orders\Delivery\ItemDeclaredValue>")
* @JMS\SerializedName("itemDeclaredValues")
*/
public $itemDeclaredValues;
}

View file

@ -0,0 +1,31 @@
<?php
/**
* PHP version 7.3
*
* @category DeliveryData
* @package RetailCrm\Api\Model\Entity\Orders\Delivery
*/
namespace RetailCrm\Api\Model\Entity\Orders\Delivery;
use RetailCrm\Api\Component\Serializer\Annotation as JMS;
class ItemDeclaredValue
{
/**
* @var ItemDeclaredValueProduct
*
* @JMS\Type("RetailCrm\Api\Model\Entity\Orders\Delivery\ItemDeclaredValueProduct")
* @JMS\SerializedName("orderProduct")
*/
public $orderProduct;
/**
* @var float
*
* @JMS\Type("float")
* @JMS\SerializedName("value")
*/
public $value;
}

View file

@ -0,0 +1,23 @@
<?php
/**
* PHP version 7.3
*
* @category DeliveryData
* @package RetailCrm\Api\Model\Entity\Orders\Delivery
*/
namespace RetailCrm\Api\Model\Entity\Orders\Delivery;
use RetailCrm\Api\Component\Serializer\Annotation as JMS;
class ItemDeclaredValueProduct
{
/**
* @var int
*
* @JMS\Type("int")
* @JMS\SerializedName("id")
*/
public $id;
}

View file

@ -0,0 +1,45 @@
<?php
/**
* PHP version 7.3
*
* @category LinkedOrder
* @package RetailCrm\Api\Model\Entity\Orders
*/
namespace RetailCrm\Api\Model\Entity\Orders;
use RetailCrm\Api\Component\Serializer\Annotation as JMS;
/**
* Class LinkedOrder
*
* @category LinkedOrder
* @package RetailCrm\Api\Model\Entity\Orders
*/
class LinkedOrder
{
/**
* @var int
*
* @JMS\Type("int")
* @JMS\SerializedName("id")
*/
public $id;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("externalId")
*/
public $externalId;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("number")
*/
public $number;
}

View file

@ -48,6 +48,14 @@ class Order
*/
public $summ;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("currency")
*/
public $currency;
/**
* @var int
*
@ -408,6 +416,14 @@ class Order
*/
public $payments;
/**
* @var \RetailCrm\Api\Model\Entity\Orders\OrderLink[]
*
* @JMS\Type("array<RetailCrm\Api\Model\Entity\Orders\OrderLink>")
* @JMS\SerializedName("links")
*/
public $links;
/**
* @var bool
*

View file

@ -0,0 +1,46 @@
<?php
/**
* PHP version 7.3
*
* @category OrderLink
* @package RetailCrm\Api\Model\Entity\Orders
*/
namespace RetailCrm\Api\Model\Entity\Orders;
use DateTime;
use RetailCrm\Api\Component\Serializer\Annotation as JMS;
/**
* Class OrderLink
*
* @category OrderLink
* @package RetailCrm\Api\Model\Entity\Orders
*/
class OrderLink
{
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("comment")
*/
public $comment;
/**
* @var \RetailCrm\Api\Model\Entity\Orders\LinkedOrder
*
* @JMS\Type("array<RetailCrm\Api\Model\Entity\Delivery\SerializedEntityOrder>")
* @JMS\SerializedName("order")
*/
public $order;
/**
* @var DateTime
*
* @JMS\Type("DateTime<'Y-m-d H:i:s'>")
* @JMS\SerializedName("createdAt")
*/
public $createdAt;
}

View file

@ -43,6 +43,14 @@ class ApiUpdateInvoiceRequest
*/
public $amount;
/**
* @var float
*
* @JMS\Type("float")
* @JMS\SerializedName("discountAmount")
*/
public $discountAmount;
/**
* @var string
*

View file

@ -0,0 +1,79 @@
<?php
/**
* PHP version 7.3
*
* @category Currency
* @package RetailCrm\Api\Model\Entity\References
*/
namespace RetailCrm\Api\Model\Entity\References;
use RetailCrm\Api\Component\Serializer\Annotation as JMS;
/**
* Class Currency
*
* @category Currency
* @package RetailCrm\Api\Model\Entity\References
*
* @SuppressWarnings(PHPMD.LongVariable)
*/
class Currency
{
/**
* @var int
*
* @JMS\Type("int")
* @JMS\SerializedName("id")
*/
public $id;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("code")
*/
public $code;
/**
* @var bool
*
* @JMS\Type("bool")
* @JMS\SerializedName("isBase")
*/
public $isBase;
/**
* @var bool
*
* @JMS\Type("bool")
* @JMS\SerializedName("isAutoConvert")
*/
public $isAutoConvert;
/**
* @var int
*
* @JMS\Type("int")
* @JMS\SerializedName("autoConvertExtraPercent")
*/
public $autoConvertExtraPercent;
/**
* @var int
*
* @JMS\Type("int")
* @JMS\SerializedName("manualConvertNominal")
*/
public $manualConvertNominal;
/**
* @var float
*
* @JMS\Type("float")
* @JMS\SerializedName("manualConvertValue")
*/
public $manualConvertValue;
}

View file

@ -69,6 +69,14 @@ class DeliveryType
*/
public $isCostDependsOnDateTime;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("currency")
*/
public $currency;
/**
* @var string
*
@ -180,4 +188,20 @@ class DeliveryType
* @JMS\SerializedName("defaultTariffName")
*/
public $defaultTariffName;
/**
* @var \RetailCrm\Api\Model\Entity\References\DeliveryTypePaymentType[]
*
* @JMS\Type("array<RetailCrm\Api\Model\Entity\References\DeliveryTypePaymentType>")
* @JMS\SerializedName("deliveryPaymentTypes")
*/
public $deliveryPaymentTypes;
/**
* @var string[]
*
* @JMS\Type("array")
* @JMS\SerializedName("sites")
*/
public $sites;
}

View file

@ -0,0 +1,37 @@
<?php
/**
* PHP version 7.3
*
* @category DeliveryTypePaymentType
* @package RetailCrm\Api\Model\Entity\References
*/
namespace RetailCrm\Api\Model\Entity\References;
use RetailCrm\Api\Component\Serializer\Annotation as JMS;
/**
* Class DeliveryTypePaymentType
*
* @category DeliveryTypePaymentType
* @package RetailCrm\Api\Model\Entity\References
*/
class DeliveryTypePaymentType
{
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("code")
*/
public $code;
/**
* @var bool
*
* @JMS\Type("bool")
* @JMS\SerializedName("cod")
*/
public $cod;
}

View file

@ -97,7 +97,7 @@ class LegalEntity
/**
* @var DateTime
*
* @JMS\Type("DateTime<'Y-m-d H:i:s'>")
* @JMS\Type("DateTime<'Y-m-d'>")
* @JMS\SerializedName("certificateDate")
*/
public $certificateDate;

View file

@ -90,4 +90,12 @@ class PaymentType
* @JMS\SerializedName("integrationModule")
*/
public $integrationModule;
/**
* @var string[]
*
* @JMS\Type("array")
* @JMS\SerializedName("sites")
*/
public $sites;
}

View file

@ -75,6 +75,14 @@ class PriceType
*/
public $filterExpression;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("currency")
*/
public $currency;
/**
* @var \RetailCrm\Api\Model\Entity\References\GeoHierarchyRow[]
*

View file

@ -20,6 +20,14 @@ use RetailCrm\Api\Component\Serializer\Annotation as JMS;
*/
class Site
{
/**
* @var int
*
* @JMS\Type("int")
* @JMS\SerializedName("id")
*/
public $id;
/**
* @var string
*
@ -148,6 +156,14 @@ class Site
*/
public $countryIso;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("currency")
*/
public $currency;
/**
* @var string
*

View file

@ -91,6 +91,14 @@ class Store
*/
public $phone;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("contact")
*/
public $contact;
/**
* @var string
*

View file

@ -0,0 +1,45 @@
<?php
/**
* PHP version 7.3
*
* @category Feature
* @package RetailCrm\Api\Model\Entity\Settings
*/
namespace RetailCrm\Api\Model\Entity\Settings;
use RetailCrm\Api\Component\Serializer\Annotation as JMS;
/**
* Class ChannelSetting
*
* @category ChannelSetting
* @package RetailCrm\Api\Model\Entity\Settings
*/
class ChannelSetting
{
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("site")
*/
public $site;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("order_type")
*/
public $orderType;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("order_method")
*/
public $orderMethod;
}

View file

@ -0,0 +1,37 @@
<?php
/**
* PHP version 7.3
*
* @category Feature
* @package RetailCrm\Api\Model\Entity\Settings
*/
namespace RetailCrm\Api\Model\Entity\Settings;
use RetailCrm\Api\Component\Serializer\Annotation as JMS;
/**
* Class Feature
*
* @category Feature
* @package RetailCrm\Api\Model\Entity\Settings
*/
class Feature
{
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("code")
*/
public $code;
/**
* @var bool
*
* @JMS\Type("bool")
* @JMS\SerializedName("available")
*/
public $available;
}

View file

@ -0,0 +1,37 @@
<?php
/**
* PHP version 7.3
*
* @category Feature
* @package RetailCrm\Api\Model\Entity\Settings
*/
namespace RetailCrm\Api\Model\Entity\Settings;
use RetailCrm\Api\Component\Serializer\Annotation as JMS;
/**
* Class MgOrderCreationSettings
*
* @category MgOrderCreationSettings
* @package RetailCrm\Api\Model\Entity\Settings
*/
class MgOrderCreationSettings
{
/**
* @var \RetailCrm\Api\Model\Entity\Settings\ChannelSetting
*
* @JMS\Type("RetailCrm\Api\Model\Entity\Settings\ChannelSetting")
* @JMS\SerializedName("default")
*/
public $default;
/**
* @var array<int, \RetailCrm\Api\Model\Entity\Settings\ChannelSetting>
*
* @JMS\Type("array<int, RetailCrm\Api\Model\Entity\Settings\ChannelSetting>")
* @JMS\SerializedName("channels")
*/
public $channels;
}

View file

@ -0,0 +1,29 @@
<?php
/**
* PHP version 7.3
*
* @category Feature
* @package RetailCrm\Api\Model\Entity\Settings
*/
namespace RetailCrm\Api\Model\Entity\Settings;
use RetailCrm\Api\Component\Serializer\Annotation as JMS;
/**
* Class MgSettings
*
* @category MgSettings
* @package RetailCrm\Api\Model\Entity\Settings
*/
class MgSettings
{
/**
* @var \RetailCrm\Api\Model\Entity\Settings\MgOrderCreationSettings
*
* @JMS\Type("RetailCrm\Api\Model\Entity\Settings\MgOrderCreationSettings")
* @JMS\SerializedName("order_creation")
*/
public $orderCreation;
}

View file

@ -0,0 +1,37 @@
<?php
/**
* PHP version 7.3
*
* @category Value
* @package RetailCrm\Api\Model\Entity\Settings
*/
namespace RetailCrm\Api\Model\Entity\Settings;
use RetailCrm\Api\Component\Serializer\Annotation as JMS;
/**
* Class NonWorkingDay
*
* @category NonWorkingDay
* @package RetailCrm\Api\Model\Entity\Settings
*/
class NonWorkingDay
{
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("start_date")
*/
public $startDate;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("end_date")
*/
public $endDate;
}

View file

@ -42,4 +42,28 @@ class Settings
* @JMS\SerializedName("timezone")
*/
public $timezone;
/**
* @var \RetailCrm\Api\Model\Entity\Settings\WorkTime[]
*
* @JMS\Type("array<RetailCrm\Api\Model\Entity\Settings\WorkTime>")
* @JMS\SerializedName("work_times")
*/
public $workTimes;
/**
* @var \RetailCrm\Api\Model\Entity\Settings\NonWorkingDay[]
*
* @JMS\Type("array<RetailCrm\Api\Model\Entity\Settings\NonWorkingDay>")
* @JMS\SerializedName("non_working_days")
*/
public $nonWorkingDays;
/**
* @var \RetailCrm\Api\Model\Entity\Settings\MgSettings
*
* @JMS\Type("RetailCrm\Api\Model\Entity\Settings\MgSettings")
* @JMS\SerializedName("mg")
*/
public $mgSettings;
}

View file

@ -0,0 +1,61 @@
<?php
/**
* PHP version 7.3
*
* @category Value
* @package RetailCrm\Api\Model\Entity\Settings
*/
namespace RetailCrm\Api\Model\Entity\Settings;
use RetailCrm\Api\Component\Serializer\Annotation as JMS;
/**
* Class WorkTime
*
* @category WorkTime
* @package RetailCrm\Api\Model\Entity\Settings
*/
class WorkTime
{
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("day_type")
*/
public $dayType;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("start_time")
*/
public $startTime;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("end_time")
*/
public $endTime;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("lunch_start_time")
*/
public $lunchStartTime;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("lunch_end_time")
*/
public $lunchEndTime;
}

View file

@ -42,4 +42,12 @@ class OfferPrice
* @JMS\SerializedName("ordering")
*/
public $ordering;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("currency")
*/
public $currency;
}

View file

@ -0,0 +1,190 @@
<?php
/**
* PHP version 7.3
*
* @category OfferProduct
* @package RetailCrm\Api\Model\Entity\Store
*/
namespace RetailCrm\Api\Model\Entity\Store;
use DateTime;
use RetailCrm\Api\Component\Serializer\Annotation as JMS;
/**
* Class Product
*
* @category OfferProduct
* @package RetailCrm\Api\Model\Entity\Store
*/
class OfferProduct
{
/**
* @var float
*
* @JMS\Type("float")
* @JMS\SerializedName("minPrice")
*/
public $minPrice;
/**
* @var float
*
* @JMS\Type("float")
* @JMS\SerializedName("maxPrice")
*/
public $maxPrice;
/**
* @var int
*
* @JMS\Type("int")
* @JMS\SerializedName("id")
*/
public $id;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("article")
*/
public $article;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("name")
*/
public $name;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("url")
*/
public $url;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("imageUrl")
*/
public $imageUrl;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("description")
*/
public $description;
/**
* @var bool
*
* @JMS\Type("bool")
* @JMS\SerializedName("popular")
*/
public $popular;
/**
* @var bool
*
* @JMS\Type("bool")
* @JMS\SerializedName("stock")
*/
public $stock;
/**
* @var bool
*
* @JMS\Type("bool")
* @JMS\SerializedName("novelty")
*/
public $novelty;
/**
* @var bool
*
* @JMS\Type("bool")
* @JMS\SerializedName("recommended")
*/
public $recommended;
/**
* @var array<string, mixed>
*
* @JMS\Type("array")
* @JMS\SerializedName("properties")
*/
public $properties;
/**
* @var \RetailCrm\Api\Model\Entity\FixExternalRow[]
*
* @JMS\Type("array<RetailCrm\Api\Model\Entity\FixExternalRow>")
* @JMS\SerializedName("groups")
*/
public $groups;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("externalId")
*/
public $externalId;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("manufacturer")
*/
public $manufacturer;
/**
* @var bool
*
* @JMS\Type("bool")
* @JMS\SerializedName("active")
*/
public $active;
/**
* @var float
*
* @JMS\Type("float")
* @JMS\SerializedName("quantity")
*/
public $quantity;
/**
* @var bool
*
* @JMS\Type("bool")
* @JMS\SerializedName("markable")
*/
public $markable;
/**
* @var DateTime
*
* @JMS\Type("DateTime<'Y-m-d H:i:s'>")
* @JMS\SerializedName("updatedAt")
*/
public $updatedAt;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("type")
*/
public $type;
}

View file

@ -36,6 +36,14 @@ class Product
*/
public $maxPrice;
/**
* @var int
*
* @JMS\Type("int")
* @JMS\SerializedName("catalogId")
*/
public $catalogId;
/**
* @var int
*
@ -187,4 +195,12 @@ class Product
* @JMS\SerializedName("updatedAt")
*/
public $updatedAt;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("type")
*/
public $type;
}

View file

@ -0,0 +1,141 @@
<?php
/**
* PHP version 7.3
*
* @category ProductCreateInput
* @package RetailCrm\Api\Model\Request\Store
*/
namespace RetailCrm\Api\Model\Entity\Store;
use RetailCrm\Api\Component\Serializer\Annotation as JMS;
/**
* Abstract class ProductBatchBase
*
* @category ProductBatchBase
* @package RetailCrm\Api\Model\Response\Store
*/
abstract class ProductBatchBase
{
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("article")
*/
public $article;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("name")
*/
public $name;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("url")
*/
public $url;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("description")
*/
public $description;
/**
* @var bool
*
* @JMS\Type("bool")
* @JMS\SerializedName("popular")
*/
public $popular;
/**
* @var bool
*
* @JMS\Type("bool")
* @JMS\SerializedName("stock")
*/
public $stock;
/**
* @var bool
*
* @JMS\Type("bool")
* @JMS\SerializedName("novelty")
*/
public $novelty;
/**
* @var bool
*
* @JMS\Type("bool")
* @JMS\SerializedName("recommended")
*/
public $recommended;
/**
* @var \RetailCrm\Api\Model\Entity\Store\ProductEditGroupInput[]
*
* @JMS\Type("array<RetailCrm\Api\Model\Entity\Store\ProductEditGroupInput>")
* @JMS\SerializedName("groups")
*/
public $groups;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("externalId")
*/
public $externalId;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("manufacturer")
*/
public $manufacturer;
/**
* @var bool
*
* @JMS\Type("bool")
* @JMS\SerializedName("active")
*/
public $active;
/**
* @var bool
*
* @JMS\Type("bool")
* @JMS\SerializedName("markable")
*/
public $markable;
/**
* @var int
*
* @JMS\Type("int")
* @JMS\SerializedName("catalogId")
*/
public $catalogId;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("type")
*/
public $type;
}

View file

@ -0,0 +1,20 @@
<?php
/**
* PHP version 7.3
*
* @category ProductCreateInput
* @package RetailCrm\Api\Model\Request\Store
*/
namespace RetailCrm\Api\Model\Entity\Store;
/**
* Class ProductCreateInput
*
* @category ProductCreateInput
* @package RetailCrm\Api\Model\Response\Store
*/
class ProductCreateInput extends ProductBatchBase
{
}

View file

@ -17,7 +17,7 @@ use RetailCrm\Api\Component\Serializer\Annotation as JMS;
* @category ProductEditInput
* @package RetailCrm\Api\Model\Response\Store
*/
class ProductEditInput
class ProductEditInput extends ProductBatchBase
{
/**
* @var int
@ -27,110 +27,6 @@ class ProductEditInput
*/
public $id;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("article")
*/
public $article;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("name")
*/
public $name;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("url")
*/
public $url;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("description")
*/
public $description;
/**
* @var bool
*
* @JMS\Type("bool")
* @JMS\SerializedName("popular")
*/
public $popular;
/**
* @var bool
*
* @JMS\Type("bool")
* @JMS\SerializedName("stock")
*/
public $stock;
/**
* @var bool
*
* @JMS\Type("bool")
* @JMS\SerializedName("novelty")
*/
public $novelty;
/**
* @var bool
*
* @JMS\Type("bool")
* @JMS\SerializedName("recommended")
*/
public $recommended;
/**
* @var \RetailCrm\Api\Model\Entity\Store\ProductEditGroupInput[]
*
* @JMS\Type("array<RetailCrm\Api\Model\Entity\Store\ProductEditGroupInput>")
* @JMS\SerializedName("groups")
*/
public $groups;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("externalId")
*/
public $externalId;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("manufacturer")
*/
public $manufacturer;
/**
* @var bool
*
* @JMS\Type("bool")
* @JMS\SerializedName("active")
*/
public $active;
/**
* @var bool
*
* @JMS\Type("bool")
* @JMS\SerializedName("markable")
*/
public $markable;
/**
* @var string
*
@ -138,12 +34,4 @@ class ProductEditInput
* @JMS\SerializedName("site")
*/
public $site;
/**
* @var int
*
* @JMS\Type("int")
* @JMS\SerializedName("catalogId")
*/
public $catalogId;
}

View file

@ -66,4 +66,12 @@ class ProductGroup
* @JMS\SerializedName("active")
*/
public $active;
/**
* @var int
*
* @JMS\Type("int")
* @JMS\SerializedName("lvl")
*/
public $lvl;
}

View file

@ -170,4 +170,12 @@ class ProductOffer
* @JMS\SerializedName("barcode")
*/
public $barcode;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("site")
*/
public $site;
}

View file

@ -0,0 +1,45 @@
<?php
/**
* PHP version 7.3
*
* @category ProductPropertyValue
* @package RetailCrm\Api\Model\Entity\Store
*/
namespace RetailCrm\Api\Model\Entity\Store;
use RetailCrm\Api\Component\Serializer\Annotation as JMS;
/**
* Class ProductPropertyValue
*
* @category ProductPropertyValue
* @package RetailCrm\Api\Model\Entity\Store
*/
class ProductPropertyValue
{
/**
* @var \RetailCrm\Api\Model\Entity\Store\ProductProperty
*
* @JMS\Type("RetailCrm\Api\Model\Entity\Store\ProductProperty")
* @JMS\SerializedName("property")
*/
public $property;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("value")
*/
public $value;
/**
* @var int
*
* @JMS\Type("int")
* @JMS\SerializedName("offersCount")
*/
public $offersCount;
}

View file

@ -0,0 +1,77 @@
<?php
/**
* PHP version 7.3
*
* @category SerializedProductGroup
* @package RetailCrm\Api\Model\Entity\Store
*/
namespace RetailCrm\Api\Model\Entity\Store;
use RetailCrm\Api\Component\Serializer\Annotation as JMS;
/**
* Class SerializedProductGroup
*
* @category SerializedProductGroup
* @package RetailCrm\Api\Model\Entity\Store
*/
class SerializedProductGroup
{
/**
* @var int
*
* @JMS\Type("int")
* @JMS\SerializedName("parentId")
*/
public $parentId;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("name")
*/
public $name;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("description")
*/
public $description;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("externalId")
*/
public $externalId;
/**
* @var bool
*
* @JMS\Type("bool")
* @JMS\SerializedName("active")
*/
public $active;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("parentExternalId")
*/
public $parentExternalId;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("site")
*/
public $site;
}

View file

@ -0,0 +1,34 @@
<?php
/**
* PHP version 7.3
*
* @category StoreOffer
* @package RetailCrm\Api\Model\Entity\Store
*/
namespace RetailCrm\Api\Model\Entity\Store;
use RetailCrm\Api\Component\Serializer\Annotation as JMS;
/**
* Class StoreOffer
*
* @category StoreOffer
* @package RetailCrm\Api\Model\Entity\Store
*/
class StoreOffer extends ProductOffer
{
/**
* @JMS\Exclude()
*/
public $price;
/**
* @var \RetailCrm\Api\Model\Entity\Store\Product
*
* @JMS\Type("RetailCrm\Api\Model\Entity\Store\Product")
* @JMS\SerializedName("product")
*/
public $product;
}

View file

@ -0,0 +1,37 @@
<?php
/**
* PHP version 7.3
*
* @category BaseComment
* @package RetailCrm\Api\Model\Entity\Tasks
*/
namespace RetailCrm\Api\Model\Entity\Tasks;
use RetailCrm\Api\Component\Serializer\Annotation as JMS;
/**
* Class BaseComment
*
* @category BaseComment
* @package RetailCrm\Api\Model\Entity\Tasks
*/
class BaseComment
{
/**
* @var int
*
* @JMS\Type("int")
* @JMS\SerializedName("id")
*/
public $id;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("text")
*/
public $text;
}

View file

@ -0,0 +1,46 @@
<?php
/**
* PHP version 7.3
*
* @category TaskComment
* @package RetailCrm\Api\Model\Entity\Tasks
*/
namespace RetailCrm\Api\Model\Entity\Tasks;
use DateTime;
use RetailCrm\Api\Component\Serializer\Annotation as JMS;
/**
* Class TaskComment
*
* @category TaskComment
* @package RetailCrm\Api\Model\Entity\Tasks
*/
class TaskComment extends BaseComment
{
/**
* @var int
*
* @JMS\Type("int")
* @JMS\SerializedName("creator")
*/
public $creator;
/**
* @var DateTime
*
* @JMS\Type("DateTime<'Y-m-d H:i:s'>")
* @JMS\SerializedName("createdAt")
*/
public $createdAt;
/**
* @var DateTime
*
* @JMS\Type("DateTime<'Y-m-d H:i:s'>")
* @JMS\SerializedName("updatedAt")
*/
public $updatedAt;
}

View file

@ -0,0 +1,110 @@
<?php
/**
* PHP version 7.3
*
* @category TaskHistory
* @package RetailCrm\Api\Model\Entity\Tasks
*/
namespace RetailCrm\Api\Model\Entity\Tasks;
use DateTime;
use RetailCrm\Api\Component\Serializer\Annotation as JMS;
/**
* Class TaskHistory
*
* @category TaskHistory
* @package RetailCrm\Api\Model\Entity\Tasks
*/
class TaskHistory
{
/**
* @var int
*
* @JMS\Type("int")
* @JMS\SerializedName("id")
*/
public $id;
/**
* @var DateTime
*
* @JMS\Type("DateTime<'Y-m-d H:i:s'>")
* @JMS\SerializedName("createdAt")
*/
public $createdAt;
/**
* @var bool
*
* @JMS\Type("bool")
* @JMS\SerializedName("created")
*/
public $created;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("source")
*/
public $source;
/**
* @var \RetailCrm\Api\Model\Entity\HistoryUser
*
* @JMS\Type("RetailCrm\Api\Model\Entity\HistoryUser")
* @JMS\SerializedName("user")
*/
public $user;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("field")
*/
public $field;
/**
* @var mixed
*
* @JMS\Type("mixed")
* @JMS\SerializedName("oldValue")
*/
public $oldValue;
/**
* @var mixed
*
* @JMS\Type("mixed")
* @JMS\SerializedName("newValue")
*/
public $newValue;
/**
* @var \RetailCrm\Api\Model\Entity\HistoryApiKey
*
* @JMS\Type("RetailCrm\Api\Model\Entity\HistoryApiKey")
* @JMS\SerializedName("apiKey")
*/
public $apiKey;
/**
* @var \RetailCrm\Api\Model\Entity\Tasks\Task
*
* @JMS\Type("RetailCrm\Api\Model\Entity\Tasks\Task")
* @JMS\SerializedName("task")
*/
public $task;
/**
* @var \RetailCrm\Api\Model\Entity\Tasks\BaseComment
*
* @JMS\Type("RetailCrm\Api\Model\Entity\Tasks\BaseComment")
* @JMS\SerializedName("comment")
*/
public $comment;
}

View file

@ -76,6 +76,14 @@ class User
*/
public $patronymic;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("position")
*/
public $position;
/**
* @var string
*

View file

@ -0,0 +1,62 @@
<?php
/**
* PHP version 7.3
*
* @category ClientId
* @package RetailCrm\Api\Model\Entity\WebAnalytics
*/
namespace RetailCrm\Api\Model\Entity\WebAnalytics;
use DateTime;
use RetailCrm\Api\Component\Serializer\Annotation as JMS;
/**
* Class ClientId
*
* @category ClientId
* @package RetailCrm\Api\Model\Entity\WebAnalytics
*/
class ClientId
{
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("value")
*/
public $value;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("site")
*/
public $site;
/**
* @var Order
*
* @JMS\Type("RetailCrm\Api\Model\Entity\WebAnalytics\Order")
* @JMS\SerializedName("order")
*/
public $order;
/**
* @var Customer
*
* @JMS\Type("RetailCrm\Api\Model\Entity\WebAnalytics\Customer")
* @JMS\SerializedName("customer")
*/
public $customer;
/**
* @var DateTime
*
* @JMS\Type("DateTime<'Y-m-d H:i:s'>")
* @JMS\SerializedName("createdAt")
*/
public $createdAt;
}

View file

@ -0,0 +1,46 @@
<?php
/**
* PHP version 7.3
*
* @category Customer
* @package RetailCrm\Api\Model\Entity\WebAnalytics
*/
namespace RetailCrm\Api\Model\Entity\WebAnalytics;
use DateTime;
use RetailCrm\Api\Component\Serializer\Annotation as JMS;
/**
* Class Customer
*
* @category Customer
* @package RetailCrm\Api\Model\Entity\WebAnalytics
*/
class Customer
{
/**
* @var int
*
* @JMS\Type("int")
* @JMS\SerializedName("id")
*/
public $id;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("externalId")
*/
public $externalId;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("type")
*/
public $type;
}

View file

@ -0,0 +1,46 @@
<?php
/**
* PHP version 7.3
*
* @category Order
* @package RetailCrm\Api\Model\Entity\WebAnalytics
*/
namespace RetailCrm\Api\Model\Entity\WebAnalytics;
use DateTime;
use RetailCrm\Api\Component\Serializer\Annotation as JMS;
/**
* Class Order
*
* @category Order
* @package RetailCrm\Api\Model\Entity\WebAnalytics
*/
class Order
{
/**
* @var int
*
* @JMS\Type("int")
* @JMS\SerializedName("id")
*/
public $id;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("externalId")
*/
public $externalId;
/**
* @var string
*
* @JMS\Type("string")
* @JMS\SerializedName("number")
*/
public $number;
}

Some files were not shown because too many files have changed in this diff Show more