25: 集成

大多数应用程序最终都会与外部服务进行交互:聊天服务、日历、会计后端、刷卡终端、支付处理器。Phlo 提供了两种用于此的功能,均在运行时中,因此无需额外的 SDK 进行集成,也无需单独的客户端进行连接。连接器是围绕 JSON REST API 的轻量级统一封装;支付资源封装了 Stripe 和 SumUp。

25.1: 连接器

连接器是一个小类,用于一个第三方 REST API。每个连接器都扩展 Connector,读取其自己的凭据部分,并返回相同的结果形状,因此调用 Slack 的方式与调用 Shopify 的方式相同。

$slack = Slack::make()
$res = $slack->send('#general', 'Deploy finished')
if ($res->ok) log('sent') else log($res->error)

make()data/creds.ini 中加载连接器的凭据(Slack 读取 [Slack],Shopify 读取 [Shopify],依此类推)。每次调用都会返回一个标准化的对象,因此你可以根据 ->ok 进行分支,并读取 ->data,而不是为每个服务解析不同的错误格式:

obj(ok: true,  status: 200, data: {...})   // success
obj(ok: false, status: 401, error: '...')  // failure

在底层,Connector 处理请求动词(get/post/put/patch/del/form)、分页(paginate())和身份验证头。每个连接器还公开一个 static fields 凭证架构,因此设置屏幕或 CMS 可以在不硬编码的情况下进行配置。

可用连接器

组别 连接器
消息 Slack, Telegram, Twilio, MessageBird, Resend
GoogleCalendar, GoogleSheets, MicrosoftGraph
财务 ExactOnline, Moneybird, EBoekhouden
商务 Lightspeed, Shopify

使用 OAuth2 进行身份验证的服务(如 Google、Exact)扩展 OAuthConnector 而不是 Connector。它在 TokenStore 中保持一个自动刷新的承载令牌(持久化在 data/tokens/ 下,使用独占锁刷新),因此您的代码只需调用 ->events(...),令牌的处理保持不可见。

每个连接器的方法列表在 Manualconnectors 下实时更新。它是从资源文件生成的,因此不会与代码偏离。

25.2: 支付

Stripe

Stripe 资源是官方 stripe/stripe-php SDK 的一个薄层(通过 Composer 添加)。使用您的密钥调用一次 Stripe::boot(),然后使用静态助手:

Stripe::boot(%creds->Stripe)
$session = Stripe::checkout([
	'mode' => 'subscription',
	'line_items' => [['price' => 'price_123', 'quantity' => 1]],
	'success_url' => 'https://example.com/done',
	'cancel_url' => 'https://example.com/pricing',
])
location($session->url)

checkout() 创建一个结账会话,portal($customerId, $returnUrl) 打开账单门户,verifyWebhook($payload, $sigHeader, $secret) 在您采取行动之前验证传入事件。customercreateCustomersubscriptionsubscriptionsproductprice 涵盖了其余的常见接口。

SumUp

SumUp 通过 Cloud API 在配对的 SumUp Solo 读卡器上处理面对面支付。它是一个连接器(SumUp::make()[SumUp] 凭据),因此返回相同的 obj(ok, ...) 结果:

$res = SumUp::make()->createReaderCheckout(1250, 'EUR', description: 'Table 4')

createReaderCheckout($amountMinor, $currency, ...) 将结账推送到读卡器(金额以小单位表示,因此 1250 是 €12.50)。transaction()transactions() 用于查找结果,而 terminateReaderCheckout() 则取消一个待处理的结账。

我们使用必要的cookie来使该网站正常工作。在您的许可下,我们还使用分析工具来改善网站。