├── tests ├── Assets │ ├── document.txt │ ├── image.jpg │ ├── voice.ogg │ └── voice.wav ├── Telegram │ ├── MessengerDoubler.php │ ├── MessengerEventsTest.php │ └── MessengerTest.php ├── HelpersTest.php ├── EventControllerTest.php ├── ScreenItems │ ├── MessageTest.php │ ├── VoiceTest.php │ ├── ButtonTest.php │ └── FileTest.php ├── RequestTest.php ├── MessengerUserTest.php ├── MessengerPoolTest.php └── MessengerScreenTest.php ├── .bettercodehub.yml ├── src ├── Exceptions │ ├── TargetUserException.php │ ├── AccessTokenException.php │ └── AttachmentNotFoundException.php ├── MessengerWithTokenInterface.php ├── MessengerEventsInterface.php ├── ScreenItems │ ├── ScreenItemInterface.php │ ├── Message.php │ ├── Voice.php │ ├── Button.php │ └── File.php ├── Helpers.php ├── EventController.php ├── MessengerInterface.php ├── Request.php ├── MessengerUser.php ├── MessengerPool.php ├── Telegram │ ├── MessengerEvents.php │ └── Messenger.php └── MessengerScreen.php ├── .gitignore ├── .travis.yml ├── phpunit.xml.dist ├── composer.json ├── LICENSE └── README.md /tests/Assets/document.txt: -------------------------------------------------------------------------------- 1 | Hello, world -------------------------------------------------------------------------------- /.bettercodehub.yml: -------------------------------------------------------------------------------- 1 | component_depth: 2 2 | languages: 3 | - php -------------------------------------------------------------------------------- /tests/Assets/image.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/he110/communication-tools/HEAD/tests/Assets/image.jpg -------------------------------------------------------------------------------- /tests/Assets/voice.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/he110/communication-tools/HEAD/tests/Assets/voice.ogg -------------------------------------------------------------------------------- /tests/Assets/voice.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/he110/communication-tools/HEAD/tests/Assets/voice.wav -------------------------------------------------------------------------------- /src/Exceptions/TargetUserException.php: -------------------------------------------------------------------------------- 1 | ./cc-test-reporter' 8 | - 'chmod +x ./cc-test-reporter' 9 | - './cc-test-reporter before-build' 10 | 11 | after_script: 12 | - './cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT' 13 | 14 | after_success: 15 | - 'bash <(curl -s https://codecov.io/bash)' -------------------------------------------------------------------------------- /src/MessengerWithTokenInterface.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | tests/ 7 | 8 | 9 | 10 | 11 | 12 | src/ 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /tests/Telegram/MessengerDoubler.php: -------------------------------------------------------------------------------- 1 | data = $data; 26 | return $this; 27 | } 28 | 29 | protected function getPhpInput(): string 30 | { 31 | return $this->data; 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /src/Helpers.php: -------------------------------------------------------------------------------- 1 | =7.1", 17 | "telegram-bot/api": "^2.3", 18 | "ext-curl": "*" 19 | }, 20 | "require-dev": { 21 | "phpunit/phpunit": "^8" 22 | }, 23 | "autoload": { 24 | "psr-4": {"He110\\CommunicationTools\\": "src/"}, 25 | "exclude-from-classmap": [ 26 | "tests/" 27 | ] 28 | }, 29 | "autoload-dev": { 30 | "psr-4": {"He110\\CommunicationToolsTests\\": "tests/"} 31 | }, 32 | "scripts": { 33 | "test": [ 34 | "phpunit" 35 | ] 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Ilya S. Zobenko 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/HelpersTest.php: -------------------------------------------------------------------------------- 1 | assertCount(3, $array); 32 | $this->assertEquals($array[1], $insert); 33 | 34 | $array = [ 35 | "first" => 1, 36 | "second" => 2 37 | ]; 38 | 39 | Helpers::array_insert($array, "second", [$insert]); 40 | 41 | $this->assertCount(3, $array); 42 | $this->assertEquals([ 43 | "first" => 1, 44 | 0 => $insert, 45 | "second" => 2 46 | ], $array); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /tests/EventControllerTest.php: -------------------------------------------------------------------------------- 1 | addEvent("test", function () { echo "TEST"; }); 23 | $another = EventController::getInstance(); 24 | $this->assertEquals($eventController, $another); 25 | } 26 | 27 | /** 28 | * @covers \He110\CommunicationTools\EventController::addEvent() 29 | * @covers \He110\CommunicationTools\EventController::getEvent() 30 | */ 31 | public function testAddEvent() 32 | { 33 | $controller = EventController::getInstance(); 34 | $key = "telegram_onMessage"; 35 | $controller->addEvent($key, function() { 36 | echo __METHOD__; 37 | }); 38 | 39 | $closure = $controller->getEvent($key); 40 | $this->assertIsCallable($closure); 41 | 42 | $this->isNull($controller->getEvent("not_existed")); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/EventController.php: -------------------------------------------------------------------------------- 1 | events[$key] = $closure; 38 | } 39 | 40 | /** 41 | * @param string $key 42 | * @return \Closure|null 43 | */ 44 | public function getEvent(string $key): ?\Closure 45 | { 46 | return isset($this->events[$key]) && is_callable($this->events[$key]) ? $this->events[$key] : null; 47 | } 48 | 49 | // @codeCoverageIgnoreStart 50 | private function __construct() 51 | { 52 | } 53 | 54 | private function __clone() 55 | { 56 | } 57 | 58 | private function __wakeup() 59 | { 60 | } 61 | // @codeCoverageIgnoreEnd 62 | } -------------------------------------------------------------------------------- /src/ScreenItems/Message.php: -------------------------------------------------------------------------------- 1 | text ?? ""; 23 | } 24 | 25 | /** 26 | * @param string $text 27 | * @return Message 28 | */ 29 | public function setText(string $text): self 30 | { 31 | $this->text = $text; 32 | return $this; 33 | } 34 | 35 | /** 36 | * @return string 37 | */ 38 | public function __toString(): string 39 | { 40 | return $this->getText(); 41 | } 42 | 43 | /** 44 | * {@inheritdoc} 45 | */ 46 | public function toArray(): array 47 | { 48 | return [ 49 | "text" => $this->getText() 50 | ]; 51 | } 52 | 53 | /** 54 | * {@inheritdoc} 55 | */ 56 | public function fromArray(array $data) 57 | { 58 | foreach($data as $key=>$value) { 59 | $methodName = "set".ucfirst($key); 60 | if (method_exists($this, $methodName) && is_callable([$this, $methodName])) 61 | $this->{$methodName}($value); 62 | } 63 | return $this; 64 | } 65 | 66 | /** 67 | * {@inheritdoc} 68 | */ 69 | static public function create(array $config) 70 | { 71 | $o = new Message(); 72 | return $o->fromArray($config); 73 | } 74 | 75 | 76 | } -------------------------------------------------------------------------------- /src/ScreenItems/Voice.php: -------------------------------------------------------------------------------- 1 | text ?? ""; 25 | } 26 | 27 | /** 28 | * @param string $text 29 | * @return Voice 30 | */ 31 | public function setText(string $text): self 32 | { 33 | $this->text = $text; 34 | return $this; 35 | } 36 | 37 | /** 38 | * @return string|null 39 | */ 40 | public function getPath(): ?string 41 | { 42 | return $this->path ?? null; 43 | } 44 | 45 | /** 46 | * @param string $path 47 | * @return Voice 48 | */ 49 | public function setPath(string $path): self 50 | { 51 | $this->path = $path; 52 | return $this; 53 | } 54 | 55 | /** 56 | * @return array 57 | */ 58 | public function toArray(): array 59 | { 60 | return array( 61 | "path" => $this->getPath(), 62 | "text" => $this->getText() 63 | ); 64 | } 65 | 66 | /** 67 | * @param array $data 68 | * @return $this 69 | */ 70 | public function fromArray(array $data) 71 | { 72 | foreach($data as $key=>$value) { 73 | $methodName = "set".ucfirst($key); 74 | if (method_exists($this, $methodName) && is_callable([$this, $methodName])) 75 | $this->{$methodName}($value); 76 | } 77 | return $this; 78 | } 79 | 80 | /** 81 | * @param array $config 82 | * @return Voice 83 | */ 84 | static public function create(array $config) 85 | { 86 | return (new Voice())->fromArray($config); 87 | } 88 | 89 | /** 90 | * @return string 91 | */ 92 | public function __toString(): string 93 | { 94 | return $this->getText(); 95 | } 96 | 97 | } -------------------------------------------------------------------------------- /src/MessengerInterface.php: -------------------------------------------------------------------------------- 1 | assertEmpty($this->message->getText()); 26 | $this->message->setText(__METHOD__); 27 | $this->assertEquals(__METHOD__, $this->message->getText()); 28 | } 29 | 30 | /** 31 | * @covers \He110\CommunicationTools\ScreenItems\Message::fromArray() 32 | * @covers \He110\CommunicationTools\ScreenItems\Message::getText() 33 | */ 34 | public function testFromArray() 35 | { 36 | $this->assertEmpty($this->message->getText()); 37 | $this->message->fromArray(["text" => __METHOD__]); 38 | $this->assertEquals(__METHOD__, $this->message->getText()); 39 | } 40 | 41 | /** 42 | * @covers \He110\CommunicationTools\ScreenItems\Message::create() 43 | */ 44 | public function testCreate() 45 | { 46 | $ob = Message::create(["text" => __METHOD__]); 47 | $this->assertNotEquals($this->message, $ob); 48 | $this->assertEquals(Message::class, get_class($ob)); 49 | $this->assertEquals(__METHOD__, $ob->getText()); 50 | } 51 | 52 | /** 53 | * @covers \He110\CommunicationTools\ScreenItems\Message::__toString() 54 | */ 55 | public function test__toString() 56 | { 57 | $this->assertEmpty((string)$this->message); 58 | $this->message->setText(__METHOD__); 59 | $this->assertEquals(__METHOD__, (string)$this->message); 60 | } 61 | 62 | /** 63 | * @covers \He110\CommunicationTools\ScreenItems\Message::toArray() 64 | */ 65 | public function testToArray() 66 | { 67 | $this->message->setText(__METHOD__); 68 | $this->assertArrayHasKey("text", $this->message->toArray()); 69 | $this->assertEquals(__METHOD__, $this->message->toArray()["text"]); 70 | } 71 | 72 | public function setUp(): void 73 | { 74 | $this->message = new Message(); 75 | } 76 | 77 | public function tearDown(): void 78 | { 79 | $this->message = null; 80 | unset($this->message); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/Request.php: -------------------------------------------------------------------------------- 1 | user; 39 | } 40 | 41 | /** 42 | * @param MessengerUser|null $user 43 | * @return Request 44 | */ 45 | public function setUser(?MessengerUser $user): self 46 | { 47 | $this->user = $user; 48 | return $this; 49 | } 50 | 51 | 52 | 53 | /** 54 | * @return string|null 55 | */ 56 | public function getType(): ?string 57 | { 58 | return $this->type; 59 | } 60 | 61 | /** 62 | * @param string $type 63 | * @return Request 64 | */ 65 | public function setType(string $type): self 66 | { 67 | $this->type = $type; 68 | return $this; 69 | } 70 | 71 | /** 72 | * @return string 73 | */ 74 | public function getMessage(): string 75 | { 76 | return $this->message ?? ""; 77 | } 78 | 79 | /** 80 | * @param string $message 81 | * @return Request 82 | */ 83 | public function setMessage(string $message): self 84 | { 85 | $this->message = $message; 86 | return $this; 87 | } 88 | 89 | /** 90 | * @return string|null 91 | */ 92 | public function getPath(): ?string 93 | { 94 | return $this->path; 95 | } 96 | 97 | /** 98 | * @param string $path 99 | * @return Request 100 | */ 101 | public function setPath(string $path): self 102 | { 103 | $this->path = $path; 104 | return $this; 105 | } 106 | 107 | /** 108 | * @return null|string 109 | */ 110 | public function getPayload(): ?string 111 | { 112 | return $this->payload; 113 | } 114 | 115 | /** 116 | * @param null|string $payload 117 | * @return Request 118 | */ 119 | public function setPayload(?string $payload): self 120 | { 121 | $this->payload = $payload; 122 | return $this; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /tests/RequestTest.php: -------------------------------------------------------------------------------- 1 | assertNull($this->request->getPath()); 27 | $this->request->setPath(__METHOD__); 28 | $this->assertEquals(__METHOD__, $this->request->getPath()); 29 | } 30 | 31 | /** 32 | * @covers \He110\CommunicationTools\Request::setUser() 33 | * @covers \He110\CommunicationTools\Request::getUser() 34 | */ 35 | public function testSetUser() 36 | { 37 | $this->assertNull($this->request->getUser()); 38 | $user = new MessengerUser(); 39 | $user->setFirstName("Ivan"); 40 | $user->setLastName("Ivanov"); 41 | $this->request->setUser($user); 42 | $this->assertEquals($user, $this->request->getUser()); 43 | $this->assertEquals("Ivan Ivanov", (string)$this->request->getUser()); 44 | } 45 | 46 | /** 47 | * @covers \He110\CommunicationTools\Request::setType() 48 | * @covers \He110\CommunicationTools\Request::getType() 49 | */ 50 | public function testSetType() 51 | { 52 | $this->assertNull($this->request->getType()); 53 | $this->request->setType(__METHOD__); 54 | $this->assertEquals(__METHOD__, $this->request->getType()); 55 | } 56 | 57 | /** 58 | * @covers \He110\CommunicationTools\Request::setMessage() 59 | * @covers \He110\CommunicationTools\Request::getMessage() 60 | */ 61 | public function testSetMessage() 62 | { 63 | $this->assertEmpty($this->request->getMessage()); 64 | $this->request->setMessage(__METHOD__); 65 | $this->assertEquals(__METHOD__, $this->request->getMessage()); 66 | } 67 | 68 | /** 69 | * @covers \He110\CommunicationTools\Request::setPayload() 70 | * @covers \He110\CommunicationTools\Request::getPayload() 71 | */ 72 | public function testSetPayload() 73 | { 74 | $this->assertEmpty($this->request->getPayload()); 75 | $this->request->setPayload(__METHOD__); 76 | $this->assertEquals(__METHOD__, $this->request->getPayload()); 77 | } 78 | 79 | public function setUp(): void 80 | { 81 | $this->request = new Request(); 82 | } 83 | 84 | public function tearDown(): void 85 | { 86 | $this->request = null; 87 | unset($this->request); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /tests/ScreenItems/VoiceTest.php: -------------------------------------------------------------------------------- 1 | assertNull($this->voice->getPath()); 33 | $this->voice->setPath(static::VOICE_OGG); 34 | $this->assertEquals(static::VOICE_OGG, $this->voice->getPath()); 35 | } 36 | 37 | /** 38 | * @covers \He110\CommunicationTools\ScreenItems\Voice::toArray() 39 | * @covers \He110\CommunicationTools\ScreenItems\Voice::setPath() 40 | */ 41 | public function testToArray() 42 | { 43 | $this->voice->setPath(static::VOICE_OGG); 44 | $this->assertCount(2, $this->voice->toArray()); 45 | $this->assertArrayHasKey("path", $this->voice->toArray()); 46 | $this->assertArrayHasKey("text", $this->voice->toArray()); 47 | } 48 | 49 | /** 50 | * @covers \He110\CommunicationTools\ScreenItems\Voice::create() 51 | * @covers \He110\CommunicationTools\ScreenItems\Voice::fromArray() 52 | */ 53 | public function testCreate() 54 | { 55 | $ob = Voice::create(["path" => static::VOICE_OGG]); 56 | $this->assertNotEquals($this->voice, $ob); 57 | $this->assertEquals(Voice::class, get_class($ob)); 58 | $this->assertEquals(static::VOICE_OGG, $ob->getPath()); 59 | } 60 | 61 | /** 62 | * @covers \He110\CommunicationTools\ScreenItems\Voice::__toString() 63 | * @covers \He110\CommunicationTools\ScreenItems\Voice::getText() 64 | * @covers \He110\CommunicationTools\ScreenItems\Voice::setText() 65 | */ 66 | public function testGetText() 67 | { 68 | $this->assertEmpty($this->voice->getText()); 69 | $this->voice->setPath("non_existed.file"); 70 | try { 71 | $this->voice->getText(); 72 | } catch (\Exception $e) { 73 | $this->assertEquals(AttachmentNotFoundException::class, get_class($e)); 74 | } 75 | $this->voice->setPath(static::VOICE_OGG); 76 | $this->voice->setText("Some text"); 77 | $this->assertEquals((string)$this->voice, $this->voice->getText()); 78 | } 79 | 80 | public function setUp(): void 81 | { 82 | $this->voice = new Voice(); 83 | } 84 | 85 | public function tearDown(): void 86 | { 87 | $this->voice = null; 88 | unset($this->voice); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/MessengerUser.php: -------------------------------------------------------------------------------- 1 | userId; 35 | } 36 | 37 | /** 38 | * @param null|string $userId 39 | * @return MessengerUser 40 | */ 41 | public function setUserId(?string $userId): self 42 | { 43 | $this->userId = $userId; 44 | return $this; 45 | } 46 | 47 | /** 48 | * @return null|string 49 | */ 50 | public function getFirstName(): ?string 51 | { 52 | return $this->firstName; 53 | } 54 | 55 | /** 56 | * @param null|string $firstName 57 | * @return MessengerUser 58 | */ 59 | public function setFirstName(?string $firstName): self 60 | { 61 | $this->firstName = $firstName; 62 | return $this; 63 | } 64 | 65 | /** 66 | * @return null|string 67 | */ 68 | public function getLastName(): ?string 69 | { 70 | return $this->lastName; 71 | } 72 | 73 | /** 74 | * @param null|string $lastName 75 | * @return MessengerUser 76 | */ 77 | public function setLastName(?string $lastName): self 78 | { 79 | $this->lastName = $lastName; 80 | return $this; 81 | } 82 | 83 | /** 84 | * @return null|string 85 | */ 86 | public function getUsername(): ?string 87 | { 88 | return $this->username; 89 | } 90 | 91 | /** 92 | * @param null|string $username 93 | * @return MessengerUser 94 | */ 95 | public function setUsername(?string $username): self 96 | { 97 | $this->username = $username; 98 | return $this; 99 | } 100 | 101 | /** 102 | * @return null|string 103 | */ 104 | public function getLanguageCode(): ?string 105 | { 106 | return $this->languageCode; 107 | } 108 | 109 | /** 110 | * @param null|string $languageCode 111 | * @return MessengerUser 112 | */ 113 | public function setLanguageCode(?string $languageCode): self 114 | { 115 | $this->languageCode = $languageCode; 116 | return $this; 117 | } 118 | 119 | /** 120 | * @return string 121 | */ 122 | public function getFullName(): string 123 | { 124 | $firstName = $this->getFirstName() ?? ""; 125 | $lastName = $this->getLastName() ?? ""; 126 | $fullName = trim("$firstName $lastName"); 127 | return str_replace(" ", " ", $fullName); 128 | } 129 | 130 | /** 131 | * @return string 132 | */ 133 | public function __toString(): string 134 | { 135 | return $this->getFullName(); 136 | } 137 | 138 | } -------------------------------------------------------------------------------- /src/ScreenItems/Button.php: -------------------------------------------------------------------------------- 1 | label ?? ""; 33 | } 34 | 35 | /** 36 | * @param string $label 37 | * @return Button 38 | */ 39 | public function setLabel(string $label): self 40 | { 41 | $this->label = $label; 42 | return $this; 43 | } 44 | 45 | /** 46 | * @return string 47 | */ 48 | public function getContent() 49 | { 50 | return $this->content; 51 | } 52 | 53 | /** 54 | * @param string $content 55 | * @return Button 56 | */ 57 | public function setContent($content): self 58 | { 59 | $this->content = $content; 60 | return $this; 61 | } 62 | 63 | /** 64 | * @return string 65 | */ 66 | public function getType(): string 67 | { 68 | return $this->type ?? static::BUTTON_TYPE_TEXT; 69 | } 70 | 71 | /** 72 | * @param string $type 73 | * @return Button 74 | */ 75 | public function setType(string $type): self 76 | { 77 | $this->type = $type; 78 | return $this; 79 | } 80 | 81 | /** 82 | * {@inheritdoc} 83 | */ 84 | public function toArray(): array 85 | { 86 | switch ($this->getType()) { 87 | case static::BUTTON_TYPE_CALLBACK: 88 | $key = "callback"; 89 | break; 90 | case static::BUTTON_TYPE_URL: 91 | $key = "url"; 92 | break; 93 | default: 94 | $key = null; 95 | break; 96 | } 97 | $result = [ 98 | "type" => $this->getType(), 99 | "label" => $this->getLabel() 100 | ]; 101 | if (!is_null($key)) 102 | $result[$key] = $result["content"] = $this->getContent(); 103 | return $result; 104 | } 105 | 106 | /** 107 | * {@inheritdoc} 108 | */ 109 | public function fromArray(array $data) 110 | { 111 | foreach($data as $key=>$value) { 112 | $methodName = "set".ucfirst($key); 113 | if (method_exists($this, $methodName) && is_callable([$this, $methodName])) 114 | $this->{$methodName}($value); 115 | } 116 | return $this; 117 | } 118 | 119 | /** 120 | * {@inheritdoc} 121 | */ 122 | static public function create(array $config): self 123 | { 124 | $ob = new Button(); 125 | return $ob->fromArray($config); 126 | } 127 | 128 | /** 129 | * @return string 130 | */ 131 | public function __toString(): string 132 | { 133 | return $this->getLabel(); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /tests/MessengerUserTest.php: -------------------------------------------------------------------------------- 1 | assertNull($this->user->getUserId()); 26 | $this->user->setUserId(__METHOD__); 27 | $this->assertEquals(__METHOD__, $this->user->getUserId()); 28 | } 29 | 30 | /** 31 | * @covers \He110\CommunicationTools\MessengerUser::setLanguageCode() 32 | * @covers \He110\CommunicationTools\MessengerUser::getLanguageCode() 33 | */ 34 | public function testSetLanguageCode() 35 | { 36 | $this->assertNull($this->user->getLanguageCode()); 37 | $this->user->setLanguageCode("en"); 38 | $this->assertEquals("en", $this->user->getLanguageCode()); 39 | } 40 | 41 | /** 42 | * @covers \He110\CommunicationTools\MessengerUser::getFirstName() 43 | * @covers \He110\CommunicationTools\MessengerUser::setFirstName() 44 | */ 45 | public function testSetFirstName() 46 | { 47 | $this->assertNull($this->user->getFirstName()); 48 | $this->user->setFirstName(__METHOD__); 49 | $this->assertEquals(__METHOD__, $this->user->getFirstName()); 50 | } 51 | 52 | /** 53 | * @covers \He110\CommunicationTools\MessengerUser::setLastName() 54 | * @covers \He110\CommunicationTools\MessengerUser::getLastName() 55 | */ 56 | public function testSetLastName() 57 | { 58 | $this->assertNull($this->user->getLastName()); 59 | $this->user->setLastName(__METHOD__); 60 | $this->assertEquals(__METHOD__, $this->user->getLastName()); 61 | } 62 | 63 | /** 64 | * @covers \He110\CommunicationTools\MessengerUser::setUsername() 65 | * @covers \He110\CommunicationTools\MessengerUser::getUsername() 66 | */ 67 | public function testSetUsername() 68 | { 69 | $this->assertNull($this->user->getUsername()); 70 | $this->user->setUsername(__METHOD__); 71 | $this->assertEquals(__METHOD__, $this->user->getUsername()); 72 | } 73 | 74 | /** 75 | * @covers \He110\CommunicationTools\MessengerUser::getFullName() 76 | * @covers \He110\CommunicationTools\MessengerUser::getFirstName() 77 | * @covers \He110\CommunicationTools\MessengerUser::getLastName() 78 | * @covers \He110\CommunicationTools\MessengerUser::setFirstName() 79 | * @covers \He110\CommunicationTools\MessengerUser::setLastName() 80 | * @covers \He110\CommunicationTools\MessengerUser::__toString() 81 | */ 82 | public function testGetFullName() 83 | { 84 | $this->user->setFirstName("Ivan"); 85 | $this->user->setLastName("Ivanov"); 86 | $this->assertEquals("Ivan Ivanov", (string)$this->user); 87 | } 88 | 89 | public function setUp(): void 90 | { 91 | $this->user = new MessengerUser(); 92 | } 93 | 94 | public function tearDown(): void 95 | { 96 | $this->user = null; 97 | unset($this->user); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Communication Tools [![Build Status](https://travis-ci.com/he110/communication-tools.svg?branch=master)](https://travis-ci.com/he110/communication-tools) 2 | 3 | [![Latest Stable Version](https://img.shields.io/packagist/v/he110/communication-tools.svg)](https://packagist.org/packages/he110/communication-tools) [![codecov](https://codecov.io/gh/he110/communication-tools/branch/master/graph/badge.svg)](https://codecov.io/gh/he110/communication-tools) [![Maintainability](https://api.codeclimate.com/v1/badges/8fba6456c0c825fc252a/maintainability)](https://codeclimate.com/github/he110/communication-tools/maintainability) 4 | 5 | Tools set for messenger managing. Allows you to send any content via Telegram, Viber, WhatsApp, VK, Facebook Messenger and so on. 6 | 7 | ## Installation 8 | 9 | Install the latest version with 10 | 11 | ```bash 12 | $ composer require he110/communication-tools 13 | ``` 14 | 15 | ## Basic Usage 16 | 17 | ### Messenger's clients 18 | ```php 19 | setAccessToken(YOUR_TOKEN_HERE); 27 | 28 | // If you want, to send simple text message 29 | $messenger->sendMessage("Your message text here"); 30 | 31 | // To send image use method sendImage 32 | $messenger->sendImage("path/to/file", "(Optional) Your text description"); 33 | // or, to send document... 34 | $messenger->sendDocument("path/to/file", "(Optional) Your text description"); 35 | // you can also send voice files 36 | $messenger->sendVoice("path/to/file"); 37 | 38 | // If you wanna use buttons, it's better way to use MessengerScreen 39 | $screen = new MessengerScreen(); 40 | $screen->addMessage("Your message text here"); 41 | $screen->addButtonText("Text button"); 42 | $screen->addButtonLink("URL button", "https://google.com"); 43 | $messenger->sendScreen($screen); 44 | 45 | ``` 46 | 47 | ### Multiple messengers 48 | ```php 49 | setAccessToken(YOUR_TOKEN_HERE); 58 | 59 | // Pool allows you to use multiple messengers as one 60 | $pool = new MessengerPool(); 61 | $pool->add($messenger); 62 | 63 | $pool->sendMessage("Your message text here"); 64 | 65 | // If you wanna use buttons, it's better way to use MessengerScreen 66 | $screen = new MessengerScreen(); 67 | $screen->addMessage("Your message text here"); 68 | $screen->addButtonText("Text button"); 69 | $screen->addButtonLink("URL button", "https://google.com"); 70 | $pool->sendScreen($screen); 71 | 72 | ``` 73 | 74 | 75 | ### Work with events 76 | ```php 77 | setAccessToken(YOUR_TOKEN_HERE); 86 | 87 | // Action for simple incoming messages 88 | $messenger->onMessage(function(Request $request) use ($messenger) { 89 | // Your code here... 90 | $text = $request->getMessage(); 91 | /** @var MessengerUser $user $user */ 92 | $user = $request->getUser(); 93 | $messenger->setTargetUser($user->getUserId()); 94 | $messenger->sendMessage("We've got your message: '$text'"); 95 | }); 96 | 97 | // Action for buttons click 98 | $messenger->onButtonClick(function(Request $request) use ($messenger) { 99 | // Your code here... 100 | $payload = $request->getPayload(); 101 | }); 102 | 103 | // Required!!! Run this method to check if events are triggered 104 | $messenger->checkEvents(); 105 | 106 | ``` 107 | 108 | ## About 109 | 110 | ### Requirements 111 | 112 | - Communication Tools works with PHP 7.2 or above. 113 | 114 | ### Submitting bugs and feature requests 115 | 116 | Bugs and feature request are tracked on [GitHub](https://github.com/he110/communication-tools/issues) 117 | 118 | ### Author 119 | 120 | Ilya S. Zobenko - - 121 | 122 | ### License 123 | 124 | "Communication Tools" is licensed under the MIT License - see the `LICENSE` file for detail 125 | -------------------------------------------------------------------------------- /src/ScreenItems/File.php: -------------------------------------------------------------------------------- 1 | path ?? null; 38 | } 39 | 40 | /** 41 | * @param string $path 42 | * @return File 43 | */ 44 | public function setPath(string $path): self 45 | { 46 | if (file_exists($path)) { 47 | $this->setSize(filesize($path)); 48 | if (is_null($this->getName())) 49 | $this->setName(basename($path)); 50 | if (is_null($this->getType())) 51 | $this->setType($this->isImage($path) ? static::FILE_TYPE_IMAGE : static::FILE_TYPE_DOCUMENT); 52 | } 53 | $this->path = $path; 54 | return $this; 55 | } 56 | 57 | /** 58 | * @return string|null 59 | */ 60 | public function getName(): ?string 61 | { 62 | return $this->name ?? null; 63 | } 64 | 65 | /** 66 | * @param string $name 67 | */ 68 | public function setName(string $name): void 69 | { 70 | $this->name = $name; 71 | } 72 | 73 | /** 74 | * @return string 75 | */ 76 | public function getType(): ?string 77 | { 78 | return $this->type ?? null; 79 | } 80 | 81 | /** 82 | * @param string $type 83 | */ 84 | public function setType(string $type): void 85 | { 86 | $this->type = $type; 87 | } 88 | 89 | /** 90 | * @return int 91 | */ 92 | public function getSize(): int 93 | { 94 | return $this->size ?? 0; 95 | } 96 | 97 | /** 98 | * @param int $size 99 | */ 100 | private function setSize(int $size): void 101 | { 102 | $this->size = $size; 103 | } 104 | 105 | /** 106 | * @return string 107 | */ 108 | public function getDescription(): string 109 | { 110 | return $this->description ?? ""; 111 | } 112 | 113 | /** 114 | * @param string $description 115 | * @return File 116 | */ 117 | public function setDescription(string $description): self 118 | { 119 | $this->description = $description; 120 | return $this; 121 | } 122 | 123 | 124 | /** 125 | * {@inheritdoc} 126 | */ 127 | public function toArray(): array 128 | { 129 | return array( 130 | "path" => $this->getPath(), 131 | "name" => $this->getName(), 132 | "size" => $this->getSize(), 133 | "type" => $this->getType(), 134 | "description" => $this->getDescription() 135 | ); 136 | } 137 | 138 | /** 139 | * {@inheritdoc} 140 | */ 141 | public function fromArray(array $data) 142 | { 143 | if (isset($data["path"])) 144 | $this->setPath($data["path"]); 145 | foreach($data as $key=>$value) { 146 | $methodName = "set".ucfirst($key); 147 | if (method_exists($this, $methodName) && is_callable([$this, $methodName])) 148 | $this->{$methodName}($value); 149 | } 150 | return $this; 151 | } 152 | 153 | /** 154 | * {@inheritdoc} 155 | */ 156 | static public function create(array $config) 157 | { 158 | return (new File())->fromArray($config); 159 | } 160 | 161 | /** 162 | * @return null|string 163 | */ 164 | public function __toString(): string 165 | { 166 | return $this->getName(); 167 | } 168 | 169 | /** 170 | * @param $path 171 | * @return bool 172 | */ 173 | private function isImage($path): bool 174 | { 175 | $a = getimagesize($path); 176 | $imageType = $a[2]; 177 | 178 | if (in_array($imageType , array(IMAGETYPE_GIF , IMAGETYPE_JPEG ,IMAGETYPE_PNG , IMAGETYPE_BMP))) 179 | return true; 180 | return false; 181 | } 182 | } -------------------------------------------------------------------------------- /src/MessengerPool.php: -------------------------------------------------------------------------------- 1 | getTargetUser(); 27 | if (!in_array($messenger, $this->messengers)) 28 | array_push($this->messengers, $messenger); 29 | 30 | if ($targetUserId !== "") 31 | $this->setTargetUser($targetUserId); 32 | elseif ($targetUserId === "" && !empty($messenger->getTargetUser())) 33 | $this->setTargetUser($messenger->getTargetUser()); 34 | 35 | return $this; 36 | } 37 | 38 | /** 39 | * Find key of specific messenger 40 | * 41 | * @param MessengerInterface $messenger 42 | * @return int 43 | */ 44 | public function indexOf(MessengerInterface $messenger): int 45 | { 46 | $key = array_search($messenger, $this->messengers); 47 | if ($key === false) 48 | $key = -1; 49 | return $key; 50 | } 51 | 52 | /** 53 | * Removes messenger from collection by it's Key 54 | * 55 | * @param int $key 56 | * @return MessengerPool 57 | */ 58 | public function removeByKey(int $key): self 59 | { 60 | unset($this->messengers[$key]); 61 | return $this; 62 | } 63 | 64 | /** 65 | * Removes messenger from collection 66 | * 67 | * @param MessengerInterface $messenger 68 | * @return MessengerPool 69 | */ 70 | public function remove(MessengerInterface $messenger): self 71 | { 72 | if (0 <= $key = $this->indexOf($messenger)) 73 | $this->removeByKey($key); 74 | return $this; 75 | } 76 | 77 | /** 78 | * Returns all added messengers from collection 79 | * 80 | * @return MessengerInterface[] 81 | */ 82 | public function getList(): array 83 | { 84 | return $this->messengers; 85 | } 86 | 87 | /** 88 | * {@inheritdoc} 89 | */ 90 | public function setTargetUser(?string $userId) 91 | { 92 | foreach ($this->messengers as $messenger) 93 | $messenger->setTargetUser($userId); 94 | return $this; 95 | } 96 | 97 | /** 98 | * {@inheritdoc} 99 | */ 100 | public function getTargetUser(): ?string 101 | { 102 | $messenger = reset($this->messengers); 103 | if ($messenger === false) 104 | return ""; 105 | return $messenger->getTargetUser(); 106 | } 107 | 108 | /** 109 | * {@inheritdoc} 110 | */ 111 | public function sendMessage(string $text, array $buttons = []): bool 112 | { 113 | $result = true; 114 | foreach ($this->messengers as $messenger) 115 | $result = $messenger->sendMessage($text, $buttons) && $result; 116 | return $result; 117 | } 118 | 119 | /** 120 | * {@inheritdoc} 121 | */ 122 | public function sendImage(string $pathToFile, string $description = null, array $buttons = []): bool 123 | { 124 | $result = true; 125 | foreach ($this->messengers as $messenger) 126 | $result = $messenger->sendImage($pathToFile, $description, $buttons) && $result; 127 | return $result; 128 | } 129 | 130 | /** 131 | * {@inheritdoc} 132 | */ 133 | public function sendDocument(string $pathToFile, string $description = null, array $buttons = []): bool 134 | { 135 | $result = true; 136 | foreach ($this->messengers as $messenger) 137 | $result = $messenger->sendDocument($pathToFile, $description, $buttons) && $result; 138 | return $result; 139 | } 140 | 141 | /** 142 | * {@inheritdoc} 143 | */ 144 | public function sendVoice(string $pathToFile): bool 145 | { 146 | $result = true; 147 | foreach ($this->messengers as $messenger) 148 | $result = $messenger->sendVoice($pathToFile) && $result; 149 | return $result; 150 | } 151 | 152 | /** 153 | * {@inheritdoc} 154 | */ 155 | public function sendScreen(MessengerScreen $screen): bool 156 | { 157 | $result = true; 158 | foreach ($this->messengers as $messenger) 159 | $result = $messenger->sendScreen($screen) && $result; 160 | return $result; 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /tests/ScreenItems/ButtonTest.php: -------------------------------------------------------------------------------- 1 | assertEmpty($this->button->getLabel()); 27 | $this->assertEmpty((string)$this->button); 28 | $this->button->setLabel(__METHOD__); 29 | $this->assertEquals(__METHOD__, $this->button->getLabel()); 30 | $this->assertEquals((string)$this->button, $this->button->getLabel()); 31 | } 32 | 33 | /** 34 | * @covers \He110\CommunicationTools\ScreenItems\Button::setContent() 35 | * @covers \He110\CommunicationTools\ScreenItems\Button::getContent() 36 | */ 37 | public function testGetContent() 38 | { 39 | $this->assertEmpty($this->button->getContent()); 40 | $this->button->setContent("empty one"); 41 | $this->assertEquals("empty one", $this->button->getContent()); 42 | } 43 | 44 | /** 45 | * @covers \He110\CommunicationTools\ScreenItems\Button::toArray() 46 | * @covers \He110\CommunicationTools\ScreenItems\Button::fromArray() 47 | */ 48 | public function testToArray() 49 | { 50 | $this->button->fromArray([ 51 | "label" => __METHOD__, 52 | "type" => Button::BUTTON_TYPE_URL, 53 | "content" => "https://ya.ru" 54 | ]); 55 | 56 | $result = $this->button->toArray(); 57 | $this->assertArrayHasKey("label", $result); 58 | $this->assertArrayHasKey("type", $result); 59 | $this->assertArrayHasKey("content", $result); 60 | $this->assertArrayHasKey("url", $result); 61 | 62 | $this->button->setType(Button::BUTTON_TYPE_TEXT); 63 | $this->assertArrayNotHasKey("content", $this->button->toArray()); 64 | $this->assertArrayNotHasKey("url", $this->button->toArray()); 65 | 66 | $this->button->fromArray([ 67 | "type" => Button::BUTTON_TYPE_CALLBACK, 68 | "content" => function($a) { echo __METHOD__; } 69 | ]); 70 | 71 | $this->assertArrayHasKey("content", $this->button->toArray()); 72 | $this->assertArrayHasKey("callback", $this->button->toArray()); 73 | $this->assertIsCallable($this->button->getContent()); 74 | } 75 | 76 | /** 77 | * @dataProvider fromArrayProvider 78 | * 79 | * @covers \He110\CommunicationTools\ScreenItems\Button::fromArray() 80 | * @covers \He110\CommunicationTools\ScreenItems\Button::getLabel() 81 | * @covers \He110\CommunicationTools\ScreenItems\Button::getType() 82 | * @covers \He110\CommunicationTools\ScreenItems\Button::getContent() 83 | */ 84 | public function testFromArray(string $type, $content) 85 | { 86 | $config = [ 87 | "label" => __METHOD__, 88 | "type" => $type 89 | ]; 90 | if ($type !== Button::BUTTON_TYPE_TEXT) 91 | $config["content"] = $content; 92 | $this->button->fromArray($config); 93 | 94 | $this->assertEquals(__METHOD__, $this->button->getLabel()); 95 | $this->assertEquals($type, $this->button->getType()); 96 | if ($type !== Button::BUTTON_TYPE_TEXT) 97 | $this->assertEquals($content, $this->button->getContent()); 98 | 99 | if ($type === Button::BUTTON_TYPE_CALLBACK && is_callable($content)) 100 | $this->assertIsCallable($this->button->getContent()); 101 | } 102 | 103 | public function fromArrayProvider() 104 | { 105 | return array( 106 | array(Button::BUTTON_TYPE_TEXT, null), 107 | array(Button::BUTTON_TYPE_URL, "https://ya.ru"), 108 | array(Button::BUTTON_TYPE_CALLBACK, function($a) { echo __METHOD__; }), 109 | ); 110 | } 111 | 112 | /** 113 | * @covers \He110\CommunicationTools\ScreenItems\Button::create() 114 | */ 115 | public function testCreate() 116 | { 117 | $ob = Button::create(["label" => __METHOD__]); 118 | $this->assertNotEquals($this->button, $ob); 119 | $this->assertEquals(Button::class, get_class($ob)); 120 | $this->assertEquals(__METHOD__, $ob->getLabel()); 121 | } 122 | 123 | /** 124 | * @covers \He110\CommunicationTools\ScreenItems\Button::setType() 125 | * @covers \He110\CommunicationTools\ScreenItems\Button::getType() 126 | */ 127 | public function testSetType() 128 | { 129 | $this->assertEquals(Button::BUTTON_TYPE_TEXT, $this->button->getType()); 130 | $this->button->setType(Button::BUTTON_TYPE_URL); 131 | $this->assertEquals(Button::BUTTON_TYPE_URL, $this->button->getType()); 132 | } 133 | 134 | public function setUp(): void 135 | { 136 | $this->button = new Button(); 137 | } 138 | 139 | public function tearDown(): void 140 | { 141 | $this->button = null; 142 | unset($this->button); 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /src/Telegram/MessengerEvents.php: -------------------------------------------------------------------------------- 1 | addEvent(Request::REQUEST_TYPE_MESSAGE, $closure); 26 | } 27 | 28 | /** 29 | * {@inheritdoc} 30 | * 31 | * @codeCoverageIgnoreStart 32 | */ 33 | public function onMessageRead(\Closure $closure) 34 | { 35 | 36 | // TODO: Найти способ получить такой event 37 | $this->addEvent(Request::REQUEST_TYPE_MESSAGE_READ, $closure); 38 | } 39 | /** @codeCoverageIgnoreEnd */ 40 | 41 | /** 42 | * {@inheritdoc} 43 | */ 44 | public function onButtonClick(\Closure $closure) 45 | { 46 | $this->addEvent(Request::REQUEST_TYPE_BUTTON_CLICK, $closure); 47 | } 48 | 49 | /** 50 | * @param string $type 51 | * @param \Closure $closure 52 | */ 53 | private function addEvent(string $type, \Closure $closure): void 54 | { 55 | $key = spl_object_hash($this)."_".$type; 56 | EventController::getInstance()->addEvent($key, $closure); 57 | } 58 | 59 | /** 60 | * {@inheritdoc} 61 | */ 62 | public function checkEvents(): void 63 | { 64 | $request = $this->getRequest(); 65 | if ($request->getType()) { 66 | $key = spl_object_hash($this) . "_" . $request->getType(); 67 | if ($closure = EventController::getInstance()->getEvent($key)) 68 | $closure($request); 69 | } 70 | } 71 | 72 | /** 73 | * {@inheritdoc} 74 | */ 75 | public function getRequest(): Request 76 | { 77 | $request = new Request(); 78 | if ($data = json_decode($this->getPhpInput(), true)) { 79 | 80 | if (isset($data["message"])) 81 | $request = $this->buildMessageRequest($request, $data["message"]); 82 | 83 | elseif (isset($data["callback_query"])) 84 | $request = $this->buildButtonClickRequest($request, $data["callback_query"]); 85 | } 86 | return $request; 87 | } 88 | 89 | /** 90 | * @param Request $request 91 | * @param array $data 92 | * @return Request 93 | */ 94 | private function buildMessageRequest(Request &$request, array $data): Request 95 | { 96 | $data['from']['id'] = $data['chat']['id']; 97 | $this->setUserFromRequest($request, $data["from"]); 98 | 99 | if (isset($data["text"])) { 100 | $request->setType(Request::REQUEST_TYPE_MESSAGE); 101 | $request->setMessage($data["text"]); 102 | } 103 | return $request; 104 | } 105 | 106 | /** 107 | * @param Request $request 108 | * @param array $data 109 | * @return Request 110 | */ 111 | private function buildButtonClickRequest(Request &$request, array $data): Request 112 | { 113 | $this->setUserFromRequest($request, $data["from"]); 114 | if (isset($data["data"])) { 115 | $request->setType(Request::REQUEST_TYPE_BUTTON_CLICK); 116 | $payload = ""; 117 | $type = $this->detectPayloadType($data["data"],$payload); 118 | switch ($type) { 119 | case Button::BUTTON_TYPE_CALLBACK: 120 | $request->setPayload($payload); 121 | break; 122 | default: 123 | $request->setMessage($payload); 124 | break; 125 | } 126 | } 127 | return $request; 128 | } 129 | 130 | /** 131 | * @param string|null $payload 132 | * @param null $data 133 | * @return string 134 | */ 135 | private function detectPayloadType(string $payload, &$data = null): ?string 136 | { 137 | if (substr($payload, 0, 4) === "clb=") { 138 | $data = substr($payload, 4); 139 | return Button::BUTTON_TYPE_CALLBACK; 140 | } elseif (substr($payload, 0, 5) === "text=") { 141 | $data = substr($payload, 5); 142 | return Button::BUTTON_TYPE_TEXT; 143 | } else { 144 | return null; 145 | } 146 | } 147 | 148 | /** 149 | * @param Request $request 150 | * @param array $from 151 | */ 152 | private function setUserFromRequest(Request &$request, array $from): void 153 | { 154 | $user = new MessengerUser(); 155 | $user->setFirstName($from["first_name"]) 156 | ->setLastName($from["last_name"]) 157 | ->setUsername($from["username"]) 158 | ->setUserId($from['id']) 159 | ->setLanguageCode($from["language_code"]); 160 | $request->setUser($user); 161 | } 162 | 163 | /** 164 | * @return string 165 | * 166 | * @codeCoverageIgnoreStart 167 | */ 168 | protected function getPhpInput(): string 169 | { 170 | return file_get_contents("php://input"); 171 | } 172 | 173 | /** @codeCoverageIgnoreEnd */ 174 | } -------------------------------------------------------------------------------- /tests/ScreenItems/FileTest.php: -------------------------------------------------------------------------------- 1 | file->setPath(static::IMAGE_PATH); 37 | $this->assertEquals(static::IMAGE_PATH, $this->file->getPath()); 38 | $this->assertEquals("image.jpg", $this->file->getName()); 39 | $this->assertEquals(File::FILE_TYPE_IMAGE, $this->file->getType()); 40 | } 41 | 42 | /** 43 | * @covers \He110\CommunicationTools\ScreenItems\File::fromArray() 44 | * @covers \He110\CommunicationTools\ScreenItems\File::toArray() 45 | */ 46 | public function testToArray() 47 | { 48 | $conf = [ 49 | "path" => static::IMAGE_PATH, 50 | "name" => __METHOD__ 51 | ]; 52 | $this->file->fromArray($conf); 53 | $this->assertEquals($conf["path"], $this->file->getPath()); 54 | $this->assertEquals($conf["name"], $this->file->getName()); 55 | 56 | $new = $this->file->toArray(); 57 | $this->assertArrayHasKey("path", $new); 58 | $this->assertArrayHasKey("name", $new); 59 | $this->assertArrayHasKey("size", $new); 60 | $this->assertArrayHasKey("type", $new); 61 | $this->assertArrayHasKey("description", $new); 62 | 63 | $this->assertEmpty($new["description"]); 64 | 65 | $this->assertEquals($conf["path"], $new["path"]); 66 | $this->assertEquals($conf["name"], $new["name"]); 67 | $this->assertEquals(File::FILE_TYPE_IMAGE, $new["type"]); 68 | } 69 | 70 | /** 71 | * @covers \He110\CommunicationTools\ScreenItems\File::getDescription() 72 | * @covers \He110\CommunicationTools\ScreenItems\File::setDescription() 73 | */ 74 | public function testGetDescription() 75 | { 76 | $description = "TEST"; 77 | $this->file->setDescription($description); 78 | $this->assertEquals($description, $this->file->getDescription()); 79 | } 80 | 81 | /** 82 | * @covers \He110\CommunicationTools\ScreenItems\File::create() 83 | */ 84 | public function testCreate() 85 | { 86 | $ob = File::create(["path" => static::IMAGE_PATH, "name" => __METHOD__]); 87 | $this->assertNotEquals($this->file, $ob); 88 | $this->assertEquals(File::class, get_class($ob)); 89 | $this->assertEquals(__METHOD__, $ob->getName()); 90 | $this->assertEquals(static::IMAGE_PATH, $ob->getPath()); 91 | } 92 | 93 | /** 94 | * @covers \He110\CommunicationTools\ScreenItems\File::__toString() 95 | */ 96 | public function test__toString() 97 | { 98 | $this->file->setName(__METHOD__); 99 | $this->assertEquals((string)$this->file, __METHOD__); 100 | } 101 | 102 | /** 103 | * @dataProvider getSizeProvider 104 | * 105 | * @covers \He110\CommunicationTools\ScreenItems\File::getSize() 106 | * @covers \He110\CommunicationTools\ScreenItems\File::setPath() 107 | * @covers \He110\CommunicationTools\ScreenItems\File::setSize() 108 | * @covers \He110\CommunicationTools\ScreenItems\File::isImage() 109 | */ 110 | public function testGetSize(string $file, int $size, string $type) 111 | { 112 | $this->file->setPath($file); 113 | $this->assertEquals($size, $this->file->getSize()); 114 | $this->assertEquals($type, $this->file->getType()); 115 | } 116 | 117 | /** 118 | * @return array 119 | */ 120 | public function getSizeProvider(): array 121 | { 122 | return array( 123 | array(static::IMAGE_PATH, 39481, File::FILE_TYPE_IMAGE), 124 | array(static::DOCUMENT_PATH, 12, File::FILE_TYPE_DOCUMENT) 125 | ); 126 | } 127 | 128 | /** 129 | * @covers \He110\CommunicationTools\ScreenItems\File::getName() 130 | * @covers \He110\CommunicationTools\ScreenItems\File::setName() 131 | */ 132 | public function testSetName() 133 | { 134 | $this->assertNull($this->file->getName()); 135 | $this->file->setName(__METHOD__); 136 | $this->assertEquals(__METHOD__, $this->file->getName()); 137 | } 138 | 139 | /** 140 | * @covers \He110\CommunicationTools\ScreenItems\File::getType() 141 | * @covers \He110\CommunicationTools\ScreenItems\File::setType() 142 | */ 143 | public function testSetType() 144 | { 145 | $this->assertNull($this->file->getType()); 146 | $this->file->setType(File::FILE_TYPE_DOCUMENT); 147 | $this->assertEquals(File::FILE_TYPE_DOCUMENT, $this->file->getType()); 148 | } 149 | 150 | public function setUp(): void 151 | { 152 | $this->file = new File(); 153 | } 154 | 155 | public function tearDown(): void 156 | { 157 | $this->file = null; 158 | unset($this->file); 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /tests/MessengerPoolTest.php: -------------------------------------------------------------------------------- 1 | assertEmpty($pool->getTargetUser()); 29 | $pool->add($this->createMessengerMock(1)); 30 | $this->assertEquals(1, $pool->getTargetUser()); 31 | $pool->add($this->createMessengerMock(2)); 32 | $this->assertEquals(1, $pool->getTargetUser()); 33 | $pool->setTargetUser(2); 34 | $this->assertEquals(2, $pool->getTargetUser()); 35 | } 36 | 37 | /** 38 | * @covers \He110\CommunicationTools\MessengerPool::add() 39 | * @covers \He110\CommunicationTools\MessengerPool::getList() 40 | */ 41 | public function testAdd() 42 | { 43 | $list = $this->pool->getList(); 44 | $this->pool->add($this->createMessengerMock(2)); 45 | $this->assertEquals(1, count($list)); 46 | $this->assertEquals(2, count($this->pool->getList())); 47 | } 48 | 49 | /** 50 | * @covers \He110\CommunicationTools\MessengerPool::removeByKey() 51 | */ 52 | public function testRemoveByKey() 53 | { 54 | $list = $this->pool->getList(); 55 | list($messenger) = $list; 56 | $this->assertEquals(1, count($list)); 57 | $messengerKey = $this->pool->indexOf($messenger); 58 | $this->pool->removeByKey($messengerKey); 59 | $this->assertEquals(0, count($this->pool->getList())); 60 | } 61 | 62 | /** 63 | * @covers \He110\CommunicationTools\MessengerPool::remove() 64 | */ 65 | public function testRemove() 66 | { 67 | $list = $this->pool->getList(); 68 | list($messenger) = $list; 69 | $this->assertEquals(1, count($list)); 70 | $this->pool->remove($messenger); 71 | $this->assertEquals(0, count($this->pool->getList())); 72 | } 73 | 74 | /** 75 | * @covers \He110\CommunicationTools\MessengerPool::sendScreen() 76 | */ 77 | public function testSendScreen() 78 | { 79 | $screen = $this->getMockBuilder(MessengerScreen::class)->getMock(); 80 | $this->trueAndFalseTest("sendScreen", $screen); 81 | } 82 | 83 | /** 84 | * @dataProvider sendTypesProvider 85 | * 86 | * @covers \He110\CommunicationTools\MessengerPool::sendMessage() 87 | * @covers \He110\CommunicationTools\MessengerPool::sendImage() 88 | * @covers \He110\CommunicationTools\MessengerPool::sendDocument() 89 | * @covers \He110\CommunicationTools\MessengerPool::sendVoice() 90 | */ 91 | public function testSendTypes(string $type) 92 | { 93 | $this->trueAndFalseTest($type, "test_argument"); 94 | } 95 | 96 | public function sendTypesProvider() 97 | { 98 | return array( 99 | array("sendMessage"), 100 | array("sendImage"), 101 | array("sendDocument"), 102 | array("sendVoice"), 103 | ); 104 | } 105 | 106 | /** 107 | * @covers \He110\CommunicationTools\MessengerPool::indexOf() 108 | */ 109 | public function testIndexOf() 110 | { 111 | list($messenger) = $this->pool->getList(); 112 | $this->assertEquals(0, $this->pool->indexOf($messenger)); 113 | $newMessenger = $this->createMessengerMock(10, false); 114 | $this->assertEquals(-1, $this->pool->indexOf($newMessenger)); 115 | } 116 | 117 | /** 118 | * @param string $userId 119 | * @param bool $defaultResult 120 | * @return \PHPUnit\Framework\MockObject\MockObject|MessengerInterface 121 | */ 122 | private function createMessengerMock(string $userId, bool $defaultResult = true) 123 | { 124 | $userIdMemory = $userId; 125 | $messenger = $this->getMockBuilder(MessengerInterface::class)->getMock(); 126 | $messenger->method("setTargetUser")->willReturnCallback(function($argument) use (&$userIdMemory){ 127 | $userIdMemory = $argument; 128 | }); 129 | $messenger->method("getTargetUser")->will($this->returnCallback(function() use (&$userIdMemory){ 130 | return $userIdMemory; 131 | })); 132 | $messenger->method("sendMessage")->willReturn($defaultResult); 133 | $messenger->method("sendImage")->willReturn($defaultResult); 134 | $messenger->method("sendDocument")->willReturn($defaultResult); 135 | $messenger->method("sendImage")->willReturn($defaultResult); 136 | $messenger->method("sendScreen")->willReturn($defaultResult); 137 | $messenger->method("sendVoice")->willReturn($defaultResult); 138 | 139 | return $messenger; 140 | } 141 | 142 | private function trueAndFalseTest(string $methodName, $argument) 143 | { 144 | $this->assertTrue($this->pool->{$methodName}($argument)); 145 | $this->pool->add($this->createMessengerMock(2, false)); 146 | $this->assertFalse($this->pool->{$methodName}($argument)); 147 | } 148 | 149 | public function setUp(): void 150 | { 151 | $this->pool = new MessengerPool(); 152 | $this->pool->add($this->createMessengerMock(1)); 153 | } 154 | 155 | public function tearDown(): void 156 | { 157 | $this->pool = null; 158 | unset($this->pool); 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /src/MessengerScreen.php: -------------------------------------------------------------------------------- 1 | content[] = Message::create(["text" => $text]); 31 | return $this; 32 | } 33 | 34 | /** 35 | * @param string $label 36 | * @return MessengerScreen 37 | */ 38 | public function addButtonText(string $label): self 39 | { 40 | $this->content[] = Button::create([ 41 | "label" => $label, 42 | "type" => Button::BUTTON_TYPE_TEXT 43 | ]); 44 | return $this; 45 | } 46 | 47 | /** 48 | * @param string $label 49 | * @param string $url 50 | * @return MessengerScreen 51 | */ 52 | public function addButtonLink(string $label, string $url): self 53 | { 54 | $this->content[] = Button::create([ 55 | "label" => $label, 56 | "type" => Button::BUTTON_TYPE_URL, 57 | "content" => $url 58 | ]); 59 | return $this; 60 | } 61 | 62 | /** 63 | * @param string $label 64 | * @param \Closure $closure 65 | * @return MessengerScreen 66 | */ 67 | public function addButtonCallback(string $label, \Closure $closure): self 68 | { 69 | $this->content[] = Button::create([ 70 | "label" => $label, 71 | "type" => Button::BUTTON_TYPE_CALLBACK, 72 | "content" => $closure 73 | ]); 74 | return $this; 75 | } 76 | 77 | /** 78 | * @param string $pathToFile 79 | * @param string $description 80 | * @return MessengerScreen 81 | * @throws AttachmentNotFoundException 82 | */ 83 | public function addImage(string $pathToFile, string $description = ""): self 84 | { 85 | $this->checkFile($pathToFile); 86 | $file = File::create([ 87 | "path" => $pathToFile, 88 | "description" => $description, 89 | "type" => File::FILE_TYPE_IMAGE 90 | ]); 91 | $this->content[] = $file; 92 | return $this; 93 | } 94 | 95 | /** 96 | * @param string $pathToFile 97 | * @param string $description 98 | * @return MessengerScreen 99 | * @throws AttachmentNotFoundException 100 | */ 101 | public function addDocument(string $pathToFile, string $description = ""): self 102 | { 103 | $this->checkFile($pathToFile); 104 | $file = File::create([ 105 | "path" => $pathToFile, 106 | "description" => $description, 107 | "type" => File::FILE_TYPE_DOCUMENT 108 | ]); 109 | $this->content[] = $file; 110 | return $this; 111 | } 112 | 113 | /** 114 | * @param string $pathToFile 115 | * @return MessengerScreen 116 | * @throws AttachmentNotFoundException 117 | */ 118 | public function addVoice(string $pathToFile): self 119 | { 120 | $this->checkFile($pathToFile); 121 | $file = Voice::create([ 122 | "path" => $pathToFile 123 | ]); 124 | $this->content[] = $file; 125 | return $this; 126 | } 127 | 128 | /** 129 | * @param bool $asArray 130 | * @return array 131 | */ 132 | public function getContent(bool $asArray = true): array 133 | { 134 | $array = []; 135 | foreach($this->content as $item) { 136 | $array[] = $asArray ? $item->toArray() : $item; 137 | } 138 | return $array; 139 | } 140 | 141 | /** 142 | * @return MessengerScreen 143 | */ 144 | public function resetContent(): self 145 | { 146 | $this->content = []; 147 | return $this; 148 | } 149 | 150 | /** 151 | * @param string $pathToFile 152 | * @throws AttachmentNotFoundException 153 | */ 154 | private function checkFile(string $pathToFile): void 155 | { 156 | if (!file_exists($pathToFile)) 157 | throw new AttachmentNotFoundException("File not found"); 158 | } 159 | 160 | /** 161 | * @return array 162 | */ 163 | public function fixItemsOrder(): array 164 | { 165 | $content = $this->getContent(false); 166 | $buttons = []; 167 | $lastItem = null; 168 | $acceptableItem = null; 169 | $this->fixItemsOrderHelper($content, $buttons, $lastItem, $acceptableItem); 170 | 171 | if ($buttons && $content[$lastItem] instanceof Voice) 172 | $this->fixItemsOrderSorter($acceptableItem, $lastItem, $content, $buttons); 173 | 174 | return $content; 175 | } 176 | 177 | /** 178 | * @param $acceptableItem 179 | * @param $lastItem 180 | * @param $content 181 | * @param $buttons 182 | */ 183 | private function fixItemsOrderSorter($acceptableItem, $lastItem, &$content, $buttons): void 184 | { 185 | if ($acceptableItem === null) { 186 | Helpers::array_insert($content, $lastItem, [Message::create(["text" => "Use buttons"])]); 187 | $acceptableItem = $lastItem; 188 | } 189 | $content = array_slice($content, 0, count($content) - count($buttons)); 190 | Helpers::array_insert($content, $acceptableItem + 1, $buttons); 191 | } 192 | 193 | /** 194 | * @param $content 195 | * @param $buttons 196 | * @param $lastItem 197 | * @param $acceptableItem 198 | */ 199 | private function fixItemsOrderHelper($content, &$buttons, &$lastItem, &$acceptableItem): void 200 | { 201 | foreach ($content as $index => $item) { 202 | if ($item instanceof Button) { 203 | $buttons[] = $item; 204 | } else { 205 | $lastItem = $index; 206 | if (!($item instanceof Voice)) { 207 | $acceptableItem = $lastItem; 208 | } else { 209 | $buttons = []; 210 | } 211 | } 212 | } 213 | } 214 | } -------------------------------------------------------------------------------- /tests/Telegram/MessengerEventsTest.php: -------------------------------------------------------------------------------- 1 | "Ivan", 23 | "lastName" => "Ivanov", 24 | "username" => "IvanTest" 25 | ]; 26 | 27 | /** 28 | * @covers \He110\CommunicationTools\Telegram\MessengerEvents::onMessage() 29 | * @covers \He110\CommunicationTools\Telegram\MessengerEvents::getRequest() 30 | * @covers \He110\CommunicationTools\Telegram\MessengerEvents::checkEvents() 31 | * @covers \He110\CommunicationTools\Telegram\MessengerEvents::addEvent() 32 | * @covers \He110\CommunicationTools\Telegram\MessengerEvents::detectPayloadType() 33 | * @covers \He110\CommunicationTools\Telegram\MessengerEvents::setUserFromRequest() 34 | * @covers \He110\CommunicationTools\Telegram\MessengerEvents::buildMessageRequest() 35 | */ 36 | public function testOnMessage() 37 | { 38 | $var = "before"; 39 | $text = "Here is some text for test"; 40 | 41 | $client = new MessengerDoubler(); 42 | $client->setAccessToken(MessengerTest::API_KEY); 43 | $client->setTargetUser(MessengerTest::TARGET_USER); 44 | $client->setDataForInput($this->getTelegramRequestMockForMessage($text)); 45 | $client->onMessage(function($request) use (&$var, $text) { 46 | /** @var Request $request */ 47 | $var = "after"; 48 | $this->checkRequestUser($request); 49 | $this->assertEquals($text, $request->getMessage()); 50 | $this->assertEquals(Request::REQUEST_TYPE_MESSAGE, $request->getType()); 51 | }); 52 | 53 | $this->assertEquals("before", $var); 54 | $client->checkEvents(); 55 | $this->assertEquals("after", $var); 56 | } 57 | 58 | /** 59 | * @covers \He110\CommunicationTools\Telegram\MessengerEvents::onButtonClick() 60 | * @covers \He110\CommunicationTools\Telegram\MessengerEvents::getRequest() 61 | * @covers \He110\CommunicationTools\Telegram\MessengerEvents::checkEvents() 62 | * @covers \He110\CommunicationTools\Telegram\MessengerEvents::addEvent() 63 | * @covers \He110\CommunicationTools\Telegram\MessengerEvents::detectPayloadType() 64 | * @covers \He110\CommunicationTools\Telegram\MessengerEvents::setUserFromRequest() 65 | * @covers \He110\CommunicationTools\Telegram\MessengerEvents::buildButtonClickRequest() 66 | */ 67 | public function testOnButtonClick() 68 | { 69 | $var = "before"; 70 | 71 | $client = new MessengerDoubler(); 72 | $client->setAccessToken(MessengerTest::API_KEY); 73 | $client->setTargetUser(MessengerTest::TARGET_USER); 74 | $client->setDataForInput($this->getTelegramRequestMockForCallback()); 75 | $client->onButtonClick(function($request) use (&$var) { 76 | /** @var Request $request */ 77 | $var = "after"; 78 | $this->checkRequestUser($request); 79 | $this->assertEmpty($request->getMessage()); 80 | $this->assertEquals("callbackFunctionText", $request->getPayload()); 81 | $this->assertEquals(Request::REQUEST_TYPE_BUTTON_CLICK, $request->getType()); 82 | }); 83 | 84 | $this->assertEquals("before", $var); 85 | $client->checkEvents(); 86 | $this->assertEquals("after", $var); 87 | 88 | $buttonText = "Message callback"; 89 | $client->setDataForInput($this->getTelegramRequestMockForCallback("text=$buttonText")); 90 | $client->onButtonClick(function($request) use ($buttonText) { 91 | /** @var Request $request */ 92 | $this->checkRequestUser($request); 93 | $this->assertNotEmpty($request->getMessage()); 94 | $this->assertNull($request->getPayload()); 95 | $this->assertEquals(Request::REQUEST_TYPE_BUTTON_CLICK, $request->getType()); 96 | $this->assertEquals($buttonText, $request->getMessage()); 97 | }); 98 | 99 | $client->checkEvents(); 100 | 101 | $client->setDataForInput($this->getTelegramRequestMockForCallback("invalid callback")); 102 | $client->getRequest(); 103 | } 104 | 105 | /** 106 | * @param Request $request 107 | */ 108 | private function checkRequestUser(Request &$request): void 109 | { 110 | $this->assertEquals($this->from["firstName"], $request->getUser()->getFirstName()); 111 | $this->assertEquals($this->from["lastName"], $request->getUser()->getLastName()); 112 | $this->assertEquals($this->from["username"], $request->getUser()->getUsername()); 113 | } 114 | 115 | /** 116 | * @param string $text 117 | * @return string 118 | */ 119 | public function getTelegramRequestMockForMessage(string $text = "text"): string 120 | { 121 | $updateId = rand(0, 500); 122 | $messageId = rand(0, 500); 123 | $from = $this->from; 124 | $targetUser = MessengerTest::TARGET_USER; 125 | $time = time(); 126 | $text = addslashes($text); 127 | 128 | return <<from; 164 | $targetUser = MessengerTest::TARGET_USER; 165 | $time = time(); 166 | $callback = addslashes($callback); 167 | 168 | return <<client = new Messenger(); 238 | $this->client->setAccessToken(MessengerTest::API_KEY); 239 | $this->client->setTargetUser(MessengerTest::TARGET_USER); 240 | } 241 | 242 | public function tearDown(): void 243 | { 244 | $this->client = null; 245 | unset($this->client); 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /tests/MessengerScreenTest.php: -------------------------------------------------------------------------------- 1 | assertEmpty($this->screen->getContent()); 34 | $this->screen->addDocument(FileTest::DOCUMENT_PATH, static::DESCRIPTION); 35 | $this->assertCount(1, $this->screen->getContent()); 36 | list($ob) = $this->screen->getContent(); 37 | $this->assertEquals(FileTest::DOCUMENT_PATH, $ob["path"]); 38 | $this->assertEquals(static::DESCRIPTION, $ob["description"]); 39 | $this->screen->resetContent(); 40 | $this->assertEmpty($this->screen->getContent()); 41 | 42 | try { 43 | $this->screen->addDocument("not_existed.file"); 44 | } catch (\Exception $e) { 45 | $this->assertEquals(AttachmentNotFoundException::class, get_class($e)); 46 | } 47 | } 48 | 49 | /** 50 | * @covers \He110\CommunicationTools\MessengerScreen::addMessage() 51 | * @covers \He110\CommunicationTools\MessengerScreen::getContent() 52 | * @covers \He110\CommunicationTools\MessengerScreen::resetContent() 53 | */ 54 | public function testAddMessage() 55 | { 56 | $this->assertEmpty($this->screen->getContent()); 57 | $this->screen->addMessage(__METHOD__); 58 | $this->assertCount(1, $this->screen->getContent()); 59 | list($message) = $this->screen->getContent(); 60 | $this->assertEquals(__METHOD__, $message["text"]); 61 | $this->screen->resetContent(); 62 | $this->assertEmpty($this->screen->getContent()); 63 | } 64 | 65 | /** 66 | * @covers \He110\CommunicationTools\MessengerScreen::addImage() 67 | * @covers \He110\CommunicationTools\MessengerScreen::checkFile() 68 | */ 69 | public function testAddImage() 70 | { 71 | $this->assertEmpty($this->screen->getContent()); 72 | $this->screen->addImage(FileTest::IMAGE_PATH); 73 | $this->assertCount(1, $this->screen->getContent()); 74 | list($ob) = $this->screen->getContent(); 75 | $this->assertEquals(FileTest::IMAGE_PATH, $ob["path"]); 76 | $this->screen->resetContent(); 77 | $this->assertEmpty($this->screen->getContent()); 78 | 79 | try { 80 | $this->screen->addImage("not_existed.file"); 81 | } catch (\Exception $e) { 82 | $this->assertEquals(AttachmentNotFoundException::class, get_class($e)); 83 | } 84 | } 85 | 86 | /** 87 | * @covers \He110\CommunicationTools\MessengerScreen::addButtonLink() 88 | * @covers \He110\CommunicationTools\MessengerScreen::getContent() 89 | */ 90 | public function testAddButtonLink() 91 | { 92 | $url = "https://ya.ru"; 93 | $this->assertEmpty($this->screen->getContent()); 94 | $this->screen->addButtonLink(__METHOD__, $url); 95 | $this->assertCount(1, $this->screen->getContent()); 96 | list($item) = $this->screen->getContent(); 97 | $this->assertEquals(__METHOD__, $item["label"]); 98 | $this->assertEquals(Button::BUTTON_TYPE_URL, $item["type"]); 99 | $this->assertEquals($url, $item["url"]); 100 | } 101 | 102 | /** 103 | * @covers \He110\CommunicationTools\MessengerScreen::addVoice() 104 | * @covers \He110\CommunicationTools\MessengerScreen::getContent() 105 | * @covers \He110\CommunicationTools\MessengerScreen::checkFile() 106 | */ 107 | public function testAddVoice() 108 | { 109 | $this->assertEmpty($this->screen->getContent()); 110 | $this->screen->addVoice(VoiceTest::VOICE_OGG); 111 | $this->assertCount(1, $this->screen->getContent()); 112 | list($ob) = $this->screen->getContent(); 113 | $this->assertEquals(VoiceTest::VOICE_OGG, $ob["path"]); 114 | $this->screen->resetContent(); 115 | $this->assertEmpty($this->screen->getContent()); 116 | 117 | try { 118 | $this->screen->addVoice("not_existed.file"); 119 | } catch (\Exception $e) { 120 | $this->assertEquals(AttachmentNotFoundException::class, get_class($e)); 121 | } 122 | } 123 | 124 | /** 125 | * @covers \He110\CommunicationTools\MessengerScreen::addButtonText() 126 | * @covers \He110\CommunicationTools\MessengerScreen::getContent() 127 | */ 128 | public function testAddButtonText() 129 | { 130 | $this->assertEmpty($this->screen->getContent()); 131 | $this->screen->addButtonText(__METHOD__); 132 | $this->assertCount(1, $this->screen->getContent()); 133 | list($item) = $this->screen->getContent(); 134 | $this->assertEquals(__METHOD__, $item["label"]); 135 | $this->assertEquals(Button::BUTTON_TYPE_TEXT, $item["type"]); 136 | } 137 | 138 | /** 139 | * @covers \He110\CommunicationTools\MessengerScreen::addButtonCallback() 140 | * @covers \He110\CommunicationTools\MessengerScreen::getContent() 141 | */ 142 | public function testAddButtonCallback() 143 | { 144 | $this->assertEmpty($this->screen->getContent()); 145 | $this->screen->addButtonCallback(__METHOD__, function ($a) { echo __METHOD__; }); 146 | $this->assertCount(1, $this->screen->getContent()); 147 | list($item) = $this->screen->getContent(); 148 | $this->assertEquals(__METHOD__, $item["label"]); 149 | $this->assertEquals(Button::BUTTON_TYPE_CALLBACK, $item["type"]); 150 | $this->assertIsCallable($item["content"]); 151 | } 152 | 153 | /** 154 | * @covers \He110\CommunicationTools\MessengerScreen::fixItemsOrder() 155 | * @covers \He110\CommunicationTools\MessengerScreen::fixItemsOrderHelper() 156 | * @covers \He110\CommunicationTools\MessengerScreen::fixItemsOrderSorter() 157 | */ 158 | public function testFixContentOrder() 159 | { 160 | $this->screen->addMessage(__METHOD__); 161 | $this->screen->addButtonText("Text button"); 162 | 163 | $this->assertEquals($this->screen->getContent(false), $this->screen->fixItemsOrder()); 164 | 165 | $this->screen->addVoice(VoiceTest::VOICE_OGG); 166 | 167 | $this->assertEquals($this->screen->getContent(false), $this->screen->fixItemsOrder()); 168 | 169 | $this->screen->addButtonText("After voice"); 170 | 171 | $fixed = $this->screen->fixItemsOrder(); 172 | 173 | $this->assertNotEquals($this->screen->getContent(false), $fixed); 174 | 175 | $this->assertCount(4, $fixed); 176 | $this->assertInstanceOf(Message::class, $fixed[0]); 177 | $this->assertInstanceOf(Button::class, $fixed[1]); 178 | $this->assertInstanceOf(Button::class, $fixed[2]); 179 | $this->assertInstanceOf(Voice::class, $fixed[3]); 180 | 181 | $this->screen->resetContent(); 182 | 183 | $this->screen->addVoice(VoiceTest::VOICE_OGG); 184 | $this->screen->addButtonText("Single button after voice"); 185 | 186 | $fixed = $this->screen->fixItemsOrder(); 187 | 188 | $this->assertCount(3, $fixed); 189 | $this->assertInstanceOf(Message::class, $fixed[0]); 190 | $this->assertInstanceOf(Button::class, $fixed[1]); 191 | $this->assertInstanceOf(Voice::class, $fixed[2]); 192 | } 193 | 194 | /** 195 | * @covers \He110\CommunicationTools\MessengerScreen::getContent() 196 | */ 197 | public function testGetContent() 198 | { 199 | $this->screen->addMessage(__METHOD__); 200 | $this->assertCount(1, $this->screen->getContent()); 201 | list($message) = $this->screen->getContent(); 202 | $this->assertIsArray($message); 203 | 204 | list($message) = $this->screen->getContent(false); 205 | $this->assertInstanceOf(Message::class, $message); 206 | } 207 | 208 | public function setUp(): void 209 | { 210 | $this->screen = new MessengerScreen(); 211 | } 212 | 213 | public function tearDown(): void 214 | { 215 | $this->screen = null; 216 | unset($this->screen); 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /tests/Telegram/MessengerTest.php: -------------------------------------------------------------------------------- 1 | assertTrue($this->client->sendMessage(__METHOD__)); 44 | 45 | 46 | $this->assertTrue($this->client->sendMessage(__METHOD__, $this->generateButtons())); 47 | 48 | $this->client->setTargetUser("123456"); 49 | $this->assertEquals("123456", $this->client->getTargetUser()); 50 | $this->assertFalse($this->client->sendMessage(__METHOD__)); 51 | 52 | $this->client->setTargetUser(null); 53 | $this->expectException(TargetUserException::class); 54 | $this->client->sendMessage(__METHOD__); 55 | } 56 | 57 | /** 58 | * @covers \He110\CommunicationTools\Telegram\Messenger::checkRequirements() 59 | * @covers \He110\CommunicationTools\Telegram\Messenger::setAccessToken() 60 | */ 61 | public function testCheckRequirements() 62 | { 63 | $this->expectException(AccessTokenException::class); 64 | $this->client->setAccessToken(null); 65 | $this->client->sendMessage(__METHOD__); 66 | } 67 | 68 | /** 69 | * @covers \He110\CommunicationTools\Telegram\Messenger::sendScreen() 70 | * @covers \He110\CommunicationTools\Telegram\Messenger::workWithScreenItem() 71 | * @covers \He110\CommunicationTools\Telegram\Messenger::sendScreenHelper() 72 | */ 73 | public function testSendScreen() 74 | { 75 | $screen = new MessengerScreen(); 76 | $screen->addMessage(__METHOD__); 77 | $screen->addButtonLink("Author", "https://zobenko.ru"); 78 | $screen->addButtonText("Hello, world"); 79 | $screen->addImage(FileTest::IMAGE_PATH, "Description"); 80 | $screen->addVoice(VoiceTest::VOICE_WAV); 81 | 82 | $this->assertTrue($this->client->sendScreen($screen)); 83 | } 84 | 85 | /** 86 | * @covers \He110\CommunicationTools\Telegram\Messenger::sendVoice() 87 | * @covers \He110\CommunicationTools\Telegram\Messenger::checkRequirements() 88 | * @covers \He110\CommunicationTools\Telegram\Messenger::checkRequestResult() 89 | * @covers \He110\CommunicationTools\Telegram\Messenger::prepareFile() 90 | */ 91 | public function testSendVoice() 92 | { 93 | $this->assertTrue($this->client->sendVoice(__DIR__."/../Assets/voice.ogg")); 94 | 95 | try { 96 | $this->client->sendVoice(__DIR__ . "/../Assets/not_existed.ogg"); 97 | } catch (\Exception $e) { 98 | $this->assertEquals(AttachmentNotFoundException::class, get_class($e)); 99 | } 100 | 101 | $this->client->setTargetUser("123456"); 102 | $this->assertFalse($this->client->sendVoice(__DIR__."/../Assets/voice.ogg")); 103 | 104 | $this->client->setTargetUser(null); 105 | $this->expectException(TargetUserException::class); 106 | $this->client->sendVoice(__DIR__."/../Assets/voice.ogg"); 107 | } 108 | 109 | /** 110 | * @covers \He110\CommunicationTools\Telegram\Messenger::setAccessToken() 111 | * @covers \He110\CommunicationTools\Telegram\Messenger::getAccessToken() 112 | */ 113 | public function testSetAccessToken() 114 | { 115 | $this->assertEquals(static::API_KEY, $this->client->getAccessToken()); 116 | $newToken = md5(rand(1,100)); 117 | 118 | $this->client->setAccessToken($newToken); 119 | $this->assertEquals($newToken, $this->client->getAccessToken()); 120 | } 121 | 122 | /** 123 | * @covers \He110\CommunicationTools\Telegram\Messenger::sendImage() 124 | * @covers \He110\CommunicationTools\Telegram\Messenger::checkRequirements() 125 | * @covers \He110\CommunicationTools\Telegram\Messenger::checkRequestResult() 126 | * @covers \He110\CommunicationTools\Telegram\Messenger::prepareFile() 127 | * @covers \He110\CommunicationTools\Telegram\Messenger::generateButtonMarkup() 128 | * @covers \He110\CommunicationTools\Telegram\Messenger::buttonToArray() 129 | * @covers \He110\CommunicationTools\Telegram\Messenger::workWithAttachment() 130 | */ 131 | public function testSendImage() 132 | { 133 | $this->assertTrue($this->client->sendImage(__DIR__."/../Assets/image.jpg")); 134 | $this->assertTrue($this->client->sendImage(__DIR__."/../Assets/image.jpg", __METHOD__)); 135 | $this->assertTrue($this->client->sendImage(__DIR__."/../Assets/image.jpg", __METHOD__, $this->generateButtons())); 136 | 137 | try { 138 | $this->client->sendImage(__DIR__ . "/../Assets/not_existed.jpg"); 139 | } catch (\Exception $e) { 140 | $this->assertEquals(AttachmentNotFoundException::class, get_class($e)); 141 | } 142 | 143 | $this->client->setTargetUser("123456"); 144 | $this->assertFalse($this->client->sendImage(__DIR__."/../Assets/image.jpg")); 145 | 146 | $this->client->setTargetUser(null); 147 | $this->expectException(TargetUserException::class); 148 | $this->client->sendImage(__DIR__."/../Assets/image.jpg"); 149 | } 150 | 151 | /** 152 | * @covers \He110\CommunicationTools\Telegram\Messenger::sendDocument() 153 | * @covers \He110\CommunicationTools\Telegram\Messenger::checkRequirements() 154 | * @covers \He110\CommunicationTools\Telegram\Messenger::checkRequestResult() 155 | * @covers \He110\CommunicationTools\Telegram\Messenger::prepareFile() 156 | * @covers \He110\CommunicationTools\Telegram\Messenger::generateButtonMarkup() 157 | * @covers \He110\CommunicationTools\Telegram\Messenger::buttonToArray() 158 | * @covers \He110\CommunicationTools\Telegram\Messenger::workWithAttachment() 159 | */ 160 | public function testSendDocument() 161 | { 162 | $this->assertTrue($this->client->sendDocument(__DIR__."/../Assets/image.jpg")); 163 | $this->assertTrue($this->client->sendDocument(__DIR__."/../Assets/image.jpg", __METHOD__)); 164 | $this->assertTrue($this->client->sendDocument(__DIR__."/../Assets/image.jpg", __METHOD__, $this->generateButtons())); 165 | 166 | try { 167 | $this->client->sendDocument(__DIR__ . "/../Assets/not_existed.jpg"); 168 | } catch (\Exception $e) { 169 | $this->assertEquals(AttachmentNotFoundException::class, get_class($e)); 170 | } 171 | 172 | $this->client->setTargetUser("123456"); 173 | $this->assertFalse($this->client->sendDocument(__DIR__."/../Assets/image.jpg")); 174 | 175 | $this->client->setTargetUser(null); 176 | $this->expectException(TargetUserException::class); 177 | $this->client->sendDocument(__DIR__."/../Assets/image.jpg"); 178 | } 179 | 180 | /** 181 | * @return array 182 | */ 183 | public function generateButtons(): array 184 | { 185 | return [ 186 | Button::create([ 187 | "type" => Button::BUTTON_TYPE_URL, 188 | "label" => "Link", 189 | "content" => "https://zobenko.ru" 190 | ]), 191 | Button::create([ 192 | "type" => Button::BUTTON_TYPE_TEXT, 193 | "label" => "Text" 194 | ]), 195 | Button::create([ 196 | "type" => Button::BUTTON_TYPE_CALLBACK, 197 | "label" => "Callback", 198 | "content" => "callbackFunctionText" 199 | ]) 200 | ]; 201 | } 202 | 203 | public function setUp(): void 204 | { 205 | $this->client = new Messenger(); 206 | $this->client->setAccessToken(static::API_KEY); 207 | $this->client->setTargetUser(static::TARGET_USER); 208 | } 209 | 210 | public function tearDown(): void 211 | { 212 | $this->client = null; 213 | unset($this->client); 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /src/Telegram/Messenger.php: -------------------------------------------------------------------------------- 1 | userId = $userId; 42 | } 43 | 44 | /** 45 | * {@inheritdoc} 46 | */ 47 | public function getTargetUser(): ?string 48 | { 49 | return $this->userId; 50 | } 51 | 52 | /** 53 | * {@inheritdoc} 54 | * 55 | * @param string $text 56 | * @param array $buttons 57 | * @return bool 58 | * @throws AccessTokenException 59 | * @throws TargetUserException 60 | */ 61 | public function sendMessage(string $text, array $buttons = []): bool 62 | { 63 | $this->checkRequirements(); 64 | 65 | try { 66 | $keyboard = $this->generateButtonMarkup($buttons); 67 | $result = $this->client->sendMessage( 68 | $this->getTargetUser(), 69 | $text, 70 | null, 71 | false, 72 | null, 73 | $keyboard 74 | ); 75 | 76 | return method_exists($result, "getMessageId") && $result->getMessageId(); 77 | } catch (\Exception $exception) { 78 | return false; 79 | } 80 | 81 | } 82 | 83 | /** 84 | * {@inheritdoc} 85 | * 86 | * @param string $pathToFile 87 | * @param string|null $description 88 | * @param array $buttons 89 | * @return bool 90 | * @throws AccessTokenException 91 | * @throws AttachmentNotFoundException 92 | * @throws TargetUserException 93 | */ 94 | public function sendImage(string $pathToFile, string $description = null, array $buttons = []): bool 95 | { 96 | return $this->workWithAttachment("image", $pathToFile, $description, $buttons); 97 | } 98 | 99 | /** 100 | * {@inheritdoc} 101 | * 102 | * @param string $pathToFile 103 | * @param string|null $description 104 | * @param array $buttons 105 | * @return bool 106 | * @throws AccessTokenException 107 | * @throws AttachmentNotFoundException 108 | * @throws TargetUserException 109 | */ 110 | public function sendDocument(string $pathToFile, string $description = null, array $buttons = []): bool 111 | { 112 | return $this->workWithAttachment("document", $pathToFile, $description, $buttons); 113 | } 114 | 115 | /** 116 | * @param string $type 117 | * @param $pathToFile 118 | * @param $description 119 | * @param $buttons 120 | * @return bool 121 | * @throws AccessTokenException 122 | * @throws AttachmentNotFoundException 123 | * @throws TargetUserException 124 | */ 125 | private function workWithAttachment(string $type, $pathToFile, $description, $buttons): bool 126 | { 127 | $method = $type == "image" ? "sendPhoto" : "sendDocument"; 128 | $this->checkRequirements(); 129 | $document = $this->prepareFile($pathToFile); 130 | try { 131 | $keyboard = $this->generateButtonMarkup($buttons); 132 | $result = $this->client->{$method}( 133 | $this->getTargetUser(), 134 | $document, 135 | $description, 136 | null, 137 | $keyboard 138 | ); 139 | return $this->checkRequestResult($result); 140 | } catch (\Exception $exception) { 141 | return false; 142 | } 143 | } 144 | 145 | /** 146 | * {@inheritdoc} 147 | * 148 | * @param string $pathToFile 149 | * @return bool 150 | * @throws AccessTokenException 151 | * @throws AttachmentNotFoundException 152 | * @throws TargetUserException 153 | */ 154 | public function sendVoice(string $pathToFile): bool 155 | { 156 | $this->checkRequirements(); 157 | $document = $this->prepareFile($pathToFile); 158 | try { 159 | return $this->checkRequestResult($this->client->sendVoice($this->getTargetUser(), $document)); 160 | } catch (\Exception $exception) { 161 | return false; 162 | } 163 | } 164 | 165 | /** 166 | * {@inheritdoc} 167 | */ 168 | public function sendScreen(MessengerScreen $screen): bool 169 | { 170 | $buttons = array(); 171 | $current = null; 172 | $result = true; 173 | foreach ($screen->fixItemsOrder() as $index => $item) { 174 | if ($item instanceof Button) 175 | $buttons[] = $item; 176 | } 177 | foreach ($screen->fixItemsOrder() as $index => $item) { 178 | if (!($item instanceof Button)) { 179 | list($current, $result, $btns) = $this->sendScreenHelper($current, $item, $result, $buttons); 180 | $buttons = array_merge($buttons, $btns); 181 | $buttons = array_unique($buttons); 182 | } 183 | } 184 | $this->workWithScreenItem($current, $buttons); 185 | return $result; 186 | } 187 | 188 | /** 189 | * @param ScreenItemInterface $item 190 | * @param array $buttons 191 | * @return bool 192 | * @throws AccessTokenException 193 | * @throws AttachmentNotFoundException 194 | * @throws TargetUserException 195 | */ 196 | private function workWithScreenItem(ScreenItemInterface $item, array $buttons = []): bool 197 | { 198 | $class = get_class($item); 199 | switch ($class) { 200 | case \He110\CommunicationTools\ScreenItems\Message::class: 201 | return $this->sendMessage($item->getText(), $buttons); 202 | case Voice::class: 203 | return $this->sendVoice($item->getPath()); 204 | default: 205 | $method = $item->getType() == File::FILE_TYPE_IMAGE ? "sendImage" : "sendDocument"; 206 | return $this->{$method}($item->getPath(), $item->getDescription()); 207 | } 208 | } 209 | 210 | /** 211 | * {@inheritdoc} 212 | */ 213 | public function setAccessToken(?string $token) 214 | { 215 | $this->accessToken = $token; 216 | $this->client = new BotApi($token); 217 | } 218 | 219 | /** 220 | * {@inheritdoc} 221 | */ 222 | public function getAccessToken(): ?string 223 | { 224 | return $this->accessToken; 225 | } 226 | 227 | /** 228 | * @throws AccessTokenException 229 | * @throws TargetUserException 230 | */ 231 | private function checkRequirements() 232 | { 233 | if (is_null($this->client) || !$this->getAccessToken()) { 234 | throw new AccessTokenException("Telegram access token required"); 235 | } 236 | 237 | if (empty($this->getTargetUser())) { 238 | throw new TargetUserException("Target Client ID required"); 239 | } 240 | 241 | } 242 | 243 | /** 244 | * @param string $pathToFile 245 | * @return \CURLFile 246 | * @throws AttachmentNotFoundException 247 | */ 248 | private function prepareFile(string $pathToFile): \CURLFile 249 | { 250 | if (!file_exists($pathToFile)) 251 | throw new AttachmentNotFoundException("Attachment not found"); 252 | return new \CURLFile($pathToFile); 253 | } 254 | 255 | /** 256 | * @param Message $message 257 | * @return bool 258 | */ 259 | private function checkRequestResult(Message $message): bool 260 | { 261 | return method_exists($message, "getMessageId") && $message->getMessageId(); 262 | } 263 | 264 | /** 265 | * @param Button[] $buttons 266 | * @return null|\TelegramBot\Api\Types\Inline\InlineKeyboardMarkup 267 | */ 268 | private function generateButtonMarkup(array $buttons) 269 | { 270 | if ($buttons && current($buttons) instanceof Button) { 271 | $content = []; 272 | foreach ($buttons as $button) { 273 | $content[] = $this->buttonToArray($button); 274 | } 275 | return new \TelegramBot\Api\Types\Inline\InlineKeyboardMarkup($content); 276 | } 277 | return null; 278 | } 279 | 280 | /** 281 | * @param Button $button 282 | * @return array 283 | */ 284 | private function buttonToArray(Button $button): array 285 | { 286 | if ($button->getType() == Button::BUTTON_TYPE_URL) 287 | return array( 288 | array( 289 | "text" => $button->getLabel(), 290 | "url" => $button->getContent() 291 | ) 292 | ); 293 | elseif ($button->getType() == Button::BUTTON_TYPE_CALLBACK) { 294 | return array( 295 | array( 296 | "text" => $button->getLabel(), 297 | "callback_data" => "clb=".$button->getContent() 298 | ) 299 | ); 300 | } 301 | else { 302 | return array( 303 | array( 304 | "text" => $button->getLabel(), 305 | "callback_data" => "text=" . $button->getLabel() 306 | ) 307 | ); 308 | } 309 | } 310 | 311 | /** 312 | * @param $current 313 | * @param $item 314 | * @param $result 315 | * @param $buttons 316 | * @return array 317 | * @throws AccessTokenException 318 | * @throws AttachmentNotFoundException 319 | * @throws TargetUserException 320 | */ 321 | private function sendScreenHelper($current, $item, $result, $buttons): array 322 | { 323 | if ($current === null) { 324 | $current = $item; 325 | } elseif ($current !== $item && $current !== null) { 326 | $result = $result && $this->workWithScreenItem($current, $buttons); 327 | if (!($current instanceof Voice)) { 328 | $buttons = []; 329 | } 330 | $current = $item; 331 | } 332 | return array($current, $result, $buttons); 333 | } 334 | } --------------------------------------------------------------------------------