Skip to content

feat: Add CSV and JSON import functionality with user validation and processing#6

Closed
koriym wants to merge 45 commits into1.xfrom
demo
Closed

feat: Add CSV and JSON import functionality with user validation and processing#6
koriym wants to merge 45 commits into1.xfrom
demo

Conversation

@koriym
Copy link
Member

@koriym koriym commented Jul 5, 2025

Summary

  • Added comprehensive CSV import functionality with file validation and user processing
  • Implemented JSON configuration demo with structured data handling
  • Created multi-format import demo supporting both CSV and XML formats
  • Enhanced existing demo files with proper code formatting and type safety
  • Updated composer.json to include demo directory in code style checks

Key Features

  • CSV Import: Complete CSV processing with header detection, validation, and user data extraction
  • JSON Configuration: Structured JSON data handling with validation and processing
  • Multi-format Support: Unified interface for handling CSV, JSON, and XML data formats
  • File Upload Integration: Seamless integration with FileUpload system for secure file handling
  • Type Safety: Full type annotations and validation throughout all components

Files Added

  • demo/csv/ - Complete CSV import system with validation and processing
  • demo/json/ - JSON configuration handling and validation
  • demo/multiformat/ - Multi-format data import capabilities
  • Sample data files for testing and demonstration

Test plan

  • Run CSV import demo with sample users.csv file
  • Test JSON configuration processing with config.json
  • Verify multi-format demo with both CSV and XML files
  • Check file upload validation and error handling
  • Validate type safety and input validation across all demos

🤖 Generated with Claude Code

Summary by Sourcery

Add comprehensive demo applications for CSV, JSON, and multi-format file imports showcasing Ray\InputQuery integration with Koriym\FileUpload, user and schema validation, type-safe input objects, and improve demo infrastructure and code style configuration.

New Features:

  • Add CSV import demo with header detection, data validation, and user data extraction
  • Add JSON configuration demo with schema validation, environment-specific warnings, and default merging
  • Add multi-format demo supporting CSV, JSON, XML, and text file processing with format auto-detection

Enhancements:

  • Refactor demo classes and scripts with consistent attribute annotations, readonly properties, and unified Throwable exception handling
  • Integrate Koriym\FileUpload and Ray\InputQuery file upload attributes for secure and type-safe file handling
  • Improve code formatting, type annotations, and demo output formatting across all examples

Build:

  • Include demo directory in composer.json code style checks

Summary by CodeRabbit

  • New Features

    • Introduced comprehensive CSV and JSON file processing demos, including structured input objects, schema validation, multi-format support (CSV, TSV, JSON, XML, TXT), and summary reporting.
    • Added new classes for CSV import, user validation, configuration file handling, multi-format file processing with format detection, and import summary formatting.
    • Provided sample configuration and data files for demonstration purposes.
    • Added scripts demonstrating best practices for CSV processing and type-safe input handling using dependency injection.
  • Bug Fixes

    • Broadened error handling in file upload processing to catch all throwables.
  • Style

    • Improved code readability by reformatting attributes, adding trailing commas, and standardizing whitespace and string concatenation.
    • Enhanced import statement organization and template formatting.
  • Chores

    • Updated code style scripts to include the demo directory.

koriym and others added 30 commits July 3, 2025 21:18
Add array and ArrayObject support for Input attribute
- Remove outdated Input Format Requirements section that contradicted array support
- Add comprehensive HTML form examples with Jingu and Horikawa as sample names
- Include checkbox and multi-select examples for simple array handling
- Clarify data flow from HTML forms to PHP data structures
- Maintain existing nested object and key normalization documentation

This update makes the documentation more cohesive and removes the confusing
restriction about nested arrays that no longer applies with the array support feature.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Convert bold text to proper markdown headings for better TOC
- Add closing form tag and blank line for proper HTML structure
- Wrap checkbox/select examples in form tag for consistency
- Fix Note formatting by removing extraneous colon

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
docs: Improve array support documentation
- Add FileUpload type detection for #[Input] parameters
- Automatically create FileUpload objects from $_FILES when not provided in query
- Support both single files and multiple file uploads (HTML format)
- Maintain test-friendly design: FileUpload objects can be injected directly
- Add union type support for FileUpload|ErrorFileUpload parameters
- Environment-agnostic: works with traditional PHP, no manual $_FILES handling required

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Demo controller methods use #[Input] attributes directly on parameters
- Show 4-step process: InputQuery creation, reflection, argument resolution, method call
- Automatic FileUpload object creation from $_FILES demonstrated
- Clean separation: profile with detailed comments, gallery with minimal code
- FileUpload.move() integration for actual file saving

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Document FileUpload integration with Koriym.FileUpload
- Show test-friendly design with direct object injection
- Include composer require instructions
- Add demo execution instructions
- Demonstrate both single and multiple file upload patterns

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Compare Native PHP, Laravel, Symfony, and Ray.InputQuery approaches
- Highlight IDE support limitations in existing frameworks
- Show magic property and string-based validation issues
- Demonstrate Ray.InputQuery's type-first philosophy
- Include actual framework integration code (4-line approach)

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add koriym/file-upload to composer.json suggests section
- Enables optional file upload functionality integration

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Document technical design decisions for file upload support
- Explain environment-agnostic approach and test-friendly patterns

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Fix PHPStan errors with proper type annotations for $_FILES access
- Resolve Psalm mixed assignment warnings in foreach loops
- Remove redundant type checks and assertions
- Both PHPStan and Psalm now pass without errors

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Remove unused $inputAttributes parameter from resolveUnionType method
- Update README.md to use ReflectionMethod::invokeArgs() consistently
- Fix PHPMD UnusedFormalParameter violation
- All static analysis tools now pass without warnings

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add dedicated #[InputFile] attribute for file upload parameters
- Implement file validation with maxSize and allowedTypes options
- Add validateFileUploadValue() helper method
- Extract common logic with getDefaultValueOrThrow() method
- Support single files, arrays, and union types (FileUpload|ErrorFileUpload)
- Add comprehensive tests for file upload validation

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add hierarchical psalm domain types for better type safety
- Define FileNameArray, FileTypeArray, FileSizeArray, FileTmpNameArray, FileErrorArray
- Restructure MultipleFileData with hierarchical types
- Update all type annotations to use domain types instead of complex arrays
- Achieve perfect static analysis results (Psalm 99.0%, PHPStan clean)
- Improve code readability and maintainability through meaningful type names

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add InvalidFileUploadAttributeException for #[Input] + FileUpload usage
- Enforce #[InputFile] attribute requirement for FileUpload types
- Remove dead code paths in resolveObjectType method
- Add comprehensive test suite covering all edge cases (165 tests)
- Fix getDefaultValue handling for nullable file upload parameters
- Suppress PHPMD.BooleanArgumentFlag for InputFile configuration class
- Replace string literals with ::class constants for better maintainability

Coverage: 100% classes, 100% methods, 100% lines
Static Analysis: All checks pass (Psalm, PHPStan, PHPMD)

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add comprehensive domain types for better type safety and clarity:
  - FileUploadArray: array<array-key, FileUpload|ErrorFileUpload>
  - InputAttributes: array<ReflectionAttribute<Input>>
  - InputFileAttributes: array<ReflectionAttribute<InputFile>>
  - NestedQuery: array<string, mixed>
  - InputArray: array<int, mixed>
  - ParameterValue: scalar|array<array-key, mixed>|object|null

- Replace 11 instances of generic array<array-key, mixed> with specific domain types
- Replace 8 instances of array<ReflectionAttribute<*>> with named types
- Add proper type annotations for improved static analysis
- Maintain 100% code coverage and all static analysis checks

Domain-driven typing improves code clarity, maintainability, and type safety.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add Koriym\FileUpload\FileUpload to symbol-whitelist
- Add Koriym\FileUpload\ErrorFileUpload to symbol-whitelist
- Fix JSON trailing comma issue

These classes are optional dependencies for file upload functionality,
so they should be whitelisted to avoid false positives in dependency checking.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Remove all private method tests following best practices
- Add comprehensive public interface tests for all edge cases
- Test file upload scenarios: nullable, default values, UPLOAD_ERR_NO_FILE
- Cover ArrayObject creation and custom ArrayObject subclasses
- Test $_FILES handling including missing files and multiple formats
- Add mixed type parameter tests for complete coverage
- Replace 17 private method test files with proper public tests

This refactoring demonstrates that 100% coverage is achievable through
well-designed public interface tests without compromising maintainability.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
…ribute

- Add code coverage badge and quality section to README
- Update file upload examples to use #[InputFile] instead of #[Input]
- Document validation options (maxSize, allowedTypes, allowedExtensions)
- Update demo application with proper InputFile attribute usage
- Emphasize test quality achievements and design principles

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Use $method->invokeArgs() consistently for both profile and gallery cases
- Add comprehensive usage patterns documentation showing three approaches
- Remove verbose comments for cleaner code presentation

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add framework integration examples for Laravel, Symfony, CakePHP, Yii1, BEAR.Sunday, and Slim
- Include three usage patterns: Reflection, Direct Object Creation, and Spread Operator
- Provide testing examples with FileUpload::fromFile() for realistic mocks
- Add framework-specific configurations and best practices
- Update README with Framework Integration section and links
- Special thanks to the amazing team at bengo4.com for Yii1 integration inspiration 💝

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
- Convert bare URL to proper markdown link format
- Address static analysis suggestion for better formatting

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add allowedExtensions property to InputFile attribute for extension validation
- Update extractValidationOptions to handle allowedExtensions parameter
- Enhance union type validation to restrict to FileUpload|ErrorFileUpload|null only
- Add comprehensive test coverage for extension validation scenarios
- Fix README.md PHP code block formatting issue
- Update ValidationOptions type definition to include allowedExtensions

This provides an additional security layer by validating file extensions
alongside MIME type checking, improving file upload safety.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Major refactoring to address PHPMD complexity issues and improve design:

**FileUploadFactory (new)**
- Extract all file upload logic from InputQuery into dedicated factory
- Follow Single Responsibility Principle for file upload creation
- Support service locator pattern for testing (pre-created FileUpload objects)
- Independently usable in BEAR.Resource and other contexts
- Handle mixed type parameters with InputFile attribute
- Comprehensive documentation of service locator pattern usage

**InputQuery (simplified)**
- Reduce complexity by delegating file upload logic to FileUploadFactory
- Remove 200+ lines of file upload methods
- Maintain same public API for backward compatibility
- Use FileUploadFactory for all file upload operations

**Type System Enhancement**
- Introduce Query domain type in InputQueryInterface
- Import Query type across components for consistency
- Replace generic array types with semantic Query type
- Improve type safety and code documentation

**Benefits**
- PHPMD complexity now below threshold (was 108, now <100)
- Better separation of concerns (file vs general parameter handling)
- Enhanced testability through service locator pattern
- Reusable FileUploadFactory for standalone usage
- Clearer type definitions with Query domain type

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add FileUploadFactoryTest with 11 test cases covering all methods
- Implement validation for multiple #[InputFile] attributes on same parameter
- Add validation for conflicting #[Input] and #[InputFile] attributes
- Remove support for short class names to avoid namespace conflicts
- Test edge cases including intersection types in union types
- Achieve 100% code coverage (Classes, Methods, Lines)
- Add tests for createFromFiles() and resolveFileUploadUnionType()
- Test invalid parameter types and unsupported union types

All tests passing (102 tests, 347 assertions) with 100% coverage.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
koriym and others added 13 commits July 4, 2025 19:15
- Move intersection+union type test to FileUploadFactoryPhp82Test.php
- Add @requires PHP >= 8.2 at class level for proper version checking
- Remove unused imports from main test file
- Fix compatibility for PHP 8.1 where intersection+union syntax causes parse errors

This ensures tests run properly on all supported PHP versions.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This test case for intersection+union types causes syntax errors in PHP < 8.2
and cannot be properly isolated. The minor coverage gain is not worth the
compatibility issues.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Add @codeCoverageIgnore annotation for intersection types in union types
- This code path only occurs with PHP 8.2+ syntax like (A&B)|C
- Cannot be tested in PHP < 8.2 due to syntax parse errors
- Maintains 100% coverage while ensuring PHP version compatibility

The ignored line represents an edge case that is not encountered in
real-world applications and cannot be reliably tested across all
supported PHP versions.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
File upload support with automatic  handling
## Summary
- Create FileUploadFactoryInterface for better dependency injection and testability
- Split Factory responsibility: create() for single files, createMultiple() for arrays
- Improve type safety with FileUploadKey type for array indices
- Add comprehensive HTML form examples showing library's UI-to-PHP mapping

## Key Features
### Single File Upload
```html
<input type="file" name="avatar">
```
```php
public function __construct(
    #[InputFile] FileUpload $avatar
) {}
```

### Multiple File Upload
```html
<input type="file" name="images[]" multiple>
```
```php
public function __construct(
    #[InputFile] array $images
) {}
```

### File Upload with Validation
```html
<input type="file" name="photo" accept="image/*">
```
```php
public function __construct(
    #[InputFile(maxSize: 2048, allowedTypes: ['image/jpeg', 'image/png'])]
    FileUpload $photo
) {}
```

## Technical Improvements
- Factory pattern with clear single responsibility
- Performance optimization for BEAR.Resource compilation caching
- 100% code coverage maintained
- Full static analysis compliance (PHPStan, Psalm)

## UI-to-PHP Philosophy
This library bridges HTML forms and PHP constructors seamlessly:
- HTML form elements map directly to constructor parameters
- Type hints provide automatic validation and conversion
- Attributes configure behavior without breaking encapsulation

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
## Demo Enhancements
- Update run.php with comprehensive file upload examples
- Add FileUploadExample class showcasing factory pattern usage
- Update index.php to use FileUploadFactoryInterface with DI
- Add visual HTML-to-PHP mapping examples in web demo

## Key Demo Features
### Command Line Demo (run.php)
- Factory interface dependency injection setup
- Single and multiple file upload examples
- HTML form mapping visualization
- Factory pattern benefits explanation

### Web Demo (index.php)
- Interactive file upload forms
- Real-time HTML ↔ PHP mapping examples
- FileUploadFactoryInterface integration
- Comprehensive usage patterns

## HTML-to-PHP Mapping Showcase
Demonstrates the library's core philosophy:
```html
<input type="file" name="avatar" required>
```
↓ Maps to:
```php
#[InputFile] FileUpload $avatar
```

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
… improve API consistency

- Create FileUploadTypeChecker utility class to eliminate duplicate type checking logic between Factory and InputQuery
- Update FileUploadFactoryInterface::createMultiple to accept ReflectionParameter instead of string for consistency
- Move isFileUploadType and isValidFileUploadUnion methods to shared FileUploadTypeChecker class
- Update all callers to use the new static methods and consistent API
- Fix tests to use ReflectionParameter objects instead of strings
- Maintain 100% code coverage and pass all quality checks

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
…ony/polyfill-php83

- Add symfony/polyfill-php83 dependency to support #[Override] attribute in PHP 8.1/8.2
- Restore #[Override] attributes in InputQuery and FileUploadFactory interface implementations
- Restore Override use statements in source files
- Verify compatibility with demo/run.php and full test suite
- Maintain existing functionality while ensuring cross-version compatibility

The polyfill provides attribute class compatibility without functionality in older PHP versions,
allowing seamless upgrade to PHP 8.3+ where native Override checking will be available.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
…ate constructor calls

- Add missing import statements for all classes used in examples
- Replace \ReflectionMethod with ReflectionMethod imports
- Replace \InvalidArgumentException with InvalidArgumentException imports
- Update InputQuery constructor calls to include FileUploadFactory parameter
- Add Ray\InputQuery\FileUploadFactory imports across all framework examples
- Ensure consistent code style and proper namespace usage

Fixes full path class references in:
- Laravel integration examples
- Symfony integration examples
- CakePHP integration examples
- Yii Framework integration examples
- Slim Framework integration examples
- PHPUnit testing examples
- Common patterns section

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Fix unused loop index $i in foreach loop that only needs the document value.
This improves code clarity and follows best practices for loop iteration.

- foreach ($this->documents as $i => $doc) {
+ foreach ($this->documents as $doc) {

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
feat: Add FileUploadFactoryInterface with HTML-to-PHP Form Mapping
@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Jul 5, 2025

Reviewer's Guide

This PR introduces end-to-end import demos for CSV, JSON and multi-format files—featuring upload integration, validation, auto-detection and type-safe processing via Ray.InputQuery—while also refactoring existing demo entry points and input classes for consistent attribute formatting, error handling, and code style enhancements.

Class diagram for new and updated CSV import input objects

classDiagram
    class CsvFileInput {
        +FileUpload csvFile
        +string delimiter
        +bool hasHeader
        +string encoding
        +string importBatch
        +getFileInfo() array
    }
    class CsvToInputConverter {
        -string delimiter
        -bool hasHeader
        -string encoding
        +convertCsvToQueryData(FileUpload, string) array
        +normalizeKey(string) string
        +getSampleQueryData() array
    }
    class UserInput {
        +string name
        +string email
        +int|null age
        +string department
        +bool isActive
        +isValid() bool
        +getValidationErrors() array
        +getDisplayName() string
    }
    class CsvUsersImport {
        +UserInput[] users
        +string source
        +string importBatch
        +DateTimeImmutable importedAt
        +getValidUsers() array
        +getInvalidUsers() array
        +getStatistics() array
        +getImportSummary() string
        +getValidationReport() string
    }
    CsvUsersImport "1" *-- "*" UserInput : contains
    CsvToInputConverter ..> CsvFileInput : uses
    CsvToInputConverter ..> UserInput : creates
    CsvFileInput o-- FileUpload : csvFile
Loading

Class diagram for new JSON configuration import demo

classDiagram
    class JsonConfigDemo {
        +FileUpload configFile
        +bool validateSchema
        +bool mergeWithDefaults
        +string environment
        +processConfig() array
        +getSummary() string
        -validateConfigSchema(array) array
        -mergeWithDefaultConfig(array) array
    }
    JsonConfigDemo o-- FileUpload : configFile
Loading

Class diagram for new multi-format import demo

classDiagram
    class MultiFormatDemo {
        +FileUpload dataFile
        +string format
        +bool autoDetect
        +array options
        +processFile() array
        +getSummary() string
        -detectFileFormat() string
        -detectFormatByContent() string
        -isValidJson(string) bool
        -processCsvFile(string) array
        -processJsonFile() array
        -processXmlFile() array
        -xmlToArray(SimpleXMLElement) array
        -xmlElementToArray(SimpleXMLElement) array
        -processTextFile() array
    }
    MultiFormatDemo o-- FileUpload : dataFile
Loading

File-Level Changes

Change Details Files
Added comprehensive CSV, JSON and multi-format import demos with validation, schema handling, auto-detection and summary reporting
  • Implemented CsvImportDemo pipeline (CsvFileInput, CsvToInputConverter, UserInput, CsvUsersImport) with structured import and validation
  • Created JsonConfigDemo with schema validation, default merging and run script
  • Added MultiFormatDemo supporting CSV, TSV, JSON, XML, TXT auto-detection and processing with summary output
  • Included sample data files (products.json/xml, users.csv, config.json) for all demos
demo/csv/CsvImportDemo.php
demo/csv/CsvToInputConverter.php
demo/csv/UserInput.php
demo/csv/CsvFileInput.php
demo/csv/CsvUsersImport.php
demo/csv/run.php
demo/csv/run_structured.php
demo/csv/run_correct.php
demo/json/JsonConfigDemo.php
demo/json/run.php
demo/multiformat/MultiFormatDemo.php
demo/multiformat/products.xml
demo/multiformat/products.json
demo/json/config.json
demo/csv/users.csv
Refactored demo entry points and run scripts for consistent DI, file upload handling, attribute formatting and error handling
  • Reordered and cleaned up use imports; switched to FileUploadFactory binding
  • Standardized PHP attributes on separate lines, added trailing commas, adjusted spacing
  • Replaced Exception catches with Throwable for broader error handling
  • Harmonized HTML templates and echo statements (spacing, colon style)
demo/index.php
demo/run.php
Standardized input classes and controllers for type safety and formatting consistency
  • Moved Input/InputFile attributes to individual lines, added trailing commas in constructors
  • Ensured all public readonly properties have explicit types and normalized formatting
  • Updated BlogController methods to use proper attribute placement and Throwable
  • Applied sprintf/echo style consistency across BlogPost, UserProfile, FileUploadExample
demo/BlogPost.php
demo/UserProfile.php
demo/FileUploadExample.php
demo/BlogController.php
Updated project code style scripts to include demos
  • Expanded composer.json’s cs-fix command to run code style on demo directory
composer.json

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai
Copy link

coderabbitai bot commented Jul 5, 2025

Walkthrough

This update introduces a suite of new demos and utilities for handling structured file input in multiple formats (CSV, TSV, JSON, XML, TXT) using Ray.InputQuery. It adds new classes for CSV and JSON file processing, validation, and reporting, as well as scripts demonstrating best practices for type-safe, validated input handling. Existing files are updated for code style consistency and readability.

Changes

File(s) Change Summary
composer.json Expanded cs-fix script to include the demo directory.
demo/ArrayDemo.php, demo/BlogController.php, demo/BlogPost.php, demo/FileUploadExample.php, demo/UserProfile.php, demo/index.php, demo/run.php Code style and formatting improvements: trailing commas, attribute reformatting, explicit imports, exception handling broadened, whitespace.
demo/csv/CsvFileInput.php, demo/csv/CsvImportDemo.php, demo/csv/CsvToInputConverter.php, demo/csv/CsvUsersImport.php, demo/csv/UserInput.php New classes for CSV file input, conversion, import, validation, and reporting.
demo/csv/run.php, demo/csv/run_correct.php, demo/csv/run_structured.php New demo scripts for CSV processing, demonstrating type safety, validation, and business logic.
demo/json/JsonConfigDemo.php, demo/json/run.php New class and script for JSON config file upload, validation, schema checking, and reporting.
demo/json/config.json New sample JSON configuration file.
demo/multiformat/MultiFormatDemo.php New class for multi-format file input handling (CSV, TSV, JSON, XML, TXT).
demo/multiformat/products.json, demo/multiformat/products.xml New sample product data files in JSON and XML formats.
demo/multiformat/CsvFormatProcessor.php, demo/multiformat/FileFormatDetector.php, demo/multiformat/FormatDetectorInterface.php, demo/multiformat/FormatProcessorInterface.php, demo/multiformat/JsonFormatProcessor.php New interfaces and classes for file format detection and processing supporting CSV, TSV, JSON, and other formats.
demo/ImportSummaryFormatter.php New utility class for consistent formatting of import summaries across demos.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant FileUpload
    participant InputQuery
    participant CsvToInputConverter
    participant CsvUsersImport

    User->>FileUpload: Upload CSV file
    User->>InputQuery: Provide file and options
    InputQuery->>CsvToInputConverter: Parse CSV file to array
    CsvToInputConverter-->>InputQuery: Return structured data
    InputQuery->>CsvUsersImport: Create import object from data
    CsvUsersImport-->>User: Provide import summary, validation, stats
Loading
sequenceDiagram
    participant User
    participant FileUpload
    participant InputQuery
    participant JsonConfigDemo

    User->>FileUpload: Upload JSON config file
    User->>InputQuery: Provide file and options
    InputQuery->>JsonConfigDemo: Create config demo object
    JsonConfigDemo->>JsonConfigDemo: Validate schema, merge defaults
    JsonConfigDemo-->>User: Provide config summary and errors
Loading
sequenceDiagram
    participant User
    participant FileUpload
    participant InputQuery
    participant MultiFormatDemo

    User->>FileUpload: Upload data file (CSV/TSV/JSON/XML/TXT)
    User->>InputQuery: Specify format and options
    InputQuery->>MultiFormatDemo: Create demo object
    MultiFormatDemo->>MultiFormatDemo: Auto-detect/process format
    MultiFormatDemo-->>User: Return processed data and summary
Loading

Possibly related PRs

  • File upload support with automatic handling #3: Introduces initial file upload support including the InputFile attribute and automatic handling of file uploads, which this PR builds upon for expanded file input demos and processing.

Poem

🐇
A hop, a skip, new demos bloom,
CSVs and JSONs fill the room!
Type-safe fields and formats many,
Imports, stats, and errors—plenty!
With tidy code and files anew,
This bunny cheers: "Great work, crew!"
🥕✨

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @koriym - I've reviewed your changes - here's some feedback:

  • The MultiFormatDemo class is quite large and mixes detection, parsing, and summary generation—consider extracting format detection and processing into separate strategy classes to adhere to single responsibility and simplify maintenance.
  • In CsvImportDemo (and related CSV converters), rows with a different column count than the headers are silently padded or dropped—add explicit validation for row length mismatches to catch malformed input early.
  • Across CSV, JSON, and multi‐format demos, the getSummary methods share very similar formatting logic—extract a shared summary formatter or helper to reduce duplication and improve consistency.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The MultiFormatDemo class is quite large and mixes detection, parsing, and summary generation—consider extracting format detection and processing into separate strategy classes to adhere to single responsibility and simplify maintenance.
- In CsvImportDemo (and related CSV converters), rows with a different column count than the headers are silently padded or dropped—add explicit validation for row length mismatches to catch malformed input early.
- Across CSV, JSON, and multi‐format demos, the getSummary methods share very similar formatting logic—extract a shared summary formatter or helper to reduce duplication and improve consistency.

## Individual Comments

### Comment 1
<location> `demo/csv/CsvToInputConverter.php:40` </location>
<code_context>
+     */
+    public function convertCsvToQueryData(FileUpload $csvFile, string $importBatch = ''): array
+    {
+        $csvData = new SplFileObject($csvFile->tmpName);
+        $csvData->setFlags(SplFileObject::READ_CSV | SplFileObject::SKIP_EMPTY);
+        $csvData->setCsvControl($this->delimiter);
</code_context>

<issue_to_address>
Possible typo: should use 'tmp_name' instead of 'tmpName' for FileUpload property.

'tmp_name' is the standard property for the temporary file path. Using 'tmpName' may cause file access issues. Please check and update as needed.
</issue_to_address>

<suggested_fix>
<<<<<<< SEARCH
        $csvData = new SplFileObject($csvFile->tmpName);
=======
        $csvData = new SplFileObject($csvFile->tmp_name);
>>>>>>> REPLACE

</suggested_fix>

### Comment 2
<location> `demo/csv/CsvImportDemo.php:59` </location>
<code_context>
+            'users' => [],
+        ];
+
+        try {
+            $csvData = new SplFileObject($this->csvFile->tmp_name);
+            $csvData->setFlags(SplFileObject::READ_CSV | SplFileObject::SKIP_EMPTY);
+            $csvData->setCsvControl($this->delimiter);
</code_context>

<issue_to_address>
No explicit file encoding handling for CSV import.

SplFileObject does not convert encodings. Add logic to handle non-UTF-8 files if needed.
</issue_to_address>

### Comment 3
<location> `demo/csv/CsvImportDemo.php:75` </location>
<code_context>
+                }
+
+                // First row as headers
+                if ($this->hasHeader && $rowNumber === 1) {
+                    $headers = $row;
+                    continue;
+                }
</code_context>

<issue_to_address>
Header row may contain empty or duplicate values.

Validate headers for emptiness or duplicates before using array_combine to prevent failures or unexpected behavior.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Nitpick comments (6)
demo/UserProfile.php (1)

9-10: use function sprintf; is optional

Importing a global function is allowed but unusual. If you prefer brevity, keeping the fully-qualified call is fine; otherwise leave as is—no functional issue.

demo/FileUploadExample.php (2)

11-12: Function import is fine but optional

count() is global; importing saves two characters but adds noise. Style choice.


39-40: Minor: use \count() directly

If you drop the import, adjust call accordingly; either way is fine.

demo/csv/UserInput.php (1)

55-57: Consider adjusting the maximum age limit.

The age limit of 150 years might be too restrictive for some use cases. Consider if this should be configurable or if 120 years would be more realistic.

-        if ($this->age !== null && ($this->age < 0 || $this->age > 150)) {
-            $errors[] = 'Age must be between 0 and 150';
+        if ($this->age !== null && ($this->age < 0 || $this->age > 120)) {
+            $errors[] = 'Age must be between 0 and 120';
demo/csv/CsvToInputConverter.php (1)

65-66: Consider adding input sanitization.

While the current implementation trims whitespace, consider adding additional sanitization for security, especially if this data will be stored in a database.

                foreach ($headers as $i => $header) {
-                    $value = isset($row[$i]) ? trim($row[$i]) : '';
+                    $value = isset($row[$i]) ? trim(strip_tags($row[$i])) : '';
                    $userData[$this->normalizeKey($header)] = $value;
                }
demo/multiformat/MultiFormatDemo.php (1)

183-189: Consider consistent JSON error handling approach

The isValidJson method uses json_decode without the JSON_THROW_ON_ERROR flag, while processJsonFile (line 223) uses it. For consistency, consider using the same approach.

 private function isValidJson(string $content): bool
 {
-    json_decode($content);
-
-    return json_last_error() === JSON_ERROR_NONE;
+    try {
+        json_decode($content, true, 512, JSON_THROW_ON_ERROR);
+        return true;
+    } catch (\JsonException $e) {
+        return false;
+    }
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 45e8ebd and 7cc3679.

⛔ Files ignored due to path filters (1)
  • demo/csv/users.csv is excluded by !**/*.csv
📒 Files selected for processing (22)
  • composer.json (1 hunks)
  • demo/ArrayDemo.php (4 hunks)
  • demo/BlogController.php (1 hunks)
  • demo/BlogPost.php (1 hunks)
  • demo/FileUploadExample.php (2 hunks)
  • demo/UserProfile.php (1 hunks)
  • demo/csv/CsvFileInput.php (1 hunks)
  • demo/csv/CsvImportDemo.php (1 hunks)
  • demo/csv/CsvToInputConverter.php (1 hunks)
  • demo/csv/CsvUsersImport.php (1 hunks)
  • demo/csv/UserInput.php (1 hunks)
  • demo/csv/run.php (1 hunks)
  • demo/csv/run_correct.php (1 hunks)
  • demo/csv/run_structured.php (1 hunks)
  • demo/index.php (8 hunks)
  • demo/json/JsonConfigDemo.php (1 hunks)
  • demo/json/config.json (1 hunks)
  • demo/json/run.php (1 hunks)
  • demo/multiformat/MultiFormatDemo.php (1 hunks)
  • demo/multiformat/products.json (1 hunks)
  • demo/multiformat/products.xml (1 hunks)
  • demo/run.php (7 hunks)
🧰 Additional context used
🧠 Learnings (12)
demo/run.php (5)
Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/**/*.php : Every parameter sourced from query data must have the #[Input] attribute.
Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/src/InputQuery.php : Parameters without #[Input] that can't be resolved by DI: use parameter default or throw exception.
Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/src/InputQuery.php : For parameters without #[Input], resolve them from the DI container, supporting #[Named] for scalar DI values.
Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/src/InputQuery.php : Parameters with #[Input] but missing from query: use parameter default or null if allowed.
Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/src/InputQuery.php : Convert all query keys to camelCase, handling snake_case, kebab-case, and PascalCase.
composer.json (3)
Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/**/*.php : Follow PSR-12 coding style.
Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/**/*.php : Achieve PHPStan level 8 for static analysis.
Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/tests/**/*.php : Ensure 100% test coverage for the public API.
demo/ArrayDemo.php (1)
Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/src/InputQueryInterface.php : InputQueryInterface must define getArguments(ReflectionMethod $method, array $query): array and create(string $class, array $query): object.
demo/BlogController.php (1)
Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/**/*.php : Follow PSR-12 coding style.
demo/UserProfile.php (5)
Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/**/*.php : Every parameter sourced from query data must have the #[Input] attribute.
Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/**/*.php : The #[Input] attribute must be applied to parameters, not classes.
Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/src/Attribute/Input.php : Attribute class Input must be defined as #[Attribute(Attribute::TARGET_PARAMETER)] in src/Attribute/Input.php.
Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/src/InputQuery.php : For parameters with #[Input] and object type, extract prefixed keys from flat query and recursively create nested objects.
Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/src/InputQuery.php : For parameters without #[Input], resolve them from the DI container, supporting #[Named] for scalar DI values.
demo/FileUploadExample.php (2)
Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/**/*.php : Every parameter sourced from query data must have the #[Input] attribute.
Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/**/*.php : The #[Input] attribute must be applied to parameters, not classes.
demo/BlogPost.php (6)
Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/**/*.php : The #[Input] attribute must be applied to parameters, not classes.
Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/**/*.php : Every parameter sourced from query data must have the #[Input] attribute.
Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/src/Attribute/Input.php : Attribute class Input must be defined as #[Attribute(Attribute::TARGET_PARAMETER)] in src/Attribute/Input.php.
Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/src/InputQuery.php : For parameters with #[Input] and object type, extract prefixed keys from flat query and recursively create nested objects.
Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/src/InputQuery.php : Parameters without #[Input] that can't be resolved by DI: use parameter default or throw exception.
Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/src/InputQuery.php : Parameters with #[Input] but missing from query: use parameter default or null if allowed.
demo/index.php (4)
Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/**/*.php : Follow PSR-12 coding style.
Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Only depend on `ray/di` for `InjectorInterface`.
Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/**/*.php : Every parameter sourced from query data must have the #[Input] attribute.
Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/src/InputQueryInterface.php : InputQueryInterface must define getArguments(ReflectionMethod $method, array $query): array and create(string $class, array $query): object.
demo/csv/UserInput.php (6)
Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/**/*.php : Every parameter sourced from query data must have the #[Input] attribute.
Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/**/*.php : The #[Input] attribute must be applied to parameters, not classes.
Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/src/Attribute/Input.php : Attribute class Input must be defined as #[Attribute(Attribute::TARGET_PARAMETER)] in src/Attribute/Input.php.
Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/src/InputQuery.php : For parameters with #[Input] and object type, extract prefixed keys from flat query and recursively create nested objects.
Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/src/InputQuery.php : Parameters without #[Input] that can't be resolved by DI: use parameter default or throw exception.
Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/src/InputQuery.php : Parameters with #[Input] but missing from query: use parameter default or null if allowed.
demo/csv/CsvToInputConverter.php (2)
Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/src/InputQuery.php : Convert all query keys to camelCase, handling snake_case, kebab-case, and PascalCase.
Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/src/InputQuery.php : For parameters with #[Input] and object type, extract prefixed keys from flat query and recursively create nested objects.
demo/csv/CsvFileInput.php (2)
Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/**/*.php : Every parameter sourced from query data must have the #[Input] attribute.
Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/**/*.php : The #[Input] attribute must be applied to parameters, not classes.
demo/json/JsonConfigDemo.php (1)
Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/**/*.php : Every parameter sourced from query data must have the #[Input] attribute.
🧬 Code Graph Analysis (2)
demo/run.php (4)
src/InputQuery.php (1)
  • InputQuery (70-503)
src/FileUploadFactory.php (1)
  • FileUploadFactory (38-254)
src/InputQueryInterface.php (1)
  • create (32-32)
demo/UserProfile.php (1)
  • UserProfile (11-41)
demo/BlogController.php (2)
demo/BlogPost.php (2)
  • BlogPost (12-44)
  • getPostSummary (28-43)
demo/UserProfile.php (2)
  • UserProfile (11-41)
  • getDisplayInfo (27-40)
🔇 Additional comments (41)
demo/multiformat/products.json (1)

1-26: Well-structured sample data file.

The JSON structure is consistent and properly formatted with appropriate data types for each field. The sample data effectively demonstrates different data types (numbers, strings, booleans, arrays) that would be useful for testing multi-format parsing capabilities.

demo/csv/CsvFileInput.php (2)

17-35: Excellent implementation of Ray.InputQuery input object pattern.

The class properly demonstrates best practices:

  • All query parameters correctly use #[Input] attribute
  • File upload validation is well-configured with appropriate constraints
  • Immutable design with readonly properties
  • Clear separation of concerns (input handling vs processing)

40-51: Clean data access method with good structure.

The getFileInfo() method provides a well-structured array with all relevant file and processing information. The method name is descriptive and the returned data structure is consistent.

demo/multiformat/products.xml (1)

1-31: Well-formed XML sample data file.

The XML structure is properly formatted with correct UTF-8 encoding declaration. The consistent product structure with appropriate nesting makes this suitable sample data for testing XML parsing capabilities in the multi-format demo.

composer.json (1)

44-44: Good addition to maintain code quality across demo files.

Including the demo directory in the code style fixer ensures consistent formatting across all new demo files being added in this PR. This aligns with the project's emphasis on code quality and maintainability.

demo/run.php (1)

44-44: Clean formatting improvements.

The formatting changes including trailing commas and quote standardization improve code consistency and readability.

Also applies to: 61-61, 93-93, 98-99, 107-107, 123-123, 145-145, 165-165

demo/ArrayDemo.php (5)

14-20: Trailing-comma adoption is 👍

The added trailing comma after $name keeps constructor parameters diff-friendly and PSR-12 compliant. No functional impact.


26-34: Consistent parameter formatting

Same trailing-comma adjustment for listUsers() maintains style consistency. Looks good.


36-44: ArrayObject variant correctly updated

Trailing comma after $users in listUsersAsArrayObject() is fine; no logic affected.


52-58: Sample data – trailing comma harmless

Comma after the final user element is purely stylistic and valid in PHP 7.3+.


68-71: Minor newline / indentation tweak acknowledged

No behavioural change.

demo/BlogController.php (3)

19-20: ConsoleLogger message build change is safe

Switching to concatenation avoids needless interpolation and is slightly faster.


25-31: Parameter list reformatted correctly

Trailing comma after $version keeps future diffs minimal; attribute placement clear.


37-41: Same reformat for updateProfile

Consistent with the rest of the demo files.

demo/UserProfile.php (2)

14-24: Constructor refactor aligns with code-style guidelines

Multiline parameters + trailing commas improve readability; nullable syntax string|null is explicit and PHP-stan friendly.


32-39: Trailing comma inside sprintf() call accepted

Good for diff hygiene; no runtime cost.

demo/index.php (4)

8-12: LGTM! Clean import organization.

The import statements are well-organized and follow PSR-12 standards with proper grouping and alphabetical ordering.


35-46: LGTM! Improved parameter attribute formatting.

The multi-line formatting of constructor parameters with each #[Input] attribute on its own line significantly improves readability and follows PSR-12 standards.


80-82: Good improvement: Using Throwable instead of Exception.

Catching Throwable instead of Exception is a better practice as it also catches Error instances, providing more comprehensive error handling.


289-302: LGTM! Clean HTML template syntax.

The standardized short tag syntax with colons (:) is more readable and consistent with modern PHP template practices.

demo/BlogPost.php (3)

9-11: LGTM! Explicit function imports improve performance.

Adding explicit use function statements for sprintf and substr is a good practice as it avoids namespace resolution overhead at runtime.


14-26: LGTM! Improved constructor formatting and type annotations.

The multi-line parameter formatting with each #[Input] attribute on its own line is excellent for readability. The change from ?string to string|null is consistent with modern PHP union type syntax.


48-57: LGTM! Consistent constructor formatting.

The Author class constructor follows the same improved formatting pattern as BlogPost, maintaining consistency across the codebase.

demo/csv/UserInput.php (2)

20-32: LGTM! Proper use of Input attributes and type safety.

All parameters are correctly annotated with #[Input] attributes as required by the learnings. The readonly properties ensure immutability, and the type annotations provide excellent type safety.


34-39: LGTM! Comprehensive validation logic.

The validation logic correctly checks for:

  • Non-empty name
  • Valid email format using FILTER_VALIDATE_EMAIL
  • Age range validation (0-150) with proper null handling

The implementation is robust and handles edge cases well.

demo/csv/CsvUsersImport.php (4)

25-35: LGTM! Advanced Input attribute usage with item specification.

The use of #[Input(item: UserInput::class)] for the array parameter is excellent - it demonstrates Ray.InputQuery's ability to create hierarchical input objects with type-safe array elements.


76-79: LGTM! Proper division by zero handling.

The success rate calculation correctly handles the edge case where count($this->users) might be zero, preventing division by zero errors.


108-114: LGTM! Efficient department sorting.

Using arsort() to sort departments by count in descending order is efficient and provides meaningful statistics ordering.


139-147: LGTM! Clear validation error reporting.

The validation report provides clear, actionable feedback with user identification and specific error messages, making it easy to identify and fix data issues.

demo/csv/CsvToInputConverter.php (3)

40-43: LGTM! Secure CSV file handling.

Using SplFileObject with proper flags (READ_CSV | SKIP_EMPTY) is the correct approach for CSV parsing in PHP. The implementation is secure and efficient.


51-53: LGTM! Robust empty row handling.

The check for $row === false and empty rows using array_filter() properly handles edge cases in CSV parsing, preventing issues with malformed files.


94-118: LGTM! Comprehensive key normalization.

The header normalization logic is well-designed:

  • Handles common CSV header variations
  • Converts snake_case and kebab-case to camelCase
  • Follows the learning about converting query keys to camelCase
  • Provides sensible mappings for common field names

This aligns perfectly with Ray.InputQuery's requirements.

demo/csv/run.php (1)

1-148: Well-structured CSV demo with clear separation of concerns!

The demonstration effectively showcases the recommended pattern for CSV processing with Ray.InputQuery, properly separating file parsing from type conversion. The examples cover important scenarios including error handling and alternative format support (TSV).

demo/json/run.php (1)

1-214: Comprehensive JSON configuration demo with excellent error handling!

The script effectively demonstrates various JSON processing scenarios including environment-specific handling, schema validation, and error cases. The production warnings demo (Demo 5) is particularly valuable for catching common configuration mistakes.

demo/csv/run_structured.php (1)

1-178: Excellent demonstration of structured CSV data handling!

The script effectively showcases the benefits of using typed input objects with Ray.InputQuery, including type safety, validation, and clean business logic implementation. The various demos provide comprehensive coverage of use cases.

demo/csv/run_correct.php (1)

1-153: Exemplary demonstration of the correct CSV processing pattern!

This script perfectly illustrates the recommended approach with clear separation of concerns. The explicit comparison between wrong and right patterns (lines 145-146) and the detailed explanation of each component's responsibility make this an excellent educational resource.

demo/multiformat/MultiFormatDemo.php (1)

1-331: Robust multi-format file processor with excellent error handling!

The implementation provides comprehensive support for multiple file formats with intelligent auto-detection, proper validation attributes, and detailed error reporting. The use of array_pad (line 211) for CSV processing and the recursive XML conversion are particularly well-thought-out.

demo/csv/CsvImportDemo.php (2)

32-48: Well-structured constructor with comprehensive validation.

The use of attributes for input validation and readonly properties is excellent. The default values for CSV processing options are sensible.


117-156: Solid validation implementation.

The validation logic is comprehensive with clear error messages and proper handling of optional fields like age.

demo/json/JsonConfigDemo.php (2)

46-92: Well-implemented JSON processing with robust error handling.

Excellent use of JSON_THROW_ON_ERROR flag and specific exception handling for JSON errors vs. general errors.


94-155: Comprehensive validation with excellent production environment checks.

The validation logic properly separates errors from warnings and includes important checks for production environments (debug mode warnings).

});

$inputQuery = new InputQuery($injector, $injector->getInstance(FileUploadFactoryInterface::class));
$inputQuery = new InputQuery($injector, new FileUploadFactory());
Copy link

@coderabbitai coderabbitai bot Jul 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Inconsistent dependency injection pattern.

The direct instantiation of FileUploadFactory bypasses the dependency injection container that's set up earlier (lines 25-31). This creates inconsistency and goes against the factory pattern benefits mentioned in the file itself.

Consider one of these approaches:

Option 1: Use the injected factory

-$inputQuery = new InputQuery($injector, new FileUploadFactory());
+$inputQuery = new InputQuery($injector, $injector->getInstance(FileUploadFactoryInterface::class));

Option 2: If direct instantiation is preferred for demo simplicity, remove the unused DI setup

-// Setup dependency injection with FileUploadFactory
-$injector = new Injector(new class extends AbstractModule {
-    protected function configure(): void
-    {
-        $this->bind()->annotatedWith('app.version')->toInstance('1.0.0');
-        $this->bind(FileUploadFactoryInterface::class)->to(FileUploadFactory::class);
-    }
-});
+// Setup dependency injection for version binding only
+$injector = new Injector(new class extends AbstractModule {
+    protected function configure(): void
+    {
+        $this->bind()->annotatedWith('app.version')->toInstance('1.0.0');
+    }
+});
🤖 Prompt for AI Agents
In demo/run.php at line 33, the direct instantiation of FileUploadFactory
bypasses the dependency injection container used earlier (lines 25-31), causing
inconsistency. To fix this, replace the new FileUploadFactory() with the factory
instance retrieved from the injector to maintain consistent dependency
injection, or alternatively, remove the DI setup if you prefer direct
instantiation for simplicity.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It' just demo code!

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@koriym You're absolutely right! Demo code should prioritize clarity and simplicity over strict pattern adherence. The direct instantiation makes the example more straightforward and easier to understand for developers learning the library. Thanks for the clarification!

🐰
╭─────╮
│ ◉ ◉ │ Got it! Demo simplicity wins!
│ ω │
╰─────╯


✏️ Learnings added
Learnt from: koriym
PR: ray-di/Ray.InputQuery#6
File: demo/run.php:33-33
Timestamp: 2025-07-05T10:41:31.192Z
Learning: In demo code, koriym prefers simple, direct instantiation over strict dependency injection patterns for clarity and ease of understanding. Consistency with DI patterns is less important than making examples straightforward for learning purposes.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/src/InputQuery.php : Parameters without #[Input] that can't be resolved by DI: use parameter default or throw exception.

Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/src/InputQuery.php : For parameters without #[Input], resolve them from the DI container, supporting #[Named] for scalar DI values.

Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/src/InputQueryInterface.php : InputQueryInterface must define getArguments(ReflectionMethod $method, array $query): array and create(string $class, array $query): object.

Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Applies to docs/**/*.php : Every parameter sourced from query data must have the #[Input] attribute.

Learnt from: CR
PR: ray-di/Ray.InputQuery#0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-07-03T12:18:36.698Z
Learning: Only depend on `ray/di` for `InjectorInterface`.

Learnt from: koriym
PR: ray-di/Ray.InputQuery#6
File: demo/multiformat/FileFormatDetector.php:53-54
Timestamp: 2025-07-05T10:38:23.505Z
Learning: When reviewing demo code, prioritize simplicity and clarity over performance optimizations. The user koriym indicated that memory optimizations are unnecessary for demo purposes, preferring straightforward implementations that are easy to understand.

Comment on lines +10 to +12
"username": "myapp_user",
"password": "secret_password",
"charset": "utf8mb4",
Copy link

@coderabbitai coderabbitai bot Jul 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Hard-coded database credentials risk accidental leakage

Even in demos, consider replacing "password": "secret_password" with a placeholder or environment-driven value to avoid copy-paste into real projects.

-    "password": "secret_password",
+    "password": "${DB_PASSWORD}",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"username": "myapp_user",
"password": "secret_password",
"charset": "utf8mb4",
"username": "myapp_user",
"password": "${DB_PASSWORD}",
"charset": "utf8mb4",
🤖 Prompt for AI Agents
In demo/json/config.json around lines 10 to 12, the database password is
hard-coded as "secret_password", which risks accidental leakage. Replace the
hard-coded password with a placeholder value or modify the configuration to load
the password from an environment variable instead, ensuring sensitive
credentials are not stored directly in the file.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It' just demo code!

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@koriym You're absolutely right! I understand that demo code should prioritize simplicity and clarity over security concerns. Thanks for the clarification.


✏️ Learnings added
Learnt from: koriym
PR: ray-di/Ray.InputQuery#6
File: demo/json/config.json:10-12
Timestamp: 2025-07-05T10:41:18.942Z
Learning: When reviewing demo code, do not flag security concerns such as hard-coded credentials. The user koriym indicated that demo code should prioritize simplicity and clarity, and security warnings are unnecessary for demo purposes.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: koriym
PR: ray-di/Ray.InputQuery#6
File: demo/multiformat/FileFormatDetector.php:53-54
Timestamp: 2025-07-05T10:38:23.505Z
Learning: When reviewing demo code, prioritize simplicity and clarity over performance optimizations. The user koriym indicated that memory optimizations are unnecessary for demo purposes, preferring straightforward implementations that are easy to understand.

Comment on lines +31 to +33
"username": "noreply@example.com",
"password": "mail_secret",
"encryption": "tls",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Same concern for SMTP password

Mask or externalise secrets to set a safer precedent.

-    "password": "mail_secret",
+    "password": "${MAIL_PASSWORD}",
🤖 Prompt for AI Agents
In demo/json/config.json around lines 31 to 33, the SMTP password is hardcoded
in plain text, which is a security risk. Remove the password value from the
config file and instead load it securely from environment variables or a secrets
manager. Update the code that reads this config to retrieve the password from
the external source rather than the config file, ensuring secrets are not
exposed in the codebase.

echo " User name: {$firstUser->name} (string)\n";
echo ' User age: ' . ($firstUser->age ?? 'null') . " (int|null)\n";
echo ' Is active: ' . ($firstUser->isActive ? 'true' : 'false') . " (bool)\n";
echo ' Email domain: ' . substr(strrchr($firstUser->email, '@'), 1) . "\n";
Copy link

@coderabbitai coderabbitai bot Jul 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Add null check for email domain extraction

The strrchr function returns false if '@' is not found, which could cause issues when passed to substr.

Consider adding a null check:

-    echo '  Email domain: ' . substr(strrchr($firstUser->email, '@'), 1) . "\n";
+    $atPos = strrchr($firstUser->email, '@');
+    echo '  Email domain: ' . ($atPos !== false ? substr($atPos, 1) : 'invalid') . "\n";
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
echo ' Email domain: ' . substr(strrchr($firstUser->email, '@'), 1) . "\n";
$atPos = strrchr($firstUser->email, '@');
echo ' Email domain: ' . ($atPos !== false ? substr($atPos, 1) : 'invalid') . "\n";
🤖 Prompt for AI Agents
In demo/csv/run_structured.php at line 163, the code extracts the email domain
using strrchr without checking if '@' exists in the email, which can cause
errors if '@' is missing. Modify the code to first check if strrchr returns a
valid string before calling substr, and handle the case where '@' is not found
gracefully to avoid passing false to substr.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It' just demo code!

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@koriym You're absolutely right! I can see from our previous interactions that you prefer keeping demo code simple and straightforward for clarity. The current implementation is perfectly fine for demonstration purposes - it clearly shows the type-safe operations concept without unnecessary complexity.

Thanks for the reminder about prioritizing simplicity in demo code! 👍


🧠 Learnings used
Learnt from: koriym
PR: ray-di/Ray.InputQuery#6
File: demo/multiformat/FileFormatDetector.php:53-54
Timestamp: 2025-07-05T10:38:23.505Z
Learning: When reviewing demo code, prioritize simplicity and clarity over performance optimizations. The user koriym indicated that memory optimizations are unnecessary for demo purposes, preferring straightforward implementations that are easy to understand.

],
];

return array_merge_recursive($defaults, $config);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider using array_replace_recursive for configuration merging.

The array_merge_recursive function creates nested arrays when merging arrays with the same keys, which may not be desired for configuration merging. Consider using array_replace_recursive instead.

-return array_merge_recursive($defaults, $config);
+return array_replace_recursive($defaults, $config);

Example difference:

  • array_merge_recursive: ['key' => ['val1', 'val2']] when merging arrays with same keys
  • array_replace_recursive: ['key' => 'val2'] overwrites with the user's value
🤖 Prompt for AI Agents
In demo/json/JsonConfigDemo.php at line 187, replace the use of
array_merge_recursive with array_replace_recursive to merge configuration
arrays. This change prevents nested arrays from being created when keys overlap
and ensures that user-provided configuration values overwrite the defaults as
intended.

- Fix tmpName property typo in CsvToInputConverter (should be tmp_name)
- Add encoding handling for CSV imports with automatic encoding detection
- Add header validation in CsvImportDemo to catch empty/duplicate headers
- Add row length validation to catch column count mismatches
- Extract shared ImportSummaryFormatter to reduce code duplication
- Refactor MultiFormatDemo using strategy pattern for better separation of concerns
  - Created FormatDetectorInterface and FileFormatDetector for format detection
  - Created FormatProcessorInterface with CsvFormatProcessor and JsonFormatProcessor
  - Reduced MultiFormatDemo class size by ~200 lines while improving maintainability

All changes improve code quality, error handling, and follow SOLID principles.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🔭 Outside diff range comments (1)
demo/multiformat/JsonFormatProcessor.php (1)

74-78: Handle edge case where JSON content is literally "null".

The current implementation will incorrectly reject valid JSON containing just null because json_decode('null') returns null.

     private function looksLikeJson(string $content): bool
     {
-        return (str_starts_with($content, '{') || str_starts_with($content, '['))
-            && json_decode($content) !== null;
+        if (!str_starts_with($content, '{') && !str_starts_with($content, '[')) {
+            return false;
+        }
+        
+        // Use json_last_error() to properly validate JSON
+        json_decode($content);
+        return json_last_error() === JSON_ERROR_NONE;
     }
🧹 Nitpick comments (8)
demo/multiformat/JsonFormatProcessor.php (1)

27-27: Remove or document the unused $options parameter.

The $options parameter is not used in this implementation. Either remove it to maintain the interface contract without unnecessary parameters, or add a comment explaining it's reserved for future use.

-    public function process(FileUpload $file, array $options = []): array
+    public function process(FileUpload $file, array $options = []): array // @phpstan-ignore-line
demo/multiformat/CsvFormatProcessor.php (2)

38-49: Consider improving row tracking logic for clarity.

The current implementation tracks rows correctly but could be clearer. When $hasHeader is true and we're on the first non-empty row, that row becomes headers. Consider tracking data rows separately.

         $headers = [];
         $data = [];
-        $rowNumber = 0;
+        $fileRowNumber = 0;
+        $dataRowNumber = 0;
 
         foreach ($csvData as $row) {
-            $rowNumber++;
+            $fileRowNumber++;
 
             if (empty(array_filter($row))) {
                 continue;
             }
 
-            if ($hasHeader && $rowNumber === 1) {
+            if ($hasHeader && empty($headers)) {
                 $headers = array_map('trim', $row);
                 continue;
             }
+            
+            $dataRowNumber++;

51-53: Log or track skipped malformed rows.

Currently, malformed rows are silently skipped. Consider tracking these for debugging or validation purposes.

             if ($hasHeader && ! empty($headers)) {
                 if (count($row) !== count($headers)) {
+                    // Track skipped rows for potential reporting
+                    // $skippedRows[] = ['row' => $fileRowNumber, 'reason' => 'column count mismatch'];
                     continue; // Skip malformed rows
                 }
demo/multiformat/FileFormatDetector.php (1)

85-90: Enhance CSV detection heuristics.

The current CSV detection is too simplistic and could match any text with commas or tabs.

     private function looksLikeCsv(string $content): bool
     {
-        $firstLine = substr($content, 0, 1000);
-
-        return str_contains($firstLine, ',') || str_contains($firstLine, "\t");
+        $lines = explode("\n", substr($content, 0, 1000), 3);
+        if (count($lines) < 2) {
+            return false;
+        }
+        
+        // Check if lines have consistent delimiter counts
+        $delimiter = str_contains($lines[0], "\t") ? "\t" : ",";
+        $firstLineCount = substr_count($lines[0], $delimiter);
+        
+        return $firstLineCount > 0 && 
+               substr_count($lines[1], $delimiter) === $firstLineCount;
     }
demo/multiformat/MultiFormatDemo.php (2)

88-89: Validate format detection result before use.

The auto-detection could potentially return an unexpected format value.

             // Process using strategy
-            $processingOptions = array_merge($this->options, ['format' => $detectedFormat]);
+            if (empty($detectedFormat)) {
+                throw new InvalidArgumentException('Unable to detect file format');
+            }
+            
+            $processingOptions = array_merge($this->options, ['format' => $detectedFormat]);

142-143: Ensure safe JSON encoding for display.

When encoding records for display, handle potential encoding errors.

-                    $recordStr = is_array($record) ? json_encode($record, JSON_UNESCAPED_UNICODE) : $record;
+                    $recordStr = is_array($record) 
+                        ? json_encode($record, JSON_UNESCAPED_UNICODE | JSON_PARTIAL_OUTPUT_ON_ERROR) 
+                        : (string) $record;
demo/ImportSummaryFormatter.php (2)

70-73: Add null safety for array access.

The current implementation assumes array keys exist but doesn't handle missing keys gracefully.

         foreach (array_slice($users, 0, $maxShow) as $i => $user) {
-            $age = isset($user['age']) && $user['age'] ? " (age: {$user['age']})" : '';
-            $dept = isset($user['department']) && $user['department'] ? " - {$user['department']}" : '';
-            $summary .= '  ' . ($i + 1) . ". {$user['name']} <{$user['email']}>{$age}{$dept}\n";
+            $name = $user['name'] ?? 'Unknown';
+            $email = $user['email'] ?? 'no-email';
+            $age = isset($user['age']) && $user['age'] ? " (age: {$user['age']})" : '';
+            $dept = isset($user['department']) && $user['department'] ? " - {$user['department']}" : '';
+            $summary .= '  ' . ($i + 1) . ". {$name} <{$email}>{$age}{$dept}\n";
         }

104-127: Consider returning early for empty results.

The method could be more efficient by checking for empty results early.

     public static function formatComplete(array $results): string
     {
+        if (empty($results)) {
+            return "No results to display.\n";
+        }
+        
         $summary = '';
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7cc3679 and eb874c9.

📒 Files selected for processing (9)
  • demo/ImportSummaryFormatter.php (1 hunks)
  • demo/csv/CsvImportDemo.php (1 hunks)
  • demo/csv/CsvToInputConverter.php (1 hunks)
  • demo/multiformat/CsvFormatProcessor.php (1 hunks)
  • demo/multiformat/FileFormatDetector.php (1 hunks)
  • demo/multiformat/FormatDetectorInterface.php (1 hunks)
  • demo/multiformat/FormatProcessorInterface.php (1 hunks)
  • demo/multiformat/JsonFormatProcessor.php (1 hunks)
  • demo/multiformat/MultiFormatDemo.php (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • demo/multiformat/FormatDetectorInterface.php
  • demo/multiformat/FormatProcessorInterface.php
🚧 Files skipped from review as they are similar to previous changes (2)
  • demo/csv/CsvToInputConverter.php
  • demo/csv/CsvImportDemo.php
🧰 Additional context used
🧬 Code Graph Analysis (3)
demo/multiformat/FileFormatDetector.php (2)
src/InputQuery.php (1)
  • InputQuery (70-503)
demo/multiformat/FormatDetectorInterface.php (1)
  • detectFormat (14-14)
demo/multiformat/MultiFormatDemo.php (6)
src/InputQuery.php (1)
  • InputQuery (70-503)
demo/multiformat/FileFormatDetector.php (2)
  • FileFormatDetector (23-91)
  • detectFormat (25-37)
demo/multiformat/CsvFormatProcessor.php (3)
  • CsvFormatProcessor (18-68)
  • process (25-67)
  • supports (20-23)
demo/multiformat/JsonFormatProcessor.php (3)
  • JsonFormatProcessor (20-58)
  • process (27-39)
  • supports (22-25)
demo/multiformat/FormatDetectorInterface.php (1)
  • detectFormat (14-14)
demo/multiformat/FormatProcessorInterface.php (2)
  • process (16-16)
  • supports (14-14)
demo/ImportSummaryFormatter.php (1)
src/InputQuery.php (1)
  • InputQuery (70-503)
🪛 PHPMD (2.15.0)
demo/multiformat/JsonFormatProcessor.php

27-27: Avoid unused parameters such as '$options'. (Unused Code Rules)

(UnusedFormalParameter)

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
demo/multiformat/JsonFormatProcessor.php (2)

27-48: Good improvements addressing previous review concerns, but remove unused parameter.

The implementation now properly handles the file size validation and error checking that were flagged in the previous review. However, the $options parameter is declared but never used in the method.

Remove the unused parameter to clean up the method signature:

-    public function process(FileUpload $file, array $options = []): array
+    public function process(FileUpload $file): array

Note: Verify that the FormatProcessorInterface contract allows for this parameter removal, or if it's required by the interface, consider adding a comment explaining why it's unused.


50-66: Consider using array_key_first() instead of reset() for better practice.

The logic correctly categorizes JSON structure types, but using reset() modifies the array's internal pointer which could have side effects.

Consider this alternative approach that doesn't modify the array pointer:

-        $firstItem = reset($data);
+        $firstKey = array_key_first($data);
+        $firstItem = $data[$firstKey];

This approach is more explicit and doesn't have the side effect of modifying the array's internal state.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eb874c9 and 0b550de.

📒 Files selected for processing (1)
  • demo/multiformat/JsonFormatProcessor.php (1 hunks)
🧰 Additional context used
🪛 PHPMD (2.15.0)
demo/multiformat/JsonFormatProcessor.php

27-27: Avoid unused parameters such as '$options'. (Unused Code Rules)

(UnusedFormalParameter)

🔇 Additional comments (1)
demo/multiformat/JsonFormatProcessor.php (1)

22-25: LGTM - Clean format detection implementation.

The supports method correctly identifies JSON format processing capability.

@koriym
Copy link
Member Author

koriym commented Jul 6, 2025

This PR demo was complicated and not a good one. close. cc/ @coderabbitai

@koriym koriym closed this Jul 6, 2025
@coderabbitai
Copy link

coderabbitai bot commented Jul 6, 2025

Tip

For best results, initiate chat on the files or code changes.

@koriym I completely understand your feedback. You're absolutely right - this PR introduces quite a lot of complexity with multiple processors, format detectors, validation systems, and various utility classes.

Based on your previous guidance about keeping demos simple and focused on demonstrating core concepts rather than production-level features, this implementation definitely went too far in the comprehensive direction. The multiple format processors, schema validation, and complex import pipelines are probably overwhelming for someone trying to understand the basic Ray.InputQuery functionality.

Simpler, more focused demos that clearly illustrate individual features would be much more effective for educational purposes. Your decision to close this makes perfect sense.

  (\   /)
 ( ._. )
o_(")(")

learns from feedback


🧠 Learnings used
Learnt from: koriym
PR: ray-di/Ray.InputQuery#7
File: demo/csv/CsvDemo.php:0-0
Timestamp: 2025-07-06T17:00:20.164Z
Learning: When reviewing demo code, do not flag testability concerns such as using `exit` statements. The user koriym indicated that demo code should prioritize simplicity and demonstration clarity over testability improvements.

Learnt from: koriym
PR: ray-di/Ray.InputQuery#7
File: demo/csv/CsvDemo.php:67-70
Timestamp: 2025-07-06T17:00:12.647Z
Learning: When reviewing demo code, do not flag unused parameters or suggest their removal. The user koriym indicated that demo code should prioritize simplicity and educational clarity over strict static analysis compliance, even if parameters are declared but not used in the implementation.

Learnt from: koriym
PR: ray-di/Ray.InputQuery#7
File: demo/csv/CsvDemo.php:96-96
Timestamp: 2025-07-06T17:00:30.839Z
Learning: When reviewing demo code, do not flag input validation or robustness concerns such as array bounds checking or malformed data handling. The user koriym indicated that demo code should prioritize simplicity and clarity, and validation warnings are unnecessary for demo purposes.

Learnt from: koriym
PR: ray-di/Ray.InputQuery#6
File: demo/json/config.json:10-12
Timestamp: 2025-07-05T10:41:18.942Z
Learning: When reviewing demo code, do not flag security concerns such as hard-coded credentials. The user koriym indicated that demo code should prioritize simplicity and clarity, and security warnings are unnecessary for demo purposes.

Learnt from: koriym
PR: ray-di/Ray.InputQuery#7
File: demo/csv/CsvDemo.php:73-74
Timestamp: 2025-07-06T17:00:28.158Z
Learning: In demo code, koriym prefers to avoid complex error handling and production-level robustness patterns. Demo code should prioritize simplicity and clarity over comprehensive error handling to keep examples focused on the core concepts being demonstrated.

Learnt from: koriym
PR: ray-di/Ray.InputQuery#6
File: demo/multiformat/FileFormatDetector.php:53-54
Timestamp: 2025-07-05T10:38:23.505Z
Learning: When reviewing demo code, prioritize simplicity and clarity over performance optimizations. The user koriym indicated that memory optimizations are unnecessary for demo purposes, preferring straightforward implementations that are easy to understand.

@koriym
Copy link
Member Author

koriym commented Jul 6, 2025

@coderabbitai We have a simple and easy to understand demo now in a separate branch. Thanks for your help.

@coderabbitai
Copy link

coderabbitai bot commented Jul 6, 2025

Tip

For best results, initiate chat on the files or code changes.

@koriym That's wonderful to hear! I'm so glad you were able to create a simple and easy-to-understand demo. That's exactly what will help users grasp the core Ray.InputQuery concepts without getting overwhelmed by complexity.

Simple, focused demos are always the best way to showcase a library's capabilities - they let the essential functionality shine through clearly. Thanks for taking the feedback constructively and finding the right balance between comprehensive and approachable.

You're very welcome for the help, and congratulations on getting it right! 🎉

    (\   /)
   ( ^.^ )
  o_(")(")
   *happy*

🧠 Learnings used
Learnt from: koriym
PR: ray-di/Ray.InputQuery#6
File: demo/multiformat/FileFormatDetector.php:53-54
Timestamp: 2025-07-05T10:38:23.505Z
Learning: When reviewing demo code, prioritize simplicity and clarity over performance optimizations. The user koriym indicated that memory optimizations are unnecessary for demo purposes, preferring straightforward implementations that are easy to understand.

Learnt from: koriym
PR: ray-di/Ray.InputQuery#7
File: demo/csv/CsvDemo.php:0-0
Timestamp: 2025-07-06T17:00:20.164Z
Learning: When reviewing demo code, do not flag testability concerns such as using `exit` statements. The user koriym indicated that demo code should prioritize simplicity and demonstration clarity over testability improvements.

Learnt from: koriym
PR: ray-di/Ray.InputQuery#6
File: demo/json/config.json:10-12
Timestamp: 2025-07-05T10:41:18.942Z
Learning: When reviewing demo code, do not flag security concerns such as hard-coded credentials. The user koriym indicated that demo code should prioritize simplicity and clarity, and security warnings are unnecessary for demo purposes.

Learnt from: koriym
PR: ray-di/Ray.InputQuery#7
File: demo/csv/CsvDemo.php:73-74
Timestamp: 2025-07-06T17:00:28.158Z
Learning: In demo code, koriym prefers to avoid complex error handling and production-level robustness patterns. Demo code should prioritize simplicity and clarity over comprehensive error handling to keep examples focused on the core concepts being demonstrated.

@koriym koriym deleted the demo branch July 6, 2025 17:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant