Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
13ae2b6
Add options classes for various Paystack functionalities
frknasir Oct 30, 2025
b1aa7cf
Refactor code structure for improved readability and maintainability
frknasir Oct 30, 2025
8f6a5d5
Refactor tests for PaymentRequest, Plan, Subaccount, Transaction, and…
frknasir Oct 30, 2025
9a96ddb
Add tests for Settlement, Split, Subscription, and Transfer Recipient…
frknasir Oct 30, 2025
047a30d
Refactor API request handling and add comprehensive tests for various…
frknasir Oct 30, 2025
df12316
Add tests for ApplePay, DedicatedVirtualAccount, DirectDebit, and Vir…
frknasir Oct 30, 2025
f66b513
feat: Enhance API options and methods for Integration, Miscellaneous,…
frknasir Oct 30, 2025
c922d16
refactor: Update API options to accept objects or arrays for BulkChar…
frknasir Oct 30, 2025
d973321
feat: Add GitHub Actions workflows for release and testing; enhance t…
frknasir Oct 30, 2025
c132ebc
Enhance examples for Paystack Payment Requests
frknasir Oct 30, 2025
dc697d3
feat: Add improved type hinting demo and enhance client API method vi…
frknasir Oct 30, 2025
0168219
feat: Add typed responses for Customer, PaymentRequest, and Transacti…
frknasir Oct 30, 2025
ed55cb0
fix: upgrade to PHPUnit 10 and PHP 8.1+, fix deprecated GitHub Actions
frknasir Oct 30, 2025
14db933
fix: remove PHP 8.1 from workflow matrix to align with project requir…
frknasir Oct 30, 2025
e97bbe4
fix: update PHP requirement from ^8.1 to ^8.2 in composer.json
frknasir Oct 30, 2025
1933edb
fix: separate test commands for coverage and non-coverage runs
frknasir Oct 30, 2025
a18fd53
Update composer.lock to sync with composer.json
frknasir Oct 30, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
name: Release

on:
push:
tags:
- 'v*'

jobs:
release:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.2
extensions: dom, curl, libxml, mbstring, zip

- name: Cache dependencies
uses: actions/cache@v3
with:
path: ~/.composer/cache/files
key: dependencies-php-8.2-composer-${{ hashFiles('composer.json') }}

- name: Install dependencies
run: composer install --prefer-dist --no-interaction --no-dev

- name: Run tests
run: composer test

- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
draft: false
prerelease: false

- name: Generate changelog
run: |
echo "## What's Changed" > CHANGELOG.md
git log --oneline --no-merges $(git describe --tags --abbrev=0 HEAD^)..HEAD >> CHANGELOG.md

- name: Update release with changelog
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./CHANGELOG.md
asset_name: CHANGELOG.md
asset_content_type: text/markdown
104 changes: 104 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
name: Tests

on:
push:
branches: [ main, master, v1.x, v2.x ]
pull_request:
branches: [ main, master, v1.x, v2.x ]

jobs:
test:
runs-on: ${{ matrix.os }}

strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
php: [8.2, 8.3]
stability: [prefer-lowest, prefer-stable]

name: P${{ matrix.php }} - ${{ matrix.stability }} - ${{ matrix.os }}

steps:
- uses: actions/checkout@v4

- name: Cache dependencies
uses: actions/cache@v3
with:
path: ~/.composer/cache/files
key: dependencies-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }}

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick
coverage: xdebug

- name: Validate composer.json and composer.lock
run: composer validate --strict

- name: Install dependencies
run: composer update --${{ matrix.stability }} --prefer-dist --no-interaction

- name: Execute tests (without coverage)
if: matrix.php != '8.2' || matrix.stability != 'prefer-stable'
run: composer test

- name: Execute tests (with coverage)
if: matrix.php == '8.2' && matrix.stability == 'prefer-stable'
run: composer test:coverage

- name: Upload coverage to Codecov
if: matrix.php == '8.2' && matrix.stability == 'prefer-stable'
uses: codecov/codecov-action@v3
with:
file: ./coverage.clover
fail_ci_if_error: false

code-quality:
runs-on: ubuntu-latest
name: Code Quality

steps:
- uses: actions/checkout@v4

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.2
extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick

- name: Cache dependencies
uses: actions/cache@v3
with:
path: ~/.composer/cache/files
key: dependencies-php-8.2-composer-${{ hashFiles('composer.json') }}

- name: Install dependencies
run: composer install --prefer-dist --no-interaction

- name: Check syntax errors
run: find ./src -name "*.php" -print0 | xargs -0 -n1 -P8 php -l

- name: Check for security vulnerabilities
run: composer audit --no-dev

- name: Check if examples are working
run: |
if [ -d "examples" ]; then
echo "Found examples directory, checking syntax..."
find ./examples -name "*.php" -print0 | xargs -0 -n1 -P8 php -l
else
echo "No examples directory found, skipping..."
fi

- name: Archive test results
if: always()
uses: actions/upload-artifact@v4
with:
name: test-results-php-8.2
path: |
build/
coverage.clover
retention-days: 30
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
/vendor
/build
.phpunit.result.cache
composer.lock
156 changes: 156 additions & 0 deletions PHASE2_SUMMARY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
# Phase 2 Implementation Summary: Response DTOs

## Overview
Successfully implemented Phase 2 of the type hinting improvements, adding strongly-typed Data Transfer Objects (DTOs) for API responses.

## What Was Implemented

### Core Response Infrastructure
1. **PaystackResponse** - Generic wrapper for all API responses with type parameter support
2. **PaystackResponseException** - Exception for failed API responses
3. **PaginationMeta** - Structured pagination information with helper methods
4. **PaginatedResponse** - Generic paginated collection response

### Customer Response DTOs
- **CustomerData** - Strongly-typed customer object with properties like:
- `id`, `customer_code`, `email`, `first_name`, `last_name`
- Helper methods: `getFullName()`, `hasAuthorizations()`, `hasSubscriptions()`, etc.
- **CustomerListResponse** - Paginated customer list with typed CustomerData objects

### Transaction Response DTOs
- **TransactionData** - Complete transaction information with:
- Status checking: `isSuccessful()`, `isPending()`, `isFailed()`, `isAbandoned()`
- Amount helpers: `getAmountInMajorUnit()`, `getFormattedAmount()`
- Customer info: `getCustomerEmail()`, `getCustomerName()`
- **TransactionInitializeResponse** - Transaction initialization with:
- `authorization_url`, `access_code`, `reference`
- Helper: `isInitialized()`

### PaymentRequest Response DTOs
- **PaymentRequestData** - Payment request/invoice data with:
- Status checking: `isPending()`, `isPaid()`, `isPartiallyPaid()`, `isCancelled()`
- Calculations: `getLineItemsTotal()`, `getTaxTotal()`, `getFormattedAmount()`
- Due date helpers: `hasDueDate()`, `isOverdue()`, `getDueDateAsDateTime()`

### API Method Updates
Added typed response methods to:
- **Customer API**: `createTyped()`, `allTyped()`
- **Transaction API**: `initializeTyped()`, `verifyTyped()`, `allTyped()`
- **PaymentRequest API**: `createTyped()`, `allTyped()`

### Supporting Infrastructure
- **ResponseFactory** - Factory methods for creating typed responses
- **ResponseMediator** - Extended with typed response methods while maintaining backward compatibility

## Files Created

### Response DTOs
```
src/Response/
├── PaystackResponse.php
├── PaystackResponseException.php
├── PaginationMeta.php
├── PaginatedResponse.php
├── ResponseFactory.php
├── Customer/
│ ├── CustomerData.php
│ └── CustomerListResponse.php
├── Transaction/
│ ├── TransactionData.php
│ └── TransactionInitializeResponse.php
└── PaymentRequest/
└── PaymentRequestData.php
```

### Documentation & Examples
- `examples/typed_responses_demo.php` - Comprehensive demonstration
- Updated `examples/README.md` with Phase 2 information

### Updated Files
- `src/HttpClient/Message/ResponseMediator.php` - Added typed response methods
- `src/API/Customer.php` - Added `createTyped()`, `allTyped()`
- `src/API/Transaction.php` - Added `initializeTyped()`, `verifyTyped()`, `allTyped()`
- `src/API/PaymentRequest.php` - Added `createTyped()`, `allTyped()`

## Benefits

### For Developers
1. **Type Safety** - Catch errors at development time, not runtime
2. **IDE Support** - Full autocomplete for all response properties
3. **Helper Methods** - Convenient methods for common operations
4. **Structured Data** - DateTimeImmutable for dates, proper types throughout
5. **Documentation** - Inline PHPDoc visible in IDE tooltips

### For Code Quality
1. **No Array Key Typos** - Properties are strongly typed
2. **Refactoring Support** - IDEs can track usage and rename safely
3. **Clear Contracts** - Response structure is explicitly defined
4. **Future-Proof** - Easy to extend with new methods and properties

## Backward Compatibility

✅ **100% Backward Compatible**
- All existing array-based methods remain unchanged
- Old code continues to work without modifications
- New typed methods use `*Typed()` suffix pattern
- Gradual migration path available

## Testing

✅ **All Tests Pass**
- 144 tests, 496 assertions
- Zero regressions
- Both old and new methods work correctly

## Usage Examples

### Before (v1.x - Array-based)
```php
$response = $paystack->customers()->create([...]);
if ($response['status']) {
$email = $response['data']['email']; // No autocomplete
}
```

### After (v2.x - Typed DTOs)
```php
$response = $paystack->customers()->createTyped([...]);
if ($response->isSuccessful()) {
$customer = $response->getData(); // CustomerData object
$email = $customer->email; // Full autocomplete!
$name = $customer->getFullName(); // Helper method
}
```

## Migration Strategy

1. **New Code**: Use `*Typed()` methods immediately
2. **Existing Code**: No changes required, works as-is
3. **Gradual Migration**: Convert to typed methods during refactoring
4. **Both Supported**: Use whichever approach fits your needs

## Next Steps (Phase 3)

Phase 3 will introduce Request DTOs for type-safe API parameters:
- Strongly-typed request objects instead of arrays
- Validation at creation time
- Builder patterns for complex requests
- Full IDE support for required/optional parameters

## Demo

Run the comprehensive demonstration:
```bash
php examples/typed_responses_demo.php
```

This shows:
- Side-by-side comparison of old vs new approaches
- All DTO features and helper methods
- Pagination support
- Backward compatibility
- Real-world usage patterns

## Conclusion

Phase 2 successfully delivers strongly-typed response DTOs that significantly improve the developer experience while maintaining complete backward compatibility. The implementation provides immediate value through better IDE support, type safety, and convenient helper methods.
Loading
Loading