Skip to content

Commit c20edad

Browse files
authored
Merge pull request #1 from starfolksoftware/feat/v2.x
Feat/v2.x
2 parents c51d678 + a18fd53 commit c20edad

File tree

143 files changed

+22085
-365
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

143 files changed

+22085
-365
lines changed

.github/workflows/release.yml

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*'
7+
8+
jobs:
9+
release:
10+
runs-on: ubuntu-latest
11+
12+
steps:
13+
- uses: actions/checkout@v4
14+
15+
- name: Setup PHP
16+
uses: shivammathur/setup-php@v2
17+
with:
18+
php-version: 8.2
19+
extensions: dom, curl, libxml, mbstring, zip
20+
21+
- name: Cache dependencies
22+
uses: actions/cache@v3
23+
with:
24+
path: ~/.composer/cache/files
25+
key: dependencies-php-8.2-composer-${{ hashFiles('composer.json') }}
26+
27+
- name: Install dependencies
28+
run: composer install --prefer-dist --no-interaction --no-dev
29+
30+
- name: Run tests
31+
run: composer test
32+
33+
- name: Create Release
34+
id: create_release
35+
uses: actions/create-release@v1
36+
env:
37+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
38+
with:
39+
tag_name: ${{ github.ref }}
40+
release_name: Release ${{ github.ref }}
41+
draft: false
42+
prerelease: false
43+
44+
- name: Generate changelog
45+
run: |
46+
echo "## What's Changed" > CHANGELOG.md
47+
git log --oneline --no-merges $(git describe --tags --abbrev=0 HEAD^)..HEAD >> CHANGELOG.md
48+
49+
- name: Update release with changelog
50+
uses: actions/upload-release-asset@v1
51+
env:
52+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
53+
with:
54+
upload_url: ${{ steps.create_release.outputs.upload_url }}
55+
asset_path: ./CHANGELOG.md
56+
asset_name: CHANGELOG.md
57+
asset_content_type: text/markdown

.github/workflows/tests.yml

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
name: Tests
2+
3+
on:
4+
push:
5+
branches: [ main, master, v1.x, v2.x ]
6+
pull_request:
7+
branches: [ main, master, v1.x, v2.x ]
8+
9+
jobs:
10+
test:
11+
runs-on: ${{ matrix.os }}
12+
13+
strategy:
14+
fail-fast: false
15+
matrix:
16+
os: [ubuntu-latest]
17+
php: [8.2, 8.3]
18+
stability: [prefer-lowest, prefer-stable]
19+
20+
name: P${{ matrix.php }} - ${{ matrix.stability }} - ${{ matrix.os }}
21+
22+
steps:
23+
- uses: actions/checkout@v4
24+
25+
- name: Cache dependencies
26+
uses: actions/cache@v3
27+
with:
28+
path: ~/.composer/cache/files
29+
key: dependencies-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }}
30+
31+
- name: Setup PHP
32+
uses: shivammathur/setup-php@v2
33+
with:
34+
php-version: ${{ matrix.php }}
35+
extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick
36+
coverage: xdebug
37+
38+
- name: Validate composer.json and composer.lock
39+
run: composer validate --strict
40+
41+
- name: Install dependencies
42+
run: composer update --${{ matrix.stability }} --prefer-dist --no-interaction
43+
44+
- name: Execute tests (without coverage)
45+
if: matrix.php != '8.2' || matrix.stability != 'prefer-stable'
46+
run: composer test
47+
48+
- name: Execute tests (with coverage)
49+
if: matrix.php == '8.2' && matrix.stability == 'prefer-stable'
50+
run: composer test:coverage
51+
52+
- name: Upload coverage to Codecov
53+
if: matrix.php == '8.2' && matrix.stability == 'prefer-stable'
54+
uses: codecov/codecov-action@v3
55+
with:
56+
file: ./coverage.clover
57+
fail_ci_if_error: false
58+
59+
code-quality:
60+
runs-on: ubuntu-latest
61+
name: Code Quality
62+
63+
steps:
64+
- uses: actions/checkout@v4
65+
66+
- name: Setup PHP
67+
uses: shivammathur/setup-php@v2
68+
with:
69+
php-version: 8.2
70+
extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick
71+
72+
- name: Cache dependencies
73+
uses: actions/cache@v3
74+
with:
75+
path: ~/.composer/cache/files
76+
key: dependencies-php-8.2-composer-${{ hashFiles('composer.json') }}
77+
78+
- name: Install dependencies
79+
run: composer install --prefer-dist --no-interaction
80+
81+
- name: Check syntax errors
82+
run: find ./src -name "*.php" -print0 | xargs -0 -n1 -P8 php -l
83+
84+
- name: Check for security vulnerabilities
85+
run: composer audit --no-dev
86+
87+
- name: Check if examples are working
88+
run: |
89+
if [ -d "examples" ]; then
90+
echo "Found examples directory, checking syntax..."
91+
find ./examples -name "*.php" -print0 | xargs -0 -n1 -P8 php -l
92+
else
93+
echo "No examples directory found, skipping..."
94+
fi
95+
96+
- name: Archive test results
97+
if: always()
98+
uses: actions/upload-artifact@v4
99+
with:
100+
name: test-results-php-8.2
101+
path: |
102+
build/
103+
coverage.clover
104+
retention-days: 30

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
/vendor
22
/build
33
.phpunit.result.cache
4-
composer.lock

PHASE2_SUMMARY.md

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
# Phase 2 Implementation Summary: Response DTOs
2+
3+
## Overview
4+
Successfully implemented Phase 2 of the type hinting improvements, adding strongly-typed Data Transfer Objects (DTOs) for API responses.
5+
6+
## What Was Implemented
7+
8+
### Core Response Infrastructure
9+
1. **PaystackResponse** - Generic wrapper for all API responses with type parameter support
10+
2. **PaystackResponseException** - Exception for failed API responses
11+
3. **PaginationMeta** - Structured pagination information with helper methods
12+
4. **PaginatedResponse** - Generic paginated collection response
13+
14+
### Customer Response DTOs
15+
- **CustomerData** - Strongly-typed customer object with properties like:
16+
- `id`, `customer_code`, `email`, `first_name`, `last_name`
17+
- Helper methods: `getFullName()`, `hasAuthorizations()`, `hasSubscriptions()`, etc.
18+
- **CustomerListResponse** - Paginated customer list with typed CustomerData objects
19+
20+
### Transaction Response DTOs
21+
- **TransactionData** - Complete transaction information with:
22+
- Status checking: `isSuccessful()`, `isPending()`, `isFailed()`, `isAbandoned()`
23+
- Amount helpers: `getAmountInMajorUnit()`, `getFormattedAmount()`
24+
- Customer info: `getCustomerEmail()`, `getCustomerName()`
25+
- **TransactionInitializeResponse** - Transaction initialization with:
26+
- `authorization_url`, `access_code`, `reference`
27+
- Helper: `isInitialized()`
28+
29+
### PaymentRequest Response DTOs
30+
- **PaymentRequestData** - Payment request/invoice data with:
31+
- Status checking: `isPending()`, `isPaid()`, `isPartiallyPaid()`, `isCancelled()`
32+
- Calculations: `getLineItemsTotal()`, `getTaxTotal()`, `getFormattedAmount()`
33+
- Due date helpers: `hasDueDate()`, `isOverdue()`, `getDueDateAsDateTime()`
34+
35+
### API Method Updates
36+
Added typed response methods to:
37+
- **Customer API**: `createTyped()`, `allTyped()`
38+
- **Transaction API**: `initializeTyped()`, `verifyTyped()`, `allTyped()`
39+
- **PaymentRequest API**: `createTyped()`, `allTyped()`
40+
41+
### Supporting Infrastructure
42+
- **ResponseFactory** - Factory methods for creating typed responses
43+
- **ResponseMediator** - Extended with typed response methods while maintaining backward compatibility
44+
45+
## Files Created
46+
47+
### Response DTOs
48+
```
49+
src/Response/
50+
├── PaystackResponse.php
51+
├── PaystackResponseException.php
52+
├── PaginationMeta.php
53+
├── PaginatedResponse.php
54+
├── ResponseFactory.php
55+
├── Customer/
56+
│ ├── CustomerData.php
57+
│ └── CustomerListResponse.php
58+
├── Transaction/
59+
│ ├── TransactionData.php
60+
│ └── TransactionInitializeResponse.php
61+
└── PaymentRequest/
62+
└── PaymentRequestData.php
63+
```
64+
65+
### Documentation & Examples
66+
- `examples/typed_responses_demo.php` - Comprehensive demonstration
67+
- Updated `examples/README.md` with Phase 2 information
68+
69+
### Updated Files
70+
- `src/HttpClient/Message/ResponseMediator.php` - Added typed response methods
71+
- `src/API/Customer.php` - Added `createTyped()`, `allTyped()`
72+
- `src/API/Transaction.php` - Added `initializeTyped()`, `verifyTyped()`, `allTyped()`
73+
- `src/API/PaymentRequest.php` - Added `createTyped()`, `allTyped()`
74+
75+
## Benefits
76+
77+
### For Developers
78+
1. **Type Safety** - Catch errors at development time, not runtime
79+
2. **IDE Support** - Full autocomplete for all response properties
80+
3. **Helper Methods** - Convenient methods for common operations
81+
4. **Structured Data** - DateTimeImmutable for dates, proper types throughout
82+
5. **Documentation** - Inline PHPDoc visible in IDE tooltips
83+
84+
### For Code Quality
85+
1. **No Array Key Typos** - Properties are strongly typed
86+
2. **Refactoring Support** - IDEs can track usage and rename safely
87+
3. **Clear Contracts** - Response structure is explicitly defined
88+
4. **Future-Proof** - Easy to extend with new methods and properties
89+
90+
## Backward Compatibility
91+
92+
**100% Backward Compatible**
93+
- All existing array-based methods remain unchanged
94+
- Old code continues to work without modifications
95+
- New typed methods use `*Typed()` suffix pattern
96+
- Gradual migration path available
97+
98+
## Testing
99+
100+
**All Tests Pass**
101+
- 144 tests, 496 assertions
102+
- Zero regressions
103+
- Both old and new methods work correctly
104+
105+
## Usage Examples
106+
107+
### Before (v1.x - Array-based)
108+
```php
109+
$response = $paystack->customers()->create([...]);
110+
if ($response['status']) {
111+
$email = $response['data']['email']; // No autocomplete
112+
}
113+
```
114+
115+
### After (v2.x - Typed DTOs)
116+
```php
117+
$response = $paystack->customers()->createTyped([...]);
118+
if ($response->isSuccessful()) {
119+
$customer = $response->getData(); // CustomerData object
120+
$email = $customer->email; // Full autocomplete!
121+
$name = $customer->getFullName(); // Helper method
122+
}
123+
```
124+
125+
## Migration Strategy
126+
127+
1. **New Code**: Use `*Typed()` methods immediately
128+
2. **Existing Code**: No changes required, works as-is
129+
3. **Gradual Migration**: Convert to typed methods during refactoring
130+
4. **Both Supported**: Use whichever approach fits your needs
131+
132+
## Next Steps (Phase 3)
133+
134+
Phase 3 will introduce Request DTOs for type-safe API parameters:
135+
- Strongly-typed request objects instead of arrays
136+
- Validation at creation time
137+
- Builder patterns for complex requests
138+
- Full IDE support for required/optional parameters
139+
140+
## Demo
141+
142+
Run the comprehensive demonstration:
143+
```bash
144+
php examples/typed_responses_demo.php
145+
```
146+
147+
This shows:
148+
- Side-by-side comparison of old vs new approaches
149+
- All DTO features and helper methods
150+
- Pagination support
151+
- Backward compatibility
152+
- Real-world usage patterns
153+
154+
## Conclusion
155+
156+
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.

0 commit comments

Comments
 (0)