diff --git a/.gitignore b/.gitignore index 5c473c8c..b30d5974 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,23 @@ vendor/ /.phpdoc/ phpDocumentor.phar .phpunit.result.cache + +## Generated by OpenAPI +src/clients/channel-access-token/* +!src/clients/channel-access-token/lib/ +!src/clients/channel-access-token/test/ +src/clients/insight/* +!src/clients/insight/lib/ +!src/clients/insight/test/ +src/clients/liff/* +!src/clients/liff/lib/ +!src/clients/liff/test/ +src/clients/manage-audience/* +!src/clients/manage-audience/lib/ +!src/clients/manage-audience/test/ +src/clients/messaging-api/* +!src/clients/messaging-api/lib/ +!src/clients/messaging-api/test/ +src/webhook/* +!src/webhook/lib/ +!src/webhook/test/ diff --git a/Makefile b/Makefile deleted file mode 100644 index f2758b6b..00000000 --- a/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -.PHONY: default test doc phpcs phpmd check install-devtool copyright release clean install reinstall - -default: check - -test: - composer test - -doc: - composer doc - -phpcs: - composer cs - -phpmd: - composer md - -phpstan: - devtool/check_phpstan.sh - -copyright: - devtool/check_copyright.sh - -check: test copyright phpcs phpmd phpstan - -clean: - rm -rf vendor composer.lock - -install: - composer install - -reinstall: clean install diff --git a/README.md b/README.md index 1a5345d1..d2a7b7af 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ See the official API documentation for more information. ## Requirements -- PHP 7.2 or later +- PHP 8.1 or later ## Installation @@ -188,11 +188,6 @@ Please refer [CurlHTTPClient](/src/LINEBot/HTTPClient/CurlHTTPClient.php) that i See also -- -### [line-bot-sdk-tiny](./line-bot-sdk-tiny) - -A very simple SDK (subset) for the LINE Messaging API for PHP. -line-bot-sdk-tiny provides a simple interface and functions which makes it a good way to learn how to use the LINE Messaging API. - ### Laravel Support Easy to use from Laravel. After installed, add `LINE_BOT_CHANNEL_ACCESS_TOKEN` and `LINE_BOT_CHANNEL_SECRET` to `.env` diff --git a/composer.json b/composer.json index 282699c9..67664fd6 100644 --- a/composer.json +++ b/composer.json @@ -32,10 +32,9 @@ } ], "require": { - "php": ">=7.2", - "ext-curl": "*", - "ext-json": "*", - "ext-sockets": "*" + "php": ">=8.1", + "guzzlehttp/guzzle": "^7.3", + "guzzlehttp/psr7": "^1.7 || ^2.0" }, "require-dev": { "phpunit/phpunit": "^7||^8||^9", @@ -46,12 +45,25 @@ }, "autoload": { "psr-4": { - "LINE\\": "src/" + "LINE\\Clients\\ChannelAccessToken\\": "src/clients/channel-access-token/lib/", + "LINE\\Clients\\Insight\\": "src/clients/insight/lib/", + "LINE\\Clients\\Liff\\": "src/clients/liff/lib/", + "LINE\\Clients\\ManageAudience\\": "src/clients/manage-audience/lib/", + "LINE\\Clients\\MessagingApi\\": "src/clients/messaging-api/lib/", + "LINE\\Constants\\": "src/constants/", + "LINE\\Laravel\\": "src/laravel/lib/", + "LINE\\Parser\\": "src/parser/lib/", + "LINE\\Webhook\\": "src/webhook/lib/" } }, "autoload-dev": { "psr-4": { - "LINE\\Tests\\": "tests/" + "LINE\\Clients\\ChannelAccessToken\\Tests\\": "src/clients/channel-access-token/tests/", + "LINE\\Clients\\Insight\\Tests\\": "src/clients/insight/tests/", + "LINE\\Clients\\Liff\\Tests\\": "src/clients/liff/tests/", + "LINE\\Clients\\ManageAudience\\Tests\\": "src/clients/manage-audience/tests/", + "LINE\\Parser\\Tests\\": "src/parser/tests/", + "LINE\\Webhook\\Tests\\": "src/webhook/tests/" } }, "scripts": { @@ -66,7 +78,11 @@ "LINE\\Laravel\\LINEBotServiceProvider" ], "aliases": { - "LINEBot": "LINE\\Laravel\\Facade\\LINEBot" + "LINEChannelAccessTokenApi": "LINE\\Laravel\\Facade\\LINEChannelAccessTokenApi", + "LINEInsightApi": "LINE\\Laravel\\Facade\\LINEInsightApi", + "LINELiffApi": "LINE\\Laravel\\Facade\\LINELiffApi", + "LINEManageAudienceApi": "LINE\\Laravel\\Facade\\LINEManageAudienceApi", + "LINEMessagingApi": "LINE\\Laravel\\Facade\\LINEMessagingApi" } } } diff --git a/examples/EchoBot/composer.json b/examples/EchoBot/composer.json index cc2d1977..36d62ba5 100644 --- a/examples/EchoBot/composer.json +++ b/examples/EchoBot/composer.json @@ -4,24 +4,28 @@ { "name": "moznion", "email": "moznion@gmail.com", - "role": "Retired" + "role": "Retired" }, { "name": "Satoru Yoshihara", "email": "vaduz0@gmail.com", - "role": "Maintainer" + "role": "Retired" }, { "name": "Satoshi Shibuya", "email": "satosby@gmail.com", - "role": "Maintainer" + "role": "Maintainer" } ], "require": { - "php": ">=5.6", - "slim/slim": "^4.0.0", + "php": ">=8.1", + "slim/slim": "^4.11", + "slim/psr7": "^1.6", + "slim/http": "^1.3", "monolog/monolog": "^3.0.0", - "linecorp/line-bot-sdk": "1.6.0" + "guzzlehttp/guzzle": "^7.5", + "guzzlehttp/psr7": "^2.5", + "php-di/slim-bridge": "^3.3" }, "autoload": { "psr-4": { diff --git a/examples/EchoBot/openapitools.json b/examples/EchoBot/openapitools.json new file mode 100644 index 00000000..a3883a34 --- /dev/null +++ b/examples/EchoBot/openapitools.json @@ -0,0 +1,7 @@ +{ + "$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json", + "spaces": 2, + "generator-cli": { + "version": "6.5.0" + } +} diff --git a/examples/EchoBot/public/index.php b/examples/EchoBot/public/index.php index 6e5683d1..e238eedd 100644 --- a/examples/EchoBot/public/index.php +++ b/examples/EchoBot/public/index.php @@ -22,10 +22,10 @@ require_once __DIR__ . '/../vendor/autoload.php'; -$setting = Setting::getSetting(); -$app = new Slim\App($setting); +$container = new \DI\Container(); +(new Dependency())->register($container); -(new Dependency())->register($app); +$app = \Slim\Factory\AppFactory::createFromContainer($container); (new Route())->register($app); $app->run(); diff --git a/examples/EchoBot/src/LINEBot/EchoBot/Dependency.php b/examples/EchoBot/src/LINEBot/EchoBot/Dependency.php index 4994110f..6e4817a7 100644 --- a/examples/EchoBot/src/LINEBot/EchoBot/Dependency.php +++ b/examples/EchoBot/src/LINEBot/EchoBot/Dependency.php @@ -18,33 +18,36 @@ namespace LINE\LINEBot\EchoBot; -use LINE\LINEBot; -use LINE\LINEBot\HTTPClient\CurlHTTPClient; +use LINE\Clients\MessagingApi\Api\MessagingApiApi; +use LINE\Clients\MessagingApi\Configuration; class Dependency { - public function register(\Slim\App $app) + public function register(\DI\Container $container) { - $container = $app->getContainer(); + $container->set('settings', function ($c) { + return Setting::getSetting()['settings']; + }); - $container['logger'] = function ($c) { + $container->set(\Psr\Log\LoggerInterface::class, function ($c) { $settings = $c->get('settings')['logger']; $logger = new \Monolog\Logger($settings['name']); $logger->pushProcessor(new \Monolog\Processor\UidProcessor()); - $logger->pushHandler(new \Monolog\Handler\StreamHandler($settings['path'], \Monolog\Logger::DEBUG)); + $logger->pushHandler(new \Monolog\Handler\StreamHandler('php://stdout', \Monolog\Level::Debug)); + $logger->pushHandler(new \Monolog\Handler\StreamHandler($settings['path'], \Monolog\Level::Debug)); return $logger; - }; + }); - $container['bot'] = function ($c) { + $container->set('botMessagingApi', function ($c) { $settings = $c->get('settings'); - $channelSecret = $settings['bot']['channelSecret']; $channelToken = $settings['bot']['channelToken']; - $apiEndpointBase = $settings['apiEndpointBase']; - $bot = new LINEBot(new CurlHTTPClient($channelToken), [ - 'channelSecret' => $channelSecret, - 'endpointBase' => $apiEndpointBase, // <= Normally, you can omit this - ]); + $config = new Configuration(); + $config->setAccessToken($channelToken); + $bot = new MessagingApiApi( + client: new \GuzzleHttp\Client(), + config: $config, + ); return $bot; - }; + }); } } diff --git a/examples/EchoBot/src/LINEBot/EchoBot/Route.php b/examples/EchoBot/src/LINEBot/EchoBot/Route.php index 52761af6..71d8b9fb 100644 --- a/examples/EchoBot/src/LINEBot/EchoBot/Route.php +++ b/examples/EchoBot/src/LINEBot/EchoBot/Route.php @@ -18,21 +18,23 @@ namespace LINE\LINEBot\EchoBot; -use LINE\LINEBot\Constant\HTTPHeader; -use LINE\LINEBot\Event\MessageEvent; -use LINE\LINEBot\Event\MessageEvent\TextMessage; -use LINE\LINEBot\Exception\InvalidEventRequestException; -use LINE\LINEBot\Exception\InvalidSignatureException; +use LINE\Clients\MessagingApi\Model\ReplyMessageRequest; +use LINE\Clients\MessagingApi\Model\TextMessage; +use LINE\Constants\HTTPHeader; +use LINE\Parser\EventRequestParser; +use LINE\Webhook\Model\MessageEvent; +use LINE\Parser\Exception\InvalidEventRequestException; +use LINE\Parser\Exception\InvalidSignatureException; +use LINE\Webhook\Model\TextMessageContent; class Route { public function register(\Slim\App $app) { - $app->post('/callback', function (\Slim\Http\Request $req, \Slim\Http\Response $res) { - /** @var \LINE\LINEBot $bot */ - $bot = $this->bot; - /** @var \Monolog\Logger $logger */ - $logger = $this->logger; + $app->post('/callback', function (\Psr\Http\Message\RequestInterface $req, \Psr\Http\Message\ResponseInterface $res) { + /** @var \LINE\Clients\MessagingApi\Api\MessagingApiApi $bot */ + $bot = $this->get('botMessagingApi'); + $logger = $this->get(\Psr\Log\LoggerInterface::class); $signature = $req->getHeader(HTTPHeader::LINE_SIGNATURE); if (empty($signature)) { @@ -41,7 +43,8 @@ public function register(\Slim\App $app) // Check request with signature and parse request try { - $events = $bot->parseEventRequest($req->getBody(), $signature[0]); + $secret = $this->get('settings')['bot']['channelSecret']; + $events = EventRequestParser::parseEventRequest($req->getBody(), $secret, $signature[0]); } catch (InvalidSignatureException $e) { return $res->withStatus(400, 'Invalid signature'); } catch (InvalidEventRequestException $e) { @@ -54,18 +57,23 @@ public function register(\Slim\App $app) continue; } - if (!($event instanceof TextMessage)) { + $message = $event->getMessage(); + if (!($message instanceof TextMessageContent)) { $logger->info('Non text message has come'); continue; } - $replyText = $event->getText(); + $replyText = $message->getText(); $logger->info('Reply text: ' . $replyText); - $resp = $bot->replyText($event->getReplyToken(), $replyText); - $logger->info($resp->getHTTPStatus() . ': ' . $resp->getRawBody()); + $bot->replyMessage(new ReplyMessageRequest([ + 'replyToken' => $event->getReplyToken(), + 'messages' => [ + (new TextMessage(['text' => $replyText]))->setType('text'), + ], + ])); } - $res->write('OK'); + $res->withStatus(200, 'OK'); return $res; }); } diff --git a/examples/KitchenSink/.github/workflows/workflow.yml b/examples/KitchenSink/.github/workflows/workflow.yml new file mode 100644 index 00000000..76d38d87 --- /dev/null +++ b/examples/KitchenSink/.github/workflows/workflow.yml @@ -0,0 +1,23 @@ +on: + push: + branches: + - main + +name: deploy + +jobs: + devflow: + runs-on: ubuntu-latest + steps: + - name: checkout + uses: actions/checkout@master + + - name: context + uses: okteto/context@latest + with: + token: ${{ secrets.OKTETO_TOKEN }} + + - name: "Build" + uses: okteto/build@latest + with: + file: okteto.yml diff --git a/examples/KitchenSink/composer.json b/examples/KitchenSink/composer.json index a1203cf7..99653721 100644 --- a/examples/KitchenSink/composer.json +++ b/examples/KitchenSink/composer.json @@ -4,24 +4,38 @@ { "name": "moznion", "email": "moznion@gmail.com", - "role": "Retired" + "role": "Retired" }, { "name": "Satoru Yoshihara", "email": "vaduz0@gmail.com", - "role": "Maintainer" + "role": "Retired" }, { "name": "Satoshi Shibuya", "email": "satosby@gmail.com", - "role": "Maintainer" + "role": "Maintainer" } ], + "repositories": [ + { + "type": "path", + "url": "../../", + "options": { + "symlink": false + } + } + ], "require": { - "php": ">=5.6", - "slim/slim": "^4.0.0", + "php": ">=8.1", + "slim/slim": "^4.11", + "slim/psr7": "^1.6", + "slim/http": "^1.3", "monolog/monolog": "^3.0.0", - "linecorp/line-bot-sdk": "3.15.0" + "guzzlehttp/guzzle": "^7.5", + "guzzlehttp/psr7": "^2.5", + "php-di/slim-bridge": "^3.3", + "linecorp/line-bot-sdk": "dev-open-api" }, "autoload": { "psr-4": { diff --git a/examples/KitchenSink/public/index.php b/examples/KitchenSink/public/index.php index 7cce3ff5..1bf7115c 100644 --- a/examples/KitchenSink/public/index.php +++ b/examples/KitchenSink/public/index.php @@ -18,14 +18,13 @@ use LINE\LINEBot\KitchenSink\Dependency; use LINE\LINEBot\KitchenSink\Route; -use LINE\LINEBot\KitchenSink\Setting; require_once __DIR__ . '/../vendor/autoload.php'; -$setting = Setting::getSetting(); -$app = new \Slim\App($setting); +$container = new \DI\Container(); +(new Dependency())->register($container); +$app = \Slim\Factory\AppFactory::createFromContainer($container); (new Route())->register($app); -(new Dependency())->register($app); $app->run(); diff --git a/examples/KitchenSink/src/LINEBot/KitchenSink/Dependency.php b/examples/KitchenSink/src/LINEBot/KitchenSink/Dependency.php index dd8687af..329f2016 100644 --- a/examples/KitchenSink/src/LINEBot/KitchenSink/Dependency.php +++ b/examples/KitchenSink/src/LINEBot/KitchenSink/Dependency.php @@ -18,33 +18,49 @@ namespace LINE\LINEBot\KitchenSink; -use LINE\LINEBot; -use LINE\LINEBot\HTTPClient\CurlHTTPClient; +use LINE\Clients\MessagingApi\Api\MessagingApiApi; +use LINE\Clients\MessagingApi\Api\MessagingApiBlobApi; +use LINE\Clients\MessagingApi\Configuration; class Dependency { - public function register(\Slim\App $app) + public function register(\DI\Container $container) { - $container = $app->getContainer(); + $container->set('settings', function ($c) { + return Setting::getSetting()['settings']; + }); - $container['logger'] = function ($c) { + $container->set(\Psr\Log\LoggerInterface::class, function ($c) { $settings = $c->get('settings')['logger']; $logger = new \Monolog\Logger($settings['name']); $logger->pushProcessor(new \Monolog\Processor\UidProcessor()); - $logger->pushHandler(new \Monolog\Handler\StreamHandler($settings['path'], \Monolog\Logger::DEBUG)); + $logger->pushHandler(new \Monolog\Handler\StreamHandler('php://stdout', \Monolog\Level::Debug)); + $logger->pushHandler(new \Monolog\Handler\StreamHandler($settings['path'], \Monolog\Level::Debug)); return $logger; - }; + }); - $container['bot'] = function ($c) { + $container->set(MessagingApiApi::class, function ($c) { $settings = $c->get('settings'); - $channelSecret = $settings['bot']['channelSecret']; $channelToken = $settings['bot']['channelToken']; - $apiEndpointBase = $settings['apiEndpointBase']; - $bot = new LINEBot(new CurlHTTPClient($channelToken), [ - 'channelSecret' => $channelSecret, - 'endpointBase' => $apiEndpointBase, // <= Normally, you can omit this - ]); + $config = new Configuration(); + $config->setAccessToken($channelToken); + $bot = new MessagingApiApi( + client: new \GuzzleHttp\Client(), + config: $config, + ); return $bot; - }; + }); + + $container->set(MessagingApiBlobApi::class, function ($c) { + $settings = $c->get('settings'); + $channelToken = $settings['bot']['channelToken']; + $config = new Configuration(); + $config->setAccessToken($channelToken); + $bot = new MessagingApiBlobApi( + client: new \GuzzleHttp\Client(), + config: $config, + ); + return $bot; + }); } } diff --git a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/AccountLinkEventHandler.php b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/AccountLinkEventHandler.php index d791ca2d..5d20cadb 100644 --- a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/AccountLinkEventHandler.php +++ b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/AccountLinkEventHandler.php @@ -18,26 +18,28 @@ namespace LINE\LINEBot\KitchenSink; -use LINE\LINEBot; -use LINE\LINEBot\Event\AccountLinkEvent; +use LINE\ChannelAccessToken\Model\TextMessage; +use LINE\Clients\MessagingApi\Api\MessagingApiApi; +use LINE\Clients\MessagingApi\Model\ReplyMessageRequest; +use LINE\Constants\MessageType; +use LINE\Webhook\Model\AccountLinkEvent; class AccountLinkEventHandler { - /** @var LINEBot $bot */ + /** @var MessagingApiApi $bot */ private $bot; - /** @var \Monolog\Logger $logger */ + /** @var \Psr\Log\LoggerInterface $logger */ private $logger; /* @var AccountLinkEvent $accountLinkEvent */ private $accountLinkEvent; /** - * BeaconEventHandler constructor. - * - * @param LINEBot $bot - * @param \Monolog\Logger $logger + * AccountLinkEventHandler constructor. + * @param MessagingApiApi $bot + * @param \Psr\Log\LoggerInterface $logger * @param AccountLinkEvent $accountLinkEvent */ - public function __construct($bot, $logger, AccountLinkEvent $accountLinkEvent) + public function __construct(MessagingApiApi $bot, \Psr\Log\LoggerInterface $logger, AccountLinkEvent $accountLinkEvent) { $this->bot = $bot; $this->logger = $logger; @@ -49,9 +51,12 @@ public function __construct($bot, $logger, AccountLinkEvent $accountLinkEvent) */ public function handle() { - $this->bot->replyText( - $this->accountLinkEvent->getReplyToken(), - 'Got account link event ' . $this->accountLinkEvent->getNonce() - ); + $request = new ReplyMessageRequest([ + 'replyToken' => $this->accountLinkEvent->getReplyToken(), + 'messages' => [ + new TextMessage(['type' => MessageType::TEXT, 'text' => 'Got account link event ' . $this->accountLinkEvent->getLink()->getNonce()]), + ], + ]); + $this->bot->replyMessage($request); } } diff --git a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/BeaconEventHandler.php b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/BeaconEventHandler.php index 088ef040..4cf4defe 100644 --- a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/BeaconEventHandler.php +++ b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/BeaconEventHandler.php @@ -18,26 +18,29 @@ namespace LINE\LINEBot\KitchenSink\EventHandler; -use LINE\LINEBot; -use LINE\LINEBot\Event\BeaconDetectionEvent; +use LINE\Clients\MessagingApi\Api\MessagingApiApi; +use LINE\Clients\MessagingApi\Model\ReplyMessageRequest; +use LINE\Clients\MessagingApi\Model\TextMessage; +use LINE\Constants\MessageType; use LINE\LINEBot\KitchenSink\EventHandler; +use LINE\Webhook\Model\BeaconEvent; class BeaconEventHandler implements EventHandler { - /** @var LINEBot $bot */ + /** @var MessagingApiApi $bot */ private $bot; - /** @var \Monolog\Logger $logger */ + /** @var \Psr\Log\LoggerInterface $logger */ private $logger; - /* @var BeaconDetectionEvent $beaconEvent */ + /** @var MessageEvent $event */ private $beaconEvent; /** * BeaconEventHandler constructor. - * @param LINEBot $bot - * @param \Monolog\Logger $logger - * @param BeaconDetectionEvent $beaconEvent + * @param MessagingApiApi $bot + * @param \Psr\Log\LoggerInterface $logger + * @param BeaconEvent $beaconEvent */ - public function __construct($bot, $logger, BeaconDetectionEvent $beaconEvent) + public function __construct(MessagingApiApi $bot, \Psr\Log\LoggerInterface $logger, BeaconEvent $beaconEvent) { $this->bot = $bot; $this->logger = $logger; @@ -49,9 +52,12 @@ public function __construct($bot, $logger, BeaconDetectionEvent $beaconEvent) */ public function handle() { - $this->bot->replyText( - $this->beaconEvent->getReplyToken(), - 'Got beacon message ' . $this->beaconEvent->getHwid() - ); + $request = new ReplyMessageRequest([ + 'replyToken' => $this->beaconEvent->getReplyToken(), + 'messages' => [ + new TextMessage(['type' => MessageType::TEXT, 'text' => 'Got beacon message ' . $this->beaconEvent->getHwid()]), + ], + ]); + $this->bot->replyMessage($request); } } diff --git a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/FollowEventHandler.php b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/FollowEventHandler.php index 72df2e35..270c78be 100644 --- a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/FollowEventHandler.php +++ b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/FollowEventHandler.php @@ -18,26 +18,29 @@ namespace LINE\LINEBot\KitchenSink\EventHandler; -use LINE\LINEBot; -use LINE\LINEBot\Event\FollowEvent; +use LINE\Clients\MessagingApi\Api\MessagingApiApi; +use LINE\Clients\MessagingApi\Model\ReplyMessageRequest; +use LINE\Clients\MessagingApi\Model\TextMessage; +use LINE\Constants\MessageType; use LINE\LINEBot\KitchenSink\EventHandler; +use LINE\Webhook\Model\FollowEvent; class FollowEventHandler implements EventHandler { - /** @var LINEBot $bot */ + /** @var MessagingApiApi $bot */ private $bot; - /** @var \Monolog\Logger $logger */ + /** @var \Psr\Log\LoggerInterface $logger */ private $logger; /** @var FollowEvent $followEvent */ private $followEvent; /** * FollowEventHandler constructor. - * @param LINEBot $bot - * @param \Monolog\Logger $logger + * @param MessagingApiApi $bot + * @param \Psr\Log\LoggerInterface $logger * @param FollowEvent $followEvent */ - public function __construct($bot, $logger, FollowEvent $followEvent) + public function __construct(MessagingApiApi $bot, \Psr\Log\LoggerInterface $logger, FollowEvent $followEvent) { $this->bot = $bot; $this->logger = $logger; @@ -49,6 +52,12 @@ public function __construct($bot, $logger, FollowEvent $followEvent) */ public function handle() { - $this->bot->replyText($this->followEvent->getReplyToken(), 'Got followed event'); + $request = new ReplyMessageRequest([ + 'replyToken' => $this->followEvent->getReplyToken(), + 'messages' => [ + new TextMessage(['type' => MessageType::TEXT, 'text' => 'Got followed event']), + ], + ]); + $this->bot->replyMessage($request); } } diff --git a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/JoinEventHandler.php b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/JoinEventHandler.php index fcfbb0eb..8b51f48f 100644 --- a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/JoinEventHandler.php +++ b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/JoinEventHandler.php @@ -18,26 +18,31 @@ namespace LINE\LINEBot\KitchenSink\EventHandler; -use LINE\LINEBot; -use LINE\LINEBot\Event\JoinEvent; +use LINE\Clients\MessagingApi\Api\MessagingApiApi; +use LINE\Clients\MessagingApi\Model\ReplyMessageRequest; +use LINE\Clients\MessagingApi\Model\TextMessage; +use LINE\Constants\MessageType; use LINE\LINEBot\KitchenSink\EventHandler; +use LINE\Webhook\Model\GroupSource; +use LINE\Webhook\Model\JoinEvent; +use LINE\Webhook\Model\RoomSource; class JoinEventHandler implements EventHandler { - /** @var LINEBot $bot */ + /** @var MessagingApiApi $bot */ private $bot; - /** @var \Monolog\Logger $logger */ + /** @var \Psr\Log\LoggerInterface $logger */ private $logger; /** @var JoinEvent $joinEvent */ private $joinEvent; /** * JoinEventHandler constructor. - * @param LINEBot $bot - * @param \Monolog\Logger $logger + * @param MessagingApiApi $bot + * @param \Psr\Log\LoggerInterface $logger * @param JoinEvent $joinEvent */ - public function __construct($bot, $logger, JoinEvent $joinEvent) + public function __construct(MessagingApiApi $bot, \Psr\Log\LoggerInterface $logger, JoinEvent $joinEvent) { $this->bot = $bot; $this->logger = $logger; @@ -50,18 +55,25 @@ public function __construct($bot, $logger, JoinEvent $joinEvent) */ public function handle() { - if ($this->joinEvent->isGroupEvent()) { - $id = $this->joinEvent->getGroupId(); - } elseif ($this->joinEvent->isRoomEvent()) { - $id = $this->joinEvent->getRoomId(); + $source = $this->joinEvent->getSource(); + if ($source instanceof GroupSource) { + $id = $source->getGroupId(); + } elseif ($source instanceof RoomSource) { + $id = $source->getRoomId(); } else { $this->logger->error("Unknown event type"); return; } - $this->bot->replyText( - $this->joinEvent->getReplyToken(), - sprintf('Joined %s %s', $this->joinEvent->getType(), $id) - ); + $request = new ReplyMessageRequest([ + 'replyToken' => $this->joinEvent->getReplyToken(), + 'messages' => [ + new TextMessage([ + 'type' => MessageType::TEXT, + 'text' => sprintf('Joined %s %s', $this->joinEvent->getType(), $id), + ]), + ], + ]); + $this->bot->replyMessage($request); } } diff --git a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/LeaveEventHandler.php b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/LeaveEventHandler.php index 065ec858..d71e38d0 100644 --- a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/LeaveEventHandler.php +++ b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/LeaveEventHandler.php @@ -18,26 +18,28 @@ namespace LINE\LINEBot\KitchenSink\EventHandler; -use LINE\LINEBot; -use LINE\LINEBot\Event\LeaveEvent; +use LINE\Clients\MessagingApi\Api\MessagingApiApi; use LINE\LINEBot\KitchenSink\EventHandler; +use LINE\Webhook\Model\GroupSource; +use LINE\Webhook\Model\LeaveEvent; +use LINE\Webhook\Model\RoomSource; class LeaveEventHandler implements EventHandler { - /** @var LINEBot $bot */ + /** @var MessagingApiApi $bot */ private $bot; - /** @var \Monolog\Logger $logger */ + /** @var \Psr\Log\LoggerInterface $logger */ private $logger; /** @var LeaveEvent $leaveEvent */ private $leaveEvent; /** * LeaveEventHandler constructor. - * @param LINEBot $bot - * @param \Monolog\Logger $logger + * @param MessagingApiApi $bot + * @param \Psr\Log\LoggerInterface $logger * @param LeaveEvent $leaveEvent */ - public function __construct($bot, $logger, LeaveEvent $leaveEvent) + public function __construct(MessagingApiApi $bot, \Psr\Log\LoggerInterface $logger, LeaveEvent $leaveEvent) { $this->bot = $bot; $this->logger = $logger; @@ -46,10 +48,11 @@ public function __construct($bot, $logger, LeaveEvent $leaveEvent) public function handle() { - if ($this->leaveEvent->isGroupEvent()) { - $id = $this->leaveEvent->getGroupId(); - } elseif ($this->leaveEvent->isRoomEvent()) { - $id = $this->leaveEvent->getRoomId(); + $source = $this->leaveEvent->getSource(); + if ($source instanceof GroupSource) { + $id = $source->getGroupId(); + } elseif ($source instanceof RoomSource) { + $id = $source->getRoomId(); } else { $this->logger->error("Unknown event type"); return; diff --git a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/AudioMessageHandler.php b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/AudioMessageHandler.php index 80d2555f..3cc0210e 100644 --- a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/AudioMessageHandler.php +++ b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/AudioMessageHandler.php @@ -18,56 +18,64 @@ namespace LINE\LINEBot\KitchenSink\EventHandler\MessageHandler; -use LINE\LINEBot; -use LINE\LINEBot\Event\MessageEvent\AudioMessage; +use LINE\Clients\MessagingApi\Api\MessagingApiApi; +use LINE\Clients\MessagingApi\Api\MessagingApiBlobApi; +use LINE\Clients\MessagingApi\Model\AudioMessage; +use LINE\Clients\MessagingApi\Model\ReplyMessageRequest; +use LINE\Constants\MessageContentProviderType; +use LINE\Constants\MessageType; use LINE\LINEBot\KitchenSink\EventHandler; use LINE\LINEBot\KitchenSink\EventHandler\MessageHandler\Util\UrlBuilder; -use LINE\LINEBot\MessageBuilder\AudioMessageBuilder; +use LINE\Webhook\Model\AudioMessageContent; +use LINE\Webhook\Model\MessageEvent; +use SplFileObject; class AudioMessageHandler implements EventHandler { - /** @var LINEBot $bot */ + /** @var MessagingApiApi $bot */ private $bot; - /** @var \Monolog\Logger $logger */ + /** @var MessagingApiBlobApi $bot */ + private $botBlob; + /** @var \Psr\Log\LoggerInterface $logger */ private $logger; /** @var \Slim\Http\Request $logger */ private $req; - /** @var AudioMessage $audioMessage */ + /** @var AudioMessageContent $audioMessage */ private $audioMessage; + /** @var MessageEvent $event */ + private $event; /** * AudioMessageHandler constructor. - * @param LINEBot $bot - * @param \Monolog\Logger $logger - * @param \Slim\Http\Request $req - * @param AudioMessage $audioMessage + * @param MessagingApiApi $bot + * @param MessagingApiBlobApi $botBlob + * @param \Psr\Log\LoggerInterface $logger + * @param \Psr\Http\Message\RequestInterface $req + * @param MessageEvent $event */ - public function __construct($bot, $logger, \Slim\Http\Request $req, AudioMessage $audioMessage) + public function __construct(MessagingApiApi $bot, MessagingApiBlobApi $botBlob, \Psr\Log\LoggerInterface $logger, \Psr\Http\Message\RequestInterface $req, MessageEvent $event) { $this->bot = $bot; + $this->botBlob = $botBlob; $this->logger = $logger; $this->req = $req; - $this->audioMessage = $audioMessage; + $this->event = $event; + $this->audioMessage = $event->getMessage(); } public function handle() { - $replyToken = $this->audioMessage->getReplyToken(); + $replyToken = $this->event->getReplyToken(); $contentProvider = $this->audioMessage->getContentProvider(); - if ($contentProvider->isExternal()) { - $this->bot->replyMessage( - $replyToken, - new AudioMessageBuilder( - $contentProvider->getOriginalContentUrl(), - $this->audioMessage->getDuration() - ) - ); + if ($contentProvider->getType() == MessageContentProviderType::EXTERNAL) { + $this->replyAudioMessage($replyToken, $contentProvider->getOriginalContentUrl(), $this->audioMessage->getDuration()); return; } - $contentId = $this->audioMessage->getMessageId(); - $audio = $this->bot->getMessageContent($contentId)->getRawBody(); + $contentId = $this->audioMessage->getId(); + $sfo = $this->botBlob->getMessageContent($contentId); + $audio = $sfo->fread($sfo->getSize()); $tempFilePath = tempnam($_SERVER['DOCUMENT_ROOT'] . '/static/tmpdir', 'audio-'); unlink($tempFilePath); @@ -80,9 +88,20 @@ public function handle() $url = UrlBuilder::buildUrl($this->req, ['static', 'tmpdir', $filename]); - $this->bot->replyMessage( - $replyToken, - new AudioMessageBuilder($url, 100) - ); + $this->replyAudioMessage($replyToken, $url, 100); + } + + private function replyAudioMessage(string $replyToken, string $url, int $duration) + { + $message = new AudioMessage([ + 'type' => MessageType::AUDIO, + 'originalContentUrl' => $url, + 'duration' => $duration, + ]); + $request = new ReplyMessageRequest([ + 'replyToken' => $replyToken, + 'messages' => [$message], + ]); + $this->bot->replyMessage($request); } } diff --git a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/Flex/FlexSampleRestaurant.php b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/Flex/FlexSampleRestaurant.php index 8f079e22..e0afeee8 100644 --- a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/Flex/FlexSampleRestaurant.php +++ b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/Flex/FlexSampleRestaurant.php @@ -18,30 +18,35 @@ namespace LINE\LINEBot\KitchenSink\EventHandler\MessageHandler\Flex; -use LINE\LINEBot\TemplateActionBuilder\UriTemplateActionBuilder; -use LINE\LINEBot\TemplateActionBuilder\Uri\AltUriBuilder; -use LINE\LINEBot\Constant\Flex\ComponentButtonHeight; -use LINE\LINEBot\Constant\Flex\ComponentButtonStyle; -use LINE\LINEBot\Constant\Flex\ComponentFontSize; -use LINE\LINEBot\Constant\Flex\ComponentFontWeight; -use LINE\LINEBot\Constant\Flex\ComponentIconSize; -use LINE\LINEBot\Constant\Flex\ComponentImageAspectMode; -use LINE\LINEBot\Constant\Flex\ComponentImageAspectRatio; -use LINE\LINEBot\Constant\Flex\ComponentImageSize; -use LINE\LINEBot\Constant\Flex\ComponentLayout; -use LINE\LINEBot\Constant\Flex\ComponentMargin; -use LINE\LINEBot\Constant\Flex\ComponentSpaceSize; -use LINE\LINEBot\Constant\Flex\ComponentSpacing; -use LINE\LINEBot\Constant\Flex\BubleContainerSize; -use LINE\LINEBot\MessageBuilder\FlexMessageBuilder; -use LINE\LINEBot\MessageBuilder\Flex\ComponentBuilder\BoxComponentBuilder; -use LINE\LINEBot\MessageBuilder\Flex\ComponentBuilder\ButtonComponentBuilder; -use LINE\LINEBot\MessageBuilder\Flex\ComponentBuilder\IconComponentBuilder; -use LINE\LINEBot\MessageBuilder\Flex\ComponentBuilder\ImageComponentBuilder; -use LINE\LINEBot\MessageBuilder\Flex\ComponentBuilder\SpacerComponentBuilder; -use LINE\LINEBot\MessageBuilder\Flex\ComponentBuilder\TextComponentBuilder; -use LINE\LINEBot\MessageBuilder\Flex\ComponentBuilder\SpanComponentBuilder; -use LINE\LINEBot\MessageBuilder\Flex\ContainerBuilder\BubbleContainerBuilder; +use LINE\Clients\MessagingApi\Model\AltUri; +use LINE\Clients\MessagingApi\Model\FlexBox; +use LINE\Clients\MessagingApi\Model\FlexBubble; +use LINE\Clients\MessagingApi\Model\FlexButton; +use LINE\Clients\MessagingApi\Model\FlexComponent; +use LINE\Clients\MessagingApi\Model\FlexIcon; +use LINE\Clients\MessagingApi\Model\FlexImage; +use LINE\Clients\MessagingApi\Model\FlexMessage; +use LINE\Clients\MessagingApi\Model\FlexSpacer; +use LINE\Clients\MessagingApi\Model\FlexSpan; +use LINE\Clients\MessagingApi\Model\FlexText; +use LINE\Clients\MessagingApi\Model\URIAction; +use LINE\Constants\ActionType; +use LINE\Constants\Flex\BubbleContainerSize; +use LINE\Constants\Flex\ComponentButtonHeight; +use LINE\Constants\Flex\ComponentButtonStyle; +use LINE\Constants\Flex\ComponentFontSize; +use LINE\Constants\Flex\ComponentFontWeight; +use LINE\Constants\Flex\ComponentIconSize; +use LINE\Constants\Flex\ComponentImageAspectMode; +use LINE\Constants\Flex\ComponentImageAspectRatio; +use LINE\Constants\Flex\ComponentImageSize; +use LINE\Constants\Flex\ComponentLayout; +use LINE\Constants\Flex\ComponentMargin; +use LINE\Constants\Flex\ComponentSpaceSize; +use LINE\Constants\Flex\ComponentSpacing; +use LINE\Constants\Flex\ComponentType; +use LINE\Constants\Flex\ContainerType; +use LINE\Constants\MessageType; /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) @@ -51,147 +56,197 @@ class FlexSampleRestaurant /** * Create sample restaurant flex message * - * @return \LINE\LINEBot\MessageBuilder\FlexMessageBuilder + * @return \LINE\MessagingApi\Model\FlexMessage */ - public static function get() + public static function get(): FlexMessage { - return FlexMessageBuilder::builder() - ->setAltText('Restaurant') - ->setContents( - BubbleContainerBuilder::builder() - ->setHero(self::createHeroBlock()) - ->setBody(self::createBodyBlock()) - ->setFooter(self::createFooterBlock()) - ->setSize(BubleContainerSize::GIGA) - ); + return new FlexMessage([ + 'type' => MessageType::FLEX, + 'altText' => 'Restaurant', + 'contents' => new FlexBubble([ + 'type' => ContainerType::BUBBLE, + 'hero' => self::createHeroBlock(), + 'body' => self::createBodyBlock(), + 'footer' => self::createFooterBlock(), + 'size' => BubbleContainerSize::GIGA, + ]) + ]); } - private static function createHeroBlock() + private static function createHeroBlock(): FlexComponent { - return ImageComponentBuilder::builder() - ->setUrl('https://example.com/cafe.png') - ->setSize(ComponentImageSize::FULL) - ->setAspectRatio(ComponentImageAspectRatio::R20TO13) - ->setAspectMode(ComponentImageAspectMode::COVER) - ->setAction( - new UriTemplateActionBuilder( - null, - 'https://example.com', - new AltUriBuilder('https://example.com#desktop') - ) - ); + return new FlexImage([ + 'type' => ComponentType::IMAGE, + 'url' => 'https://example.com/cafe.png', + 'size' => ComponentImageSize::FULL, + 'aspectRatio' => ComponentImageAspectRatio::R20TO13, + 'aspectMode' => ComponentImageAspectMode::COVER, + 'action' => new URIAction([ + 'type' => ActionType::URI, + 'label' => 'cafe hero', + 'uri' => 'https://example.com', + 'altUri' => new AltUri(['desktop' => 'https://example.com#desktop']), + ]), + ]); } private static function createBodyBlock() { - $title = TextComponentBuilder::builder() - ->setText('Brown Cafe') - ->setWeight(ComponentFontWeight::BOLD) - ->setSize(ComponentFontSize::XL); + return new FlexBox([ + 'type' => ComponentType::BOX, + 'layout' => ComponentLayout::VERTICAL, + 'backgroundColor' => '#fafafa', + 'paddingAll' => '8%', + 'contents' => [ + // Title + new FlexText([ + 'type' => ComponentType::TEXT, + 'text' => 'Brown Cafe', + 'weight' => ComponentFontWeight::BOLD, + 'size' => ComponentFontSize::XL, + ]), + self::createBodyReview(), + self::createBodyInfoBlock(), + ], + ]); + } - $goldStar = IconComponentBuilder::builder() - ->setUrl('https://example.com/gold_star.png') - ->setSize(ComponentIconSize::SM); - $grayStar = IconComponentBuilder::builder() - ->setUrl('https://example.com/gray_star.png') - ->setSize(ComponentIconSize::SM); - $point = TextComponentBuilder::builder() - ->setText('4.0') - ->setSize(ComponentFontSize::SM) - ->setColor('#999999') - ->setMargin(ComponentMargin::MD) - ->setFlex(0); - $review = BoxComponentBuilder::builder() - ->setLayout(ComponentLayout::BASELINE) - ->setMargin(ComponentMargin::MD) - ->setContents([$goldStar, $goldStar, $goldStar, $goldStar, $grayStar, $point]); + private static function createBodyReview(): FlexBox + { + $goldStar = new FlexIcon([ + 'type' => ComponentType::ICON, + 'url' => 'https://example.com/gold_star.png', + 'size' => ComponentIconSize::SM, + ]); + $grayStar = new FlexIcon([ + 'type' => ComponentType::ICON, + 'url' => 'https://example.com/gray_star.png', + 'size' => ComponentIconSize::SM, + ]); + $point = new FlexText([ + 'type' => ComponentType::TEXT, + 'text' => '4.0', + 'size' => ComponentFontSize::SM, + 'color' => '#999999', + 'margin' => ComponentMargin::MD, + 'flex' => 0, + ]); - $place = BoxComponentBuilder::builder() - ->setLayout(ComponentLayout::BASELINE) - ->setSpacing(ComponentSpacing::SM) - ->setContents([ - TextComponentBuilder::builder() - ->setText('Place') - ->setColor('#aaaaaa') - ->setSize(ComponentFontSize::SM) - ->setFlex(1), - TextComponentBuilder::builder() - ->setText('Miraina Tower, 4-1-6 Shinjuku, Tokyo') - ->setWrap(true) - ->setColor('#666666') - ->setSize(ComponentFontSize::SM) - ->setFlex(5) - ]); - $time = BoxComponentBuilder::builder() - ->setLayout(ComponentLayout::BASELINE) - ->setSpacing(ComponentSpacing::SM) - ->setContents([ - TextComponentBuilder::builder() - ->setText('Time') - ->setColor('#aaaaaa') - ->setSize(ComponentFontSize::SM) - ->setFlex(1), - TextComponentBuilder::builder() - ->setText('10:00 - 23:00') - ->setWrap(true) - ->setColor('#666666') - ->setSize(ComponentFontSize::SM) - ->setFlex(5) - ->setContents([ - SpanComponentBuilder::builder() - ->setText('10:00'), - SpanComponentBuilder::builder() - ->setText('-') - ->setColor('#a0a0a0') - ->setSize(ComponentFontSize::XS), - SpanComponentBuilder::builder() - ->setText('23:00'), - ]) - ]); - $info = BoxComponentBuilder::builder() - ->setLayout(ComponentLayout::VERTICAL) - ->setMargin(ComponentMargin::LG) - ->setSpacing(ComponentSpacing::SM) - ->setContents([$place, $time]); + return new FlexBox([ + 'type' => ComponentType::BOX, + 'layout' => ComponentLayout::BASELINE, + 'margin' => ComponentMargin::MD, + 'contents' => [$goldStar, $goldStar, $goldStar, $goldStar, $grayStar, $point], + ]); + } - return BoxComponentBuilder::builder() - ->setLayout(ComponentLayout::VERTICAL) - ->setBackgroundColor('#fafafa') - ->setPaddingAll('8%') - ->setContents([$title, $review, $info]); + private static function createBodyInfoBlock(): FlexBox + { + $place = new FlexBox([ + 'type' => ComponentType::BOX, + 'layout' => ComponentLayout::BASELINE, + 'spacing' => ComponentSpacing::SM, + 'contents' => [ + new FlexText([ + 'type' => ComponentType::TEXT, + 'text' => 'Place', + 'color' => '#aaaaaa', + 'size' => ComponentFontSize::SM, + 'flex' => 1, + ]), + new FlexText([ + 'type' => ComponentType::TEXT, + 'text' => 'Miraina Tower, 4-1-6 Shinjuku, Tokyo', + 'wrap' => true, + 'color' => '#666666', + 'size' => ComponentFontSize::SM, + 'flex' => 5, + ]), + ], + ]); + $time = new FlexBox([ + 'type' => ComponentType::BOX, + 'layout' => ComponentLayout::BASELINE, + 'spacing' => ComponentSpacing::SM, + 'contents' => [ + new FlexText([ + 'type' => ComponentType::TEXT, + 'text' => 'Time', + 'color' => '#aaaaaa', + 'size' => ComponentFontSize::SM, + 'flex' => 1, + ]), + new FlexText([ + 'type' => ComponentType::TEXT, + 'text' => '10:00 - 23:00', + 'wrap' => true, + 'color' => '#666666', + 'size' => ComponentFontSize::SM, + 'flex' => 5, + 'contents' => [ + new FlexSpan([ + 'type' => ComponentType::SPAN, + 'text' => '10:00', + ]), + new FlexSpan([ + 'type' => ComponentType::SPAN, + 'text' => '-', + 'color' => '#a0a0a0', + 'size' => ComponentFontSize::XS, + ]), + new FlexSpan([ + 'type' => ComponentType::SPAN, + 'text' => '23:00', + ]), + ], + ]), + ], + ]); + + return new FlexBox([ + 'type' => ComponentType::BOX, + 'layout' => ComponentLayout::VERTICAL, + 'margin' => ComponentMargin::LG, + 'spacing' => ComponentSpacing::SM, + 'contents' => [$place, $time], + ]); } private static function createFooterBlock() { - $callButton = ButtonComponentBuilder::builder() - ->setStyle(ComponentButtonStyle::LINK) - ->setHeight(ComponentButtonHeight::SM) - ->setAction( - new UriTemplateActionBuilder( - 'CALL', - 'https://example.com', - new AltUriBuilder('https://example.com#desktop') - ) - ); - $websiteButton = ButtonComponentBuilder::builder() - ->setStyle(ComponentButtonStyle::LINK) - ->setHeight(ComponentButtonHeight::SM) - ->setAction( - new UriTemplateActionBuilder( - 'WEBSITE', - 'https://example.com', - new AltUriBuilder('https://example.com#desktop') - ) - ); - $spacer = new SpacerComponentBuilder(ComponentSpaceSize::SM); + $callButton = new FlexButton([ + 'type' => ComponentType::BUTTON, + 'style' => ComponentButtonStyle::LINK, + 'height' => ComponentButtonHeight::SM, + 'action' => new URIAction([ + 'type' => ActionType::URI, + 'label' => 'CALL', + 'uri' => 'https://example.com', + 'altUri' => new AltUri(['desktop' => 'https://example.com#desktop']), + ]), + ]); + $websiteButton = new FlexButton([ + 'type' => ComponentType::BUTTON, + 'style' => ComponentButtonStyle::LINK, + 'height' => ComponentButtonHeight::SM, + 'action' => new URIAction([ + 'type' => ActionType::URI, + 'label' => 'WEBSITE', + 'uri' => 'https://example.com', + 'altUri' => new AltUri(['desktop' => 'https://example.com#desktop']), + ]), + ]); + $spacer = new FlexSpacer(['type' => ComponentType::SPACER, 'size' => ComponentSpaceSize::SM]); - return BoxComponentBuilder::builder() - ->setLayout(ComponentLayout::VERTICAL) - ->setSpacing(ComponentSpacing::SM) - ->setFlex(0) - ->setBackgroundColor('#fafafa') - ->setBorderColor('#e0e0e0') - ->setBorderWidth('1px') - ->setContents([$callButton, $websiteButton, $spacer]); + return new FlexBox([ + 'type' => ComponentType::BOX, + 'layout' => ComponentLayout::VERTICAL, + 'spacing' => ComponentSpacing::SM, + 'flex' => 0, + 'backgroundColor' => '#fafafa', + 'borderColor' => '#e0e0e0', + 'borderWidth' => '1px', + 'contents' => [$callButton, $websiteButton, $spacer], + ]); } } diff --git a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/Flex/FlexSampleShopping.php b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/Flex/FlexSampleShopping.php index 90e4b066..e3b5c174 100644 --- a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/Flex/FlexSampleShopping.php +++ b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/Flex/FlexSampleShopping.php @@ -18,25 +18,29 @@ namespace LINE\LINEBot\KitchenSink\EventHandler\MessageHandler\Flex; -use LINE\LINEBot\TemplateActionBuilder\UriTemplateActionBuilder; -use LINE\LINEBot\TemplateActionBuilder\Uri\AltUriBuilder; -use LINE\LINEBot\Constant\Flex\ComponentButtonStyle; -use LINE\LINEBot\Constant\Flex\ComponentFontSize; -use LINE\LINEBot\Constant\Flex\ComponentFontWeight; -use LINE\LINEBot\Constant\Flex\ComponentGravity; -use LINE\LINEBot\Constant\Flex\ComponentImageAspectMode; -use LINE\LINEBot\Constant\Flex\ComponentImageAspectRatio; -use LINE\LINEBot\Constant\Flex\ComponentImageSize; -use LINE\LINEBot\Constant\Flex\ComponentLayout; -use LINE\LINEBot\Constant\Flex\ComponentMargin; -use LINE\LINEBot\Constant\Flex\ComponentSpacing; -use LINE\LINEBot\MessageBuilder\FlexMessageBuilder; -use LINE\LINEBot\MessageBuilder\Flex\ComponentBuilder\BoxComponentBuilder; -use LINE\LINEBot\MessageBuilder\Flex\ComponentBuilder\ButtonComponentBuilder; -use LINE\LINEBot\MessageBuilder\Flex\ComponentBuilder\ImageComponentBuilder; -use LINE\LINEBot\MessageBuilder\Flex\ComponentBuilder\TextComponentBuilder; -use LINE\LINEBot\MessageBuilder\Flex\ContainerBuilder\BubbleContainerBuilder; -use LINE\LINEBot\MessageBuilder\Flex\ContainerBuilder\CarouselContainerBuilder; +use LINE\Clients\MessagingApi\Model\AltUri; +use LINE\Clients\MessagingApi\Model\FlexBox; +use LINE\Clients\MessagingApi\Model\FlexBubble; +use LINE\Clients\MessagingApi\Model\FlexButton; +use LINE\Clients\MessagingApi\Model\FlexCarousel; +use LINE\Clients\MessagingApi\Model\FlexImage; +use LINE\Clients\MessagingApi\Model\FlexMessage; +use LINE\Clients\MessagingApi\Model\FlexText; +use LINE\Clients\MessagingApi\Model\URIAction; +use LINE\Constants\ActionType; +use LINE\Constants\Flex\ComponentButtonStyle; +use LINE\Constants\Flex\ComponentFontSize; +use LINE\Constants\Flex\ComponentFontWeight; +use LINE\Constants\Flex\ComponentGravity; +use LINE\Constants\Flex\ComponentImageAspectMode; +use LINE\Constants\Flex\ComponentImageAspectRatio; +use LINE\Constants\Flex\ComponentImageSize; +use LINE\Constants\Flex\ComponentLayout; +use LINE\Constants\Flex\ComponentMargin; +use LINE\Constants\Flex\ComponentSpacing; +use LINE\Constants\Flex\ComponentType; +use LINE\Constants\Flex\ContainerType; +use LINE\Constants\MessageType; /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) @@ -61,128 +65,156 @@ class FlexSampleShopping /** * Create sample shopping flex message * - * @return \LINE\LINEBot\MessageBuilder\FlexMessageBuilder + * @return \LINE\Clients\MessagingApi\Model\FlexMessage */ - public static function get() + public static function get(): FlexMessage { - return FlexMessageBuilder::builder() - ->setAltText('Shopping') - ->setContents(new CarouselContainerBuilder([ - self::createItemBubble(111), - self::createItemBubble(112), - self::createMoreBubble() - ])); + return new FlexMessage([ + 'type' => MessageType::FLEX, + 'altText' => 'Shopping', + 'contents' => new FlexCarousel([ + 'type' => ContainerType::CAROUSEL, + 'contents' => [ + self::createItemBubble(111), + self::createItemBubble(112), + self::createMoreBubble(), + ], + ]), + ]); } - private static function createItemBubble($itemId) + private static function createItemBubble($itemId): FlexBubble { $item = self::$items[$itemId]; - return BubbleContainerBuilder::builder() - ->setHero(self::createItemHeroBlock($item)) - ->setBody(self::createItemBodyBlock($item)) - ->setFooter(self::createItemFooterBlock($item)); + return new FlexBubble([ + 'type' => ContainerType::BUBBLE, + 'hero' => self::createItemHeroBlock($item), + 'body' => self::createItemBodyBlock($item), + 'footer' => self::createItemFooterBlock($item), + ]); } - private static function createItemHeroBlock($item) + private static function createItemHeroBlock($item): FlexImage { - return ImageComponentBuilder::builder() - ->setUrl($item['photo']) - ->setSize(ComponentImageSize::FULL) - ->setAspectRatio(ComponentImageAspectRatio::R20TO13) - ->setAspectMode(ComponentImageAspectMode::COVER); + return new FlexImage([ + 'type' => ComponentType::IMAGE, + 'url' => $item['photo'], + 'size' => ComponentImageSize::FULL, + 'aspectRatio' => ComponentImageAspectRatio::R20TO13, + 'aspectMode' => ComponentImageAspectMode::COVER, + ]); } - private static function createItemBodyBlock($item) + private static function createItemBodyBlock($item): FlexBox { - $components = []; - $components[] = TextComponentBuilder::builder() - ->setText($item['name']) - ->setWrap(true) - ->setWeight(ComponentFontWeight::BOLD) - ->setSize(ComponentFontSize::XL); - $price = explode('.', number_format($item['price'], 2)); - $components[] = BoxComponentBuilder::builder() - ->setLayout(ComponentLayout::BASELINE) - ->setContents([ - TextComponentBuilder::builder() - ->setText('$' . $price[0]) - ->setWrap(true) - ->setWeight(ComponentFontWeight::BOLD) - ->setSize(ComponentFontSize::XL) - ->setFlex(0), - TextComponentBuilder::builder() - ->setText('.' . $price[1]) - ->setWrap(true) - ->setWeight(ComponentFontWeight::BOLD) - ->setSize(ComponentFontSize::SM) - ->setFlex(0) - ]); + $components = [ + new FlexText([ + 'type' => ComponentType::TEXT, + 'text' => $item['name'], + 'wrap' => true, + 'weight' => ComponentFontWeight::BOLD, + 'size' => ComponentFontSize::XL, + ]), + new FlexBox([ + 'type' => ComponentType::BOX, + 'layout' => ComponentLayout::BASELINE, + 'contents' => [ + new FlexText([ + 'type' => ComponentType::TEXT, + 'text' => '$' . $price[0], + 'wrap' => true, + 'weight' => ComponentFontWeight::BOLD, + 'size' => ComponentFontSize::XL, + 'flex' => 0, + ]), + new FlexText([ + 'type' => ComponentType::TEXT, + 'text' => '.' . $price[1], + 'wrap' => true, + 'weight' => ComponentFontWeight::BOLD, + 'size' => ComponentFontSize::SM, + 'flex' => 0, + ]), + ], + ]) + ]; if (!$item['stock']) { - $components[] = TextComponentBuilder::builder() - ->setText('Temporarily out of stock') - ->setWrap(true) - ->setSize(ComponentFontSize::XXS) - ->setMargin(ComponentMargin::MD) - ->setColor('#ff5551') - ->setFlex(0); + $components[] = new FlexText([ + 'type' => ComponentType::TEXT, + 'text' => 'Temporarily out of stock', + 'wrap' => true, + 'size' => ComponentFontSize::XXS, + 'margin' => ComponentMargin::MD, + 'color' => '#ff5551', + 'flex' => 0, + ]); } - return BoxComponentBuilder::builder() - ->setLayout(ComponentLayout::VERTICAL) - ->setSpacing(ComponentSpacing::SM) - ->setContents($components); + return new FlexBox([ + 'type' => ComponentType::BOX, + 'layout' => ComponentLayout::VERTICAL, + 'spacing' => ComponentSpacing::SM, + 'contents' => $components, + ]); } - private static function createItemFooterBlock($item) + private static function createItemFooterBlock($item): FlexBox { $color = $item['stock'] ? null : '#aaaaaa'; - $cartButton = ButtonComponentBuilder::builder() - ->setStyle(ComponentButtonStyle::PRIMARY) - ->setColor($color) - ->setAction( - new UriTemplateActionBuilder( - 'Add to Cart', - 'https://example.com', - new AltUriBuilder('https://example.com#desktop') - ) - ); + $cartButton = new FlexButton([ + 'type' => ComponentType::BUTTON, + 'style' => ComponentButtonStyle::PRIMARY, + 'color' => $color, + 'action' => new URIAction([ + 'type' => ActionType::URI, + 'label' => 'Add to Cart', + 'uri' => 'https://example.com', + 'altUri' => new AltUri(['desktop' => 'https://example.com#desktop']), + ]), + ]); - $wishButton = ButtonComponentBuilder::builder() - ->setAction( - new UriTemplateActionBuilder( - 'Add to wishlist', - 'https://example.com', - new AltUriBuilder('https://example.com#desktop') - ) - ); + $wishButton = new FlexButton([ + 'type' => ComponentType::BUTTON, + 'action' => new URIAction([ + 'type' => ActionType::URI, + 'label' => 'Add to wishlist', + 'uri' => 'https://example.com', + 'altUri' => new AltUri(['desktop' => 'https://example.com#desktop']), + ]), + ]); - return BoxComponentBuilder::builder() - ->setLayout(ComponentLayout::VERTICAL) - ->setSpacing(ComponentSpacing::SM) - ->setContents([$cartButton, $wishButton]); + return new FlexBox([ + 'type' => ComponentType::BOX, + 'layout' => ComponentLayout::VERTICAL, + 'spacing' => ComponentSpacing::SM, + 'contents' => [$cartButton, $wishButton], + ]); } - private static function createMoreBubble() + private static function createMoreBubble(): FlexBubble { - return BubbleContainerBuilder::builder() - ->setBody( - BoxComponentBuilder::builder() - ->setLayout(ComponentLayout::VERTICAL) - ->setSpacing(ComponentSpacing::SM) - ->setContents([ - ButtonComponentBuilder::builder() - ->setFlex(1) - ->setGravity(ComponentGravity::CENTER) - ->setAction( - new UriTemplateActionBuilder( - 'See more', - 'https://example.com', - new AltUriBuilder('https://example.com#desktop') - ) - ) - ]) - ); + return new FlexBubble([ + 'type' => ContainerType::BUBBLE, + 'body' => new FlexBox([ + 'type' => ComponentType::BOX, + 'layout' => ComponentLayout::VERTICAL, + 'spacing' => ComponentSpacing::SM, + 'contents' => [ + new FlexButton([ + 'type' => ComponentType::BUTTON, + 'flex' => 1, + 'gravity' => ComponentGravity::CENTER, + 'action' => new URIAction([ + 'type' => ActionType::URI, + 'label' => 'See more', + 'uri' => 'https://example.com', + 'altUri' => new AltUri(['desktop' => 'https://example.com#desktop']), + ]), + ]), + ], + ]), + ]); } } diff --git a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/ImageMessageHandler.php b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/ImageMessageHandler.php index ae2bd7f2..ba116ac9 100644 --- a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/ImageMessageHandler.php +++ b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/ImageMessageHandler.php @@ -18,56 +18,67 @@ namespace LINE\LINEBot\KitchenSink\EventHandler\MessageHandler; -use LINE\LINEBot; -use LINE\LINEBot\Event\MessageEvent\ImageMessage; +use LINE\Clients\MessagingApi\Api\MessagingApiApi; +use LINE\Clients\MessagingApi\Api\MessagingApiBlobApi; +use LINE\Clients\MessagingApi\Model\ImageMessage; +use LINE\Clients\MessagingApi\Model\ReplyMessageRequest; +use LINE\Constants\MessageContentProviderType; +use LINE\Constants\MessageType; use LINE\LINEBot\KitchenSink\EventHandler; use LINE\LINEBot\KitchenSink\EventHandler\MessageHandler\Util\UrlBuilder; -use LINE\LINEBot\MessageBuilder\ImageMessageBuilder; +use LINE\Webhook\Model\ImageMessageContent; +use LINE\Webhook\Model\MessageEvent; class ImageMessageHandler implements EventHandler { - /** @var LINEBot $bot */ + /** @var = $bot */ private $bot; + /** @var MessagingApiBlobApi $bot */ + private $botBlob; /** @var \Monolog\Logger $logger */ private $logger; /** @var \Slim\Http\Request $logger */ private $req; - /** @var ImageMessage $imageMessage */ + /** @var ImageMessageContent $imageMessage */ private $imageMessage; + /** @var MessageEvent $event */ + private $event; /** * ImageMessageHandler constructor. - * @param LINEBot $bot - * @param \Monolog\Logger $logger - * @param \Slim\Http\Request $req - * @param ImageMessage $imageMessage + * @param MessagingApiApi $bot + * @param MessagingApiBlobApi $botBlob + * @param \Psr\Log\LoggerInterface $logger + * @param \Psr\Http\Message\RequestInterface $req + * @param MessageEvent $event */ - public function __construct($bot, $logger, \Slim\Http\Request $req, ImageMessage $imageMessage) + public function __construct(MessagingApiApi $bot, MessagingApiBlobApi $botBlob, \Psr\Log\LoggerInterface $logger, \Psr\Http\Message\RequestInterface $req, MessageEvent $event) { $this->bot = $bot; + $this->botBlob = $botBlob; $this->logger = $logger; $this->req = $req; - $this->imageMessage = $imageMessage; + $this->event = $event; + $this->imageMessage = $event->getMessage(); } public function handle() { - $replyToken = $this->imageMessage->getReplyToken(); + $replyToken = $this->event->getReplyToken(); $contentProvider = $this->imageMessage->getContentProvider(); - if ($contentProvider->isExternal()) { - $this->bot->replyMessage( + if ($contentProvider->getType() == MessageContentProviderType::EXTERNAL) { + $this->replyImageMessage( $replyToken, - new ImageMessageBuilder( - $contentProvider->getOriginalContentUrl(), - $contentProvider->getPreviewImageUrl() - ) + $contentProvider->getOriginalContentUrl(), + $contentProvider->getPreviewImageUrl(), ); return; } - $contentId = $this->imageMessage->getMessageId(); - $image = $this->bot->getMessageContent($contentId)->getRawBody(); + $contentId = $this->imageMessage->getId(); + $sfo = $this->botBlob->getMessageContent($contentId); + $image = $sfo->fread($sfo->getSize()); $tempFilePath = tempnam($_SERVER['DOCUMENT_ROOT'] . '/static/tmpdir', 'image-'); unlink($tempFilePath); @@ -82,6 +93,20 @@ public function handle() // NOTE: You should pass the url of small image to `previewImageUrl`. // This sample doesn't treat that. - $this->bot->replyMessage($replyToken, new ImageMessageBuilder($url, $url)); + $this->replyImageMessage($replyToken, $url, $url); + } + + private function replyImageMessage(string $replyToken, string $original, string $preview) + { + $message = new ImageMessage([ + 'type' => MessageType::IMAGE, + 'originalContentUrl' => $original, + 'previewImageUrl' => $preview, + ]); + $request = new ReplyMessageRequest([ + 'replyToken' => $replyToken, + 'messages' => [$message], + ]); + $this->bot->replyMessage($request); } } diff --git a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/LocationMessageHandler.php b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/LocationMessageHandler.php index 59e3678e..2ff78127 100644 --- a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/LocationMessageHandler.php +++ b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/LocationMessageHandler.php @@ -18,44 +18,54 @@ namespace LINE\LINEBot\KitchenSink\EventHandler\MessageHandler; -use LINE\LINEBot; -use LINE\LINEBot\Event\MessageEvent\LocationMessage; +use LINE\Clients\MessagingApi\Api\MessagingApiApi; +use LINE\Clients\MessagingApi\Model\LocationMessage; +use LINE\Clients\MessagingApi\Model\ReplyMessageRequest; +use LINE\Constants\MessageType; use LINE\LINEBot\KitchenSink\EventHandler; -use LINE\LINEBot\MessageBuilder\LocationMessageBuilder; +use LINE\Webhook\Model\LocationMessageContent; +use LINE\Webhook\Model\MessageEvent; class LocationMessageHandler implements EventHandler { - /** @var LINEBot $bot */ + /** @var MessagingApiApi $bot */ private $bot; - /** @var \Monolog\Logger $logger */ + /** @var \Psr\Log\LoggerInterface $logger */ private $logger; - /** @var LocationMessage $event */ + /** @var LocationMessageContent $locationMessage */ private $locationMessage; + /** @var MessageEvent $event */ + private $event; /** * LocationMessageHandler constructor. - * @param LINEBot $bot - * @param \Monolog\Logger $logger - * @param LocationMessage $locationMessage + * @param MessagingApiApi $bot + * @param \Psr\Log\LoggerInterface $logger + * @param MessageEvent $event */ - public function __construct($bot, $logger, LocationMessage $locationMessage) + public function __construct(MessagingApiApi $bot, \Psr\Log\LoggerInterface $logger, MessageEvent $event) { $this->bot = $bot; $this->logger = $logger; - $this->locationMessage = $locationMessage; + $this->event = $event; + $this->locationMessage = $event->getMessage(); } public function handle() { - $replyToken = $this->locationMessage->getReplyToken(); - $title = $this->locationMessage->getTitle(); - $address = $this->locationMessage->getAddress(); - $latitude = $this->locationMessage->getLatitude(); - $longitude = $this->locationMessage->getLongitude(); + $replyToken = $this->event->getReplyToken(); - $this->bot->replyMessage( - $replyToken, - new LocationMessageBuilder($title, $address, $latitude, $longitude) - ); + $message = new LocationMessage([ + 'type' => MessageType::LOCATION, + 'title' => $this->locationMessage->getTitle(), + 'address' => $this->locationMessage->getAddress(), + 'latitude' => $this->locationMessage->getLatitude(), + 'longitude' => $this->locationMessage->getLongitude(), + ]); + $request = new ReplyMessageRequest([ + 'replyToken' => $replyToken, + 'messages' => [$message], + ]); + $this->bot->replyMessage($request); } } diff --git a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/StickerMessageHandler.php b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/StickerMessageHandler.php index 05f6f137..555952d3 100644 --- a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/StickerMessageHandler.php +++ b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/StickerMessageHandler.php @@ -18,38 +18,51 @@ namespace LINE\LINEBot\KitchenSink\EventHandler\MessageHandler; -use LINE\LINEBot; -use LINE\LINEBot\Event\MessageEvent\StickerMessage; +use LINE\Clients\MessagingApi\Api\MessagingApiApi; +use LINE\Clients\MessagingApi\Model\ReplyMessageRequest; +use LINE\Clients\MessagingApi\Model\StickerMessage; +use LINE\Constants\MessageType; use LINE\LINEBot\KitchenSink\EventHandler; -use LINE\LINEBot\MessageBuilder\StickerMessageBuilder; +use LINE\Webhook\Model\MessageEvent; +use LINE\Webhook\Model\StickerMessageContent; class StickerMessageHandler implements EventHandler { /** @var LINEBot $bot */ private $bot; - /** @var \Monolog\Logger $logger */ + /** @var \Psr\Log\LoggerInterface $logger */ private $logger; - /** @var StickerMessage $stickerMessage */ + /** @var StickerMessageContent $stickerMessage */ private $stickerMessage; + /** @var MessageEvent $event */ + private $event; /** * StickerMessageHandler constructor. - * @param LINEBot $bot - * @param \Monolog\Logger $logger - * @param StickerMessage $stickerMessage + * @param MessagingApiApi $bot + * @param \Psr\Log\LoggerInterface $logger + * @param MessageEvent $event */ - public function __construct($bot, $logger, StickerMessage $stickerMessage) + public function __construct(MessagingApiApi $bot, \Psr\Log\LoggerInterface $logger, MessageEvent $event) { $this->bot = $bot; $this->logger = $logger; - $this->stickerMessage = $stickerMessage; + $this->event = $event; + $this->stickerMessage = $event->getMessage(); } public function handle() { - $replyToken = $this->stickerMessage->getReplyToken(); - $packageId = $this->stickerMessage->getPackageId(); - $stickerId = $this->stickerMessage->getStickerId(); - $this->bot->replyMessage($replyToken, new StickerMessageBuilder($packageId, $stickerId)); + $replyToken = $this->event->getReplyToken(); + $message = new StickerMessage([ + 'type' => MessageType::STICKER, + 'packageId' => $this->stickerMessage->getPackageId(), + 'stickerId' => $this->stickerMessage->getStickerId(), + ]); + $request = new ReplyMessageRequest([ + 'replyToken' => $replyToken, + 'messages' => [$message], + ]); + $this->bot->replyMessage($request); } } diff --git a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/TextMessageHandler.php b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/TextMessageHandler.php index 8c4efc32..4e86d68c 100644 --- a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/TextMessageHandler.php +++ b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/TextMessageHandler.php @@ -18,36 +18,43 @@ namespace LINE\LINEBot\KitchenSink\EventHandler\MessageHandler; -use LINE\LINEBot; -use LINE\LINEBot\ImagemapActionBuilder\AreaBuilder; -use LINE\LINEBot\ImagemapActionBuilder\ImagemapMessageActionBuilder; -use LINE\LINEBot\ImagemapActionBuilder\ImagemapUriActionBuilder; -use LINE\LINEBot\MessageBuilder\TextMessageBuilder; -use LINE\LINEBot\MessageBuilder\Text\EmojiTextBuilder; -use LINE\LINEBot\MessageBuilder\Text\EmojiBuilder; -use LINE\LINEBot\QuickReplyBuilder\ButtonBuilder\QuickReplyButtonBuilder; -use LINE\LINEBot\QuickReplyBuilder\QuickReplyMessageBuilder; -use LINE\LINEBot\TemplateActionBuilder\CameraRollTemplateActionBuilder; -use LINE\LINEBot\TemplateActionBuilder\CameraTemplateActionBuilder; -use LINE\LINEBot\TemplateActionBuilder\DatetimePickerTemplateActionBuilder; -use LINE\LINEBot\TemplateActionBuilder\LocationTemplateActionBuilder; -use LINE\LINEBot\TemplateActionBuilder\MessageTemplateActionBuilder; -use LINE\LINEBot\TemplateActionBuilder\PostbackTemplateActionBuilder; -use LINE\LINEBot\TemplateActionBuilder\UriTemplateActionBuilder; -use LINE\LINEBot\Event\MessageEvent\TextMessage; +use LINE\Clients\MessagingApi\Api\MessagingApiApi; +use LINE\Clients\MessagingApi\Model\ButtonsTemplate; +use LINE\Clients\MessagingApi\Model\CameraAction; +use LINE\Clients\MessagingApi\Model\CameraRollAction; +use LINE\Clients\MessagingApi\Model\CarouselColumn; +use LINE\Clients\MessagingApi\Model\CarouselTemplate; +use LINE\Clients\MessagingApi\Model\ConfirmTemplate; +use LINE\Clients\MessagingApi\Model\DatetimePickerAction; +use LINE\Clients\MessagingApi\Model\Emoji; +use LINE\Clients\MessagingApi\Model\ImagemapArea; +use LINE\Clients\MessagingApi\Model\ImagemapBaseSize; +use LINE\Clients\MessagingApi\Model\ImagemapExternalLink; +use LINE\Clients\MessagingApi\Model\ImagemapMessage; +use LINE\Clients\MessagingApi\Model\ImagemapVideo; +use LINE\Clients\MessagingApi\Model\LocationAction; +use LINE\Clients\MessagingApi\Model\Message; +use LINE\Clients\MessagingApi\Model\MessageAction; +use LINE\Clients\MessagingApi\Model\MessageImagemapAction; +use LINE\Clients\MessagingApi\Model\PostbackAction; +use LINE\Clients\MessagingApi\Model\QuickReply; +use LINE\Clients\MessagingApi\Model\QuickReplyItem; +use LINE\Clients\MessagingApi\Model\ReplyMessageRequest; +use LINE\Clients\MessagingApi\Model\TemplateMessage; +use LINE\Clients\MessagingApi\Model\TextMessage; +use LINE\Clients\MessagingApi\Model\URIAction; +use LINE\Clients\MessagingApi\Model\URIImagemapAction; use LINE\LINEBot\KitchenSink\EventHandler; use LINE\LINEBot\KitchenSink\EventHandler\MessageHandler\Flex\FlexSampleRestaurant; use LINE\LINEBot\KitchenSink\EventHandler\MessageHandler\Flex\FlexSampleShopping; use LINE\LINEBot\KitchenSink\EventHandler\MessageHandler\Util\UrlBuilder; -use LINE\LINEBot\MessageBuilder\Imagemap\BaseSizeBuilder; -use LINE\LINEBot\MessageBuilder\Imagemap\VideoBuilder; -use LINE\LINEBot\MessageBuilder\Imagemap\ExternalLinkBuilder; -use LINE\LINEBot\MessageBuilder\ImagemapMessageBuilder; -use LINE\LINEBot\MessageBuilder\TemplateMessageBuilder; -use LINE\LINEBot\MessageBuilder\TemplateBuilder\ButtonTemplateBuilder; -use LINE\LINEBot\MessageBuilder\TemplateBuilder\CarouselColumnTemplateBuilder; -use LINE\LINEBot\MessageBuilder\TemplateBuilder\CarouselTemplateBuilder; -use LINE\LINEBot\MessageBuilder\TemplateBuilder\ConfirmTemplateBuilder; +use LINE\Constants\ActionType; +use LINE\Constants\MessageType; +use LINE\Constants\TemplateType; +use LINE\Webhook\Model\GroupSource; +use LINE\Webhook\Model\MessageEvent; +use LINE\Webhook\Model\RoomSource; +use LINE\Webhook\Model\TextMessageContent; /** * @SuppressWarnings(PHPMD.CouplingBetweenObjects) @@ -56,199 +63,371 @@ */ class TextMessageHandler implements EventHandler { - /** @var LINEBot $bot */ + /** @var MessagingApiApi $bot */ private $bot; - /** @var \Monolog\Logger $logger */ + /** @var \Psr\Log\LoggerInterface $logger */ private $logger; /** @var \Slim\Http\Request $logger */ private $req; - /** @var TextMessage $textMessage */ + /** @var TextMessageContent $textMessage */ private $textMessage; + /** @var MessageEvent $event */ + private $event; /** * TextMessageHandler constructor. * @param $bot - * @param $logger - * @param \Slim\Http\Request $req - * @param TextMessage $textMessage + * @param \Psr\Log\LoggerInterface $logger + * @param \Psr\Http\Message\RequestInterface $req + * @param TextMessageContent $textMessage */ - public function __construct($bot, $logger, \Slim\Http\Request $req, TextMessage $textMessage) + public function __construct(MessagingApiApi $bot, \Psr\Log\LoggerInterface $logger, \Psr\Http\Message\RequestInterface $req, MessageEvent $event) { $this->bot = $bot; $this->logger = $logger; $this->req = $req; - $this->textMessage = $textMessage; + $this->event = $event; + $this->textMessage = $event->getMessage(); } /** - * @throws LINEBot\Exception\InvalidEventSourceException + * @throws \LINE\Parser\Exception\InvalidEventSourceException * @throws \ReflectionException */ public function handle() { $text = $this->textMessage->getText(); - $replyToken = $this->textMessage->getReplyToken(); + $replyToken = $this->event->getReplyToken(); + $source = $this->event->getSource(); $this->logger->info("Got text message from $replyToken: $text"); switch ($text) { case 'profile': - $userId = $this->textMessage->getUserId(); + $userId = $source->getUserId(); $this->sendProfile($replyToken, $userId); break; case 'bye': - if ($this->textMessage->isRoomEvent()) { - $this->bot->replyText($replyToken, 'Leaving room'); - $this->bot->leaveRoom($this->textMessage->getRoomId()); + if ($source instanceof RoomSource) { + $this->replyText($replyToken, 'Leaving room'); + $this->bot->leaveRoom($source->getRoomId()); break; } - if ($this->textMessage->isGroupEvent()) { - $this->bot->replyText($replyToken, 'Leaving group'); - $this->bot->leaveGroup($this->textMessage->getGroupId()); + if ($source instanceof GroupSource) { + $this->replyText($replyToken, 'Leaving group'); + $this->bot->leaveGroup($source->getGroupId()); break; } - $this->bot->replyText($replyToken, 'Bot cannot leave from 1:1 chat'); + $this->replyText($replyToken, 'Bot cannot leave from 1:1 chat'); break; case 'confirm': - $this->bot->replyMessage( - $replyToken, - new TemplateMessageBuilder( - 'Confirm alt text', - new ConfirmTemplateBuilder('Do it?', [ - new MessageTemplateActionBuilder('Yes', 'Yes!'), - new MessageTemplateActionBuilder('No', 'No!'), - ]) - ) - ); + $templateMessage = new TemplateMessage([ + 'type' => MessageType::TEMPLATE, + 'altText' => 'Confirm alt text', + 'template' => new ConfirmTemplate([ + 'type' => TemplateType::CONFIRM, + 'text' => 'Do it?', + 'actions' => [ + new MessageAction([ + 'type' => ActionType::MESSAGE, + 'label' => 'Yes', + 'text' => 'Yes!', + ]), + new MessageAction([ + 'type' => ActionType::MESSAGE, + 'label' => 'No', + 'text' => 'No!', + ]), + ], + ]), + ]); + $this->replyMessage($replyToken, $templateMessage); break; case 'buttons': $imageUrl = UrlBuilder::buildUrl($this->req, ['static', 'buttons', '1040.jpg']); - $buttonTemplateBuilder = new ButtonTemplateBuilder( - 'My button sample', - 'Hello my button', - $imageUrl, - [ - new UriTemplateActionBuilder('Go to line.me', 'https://line.me'), - new PostbackTemplateActionBuilder('Buy', 'action=buy&itemid=123'), - new PostbackTemplateActionBuilder('Add to cart', 'action=add&itemid=123'), - new MessageTemplateActionBuilder('Say message', 'hello hello'), - ] - ); - $templateMessage = new TemplateMessageBuilder('Button alt text', $buttonTemplateBuilder); - $this->bot->replyMessage($replyToken, $templateMessage); + $this->logger->info('imageUrl: ' . $imageUrl); + $templateMessage = new TemplateMessage([ + 'type' => MessageType::TEMPLATE, + 'altText' => 'Button alt text', + 'template' => new ButtonsTemplate([ + 'type' => TemplateType::BUTTONS, + 'title' => 'My button sample', + 'text' => 'Hello my button', + 'thumbnailImageUrl' => $imageUrl, + 'actions' => [ + new URIAction([ + 'type' => ActionType::URI, + 'label' => 'Go to line.me', + 'uri' => 'https://line.me', + ]), + new PostbackAction([ + 'type' => ActionType::POSTBACK, + 'label' => 'Buy', + 'data' => 'action=buy&itemid=123', + ]), + new PostbackAction([ + 'type' => ActionType::POSTBACK, + 'label' => 'Add to cart', + 'data' => 'action=add&itemid=123', + ]), + new MessageAction([ + 'type' => ActionType::MESSAGE, + 'label' => 'Say message', + 'text' => 'hello hello', + ]), + ], + ]), + ]); + $this->replyMessage($replyToken, $templateMessage); break; case 'carousel': $imageUrl = UrlBuilder::buildUrl($this->req, ['static', 'buttons', '1040.jpg']); - $carouselTemplateBuilder = new CarouselTemplateBuilder([ - new CarouselColumnTemplateBuilder('foo', 'bar', $imageUrl, [ - new UriTemplateActionBuilder('Go to line.me', 'https://line.me'), - new PostbackTemplateActionBuilder('Buy', 'action=buy&itemid=123'), - ]), - new CarouselColumnTemplateBuilder('buz', 'qux', $imageUrl, [ - new PostbackTemplateActionBuilder('Add to cart', 'action=add&itemid=123'), - new MessageTemplateActionBuilder('Say message', 'hello hello'), + $templateMessage = new TemplateMessage([ + 'type' => MessageType::TEMPLATE, + 'altText' => 'Button alt text', + 'template' => new CarouselTemplate([ + 'type' => TemplateType::CAROUSEL, + 'columns' => [ + new CarouselColumn([ + 'title' => 'foo', + 'text' => 'bar', + 'thumbnailImageUrl' => $imageUrl, + 'actions' => [ + new URIAction([ + 'type' => ActionType::URI, + 'label' => 'Go to line.me', + 'uri' => 'https://line.me', + ]), + new PostbackAction([ + 'type' => ActionType::POSTBACK, + 'label' => 'Buy', + 'data' => 'action=buy&itemid=123', + ]), + ], + ]), + new CarouselColumn([ + 'title' => 'buz', + 'text' => 'qux', + 'thumbnailImageUrl' => $imageUrl, + 'actions' => [ + new PostbackAction([ + 'type' => ActionType::POSTBACK, + 'label' => 'Add to cart', + 'data' => 'action=add&itemid=123', + ]), + new MessageAction([ + 'type' => ActionType::MESSAGE, + 'label' => 'Say message', + 'text' => 'hello hello', + ]), + ], + ]), + ], ]), ]); - $templateMessage = new TemplateMessageBuilder('Button alt text', $carouselTemplateBuilder); - $this->bot->replyMessage($replyToken, $templateMessage); + $this->replyMessage($replyToken, $templateMessage); break; case 'imagemap': - $richMessageUrl = UrlBuilder::buildUrl($this->req, ['static', 'rich']); - $imagemapMessageBuilder = new ImagemapMessageBuilder( - $richMessageUrl, - 'This is alt text', - new BaseSizeBuilder(1040, 1040), - [ - new ImagemapUriActionBuilder( - 'https://store.line.me/family/manga/en', - new AreaBuilder(0, 0, 520, 520) - ), - new ImagemapUriActionBuilder( - 'https://store.line.me/family/music/en', - new AreaBuilder(520, 0, 520, 520) - ), - new ImagemapUriActionBuilder( - 'https://store.line.me/family/play/en', - new AreaBuilder(0, 520, 520, 520) - ), - new ImagemapMessageActionBuilder( - 'URANAI!', - new AreaBuilder(520, 520, 520, 520) - ) - ] - ); - $this->bot->replyMessage($replyToken, $imagemapMessageBuilder); + $richMessageUrl = UrlBuilder::buildUrl($this->req, ['static', 'rich']); + $imagemapMessage = new ImagemapMessage([ + 'type' => MessageType::IMAGEMAP, + 'baseUrl' => $richMessageUrl, + 'altText' => 'This is alt text', + 'baseSize' => new ImagemapBaseSize([ + 'width' => 1040, + 'height' => 1040, + ]), + 'actions' => [ + new URIImagemapAction([ + 'type' => ActionType::URI, + 'linkUri' => 'https://store.line.me/family/manga/en', + 'area' => new ImagemapArea([ + 'x' => 0, + 'y' => 0, + 'width' => 520, + 'height' => 520, + ]), + ]), + new URIImagemapAction([ + 'type' => ActionType::URI, + 'linkUri' => 'https://store.line.me/family/music/en', + 'area' => new ImagemapArea([ + 'x' => 520, + 'y' => 0, + 'width' => 520, + 'height' => 520, + ]), + ]), + new URIImagemapAction([ + 'type' => ActionType::URI, + 'linkUri' => 'https://store.line.me/family/play/en', + 'area' => new ImagemapArea([ + 'x' => 0, + 'y' => 520, + 'width' => 520, + 'height' => 520, + ]), + ]), + new MessageImagemapAction([ + 'type' => ActionType::MESSAGE, + 'text' => 'URANAI!', + 'area' => new ImagemapArea([ + 'x' => 520, + 'y' => 520, + 'width' => 520, + 'height' => 520, + ]), + ]), + ], + ]); + $this->replyMessage($replyToken, $imagemapMessage); break; case 'imagemapVideo': + $this->logger->info('static: ' . UrlBuilder::buildUrl($this->req, ['static', 'video.mp4'])); + $this->logger->info('static: ' . UrlBuilder::buildUrl($this->req, ['static', 'preview.jpg'])); $richMessageUrl = UrlBuilder::buildUrl($this->req, ['static', 'rich']); - $imagemapMessageBuilder = new ImagemapMessageBuilder( - $richMessageUrl, - 'This is alt text', - new BaseSizeBuilder(1040, 1040), - [ - new ImagemapUriActionBuilder( - 'https://store.line.me/family/manga/en', - new AreaBuilder(0, 0, 520, 520) - ), - new ImagemapUriActionBuilder( - 'https://store.line.me/family/music/en', - new AreaBuilder(520, 0, 520, 520) - ), - new ImagemapUriActionBuilder( - 'https://store.line.me/family/play/en', - new AreaBuilder(0, 520, 520, 520) - ), - new ImagemapMessageActionBuilder( - 'URANAI!', - new AreaBuilder(520, 520, 520, 520) - ) + $imagemapMessage = new ImagemapMessage([ + 'type' => MessageType::IMAGEMAP, + 'baseUrl' => $richMessageUrl, + 'altText' => 'This is alt text', + 'baseSize' => new ImagemapBaseSize([ + 'width' => 1040, + 'height' => 1040, + ]), + 'actions' => [ + new URIImagemapAction([ + 'type' => ActionType::URI, + 'linkUri' => 'https://store.line.me/family/manga/en', + 'area' => new ImagemapArea([ + 'x' => 0, + 'y' => 0, + 'width' => 520, + 'height' => 520, + ]), + ]), + new URIImagemapAction([ + 'type' => ActionType::URI, + 'linkUri' => 'https://store.line.me/family/music/en', + 'area' => new ImagemapArea([ + 'x' => 520, + 'y' => 0, + 'width' => 520, + 'height' => 520, + ]), + ]), + new URIImagemapAction([ + 'type' => ActionType::URI, + 'linkUri' => 'https://store.line.me/family/play/en', + 'area' => new ImagemapArea([ + 'x' => 0, + 'y' => 520, + 'width' => 520, + 'height' => 520, + ]), + ]), + new MessageImagemapAction([ + 'type' => ActionType::MESSAGE, + 'text' => 'URANAI!', + 'area' => new ImagemapArea([ + 'x' => 520, + 'y' => 520, + 'width' => 520, + 'height' => 520, + ]), + ]), ], - null, - new VideoBuilder( - UrlBuilder::buildUrl($this->req, ['static', 'video.mp4']), - UrlBuilder::buildUrl($this->req, ['static', 'preview.jpg']), - new AreaBuilder(260, 260, 520, 520), - new ExternalLinkBuilder('https://line.me', 'LINE') - ) - ); - $this->bot->replyMessage($replyToken, $imagemapMessageBuilder); + 'video' => new ImagemapVideo([ + 'originalContentUrl' => UrlBuilder::buildUrl($this->req, ['static', 'video.mp4']), + 'previewImageUrl' => UrlBuilder::buildUrl($this->req, ['static', 'preview.jpg']), + 'area' => new ImagemapArea([ + 'x' => 260, + 'y' => 260, + 'width' => 520, + 'height' => 520, + ]), + 'externalLink' => new ImagemapExternalLink([ + 'linkUri' => 'https://line.me', + 'label' => 'LINE', + ]), + ]), + ]); + $this->replyMessage($replyToken, $imagemapMessage); break; case 'restaurant': - $flexMessageBuilder = FlexSampleRestaurant::get(); - $this->bot->replyMessage($replyToken, $flexMessageBuilder); + $this->replyMessage($replyToken, FlexSampleRestaurant::get()); break; case 'shopping': - $flexMessageBuilder = FlexSampleShopping::get(); - $this->bot->replyMessage($replyToken, $flexMessageBuilder); + $this->replyMessage($replyToken, FlexSampleShopping::get()); break; case 'quickReply': - $postback = new PostbackTemplateActionBuilder('Buy', 'action=quickBuy&itemid=222', 'Buy'); - $datetimePicker = new DatetimePickerTemplateActionBuilder( - 'Select date', - 'storeId=12345', - 'datetime', - '2017-12-25t00:00', - '2018-01-24t23:59', - '2017-12-25t00:00' - ); - - $quickReply = new QuickReplyMessageBuilder([ - new QuickReplyButtonBuilder(new LocationTemplateActionBuilder('Location')), - new QuickReplyButtonBuilder(new CameraTemplateActionBuilder('Camera')), - new QuickReplyButtonBuilder(new CameraRollTemplateActionBuilder('Camera roll')), - new QuickReplyButtonBuilder($postback), - new QuickReplyButtonBuilder($datetimePicker), + $quickReply = new QuickReply([ + 'items' => [ + new QuickReplyItem([ + 'type' => 'action', + 'action' => new LocationAction([ + 'type' => ActionType::LOCATION, + 'label' => 'Location', + ]), + ]), + new QuickReplyItem([ + 'type' => 'action', + 'action' => new CameraAction([ + 'type' => ActionType::CAMERA, + 'label' => 'Camera', + ]), + ]), + new QuickReplyItem([ + 'type' => 'action', + 'action' => new CameraRollAction([ + 'type' => ActionType::CAMERA_ROLL, + 'label' => 'Camera roll', + ]), + ]), + new QuickReplyItem([ + 'type' => 'action', + 'action' => new PostbackAction([ + 'type' => ActionType::POSTBACK, + 'label' => 'Buy', + 'text' => 'Buy', + 'data' => 'action=buy&itemid=123', + ]), + ]), + new QuickReplyItem([ + 'type' => 'action', + 'action' => new DatetimePickerAction([ + 'type' => ActionType::DATETIME_PICKER, + 'label' => 'Select date', + 'data' => 'storeId=12345', + 'mode' => 'datetime', + 'initial' => '2017-12-25t00:00', + 'max' => '2018-01-24t23:59', + 'min' => '2017-12-25t00:00', + ]), + ]), + ] ]); - $messageTemplate = new TextMessageBuilder( - 'Text with quickReply buttons', - new EmojiTextBuilder( - '$ click button! $', - new EmojiBuilder(0, '5ac1bfd5040ab15980c9b435', '001'), - new EmojiBuilder(16, '5ac1bfd5040ab15980c9b435', '001') - ), - $quickReply - ); - $this->bot->replyMessage($replyToken, $messageTemplate); + $message = new TextMessage([ + 'text' => '$ click button! $', + 'type' => MessageType::TEXT, + 'emojis' => [ + new Emoji([ + 'index' => 0, + 'productId' => '5ac1bfd5040ab15980c9b435', + 'emojiId' => '001', + ]), + new Emoji([ + 'index' => 16, + 'productId' => '5ac1bfd5040ab15980c9b435', + 'emojiId' => '001', + ]), + ], + 'quickReply' => $quickReply, + ]); + $request = new ReplyMessageRequest([ + 'replyToken' => $replyToken, + 'messages' => [$message], + ]); + $this->bot->replyMessage($request); break; default: $this->echoBack($replyToken, $text); @@ -264,7 +443,7 @@ public function handle() private function echoBack($replyToken, $text) { $this->logger->info("Returns echo message $replyToken: $text"); - $this->bot->replyText($replyToken, $text); + $this->replyText($replyToken, $text); } /** @@ -275,21 +454,40 @@ private function echoBack($replyToken, $text) private function sendProfile($replyToken, $userId) { if (!isset($userId)) { - $this->bot->replyText($replyToken, "Bot can't use profile API without user ID"); + $this->replyText($replyToken, "Bot can't use profile API without user ID"); return; } - $response = $this->bot->getProfile($userId); - if (!$response->isSucceeded()) { - $this->bot->replyText($replyToken, $response->getRawBody()); + try { + $profile = $this->bot->getProfile($userId); + } catch (\LINE\Webhook\ApiException $e) { + $this->replyText($replyToken, json_encode($e->getResponseBody())); return; } - $profile = $response->getJSONDecodedBody(); - $this->bot->replyText( + $this->replyText( $replyToken, - 'Display name: ' . $profile['displayName'], - 'Status message: ' . $profile['statusMessage'] + 'Display name: ' . $profile->getDisplayName(), + 'Status message: ' . $profile->getStatusMessage(), ); } + + private function replyText(string $replyToken, string $text) { + $textMessage = (new TextMessage(['text' => $text, 'type' => MessageType::TEXT])); + return $this->replyMessage($replyToken, $textMessage); + } + + private function replyMessage(string $replyToken, Message $message) + { + $request = new ReplyMessageRequest([ + 'replyToken' => $replyToken, + 'messages' => [$message], + ]); + try { + $this->bot->replyMessage($request); + } catch (\LINE\Clients\MessagingApi\ApiException $e) { + $this->logger->info('BODY:' . $e->getResponseBody()); + throw $e; + } + } } diff --git a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/Util/UrlBuilder.php b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/Util/UrlBuilder.php index d88574e9..0873061a 100644 --- a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/Util/UrlBuilder.php +++ b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/Util/UrlBuilder.php @@ -20,11 +20,12 @@ class UrlBuilder { - public static function buildUrl(\Slim\Http\Request $req, array $paths) + public static function buildUrl(\Psr\Http\Message\RequestInterface $req, array $paths) { // NOTE: You should configure $baseUri according to your environment // Perhaps, it is prefer to use $_SERVER['HTTP_HOST'], $_SERVER['HTTP_X_FORWARDED_HOST'] or etc - $baseUri = $req->getUri()->getBaseUrl(); + // $baseUri = "{$req->getUri()->getScheme()}://{$req->getUri()->getHost()}"; + $baseUri = "{$req->getHeader('X-Forwarded-Scheme')[0]}://{$req->getHeader('X-Forwarded-Host')[0]}"; foreach ($paths as $path) { $baseUri .= '/' . urlencode($path); } diff --git a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/VideoMessageHandler.php b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/VideoMessageHandler.php index 779b10a3..ec1d64e8 100644 --- a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/VideoMessageHandler.php +++ b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/VideoMessageHandler.php @@ -18,57 +18,68 @@ namespace LINE\LINEBot\KitchenSink\EventHandler\MessageHandler; -use LINE\LINEBot; -use LINE\LINEBot\Event\MessageEvent\VideoMessage; +use LINE\Clients\MessagingApi\Api\MessagingApiApi; +use LINE\Clients\MessagingApi\Api\MessagingApiBlobApi; +use LINE\Clients\MessagingApi\Model\ReplyMessageRequest; +use LINE\Clients\MessagingApi\Model\VideoMessage; +use LINE\Constants\MessageContentProviderType; +use LINE\Constants\MessageType; use LINE\LINEBot\KitchenSink\EventHandler; use LINE\LINEBot\KitchenSink\EventHandler\MessageHandler\Util\UrlBuilder; -use LINE\LINEBot\MessageBuilder\VideoMessageBuilder; +use LINE\Webhook\Model\MessageEvent; +use LINE\Webhook\Model\VideoMessageContent; class VideoMessageHandler implements EventHandler { - /** @var LINEBot $bot */ + /** @var MessagingApiApi $bot */ private $bot; - /** @var \Monolog\Logger $logger */ + /** @var MessagingApiBlobApi $bot */ + private $botBlob; + /** @var \Psr\Log\LoggerInterface $logger */ private $logger; /** @var \Slim\Http\Request $logger */ private $req; - /** @var VideoMessage $videoMessage */ + /** @var VideoMessageContent $videoMessage */ private $videoMessage; + /** @var MessageEvent $event */ + private $event; /** * VideoMessageHandler constructor. * - * @param LINEBot $bot - * @param \Monolog\Logger $logger - * @param \Slim\Http\Request $req - * @param VideoMessage $videoMessage + * @param MessagingApiApi $bot + * @param MessagingApiBlobApi $botBlob + * @param \Psr\Log\LoggerInterface $logger + * @param \Psr\Http\Message\RequestInterface $req + * @param MessageEvent $event */ - public function __construct($bot, $logger, \Slim\Http\Request $req, VideoMessage $videoMessage) + public function __construct(MessagingApiApi $bot, MessagingApiBlobApi $botBlob, \Psr\Log\LoggerInterface $logger, \Psr\Http\Message\RequestInterface $req, MessageEvent $event) { $this->bot = $bot; + $this->botBlob = $botBlob; $this->logger = $logger; $this->req = $req; - $this->videoMessage = $videoMessage; + $this->event = $event; + $this->videoMessage = $event->getMessage(); } public function handle() { - $replyToken = $this->videoMessage->getReplyToken(); + $replyToken = $this->event->getReplyToken(); $contentProvider = $this->videoMessage->getContentProvider(); - if ($contentProvider->isExternal()) { - $this->bot->replyMessage( + if ($contentProvider->getType() == MessageContentProviderType::EXTERNAL) { + $this->replyVideoMessage( $replyToken, - new VideoMessageBuilder( - $contentProvider->getOriginalContentUrl(), - $contentProvider->getPreviewImageUrl() - ) + $contentProvider->getOriginalContentUrl(), + $contentProvider->getPreviewImageUrl(), ); return; } - $contentId = $this->videoMessage->getMessageId(); - $video = $this->bot->getMessageContent($contentId)->getRawBody(); + $contentId = $this->videoMessage->getId(); + $sfo = $this->botBlob->getMessageContent($contentId); + $video = $sfo->fread($sfo->getSize()); $tempFilePath = tempnam($_SERVER['DOCUMENT_ROOT'] . '/static/tmpdir', 'video-'); unlink($tempFilePath); @@ -80,9 +91,24 @@ public function handle() fclose($fh); $url = UrlBuilder::buildUrl($this->req, ['static', 'tmpdir', $filename]); + $previewUrl = UrlBuilder::buildUrl($this->req, ['static', 'preview.jpg']); // NOTE: You should pass the url of thumbnail image to `previewImageUrl`. // This sample doesn't treat that so this sample cannot show the thumbnail. - $this->bot->replyMessage($replyToken, new VideoMessageBuilder($url, $url)); + $this->replyVideoMessage($replyToken, $url, $previewUrl); + } + + private function replyVideoMessage(string $replyToken, string $original, string $preview) + { + $message = new VideoMessage([ + 'type' => MessageType::VIDEO, + 'originalContentUrl' => $original, + 'previewImageUrl' => $preview, + ]); + $request = new ReplyMessageRequest([ + 'replyToken' => $replyToken, + 'messages' => [$message], + ]); + $this->bot->replyMessage($request); } } diff --git a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/PostbackEventHandler.php b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/PostbackEventHandler.php index 7538ac3d..8e653fa2 100644 --- a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/PostbackEventHandler.php +++ b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/PostbackEventHandler.php @@ -18,26 +18,29 @@ namespace LINE\LINEBot\KitchenSink\EventHandler; -use LINE\LINEBot; -use LINE\LINEBot\Event\PostbackEvent; +use LINE\Clients\MessagingApi\Api\MessagingApiApi; +use LINE\Clients\MessagingApi\Model\ReplyMessageRequest; +use LINE\Clients\MessagingApi\Model\TextMessage; +use LINE\Constants\MessageType; use LINE\LINEBot\KitchenSink\EventHandler; +use LINE\Webhook\Model\PostbackEvent; class PostbackEventHandler implements EventHandler { - /** @var LINEBot $bot */ + /** @var MessagingApiApi $bot */ private $bot; - /** @var \Monolog\Logger $logger */ + /** @var \Psr\Log\LoggerInterface $logger */ private $logger; /** @var PostbackEvent $postbackEvent */ private $postbackEvent; /** * PostbackEventHandler constructor. - * @param LINEBot $bot - * @param \Monolog\Logger $logger + * @param MessagingApiApi $bot + * @param \Psr\Log\LoggerInterface $logger * @param PostbackEvent $postbackEvent */ - public function __construct($bot, $logger, PostbackEvent $postbackEvent) + public function __construct(MessagingApiApi $bot, \Psr\Log\LoggerInterface $logger, PostbackEvent $postbackEvent) { $this->bot = $bot; $this->logger = $logger; @@ -49,9 +52,12 @@ public function __construct($bot, $logger, PostbackEvent $postbackEvent) */ public function handle() { - $this->bot->replyText( - $this->postbackEvent->getReplyToken(), - 'Got postback ' . $this->postbackEvent->getPostbackData() - ); + $request = new ReplyMessageRequest([ + 'replyToken' => $this->postbackEvent->getReplyToken(), + 'messages' => [ + new TextMessage(['type' => MessageType::TEXT, 'text' => 'Got postback ' . $this->postbackEvent->getPostback()]), + ], + ]); + $this->bot->replyMessage($request); } } diff --git a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/ThingsEventHandler.php b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/ThingsEventHandler.php index b1aa9cd5..13be72ae 100644 --- a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/ThingsEventHandler.php +++ b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/ThingsEventHandler.php @@ -18,15 +18,19 @@ namespace LINE\LINEBot\KitchenSink\EventHandler; -use LINE\LINEBot; -use LINE\LINEBot\Event\ThingsEvent; +use LINE\Clients\MessagingApi\Api\MessagingApiApi; +use LINE\Clients\MessagingApi\Model\ReplyMessageRequest; +use LINE\Clients\MessagingApi\Model\TextMessage; +use LINE\Constants\MessageType; +use LINE\Constants\ThingsEventType; use LINE\LINEBot\KitchenSink\EventHandler; +use LINE\Webhook\Model\ThingsEvent; class ThingsEventHandler implements EventHandler { - /** @var LINEBot $bot */ + /** @var MessagingApiApi $bot */ private $bot; - /** @var \Monolog\Logger $logger */ + /** @var \Psr\Log\LoggerInterface $logger */ private $logger; /** @var ThingsEvent $thingsEvent */ private $thingsEvent; @@ -38,7 +42,7 @@ class ThingsEventHandler implements EventHandler * @param \Monolog\Logger $logger * @param ThingsEvent $thingsEvent */ - public function __construct($bot, $logger, ThingsEvent $thingsEvent) + public function __construct(MessagingApiApi $bot, \Psr\Log\LoggerInterface $logger, ThingsEvent $thingsEvent) { $this->bot = $bot; $this->logger = $logger; @@ -50,19 +54,26 @@ public function __construct($bot, $logger, ThingsEvent $thingsEvent) */ public function handle() { - $text = 'Device ' . $this->thingsEvent->getDeviceId(); + $text = 'Device ' . $this->thingsEvent->getThings()->getDeviceId(); switch ($this->thingsEvent->getThingsEventType()) { - case ThingsEvent::TYPE_DEVICE_LINKED: + case ThingsEventType::DEVICE_LINKED: $text .= ' was linked!'; break; - case ThingsEvent::TYPE_DEVICE_UNLINKED: + case ThingsEventType::DEVICE_UNLINKED: $text .= ' was unlinked!'; break; - case ThingsEvent::TYPE_SCENARIO_RESULT: - $result = $this->thingsEvent->getScenarioResult(); + case ThingsEventType::SCENARIO_RESULT: + $result = $this->thingsEvent->getThings(); $text .= ' executed scenario:' . $result->getScenarioId(); break; } - $this->bot->replyText($this->thingsEvent->getReplyToken(), $text); + + $request = new ReplyMessageRequest([ + 'replyToken' => $this->thingsEvent->getReplyToken(), + 'messages' => [ + new TextMessage(['type' => MessageType::TEXT, 'text' => $text]), + ], + ]); + $this->bot->replyMessage($request); } } diff --git a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/UnfollowEventHandler.php b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/UnfollowEventHandler.php index b5d71c33..1bba8d2d 100644 --- a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/UnfollowEventHandler.php +++ b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/UnfollowEventHandler.php @@ -18,26 +18,26 @@ namespace LINE\LINEBot\KitchenSink\EventHandler; -use LINE\LINEBot; -use LINE\LINEBot\Event\UnfollowEvent; +use LINE\Clients\MessagingApi\Api\MessagingApiApi; use LINE\LINEBot\KitchenSink\EventHandler; +use LINE\Webhook\Model\UnfollowEvent; class UnfollowEventHandler implements EventHandler { - /** @var LINEBot $bot */ + /** @var MessagingApiApi $bot */ private $bot; - /** @var \Monolog\Logger $logger */ + /** @var \Psr\Log\LoggerInterface $logger */ private $logger; /** @var UnfollowEvent $unfollowEvent */ private $unfollowEvent; /** * UnfollowEventHandler constructor. - * @param LINEBot $bot - * @param \Monolog\Logger $logger + * @param MessagingApiApi $bot + * @param \Psr\Log\LoggerInterface $logger * @param UnfollowEvent $unfollowEvent */ - public function __construct($bot, $logger, UnfollowEvent $unfollowEvent) + public function __construct(MessagingApiApi $bot, \Psr\Log\LoggerInterface $logger, UnfollowEvent $unfollowEvent) { $this->bot = $bot; $this->logger = $logger; @@ -49,7 +49,7 @@ public function handle() $this->logger->info(sprintf( 'Unfollowed this bot %s %s', $this->unfollowEvent->getType(), - $this->unfollowEvent->getUserId() + $this->unfollowEvent->getSource()->getUserId() )); } } diff --git a/examples/KitchenSink/src/LINEBot/KitchenSink/Route.php b/examples/KitchenSink/src/LINEBot/KitchenSink/Route.php index f32e8b20..706f31a9 100644 --- a/examples/KitchenSink/src/LINEBot/KitchenSink/Route.php +++ b/examples/KitchenSink/src/LINEBot/KitchenSink/Route.php @@ -18,27 +18,10 @@ namespace LINE\LINEBot\KitchenSink; -use LINE\LINEBot; -use LINE\LINEBot\Constant\HTTPHeader; -use LINE\LINEBot\Event\AccountLinkEvent; -use LINE\LINEBot\Event\BeaconDetectionEvent; -use LINE\LINEBot\Event\FollowEvent; -use LINE\LINEBot\Event\JoinEvent; -use LINE\LINEBot\Event\LeaveEvent; -use LINE\LINEBot\Event\MessageEvent; -use LINE\LINEBot\Event\MessageEvent\AudioMessage; -use LINE\LINEBot\Event\MessageEvent\ImageMessage; -use LINE\LINEBot\Event\MessageEvent\LocationMessage; -use LINE\LINEBot\Event\MessageEvent\StickerMessage; -use LINE\LINEBot\Event\MessageEvent\TextMessage; -use LINE\LINEBot\Event\MessageEvent\UnknownMessage; -use LINE\LINEBot\Event\MessageEvent\VideoMessage; -use LINE\LINEBot\Event\PostbackEvent; -use LINE\LINEBot\Event\ThingsEvent; -use LINE\LINEBot\Event\UnfollowEvent; -use LINE\LINEBot\Event\UnknownEvent; -use LINE\LINEBot\Exception\InvalidEventRequestException; -use LINE\LINEBot\Exception\InvalidSignatureException; +use LINE\Clients\MessagingApi\Api\MessagingApiApi; +use LINE\Clients\MessagingApi\Api\MessagingApiBlobApi; +use LINE\LINEBot\Event\MessageEvent\UnknownMessageContent; +use LINE\LINEBot\KitchenSink\AccountLinkEventHandler; use LINE\LINEBot\KitchenSink\EventHandler\BeaconEventHandler; use LINE\LINEBot\KitchenSink\EventHandler\FollowEventHandler; use LINE\LINEBot\KitchenSink\EventHandler\JoinEventHandler; @@ -52,27 +35,47 @@ use LINE\LINEBot\KitchenSink\EventHandler\PostbackEventHandler; use LINE\LINEBot\KitchenSink\EventHandler\ThingsEventHandler; use LINE\LINEBot\KitchenSink\EventHandler\UnfollowEventHandler; +use LINE\Constants\HTTPHeader; +use LINE\Parser\Event\UnknownEvent; +use LINE\Parser\EventRequestParser; +use LINE\Webhook\Model\MessageEvent; +use LINE\Parser\Exception\InvalidEventRequestException; +use LINE\Parser\Exception\InvalidSignatureException; +use LINE\Webhook\Model\AccountLinkEvent; +use LINE\Webhook\Model\AudioMessageContent; +use LINE\Webhook\Model\BeaconEvent; +use LINE\Webhook\Model\FollowEvent; +use LINE\Webhook\Model\ImageMessageContent; +use LINE\Webhook\Model\JoinEvent; +use LINE\Webhook\Model\LeaveEvent; +use LINE\Webhook\Model\LocationMessageContent; +use LINE\Webhook\Model\PostbackEvent; +use LINE\Webhook\Model\StickerMessageContent; +use LINE\Webhook\Model\TextMessageContent; +use LINE\Webhook\Model\ThingsEvent; +use LINE\Webhook\Model\UnfollowEvent; +use LINE\Webhook\Model\VideoMessageContent; class Route { public function register(\Slim\App $app) { - $app->post('/callback', function (\Slim\Http\Request $req, \Slim\Http\Response $res) { - /** @var LINEBot $bot */ - $bot = $this->bot; - /** @var \Monolog\Logger $logger */ - $logger = $this->logger; + $app->post('/callback', function (\Psr\Http\Message\RequestInterface $req, \Psr\Http\Message\ResponseInterface $res) { + /** @var \LINE\Clients\MessagingApi\Api\MessagingApiApi $bot */ + $bot = $this->get(MessagingApiApi::class); + $botBlob = $this->get(MessagingApiBlobApi::class); + $logger = $this->get(\Psr\Log\LoggerInterface::class); $signature = $req->getHeader(HTTPHeader::LINE_SIGNATURE); if (empty($signature)) { - $logger->info('Signature is missing'); return $res->withStatus(400, 'Bad Request'); } + // Check request with signature and parse request try { - $events = $bot->parseEventRequest($req->getBody(), $signature[0]); + $secret = $this->get('settings')['bot']['channelSecret']; + $events = EventRequestParser::parseEventRequest($req->getBody(), $secret, $signature[0]); } catch (InvalidSignatureException $e) { - $logger->info('Invalid signature'); return $res->withStatus(400, 'Invalid signature'); } catch (InvalidEventRequestException $e) { return $res->withStatus(400, "Invalid event request"); @@ -83,22 +86,23 @@ public function register(\Slim\App $app) $handler = null; if ($event instanceof MessageEvent) { - if ($event instanceof TextMessage) { + $message = $event->getMessage(); + if ($message instanceof TextMessageContent) { $handler = new TextMessageHandler($bot, $logger, $req, $event); - } elseif ($event instanceof StickerMessage) { + } elseif ($message instanceof StickerMessageContent) { $handler = new StickerMessageHandler($bot, $logger, $event); - } elseif ($event instanceof LocationMessage) { + } elseif ($message instanceof LocationMessageContent) { $handler = new LocationMessageHandler($bot, $logger, $event); - } elseif ($event instanceof ImageMessage) { - $handler = new ImageMessageHandler($bot, $logger, $req, $event); - } elseif ($event instanceof AudioMessage) { - $handler = new AudioMessageHandler($bot, $logger, $req, $event); - } elseif ($event instanceof VideoMessage) { - $handler = new VideoMessageHandler($bot, $logger, $req, $event); - } elseif ($event instanceof UnknownMessage) { + } elseif ($message instanceof ImageMessageContent) { + $handler = new ImageMessageHandler($bot, $botBlob, $logger, $req, $event); + } elseif ($message instanceof AudioMessageContent) { + $handler = new AudioMessageHandler($bot, $botBlob, $logger, $req, $event); + } elseif ($message instanceof VideoMessageContent) { + $handler = new VideoMessageHandler($bot, $botBlob, $logger, $req, $event); + } elseif ($message instanceof UnknownMessageContent) { $logger->info(sprintf( 'Unknown message type has come [message type: %s]', - $event->getMessageType() + $message->getType() )); } else { // Unexpected behavior (just in case) @@ -119,7 +123,7 @@ public function register(\Slim\App $app) $handler = new LeaveEventHandler($bot, $logger, $event); } elseif ($event instanceof PostbackEvent) { $handler = new PostbackEventHandler($bot, $logger, $event); - } elseif ($event instanceof BeaconDetectionEvent) { + } elseif ($event instanceof BeaconEvent) { $handler = new BeaconEventHandler($bot, $logger, $event); } elseif ($event instanceof AccountLinkEvent) { $handler = new AccountLinkEventHandler($bot, $logger, $event); @@ -140,7 +144,7 @@ public function register(\Slim\App $app) $handler->handle(); } - $res->write('OK'); + $res->withStatus(200, 'OK'); return $res; }); } diff --git a/line-bot-sdk-tiny/LINEBotTiny.php b/line-bot-sdk-tiny/LINEBotTiny.php deleted file mode 100644 index b69de50f..00000000 --- a/line-bot-sdk-tiny/LINEBotTiny.php +++ /dev/null @@ -1,146 +0,0 @@ -channelAccessToken = $channelAccessToken; - $this->channelSecret = $channelSecret; - } - - /** - * @return mixed - */ - public function parseEvents() - { - if ($_SERVER['REQUEST_METHOD'] !== 'POST') { - http_response_code(405); - error_log('Method not allowed'); - exit(); - } - - $entityBody = file_get_contents('php://input'); - - if ($entityBody === false || strlen($entityBody) === 0) { - http_response_code(400); - error_log('Missing request body'); - exit(); - } - - if (!hash_equals($this->sign($entityBody), $_SERVER['HTTP_X_LINE_SIGNATURE'])) { - http_response_code(400); - error_log('Invalid signature value'); - exit(); - } - - $data = json_decode($entityBody, true); - if (!isset($data['events'])) { - http_response_code(400); - error_log('Invalid request body: missing events property'); - exit(); - } - return $data['events']; - } - - /** - * @param array $message - * @return void - */ - public function replyMessage($message) - { - $header = array( - 'Content-Type: application/json', - 'Authorization: Bearer ' . $this->channelAccessToken, - ); - - $context = stream_context_create([ - 'http' => [ - 'ignore_errors' => true, - 'method' => 'POST', - 'header' => implode("\r\n", $header), - 'content' => json_encode($message), - ], - ]); - - $response = file_get_contents('https://api.line.me/v2/bot/message/reply', false, $context); - if (strpos($http_response_header[0], '200') === false) { - error_log('Request failed: ' . $response); - } - } - - /** - * @param string $body - * @return string - */ - private function sign($body) - { - $hash = hash_hmac('sha256', $body, $this->channelSecret, true); - $signature = base64_encode($hash); - return $signature; - } -} diff --git a/line-bot-sdk-tiny/README.md b/line-bot-sdk-tiny/README.md deleted file mode 100644 index 6acea44e..00000000 --- a/line-bot-sdk-tiny/README.md +++ /dev/null @@ -1,45 +0,0 @@ -line-bot-sdk-tiny -== - -A very simple SDK (subset) for the LINE Messaging API for PHP. - -Description (and motivation) --- - -[line-bot-sdk-php](https://github.com/line/line-bot-sdk-php) is a full-stack implementation of the LINE Messaging API SDK, which uses an OOP interface and functions. It provides an API client, a message builder, an HTTP client, an event parser and other useful components. - -On the other hand, line-bot-sdk-tiny provides a simple interface and functions. It contains a part of the API functions (not full function). - -This SDK contains only one file, so it is easy to add `LINEBotTiny.php` to your environment and require that from your script. -And of course, you can also copy and paste this SDK. - -Example --- - -See [echo_bot](./echo_bot.php). - -When running this example, make sure that you have set your Channel access token and Channel secret. - -Requirements --- - -PHP 5.5 or later - -License --- - -``` -Copyright 2016 LINE Corporation - -LINE Corporation licenses this file to you under the Apache License, -version 2.0 (the "License"); you may not use this file except in compliance -with the License. You may obtain a copy of the License at: - - https://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -License for the specific language governing permissions and limitations -under the License. -``` diff --git a/line-bot-sdk-tiny/echo_bot.php b/line-bot-sdk-tiny/echo_bot.php deleted file mode 100644 index 0163e685..00000000 --- a/line-bot-sdk-tiny/echo_bot.php +++ /dev/null @@ -1,50 +0,0 @@ -'; -$channelSecret = ''; - -$client = new LINEBotTiny($channelAccessToken, $channelSecret); -foreach ($client->parseEvents() as $event) { - switch ($event['type']) { - case 'message': - $message = $event['message']; - switch ($message['type']) { - case 'text': - $client->replyMessage([ - 'replyToken' => $event['replyToken'], - 'messages' => [ - [ - 'type' => 'text', - 'text' => $message['text'] - ] - ] - ]); - break; - default: - error_log('Unsupported message type: ' . $message['type']); - break; - } - break; - default: - error_log('Unsupported event type: ' . $event['type']); - break; - } -}; diff --git a/openapitools.json b/openapitools.json new file mode 100644 index 00000000..a3883a34 --- /dev/null +++ b/openapitools.json @@ -0,0 +1,7 @@ +{ + "$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json", + "spaces": 2, + "generator-cli": { + "version": "6.5.0" + } +} diff --git a/phpcs.xml b/phpcs.xml deleted file mode 100644 index cf76f59d..00000000 --- a/phpcs.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - The coding standard for line-bot-sdk-php. - - src - tests - examples/EchoBot/src - examples/EchoBot/public - examples/KitchenSink/src - examples/KitchenSink/public - - - - - - - - - - - - diff --git a/phpdoc.xml b/phpdoc.xml deleted file mode 100644 index 96d5a618..00000000 --- a/phpdoc.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - LINE Messaging API SDK for PHP - - docs - - - latest - - - src - - - - - - php - - - -