bubbaops / slack-php-framework
提供一个基础,用于在PHP中构建Slack应用
Requires
- php: >=8.1
- ext-ctype: *
- ext-json: *
- nyholm/psr7: ^1.3
- nyholm/psr7-server: ^1.0
- psr/container: ^1.0
- psr/http-factory: ^1.0
- psr/http-message: ^1.0
- psr/http-server-handler: ^1.0
- psr/http-server-middleware: ^1.0
- psr/log: ^3.0.0
- slack-php/slack-block-kit: ^0.19.0 || ^1.0.0
Requires (Dev)
- laravel/pint: ^1.0
- phpstan/phpstan: ^0.12.77
- phpunit/phpunit: ^9.6
This package is auto-updated.
Last update: 2024-09-21 19:06:39 UTC
README
PHP Slack应用框架
由Jeremy Lindblom (@jeremeamia)创作
由Bubba Hines分叉
简介
一个用于构建Slack应用的PHP框架。它从Slack的Bolt框架中汲取灵感。
如果你是Slack应用开发的初学者,你可以在Slack的网站上了解它。这个库只有在你已经了解构建Slack应用的基本知识时才有用。
安装
- 需要PHP 7.4+
- 使用Composer安装:
composer require slack-php/slack-app-framework
通用用法
快速警告
这个库已经经过大量的测试,但是项目在测试覆盖和文档方面严重不足,所以请在了解MIT许可协议的情况下自行承担风险。
开发模式
创建应用时,您可以从Slack网站上配置您的应用。框架设计用于接收来自应用所有交互点的请求,因此您应将所有URL(例如,在“/strong>Slash Commands”、“/strong>Interactivity & Shortcuts”(不要忘记“/em>Select Menus”部分)和“/strong>Event Subscriptions”)配置为指向已部署的应用代码的根URL。
在开发应用代码时,您可以使用对应于不同类型应用交互的“App”的路线方法声明一个或多个“Listener”。“Listener”可以声明为闭包,也可以声明为类型为“BubbaOps\Framework\Listener”的对象和类名。一个“Listener”接收一个“Context”对象,它包含Slack提供给应用的有效负载数据,并提供与Slack交互或进行通信的方法。
快速示例
这个小应用响应“/cool”斜杠命令。
假设
- 您已要求Composer自动加载器启用框架文件的自动加载。
- 您已在环境中设置了“SLACK_SIGNING_KEY”(例如,“putenv("SLACK_SIGNING_KEY=foo");”)
<?php use BubbaOps\Framework\App; use BubbaOps\Framework\Context; App::new() ->command('cool', function (Context $ctx) { $ctx->ack(':thumbsup: That is so cool!'); }) ->run();
示例应用
“Hello World”应用通过利用所有类型的应用交互(包括:斜杠命令、块操作、块建议(即菜单选项)、快捷方式(全局和消息级别)、模态、事件和应用主页)向您说你好。
“Hello World”应用代码
假设
- 您已要求Composer自动加载器启用框架文件的自动加载。
- 您已在环境中设置了“SLACK_SIGNING_KEY”(例如,“putenv("SLACK_SIGNING_KEY=foo");”)
- 您已在环境中设置了“SLACK_BOT_TOKEN”(例如,“putenv("SLACK_BOT_TOKEN=bar");”)
<?php declare(strict_types=1); use BubbaOps\BlockKit\Surfaces\{Message, Modal}; use BubbaOps\Framework\{App, Context, Route}; // Helper for creating a modal with the "hello-form" for choosing a greeting. $createModal = function (): Modal { return Modal::new() ->title('Choose a Greeting') ->submit('Submit') ->callbackId('hello-form') ->notifyOnClose(true) ->tap(function (Modal $modal) { $modal->newInput('greeting-block') ->label('Which Greeting?') ->newSelectMenu('greeting') ->forExternalOptions() ->placeholder('Choose a greeting...'); }); }; App::new() // Handles the `/hello` slash command. ->command('hello', function (Context $ctx) { $ctx->ack(Message::new()->tap(function (Message $msg) { $msg->newSection() ->mrkdwnText(':wave: Hello world!') ->newButtonAccessory('open-form') ->text('Choose a Greeting'); })); }) // Handles the "open-form" button click. ->blockAction('open-form', function (Context $ctx) use ($createModal) { $ctx->modals()->open($createModal()); }) // Handles when the "greeting" select menu needs its options. ->blockSuggestion('greeting', function (Context $ctx) { $ctx->options(['Hello', 'Howdy', 'Good Morning', 'Hey']); }) // Handles when the "hello-form" modal is submitted. ->viewSubmission('hello-form', function (Context $ctx) { $state = $ctx->payload()->getState(); $greeting = $state->get('greeting-block.greeting.selected_option.value'); $ctx->view()->update(":wave: {$greeting} world!"); }) // Handles when the "hello-form" modal is closed without submitting. ->viewClosed('hello-form', function (Context $ctx) { $ctx->logger()->notice('User closed hello-form modal early.'); }) // Handles when the "hello-global" global shortcut is triggered from the lightning menu. ->globalShortcut('hello-global', function (Context $ctx) use ($createModal) { $ctx->modals()->open($createModal()); }) // Handles when the "hello-message" message shortcut is triggered from a message context menu. ->messageShortcut('hello-message', function (Context $ctx) { $user = $ctx->fmt()->user($ctx->payload()->get('message.user')); $ctx->say(":wave: Hello {$user}!", null, $ctx->payload()->get('message.ts')); }) // Handles when the Hello World app "home" is accessed. ->event('app_home_opened', function (Context $ctx) { $user = $ctx->fmt()->user($ctx->payload()->get('event.user')); $ctx->home(":wave: Hello {$user}!"); }) // Handles when any public message contains the word "hello". ->event('message', Route::filter( ['event.channel_type' => 'channel', 'event.text' => 'regex:/^.*hello.*$/i'], function (Context $ctx) { $user = $ctx->fmt()->user($ctx->payload()->get('event.user')); $ctx->say(":wave: Hello {$user}!"); }) ) // Run that app to process the incoming Slack request. ->run();
面向对象版本
您还可以将您的应用和监听器创建为一组类。如果您有多个监听器或监听器比较复杂,我建议您采用这种方法。以下是一个示例,说明如何以这种方式开发“Hello World”应用。
“Hello World”应用代码
App.php
<?php declare(strict_types=1); namespace MyApp; use BubbaOps\Framework\{BaseApp, Route, Router}; use MyApp\Listeners; class MyCoolApp extends BaseApp { protected function prepareRouter(Router $router): void { $router->command('hello', Listeners\HelloCommand::class) ->blockAction('open-form', Listeners\OpenFormButtonClick::class) ->blockSuggestion('greeting', Listeners\GreetingOptions::class) ->viewSubmission('hello-form', Listeners\FormSubmission::class) ->viewClosed('hello-form', Listeners\FormClosed::class) ->globalShortcut('hello-global', Listeners\HelloGlobalShortcut::class) ->messageShortcut('hello-message', Listeners\HelloMessageShortcut::class) ->event('app_home_opened', Listeners\AppHome::class) ->event('message', Route::filter( ['event.channel_type' => 'channel', 'event.text' => 'regex:/^.*hello.*$/i'], Listeners\HelloMessage::class )); } }
index.php
假设
- 您已要求Composer自动加载器启用框架文件的自动加载。
- 您已配置composer.json,以便自动加载您的命名空间为“MyApp”的代码。
- 您已在环境中设置了“SLACK_SIGNING_KEY”(例如,“putenv("SLACK_SIGNING_KEY=foo");”)
- 您已在环境中设置了“SLACK_BOT_TOKEN”(例如,“putenv("SLACK_BOT_TOKEN=bar");”)
<?php use MyApp\MyCoolApp; $app = new MyCoolApp(); $app->run();
使用“Context”对象处理请求
Context
对象是您的应用程序与 Slack 交互的主要点。以下是您可以与 Context
做的所有事情。
// To respond (ack) to incoming Slack request:
$ctx->ack(Message|array|string|null) // Responds to request with 200 (and optional message)
$ctx->options(OptionList|array|null) // Responds to request with an options list
$ctx->view(): View
->clear() // Responds to modal submission by clearing modal stack
->close() // Responds to modal submission by clearing current modal
->errors(array) // Responds to modal submission by providing form errors
->push(Modal|array|string) // Responds to modal submission by pushing new modal to stack
->update(Modal|array|string) // Responds to modal submission by updating current modal
// To call Slack APIs (to send messages, open/update modals, etc.) after the ack:
$ctx->respond(Message|array|string) // Responds to message. Uses payload.response_url
$ctx->say(Message|array|string) // Responds in channel. Uses API and payload.channel.id
$ctx->modals(): Modals
->open(Modal|array|string) // Opens a modal. Uses API and payload.trigger_id
->push(Modal|array|string) // Pushes a new modal. Uses API and payload.trigger_id
->update(Modal|array|string) // Updates a modal. Uses API and payload.view.id
$ctx->home(AppHome|array|string) // Modifies App Home for user. Uses API and payload.user.id
$ctx->api(string $api, array $params) // Use Slack API client for arbitrary API operations
// Access payload or other contextual data:
$ctx->payload(): Payload // Returns the payload of the incoming request from Slack
$ctx->getAppId(): ?string // Gets the app ID, if it's known
$ctx->get(string): mixed // Gets a value from the context
$ctx->set(string, mixed) // Sets a value in the context
$ctx->isAcknowledged(): bool // Returns true if ack has been sent
$ctx->isDeferred(): bool // Returns true if additional processing will happen after the ack
// Access additional helpers:
$ctx->blocks(): Blocks // Returns a helper for creating Block Kit surfaces
$ctx->fmt(): Formatter // Returns the "mrkdwn" formatting helper for Block Kit text
$ctx->logger(): LoggerInterface // Returns an instance of the configured PSR-3 logger
$ctx->container(): ContainerInterface // Returns an instance of the configured PSR-11 container
高级设计
YUML 源
[AppServer]<>-runs>[App] [AppServer]creates->[Context] [App]<>->[AppConfig] [App]<>->[Router] [Router]-^[Listener] [Router]<>1-*>[Listener] [Listener]handles->[Context] [Context]<>->[Payload] [Context]<>->[AppConfig] [Context]<>->[_Clients_;RespondClient;ApiClient] [Context]<>->[_Helpers_;BlockKit;Modals;View] [Context]<>->[_Metadata_] [AppConfig]<>->[Logger] [AppConfig]<>->[Container] [AppConfig]<>->[_Credentials_]
Socket 模式
Socket 模式支持由一个单独的包提供。请参阅 slack-php/slack-php-socket-mode。
未实现
以下功能已知缺失
- 处理安装到不同工作区的 OAuth 流程。
- 尽管在
BubbaOps\Framework\Auth
命名空间中有一些类,但如果你现在需要自己实现,请这样做。
- 尽管在
使用的标准
- PSR-1, PSR-12: 编码风格
- PSR-3: 日志接口
- PSR-4: 自动加载
- PSR-7, PSR-15, PSR-17: HTTP
- PSR-11: 容器接口