v1.0.0 Release - PHP 8.2+ with Full Feature Parity#42
Merged
MarketDataApp merged 184 commits intomainfrom Feb 20, 2026
Merged
Conversation
- Update composer.json PHP requirement from ^8.1 to ^8.2 - Update test matrix in run-tests.yml to [8.4, 8.3, 8.2] - Update phpdoc.yml PHP version to 8.2 - Update actions/checkout to v4 and create-pull-request to v7 in phpdoc.yml
Updates the requirements on [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) to permit the latest version. - [Release notes](https://github.com/sebastianbergmann/phpunit/releases) - [Changelog](https://github.com/sebastianbergmann/phpunit/blob/11.4.0/ChangeLog-11.4.md) - [Commits](sebastianbergmann/phpunit@10.3.2...11.4.0) --- updated-dependencies: - dependency-name: phpunit/phpunit dependency-type: direct:development ... Signed-off-by: dependabot[bot] <support@github.com>
- Fix earnings currency: Make Earning::$currency nullable (string|null) and update Earnings.php to use null coalescing for currency to handle API returning null for future earnings reports - Fix expired option tests: Update option symbol to AAPL281215C00400000 (expires 2028-12-15) and expiration date to 2028-12-15 for long-term test validity - Remove rho property: Remove rho from all option models (Quote, OptionChainStrike) and all tests as it's no longer supported by the API - Fix utilities service count: Change assertion from assertCount(4) to assertGreaterThanOrEqual(4) since API now returns 12 services - Update all integration tests: Update setUp() methods to use MARKETDATA_TOKEN environment variable and skip tests if not set - Update StocksTest: Update currency assertion to handle nullable type - Update OptionsTest: Remove rho assertions and update to use valid option contracts - Update Unit/OptionsTest: Remove rho from mocks and assertions All tests now pass (82 tests, 814 assertions)
- Remove bulkQuotes() method from Stocks endpoint - Delete BulkQuotes and BulkQuote response classes - Remove all bulkQuotes test methods from unit and integration tests - Update README.md to remove bulkQuotes example - Update CHANGELOG.md to document bulkQuotes removal BREAKING CHANGE: The bulkQuotes endpoint has been removed as it is no longer supported by the API.
Retry Logic Implementation: - Added RetryConfig class with configurable retry attempts and exponential backoff - Implemented retry logic in ClientBase for both sync (execute) and async (async) requests - Added RequestError and BadStatusCodeError exception classes - Retry logic matches Python SDK behavior: - 3 max retry attempts - Exponential backoff: 0.5s → 1s → 2s (max 5s) - Retries on status codes > 500 and network errors - No retry on 4xx errors (except 404 special case) Test Fixes: - Modified testParallelRetryOnServerError_mixedResults to verify behavior (all symbols present) rather than implementation details (response ordering) - Test now uses order-independent symbol verification to avoid race conditions with MockHandler's FIFO queue - Fixed testExceptionHandling_throwsGuzzleException to account for retry logic requiring 3 mock responses to exhaust retries - Added comprehensive retry test suite (21 tests covering sync, async, and parallel scenarios) All tests passing (85/85)
- Add RateLimits value object for reusable rate limit data structure - Add extractRateLimitsFromResponse() method to ClientBase for modular header extraction - Add User response class wrapping RateLimits - Add user() method to Utilities class calling /user/ endpoint - Add makeRawRequest() helper method to ClientBase for accessing response headers - Add comprehensive unit tests covering edge cases and failure paths: - Missing headers, partial headers, invalid values, empty values - Case-insensitive matching, numeric formats, invalid timestamps, boundary values - Add integration tests: - Test to determine if /user/ endpoint consumes requests - Test verifying rate limits after real SPY quote API call - Update documentation to clarify consumed is per-request (not cumulative) - All 97 tests passing with 727 assertions
- Create UnauthorizedException class extending BadStatusCodeError - Update ClientBase to detect 401 status codes and throw UnauthorizedException - Add unit tests for 401 UnauthorizedException handling - Add integration tests for /user/ endpoint with invalid token - Add integration test for SPY quote with no token - Update makeRawRequest() to handle 401 errors for /user/ endpoint All tests passing (103 tests, 753 assertions)
- Add public rate_limits property to ClientBase that automatically tracks rate limits - Initialize rate limits during client construction via /user/ endpoint - Automatically update rate limits after every successful API request - Gracefully handle missing rate limit headers (no update, no error) - Add comprehensive unit tests (8 tests) with mocked responses - Add comprehensive integration tests (6 tests) with real API calls - All 117 existing tests pass, no regressions
- Change rate limit property names to match API header names: - credits_limit -> limit (x-api-ratelimit-limit) - credits_remaining -> remaining (x-api-ratelimit-remaining) - credits_reset -> reset (x-api-ratelimit-reset) - credits_consumed -> consumed (x-api-ratelimit-consumed) - Update all documentation to clarify that rate limits track credits, not requests - Add examples directory with rate_limit_tracking.php example demonstrating automatic rate limit tracking - Add examples/README.md with documentation for examples - Update all tests to use new property names - All 117 tests pass, no regressions
- Prevent client initialization with invalid tokens by validating via /user endpoint - Allow empty token for free symbols like AAPL (skips validation) - Throw UnauthorizedException during construction if token is invalid - Update all unit tests to use empty tokens (they use mocks anyway) - Add comprehensive integration tests for token validation scenarios - Update existing tests to reflect new behavior All tests pass (123 tests, 874 assertions)
- Add vlucas/phpdotenv dependency for .env file support - Create Settings class with automatic token resolution from: 1. Explicit token (constructor parameter) - highest priority 2. MARKETDATA_TOKEN environment variable 3. .env file (MARKETDATA_TOKEN) 4. Empty string fallback (for free symbols) - Make token parameter optional in Client and ClientBase constructors - Update documentation with Configuration section matching Python SDK - Update examples to show automatic env var support - Add comprehensive tests for token resolution and env var support - Maintain backward compatibility (explicit tokens still work) Matches Python SDK developer experience for token configuration.
- Updated GitHub Actions workflow to test PHP 8.2, 8.3, 8.4, and 8.5 - Updated README badge to include PHP 8.5 - Created TESTING_STRATEGY.md with comprehensive testing documentation - Updated CHANGELOG.md with PHP 8.5 support (v0.8.0-beta) - Fixed integration test skipping issue (environment variable cleanup in SettingsTest) - All PHP 8.5 compatibility fixes from 8.5-tests branch included - Renamed branch from update/php-8.2-8.4 to update/php-8.2-8.5 All tests pass on PHP 8.5.2: 164 tests, 1165 assertions, 0 skipped
- Add script to run GitHub Actions tests locally using act - Support testing all PHP versions (default) or a specific version - Quick test mode: when a PHP version is specified, runs only 1 job (prefer-stable) - Full test mode: when no version is specified, runs all 8 jobs (4 versions × 2 stability options) - Includes Docker caching optimization (--pull=false) for faster subsequent runs - Validates test results and fails if any tests are skipped - Properly passes MARKETDATA_TOKEN environment variable for integration tests
- Add Mode enum with LIVE, CACHED, DELAYED values - Add mode parameter to Parameters class (nullable, optional) - Update UniversalParameters trait to handle mode in execute() and execute_in_parallel() - Add unit tests for mode parameter (5 tests) - Add integration tests for mode parameter using stockquote endpoint (3 tests) - Update README with documentation for PHP version testing script - All tests pass on PHP 8.2, 8.3, 8.4, and 8.5 Implements medium priority feature from universal parameters comparison document.
- Add DateFormat enum with TIMESTAMP, UNIX, and SPREADSHEET values - Add date_format parameter to Parameters class (CSV-only restriction) - Update UniversalParameters trait to pass dateformat query parameter - Add comprehensive unit tests for parameter validation - Add integration tests for all date formats across endpoints - All 208 tests passing (1314 assertions)
- Updated Parameters class validation to allow date_format with both CSV and HTML formats - Updated UniversalParameters trait to pass dateformat parameter for HTML format - Added unit tests to validate HTML format with date_format - Updated all error messages to reflect CSV/HTML support All 210 tests passing (1323 assertions)
- Add columns parameter to Parameters class with CSV/HTML-only validation - Update UniversalParameters trait to pass columns parameter to API requests - Add comprehensive unit tests for columns parameter validation - Add integration tests using quote endpoint to verify CSV column filtering - All 225 tests passing (21 new unit tests, 3 new integration tests)
- Add add_headers parameter to Parameters class with CSV/HTML-only validation - Update UniversalParameters trait to pass headers parameter to API in both execute() and execute_in_parallel() methods - Fix execute_in_parallel() to properly handle CSV/HTML responses (was incorrectly trying to json_decode plain text) - Fix Quotes class to handle null responses gracefully and initialize quotes array - Add comprehensive unit tests for add_headers parameter validation (7 tests) - Add integration tests for CSV output with add_headers=true/false using stocks/quotes endpoint (4 tests) - All tests passing (236 tests, 1422 assertions, 0 skipped) This fix also enables parallel requests to work correctly with CSV/HTML formats, which was previously broken due to incorrect response parsing.
- Add optional filename parameter to Parameters class - Validates filename extension matches format (.csv or .html) - Validates that at least one parent directory exists (nested subdirectories created automatically) - Prevents overwriting existing files - Disallows filename with parallel requests (throws exception) - Implements file writing in processResponse when filename provided - Adds saveToFile() convenience method to ResponseBase - Maintains backward compatibility (filename is optional) - Returns response object with CSV/HTML string even when file is saved - Supports both relative and absolute paths - Handles multi-level nested directory creation - Comprehensive unit and integration test coverage All tests pass (257 tests, 1484 assertions, 0 skipped)
- Add Prices response class supporting JSON, CSV, HTML, and human-readable formats - Add prices() method to Stocks class supporting single symbol (path) and multiple symbols (query) formats - Support extended parameter (boolean, defaults to true) - Add comprehensive unit tests (8 tests) covering all scenarios - Add integration tests (6 tests) making real API calls - All 271 tests pass with no regressions
- Created ValidatesInputs trait with reusable validation methods - Added date range validation (only when both dates are parseable) - Added numeric range validation (positive integers, min/max) - Added string/array validation (non-empty, symbols) - Added format validation (resolution, country codes) - Follows Python SDK approach: allows relative dates and option expiration dates - Added validation to all endpoint methods (Stocks, Options, Markets, MutualFunds) - Added comprehensive test coverage (38 trait tests + 25 endpoint tests) - All 334 tests passing, no regressions - Backward compatible, no breaking changes
- Add default_params property to ClientBase for client-level parameter defaults - Implement three-level configuration hierarchy: env vars → client defaults → method params - Add Settings::getDefaultParameters() to read universal params from environment - Update UniversalParameters trait with mergeParameters() and validation - Add comprehensive test suite (77 tests, 113 assertions) with environment isolation - Validate CSV-only parameters cannot be used with JSON format after merging - Support .env file loading with parent directory search (up to 5 levels) - Maintain backward compatibility with existing code patterns
- Introduced a new `test.sh` script to streamline test execution, allowing for unit and integration tests to be run with configurable options. - Updated `phpunit.xml.dist` to define separate test suites for Unit, Integration, and All tests, enhancing clarity and control over test execution. - The new script supports logging, PHP version selection, and provides real-time output to both console and log files. All tests remain passing with the new structure in place.
- Add VERSION constant (0.8.0) to ClientBase class - Update headers() method to include User-Agent: marketdata-sdk-php/0.8.0 - Follow RFC 7231 format: product/product-version (with slash separator) - Add comprehensive test suite (8 tests) for User-Agent functionality - All tests passing (325 tests total) This implementation uses the correct RFC 7231 format, unlike the Python SDK which uses marketdata-sdk-py-1.1.0 (missing slash separator).
…ecking - Add ApiStatusResult enum (ONLINE, OFFLINE, UNKNOWN) - Add online boolean field to ServiceStatus class - Update ApiStatus to parse online field from API response - Create ApiStatusData class with smart caching: * 5-minute cache validity * 4min30sec refresh trigger window * Async refresh in refresh window * Blocking refresh when cache is stale - Add getServiceStatus() method to check specific service status - Add refreshApiStatus() method for manual cache refresh - Add constants for refresh interval and cache validity - Add comprehensive unit and integration tests - Failed refreshes don't overwrite existing cache - Backward compatible with missing online field
- Add getServicePath() helper method with hardcoded mapping from method paths to service paths - Integrate API status checking into execute() and async() retry logic - Skip retries when service is known to be offline (matches Python SDK behavior) - Continue retries when service is online or unknown - Handle status endpoint special case (skip checking its own status) - Add unit tests for intelligent retry behavior with different service statuses - Add integration test for real API service status detection - Optimize getApiStatus() to skip blocking refresh during retry logic This matches the Python SDK's @api_error_handler decorator functionality.
- Update actions/checkout from v4 to v6 in all workflows - Update codecov/codecov-action from v4 to v5 in run-tests.yml - Update peter-evans/create-pull-request from v7 to v8 in phpdoc.yml - Update stefanzweifel/git-auto-commit-action from v5 to v7 in update-changelog.yml - Remove deprecated ReflectionMethod::setAccessible() call in ValidatesInputsTest.php (deprecated in PHP 8.5, no longer needed since PHP 8.1)
- Changed code block syntax from triple backticks to triple tildes for markdown formatting in comment templates. - Ensured consistency in formatting across user error, works as designed, and fixed comment templates.
- Added a new section in CONTRIBUTING.md outlining a systematic bug finding workflow. - Introduced .github/BUG_FINDING.md to provide detailed instructions for proactive bug discovery, including exploration areas and test scenarios. - Updated CONTRIBUTING.md to reference the new bug finding document, improving clarity on how to report and document bugs.
- Added entry for 50+ bug fixes addressing various edge cases and API compatibility. - Documented parameter changes for `option_chain()` and `expirations()` methods. - Introduced new features including cache freshness control and extended hours control. - Updated examples and API documentation links across multiple endpoints for clarity and usability.
…response - Introduced a new test to verify that the application gracefully handles empty Symbol arrays in the human-readable news format. - Ensured that defaults are returned when the API response contains empty arrays, preventing potential errors and maintaining stability.
Add comprehensive example applications demonstrating SDK usage: - portfolio-tracker: Track portfolio value with real-time P&L - earnings-calendar: Generate earnings calendar for watchlists - options-screener: Screen for covered calls and cash-secured puts - historical-data-exporter: Download multi-year data for backtesting - market-hours-scheduler: Schedule tasks around market sessions - news-sentiment-monitor: Monitor and aggregate stock news - api-health-dashboard: Monitor API health and rate limits Each example includes plan.md documentation and sample data files.
Add required checkboxes to bug template forcing reporters to confirm they've reviewed the API docs and that the reported behavior differs from documented behavior. This prevents false bug reports for cases where the SDK correctly returns API data (e.g., percentages as decimals). Updates ISSUE_WORKFLOW.md with corresponding validation criteria, comment template, and example for "Expected API Behavior" cases.
Add explicit requirements throughout BUG_FINDING.md to ensure that discovered bugs are submitted as actual GitHub issues, not just documented in markdown files: - Add prominent callout at document top requiring GitHub issues - Update workflow line to mark issue creation as REQUIRED - Expand Bug Documentation section with CLI command template - Add Completion Checklist at end to verify issues were created
The human-readable format now properly handles missing or empty arrays for all fields except Symbol. This prevents "Undefined array key 0" errors when the API returns partial data.
…ess (closes #45) Both human-readable and regular formats now calculate the minimum length across all required arrays (Open/High/Low/Close/Volume/Date) before iterating. This prevents "Undefined array key" errors when the API returns mismatched array lengths.
…s access (closes #46) Both human-readable and regular formats now calculate the minimum length across all required arrays before iterating. This prevents "Undefined array key" errors when the API returns mismatched array lengths.
- Added null-coalescing for nullable EPS fields in both human-readable and regular formats (reported_eps, estimated_eps, surprise_eps, surprise_eps_pct) - Added minimum array length calculation to prevent out-of-bounds access when API returns mismatched array lengths
This issue was already fixed by the min() array length calculation added in the Issue #47 fix. Adding explicit test coverage.
This issue was already fixed by the min() array length calculation added in the Issue #45 fix. Adding explicit test coverage.
This issue was already fixed by the min() array length calculation added in the Issue #46 fix. Adding explicit test coverage.
…a (closes #51) Both human-readable and regular formats now validate that keys match the YYYY-MM-DD date pattern before adding them to the dates array. This prevents unknown metadata fields from being incorrectly treated as date entries.
…n (closes #63) Header deduplication in concurrent CSV responses now uses trim() on both strings before comparison to handle potential whitespace variations.
…oses #53) The execute_in_parallel() method now determines failure tolerance based on whether a non-null array reference is provided, rather than checking if any second argument was passed. This makes the behavior consistent and predictable.
…ses #54) The Stocks endpoint now uses array_unique() to deduplicate symbols, matching the behavior of the Options endpoint. This prevents redundant API calls when duplicate symbols are provided.
…y (closes #55) The Stocks.quotes() method now delegates single-symbol arrays to the more efficient single-symbol API path, matching the Options endpoint behavior.
…sitives (closes #56) The canParseAsDate() function now uses regex patterns to identify actual date strings instead of accepting any string with '-' or '/'. This prevents stock symbols like "AAPL-WKS" from being misidentified as dates.
Symbols are now uppercased during deduplication to ensure that 'AAPL', 'aapl', and 'AaPl' are treated as the same symbol, preventing redundant API calls.
Updated canParseAsDate() to properly recognize all relative date formats documented at marketdata.app/docs/api/dates-and-times: - Relative keywords: today, yesterday, tomorrow, now - Relative offsets: -5 days, +1 week, -30 minutes - Relative past: "X days ago", "X weeks ago" - Option expiration: "this month's expiration", "next week's expiration" - Option expiration: "expiration in X weeks" This allows proper date range validation while still permitting flexible relative date inputs that the API accepts.
Bump PHPUnit to a patched version, make act-wrapper failure detection robust, and make permission-path tests pass in non-applicable root/container contexts.
Updated PHPUnit from ^11.4.0 to ^11.5.50 in the CHANGELOG. Corrected the README example for bulkCandles to use separate array elements for symbols instead of a single string.
Switch phpdoc workflow to GitHub Pages Actions deploy, update template links to the repository Pages URL, and ignore local release-readiness artifacts.
Ignore docs output and keep only docs/.nojekyll tracked so local/generated phpdoc files no longer create commit noise.
Add a manual release workflow that runs full validation and test matrix before creating the version tag and GitHub Release, preventing bad tags from reaching Packagist.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
v1.0.0 Release - PHP 8.2+ with Full Feature Parity
Summary
This PR prepares the PHP SDK for its 1.0.0 stable release. This is a major upgrade from v0.6.2-beta representing 172 commits, 245 files changed, and ~30,000 lines of new code. The SDK now has full feature parity with the Python SDK and 100% test coverage.
TL;DR for Review
Key files to review:
CHANGELOG.md- Release notes and migration guideSDK_FEATURE_COMPARISON.md- Feature parity documentationBreaking Changes (from v0.6.2-beta)
1. PHP Version Requirement
2. Removed: bulkQuotes Method
3. Options Quote Class Consolidation
QuoteandOptionChainStrikeclasses merged into unifiedOptionQuoteclass4. Client Constructor Changes
MARKETDATA_TOKENenv var or.envfile)UnauthorizedExceptionduring construction (not on first API call)$loggerparameter for custom PSR-3 logger injectionNew Features
Core Infrastructure
DefaultLogger,LoggerFactory, configurable viaMARKETDATA_LOGGING_LEVEL.envfile support (searches up to 5 directories)RetryConfigwith exponential backoff (3 attempts, 0.5-5s)$client->rate_limitsafter each requestNew Source Files Added (17 files)
New Endpoints/Methods
$client->stocks->prices()- SmartMid model prices$client->options->quotes()- Now supports multiple symbols with concurrent fetching$client->utilities->user()- User account informationNew Exception Hierarchy
Response Enhancements
__toString()for human-readable outputFormatsForDisplaytrait for currency, percent, volume formattingValidatesInputstrait for comprehensive input validationOptionChains Convenience Methods
Test Coverage Summary
The test suite now includes comprehensive tests for:
__toString()methodsChanges by Category
src/)tests/)Checklist
Post-Merge Release Steps
v1.0.0on main branchcomposer require marketdataapp/sdk-php ^1.0Questions for Your Review