Problem/Motivation
PHP instantiates stream wrapper classes itself, bypassing the DI container. FlysystemStreamWrapper handles that with a static factory reference primed by FlysystemStreamWrapper::primeStaticFactory(), which is documented as being called from FlysystemStreamWrapperManager::register() "at bootstrap (e.g. from hook_boot or a service subscriber)".
Nothing in the module ever calls register(). Grepping 3.0.0-beta2, the only caller of primeStaticFactory() is FlysystemStreamWrapperManager::register() itself, and register() has no callers at all — the schemes are registered as tagged stream_wrapper services through core's StreamWrapperManager instead, which never touches the static reference.
So any wrapper instance that PHP creates internally — every native call such as move_uploaded_file(), is_dir(), fopen() on a Flysystem URI made outside a container-built wrapper — has no factory and cannot resolve its filesystem. We hit this through FlysystemFileSystem::moveUploadedFile(), which calls move_uploaded_file() unconditionally: the upload silently fails to reach the object store.
Steps to reproduce
- Configure a Flysystem scheme and set it as the destination of a file field.
- Upload a file through the UI (goes through
FlysystemFileSystem::moveUploadedFile()→move_uploaded_file()→ PHP-instantiatedFlysystemStreamWrapper). - The internally instantiated wrapper has no factory available.
Proposed resolution
Prime the static factory in the FlysystemFileSystem constructor. file_system is the service every one of those native-function code paths is reached through, so priming there guarantees the reference exists before the first native call, without depending on a bootstrap hook that does not exist:
public function __construct( private readonly FilesystemFactoryInterface $factory, // ... ) { FlysystemStreamWrapper::primeStaticFactory($factory); }
Alternatives (either is fine, they are not exclusive):
- Call
FlysystemStreamWrapperManager::register()from a real bootstrap point (a service subscriber or hook_boot-equivalent), as its docblock intends. - Prime the static factory from the stream wrapper service factory so that it is set as soon as the container builds a wrapper.
Remaining tasks
- Review; decide where priming belongs (this patch takes the cheapest safe option).
- Kernel test: upload a file to a Flysystem-backed field and assert the object exists in the adapter.
User interface changes
None.
API changes
None.
Data model changes
None.
| Comment | File | Size | Author |
|---|---|---|---|
| flysystem-02-prime-static-factory.patch | 1.53 KB | luigisa |
Issue fork flysystem-3616485
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #4
lisa.rae commented@luigisa Turned your patch into a MR and added a test. Verified that test fails without the patch and passes with the patch. Please review and provide feedback. If acceptable, change status of the ticket to RTBC.
Comment #5
luigisa commentedPerfect. Thank you very much for your help.
Comment #7
lisa.rae commentedComment #9
lisa.rae commented