maxanstey/php-modern-google-pay

Google Pay for Passes PHP 库的现代、符合PSR规范的重构版本。

dev-master 2022-03-02 09:41 UTC

This package is auto-updated.

Last update: 2024-09-29 05:56:46 UTC


README

Google Pay for Passes PHP 库的现代、符合PSR规范的重构版本。

有关如何使用此包的示例,请参阅本readme文件的底部。

为什么这个包存在?

我最近有一个项目需要实现“保存到Google Pay”按钮,阅读了文档后,我发现提供的示例PHP代码是一个非常长的文件(10,000+行),里面有很多类,无法自动加载,不符合PSR规范,理解起来很麻烦。因此,我决定重构整个代码库,使其符合PSR规范,尽可能使用PHP8+的类型提示,并将所有类重新组织到命名空间中,我认为这是合理的。

我做了什么?

诚然,我只是埋头苦干,所以这个列表不会很全面,但我所做的多数工作包括

  • 添加类型提示
  • 重新组织类
  • 使代码符合PSR-12规范*
  • 花时间减少代码重复和删除无用代码
  • 更正文档块中错误的语法或不正确的提示
  • 使类setter方法流畅
  • 添加缺少的类属性
  • 将所有类属性初始化为null*

*代码不是严格符合PSR-12规范,因为我没有通过嗅探器运行它,但大部分应该是。

*由于Google\Model中的代码在初始化之前访问它们,我不得不将所有类属性初始化为null。我无意检查10,000+行代码并查看哪些被访问,所以我简单地将它们全部初始化。

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

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

注意事项

我无法立即理解所有类属性的正确可见性,一些通过getter访问,一些直接访问,一些在类内部访问,一些在外部。因此,我决定将所有类属性设置为公共的。

在我重构的过程中,我才意识到一些“未使用”的类属性实际上以字符串的形式说明了已使用属性的类型——例如,public $barcodeDataType = 'Google_Walletsobjects_Barcode'——因此,一些类型是混合的或数组,可以是Barcode或Barcode[]。

主要任务是对代码进行重新组织,使其更易于阅读和维护,我没有花太多时间纠正注释等,因此一些注释可能是不相关的或完全错误的。这并不是对库的重写,而是一次重新组织和类型提示。

我没有做什么?

运行任何单元测试,或确保它除了为我特定的用例生成JWT之外还适用于其他情况。

已知问题

类型为array|null,而不是array|SomeClass|array

似乎由于某种原因,Google库将属性设置为类,然后设置为数组或反之亦然。

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

应该是

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

仅返回GuzzleHttpRequest,而不是GuzzleHttpRequest|ExpectedClass

这是我后来才意识到的。我已经为我的用例(Offer类生成)修复了它,但其他人可能需要修复。

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

应该是

 * @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
    );
}

报告问题

欢迎您提出PR或提交问题,此项目将得到维护(尽管不是全职)。

示例用法

创建一个服务帐户并设置必要的权限以访问REST API,具体操作请参考谷歌文档:[此处](https://developers.google.com/pay/passes/guides/basic-setup/get-access-to-rest-api)。

生成一个服务帐户密钥并下载证书JSON文件。如果您遇到困难,可以参考以下链接:[此处](https://stackoverflow.com/questions/46287267/how-can-i-get-the-file-service-account-json-for-google-translate-api)。

运行以下PHP代码以生成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 = [
    'https://: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));

这将返回如下所示的JWT

eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJvYmZ1c2NhdGVkIiwiYXVk...

复制此JWT并使用它生成以下HTML

<html>
    <head>
        <script src="https://apis.google.com/js/platform.js" async defer></script>
    </head>
    <body>
        <div id="google_wallet_button"></div>

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

*个人建议您从您的网站向负责生成JWT的API发起API请求并获取JWT,但为了简化,本指南中我将使用复制粘贴的方式。

有关渲染HTML按钮的更多信息,请参阅[谷歌文档](https://developers.google.com/pay/passes/reference/s2w-reference)。