Skip to content
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
a1b5168
feat: Add file upload support with automatic $_FILES handling
koriym Jul 3, 2025
9be3db8
feat: Add file upload demo with clean method parameter approach
koriym Jul 3, 2025
bcfc7e3
docs: Add file upload integration section to README
koriym Jul 3, 2025
a21f2be
docs: Add comprehensive framework comparison
koriym Jul 3, 2025
fd463af
feat: Add Koriym.FileUpload as suggested dependency
koriym Jul 3, 2025
5c4f56b
docs: Add file upload integration design documentation
koriym Jul 3, 2025
83b6fdf
refactor: Clean up code formatting and improve import statements in I…
koriym Jul 3, 2025
a05cf94
fix: Resolve all static analysis errors in file upload handling
koriym Jul 3, 2025
2ceb721
feat: Enhance framework integration examples in documentation
koriym Jul 3, 2025
45d2766
refactor: Remove unused parameter and improve method consistency
koriym Jul 3, 2025
566aadc
feat: Add #[InputFile] attribute for file upload handling
koriym Jul 4, 2025
ecc28ee
feat: Implement hierarchical domain types for static analysis
koriym Jul 4, 2025
4afd99d
feat: Achieve 100% code coverage with strict FileUpload validation
koriym Jul 4, 2025
1ae1c14
refactor: Enhance domain types to eliminate generic array types
koriym Jul 4, 2025
5d73646
fix: Add FileUpload classes to composer-require-checker whitelist
koriym Jul 4, 2025
e853a3a
test: Achieve 100% code coverage through public interface tests only
koriym Jul 4, 2025
5de89cc
docs: Update documentation to reflect 100% coverage and InputFile att…
koriym Jul 4, 2025
23a272e
docs: Update demo to use consistent method invocation pattern
koriym Jul 4, 2025
70e3bad
docs: Add comprehensive framework integration guide
koriym Jul 4, 2025
5729f5a
Update README.md
koriym Jul 4, 2025
26f122f
docs: Fix bare URL formatting in README
koriym Jul 4, 2025
fa8f49c
docs: Reorder badge display and fix typo in README
koriym Jul 4, 2025
a1857be
feat: Implement allowedExtensions validation for file uploads
koriym Jul 4, 2025
e67c413
refactor: Extract FileUploadFactory following SRP and reduce complexity
koriym Jul 4, 2025
ef22cfe
feat: Achieve 100% code coverage and add comprehensive validations
koriym Jul 4, 2025
52596f4
fix: Separate PHP 8.2+ specific tests to avoid syntax errors
koriym Jul 4, 2025
1ba7131
revert: Remove PHP 8.2+ specific test due to compatibility issues
koriym Jul 4, 2025
0ad20dd
fix: Add coverage ignore for PHP 8.2+ specific code
koriym Jul 4, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion .claude/settings.local.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,14 @@
"Bash(./vendor/bin/phpunit:*)",
"Bash(./vendor/bin/phpmd:*)",
"Bash(vendor/bin/phpunit:*)",
"Bash(XDEBUG_MODE=coverage vendor/bin/phpunit --coverage-text --coverage-filter src/)"
"Bash(XDEBUG_MODE=coverage vendor/bin/phpunit --coverage-text --coverage-filter src/)",
"Bash(find:*)",
"mcp__ide__getDiagnostics",
"Bash(XDEBUG_MODE=coverage vendor/bin/phpunit --coverage-text --coverage-filter=src/)",
"Bash(XDEBUG_MODE=coverage vendor/bin/phpunit --coverage-text --coverage-filter=src/ --colors=never)",
"Bash(XDEBUG_MODE=coverage vendor/bin/phpunit --coverage-html coverage-report --coverage-filter=src/)",
"Bash(ls:*)",
"Bash(grep:*)"
],
"deny": []
}
Expand Down
163 changes: 157 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# Ray.InputQuery

Structured input objects from HTTP.
[![codecov](https://codecov.io/gh/ray-di/Ray.InputQuery/branch/main/graph/badge.svg)](https://codecov.io/gh/ray-di/Ray.InputQuery)
[![Type Coverage](https://shepherd.dev/github/ray-di/Ray.InputQuery/coverage.svg)](https://shepherd.dev/github/ray-di/Ray.InputQuery)
[![Continuous Integration](https://github.com/ray-di/Ray.InputQuery/actions/workflows/continuous-integration.yml/badge.svg)](https://github.com/ray-di/Ray.InputQuery/actions/workflows/continuous-integration.yml)

Structured input objects from HTTP with 100% test coverage.

## Overview

Expand Down Expand Up @@ -44,10 +48,28 @@ public function createTodo(TodoInput $input) {
composer require ray/input-query
```

## Demo

To see file upload integration in action:

```bash
php -S localhost:8080 -t demo/
```

Then visit http://localhost:8080 in your browser.

## Documentation

Comprehensive documentation including design philosophy, AI prompts for development assistance, and sample data examples can be found in the [docs/](docs/) directory.

### Framework Integration

For framework-specific integration examples, see the **[Framework Integration Guide](docs/framework_integration.md)** which covers:

- Laravel, Symfony, CakePHP, Yii Framework 1.x, BEAR.Sunday, and Slim Framework
- Three usage patterns (Reflection, Direct Object Creation, Spread Operator)
- Testing examples and best practices

## Usage

Ray.InputQuery converts flat query data into typed PHP objects automatically.
Expand Down Expand Up @@ -89,11 +111,11 @@ echo $user->email; // john@example.com
// Method argument resolution from $_POST
$method = new ReflectionMethod(UserController::class, 'register');
$args = $inputQuery->getArguments($method, $_POST);
$controller->register(...$args);
$result = $method->invokeArgs($controller, $args);

// Or with PSR-7 Request
// Or with PSR-7 Requestcom
$args = $inputQuery->getArguments($method, $request->getParsedBody());
$controller->register(...$args);
$result = $method->invokeArgs($controller, $args);
```

### Nested Objects
Expand Down Expand Up @@ -185,8 +207,8 @@ $data = [
]
];

$args = $inputQuery->getArguments($method, $data);
// $args[0] will be an array of UserInput objects
$result = $method->invokeArgs($controller, $inputQuery->getArguments($method, $data));
// Arguments automatically resolved as UserInput objects
```

#### Simple array values (e.g., checkboxes)
Expand Down Expand Up @@ -286,13 +308,142 @@ All query keys are normalized to camelCase:
- `user-name` → `userName`
- `UserName` → `userName`

## File Upload Integration

Ray.InputQuery provides comprehensive file upload support through integration with [Koriym.FileUpload](https://github.com/koriym/Koriym.FileUpload):

```bash
composer require koriym/file-upload
```

### Using #[InputFile] Attribute

For file uploads, use the dedicated `#[InputFile]` attribute which provides validation options:

```php
use Koriym\FileUpload\FileUpload;
use Koriym\FileUpload\ErrorFileUpload;
use Ray\InputQuery\Attribute\InputFile;

final class UserProfileInput
{
public function __construct(
#[Input] public readonly string $name,
#[Input] public readonly string $email,
#[InputFile(
maxSize: 5 * 1024 * 1024, // 5MB
allowedTypes: ['image/jpeg', 'image/png'],
allowedExtensions: ['jpg', 'jpeg', 'png']
)]
public readonly FileUpload|ErrorFileUpload $avatar,
#[InputFile] public readonly FileUpload|ErrorFileUpload|null $banner = null,
) {}
}

// Method usage example - Direct attribute approach
RE}
```

### Test-Friendly Design

File upload handling is designed to be test-friendly:

- **Production** - FileUpload library handles file uploads automatically
- **Testing** - Direct FileUpload object injection for easy mocking

```php
// Production usage - FileUpload library handles file uploads automatically
$input = $inputQuery->create(UserProfileInput::class, $_POST);
// FileUpload objects are created automatically from uploaded files

// Testing usage - inject mock FileUpload objects directly for easy testing
$mockAvatar = FileUpload::create([
'name' => 'test.jpg',
'type' => 'image/jpeg',
'size' => 1024,
'tmp_name' => '/tmp/test',
'error' => UPLOAD_ERR_OK,
]);

$input = $inputQuery->create(UserProfileInput::class, [
'name' => 'Test User',
'email' => 'test@example.com',
'avatar' => $mockAvatar,
'banner' => null
]);
```

### Multiple File Uploads

Support for multiple file uploads using array types with validation:

```php
final class GalleryInput
{
/**
* @param list<FileUpload|ErrorFileUpload> $images
*/
public function __construct(
#[Input] public readonly string $title,
#[InputFile(
maxSize: 10 * 1024 * 1024, // 10MB per file
allowedTypes: ['image/*']
)]
public readonly array $images,
) {}
}

// Method usage example
class GalleryController
{
public function createGallery(GalleryInput $input): void
{
$savedImages = [];
foreach ($input->images as $image) {
if ($image instanceof FileUpload) {
$savedImages[] = $this->saveFile($image, 'gallery/');
} elseif ($image instanceof ErrorFileUpload) {
// Log error but continue with other images
$this->logger->warning('Image upload failed: ' . $image->message);
}
}

$this->galleryService->create($input->title, $savedImages);
}
}

// Production usage - FileUpload library handles multiple files automatically
$input = $inputQuery->create(GalleryInput::class, $_POST);
// Array of FileUpload objects created automatically from uploaded files

// Testing usage - inject array of mock FileUpload objects for easy testing
$mockImages = [
FileUpload::create(['name' => 'image1.jpg', ...]),
FileUpload::create(['name' => 'image2.png', ...])
];

$input = $inputQuery->create(GalleryInput::class, [
'title' => 'My Gallery',
'images' => $mockImages
]);
```

## Integration

Ray.InputQuery is designed as a foundation library to be used by:

- [Ray.MediaQuery](https://github.com/ray-di/Ray.MediaQuery) - For database query integration
- [BEAR.Resource](https://github.com/bearsunday/BEAR.Resource) - For REST resource integration

## Project Quality

This project maintains high quality standards:

- **100% Code Coverage** - Achieved through public interface tests only
- **Static Analysis** - Psalm and PHPStan at maximum levels
- **Test Design** - No private method tests, ensuring maintainability
- **Type Safety** - Comprehensive Psalm type annotations

## Requirements

- PHP 8.1+
Expand Down
5 changes: 4 additions & 1 deletion composer-require-checker.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
{
"symbol-whitelist" : [],
"symbol-whitelist" : [
"Koriym\\FileUpload\\FileUpload",
"Koriym\\FileUpload\\ErrorFileUpload"
],
"php-core-extensions" : [
"Core",
"date",
Expand Down
6 changes: 5 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,13 @@
"php": "^8.1",
"ray/di": "^2.18"
},
"suggest": {
"koriym/file-upload": "For file upload handling integration"
},
"require-dev": {
"bamarni/composer-bin-plugin": "^1.8",
"phpunit/phpunit": "^10.5"
"phpunit/phpunit": "^10.5",
"koriym/file-upload": "^0.2.0"
},
"autoload": {
"psr-4": {
Expand Down
Loading