Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 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
134 changes: 134 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,16 @@ 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.
Expand Down Expand Up @@ -286,6 +296,130 @@ All query keys are normalized to camelCase:
- `user-name` → `userName`
- `UserName` → `userName`

## File Upload Integration

Ray.InputQuery supports file uploads through integration with [Koriym.FileUpload](https://github.com/koriym/Koriym.FileUpload):

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

```php
use Koriym\FileUpload\FileUpload;
use Koriym\FileUpload\ErrorFileUpload;

final class UserProfileInput
{
public function __construct(
#[Input] public readonly string $name,
#[Input] public readonly string $email,
#[Input] public readonly FileUpload|ErrorFileUpload $avatar, // Required avatar
#[Input] public readonly FileUpload|ErrorFileUpload|null $banner = null, // Optional banner
) {}
}

// Method usage example
class UserController
{
public function updateProfile(UserProfileInput $input): void
{
// Handle avatar upload
if ($input->avatar instanceof FileUpload) {
$avatarPath = $this->saveFile($input->avatar, 'avatars/');
$this->userService->updateAvatar($input->name, $avatarPath);
} elseif ($input->avatar instanceof ErrorFileUpload) {
throw new InvalidArgumentException($input->avatar->message);
}

// Handle optional banner
if ($input->banner instanceof FileUpload) {
$bannerPath = $this->saveFile($input->banner, 'banners/');
$this->userService->updateBanner($input->name, $bannerPath);
}
}
}
```

### 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:

```php
final class GalleryInput
{
/**
* @param list<FileUpload|ErrorFileUpload> $images
*/
public function __construct(
#[Input] public readonly string $title,
#[Input] 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:
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
Loading