diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1754c28 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,8 @@ +/.github export-ignore +/build export-ignore +/tests export-ignore +/tests-resources export-ignore +/.gitattributes export-ignore +/.gitignore export-ignore + +*.php diff=php \ No newline at end of file diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..9385edd --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,56 @@ +name: Tests + +on: + push: + branches: + - main + - master + pull_request: + branches: + - main + - master + +jobs: + tests: + name: PHP ${{ matrix.php }} + runs-on: ubuntu-latest + strategy: + matrix: + php: + - 7.0 + - 7.1 + - 7.2 + - 7.3 + - 7.4 + - 8.0 + - 8.1 + - 8.2 + - 8.3 + - 8.4 + - 8.5 + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + + - id: composer-cache + run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT + + - name: Cache Composer dependencies + uses: actions/cache@v3 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: composer-${{ runner.os }}-${{ matrix.php }}-${{ hashFiles('composer.json') }} + + - name: Install dependencies + run: composer update --prefer-dist --no-interaction + + - name: Audit dependencies + run: composer audit || true + + - name: Running unit tests + run: php vendor/bin/phpunit --configuration tests-resources/phpunit.dist.xml --testsuite unit diff --git a/.gitignore b/.gitignore index 2a0d621..130e21e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ /tests-resources/config/config.yml +/tests-resources/phpunit.xml /vendor /composer.lock -/phpunit.xml -/composer.phar +.phpunit.result.cache diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 1edde00..0000000 --- a/.travis.yml +++ /dev/null @@ -1,11 +0,0 @@ -language: php -php: -- '7.0' -- '7.1' -- '7.2' -- '7.3' -- '7.4' -before_script: -- composer self-update -- composer install -script: ./vendor/bin/phpunit --configuration phpunit.dist.xml --testsuite unit diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b74274..190eb08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,13 +3,84 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [3.0.13] - 2026-01-12 +### Added +- PHP-8.5 support + +## [3.0.12] - 2025-07-03 +### Added +- PHP-8.4 support + +## [3.0.11] - 2024-03-27 +### Added +- service url scheme and host validation +- service url with port support + +### Changed +- PSR-18 HTTP client related exceptions namespace moved + +## [3.0.10] - 2024-01-16 +### Added +- PHP-8.3 support +- `SendSmsBag::$timeRestriction` optional parameter +- `SendSmssBag::$timeRestriction` optional parameter +- `SendSmsToGroupBag::$timeRestriction` optional parameter +- `ScheduleSmsBag::$timeRestriction` optional parameter +- `ScheduleSmssBag::$timeRestriction` optional parameter +- `ScheduleSmsToGroupBag::$timeRestriction` optional parameter +### Fixed +- sending/scheduling smses in large amount + +## [3.0.9] - 2024-01-09 +### Fixed +- expired MFA code verification + +## [3.0.8] - 2023-10-18 +### Added +- `psr/http-message` v2 support + +## [3.0.7] - 2022-11-21 +### Fixed +- dynamic property deprecations + +## [3.0.6] - 2022-03-28 +### Fixed +- HTTP headers parsing, PSR-7 compliant + +## [3.0.5] - 2022-03-23 +### Fixed +- HTTP headers parsing, `HttpClient` issue + +## [3.0.4] - 2022-01-17 +### Added +- `psr/log` v2, v3 support + +## [3.0.3] - 2021-07-21 +### Fixed +- Guzzle PSR7 incompatible URI paths, `The path of a URI with an authority must start with a slash "/" or be empty` + +## [3.0.2] - 2021-01-29 +### Added +- PHP-8 support + +## [3.0.1] - 2020-12-08 +### Changed +- Guzzle HTTP helpers marked as optional dependency + +## [3.0.0] - 2020-11-19 +### Added +- PSR-18 support +- PSR-17 support + ### Changed - utf-8 as default encoding - `CreateContactBag::withPhone` marked as deprecated - `PingFeature::ping` returns authorization and service availability status ### Removed +- built-in proxy support - use own implementation +- concrete HTTP client dependency (Guzzle 6) +- `PushFeature` - `SendSmsBag::setIdx` - `DeleteSmsBag` - `FindSendernamesBag` diff --git a/Makefile b/Makefile deleted file mode 100644 index 1704bc8..0000000 --- a/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -.PHONY: help - -help: - @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' - -.DEFAULT_GOAL := help - -prepare: ## load dependencies - docker-compose run -T php /usr/bin/composer update - -test: prepare ## run test - docker-compose run -T php php vendor/bin/phing -f build.xml test - -test-suite: prepare ## run test against suite, ex: make test-suite SUITE="unit" - docker-compose run -T php php vendor/bin/phing -f build.xml test -Dsuite=$(SUITE) \ No newline at end of file diff --git a/README.md b/README.md index b5482c5..95ef8f3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # SMSAPI PHP Client -[![Build Status](https://travis-ci.org/smsapi/smsapi-php-client.svg?branch=master)](https://travis-ci.org/smsapi/smsapi-php-client) +[![Build Status](https://github.com/smsapi/smsapi-php-client/actions/workflows/tests.yml/badge.svg)](https://github.com/smsapi/smsapi-php-client/actions/workflows/tests.yml) [![Packagist - latest version](https://img.shields.io/packagist/v/smsapi/php-client.svg)](https://packagist.org/packages/smsapi/php-client) [![Packagist - downloads](https://img.shields.io/packagist/dt/smsapi/php-client.svg)](https://packagist.org/packages/smsapi/php-client) [![Packagist - license](https://img.shields.io/packagist/l/smsapi/php-client.svg)](https://packagist.org/packages/smsapi/php-client) @@ -23,144 +23,181 @@ Execute: `composer require smsapi/php-client` Depending on which of SMSAPI service your account is, you should pick it calling one of a method from examples below: -### How to use *SMSAPI.COM* client? +### PSR-17 and PSR-18 + +Starting from version 3, SMSAPI PHP Client supports PSR-17 and PSR-18 compliant HTTP clients. +That way this library is independent of client of your choice. +You have to provide HTTP client, request factory and stream factory to use our library. + +For your convenience we provide an adapter for Curl. To use it you have to enable PHP curl extension and install some HTTP helpers: + +``` +composer require guzzlehttp/psr7:^1 +``` + +Example below shows how to make use of that adapter (pay attention to namespace *Smsapi\Client\Curl*): ```php smsapiComService($apiToken); +$client = new SmsapiHttpClient($httpClient, $requestFactory, $streamFactory); ``` -### How to use *SMSAPI.PL* client? +All following examples consider you have client well-defined in `client.php` file. + +### How to use *SMSAPI.COM* service? ```php smsapiPlService($apiToken); +$service = $client->smsapiComService($apiToken); ``` -All following examples consider you have a account on SMSAPI.COM. - -## How to use a custom URI? +### How to use *SMSAPI.PL* service? ```php smsapiComServiceWithUri($apiToken, $uri); -``` - -## How to use service business features? +$service = $client->smsapiPlService($apiToken); +``` -### How to use ping feature? +### How to use *SMSAPI.SE* or *SMSAPI.BG* services? ```php smsapiComService($apiToken); -$result = $service->pingFeature() - ->ping(); - -if ($result->authorized) { - echo 'Authorized'; -} else { - echo 'Not authorized'; -} +$service = $client->smsapiComServiceWithUri($apiToken, $uri); ``` -### How to send a SMS? +## How to use service business features? + +All following examples consider you have an account on SMSAPI.COM and service has been setup in `service.php` file. + +### How to use ping feature? ```php pingFeature() + ->ping(); -$service = (new SmsapiHttpClient()) - ->smsapiComService($apiToken); -$service->smsFeature() - ->sendSms($sms); +if ($result->authorized) { + echo 'Authorized'; +} else { + echo 'Not authorized'; +} ``` -### How to send a SMS with optional from field? +### How to send a SMS? ```php from = 'Test'; -$service = (new SmsapiHttpClient()) - ->smsapiComService($apiToken); $service->smsFeature() ->sendSms($sms); ``` -For more usage examples take a look at client test suite. - -### How to use optional request parameters? +### How to use request parameters? Request parameters are represented in a form of data transfer object. DTOs can be found by searching for 'bag' postfixed classes. Each bag may contain required and optional parameters. -Required parameters are that class public properties, usually accessible via some form of a setter or named constructor. -Optional parameters are described by docblock's '@property' annotation. +#### Required parameters + +Required parameters are that class public properties, usually accessible via some form of a setter or named constructor. Each parameter can be also set directly by setting bag property, as in example: +##### How to change SMS encoding? + ```php encoding = 'utf-8'; ``` -## How to use additional features? +#### Optional parameters -### How to use proxy server? +Some of request's optional parameters have been described by docblock's '@property' annotation. +You can always add any not documented here optional parameter by setting dynamic property to 'bag'. +Camel case property names are being converted to snake case on the fly. + +##### How to send a SMS with optional from field? ```php from = 'Test'; -(new SmsapiHttpClient())->setProxy($proxyUrl); +$service->smsFeature() + ->sendSms($sms); ``` +For more usage examples take a look at client test suite. + +## How to use additional features? + +### How to use proxy server? + +To use proxy server you have to define it with your HTTP client. + ### How to log requests and responses? Set logger to `SmsapiHttpClient` instance. @@ -202,10 +255,14 @@ declare(strict_types=1); use Psr\Log\LoggerInterface; use Psr\Log\LoggerTrait; +use Smsapi\Client\SmsapiClient; require_once 'vendor/autoload.php'; -use Smsapi\Client\SmsapiHttpClient; +/** + * @var SmsapiClient $client + */ +require_once 'client.php'; $logger = new class() implements LoggerInterface { @@ -217,17 +274,54 @@ $logger = new class() implements LoggerInterface } }; -(new SmsapiHttpClient())->setLogger($logger); +$client->setLogger($logger); +``` + +## How to test package + +Copy `phpunit.dist.xml` to `phpunit.xml`. You may adjust it to your needs then. + +Copy `tests-resources/config/config.dist.yml` to `tests-resources/config/config.yml`. Fill in SMSAPI service connection data. + +### How to run unit tests + +Unit tests are included into package build process and run against its current version on every commit (see workflow Tests). +You can run those tests locally with ease using provided Docker configuration, simply run: + +```shell +make test-suite SUITE="unit" ``` -## Test package -1. Download package: `composer create-project smsapi/php-client` -2. Execute tests: `./vendor/bin/phing` +### How to run integration tests + +Note that integration test works within an account you have configured in `tests-resources/config/config.yml`. +Although those test have been written to self-cleanup on exit, in case of failure some trash data may stay. +Use it with caution. + +```shell +make test-suite SUITE="integration" +``` + +### How to run feature tests + +Feature test groups are defined in `phpunit.dist.xml`. To run tests execute: + +```shell +make test-suite SUITE="feature-contacts" +``` + +### How to run tests against PHP8 + +To run any of mentioned above against PHP8 use make targets with `php8` suffix. See `Makefile.php8`. ## Docs & Infos * [SMSAPI.COM API documentation](https://www.smsapi.com/docs) * [SMSAPI.PL API documentation](https://www.smsapi.pl/docs) -* [Repository on GitHub](https://github.com/smsapi/smsapi-php-client) -* [Package on Packagist](https://packagist.org/packages/smsapi/php-client) +* [SMSAPI.SE API documentation](https://www.smsapi.se/docs) +* [SMSAPI.BG API documentation](https://www.smsapi.bg/docs) * [SMSAPI.COM web page](https://smsapi.com) * [SMSAPI.PL web page](https://smsapi.pl) +* [SMSAPI.SE web page](https://smsapi.se) +* [SMSAPI.BG web page](https://smsapi.bg) +* [Repository on GitHub](https://github.com/smsapi/smsapi-php-client) +* [Package on Packagist](https://packagist.org/packages/smsapi/php-client) diff --git a/build.xml b/build.xml deleted file mode 100644 index 8fde3ed..0000000 --- a/build.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - diff --git a/build/Makefile b/build/Makefile new file mode 100644 index 0000000..5d807b1 --- /dev/null +++ b/build/Makefile @@ -0,0 +1,46 @@ +.PHONY: help build test + +include $(CURDIR)/php-7.0/Makefile +include $(CURDIR)/php-7.1/Makefile +include $(CURDIR)/php-7.2/Makefile +include $(CURDIR)/php-7.3/Makefile +include $(CURDIR)/php-7.4/Makefile +include $(CURDIR)/php-8.0/Makefile +include $(CURDIR)/php-8.1/Makefile +include $(CURDIR)/php-8.2/Makefile +include $(CURDIR)/php-8.3/Makefile +include $(CURDIR)/php-8.4/Makefile + +help: + @grep -hE '^[a-zA-Z0-9_.-]+:.*?## .*$$' $(MAKEFILE_LIST) \ + | sort \ + | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' + +build: ## build php images + docker compose build + +test: ## test all against all php images + $(MAKE) test-php-7.0 + $(MAKE) test-php-7.1 + $(MAKE) test-php-7.2 + $(MAKE) test-php-7.3 + $(MAKE) test-php-7.4 + $(MAKE) test-php-8.0 + $(MAKE) test-php-8.1 + $(MAKE) test-php-8.2 + $(MAKE) test-php-8.3 + $(MAKE) test-php-8.4 + +test-unit: ## test unit suite against all php images + $(MAKE) test-suite-php-7.0 SUITE=unit + $(MAKE) test-suite-php-7.1 SUITE=unit + $(MAKE) test-suite-php-7.2 SUITE=unit + $(MAKE) test-suite-php-7.3 SUITE=unit + $(MAKE) test-suite-php-7.4 SUITE=unit + $(MAKE) test-suite-php-8.0 SUITE=unit + $(MAKE) test-suite-php-8.1 SUITE=unit + $(MAKE) test-suite-php-8.2 SUITE=unit + $(MAKE) test-suite-php-8.3 SUITE=unit + $(MAKE) test-suite-php-8.4 SUITE=unit + +.DEFAULT_GOAL := help diff --git a/build/docker-compose.yml b/build/docker-compose.yml new file mode 100644 index 0000000..dcbfba0 --- /dev/null +++ b/build/docker-compose.yml @@ -0,0 +1,80 @@ +version: '3.5' + +services: + + php-7.0: + build: + context: php-7.0 + volumes: + - ..:/app + network_mode: host + + php-7.1: + build: + context: php-7.1 + volumes: + - ..:/app + network_mode: host + + php-7.2: + build: + context: php-7.2 + volumes: + - ..:/app + network_mode: host + + php-7.3: + build: + context: php-7.3 + volumes: + - ..:/app + network_mode: host + + php-7.4: + build: + context: php-7.4 + volumes: + - ..:/app + network_mode: host + + php-8.0: + build: + context: php-8.0 + volumes: + - ..:/app + network_mode: host + + php-8.1: + build: + context: php-8.1 + volumes: + - ..:/app + network_mode: host + + php-8.2: + build: + context: php-8.2 + volumes: + - ..:/app + network_mode: host + + php-8.3: + build: + context: php-8.3 + volumes: + - ..:/app + network_mode: host + + php-8.4: + build: + context: php-8.4 + volumes: + - ..:/app + network_mode: host + + php-8.5: + build: + context: php-8.5 + volumes: + - ..:/app + network_mode: host \ No newline at end of file diff --git a/Dockerfile b/build/php-7.0/Dockerfile similarity index 62% rename from Dockerfile rename to build/php-7.0/Dockerfile index f1bf11c..ed516f7 100644 --- a/Dockerfile +++ b/build/php-7.0/Dockerfile @@ -1,4 +1,4 @@ -FROM composer:latest as composer +FROM composer:2.2 as composer FROM php:7.0-cli-alpine RUN apk update && \ @@ -8,10 +8,6 @@ RUN apk update && \ g++ \ make -RUN pecl install xdebug-2.7.2 && \ - pecl clear-cache && \ - docker-php-ext-enable xdebug - COPY --from=composer /usr/bin/composer /usr/bin/composer WORKDIR /app/ \ No newline at end of file diff --git a/build/php-7.0/Makefile b/build/php-7.0/Makefile new file mode 100644 index 0000000..62c467c --- /dev/null +++ b/build/php-7.0/Makefile @@ -0,0 +1,10 @@ +.PHONY: prepare-php-7.0 test-php-7.0 test-suite-php-7.0 + +prepare-php-7.0: ## load dependencies with php 7.0 + docker compose run -T php-7.0 /usr/bin/composer update + +test-php-7.0: prepare-php-7.0 ## run tests against php 7.0 + docker compose run -T php-7.0 php vendor/bin/phpunit --configuration tests-resources/phpunit.xml + +test-suite-php-7.0: prepare-php-7.0 ## run suite tests against php 7.0, ex: make test-suite-php-7.0 SUITE="unit" + docker compose run -T php-7.0 php vendor/bin/phpunit --configuration tests-resources/phpunit.xml --testsuite $(SUITE) \ No newline at end of file diff --git a/build/php-7.1/Dockerfile b/build/php-7.1/Dockerfile new file mode 100644 index 0000000..2a0487e --- /dev/null +++ b/build/php-7.1/Dockerfile @@ -0,0 +1,10 @@ +FROM composer:2.2 as composer +FROM php:7.1-cli-alpine + +RUN apk update && \ + apk upgrade && \ + apk add --no-cache make + +COPY --from=composer /usr/bin/composer /usr/bin/composer + +WORKDIR /app/ \ No newline at end of file diff --git a/build/php-7.1/Makefile b/build/php-7.1/Makefile new file mode 100644 index 0000000..26cbfad --- /dev/null +++ b/build/php-7.1/Makefile @@ -0,0 +1,10 @@ +.PHONY: prepare-php-7.1 test-php-7.1 test-suite-php-7.1 + +prepare-php-7.1: ## load dependencies with php 7.1 + docker compose run -T php-7.1 /usr/bin/composer update + +test-php-7.1: prepare-php-7.1 ## run tests against php 7.1 + docker compose run -T php-7.1 php vendor/bin/phpunit --configuration tests-resources/phpunit.xml + +test-suite-php-7.1: prepare-php-7.1 ## run suite tests against php 7.1, ex: make test-suite-php-7.1 SUITE="unit" + docker compose run -T php-7.1 php vendor/bin/phpunit --configuration tests-resources/phpunit.xml --testsuite $(SUITE) \ No newline at end of file diff --git a/build/php-7.2/Dockerfile b/build/php-7.2/Dockerfile new file mode 100644 index 0000000..bd7b230 --- /dev/null +++ b/build/php-7.2/Dockerfile @@ -0,0 +1,10 @@ +FROM composer:2.2 as composer +FROM php:7.2-cli-alpine + +RUN apk update && \ + apk upgrade && \ + apk add --no-cache make + +COPY --from=composer /usr/bin/composer /usr/bin/composer + +WORKDIR /app/ \ No newline at end of file diff --git a/build/php-7.2/Makefile b/build/php-7.2/Makefile new file mode 100644 index 0000000..6cb0833 --- /dev/null +++ b/build/php-7.2/Makefile @@ -0,0 +1,10 @@ +.PHONY: prepare-php-7.2 test-php-7.2 test-suite-php-7.2 + +prepare-php-7.2: ## load dependencies with php 7.2 + docker compose run -T php-7.2 /usr/bin/composer update + +test-php-7.2: prepare-php-7.2 ## run tests against php 7.2 + docker compose run -T php-7.2 php vendor/bin/phpunit --configuration tests-resources/phpunit.xml + +test-suite-php-7.2: prepare-php-7.2 ## run suite tests against php 7.2, ex: make test-suite-php-7.2 SUITE="unit" + docker compose run -T php-7.2 php vendor/bin/phpunit --configuration tests-resources/phpunit.xml --testsuite $(SUITE) \ No newline at end of file diff --git a/build/php-7.3/Dockerfile b/build/php-7.3/Dockerfile new file mode 100644 index 0000000..28ef4fc --- /dev/null +++ b/build/php-7.3/Dockerfile @@ -0,0 +1,10 @@ +FROM composer:2.2 as composer +FROM php:7.3-cli-alpine + +RUN apk update && \ + apk upgrade && \ + apk add --no-cache make + +COPY --from=composer /usr/bin/composer /usr/bin/composer + +WORKDIR /app/ \ No newline at end of file diff --git a/build/php-7.3/Makefile b/build/php-7.3/Makefile new file mode 100644 index 0000000..99e7817 --- /dev/null +++ b/build/php-7.3/Makefile @@ -0,0 +1,10 @@ +.PHONY: prepare-php-7.3 test-php-7.3 test-suite-php-7.3 + +prepare-php-7.3: ## load dependencies with php 7.3 + docker compose run -T php-7.3 /usr/bin/composer update + +test-php-7.3: prepare-php-7.3 ## run tests against php 7.3 + docker compose run -T php-7.3 php vendor/bin/phpunit --configuration tests-resources/phpunit.xml + +test-suite-php-7.3: prepare-php-7.3 ## run suite tests against php 7.3, ex: make test-suite-php-7.3 SUITE="unit" + docker compose run -T php-7.3 php vendor/bin/phpunit --configuration tests-resources/phpunit.xml --testsuite $(SUITE) \ No newline at end of file diff --git a/build/php-7.4/Dockerfile b/build/php-7.4/Dockerfile new file mode 100644 index 0000000..d810922 --- /dev/null +++ b/build/php-7.4/Dockerfile @@ -0,0 +1,10 @@ +FROM composer:2.2 as composer +FROM php:7.4-cli-alpine + +RUN apk update && \ + apk upgrade && \ + apk add --no-cache make + +COPY --from=composer /usr/bin/composer /usr/bin/composer + +WORKDIR /app/ \ No newline at end of file diff --git a/build/php-7.4/Makefile b/build/php-7.4/Makefile new file mode 100644 index 0000000..d68c343 --- /dev/null +++ b/build/php-7.4/Makefile @@ -0,0 +1,10 @@ +.PHONY: prepare-php-7.4 test-php-7.4 test-suite-php-7.4 + +prepare-php-7.4: ## load dependencies with php 7.4 + docker compose run -T php-7.4 /usr/bin/composer update + +test-php-7.4: prepare-php-7.4 ## run tests against php 7.4 + docker compose run -T php-7.4 php vendor/bin/phpunit --configuration tests-resources/phpunit.xml + +test-suite-php-7.4: prepare-php-7.4 ## run suite tests against php 7.4, ex: make test-suite-php-7.4 SUITE="unit" + docker compose run -T php-7.4 php vendor/bin/phpunit --configuration tests-resources/phpunit.xml --testsuite $(SUITE) \ No newline at end of file diff --git a/build/php-8.0/Dockerfile b/build/php-8.0/Dockerfile new file mode 100644 index 0000000..04a6435 --- /dev/null +++ b/build/php-8.0/Dockerfile @@ -0,0 +1,10 @@ +FROM composer:latest as composer +FROM php:8.0-cli-alpine + +RUN apk update && \ + apk upgrade && \ + apk add --no-cache make + +COPY --from=composer /usr/bin/composer /usr/bin/composer + +WORKDIR /app/ \ No newline at end of file diff --git a/build/php-8.0/Makefile b/build/php-8.0/Makefile new file mode 100644 index 0000000..b8b7eaf --- /dev/null +++ b/build/php-8.0/Makefile @@ -0,0 +1,10 @@ +.PHONY: prepare-php-8.0 test-php-8.0 test-suite-php-8.0 + +prepare-php-8.0: ## load dependencies with php 8.0 + docker compose run -T php-8.0 /usr/bin/composer update + +test-php-8.0: prepare-php-8.0 ## run tests against php 8.0 + docker compose run -T php-8.0 php vendor/bin/phpunit --configuration tests-resources/phpunit.xml + +test-suite-php-8.0: prepare-php-8.0 ## run suite tests against php 8.0, ex: make test-suite-php-8.0 SUITE="unit" + docker compose run -T php-8.0 php vendor/bin/phpunit --configuration tests-resources/phpunit.xml --testsuite $(SUITE) \ No newline at end of file diff --git a/build/php-8.1/Dockerfile b/build/php-8.1/Dockerfile new file mode 100644 index 0000000..70aea88 --- /dev/null +++ b/build/php-8.1/Dockerfile @@ -0,0 +1,10 @@ +FROM composer:latest as composer +FROM php:8.1-cli-alpine + +RUN apk update && \ + apk upgrade && \ + apk add --no-cache make + +COPY --from=composer /usr/bin/composer /usr/bin/composer + +WORKDIR /app/ \ No newline at end of file diff --git a/build/php-8.1/Makefile b/build/php-8.1/Makefile new file mode 100644 index 0000000..607d37b --- /dev/null +++ b/build/php-8.1/Makefile @@ -0,0 +1,10 @@ +.PHONY: prepare-php-8.1 test-php-8.1 test-suite-php-8.1 + +prepare-php-8.1: ## load dependencies with php 8.1 + docker compose run -T php-8.1 /usr/bin/composer update + +test-php-8.1: prepare-php-8.1 ## run tests against php 8.1 + docker compose run -T php-8.1 php vendor/bin/phpunit --configuration tests-resources/phpunit.xml + +test-suite-php-8.1: prepare-php-8.1 ## run suite tests against php 8.1, ex: make test-suite-php-8.1 SUITE="unit" + docker compose run -T php-8.1 php vendor/bin/phpunit --configuration tests-resources/phpunit.xml --testsuite $(SUITE) \ No newline at end of file diff --git a/build/php-8.2/Dockerfile b/build/php-8.2/Dockerfile new file mode 100644 index 0000000..677d0ad --- /dev/null +++ b/build/php-8.2/Dockerfile @@ -0,0 +1,10 @@ +FROM composer:latest as composer +FROM php:8.2-cli-alpine + +RUN apk update && \ + apk upgrade && \ + apk add --no-cache make + +COPY --from=composer /usr/bin/composer /usr/bin/composer + +WORKDIR /app/ \ No newline at end of file diff --git a/build/php-8.2/Makefile b/build/php-8.2/Makefile new file mode 100644 index 0000000..3867be5 --- /dev/null +++ b/build/php-8.2/Makefile @@ -0,0 +1,10 @@ +.PHONY: prepare-php-8.2 test-php-8.2 test-suite-php-8.2 + +prepare-php-8.2: ## load dependencies with php 8.2 + docker compose run -T php-8.2 /usr/bin/composer update + +test-php-8.2: prepare-php-8.2 ## run tests against php 8.2 + docker compose run -T php-8.2 php vendor/bin/phpunit --configuration tests-resources/phpunit.xml + +test-suite-php-8.2: prepare-php-8.2 ## run suite tests against php 8.2, ex: make test-suite-php-8.2 SUITE="unit" + docker compose run -T php-8.2 php vendor/bin/phpunit --configuration tests-resources/phpunit.xml --testsuite $(SUITE) \ No newline at end of file diff --git a/build/php-8.3/Dockerfile b/build/php-8.3/Dockerfile new file mode 100644 index 0000000..94ac096 --- /dev/null +++ b/build/php-8.3/Dockerfile @@ -0,0 +1,10 @@ +FROM composer:latest as composer +FROM php:8.3-cli-alpine + +RUN apk update && \ + apk upgrade && \ + apk add --no-cache make + +COPY --from=composer /usr/bin/composer /usr/bin/composer + +WORKDIR /app/ \ No newline at end of file diff --git a/build/php-8.3/Makefile b/build/php-8.3/Makefile new file mode 100644 index 0000000..886f5d4 --- /dev/null +++ b/build/php-8.3/Makefile @@ -0,0 +1,10 @@ +.PHONY: prepare-php-8.3 test-php-8.3 test-suite-php-8.3 + +prepare-php-8.3: ## load dependencies with php 8.3 + docker compose run -T php-8.3 /usr/bin/composer update + +test-php-8.3: prepare-php-8.3 ## run tests against php 8.3 + docker compose run -T php-8.3 php vendor/bin/phpunit --configuration tests-resources/phpunit.xml + +test-suite-php-8.3: prepare-php-8.3 ## run suite tests against php 8.3, ex: make test-suite-php-8.3 SUITE="unit" + docker compose run -T php-8.3 php vendor/bin/phpunit --configuration tests-resources/phpunit.xml --testsuite $(SUITE) \ No newline at end of file diff --git a/build/php-8.4/Dockerfile b/build/php-8.4/Dockerfile new file mode 100644 index 0000000..ba691e0 --- /dev/null +++ b/build/php-8.4/Dockerfile @@ -0,0 +1,10 @@ +FROM composer:latest AS composer +FROM php:8.4-cli-alpine + +RUN apk update && \ + apk upgrade && \ + apk add --no-cache make + +COPY --from=composer /usr/bin/composer /usr/bin/composer + +WORKDIR /app/ \ No newline at end of file diff --git a/build/php-8.4/Makefile b/build/php-8.4/Makefile new file mode 100644 index 0000000..bd4cfd0 --- /dev/null +++ b/build/php-8.4/Makefile @@ -0,0 +1,10 @@ +.PHONY: prepare-php-8.4 test-php-8.4 test-suite-php-8.4 + +prepare-php-8.4: ## load dependencies with php 8.4 + docker compose run -T php-8.4 /usr/bin/composer update + +test-php-8.4: prepare-php-8.4 ## run tests against php 8.4 + docker compose run -T php-8.4 php vendor/bin/phpunit --configuration tests-resources/phpunit.xml + +test-suite-php-8.4: prepare-php-8.4 ## run suite tests against php 8.4, ex: make test-suite-php-8.4 SUITE="unit" + docker compose run -T php-8.4 php vendor/bin/phpunit --configuration tests-resources/phpunit.xml --testsuite $(SUITE) \ No newline at end of file diff --git a/build/php-8.5/Dockerfile b/build/php-8.5/Dockerfile new file mode 100644 index 0000000..c93d62d --- /dev/null +++ b/build/php-8.5/Dockerfile @@ -0,0 +1,6 @@ +FROM composer:latest AS composer +FROM php:8.5-cli-alpine + +COPY --from=composer /usr/bin/composer /usr/bin/composer + +WORKDIR /app/ \ No newline at end of file diff --git a/build/php-8.5/Makefile b/build/php-8.5/Makefile new file mode 100644 index 0000000..3a38702 --- /dev/null +++ b/build/php-8.5/Makefile @@ -0,0 +1,10 @@ +.PHONY: prepare-php-8.5 test-php-8.5 test-suite-php-8.5 + +prepare-php-8.5: ## load dependencies with php 8.5 + docker compose run -T php-8.5 /usr/bin/composer update + +test-php-8.5: prepare-php-8.5 ## run tests against php 8.5 + docker compose run -T php-8.5 php vendor/bin/phpunit --configuration tests-resources/phpunit.xml + +test-suite-php-8.5: prepare-php-8.5 ## run suite tests against php 8.5, ex: make test-suite-php-8.5 SUITE="unit" + docker compose run -T php-8.5 php vendor/bin/phpunit --configuration tests-resources/phpunit.xml --testsuite $(SUITE) \ No newline at end of file diff --git a/composer.json b/composer.json index c63aa0a..8c5dad5 100644 --- a/composer.json +++ b/composer.json @@ -16,21 +16,26 @@ } }, "require": { - "php": "^7", + "php": "^7 || ~8.0 || ~8.1 || ~8.2 || ~8.3 || ~8.4 || ~8.5", "ext-json": "*", - "psr/log": "^1", - "psr/http-message": "^1", + "psr/log": "^1 || ^2 || ^3", + "psr/http-message": "~1.0 || ~1.1 || ~2.0", "psr/http-client": "^1", - "guzzlehttp/guzzle": "^6" + "psr/http-factory": "^1" }, "require-dev": { - "phpunit/phpunit": "^6", + "ext-mbstring": "*", + "phpunit/phpunit": "^6 || ~8.5", + "phpspec/prophecy": "^1.7", "symfony/yaml": "^3", - "theodorejb/polycast": "^1", - "marc-mabe/php-enum": "^3", - "phing/phing": "^2.5", - "doctrine/instantiator": "1.0.5", - "phpdocumentor/reflection-docblock": "^4.3", - "phpdocumentor/type-resolver": "^0.5" + "doctrine/instantiator": "1.0.5 || ^1.4.0", + "phpdocumentor/reflection-docblock": "^4.3 || ^5.2.0", + "phpdocumentor/type-resolver": "^0.5 || ^1.3.0", + "guzzlehttp/psr7": "^1 || ^2", + "ext-curl": "*" + }, + "suggest": { + "ext-curl": "To use Curl HttpClient", + "guzzlehttp/psr7": "To use Curl HttpClient and HTTP message factories" } } diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index f669f77..0000000 --- a/docker-compose.yml +++ /dev/null @@ -1,9 +0,0 @@ -version: '3.5' - -services: - php: - build: . - volumes: - - .:/app - network_mode: host - diff --git a/phpcs.xml b/phpcs.xml deleted file mode 100644 index 1a5512f..0000000 --- a/phpcs.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - SMSAPI Coding Standard - - - - - */Standards/*/Tests/*\.(inc|css|js) - - - - - - **/tests/Unit/** - **/tests/Integration/** - - \ No newline at end of file diff --git a/src/Curl/Discovery/CurlDiscovery.php b/src/Curl/Discovery/CurlDiscovery.php new file mode 100644 index 0000000..065b9d4 --- /dev/null +++ b/src/Curl/Discovery/CurlDiscovery.php @@ -0,0 +1,23 @@ +prepareRequestHttpClient($request); + + $this->prepareRequestMethod($request, $httpClient); + $this->prepareRequestBody($request, $httpClient); + $this->prepareRequestHeaders($request, $httpClient); + $this->prepareResponseOptions($httpClient); + + $response = $this->execute($request, $httpClient); + + $this->closeHttpClient($httpClient); + + return $response; + } + + private function prepareRequestHttpClient(RequestInterface $request) + { + $url = strtr("{scheme}://{host}{port}{path}", [ + '{scheme}' => $request->getUri()->getScheme(), + '{host}' => $request->getUri()->getHost(), + '{port}' => $request->getUri()->getPort() ? ':' . $request->getUri()->getPort() : '', + '{path}' => $request->getRequestTarget() + ]); + + $httpClient = curl_init($url); + + if ($httpClient === false) { + throw NetworkException::withRequest( + 'Cannot prepare HTTP client: ' . curl_error($httpClient), + $request + ); + } + + return $httpClient; + } + + private function prepareRequestMethod(RequestInterface $request, $httpClient) + { + curl_setopt($httpClient, CURLOPT_CUSTOMREQUEST, $request->getMethod()); + } + + private function prepareRequestBody(RequestInterface $request, $httpClient) + { + curl_setopt($httpClient, CURLOPT_POSTFIELDS, (string)$request->getBody()); + } + + private function prepareRequestHeaders(RequestInterface $request, $httpClient) + { + $headers = []; + foreach ($request->getHeaders() as $name => $values) { + $headers[] = $name . ': ' . implode(', ', $values); + } + + curl_setopt($httpClient, CURLOPT_HTTPHEADER, $headers); + } + + private function prepareResponseOptions($httpClient) + { + curl_setopt($httpClient, CURLOPT_HEADER, true); + curl_setopt($httpClient, CURLOPT_RETURNTRANSFER, true); + } + + private function execute(RequestInterface $request, $httpClient): ResponseInterface + { + $response = curl_exec($httpClient); + + if ($response === false) { + throw RequestException::withRequest( + 'Cannot send request: ' . curl_error($httpClient), + $request + ); + } + + $responseStatus = curl_getinfo($httpClient, CURLINFO_HTTP_CODE); + + $headerSize = curl_getinfo($httpClient, CURLINFO_HEADER_SIZE); + $headerString = substr($response, 0, $headerSize); + $headers = HttpHeadersParser::parse($headerString); + + $body = substr($response, $headerSize); + + return new Response($responseStatus, $headers, $body); + } + + private function closeHttpClient($httpClient) + { + curl_close($httpClient); + } +} diff --git a/src/Curl/HttpHeadersParser.php b/src/Curl/HttpHeadersParser.php new file mode 100644 index 0000000..9ae2d69 --- /dev/null +++ b/src/Curl/HttpHeadersParser.php @@ -0,0 +1,23 @@ +httpClient = new \Smsapi\Client\SmsapiHttpClient( + new HttpClient(), + new RequestFactory(), + new StreamFactory() + ); + } + + public function smsapiPlService(string $apiToken): SmsapiPlService + { + return $this->httpClient()->smsapiPlService($apiToken); + } + + public function smsapiPlServiceWithUri(string $apiToken, string $uri): SmsapiPlService + { + return $this->httpClient()->smsapiPlServiceWithUri($apiToken, $uri); + } + + public function smsapiComService(string $apiToken): SmsapiComService + { + return $this->httpClient()->smsapiComService($apiToken); + } + + public function smsapiComServiceWithUri(string $apiToken, string $uri): SmsapiComService + { + return $this->httpClient()->smsapiComServiceWithUri($apiToken, $uri); + } + + private function httpClient(): \Smsapi\Client\SmsapiHttpClient + { + if ($this->logger instanceof LoggerInterface) { + $this->httpClient->setLogger($this->logger); + } + + return $this->httpClient; + } +} diff --git a/src/Curl/StreamFactory.php b/src/Curl/StreamFactory.php new file mode 100644 index 0000000..db5e2a3 --- /dev/null +++ b/src/Curl/StreamFactory.php @@ -0,0 +1,31 @@ +dataFactoryProvider = $dataFactoryProvider; } + /** + * @todo method signature to be changed in next major release as implicitly marking parameter as nullable is deprecated since PHP 8.4 + */ public function findContacts(FindContactsBag $findContactsBag = null): array { $result = $this->restRequestExecutor->read('contacts', (array)$findContactsBag); diff --git a/src/Feature/Contacts/Fields/Bag/CreateContactFieldBag.php b/src/Feature/Contacts/Fields/Bag/CreateContactFieldBag.php index 1a45b1c..2269dcc 100644 --- a/src/Feature/Contacts/Fields/Bag/CreateContactFieldBag.php +++ b/src/Feature/Contacts/Fields/Bag/CreateContactFieldBag.php @@ -8,6 +8,7 @@ * @api * @property string $type */ +#[\AllowDynamicProperties] class CreateContactFieldBag { diff --git a/src/Feature/Contacts/Fields/Bag/DeleteContactFieldBag.php b/src/Feature/Contacts/Fields/Bag/DeleteContactFieldBag.php index ecdaabb..cbbb706 100644 --- a/src/Feature/Contacts/Fields/Bag/DeleteContactFieldBag.php +++ b/src/Feature/Contacts/Fields/Bag/DeleteContactFieldBag.php @@ -7,6 +7,7 @@ /** * @api */ +#[\AllowDynamicProperties] class DeleteContactFieldBag { diff --git a/src/Feature/Contacts/Fields/Bag/FindContactFieldOptionsBag.php b/src/Feature/Contacts/Fields/Bag/FindContactFieldOptionsBag.php index e48acc9..adf4d6d 100644 --- a/src/Feature/Contacts/Fields/Bag/FindContactFieldOptionsBag.php +++ b/src/Feature/Contacts/Fields/Bag/FindContactFieldOptionsBag.php @@ -7,6 +7,7 @@ /** * @api */ +#[\AllowDynamicProperties] class FindContactFieldOptionsBag { diff --git a/src/Feature/Contacts/Fields/Bag/UpdateContactFieldBag.php b/src/Feature/Contacts/Fields/Bag/UpdateContactFieldBag.php index 1dd2024..0e5cdbd 100644 --- a/src/Feature/Contacts/Fields/Bag/UpdateContactFieldBag.php +++ b/src/Feature/Contacts/Fields/Bag/UpdateContactFieldBag.php @@ -7,6 +7,7 @@ /** * @api */ +#[\AllowDynamicProperties] class UpdateContactFieldBag { diff --git a/src/Feature/Contacts/Groups/Bag/AssignContactToGroupBag.php b/src/Feature/Contacts/Groups/Bag/AssignContactToGroupBag.php index f4124ad..b51723e 100644 --- a/src/Feature/Contacts/Groups/Bag/AssignContactToGroupBag.php +++ b/src/Feature/Contacts/Groups/Bag/AssignContactToGroupBag.php @@ -7,6 +7,7 @@ /** * @api */ +#[\AllowDynamicProperties] class AssignContactToGroupBag { diff --git a/src/Feature/Contacts/Groups/Bag/CreateGroupBag.php b/src/Feature/Contacts/Groups/Bag/CreateGroupBag.php index 4770a7c..80e934a 100644 --- a/src/Feature/Contacts/Groups/Bag/CreateGroupBag.php +++ b/src/Feature/Contacts/Groups/Bag/CreateGroupBag.php @@ -10,6 +10,7 @@ * @property string $idx * @property integer $contactExpireAfter */ +#[\AllowDynamicProperties] class CreateGroupBag { diff --git a/src/Feature/Contacts/Groups/Bag/DeleteGroupBag.php b/src/Feature/Contacts/Groups/Bag/DeleteGroupBag.php index d6f1bdf..cf7da05 100644 --- a/src/Feature/Contacts/Groups/Bag/DeleteGroupBag.php +++ b/src/Feature/Contacts/Groups/Bag/DeleteGroupBag.php @@ -8,6 +8,7 @@ * @api * @property bool $deleteContacts */ +#[\AllowDynamicProperties] class DeleteGroupBag { diff --git a/src/Feature/Contacts/Groups/Bag/FindContactGroupBag.php b/src/Feature/Contacts/Groups/Bag/FindContactGroupBag.php index 3c4c8e6..2ecfb43 100644 --- a/src/Feature/Contacts/Groups/Bag/FindContactGroupBag.php +++ b/src/Feature/Contacts/Groups/Bag/FindContactGroupBag.php @@ -7,6 +7,7 @@ /** * @api */ +#[\AllowDynamicProperties] class FindContactGroupBag { diff --git a/src/Feature/Contacts/Groups/Bag/FindContactGroupsBag.php b/src/Feature/Contacts/Groups/Bag/FindContactGroupsBag.php index 9ff20f4..053a7bc 100644 --- a/src/Feature/Contacts/Groups/Bag/FindContactGroupsBag.php +++ b/src/Feature/Contacts/Groups/Bag/FindContactGroupsBag.php @@ -7,6 +7,7 @@ /** * @api */ +#[\AllowDynamicProperties] class FindContactGroupsBag { diff --git a/src/Feature/Contacts/Groups/Bag/FindGroupBag.php b/src/Feature/Contacts/Groups/Bag/FindGroupBag.php index 3b17dd4..b169b8a 100644 --- a/src/Feature/Contacts/Groups/Bag/FindGroupBag.php +++ b/src/Feature/Contacts/Groups/Bag/FindGroupBag.php @@ -7,6 +7,7 @@ /** * @api */ +#[\AllowDynamicProperties] class FindGroupBag { diff --git a/src/Feature/Contacts/Groups/Bag/UnpinContactFromGroupBag.php b/src/Feature/Contacts/Groups/Bag/UnpinContactFromGroupBag.php index 550b81d..3b9000d 100644 --- a/src/Feature/Contacts/Groups/Bag/UnpinContactFromGroupBag.php +++ b/src/Feature/Contacts/Groups/Bag/UnpinContactFromGroupBag.php @@ -7,6 +7,7 @@ /** * @api */ +#[\AllowDynamicProperties] class UnpinContactFromGroupBag { diff --git a/src/Feature/Contacts/Groups/Bag/UpdateGroupBag.php b/src/Feature/Contacts/Groups/Bag/UpdateGroupBag.php index ca9a3e4..2eb918f 100644 --- a/src/Feature/Contacts/Groups/Bag/UpdateGroupBag.php +++ b/src/Feature/Contacts/Groups/Bag/UpdateGroupBag.php @@ -10,6 +10,7 @@ * @property string $idx * @property integer $contactExpireAfter */ +#[\AllowDynamicProperties] class UpdateGroupBag { diff --git a/src/Feature/Contacts/Groups/ContactsGroupsHttpFeature.php b/src/Feature/Contacts/Groups/ContactsGroupsHttpFeature.php index 43799b8..da0066f 100644 --- a/src/Feature/Contacts/Groups/ContactsGroupsHttpFeature.php +++ b/src/Feature/Contacts/Groups/ContactsGroupsHttpFeature.php @@ -4,7 +4,6 @@ namespace Smsapi\Client\Feature\Contacts\Groups; -use Smsapi\Client\Feature\Contacts\Groups\Bag\FindGroupsBag; use Smsapi\Client\Feature\Data\DataFactoryProvider; use Smsapi\Client\Infrastructure\RequestExecutor\RestRequestExecutor; use Smsapi\Client\Feature\Contacts\Data\ContactGroup; diff --git a/src/Feature/Contacts/Groups/Members/Bag/AddContactToGroupByQueryBag.php b/src/Feature/Contacts/Groups/Members/Bag/AddContactToGroupByQueryBag.php index 5d63613..a8ee959 100644 --- a/src/Feature/Contacts/Groups/Members/Bag/AddContactToGroupByQueryBag.php +++ b/src/Feature/Contacts/Groups/Members/Bag/AddContactToGroupByQueryBag.php @@ -15,6 +15,7 @@ * @property string $gender * @property string $birthdayDate */ +#[\AllowDynamicProperties] class AddContactToGroupByQueryBag { diff --git a/src/Feature/Contacts/Groups/Members/Bag/FindContactInGroupBag.php b/src/Feature/Contacts/Groups/Members/Bag/FindContactInGroupBag.php index ffa7b02..9238eaa 100644 --- a/src/Feature/Contacts/Groups/Members/Bag/FindContactInGroupBag.php +++ b/src/Feature/Contacts/Groups/Members/Bag/FindContactInGroupBag.php @@ -7,6 +7,7 @@ /** * @api */ +#[\AllowDynamicProperties] class FindContactInGroupBag { diff --git a/src/Feature/Contacts/Groups/Members/Bag/MoveContactToGroupByQueryBag.php b/src/Feature/Contacts/Groups/Members/Bag/MoveContactToGroupByQueryBag.php index c7591b5..2d88a19 100644 --- a/src/Feature/Contacts/Groups/Members/Bag/MoveContactToGroupByQueryBag.php +++ b/src/Feature/Contacts/Groups/Members/Bag/MoveContactToGroupByQueryBag.php @@ -15,6 +15,7 @@ * @property string $gender * @property string $birthdayDate */ +#[\AllowDynamicProperties] class MoveContactToGroupByQueryBag { diff --git a/src/Feature/Contacts/Groups/Members/Bag/PinContactToGroupBag.php b/src/Feature/Contacts/Groups/Members/Bag/PinContactToGroupBag.php index be2f10a..9fe9cbb 100644 --- a/src/Feature/Contacts/Groups/Members/Bag/PinContactToGroupBag.php +++ b/src/Feature/Contacts/Groups/Members/Bag/PinContactToGroupBag.php @@ -7,6 +7,7 @@ /** * @api */ +#[\AllowDynamicProperties] class PinContactToGroupBag { diff --git a/src/Feature/Contacts/Groups/Members/Bag/UnpinContactFromGroupBag.php b/src/Feature/Contacts/Groups/Members/Bag/UnpinContactFromGroupBag.php index 992a168..50cde48 100644 --- a/src/Feature/Contacts/Groups/Members/Bag/UnpinContactFromGroupBag.php +++ b/src/Feature/Contacts/Groups/Members/Bag/UnpinContactFromGroupBag.php @@ -7,6 +7,7 @@ /** * @api */ +#[\AllowDynamicProperties] class UnpinContactFromGroupBag { diff --git a/src/Feature/Contacts/Groups/Members/Bag/UnpinContactFromGroupByQueryBag.php b/src/Feature/Contacts/Groups/Members/Bag/UnpinContactFromGroupByQueryBag.php index a7a8cd3..e36d5c8 100644 --- a/src/Feature/Contacts/Groups/Members/Bag/UnpinContactFromGroupByQueryBag.php +++ b/src/Feature/Contacts/Groups/Members/Bag/UnpinContactFromGroupByQueryBag.php @@ -15,6 +15,7 @@ * @property string $gender * @property string $birthdayDate */ +#[\AllowDynamicProperties] class UnpinContactFromGroupByQueryBag { diff --git a/src/Feature/Contacts/Groups/Permissions/Bag/CreateGroupPermissionBag.php b/src/Feature/Contacts/Groups/Permissions/Bag/CreateGroupPermissionBag.php index 6305d3e..e48404a 100644 --- a/src/Feature/Contacts/Groups/Permissions/Bag/CreateGroupPermissionBag.php +++ b/src/Feature/Contacts/Groups/Permissions/Bag/CreateGroupPermissionBag.php @@ -10,6 +10,7 @@ * @property string $write * @property string $send */ +#[\AllowDynamicProperties] class CreateGroupPermissionBag { diff --git a/src/Feature/Contacts/Groups/Permissions/Bag/DeleteGroupPermissionBag.php b/src/Feature/Contacts/Groups/Permissions/Bag/DeleteGroupPermissionBag.php index f6ba1f2..591cad1 100644 --- a/src/Feature/Contacts/Groups/Permissions/Bag/DeleteGroupPermissionBag.php +++ b/src/Feature/Contacts/Groups/Permissions/Bag/DeleteGroupPermissionBag.php @@ -7,6 +7,7 @@ /** * @api */ +#[\AllowDynamicProperties] class DeleteGroupPermissionBag { diff --git a/src/Feature/Contacts/Groups/Permissions/Bag/FindGroupPermissionBag.php b/src/Feature/Contacts/Groups/Permissions/Bag/FindGroupPermissionBag.php index 4c285e0..150efff 100644 --- a/src/Feature/Contacts/Groups/Permissions/Bag/FindGroupPermissionBag.php +++ b/src/Feature/Contacts/Groups/Permissions/Bag/FindGroupPermissionBag.php @@ -7,6 +7,7 @@ /** * @api */ +#[\AllowDynamicProperties] class FindGroupPermissionBag { diff --git a/src/Feature/Contacts/Groups/Permissions/Bag/FindGroupPermissionsBag.php b/src/Feature/Contacts/Groups/Permissions/Bag/FindGroupPermissionsBag.php index e7d2327..384d47e 100644 --- a/src/Feature/Contacts/Groups/Permissions/Bag/FindGroupPermissionsBag.php +++ b/src/Feature/Contacts/Groups/Permissions/Bag/FindGroupPermissionsBag.php @@ -7,6 +7,7 @@ /** * @api */ +#[\AllowDynamicProperties] class FindGroupPermissionsBag { diff --git a/src/Feature/Contacts/Groups/Permissions/Bag/UpdateGroupPermissionBag.php b/src/Feature/Contacts/Groups/Permissions/Bag/UpdateGroupPermissionBag.php index 4a807e4..54fd14e 100644 --- a/src/Feature/Contacts/Groups/Permissions/Bag/UpdateGroupPermissionBag.php +++ b/src/Feature/Contacts/Groups/Permissions/Bag/UpdateGroupPermissionBag.php @@ -10,6 +10,7 @@ * @property string $write * @property string $send */ +#[\AllowDynamicProperties] class UpdateGroupPermissionBag { diff --git a/src/Feature/Data/DataFactoryProvider.php b/src/Feature/Data/DataFactoryProvider.php index 5ee2506..ca9044a 100644 --- a/src/Feature/Data/DataFactoryProvider.php +++ b/src/Feature/Data/DataFactoryProvider.php @@ -19,12 +19,6 @@ use Smsapi\Client\Feature\Profile\Data\ProfilePriceCountryFactory; use Smsapi\Client\Feature\Profile\Data\ProfilePriceFactory; use Smsapi\Client\Feature\Profile\Data\ProfilePriceNetworkFactory; -use Smsapi\Client\Feature\Push\Data\PushAppFactory; -use Smsapi\Client\Feature\Push\Data\PushShipmentDispatchDetailsFactory; -use Smsapi\Client\Feature\Push\Data\PushShipmentFactory; -use Smsapi\Client\Feature\Push\Data\PushShipmentFallbackFactory; -use Smsapi\Client\Feature\Push\Data\PushShipmentPayloadFactory; -use Smsapi\Client\Feature\Push\Data\PushShipmentSummaryFactory; use Smsapi\Client\Feature\ShortUrl\Data\ShortUrlLinkFactory; use Smsapi\Client\Feature\Sms\Data\SmsFactory; use Smsapi\Client\Feature\Mfa\Data\MfaFactory; @@ -91,17 +85,6 @@ public function provideShortUrlLinkFactory(): ShortUrlLinkFactory return new ShortUrlLinkFactory(); } - public function providePushShipmentFactory(): PushShipmentFactory - { - return new PushShipmentFactory( - new PushAppFactory(), - new PushShipmentPayloadFactory(), - new PushShipmentSummaryFactory(), - new PushShipmentDispatchDetailsFactory(), - new PushShipmentFallbackFactory() - ); - } - public function provideContactFactory(): ContactFactory { return new ContactFactory($this->provideContactGroupFactory(), $this->provideConntactCustomFieldFactory()); diff --git a/src/Feature/Data/PointsFactory.php b/src/Feature/Data/PointsFactory.php index bb18c4f..9ead0d9 100644 --- a/src/Feature/Data/PointsFactory.php +++ b/src/Feature/Data/PointsFactory.php @@ -4,12 +4,14 @@ namespace Smsapi\Client\Feature\Data; +use stdClass; + /** * @internal */ class PointsFactory { - public function createFromObject(\stdClass $object): Points + public function createFromObject(stdClass $object): Points { $points = new Points(); $points->fromAccount = $object->from_account; diff --git a/src/Feature/Hlr/Bag/SendHlrBag.php b/src/Feature/Hlr/Bag/SendHlrBag.php index fa7428a..991fc60 100644 --- a/src/Feature/Hlr/Bag/SendHlrBag.php +++ b/src/Feature/Hlr/Bag/SendHlrBag.php @@ -8,6 +8,7 @@ * @api * @property string $idx */ +#[\AllowDynamicProperties] class SendHlrBag { diff --git a/src/Feature/Mfa/Bag/CreateMfaBag.php b/src/Feature/Mfa/Bag/CreateMfaBag.php index 05036be..bafdac6 100644 --- a/src/Feature/Mfa/Bag/CreateMfaBag.php +++ b/src/Feature/Mfa/Bag/CreateMfaBag.php @@ -10,6 +10,7 @@ * @property string $content * @property bool $fast */ +#[\AllowDynamicProperties] class CreateMfaBag { /** diff --git a/src/Feature/Mfa/Bag/VerificationMfaBag.php b/src/Feature/Mfa/Bag/VerificationMfaBag.php index f1c8a7c..ba371e4 100644 --- a/src/Feature/Mfa/Bag/VerificationMfaBag.php +++ b/src/Feature/Mfa/Bag/VerificationMfaBag.php @@ -7,6 +7,7 @@ /** * @api */ +#[\AllowDynamicProperties] class VerificationMfaBag { /** diff --git a/src/Feature/Mms/Bag/SendMmsBag.php b/src/Feature/Mms/Bag/SendMmsBag.php index e3ce33a..6db03e1 100644 --- a/src/Feature/Mms/Bag/SendMmsBag.php +++ b/src/Feature/Mms/Bag/SendMmsBag.php @@ -7,6 +7,7 @@ * @api * @property bool $test */ +#[\AllowDynamicProperties] class SendMmsBag { diff --git a/src/Feature/Push/Bag/SendPushBag.php b/src/Feature/Push/Bag/SendPushBag.php deleted file mode 100644 index 61e2547..0000000 --- a/src/Feature/Push/Bag/SendPushBag.php +++ /dev/null @@ -1,54 +0,0 @@ -appId = $appId; - $this->data['alert'] = $alert; - } - - public function setFallback(string $message, string $from, int $delay): self - { - $this->fallback['message'] = $message; - $this->fallback['from'] = $from; - $this->fallback['delay'] = $delay; - - return $this; - } - - public function setAndroidData(string $title, string $url): self - { - $this->data['from'] = $title; - $this->data['delay'] = $url; - - return $this; - } - - public function setIosData(string $badge, string $sound, string $category, bool $contentAvailable): self - { - $this->data['badge'] = $badge; - $this->data['sound'] = $sound; - $this->data['category'] = $category; - $this->data['contentAvailable'] = $contentAvailable; - - return $this; - } -} diff --git a/src/Feature/Push/Data/PushApp.php b/src/Feature/Push/Data/PushApp.php deleted file mode 100644 index b73149a..0000000 --- a/src/Feature/Push/Data/PushApp.php +++ /dev/null @@ -1,19 +0,0 @@ -id = $object->id; - $pushApp->name = $object->name; - - if (isset($object->icon)) { - $pushApp->icon = $object->icon; - } - - return $pushApp; - } -} diff --git a/src/Feature/Push/Data/PushShipment.php b/src/Feature/Push/Data/PushShipment.php deleted file mode 100644 index 75c3dae..0000000 --- a/src/Feature/Push/Data/PushShipment.php +++ /dev/null @@ -1,42 +0,0 @@ -channels = $object->channels; - $details->deviceIds = $object->device_ids; - $details->deviceType = $object->device_type; - - return $details; - } -} diff --git a/src/Feature/Push/Data/PushShipmentFactory.php b/src/Feature/Push/Data/PushShipmentFactory.php deleted file mode 100644 index e391a7a..0000000 --- a/src/Feature/Push/Data/PushShipmentFactory.php +++ /dev/null @@ -1,50 +0,0 @@ -appFactory = $appFactory; - $this->payloadFactory = $payloadFactory; - $this->summaryFactory = $summaryFactory; - $this->detailsFactory = $detailsFactory; - $this->fallbackFactory = $fallbackFactory; - } - - public function createFromObject(stdClass $object): PushShipment - { - $pushShipment = new PushShipment(); - $pushShipment->id = $object->id; - $pushShipment->status = $object->status; - $pushShipment->dateCreated = new DateTime($object->date_created); - $pushShipment->scheduledDate = new DateTime($object->scheduled_date); - $pushShipment->app = $this->appFactory->createFromObject($object->app); - $pushShipment->payload = $this->payloadFactory->createFromObject($object->payload); - $pushShipment->summary = $this->summaryFactory->createFromObject($object->summary); - $pushShipment->dispatchDetails = $this->detailsFactory->createFromObject($object->dispatch_details); - $pushShipment->fallback = $this->fallbackFactory->createFromObject($object->fallback); - - return $pushShipment; - } -} diff --git a/src/Feature/Push/Data/PushShipmentFallback.php b/src/Feature/Push/Data/PushShipmentFallback.php deleted file mode 100644 index 2b05a0d..0000000 --- a/src/Feature/Push/Data/PushShipmentFallback.php +++ /dev/null @@ -1,22 +0,0 @@ -message = $object->message; - $fallback->from = $object->from; - $fallback->delay = $object->delay; - $fallback->status = $object->status; - - return $fallback; - } -} diff --git a/src/Feature/Push/Data/PushShipmentPayload.php b/src/Feature/Push/Data/PushShipmentPayload.php deleted file mode 100644 index e7a4feb..0000000 --- a/src/Feature/Push/Data/PushShipmentPayload.php +++ /dev/null @@ -1,13 +0,0 @@ -alert = $object->alert; - - return $payload; - } -} diff --git a/src/Feature/Push/Data/PushShipmentSummary.php b/src/Feature/Push/Data/PushShipmentSummary.php deleted file mode 100644 index 36cc8cf..0000000 --- a/src/Feature/Push/Data/PushShipmentSummary.php +++ /dev/null @@ -1,19 +0,0 @@ -points = (float)$object->points; - $summary->recipientsCount = $object->recipients_count; - $summary->errorCode = $object->error_code; - - return $summary; - } -} diff --git a/src/Feature/Push/PushFeature.php b/src/Feature/Push/PushFeature.php deleted file mode 100644 index bad467f..0000000 --- a/src/Feature/Push/PushFeature.php +++ /dev/null @@ -1,16 +0,0 @@ -restRequestExecutor = $restRequestExecutor; - $this->pushShipmentFactory = $pushShipmentFactory; - } - - /** - * @param SendPushBag $sendPushBag - * @return PushShipment - * @throws SmsapiClientException - */ - public function createPush(SendPushBag $sendPushBag): PushShipment - { - $result = $this->restRequestExecutor->create('push', (array)$sendPushBag); - - return $this->pushShipmentFactory->createFromObject($result); - } -} diff --git a/src/Feature/ShortUrl/Bag/CreateShortUrlLinkBag.php b/src/Feature/ShortUrl/Bag/CreateShortUrlLinkBag.php index 7452f19..05b5e94 100644 --- a/src/Feature/ShortUrl/Bag/CreateShortUrlLinkBag.php +++ b/src/Feature/ShortUrl/Bag/CreateShortUrlLinkBag.php @@ -14,12 +14,13 @@ * @property DateTimeInterface $expire * @property string $description */ +#[\AllowDynamicProperties] class CreateShortUrlLinkBag { public static function withUrl(string $url): self { - $bag = new self(); + $bag = new CreateShortUrlLinkBag(); $bag->url = $url; return $bag; } diff --git a/src/Feature/Sms/Bag/DeleteScheduledSmssBag.php b/src/Feature/Sms/Bag/DeleteScheduledSmssBag.php index 748a5e6..51f6a09 100644 --- a/src/Feature/Sms/Bag/DeleteScheduledSmssBag.php +++ b/src/Feature/Sms/Bag/DeleteScheduledSmssBag.php @@ -4,6 +4,10 @@ namespace Smsapi\Client\Feature\Sms\Bag; +/** + * @api + */ +#[\AllowDynamicProperties] class DeleteScheduledSmssBag { /** @var array */ diff --git a/src/Feature/Sms/Bag/ScheduleSmsBag.php b/src/Feature/Sms/Bag/ScheduleSmsBag.php index dc328e9..2ce4b52 100644 --- a/src/Feature/Sms/Bag/ScheduleSmsBag.php +++ b/src/Feature/Sms/Bag/ScheduleSmsBag.php @@ -24,7 +24,9 @@ * @property string $param2 * @property string $param3 * @property string $param4 + * @property string $timeRestriction */ +#[\AllowDynamicProperties] class ScheduleSmsBag { /** @var string */ @@ -65,6 +67,9 @@ public function setParams(array $params): self return $this; } + /** + * @todo method signature to be changed in next major release as implicitly marking parameter as nullable is deprecated since PHP 8.4 + */ public function setExternalId(string $idx, bool $checkIdx = null): self { $this->idx = [$idx]; diff --git a/src/Feature/Sms/Bag/ScheduleSmsToGroupBag.php b/src/Feature/Sms/Bag/ScheduleSmsToGroupBag.php index 0b39fa5..0981fd2 100644 --- a/src/Feature/Sms/Bag/ScheduleSmsToGroupBag.php +++ b/src/Feature/Sms/Bag/ScheduleSmsToGroupBag.php @@ -20,7 +20,9 @@ * @property bool $normalize * @property string $notifyUrl * @property bool $test + * @property string $timeRestriction */ +#[\AllowDynamicProperties] class ScheduleSmsToGroupBag { @@ -53,6 +55,9 @@ public static function withTemplateName(DateTimeInterface $scheduleAt, string $g return $bag; } + /** + * @todo method signature to be changed in next major release as implicitly marking parameter as nullable is deprecated since PHP 8.4 + */ public function setExternalId(string $idx, bool $checkIdx = null): self { $this->idx = [$idx]; diff --git a/src/Feature/Sms/Bag/ScheduleSmssBag.php b/src/Feature/Sms/Bag/ScheduleSmssBag.php index 3e5fd10..b214567 100644 --- a/src/Feature/Sms/Bag/ScheduleSmssBag.php +++ b/src/Feature/Sms/Bag/ScheduleSmssBag.php @@ -25,10 +25,12 @@ * @property array $param2 * @property array $param3 * @property array $param4 + * @property string $timeRestriction */ +#[\AllowDynamicProperties] class ScheduleSmssBag { - /** @var array */ + /** @var array|string */ public $to; /** @var DateTimeInterface */ @@ -66,6 +68,9 @@ public function setParams(array $params): self return $this; } + /** + * @todo method signature to be changed in next major release as implicitly marking parameter as nullable is deprecated since PHP 8.4 + */ public function setExternalId(array $idx, bool $checkIdx = null): self { $this->idx = $idx; diff --git a/src/Feature/Sms/Bag/SendSmsBag.php b/src/Feature/Sms/Bag/SendSmsBag.php index 181a00f..9ac48b5 100644 --- a/src/Feature/Sms/Bag/SendSmsBag.php +++ b/src/Feature/Sms/Bag/SendSmsBag.php @@ -24,7 +24,9 @@ * @property string $param2 * @property string $param3 * @property string $param4 + * @property string $timeRestriction */ +#[\AllowDynamicProperties] class SendSmsBag { /** @var string */ @@ -60,6 +62,9 @@ public function setParams(array $params): self return $this; } + /** + * @todo method signature to be changed in next major release as implicitly marking parameter as nullable is deprecated since PHP 8.4 + */ public function setExternalId(string $idx, bool $checkIdx = null): self { $this->idx = [$idx]; diff --git a/src/Feature/Sms/Bag/SendSmsToGroupBag.php b/src/Feature/Sms/Bag/SendSmsToGroupBag.php index 52adfdf..a6da846 100644 --- a/src/Feature/Sms/Bag/SendSmsToGroupBag.php +++ b/src/Feature/Sms/Bag/SendSmsToGroupBag.php @@ -19,7 +19,9 @@ * @property bool $normalize * @property string $notifyUrl * @property bool $test + * @property string $timeRestriction */ +#[\AllowDynamicProperties] class SendSmsToGroupBag { /** @var string */ @@ -46,6 +48,9 @@ public static function withTemplateName(string $group, string $templateName): se return $bag; } + /** + * @todo method signature to be changed in next major release as implicitly marking parameter as nullable is deprecated since PHP 8.4 + */ public function setExternalId(string $idx, bool $checkIdx = null): self { $this->idx = [$idx]; diff --git a/src/Feature/Sms/Bag/SendSmssBag.php b/src/Feature/Sms/Bag/SendSmssBag.php index fddbf5b..279bc53 100644 --- a/src/Feature/Sms/Bag/SendSmssBag.php +++ b/src/Feature/Sms/Bag/SendSmssBag.php @@ -25,10 +25,12 @@ * @property array $param2 * @property array $param3 * @property array $param4 + * @property string $timeRestriction */ +#[\AllowDynamicProperties] class SendSmssBag { - /** @var array */ + /** @var array|string */ public $to; /** @var string */ @@ -61,6 +63,9 @@ public function setParams(array $params): self return $this; } + /** + * @todo method signature to be changed in next major release as implicitly marking parameter as nullable is deprecated since PHP 8.4 + */ public function setExternalId(array $idx, bool $checkIdx = null): self { $this->idx = $idx; diff --git a/src/Feature/Sms/Sendernames/Bag/CreateSendernameBag.php b/src/Feature/Sms/Sendernames/Bag/CreateSendernameBag.php index 81d6f10..09d40c1 100644 --- a/src/Feature/Sms/Sendernames/Bag/CreateSendernameBag.php +++ b/src/Feature/Sms/Sendernames/Bag/CreateSendernameBag.php @@ -6,6 +6,7 @@ /** * @api */ +#[\AllowDynamicProperties] class CreateSendernameBag { public $sender; diff --git a/src/Feature/Sms/Sendernames/Bag/DeleteSendernameBag.php b/src/Feature/Sms/Sendernames/Bag/DeleteSendernameBag.php index 9f54dde..8e34293 100644 --- a/src/Feature/Sms/Sendernames/Bag/DeleteSendernameBag.php +++ b/src/Feature/Sms/Sendernames/Bag/DeleteSendernameBag.php @@ -6,6 +6,7 @@ /** * @api */ +#[\AllowDynamicProperties] class DeleteSendernameBag { public $sender; diff --git a/src/Feature/Sms/Sendernames/Bag/FindSendernameBag.php b/src/Feature/Sms/Sendernames/Bag/FindSendernameBag.php index cf4e58e..60abde0 100644 --- a/src/Feature/Sms/Sendernames/Bag/FindSendernameBag.php +++ b/src/Feature/Sms/Sendernames/Bag/FindSendernameBag.php @@ -6,6 +6,7 @@ /** * @api */ +#[\AllowDynamicProperties] class FindSendernameBag { public $sender; diff --git a/src/Feature/Sms/Sendernames/Bag/MakeSendernameDefaultBag.php b/src/Feature/Sms/Sendernames/Bag/MakeSendernameDefaultBag.php index 28539af..991e2d0 100644 --- a/src/Feature/Sms/Sendernames/Bag/MakeSendernameDefaultBag.php +++ b/src/Feature/Sms/Sendernames/Bag/MakeSendernameDefaultBag.php @@ -6,6 +6,7 @@ /** * @api */ +#[\AllowDynamicProperties] class MakeSendernameDefaultBag { public $sender; diff --git a/src/Feature/Sms/SmsFeature.php b/src/Feature/Sms/SmsFeature.php index 8ccddf7..9f3c9fe 100644 --- a/src/Feature/Sms/SmsFeature.php +++ b/src/Feature/Sms/SmsFeature.php @@ -11,7 +11,6 @@ use Smsapi\Client\Feature\Sms\Bag\SendSmssBag; use Smsapi\Client\Feature\Sms\Bag\SendSmsToGroupBag; use Smsapi\Client\Feature\Sms\Data\Sms; -use Smsapi\Client\Feature\Mfa\MfaFeature; use Smsapi\Client\Feature\Sms\Sendernames\SendernamesFeature; /** diff --git a/src/Feature/Sms/SmsHttpFeature.php b/src/Feature/Sms/SmsHttpFeature.php index 5eafd75..b2e2299 100644 --- a/src/Feature/Sms/SmsHttpFeature.php +++ b/src/Feature/Sms/SmsHttpFeature.php @@ -3,6 +3,7 @@ namespace Smsapi\Client\Feature\Sms; +use Psr\Http\Client\ClientInterface; use Smsapi\Client\Feature\Data\DataFactoryProvider; use Smsapi\Client\Feature\Sms\Bag\DeleteScheduledSmssBag; use Smsapi\Client\Feature\Sms\Bag\ScheduleSmsBag; @@ -12,8 +13,6 @@ use Smsapi\Client\Feature\Sms\Bag\SendSmssBag; use Smsapi\Client\Feature\Sms\Bag\SendSmsToGroupBag; use Smsapi\Client\Feature\Sms\Data\Sms; -use Smsapi\Client\Feature\Mfa\MfaFeature; -use Smsapi\Client\Feature\Mfa\MfaHttpFeature; use Smsapi\Client\Feature\Sms\Sendernames\SendernamesFeature; use Smsapi\Client\Feature\Sms\Sendernames\SendernamesHttpFeature; use Smsapi\Client\Infrastructure\RequestExecutor\RequestExecutorFactory; @@ -25,13 +24,16 @@ */ class SmsHttpFeature implements SmsFeature { + private $externalHttpClient; private $requestExecutorFactory; private $dataFactoryProvider; public function __construct( + ClientInterface $externalHttpClient, RequestExecutorFactory $requestExecutorFactory, DataFactoryProvider $dataFactoryProvider ) { + $this->externalHttpClient = $externalHttpClient; $this->requestExecutorFactory = $requestExecutorFactory; $this->dataFactoryProvider = $dataFactoryProvider; } @@ -39,7 +41,7 @@ public function __construct( public function sendernameFeature(): SendernamesFeature { return new SendernamesHttpFeature( - $this->requestExecutorFactory->createRestRequestExecutor(), + $this->requestExecutorFactory->createRestRequestExecutor($this->externalHttpClient), $this->dataFactoryProvider->provideSendernameFactory() ); } @@ -108,6 +110,8 @@ public function sendFlashSmsToGroup(SendSmsToGroupBag $sendSmsToGroupBag): array public function sendSmss(SendSmssBag $sendSmssBag): array { + $sendSmssBag->to = implode(',', $sendSmssBag->to); + return array_map( [$this->dataFactoryProvider->provideSmsFactory(), 'createFromObject'], $this->makeRequest($sendSmssBag)->list @@ -116,6 +120,8 @@ public function sendSmss(SendSmssBag $sendSmssBag): array public function sendFlashSmss(SendSmssBag $sendSmssBag): array { + $sendSmssBag->to = implode(',', $sendSmssBag->to); + return array_map( [$this->dataFactoryProvider->provideSmsFactory(), 'createFromObject'], $this->makeRequest($sendSmssBag)->list @@ -144,6 +150,7 @@ public function scheduleSms(ScheduleSmsBag $scheduleSmsBag): Sms public function scheduleSmss(ScheduleSmssBag $scheduleSmssBag): array { + $scheduleSmssBag->to = implode(',', $scheduleSmssBag->to); $scheduleSmssBag->dateValidate = true; return array_map( @@ -216,6 +223,8 @@ public function deleteScheduledSms(DeleteScheduledSmssBag $deleteScheduledSmsBag */ private function makeRequest($data): stdClass { - return $this->requestExecutorFactory->createLegacyRequestExecutor()->request('sms.do', (array)$data); + return $this->requestExecutorFactory + ->createLegacyRequestExecutor($this->externalHttpClient) + ->request('sms.do', (array)$data); } } diff --git a/src/Feature/Subusers/Bag/CreateSubuserBag.php b/src/Feature/Subusers/Bag/CreateSubuserBag.php index 2ea4249..a45cb3c 100644 --- a/src/Feature/Subusers/Bag/CreateSubuserBag.php +++ b/src/Feature/Subusers/Bag/CreateSubuserBag.php @@ -8,6 +8,7 @@ * @property bool $active * @property string $description */ +#[\AllowDynamicProperties] class CreateSubuserBag { /** @var string */ diff --git a/src/Feature/Subusers/Bag/DeleteSubuserBag.php b/src/Feature/Subusers/Bag/DeleteSubuserBag.php index 65edc86..b5c741c 100644 --- a/src/Feature/Subusers/Bag/DeleteSubuserBag.php +++ b/src/Feature/Subusers/Bag/DeleteSubuserBag.php @@ -6,6 +6,7 @@ /** * @api */ +#[\AllowDynamicProperties] class DeleteSubuserBag { public $id; diff --git a/src/Feature/Subusers/Bag/UpdateSubuserBag.php b/src/Feature/Subusers/Bag/UpdateSubuserBag.php index f7eea08..fff8f26 100644 --- a/src/Feature/Subusers/Bag/UpdateSubuserBag.php +++ b/src/Feature/Subusers/Bag/UpdateSubuserBag.php @@ -11,6 +11,7 @@ * @property bool $active * @property string $description */ +#[\AllowDynamicProperties] class UpdateSubuserBag { /** @var string */ diff --git a/src/Feature/Vms/Bag/SendVmsBag.php b/src/Feature/Vms/Bag/SendVmsBag.php index a194a28..ef88cef 100644 --- a/src/Feature/Vms/Bag/SendVmsBag.php +++ b/src/Feature/Vms/Bag/SendVmsBag.php @@ -13,6 +13,7 @@ * @property bool $checkIdx * @property bool $test */ +#[\AllowDynamicProperties] class SendVmsBag { diff --git a/src/Infrastructure/Client/GuzzleClient.php b/src/Infrastructure/Client/GuzzleClient.php deleted file mode 100644 index 97c9cc6..0000000 --- a/src/Infrastructure/Client/GuzzleClient.php +++ /dev/null @@ -1,48 +0,0 @@ -proxy = $proxy; - } - - public function sendRequest(RequestInterface $request): ResponseInterface - { - $guzzleClient = new Client([ - RequestOptions::HTTP_ERRORS => false, - RequestOptions::PROXY => $this->proxy, - ]); - - try { - return $guzzleClient->send($request); - } catch (GuzzleRequestException $e) { - throw RequestException::create($request, $e); - } catch (GuzzleTransferException $e) { - throw NetworkException::create($request, $e); - } catch (GuzzleException $e) { - throw ClientException::create($request, $e); - } - } -} \ No newline at end of file diff --git a/src/Infrastructure/Client/GuzzleClientFactory.php b/src/Infrastructure/Client/GuzzleClientFactory.php deleted file mode 100644 index e9980a5..0000000 --- a/src/Infrastructure/Client/GuzzleClientFactory.php +++ /dev/null @@ -1,46 +0,0 @@ -logger = new NullLogger(); - $this->apiToken = $apiToken; - $this->uri = $uri; - $this->proxy = $proxy; - } - - public function createClient(): ClientInterface - { - $client = new GuzzleClient($this->proxy); - $client = new GuzzleClientLoggerDecorator($client, $this->logger); - $client = new GuzzleClientBaseUriDecorator($client, $this->uri); - $client = new GuzzleClientAuthorizationHeaderDecorator($client, $this->apiToken); - $client = new GuzzleClientUserAgentHeaderDecorator($client); - $client = new GuzzleClientCorrelationIdHeaderDecorator($client); - - return $client; - } -} diff --git a/src/Infrastructure/Client/Exception/ClientException.php b/src/Infrastructure/HttpClient/ClientException.php similarity index 52% rename from src/Infrastructure/Client/Exception/ClientException.php rename to src/Infrastructure/HttpClient/ClientException.php index c276470..a17f164 100644 --- a/src/Infrastructure/Client/Exception/ClientException.php +++ b/src/Infrastructure/HttpClient/ClientException.php @@ -2,23 +2,24 @@ declare(strict_types=1); -namespace Smsapi\Client\Infrastructure\Client\Exception; +namespace Smsapi\Client\Infrastructure\HttpClient; +use Exception; use Psr\Http\Client\ClientExceptionInterface; use Psr\Http\Message\RequestInterface; -use Throwable; /** * @api */ -class ClientException extends \Exception implements ClientExceptionInterface +class ClientException extends Exception implements ClientExceptionInterface { private $request; - public static function create(RequestInterface $request, Throwable $previous): self + public static function withRequest(string $message, RequestInterface $request): self { - $exception = new self($previous->getMessage(), 0, $previous); + $exception = new static($message); $exception->request = $request; + return $exception; } diff --git a/src/Infrastructure/Client/Decorator/GuzzleClientAcceptJsonHeaderDecorator.php b/src/Infrastructure/HttpClient/Decorator/AcceptJsonHeaderDecorator.php similarity index 83% rename from src/Infrastructure/Client/Decorator/GuzzleClientAcceptJsonHeaderDecorator.php rename to src/Infrastructure/HttpClient/Decorator/AcceptJsonHeaderDecorator.php index b0d1582..5997a90 100644 --- a/src/Infrastructure/Client/Decorator/GuzzleClientAcceptJsonHeaderDecorator.php +++ b/src/Infrastructure/HttpClient/Decorator/AcceptJsonHeaderDecorator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Smsapi\Client\Infrastructure\Client\Decorator; +namespace Smsapi\Client\Infrastructure\HttpClient\Decorator; use Psr\Http\Client\ClientInterface; use Psr\Http\Message\RequestInterface; @@ -11,7 +11,7 @@ /** * @internal */ -class GuzzleClientAcceptJsonHeaderDecorator implements ClientInterface +class AcceptJsonHeaderDecorator implements ClientInterface { private $client; diff --git a/src/Infrastructure/Client/Decorator/GuzzleClientAuthorizationHeaderDecorator.php b/src/Infrastructure/HttpClient/Decorator/AuthorizationHeaderDecorator.php similarity index 85% rename from src/Infrastructure/Client/Decorator/GuzzleClientAuthorizationHeaderDecorator.php rename to src/Infrastructure/HttpClient/Decorator/AuthorizationHeaderDecorator.php index 116385e..78a353e 100644 --- a/src/Infrastructure/Client/Decorator/GuzzleClientAuthorizationHeaderDecorator.php +++ b/src/Infrastructure/HttpClient/Decorator/AuthorizationHeaderDecorator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Smsapi\Client\Infrastructure\Client\Decorator; +namespace Smsapi\Client\Infrastructure\HttpClient\Decorator; use Psr\Http\Client\ClientInterface; use Psr\Http\Message\RequestInterface; @@ -11,7 +11,7 @@ /** * @internal */ -class GuzzleClientAuthorizationHeaderDecorator implements ClientInterface +class AuthorizationHeaderDecorator implements ClientInterface { private $client; private $apiToken; diff --git a/src/Infrastructure/Client/Decorator/GuzzleClientBaseUriDecorator.php b/src/Infrastructure/HttpClient/Decorator/BaseUriDecorator.php similarity index 51% rename from src/Infrastructure/Client/Decorator/GuzzleClientBaseUriDecorator.php rename to src/Infrastructure/HttpClient/Decorator/BaseUriDecorator.php index decf602..79cc2fc 100644 --- a/src/Infrastructure/Client/Decorator/GuzzleClientBaseUriDecorator.php +++ b/src/Infrastructure/HttpClient/Decorator/BaseUriDecorator.php @@ -2,16 +2,17 @@ declare(strict_types=1); -namespace Smsapi\Client\Infrastructure\Client\Decorator; +namespace Smsapi\Client\Infrastructure\HttpClient\Decorator; use Psr\Http\Client\ClientInterface; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; +use Smsapi\Client\Infrastructure\HttpClient\RequestException; /** * @internal */ -class GuzzleClientBaseUriDecorator implements ClientInterface +class BaseUriDecorator implements ClientInterface { private $client; private $baseUri; @@ -33,11 +34,22 @@ private function prependBaseUri(RequestInterface $request): RequestInterface { $uri = $request->getUri(); + if (!filter_var($this->baseUri, FILTER_VALIDATE_URL)) { + throw RequestException::withRequest("Invalid Base URI", $request); + } + $baseUriParts = parse_url($this->baseUri); - $uri = $uri->withScheme($baseUriParts['scheme'] ?? ''); - $uri = $uri->withHost($baseUriParts['host'] ?? ''); - $uri = $uri->withPath($baseUriParts['path'] . $uri->getPath()); + $scheme = $baseUriParts['scheme'] ?? ''; + $host = $baseUriParts['host'] ?? ''; + $port = $baseUriParts['port'] ?? null; + $basePath = $baseUriParts['path'] ?? ''; + $basePath = rtrim($basePath, '/'); + + $uri = $uri->withPath($basePath . '/' . $uri->getPath()); + $uri = $uri->withPort($port); + $uri = $uri->withHost($host); + $uri = $uri->withScheme($scheme); return $request->withUri($uri); } diff --git a/src/Infrastructure/Client/Decorator/GuzzleClientCorrelationIdHeaderDecorator.php b/src/Infrastructure/HttpClient/Decorator/CorrelationIdHeaderDecorator.php similarity index 85% rename from src/Infrastructure/Client/Decorator/GuzzleClientCorrelationIdHeaderDecorator.php rename to src/Infrastructure/HttpClient/Decorator/CorrelationIdHeaderDecorator.php index 86ac269..f54a2e4 100644 --- a/src/Infrastructure/Client/Decorator/GuzzleClientCorrelationIdHeaderDecorator.php +++ b/src/Infrastructure/HttpClient/Decorator/CorrelationIdHeaderDecorator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Smsapi\Client\Infrastructure\Client\Decorator; +namespace Smsapi\Client\Infrastructure\HttpClient\Decorator; use Psr\Http\Client\ClientInterface; use Psr\Http\Message\RequestInterface; @@ -11,7 +11,7 @@ /** * @internal */ -class GuzzleClientCorrelationIdHeaderDecorator implements ClientInterface +class CorrelationIdHeaderDecorator implements ClientInterface { private $client; diff --git a/src/Infrastructure/Client/Decorator/GuzzleClientUserAgentHeaderDecorator.php b/src/Infrastructure/HttpClient/Decorator/HttpClientUserAgentHeaderDecorator.php similarity index 75% rename from src/Infrastructure/Client/Decorator/GuzzleClientUserAgentHeaderDecorator.php rename to src/Infrastructure/HttpClient/Decorator/HttpClientUserAgentHeaderDecorator.php index b4610cd..6b86a4c 100644 --- a/src/Infrastructure/Client/Decorator/GuzzleClientUserAgentHeaderDecorator.php +++ b/src/Infrastructure/HttpClient/Decorator/HttpClientUserAgentHeaderDecorator.php @@ -2,9 +2,8 @@ declare(strict_types=1); -namespace Smsapi\Client\Infrastructure\Client\Decorator; +namespace Smsapi\Client\Infrastructure\HttpClient\Decorator; -use GuzzleHttp\ClientInterface as GuzzleClientInterface; use Psr\Http\Client\ClientInterface; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; @@ -13,7 +12,7 @@ /** * @internal */ -class GuzzleClientUserAgentHeaderDecorator implements ClientInterface +class HttpClientUserAgentHeaderDecorator implements ClientInterface { private $client; @@ -37,9 +36,8 @@ private function addUserAgentHeader(RequestInterface $request): RequestInterface private function createUserAgent(): string { return sprintf( - 'smsapi/php-client:%s;guzzle:%s;php:%s', + 'smsapi/php-client:%s;php:%s', SmsapiClient::VERSION, - GuzzleClientInterface::VERSION, PHP_VERSION ); } diff --git a/src/Infrastructure/Client/Decorator/GuzzleClientLoggerDecorator.php b/src/Infrastructure/HttpClient/Decorator/LoggerDecorator.php similarity index 61% rename from src/Infrastructure/Client/Decorator/GuzzleClientLoggerDecorator.php rename to src/Infrastructure/HttpClient/Decorator/LoggerDecorator.php index f033c1a..decd283 100644 --- a/src/Infrastructure/Client/Decorator/GuzzleClientLoggerDecorator.php +++ b/src/Infrastructure/HttpClient/Decorator/LoggerDecorator.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Smsapi\Client\Infrastructure\Client\Decorator; +namespace Smsapi\Client\Infrastructure\HttpClient\Decorator; use Psr\Http\Client\ClientInterface; use Psr\Http\Message\RequestInterface; @@ -12,7 +12,7 @@ /** * @internal */ -class GuzzleClientLoggerDecorator implements ClientInterface +class LoggerDecorator implements ClientInterface { private $client; private $logger; @@ -26,13 +26,20 @@ public function __construct(ClientInterface $client, LoggerInterface $logger) public function sendRequest(RequestInterface $request): ResponseInterface { $this->logger->info('Request', [ + 'request' => $request, 'method' => $request->getMethod(), 'uri' => $request->getUri(), + 'headers' => $request->getHeaders(), + 'body' => $request->getBody()->getContents(), ]); $response = $this->client->sendRequest($request); - $this->logger->info('Response', ['response' => $response]); + $this->logger->info('Response', [ + 'response' => $response, + 'headers' => $response->getHeaders(), + 'body' => $response->getBody()->getContents(), + ]); return $response; } diff --git a/src/Infrastructure/HttpClient/HttpClientFactory.php b/src/Infrastructure/HttpClient/HttpClientFactory.php new file mode 100644 index 0000000..2cbf467 --- /dev/null +++ b/src/Infrastructure/HttpClient/HttpClientFactory.php @@ -0,0 +1,43 @@ +logger = new NullLogger(); + $this->apiToken = $apiToken; + $this->uri = $uri; + } + + public function createClient(ClientInterface $externalClient): ClientInterface + { + $client = new LoggerDecorator($externalClient, $this->logger); + $client = new BaseUriDecorator($client, $this->uri); + $client = new AuthorizationHeaderDecorator($client, $this->apiToken); + $client = new HttpClientUserAgentHeaderDecorator($client); + $client = new CorrelationIdHeaderDecorator($client); + + return $client; + } +} diff --git a/src/Infrastructure/Client/Exception/NetworkException.php b/src/Infrastructure/HttpClient/NetworkException.php similarity index 76% rename from src/Infrastructure/Client/Exception/NetworkException.php rename to src/Infrastructure/HttpClient/NetworkException.php index bc49aa8..8464188 100644 --- a/src/Infrastructure/Client/Exception/NetworkException.php +++ b/src/Infrastructure/HttpClient/NetworkException.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Smsapi\Client\Infrastructure\Client\Exception; +namespace Smsapi\Client\Infrastructure\HttpClient; use Psr\Http\Client\NetworkExceptionInterface; diff --git a/src/Infrastructure/Client/Exception/RequestException.php b/src/Infrastructure/HttpClient/RequestException.php similarity index 76% rename from src/Infrastructure/Client/Exception/RequestException.php rename to src/Infrastructure/HttpClient/RequestException.php index f719a12..2158e32 100644 --- a/src/Infrastructure/Client/Exception/RequestException.php +++ b/src/Infrastructure/HttpClient/RequestException.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Smsapi\Client\Infrastructure\Client\Exception; +namespace Smsapi\Client\Infrastructure\HttpClient; use Psr\Http\Client\RequestExceptionInterface; diff --git a/src/Infrastructure/RequestAssembler/GuzzleRequestAssembler.php b/src/Infrastructure/RequestAssembler/GuzzleRequestAssembler.php deleted file mode 100644 index 4dff137..0000000 --- a/src/Infrastructure/RequestAssembler/GuzzleRequestAssembler.php +++ /dev/null @@ -1,25 +0,0 @@ -getMethod(), - $request->getUri(), - $request->getHeaders(), - $request->getBody() - ); - } -} diff --git a/src/Infrastructure/RequestAssembler/RequestAssembler.php b/src/Infrastructure/RequestAssembler/RequestAssembler.php new file mode 100644 index 0000000..1b76a01 --- /dev/null +++ b/src/Infrastructure/RequestAssembler/RequestAssembler.php @@ -0,0 +1,41 @@ +requestFactory = $requestFactory; + $this->streamFactory = $streamFactory; + } + + public function assemble(Request $requestDTO): RequestInterface + { + $request = $this->requestFactory->createRequest( + $requestDTO->getMethod(), + $requestDTO->getUri() + ); + + foreach ($requestDTO->getHeaders() as $header => $value) { + $request = $request->withHeader($header, $value); + } + + $request = $request->withBody($this->streamFactory->createStream($requestDTO->getBody())); + + return $request; + } +} diff --git a/src/Infrastructure/RequestExecutor/LegacyRequestExecutor.php b/src/Infrastructure/RequestExecutor/LegacyRequestExecutor.php index c260e47..8aaec38 100644 --- a/src/Infrastructure/RequestExecutor/LegacyRequestExecutor.php +++ b/src/Infrastructure/RequestExecutor/LegacyRequestExecutor.php @@ -5,7 +5,9 @@ namespace Smsapi\Client\Infrastructure\RequestExecutor; use Psr\Http\Client\ClientInterface; -use Smsapi\Client\Infrastructure\RequestAssembler\GuzzleRequestAssembler; +use Psr\Http\Message\RequestFactoryInterface; +use Psr\Http\Message\StreamFactoryInterface; +use Smsapi\Client\Infrastructure\RequestAssembler\RequestAssembler; use Smsapi\Client\Infrastructure\RequestMapper\LegacyRequestMapper; use Smsapi\Client\Infrastructure\ResponseMapper\LegacyResponseMapper; use stdClass; @@ -18,25 +20,28 @@ class LegacyRequestExecutor private $requestMapper; private $client; private $legacyResponseMapper; - private $requestAssembler; + private $requestFactory; + private $streamFactory; public function __construct( LegacyRequestMapper $requestMapper, ClientInterface $client, LegacyResponseMapper $legacyResponseMapper, - GuzzleRequestAssembler $requestAssembler + RequestFactoryInterface $requestFactory, + StreamFactoryInterface $streamFactory ) { $this->requestMapper = $requestMapper; $this->client = $client; $this->legacyResponseMapper = $legacyResponseMapper; - $this->requestAssembler = $requestAssembler; + $this->requestFactory = $requestFactory; + $this->streamFactory = $streamFactory; } public function request(string $path, array $builtInParameters, array $userParameters = []): stdClass { $request = $this->requestMapper->map($path, $builtInParameters, $userParameters); - $assembledRequest = $this->requestAssembler->assemble($request); + $assembledRequest = (new RequestAssembler($this->requestFactory, $this->streamFactory))->assemble($request); $response = $this->client->sendRequest($assembledRequest); diff --git a/src/Infrastructure/RequestExecutor/RequestExecutorFactory.php b/src/Infrastructure/RequestExecutor/RequestExecutorFactory.php index 19a1f3e..4be0532 100644 --- a/src/Infrastructure/RequestExecutor/RequestExecutorFactory.php +++ b/src/Infrastructure/RequestExecutor/RequestExecutorFactory.php @@ -5,10 +5,11 @@ namespace Smsapi\Client\Infrastructure\RequestExecutor; use Psr\Http\Client\ClientInterface; +use Psr\Http\Message\RequestFactoryInterface; +use Psr\Http\Message\StreamFactoryInterface; use Psr\Log\LoggerAwareTrait; use Psr\Log\NullLogger; -use Smsapi\Client\Infrastructure\Client\GuzzleClientFactory; -use Smsapi\Client\Infrastructure\RequestAssembler\GuzzleRequestAssembler; +use Smsapi\Client\Infrastructure\HttpClient\HttpClientFactory; use Smsapi\Client\Infrastructure\RequestMapper\Query\Formatter\ComplexParametersQueryFormatter; use Smsapi\Client\Infrastructure\ResponseMapper\LegacyResponseMapper; use Smsapi\Client\Infrastructure\RequestMapper\RestRequestMapper; @@ -25,19 +26,24 @@ class RequestExecutorFactory private $queryFormatter; private $jsonDecode; - private $requestAssembler; - private $guzzleClientFactory; + private $httpClientFactory; + private $requestFactory; + private $streamFactory; - public function __construct(GuzzleClientFactory $guzzleClientFactory) - { + public function __construct( + HttpClientFactory $httpClientFactory, + RequestFactoryInterface $requestFactory, + StreamFactoryInterface $streamFactory + ) { $this->logger = new NullLogger(); $this->queryFormatter = new ComplexParametersQueryFormatter(); $this->jsonDecode = new JsonDecode(); - $this->requestAssembler = new GuzzleRequestAssembler(); - $this->guzzleClientFactory = $guzzleClientFactory; + $this->httpClientFactory = $httpClientFactory; + $this->requestFactory = $requestFactory; + $this->streamFactory = $streamFactory; } - public function createRestRequestExecutor(): RestRequestExecutor + public function createRestRequestExecutor(ClientInterface $externalClient): RestRequestExecutor { $restRequestMapper = new RestRequestMapper($this->queryFormatter); $restResponseMapper = new RestResponseMapper($this->jsonDecode); @@ -45,13 +51,14 @@ public function createRestRequestExecutor(): RestRequestExecutor return new RestRequestExecutor( $restRequestMapper, - $this->createGuzzleClient(), + $this->createHttpClient($externalClient), $restResponseMapper, - $this->requestAssembler + $this->requestFactory, + $this->streamFactory ); } - public function createLegacyRequestExecutor(): LegacyRequestExecutor + public function createLegacyRequestExecutor(ClientInterface $externalClient): LegacyRequestExecutor { $legacyRequestMapper = new LegacyRequestMapper($this->queryFormatter); $legacyResponseMapper = new LegacyResponseMapper($this->jsonDecode); @@ -59,15 +66,16 @@ public function createLegacyRequestExecutor(): LegacyRequestExecutor return new LegacyRequestExecutor( $legacyRequestMapper, - $this->createGuzzleClient(), + $this->createHttpClient($externalClient), $legacyResponseMapper, - $this->requestAssembler + $this->requestFactory, + $this->streamFactory ); } - private function createGuzzleClient(): ClientInterface + private function createHttpClient(ClientInterface $externalHttpClient): ClientInterface { - $this->guzzleClientFactory->setLogger($this->logger); - return $this->guzzleClientFactory->createClient(); + $this->httpClientFactory->setLogger($this->logger); + return $this->httpClientFactory->createClient($externalHttpClient); } } diff --git a/src/Infrastructure/RequestExecutor/RestRequestExecutor.php b/src/Infrastructure/RequestExecutor/RestRequestExecutor.php index 5914b92..8665951 100644 --- a/src/Infrastructure/RequestExecutor/RestRequestExecutor.php +++ b/src/Infrastructure/RequestExecutor/RestRequestExecutor.php @@ -5,8 +5,10 @@ namespace Smsapi\Client\Infrastructure\RequestExecutor; use Psr\Http\Client\ClientInterface; +use Psr\Http\Message\RequestFactoryInterface; +use Psr\Http\Message\StreamFactoryInterface; use Smsapi\Client\Infrastructure\Request; -use Smsapi\Client\Infrastructure\RequestAssembler\GuzzleRequestAssembler; +use Smsapi\Client\Infrastructure\RequestAssembler\RequestAssembler; use Smsapi\Client\Infrastructure\RequestMapper\RestRequestMapper; use Smsapi\Client\Infrastructure\ResponseMapper\RestResponseMapper; use stdClass; @@ -19,18 +21,21 @@ class RestRequestExecutor private $requestMapper; private $client; private $restResponseMapper; - private $requestAssembler; + private $requestFactory; + private $streamFactory; public function __construct( RestRequestMapper $requestMapper, ClientInterface $client, RestResponseMapper $restResponseMapper, - GuzzleRequestAssembler $guzzleRequestAssembler + RequestFactoryInterface $requestFactory, + StreamFactoryInterface $streamFactory ) { $this->requestMapper = $requestMapper; $this->client = $client; $this->restResponseMapper = $restResponseMapper; - $this->requestAssembler = $guzzleRequestAssembler; + $this->requestFactory = $requestFactory; + $this->streamFactory = $streamFactory; } public function create(string $path, array $builtInParameters, array $userParameters = []): stdClass @@ -68,7 +73,7 @@ public function info(string $path, array $builtInParameters, array $userParamete private function sendRequestAndMapResponse(Request $request): stdClass { - $assembledRequest = $this->requestAssembler->assemble($request); + $assembledRequest = (new RequestAssembler($this->requestFactory, $this->streamFactory))->assemble($request); $response = $this->client->sendRequest($assembledRequest); diff --git a/src/Infrastructure/RequestMapper/LegacyRequestMapper.php b/src/Infrastructure/RequestMapper/LegacyRequestMapper.php index c59e314..b881e30 100644 --- a/src/Infrastructure/RequestMapper/LegacyRequestMapper.php +++ b/src/Infrastructure/RequestMapper/LegacyRequestMapper.php @@ -34,9 +34,7 @@ private function createRequest( array $builtInParameters, array $userParameters ): Request { - $builtInParameters['format'] = 'json'; - - $parameters = new QueryParametersData($builtInParameters, $userParameters); + $parameters = new QueryParametersData(['format' => 'json'] + $builtInParameters, $userParameters); return new Request($method, $path, $this->queryFormatter->format($parameters)); } diff --git a/src/Infrastructure/ResponseHttpCode.php b/src/Infrastructure/ResponseHttpCode.php index 2c201f5..4ef42b5 100644 --- a/src/Infrastructure/ResponseHttpCode.php +++ b/src/Infrastructure/ResponseHttpCode.php @@ -13,5 +13,6 @@ class ResponseHttpCode const CREATED = 201; const ACCEPTED = 202; const NO_CONTENT = 204; + const REQUEST_TIMEOUT = 408; const SERVICE_UNAVAILABLE = 503; } diff --git a/src/Infrastructure/ResponseMapper/RestResponseMapper.php b/src/Infrastructure/ResponseMapper/RestResponseMapper.php index fff15e3..04106a3 100644 --- a/src/Infrastructure/ResponseMapper/RestResponseMapper.php +++ b/src/Infrastructure/ResponseMapper/RestResponseMapper.php @@ -40,6 +40,8 @@ public function map(ResponseInterface $response): stdClass return new stdClass(); } elseif ($statusCode == ResponseHttpCode::SERVICE_UNAVAILABLE) { throw ApiErrorException::withMessageAndStatusCode('Service unavailable', $statusCode); + } elseif ($statusCode == ResponseHttpCode::REQUEST_TIMEOUT) { + throw ApiErrorException::withMessageAndStatusCode('Request timed out', $statusCode); } elseif ($contents) { $object = $this->jsonDecode->decode($contents); diff --git a/src/Service/HttpDefaultFeatures.php b/src/Service/HttpDefaultFeatures.php index 61f99ef..0189fe7 100644 --- a/src/Service/HttpDefaultFeatures.php +++ b/src/Service/HttpDefaultFeatures.php @@ -10,8 +10,6 @@ use Smsapi\Client\Feature\Data\DataFactoryProvider; use Smsapi\Client\Feature\Hlr\HlrFeature; use Smsapi\Client\Feature\Hlr\HlrHttpFeature; -use Smsapi\Client\Feature\Push\PushFeature; -use Smsapi\Client\Feature\Push\PushHttpFeature; use Smsapi\Client\Feature\ShortUrl\ShortUlrHttpFeature; use Smsapi\Client\Feature\ShortUrl\ShortUrlFeature; use Smsapi\Client\Feature\Mfa\MfaFeature; @@ -37,7 +35,7 @@ trait HttpDefaultFeatures public function pingFeature(): PingFeature { - $restRequestExecutor = $this->requestExecutorFactory->createRestRequestExecutor(); + $restRequestExecutor = $this->requestExecutorFactory->createRestRequestExecutor($this->externalHttpClient); $pingFactory = $this->dataFactoryProvider->providePingFactory(); return new PingHttpFeature($restRequestExecutor, $pingFactory); @@ -45,12 +43,16 @@ public function pingFeature(): PingFeature public function smsFeature(): SmsFeature { - return new SmsHttpFeature($this->requestExecutorFactory, $this->dataFactoryProvider); + return new SmsHttpFeature( + $this->externalHttpClient, + $this->requestExecutorFactory, + $this->dataFactoryProvider + ); } public function mfaFeature(): MfaFeature { - $restRequestExecutor = $this->requestExecutorFactory->createRestRequestExecutor(); + $restRequestExecutor = $this->requestExecutorFactory->createRestRequestExecutor($this->externalHttpClient); $mfaFactory = $this->dataFactoryProvider->provideMfaFactory(); return new MfaHttpFeature($restRequestExecutor, $mfaFactory); @@ -59,7 +61,7 @@ public function mfaFeature(): MfaFeature public function hlrFeature(): HlrFeature { return new HlrHttpFeature( - $this->requestExecutorFactory->createLegacyRequestExecutor(), + $this->requestExecutorFactory->createLegacyRequestExecutor($this->externalHttpClient), $this->dataFactoryProvider->provideHlrFactory() ); } @@ -67,7 +69,7 @@ public function hlrFeature(): HlrFeature public function subusersFeature(): SubusersFeature { return new SubusersHttpFeature( - $this->requestExecutorFactory->createRestRequestExecutor(), + $this->requestExecutorFactory->createRestRequestExecutor($this->externalHttpClient), $this->dataFactoryProvider->provideSubuserFactory() ); } @@ -75,7 +77,7 @@ public function subusersFeature(): SubusersFeature public function shortUrlFeature(): ShortUrlFeature { return new ShortUlrHttpFeature( - $this->requestExecutorFactory->createRestRequestExecutor(), + $this->requestExecutorFactory->createRestRequestExecutor($this->externalHttpClient), $this->dataFactoryProvider->provideShortUrlLinkFactory() ); } @@ -83,23 +85,15 @@ public function shortUrlFeature(): ShortUrlFeature public function contactsFeature(): ContactsFeature { return new ContactsHttpFeature( - $this->requestExecutorFactory->createRestRequestExecutor(), + $this->requestExecutorFactory->createRestRequestExecutor($this->externalHttpClient), $this->dataFactoryProvider ); } - public function pushFeature(): PushFeature - { - return new PushHttpFeature( - $this->requestExecutorFactory->createRestRequestExecutor(), - $this->dataFactoryProvider->providePushShipmentFactory() - ); - } - public function blacklistFeature(): BlacklistFeature { return new BlacklistHttpFeature( - $this->requestExecutorFactory->createRestRequestExecutor(), + $this->requestExecutorFactory->createRestRequestExecutor($this->externalHttpClient), $this->dataFactoryProvider->provideBlacklistedPhoneNumberFactory() ); } diff --git a/src/Service/SmsapiComHttpService.php b/src/Service/SmsapiComHttpService.php index a32742a..39d5816 100644 --- a/src/Service/SmsapiComHttpService.php +++ b/src/Service/SmsapiComHttpService.php @@ -4,11 +4,10 @@ namespace Smsapi\Client\Service; +use Psr\Http\Client\ClientInterface; use Smsapi\Client\Feature\Data\DataFactoryProvider; use Smsapi\Client\Feature\Profile\ProfileFeature; use Smsapi\Client\Feature\Profile\ProfileHttpFeature; -use Smsapi\Client\Feature\Profile\SmsapiPlProfileFeature; -use Smsapi\Client\Feature\Profile\SmsapiPlProfileHttpFeature; use Smsapi\Client\Infrastructure\RequestExecutor\RequestExecutorFactory; /** @@ -18,13 +17,16 @@ class SmsapiComHttpService implements SmsapiComService { use HttpDefaultFeatures; + private $externalHttpClient; private $requestExecutorFactory; private $dataFactoryProvider; public function __construct( + ClientInterface $externalHttpClient, RequestExecutorFactory $requestExecutorFactory, DataFactoryProvider $dataFactoryProvider ) { + $this->externalHttpClient = $externalHttpClient; $this->requestExecutorFactory = $requestExecutorFactory; $this->dataFactoryProvider = $dataFactoryProvider; } @@ -32,7 +34,7 @@ public function __construct( public function profileFeature(): ProfileFeature { return new ProfileHttpFeature( - $this->requestExecutorFactory->createRestRequestExecutor(), + $this->requestExecutorFactory->createRestRequestExecutor($this->externalHttpClient), $this->dataFactoryProvider ); } diff --git a/src/Service/SmsapiComService.php b/src/Service/SmsapiComService.php index ccb43cc..a86abed 100644 --- a/src/Service/SmsapiComService.php +++ b/src/Service/SmsapiComService.php @@ -9,7 +9,6 @@ use Smsapi\Client\Feature\Hlr\HlrFeature; use Smsapi\Client\Feature\Ping\PingFeature; use Smsapi\Client\Feature\Profile\ProfileFeature; -use Smsapi\Client\Feature\Push\PushFeature; use Smsapi\Client\Feature\ShortUrl\ShortUrlFeature; use Smsapi\Client\Feature\Mfa\MfaFeature; use Smsapi\Client\Feature\Sms\SmsFeature; @@ -36,8 +35,5 @@ public function shortUrlFeature(): ShortUrlFeature; public function contactsFeature(): ContactsFeature; - /** @deprecated */ - public function pushFeature(): PushFeature; - public function blacklistFeature(): BlacklistFeature; } diff --git a/src/Service/SmsapiPlHttpService.php b/src/Service/SmsapiPlHttpService.php index 4ba8425..17f9772 100644 --- a/src/Service/SmsapiPlHttpService.php +++ b/src/Service/SmsapiPlHttpService.php @@ -4,6 +4,7 @@ namespace Smsapi\Client\Service; +use Psr\Http\Client\ClientInterface; use Smsapi\Client\Feature\Data\DataFactoryProvider; use Smsapi\Client\Feature\Mms\MmsFeature; use Smsapi\Client\Feature\Mms\MmsHttpFeature; @@ -20,13 +21,16 @@ class SmsapiPlHttpService implements SmsapiPlService { use HttpDefaultFeatures; + private $externalHttpClient; private $requestExecutorFactory; private $dataFactoryProvider; public function __construct( + ClientInterface $externalHttpClient, RequestExecutorFactory $requestExecutorFactory, DataFactoryProvider $dataFactoryProvider ) { + $this->externalHttpClient = $externalHttpClient; $this->requestExecutorFactory = $requestExecutorFactory; $this->dataFactoryProvider = $dataFactoryProvider; } @@ -34,7 +38,7 @@ public function __construct( public function mmsFeature(): MmsFeature { return new MmsHttpFeature( - $this->requestExecutorFactory->createLegacyRequestExecutor(), + $this->requestExecutorFactory->createLegacyRequestExecutor($this->externalHttpClient), $this->dataFactoryProvider->provideMmsFactory() ); } @@ -42,7 +46,7 @@ public function mmsFeature(): MmsFeature public function vmsFeature(): VmsFeature { return new VmsHttpFeature( - $this->requestExecutorFactory->createLegacyRequestExecutor(), + $this->requestExecutorFactory->createLegacyRequestExecutor($this->externalHttpClient), $this->dataFactoryProvider->provideVmsFactory() ); } @@ -50,7 +54,7 @@ public function vmsFeature(): VmsFeature public function profileFeature(): SmsapiPlProfileFeature { return new SmsapiPlProfileHttpFeature( - $this->requestExecutorFactory->createRestRequestExecutor(), + $this->requestExecutorFactory->createRestRequestExecutor($this->externalHttpClient), $this->dataFactoryProvider ); } diff --git a/src/Service/SmsapiPlService.php b/src/Service/SmsapiPlService.php index 7cf33f4..2f4e9b8 100644 --- a/src/Service/SmsapiPlService.php +++ b/src/Service/SmsapiPlService.php @@ -10,7 +10,6 @@ use Smsapi\Client\Feature\Mms\MmsFeature; use Smsapi\Client\Feature\Ping\PingFeature; use Smsapi\Client\Feature\Profile\SmsapiPlProfileFeature; -use Smsapi\Client\Feature\Push\PushFeature; use Smsapi\Client\Feature\ShortUrl\ShortUrlFeature; use Smsapi\Client\Feature\Mfa\MfaFeature; use Smsapi\Client\Feature\Sms\SmsFeature; @@ -38,9 +37,6 @@ public function shortUrlFeature(): ShortUrlFeature; public function contactsFeature(): ContactsFeature; - /** @deprecated */ - public function pushFeature(): PushFeature; - public function mmsFeature(): MmsFeature; public function vmsFeature(): VmsFeature; diff --git a/src/SmsapiClient.php b/src/SmsapiClient.php index b7bd2c7..1c2bc2b 100644 --- a/src/SmsapiClient.php +++ b/src/SmsapiClient.php @@ -12,9 +12,7 @@ */ interface SmsapiClient extends LoggerAwareInterface { - const VERSION = 'Unreleased'; - - public function setProxy(string $proxy): self; + const VERSION = '3.0.13'; public function smsapiPlService(string $apiToken): SmsapiPlService; diff --git a/src/SmsapiClientException.php b/src/SmsapiClientException.php index 07bd9b1..3581dea 100644 --- a/src/SmsapiClientException.php +++ b/src/SmsapiClientException.php @@ -3,9 +3,11 @@ namespace Smsapi\Client; +use Exception; + /** * @api */ -class SmsapiClientException extends \Exception +class SmsapiClientException extends Exception { } diff --git a/src/SmsapiHttpClient.php b/src/SmsapiHttpClient.php index 9723bc6..00b8967 100644 --- a/src/SmsapiHttpClient.php +++ b/src/SmsapiHttpClient.php @@ -4,10 +4,13 @@ namespace Smsapi\Client; +use Psr\Http\Client\ClientInterface; +use Psr\Http\Message\RequestFactoryInterface; +use Psr\Http\Message\StreamFactoryInterface; use Psr\Log\LoggerAwareTrait; use Psr\Log\NullLogger; use Smsapi\Client\Feature\Data\DataFactoryProvider; -use Smsapi\Client\Infrastructure\Client\GuzzleClientFactory; +use Smsapi\Client\Infrastructure\HttpClient\HttpClientFactory; use Smsapi\Client\Infrastructure\RequestExecutor\RequestExecutorFactory; use Smsapi\Client\Service\SmsapiComService; use Smsapi\Client\Service\SmsapiComHttpService; @@ -21,22 +24,24 @@ class SmsapiHttpClient implements SmsapiClient { use LoggerAwareTrait; + private $httpClient; + private $requestFactory; + private $streamFactory; + private $smsapiPlUri = 'https://api.smsapi.pl'; private $smsapiComUri = 'https://api.smsapi.com'; - private $proxy = ''; private $dataFactoryProvider; - public function __construct() - { + public function __construct( + ClientInterface $httpClient, + RequestFactoryInterface $requestFactory, + StreamFactoryInterface $streamFactory + ) { + $this->httpClient = $httpClient; + $this->requestFactory = $requestFactory; $this->dataFactoryProvider = new DataFactoryProvider(); $this->logger = new NullLogger(); - } - - public function setProxy(string $proxy): SmsapiClient - { - $this->proxy = $proxy; - - return $this; + $this->streamFactory = $streamFactory; } public function smsapiPlService(string $apiToken): SmsapiPlService @@ -47,6 +52,7 @@ public function smsapiPlService(string $apiToken): SmsapiPlService public function smsapiPlServiceWithUri(string $apiToken, string $uri): SmsapiPlService { return new SmsapiPlHttpService( + $this->httpClient, $this->createRequestExecutorFactory($apiToken, $uri), $this->dataFactoryProvider ); @@ -60,6 +66,7 @@ public function smsapiComService(string $apiToken): SmsapiComService public function smsapiComServiceWithUri(string $apiToken, string $uri): SmsapiComService { return new SmsapiComHttpService( + $this->httpClient, $this->createRequestExecutorFactory($apiToken, $uri), $this->dataFactoryProvider ); @@ -67,8 +74,8 @@ public function smsapiComServiceWithUri(string $apiToken, string $uri): SmsapiCo private function createRequestExecutorFactory(string $apiToken, string $uri): RequestExecutorFactory { - $guzzleClientFactory = new GuzzleClientFactory($apiToken, $uri, $this->proxy); - $requestExecutorFactory = new RequestExecutorFactory($guzzleClientFactory); + $httpClientFactory = new HttpClientFactory($apiToken, $uri); + $requestExecutorFactory = new RequestExecutorFactory($httpClientFactory, $this->requestFactory, $this->streamFactory); $requestExecutorFactory->setLogger($this->logger); return $requestExecutorFactory; diff --git a/tests-resources/config/config.dist.yml b/tests-resources/config/config.dist.yml index c3da0b8..7f9437f 100644 --- a/tests-resources/config/config.dist.yml +++ b/tests-resources/config/config.dist.yml @@ -1,3 +1,3 @@ Service name: SMSAPI.PL API URI: https://api.smsapi.pl -logger: false +API token: 0000000000000000000000000000000000000000 diff --git a/tests-resources/config/config.yml.example b/tests-resources/config/config.yml.example index ffbe66d..f93b66c 100644 --- a/tests-resources/config/config.yml.example +++ b/tests-resources/config/config.yml.example @@ -1,4 +1,3 @@ Service name: "SMSAPI.PL" OR "SMSAPI.COM" API token: 40-characters length string generated in SMSAPI Panel API URI: "https://api.smsapi.pl", "https://api.smsapi.com", "https://api2.smsapi.pl" or "https://api2.smsapi.com" -logger: true diff --git a/phpunit.dist.xml b/tests-resources/phpunit.dist.xml similarity index 53% rename from phpunit.dist.xml rename to tests-resources/phpunit.dist.xml index 95cb746..4d4acd5 100644 --- a/phpunit.dist.xml +++ b/tests-resources/phpunit.dist.xml @@ -1,7 +1,7 @@ - tests + ../tests - tests/Unit + ../tests/Unit - tests/Integration + ../tests/Integration - tests/Integration/Feature/Contacts - tests/Unit/Feature/Contacts + ../tests/Integration/Feature/Contacts + ../tests/Unit/Feature/Contacts - tests/Integration/Feature/Hlr + ../tests/Integration/Feature/Hlr - tests/Integration/Feature/Mms + ../tests/Integration/Feature/Mms - tests/Integration/Feature/Ping + ../tests/Integration/Feature/Ping - tests/Integration/Feature/Profile + ../tests/Integration/Feature/Profile - tests/Unit/Feature/Push + ../tests/Unit/Feature/Push - tests/Integration/Feature/Sendernames + ../tests/Integration/Feature/Sendernames - tests/Integration/Feature/ShortUrl + ../tests/Integration/Feature/ShortUrl - tests/Integration/Feature/Sms - tests/Unit/Feature/Sms + ../tests/Integration/Feature/Sms + ../tests/Unit/Feature/Sms - tests/Integration/Feature/Mfa + ../tests/Integration/Feature/Mfa - tests/Integration/Feature/Subusers + ../tests/Integration/Feature/Subusers - tests/Integration/Feature/Vms + ../tests/Integration/Feature/Vms - tests/Integration/Feature/Blacklist + ../tests/Integration/Feature/Blacklist + + + + + + diff --git a/tests/Config.php b/tests/Config.php index 05e94b3..541ac50 100644 --- a/tests/Config.php +++ b/tests/Config.php @@ -20,9 +20,4 @@ public static function get(string $key) return $config[$key] ?? null; } - - public static function getServiceName(): ServiceName - { - return ServiceName::byValue(self::get('Service name')); - } } diff --git a/tests/Fixture/GuzzleClientFactoryMother.php b/tests/Fixture/GuzzleClientFactoryMother.php deleted file mode 100644 index 9fcfceb..0000000 --- a/tests/Fixture/GuzzleClientFactoryMother.php +++ /dev/null @@ -1,15 +0,0 @@ -responseStatusCode, [], $this->responseBody); + } + + public function mockResponse(int $responseStatusCode, string $responseBody) + { + $this->responseStatusCode = $responseStatusCode; + $this->responseBody = $responseBody; + } +} \ No newline at end of file diff --git a/tests/Helper/HttpClient/HttpClientRequestSpy.php b/tests/Helper/HttpClient/HttpClientRequestSpy.php new file mode 100644 index 0000000..375e984 --- /dev/null +++ b/tests/Helper/HttpClient/HttpClientRequestSpy.php @@ -0,0 +1,27 @@ +lastSentRequest = $request; + + return new Response(); + } + + public function getLastSentRequest(): RequestInterface + { + return $this->lastSentRequest; + } +} \ No newline at end of file diff --git a/tests/Integration/Feature/Contacts/Fields/ContactsFieldsFeatureTest.php b/tests/Integration/Feature/Contacts/Fields/ContactsFieldsFeatureTest.php index 09aae76..b365387 100644 --- a/tests/Integration/Feature/Contacts/Fields/ContactsFieldsFeatureTest.php +++ b/tests/Integration/Feature/Contacts/Fields/ContactsFieldsFeatureTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Smsapi\Client\Tests\Integration\Contacts; +namespace Smsapi\Client\Tests\Integration\Feature\Contacts\Fields; use Smsapi\Client\Feature\Contacts\Bag\CreateContactBag; use Smsapi\Client\Feature\Contacts\Bag\DeleteContactBag; diff --git a/tests/Integration/Feature/Mfa/MfaFeatureTest.php b/tests/Integration/Feature/Mfa/MfaFeatureTest.php index 7fdbc3c..1a01cfb 100644 --- a/tests/Integration/Feature/Mfa/MfaFeatureTest.php +++ b/tests/Integration/Feature/Mfa/MfaFeatureTest.php @@ -32,7 +32,7 @@ public function it_should_create_mfa() /** * @test */ - public function it_should_not_create_mfa_for_an_ivalid_mobile_phone_number() + public function it_should_not_create_mfa_for_an_invalid_mobile_phone_number() { //given $mfaFeature = self::$smsapiService->mfaFeature(); @@ -97,7 +97,7 @@ public function it_should_not_verify_invalid_code() { //given $mfaFeature = self::$smsapiService->mfaFeature(); - $verificationMfaBag = new VerificationMfaBag('123 456', PhoneNumberFixture::anyValidMobile()); + $verificationMfaBag = new VerificationMfaBag('invalid', PhoneNumberFixture::anyValidMobile()); //expect $this->expectException(SmsapiClientException::class); $this->expectExceptionMessage('MFA code has invalid format'); diff --git a/tests/Integration/Feature/Ping/PingFeatureTest.php b/tests/Integration/Feature/Ping/PingFeatureTest.php index 548ac3f..11b8df1 100644 --- a/tests/Integration/Feature/Ping/PingFeatureTest.php +++ b/tests/Integration/Feature/Ping/PingFeatureTest.php @@ -3,7 +3,6 @@ namespace Smsapi\Client\Tests\Integration\Feature\Ping; -use Smsapi\Client\Feature\Ping\Data\Ping; use Smsapi\Client\Tests\SmsapiClientIntegrationTestCase; class PingFeatureTest extends SmsapiClientIntegrationTestCase diff --git a/tests/Integration/Feature/Sms/SmsFeatureTest.php b/tests/Integration/Feature/Sms/SmsFeatureTest.php index e9b056e..c5051f8 100644 --- a/tests/Integration/Feature/Sms/SmsFeatureTest.php +++ b/tests/Integration/Feature/Sms/SmsFeatureTest.php @@ -48,7 +48,7 @@ public function it_should_send_sms_with_external_id() /** * @test */ - public function it_should_receive_details_for_single_sms() + public function it_should_receive_content_details_for_single_sms() { $smsFeature = self::$smsapiService->smsFeature(); $sendSmsBag = $this->givenSmsToSend(); @@ -82,12 +82,12 @@ public function it_should_send_flash_sms() public function it_should_send_smss() { $smsFeature = self::$smsapiService->smsFeature(); - $sendSmssBag = $this->givenSmssToSend(); + $sendSmssBag = $this->givenSmssToSend(2); $sendSmssBag->test = true; $results = $smsFeature->sendSmss($sendSmssBag); - $this->assertCount(count($sendSmssBag->to), $results); + $this->assertCount(2, $results); } /** @@ -96,27 +96,28 @@ public function it_should_send_smss() public function it_should_send_flash_smss() { $smsFeature = self::$smsapiService->smsFeature(); - $sendSmssBag = $this->givenSmssToSend(); + $sendSmssBag = $this->givenSmssToSend(2); $sendSmssBag->test = true; $results = $smsFeature->sendFlashSmss($sendSmssBag); - $this->assertCount(count($sendSmssBag->to), $results); + $this->assertCount(2, $results); } /** * @test */ - public function it_should_not_receive_details_for_smss() + public function it_should_not_receive_content_details_for_smss() { $smsFeature = self::$smsapiService->smsFeature(); - $sendSmsesBag = $this->givenSmssToSend(); + $sendSmsesBag = $this->givenSmssToSend(2); $sendSmsesBag->test = true; + /** @var Sms[] $results */ $results = $smsFeature->sendSmss($sendSmsesBag); foreach ($results as $result) { - $this->assertNull($result->details); + $this->assertNull($result->content); } } @@ -141,12 +142,12 @@ public function it_should_schedule_sms() public function it_should_schedule_smss() { $smsFeature = self::$smsapiService->smsFeature(); - $scheduleSmssBag = $this->givenSmssToSchedule(); + $scheduleSmssBag = $this->givenSmssToSchedule(2); $scheduleSmssBag->test = true; $results = $smsFeature->scheduleSmss($scheduleSmssBag); - $this->assertCount(count($scheduleSmssBag->to), $results); + $this->assertCount(2, $results); } /** @@ -170,7 +171,7 @@ public function it_should_schedule_flash_sms() public function it_should_delete_scheduled_smss() { $smsFeature = self::$smsapiService->smsFeature(); - $scheduleSmssBag = $this->givenSmssToSchedule(); + $scheduleSmssBag = $this->givenSmssToSchedule(2); $results = $smsFeature->scheduleSmss($scheduleSmssBag); $smsIds = array_map(function (Sms $sms) { @@ -189,12 +190,9 @@ private function givenSmsToSend(): SendSmsBag return SendSmsBag::withMessage($someReceiver, 'some message'); } - private function givenSmssToSend(): SendSmssBag + private function givenSmssToSend(int $x): SendSmssBag { - $receivers = [ - PhoneNumberFixture::anyValidMobile(), - PhoneNumberFixture::anyValidMobile(), - ]; + $receivers = PhoneNumberFixture::xValidMobile($x); return SendSmssBag::withMessage($receivers, 'some message'); } @@ -205,13 +203,10 @@ private function givenSmsToSchedule(): ScheduleSmsBag return ScheduleSmsBag::withMessage($someDate, $someReceiver, 'some message'); } - private function givenSmssToSchedule(): ScheduleSmssBag + private function givenSmssToSchedule(int $x): ScheduleSmssBag { $someDate = new DateTime('+1 day noon'); - $receivers = [ - PhoneNumberFixture::anyValidMobile(), - PhoneNumberFixture::anyValidMobile(), - ]; + $receivers = PhoneNumberFixture::xValidMobile($x); return ScheduleSmssBag::withMessage($someDate, $receivers, 'some message'); } } diff --git a/tests/Integration/Feature/Sms/SmsToContactsGroupFeatureTest.php b/tests/Integration/Feature/Sms/SmsToContactsGroupFeatureTest.php index 9869b0e..0997dad 100644 --- a/tests/Integration/Feature/Sms/SmsToContactsGroupFeatureTest.php +++ b/tests/Integration/Feature/Sms/SmsToContactsGroupFeatureTest.php @@ -27,7 +27,10 @@ class SmsToContactsGroupFeatureTest extends SmsapiClientIntegrationTestCase /** @var ContactGroup */ private $contactGroup; - protected function setUp() + /** + * @before + */ + public function createContacts() { $this->phoneNumber = PhoneNumberFixture::anyValidMobile(); @@ -42,7 +45,10 @@ protected function setUp() self::$smsapiService->contactsFeature()->groupsFeature()->assignContactToGroup($assignContactToGroupBag); } - protected function tearDown() + /** + * @after + */ + public function removeContacts() { $contactsHelper = new ContactsHelper(self::$smsapiService->contactsFeature()); $contactsHelper->deleteContact($this->contact->id); diff --git a/tests/ServiceName.php b/tests/ServiceName.php index 69f4eef..9a2dab5 100644 --- a/tests/ServiceName.php +++ b/tests/ServiceName.php @@ -3,14 +3,7 @@ namespace Smsapi\Client\Tests; -use MabeEnum\Enum; - -/** - * @method static ServiceName SMSAPI_PL - * @method static ServiceName SMSAPI_COM - * @method static ServiceName byValue($value) - */ -class ServiceName extends Enum +class ServiceName { const SMSAPI_PL = 'SMSAPI.PL'; const SMSAPI_COM = 'SMSAPI.COM'; diff --git a/tests/SmsapiClientIntegrationTestCase.php b/tests/SmsapiClientIntegrationTestCase.php index 68c7eb9..09cc561 100644 --- a/tests/SmsapiClientIntegrationTestCase.php +++ b/tests/SmsapiClientIntegrationTestCase.php @@ -4,9 +4,9 @@ namespace Smsapi\Client\Tests; use RuntimeException; +use Smsapi\Client\Curl\SmsapiHttpClient; use Smsapi\Client\Service\SmsapiComService; use Smsapi\Client\Service\SmsapiPlService; -use Smsapi\Client\SmsapiHttpClient; class SmsapiClientIntegrationTestCase extends SmsapiClientTestCase { @@ -27,19 +27,12 @@ public static function prepare() $apiUri = Config::get('API URI'); - if (!filter_var($apiUri, FILTER_VALIDATE_URL)) { - throw new RuntimeException('Invalid API URI'); - } - $smsapiHttpClient = new SmsapiHttpClient(); - if (Config::get('logger')) { - $smsapiHttpClient->setLogger(new TestLogger()); - } - - if (Config::getServiceName()->is(ServiceName::SMSAPI_PL)) { + $serviceName = Config::get('Service name'); + if ($serviceName === ServiceName::SMSAPI_PL) { self::$smsapiService = $smsapiHttpClient->smsapiPlServiceWithUri(self::$apiToken, $apiUri); - } elseif (Config::getServiceName()->is(ServiceName::SMSAPI_COM)) { + } elseif ($serviceName === ServiceName::SMSAPI_COM) { self::$smsapiService = $smsapiHttpClient->smsapiComServiceWithUri(self::$apiToken, $apiUri); } } diff --git a/tests/SmsapiClientUnitTestCase.php b/tests/SmsapiClientUnitTestCase.php index c7bffa5..eb84c6e 100644 --- a/tests/SmsapiClientUnitTestCase.php +++ b/tests/SmsapiClientUnitTestCase.php @@ -3,15 +3,9 @@ namespace Smsapi\Client\Tests; -use GuzzleHttp\Client; -use GuzzleHttp\Handler\MockHandler; -use GuzzleHttp\HandlerStack; -use GuzzleHttp\Psr7\Response; -use Psr\Http\Client\ClientInterface; -use Psr\Http\Message\RequestInterface; -use Psr\Http\Message\ResponseInterface; use Smsapi\Client\Feature\Data\DataFactoryProvider; -use Smsapi\Client\Infrastructure\RequestAssembler\GuzzleRequestAssembler; +use Smsapi\Client\Curl\RequestFactory; +use Smsapi\Client\Curl\StreamFactory; use Smsapi\Client\Infrastructure\RequestExecutor\LegacyRequestExecutor; use Smsapi\Client\Infrastructure\RequestExecutor\RequestExecutorFactory; use Smsapi\Client\Infrastructure\RequestExecutor\RestRequestExecutor; @@ -22,65 +16,59 @@ use Smsapi\Client\Infrastructure\ResponseMapper\LegacyResponseMapper; use Smsapi\Client\Infrastructure\ResponseMapper\RestResponseMapper; use Smsapi\Client\Service\SmsapiPlHttpService; +use Smsapi\Client\Tests\Helper\HttpClient\HttpClientMock; class SmsapiClientUnitTestCase extends SmsapiClientTestCase { - /** @var MockHandler */ - private $mockHandler; + /** @var HttpClientMock */ + private $httpClient; /** * @before */ public function prepare() { - $this->mockHandler = new MockHandler(); - - $guzzleHttp = new class($this->mockHandler) implements ClientInterface { - private $handler; - - public function __construct(MockHandler $handler) - { - $this->handler = $handler; - } - - public function sendRequest(RequestInterface $request): ResponseInterface - { - $guzzleClient = new Client(['handler' => HandlerStack::create($this->handler)]); - - return $guzzleClient->send($request); - } - }; + $this->httpClient = new HttpClientMock(); + $requestFactory = new RequestFactory(); + $streamFactory = new StreamFactory(); $queryFormatter = new ComplexParametersQueryFormatter(); $jsonDecode = new JsonDecode(); + /** @var RequestExecutorFactory $requestExecutorFactory */ $requestExecutorFactory = $this->prophesize(RequestExecutorFactory::class); $requestExecutorFactory - ->createLegacyRequestExecutor() + ->createLegacyRequestExecutor($this->httpClient) ->willReturn( new LegacyRequestExecutor( new LegacyRequestMapper($queryFormatter), - $guzzleHttp, + $this->httpClient, new LegacyResponseMapper($jsonDecode), - new GuzzleRequestAssembler() + $requestFactory, + $streamFactory ) ); $requestExecutorFactory - ->createRestRequestExecutor() + ->createRestRequestExecutor($this->httpClient) ->willReturn( new RestRequestExecutor( new RestRequestMapper($queryFormatter), - $guzzleHttp, + $this->httpClient, new RestResponseMapper($jsonDecode), - new GuzzleRequestAssembler() + $requestFactory, + $streamFactory ) ); - self::$smsapiService = new SmsapiPlHttpService($requestExecutorFactory->reveal(), new DataFactoryProvider()); + self::$smsapiService = new SmsapiPlHttpService( + $this->httpClient, + $requestExecutorFactory->reveal(), + new DataFactoryProvider() + ); } protected function mockResponse(int $statusCode, string $body) { - $this->mockHandler->append(new Response($statusCode, [], $body)); + $this->httpClient->mockResponse($statusCode, $body); } } diff --git a/tests/TestLogger.php b/tests/TestLogger.php deleted file mode 100644 index 3ff6519..0000000 --- a/tests/TestLogger.php +++ /dev/null @@ -1,37 +0,0 @@ - $value) { - if ($value instanceof RequestInterface) { - $context[$item] = [ - 'headers' => $value->getHeaders(), - 'uri' => $value->getUri()->__toString(), - 'method' => $value->getMethod(), - 'contents' => $value->getBody()->__toString(), - ]; - } elseif ($value instanceof ResponseInterface) { - $context[$item] = [ - 'headers' => $value->getHeaders(), - 'status_code' => $value->getStatusCode(), - 'contents' => $value->getBody()->__toString(), - ]; - } - } - - echo sprintf("[%s] %s (%s)\n", $level, $message, print_r($context)); - } -} diff --git a/tests/Unit/Curl/HttpHeadersParserTest.php b/tests/Unit/Curl/HttpHeadersParserTest.php new file mode 100644 index 0000000..cdfdbd8 --- /dev/null +++ b/tests/Unit/Curl/HttpHeadersParserTest.php @@ -0,0 +1,85 @@ +assertArrayNotHasKey('HTTP/1.1 202 OK', $headers); + $this->assertNotContains('HTTP/1.1 202 OK', $headers); + } + + /** + * @test + */ + public function not_bypass_non_http_status_line_first_line() + { + $rawHeaders = "Header1: any\r\nHeader2: any, other\r\n"; + + $headers = HttpHeadersParser::parse($rawHeaders); + + $this->assertArrayHasKey('Header1', $headers); + } + + /** + * @test + */ + public function bypass_empty_line() + { + $rawHeaders = "HTTP/1.1 202 OK\r\nHeader1: any\r\nHeader2: any, other\r\n\r\n"; + + $headers = HttpHeadersParser::parse($rawHeaders); + + $this->assertCount(2, array_keys($headers)); + } + + /** + * @test + */ + public function add_all_headers() + { + $rawHeaders = "HTTP/1.1 202 OK\r\nHeader1: any\r\nHeader2: any, other\r\n"; + + $headers = HttpHeadersParser::parse($rawHeaders); + + $this->assertArrayHasKey('Header1', $headers); + $this->assertArrayHasKey('Header2', $headers); + } + + /** + * @test + */ + public function add_single_value_headers() + { + $rawHeaders = "HTTP/1.1 202 OK\r\nHeader1: any\r\nHeader2: any, other\r\n"; + + $headers = HttpHeadersParser::parse($rawHeaders); + + $this->assertEquals('any', $headers['Header1']); + } + + /** + * @test + */ + public function add_multi_value_headers() + { + $rawHeaders = "HTTP/1.1 202 OK\r\nHeader1: any\r\nHeader2: any, other\r\n"; + + $headers = HttpHeadersParser::parse($rawHeaders); + + $this->assertEquals('any, other', $headers['Header2']); + } +} \ No newline at end of file diff --git a/tests/Unit/Feature/Contacts/Data/ContactFactoryTest.php b/tests/Unit/Feature/Contacts/Data/ContactFactoryTest.php index bc690c5..d281731 100644 --- a/tests/Unit/Feature/Contacts/Data/ContactFactoryTest.php +++ b/tests/Unit/Feature/Contacts/Data/ContactFactoryTest.php @@ -4,19 +4,19 @@ namespace Smsapi\Client\Tests\Unit\Feature\Contacts\Data; +use DateTime; use PHPUnit\Framework\TestCase; use Smsapi\Client\Feature\Contacts\Data\ContactCustomFieldFactory; use Smsapi\Client\Feature\Contacts\Data\ContactFactory; use Smsapi\Client\Feature\Contacts\Data\ContactGroupFactory; use Smsapi\Client\Feature\Contacts\Groups\Permissions\Data\GroupPermissionFactory; +use stdClass; class ContactFactoryTest extends TestCase { - private $contactFactory; - - protected function setUp() + private function createContactsFactory() { - $this->contactFactory = new ContactFactory( + return new ContactFactory( new ContactGroupFactory(new GroupPermissionFactory()), new ContactCustomFieldFactory() ); @@ -27,7 +27,7 @@ protected function setUp() */ public function it_should_convert_mandatory_built_in_contact_fields() { - $contactData = new \stdClass(); + $contactData = new stdClass(); $contactData->id = 'any'; $contactData->date_created = '2020-05-11'; $contactData->date_updated = '2020-05-12'; @@ -36,11 +36,11 @@ public function it_should_convert_mandatory_built_in_contact_fields() $this->assertTrue(true); - $contact = $this->contactFactory->createFromObject($contactData); + $contact = $this->createContactsFactory()->createFromObject($contactData); $this->assertEquals('any', $contact->id); - $this->assertEquals(new \DateTime('2020-05-11'), $contact->dateCreated); - $this->assertEquals(new \DateTime('2020-05-12'), $contact->dateUpdated); + $this->assertEquals(new DateTime('2020-05-11'), $contact->dateCreated); + $this->assertEquals(new DateTime('2020-05-12'), $contact->dateUpdated); $this->assertEquals('M', $contact->gender); } @@ -50,26 +50,26 @@ public function it_should_convert_mandatory_built_in_contact_fields() public function it_should_convert_optional_built_in_contact_fields() { $contactData = $this->givenAnyContactData(); - $contact = $this->contactFactory->createFromObject($contactData); + $contact = $this->createContactsFactory()->createFromObject($contactData); $this->assertNull($contact->email); $this->assertNull($contact->phoneNumber); $this->assertNull($contact->country); $this->assertNull($contact->undeliveredMessages); $contactData->email = 'any@example.com'; - $contact = $this->contactFactory->createFromObject($contactData); + $contact = $this->createContactsFactory()->createFromObject($contactData); $this->assertEquals('any@example.com', $contact->email); $contactData->phone_number = '123123123'; - $contact = $this->contactFactory->createFromObject($contactData); + $contact = $this->createContactsFactory()->createFromObject($contactData); $this->assertEquals('123123123', $contact->phoneNumber); $contactData->country = 'any'; - $contact = $this->contactFactory->createFromObject($contactData); + $contact = $this->createContactsFactory()->createFromObject($contactData); $this->assertEquals('any', $contact->country); $contactData->undelivered_messages = 1; - $contact = $this->contactFactory->createFromObject($contactData); + $contact = $this->createContactsFactory()->createFromObject($contactData); $this->assertEquals(1, $contact->undeliveredMessages); } @@ -83,7 +83,7 @@ public function it_should_convert_custom_fields() $contactData->custom_field_1 = 'any1'; $contactData->custom_field_2 = 'any2'; - $contact = $this->contactFactory->createFromObject($contactData); + $contact = $this->createContactsFactory()->createFromObject($contactData); $this->assertEquals('custom_field_1', $contact->customFields[0]->name); $this->assertEquals('any1', $contact->customFields[0]->value); @@ -91,9 +91,9 @@ public function it_should_convert_custom_fields() $this->assertEquals('any2', $contact->customFields[1]->value); } - private function givenAnyContactData(): \stdClass + private function givenAnyContactData(): stdClass { - $contactData = new \stdClass(); + $contactData = new stdClass(); $contactData->id = 'any'; $contactData->date_created = '2020-05-11'; $contactData->date_updated = '2020-05-12'; diff --git a/tests/Unit/Feature/Push/PushFeatureTest.php b/tests/Unit/Feature/Push/PushFeatureTest.php deleted file mode 100644 index a40bf6e..0000000 --- a/tests/Unit/Feature/Push/PushFeatureTest.php +++ /dev/null @@ -1,75 +0,0 @@ -mockResponse(ResponseHttpCode::OK, $body); - $pushShipment = json_decode($body); - $pushFeature = self::$smsapiService->pushFeature(); - $sendPushBag = new SendPushBag('1', $pushShipment->payload->alert); - - $result = $pushFeature->createPush($sendPushBag); - - $this->assertPushShipment($pushShipment, $result); - } - - private function assertPushShipment(stdClass $expected, PushShipment $actual) - { - $pushShipment = new PushShipment(); - $pushShipment->id = $expected->id; - $pushShipment->status = $expected->status; - $pushShipment->dateCreated = new DateTime($expected->date_created); - $pushShipment->scheduledDate = new DateTime($expected->scheduled_date); - - $pushShipment->app = new PushApp(); - $pushShipment->app->id = $expected->app->id; - $pushShipment->app->name = $expected->app->name; - $pushShipment->app->icon = $expected->app->icon; - - $pushShipment->payload = new PushShipmentPayload(); - $pushShipment->payload->alert = $expected->payload->alert; - - $pushShipment->summary = new PushShipmentSummary(); - $pushShipment->summary->points = to_float($expected->summary->points); - $pushShipment->summary->recipientsCount = $expected->summary->recipients_count; - $pushShipment->summary->errorCode = $expected->summary->error_code; - - $pushShipment->dispatchDetails = new PushShipmentDispatchDetails(); - $pushShipment->dispatchDetails->channels = $expected->dispatch_details->channels; - $pushShipment->dispatchDetails->deviceIds = $expected->dispatch_details->device_ids; - $pushShipment->dispatchDetails->deviceType = $expected->dispatch_details->device_type; - - $pushShipment->fallback = new PushShipmentFallback(); - $pushShipment->fallback->message = $expected->fallback->message; - $pushShipment->fallback->from = $expected->fallback->from; - $pushShipment->fallback->delay = $expected->fallback->delay; - $pushShipment->fallback->status = $expected->fallback->status; - - $this->assertEquals($pushShipment, $actual); - } -} diff --git a/tests/Unit/Infrastructure/HttpClient/Decorator/BaseUriDecoratorTest.php b/tests/Unit/Infrastructure/HttpClient/Decorator/BaseUriDecoratorTest.php new file mode 100644 index 0000000..0e538bd --- /dev/null +++ b/tests/Unit/Infrastructure/HttpClient/Decorator/BaseUriDecoratorTest.php @@ -0,0 +1,162 @@ +sendRequestToAnyEndpoint($decorator); + + $this->assertEquals($expectedRequestUri, (string)$sentRequestSpy->getLastSentRequest()->getUri()); + $this->assertEquals($expectedRequestSchema, $sentRequestSpy->getLastSentRequest()->getUri()->getScheme()); + } + + /** + * @test + * @testWith + * ["example.com"] + * ["example.com/base/"] + * ["example.com:80"] + * ["example.com:80/base/"] + * ["any://"] + * ["any:///"] + * ["any://:80/"] + */ + public function dont_send_request_without_base_schema_or_host(string $baseUri) + { + $sentRequestSpy = new HttpClientRequestSpy(); + $decorator = new BaseUriDecorator($sentRequestSpy, $baseUri); + + $this->expectException(RequestException::class); + $this->expectExceptionMessage('Invalid Base URI'); + $this->sendRequestToAnyEndpoint($decorator); + } + + /** + * @test + * @testWith + * ["any://example.com", "any://example.com/endpoint", "example.com"] + * ["any://example.com:80", "any://example.com:80/endpoint", "example.com"] + * ["any://example", "any://example/endpoint", "example"] + * ["any://example:80", "any://example:80/endpoint", "example"] + */ + public function send_request_with_base_host(string $baseUri, string $expectedRequestUri, string $expectedRequestHost) + { + $sentRequestSpy = new HttpClientRequestSpy(); + $decorator = new BaseUriDecorator($sentRequestSpy, $baseUri); + + $this->sendRequestToAnyEndpoint($decorator); + + $this->assertEquals($expectedRequestUri, (string)$sentRequestSpy->getLastSentRequest()->getUri()); + $this->assertEquals($expectedRequestHost, $sentRequestSpy->getLastSentRequest()->getUri()->getHost()); + } + + /** + * @test + * @testWith + * ["any://example.com:80", "any://example.com:80/endpoint", "80"] + * ["any://example:80", "any://example:80/endpoint", "80"] + */ + public function send_request_with_base_port(string $baseUri, string $expectedRequestUri, string $expectedRequestPort) + { + $sentRequestSpy = new HttpClientRequestSpy(); + $decorator = new BaseUriDecorator($sentRequestSpy, $baseUri); + + $this->sendRequestToAnyEndpoint($decorator); + + $this->assertEquals($expectedRequestUri, (string)$sentRequestSpy->getLastSentRequest()->getUri()); + $this->assertEquals($expectedRequestPort, $sentRequestSpy->getLastSentRequest()->getUri()->getPort()); + } + + /** + * @test + * @testWith + * ["any://example.com", "any://example.com/endpoint"] + * ["any://example", "any://example/endpoint"] + * ["any://example.com/base", "any://example.com/base/endpoint"] + * ["any://example/base", "any://example/base/endpoint"] + */ + public function send_request_without_base_port(string $baseUri, string $expectedRequestUri) + { + $sentRequestSpy = new HttpClientRequestSpy(); + $decorator = new BaseUriDecorator($sentRequestSpy, $baseUri); + + $this->sendRequestToAnyEndpoint($decorator); + + $this->assertEquals($expectedRequestUri, (string)$sentRequestSpy->getLastSentRequest()->getUri()); + $this->assertEquals('', $sentRequestSpy->getLastSentRequest()->getUri()->getPort()); + } + + /** + * @test + * @testWith + * ["any://example.com/base", "any://example.com/base/endpoint", "/base/endpoint"] + * ["any://example.com:80/base/", "any://example.com:80/base/endpoint", "/base/endpoint"] + * ["any://example:80/base", "any://example:80/base/endpoint", "/base/endpoint"] + * ["any://example.com/base/", "any://example.com/base/endpoint", "/base/endpoint"] + * ["any://example/base/", "any://example/base/endpoint", "/base/endpoint"] + * ["any://example.com:80/base/", "any://example.com:80/base/endpoint", "/base/endpoint"] + * ["any://example:80/base", "any://example:80/base/endpoint", "/base/endpoint"] + */ + public function send_request_with_base_path(string $baseUri, string $expectedRequestUri, string $expectedRequestPath) + { + $sentRequestSpy = new HttpClientRequestSpy(); + $decorator = new BaseUriDecorator($sentRequestSpy, $baseUri); + + $this->sendRequestToAnyEndpoint($decorator); + + $this->assertEquals($expectedRequestUri, (string)$sentRequestSpy->getLastSentRequest()->getUri()); + $this->assertEquals($expectedRequestPath, $sentRequestSpy->getLastSentRequest()->getUri()->getPath()); + } + + /** + * @test + * @testWith + * ["any://example.com", "any://example.com/endpoint", "/endpoint"] + * ["any://example", "any://example/endpoint", "/endpoint"] + * ["any://example.com:80", "any://example.com:80/endpoint", "/endpoint"] + * ["any://example:80", "any://example:80/endpoint", "/endpoint"] + * ["any://example.com/", "any://example.com/endpoint", "/endpoint"] + * ["any://example/", "any://example/endpoint", "/endpoint"] + * ["any://example.com:80/", "any://example.com:80/endpoint", "/endpoint"] + * ["any://example:80/", "any://example:80/endpoint", "/endpoint"] + */ + public function send_request_without_base_path(string $baseUri, string $expectedRequestUri, string $expectedRequestPath) + { + $sentRequestSpy = new HttpClientRequestSpy(); + $decorator = new BaseUriDecorator($sentRequestSpy, $baseUri); + + $this->sendRequestToAnyEndpoint($decorator); + + $this->assertEquals($expectedRequestUri, (string)$sentRequestSpy->getLastSentRequest()->getUri()); + $this->assertEquals($expectedRequestPath, $sentRequestSpy->getLastSentRequest()->getUri()->getPath()); + } + + private function sendRequestToAnyEndpoint(BaseUriDecorator $decorator) + { + $request = new Request('ANY', 'endpoint'); + $decorator->sendRequest($request); + } +} \ No newline at end of file diff --git a/tests/Unit/Infrastructure/RequestExecutor/GuzzleClientFactoryTest.php b/tests/Unit/Infrastructure/RequestExecutor/GuzzleClientFactoryTest.php deleted file mode 100644 index 02d99c5..0000000 --- a/tests/Unit/Infrastructure/RequestExecutor/GuzzleClientFactoryTest.php +++ /dev/null @@ -1,24 +0,0 @@ -createClient(); - - $this->assertInstanceOf(ClientInterface::class, $result); - } -} diff --git a/tests/Unit/Infrastructure/RequestExecutor/RequestExecutorFactoryTest.php b/tests/Unit/Infrastructure/RequestExecutor/RequestExecutorFactoryTest.php deleted file mode 100644 index 47befd6..0000000 --- a/tests/Unit/Infrastructure/RequestExecutor/RequestExecutorFactoryTest.php +++ /dev/null @@ -1,38 +0,0 @@ -createRestRequestExecutor(); - - $this->assertInstanceOf(RestRequestExecutor::class, $result); - } - - /** - * @test - */ - public function it_should_create_legacy_request_executor() - { - $requestExecutorFactory = new RequestExecutorFactory(GuzzleClientFactoryMother::any()); - - $result = $requestExecutorFactory->createLegacyRequestExecutor(); - - $this->assertInstanceOf(LegacyRequestExecutor::class, $result); - } -} diff --git a/tests/Unit/Infrastructure/RequestMapper/LegacyRequestMapperTest.php b/tests/Unit/Infrastructure/RequestMapper/LegacyRequestMapperTest.php index 63f910f..9b5246a 100644 --- a/tests/Unit/Infrastructure/RequestMapper/LegacyRequestMapperTest.php +++ b/tests/Unit/Infrastructure/RequestMapper/LegacyRequestMapperTest.php @@ -25,10 +25,69 @@ public function init() /** * @test */ - public function it_should_create_post_request_with_parameters() + public function it_should_use_path_as_request_uri() { $path = 'anyPath'; + $request = $this->mapper->map($path, []); + + $this->assertEquals($path, $request->getUri()); + } + + /** + * @test + */ + public function it_should_send_request_as_post() + { + $request = $this->mapper->map('anyPath', []); + + $this->assertEquals(RequestHttpMethod::POST, $request->getMethod()); + } + + /** + * @test + */ + public function it_should_always_set_format_json_parameter() + { + $builtInParameters = []; + $userParameters = []; + + $request = $this->mapper->map('anyPath', $builtInParameters, $userParameters); + + $this->assertEquals('format=json', $request->getBody()); + } + + /** + * @test + */ + public function it_should_prepend_format_parameter_to_built_in_parameters_when_none() + { + $builtInParameters = []; + $userParameters = ['any2' => 'any']; + + $request = $this->mapper->map('anyPath', $builtInParameters, $userParameters); + + $this->assertEquals('format=json&any2=any', $request->getBody()); + } + + /** + * @test + */ + public function it_should_prepend_format_parameter_to_built_in_parameters_when_set() + { + $builtInParameters = ['any1' => 'any']; + $userParameters = []; + + $request = $this->mapper->map('anyPath', $builtInParameters, $userParameters); + + $this->assertEquals('format=json&any1=any', $request->getBody()); + } + + /** + * @test + */ + public function it_should_merge_both_built_in_and_user_parameters() + { $builtInParameters = [ 'any1' => 'any', ]; @@ -36,11 +95,8 @@ public function it_should_create_post_request_with_parameters() 'any2' => 'any', ]; - $request = $this->mapper->map($path, $builtInParameters, $userParameters); - - $this->assertEquals($path, $request->getUri()); - $this->assertEquals(RequestHttpMethod::POST, $request->getMethod()); + $request = $this->mapper->map('anyPath', $builtInParameters, $userParameters); - $this->assertEquals('any1=any&format=json&any2=any', $request->getBody()); + $this->assertEquals('format=json&any1=any&any2=any', $request->getBody()); } } diff --git a/tests/Unit/Infrastructure/RequestMapper/Query/Formatter/BuiltInParametersQueryFormatterTest.php b/tests/Unit/Infrastructure/RequestMapper/Query/Formatter/BuiltInParametersQueryFormatterTest.php index 95c0d43..9acd9d0 100644 --- a/tests/Unit/Infrastructure/RequestMapper/Query/Formatter/BuiltInParametersQueryFormatterTest.php +++ b/tests/Unit/Infrastructure/RequestMapper/Query/Formatter/BuiltInParametersQueryFormatterTest.php @@ -4,6 +4,7 @@ namespace Smsapi\Client\Tests\Unit\Infrastructure\RequestMapper\Query\Formatter; +use DateTime; use PHPUnit\Framework\TestCase; use Smsapi\Client\Infrastructure\RequestMapper\Query\Formatter\BuiltInParametersQueryFormatter; use Smsapi\Client\Infrastructure\RequestMapper\Query\QueryParametersData; @@ -72,7 +73,7 @@ public function it_should_change_camel_case_parameter_name_to_underscore() */ public function it_should_format_datetime_values() { - $date = new \DateTime(); + $date = new DateTime(); $dateEncoded = rawurlencode($date->format('c')); $builtInParameters = [ diff --git a/tests/Unit/Infrastructure/RequestMapper/Query/Formatter/ComplexParametersQueryFormatterTest.php b/tests/Unit/Infrastructure/RequestMapper/Query/Formatter/ComplexParametersQueryFormatterTest.php index 27d7dea..44973ce 100644 --- a/tests/Unit/Infrastructure/RequestMapper/Query/Formatter/ComplexParametersQueryFormatterTest.php +++ b/tests/Unit/Infrastructure/RequestMapper/Query/Formatter/ComplexParametersQueryFormatterTest.php @@ -4,6 +4,7 @@ namespace Smsapi\Client\Tests\Unit\Infrastructure\RequestMapper\Query\Formatter; +use DateTime; use PHPUnit\Framework\TestCase; use Smsapi\Client\Infrastructure\RequestMapper\Query\Formatter\ComplexParametersQueryFormatter; use Smsapi\Client\Infrastructure\RequestMapper\Query\QueryParametersData; @@ -153,7 +154,7 @@ public function it_should_not_change_camel_case_parameter_name_to_underscore() */ public function it_should_format_datetime_values() { - $date = new \DateTime(); + $date = new DateTime(); $dateEncoded = rawurlencode($date->format('c')); $builtInParameters = [ diff --git a/tests/Unit/Infrastructure/RequestMapper/Query/Formatter/UserParametersQueryFormatterTest.php b/tests/Unit/Infrastructure/RequestMapper/Query/Formatter/UserParametersQueryFormatterTest.php index f54bc88..91760f9 100644 --- a/tests/Unit/Infrastructure/RequestMapper/Query/Formatter/UserParametersQueryFormatterTest.php +++ b/tests/Unit/Infrastructure/RequestMapper/Query/Formatter/UserParametersQueryFormatterTest.php @@ -4,6 +4,7 @@ namespace Smsapi\Client\Tests\Unit\Infrastructure\RequestMapper\Query\Formatter; +use DateTime; use PHPUnit\Framework\TestCase; use Smsapi\Client\Infrastructure\RequestMapper\Query\Formatter\UserParametersQueryFormatter; use Smsapi\Client\Infrastructure\RequestMapper\Query\QueryParametersData; @@ -73,7 +74,7 @@ public function it_should_not_change_camel_case_parameter_name_to_underscore() */ public function it_should_format_datetime_values() { - $date = new \DateTime(); + $date = new DateTime(); $dateEncoded = rawurlencode($date->format('c')); $userParameters = [ diff --git a/tests/Unit/Infrastructure/ResponseMapper/LegacyResponseMapperTest.php b/tests/Unit/Infrastructure/ResponseMapper/LegacyResponseMapperTest.php index 2eecaed..809e1ab 100644 --- a/tests/Unit/Infrastructure/ResponseMapper/LegacyResponseMapperTest.php +++ b/tests/Unit/Infrastructure/ResponseMapper/LegacyResponseMapperTest.php @@ -6,6 +6,7 @@ use GuzzleHttp\Psr7\Response; use Smsapi\Client\Infrastructure\ResponseHttpCode; +use Smsapi\Client\Infrastructure\ResponseMapper\ApiErrorException; use Smsapi\Client\Infrastructure\ResponseMapper\JsonDecode; use Smsapi\Client\Infrastructure\ResponseMapper\LegacyResponseMapper; use Smsapi\Client\Tests\SmsapiClientUnitTestCase; @@ -40,24 +41,24 @@ public function it_should_return_decoded_body_on_ok() /** * @test - * @expectedException \Smsapi\Client\Infrastructure\ResponseMapper\ApiErrorException */ public function it_should_return_error_on_ok_with_message_and_error() { $bodyWithMessageAndError = '{"message":"some message","error":1}'; $responseWithOkMessageAndError = $this->createResponse(ResponseHttpCode::OK, $bodyWithMessageAndError); + $this->expectException(ApiErrorException::class); $this->legacyResponseMapper->map($responseWithOkMessageAndError); } /** * @test - * @expectedException \Smsapi\Client\Infrastructure\ResponseMapper\ApiErrorException */ public function it_should_throw_exception_on_unrecognized_status() { $responseWithUnrecognizedStatus = new Response(400); + $this->expectException(ApiErrorException::class); $this->legacyResponseMapper->map($responseWithUnrecognizedStatus); } diff --git a/tests/Unit/Infrastructure/ResponseMapper/RestResponseMapperTest.php b/tests/Unit/Infrastructure/ResponseMapper/RestResponseMapperTest.php index db60d89..9419e90 100644 --- a/tests/Unit/Infrastructure/ResponseMapper/RestResponseMapperTest.php +++ b/tests/Unit/Infrastructure/ResponseMapper/RestResponseMapperTest.php @@ -6,6 +6,7 @@ use GuzzleHttp\Psr7\Response; use Smsapi\Client\Infrastructure\ResponseHttpCode; +use Smsapi\Client\Infrastructure\ResponseMapper\ApiErrorException; use Smsapi\Client\Infrastructure\ResponseMapper\JsonDecode; use Smsapi\Client\Infrastructure\ResponseMapper\RestResponseMapper; use Smsapi\Client\Tests\SmsapiClientUnitTestCase; @@ -81,24 +82,36 @@ public function it_should_return_empty_object_on_no_content() /** * @test - * @expectedException \Smsapi\Client\Infrastructure\ResponseMapper\ApiErrorException - * @expectedExceptionMessage Service unavailable */ public function it_should_throw_exception_on_service_unavailable() { $responseWithServiceUnavailable = new Response(ResponseHttpCode::SERVICE_UNAVAILABLE); + $this->expectException(ApiErrorException::class); + $this->expectExceptionMessage("Service unavailable"); + $this->restResponseMapper->map($responseWithServiceUnavailable); + } + + /** + * @test + */ + public function it_should_throw_exception_on_request_timeout() + { + $responseWithServiceUnavailable = new Response(ResponseHttpCode::REQUEST_TIMEOUT); + + $this->expectException(ApiErrorException::class); + $this->expectExceptionMessage("Request timed out"); $this->restResponseMapper->map($responseWithServiceUnavailable); } /** * @test - * @expectedException \Smsapi\Client\Infrastructure\ResponseMapper\ApiErrorException */ public function it_should_throw_exception_on_unrecognized_status() { $responseWithUnrecognizedStatus = new Response(400); + $this->expectException(ApiErrorException::class); $this->restResponseMapper->map($responseWithUnrecognizedStatus); } diff --git a/tests/Unit/SmsapiHttpClientTest.php b/tests/Unit/SmsapiHttpClientTest.php index 6e08d17..b16d1be 100644 --- a/tests/Unit/SmsapiHttpClientTest.php +++ b/tests/Unit/SmsapiHttpClientTest.php @@ -24,7 +24,7 @@ private function grabVersionFromChangelog() { $changelog = file_get_contents(dirname(dirname(__DIR__)) . '/CHANGELOG.md'); - preg_match('/^## \[(?Unreleased|\d+.\d+.\d+)\]/m', $changelog, $matches); + preg_match('/^## \[(?Unreleased|\d+.\d+.\d+)]/m', $changelog, $matches); $this->assertArrayHasKey('version', $matches);