PHPackages                             maxanstey/php-modern-google-pay - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. maxanstey/php-modern-google-pay

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

maxanstey/php-modern-google-pay
===============================

A modern, PSR-compliant, refactor of the Google Pay for Passes PHP library.

5825↓86%2PHP

Since Mar 2Pushed 4y ago1 watchersCompare

[ Source](https://github.com/maxanstey/php-modern-google-pay)[ Packagist](https://packagist.org/packages/maxanstey/php-modern-google-pay)[ RSS](/packages/maxanstey-php-modern-google-pay/feed)WikiDiscussions master Synced today

READMEChangelogDependenciesVersions (1)Used By (0)

php-modern-google-pay
=====================

[](#php-modern-google-pay)

A modern, PSR-compliant, refactor of the Google Pay for Passes PHP library.

For an example on how to use this package, see the bottom of this readme.

Why does this package exist?
============================

[](#why-does-this-package-exist)

I had a recent requirement to implement the "Save to Google Pay" button on a project I was working on, and after reading the documentation, I found the example PHP code provided was largely a [10,000+ line file with many, many classes inside of it](https://github.com/google-pay/passes-rest-samples/blob/master/php/Walletobjects.php) that wasn't able to be autoloaded, wasn't PSR-compliant, and was generally a headache to understand. With this in mind I set out to refactor the entire codebase to be PSR-compliant, utilise PHP8+ typing where practical, and reorganise all the classes to be namespaced as I thought reasonable.

What did I do?
==============

[](#what-did-i-do)

Admittedly, I did get my head down and just "get it done" so this list won't be comprehensive, but the majority of what I did consisted of:

- Added type hints
- Re-organised classes
- Made code PSR-12 compliant\*
- Spent some time DRYing up code and removing dead code
- Corrected doc blocks with incorrect syntax or incorrect hinting
- Made class setter methods fluent
- Added missing class properties
- Initialised all class properties as null\*

\*The code isn't strictly PSR-12 compliant as I haven't ran it through a sniffer, but for the most part it should be.

\*I had to initialise all class properties as null because of the code in Google\\Model that accesses them before initialisation (see below). I wasn't going to check the 10,000+ lines and see which ones are accessed, so I simply initialised them all.

```
$result = $this->getSimpleValue($val);

if ($result !== null) {
    $object->$key = $this->nullPlaceholderCheck($result);
}

```

Considerations
--------------

[](#considerations)

It wasn't possible for me to understand immediately the correct visibility of all the class properties, some were accessed via getters, some directly, some inside the class itself, some outside. As a result, I made the decision to make all class properties public.

I didn't realise until mid-way the refactor that there were some "unused" class properties that actually made known the typings of the used properties as a string -- e.g. public $barcodeDataType = 'Google\_Walletsobjects\_Barcode' -- so some typings are mixed or array, where they could be Barcode or Barcode\[\].

The main task here was to reorganise the code so that it was more readable and maintainable, I didn't spend too much time correcting comments, etc. so some comments may be irrelevant or outright wrong. This wasn't a rewrite of the library as much as a reorganisation + typings.

What didn't I do?
=================

[](#what-didnt-i-do)

Run any unit tests, or ensure it works for anything other than my specific use-case being generating a JWT for Offers.

Known bugs
==========

[](#known-bugs)

Types as array|null, instead of array|SomeClass|array
-----------------------------------------------------

[](#types-as-arraynull-instead-of-arraysomeclassarray)

It appears the Google library sets properties to a class, then to an array or vice versa for some reason.

```
/**
 * @var Barcode|null
 */
public Barcode|null $barcode = null;

```

Should be

```
/**
 * @var array|Barcode|null
 */
public array|Barcode|null $barcode = null;

```

Returning just GuzzleHttpRequest instead of GuzzleHttpRequest|ExpectedClass
---------------------------------------------------------------------------

[](#returning-just-guzzlehttprequest-instead-of-guzzlehttprequestexpectedclass)

This was something I didn't realise until later on. I've fixed it for my use case, the Offer Class generation, but others will need fixing.

```
 * @return GuzzleHttpRequest
 * @throws GoogleException
 */
public function insert(
    OfferObject $postBody,
    array $optionalParameters = []
): GuzzleHttpRequest {
    return $this->call(
        'insert',
        [array_merge(
            [
                'postBody' => $postBody,
            ],
            $optionalParameters
        )],
        OfferObject::class
    );
}

```

Should be

```
 * @return GuzzleHttpRequest|OfferObject
 * @throws GoogleException
 */
public function insert(
    OfferObject $postBody,
    array $optionalParameters = []
): GuzzleHttpRequest|OfferObject {
    return $this->call(
        'insert',
        [array_merge(
            [
                'postBody' => $postBody,
            ],
            $optionalParameters
        )],
        OfferObject::class
    );
}

```

Reporting issues
================

[](#reporting-issues)

You are welcome to raise PRs or submit issues, this project will be maintained (though not full-time).

Example usage
=============

[](#example-usage)

Create a Service Account and set up the required permissions in order to access the REST API, as found in Google's documentation here: .

Generate a Service Account key and download the credentials JSON. [This link](https://stackoverflow.com/questions/46287267/how-can-i-get-the-file-service-account-json-for-google-translate-api) might help if you get stuck.

Run the following PHP to generate a JWT:

```
$json = file_get_contents('YOUR-SERVICE-ACCOUNT-CREDENTIALS.json');

$issuerId = 3388000000000000000; // YOUR ISSUER ID

$serviceAccountEmailAddress = 'YOUR-EMAIL@YOUR-PROJECT.iam.gserviceaccount.com';
$applicationName = 'YOUR APPLICATION NAME';
$origins = [
    'http://localhost:3000',
];

$generator = new \PassGeneration\GooglePassGenerator(
  $serviceAccountEmailAddress,
  $json,
  $applicationName,
  $issuerId,
  $origins
);

$randomClassIdString = md5(uniqid('', true)); // Not cryptographically secure, just an example
$classId = sprintf("%s.%s", $issuerId, $randomClassIdString);

$randomObjectIdString = md5(uniqid('', true)); // Not cryptographically secure, just an example
$objectId = sprintf("%s.%s", $issuerId, $randomObjectIdString);

$verticalType = VerticalType::OFFER;

/** @var OfferClass $offerClass */
$offerClass = $generator->createClassByVerticalType($verticalType, $classId);
// e.g. $offerClass->setTitle('My title');

/** @var OfferObject $offerObject */
$offerObject = $generator->createObjectResourceByVerticalType($verticalType, $classId, $objectId);
// e.g. $offerObject->setHasUsers(false);

$jwt = $generator->generateSignedJwt(
    $serviceAccountEmailAddress,
    $generator->getAudience(),
    $generator->getJwtType(),
    [
        JwtKey::OFFER_CLASS => [
            $offerClass,
        ],
        JwtKey::OFFER_OBJECT => [
            $offerObject,
        ],
    ],
    $origins
);

die(var_dump($jwt));

```

This will return a JWT such as the below:

```
eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJvYmZ1c2NhdGVkIiwiYXVk...

```

Copy this JWT and use it to generate some HTML as below\*

```

          window.onload = () => {
                gapi.savetoandroidpay.render(
                    'google_wallet_button',
                    {
                        jwt: 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJvYmZ1c2NhdGVkIiwiYXVk...',
                        onsuccess: 'successHandler',
                        onfailure: 'failureHandler',
                    }
                )
          }

```

\*Personally I would make an API request from your site to your API responsible for generating the JWT and obtain it that way, but I am using a copy-paste in this guide for simplicity.

See [Google's documentation](https://developers.google.com/pay/passes/reference/s2w-reference) for more info on rendering HTML buttons.

###  Health Score

21

—

LowBetter than 18% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity22

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity27

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/26803203?v=4)[maxanstey](/maintainers/maxanstey)[@maxanstey](https://github.com/maxanstey)

---

Top Contributors

[![maxanstey](https://avatars.githubusercontent.com/u/26803203?v=4)](https://github.com/maxanstey "maxanstey (15 commits)")

### Embed Badge

![Health badge](/badges/maxanstey-php-modern-google-pay/health.svg)

```
[![Health](https://phpackages.com/badges/maxanstey-php-modern-google-pay/health.svg)](https://phpackages.com/packages/maxanstey-php-modern-google-pay)
```

###  Alternatives

[spatie/laravel-dashboard

A dashboard for Laravel

573170.7k96](/packages/spatie-laravel-dashboard)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
