What's Changed
Add Flysystem v3 support and improve asset management
Breaking Changes
- Reworked asset storage from filesystem-root paths to named storage disks.
- Asset rows now store
storageplus a storage-relativepath; physical roots and public URL prefixes live inConfig\Asset::$storages. local_pathcan now benullfor remote disks such as S3, FTP, SFTP, Google Cloud Storage, Azure Blob Storage, WebDAV, memory, or any custom Flysystem adapter.- Public asset URLs now come from the configured storage disk
public_urlor Flysystem public URL support. Protected assets continue to go through AssetConnect routes and authorization. - Default generated paths changed to the shorter
{date}/{random-id}/{file-name}format.
Added
- Added configurable storage disks with
defaultPublicStorage,defaultProtectedStorage, and per-collectionsetStorage(). - Added
StorageManager,FlysystemStorageDisk, and storage-link support for exposing local public disks withphp spark asset-connect:storage-link. - Added support for official Flysystem adapters through driver-specific
setupStorage{Driver}()methods, including S3-style and other remote storage backends. - Added
asset-connect:migrate-pathsto normalize legacy rows into the newstorageplus relativepathmodel. - Added
Asset::transferToStorage()for moving or copying an existing asset between configured disks, including variants and database metadata updates. - Added
copyToTemporaryFile()andwithTemporaryFile()on assets and variants for queue-safe processing of files stored on remote disks. - Added internal asset metadata through
getInternalProperty(),setInternalProperty(), andgetInternalProperties()for backend-only state that should not be mixed with user custom properties. - Added path helper methods
getDate()andgetRandomId()for readable collision-resistant custom path generators.
Changed
- Asset persistence now writes through the configured storage disk instead of storing files directly against a physical base directory.
- Variants now retain their storage disk metadata, making transfers and remote storage workflows consistent for originals and generated files.
- The default path generator now produces shorter paths such as
2026-06-15/97847659691b3cae8857/photo.jpg. - Documentation was expanded for storage configuration, custom path generators, migration to 2.0.0, and remote-disk behavior.
Benefits
- Storage is portable across environments because database rows no longer contain absolute filesystem roots.
- Remote storage is first-class: applications can use S3-compatible services, CDN-backed disks, or any Flysystem adapter without changing asset entities.
- Public and protected asset handling is clearer because visibility and URL generation belong to the storage disk configuration.
- Existing assets can be moved between disks without changing their relative path or manually rewriting database rows.
- Backend processing metadata can be stored separately from user-visible custom properties.
- Generated file paths are shorter, cleaner, and still collision-resistant.
Upgrade Notes
- See the full upgrade guide: Upgrade from 1.0.2 to 2.0.0.
- Run the package migrations so the
storagecolumn exists. - Configure
Config\Asset::$storagesbefore using the new storage model. - Run
php spark asset-connect:migrate-paths --storage public --dry-runfirst, then rerun without--dry-runafter reviewing the plan. - For local public disks, run
php spark asset-connect:storage-linkor configure an equivalent web-server alias. - Update any code that assumes
local_pathis always available; remote disks should be handled through storage streams or disk APIs.
Full Changelog: v1.0.2...v2.0.0