diff --git a/.gitattributes b/.gitattributes index 1c14d13..a9835b7 100644 --- a/.gitattributes +++ b/.gitattributes @@ -13,4 +13,3 @@ phpstan.neon.dist export-ignore phpunit.xml.dist export-ignore pint.json export-ignore rector.php export-ignore -renovate.json export-ignore diff --git a/.github/workflows/autofix.yml b/.github/workflows/autofix.yml new file mode 100644 index 0000000..bf478fb --- /dev/null +++ b/.github/workflows/autofix.yml @@ -0,0 +1,12 @@ +name: Autofix + +on: [pull_request] + +permissions: + contents: write + +jobs: + autofix: + uses: hosmelq/.github/.github/workflows/php-autofix.yml@main + with: + php-version: '8.3' diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 827d754..ed5c83a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,154 +1,96 @@ -name: Continuous integration +name: Continuous Integration on: - pull_request: push: - branches: - - main + branches: [ main ] + pull_request: + +concurrency: + cancel-in-progress: true + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} jobs: - check-static-code: - name: Check static code (PHP ${{ matrix.php-version }}) + check-unused-composer-dependencies: + name: Check unused composer dependencies runs-on: ubuntu-latest - strategy: - matrix: - php-version: [ 8.1, 8.2, 8.3 ] - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup PHP - uses: shivammathur/setup-php@v2 + - name: Check unused composer dependencies + uses: hosmelq/.github/.github/actions/composer-unused-dependencies-check@main with: - coverage: none - php-version: ${{ matrix.php-version }} - tools: cs2pr + php-version: '8.3' - - name: Get composer cache directory - id: composer-cache - run: | - echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT - - - name: Restore composer cache - uses: actions/cache@v4 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} - restore-keys: | - ${{ runner.os }}-composer- + check-composer: + name: Check composer - - name: Install composer dependencies - run: composer install --no-progress + runs-on: ubuntu-latest - - name: Run PHPStan - run: vendor/bin/phpstan analyse --error-format=checkstyle | cs2pr + steps: + - name: Check composer normalize + uses: hosmelq/.github/.github/actions/composer-normalize-check@main + with: + php-version: '8.3' - check-code-quality: - name: Check code quality (PHP ${{ matrix.php-version }}) + check-static-code: + name: Check static code runs-on: ubuntu-latest - strategy: - matrix: - php-version: [ 8.1, 8.2, 8.3 ] - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup PHP - uses: shivammathur/setup-php@v2 + - name: Check static code + uses: hosmelq/.github/.github/actions/phpstan-check@main with: - coverage: none - php-version: ${{ matrix.php-version }} + php-version: '8.3' - - name: Get composer cache directory - id: composer-cache - run: | - echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT - - - name: Restore composer cache - uses: actions/cache@v4 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} - restore-keys: | - ${{ runner.os }}-composer- + check-code-quality: + name: Check code quality - - name: Install composer dependencies - run: composer install --no-progress + runs-on: ubuntu-latest - - name: Run Rector - run: vendor/bin/rector --ansi --dry-run + steps: + - name: Check code quality + uses: hosmelq/.github/.github/actions/php-rector-check@main + with: + php-version: '8.3' check-code-style: - name: Check code style (PHP ${{ matrix.php-version }}) + name: Check code style runs-on: ubuntu-latest - strategy: - matrix: - php-version: [ 8.1, 8.2, 8.3 ] - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup PHP - uses: shivammathur/setup-php@v2 + - name: Check code style + uses: hosmelq/.github/.github/actions/php-pint-check@main with: - coverage: none - php-version: ${{ matrix.php-version }} - tools: cs2pr - - - name: Install composer dependencies - run: composer install --no-progress - - - name: Run Pint - id: pint-test - run: vendor/bin/pint --test - - - name: Run Pint with annotations - if: failure() && steps.pint-test.outcome != 'success' - run: vendor/bin/pint --format=checkstyle --test | cs2pr + php-version: '8.3' tests: - name: PHP tests (PHP ${{ matrix.php-version }}) + name: PHP ${{ matrix.php }} runs-on: ubuntu-latest strategy: + fail-fast: false matrix: - php-version: [ 8.1, 8.2, 8.3 ] + php: ['8.3', '8.4', '8.5'] steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - - name: Setup PHP - uses: shivammathur/setup-php@v2 + - name: Install composer dependencies + uses: hosmelq/.github/.github/actions/composer-install@main with: - coverage: none - php-version: ${{ matrix.php-version }} + php-version: ${{ matrix.php }} - - name: Get composer cache directory - id: composer-cache - run: | - echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT - - - name: Restore composer cache - uses: actions/cache@v4 - with: - path: ${{ steps.composer-cache.outputs.dir }} - key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} - restore-keys: | - ${{ runner.os }}-composer- + - name: Installed dependencies + run: composer show -D - - name: Install composer dependencies - run: composer install --no-progress + - name: Setup problem matchers + run: | + echo "::add-matcher::${{ runner.tool_cache }}/php.json" + echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" - name: Run tests run: composer test diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml new file mode 100644 index 0000000..f444792 --- /dev/null +++ b/.github/workflows/labeler.yml @@ -0,0 +1,7 @@ +name: Labeler + +on: [pull_request] + +jobs: + label: + uses: hosmelq/.github/.github/workflows/labeler.yml@main diff --git a/.github/workflows/update-changelog.yml b/.github/workflows/update-changelog.yml index b3498c4..5f2a974 100644 --- a/.github/workflows/update-changelog.yml +++ b/.github/workflows/update-changelog.yml @@ -2,20 +2,20 @@ name: Update Changelog on: release: - types: [ released ] + types: [released] jobs: update-changelog: name: Update Changelog - runs-on: ubuntu-latest - permissions: contents: write + runs-on: ubuntu-latest + steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 0 ref: ${{ github.event.release.target_commitish }} @@ -28,13 +28,14 @@ jobs: - name: Update Changelog uses: stefanzweifel/changelog-updater-action@v1 with: - release-date: ${{ steps.release_date.outputs.date }} - release-notes: ${{ github.event.release.body }} + compare-url-target-revision: ${{ github.event.release.target_commitish }} latest-version: ${{ github.event.release.tag_name }} parse-github-usernames: true + release-date: ${{ steps.release_date.outputs.date }} + release-notes: ${{ github.event.release.body }} - name: Commit updated CHANGELOG - uses: stefanzweifel/git-auto-commit-action@v5 + uses: stefanzweifel/git-auto-commit-action@v7 with: branch: ${{ github.event.release.target_commitish }} commit_message: Update CHANGELOG diff --git a/.gitignore b/.gitignore index 6694952..1b2f9d6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,7 @@ +.DS_Store .idea +.phpunit.cache +.vscode vendor diff --git a/CHANGELOG.md b/CHANGELOG.md index 52c5227..ade3eb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,9 +5,9 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased](https://github.com//plutolinks/loops-php/compare/v0.3.0...HEAD) +## [Unreleased](https://github.com/hosmelq/loops-php/compare/v0.3.0...HEAD) -## [v0.3.0](https://github.com//plutolinks/loops-php/compare/v0.2.0...v0.3.0) - 2025-07-28 +## [v0.3.0](https://github.com/hosmelq/loops-php/compare/v0.2.0...v0.3.0) - 2025-07-28 ### What's Changed @@ -19,17 +19,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 **Full Changelog**: https://github.com/hosmelq/loops-php/compare/v0.2.0...v0.3.0 -## [v0.2.0](https://github.com//plutolinks/loops-php/compare/v0.1.0...v0.2.0) - 2024-05-18 +## [v0.2.0](https://github.com/hosmelq/loops-php/compare/v0.1.0...v0.2.0) - 2024-05-18 ### What's Changed -* Fix: ErrorException in EventSendResponse due to Undefined array key "message" (add missing null coalesce operator) by [@HelgeSverre](https://github.com/HelgeSverre) in https://github.com/plutolinks/loops-php/pull/2 +* Fix: ErrorException in EventSendResponse due to Undefined array key "message" (add missing null coalesce operator) by [@HelgeSverre](https://github.com/HelgeSverre) in https://github.com/hosmelq/loops-php/pull/2 ### New Contributors -* [@HelgeSverre](https://github.com/HelgeSverre) made their first contribution in https://github.com/plutolinks/loops-php/pull/2 +* [@HelgeSverre](https://github.com/HelgeSverre) made their first contribution in https://github.com/hosmelq/loops-php/pull/2 -**Full Changelog**: https://github.com/plutolinks/loops-php/compare/v0.1.0...v0.2.0 +**Full Changelog**: https://github.com/hosmelq/loops-php/compare/v0.1.0...v0.2.0 ## v0.1.0 - 2024-03-11 diff --git a/README.md b/README.md index e8b3f1e..ace6efe 100644 --- a/README.md +++ b/README.md @@ -6,14 +6,14 @@ The Loops PHP SDK provides an expressive interface for interacting with [Loops]( ## Requirements -Requires PHP 8.1+ +Requires PHP 8.3+ ## Installation You may install Loops into your project using the Composer package manager: ```sh -composer require plutolinks/loops +composer require hosmelq/loops ``` ## Usage @@ -21,7 +21,7 @@ composer require plutolinks/loops You can create an instance of the SDK like so: ```php -use PlutoLinks\Loops\Loops; +use Hosmelq\Loops\Loops; $loops = Loops::client(''); ``` diff --git a/composer-dependency-analyser.php b/composer-dependency-analyser.php new file mode 100644 index 0000000..87125d2 --- /dev/null +++ b/composer-dependency-analyser.php @@ -0,0 +1,10 @@ +ignoreErrorsOnPackages([ + 'thecodingmachine/safe', + ], ['unused-dependency']); diff --git a/composer.json b/composer.json index 3883b89..de0f8af 100644 --- a/composer.json +++ b/composer.json @@ -1,8 +1,8 @@ { - "name": "plutolinks/loops", + "name": "hosmelq/loops", "license": "MIT", "keywords": [ - "plutolinks", + "hosmelq", "loops", "php", "email", @@ -16,29 +16,36 @@ } ], "require": { - "php": "^8.1", - "saloonphp/saloon": "^3.7", - "thecodingmachine/safe": "^3.0" + "php": "^8.3", + "saloonphp/saloon": "^4.0", + "thecodingmachine/safe": "^3.4" }, "require-dev": { - "ergebnis/composer-normalize": "^2.42", - "laravel/pint": "^1.14", - "pestphp/pest": "^2.34", - "phpstan/extension-installer": "^1.3", - "phpstan/phpstan": "^2.0", - "phpstan/phpstan-deprecation-rules": "^2.0", - "rector/rector": "^2.0", - "spaze/phpstan-disallowed-calls": "^4.0", - "thecodingmachine/phpstan-safe-rule": "^1.3.1" + "ergebnis/composer-normalize": "^2.50", + "laravel/pint": "^1.29", + "pestphp/pest": "^4.4.5", + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^2.1.46", + "phpstan/phpstan-deprecation-rules": "^2.0.4", + "phpstan/phpstan-strict-rules": "^2.0.10", + "rector/rector": "^2.3.9", + "rector/type-perfect": "^2.1.2", + "shipmonk/composer-dependency-analyser": "^1.8.4", + "spaze/phpstan-disallowed-calls": "^4.9.2", + "thecodingmachine/phpstan-safe-rule": "^1.4.3", + "ticketswap/phpstan-error-formatter": "^1.3", + "tomasvotruba/type-coverage": "^2.1" }, + "minimum-stability": "stable", + "prefer-stable": true, "autoload": { "psr-4": { - "PlutoLinks\\Loops\\": "src/" + "Hosmelq\\Loops\\": "src/" } }, "autoload-dev": { "psr-4": { - "PlutoLinks\\Loops\\Tests\\": "tests/" + "Hosmelq\\Loops\\Tests\\": "tests/" } }, "config": { @@ -47,12 +54,21 @@ "pestphp/pest-plugin": true, "phpstan/extension-installer": true }, - "preferred-install": "dist", "sort-packages": true }, "scripts": { - "analyse": "phpstan analyse --configuration=phpstan.neon.dist --memory-limit=4G", + "phpstan": "phpstan analyse --configuration=phpstan.neon.dist --memory-limit=4G", + "pint": "pint", "rector": "rector", - "test": "pest" - } + "test": "pest", + "test-coverage": "pest --coverage" + }, + "scripts-descriptions": { + "phpstan": "Run PHPStan static analysis.", + "pint": "Format code using Laravel Pint.", + "rector": "Run Rector automated refactoring.", + "test": "Run the test suite using Pest.", + "test-coverage": "Run the test suite with code coverage using Pest." + }, + "$schema": "https://getcomposer.org/schema.json" } diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 60aaf47..33ee608 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -6,11 +6,19 @@ includes: parameters: checkBenevolentUnionTypes: true + editorUrl: 'phpstorm://open?file=%%file%%&line=%%line%%' + errorFormat: ticketswap level: max - - ignoreErrors: - - - identifier: missingType.iterableValue - paths: - src + type_coverage: + constant: 100 + declare: 100 + param: 100 + property: 100 + return: 100 + type_perfect: + no_mixed: true + null_over_false: true + narrow_param: true + narrow_return: true diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 0c12bb9..a560db8 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -6,12 +6,12 @@ > - ./tests + tests - ./src + ./src diff --git a/pint.json b/pint.json index 371d6d7..d75c19e 100644 --- a/pint.json +++ b/pint.json @@ -1,45 +1,127 @@ { - "preset": "psr12", - "rules": { - "array_indentation": true, - "binary_operator_spaces": { - "default": "single_space" - }, - "cast_spaces": true, - "class_attributes_separation": true, - "concat_space": true, - "declare_strict_types": true, - "lambda_not_used_import": true, - "method_chaining_indentation": true, - "multiline_whitespace_before_semicolons": true, - "no_extra_blank_lines": { - "tokens": [ - "extra", - "throw", - "use" - ] - }, - "no_trailing_comma_in_singleline_array": true, - "no_unneeded_import_alias": true, - "no_unused_imports": true, - "no_whitespace_before_comma_in_array": true, - "not_operator_with_successor_space": true, - "object_operator_without_whitespace": true, - "ordered_imports": { - "imports_order": [ - "const", - "function", - "class" - ], - "sort_algorithm": "alpha" - }, - "single_import_per_statement": false, - "single_quote": true, - "trailing_comma_in_multiline": { - "elements": ["arrays"] - }, - "trim_array_spaces": true, - "unary_operator_spaces": true, - "whitespace_after_comma_in_array": true - } + "preset": "psr12", + "rules": { + "array_indentation": true, + "array_push": true, + "binary_operator_spaces": { + "default": "single_space" + }, + "blank_line_before_statement": { + "statements": [ + "break", + "case", + "continue", + "do", + "for", + "foreach", + "if", + "return", + "switch", + "throw", + "try", + "while" + ] + }, + "cast_spaces": true, + "class_attributes_separation": true, + "concat_space": true, + "date_time_immutable": true, + "declare_strict_types": true, + "fully_qualified_strict_types": { + "import_symbols": true + }, + "general_phpdoc_tag_rename": { + "replacements": { + "inheritdocs": "inheritDoc" + } + }, + "global_namespace_import": true, + "lambda_not_used_import": true, + "lowercase_keywords": true, + "mb_str_functions": true, + "method_chaining_indentation": true, + "modernize_types_casting": true, + "multiline_whitespace_before_semicolons": true, + "no_empty_comment": true, + "no_extra_blank_lines": { + "tokens": ["extra", "throw", "use"] + }, + "no_multiple_statements_per_line": true, + "no_superfluous_elseif": true, + "no_trailing_comma_in_singleline_array": true, + "no_unneeded_import_alias": true, + "no_unused_imports": true, + "no_useless_else": true, + "no_whitespace_before_comma_in_array": true, + "not_operator_with_successor_space": true, + "nullable_type_declaration": { + "syntax": "union" + }, + "object_operator_without_whitespace": true, + "ordered_class_elements": { + "order": [ + "use_trait", + "case", + "constant", + "constant_public", + "constant_protected", + "constant_private", + "property_public", + "property_protected", + "property_private", + "construct", + "destruct", + "method_abstract", + "method_public_static", + "method_public", + "method_protected_static", + "method_protected", + "method_private_static", + "method_private", + "magic" + ], + "sort_algorithm": "alpha" + }, + "ordered_imports": { + "imports_order": ["const", "function", "class"], + "sort_algorithm": "alpha" + }, + "ordered_interfaces": true, + "ordered_traits": true, + "ordered_types": true, + "phpdoc_add_missing_param_annotation": true, + "phpdoc_align": { + "align": "left", + "spacing": 1 + }, + "phpdoc_indent": true, + "phpdoc_inline_tag_normalizer": true, + "phpdoc_line_span": true, + "phpdoc_no_useless_inheritdoc": true, + "phpdoc_order": { + "order": ["param", "return", "throws"] + }, + "phpdoc_param_order": true, + "phpdoc_scalar": true, + "phpdoc_separation": true, + "phpdoc_summary": true, + "phpdoc_tag_casing": true, + "phpdoc_trim": true, + "phpdoc_trim_consecutive_blank_line_separation": true, + "phpdoc_types_order": true, + "phpdoc_var_annotation_correct_order": true, + "phpdoc_var_without_name": true, + "protected_to_private": true, + "self_accessor": true, + "self_static_accessor": true, + "single_import_per_statement": false, + "single_quote": true, + "strict_param": true, + "trailing_comma_in_multiline": { + "elements": ["arrays"] + }, + "trim_array_spaces": true, + "unary_operator_spaces": true, + "whitespace_after_comma_in_array": true + } } diff --git a/rector.php b/rector.php index d179038..87f23ae 100644 --- a/rector.php +++ b/rector.php @@ -6,16 +6,20 @@ use Rector\Php74\Rector\Closure\ClosureToArrowFunctionRector; return RectorConfig::configure() + ->withImportNames() ->withPaths([ __DIR__.'/src', __DIR__.'/tests', ]) - ->withPhpSets() + ->withPhpSets(php83: true) ->withPreparedSets( deadCode: true, codeQuality: true, + codingStyle: true, typeDeclarations: true, - earlyReturn: true + instanceOf: true, + earlyReturn: true, + rectorPreset: true ) ->withSkip([ ClosureToArrowFunctionRector::class, diff --git a/renovate.json b/renovate.json deleted file mode 100644 index 6e23a19..0000000 --- a/renovate.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "automerge": true, - "enabledManagers": ["composer", "github-actions"], - "extends": ["config:base", "schedule:weekly"], - "labels": ["dependencies"], - "lockFileMaintenance": { - "enabled": false - }, - "major": { - "automerge": false - }, - "packageRules": [ - { - "addLabels": ["composer"], - "groupName": "Composer", - "matchManagers": ["composer"] - }, - { - "addLabels": ["github-actions"], - "groupName": "GitHub Actions", - "matchManagers": ["github-actions"] - } - ], - "rangeStrategy": "update-lockfile", - "rebaseWhen": "conflicted" -} diff --git a/src/DataTransferObjects/Contact.php b/src/DataTransferObjects/Contact.php index 6ceda53..5185237 100644 --- a/src/DataTransferObjects/Contact.php +++ b/src/DataTransferObjects/Contact.php @@ -2,14 +2,14 @@ declare(strict_types=1); -namespace PlutoLinks\Loops\DataTransferObjects; +namespace Hosmelq\Loops\DataTransferObjects; class Contact { /** * @var list */ - public const DEFAULT_PROPERTIES = [ + public const array DEFAULT_PROPERTIES = [ 'email', 'firstName', 'id', @@ -23,27 +23,22 @@ class Contact public function __construct( public readonly string $id, public readonly string $email, - public readonly string|null $firstName = null, - public readonly string|null $lastName = null, - public readonly string|null $source = null, + public readonly null|string $firstName = null, + public readonly null|string $lastName = null, + public readonly null|string $source = null, public readonly bool $subscribed = true, - public readonly string|null $userGroup = null, - public readonly string|null $userId = null, - public readonly ?array $properties = null, + public readonly null|string $userGroup = null, + public readonly null|string $userId = null, + public readonly null|array $properties = null, ) { } - public function __get(string $name): mixed - { - return $this->properties[$name] ?? null; - } - /** - * @param array{email: string, firstName: string|null, id: string, lastName: string|null, source: string, subscribed: bool, userGroup: string, userId: string|null} $attributes + * @param array{email: string, firstName: null|string, id: string, lastName: null|string, source: string, subscribed: bool, userGroup: string, userId: null|string} $attributes */ - public static function from(array $attributes): Contact + public static function from(array $attributes): self { - return new Contact( + return new self( id: $attributes['id'], email: $attributes['email'], firstName: $attributes['firstName'], @@ -55,4 +50,9 @@ public static function from(array $attributes): Contact properties: array_diff_key($attributes, array_flip(static::DEFAULT_PROPERTIES)), ); } + + public function __get(string $name): mixed + { + return $this->properties[$name] ?? null; + } } diff --git a/src/DataTransferObjects/CustomField.php b/src/DataTransferObjects/CustomField.php index d926124..5a2ad91 100644 --- a/src/DataTransferObjects/CustomField.php +++ b/src/DataTransferObjects/CustomField.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace PlutoLinks\Loops\DataTransferObjects; +namespace Hosmelq\Loops\DataTransferObjects; class CustomField { @@ -19,9 +19,9 @@ public function __construct( /** * @param array{key: string, label: string, type: 'boolean'|'date'|'number'|'string'} $attributes */ - public static function from(array $attributes): CustomField + public static function from(array $attributes): self { - return new CustomField( + return new self( key: $attributes['key'], label: $attributes['label'], type: $attributes['type'] diff --git a/src/Loops.php b/src/Loops.php index b595384..407018f 100644 --- a/src/Loops.php +++ b/src/Loops.php @@ -2,11 +2,11 @@ declare(strict_types=1); -namespace PlutoLinks\Loops; +namespace Hosmelq\Loops; -use PlutoLinks\Loops\Resources\ContactResource; -use PlutoLinks\Loops\Resources\EventResource; -use PlutoLinks\Loops\Resources\TransactionalResource; +use Hosmelq\Loops\Resources\ContactResource; +use Hosmelq\Loops\Resources\EventResource; +use Hosmelq\Loops\Resources\TransactionalResource; use Saloon\Contracts\Authenticator; use Saloon\Http\Auth\TokenAuthenticator; use Saloon\Http\Connector; @@ -20,19 +20,9 @@ public function __construct(public readonly string $token) { } - protected function defaultAuth(): Authenticator - { - return new TokenAuthenticator($this->token); - } - - public function resolveBaseUrl(): string - { - return 'https://app.loops.so/api/v1'; - } - - public static function client(string $token): Loops + public static function client(string $token): self { - return new Loops($token); + return new self($token); } public function contacts(): ContactResource @@ -45,8 +35,18 @@ public function events(): EventResource return new EventResource($this); } + public function resolveBaseUrl(): string + { + return 'https://app.loops.so/api/v1'; + } + public function transactional(): TransactionalResource { return new TransactionalResource($this); } + + protected function defaultAuth(): Authenticator + { + return new TokenAuthenticator($this->token); + } } diff --git a/src/Requests/Contacts/ContactCreateRequest.php b/src/Requests/Contacts/ContactCreateRequest.php index cdfeeaa..c2fa5c3 100644 --- a/src/Requests/Contacts/ContactCreateRequest.php +++ b/src/Requests/Contacts/ContactCreateRequest.php @@ -2,9 +2,9 @@ declare(strict_types=1); -namespace PlutoLinks\Loops\Requests\Contacts; +namespace Hosmelq\Loops\Requests\Contacts; -use PlutoLinks\Loops\Responses\Contacts\ContactCreateResponse; +use Hosmelq\Loops\Responses\Contacts\ContactCreateResponse; use Saloon\Contracts\Body\HasBody; use Saloon\Enums\Method; use Saloon\Http\Request; @@ -23,7 +23,7 @@ public function __construct(protected readonly array $properties) public function createDtoFromResponse(Response $response): ContactCreateResponse { - /** @var array{id: string|null, message: string|null, success: bool} $data */ + /** @var array{id: null|string, message: null|string, success: bool} $data */ $data = $response->json(); return new ContactCreateResponse( @@ -33,13 +33,13 @@ public function createDtoFromResponse(Response $response): ContactCreateResponse ); } - protected function defaultBody(): array + public function resolveEndpoint(): string { - return $this->properties; + return 'contacts/create'; } - public function resolveEndpoint(): string + protected function defaultBody(): array { - return 'contacts/create'; + return $this->properties; } } diff --git a/src/Requests/Contacts/ContactCustomFieldsRequest.php b/src/Requests/Contacts/ContactCustomFieldsRequest.php index b1ed86d..64fe847 100644 --- a/src/Requests/Contacts/ContactCustomFieldsRequest.php +++ b/src/Requests/Contacts/ContactCustomFieldsRequest.php @@ -2,9 +2,9 @@ declare(strict_types=1); -namespace PlutoLinks\Loops\Requests\Contacts; +namespace Hosmelq\Loops\Requests\Contacts; -use PlutoLinks\Loops\DataTransferObjects\CustomField; +use Hosmelq\Loops\DataTransferObjects\CustomField; use Saloon\Enums\Method; use Saloon\Http\Request; use Saloon\Http\Response; @@ -18,7 +18,7 @@ public function createDtoFromResponse(Response $response): array /** @var array $data */ $data = $response->json(); - return array_map(fn (array $customField): CustomField => CustomField::from($customField), $data); + return array_map(CustomField::from(...), $data); } public function resolveEndpoint(): string diff --git a/src/Requests/Contacts/ContactDeleteRequest.php b/src/Requests/Contacts/ContactDeleteRequest.php index 96c25de..b311468 100644 --- a/src/Requests/Contacts/ContactDeleteRequest.php +++ b/src/Requests/Contacts/ContactDeleteRequest.php @@ -2,9 +2,9 @@ declare(strict_types=1); -namespace PlutoLinks\Loops\Requests\Contacts; +namespace Hosmelq\Loops\Requests\Contacts; -use PlutoLinks\Loops\Responses\Contacts\ContactDeleteResponse; +use Hosmelq\Loops\Responses\Contacts\ContactDeleteResponse; use Saloon\Contracts\Body\HasBody; use Saloon\Enums\Method; use Saloon\Http\Request; @@ -18,8 +18,8 @@ class ContactDeleteRequest extends Request implements HasBody protected Method $method = Method::POST; public function __construct( - protected readonly string|null $email = null, - protected readonly string|null $userId = null + protected readonly null|string $email = null, + protected readonly null|string $userId = null ) { } @@ -34,6 +34,11 @@ public function createDtoFromResponse(Response $response): ContactDeleteResponse ); } + public function resolveEndpoint(): string + { + return 'contacts/delete'; + } + protected function defaultBody(): array { return array_filter([ @@ -41,9 +46,4 @@ protected function defaultBody(): array 'userId' => $this->userId, ]); } - - public function resolveEndpoint(): string - { - return 'contacts/delete'; - } } diff --git a/src/Requests/Contacts/ContactRetrieveRequest.php b/src/Requests/Contacts/ContactRetrieveRequest.php index a4cada7..a9b1534 100644 --- a/src/Requests/Contacts/ContactRetrieveRequest.php +++ b/src/Requests/Contacts/ContactRetrieveRequest.php @@ -2,9 +2,9 @@ declare(strict_types=1); -namespace PlutoLinks\Loops\Requests\Contacts; +namespace Hosmelq\Loops\Requests\Contacts; -use PlutoLinks\Loops\DataTransferObjects\Contact; +use Hosmelq\Loops\DataTransferObjects\Contact; use Saloon\Enums\Method; use Saloon\Http\Request; use Saloon\Http\Response; @@ -17,9 +17,9 @@ public function __construct(protected readonly string $email) { } - public function createDtoFromResponse(Response $response): Contact|null + public function createDtoFromResponse(Response $response): null|Contact { - /** @var array{email: string, firstName: string|null, id: string, lastName: string|null, source: string, subscribed: bool, userGroup: string, userId: string|null}|null $data */ + /** @var null|array{email: string, firstName: null|string, id: string, lastName: null|string, source: string, subscribed: bool, userGroup: string, userId: null|string} $data */ $data = $response->json('0'); if (is_null($data)) { @@ -29,15 +29,15 @@ public function createDtoFromResponse(Response $response): Contact|null return Contact::from($data); } + public function resolveEndpoint(): string + { + return 'contacts/find'; + } + protected function defaultQuery(): array { return [ 'email' => $this->email, ]; } - - public function resolveEndpoint(): string - { - return 'contacts/find'; - } } diff --git a/src/Requests/Contacts/ContactUpdateRequest.php b/src/Requests/Contacts/ContactUpdateRequest.php index 178a310..7c42ef8 100644 --- a/src/Requests/Contacts/ContactUpdateRequest.php +++ b/src/Requests/Contacts/ContactUpdateRequest.php @@ -2,9 +2,9 @@ declare(strict_types=1); -namespace PlutoLinks\Loops\Requests\Contacts; +namespace Hosmelq\Loops\Requests\Contacts; -use PlutoLinks\Loops\Responses\Contacts\ContactUpdateResponse; +use Hosmelq\Loops\Responses\Contacts\ContactUpdateResponse; use Saloon\Contracts\Body\HasBody; use Saloon\Enums\Method; use Saloon\Http\Request; @@ -25,7 +25,7 @@ public function __construct( public function createDtoFromResponse(Response $response): ContactUpdateResponse { - /** @var array{id: string|null, message: string|null, success: bool} $data */ + /** @var array{id: null|string, message: null|string, success: bool} $data */ $data = $response->json(); return new ContactUpdateResponse( @@ -35,6 +35,11 @@ public function createDtoFromResponse(Response $response): ContactUpdateResponse ); } + public function resolveEndpoint(): string + { + return 'contacts/update'; + } + protected function defaultBody(): array { return [ @@ -42,9 +47,4 @@ protected function defaultBody(): array 'email' => $this->email, ]; } - - public function resolveEndpoint(): string - { - return 'contacts/update'; - } } diff --git a/src/Requests/Events/EventSendRequest.php b/src/Requests/Events/EventSendRequest.php index a2ad19b..2c9034e 100644 --- a/src/Requests/Events/EventSendRequest.php +++ b/src/Requests/Events/EventSendRequest.php @@ -2,9 +2,9 @@ declare(strict_types=1); -namespace PlutoLinks\Loops\Requests\Events; +namespace Hosmelq\Loops\Requests\Events; -use PlutoLinks\Loops\Responses\Events\EventSendResponse; +use Hosmelq\Loops\Responses\Events\EventSendResponse; use Saloon\Contracts\Body\HasBody; use Saloon\Enums\Method; use Saloon\Http\Request; @@ -19,15 +19,15 @@ class EventSendRequest extends Request implements HasBody public function __construct( public readonly string $eventName, - public readonly string|null $email = null, - public readonly string|null $userId = null, + public readonly null|string $email = null, + public readonly null|string $userId = null, public readonly array $properties = [], ) { } public function createDtoFromResponse(Response $response): EventSendResponse { - /** @var array{message: string|null, success: bool} $data */ + /** @var array{message: null|string, success: bool} $data */ $data = $response->json(); return new EventSendResponse( @@ -36,6 +36,11 @@ public function createDtoFromResponse(Response $response): EventSendResponse ); } + public function resolveEndpoint(): string + { + return 'events/send'; + } + protected function defaultBody(): array { return [ @@ -47,9 +52,4 @@ protected function defaultBody(): array 'eventName' => $this->eventName, ]; } - - public function resolveEndpoint(): string - { - return 'events/send'; - } } diff --git a/src/Requests/Transactional/TransactionalSendRequest.php b/src/Requests/Transactional/TransactionalSendRequest.php index 32283cb..8d26915 100644 --- a/src/Requests/Transactional/TransactionalSendRequest.php +++ b/src/Requests/Transactional/TransactionalSendRequest.php @@ -2,9 +2,9 @@ declare(strict_types=1); -namespace PlutoLinks\Loops\Requests\Transactional; +namespace Hosmelq\Loops\Requests\Transactional; -use PlutoLinks\Loops\Responses\Transactional\TransactionalSendResponse; +use Hosmelq\Loops\Responses\Transactional\TransactionalSendResponse; use Saloon\Contracts\Body\HasBody; use Saloon\Enums\Method; use Saloon\Http\Request; @@ -27,7 +27,7 @@ public function __construct( public function createDtoFromResponse(Response $response): TransactionalSendResponse { - /** @var array{error: array{path: string, message: string}|null, message: string|null, path: string|null, success: bool, transactionalId: string|null} $data */ + /** @var array{error: null|array{path: string, message: string}, message: null|string, path: null|string, success: bool, transactionalId: null|string} $data */ $data = $response->json(); return new TransactionalSendResponse( @@ -39,6 +39,11 @@ public function createDtoFromResponse(Response $response): TransactionalSendResp ); } + public function resolveEndpoint(): string + { + return 'transactional'; + } + protected function defaultBody(): array { return [ @@ -48,9 +53,4 @@ protected function defaultBody(): array 'transactionalId' => $this->transactionalId, ]; } - - public function resolveEndpoint(): string - { - return 'transactional'; - } } diff --git a/src/Resources/ContactResource.php b/src/Resources/ContactResource.php index 7e92107..da1c30f 100644 --- a/src/Resources/ContactResource.php +++ b/src/Resources/ContactResource.php @@ -2,23 +2,23 @@ declare(strict_types=1); -namespace PlutoLinks\Loops\Resources; +namespace Hosmelq\Loops\Resources; -use PlutoLinks\Loops\DataTransferObjects\Contact; -use PlutoLinks\Loops\Requests\Contacts\ContactCreateRequest; -use PlutoLinks\Loops\Requests\Contacts\ContactCustomFieldsRequest; -use PlutoLinks\Loops\Requests\Contacts\ContactDeleteRequest; -use PlutoLinks\Loops\Requests\Contacts\ContactRetrieveRequest; -use PlutoLinks\Loops\Requests\Contacts\ContactUpdateRequest; -use PlutoLinks\Loops\Responses\Contacts\ContactCreateResponse; -use PlutoLinks\Loops\Responses\Contacts\ContactDeleteResponse; -use PlutoLinks\Loops\Responses\Contacts\ContactUpdateResponse; +use Hosmelq\Loops\DataTransferObjects\Contact; +use Hosmelq\Loops\Requests\Contacts\ContactCreateRequest; +use Hosmelq\Loops\Requests\Contacts\ContactCustomFieldsRequest; +use Hosmelq\Loops\Requests\Contacts\ContactDeleteRequest; +use Hosmelq\Loops\Requests\Contacts\ContactRetrieveRequest; +use Hosmelq\Loops\Requests\Contacts\ContactUpdateRequest; +use Hosmelq\Loops\Responses\Contacts\ContactCreateResponse; +use Hosmelq\Loops\Responses\Contacts\ContactDeleteResponse; +use Hosmelq\Loops\Responses\Contacts\ContactUpdateResponse; use Saloon\Http\BaseResource; class ContactResource extends BaseResource { /** - * @param array{email: string, firstName: string|null, lastName: string|null, source: string, subscribed: bool, userGroup: string|null, userId: string|null} $properties + * @param array{email: string, firstName: null|string, lastName: null|string, source: string, subscribed: bool, userGroup: null|string, userId: null|string} $properties */ public function create(array $properties): ContactCreateResponse { @@ -36,7 +36,7 @@ public function customFields(): array return $response; } - public function delete(string|null $email = null, string|null $userId = null): ContactDeleteResponse + public function delete(null|string $email = null, null|string $userId = null): ContactDeleteResponse { /** @var ContactDeleteResponse $response */ $response = $this->connector->send( diff --git a/src/Resources/EventResource.php b/src/Resources/EventResource.php index 16ddc45..013d409 100644 --- a/src/Resources/EventResource.php +++ b/src/Resources/EventResource.php @@ -2,18 +2,18 @@ declare(strict_types=1); -namespace PlutoLinks\Loops\Resources; +namespace Hosmelq\Loops\Resources; -use PlutoLinks\Loops\Requests\Events\EventSendRequest; -use PlutoLinks\Loops\Responses\Events\EventSendResponse; +use Hosmelq\Loops\Requests\Events\EventSendRequest; +use Hosmelq\Loops\Responses\Events\EventSendResponse; use Saloon\Http\BaseResource; class EventResource extends BaseResource { public function send( string $eventName, - string|null $email = null, - string|null $userId = null, + null|string $email = null, + null|string $userId = null, array $properties = [] ): EventSendResponse { /** @var EventSendResponse $response */ diff --git a/src/Resources/TransactionalResource.php b/src/Resources/TransactionalResource.php index 17e9bb0..c8c5b32 100644 --- a/src/Resources/TransactionalResource.php +++ b/src/Resources/TransactionalResource.php @@ -2,10 +2,10 @@ declare(strict_types=1); -namespace PlutoLinks\Loops\Resources; +namespace Hosmelq\Loops\Resources; -use PlutoLinks\Loops\Requests\Transactional\TransactionalSendRequest; -use PlutoLinks\Loops\Responses\Transactional\TransactionalSendResponse; +use Hosmelq\Loops\Requests\Transactional\TransactionalSendRequest; +use Hosmelq\Loops\Responses\Transactional\TransactionalSendResponse; use Saloon\Http\BaseResource; class TransactionalResource extends BaseResource diff --git a/src/Responses/Contacts/ContactCreateResponse.php b/src/Responses/Contacts/ContactCreateResponse.php index 98161f1..ef202fd 100644 --- a/src/Responses/Contacts/ContactCreateResponse.php +++ b/src/Responses/Contacts/ContactCreateResponse.php @@ -2,14 +2,14 @@ declare(strict_types=1); -namespace PlutoLinks\Loops\Responses\Contacts; +namespace Hosmelq\Loops\Responses\Contacts; class ContactCreateResponse { public function __construct( public readonly bool $success, - public readonly string|null $id, - public readonly string|null $message, + public readonly null|string $id, + public readonly null|string $message, ) { } } diff --git a/src/Responses/Contacts/ContactDeleteResponse.php b/src/Responses/Contacts/ContactDeleteResponse.php index 727e65b..010c2e7 100644 --- a/src/Responses/Contacts/ContactDeleteResponse.php +++ b/src/Responses/Contacts/ContactDeleteResponse.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace PlutoLinks\Loops\Responses\Contacts; +namespace Hosmelq\Loops\Responses\Contacts; class ContactDeleteResponse { diff --git a/src/Responses/Contacts/ContactUpdateResponse.php b/src/Responses/Contacts/ContactUpdateResponse.php index 1a9d43e..f2fe99f 100644 --- a/src/Responses/Contacts/ContactUpdateResponse.php +++ b/src/Responses/Contacts/ContactUpdateResponse.php @@ -2,14 +2,14 @@ declare(strict_types=1); -namespace PlutoLinks\Loops\Responses\Contacts; +namespace Hosmelq\Loops\Responses\Contacts; class ContactUpdateResponse { public function __construct( public readonly bool $success, - public readonly string|null $id, - public readonly string|null $message, + public readonly null|string $id, + public readonly null|string $message, ) { } } diff --git a/src/Responses/Events/EventSendResponse.php b/src/Responses/Events/EventSendResponse.php index 154bc53..4c59d85 100644 --- a/src/Responses/Events/EventSendResponse.php +++ b/src/Responses/Events/EventSendResponse.php @@ -2,13 +2,13 @@ declare(strict_types=1); -namespace PlutoLinks\Loops\Responses\Events; +namespace Hosmelq\Loops\Responses\Events; class EventSendResponse { public function __construct( public readonly bool $success, - public readonly string|null $message, + public readonly null|string $message, ) { } } diff --git a/src/Responses/Transactional/TransactionalSendResponse.php b/src/Responses/Transactional/TransactionalSendResponse.php index d55e002..11c0f9b 100644 --- a/src/Responses/Transactional/TransactionalSendResponse.php +++ b/src/Responses/Transactional/TransactionalSendResponse.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace PlutoLinks\Loops\Responses\Transactional; +namespace Hosmelq\Loops\Responses\Transactional; class TransactionalSendResponse { @@ -11,10 +11,10 @@ class TransactionalSendResponse */ public function __construct( public readonly bool $success, - public readonly array|null $error = null, - public readonly string|null $message = null, - public readonly string|null $path = null, - public readonly string|null $transactionalId = null, + public readonly null|array $error = null, + public readonly null|string $message = null, + public readonly null|string $path = null, + public readonly null|string $transactionalId = null, ) { } } diff --git a/tests/Feature/Resources/ContactResourceTest.php b/tests/Feature/Resources/ContactResourceTest.php index 3ba84ef..61180d2 100644 --- a/tests/Feature/Resources/ContactResourceTest.php +++ b/tests/Feature/Resources/ContactResourceTest.php @@ -2,17 +2,17 @@ declare(strict_types=1); -use PlutoLinks\Loops\DataTransferObjects\Contact; -use PlutoLinks\Loops\DataTransferObjects\CustomField; -use PlutoLinks\Loops\Loops; -use PlutoLinks\Loops\Requests\Contacts\ContactCreateRequest; -use PlutoLinks\Loops\Requests\Contacts\ContactCustomFieldsRequest; -use PlutoLinks\Loops\Requests\Contacts\ContactDeleteRequest; -use PlutoLinks\Loops\Requests\Contacts\ContactRetrieveRequest; -use PlutoLinks\Loops\Requests\Contacts\ContactUpdateRequest; -use PlutoLinks\Loops\Responses\Contacts\ContactCreateResponse; -use PlutoLinks\Loops\Responses\Contacts\ContactDeleteResponse; -use PlutoLinks\Loops\Responses\Contacts\ContactUpdateResponse; +use Hosmelq\Loops\DataTransferObjects\Contact; +use Hosmelq\Loops\DataTransferObjects\CustomField; +use Hosmelq\Loops\Loops; +use Hosmelq\Loops\Requests\Contacts\ContactCreateRequest; +use Hosmelq\Loops\Requests\Contacts\ContactCustomFieldsRequest; +use Hosmelq\Loops\Requests\Contacts\ContactDeleteRequest; +use Hosmelq\Loops\Requests\Contacts\ContactRetrieveRequest; +use Hosmelq\Loops\Requests\Contacts\ContactUpdateRequest; +use Hosmelq\Loops\Responses\Contacts\ContactCreateResponse; +use Hosmelq\Loops\Responses\Contacts\ContactDeleteResponse; +use Hosmelq\Loops\Responses\Contacts\ContactUpdateResponse; use Saloon\Http\Faking\MockClient; use Saloon\Http\Faking\MockResponse; diff --git a/tests/Feature/Resources/EventResourceTest.php b/tests/Feature/Resources/EventResourceTest.php index fd90501..2b32680 100644 --- a/tests/Feature/Resources/EventResourceTest.php +++ b/tests/Feature/Resources/EventResourceTest.php @@ -2,8 +2,8 @@ declare(strict_types=1); -use PlutoLinks\Loops\Loops; -use PlutoLinks\Loops\Requests\Events\EventSendRequest; +use Hosmelq\Loops\Loops; +use Hosmelq\Loops\Requests\Events\EventSendRequest; use Saloon\Http\Faking\MockClient; use Saloon\Http\Faking\MockResponse; diff --git a/tests/Feature/Resources/TransactionalResourceTest.php b/tests/Feature/Resources/TransactionalResourceTest.php index a47ebd2..bd1001b 100644 --- a/tests/Feature/Resources/TransactionalResourceTest.php +++ b/tests/Feature/Resources/TransactionalResourceTest.php @@ -2,8 +2,8 @@ declare(strict_types=1); -use PlutoLinks\Loops\Loops; -use PlutoLinks\Loops\Requests\Transactional\TransactionalSendRequest; +use Hosmelq\Loops\Loops; +use Hosmelq\Loops\Requests\Transactional\TransactionalSendRequest; use Saloon\Http\Faking\MockClient; use Saloon\Http\Faking\MockResponse; diff --git a/tests/LoopsTest.php b/tests/LoopsTest.php index 7f3fd94..d448a8f 100644 --- a/tests/LoopsTest.php +++ b/tests/LoopsTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); -use PlutoLinks\Loops\Loops; +use Hosmelq\Loops\Loops; it('may create a client', function (): void { $loops = Loops::client('asdf');