jeffersongoncalves/flysystem-google-drive
A Flysystem adapter for Google Drive, letting you read, write, list, and delete files on Google Drive through Laravel's familiar Storage API. Drop it in as a disk driver to sync uploads and backups without changing your existing filesystem code.
composer require the package; the service provider and google driver are auto-discovered, so no manual Storage::extend() wiring is needed.// config/filesystems.php
'google' => [
'driver' => 'google',
// credentials: service account JSON *or* OAuth client + refresh token
// root/folder id for the base folder
],
Check the package's config/ file for the exact key names before publishing — the adapter is zero-config only in the sense that the driver is registered for you, credentials still have to be supplied.
Storage facade — Storage::disk('google')->put('backups/db.sql.gz', $stream).Storage::disk('google') — put, putFileAs, get, readStream, files, delete, move. Don't call the Google client directly unless you need Drive-specific features (permissions, shared drives); mixing the two is where ID/path confusion starts.google-backups, google-media, google-tenant-{id}) rather than juggling prefixes. For multi-tenant, build configuration at runtime with Storage::build([...]) or config([...]) before the first call, and cache the resolved disk per tenant.put with a stream (or putFileAs for uploads) avoids loading whole files into memory; Drive uploads are chunked internally and the adapter handles the transfer.Storage::disk('google')->putFileAs('media', $request->file('upload'), $name) — but do it in a queued job for anything sizeable, because the request now depends on Google's latency and quota.allFiles() walks folder by folder with a paginated API call each time. Prefer shallow listings plus known paths, cache directory listings briefly, and never call files() inside a loop over files.Storage::url() is not usable. Stream through a controller: return response()->streamDownload(fn () => $disk->readStream($path), $name); with your own authorization in front.config/backup.php and let the scheduler run; keep the retention/cleanup step (backup:clean) since trashed files still count against quota.Storage::fake('google') does not intercept this driver — it swaps a local disk under the same name only if the name is fake-able. Set filesystems.disks.google.driver = local (or inject a Filesystem interface) in phpunit.xml/TestCase, and keep real-Drive tests as a small, explicitly tagged integration suite.report.pdf in the same folder can coexist, and path-based lookups may resolve to either. Enforce unique paths in your app layer.delete() no longer swallows API failures, so previously "successful" deletes may start throwing UnableToDeleteFile. Wrap destructive calls in try/catch and treat failures as real — if you migrated from the unmaintained alternative, audit every delete()/exists() call site, because silent-failure assumptions are now invalid.isReachable() is a health check, not an existence check. It no longer throws on a missing folder — use directoryExists() / fileExists() for that. A good pattern is a scheduled command that calls isReachable() per disk and alerts, plus exposing it via a health endpoint.fileExists() is an API round trip. Loops of exists() before put() will hit userRateLimitExceeded fast — check once per listing, or just overwrite. Handle 403 rate-limit errors with exponential backoff (retry() or a queued job with backoff) rather than immediate retries.drive.file scope the app only sees files it created — anything a human drops into the folder is invisible. Refresh tokens for apps left in "Testing" publishing status expire after ~7 days; publish the app or use a service account.visibility does not map to "anyone with the link"; there's no url() and no temporary URL support. Don't build features that assume it.php artisan config:cache (and clear it in deploys) — a stale cached config with an old refresh token produces confusing auth errors that look like API outages.reason like notFound, rateLimitExceeded, storageQuotaExceeded), and add Guzzle/Http middleware logging behind a debug flag. Check storage/logs/laravel.log before assuming the adapter is at fault.FilesystemAdapter to add retry/metrics, or add Flysystem plugins for convenience methods. Keep such subclasses thin so upstream fixes — like the query-escaping fix in this release — aren't lost.How can I help you explore Laravel packages today?