diff --git a/.gitignore b/.gitignore index 8d7ac75b..b35a9758 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ /.idea/ -/vendor/ -/composer.lock -/composer.phar +composer.lock +composer.phar /tests/Private -/,/ /docs/ +*.iml +vendor/ diff --git a/.travis.yml b/.travis.yml index ac7865b5..235dc1e2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,13 +1,7 @@ language: php - -matrix: - include: - - php: '5.4' - before_script: composer require 'indigophp/hash-compat:^1.1' - - php: '5.5' - before_script: composer require 'indigophp/hash-compat:^1.1' - - php: '5.6' - - php: '7.0' +php: + - '5.6' + - '7.0' install: composer update script: ./vendor/bin/phpunit ./tests sudo: false diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d019c6d4..488647b0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,10 +3,10 @@ First of all, thank you so much for taking your time to contribute! LINE Bot SDK for PHP is not very different from any other open source projects you are aware of. It will be amazing if you could help us by doing any of the following: -- File an issue in [the issue tracker](https://github.com/line/line-bot-sdk-php/issues) to report bugs and propose new features and +- File an issue in [the issue tracker](https://github.com/line/line-bot-sdk-php-v2/issues) to report bugs and propose new features and improvements. -- Ask a question using [the issue tracker](https://github.com/line/line-bot-sdk-php/issues) (__Please ask only about this SDK__). -- Contribute your work by sending [a pull request](https://github.com/line/line-bot-sdk-php/pulls). +- Ask a question using [the issue tracker](https://github.com/line/line-bot-sdk-php-v2/issues) (__Please ask only about this SDK__). +- Contribute your work by sending [a pull request](https://github.com/line/line-bot-sdk-php-v2/pulls). ### Contributor license agreement diff --git a/LICENSE b/LICENSE index 5c515ba9..378cc222 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ Apache License Version 2.0, January 2004 - http://www.apache.org/licenses/ + https://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION @@ -192,7 +192,7 @@ you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + 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, diff --git a/Makefile b/Makefile index a415cbce..2ff1bfd8 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,9 @@ COMPOSER_BIN = ./vendor/bin +.PHONY: default test doc phpcs phpmd check + +default: check + test: $(COMPOSER_BIN)/phpunit ./tests @@ -7,13 +11,18 @@ doc: yes yes | $(COMPOSER_BIN)/apigen generate --source=./src --destination=./docs --title line-bot-sdk-php phpcs: - $(COMPOSER_BIN)/phpcs --standard=PSR2 src/ examples/SendingSample/ examples/EchoBot/src examples/EchoBot/public + $(COMPOSER_BIN)/phpcs --standard=PSR2 src/ tests/ examples/EchoBot/src examples/EchoBot/public examples/KitchenSink/src examples/KitchenSink/public phpmd: $(COMPOSER_BIN)/phpmd ./src text cleancode,codesize,controversial,design,unusedcode,naming | grep -v 'Avoid using static access to class' - $(COMPOSER_BIN)/phpmd ./examples/SendingSample text cleancode,codesize,controversial,design,unusedcode,naming | grep -v 'Avoid using static access to class' + $(COMPOSER_BIN)/phpmd ./tests text cleancode,codesize,controversial,design,unusedcode,naming | grep -v 'Avoid using static access to class' $(COMPOSER_BIN)/phpmd ./examples/EchoBot/src text cleancode,codesize,controversial,design,unusedcode,naming | grep -v 'Avoid using static access to class' $(COMPOSER_BIN)/phpmd ./examples/EchoBot/public text cleancode,codesize,controversial,design,unusedcode,naming | grep -v 'Avoid using static access to class' + $(COMPOSER_BIN)/phpmd ./examples/KitchenSink/src text cleancode,codesize,controversial,design,unusedcode,naming | grep -v 'Avoid using static access to class' + $(COMPOSER_BIN)/phpmd ./examples/KitchenSink/public text cleancode,codesize,controversial,design,unusedcode,naming | grep -v 'Avoid using static access to class' + +copyright: + bash ./devtool/check_copyright.sh -check: test phpcs phpmd +check: test copyright phpcs phpmd diff --git a/README.md b/README.md index 8017f92a..f7cf5676 100644 --- a/README.md +++ b/README.md @@ -2,193 +2,172 @@ line-bot-sdk-php == [![Build Status](https://travis-ci.org/line/line-bot-sdk-php.svg?branch=master)](https://travis-ci.org/line/line-bot-sdk-php) -[![Latest Stable Version](https://poser.pugx.org/linecorp/line-bot-sdk/v/stable.svg)](https://packagist.org/packages/linecorp/line-bot-sdk) -[![License](https://poser.pugx.org/linecorp/line-bot-sdk/license.svg)](https://packagist.org/packages/linecorp/line-bot-sdk) -SDK of the LINE BOT API Trial for PHP. +SDK of the LINE Messaging API for PHP. + +About LINE Messaging API +-- + +Please refer to the official API documents for details. + +en: [https://devdocs.line.me/en/](https://devdocs.line.me/en/) + +ja: [https://devdocs.line.me/ja/](https://devdocs.line.me/ja/) Installation -- -The LINE BOT API SDK can be installed with [Composer](https://getcomposer.org/). +The LINE messaging API SDK can be installed with [Composer](https://getcomposer.org/). ``` -composer require linecorp/line-bot-sdk +$ composer require linecorp/line-bot-sdk ``` -Note +Getting started -- -If you use __PHP 5.5 or lower__, please use this SDK with polyfill of [hash_equals()](http://php.net/manual/function.hash-equals.php). +### Create the bot client instance -e.g. +Instance of bot client is a handler of the Messaging API. -- [indigophp/hash-compat](https://packagist.org/packages/indigophp/hash-compat) +```php +$httpClient = new \LINE\LINEBot\HTTPClient\CurlHTTPClient(''); +$bot = new \LINE\LINEBot($httpClient, ['channelSecret' => '']); +``` -Methods --- +The constructor of bot client requires an instance of `HTTPClient`. +This library provides `CurlHTTPClient` as default. -### Constructor +### Call API -#### new LINEBot(array $args, HTTPClient $client) +You can call API through the bot client instance. -Create a `LINEBot` constructor. +Deadly simple sample is following; ```php -$config = [ - 'channelId' => '', - 'channelSecret' => '', - 'channelMid' => '', -]; -$bot = new LINEBot($config, new GuzzleHTTPClient($config)); +$response = $bot->replyText('', 'hello!'); ``` -### Sending Message - -#### LINEBot#sendText($mid, $text) +This procedure sends a message to the destination that is associated with ``. -Send a text message to mid(s). -[https://developers.line.me/bot-api/api-reference#sending_message_text](https://developers.line.me/bot-api/api-reference#sending_message_text) +More advanced sample is below; ```php -$res = $bot->sendText(['TARGET_MID'], 'Message'); +$textMessageBuilder = new \LINE\LINEBot\MessageBuilder\TextMessageBuilder('hello'); +$response = $bot->replyMessage('', $textMessageBuilder); +if ($response->isSecceeded()) { + echo 'Succeeded!'; + return; +} + +// Failed +echo $response->getHTTPStatus . ' ' . $response->getBody(); ``` -#### LINEBot#sendImage($mid, $imageURL, $previewURL) +`LINEBot#replyMessage()` takes reply token and `MessageBuilder`. +This method sends message that is built by `MessageBuilder` to the destination. -Send an image to mid(s). -[https://developers.line.me/bot-api/api-reference#sending_message_image](https://developers.line.me/bot-api/api-reference#sending_message_image) +#### MessageBuilder -```php -$bot->sendImage(['TARGET_MID'] 'http://example.com/image.jpg', 'http://example.com/preview.jpg'); -``` +Type of message depends on the type of instance of `MessageBuilder`. +That means this method sends text message if you pass `TextMessageBuilder`, +on the other hand it sends image message if you pass `ImaageMessageBuilder`. -#### LINEBot#sendVideo($mid, $videoURL, $previewImageURL) +If you want detail information of `MessageBuilder`, please refer `\LINE\LINEBot\MessageBuilder` and the namespace. -Send a video to mid(s). -[https://developers.line.me/bot-api/api-reference#sending_message_video](https://developers.line.me/bot-api/api-reference#sending_message_video) +Other methods that take `MessageBuilder` behave the same. -```php -$bot->sendVideo(['TARGET_MID'], 'http://example.com/video.mp4', 'http://example.com/video_preview.jpg'); -``` +#### Response -#### LINEBot#sendAudio($mid, $audioURL, $durationMillis) +Methods that call API returns `Response`. Response has three methods; -Send a voice message to mid(s). -[https://developers.line.me/bot-api/api-reference#sending_message_audio](https://developers.line.me/bot-api/api-reference#sending_message_audio) +- `Response#isSucceeded()` +- `Response#getHTTPStatus()` +- `Response#getBody()` -```php -$bot->sendAudio(['TARGET_MID'], 'http://example.com/audio.m4a', 5000); -``` +You can use these method to check response status and take response body. -#### LINEBot#sendLocation($mid, $text, $latitude, $longitude) +##### `Response#isSucceeded()` -Send location information to mid(s). -[https://developers.line.me/bot-api/api-reference#sending_message_location](https://developers.line.me/bot-api/api-reference#sending_message_location) +This method returns the boolean value. Return value represents "request is succeeded or not". -```php -$bot->sendLocation(['TARGET_MID'], '2 Chome-21-1 Shibuya Tokyo 150-0002, Japan', 35.658240, 139.703478); -``` +##### `Response#getHTTPStatus()` -#### LINEBot#sendSticker($mid, $stkid, $stkpkgid, $stkver) +This method returns the HTTP status code of response. -Send a sticker to mid(s). -[https://developers.line.me/bot-api/api-reference#sending_message_sticker](https://developers.line.me/bot-api/api-reference#sending_message_sticker) +##### `Response#getBody()` -```php -$bot->sendSticker(['TARGET_MID'], 1, 1, 100); -``` +This method returns the body of response as string. -#### LINEBot#sendRichMessage($mid, $imageURL, $altText, Markup $markup) +### More information -Send a rich message to mid(s). -[https://developers.line.me/bot-api/api-reference#sending_rich_content_message_request](https://developers.line.me/bot-api/api-reference#sending_rich_content_message_request) +Please check [official API documents](#about-line-messaging-api) and PHPDoc. +If you first time to use this library, we recommend to see `examples` and PHPDoc of `\LINE\LINEBot`. -```php -$markup = (new Markup(1040)) - ->setAction('SOMETHING', 'something', 'https://line.me') - ->addListener('SOMETHING', 0, 0, 1040, 1040); -$bot->sendRichMessage(['TARGET_MID'], 'https://example.com/image.jpg', "Alt text", $markup); -``` +Hints +-- -#### LINEBot#sendMultipleMessages($mid, MultipleMessages $multipleMessages) +### Examples -Send multiple messages to mids(s). -[https://developers.line.me/bot-api/api-reference#sending_multiple_messages_request](https://developers.line.me/bot-api/api-reference#sending_multiple_messages_request) +This repository contains two examples of LINE Messaging API. -```php -$multipleMessages = (new \LINE\LINEBot\Message\MultipleMessages()) - ->addText('hello!') - ->addImage('http://example.com/image.jpg', 'http://example.com/preview.jpg') - ->addAudio('http://example.com/audio.m4a', 6000) - ->addVideo('http://example.com/video.mp4', 'http://example.com/video_preview.jpg') - ->addLocation('2 Chome-21-1 Shibuya Tokyo 150-0002, Japan', 35.658240, 139.703478) - ->addSticker(1, 1, 100); -$bot->sendMultipleMessages(['TARGET_MID'], $multipleMessages); -``` +#### [EchoBot](/examples/EchoBot) -### Getting Message Contents +A simple sample implementation. This application reacts to text message that is from user. -#### LINEBot#getMessageContent($messageId, $fileHandler = null) +#### [KitchenSink](/examples/KitchenSink) -Retrieve the content of a user's message which is an image or video file. -[https://developers.line.me/bot-api/api-reference#getting_message_content_request](https://developers.line.me/bot-api/api-reference#getting_message_content_request) +A full-stack (and a bit complex) sample implementation. That will show you practical usage of LINE Messaging API. -```php -$content = $bot->getMessageContent('1234567890'); -``` +### PHPDoc -#### LINEBot#getMessageContentPreview($messageId, $fileHandler = null) +This library provides PHPDoc. That will helps you to know usages of methods. -Retrieve thumbnail preview of the message. -[https://developers.line.me/bot-api/api-reference#getting_message_content_preview_request](https://developers.line.me/bot-api/api-reference#getting_message_content_preview_request) +This library can generate pretty documents by [apigen](http://www.apigen.org/). Please try: -```php -$content = $bot->getMessageContentPreview('1234567890'); +``` +$ make doc ``` -### Getting User Profile +When HTML documents will be put on `docs/`. -#### LINEBot#getUserProfile($mid) +### Official API documents -Retrieve user profile(s) that is associated with mid(s). -[https://developers.line.me/bot-api/api-reference#getting_user_profile_information_request](https://developers.line.me/bot-api/api-reference#getting_user_profile_information_request) +[Official API documents](#about-line-messaging-api) shows the detail of Messaging API and fundamental usage of SDK. -```php -$profile = $bot->getUserProfile(['TARGET_MID']); -``` +Notes +-- -### Signature Validation +### How to switch HTTP client implementation? -#### LINEBot#validateSignature($json, $signature) +1. Implement `\LINE\LINEBot\HTTPClient` +2. Pass the implementation to the constructor of `\LINE\LINEBot` -Validate signature. +Please refer [CurlHTTPClient](/src/LINEBot/HTTPClient/CurlHTTPClient.php) that is the default HTTP client implementation. -```php -$isValid = $bot->validateSignature($requestJSON, 'expected-signature'); -``` +Requirements +-- -Run Tests +- PHP 5.6 or later + +For SDK developers -- -### Execute with `phpunit` +### How to run tests? -``` -composer install -./vendor/bin/phpunit ./tests -``` +Please use `make test`. -### Execute `make test` +### How to execute [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer)? -``` -composer install -make -``` +Please use `make phpcs`. -Hints --- +### How to execute [PHPMD](https://phpmd.org/)? + +Please use `make phpmd`. + +### How to execute them all?? -You can find some implementation examples [here](./examples). +`make` License -- @@ -200,7 +179,7 @@ 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: - http://www.apache.org/licenses/LICENSE-2.0 + 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 @@ -209,10 +188,3 @@ License for the specific language governing permissions and limitations under the License. ``` -See Also --- - -- [https://business.line.me/](https://business.line.me/) -- [https://developers.line.me/bot-api/overview](https://developers.line.me/bot-api/overview) -- [https://developers.line.me/bot-api/getting-started-with-bot-api-trial](https://developers.line.me/bot-api/getting-started-with-bot-api-trial) - diff --git a/composer.json b/composer.json index a146c608..9d68462c 100644 --- a/composer.json +++ b/composer.json @@ -1,13 +1,13 @@ { "name": "linecorp/line-bot-sdk", - "description": "SDK of the LINE BOT API Trial for PHP", + "description": "SDK of the LINE BOT API for PHP", "keywords": [ "LINE", "bot", "sdk" ], "type": "library", - "homepage": "http://github.com/line/line-bot-sdk-php", + "homepage": "https://github.com/line/line-bot-sdk-php", "license": "Apache License Version 2.0", "authors": [ { @@ -16,8 +16,7 @@ } ], "require": { - "php": ">=5.4", - "guzzlehttp/guzzle": "^5.3" + "php": ">=5.6" }, "require-dev": { "phpunit/phpunit": "^4.8.24", diff --git a/devtool/check_copyright.sh b/devtool/check_copyright.sh new file mode 100644 index 00000000..596bd067 --- /dev/null +++ b/devtool/check_copyright.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +FILES=$(cd ./$(git rev-parse --show-cdup); find `pwd` -name '*.php' | grep -v /vendor/) + +NOT_INCLUDE_COPYRIGHT_FILES=() + +for FILE in $FILES; do + if ! grep -q 'LINE Corporation licenses this file to you under the Apache License' $FILE; then + NOT_INCLUDE_COPYRIGHT_FILES=("${NOT_INCLUDE_COPYRIGHT_FILES[@]}" $FILE) + fi +done + +EXIT_CODE=0 +if [ ${#NOT_INCLUDE_COPYRIGHT_FILES[@]} -gt 0 ]; then + echo '[ERROR] Detected file(s) that does not include copyright' + EXIT_CODE=1 +fi + +for FILE in ${NOT_INCLUDE_COPYRIGHT_FILES[@]}; do + echo $FILE +done + +exit $EXIT_CODE + diff --git a/examples/EchoBot/.gitignore b/examples/EchoBot/.gitignore index a27edd14..760f22ab 100644 --- a/examples/EchoBot/.gitignore +++ b/examples/EchoBot/.gitignore @@ -1,5 +1,2 @@ -/vendor/ -/logs/* !/logs/.gitkeep -composer.lock -composer.phar +/logs/* diff --git a/examples/EchoBot/LICENSE b/examples/EchoBot/LICENSE index 5c515ba9..378cc222 100644 --- a/examples/EchoBot/LICENSE +++ b/examples/EchoBot/LICENSE @@ -1,6 +1,6 @@ Apache License Version 2.0, January 2004 - http://www.apache.org/licenses/ + https://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION @@ -192,7 +192,7 @@ you may not use this file except in compliance with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + 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, diff --git a/examples/EchoBot/README.md b/examples/EchoBot/README.md index 2c38e7ce..81f26617 100644 --- a/examples/EchoBot/README.md +++ b/examples/EchoBot/README.md @@ -1,7 +1,8 @@ line-echo-bot-sample == -A sample echo bot implementation of LINE BOT API Trial. +A sample echo bot implementation of LINE Messaging API. + This project is using [Slim framework](http://www.slimframework.com/). Getting Started @@ -10,8 +11,8 @@ Getting Started ``` $ (cd ../../ && composer install) $ composer install -$ $EDITOR ./src/settings.php # <= edit your bot information -$ php -S 0.0.0.0:8080 -t public ./public/index.php +$ $EDITOR ./src/LINEBot/EchoBot/Setting.php # <= edit your bot information +$ php -S 0.0.0.0:8080 -t public ``` Hints @@ -21,7 +22,7 @@ Hints Entry point of this application. -### [src/routes.php](./src/routes.php) +### [src/LINEBot/EchoBot/Route.php](./src/LINEBot/EchoBot/Route.php) Core logic of this application that uses LINE BOT API. @@ -35,7 +36,7 @@ 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: - http://www.apache.org/licenses/LICENSE-2.0 + 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 @@ -43,3 +44,4 @@ 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/examples/EchoBot/composer.json b/examples/EchoBot/composer.json index 02868453..c3c48d60 100644 --- a/examples/EchoBot/composer.json +++ b/examples/EchoBot/composer.json @@ -7,8 +7,13 @@ } ], "require": { - "php": ">=5.5", - "slim/slim": "^3.0", - "monolog/monolog": "^1.19.0" + "php": ">=5.6", + "slim/slim": "^3.5.0", + "monolog/monolog": "^1.21.0" + }, + "autoload": { + "psr-4": { + "LINE\\": "src/" + } } } diff --git a/examples/EchoBot/public/index.php b/examples/EchoBot/public/index.php index af8f6c32..cb802165 100644 --- a/examples/EchoBot/public/index.php +++ b/examples/EchoBot/public/index.php @@ -1,4 +1,5 @@ register($app); +(new Route())->register($app); $app->run(); diff --git a/examples/EchoBot/src/LINEBot/EchoBot/Dependency.php b/examples/EchoBot/src/LINEBot/EchoBot/Dependency.php new file mode 100644 index 00000000..4994110f --- /dev/null +++ b/examples/EchoBot/src/LINEBot/EchoBot/Dependency.php @@ -0,0 +1,50 @@ +getContainer(); + + $container['logger'] = 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)); + return $logger; + }; + + $container['bot'] = 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 + ]); + return $bot; + }; + } +} diff --git a/examples/EchoBot/src/LINEBot/EchoBot/Route.php b/examples/EchoBot/src/LINEBot/EchoBot/Route.php new file mode 100644 index 00000000..83bc78e9 --- /dev/null +++ b/examples/EchoBot/src/LINEBot/EchoBot/Route.php @@ -0,0 +1,79 @@ +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; + + $signature = $req->getHeader(HTTPHeader::LINE_SIGNATURE); + if (empty($signature)) { + return $res->withStatus(400, 'Bad Request'); + } + + // Check request with signature and parse request + try { + $events = $bot->parseEventRequest($req->getBody(), $signature[0]); + } catch (InvalidSignatureException $e) { + return $res->withStatus(400, 'Invalid signature'); + } catch (UnknownEventTypeException $e) { + return $res->withStatus(400, 'Unknown event type has come'); + } catch (UnknownMessageTypeException $e) { + return $res->withStatus(400, 'Unknown message type has come'); + } catch (InvalidEventRequestException $e) { + return $res->withStatus(400, "Invalid event request"); + } + + foreach ($events as $event) { + if (!($event instanceof MessageEvent)) { + $logger->info('Non message event has come'); + continue; + } + + if (!($event instanceof TextMessage)) { + $logger->info('Non text message has come'); + continue; + } + + $replyText = $event->getText(); + $logger->info('Reply text: ' . $replyText); + $resp = $bot->replyText($event->getReplyToken(), $replyText); + $logger->info($resp->getHTTPStatus() . ': ' . $resp->getRawBody()); + } + + $res->write('OK'); + return $res; + }); + } +} diff --git a/examples/EchoBot/src/LINEBot/EchoBot/Setting.php b/examples/EchoBot/src/LINEBot/EchoBot/Setting.php new file mode 100644 index 00000000..9312e691 --- /dev/null +++ b/examples/EchoBot/src/LINEBot/EchoBot/Setting.php @@ -0,0 +1,43 @@ + [ + 'displayErrorDetails' => true, // set to false in production + + 'logger' => [ + 'name' => 'slim-app', + 'path' => __DIR__ . '/../../../logs/app.log', + ], + + 'bot' => [ + 'channelToken' => getenv('LINEBOT_CHANNEL_TOKEN') ?: '', + 'channelSecret' => getenv('LINEBOT_CHANNEL_SECRET') ?: '', + ], + + 'apiEndpointBase' => getenv('LINEBOT_API_ENDPOINT_BASE'), + ], + ]; + } +} diff --git a/examples/EchoBot/src/dependencies.php b/examples/EchoBot/src/dependencies.php deleted file mode 100644 index f1d0ea50..00000000 --- a/examples/EchoBot/src/dependencies.php +++ /dev/null @@ -1,39 +0,0 @@ -getContainer(); - -$container['logger'] = 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)); - return $logger; -}; - -$container['bot'] = function ($c) { - $settings = $c->get('settings')['bot']; - $config = [ - 'channelId' => $settings['channelId'], - 'channelSecret' => $settings['channelSecret'], - 'channelMid' => $settings['channelMid'], - ]; - $bot = new LINEBot($config, new GuzzleHTTPClient($config)); - return $bot; -}; diff --git a/examples/EchoBot/src/routes.php b/examples/EchoBot/src/routes.php deleted file mode 100644 index 18b54233..00000000 --- a/examples/EchoBot/src/routes.php +++ /dev/null @@ -1,133 +0,0 @@ -post('/callback', function (Request $req, Response $res, $arg) { - $body = $req->getBody(); - $signatureHeader = $req->getHeader('X-LINE-ChannelSignature'); - if (empty($signatureHeader) || !$this->bot->validateSignature($body, $signatureHeader[0])) { - return $res->withStatus(400, "Bad Request"); - } - - /** @var LINEBot $bot */ - $bot = $this->bot; - - /** @var Receive[] $receives */ - $receives = $bot->createReceivesFromJSON($body); - foreach ($receives as $receive) { - if ($receive->isMessage()) { - /** @var Message $receive */ - - $this->logger->info(sprintf( - 'contentId=%s, fromMid=%s, createdTime=%s', - $receive->getContentId(), - $receive->getFromMid(), - $receive->getCreatedTime() - )); - - if ($receive->isText()) { - /** @var Text $receive */ - if ($receive->getText() === 'me') { - $ret = $bot->getUserProfile($receive->getFromMid()); - $contact = $ret['contacts'][0]; - $multipleMsgs = (new MultipleMessages()) - ->addText(sprintf( - 'Hello! %s san! Your status message is %s', - $contact['displayName'], - $contact['statusMessage'] - )) - ->addImage($contact['pictureUrl'], $contact['pictureUrl']) - ->addSticker(mt_rand(0, 10), 1, 100); - $bot->sendMultipleMessages($receive->getFromMid(), $multipleMsgs); - } else { - $bot->sendText($receive->getFromMid(), $receive->getText()); - } - } elseif ($receive->isImage() || $receive->isVideo()) { - $content = $bot->getMessageContent($receive->getContentId()); - $meta = stream_get_meta_data($content->getFileHandle()); - $contentSize = filesize($meta['uri']); - $type = $receive->isImage() ? 'image' : 'video'; - - $previewContent = $bot->getMessageContentPreview($receive->getContentId()); - $previewMeta = stream_get_meta_data($previewContent->getFileHandle()); - $previewContentSize = filesize($previewMeta['uri']); - - $bot->sendText( - $receive->getFromMid(), - "Thank you for sending a $type.\nOriginal file size: " . - "$contentSize\nPreview file size: $previewContentSize" - ); - } elseif ($receive->isAudio()) { - $bot->sendText($receive->getFromMid(), "Thank you for sending a audio."); - } elseif ($receive->isLocation()) { - /** @var Location $receive */ - $bot->sendLocation( - $receive->getFromMid(), - sprintf("%s\n%s", $receive->getText(), $receive->getAddress()), - $receive->getLatitude(), - $receive->getLongitude() - ); - } elseif ($receive->isSticker()) { - /** @var Sticker $receive */ - $bot->sendSticker( - $receive->getFromMid(), - $receive->getStkId(), - $receive->getStkPkgId(), - $receive->getStkVer() - ); - } elseif ($receive->isContact()) { - /** @var Contact $receive */ - $bot->sendText( - $receive->getFromMid(), - sprintf("Thank you for sending %s information.", $receive->getDisplayName()) - ); - } else { - throw new \Exception("Received invalid message type"); - } - } elseif ($receive->isOperation()) { - /** @var Operation $receive */ - - $this->logger->info(sprintf( - 'revision=%s, fromMid=%s', - $receive->getRevision(), - $receive->getFromMid() - )); - - if ($receive->isAddContact()) { - $bot->sendText($receive->getFromMid(), "Thank you for adding me to your contact list!"); - } elseif ($receive->isBlockContact()) { - $this->logger->info("Blocked"); - } else { - throw new \Exception("Received invalid operation type"); - } - } else { - throw new \Exception("Received invalid receive type"); - } - } - - return $res->getBody()->write("OK"); -}); diff --git a/examples/EchoBot/src/settings.php b/examples/EchoBot/src/settings.php deleted file mode 100644 index edce9d8f..00000000 --- a/examples/EchoBot/src/settings.php +++ /dev/null @@ -1,32 +0,0 @@ - [ - 'displayErrorDetails' => true, // set to false in production - - 'logger' => [ - 'name' => 'slim-app', - 'path' => __DIR__ . '/../logs/app.log', - ], - - 'bot' => [ - 'channelId' => '', - 'channelSecret' => '', - 'channelMid' => '', - ], - ], -]; diff --git a/examples/KitchenSink/.gitignore b/examples/KitchenSink/.gitignore new file mode 100644 index 00000000..20778ea7 --- /dev/null +++ b/examples/KitchenSink/.gitignore @@ -0,0 +1,4 @@ +!/logs/.gitkeep +/logs/* +!/public/static/tmpdir/.gitkeep +/public/static/tmpdir/* diff --git a/examples/KitchenSink/LICENSE b/examples/KitchenSink/LICENSE new file mode 100644 index 00000000..378cc222 --- /dev/null +++ b/examples/KitchenSink/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (C) 2016 LINE Corp. + + Licensed 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/examples/KitchenSink/README.md b/examples/KitchenSink/README.md new file mode 100644 index 00000000..46fd3ccb --- /dev/null +++ b/examples/KitchenSink/README.md @@ -0,0 +1,68 @@ +line-bot-sample +== + +A full-stack LINE Messaging API sample implementation. This sample will show you practical usage of LINE Messaging API. + +This project is using [Slim framework](http://www.slimframework.com/). + +Getting Started +-- + +``` +$ (cd ../../ && composer install) +$ composer install +$ $EDITOR ./src/LINEBot/KitchenSink/Setting.php # <= edit your bot information +$ ./run.sh 8080 +``` + +Hints +-- + +### [public/index.php](./public/index.php) + +Entry point of this application. + +### [src/LINEBot/KitchenSink/Route.php](./src/LINEBot/KitchenSink/Route.php) + +Core logic of this application that uses LINE BOT API. + +### [Event handlers](./src/LINEBot/KitchenSink/EventHandler) + +Handlers for LINE Messaging API events. + +Notes +-- + +### Temporary directory + +This application downloads multimedia files on `./public/static/tmpdir/`. +`./run.sh` wrapper removes such contents on shutting down the PHP server. + +### Base URL + +This application serves downloaded multimedia files. + +Default, this app constructs URL of such content with `\Slim\Http\Request->getUri()->getBaseUrl()` as base URL. +Unfortunately this processing doesn't work correctly if this app runs on reverse-proxied environment. + +If you get such symptom, please configure base URL as you like => [UrlBuilder](./src/LINEBot/KitchenSink/EventHandler/MessageHandler/Util/UrlBuilder.php) + +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/examples/KitchenSink/composer.json b/examples/KitchenSink/composer.json new file mode 100644 index 00000000..c3c48d60 --- /dev/null +++ b/examples/KitchenSink/composer.json @@ -0,0 +1,19 @@ +{ + "license": "Apache License, Version 2.0", + "authors": [ + { + "name": "moznion", + "email": "moznion@gmail.com" + } + ], + "require": { + "php": ">=5.6", + "slim/slim": "^3.5.0", + "monolog/monolog": "^1.21.0" + }, + "autoload": { + "psr-4": { + "LINE\\": "src/" + } + } +} diff --git a/examples/KitchenSink/public/.htaccess b/examples/KitchenSink/public/.htaccess new file mode 100644 index 00000000..c1245d13 --- /dev/null +++ b/examples/KitchenSink/public/.htaccess @@ -0,0 +1,11 @@ +RewriteEngine On + +# Some hosts may require you to use the `RewriteBase` directive. +# If you need to use the `RewriteBase` directive, it should be the +# absolute physical path to the directory that contains this htaccess file. +# +# RewriteBase / + +RewriteCond %{REQUEST_FILENAME} !-f +RewriteRule ^ index.php [QSA,L] + diff --git a/examples/KitchenSink/public/index.php b/examples/KitchenSink/public/index.php new file mode 100644 index 00000000..d582037a --- /dev/null +++ b/examples/KitchenSink/public/index.php @@ -0,0 +1,32 @@ +register($app); +(new Dependency())->register($app); + +$app->run(); diff --git a/examples/KitchenSink/public/static/buttons/1040.jpg b/examples/KitchenSink/public/static/buttons/1040.jpg new file mode 100644 index 00000000..de65e1c9 Binary files /dev/null and b/examples/KitchenSink/public/static/buttons/1040.jpg differ diff --git a/examples/KitchenSink/public/static/rich/1040 b/examples/KitchenSink/public/static/rich/1040 new file mode 100644 index 00000000..de65e1c9 Binary files /dev/null and b/examples/KitchenSink/public/static/rich/1040 differ diff --git a/examples/KitchenSink/public/static/rich/240 b/examples/KitchenSink/public/static/rich/240 new file mode 100644 index 00000000..eeedf27d Binary files /dev/null and b/examples/KitchenSink/public/static/rich/240 differ diff --git a/examples/KitchenSink/public/static/rich/300 b/examples/KitchenSink/public/static/rich/300 new file mode 100644 index 00000000..357c444b Binary files /dev/null and b/examples/KitchenSink/public/static/rich/300 differ diff --git a/examples/KitchenSink/public/static/rich/460 b/examples/KitchenSink/public/static/rich/460 new file mode 100644 index 00000000..46709f9c Binary files /dev/null and b/examples/KitchenSink/public/static/rich/460 differ diff --git a/examples/KitchenSink/public/static/rich/700 b/examples/KitchenSink/public/static/rich/700 new file mode 100644 index 00000000..63d8062f Binary files /dev/null and b/examples/KitchenSink/public/static/rich/700 differ diff --git a/examples/KitchenSink/run.sh b/examples/KitchenSink/run.sh new file mode 100755 index 00000000..b49dd35c --- /dev/null +++ b/examples/KitchenSink/run.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +PORT=$1 +if [ -z $PORT ]; then + cat <getContainer(); + + $container['logger'] = 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)); + return $logger; + }; + + $container['bot'] = 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 + ]); + return $bot; + }; + } +} diff --git a/src/LINEBot/Exception/LINEBotAPIException.php b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler.php similarity index 81% rename from src/LINEBot/Exception/LINEBotAPIException.php rename to examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler.php index 5c8fe92f..33c6280c 100644 --- a/src/LINEBot/Exception/LINEBotAPIException.php +++ b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler.php @@ -1,4 +1,5 @@ bot = $bot; + $this->logger = $logger; + $this->beaconEvent = $beaconEvent; + } + + public function handle() + { + $this->bot->replyText( + $this->beaconEvent->getReplyToken(), + 'Got beacon message ' . $this->beaconEvent->getHwid() + ); + } +} diff --git a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/FollowEventHandler.php b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/FollowEventHandler.php new file mode 100644 index 00000000..678fe3df --- /dev/null +++ b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/FollowEventHandler.php @@ -0,0 +1,51 @@ +bot = $bot; + $this->logger = $logger; + $this->followEvent = $followEvent; + } + + public function handle() + { + $this->bot->replyText($this->followEvent->getReplyToken(), 'Got followed event'); + } +} diff --git a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/JoinEventHandler.php b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/JoinEventHandler.php new file mode 100644 index 00000000..568b51fa --- /dev/null +++ b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/JoinEventHandler.php @@ -0,0 +1,54 @@ +bot = $bot; + $this->logger = $logger; + $this->joinEvent = $joinEvent; + } + + public function handle() + { + $this->bot->replyText( + $this->joinEvent->getReplyToken(), + sprintf('Joined %s %s', $this->joinEvent->getType(), $this->joinEvent->getUserId()) + ); + } +} diff --git a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/LeaveEventHandler.php b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/LeaveEventHandler.php new file mode 100644 index 00000000..90fcc96c --- /dev/null +++ b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/LeaveEventHandler.php @@ -0,0 +1,54 @@ +bot = $bot; + $this->logger = $logger; + $this->leaveEvent = $leaveEvent; + } + + public function handle() + { + $this->bot->replyText( + $this->leaveEvent->getReplyToken(), + sprintf('Leaved %s %s', $this->leaveEvent->getType(), $this->leaveEvent->getUserId()) + ); + } +} diff --git a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/AudioMessageHandler.php b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/AudioMessageHandler.php new file mode 100644 index 00000000..ddbf1902 --- /dev/null +++ b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/AudioMessageHandler.php @@ -0,0 +1,77 @@ +bot = $bot; + $this->logger = $logger; + $this->req = $req; + $this->audioMessage = $audioMessage; + } + + public function handle() + { + $contentId = $this->audioMessage->getMessageId(); + $audio = $this->bot->getMessageContent($contentId)->getRawBody(); + + $tmpfilePath = tempnam($_SERVER['DOCUMENT_ROOT'] . '/static/tmpdir', 'audio-'); + unlink($tmpfilePath); + $filePath = $tmpfilePath . '.mp4'; + $filename = basename($filePath); + + $fh = fopen($filePath, 'x'); + fwrite($fh, $audio); + fclose($fh); + + $replyToken = $this->audioMessage->getReplyToken(); + + $url = UrlBuilder::buildUrl($this->req, ['static', 'tmpdir', $filename]); + + $resp = $this->bot->replyMessage( + $replyToken, + new AudioMessageBuilder($url, 100) + ); + $this->logger->info($resp->getRawBody()); + } +} diff --git a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/ImageMessageHandler.php b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/ImageMessageHandler.php new file mode 100644 index 00000000..5ab7ae23 --- /dev/null +++ b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/ImageMessageHandler.php @@ -0,0 +1,75 @@ +bot = $bot; + $this->logger = $logger; + $this->req = $req; + $this->imageMessage = $imageMessage; + } + + public function handle() + { + $contentId = $this->imageMessage->getMessageId(); + $image = $this->bot->getMessageContent($contentId)->getRawBody(); + + $tmpfilePath = tempnam($_SERVER['DOCUMENT_ROOT'] . '/static/tmpdir', 'image-'); + unlink($tmpfilePath); + $filePath = $tmpfilePath . '.jpg'; + $filename = basename($filePath); + + $fh = fopen($filePath, 'x'); + fwrite($fh, $image); + fclose($fh); + + $replyToken = $this->imageMessage->getReplyToken(); + + $url = UrlBuilder::buildUrl($this->req, ['static', 'tmpdir', $filename]); + + // 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)); + } +} diff --git a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/LocationMessageHandler.php b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/LocationMessageHandler.php new file mode 100644 index 00000000..59e3678e --- /dev/null +++ b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/LocationMessageHandler.php @@ -0,0 +1,61 @@ +bot = $bot; + $this->logger = $logger; + $this->locationMessage = $locationMessage; + } + + public function handle() + { + $replyToken = $this->locationMessage->getReplyToken(); + $title = $this->locationMessage->getTitle(); + $address = $this->locationMessage->getAddress(); + $latitude = $this->locationMessage->getLatitude(); + $longitude = $this->locationMessage->getLongitude(); + + $this->bot->replyMessage( + $replyToken, + new LocationMessageBuilder($title, $address, $latitude, $longitude) + ); + } +} diff --git a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/StickerMessageHandler.php b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/StickerMessageHandler.php new file mode 100644 index 00000000..05f6f137 --- /dev/null +++ b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/StickerMessageHandler.php @@ -0,0 +1,55 @@ +bot = $bot; + $this->logger = $logger; + $this->stickerMessage = $stickerMessage; + } + + public function handle() + { + $replyToken = $this->stickerMessage->getReplyToken(); + $packageId = $this->stickerMessage->getPackageId(); + $stickerId = $this->stickerMessage->getStickerId(); + $this->bot->replyMessage($replyToken, new StickerMessageBuilder($packageId, $stickerId)); + } +} diff --git a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/TextMessageHandler.php b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/TextMessageHandler.php new file mode 100644 index 00000000..e2732f2c --- /dev/null +++ b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/TextMessageHandler.php @@ -0,0 +1,195 @@ +bot = $bot; + $this->logger = $logger; + $this->req = $req; + $this->textMessage = $textMessage; + } + + public function handle() + { + $text = $this->textMessage->getText(); + $replyToken = $this->textMessage->getReplyToken(); + $this->logger->info("Got text message from $replyToken: $text"); + + switch ($text) { + case 'profile': + $userId = $this->textMessage->getUserId(); + $this->sendProfile($replyToken, $userId); + break; + case 'bye': + if ($this->textMessage->isRoomEvent()) { + $this->bot->replyText($replyToken, 'Leaving room'); + $this->bot->leaveRoom($this->textMessage->getRoomId()); + break; + } + if ($this->textMessage->isGroupEvent()) { + $this->bot->replyText($replyToken, 'Leaving group'); + $this->bot->leaveGroup($this->textMessage->getGroupId()); + break; + } + $this->bot->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!'), + ]) + ) + ); + 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); + 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 TemplateMessageBuilder('Button alt text', $carouselTemplateBuilder); + $this->bot->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); + break; + default: + $this->echoBack($replyToken, $text); + break; + } + } + + /** + * @param string $replyToken + * @param string $text + */ + private function echoBack($replyToken, $text) + { + $this->logger->info("Returns echo message $replyToken: $text"); + $this->bot->replyText($replyToken, $text); + } + + private function sendProfile($replyToken, $userId) + { + if (!isset($userId)) { + $this->bot->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()); + return; + } + + $profile = $response->getJSONDecodedBody(); + $this->bot->replyText( + $replyToken, + 'Display name: ' . $profile['displayName'], + 'Status message: ' . $profile['statusMessage'] + ); + } +} diff --git a/src/LINEBot/Receive/Operation.php b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/Util/UrlBuilder.php similarity index 52% rename from src/LINEBot/Receive/Operation.php rename to examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/Util/UrlBuilder.php index 3213aaa8..d88574e9 100644 --- a/src/LINEBot/Receive/Operation.php +++ b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/Util/UrlBuilder.php @@ -1,4 +1,5 @@ getResult()['content']['revision']; - } +namespace LINE\LINEBot\KitchenSink\EventHandler\MessageHandler\Util; - public function getFromMid() - { - return $this->getResult()['content']['params'][0]; - } - - public function isAddContact() - { - return false; - } - - public function isBlockContact() +class UrlBuilder +{ + public static function buildUrl(\Slim\Http\Request $req, array $paths) { - return false; + // 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(); + foreach ($paths as $path) { + $baseUri .= '/' . urlencode($path); + } + return $baseUri; } } diff --git a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/VideoMessageHandler.php b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/VideoMessageHandler.php new file mode 100644 index 00000000..fc5c5b6a --- /dev/null +++ b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/MessageHandler/VideoMessageHandler.php @@ -0,0 +1,76 @@ +bot = $bot; + $this->logger = $logger; + $this->req = $req; + $this->videoMessage = $videoMessage; + } + + public function handle() + { + $contentId = $this->videoMessage->getMessageId(); + $video = $this->bot->getMessageContent($contentId)->getRawBody(); + + $tmpfilePath = tempnam($_SERVER['DOCUMENT_ROOT'] . '/static/tmpdir', 'video-'); + unlink($tmpfilePath); + $filePath = $tmpfilePath . '.mp4'; + $filename = basename($filePath); + + $fh = fopen($filePath, 'x'); + fwrite($fh, $video); + fclose($fh); + + $replyToken = $this->videoMessage->getReplyToken(); + + $url = UrlBuilder::buildUrl($this->req, ['static', 'tmpdir', $filename]); + + // 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)); + } +} diff --git a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/PostbackEventHandler.php b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/PostbackEventHandler.php new file mode 100644 index 00000000..ebe74ff5 --- /dev/null +++ b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/PostbackEventHandler.php @@ -0,0 +1,54 @@ +bot = $bot; + $this->logger = $logger; + $this->postbackEvent = $postbackEvent; + } + + public function handle() + { + $this->bot->replyText( + $this->postbackEvent->getReplyToken(), + 'Got postback ' . $this->postbackEvent->getPostbackData() + ); + } +} diff --git a/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/UnfollowEventHandler.php b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/UnfollowEventHandler.php new file mode 100644 index 00000000..b5d71c33 --- /dev/null +++ b/examples/KitchenSink/src/LINEBot/KitchenSink/EventHandler/UnfollowEventHandler.php @@ -0,0 +1,55 @@ +bot = $bot; + $this->logger = $logger; + $this->unfollowEvent = $unfollowEvent; + } + + public function handle() + { + $this->logger->info(sprintf( + 'Unfollowed this bot %s %s', + $this->unfollowEvent->getType(), + $this->unfollowEvent->getUserId() + )); + } +} diff --git a/examples/KitchenSink/src/LINEBot/KitchenSink/Route.php b/examples/KitchenSink/src/LINEBot/KitchenSink/Route.php new file mode 100644 index 00000000..a5392c25 --- /dev/null +++ b/examples/KitchenSink/src/LINEBot/KitchenSink/Route.php @@ -0,0 +1,129 @@ +post('/callback', function (\Slim\Http\Request $req, \Slim\Http\Response $res) { + /** @var LINEBot $bot */ + $bot = $this->bot; + /** @var \Monolog\Logger $logger */ + $logger = $this->logger; + + $signature = $req->getHeader(HTTPHeader::LINE_SIGNATURE); + if (empty($signature)) { + $logger->info('Signature is missing'); + return $res->withStatus(400, 'Bad Request'); + } + + try { + $events = $bot->parseEventRequest($req->getBody(), $signature[0]); + } catch (InvalidSignatureException $e) { + $logger->info('Invalid signature'); + return $res->withStatus(400, 'Invalid signature'); + } catch (UnknownEventTypeException $e) { + return $res->withStatus(400, 'Unknown event type has come'); + } catch (UnknownMessageTypeException $e) { + return $res->withStatus(400, 'Unknown message type has come'); + } catch (InvalidEventRequestException $e) { + return $res->withStatus(400, "Invalid event request"); + } + + foreach ($events as $event) { + /** @var EventHandler $handler */ + $handler = null; + + if ($event instanceof MessageEvent) { + if ($event instanceof TextMessage) { + $handler = new TextMessageHandler($bot, $logger, $req, $event); + } elseif ($event instanceof StickerMessage) { + $handler = new StickerMessageHandler($bot, $logger, $event); + } elseif ($event instanceof LocationMessage) { + $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); + } else { + // Just in case... + $logger->info('Unknown message type has come'); + continue; + } + } elseif ($event instanceof UnfollowEvent) { + $handler = new UnfollowEventHandler($bot, $logger, $event); + } elseif ($event instanceof FollowEvent) { + $handler = new FollowEventHandler($bot, $logger, $event); + } elseif ($event instanceof JoinEvent) { + $handler = new JoinEventHandler($bot, $logger, $event); + } elseif ($event instanceof LeaveEvent) { + $handler = new LeaveEventHandler($bot, $logger, $event); + } elseif ($event instanceof PostbackEvent) { + $handler = new PostbackEventHandler($bot, $logger, $event); + } elseif ($event instanceof BeaconDetectionEvent) { + $handler = new BeaconEventHandler($bot, $logger, $event); + } else { + // Just in case... + $logger->info('Unknown event type has come'); + continue; + } + + $handler->handle(); + } + + $res->write('OK'); + return $res; + }); + } +} diff --git a/examples/KitchenSink/src/LINEBot/KitchenSink/Setting.php b/examples/KitchenSink/src/LINEBot/KitchenSink/Setting.php new file mode 100644 index 00000000..a0dcd398 --- /dev/null +++ b/examples/KitchenSink/src/LINEBot/KitchenSink/Setting.php @@ -0,0 +1,43 @@ + [ + 'displayErrorDetails' => true, // set to false in production + + 'logger' => [ + 'name' => 'slim-app', + 'path' => __DIR__ . '/../../../logs/app.log', + ], + + 'bot' => [ + 'channelToken' => getenv('LINEBOT_CHANNEL_TOKEN') ?: '', + 'channelSecret' => getenv('LINEBOT_CHANNEL_SECRET') ?: '', + ], + + 'apiEndpointBase' => getenv('LINEBOT_API_ENDPOINT_BASE'), + ], + ]; + } +} diff --git a/examples/SendingSample/sample.php b/examples/SendingSample/sample.php deleted file mode 100644 index 595c1c18..00000000 --- a/examples/SendingSample/sample.php +++ /dev/null @@ -1,71 +0,0 @@ - $channelId, - 'channelSecret' => $channelSecret, - 'channelMid' => $channelMid, -]; -$sdk = new LINEBot($config, new GuzzleHTTPClient($config)); - -// Send a text message -$sdk->sendText([$targetMid], 'hello!'); - -// Send an image -$sdk->sendImage([$targetMid], 'http://example.com/image.jpg', 'http://example.com/preview.jpg'); - -// Send an voice message -$sdk->sendAudio([$targetMid], 'http://example.com/audio.m4a', 5000); - -// Send a video -$sdk->sendVideo([$targetMid], 'http://example.com/video.mp4', 'http://example.com/video_preview.jpg'); - -// Send a location -$sdk->sendLocation([$targetMid], '2 Chome-21-1 Shibuya Tokyo 150-0002, Japan', 35.658240, 139.703478); - -// Send a sticker -$sdk->sendSticker([$targetMid], 1, 1, 100); - -// Send a rich message -$markup = (new Markup(1040)) - ->setAction('SOMETHING', 'something', 'https://line.me') - ->addListener('SOMETHING', 0, 0, 1040, 1040); -$sdk->sendRichMessage([$targetMid], 'https://example.com/image.jpg', "Alt text", $markup); - -// Send multiple messages -$multipleMessages = (new MultipleMessages()) - ->addText('hello!') - ->addImage('http://example.com/image.jpg', 'http://example.com/preview.jpg') - ->addAudio('http://example.com/audio.m4a', 6000) - ->addVideo('http://example.com/video.mp4', 'http://example.com/video_preview.jpg') - ->addLocation('2 Chome-21-1 Shibuya Tokyo 150-0002, Japan', 35.658240, 139.703478) - ->addSticker(1, 1, 100); -$sdk->sendMultipleMessages([$targetMid], $multipleMessages); diff --git a/examples/SendingSample/settings.php b/examples/SendingSample/settings.php deleted file mode 100644 index 95f5bf04..00000000 --- a/examples/SendingSample/settings.php +++ /dev/null @@ -1,8 +0,0 @@ - '', - 'channelSecret' => '', - 'channelMid' => '', - 'targetMid' => '', -]; diff --git a/phpunit.xml b/phpunit.xml index f278eeb1..fefe4038 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,3 +1,4 @@ + diff --git a/src/LINEBot.php b/src/LINEBot.php index edf0bed6..064e7a27 100644 --- a/src/LINEBot.php +++ b/src/LINEBot.php @@ -1,4 +1,5 @@ client = $client; - $this->channelId = $args['channelId']; + $this->httpClient = $httpClient; $this->channelSecret = $args['channelSecret']; - $this->channelMid = $args['channelMid']; - $this->eventAPIEndpoint = isset($args['eventAPIEndpoint']) ? - $args['eventAPIEndpoint'] : 'https://trialbot-api.line.me/v1/events'; - $this->botAPIEndpoint = isset($args['botAPIEndpoint']) ? - $args['botAPIEndpoint'] : 'https://trialbot-api.line.me/v1'; + $this->endpointBase = + array_key_exists('endpointBase', $args) && $args['endpointBase'] ?: LINEBot::DEFAULT_ENDPOINT_BASE; } /** - * Send a text message to mid(s). + * Gets specified user's profile through API calling. * - * @link https://developers.line.me/bot-api/api-reference#sending_message_text - * @param string|array $mid Target user's MID string or MID array. - * @param string $text String you want to send. Message can contain up to 1024 characters - * @param int $toType Type of user who will receive the message (Default: 1 = user). - * @return FailedResponse|SucceededResponse + * @param string $userId The user ID to retrieve profile. + * @return Response */ - public function sendText($mid, $text, $toType = RecipientType::USER) + public function getProfile($userId) { - return $this->sendMessage($mid, MessageBuilder::buildText($text), $toType); + return $this->httpClient->get($this->endpointBase . '/v2/bot/profile/' . urlencode($userId)); } /** - * Send a image to mid(s). + * Gets message content which is associated with specified message ID. * - * @link https://developers.line.me/bot-api/api-reference#sending_message_image - * @param string|array $mid Target user's MID string or MID array. - * @param string $imageURL URL of image. Only JPEG format supported. Image size cannot be larger than 1024×1024. - * @param string $previewURL URL of thumbnail image. For preview. Only JPEG format supported. - * Image size cannot be larger than 240×240. - * @param int $toType Type of user who will receive the message (Default: 1 = user). - * @return FailedResponse|SucceededResponse + * @param string $messageId The message ID to retrieve content. + * @return Response */ - public function sendImage($mid, $imageURL, $previewURL, $toType = RecipientType::USER) + public function getMessageContent($messageId) { - return $this->sendMessage($mid, MessageBuilder::buildImage($imageURL, $previewURL), $toType); + return $this->httpClient->get($this->endpointBase . '/v2/bot/message/' . urlencode($messageId) . '/content'); } /** - * Send a video to mid(s). + * Replies arbitrary message to destination which is associated with reply token. * - * @link https://developers.line.me/bot-api/api-reference#sending_message_video - * @param string|array $mid Target user's MID string or MID array. - * @param string $videoURL URL of the movie. The “mp4” format is recommended. - * @param string $previewImageURL URL of thumbnail image used as a preview. - * @param int $toType Type of user who will receive the message (Default: 1 = user). - * @return FailedResponse|SucceededResponse + * @param string $replyToken Identifier of destination. + * @param MessageBuilder $messageBuilder Message builder to send. + * @return Response */ - public function sendVideo($mid, $videoURL, $previewImageURL, $toType = RecipientType::USER) + public function replyMessage($replyToken, MessageBuilder $messageBuilder) { - return $this->sendMessage($mid, MessageBuilder::buildVideo($videoURL, $previewImageURL), $toType); + return $this->httpClient->post($this->endpointBase . '/v2/bot/message/reply', [ + 'replyToken' => $replyToken, + 'messages' => $messageBuilder->buildMessage(), + ]); } /** - * Send a voice message to mid(s). + * Replies text message(s) to destination which is associated with reply token. * - * @link https://developers.line.me/bot-api/api-reference#sending_message_audio - * @param string|array $mid Target user's MID string or MID array. - * @param string $audioURL URL of audio file. The “m4a” format is recommended. - * @param int $durationMillis Length of voice message. The unit is given in milliseconds. - * @param int $toType Type of user who will receive the message (Default: 1 = user). - * @return FailedResponse|SucceededResponse - */ - public function sendAudio($mid, $audioURL, $durationMillis, $toType = RecipientType::USER) - { - return $this->sendMessage($mid, MessageBuilder::buildAudio($audioURL, $durationMillis), $toType); - } - - /** - * Send location information to mid(s). + * This method receives variable texts. It can send text(s) message as bulk. * - * @link https://developers.line.me/bot-api/api-reference#sending_message_location - * @param string|array $mid Target user's MID string or MID array. - * @param string $text String used to explain the location information (example: name of restaurant, address). - * @param float $latitude Latitude. - * @param float $longitude Longitude. - * @param int $toType Type of user who will receive the message (Default: 1 = user). - * @return FailedResponse|SucceededResponse + * @param string $replyToken Identifier of destination. + * @param string $text Text of message. + * @param string[] $extraTexts Extra text of message. + * @return Response */ - public function sendLocation($mid, $text, $latitude, $longitude, $toType = RecipientType::USER) + public function replyText($replyToken, $text, ...$extraTexts) { - return $this->sendMessage($mid, MessageBuilder::buildLocation($text, $latitude, $longitude), $toType); + $textMessageBuilder = new TextMessageBuilder($text, ...$extraTexts); + return $this->replyMessage($replyToken, $textMessageBuilder); } /** - * Send a sticker to mid(s). + * Sends arbitrary message to destination. * - * @link https://developers.line.me/bot-api/api-reference#sending_message_sticker - * @param string|array $mid Target user's MID string or MID array. - * @param int $stkid ID of the sticker. - * @param int $stkpkgid Package ID of the sticker. - * @param int $stkver Version number of the sticker. If omitted, the latest version number is applied. - * @param int $toType Type of user who will receive the message (Default: 1 = user). - * @return FailedResponse|SucceededResponse + * @param string $to Identifier of destination. + * @param MessageBuilder $messageBuilder Message builder to send. + * @return Response */ - public function sendSticker($mid, $stkid, $stkpkgid, $stkver = null, $toType = RecipientType::USER) + public function pushMessage($to, MessageBuilder $messageBuilder) { - return $this->sendMessage($mid, MessageBuilder::buildSticker($stkid, $stkpkgid, $stkver), $toType); + return $this->httpClient->post($this->endpointBase . '/v2/bot/message/push', [ + 'to' => $to, + 'messages' => $messageBuilder->buildMessage(), + ]); } /** - * Send a rich message to mid(s). + * Leaves from group. * - * @link https://developers.line.me/bot-api/api-reference#sending_rich_content_message_request - * @param string|array $mid Target user's MID string or MID array. - * @param string $imageURL URL of image which is on your server. - * @param string $altText Alternative string displayed on low-level devices. - * @param Markup $markup Markup json of rich message object. - * @param int $toType Type of user who will receive the message (Default: 1 = user). - * @return FailedResponse|SucceededResponse + * @param string $groupId Identifier of group to leave. + * @return Response */ - public function sendRichMessage($mid, $imageURL, $altText, Markup $markup, $toType = RecipientType::USER) + public function leaveGroup($groupId) { - return $this->sendMessage($mid, RichMessageBuilder::buildRichMessage($imageURL, $altText, $markup), $toType); + return $this->httpClient->post($this->endpointBase . '/v2/bot/group/' . urlencode($groupId) . '/leave', []); } /** - * Send multiple messages to mid(s). + * Leaves from room. * - * @link https://developers.line.me/bot-api/api-reference#sending_multiple_messages_request - * @param string|array $mid Target user's MID string or MID array. - * @param MultipleMessages $multipleMessages Multiple messages to send. - * @param int $messageNotified Zero-based index of the message to be notified. Default value is 0. - * @return FailedResponse|SucceededResponse + * @param string $roomId Identifier of room to leave. + * @return Response */ - public function sendMultipleMessages($mid, MultipleMessages $multipleMessages, $messageNotified = 0) + public function leaveRoom($roomId) { - $multipleMessages = MultipleMessagesBuilder::buildMultipleMessages($multipleMessages, $messageNotified); - return $this->sendMessage($mid, $multipleMessages, null, EventType::SENDING_MULTIPLE_MESSAGES); + return $this->httpClient->post($this->endpointBase . '/v2/bot/room/' . urlencode($roomId) . '/leave', []); } /** - * Retrieve the content of a user's message which is an image or video file. + * Parse event request to Event objects. * - * @link https://developers.line.me/bot-api/api-reference#getting_message_content_request - * @param string $messageId ID of the message. - * @param resource $fileHandler File handler to store contents temporally. - * @return DownloadedContents + * @param string $body Request body. + * @param string $signature Signature of request. + * @return LINEBot\Event\BaseEvent[] */ - public function getMessageContent($messageId, $fileHandler = null) + public function parseEventRequest($body, $signature) { - return $this->client->downloadContents($this->botAPIEndpoint . "/bot/message/$messageId/content", $fileHandler); + return EventRequestParser::parseEventRequest($body, $this->channelSecret, $signature); } /** - * Retrieve thumbnail preview of the message. + * Validate request with signature. * - * @link https://developers.line.me/bot-api/api-reference#getting_message_content_preview_request - * @param string $messageId ID of the message. - * @param resource $fileHandler File handler to store contents temporally. - * @return DownloadedContents + * @param string $body Request body. + * @param string $signature Signature of request. + * @return bool Request is valid or not. */ - public function getMessageContentPreview($messageId, $fileHandler = null) + public function validateSignature($body, $signature) { - return $this->client - ->downloadContents($this->botAPIEndpoint . "/bot/message/$messageId/content/preview", $fileHandler); - } - - /** - * Retrieve user profiles. - * - * @link https://developers.line.me/bot-api/api-reference#getting_user_profile_information_request - * @param string|array $mid Array of MIDs to retrieve user profile. - * @return array User profiles. - * @throws LINEBotAPIException When request is failed or received invalid response. - */ - public function getUserProfile($mid) - { - $query = http_build_query( - ['mids' => (is_array($mid) ? implode(',', $mid) : $mid)] - ); - return $this->client->get($this->botAPIEndpoint . '/profiles?' . $query); - } - - /** - * Validate signature. - * - * @param string $json JSON body. - * @param string $signature The signature to validate. - * @return bool - */ - public function validateSignature($json, $signature) - { - return SignatureValidator::validateSignature($json, $this->channelSecret, $signature); - } - - /** - * Create receives from JSON request string. - * - * @param string $json JSON body. - * @return Receive[] - */ - public function createReceivesFromJSON($json) - { - return ReceiveFactory::createFromJSON([ - 'channelId' => $this->channelId, - 'channelSecret' => $this->channelSecret, - 'channelMid' => $this->channelMid, - ], $json); - } - - /** - * Send a message. - * - * @param string|array $mid - * @param array $data - * @param int $toType - * @param string $eventType - * @return FailedResponse|SucceededResponse - */ - private function sendMessage( - $mid, - array $data, - $toType = RecipientType::USER, - $eventType = EventType::SENDING_MESSAGE - ) { - return $this->postMessage([ - 'to' => is_array($mid) ? $mid : [$mid], - 'content' => array_merge(['toType' => $toType], $data), - ], $eventType); - } - - /** - * POST a message. - * - * @param array $data - * @param string $eventType - * @return FailedResponse|SucceededResponse - */ - private function postMessage(array $data, $eventType = EventType::SENDING_MESSAGE) - { - $data['toChannel'] = BotAPIChannel::SENDING_CHANNEL_ID; - $data['eventType'] = $eventType; - - $res = $this->client->post($this->eventAPIEndpoint, $data); - return ResponseFactory::createResponse($res); + return SignatureValidator::validateSignature($body, $this->channelSecret, $signature); } } diff --git a/src/LINEBot/Exception/ContentsDownloadingFailedException.php b/src/LINEBot/Constant/ActionType.php similarity index 76% rename from src/LINEBot/Exception/ContentsDownloadingFailedException.php rename to src/LINEBot/Constant/ActionType.php index e53a26a7..1649e9ec 100644 --- a/src/LINEBot/Exception/ContentsDownloadingFailedException.php +++ b/src/LINEBot/Constant/ActionType.php @@ -1,4 +1,5 @@ event = $event; + } + + /** + * Returns event type. + * + * @return string + */ + public function getType() + { + return $this->event['type']; + } + + /** + * Returns timestamp of the event. + * + * @return int + */ + public function getTimestamp() + { + return $this->event['timestamp']; + } + + /** + * Returns reply token of the event. + * + * @return string|null + */ + public function getReplyToken() + { + return array_key_exists('replyToken', $this->event) ? $this->event['replyToken'] : null; + } + + /** + * Returns the event is user's one or not. + * + * @return bool + */ + public function isUserEvent() + { + return $this->event['source']['type'] === EventSourceType::USER; + } + + /** + * Returns the event is group's one or not. + * + * @return bool + */ + public function isGroupEvent() + { + return $this->event['source']['type'] === EventSourceType::GROUP; + } + + /** + * Returns the event is room's one or not. + * + * @return bool + */ + public function isRoomEvent() + { + return $this->event['source']['type'] === EventSourceType::ROOM; + } + + /** + * Returns user ID of the event. + * + * @return string|null + * @throws InvalidEventSourceException Raise when called with non user type event. + */ + public function getUserId() + { + if (!$this->isUserEvent()) { + throw new InvalidEventSourceException('This event source is not a user type'); + } + return array_key_exists('userId', $this->event['source']) + ? $this->event['source']['userId'] + : null; + } + + /** + * Returns group ID of the event. + * + * @return string|null + * @throws InvalidEventSourceException Raise when called with non group type event. + */ + public function getGroupId() + { + if (!$this->isGroupEvent()) { + throw new InvalidEventSourceException('This event source is not a group type'); + } + return array_key_exists('groupId', $this->event['source']) + ? $this->event['source']['groupId'] + : null; + } + + /** + * Returns room ID of the event. + * + * @return string|null + * @throws InvalidEventSourceException Raise when called with non room type event. + */ + public function getRoomId() + { + if (!$this->isRoomEvent()) { + throw new InvalidEventSourceException('This event source is not a room type'); + } + return array_key_exists('roomId', $this->event['source']) + ? $this->event['source']['roomId'] + : null; + } +} diff --git a/src/LINEBot/Response/FailedResponse.php b/src/LINEBot/Event/BeaconDetectionEvent.php similarity index 53% rename from src/LINEBot/Response/FailedResponse.php rename to src/LINEBot/Event/BeaconDetectionEvent.php index b13f87ee..e23ff68c 100644 --- a/src/LINEBot/Response/FailedResponse.php +++ b/src/LINEBot/Event/BeaconDetectionEvent.php @@ -1,4 +1,5 @@ data = $data; - } - public function getHTTPStatus() - { - return $this->data['httpStatus']; - } +namespace LINE\LINEBot\Event; - public function isSucceeded() - { - return false; - } - - public function getStatusCode() +/** + * A class that represents the event of beacon detection. + * + * @package LINE\LINEBot\Event + */ +class BeaconDetectionEvent extends BaseEvent +{ + /** + * BeaconDetectionEvent constructor. + * + * @param array $event + */ + public function __construct($event) { - return $this->data['statusCode']; + parent::__construct($event); } - public function getStatusMessage() + /** + * Get hardware ID of the beacon. + * + * @return string + */ + public function getHwid() { - return $this->data['statusMessage']; + return $this->event['beacon']['hwid']; } } diff --git a/src/LINEBot/Event/FollowEvent.php b/src/LINEBot/Event/FollowEvent.php new file mode 100644 index 00000000..e8152fc8 --- /dev/null +++ b/src/LINEBot/Event/FollowEvent.php @@ -0,0 +1,37 @@ +fileHandler = $fileHandler; - $this->headers = $headers; - } + parent::__construct($event); - /** - * Get file handler. - * - * @return resource - */ - public function getFileHandle() - { - return $this->fileHandler; + $this->message = $event['message']; } /** - * Get headers. + * Returns the identifier of the message. * - * @return array + * @return string */ - public function getHeaders() + public function getMessageId() { - return $this->headers; + return $this->message['id']; } } diff --git a/src/LINEBot/Event/MessageEvent/AudioMessage.php b/src/LINEBot/Event/MessageEvent/AudioMessage.php new file mode 100644 index 00000000..3be1b195 --- /dev/null +++ b/src/LINEBot/Event/MessageEvent/AudioMessage.php @@ -0,0 +1,39 @@ +message['title']; + } + + /** + * Returns address of the location message. + * + * @return string + */ + public function getAddress() + { + return $this->message['address']; + } + + /** + * Returns latitude of the location message. + * + * @return double + */ + public function getLatitude() + { + return $this->message['latitude']; + } + + /** + * Returns longitude of the location message. + * + * @return double + */ + public function getLongitude() + { + return $this->message['longitude']; + } +} diff --git a/src/LINEBot/Event/MessageEvent/StickerMessage.php b/src/LINEBot/Event/MessageEvent/StickerMessage.php new file mode 100644 index 00000000..bfe20fa1 --- /dev/null +++ b/src/LINEBot/Event/MessageEvent/StickerMessage.php @@ -0,0 +1,59 @@ +message['packageId']; + } + + /** + * Returns the identifier of the sticker. + * + * @return string + */ + public function getStickerId() + { + return $this->message['stickerId']; + } +} diff --git a/src/LINEBot/Receive/Message/Image.php b/src/LINEBot/Event/MessageEvent/TextMessage.php similarity index 51% rename from src/LINEBot/Receive/Message/Image.php rename to src/LINEBot/Event/MessageEvent/TextMessage.php index 26805bc7..0df46113 100644 --- a/src/LINEBot/Receive/Message/Image.php +++ b/src/LINEBot/Event/MessageEvent/TextMessage.php @@ -1,4 +1,5 @@ config = $config; - $this->result = $result; - } - - public function getResult() - { - return $this->result; - } - - public function getConfig() +/** + * A class that represents the message event of text. + * + * @package LINE\LINEBot\Event\MessageEvent + */ +class TextMessage extends MessageEvent +{ + /** + * TextMessage constructor. + * + * @param array $event + */ + public function __construct($event) { - return $this->config; + parent::__construct($event); } - public function isImage() + /** + * Returns text of the message. + * + * @return string + */ + public function getText() { - return true; + return $this->message['text']; } } diff --git a/src/LINEBot/Event/MessageEvent/VideoMessage.php b/src/LINEBot/Event/MessageEvent/VideoMessage.php new file mode 100644 index 00000000..fa080f07 --- /dev/null +++ b/src/LINEBot/Event/MessageEvent/VideoMessage.php @@ -0,0 +1,39 @@ + 'LINE\LINEBot\Event\MessageEvent', + 'follow' => 'LINE\LINEBot\Event\FollowEvent', + 'unfollow' => 'LINE\LINEBot\Event\UnfollowEvent', + 'join' => 'LINE\LINEBot\Event\JoinEvent', + 'leave' => 'LINE\LINEBot\Event\LeaveEvent', + 'postback' => 'LINE\LINEBot\Event\PostbackEvent', + 'beacon' => 'LINE\LINEBot\Event\BeaconDetectionEvent', + ]; + + private static $messageType2class = [ + 'text' => 'LINE\LINEBot\Event\MessageEvent\TextMessage', + 'image' => 'LINE\LINEBot\Event\MessageEvent\ImageMessage', + 'video' => 'LINE\LINEBot\Event\MessageEvent\VideoMessage', + 'audio' => 'LINE\LINEBot\Event\MessageEvent\AudioMessage', + 'location' => 'LINE\LINEBot\Event\MessageEvent\LocationMessage', + 'sticker' => 'LINE\LINEBot\Event\MessageEvent\StickerMessage', + ]; + + /** + * @param string $body + * @param string $channelSecret + * @param string $signature + * @return \LINE\LINEBot\Event\BaseEvent[] array + * @throws InvalidEventRequestException + * @throws InvalidSignatureException + * @throws UnknownEventTypeException + */ + public static function parseEventRequest($body, $channelSecret, $signature) + { + if (!isset($signature)) { + throw new InvalidSignatureException('Request does not contain signature'); + } + + if (!SignatureValidator::validateSignature($body, $channelSecret, $signature)) { + throw new InvalidSignatureException('Invalid signature has given'); + } + + $events = []; + + $parsedReq = json_decode($body, true); + if (!array_key_exists('events', $parsedReq)) { + throw new InvalidEventRequestException(); + } + + foreach ($parsedReq['events'] as $eventData) { + $eventType = $eventData['type']; + $eventClass = self::$eventType2class[$eventType]; + if (!isset($eventClass)) { + throw new UnknownEventTypeException('Unknown event type has come: ' . $eventType); + } + + if ($eventType === 'message') { + $events[] = self::parseMessageEvent($eventData); + continue; + } + + $refClass = new ReflectionClass($eventClass); + $events[] = $refClass->newInstance($eventData); + } + + return $events; + } + + /** + * @param array $eventData + * @return MessageEvent|object + * @throws UnknownMessageTypeException + */ + private static function parseMessageEvent($eventData) + { + $messageType = $eventData['message']['type']; + $messageClass = self::$messageType2class[$messageType]; + if (!isset($messageClass)) { + throw new UnknownMessageTypeException('Unknown message type has come: ' . $messageType); + } + $refClass = new ReflectionClass($messageClass); + return $refClass->newInstance($eventData); + } +} diff --git a/src/LINEBot/Response/ResponseFactory.php b/src/LINEBot/Event/PostbackEvent.php similarity index 54% rename from src/LINEBot/Response/ResponseFactory.php rename to src/LINEBot/Event/PostbackEvent.php index 8ee918fb..3c70fee3 100644 --- a/src/LINEBot/Response/ResponseFactory.php +++ b/src/LINEBot/Event/PostbackEvent.php @@ -1,4 +1,5 @@ event['postback']['data']; } } diff --git a/src/LINEBot/Event/UnfollowEvent.php b/src/LINEBot/Event/UnfollowEvent.php new file mode 100644 index 00000000..667042cf --- /dev/null +++ b/src/LINEBot/Event/UnfollowEvent.php @@ -0,0 +1,37 @@ +ch = curl_init($url); + } + + /** + * Set multiple options for a cURL transfer + * + * @param array $options Returns TRUE if all options were successfully set. If an option could not be + * successfully set, FALSE is immediately returned, ignoring any future options in the options array. + * @return bool + */ + public function setoptArray(array $options) + { + return curl_setopt_array($this->ch, $options); + } + + /** + * Perform a cURL session + * + * @return bool Returns TRUE on success or FALSE on failure. However, if the CURLOPT_RETURNTRANSFER + * option is set, it will return the result on success, FALSE on failure. + */ + public function exec() + { + return curl_exec($this->ch); + } + + /** + * Gets information about the last transfer. + * + * @return array + */ + public function getinfo() + { + return curl_getinfo($this->ch); + } + + /** + * @return int Returns the error number or 0 (zero) if no error occurred. + */ + public function errno() + { + return curl_errno($this->ch); + } + + /** + * @return string Returns the error message or '' (the empty string) if no error occurred. + */ + public function error() + { + return curl_error($this->ch); + } + + /** + * Closes a cURL session and frees all resources. The cURL handle, ch, is also deleted. + */ + public function __destruct() + { + curl_close($this->ch); + } +} diff --git a/src/LINEBot/HTTPClient/CurlHTTPClient.php b/src/LINEBot/HTTPClient/CurlHTTPClient.php new file mode 100644 index 00000000..b1644cbb --- /dev/null +++ b/src/LINEBot/HTTPClient/CurlHTTPClient.php @@ -0,0 +1,115 @@ +authHeaders = [ + "Authorization: Bearer $channelToken", + ]; + } + + /** + * Sends GET request to LINE Messaging API. + * + * @param string $url Request URL. + * @return Response Response of API request. + */ + public function get($url) + { + return $this->sendRequest('GET', $url, [], []); + } + + /** + * Sends POST request to LINE Messaging API. + * + * @param string $url Request URL. + * @param array $data Request body. + * @return Response Response of API request. + */ + public function post($url, array $data) + { + return $this->sendRequest('POST', $url, ['Content-Type: application/json; charset=utf-8'], $data); + } + + /** + * @param string $method + * @param string $url + * @param array $additionalHeader + * @param array $reqBody + * @return Response + * @throws CurlExecutionException + */ + private function sendRequest($method, $url, array $additionalHeader, array $reqBody) + { + $curl = new Curl($url); + + $headers = array_merge($this->authHeaders, $this->userAgentHeader, $additionalHeader); + + $options = [ + CURLOPT_CUSTOMREQUEST => $method, + CURLOPT_HTTPHEADER => $headers, + CURLOPT_HEADER => false, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_BINARYTRANSFER => true, + ]; + + if ($method === 'POST' && !empty($reqBody)) { + $options[CURLOPT_POSTFIELDS] = json_encode($reqBody); + } + + $curl->setoptArray($options); + + $body = $curl->exec(); + + $info = $curl->getinfo(); + $httpStatus = $info['http_code']; + + if ($curl->errno()) { + throw new CurlExecutionException($curl->error()); + } + + return new Response($httpStatus, $body); + } +} diff --git a/src/LINEBot/HTTPClient/GuzzleHTTPClient.php b/src/LINEBot/HTTPClient/GuzzleHTTPClient.php deleted file mode 100644 index 90c9d274..00000000 --- a/src/LINEBot/HTTPClient/GuzzleHTTPClient.php +++ /dev/null @@ -1,179 +0,0 @@ -channelId = $args['channelId']; - $this->channelSecret = $args['channelSecret']; - $this->channelMid = $args['channelMid']; - - $this->guzzle = new Client($args); - } - - /** - * Send get request with credential headers. - * - * @param string $url Destination URL to send. - * @return array - * @throws LINEBotAPIException When request is failed or received invalid response. - */ - public function get($url) - { - try { - $res = $this->guzzle->get($url, ['headers' => $this->credentials()]); - } catch (BadResponseException $e) { - $res = $e->getResponse(); - } - - $resContent = $res->getBody(); - $resStatus = $res->getStatusCode(); - - if (!$resContent || !preg_match('/\A{.+}\z/u', $resContent)) { - throw new LINEBotAPIException("LINE BOT API error: $resStatus"); - } - - $ret = json_decode($resContent, true); - if ($ret === null) { - throw new LINEBotAPIException("LINE BOT API error: $resStatus"); - } - return $ret; - } - - /** - * Send post request with credential headers. - * - * @param string $url Destination URL to send. - * @param array $data Request body - * @return array - * @throws JSONEncodingException When invalid request has come. - * @throws LINEBotAPIException When request is failed or received invalid response. - */ - public function post($url, array $data) - { - $json = json_encode($data); - if ($json === false) { - throw new JSONEncodingException("Failed to encode request JSON"); - } - - $headers = array_merge($this->credentials(), [ - 'Content-Type' => 'application/json; charset=UTF-8', - 'Content-Length' => strlen($json), - ]); - - try { - $res = $this->guzzle->post($url, [ - 'headers' => $headers, - 'body' => $json, - ]); - } catch (BadResponseException $e) { - $res = $e->getResponse(); - } - - $resContent = $res->getBody(); - $resStatus = $res->getStatusCode(); - - if (!$resContent || !preg_match('/\A{.+}\z/u', $resContent)) { - throw new LINEBotAPIException("LINE BOT API error: $resStatus"); - } - - $ret = json_decode($resContent, true); - if ($ret === null) { - throw new LINEBotAPIException("LINE BOT API error: $resStatus"); - } - - $ret['httpStatus'] = $resStatus; - return $ret; - } - - /** - * Download contents. - * - * @param string $url Contents URL. - * @param resource $fileHandler File handler to store contents temporally. - * @return DownloadedContents - * @throws ContentsDownloadingFailedException When failed to download contents. - */ - public function downloadContents($url, $fileHandler = null) - { - if ($fileHandler === null) { - $fileHandler = tmpfile(); - } - $stream = Stream::factory($fileHandler); - - try { - $res = $this->guzzle->get($url, [ - 'save_to' => $stream, - 'headers' => $this->credentials(), - ]); - } catch (BadResponseException $e) { - $res = $e->getResponse(); - } - - $resStatus = $res->getStatusCode(); - if ($resStatus !== 200) { - $resContent = $res->getBody(); - throw new ContentsDownloadingFailedException( - "LINE BOT API contents_download error: $resStatus $url\ncontent=$resContent" - ); - } - - return new DownloadedContents($stream->detach(), $res->getHeaders()); - } - - private function credentials() - { - return [ - 'X-Line-ChannelID' => $this->channelId, - 'X-Line-ChannelSecret' => $this->channelSecret, - 'X-Line-Trusted-User-With-ACL' => $this->channelMid, - ]; - } -} diff --git a/src/LINEBot/Constant/ContentType.php b/src/LINEBot/ImagemapActionBuilder.php similarity index 62% rename from src/LINEBot/Constant/ContentType.php rename to src/LINEBot/ImagemapActionBuilder.php index fb23550d..c7065ad5 100644 --- a/src/LINEBot/Constant/ContentType.php +++ b/src/LINEBot/ImagemapActionBuilder.php @@ -1,4 +1,5 @@ x = $x; + $this->y = $y; + $this->width = $width; + $this->height = $height; + } + + /** + * Builds imagemap area structure. + * + * @return array Built area structure. + */ + public function build() + { + return [ + 'x' => $this->x, + 'y' => $this->y, + 'width' => $this->width, + 'height' => $this->height, + ]; + } +} diff --git a/src/LINEBot/ImagemapActionBuilder/ImagemapMessageActionBuilder.php b/src/LINEBot/ImagemapActionBuilder/ImagemapMessageActionBuilder.php new file mode 100644 index 00000000..255fea8f --- /dev/null +++ b/src/LINEBot/ImagemapActionBuilder/ImagemapMessageActionBuilder.php @@ -0,0 +1,61 @@ +text = $text; + $this->areaBuilder = $areaBuilder; + } + + /** + * Builds imagemap message action structure. + * + * @return array Built imagemap structure. + */ + public function buildImagemapAction() + { + return [ + 'type' => ActionType::MESSAGE, + 'text' => $this->text, + 'area' => $this->areaBuilder->build(), + ]; + } +} diff --git a/src/LINEBot/ImagemapActionBuilder/ImagemapUriActionBuilder.php b/src/LINEBot/ImagemapActionBuilder/ImagemapUriActionBuilder.php new file mode 100644 index 00000000..3256168a --- /dev/null +++ b/src/LINEBot/ImagemapActionBuilder/ImagemapUriActionBuilder.php @@ -0,0 +1,59 @@ +linkUri = $linkUri; + $this->areaBuilder = $areaBuilder; + } + + /** + * Builds imagemap URI action structure. + * + * @return array Built URI action structure. + */ + public function buildImagemapAction() + { + return [ + 'type' => ActionType::URI, + 'linkUri' => $this->linkUri, + 'area' => $this->areaBuilder->build(), + ]; + } +} diff --git a/src/LINEBot/Message/Builder/MessageBuilder.php b/src/LINEBot/Message/Builder/MessageBuilder.php deleted file mode 100644 index 9b67cefc..00000000 --- a/src/LINEBot/Message/Builder/MessageBuilder.php +++ /dev/null @@ -1,137 +0,0 @@ - ContentType::TEXT, - 'text' => $text, - ]; - } - - /** - * Build image message payload. - * - * @link https://developers.line.me/bot-api/api-reference#sending_message_image - * @param string $imageURL - * @param string $previewURL - * @return array - */ - public static function buildImage($imageURL, $previewURL) - { - return [ - 'contentType' => ContentType::IMAGE, - 'originalContentUrl' => $imageURL, - 'previewImageUrl' => $previewURL, - ]; - } - - /** - * Build video message payload. - * - * @link https://developers.line.me/bot-api/api-reference#sending_message_video - * @param string $videoURL - * @param string $previewImageURL - * @return array - */ - public static function buildVideo($videoURL, $previewImageURL) - { - return [ - 'contentType' => ContentType::VIDEO, - 'originalContentUrl' => $videoURL, - 'previewImageUrl' => $previewImageURL, - ]; - } - - /** - * Build voice message payload. - * - * @link https://developers.line.me/bot-api/api-reference#sending_message_audio - * @param string $audioURL - * @param int $durationMillis - * @return array - */ - public static function buildAudio($audioURL, $durationMillis) - { - return [ - 'contentType' => ContentType::AUDIO, - 'originalContentUrl' => $audioURL, - 'contentMetadata' => [ - 'AUDLEN' => (string)$durationMillis, - ], - ]; - } - - /** - * Build location message payload. - * - * @link https://developers.line.me/bot-api/api-reference#sending_message_location - * @param string $text - * @param float $latitude - * @param float $longitude - * @return array - */ - public static function buildLocation($text, $latitude, $longitude) - { - return [ - 'contentType' => ContentType::LOCATION, - 'text' => $text, - 'location' => [ - 'title' => $text, - 'latitude' => $latitude, - 'longitude' => $longitude, - ], - ]; - } - - /** - * Build sticker message payload. - * - * @link https://developers.line.me/bot-api/api-reference#sending_message_sticker - * @param int $stkid - * @param int $stkpkgid - * @param int $stkver - * @return array - */ - public static function buildSticker($stkid, $stkpkgid, $stkver = null) - { - $meta = [ - 'STKID' => (string)$stkid, - 'STKPKGID' => (string)$stkpkgid, - ]; - if ($stkver !== null) { - $meta = array_merge($meta, ['STKVER' => (string)$stkver]); - } - - return [ - 'contentType' => ContentType::STICKER, - 'contentMetadata' => $meta, - ]; - } -} diff --git a/src/LINEBot/Message/Builder/MultipleMessagesBuilder.php b/src/LINEBot/Message/Builder/MultipleMessagesBuilder.php deleted file mode 100644 index 22350f7f..00000000 --- a/src/LINEBot/Message/Builder/MultipleMessagesBuilder.php +++ /dev/null @@ -1,39 +0,0 @@ - $messageNotified, - 'messages' => $multipleMessages->getMessages(), - ]; - } -} diff --git a/src/LINEBot/Message/Builder/RichMessageBuilder.php b/src/LINEBot/Message/Builder/RichMessageBuilder.php deleted file mode 100644 index 756fe4a5..00000000 --- a/src/LINEBot/Message/Builder/RichMessageBuilder.php +++ /dev/null @@ -1,46 +0,0 @@ - ContentType::RICH_MESSAGE, - 'contentMetadata' => [ - 'SPEC_REV' => '1', - 'DOWNLOAD_URL' => $imageURL, - 'ALT_TEXT' => $altText, - 'MARKUP_JSON' => $markup->build(), - ], - ]; - } -} diff --git a/src/LINEBot/Message/MultipleMessages.php b/src/LINEBot/Message/MultipleMessages.php deleted file mode 100644 index e28cea1e..00000000 --- a/src/LINEBot/Message/MultipleMessages.php +++ /dev/null @@ -1,120 +0,0 @@ -messages[] = MessageBuilder::buildText($text); - return $this; - } - - /** - * Add image message. - * - * @link https://developers.line.me/bot-api/api-reference#sending_message_image - * @param string $imageURL - * @param string $previewURL - * @return MultipleMessages $this - */ - public function addImage($imageURL, $previewURL) - { - $this->messages[] = MessageBuilder::buildImage($imageURL, $previewURL); - return $this; - } - - /** - * Add video message. - * - * @link https://developers.line.me/bot-api/api-reference#sending_message_video - * @param string $videoURL - * @param string $previewImageURL - * @return MultipleMessages $this - */ - public function addVideo($videoURL, $previewImageURL) - { - $this->messages[] = MessageBuilder::buildVideo($videoURL, $previewImageURL); - return $this; - } - - /** - * Add voice message. - * - * @link https://developers.line.me/bot-api/api-reference#sending_message_audio - * @param string $audioURL - * @param int $duration - * @return MultipleMessages $this - */ - public function addAudio($audioURL, $duration) - { - $this->messages[] = MessageBuilder::buildAudio($audioURL, $duration); - return $this; - } - - /** - * Add location message. - * - * @link https://developers.line.me/bot-api/api-reference#sending_message_location - * @param string $text - * @param float $latitude - * @param float $longitude - * @return MultipleMessages $this - */ - public function addLocation($text, $latitude, $longitude) - { - $this->messages[] = MessageBuilder::buildLocation($text, $latitude, $longitude); - return $this; - } - - /** - * Add sticker message. - * - * @link https://developers.line.me/bot-api/api-reference#sending_message_sticker - * @param int $stkid - * @param int $stkpkgid - * @param int $stkver - * @return MultipleMessages $this - */ - public function addSticker($stkid, $stkpkgid, $stkver = null) - { - $this->messages[] = MessageBuilder::buildSticker($stkid, $stkpkgid, $stkver); - return $this; - } - - /** - * Get registered messages. - * - * @return array - */ - public function getMessages() - { - return $this->messages; - } -} diff --git a/src/LINEBot/Message/RichMessage/Markup.php b/src/LINEBot/Message/RichMessage/Markup.php deleted file mode 100644 index 11c069fa..00000000 --- a/src/LINEBot/Message/RichMessage/Markup.php +++ /dev/null @@ -1,152 +0,0 @@ - 2080) { - throw new IllegalRichMessageHeightException('Rich Message canvas\'s height ' . - 'should be less than or equals 2080px'); - } - - $this->canvas = [ - 'height' => $height, // Integer value. Max value is 2080px. - 'width' => 1040, // Integer fixed value: 1040. - 'initialScene' => 'scene1' // Fixed string: 'scene1' - ]; - - $this->images = [ - 'image1' => [ - 'x' => 0, // Fixed 0. - 'y' => 0, // Fixed 0. - 'w' => 1040, // Integer fixed value: 1040. - 'h' => $height, // Integer value. Max value is 2080px. - ], - ]; - - $this->actions = []; - - $this->scenes = [ - 'scene1' => [ - 'draws' => [ - [ - 'image' => 'image1', // Use the image ID "image1". - 'x' => 0, // Fixed 0. - 'y' => 0, // Fixed 0. - 'w' => 1040, // Integer fixed value: 1040. - 'h' => $height, // Integer value. Max value is 2080px. - ] - ], - 'listeners' => [], - ], - ]; - } - - /** - * Set an action. - * - * @param string $actionName Name of an action. - * @param string $text Alternative string displayed on low-level devices. - * @param string $linkURI URL to opened in the web browser. - * @param string $type Action type. - * @return Markup $this - */ - public function setAction($actionName, $text, $linkURI, $type = 'web') - { - $obj = [ - 'type' => $type, - ]; - - if ($type === 'web') { - $obj['text'] = $text; - $obj['params'] = [ - 'linkUri' => $linkURI, - ]; - } elseif ($type === 'sendMessage') { - $obj['params'] = [ - 'text' => $text, - ]; - } - - $this->actions[$actionName] = $obj; - - return $this; - } - - /** - * Add a listener which is associated with an action. - * - * @param string $actionName Action name to associate with listener. - * @param int $x x-coordinate value. - * @param int $y y-coordinate value. - * @param int $width Width of the image. - * @param int $height Height of the image. - * @return Markup $this - */ - public function addListener($actionName, $x, $y, $width, $height) - { - $this->scenes['scene1']['listeners'][] = [ - 'type' => 'touch', # Fixed string: 'touch' - 'params' => [$x, $y, $width, $height], - 'action' => $actionName, - ]; - - return $this; - } - - /** - * Generate markup JSON from this instance. - * - * @return string Markup JSON. - * @throws JSONEncodingException - */ - public function build() - { - $json = json_encode([ - 'canvas' => $this->canvas, - 'images' => $this->images, - 'actions' => $this->actions, - 'scenes' => $this->scenes, - ]); - - if ($json === false) { - throw new JSONEncodingException("Failed to encode markup JSON"); - } - return $json; - } -} diff --git a/src/LINEBot/Constant/BotAPIChannel.php b/src/LINEBot/MessageBuilder.php similarity index 64% rename from src/LINEBot/Constant/BotAPIChannel.php rename to src/LINEBot/MessageBuilder.php index 57460d60..3505da3e 100644 --- a/src/LINEBot/Constant/BotAPIChannel.php +++ b/src/LINEBot/MessageBuilder.php @@ -1,4 +1,5 @@ originalContentUrl = $originalContentUrl; + $this->duration = $duration; + } + + /** + * Builds + * @return array + */ + public function buildMessage() + { + return [ + [ + 'type' => MessageType::AUDIO, + 'originalContentUrl' => $this->originalContentUrl, + 'duration' => $this->duration, + ] + ]; + } +} diff --git a/src/LINEBot/MessageBuilder/ImageMessageBuilder.php b/src/LINEBot/MessageBuilder/ImageMessageBuilder.php new file mode 100644 index 00000000..1d64183e --- /dev/null +++ b/src/LINEBot/MessageBuilder/ImageMessageBuilder.php @@ -0,0 +1,63 @@ +originalContentUrl = $originalContentUrl; + $this->previewImageUrl = $previewImageUrl; + } + + /** + * Builds image message structure. + * + * @return array + */ + public function buildMessage() + { + return [ + [ + 'type' => MessageType::IMAGE, + 'originalContentUrl' => $this->originalContentUrl, + 'previewImageUrl' => $this->previewImageUrl, + ] + ]; + } +} diff --git a/src/LINEBot/MessageBuilder/Imagemap/BaseSizeBuilder.php b/src/LINEBot/MessageBuilder/Imagemap/BaseSizeBuilder.php new file mode 100644 index 00000000..603abded --- /dev/null +++ b/src/LINEBot/MessageBuilder/Imagemap/BaseSizeBuilder.php @@ -0,0 +1,57 @@ +height = $height; + $this->width = $width; + } + + /** + * Builds base size of imagemap. + * + * @return array + */ + public function build() + { + return [ + 'height' => $this->height, + 'width' => $this->width, + ]; + } +} diff --git a/src/LINEBot/MessageBuilder/ImagemapMessageBuilder.php b/src/LINEBot/MessageBuilder/ImagemapMessageBuilder.php new file mode 100644 index 00000000..7a4cb16e --- /dev/null +++ b/src/LINEBot/MessageBuilder/ImagemapMessageBuilder.php @@ -0,0 +1,87 @@ +baseUrl = $baseUrl; + $this->altText = $altText; + $this->baseSizeBuilder = $baseSizeBuilder; + $this->imagemapActionBuilders = $imagemapActionBuilders; + } + + /** + * Builds imagemap message strucutre. + * + * @return array + */ + public function buildMessage() + { + if (!empty($this->message)) { + return $this->message; + } + + $actions = []; + foreach ($this->imagemapActionBuilders as $builder) { + $actions[] = $builder->buildImagemapAction(); + } + + $this->message[] = [ + 'type' => MessageType::IMAGEMAP, + 'baseUrl' => $this->baseUrl, + 'altText' => $this->altText, + 'baseSize' => $this->baseSizeBuilder->build(), + 'actions' => $actions, + ]; + + return $this->message; + } +} diff --git a/src/LINEBot/MessageBuilder/LocationMessageBuilder.php b/src/LINEBot/MessageBuilder/LocationMessageBuilder.php new file mode 100644 index 00000000..0650f3ba --- /dev/null +++ b/src/LINEBot/MessageBuilder/LocationMessageBuilder.php @@ -0,0 +1,73 @@ +title = $title; + $this->address = $address; + $this->latitude = $latitude; + $this->longitude = $longitude; + } + + /** + * Builds location message structure. + * + * @return array + */ + public function buildMessage() + { + return [ + [ + 'type' => MessageType::LOCATION, + 'title' => $this->title, + 'address' => $this->address, + 'latitude' => $this->latitude, + 'longitude' => $this->longitude, + ] + ]; + } +} diff --git a/src/LINEBot/MessageBuilder/MultiMessageBuilder.php b/src/LINEBot/MessageBuilder/MultiMessageBuilder.php new file mode 100644 index 00000000..4a204695 --- /dev/null +++ b/src/LINEBot/MessageBuilder/MultiMessageBuilder.php @@ -0,0 +1,56 @@ +messageBuilders[] = $messageBuilder; + return $this; + } + + /** + * Builds message structure. + * + * @return array Built message structure. + */ + public function buildMessage() + { + $messages = []; + foreach ($this->messageBuilders as $messageBuilder) { + foreach ($messageBuilder->buildMessage() as $message) { + $messages[] = $message; + } + } + + return $messages; + } +} diff --git a/src/LINEBot/MessageBuilder/StickerMessageBuilder.php b/src/LINEBot/MessageBuilder/StickerMessageBuilder.php new file mode 100644 index 00000000..dfc336e6 --- /dev/null +++ b/src/LINEBot/MessageBuilder/StickerMessageBuilder.php @@ -0,0 +1,63 @@ +packageId = $packageId; + $this->stickerId = $stickerId; + } + + /** + * Builds sticker message structure. + * + * @return array + */ + public function buildMessage() + { + return [ + [ + 'type' => MessageType::STICKER, + 'packageId' => $this->packageId, + 'stickerId' => $this->stickerId, + ] + ]; + } +} diff --git a/src/LINEBot/MessageBuilder/TemplateBuilder.php b/src/LINEBot/MessageBuilder/TemplateBuilder.php new file mode 100644 index 00000000..37bcc2be --- /dev/null +++ b/src/LINEBot/MessageBuilder/TemplateBuilder.php @@ -0,0 +1,34 @@ +title = $title; + $this->text = $text; + $this->thumbnailImageUrl = $thumbnailImageUrl; + $this->actionBuilders = $actionBuilders; + } + + /** + * Builds button template message structure. + * + * @return array + */ + public function buildTemplate() + { + if (!empty($this->template)) { + return $this->template; + } + + $actions = []; + foreach ($this->actionBuilders as $actionBuilder) { + $actions[] = $actionBuilder->buildTemplateAction(); + } + + $this->template = [ + 'type' => TemplateType::BUTTONS, + 'thumbnailImageUrl' => $this->thumbnailImageUrl, + 'title' => $this->title, + 'text' => $this->text, + 'actions' => $actions, + ]; + + return $this->template; + } +} diff --git a/src/LINEBot/MessageBuilder/TemplateBuilder/CarouselColumnTemplateBuilder.php b/src/LINEBot/MessageBuilder/TemplateBuilder/CarouselColumnTemplateBuilder.php new file mode 100644 index 00000000..db35dc59 --- /dev/null +++ b/src/LINEBot/MessageBuilder/TemplateBuilder/CarouselColumnTemplateBuilder.php @@ -0,0 +1,84 @@ +title = $title; + $this->text = $text; + $this->thumbnailImageUrl = $thumbnailImageUrl; + $this->actionBuilders = $actionBuilders; + } + + /** + * Builds column of carousel template structure. + * + * @return array + */ + public function buildTemplate() + { + if (!empty($this->template)) { + return $this->template; + } + + $actions = []; + foreach ($this->actionBuilders as $actionBuilder) { + $actions[] = $actionBuilder->buildTemplateAction(); + } + + $this->template = [ + 'thumbnailImageUrl' => $this->thumbnailImageUrl, + 'title' => $this->title, + 'text' => $this->text, + 'actions' => $actions, + ]; + + return $this->template; + } +} diff --git a/src/LINEBot/MessageBuilder/TemplateBuilder/CarouselTemplateBuilder.php b/src/LINEBot/MessageBuilder/TemplateBuilder/CarouselTemplateBuilder.php new file mode 100644 index 00000000..0e8b6de8 --- /dev/null +++ b/src/LINEBot/MessageBuilder/TemplateBuilder/CarouselTemplateBuilder.php @@ -0,0 +1,70 @@ +columnTemplateBuilders = $columnTemplateBuilders; + } + + /** + * Builds carousel template structure. + * + * @return array + */ + public function buildTemplate() + { + if (!empty($this->template)) { + return $this->template; + } + + $columns = []; + foreach ($this->columnTemplateBuilders as $columnTemplateBuilder) { + $columns[] = $columnTemplateBuilder->buildTemplate(); + } + + $this->template = [ + 'type' => TemplateType::CAROUSEL, + 'columns' => $columns, + ]; + + return $this->template; + } +} diff --git a/src/LINEBot/MessageBuilder/TemplateBuilder/ConfirmTemplateBuilder.php b/src/LINEBot/MessageBuilder/TemplateBuilder/ConfirmTemplateBuilder.php new file mode 100644 index 00000000..d5ac80fc --- /dev/null +++ b/src/LINEBot/MessageBuilder/TemplateBuilder/ConfirmTemplateBuilder.php @@ -0,0 +1,76 @@ +text = $text; + $this->actionBuilders = $actionBuilders; + } + + /** + * Builds confirm template structure. + * + * @return array + */ + public function buildTemplate() + { + if (!empty($this->template)) { + return $this->template; + } + + $actions = []; + foreach ($this->actionBuilders as $actionBuilder) { + $actions[] = $actionBuilder->buildTemplateAction(); + } + + $this->template = [ + 'type' => TemplateType::CONFIRM, + 'text' => $this->text, + 'actions' => $actions, + ]; + + return $this->template; + } +} diff --git a/src/LINEBot/MessageBuilder/TemplateMessageBuilder.php b/src/LINEBot/MessageBuilder/TemplateMessageBuilder.php new file mode 100644 index 00000000..4c9d7845 --- /dev/null +++ b/src/LINEBot/MessageBuilder/TemplateMessageBuilder.php @@ -0,0 +1,62 @@ +altText = $altText; + $this->templateBuilder = $templateBuilder; + } + + /** + * Builds template message structure. + * + * @return array + */ + public function buildMessage() + { + return [ + [ + 'type' => MessageType::TEMPLATE, + 'altText' => $this->altText, + 'template' => $this->templateBuilder->buildTemplate(), + ] + ]; + } +} diff --git a/src/LINEBot/MessageBuilder/TextMessageBuilder.php b/src/LINEBot/MessageBuilder/TextMessageBuilder.php new file mode 100644 index 00000000..655ae35b --- /dev/null +++ b/src/LINEBot/MessageBuilder/TextMessageBuilder.php @@ -0,0 +1,67 @@ +texts = array_merge([$text], $extraTexts); + } + + /** + * Builds text message structure. + * + * @return array + */ + public function buildMessage() + { + if (!empty($this->message)) { + return $this->message; + } + + foreach ($this->texts as $text) { + $this->message[] = [ + 'type' => MessageType::TEXT, + 'text' => $text, + ]; + } + + return $this->message; + } +} diff --git a/src/LINEBot/MessageBuilder/VideoMessageBuilder.php b/src/LINEBot/MessageBuilder/VideoMessageBuilder.php new file mode 100644 index 00000000..55c23500 --- /dev/null +++ b/src/LINEBot/MessageBuilder/VideoMessageBuilder.php @@ -0,0 +1,63 @@ +originalContentUrl = $originalContentUrl; + $this->previewImageUrl = $previewImageUrl; + } + + /** + * Builds video message structure. + * + * @return array + */ + public function buildMessage() + { + return [ + [ + 'type' => MessageType::VIDEO, + 'originalContentUrl' => $this->originalContentUrl, + 'previewImageUrl' => $this->previewImageUrl, + ] + ]; + } +} diff --git a/src/LINEBot/Receive/Message.php b/src/LINEBot/Receive/Message.php deleted file mode 100644 index 8fe84e8c..00000000 --- a/src/LINEBot/Receive/Message.php +++ /dev/null @@ -1,88 +0,0 @@ -getConfig()['channelMid']; - foreach ($this->getResult()['content']['to'] as $mid) { - if ($myMid === $mid) { - return true; - } - } - return false; - } - - public function getContentId() - { - return $this->getResult()['content']['id']; - } - - public function getCreatedTime() - { - return $this->getResult()['content']['createdTime']; - } - - public function getFromMid() - { - return $this->getResult()['content']['from']; - } - - public function isText() - { - return false; - } - - public function isImage() - { - return false; - } - - public function isVideo() - { - return false; - } - - public function isAudio() - { - return false; - } - - public function isLocation() - { - return false; - } - - public function isSticker() - { - return false; - } - - public function isContact() - { - return false; - } -} diff --git a/src/LINEBot/Receive/Message/Audio.php b/src/LINEBot/Receive/Message/Audio.php deleted file mode 100644 index b2ce2902..00000000 --- a/src/LINEBot/Receive/Message/Audio.php +++ /dev/null @@ -1,50 +0,0 @@ -config = $config; - $this->result = $result; - } - - public function getResult() - { - return $this->result; - } - - public function getConfig() - { - return $this->config; - } - - public function isAudio() - { - return true; - } -} diff --git a/src/LINEBot/Receive/Message/Contact.php b/src/LINEBot/Receive/Message/Contact.php deleted file mode 100644 index c53a0f7e..00000000 --- a/src/LINEBot/Receive/Message/Contact.php +++ /dev/null @@ -1,63 +0,0 @@ -config = $config; - $this->result = $result; - $this->meta = $result['content']['contentMetadata']; - } - - public function getResult() - { - return $this->result; - } - - public function getConfig() - { - return $this->config; - } - - public function isContact() - { - return true; - } - - public function getMid() - { - return $this->meta['mid']; - } - - public function getDisplayName() - { - return $this->meta['displayName']; - } -} diff --git a/src/LINEBot/Receive/Message/Location.php b/src/LINEBot/Receive/Message/Location.php deleted file mode 100644 index bc9332c6..00000000 --- a/src/LINEBot/Receive/Message/Location.php +++ /dev/null @@ -1,78 +0,0 @@ -config = $config; - $this->result = $result; - $this->location = $result['content']['location']; - } - - public function getResult() - { - return $this->result; - } - - public function getConfig() - { - return $this->config; - } - - public function isLocation() - { - return true; - } - - public function getText() - { - return $this->location['title']; // `$this->location['text'] }` is always null - } - - public function getTitle() - { - return $this->location['title']; - } - - public function getAddress() - { - return $this->location['address']; - } - - public function getLatitude() - { - return $this->location['latitude']; - } - - public function getLongitude() - { - return $this->location['longitude']; - } -} diff --git a/src/LINEBot/Receive/Message/MessageReceiveFactory.php b/src/LINEBot/Receive/Message/MessageReceiveFactory.php deleted file mode 100644 index f5e381c0..00000000 --- a/src/LINEBot/Receive/Message/MessageReceiveFactory.php +++ /dev/null @@ -1,55 +0,0 @@ -config = $config; - $this->result = $result; - $this->meta = $result['content']['contentMetadata']; - } - - public function getResult() - { - return $this->result; - } - - public function getConfig() - { - return $this->config; - } - - public function isSticker() - { - return true; - } - - public function getStkPkgId() - { - return $this->meta['STKPKGID']; - } - - public function getStkId() - { - return $this->meta['STKID']; - } - - public function getStkVer() - { - return $this->meta['STKVER']; - } - - public function getStkTxt() - { - return $this->meta['STKTXT']; - } -} diff --git a/src/LINEBot/Receive/Message/Text.php b/src/LINEBot/Receive/Message/Text.php deleted file mode 100644 index 2a143d70..00000000 --- a/src/LINEBot/Receive/Message/Text.php +++ /dev/null @@ -1,55 +0,0 @@ -config = $config; - $this->result = $result; - } - - public function getResult() - { - return $this->result; - } - - public function getConfig() - { - return $this->config; - } - - public function isText() - { - return true; - } - - public function getText() - { - return $this->result['content']['text']; - } -} diff --git a/src/LINEBot/Receive/Message/Video.php b/src/LINEBot/Receive/Message/Video.php deleted file mode 100644 index b464e550..00000000 --- a/src/LINEBot/Receive/Message/Video.php +++ /dev/null @@ -1,50 +0,0 @@ -config = $config; - $this->result = $result; - } - - public function getResult() - { - return $this->result; - } - - public function getConfig() - { - return $this->config; - } - - public function isVideo() - { - return true; - } -} diff --git a/src/LINEBot/Receive/Operation/AddContact.php b/src/LINEBot/Receive/Operation/AddContact.php deleted file mode 100644 index 871fdff2..00000000 --- a/src/LINEBot/Receive/Operation/AddContact.php +++ /dev/null @@ -1,50 +0,0 @@ -config = $config; - $this->result = $result; - } - - public function getResult() - { - return $this->result; - } - - public function getConfig() - { - return $this->config; - } - - public function isAddContact() - { - return true; - } -} diff --git a/src/LINEBot/Receive/Operation/BlockContact.php b/src/LINEBot/Receive/Operation/BlockContact.php deleted file mode 100644 index 332412ec..00000000 --- a/src/LINEBot/Receive/Operation/BlockContact.php +++ /dev/null @@ -1,50 +0,0 @@ -config = $config; - $this->result = $result; - } - - public function getResult() - { - return $this->result; - } - - public function getConfig() - { - return $this->config; - } - - public function isBlockContact() - { - return true; - } -} diff --git a/src/LINEBot/Receive/Operation/OperationReceiveFactory.php b/src/LINEBot/Receive/Operation/OperationReceiveFactory.php deleted file mode 100644 index 9fbc8367..00000000 --- a/src/LINEBot/Receive/Operation/OperationReceiveFactory.php +++ /dev/null @@ -1,44 +0,0 @@ -getResult(); - $config = $this->getConfig(); - - return $result['toChannel'] == $config['channelId'] && - $result['fromChannel'] == BotAPIChannel::RECEIVING_CHANNEL_ID && - $result['from'] == BotAPIChannel::RECEIVING_CHANNEL_MID; - } - - public function getId() - { - return $this->getResult()['id']; - } - - /** - * Validate request with signature. - * - * @param string $json JSON request. - * @param string $signature - * @return bool - */ - public function validateSignature($json, $signature) - { - return SignatureValidator::validateSignature($json, $this->getConfig()['channelSecret'], $signature); - } - - abstract function getResult(); - - abstract function getConfig(); -} diff --git a/src/LINEBot/Receive/ReceiveFactory.php b/src/LINEBot/Receive/ReceiveFactory.php deleted file mode 100644 index e9c3cec1..00000000 --- a/src/LINEBot/Receive/ReceiveFactory.php +++ /dev/null @@ -1,83 +0,0 @@ -httpStatus = $httpStatus; + $this->body = $body; + } + + /** + * Returns HTTP status code of response. + * + * @return int HTTP status code of response. + */ + public function getHTTPStatus() + { + return $this->httpStatus; + } + + /** + * Returns request is succeeded or not. + * + * @return bool Request is succeeded or not. + */ + public function isSucceeded() + { + return $this->httpStatus === 200; + } + + /** + * Returns raw request body. + * + * @return string Raw request body. + */ + public function getRawBody() + { + return $this->body; + } + + /** + * Returns request body as array (it means, returns JSON decoded body). + * + * @return array Request body that is JSON decoded. + */ + public function getJSONDecodedBody() + { + return json_decode($this->body, true); + } +} diff --git a/src/LINEBot/Response/SucceededResponse.php b/src/LINEBot/Response/SucceededResponse.php deleted file mode 100644 index a888f4f1..00000000 --- a/src/LINEBot/Response/SucceededResponse.php +++ /dev/null @@ -1,57 +0,0 @@ -data = $data; - } - - public function getHTTPStatus() - { - return $this->data['httpStatus']; - } - - public function isSucceeded() - { - return true; - } - - public function getVersion() - { - return $this->data['version']; - } - - public function getMessageId() - { - return $this->data['messageId']; - } - - public function getTimestamp() - { - return $this->data['timestamp']; - } - - public function getFailed() - { - return $this->data['failed']; - } -} diff --git a/src/LINEBot/SignatureValidator.php b/src/LINEBot/SignatureValidator.php index 6bff0d1d..8210b8d5 100644 --- a/src/LINEBot/SignatureValidator.php +++ b/src/LINEBot/SignatureValidator.php @@ -1,4 +1,5 @@ label = $label; + $this->text = $text; + } + + /** + * Builds message action structure. + * + * @return array Built message action structure. + */ + public function buildTemplateAction() + { + return [ + 'type' => ActionType::MESSAGE, + 'label' => $this->label, + 'text' => $this->text, + ]; + } +} diff --git a/src/LINEBot/TemplateActionBuilder/PostbackTemplateActionBuilder.php b/src/LINEBot/TemplateActionBuilder/PostbackTemplateActionBuilder.php new file mode 100644 index 00000000..507afad1 --- /dev/null +++ b/src/LINEBot/TemplateActionBuilder/PostbackTemplateActionBuilder.php @@ -0,0 +1,61 @@ +label = $label; + $this->data = $data; + } + + /** + * Builds postback action structure. + * + * @return array Built postback action structure. + */ + public function buildTemplateAction() + { + return [ + 'type' => ActionType::POSTBACK, + 'label' => $this->label, + 'data' => $this->data, + ]; + } +} diff --git a/src/LINEBot/TemplateActionBuilder/UriTemplateActionBuilder.php b/src/LINEBot/TemplateActionBuilder/UriTemplateActionBuilder.php new file mode 100644 index 00000000..f8eb7755 --- /dev/null +++ b/src/LINEBot/TemplateActionBuilder/UriTemplateActionBuilder.php @@ -0,0 +1,61 @@ +label = $label; + $this->uri = $uri; + } + + /** + * Builds URI action structure. + * + * @return array Built URI action structure. + */ + public function buildTemplateAction() + { + return [ + 'type' => ActionType::URI, + 'label' => $this->label, + 'uri' => $this->uri, + ]; + } +} diff --git a/tests/LINEBot/EventRequestParserTest.php b/tests/LINEBot/EventRequestParserTest.php new file mode 100644 index 00000000..af65f9b5 --- /dev/null +++ b/tests/LINEBot/EventRequestParserTest.php @@ -0,0 +1,311 @@ + 'testsecret']); + $events = $bot->parseEventRequest($this::$json, 'Nq7AExtg27CQRfM3ngKtQxtVeIM/757ZTyDOrxQtWNg='); + + $this->assertEquals(count($events), 12); + + { + // text + $event = $events[0]; + $this->assertEquals(12345678901234, $event->getTimestamp()); + $this->assertTrue($event->isUserEvent()); + $this->assertEquals('userid', $event->getUserId()); + $this->assertInstanceOf('LINE\LINEBot\Event\MessageEvent', $event); + $this->assertInstanceOf('LINE\LINEBot\Event\MessageEvent\TextMessage', $event); + /** @var TextMessage $event */ + $this->assertEquals('replytoken', $event->getReplyToken()); + $this->assertEquals('contentid', $event->getMessageId()); + $this->assertEquals('message', $event->getText()); + } + + { + // image + $event = $events[1]; + $this->assertTrue($event->isGroupEvent()); + $this->assertEquals('groupid', $event->getGroupId()); + $this->assertInstanceOf('LINE\LINEBot\Event\MessageEvent\ImageMessage', $event); + /** @var ImageMessage $event */ + $this->assertEquals('replytoken', $event->getReplyToken()); + } + + { + // video + $event = $events[2]; + $this->assertTrue($event->isRoomEvent()); + $this->assertEquals('roomid', $event->getRoomId()); + $this->assertInstanceOf('LINE\LINEBot\Event\MessageEvent\VideoMessage', $event); + /** @var VideoMessage $event */ + $this->assertEquals('replytoken', $event->getReplyToken()); + } + + { + // audio + $event = $events[3]; + $this->assertInstanceOf('LINE\LINEBot\Event\MessageEvent\AudioMessage', $event); + /** @var AudioMessage $event */ + $this->assertEquals('replytoken', $event->getReplyToken()); + } + + { + // location + $event = $events[4]; + $this->assertInstanceOf('LINE\LINEBot\Event\MessageEvent\LocationMessage', $event); + /** @var LocationMessage $event */ + $this->assertEquals('replytoken', $event->getReplyToken()); + $this->assertEquals('label', $event->getTitle()); + $this->assertEquals('tokyo', $event->getAddress()); + $this->assertEquals('-34.12', $event->getLatitude()); + $this->assertEquals('134.23', $event->getLongitude()); + } + + { + // sticker + $event = $events[5]; + $this->assertInstanceOf('LINE\LINEBot\Event\MessageEvent\StickerMessage', $event); + /** @var StickerMessage $event */ + $this->assertEquals('replytoken', $event->getReplyToken()); + $this->assertEquals(1, $event->getPackageId()); + $this->assertEquals(2, $event->getStickerId()); + } + + { + // follow + $event = $events[6]; + $this->assertInstanceOf('LINE\LINEBot\Event\FollowEvent', $event); + /** @var FollowEvent $event */ + $this->assertEquals('replytoken', $event->getReplyToken()); + } + + { + // unfollow + $event = $events[7]; + $this->assertInstanceOf('LINE\LINEBot\Event\UnfollowEvent', $event); + /** @var UnfollowEvent $event */ + $this->assertTrue($event->getReplyToken() === null); + } + + { + // join + $event = $events[8]; + $this->assertInstanceOf('LINE\LINEBot\Event\JoinEvent', $event); + /** @var JoinEvent $event */ + $this->assertEquals('replytoken', $event->getReplyToken()); + } + + { + // leave + $event = $events[9]; + $this->assertInstanceOf('LINE\LINEBot\Event\LeaveEvent', $event); + /** @var LeaveEvent $event */ + $this->assertTrue($event->getReplyToken() === null); + } + + { + // postback + $event = $events[10]; + $this->assertInstanceOf('LINE\LINEBot\Event\PostbackEvent', $event); + /** @var PostbackEvent $event */ + $this->assertEquals('replytoken', $event->getReplyToken()); + $this->assertEquals('postback', $event->getPostbackData()); + } + + { + // beacon + $event = $events[11]; + $this->assertInstanceOf('LINE\LINEBot\Event\BeaconDetectionEvent', $event); + /** @var BeaconDetectionEvent $event */ + $this->assertEquals('replytoken', $event->getReplyToken()); + $this->assertEquals('bid', $event->getHwid()); + } + } +} diff --git a/tests/LINEBot/GetProfileTest.php b/tests/LINEBot/GetProfileTest.php new file mode 100644 index 00000000..a11e75f0 --- /dev/null +++ b/tests/LINEBot/GetProfileTest.php @@ -0,0 +1,52 @@ +assertEquals('GET', $httpMethod); + $testRunner->assertEquals('https://api.line.me/v2/bot/profile/USER_ID', $url); + + return [ + 'displayName' => 'BOT API', + 'userId' => 'userId', + 'pictureUrl' => 'https://example.com/abcdefghijklmn', + 'statusMessage' => 'Hello, LINE!', + ]; + }; + $bot = new LINEBot(new DummyHttpClient($this, $mock), ['channelSecret' => 'CHANNEL-SECRET']); + $res = $bot->getProfile('USER_ID'); + + $this->assertEquals(200, $res->getHTTPStatus()); + $this->assertTrue($res->isSucceeded()); + + $data = $res->getJSONDecodedBody(); + $this->assertEquals('BOT API', $data['displayName']); + $this->assertEquals('userId', $data['userId']); + $this->assertEquals('https://example.com/abcdefghijklmn', $data['pictureUrl']); + $this->assertEquals('Hello, LINE!', $data['statusMessage']); + } +} diff --git a/tests/LINEBot/GettingContentsTest.php b/tests/LINEBot/GettingContentsTest.php deleted file mode 100644 index 0f82c4fa..00000000 --- a/tests/LINEBot/GettingContentsTest.php +++ /dev/null @@ -1,81 +0,0 @@ - '1000000000', - 'channelSecret' => 'testsecret', - 'channelMid' => 'TEST_MID', - ]; - - $histories = new History(); - $emitter = new Emitter(); - $emitter->attach($mock); - $emitter->attach($histories); - - $sdk = new LINEBot( - $config, - new LINEBot\HTTPClient\GuzzleHTTPClient(array_merge($config, ['emitter' => $emitter])) - ); - - $res = $sdk->getUserProfile('DUMMY_MID_GET_DISPLAY_NAME'); - $this->assertEquals($res['count'], 1); - $this->assertEquals($res['contacts'][0]['displayName'], 'BOT API'); - - $history = $histories->getIterator()[0]; - - /** @var Request $req */ - $req = $history['request']; - $this->assertEquals($req->getMethod(), 'GET'); - $this->assertEquals( - $req->getUrl(), - 'https://trialbot-api.line.me/v1/profiles?mids=DUMMY_MID_GET_DISPLAY_NAME' - ); - - $channelIdHeader = $req->getHeaderAsArray('X-Line-ChannelID'); - $this->assertEquals(sizeof($channelIdHeader), 1); - $this->assertEquals($channelIdHeader[0], '1000000000'); - - $channelSecretHeader = $req->getHeaderAsArray('X-Line-ChannelSecret'); - $this->assertEquals(sizeof($channelSecretHeader), 1); - $this->assertEquals($channelSecretHeader[0], 'testsecret'); - - $channelMidHeader = $req->getHeaderAsArray('X-Line-Trusted-User-With-ACL'); - $this->assertEquals(sizeof($channelMidHeader), 1); - $this->assertEquals($channelMidHeader[0], 'TEST_MID'); - } -} diff --git a/tests/LINEBot/MessageSendingTest.php b/tests/LINEBot/MessageSendingTest.php deleted file mode 100644 index de2e9a8e..00000000 --- a/tests/LINEBot/MessageSendingTest.php +++ /dev/null @@ -1,549 +0,0 @@ - '1000000000', - 'channelSecret' => 'testsecret', - 'channelMid' => 'TEST_MID', - ]; - - public function testSendText() - { - $mock = new Mock([ - new Response( - 200, - [], - Stream::factory('{"failed":[],"messageId":"1460826285060","timestamp":1460826285060,"version":1}') - ), - new Response( - 400, - [], - Stream::factory('{"statusCode":"422","statusMessage":"invalid users"}') - ), - new Response( - 500, - [], - Stream::factory( - '{"statusCode":"500","statusMessage":"unexpected error found at call bot api sendMessage"}' - ) - ), - ]); - - $histories = new History(); - $emitter = new Emitter(); - $emitter->attach($mock); - $emitter->attach($histories); - - $sdk = new LINEBot( - $this::$config, - new GuzzleHTTPClient(array_merge($this::$config, ['emitter' => $emitter])) - ); - - $res = $sdk->sendText(['DUMMY_MID'], 'hello!'); - $this->assertInstanceOf('\LINE\LINEBot\Response\SucceededResponse', $res); - /** @var \LINE\LINEBot\Response\SucceededResponse $res */ - $this->assertTrue($res->isSucceeded()); - $this->assertEquals(200, $res->getHTTPStatus()); - $this->assertEmpty($res->getFailed()); - $this->assertEquals('1460826285060', $res->getMessageId()); - $this->assertEquals(1460826285060, $res->getTimestamp()); - $this->assertEquals(1, $res->getVersion()); - - $res = $sdk->sendText(['INVALID_MID'], 'hello!'); - $this->assertInstanceOf('\LINE\LINEBot\Response\FailedResponse', $res); - /** @var \LINE\LINEBot\Response\FailedResponse $res */ - $this->assertFalse($res->isSucceeded()); - $this->assertEquals(400, $res->getHTTPStatus()); - $this->assertEquals('422', $res->getStatusCode()); - $this->assertEquals('invalid users', $res->getStatusMessage()); - - $res = $sdk->sendText(['DUMMY_MID'], 'SOMETHING WRONG PAYLOAD'); - $this->assertInstanceOf('\LINE\LINEBot\Response\FailedResponse', $res); - /** @var \LINE\LINEBot\Response\FailedResponse $res */ - $this->assertFalse($res->isSucceeded()); - $this->assertEquals(500, $res->getHTTPStatus()); - $this->assertEquals('500', $res->getStatusCode()); - $this->assertEquals('unexpected error found at call bot api sendMessage', $res->getStatusMessage()); - - $history = $histories->getIterator()[0]; - /** @var Request $req */ - $req = $history['request']; - $this->assertEquals($req->getMethod(), 'POST'); - $this->assertEquals($req->getUrl(), 'https://trialbot-api.line.me/v1/events'); - - $data = json_decode($req->getBody(), true); - $this->assertEquals($data['eventType'], 138311608800106203); - $this->assertEquals($data['to'], ['DUMMY_MID']); - $this->assertEquals($data['content']['text'], 'hello!'); - $this->assertEquals($data['content']['contentType'], ContentType::TEXT); - $this->assertEquals($data['content']['toType'], RecipientType::USER); - - $channelIdHeader = $req->getHeaderAsArray('X-Line-ChannelID'); - $this->assertEquals(sizeof($channelIdHeader), 1); - $this->assertEquals($channelIdHeader[0], '1000000000'); - - $channelSecretHeader = $req->getHeaderAsArray('X-Line-ChannelSecret'); - $this->assertEquals(sizeof($channelSecretHeader), 1); - $this->assertEquals($channelSecretHeader[0], 'testsecret'); - - $channelMidHeader = $req->getHeaderAsArray('X-Line-Trusted-User-With-ACL'); - $this->assertEquals(sizeof($channelMidHeader), 1); - $this->assertEquals($channelMidHeader[0], 'TEST_MID'); - - } - - public function testSendImage() - { - $mock = new Mock([ - new Response( - 200, - [], - Stream::factory('{"failed":[],"messageId":"1460826285060","timestamp":1460826285060,"version":1}') - ), - new Response( - 400, - [], - Stream::factory('{"statusCode":"422","statusMessage":"invalid users"}')), - new Response( - 500, - [], - Stream::factory( - '{"statusCode":"500","statusMessage":"unexpected error found at call bot api sendMessage"}' - ) - ), - ]); - - $histories = new History(); - $emitter = new Emitter(); - $emitter->attach($mock); - $emitter->attach($histories); - - $sdk = new LINEBot( - $this::$config, - new GuzzleHTTPClient(array_merge($this::$config, ['emitter' => $emitter])) - ); - - $res = $sdk->sendImage(['DUMMY_MID'], 'http://example.com/image.jpg', 'http://example.com/preview.jpg'); - $this->assertInstanceOf('\LINE\LINEBot\Response\SucceededResponse', $res); - /** @var \LINE\LINEBot\Response\SucceededResponse $res */ - $this->assertTrue($res->isSucceeded()); - $this->assertEquals(200, $res->getHTTPStatus()); - $this->assertEmpty($res->getFailed()); - $this->assertEquals('1460826285060', $res->getMessageId()); - $this->assertEquals(1460826285060, $res->getTimestamp()); - $this->assertEquals(1, $res->getVersion()); - - $res = $sdk->sendImage(['INVALID_MID'], 'http://example.com/image.jpg', 'http://example.com/preview.jpg'); - $this->assertInstanceOf('\LINE\LINEBot\Response\FailedResponse', $res); - /** @var \LINE\LINEBot\Response\FailedResponse $res */ - $this->assertFalse($res->isSucceeded()); - $this->assertEquals(400, $res->getHTTPStatus()); - $this->assertEquals('422', $res->getStatusCode()); - $this->assertEquals('invalid users', $res->getStatusMessage()); - - $res = $sdk->sendImage(['DUMMY_MID'], 'http://example.com/image.jpg', 'http://example.com/preview.jpg'); - $this->assertInstanceOf('\LINE\LINEBot\Response\FailedResponse', $res); - /** @var \LINE\LINEBot\Response\FailedResponse $res */ - $this->assertFalse($res->isSucceeded()); - $this->assertEquals(500, $res->getHTTPStatus()); - $this->assertEquals('500', $res->getStatusCode()); - $this->assertEquals('unexpected error found at call bot api sendMessage', $res->getStatusMessage()); - - $history = $histories->getIterator()[0]; - /** @var Request $req */ - $req = $history['request']; - $this->assertEquals($req->getMethod(), 'POST'); - $this->assertEquals($req->getUrl(), 'https://trialbot-api.line.me/v1/events'); - - $data = json_decode($req->getBody(), true); - $this->assertEquals($data['eventType'], 138311608800106203); - $this->assertEquals($data['to'], ['DUMMY_MID']); - $this->assertEquals($data['content']['originalContentUrl'], 'http://example.com/image.jpg'); - $this->assertEquals($data['content']['previewImageUrl'], 'http://example.com/preview.jpg'); - $this->assertEquals($data['content']['contentType'], ContentType::IMAGE); - $this->assertEquals($data['content']['toType'], RecipientType::USER); - - $channelIdHeader = $req->getHeaderAsArray('X-Line-ChannelID'); - $this->assertEquals(sizeof($channelIdHeader), 1); - $this->assertEquals($channelIdHeader[0], '1000000000'); - - $channelSecretHeader = $req->getHeaderAsArray('X-Line-ChannelSecret'); - $this->assertEquals(sizeof($channelSecretHeader), 1); - $this->assertEquals($channelSecretHeader[0], 'testsecret'); - - $channelMidHeader = $req->getHeaderAsArray('X-Line-Trusted-User-With-ACL'); - $this->assertEquals(sizeof($channelMidHeader), 1); - $this->assertEquals($channelMidHeader[0], 'TEST_MID'); - } - - public function testSendVideo() - { - $mock = new Mock([ - new Response( - 200, - [], - Stream::factory('{"failed":[],"messageId":"1460867315795","timestamp":1460867315795,"version":1}') - ), - new Response( - 400, - [], - Stream::factory('{"statusCode":"422","statusMessage":"invalid users"}') - ), - new Response( - 500, - [], - Stream::factory( - '{"statusCode":"500","statusMessage":"unexpected error found at call bot api sendMessage"}' - ) - ), - ]); - - $histories = new History(); - $emitter = new Emitter(); - $emitter->attach($mock); - $emitter->attach($histories); - - $sdk = new LINEBot( - $this::$config, - new GuzzleHTTPClient(array_merge($this::$config, ['emitter' => $emitter])) - ); - - $res = $sdk->sendVideo(['DUMMY_MID'], 'http://example.com/video.mp4', 'http://example.com/preview.jpg'); - $this->assertInstanceOf('\LINE\LINEBot\Response\SucceededResponse', $res); - /** @var \LINE\LINEBot\Response\SucceededResponse $res */ - $this->assertTrue($res->isSucceeded()); - $this->assertEquals(200, $res->getHTTPStatus()); - $this->assertEmpty($res->getFailed()); - $this->assertEquals('1460867315795', $res->getMessageId()); - $this->assertEquals(1460867315795, $res->getTimestamp()); - $this->assertEquals(1, $res->getVersion()); - - $res = $sdk->sendVideo(['INVALID_MID'], 'http://example.com/video.mp4', 'http://example.com/preview.jpg'); - $this->assertInstanceOf('\LINE\LINEBot\Response\FailedResponse', $res); - /** @var \LINE\LINEBot\Response\FailedResponse $res */ - $this->assertFalse($res->isSucceeded()); - $this->assertEquals(400, $res->getHTTPStatus()); - $this->assertEquals('422', $res->getStatusCode()); - $this->assertEquals('invalid users', $res->getStatusMessage()); - - $res = $sdk->sendVideo(['DUMMY_MID'], 'http://example.com/video.mp4', 'http://example.com/preview.jpg'); - $this->assertInstanceOf('\LINE\LINEBot\Response\FailedResponse', $res); - /** @var \LINE\LINEBot\Response\FailedResponse $res */ - $this->assertFalse($res->isSucceeded()); - $this->assertEquals(500, $res->getHTTPStatus()); - $this->assertEquals('500', $res->getStatusCode()); - $this->assertEquals('unexpected error found at call bot api sendMessage', $res->getStatusMessage()); - - $history = $histories->getIterator()[0]; - /** @var Request $req */ - $req = $history['request']; - $this->assertEquals($req->getMethod(), 'POST'); - $this->assertEquals($req->getUrl(), 'https://trialbot-api.line.me/v1/events'); - - $data = json_decode($req->getBody(), true); - $this->assertEquals($data['eventType'], 138311608800106203); - $this->assertEquals($data['to'], ['DUMMY_MID']); - $this->assertEquals($data['content']['originalContentUrl'], 'http://example.com/video.mp4'); - $this->assertEquals($data['content']['previewImageUrl'], 'http://example.com/preview.jpg'); - $this->assertEquals($data['content']['contentType'], ContentType::VIDEO); - $this->assertEquals($data['content']['toType'], RecipientType::USER); - - $channelIdHeader = $req->getHeaderAsArray('X-Line-ChannelID'); - $this->assertEquals(sizeof($channelIdHeader), 1); - $this->assertEquals($channelIdHeader[0], '1000000000'); - - $channelSecretHeader = $req->getHeaderAsArray('X-Line-ChannelSecret'); - $this->assertEquals(sizeof($channelSecretHeader), 1); - $this->assertEquals($channelSecretHeader[0], 'testsecret'); - - $channelMidHeader = $req->getHeaderAsArray('X-Line-Trusted-User-With-ACL'); - $this->assertEquals(sizeof($channelMidHeader), 1); - $this->assertEquals($channelMidHeader[0], 'TEST_MID'); - } - - public function testSendAudio() - { - $mock = new Mock([ - new Response( - 200, - [], - Stream::factory('{"failed":[],"messageId":"1460867315795","timestamp":1460867315795,"version":1}') - ), - new Response( - 400, - [], - Stream::factory('{"statusCode":"422","statusMessage":"invalid users"}') - ), - new Response( - 500, - [], - Stream::factory( - '{"statusCode":"500","statusMessage":"unexpected error found at call bot api sendMessage"}' - ) - ), - ]); - - $histories = new History(); - $emitter = new Emitter(); - $emitter->attach($mock); - $emitter->attach($histories); - - $sdk = new LINEBot( - $this::$config, - new GuzzleHTTPClient(array_merge($this::$config, ['emitter' => $emitter])) - ); - - $res = $sdk->sendAudio(['DUMMY_MID'], 'http://example.com/sound.m4a', 5000); - $this->assertInstanceOf('\LINE\LINEBot\Response\SucceededResponse', $res); - /** @var \LINE\LINEBot\Response\SucceededResponse $res */ - $this->assertTrue($res->isSucceeded()); - $this->assertEquals(200, $res->getHTTPStatus()); - $this->assertEmpty($res->getFailed()); - $this->assertEquals('1460867315795', $res->getMessageId()); - $this->assertEquals(1460867315795, $res->getTimestamp()); - $this->assertEquals(1, $res->getVersion()); - - $res = $sdk->sendAudio(['INVALID_MID'], 'http://example.com/sound.m4a', 5000); - $this->assertInstanceOf('\LINE\LINEBot\Response\FailedResponse', $res); - /** @var \LINE\LINEBot\Response\FailedResponse $res */ - $this->assertFalse($res->isSucceeded()); - $this->assertEquals(400, $res->getHTTPStatus()); - $this->assertEquals('422', $res->getStatusCode()); - $this->assertEquals('invalid users', $res->getStatusMessage()); - - $res = $sdk->sendAudio(['DUMMY_MID'], 'http://example.com/sound.m4a', 5000); - $this->assertInstanceOf('\LINE\LINEBot\Response\FailedResponse', $res); - /** @var \LINE\LINEBot\Response\FailedResponse $res */ - $this->assertFalse($res->isSucceeded()); - $this->assertEquals(500, $res->getHTTPStatus()); - $this->assertEquals('500', $res->getStatusCode()); - $this->assertEquals('unexpected error found at call bot api sendMessage', $res->getStatusMessage()); - - $history = $histories->getIterator()[0]; - /** @var Request $req */ - $req = $history['request']; - $this->assertEquals($req->getMethod(), 'POST'); - $this->assertEquals($req->getUrl(), 'https://trialbot-api.line.me/v1/events'); - - $data = json_decode($req->getBody(), true); - $this->assertEquals($data['eventType'], 138311608800106203); - $this->assertEquals($data['to'], ['DUMMY_MID']); - $this->assertEquals($data['content']['originalContentUrl'], 'http://example.com/sound.m4a'); - $this->assertEquals($data['content']['contentMetadata']['AUDLEN'], '5000'); - $this->assertEquals($data['content']['contentType'], ContentType::AUDIO); - $this->assertEquals($data['content']['toType'], RecipientType::USER); - - $channelIdHeader = $req->getHeaderAsArray('X-Line-ChannelID'); - $this->assertEquals(sizeof($channelIdHeader), 1); - $this->assertEquals($channelIdHeader[0], '1000000000'); - - $channelSecretHeader = $req->getHeaderAsArray('X-Line-ChannelSecret'); - $this->assertEquals(sizeof($channelSecretHeader), 1); - $this->assertEquals($channelSecretHeader[0], 'testsecret'); - - $channelMidHeader = $req->getHeaderAsArray('X-Line-Trusted-User-With-ACL'); - $this->assertEquals(sizeof($channelMidHeader), 1); - $this->assertEquals($channelMidHeader[0], 'TEST_MID'); - } - - public function testSendLocation() - { - $mock = new Mock([ - new Response( - 200, - [], - Stream::factory('{"failed":[],"messageId":"1460867315795","timestamp":1460867315795,"version":1}') - ), - new Response( - 400, - [], - Stream::factory('{"statusCode":"422","statusMessage":"invalid users"}')), - new Response( - 500, - [], - Stream::factory('{"statusCode":"500","statusMessage":"unexpected error found at call bot api sendMessage"}') - ), - ]); - - $histories = new History(); - $emitter = new Emitter(); - $emitter->attach($mock); - $emitter->attach($histories); - - $sdk = new LINEBot( - $this::$config, - new GuzzleHTTPClient(array_merge($this::$config, ['emitter' => $emitter])) - ); - - $res = $sdk->sendLocation(['DUMMY_MID'], '2 Chome-21-1 Shibuya Tokyo 150-0002, Japan', 35.658240, 139.703478); - $this->assertInstanceOf('\LINE\LINEBot\Response\SucceededResponse', $res); - /** @var \LINE\LINEBot\Response\SucceededResponse $res */ - $this->assertTrue($res->isSucceeded()); - $this->assertEquals(200, $res->getHTTPStatus()); - $this->assertEmpty($res->getFailed()); - $this->assertEquals('1460867315795', $res->getMessageId()); - $this->assertEquals(1460867315795, $res->getTimestamp()); - $this->assertEquals(1, $res->getVersion()); - - $res = $sdk->sendLocation(['INVALID_MID'], '2 Chome-21-1 Shibuya Tokyo 150-0002, Japan', 35.658240, 139.703478); - $this->assertInstanceOf('\LINE\LINEBot\Response\FailedResponse', $res); - /** @var \LINE\LINEBot\Response\FailedResponse $res */ - $this->assertFalse($res->isSucceeded()); - $this->assertEquals(400, $res->getHTTPStatus()); - $this->assertEquals('422', $res->getStatusCode()); - $this->assertEquals('invalid users', $res->getStatusMessage()); - - $res = $sdk->sendLocation(['DUMMY_MID'], '2 Chome-21-1 Shibuya Tokyo 150-0002, Japan', 35.658240, 139.703478); - $this->assertInstanceOf('\LINE\LINEBot\Response\FailedResponse', $res); - /** @var \LINE\LINEBot\Response\FailedResponse $res */ - $this->assertFalse($res->isSucceeded()); - $this->assertEquals(500, $res->getHTTPStatus()); - $this->assertEquals('500', $res->getStatusCode()); - $this->assertEquals('unexpected error found at call bot api sendMessage', $res->getStatusMessage()); - - $history = $histories->getIterator()[0]; - /** @var Request $req */ - $req = $history['request']; - $this->assertEquals($req->getMethod(), 'POST'); - $this->assertEquals($req->getUrl(), 'https://trialbot-api.line.me/v1/events'); - - $data = json_decode($req->getBody(), true); - $this->assertEquals($data['eventType'], 138311608800106203); - $this->assertEquals($data['to'], ['DUMMY_MID']); - - $content = $data['content']; - $location = $content['location']; - - $this->assertEquals($content['contentType'], ContentType::LOCATION); - $this->assertEquals($content['text'], '2 Chome-21-1 Shibuya Tokyo 150-0002, Japan'); - $this->assertEquals($location['title'], $content['text']); - $this->assertEquals($location['latitude'], 35.658240); - $this->assertEquals($location['longitude'], 139.703478); - - $channelIdHeader = $req->getHeaderAsArray('X-Line-ChannelID'); - $this->assertEquals(sizeof($channelIdHeader), 1); - $this->assertEquals($channelIdHeader[0], '1000000000'); - - $channelSecretHeader = $req->getHeaderAsArray('X-Line-ChannelSecret'); - $this->assertEquals(sizeof($channelSecretHeader), 1); - $this->assertEquals($channelSecretHeader[0], 'testsecret'); - - $channelMidHeader = $req->getHeaderAsArray('X-Line-Trusted-User-With-ACL'); - $this->assertEquals(sizeof($channelMidHeader), 1); - $this->assertEquals($channelMidHeader[0], 'TEST_MID'); - } - - public function testSendSticker() - { - $mock = new Mock([ - new Response( - 200, - [], - Stream::factory('{"failed":[],"messageId":"1460867315795","timestamp":1460867315795,"version":1}') - ), - new Response( - 400, - [], - Stream::factory('{"statusCode":"422","statusMessage":"invalid users"}') - ), - new Response( - 500, - [], - Stream::factory( - '{"statusCode":"500","statusMessage":"unexpected error found at call bot api sendMessage"}' - ) - ), - ]); - - $histories = new History(); - $emitter = new Emitter(); - $emitter->attach($mock); - $emitter->attach($histories); - - $sdk = new LINEBot( - $this::$config, - new GuzzleHTTPClient(array_merge($this::$config, ['emitter' => $emitter])) - ); - - $res = $sdk->sendSticker(['DUMMY_MID'], 1, 2, 100); - $this->assertInstanceOf('\LINE\LINEBot\Response\SucceededResponse', $res); - /** @var \LINE\LINEBot\Response\SucceededResponse $res */ - $this->assertTrue($res->isSucceeded()); - $this->assertEquals(200, $res->getHTTPStatus()); - $this->assertEmpty($res->getFailed()); - $this->assertEquals('1460867315795', $res->getMessageId()); - $this->assertEquals(1460867315795, $res->getTimestamp()); - $this->assertEquals(1, $res->getVersion()); - - $res = $sdk->sendSticker(['INVALID_MID'], 1, 1, 100); - $this->assertInstanceOf('\LINE\LINEBot\Response\FailedResponse', $res); - /** @var \LINE\LINEBot\Response\FailedResponse $res */ - $this->assertFalse($res->isSucceeded()); - $this->assertEquals(400, $res->getHTTPStatus()); - $this->assertEquals('422', $res->getStatusCode()); - $this->assertEquals('invalid users', $res->getStatusMessage()); - - $res = $sdk->sendSticker(['DUMMY_MID'], 1, 1, 100); - $this->assertInstanceOf('\LINE\LINEBot\Response\FailedResponse', $res); - /** @var \LINE\LINEBot\Response\FailedResponse $res */ - $this->assertFalse($res->isSucceeded()); - $this->assertEquals(500, $res->getHTTPStatus()); - $this->assertEquals('500', $res->getStatusCode()); - $this->assertEquals('unexpected error found at call bot api sendMessage', $res->getStatusMessage()); - - $history = $histories->getIterator()[0]; - /** @var Request $req */ - $req = $history['request']; - $this->assertEquals($req->getMethod(), 'POST'); - $this->assertEquals($req->getUrl(), 'https://trialbot-api.line.me/v1/events'); - - $data = json_decode($req->getBody(), true); - $this->assertEquals($data['eventType'], 138311608800106203); - $this->assertEquals($data['to'], ['DUMMY_MID']); - - $this->assertEquals($data['content']['contentType'], ContentType::STICKER); - $this->assertEquals($data['content']['contentMetadata']['STKID'], '1'); - $this->assertEquals($data['content']['contentMetadata']['STKPKGID'], '2'); - $this->assertEquals($data['content']['contentMetadata']['STKVER'], '100'); - - $channelIdHeader = $req->getHeaderAsArray('X-Line-ChannelID'); - $this->assertEquals(sizeof($channelIdHeader), 1); - $this->assertEquals($channelIdHeader[0], '1000000000'); - - $channelSecretHeader = $req->getHeaderAsArray('X-Line-ChannelSecret'); - $this->assertEquals(sizeof($channelSecretHeader), 1); - $this->assertEquals($channelSecretHeader[0], 'testsecret'); - - $channelMidHeader = $req->getHeaderAsArray('X-Line-Trusted-User-With-ACL'); - $this->assertEquals(sizeof($channelMidHeader), 1); - $this->assertEquals($channelMidHeader[0], 'TEST_MID'); - } -} \ No newline at end of file diff --git a/tests/LINEBot/MultipleMessagesSendingTest.php b/tests/LINEBot/MultipleMessagesSendingTest.php deleted file mode 100644 index 12387244..00000000 --- a/tests/LINEBot/MultipleMessagesSendingTest.php +++ /dev/null @@ -1,165 +0,0 @@ - '1000000000', - 'channelSecret' => 'testsecret', - 'channelMid' => 'TEST_MID', - ]; - - $histories = new History(); - $emitter = new Emitter(); - $emitter->attach($mock); - $emitter->attach($histories); - - $sdk = new LINEBot($config, new GuzzleHTTPClient(array_merge($config, ['emitter' => $emitter]))); - - $multipleMessages = (new MultipleMessages()) - ->addText('hello!') - ->addImage('http://example.com/image.jpg', 'http://example.com/preview.jpg') - ->addAudio('http://example.com/audio.m4a', 6000) - ->addVideo('http://example.com/video.mp4', 'http://example.com/video_preview.jpg') - ->addLocation('2 Chome-21-1 Shibuya Tokyo 150-0002, Japan', 35.658240, 139.703478) - ->addSticker(1, 2, 100); - - $res = $sdk->sendMultipleMessages(['DUMMY_MID'], $multipleMessages); - $this->assertInstanceOf('\LINE\LINEBot\Response\SucceededResponse', $res); - /** @var \LINE\LINEBot\Response\SucceededResponse $res */ - $this->assertTrue($res->isSucceeded()); - $this->assertEquals(200, $res->getHTTPStatus()); - $this->assertEmpty($res->getFailed()); - $this->assertEquals('1460867315795', $res->getMessageId()); - $this->assertEquals(1460867315795, $res->getTimestamp()); - $this->assertEquals(1, $res->getVersion()); - - $res = $sdk->sendMultipleMessages(['INVALID_MID'], $multipleMessages); - $this->assertInstanceOf('\LINE\LINEBot\Response\FailedResponse', $res); - /** @var \LINE\LINEBot\Response\FailedResponse $res */ - $this->assertFalse($res->isSucceeded()); - $this->assertEquals(400, $res->getHTTPStatus()); - $this->assertEquals('422', $res->getStatusCode()); - $this->assertEquals('invalid users', $res->getStatusMessage()); - - $res = $sdk->sendMultipleMessages(['DUMMY_MID'], $multipleMessages); - $this->assertInstanceOf('\LINE\LINEBot\Response\FailedResponse', $res); - /** @var \LINE\LINEBot\Response\FailedResponse $res */ - $this->assertFalse($res->isSucceeded()); - $this->assertEquals(500, $res->getHTTPStatus()); - $this->assertEquals('500', $res->getStatusCode()); - $this->assertEquals('unexpected error found at call bot api sendMessage', $res->getStatusMessage()); - - $history = $histories->getIterator()[0]; - /** @var Request $req */ - $req = $history['request']; - $this->assertEquals($req->getMethod(), 'POST'); - $this->assertEquals($req->getUrl(), 'https://trialbot-api.line.me/v1/events'); - - $data = json_decode($req->getBody(), true); - $this->assertEquals($data['eventType'], 140177271400161403); - $this->assertEquals($data['to'], ['DUMMY_MID']); - - $this->assertEquals(sizeof($data['content']['messages']), 6); - - { - $content = $data['content']['messages'][0]; - $this->assertEquals($content['text'], 'hello!'); - $this->assertEquals($content['contentType'], ContentType::TEXT); - } - { - $content = $data['content']['messages'][1]; - $this->assertEquals($content['originalContentUrl'], 'http://example.com/image.jpg'); - $this->assertEquals($content['previewImageUrl'], 'http://example.com/preview.jpg'); - $this->assertEquals($content['contentType'], ContentType::IMAGE); - } - { - $content = $data['content']['messages'][2]; - $this->assertEquals($content['originalContentUrl'], 'http://example.com/audio.m4a'); - $this->assertEquals($content['contentMetadata']['AUDLEN'], '6000'); - $this->assertEquals($content['contentType'], ContentType::AUDIO); - } - { - $content = $data['content']['messages'][3]; - $this->assertEquals($content['originalContentUrl'], 'http://example.com/video.mp4'); - $this->assertEquals($content['previewImageUrl'], 'http://example.com/video_preview.jpg'); - $this->assertEquals($content['contentType'], ContentType::VIDEO); - } - { - $content = $data['content']['messages'][4]; - $location = $content['location']; - $this->assertEquals($content['text'], '2 Chome-21-1 Shibuya Tokyo 150-0002, Japan'); - $this->assertEquals($location['title'], $content['text']); - $this->assertEquals($location['latitude'], 35.658240); - $this->assertEquals($location['longitude'], 139.703478); - $this->assertEquals($content['contentType'], ContentType::LOCATION); - } - { - $content = $data['content']['messages'][5]; - $this->assertEquals($content['contentType'], ContentType::STICKER); - $this->assertEquals($content['contentMetadata']['STKID'], '1'); - $this->assertEquals($content['contentMetadata']['STKPKGID'], '2'); - $this->assertEquals($content['contentMetadata']['STKVER'], '100'); - } - - $channelIdHeader = $req->getHeaderAsArray('X-Line-ChannelID'); - $this->assertEquals(sizeof($channelIdHeader), 1); - $this->assertEquals($channelIdHeader[0], '1000000000'); - - $channelSecretHeader = $req->getHeaderAsArray('X-Line-ChannelSecret'); - $this->assertEquals(sizeof($channelSecretHeader), 1); - $this->assertEquals($channelSecretHeader[0], 'testsecret'); - - $channelMidHeader = $req->getHeaderAsArray('X-Line-Trusted-User-With-ACL'); - $this->assertEquals(sizeof($channelMidHeader), 1); - $this->assertEquals($channelMidHeader[0], 'TEST_MID'); - } -} \ No newline at end of file diff --git a/tests/LINEBot/ReceiveFactoryTest.php b/tests/LINEBot/ReceiveFactoryTest.php deleted file mode 100644 index 7108b7a0..00000000 --- a/tests/LINEBot/ReceiveFactoryTest.php +++ /dev/null @@ -1,108 +0,0 @@ - '1441301333', - 'channelSecret' => 'testsecret', - 'channelMid' => 'u0a556cffd4da0dd89c94fb36e36e1cdc', - ]; - - private static $json = <<assertEquals(sizeof($reqs), 2); - - { - $req = $reqs[0]; - $this->assertInstanceOf('\LINE\LINEBot\Receive\Message\Text', $req); - /** @var Text $req */ - $this->assertTrue($req->isMessage()); - $this->assertFalse($req->isOperation()); - $this->assertTrue($req->isValidEvent()); - $this->assertTrue($req->isSentMe()); - - $this->assertEquals($req->getId(), 'ABCDEF-12345678901'); - $this->assertEquals($req->getContentId(), '325708'); - $this->assertEquals($req->getCreatedTime(), '1332394961610'); - $this->assertEquals($req->getFromMid(), 'uff2aec188e58752ee1fb0f9507c6529a'); - - $this->assertTrue($req->isText()); - $this->assertEquals($req->getText(), 'hello'); - } - - { - $req = $reqs[1]; - $this->assertInstanceOf('\LINE\LINEBot\Receive\Operation\AddContact', $req); - /** @var AddContact $req */ - $this->assertFalse($req->isMessage()); - $this->assertTrue($req->isOperation()); - $this->assertTrue($req->isValidEvent()); - - $this->assertTrue($req->isAddContact()); - $this->assertEquals($req->getRevision(), '2469'); - $this->assertEquals($req->getFromMid(), 'u0f3bfc598b061eba02183bfc5280886a'); - } - } -} \ No newline at end of file diff --git a/tests/LINEBot/RichMessageSendingTest.php b/tests/LINEBot/RichMessageSendingTest.php deleted file mode 100644 index 90cb62fb..00000000 --- a/tests/LINEBot/RichMessageSendingTest.php +++ /dev/null @@ -1,179 +0,0 @@ - '1000000000', - 'channelSecret' => 'testsecret', - 'channelMid' => 'TEST_MID', - ]; - - $histories = new History(); - $emitter = new Emitter(); - $emitter->attach($mock); - $emitter->attach($histories); - - $sdk = new LINEBot($config, new GuzzleHTTPClient(array_merge($config, ['emitter' => $emitter]))); - - $markup = (new Markup(1040)) - ->setAction('SOMETHING', 'something', 'https://line.me') - ->addListener('SOMETHING', 0, 0, 520, 520); - - $res = $sdk->sendRichMessage(["DUMMY_MID"], 'http://example.com/image.jpg', "Alt text", $markup); - $this->assertInstanceOf('\LINE\LINEBot\Response\SucceededResponse', $res); - /** @var \LINE\LINEBot\Response\SucceededResponse $res */ - $this->assertTrue($res->isSucceeded()); - $this->assertEquals(200, $res->getHTTPStatus()); - $this->assertEmpty($res->getFailed()); - $this->assertEquals('1460867315795', $res->getMessageId()); - $this->assertEquals(1460867315795, $res->getTimestamp()); - $this->assertEquals(1, $res->getVersion()); - - $res = $sdk->sendRichMessage(["INVALID_MID"], 'http://example.com/image.jpg', "Alt text", $markup); - $this->assertInstanceOf('\LINE\LINEBot\Response\FailedResponse', $res); - /** @var \LINE\LINEBot\Response\FailedResponse $res */ - $this->assertFalse($res->isSucceeded()); - $this->assertEquals(400, $res->getHTTPStatus()); - $this->assertEquals('422', $res->getStatusCode()); - $this->assertEquals('invalid users', $res->getStatusMessage()); - - $res = $sdk->sendRichMessage(["DUMMY_MID"], 'http://example.com/image.jpg', "Alt text", $markup); - $this->assertInstanceOf('\LINE\LINEBot\Response\FailedResponse', $res); - /** @var \LINE\LINEBot\Response\FailedResponse $res */ - $this->assertFalse($res->isSucceeded()); - $this->assertEquals(500, $res->getHTTPStatus()); - $this->assertEquals('500', $res->getStatusCode()); - $this->assertEquals('unexpected error found at call bot api sendMessage', $res->getStatusMessage()); - - $history = $histories->getIterator()[0]; - /** @var Request $req */ - $req = $history['request']; - - $this->assertEquals($req->getMethod(), 'POST'); - $this->assertEquals($req->getUrl(), 'https://trialbot-api.line.me/v1/events'); - - $data = json_decode($req->getBody(), true); - $this->assertEquals($data['eventType'], 138311608800106203); - $this->assertEquals($data['to'], ['DUMMY_MID']); - $this->assertEquals($data['content']['contentMetadata']['ALT_TEXT'], 'Alt text'); - $this->assertEquals( - $data['content']['contentMetadata']['DOWNLOAD_URL'], - 'http://example.com/image.jpg' - ); - - $json = $data['content']['contentMetadata']['MARKUP_JSON']; - $this->assertEquals( - json_decode($json, true), - [ - 'scenes' => [ - 'scene1' => [ - 'listeners' => [ - [ - 'params' => [ - 0, - 0, - 520, - 520, - ], - 'type' => 'touch', - 'action' => 'SOMETHING', - ], - ], - 'draws' => [ - [ - 'image' => 'image1', - 'x' => 0, - 'y' => 0, - 'w' => 1040, - 'h' => 1040, - ], - ], - ], - ], - 'images' => [ - 'image1' => [ - 'x' => 0, - 'y' => 0, - 'w' => 1040, - 'h' => 1040, - ], - ], - 'actions' => [ - 'SOMETHING' => [ - 'text' => 'something', - 'params' => [ - 'linkUri' => 'https://line.me', - ], - 'type' => 'web', - ], - ], - 'canvas' => [ - 'initialScene' => 'scene1', - 'width' => 1040, - 'height' => 1040, - ], - ] - ); - - $channelIdHeader = $req->getHeaderAsArray('X-Line-ChannelID'); - $this->assertEquals(sizeof($channelIdHeader), 1); - $this->assertEquals($channelIdHeader[0], '1000000000'); - - $channelSecretHeader = $req->getHeaderAsArray('X-Line-ChannelSecret'); - $this->assertEquals(sizeof($channelSecretHeader), 1); - $this->assertEquals($channelSecretHeader[0], 'testsecret'); - - $channelMidHeader = $req->getHeaderAsArray('X-Line-Trusted-User-With-ACL'); - $this->assertEquals(sizeof($channelMidHeader), 1); - $this->assertEquals($channelMidHeader[0], 'TEST_MID'); - } -} \ No newline at end of file diff --git a/tests/LINEBot/SendAudioTest.php b/tests/LINEBot/SendAudioTest.php new file mode 100644 index 00000000..ca8ae533 --- /dev/null +++ b/tests/LINEBot/SendAudioTest.php @@ -0,0 +1,79 @@ +assertEquals('POST', $httpMethod); + $testRunner->assertEquals('https://api.line.me/v2/bot/message/reply', $url); + + $testRunner->assertEquals('REPLY-TOKEN', $data['replyToken']); + $testRunner->assertEquals(1, count($data['messages'])); + $testRunner->assertEquals(MessageType::AUDIO, $data['messages'][0]['type']); + $testRunner->assertEquals('https://example.com/audio.mp4', $data['messages'][0]['originalContentUrl']); + $testRunner->assertEquals(12345, $data['messages'][0]['duration']); + + return ['status' => 200]; + }; + $bot = new LINEBot(new DummyHttpClient($this, $mock), ['channelSecret' => 'CHANNEL-SECRET']); + $res = $bot->replyMessage( + 'REPLY-TOKEN', + new AudioMessageBuilder('https://example.com/audio.mp4', 12345) + ); + + $this->assertEquals(200, $res->getHTTPStatus()); + $this->assertTrue($res->isSucceeded()); + $this->assertEquals(200, $res->getJSONDecodedBody()['status']); + } + + public function testPushAudio() + { + $mock = function ($testRunner, $httpMethod, $url, $data) { + /** @var \PHPUnit_Framework_TestCase $testRunner */ + $testRunner->assertEquals('POST', $httpMethod); + $testRunner->assertEquals('https://api.line.me/v2/bot/message/push', $url); + + $testRunner->assertEquals('DESTINATION', $data['to']); + $testRunner->assertEquals(1, count($data['messages'])); + $testRunner->assertEquals(MessageType::AUDIO, $data['messages'][0]['type']); + $testRunner->assertEquals('https://example.com/audio.mp4', $data['messages'][0]['originalContentUrl']); + $testRunner->assertEquals(12345, $data['messages'][0]['duration']); + + return ['status' => 200]; + }; + $bot = new LINEBot(new DummyHttpClient($this, $mock), ['channelSecret' => 'CHANNEL-SECRET']); + $res = $bot->pushMessage( + 'DESTINATION', + new AudioMessageBuilder('https://example.com/audio.mp4', 12345) + ); + + $this->assertEquals(200, $res->getHTTPStatus()); + $this->assertTrue($res->isSucceeded()); + $this->assertEquals(200, $res->getJSONDecodedBody()['status']); + } +} diff --git a/tests/LINEBot/SendImageTest.php b/tests/LINEBot/SendImageTest.php new file mode 100644 index 00000000..6525ea7e --- /dev/null +++ b/tests/LINEBot/SendImageTest.php @@ -0,0 +1,79 @@ +assertEquals('POST', $httpMethod); + $testRunner->assertEquals('https://api.line.me/v2/bot/message/reply', $url); + + $testRunner->assertEquals('REPLY-TOKEN', $data['replyToken']); + $testRunner->assertEquals(1, count($data['messages'])); + $testRunner->assertEquals(MessageType::IMAGE, $data['messages'][0]['type']); + $testRunner->assertEquals('https://example.com/image.jpg', $data['messages'][0]['originalContentUrl']); + $testRunner->assertEquals('https://example.com/image_preview.jpg', $data['messages'][0]['previewImageUrl']); + + return ['status' => 200]; + }; + $bot = new LINEBot(new DummyHttpClient($this, $mock), ['channelSecret' => 'CHANNEL-SECRET']); + $res = $bot->replyMessage( + 'REPLY-TOKEN', + new ImageMessageBuilder('https://example.com/image.jpg', 'https://example.com/image_preview.jpg') + ); + + $this->assertEquals(200, $res->getHTTPStatus()); + $this->assertTrue($res->isSucceeded()); + $this->assertEquals(200, $res->getJSONDecodedBody()['status']); + } + + public function testPushImage() + { + $mock = function ($testRunner, $httpMethod, $url, $data) { + /** @var \PHPUnit_Framework_TestCase $testRunner */ + $testRunner->assertEquals('POST', $httpMethod); + $testRunner->assertEquals('https://api.line.me/v2/bot/message/push', $url); + + $testRunner->assertEquals('DESTINATION', $data['to']); + $testRunner->assertEquals(1, count($data['messages'])); + $testRunner->assertEquals(MessageType::IMAGE, $data['messages'][0]['type']); + $testRunner->assertEquals('https://example.com/image.jpg', $data['messages'][0]['originalContentUrl']); + $testRunner->assertEquals('https://example.com/image_preview.jpg', $data['messages'][0]['previewImageUrl']); + + return ['status' => 200]; + }; + $bot = new LINEBot(new DummyHttpClient($this, $mock), ['channelSecret' => 'CHANNEL-SECRET']); + $res = $bot->pushMessage( + 'DESTINATION', + new ImageMessageBuilder('https://example.com/image.jpg', 'https://example.com/image_preview.jpg') + ); + + $this->assertEquals(200, $res->getHTTPStatus()); + $this->assertTrue($res->isSucceeded()); + $this->assertEquals(200, $res->getJSONDecodedBody()['status']); + } +} diff --git a/tests/LINEBot/SendImagemapTest.php b/tests/LINEBot/SendImagemapTest.php new file mode 100644 index 00000000..d9fd924a --- /dev/null +++ b/tests/LINEBot/SendImagemapTest.php @@ -0,0 +1,146 @@ +assertEquals('POST', $httpMethod); + $testRunner->assertEquals('https://api.line.me/v2/bot/message/reply', $url); + + $testRunner->assertEquals('REPLY-TOKEN', $data['replyToken']); + $testRunner->assertEquals(1, count($data['messages'])); + + $message = $data['messages'][0]; + $testRunner->assertEquals(MessageType::IMAGEMAP, $message['type']); + $testRunner->assertEquals('https://example.com/imagemap_base', $message['baseUrl']); + $testRunner->assertEquals('alt test', $message['altText']); + $testRunner->assertEquals(1040, $message['baseSize']['width']); + $testRunner->assertEquals(1040, $message['baseSize']['height']); + + $testRunner->assertEquals(2, count($message['actions'])); + $testRunner->assertEquals(ActionType::URI, $message['actions'][0]['type']); + $testRunner->assertEquals(0, $message['actions'][0]['area']['x']); + $testRunner->assertEquals(0, $message['actions'][0]['area']['y']); + $testRunner->assertEquals(1040, $message['actions'][0]['area']['width']); + $testRunner->assertEquals(520, $message['actions'][0]['area']['height']); + + $testRunner->assertEquals(ActionType::MESSAGE, $message['actions'][1]['type']); + $testRunner->assertEquals(0, $message['actions'][1]['area']['x']); + $testRunner->assertEquals(520, $message['actions'][1]['area']['y']); + $testRunner->assertEquals(1040, $message['actions'][1]['area']['width']); + $testRunner->assertEquals(520, $message['actions'][1]['area']['height']); + + return ['status' => 200]; + }; + $bot = new LINEBot(new DummyHttpClient($this, $mock), ['channelSecret' => 'CHANNEL-SECRET']); + $res = $bot->replyMessage( + 'REPLY-TOKEN', + new ImagemapMessageBuilder( + 'https://example.com/imagemap_base', + 'alt test', + new BaseSizeBuilder(1040, 1040), + [ + new ImagemapUriActionBuilder( + 'https://example.com/foo/bar', + new AreaBuilder(0, 0, 1040, 520) + ), + new ImagemapMessageActionBuilder( + 'Fortune', + new AreaBuilder(0, 520, 1040, 520) + ), + ] + ) + ); + + $this->assertEquals(200, $res->getHTTPStatus()); + $this->assertTrue($res->isSucceeded()); + $this->assertEquals(200, $res->getJSONDecodedBody()['status']); + } + + public function testPushImagemap() + { + $mock = function ($testRunner, $httpMethod, $url, $data) { + /** @var \PHPUnit_Framework_TestCase $testRunner */ + $testRunner->assertEquals('POST', $httpMethod); + $testRunner->assertEquals('https://api.line.me/v2/bot/message/push', $url); + + $testRunner->assertEquals('DESTINATION', $data['to']); + $testRunner->assertEquals(1, count($data['messages'])); + + $message = $data['messages'][0]; + $testRunner->assertEquals(MessageType::IMAGEMAP, $message['type']); + $testRunner->assertEquals('https://example.com/imagemap_base', $message['baseUrl']); + $testRunner->assertEquals('alt test', $message['altText']); + $testRunner->assertEquals(1040, $message['baseSize']['width']); + $testRunner->assertEquals(1040, $message['baseSize']['height']); + + $testRunner->assertEquals(2, count($message['actions'])); + $testRunner->assertEquals(ActionType::URI, $message['actions'][0]['type']); + $testRunner->assertEquals(0, $message['actions'][0]['area']['x']); + $testRunner->assertEquals(0, $message['actions'][0]['area']['y']); + $testRunner->assertEquals(1040, $message['actions'][0]['area']['width']); + $testRunner->assertEquals(520, $message['actions'][0]['area']['height']); + + $testRunner->assertEquals(ActionType::MESSAGE, $message['actions'][1]['type']); + $testRunner->assertEquals(0, $message['actions'][1]['area']['x']); + $testRunner->assertEquals(520, $message['actions'][1]['area']['y']); + $testRunner->assertEquals(1040, $message['actions'][1]['area']['width']); + $testRunner->assertEquals(520, $message['actions'][1]['area']['height']); + + return ['status' => 200]; + }; + $bot = new LINEBot(new DummyHttpClient($this, $mock), ['channelSecret' => 'CHANNEL-SECRET']); + $res = $bot->pushMessage( + 'DESTINATION', + new ImagemapMessageBuilder( + 'https://example.com/imagemap_base', + 'alt test', + new BaseSizeBuilder(1040, 1040), + [ + new ImagemapUriActionBuilder( + 'https://example.com/foo/bar', + new AreaBuilder(0, 0, 1040, 520) + ), + new ImagemapMessageActionBuilder( + 'Fortune', + new AreaBuilder(0, 520, 1040, 520) + ), + ] + ) + ); + + $this->assertEquals(200, $res->getHTTPStatus()); + $this->assertTrue($res->isSucceeded()); + $this->assertEquals(200, $res->getJSONDecodedBody()['status']); + } +} diff --git a/tests/LINEBot/SendLocationTest.php b/tests/LINEBot/SendLocationTest.php new file mode 100644 index 00000000..d5f994e9 --- /dev/null +++ b/tests/LINEBot/SendLocationTest.php @@ -0,0 +1,83 @@ +assertEquals('POST', $httpMethod); + $testRunner->assertEquals('https://api.line.me/v2/bot/message/reply', $url); + + $testRunner->assertEquals('REPLY-TOKEN', $data['replyToken']); + $testRunner->assertEquals(1, count($data['messages'])); + $testRunner->assertEquals(MessageType::LOCATION, $data['messages'][0]['type']); + $testRunner->assertEquals('Location test', $data['messages'][0]['title']); + $testRunner->assertEquals('Tokyo Shibuya', $data['messages'][0]['address']); + $testRunner->assertEquals(35.6566285, $data['messages'][0]['latitude']); + $testRunner->assertEquals(139.6999638, $data['messages'][0]['longitude']); + + return ['status' => 200]; + }; + $bot = new LINEBot(new DummyHttpClient($this, $mock), ['channelSecret' => 'CHANNEL-SECRET']); + $res = $bot->replyMessage( + 'REPLY-TOKEN', + new LocationMessageBuilder('Location test', 'Tokyo Shibuya', 35.6566285, 139.6999638) + ); + + $this->assertEquals(200, $res->getHTTPStatus()); + $this->assertTrue($res->isSucceeded()); + $this->assertEquals(200, $res->getJSONDecodedBody()['status']); + } + + public function testPushLocation() + { + $mock = function ($testRunner, $httpMethod, $url, $data) { + /** @var \PHPUnit_Framework_TestCase $testRunner */ + $testRunner->assertEquals('POST', $httpMethod); + $testRunner->assertEquals('https://api.line.me/v2/bot/message/push', $url); + + $testRunner->assertEquals('DESTINATION', $data['to']); + $testRunner->assertEquals(1, count($data['messages'])); + $testRunner->assertEquals(MessageType::LOCATION, $data['messages'][0]['type']); + $testRunner->assertEquals('Location test', $data['messages'][0]['title']); + $testRunner->assertEquals('Tokyo Shibuya', $data['messages'][0]['address']); + $testRunner->assertEquals(35.6566285, $data['messages'][0]['latitude']); + $testRunner->assertEquals(139.6999638, $data['messages'][0]['longitude']); + + return ['status' => 200]; + }; + $bot = new LINEBot(new DummyHttpClient($this, $mock), ['channelSecret' => 'CHANNEL-SECRET']); + $res = $bot->pushMessage( + 'DESTINATION', + new LocationMessageBuilder('Location test', 'Tokyo Shibuya', 35.6566285, 139.6999638) + ); + + $this->assertEquals(200, $res->getHTTPStatus()); + $this->assertTrue($res->isSucceeded()); + $this->assertEquals(200, $res->getJSONDecodedBody()['status']); + } +} diff --git a/tests/LINEBot/SendMultiMessageTest.php b/tests/LINEBot/SendMultiMessageTest.php new file mode 100644 index 00000000..e0ee6c7a --- /dev/null +++ b/tests/LINEBot/SendMultiMessageTest.php @@ -0,0 +1,88 @@ +assertEquals('POST', $httpMethod); + $testRunner->assertEquals('https://api.line.me/v2/bot/message/reply', $url); + + $testRunner->assertEquals('REPLY-TOKEN', $data['replyToken']); + $testRunner->assertEquals(3, count($data['messages'])); + $testRunner->assertEquals(MessageType::TEXT, $data['messages'][0]['type']); + $testRunner->assertEquals('text1', $data['messages'][0]['text']); + $testRunner->assertEquals(MessageType::TEXT, $data['messages'][1]['type']); + $testRunner->assertEquals('text2', $data['messages'][1]['text']); + $testRunner->assertEquals(MessageType::AUDIO, $data['messages'][2]['type']); + + return ['status' => 200]; + }; + + $bot = new LINEBot(new DummyHttpClient($this, $mock), ['channelSecret' => 'CHANNEL-SECRET']); + $res = $bot->replyMessage( + 'REPLY-TOKEN', + (new LINEBot\MessageBuilder\MultiMessageBuilder())->add(new TextMessageBuilder('text1', 'text2')) + ->add(new AudioMessageBuilder('https://example.com/audio.mp4', 1000)) + ); + + $this->assertEquals(200, $res->getHTTPStatus()); + $this->assertTrue($res->isSucceeded()); + $this->assertEquals(200, $res->getJSONDecodedBody()['status']); + } + + public function testPushMultiMessage() + { + $mock = function ($testRunner, $httpMethod, $url, $data) { + /** @var \PHPUnit_Framework_TestCase $testRunner */ + $testRunner->assertEquals('POST', $httpMethod); + $testRunner->assertEquals('https://api.line.me/v2/bot/message/push', $url); + + $testRunner->assertEquals('DESTINATION', $data['to']); + $testRunner->assertEquals(3, count($data['messages'])); + $testRunner->assertEquals(MessageType::TEXT, $data['messages'][0]['type']); + $testRunner->assertEquals('text1', $data['messages'][0]['text']); + $testRunner->assertEquals(MessageType::TEXT, $data['messages'][1]['type']); + $testRunner->assertEquals('text2', $data['messages'][1]['text']); + $testRunner->assertEquals(MessageType::AUDIO, $data['messages'][2]['type']); + + return ['status' => 200]; + }; + + $bot = new LINEBot(new DummyHttpClient($this, $mock), ['channelSecret' => 'CHANNEL-SECRET']); + $res = $bot->pushMessage( + 'DESTINATION', + (new LINEBot\MessageBuilder\MultiMessageBuilder())->add(new TextMessageBuilder('text1', 'text2')) + ->add(new AudioMessageBuilder('https://example.com/audio.mp4', 1000)) + ); + + $this->assertEquals(200, $res->getHTTPStatus()); + $this->assertTrue($res->isSucceeded()); + $this->assertEquals(200, $res->getJSONDecodedBody()['status']); + } +} diff --git a/tests/LINEBot/SendStickerTest.php b/tests/LINEBot/SendStickerTest.php new file mode 100644 index 00000000..a22bd06c --- /dev/null +++ b/tests/LINEBot/SendStickerTest.php @@ -0,0 +1,73 @@ +assertEquals('POST', $httpMethod); + $testRunner->assertEquals('https://api.line.me/v2/bot/message/reply', $url); + + $testRunner->assertEquals('REPLY-TOKEN', $data['replyToken']); + $testRunner->assertEquals(1, count($data['messages'])); + $testRunner->assertEquals(MessageType::STICKER, $data['messages'][0]['type']); + $testRunner->assertEquals('1', $data['messages'][0]['packageId']); + $testRunner->assertEquals('2', $data['messages'][0]['stickerId']); + + return ['status' => 200]; + }; + $bot = new LINEBot(new DummyHttpClient($this, $mock), ['channelSecret' => 'CHANNEL-SECRET']); + $res = $bot->replyMessage('REPLY-TOKEN', new StickerMessageBuilder('1', '2')); + + $this->assertEquals(200, $res->getHTTPStatus()); + $this->assertTrue($res->isSucceeded()); + $this->assertEquals(200, $res->getJSONDecodedBody()['status']); + } + + public function testPushSticker() + { + $mock = function ($testRunner, $httpMethod, $url, $data) { + /** @var \PHPUnit_Framework_TestCase $testRunner */ + $testRunner->assertEquals('POST', $httpMethod); + $testRunner->assertEquals('https://api.line.me/v2/bot/message/push', $url); + + $testRunner->assertEquals('DESTINATION', $data['to']); + $testRunner->assertEquals(1, count($data['messages'])); + $testRunner->assertEquals(MessageType::STICKER, $data['messages'][0]['type']); + $testRunner->assertEquals('1', $data['messages'][0]['packageId']); + $testRunner->assertEquals('2', $data['messages'][0]['stickerId']); + + return ['status' => 200]; + }; + $bot = new LINEBot(new DummyHttpClient($this, $mock), ['channelSecret' => 'CHANNEL-SECRET']); + $res = $bot->pushMessage('DESTINATION', new StickerMessageBuilder('1', '2')); + + $this->assertEquals(200, $res->getHTTPStatus()); + $this->assertTrue($res->isSucceeded()); + $this->assertEquals(200, $res->getJSONDecodedBody()['status']); + } +} diff --git a/tests/LINEBot/SendTemplateTest.php b/tests/LINEBot/SendTemplateTest.php new file mode 100644 index 00000000..6a27226e --- /dev/null +++ b/tests/LINEBot/SendTemplateTest.php @@ -0,0 +1,150 @@ +assertEquals('POST', $httpMethod); + $testRunner->assertEquals('https://api.line.me/v2/bot/message/reply', $url); + + $testRunner->assertEquals('REPLY-TOKEN', $data['replyToken']); + $testRunner->assertEquals(1, count($data['messages'])); + + $message = $data['messages'][0]; + $testRunner->assertEquals(MessageType::TEMPLATE, $message['type']); + $testRunner->assertEquals('alt test', $message['altText']); + + $template = $message['template']; + $testRunner->assertEquals(TemplateType::BUTTONS, $template['type']); + $testRunner->assertEquals('button title', $template['title']); + $testRunner->assertEquals('button button', $template['text']); + $testRunner->assertEquals('https://example.com/thumbnail.jpg', $template['thumbnailImageUrl']); + + $actions = $template['actions']; + $testRunner->assertEquals(3, count($actions)); + $testRunner->assertEquals(ActionType::POSTBACK, $actions[0]['type']); + $testRunner->assertEquals('postback label', $actions[0]['label']); + $testRunner->assertEquals('post=back', $actions[0]['data']); + + $testRunner->assertEquals(ActionType::MESSAGE, $actions[1]['type']); + $testRunner->assertEquals('message label', $actions[1]['label']); + $testRunner->assertEquals('test message', $actions[1]['text']); + + $testRunner->assertEquals(ActionType::URI, $actions[2]['type']); + $testRunner->assertEquals('uri label', $actions[2]['label']); + $testRunner->assertEquals('https://example.com', $actions[2]['uri']); + + return ['status' => 200]; + }; + $bot = new LINEBot(new DummyHttpClient($this, $mock), ['channelSecret' => 'CHANNEL-SECRET']); + $res = $bot->replyMessage( + 'REPLY-TOKEN', + new LINEBot\MessageBuilder\TemplateMessageBuilder( + 'alt test', + new ButtonTemplateBuilder( + 'button title', + 'button button', + 'https://example.com/thumbnail.jpg', + [ + new PostbackTemplateActionBuilder('postback label', 'post=back'), + new MessageTemplateActionBuilder('message label', 'test message'), + new UriTemplateActionBuilder('uri label', 'https://example.com'), + ] + ) + ) + ); + + $this->assertEquals(200, $res->getHTTPStatus()); + $this->assertTrue($res->isSucceeded()); + $this->assertEquals(200, $res->getJSONDecodedBody()['status']); + } + + public function testPushTemplate() + { + $mock = function ($testRunner, $httpMethod, $url, $data) { + /** @var \PHPUnit_Framework_TestCase $testRunner */ + $testRunner->assertEquals('POST', $httpMethod); + $testRunner->assertEquals('https://api.line.me/v2/bot/message/push', $url); + + $testRunner->assertEquals('DESTINATION', $data['to']); + $testRunner->assertEquals(1, count($data['messages'])); + + $message = $data['messages'][0]; + $testRunner->assertEquals(MessageType::TEMPLATE, $message['type']); + $testRunner->assertEquals('alt test', $message['altText']); + + $template = $message['template']; + $testRunner->assertEquals(TemplateType::BUTTONS, $template['type']); + $testRunner->assertEquals('button title', $template['title']); + $testRunner->assertEquals('button button', $template['text']); + $testRunner->assertEquals('https://example.com/thumbnail.jpg', $template['thumbnailImageUrl']); + + $actions = $template['actions']; + $testRunner->assertEquals(3, count($actions)); + $testRunner->assertEquals(ActionType::POSTBACK, $actions[0]['type']); + $testRunner->assertEquals('postback label', $actions[0]['label']); + $testRunner->assertEquals('post=back', $actions[0]['data']); + + $testRunner->assertEquals(ActionType::MESSAGE, $actions[1]['type']); + $testRunner->assertEquals('message label', $actions[1]['label']); + $testRunner->assertEquals('test message', $actions[1]['text']); + + $testRunner->assertEquals(ActionType::URI, $actions[2]['type']); + $testRunner->assertEquals('uri label', $actions[2]['label']); + $testRunner->assertEquals('https://example.com', $actions[2]['uri']); + + return ['status' => 200]; + }; + $bot = new LINEBot(new DummyHttpClient($this, $mock), ['channelSecret' => 'CHANNEL-SECRET']); + $res = $bot->pushMessage( + 'DESTINATION', + new LINEBot\MessageBuilder\TemplateMessageBuilder( + 'alt test', + new ButtonTemplateBuilder( + 'button title', + 'button button', + 'https://example.com/thumbnail.jpg', + [ + new PostbackTemplateActionBuilder('postback label', 'post=back'), + new MessageTemplateActionBuilder('message label', 'test message'), + new UriTemplateActionBuilder('uri label', 'https://example.com'), + ] + ) + ) + ); + + $this->assertEquals(200, $res->getHTTPStatus()); + $this->assertTrue($res->isSucceeded()); + $this->assertEquals(200, $res->getJSONDecodedBody()['status']); + } +} diff --git a/tests/LINEBot/SendTextTest.php b/tests/LINEBot/SendTextTest.php new file mode 100644 index 00000000..4b96a928 --- /dev/null +++ b/tests/LINEBot/SendTextTest.php @@ -0,0 +1,152 @@ +assertEquals('POST', $httpMethod); + $testRunner->assertEquals('https://api.line.me/v2/bot/message/reply', $url); + + $testRunner->assertEquals('REPLY-TOKEN', $data['replyToken']); + $testRunner->assertEquals(1, count($data['messages'])); + $testRunner->assertEquals(MessageType::TEXT, $data['messages'][0]['type']); + $testRunner->assertEquals('test text', $data['messages'][0]['text']); + + return ['status' => 200]; + }; + $bot = new LINEBot(new DummyHttpClient($this, $mock), ['channelSecret' => 'CHANNEL-SECRET']); + $res = $bot->replyText('REPLY-TOKEN', 'test text'); + + $this->assertEquals(200, $res->getHTTPStatus()); + $this->assertTrue($res->isSucceeded()); + $this->assertEquals(200, $res->getJSONDecodedBody()['status']); + } + + public function testReplyMultiTexts() + { + $mock = function ($testRunner, $httpMethod, $url, $data) { + /** @var \PHPUnit_Framework_TestCase $testRunner */ + $testRunner->assertEquals('POST', $httpMethod); + $testRunner->assertEquals('https://api.line.me/v2/bot/message/reply', $url); + + $testRunner->assertEquals('REPLY-TOKEN', $data['replyToken']); + $testRunner->assertEquals(3, count($data['messages'])); + $testRunner->assertEquals(MessageType::TEXT, $data['messages'][0]['type']); + $testRunner->assertEquals('test text1', $data['messages'][0]['text']); + $testRunner->assertEquals(MessageType::TEXT, $data['messages'][1]['type']); + $testRunner->assertEquals('test text2', $data['messages'][1]['text']); + $testRunner->assertEquals(MessageType::TEXT, $data['messages'][2]['type']); + $testRunner->assertEquals('test text3', $data['messages'][2]['text']); + + return ['status' => 200]; + }; + $bot = new LINEBot(new DummyHttpClient($this, $mock), ['channelSecret' => 'CHANNEL-SECRET']); + $res = $bot->replyText('REPLY-TOKEN', 'test text1', 'test text2', 'test text3'); + + $this->assertEquals(200, $res->getHTTPStatus()); + $this->assertTrue($res->isSucceeded()); + $this->assertEquals(200, $res->getJSONDecodedBody()['status']); + } + + public function testReplyMessageWithSingleText() + { + $mock = function ($testRunner, $httpMethod, $url, $data) { + /** @var \PHPUnit_Framework_TestCase $testRunner */ + $testRunner->assertEquals('POST', $httpMethod); + $testRunner->assertEquals('https://api.line.me/v2/bot/message/reply', $url); + + $testRunner->assertEquals('REPLY-TOKEN', $data['replyToken']); + $testRunner->assertEquals(1, count($data['messages'])); + $testRunner->assertEquals(MessageType::TEXT, $data['messages'][0]['type']); + $testRunner->assertEquals('test text', $data['messages'][0]['text']); + + return ['status' => 200]; + }; + + $bot = new LINEBot(new DummyHttpClient($this, $mock), ['channelSecret' => 'CHANNEL-SECRET']); + $res = $bot->replyMessage('REPLY-TOKEN', new TextMessageBuilder('test text')); + + $this->assertEquals(200, $res->getHTTPStatus()); + $this->assertTrue($res->isSucceeded()); + $this->assertEquals(200, $res->getJSONDecodedBody()['status']); + } + + public function testReplyMessageWithMultiTexts() + { + $mock = function ($testRunner, $httpMethod, $url, $data) { + /** @var \PHPUnit_Framework_TestCase $testRunner */ + $testRunner->assertEquals('POST', $httpMethod); + $testRunner->assertEquals('https://api.line.me/v2/bot/message/reply', $url); + + $testRunner->assertEquals('REPLY-TOKEN', $data['replyToken']); + $testRunner->assertEquals(3, count($data['messages'])); + $testRunner->assertEquals(MessageType::TEXT, $data['messages'][0]['type']); + $testRunner->assertEquals('test text1', $data['messages'][0]['text']); + $testRunner->assertEquals(MessageType::TEXT, $data['messages'][1]['type']); + $testRunner->assertEquals('test text2', $data['messages'][1]['text']); + $testRunner->assertEquals(MessageType::TEXT, $data['messages'][2]['type']); + $testRunner->assertEquals('test text3', $data['messages'][2]['text']); + + return ['status' => 200]; + }; + + $bot = new LINEBot(new DummyHttpClient($this, $mock), ['channelSecret' => 'CHANNEL-SECRET']); + $res = $bot->replyMessage('REPLY-TOKEN', new TextMessageBuilder('test text1', 'test text2', 'test text3')); + + $this->assertEquals(200, $res->getHTTPStatus()); + $this->assertTrue($res->isSucceeded()); + $this->assertEquals(200, $res->getJSONDecodedBody()['status']); + } + + public function testPushTextMessage() + { + $mock = function ($testRunner, $httpMethod, $url, $data) { + /** @var \PHPUnit_Framework_TestCase $testRunner */ + $testRunner->assertEquals('POST', $httpMethod); + $testRunner->assertEquals('https://api.line.me/v2/bot/message/push', $url); + + $testRunner->assertEquals('DESTINATION', $data['to']); + $testRunner->assertEquals(3, count($data['messages'])); + $testRunner->assertEquals(MessageType::TEXT, $data['messages'][0]['type']); + $testRunner->assertEquals('test text1', $data['messages'][0]['text']); + $testRunner->assertEquals(MessageType::TEXT, $data['messages'][1]['type']); + $testRunner->assertEquals('test text2', $data['messages'][1]['text']); + $testRunner->assertEquals(MessageType::TEXT, $data['messages'][2]['type']); + $testRunner->assertEquals('test text3', $data['messages'][2]['text']); + + return ['status' => 200]; + }; + + $bot = new LINEBot(new DummyHttpClient($this, $mock), ['channelSecret' => 'CHANNEL-SECRET']); + $res = $bot->pushMessage('DESTINATION', new TextMessageBuilder('test text1', 'test text2', 'test text3')); + + $this->assertEquals(200, $res->getHTTPStatus()); + $this->assertTrue($res->isSucceeded()); + $this->assertEquals(200, $res->getJSONDecodedBody()['status']); + } +} diff --git a/tests/LINEBot/SendVideoTest.php b/tests/LINEBot/SendVideoTest.php new file mode 100644 index 00000000..0f43fdea --- /dev/null +++ b/tests/LINEBot/SendVideoTest.php @@ -0,0 +1,79 @@ +assertEquals('POST', $httpMethod); + $testRunner->assertEquals('https://api.line.me/v2/bot/message/reply', $url); + + $testRunner->assertEquals('REPLY-TOKEN', $data['replyToken']); + $testRunner->assertEquals(1, count($data['messages'])); + $testRunner->assertEquals(MessageType::VIDEO, $data['messages'][0]['type']); + $testRunner->assertEquals('https://example.com/video.mp4', $data['messages'][0]['originalContentUrl']); + $testRunner->assertEquals('https://example.com/video_preview.jpg', $data['messages'][0]['previewImageUrl']); + + return ['status' => 200]; + }; + $bot = new LINEBot(new DummyHttpClient($this, $mock), ['channelSecret' => 'CHANNEL-SECRET']); + $res = $bot->replyMessage( + 'REPLY-TOKEN', + new VideoMessageBuilder('https://example.com/video.mp4', 'https://example.com/video_preview.jpg') + ); + + $this->assertEquals(200, $res->getHTTPStatus()); + $this->assertTrue($res->isSucceeded()); + $this->assertEquals(200, $res->getJSONDecodedBody()['status']); + } + + public function testPushVideo() + { + $mock = function ($testRunner, $httpMethod, $url, $data) { + /** @var \PHPUnit_Framework_TestCase $testRunner */ + $testRunner->assertEquals('POST', $httpMethod); + $testRunner->assertEquals('https://api.line.me/v2/bot/message/push', $url); + + $testRunner->assertEquals('DESTINATION', $data['to']); + $testRunner->assertEquals(1, count($data['messages'])); + $testRunner->assertEquals(MessageType::VIDEO, $data['messages'][0]['type']); + $testRunner->assertEquals('https://example.com/video.mp4', $data['messages'][0]['originalContentUrl']); + $testRunner->assertEquals('https://example.com/video_preview.jpg', $data['messages'][0]['previewImageUrl']); + + return ['status' => 200]; + }; + $bot = new LINEBot(new DummyHttpClient($this, $mock), ['channelSecret' => 'CHANNEL-SECRET']); + $res = $bot->pushMessage( + 'DESTINATION', + new VideoMessageBuilder('https://example.com/video.mp4', 'https://example.com/video_preview.jpg') + ); + + $this->assertEquals(200, $res->getHTTPStatus()); + $this->assertTrue($res->isSucceeded()); + $this->assertEquals(200, $res->getJSONDecodedBody()['status']); + } +} diff --git a/tests/LINEBot/SignatureValidationTest.php b/tests/LINEBot/SignatureValidationTest.php deleted file mode 100644 index d67737a3..00000000 --- a/tests/LINEBot/SignatureValidationTest.php +++ /dev/null @@ -1,110 +0,0 @@ - '1441301333', - 'channelSecret' => 'testsecret', - 'channelMid' => 'u0a556cffd4da0dd89c94fb36e36e1cdc', - ]; - private static $json = <<assertTrue(SignatureValidator::validateSignature( - $this::$json, - $this::$config['channelSecret'], - 'kPXp0nPWSzfWAapWHiesbcztpKnXJoX8krCa1CcTghk=' - )); - $this->assertFalse(SignatureValidator::validateSignature( - $this::$json, - $this::$config['channelSecret'], - 'XXX' - )); - } - - public function testValidateSignatureByReceive() - { - $reqs = ReceiveFactory::createFromJSON($this::$config, $this::$json); - /** @var Text $req */ - $req = $reqs[0]; - $this->assertTrue($req->validateSignature($this::$json, 'kPXp0nPWSzfWAapWHiesbcztpKnXJoX8krCa1CcTghk=')); - $this->assertFalse($req->validateSignature($this::$json, 'XXX')); - } - - public function testValidateSignatureByBot() - { - $bot = new LINEBot($this::$config, new GuzzleHTTPClient($this::$config)); - $this->assertTrue($bot->validateSignature($this::$json, 'kPXp0nPWSzfWAapWHiesbcztpKnXJoX8krCa1CcTghk=')); - $this->assertFalse($bot->validateSignature($this::$json, 'XXX')); - } - - /** - * @expectedException \LINE\LINEBot\Exception\InvalidSignatureException - */ - public function testValidateSignatureWithEmptySignature() - { - SignatureValidator::validateSignature($this::$json, $this::$config['channelSecret'], ''); - } -} \ No newline at end of file diff --git a/tests/LINEBot/SignatureValidatorTest.php b/tests/LINEBot/SignatureValidatorTest.php new file mode 100644 index 00000000..2193dae9 --- /dev/null +++ b/tests/LINEBot/SignatureValidatorTest.php @@ -0,0 +1,190 @@ +assertTrue(SignatureValidator::validateSignature( + $this::$json, + $this::$channelSecret, + 'Nq7AExtg27CQRfM3ngKtQxtVeIM/757ZTyDOrxQtWNg=' + )); + $this->assertFalse(SignatureValidator::validateSignature( + $this::$json, + $this::$channelSecret, + 'deadbeef' + )); + } +} diff --git a/tests/LINEBot/Util/DummyHttpClient.php b/tests/LINEBot/Util/DummyHttpClient.php new file mode 100644 index 00000000..172c2135 --- /dev/null +++ b/tests/LINEBot/Util/DummyHttpClient.php @@ -0,0 +1,57 @@ +testRunner = $testRunner; + $this->mock = $mock; + } + + /** + * @param string $url + * @return Response + */ + public function get($url) + { + $ret = call_user_func($this->mock, $this->testRunner, 'GET', $url, []); + return new Response(200, json_encode($ret)); + } + + /** + * @param string $url + * @param array $data + * @return Response + */ + public function post($url, array $data) + { + $ret = call_user_func($this->mock, $this->testRunner, 'POST', $url, $data); + return new Response(200, json_encode($ret)); + } +} diff --git a/tests/LINEBotTest.php b/tests/LINEBotTest.php deleted file mode 100644 index 73ecca47..00000000 --- a/tests/LINEBotTest.php +++ /dev/null @@ -1,73 +0,0 @@ - '1000000000', - 'channelSecret' => 'testsecret', - 'channelMid' => 'TEST_MID', - ]; - - /** - * @expectedException \LINE\LINEBot\Exception\LINEBotAPIException - */ - public function testLINEBotAPIExceptionCausedByEmptyResponseBody() - { - $mock = new Mock([ - new Response(200, []), // missing body - ]); - - $emitter = new Emitter(); - $emitter->attach($mock); - - $sdk = new LINEBot( - $this::$config, - new GuzzleHTTPClient(array_merge($this::$config, ['emitter' => $emitter])) - ); - - $sdk->sendText(['DUMMY_MID'], 'hello!'); - } - - /** - * @expectedException \LINE\LINEBot\Exception\LINEBotAPIException - */ - public function textLINEBotAPIExceptionCausedByInvalidResponseBody() - { - $mock = new Mock([ - new Response(200, [], Stream::factory('I AM NOT A JSON')), // not JSON - ]); - - $emitter = new Emitter(); - $emitter->attach($mock); - - $sdk = new LINEBot( - $this::$config, - new GuzzleHTTPClient(array_merge($this::$config, ['emitter' => $emitter])) - ); - - $sdk->sendText(['DUMMY_MID'], 'hello!'); - } -} diff --git a/tests/bootstrap.php b/tests/bootstrap.php index bb1bb515..e4543911 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -1,4 +1,5 @@