Skip to content

Commit 3e1873a

Browse files
committed
Update CLAUDE.md and README.md with enhanced project documentation and command details; remove obsolete openapi.json file.
1 parent 6418be1 commit 3e1873a

5 files changed

Lines changed: 345 additions & 47 deletions

File tree

.cursorrules

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
You are working on `procoders/astrology-api-php` — a PHP 8.1+ SDK for the Astrology API v3.
2+
3+
# Stack
4+
- PHP 8.1+ with `declare(strict_types=1)` in every file
5+
- Guzzle 7 for HTTP
6+
- PHPUnit 10 for testing
7+
- PHP-CS-Fixer (PSR-12 + single quotes + short arrays + strict params)
8+
9+
# Architecture
10+
Entry point: `src/AstrologyClient.php` — creates Guzzle client with middleware (retry, API key, logging) and 26 readonly category client properties.
11+
12+
Data flow: CategoryClient method → Validators::validate*() → $this->http->post() → GuzzleHttpHelper → Guzzle → API
13+
14+
Key files:
15+
- `src/Categories/BaseCategoryClient.php` — abstract base with `buildUrl(string ...$segments)`
16+
- `src/Utils/HttpHelper.php` — interface: get/post/put/delete
17+
- `src/Utils/GuzzleHttpHelper.php` — extracts `data` or `result` from JSON responses
18+
- `src/Utils/Validators.php` — all static validation, throws `AstrologyError`
19+
- `src/Exceptions/AstrologyError.php` — single exception type with statusCode, errorCode, details
20+
- `src/Categories/InsightsClient.php` — special: contains 5 nested sub-clients
21+
22+
# Strict Rules
23+
1. Every class is `final` unless it needs inheritance
24+
2. Use `readonly` properties for immutable state
25+
3. Category client methods return `mixed`, take `array $options = []` as last param
26+
4. Validate BEFORE HTTP calls, never after
27+
5. Only throw `AstrologyError` — never other exception types
28+
6. Validation context strings: `'ClassName.fieldName'` format
29+
7. `buildUrl()` accepts only strings — cast integers: `(string) $year`
30+
31+
# New Category Client Pattern
32+
```php
33+
<?php
34+
declare(strict_types=1);
35+
namespace Procoders\AstrologyApi\Categories;
36+
use Procoders\AstrologyApi\Utils\HttpHelper;
37+
use Procoders\AstrologyApi\Utils\Validators;
38+
39+
final class FooClient extends BaseCategoryClient
40+
{
41+
private const API_PREFIX = '/api/v3/foo';
42+
public function __construct(HttpHelper $http) { parent::__construct($http, self::API_PREFIX); }
43+
44+
public function getBar(array $request, array $options = []): mixed
45+
{
46+
Validators::validateSubject($request['subject'] ?? [], 'BarRequest.subject');
47+
return $this->http->post($this->buildUrl('bar'), $request, $options);
48+
}
49+
}
50+
```
51+
Then register in AstrologyClient.php: add use import, readonly property, constructor instantiation.
52+
53+
# Unit Test Pattern
54+
Use `SpyHttpHelper` (captures lastMethod, lastPath, lastPayload, lastQuery, lastOptions):
55+
```php
56+
$this->http = new SpyHttpHelper();
57+
$this->client = new FooClient($this->http);
58+
$this->client->getBar(['subject' => $this->subject()]);
59+
self::assertSame('/api/v3/foo/bar', $this->http->lastPath);
60+
```
61+
62+
# Integration Test Pattern
63+
Extend `IntegrationTestCase` — auto-skips without `ASTROLOGY_API_KEY` env var:
64+
```php
65+
$response = self::$client->foo->getBar(['subject' => $this->subject()]);
66+
$this->assertSuccessResponse($response);
67+
```
68+
Real API needs location inside `birth_data`: latitude, longitude, city, nation, timezone.
69+
70+
# Validation Reference
71+
Subject: birth_data with year(1900-2100), month(1-12), day(1-31), hour(0-23), minute(0-59), second(0-59)
72+
Sun signs: Aries..Pisces + Ari,Tau,Gem,Can,Vir,Lib,Sco,Sag,Cap,Aqu,Pis
73+
Horoscope formats: paragraph, bullets, short, long
74+
Progression types: secondary, primary, tertiary, minor
75+
Direction types: solar_arc, symbolic, profection, naibod
76+
House systems: P, W, K, A, R, C, B, M, O, E, V, X, H, T, G
77+
78+
# Commands
79+
```
80+
composer test # all tests
81+
composer test:unit # mocked unit tests
82+
composer test:integration # real API (needs ASTROLOGY_API_KEY)
83+
composer lint # check style
84+
composer lint:fix # auto-fix
85+
```
86+
87+
# Pitfalls
88+
- SVG/PDF endpoints return non-JSON — don't assume array
89+
- InsightsClient has nested sub-clients: $client->insights->relationship->getCompatibility(...)
90+
- Use caret constraints (^7.5) not exact versions — this is a library

.github/copilot-instructions.md

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Copilot Instructions for procoders/astrology-api-php
2+
3+
PHP 8.1+ SDK for the Astrology API v3. Guzzle 7 HTTP transport. Standalone library (no framework).
4+
5+
## Code Style
6+
7+
- `declare(strict_types=1)` in every file
8+
- PSR-12 with single quotes, short array syntax `[]`, strict params
9+
- All classes `final` unless they need inheritance
10+
- PHP 8.1+ `readonly` properties for immutable state
11+
- Namespace: `Procoders\AstrologyApi\` maps to `src/`
12+
13+
## Architecture
14+
15+
`AstrologyClient` is the entry point with 26 readonly category client properties (e.g. `$client->charts`, `$client->horoscope`). Each category client extends `BaseCategoryClient` which provides `buildUrl(string ...$segments)` for URL construction.
16+
17+
Data flow: validate inputs via `Validators::validate*()` → call `$this->http->post/get()``GuzzleHttpHelper` normalizes response (extracts `data` or `result` key from JSON).
18+
19+
Only exception type: `AstrologyError` (statusCode, errorCode, details, isClientError(), isServerError()).
20+
21+
## Category Client Method Pattern
22+
23+
```php
24+
public function getBar(array $request, array $options = []): mixed
25+
{
26+
Validators::validateSubject($request['subject'] ?? [], 'BarRequest.subject');
27+
return $this->http->post($this->buildUrl('bar'), $request, $options);
28+
}
29+
```
30+
31+
Rules:
32+
- Return type is always `mixed`
33+
- `$options` is always the last parameter
34+
- Validate BEFORE HTTP call
35+
- Validation context: `'ClassName.fieldName'`
36+
- `buildUrl()` takes only strings — cast integers: `(string) $year`
37+
38+
## Test Pattern (Unit)
39+
40+
Use `SpyHttpHelper` — captures lastMethod, lastPath, lastPayload, lastQuery:
41+
```php
42+
$this->http = new SpyHttpHelper();
43+
$this->client = new FooClient($this->http);
44+
$this->client->getBar(['subject' => $this->subject()]);
45+
self::assertSame('/api/v3/foo/bar', $this->http->lastPath);
46+
```
47+
48+
## Test Pattern (Integration)
49+
50+
Extend `IntegrationTestCase` (auto-skips without `ASTROLOGY_API_KEY`):
51+
```php
52+
$response = self::$client->foo->getBar(['subject' => $this->subject()]);
53+
$this->assertSuccessResponse($response);
54+
```
55+
56+
## Validation Reference
57+
58+
Subject birth_data requires: year (1900-2100), month (1-12), day (1-31), hour (0-23), minute (0-59), second (0-59). Optional: latitude, longitude, city, country_code.
59+
60+
Enums: Sun signs (Aries..Pisces + 3-letter), horoscope formats (paragraph/bullets/short/long), progression types (secondary/primary/tertiary/minor), direction types (solar_arc/symbolic/profection/naibod), house systems (P/W/K/A/R/C/B/M/O/E/V/X/H/T/G).
61+
62+
## Important Notes
63+
64+
- `InsightsClient` has nested sub-clients: `$client->insights->relationship->getCompatibility(...)`
65+
- SVG/PDF endpoints return non-JSON (raw strings) — don't assume array response
66+
- Real API requires location data INSIDE `birth_data` (latitude, longitude, city, nation, timezone)

0 commit comments

Comments
 (0)