Feature laravel13#90
Conversation
There was a problem hiding this comment.
Pull request overview
This PR upgrades the package for Laravel 13 / PHP 8.3+ and refactors the Cloudinary Flysystem adapter to better align with Flysystem v3 behavior (exceptions + attribute objects), while reorganizing and expanding the test suite.
Changes:
- Upgrade dependencies/tooling and CI to Laravel 13, PHP 8.3–8.5, Pest 4, Testbench 11, Larastan 3.9.
- Refactor
FlysystemCloudinaryAdapterby extracting responsibilities into focused classes (path normalization, disk options, URL building, list assembly, resource operations, metadata). - Update tests/docs to reflect Flysystem 3 semantics (iterable attributes from
listContents, proper Flysystem exceptions, integration-test gating).
Reviewed changes
Copilot reviewed 42 out of 42 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
src/FlysystemCloudinaryServiceProvider.php |
Resolve disk options from disk config and pass into adapter during Storage::extend. |
src/FlysystemCloudinaryAdapter.php |
Major refactor: extracted helpers, Flysystem v3 exception behavior, listContents() now returns attribute objects, added “last*” accessors. |
src/Concerns/InteractsWithCloudinaryMetadata.php |
Shared metadata retrieval logic for adapter/test doubles. |
src/CloudinaryUrlBuilder.php |
Centralizes delivery URL and explicit-URL selection (secure vs insecure). |
src/CloudinaryStringUploadSource.php |
Temporary-file helper for uploading string bodies to Cloudinary SDK. |
src/CloudinaryResponseMapper.php |
Normalizes Cloudinary responses and maps to FileAttributes. |
src/CloudinaryResponseLogger.php |
Dispatches the response-log event. |
src/CloudinaryResourceOperations.php |
Encapsulates explicit/destroy across resource types with logging. |
src/CloudinaryPathNormalizer.php |
Handles folder prefixing and logical path mapping. |
src/CloudinaryListResponseAssembler.php |
Builds shallow directory listings as FileAttributes/DirectoryAttributes. |
src/CloudinaryDiskOptions.php |
Merges published config + disk config + per-operation Flysystem config for upload options and URL preference. |
src/CloudinaryAdminFolderLocator.php |
Folder existence checks via Admin API pagination. |
tests/Pest.php |
Adds shared integration helper loading and sets up adapter for Feature/Adapter tests; groups Integration tests. |
tests/cloudinary_integration.php |
Skips live integration tests unless real Cloudinary env credentials are present. |
tests/Integration/CloudinaryTest.php |
Updates integration expectations for Flysystem v3 semantics (exceptions, stream return types, etc.). |
tests/Feature/FlysystemCloudinaryServiceProviderTest.php |
Ensures storage driver registration returns the Cloudinary adapter. |
tests/Feature/Adapter/UploadWriteTest.php |
Splits legacy adapter tests: write/update + string upload behavior. |
tests/Feature/Adapter/RenameCopyTest.php |
Covers rename/copy behavior, including folder-prefix behavior and exception cases. |
tests/Feature/Adapter/ReadListHasTest.php |
Covers has/readStream/listContents behaviors under Flysystem v3 expectations. |
tests/Feature/Adapter/DeleteDirectoryTest.php |
Covers delete/deleteDir/createDir and folder-prefix behavior. |
tests/Feature/Adapter/UrlTest.php |
Covers URL generation paths. |
tests/Feature/AdapterTest.php |
Removed monolithic feature test and replaced with focused Feature/Adapter test files. |
tests/Unit/InteractsWithCloudinaryMetadataTest.php |
Unit tests for metadata trait mapping + error wrapping. |
tests/Unit/FlysystemCloudinaryResponseLogTest.php |
Unit test for event payload. |
tests/Unit/CloudinaryUrlBuilderTest.php |
Unit tests for URL builder behavior (NotFound, secure-url preference, logging). |
tests/Unit/CloudinaryStringUploadSourceTest.php |
Unit tests for temp-file creation for string uploads. |
tests/Unit/CloudinaryResponseMapperTest.php |
Unit tests for normalization + attribute mapping + extra metadata extraction. |
tests/Unit/CloudinaryResponseLoggerTest.php |
Unit tests for event dispatch. |
tests/Unit/CloudinaryResourceOperationsTest.php |
Unit tests for resource-type iteration behavior + logging. |
tests/Unit/CloudinaryPathNormalizerTest.php |
Unit tests for prefixing/logical behavior. |
tests/Unit/CloudinaryListResponseAssemblerTest.php |
Unit tests for list assembly into attribute objects. |
tests/Unit/CloudinaryDiskOptionsTest.php |
Unit tests for option merge precedence. |
tests/Unit/CloudinaryAdminFolderLocatorTest.php |
Unit tests for folder pagination and edge cases. |
README.md |
Updates version matrix, config env var naming, and documents folder mode + integration test behavior. |
phpunit.xml.dist |
Switches default filesystem env key to FILESYSTEM_DISK and keeps Cloudinary placeholders. |
composer.json |
Laravel 13 + PHP 8.3+ constraints, tooling updates, scripts updated to Pest/PHPStan/Pint, adds branch-alias and changes stability. |
CHANGELOG.md |
Documents v13.0.0 changes and behavioral notes. |
.github/workflows/run-tests.yml |
Updates matrix to Laravel 13 / PHP 8.3–8.5 and runs Pest. |
.github/workflows/phpstan.yml |
Updates PHP version used for static analysis. |
.github/workflows/fix-php-code-style-issues.yml |
Switches formatting workflow to run Pint directly after installing deps. |
.github/workflows/composer-audit.yml |
Updates PHP version used for audit job. |
.github/ISSUE_TEMPLATE/bug_report.yml |
Updates PHP/Laravel placeholders to 8.5 / 13.0. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| $configurationProperty = new ReflectionProperty(Cloudinary::class, 'configuration'); | ||
| if ($configurationProperty->isInitialized($cloudinary)) { | ||
| Configuration::instance($cloudinary->configuration); | ||
| } | ||
| } |
There was a problem hiding this comment.
ReflectionProperty(Cloudinary::class, 'configuration') will throw a ReflectionException if the Cloudinary SDK changes internal property names (or removes the property). Since this is executed in the adapter constructor, it would hard-fail adapter instantiation. Consider guarding this with a try/catch around the reflection lookup (and/or checking property_exists), and only calling Configuration::instance(...) when the property both exists and is initialized.
| } | ||
| }, | ||
| "minimum-stability": "stable", | ||
| "minimum-stability": "dev", |
There was a problem hiding this comment.
Setting "minimum-stability": "dev" for the package increases the chance that CI/dev installs resolve to dev releases of dependencies (especially under prefer-lowest), which can make the test matrix flaky and harder to reproduce. Unless this is required for a specific dependency, consider keeping minimum-stability at stable and relying on explicit version constraints / @dev flags only where needed.
| "minimum-stability": "dev", | |
| "minimum-stability": "stable", |
| - name: Execute tests | ||
| run: cp phpunit.xml.dist phpunit.xml | ||
|
|
||
| - name: Execute tests | ||
| run: vendor/bin/pest | ||
| run: vendor/bin/pest --no-coverage |
There was a problem hiding this comment.
The workflow has two consecutive steps with the same name "Execute tests" (one copies phpunit.xml, the next runs Pest). Renaming the first to something like "Prepare phpunit.xml" makes CI logs clearer and avoids confusion when debugging failures.
| * | ||
| * @var array<string, mixed>|false | ||
| */ | ||
| public array|false $meta; |
There was a problem hiding this comment.
public array|false $meta; is a typed property without a default value and it’s not initialized in the constructor. Accessing $adapter->meta (or calling lastUploadMetadata()) before the first write will trigger a fatal "Typed property must not be accessed before initialization" error. Initialize it (e.g. default to false) in the property declaration and/or in the constructor.
| public array|false $meta; | |
| public array|false $meta = false; |
| $folders = []; | ||
| $response = null; | ||
| do { | ||
| $response = (array) $cloudinary->adminApi()->subFolders($needle, [ | ||
| 'max_results' => 500, | ||
| 'next_cursor' => $response['next_cursor'] ?? null, | ||
| ]); |
There was a problem hiding this comment.
$response starts as null, but the first loop iteration reads $response['next_cursor'] ?? null, which triggers a warning for array offset access on null in PHP 8+. Initializing $response to an empty array (or using a separate $nextCursor variable) avoids noisy warnings and prevents failures in environments that convert warnings to exceptions.
No description provided.