Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Gcloud Integration Bundle Laravel Package

softspring/gcloud-integration-bundle

A Symfony bundle for integrating Google Cloud services into your app. It provides configuration and service wiring for credentials, Google Cloud clients, and common resources, helping you connect storage, messaging, and other GCP APIs with less boilerplate.

View on GitHub
Deep Wiki
Context7

Getting Started

Before you install anything, understand what you're holding: this is a Symfony bundle, not a Laravel package. There is no ServiceProvider, no config/gcloud.php, no package auto-discovery. If your application is Laravel, you have two realistic paths:

  1. Port the wiring — read how the bundle constructs and configures the Google Cloud clients, then bind those same clients as singletons in a Laravel service provider. This is usually the right call. The bundle is thin glue over google/cloud-*; the SDK does the actual work.
  2. Install it anyway — only viable if you're building a hybrid/app-server setup. Expect Composer constraint pain (see Gotchas).

If you are in a Symfony app, the minimal path is:

composer require softspring/gcloud-integration-bundle

Register it in config/bundles.php (Flex recipes may do this for you):

return [
    // ...
    Softspring\GCloudIntegrationBundle\SoftspringGCloudIntegrationBundle::class => ['all' => true],
];

Then provide credentials out-of-band — never in the repo:

GOOGLE_APPLICATION_CREDENTIALS=/run/secrets/gcp-sa.json
GOOGLE_CLOUD_PROJECT=my-project-id

Where to look first, in this order:

  • src/DependencyInjection/Configuration.php — the authoritative list of config keys. Anything you read in the README may lag behind the code. This file is the source of truth.
  • src/DependencyInjection/SoftspringGCloudIntegrationExtension.php — shows exactly which parameters feed which service arguments.
  • src/Resources/config/services.yaml — the service IDs you'll inject. Copy these into your own config/services.yaml aliases.
  • tests/ — if there are functional tests, they're the fastest way to see a working end-to-end call.

First use case: upload a file to a bucket and hand back a time-limited URL. That exercises credentials, project config, the client wiring, and the most common production need (private objects) in one go. Write it as a console command first, not a controller — you'll iterate faster and you avoid the HTTP layer while you're validating IAM.

// config/services.yaml
services:
    Softspring\GCloudIntegrationBundle\Storage\StorageClientInterface:
        alias: softspring_gcloud.storage_client

Confirm the actual service ID from services.yaml before trusting the alias above — bundle service IDs are not stable API.

Implementation Patterns

Constructor injection, never container-pull. The bundle's value is that it hands you a pre-configured, credential-aware client. Let the container do its job:

final class ExportUserDataHandler
{
    public function __construct(
        private readonly StorageClientInterface $storage,
    ) {}

    public function __invoke(UserId $id): string
    {
        $objectName = sprintf('exports/%s/%s.csv', $id, bin2hex(random_bytes(8)));
        $this->storage->write($objectName, $this->renderCsv($id));

        return $this->storage->signedUrl($objectName, '+15 minutes');
    }
}

Depend on the bundle's interface, not the concrete class. That's what makes the whole thing testable — you can swap in an in-memory implementation for unit tests and the GCS emulator for integration tests.

Wrap it in Flysystem. Direct SDK calls leak pagination, retries, and stream handling into your domain code. A Flysystem adapter gives you put, readStream, temporaryUrl, and a disk abstraction that lets you switch to local storage in test environments. Laravel developers get this for free via Storage::disk('gcs'); in Symfony you wire it yourself, but the bundle supplies the authenticated client that the adapter needs:

services:
    League\Flysystem\Filesystem:
        arguments:
            - !service
                class: League\Flysystem\GoogleCloudStorage\GoogleCloudStorageAdapter
                arguments: ['@softspring_gcloud.storage_client', '%gcs_bucket%']

Configuration over construction. Anything environment-dependent — bucket names, project IDs, prefixes — belongs in bundle config, resolved from %env()%. Don't construct a second StorageClient by hand in a service; you'll duplicate credential logic and it will drift the first time credentials move to Workload Identity.

Async by default for anything user-facing. Uploads over a few hundred KB, or anything that touches a cold bucket, should go through a queue job. The bundle client is a plain service — it serialises fine into a job payload only if you inject it in the handler rather than passing it as an argument. Inject into the handler.

Batch operations go through commands. Garbage-collecting orphaned objects, recomputing signed URLs after a key rotation, backfilling a bucket — all of these want to be bin/console commands with progress output and idempotent re-runs. Don't put them behind an HTTP endpoint you'll have to authenticate.

For the Laravel port, the provider is short:

final class GCloudServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->singleton(StorageClient::class, fn () => new StorageClient([
            'projectId' => config('services.gcp.project'),
            'keyFilePath' => config('services.gcp.credentials'),
        ]));
    }
}

Then use League\Flysystem\GoogleCloudStorage\GoogleCloudStorageAdapter for the disk driver, or spatie/flysystem-google-cloud-storage if you want the adapter maintained for you. You get the same result with far less dependency surface.

Gotchas and Tips

The Composer constraint problem is real. Symfony bundles almost always require symfony/framework-bundle, symfony/dependency-injection, or symfony/http-kernel at fixed major versions. Laravel pins its own symfony/* components (console, http-foundation, routing, error-handler, etc.) at specific minors. Installing a bundle that requires symfony/framework-bundle: ^6.4 into a Laravel 10/11 app can either fail to resolve or drag the entire Symfony framework into your vendor tree. Check composer.json's require block before running composer require. If framework-bundle is there, stop — port the code instead.

The package is unproven. Zero dependent packages and an empty star count means: no ecosystem pressure to keep it compatible, no user reports when a Google SDK major bump breaks it, and no guarantee the maintainer is still watching. Pin to an exact version ("softspring/gcloud-integration-bundle": "1.2.3") rather than a caret range, and be prepared to vendor-fork it. Since the bundle surface is small — config, a couple of service definitions, a factory — the fork is typically an afternoon.

Credentials resolution order will bite you. ADC checks GOOGLE_APPLICATION_CREDENTIALS, then the gcloud CLI's well-known file, then the GCE/GKE metadata server. Locally that means your laptop may silently use a totally different service account than production. Log the resolved client email at boot in non-production. On GCP, prefer Workload Identity Federation over key files — no JSON to rotate, leak, or accidentally commit.

Config changes need a cache clear. Symfony compiles bundle config into the container. Editing softspring_gcloud.yaml or a .env value and seeing no effect is the single most common confusion. bin/console cache:clear (and cache:warmup) after every config change, and remember config:dump-reference softspring_gcloud prints the live, merged schema — use it instead of guessing.

Signed URLs and the emulator don't mix. fake-gcs-server and STORAGE_EMULATOR_HOST are excellent for put/get/delete in CI, but signed URL generation requires a real private key to sign with. Stub the signing layer in tests, or use V4 signing with an explicit key passed to the URL signer rather than relying on IAM signBlob.

Signed URL expiry is capped. V4 signed URLs max out at 7 days. Anything longer needs a token service or an authenticated proxy route. Also watch clock skew — if your app server drifts more than a few minutes, a freshly minted URL is already expired for the client.

IAM is usually the bug, not the code. 403 Forbidden on write almost always means the service account lacks roles/storage.objectAdmin on the bucket, or Uniform Bucket-Level Access is on and the object ACL the code sets is being ignored. 404 on an object you know exists usually means wrong project ID or a bucket-name typo in config — the SDK does not distinguish those well.

Stream large files, don't load them. The client returns streams for a reason. file_get_contents() on a multi-GB object is an OOM waiting for a Tuesday. Use readStream/writeStream and let Guzzle handle chunked transfer.

Testing strategy. Unit-test against the bundle's interface with a fake. Integration-test against the GCS emulator in CI with bucket creation in a fixture. Reserve real-bucket tests for a smoke suite on deploy — they're slow and they cost money.

Extension points to prefer. If the bundle exposes a client factory or a service you can decorate, decorate it rather than replacing the definition outright. A decorating service survives a bundle upgrade; a full override of services.yaml does not, and the breakage shows up as a cryptic "service not found" at container compile time rather than at the call site.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib