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

Cloud Common Protos Laravel Package

google/cloud-common-protos

PHP classes generated from the protocol buffer types shared across multiple Google Cloud APIs. Stable and backward-compatible, this Apache 2.0 licensed Composer package lets you depend on these common protos directly via composer require google/cloud-common-protos.

View on GitHub
Deep Wiki
Context7

Getting Started

First, check whether you already have it. This package is almost never a direct dependency — it arrives transitively with google/cloud-logging, google/cloud-pub-sub, google/cloud-firestore, google/cloud-trace, etc. Before adding anything:

composer show | grep -i proto
# google/cloud-common-protos  1.0.3
# google/common-protos        4.x
# google/protobuf             4.x

Note there are two similarly named packages. google/common-protos ships the google.protobuf.*, Google\Rpc\*, Google\Type\* and Google\LongRunning\* types; google/cloud-common-protos layers the Cloud-specific shared protos on top (Google\Api\* annotations, IAM policy types, audit logging, etc.). Requiring the latter pulls the former. Inspect vendor/google/ after install to confirm exactly which namespaces you have rather than guessing from docs.

Install only if you are using the classes directly:

composer require google/cloud-common-protos:^1.0

The PHP protobuf runtime ships a pure-PHP fallback, so ext-protobuf is optional — but install it in production if you serialize a lot (10–50x faster). ext-grpc is not required to use these message classes; they are plain DTOs.

First use case worth wiring: a shared serialization helper. In Laravel, register one small service and use it everywhere:

// app/Support/Proto.php
namespace App\Support;

use Google\Protobuf\Internal\Message;

final class Proto
{
    /** @return array<string,mixed> */
    public static function toArray(Message $m): array
    {
        return json_decode($m->serializeToJsonString(), true, 512, JSON_THROW_ON_ERROR);
    }

    public static function fromJson(Message $m, string $json): Message
    {
        return $m->mergeFromJsonString($json);
    }
}

Use it to standardize API error envelopes (see below) or to format Google\Type\Money for invoices — Google\Type\Money is the safest first real-world use because it is trivial, testable, and touches no IAM or gRPC surface.

Implementation Patterns

1. Money for anything financial. Never use floats. Store minor units, format at the edge:

use Google\Type\Money;

$price = (new Money())
    ->setCurrencyCode('EUR')
    ->setUnits(19)
    ->setNanos(990000000); // 19.99

// persist
$cents = $price->getUnits() * 100 + intdiv($price->getNanos(), 10_000_000);

// present
$formatted = number_format($price->getUnits() + $price->getNanos() / 1e9, 2);

2. Carbon ↔ Google\Protobuf\Timestamp in one place. Do not scatter ->getSeconds() calls. Timestamps are (seconds, nanos), not floats:

use Google\Protobuf\Timestamp;

function toTimestamp(\Carbon\CarbonInterface $c): Timestamp
{
    return (new Timestamp())->setSeconds($c->getTimestamp());
}

function fromTimestamp(Timestamp $t): \Carbon\CarbonImmutable
{
    return \Carbon\CarbonImmutable::createFromTimestampUTC($t->getSeconds());
}

3. Google\Protobuf\Struct/Value for dynamic JSON (Pub/Sub attributes, Firestore documents, Vertex AI parameters). The ergonomics are poor — wrap it:

use Google\Protobuf\Struct;
use Google\Protobuf\Value;
use Google\Protobuf\ListValue;
use Google\Protobuf\NullValue;

function toStruct(array $data): Struct
{
    $s = new Struct();
    foreach ($data as $k => $v) {
        $s->getFields()[$k] = toValue($v);
    }
    return $s;
}

function toValue(mixed $v): Value
{
    $val = new Value();
    return match (true) {
        is_null($v)     => $val->setNullValue(NullValue::NULL_VALUE),
        is_bool($v)     => $val->setBoolValue($v),
        is_int($v), is_float($v) => $val->setNumberValue((float) $v),
        is_array($v) && array_is_list($v)
                        => $val->setListValue((new ListValue())->setValues(array_map('toValue', $v))),
        is_array($v)    => $val->setStructValue(toStruct($v)),
        default         => $val->setStringValue((string) $v),
    };
}

4. Standardized error responses via Google\Rpc\Status. If your Laravel app talks to GCP services and front-ends to a public API, mirror Google's error contract so clients need one parser:

use Google\Rpc\Status;
use Google\Rpc\Code;

// app/Exceptions/Handler.php
public function render($request, Throwable $e)
{
    if ($request->expectsJson() && $e instanceof GoogleApiException) {
        $status = (new Status())
            ->setCode(Code::INVALID_ARGUMENT)
            ->setMessage($e->getMessage());

        return response()->json(
            \App\Support\Proto::toArray($status),
            match ($status->getCode()) {
                Code::NOT_FOUND => 404,
                Code::PERMISSION_DENIED => 403,
                Code::INVALID_ARGUMENT => 422,
                default => 500,
            }
        );
    }
    return parent::render($request, $e);
}

5. DTO mapping with spatie/laravel-data or plain mappers. Protobuf messages are not containers you should pass through your domain. Keep a PaymentData DTO and add toMoney() / toTimestamp() methods; keep protobuf construction at the infrastructure boundary. This is the single biggest ergonomic win — protobuf objects are verbose, weakly typed at the PHP level, and hostile to Eloquent::create().

6. Container binding. Bind clients, never messages. Messages are values; the container should hold a ProtoMapper or a CloudLoggingClient factory. Don't make messages singletons.

7. Testing. Assert on the JSON projection, not on object identity — generated classes don't compare well and field ordering in JSON is not guaranteed:

$this->assertSame(
    ['currencyCode' => 'EUR', 'units' => 19, 'nanos' => 990000000],
    json_decode($money->serializeToJsonString(), true)
);

For inbound fixtures, use mergeFromJsonString() from a tests/Fixtures/*.json file — it's more readable than 20 setter calls and doubles as documentation of the wire shape.

Gotchas and Tips

  • json_encode($message) returns {}. Generated messages are not JsonSerializable. Always call serializeToJsonString(). This bites everyone once, usually inside a response()->json($msg).
  • Protobuf JSON is lowerCamelCase and omits defaults. json_decode($msg->serializeToJsonString()) will not round-trip a field explicitly set to its zero value. If a consumer needs to distinguish "unset" from zero, use optional fields in a .proto you control, or carry a FieldMask.
  • Don't build protobuf messages in Eloquent casts. Accessors returning Timestamp will silently break toArray(), model serialization, and queue payloads. Convert at the boundary instead.
  • Repeated fields: $msg->setFoo([$a, $b]) works, but $msg->getFoo()[] = $a does not (it returns a copy). For maps like Struct::$fields, use $s->getFields()[$k] = $v — this one does mutate, which is inconsistent with repeated fields and easy to get wrong. Verify with a test.
  • var_dump is useless — you get deeply nested private internals. Debug with serializeToJsonString() or serializeToString() + hex.
  • Google\Protobuf\Any requires a type registry. Unpacking needs Any::unpack() with the concrete class; if you're storing Any payloads in the DB, also store the type_url so you can map back later.
  • Version pinning: ^1.0 for cloud-common-protos, but also pin google/protobuf and google/common-protos in CI. GCP SDKs have historically bumped common-protos majors independently (v2 → v3 → v4), and a composer update on a Tuesday can move them.
  • The extension changes behavior subtly. Pure-PHP vs ext-protobuf can differ in performance and, historically, in error messages on malformed input. Run your test suite in both modes if you can — at minimum, mirror the production configuration in CI.
  • Enums are integer constants, not PHP enums. Code::NOT_FOUND is an int. Don't type-hint them as enums, and don't assume Code::name() exists.
  • Deprecated fields stay in the schema for a long time. Recent histories show deprecations (e.g. ReservationResourceUsage). Grep your codebase for fields you use when bumping the package; PHPStan won't tell you.
  • Skip the package entirely if you're REST-only. If you call google/cloud-storage over HTTP and never touch audit logs, Pub/Sub binary payloads, or gRPC, every class here is dead weight. The strongest signal is: do you ever need to construct a Struct, Money, Timestamp, or Status yourself? If no, let it arrive transitively and ignore it.
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.
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels