├── .gitignore ├── .travis.yml ├── LICENCE ├── README.md ├── composer.json ├── makephar ├── phpunit.xml.dist ├── src ├── Attachment.php ├── Exceptions │ ├── SlackBotException.php │ └── SlackRequestException.php ├── Handlers │ ├── CurlHandler.php │ └── RequestHandler.php ├── Message.php ├── Mrkdwn.php ├── SlackBot.php ├── SlackRequest.php ├── Transferrable.php └── WebColors.php └── tests ├── AttachmentTest.php ├── MessageTest.php ├── Mocks └── MockHandler.php ├── MrkdwnTest.php ├── RequestTest.php └── SlackBotTest.php /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### JetBrains template 3 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion 4 | 5 | *.iml 6 | 7 | ## Directory-based project format: 8 | .idea/ 9 | # if you remove the above rule, at least ignore the following: 10 | 11 | # User-specific stuff: 12 | # .idea/workspace.xml 13 | # .idea/tasks.xml 14 | # .idea/dictionaries 15 | 16 | # Sensitive or high-churn files: 17 | # .idea/dataSources.ids 18 | # .idea/dataSources.xml 19 | # .idea/sqlDataSources.xml 20 | # .idea/dynamic.xml 21 | # .idea/uiDesigner.xml 22 | 23 | # Gradle: 24 | # .idea/gradle.xml 25 | # .idea/libraries 26 | 27 | # Mongo Explorer plugin: 28 | # .idea/mongoSettings.xml 29 | 30 | ## File-based project format: 31 | *.ipr 32 | *.iws 33 | 34 | ## Plugin-specific files: 35 | 36 | # IntelliJ 37 | /out/ 38 | 39 | # mpeltonen/sbt-idea plugin 40 | .idea_modules/ 41 | 42 | # JIRA plugin 43 | atlassian-ide-plugin.xml 44 | 45 | # Crashlytics plugin (for Android Studio and IntelliJ) 46 | com_crashlytics_export_strings.xml 47 | crashlytics.properties 48 | crashlytics-build.properties 49 | 50 | 51 | ### Composer template 52 | composer.phar 53 | vendor/ 54 | composer.lock 55 | 56 | # Commit your application's lock file http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file 57 | # You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file 58 | # composer.lock 59 | 60 | 61 | 62 | /phpslackbot.phar 63 | phpunit.local.xml 64 | /.gitignore 65 | 66 | # Commit your application's lock file http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file 67 | # You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file 68 | # composer.lock 69 | 70 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: php 4 | php: 5 | - '5.3' 6 | - '5.4' 7 | - '5.5' 8 | 9 | before_script: composer install 10 | 11 | script: phpunit --coverage-clover=coverage.clover 12 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Vlad Lyga 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PHP-SlackBot [![Packagist](https://img.shields.io/packagist/l/lygav/php-slackbot.svg)](https://packagist.org/packages/lygav/php-slackbot) 2 | 3 | [![Build Status](https://travis-ci.org/lygav/php-slackbot.svg?branch=master)](https://travis-ci.org/lygav/php-slackbot) 4 | [![Scrutinizer](https://img.shields.io/scrutinizer/g/lygav/php-slackbot.svg)]() 5 | [![Packagist](https://img.shields.io/packagist/dt/lygav/php-slackbot.svg)](https://packagist.org/packages/lygav/php-slackbot) 6 | [![Packagist Pre Release](https://img.shields.io/packagist/vpre/lygav/php-slackbot.svg)](https://packagist.org/packages/lygav/php-slackbot) 7 | 8 | 9 | 10 | 11 | Simple, easy to use, PHP package for sending messages to Slack. 12 | Send pretty, colourful messages with rich attachments quickly with this friendly API. 13 | 14 | Compatible with PHP >= 5.3 15 | 16 | ## Installation 17 | ### Via composer 18 | ```json 19 | "require": { 20 | "lygav/php-slackbot": "0.0.*" 21 | } 22 | ``` 23 | 24 | ### Without composer, via PHAR 25 | From the command line, enter into the cloned repository dir and run: 26 | ``` 27 | php makephar 28 | ``` 29 | You will see that a new file was created named "phpslackbot.phar". 30 | Then in your application: 31 | ```php 32 | include 'path/to/phpslackbot.phar'; 33 | ``` 34 | The rest is the same as when installed with 'composer' 35 | 36 | ## Your first message 37 | ```PHP 38 | $bot = new Slackbot("https://hooks.slack.com/services/your/incoming/hook"); 39 | $bot->text("Hi")->send(); 40 | ``` 41 | ## Direct messages 42 | ```PHP 43 | $bot->text("Hi all!") 44 | ->from("username") 45 | ->toChannel("mychannel") 46 | ->send(); 47 | ``` 48 | ## Create pretty, colorful attachments easily 49 | ```PHP 50 | $bot->attach( 51 | $bot->buildAttachment("fallback text") 52 | ->enableMarkdown() 53 | ->setText("We can have *mrkdwn* `code` _italic_ also in attachments") 54 | ) 55 | ->toGroup("mygroup") 56 | ->send(); 57 | ``` 58 | 59 | ## Customise freely 60 | ```PHP 61 | $attachment = $bot->buildAttachment("fallback text"/* mandatory by slack */) 62 | ->setPretext("pretext line") 63 | ->setText("attachment body text") 64 | /* 65 | Human web-safe colors automatically 66 | translated into HEX equivalent 67 | */ 68 | ->setColor("lightblue") 69 | ->setAuthor("me") 70 | ->addField("short field", "i'm inline", TRUE) 71 | ->addField("short field 2", "i'm also inline", TRUE) 72 | ->setImageUrl("http://my-website.com/path/to/image.jpg"); 73 | 74 | $bot->attach($attachment)->send(); 75 | ``` 76 | 77 | ## Set/ Override every possible setting 78 | ```PHP 79 | $options = array( 80 | 'username' => 'my-bot-name', 81 | 'icon_emoji' => ':icon name:', 82 | 'icon_url' => 'http://someicon.com', 83 | 'channel' => '#test-channel' 84 | ); 85 | 86 | $bot = new Slackbot($url, $options); 87 | $bot->text("check out bot new icon")->send(); 88 | 89 | // Choose to override 'last minute' (ex. when dealing with multiple consequtive messages) 90 | $bot->text("check out bot new icon")->send(array("username" => "other-bot-name")); 91 | ``` 92 | 93 | # Advanced Usage 94 | 95 | ## Use custom transfer handlers 96 | ```PHP 97 | $handler = new MockHandler(); 98 | $bot = new SlackBot($url, ['handler' => $handler]); 99 | $bot->text("some text") 100 | ->from("my-test-bot") 101 | ->toGroup("bot-testing") 102 | ->send(); 103 | ``` 104 | 105 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lygav/php-slackbot", 3 | "description": "Simple, easy to use, PHP package for sending messages to Slack. Send pretty, colourful messages with rich attachments quickly with this friendly API", 4 | "minimum-stability": "stable", 5 | "homepage": "https://github.com/lygav/php-slackbot", 6 | "keywords": [ 7 | "slack", 8 | "slackbot", 9 | "php-slackbot" 10 | ], 11 | "license": "MIT", 12 | "type": "library", 13 | "authors": [ 14 | { 15 | "name": "Vladimir (Vladi) Lyga", 16 | "homepage": "https://github.com/lygav", 17 | "email": "lyvladi@gmail.com" 18 | } 19 | ], 20 | 21 | "require": { 22 | "php": ">=5.3" 23 | }, 24 | 25 | "require-dev": { 26 | "phpunit/phpunit": "3.7.*" 27 | }, 28 | 29 | "autoload": { 30 | "psr-4": { 31 | "lygav\\slackbot\\": "src/" 32 | } 33 | }, 34 | 35 | "autoload-dev": { 36 | "psr-4": { "lygav\\slackbot\\tests\\": "tests/" } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /makephar: -------------------------------------------------------------------------------- 1 | buildFromDirectory(dirname(__FILE__)); 6 | $stub = ' 7 | 17 | '; 18 | 19 | spl_autoload_register(function($class) { 20 | $filepath = str_replace("lygav\\slackbot", "src/", $class); 21 | $filepath = str_replace("\\", "/", $filepath); 22 | $path = dirname(__FILE__)."/".$filepath.".php"; 23 | include $path; 24 | }); 25 | 26 | 27 | $phar->setStub($stub); 28 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | ./tests 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/Attachment.php: -------------------------------------------------------------------------------- 1 | options["fallback"] = (string) $fallback; 15 | } 16 | 17 | public static function fromOptions(array $options) 18 | { 19 | if ( ! isset($options['fallback'])) { 20 | throw new SlackBotException("'fallback' is mandatory for 21 | attachments"); 22 | } 23 | $attachment = new self($options['fallback']); 24 | if (isset($options['color'])) { 25 | $attachment->setColor($options['color']); 26 | unset($options['color']); 27 | } 28 | $attachment->options = array_replace($attachment->options, $options); 29 | return $attachment; 30 | } 31 | 32 | public function serialize() 33 | { 34 | return $this->options; 35 | } 36 | 37 | public function enableMarkdown(array $in_options = array()) 38 | { 39 | if (empty($in_options)) { 40 | $this->applyOption("mrkdwn_in", array_keys($this->options)); 41 | } else { 42 | $this->applyOption("mrkdwn_in", $in_options); 43 | } 44 | return $this; 45 | } 46 | 47 | public function setTitle($title) 48 | { 49 | $this->applyOption('title', $title); 50 | return $this; 51 | } 52 | 53 | public function addField($title, $text, $is_short = FALSE) 54 | { 55 | if ( ! isset($this->options['fields']) 56 | OR ! is_array($this->options['fields']) 57 | ) { 58 | $this->options['fields'] = array(); 59 | } 60 | array_push($this->options['fields'], array( 61 | 'title' => $title, 62 | 'value' => $text, 63 | 'short' => $is_short 64 | )); 65 | return $this; 66 | } 67 | 68 | public function setAuthor($name, $link = NULL, $icon = NULL) 69 | { 70 | $this->applyOption('author_name', $name); 71 | $this->applyOption('author_link', $link); 72 | $this->applyOption('author_icon', $icon); 73 | return $this; 74 | } 75 | 76 | public function setColor($color) 77 | { 78 | $this->applyOption('color', WebColors::human2hex($color) ? : $color); 79 | return $this; 80 | } 81 | 82 | public function setText($text) 83 | { 84 | $this->applyOption('text', $text); 85 | return $this; 86 | } 87 | 88 | /** 89 | * @param string $pretext 90 | */ 91 | public function setPretext($pretext) 92 | { 93 | $this->applyOption('pretext', $pretext); 94 | return $this; 95 | } 96 | 97 | /** 98 | * @param null $image_url 99 | */ 100 | public function setImageUrl($image_url) 101 | { 102 | $this->applyOption('image_url', $image_url); 103 | return $this; 104 | } 105 | 106 | /** 107 | * @param null $thumb_url 108 | */ 109 | public function setThumbUrl($thumb_url) 110 | { 111 | $this->applyOption('thumb_url', $thumb_url); 112 | return $this; 113 | } 114 | 115 | private function applyOption($name, $value) 116 | { 117 | $this->options[$name] = $value; 118 | return $this; 119 | } 120 | } -------------------------------------------------------------------------------- /src/Exceptions/SlackBotException.php: -------------------------------------------------------------------------------- 1 | $request->url(), 17 | CURLOPT_POSTFIELDS => $request->body(), 18 | CURLOPT_SSL_VERIFYPEER => FALSE, 19 | CURLOPT_SSL_VERIFYHOST => FALSE, 20 | CURLOPT_POST => TRUE, 21 | CURLOPT_RETURNTRANSFER => TRUE, 22 | ) 23 | ); 24 | $result = curl_exec($ch); 25 | curl_close($ch); 26 | return $result; 27 | } 28 | } -------------------------------------------------------------------------------- /src/Handlers/RequestHandler.php: -------------------------------------------------------------------------------- 1 | text = (string) $text; 14 | $this->options = $options; 15 | } 16 | 17 | public function attach(Attachment $attachment) 18 | { 19 | array_push($this->attachments, $attachment->serialize()); 20 | } 21 | 22 | public function serialize() 23 | { 24 | $ret = array_merge(array('text' => $this->text), $this->options); 25 | if ( ! empty($this->attachments)) { 26 | $ret['attachments'] = $this->attachments; 27 | } 28 | return $ret; 29 | } 30 | } -------------------------------------------------------------------------------- /src/Mrkdwn.php: -------------------------------------------------------------------------------- 1 | ", (strpos($slackname, "@") === 0 ? "" : "@") . $slackname); 11 | } 12 | 13 | public static function channelRef($channel) 14 | { 15 | $channel = self::normalize($channel); 16 | return sprintf("<%s>", (strpos($channel, "#") === 0 ? "" : "#") . $channel); 17 | } 18 | 19 | public static function code($text) 20 | { 21 | return sprintf("`%s`", $text); 22 | } 23 | 24 | public static function pre($text) 25 | { 26 | return sprintf("```%s```", $text); 27 | } 28 | 29 | public static function link($url, $alias) 30 | { 31 | $url = self::normalize($url); 32 | $alias = self::normalize($alias); 33 | return sprintf("<%s|%s>", $url, $alias); 34 | } 35 | 36 | private static function normalize($string) 37 | { 38 | return preg_replace( 39 | array("#(^\s|\s$)+#", "#[\r\n\s\s]+#"), array("", " "), $string); 40 | } 41 | } -------------------------------------------------------------------------------- /src/SlackBot.php: -------------------------------------------------------------------------------- 1 | webhook_url = $webhook_url; 21 | if (isset($options['handler'])) { 22 | $this->handler = $options['handler']; 23 | unset($options['handler']); 24 | } 25 | $this->global_options = $options; 26 | } 27 | 28 | public function text($text) 29 | { 30 | $this->text = $text; 31 | return $this; 32 | } 33 | 34 | public function from($name) 35 | { 36 | $this->setRequestOption('username', $name); 37 | return $this; 38 | } 39 | 40 | public function attach(Attachment $attachment) 41 | { 42 | array_push($this->attachments, $attachment); 43 | return $this; 44 | } 45 | 46 | public function buildAttachment($fallback_text) 47 | { 48 | return new Attachment($fallback_text); 49 | } 50 | 51 | public function toChannel($name) 52 | { 53 | $this->setRequestChannel($name); 54 | return $this; 55 | } 56 | 57 | public function toGroup($name) 58 | { 59 | $this->setRequestChannel($name); 60 | return $this; 61 | } 62 | 63 | public function toPerson($name) 64 | { 65 | $this->setRequestChannel($name, TRUE); 66 | return $this; 67 | } 68 | 69 | public function send(array $options = array()) 70 | { 71 | $options = array_replace($this->global_options, $this->request_options, $options); 72 | $message = new Message($this->text, $options); 73 | if ( ! empty($this->attachments)) { 74 | array_map(array($message, 'attach'), $this->attachments); 75 | } 76 | $request = new SlackRequest($this->webhook_url, $message); 77 | $this->transfer($request); 78 | $this->reset(); 79 | } 80 | 81 | public function disableMarkdown() 82 | { 83 | $this->setRequestOption('mrkdwn', FALSE); 84 | return $this; 85 | } 86 | 87 | public function enableMarkdown() 88 | { 89 | $this->setRequestOption('mrkdwn', TRUE); 90 | return $this; 91 | } 92 | 93 | private function transfer(SlackRequest $request) 94 | { 95 | $result = call_user_func($this->handler(), $request); 96 | if ($result !== 'ok') { 97 | throw new SlackRequestException($result); 98 | } else { 99 | return $result; 100 | } 101 | } 102 | 103 | private function reset() 104 | { 105 | $this->attachments = array(); 106 | $this->text = ""; 107 | $this->request_options = array(); 108 | } 109 | 110 | private function handler() 111 | { 112 | return $this->handler ? : new CurlHandler(); 113 | } 114 | 115 | private function setRequestChannel($name, $private = FALSE) 116 | { 117 | if ($private) { 118 | $this->setRequestOption('channel', strpos($name, "@") === 0 ? : "@".$name); 119 | } else { 120 | $this->setRequestOption('channel', strpos($name, "#") === 0 ? : "#".$name); 121 | } 122 | } 123 | 124 | private function setRequestOption($name, $value) 125 | { 126 | $this->request_options[$name] = $value; 127 | } 128 | } -------------------------------------------------------------------------------- /src/SlackRequest.php: -------------------------------------------------------------------------------- 1 | url = $url; 16 | $this->setBody($message->serialize()); 17 | } 18 | 19 | public function body() 20 | { 21 | return $this->payload_for($this->body); 22 | } 23 | 24 | private function setBody(array $body) 25 | { 26 | $empty_body = array('text' => ''); 27 | if ($body === $empty_body) { 28 | throw new SlackRequestException("Trying to construct SlackRequest with empty message"); 29 | } 30 | $this->body = $body; 31 | } 32 | 33 | public function url() 34 | { 35 | return $this->url; 36 | } 37 | 38 | private function payload_for($body) 39 | { 40 | return http_build_query( 41 | array("payload" => json_encode($body)) 42 | ); 43 | } 44 | } -------------------------------------------------------------------------------- /src/Transferrable.php: -------------------------------------------------------------------------------- 1 | "#F0F8FF", 9 | "antiquewhite" => "#FAEBD7", 10 | "aqua" => "#00FFFF", 11 | "aquamarine" => "#7FFFD4", 12 | "azure" => "#F0FFFF", 13 | "beige" => "#F5F5DC", 14 | "bisque" => "#FFE4C4", 15 | "black" => "#000000", 16 | "blanchedalmond" => "#FFEBCD", 17 | "blue" => "#0000FF", 18 | "blueviolet" => "#8A2BE2", 19 | "brown" => "#A52A2A", 20 | "burlywood" => "#DEB887", 21 | "cadetblue" => "#5F9EA0", 22 | "chartreuse" => "#7FFF00", 23 | "chocolate" => "#D2691E", 24 | "coral" => "#FF7F50", 25 | "cornflowerblue" => "#6495ED", 26 | "cornsilk" => "#FFF8DC", 27 | "crimson" => "#DC143C", 28 | "cyan" => "#00FFFF", 29 | "darkblue" => "#00008B", 30 | "darkcyan" => "#008B8B", 31 | "darkgoldenrod" => "#B8860B", 32 | "darkgray" => "#A9A9A9", 33 | "darkgreen" => "#006400", 34 | "darkkhaki" => "#BDB76B", 35 | "darkmagenta" => "#8B008B", 36 | "darkolivegreen" => "#556B2F", 37 | "darkorange" => "#FF8C00", 38 | "darkorchid" => "#9932CC", 39 | "darkred" => "#8B0000", 40 | "darksalmon" => "#E9967A", 41 | "darkseagreen" => "#8FBC8F", 42 | "darkslateblue" => "#483D8B", 43 | "darkslategray" => "#2F4F4F", 44 | "darkturquoise" => "#00CED1", 45 | "darkviolet" => "#9400D3", 46 | "deeppink" => "#FF1493", 47 | "deepskyblue" => "#00BFFF", 48 | "dimgray" => "#696969", 49 | "dodgerblue" => "#1E90FF", 50 | "firebrick" => "#B22222", 51 | "floralwhite" => "#FFFAF0", 52 | "forestgreen" => "#228B22", 53 | "fuchsia" => "#FF00FF", 54 | "gainsboro" => "#DCDCDC", 55 | "ghostwhite" => "#F8F8FF", 56 | "gold" => "#FFD700", 57 | "goldenrod" => "#DAA520", 58 | "gray" => "#808080", 59 | "green" => "#008000", 60 | "greenyellow" => "#ADFF2F", 61 | "honeydew" => "#F0FFF0", 62 | "hotpink" => "#FF69B4", 63 | "indianred" => "#CD5C5C", 64 | "indigo" => "#4B0082", 65 | "ivory" => "#FFFFF0", 66 | "khaki" => "#F0E68C", 67 | "lavender" => "#E6E6FA", 68 | "lavenderblush" => "#FFF0F5", 69 | "lawngreen" => "#7CFC00", 70 | "lemonchiffon" => "#FFFACD", 71 | "lightblue" => "#ADD8E6", 72 | "lightcoral" => "#F08080", 73 | "lightcyan" => "#E0FFFF", 74 | "lightgoldenrodyellow" => "#FAFAD2", 75 | "lightgray" => "#D3D3D3", 76 | "lightgreen" => "#90EE90", 77 | "lightpink" => "#FFB6C1", 78 | "lightsalmon" => "#FFA07A", 79 | "lightseagreen" => "#20B2AA", 80 | "lightskyblue" => "#87CEFA", 81 | "lightslategray" => "#778899", 82 | "lightsteelblue" => "#B0C4DE", 83 | "lightyellow" => "#FFFFE0", 84 | "lime" => "#00FF00", 85 | "limegreen" => "#32CD32", 86 | "linen" => "#FAF0E6", 87 | "magenta" => "#FF00FF", 88 | "maroon" => "#800000", 89 | "mediumaquamarine" => "#66CDAA", 90 | "mediumblue" => "#0000CD", 91 | "mediumorchid" => "#BA55D3", 92 | "mediumpurple" => "#9370DB", 93 | "mediumseagreen" => "#3CB371", 94 | "mediumslateblue" => "#7B68EE", 95 | "mediumspringgreen" => "#00FA9A", 96 | "mediumturquoise" => "#48D1CC", 97 | "mediumvioletred" => "#C71585", 98 | "midnightblue" => "#191970", 99 | "mintcream" => "#F5FFFA", 100 | "mistyrose" => "#FFE4E1", 101 | "moccasin" => "#FFE4B5", 102 | "navajowhite" => "#FFDEAD", 103 | "navy" => "#000080", 104 | "oldlace" => "#FDF5E6", 105 | "olive" => "#808000", 106 | "olivedrab" => "#6B8E23", 107 | "orange" => "#FFA500", 108 | "orangered" => "#FF4500", 109 | "orchid" => "#DA70D6", 110 | "palegoldenrod" => "#EEE8AA", 111 | "palegreen" => "#98FB98", 112 | "paleturquoise" => "#AFEEEE", 113 | "palevioletred" => "#DB7093", 114 | "papayawhip" => "#FFEFD5", 115 | "peachpuff" => "#FFDAB9", 116 | "peru" => "#CD853F", 117 | "pink" => "#FFC0CB", 118 | "plum" => "#DDA0DD", 119 | "powderblue" => "#B0E0E6", 120 | "purple" => "#800080", 121 | "rebeccapurple" => "#663399", 122 | "red" => "#FF0000", 123 | "rosybrown" => "#BC8F8F", 124 | "royalblue" => "#4169E1", 125 | "saddlebrown" => "#8B4513", 126 | "salmon" => "#FA8072", 127 | "sandybrown" => "#F4A460", 128 | "seagreen" => "#2E8B57", 129 | "seashell" => "#FFF5EE", 130 | "sienna" => "#A0522D", 131 | "silver" => "#C0C0C0", 132 | "skyblue" => "#87CEEB", 133 | "slateblue" => "#6A5ACD", 134 | "slategray" => "#708090", 135 | "snow" => "#FFFAFA", 136 | "springgreen" => "#00FF7F", 137 | "steelblue" => "#4682B4", 138 | "tan" => "#D2B48C", 139 | "teal" => "#008080", 140 | "thistle" => "#D8BFD8", 141 | "tomato" => "#FF6347", 142 | "turquoise" => "#40E0D0", 143 | "violet" => "#EE82EE", 144 | "wheat" => "#F5DEB3", 145 | "white" => "#FFFFFF", 146 | "whitesmoke" => "#F5F5F5", 147 | "yellow" => "#FFFF00", 148 | "YellowGreen" => "#9ACD32" 149 | ); 150 | 151 | public static function human2hex($color_name) 152 | { 153 | $color_name = strtolower((string) $color_name); 154 | if (array_key_exists($color_name, self::$color_map)) { 155 | return self::$color_map[$color_name]; 156 | } 157 | return FALSE; 158 | } 159 | 160 | public static function hex2human($color_code) 161 | { 162 | $color_code = strtoupper((string) $color_code); 163 | if (FALSE !== ($index = array_search($color_code, self::$color_map))) { 164 | return $index; 165 | } 166 | return FALSE; 167 | } 168 | } -------------------------------------------------------------------------------- /tests/AttachmentTest.php: -------------------------------------------------------------------------------- 1 | assertEquals(array ('fallback' => 'test fallback text'), $attachment->serialize()); 16 | } 17 | 18 | public function testCanCreateFromFullOptionsArray() 19 | { 20 | $options = array( 21 | 'fallback' => 'fallback test', 22 | 'color' => '#000000', 23 | 'author_name' => 'bobby', 24 | 'author_link' => 'http://flickr.com/bobby/', 25 | 'author_icon' => 'http://flickr.com/icons/bobby.jpg', 26 | 'title' => 'Optional title', 27 | 'text' => 'optional text', 28 | 'pretext' => 'optional pretext', 29 | 'image_url' => 'http://my-website.com/path/to/image.jpg', 30 | 'thumb_url' => 'http://example.com/path/to/thumb.png' 31 | ); 32 | $attachment = Attachment::fromOptions($options); 33 | $this->assertEquals($options, $attachment->serialize()); 34 | } 35 | 36 | public function testEnableMarkdownForAllOptions() 37 | { 38 | $options = array( 39 | 'fallback' => 'fallback text', 40 | 'text' => 'my bold *text*', 41 | 'pretext' => 'some _italic_ markdown here' 42 | ); 43 | $attachment = Attachment::fromOptions($options); 44 | $attachment->enableMarkdown(); 45 | $this->assertEquals(array ( 46 | 'fallback' => 'fallback text', 47 | 'text' => 'my bold *text*', 48 | 'pretext' => 'some _italic_ markdown here', 49 | 'mrkdwn_in' => 50 | array ( 51 | 'fallback', 52 | 'text', 53 | 'pretext', 54 | ), 55 | ), $attachment->serialize()); 56 | } 57 | 58 | public function testEnableMarkdownOnlyForSelectedOptions() 59 | { 60 | $options = array( 61 | 'fallback' => 'fallback text', 62 | 'text' => 'my bold *text*', 63 | 'pretext' => 'some _italic_ markdown here' 64 | ); 65 | $attachment = Attachment::fromOptions($options); 66 | $attachment->enableMarkdown(array('text')); 67 | $this->assertEquals(array ( 68 | 'fallback' => 'fallback text', 69 | 'text' => 'my bold *text*', 70 | 'pretext' => 'some _italic_ markdown here', 71 | 'mrkdwn_in' => 72 | array ( 73 | 'text' 74 | ), 75 | ), $attachment->serialize()); 76 | } 77 | 78 | public function testReplaceHumanColorNameWithHexCode() 79 | { 80 | $options = array('fallback' => 'fallback text', 'color' => 'black'); 81 | $attachment = Attachment::fromOptions($options); 82 | $options['color'] = WebColors::human2hex($options['color']); 83 | $this->assertEquals($options, $attachment->serialize()); 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /tests/MessageTest.php: -------------------------------------------------------------------------------- 1 | assertEquals( 16 | array("text" => $text), 17 | $message->serialize() 18 | ); 19 | } 20 | 21 | public function testSerializeWithOptions() 22 | { 23 | $text = "hello world"; 24 | $options = array( 25 | 'username' => 'my-bot-name', 26 | 'icon_emoji' => ':icon name:', 27 | 'icon_url' => 'http://someicon.com', 28 | 'channel' => '#test-channel' 29 | ); 30 | $message = new Message($text, $options); 31 | $this->assertEquals( 32 | array_merge(array("text" => $text), $options), 33 | $message->serialize() 34 | ); 35 | } 36 | 37 | public function testSerializeWithAttachment() 38 | { 39 | $text = "hello worlds"; 40 | $message = new Message($text); 41 | $message->attach(new Attachment('plain text fallback')); 42 | $this->assertEquals( 43 | array( 44 | "text" => $text, 45 | "attachments" => array( 46 | array("fallback" => "plain text fallback") 47 | ) 48 | ), 49 | $message->serialize() 50 | ); 51 | } 52 | 53 | 54 | } 55 | -------------------------------------------------------------------------------- /tests/Mocks/MockHandler.php: -------------------------------------------------------------------------------- 1 | request = $request; 14 | return 'ok'; 15 | } 16 | 17 | public function lastRequest() 18 | { 19 | return $this->request; 20 | } 21 | } -------------------------------------------------------------------------------- /tests/MrkdwnTest.php: -------------------------------------------------------------------------------- 1 | '), 14 | array('@withsign', '<@withsign>') 15 | ); 16 | } 17 | 18 | /** 19 | * @dataProvider userNames 20 | */ 21 | public function testFormatsNameStringIntoUserReference($unformatted, $expected) 22 | { 23 | $this->assertEquals( 24 | $expected, 25 | Mrkdwn::userRef($unformatted) 26 | ); 27 | } 28 | 29 | public function chanelNames() 30 | { 31 | return array( 32 | array('withoutatsign', '<#withoutatsign>'), 33 | array('#withsign', '<#withsign>') 34 | ); 35 | } 36 | 37 | /** 38 | * @dataProvider chanelNames 39 | */ 40 | public function testFormatNameStringIntoChannelReference($unformatted, $expected) 41 | { 42 | $this->assertEquals( 43 | $expected, 44 | Mrkdwn::channelRef($unformatted) 45 | ); 46 | } 47 | 48 | public function strings() 49 | { 50 | return array( 51 | array("http://google.com", "search google", ""), 52 | array("http://google.com", "search google", ""), 53 | array(" http://google.com ", " search google ", ""), 54 | array("http://google.com", "search\ngoogle", ""), 55 | array("http://google.com", "search\r\ngoogle", ""), 56 | ); 57 | } 58 | 59 | /** 60 | * @dataProvider strings 61 | */ 62 | public function testNormalizeText($link, $alias, $expected) 63 | { 64 | $this->assertEquals( 65 | $expected, 66 | Mrkdwn::link($link, $alias) 67 | ); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /tests/RequestTest.php: -------------------------------------------------------------------------------- 1 | assertEquals('payload={"text":"hello world"}', 18 | urldecode($request->body())); 19 | } 20 | 21 | public function testCreatePayloadForMessageWithAttachment() 22 | { 23 | $message = new Message('hello world'); 24 | $message->attach(new Attachment("fallback text")); 25 | $request = new SlackRequest('http://url.com', $message); 26 | 27 | $this->assertEquals('payload={"text":"hello world","attachments":[{"fallback":"fallback text"}]}', 28 | urldecode($request->body())); 29 | } 30 | 31 | public function emptyMessageProvider() 32 | { 33 | return array( 34 | array(new Message(NULL)), 35 | array(new Message("")) 36 | ); 37 | } 38 | 39 | /** 40 | * @dataProvider emptyMessageProvider 41 | * @expectedException lygav\slackbot\Exceptions\SlackRequestException 42 | */ 43 | public function testExceptionOnEmptyMessage(Message $message) 44 | { 45 | new SlackRequest("www.url.com", $message); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tests/SlackBotTest.php: -------------------------------------------------------------------------------- 1 | handler = new MockHandler(); 25 | $this->slackbot = new SlackBot($this->url, array('handler' => $this->handler)); 26 | } 27 | 28 | public function testSupplyCustomHandler() 29 | { 30 | $handler = new MockHandler(); 31 | $bot = new SlackBot($this->url, array('handler' => $handler)); 32 | $bot->text("some text") 33 | ->from("my-test-bot") 34 | ->toGroup("bot-testing") 35 | ->send(); 36 | $this->assertInstanceOf("lygav\\slackbot\\SlackRequest", $handler->lastRequest()); 37 | } 38 | 39 | public function testOverrideOptionsOnSend() 40 | { 41 | $slack = $this->defaultTestBot(); 42 | $slack->text("some text")->send(array( 43 | "username" => "overriden-bot-name" 44 | )); 45 | } 46 | 47 | public function testSendMessageWithSimpleAttachment() 48 | { 49 | $slack = $this->defaultTestBot(); 50 | $slack->text("Markdown formatted text with *bold* `code` _italic_") 51 | ->attach( 52 | $slack->buildAttachment("fallback text") 53 | ->enableMarkdown() 54 | ->setText("We can have *mrkdwn* `code` _italic_ also in attachments") 55 | ) 56 | ->toGroup("bot-testing") 57 | ->send(); 58 | } 59 | 60 | public function testCreateCompleteAttachments() 61 | { 62 | $slack = $this->defaultTestBot(); 63 | $attachment = $slack->buildAttachment("fallback text"/* mandatory by slack */) 64 | ->setPretext("pretext line") 65 | ->setText("attachment body text") 66 | /* 67 | Human web-safe colors automatically 68 | translated into HEX equivalent 69 | */ 70 | ->setColor("lightblue") 71 | ->setAuthor("tester") 72 | ->addField("short field", "i'm inline", TRUE) 73 | ->addField("short field 2", "i'm also inline", TRUE) 74 | ->setImageUrl("http://my-website.com/path/to/image.jpg"); 75 | 76 | $slack->attach($attachment)->send(); 77 | } 78 | 79 | /** 80 | * @expectedException lygav\slackbot\Exceptions\SlackRequestException 81 | */ 82 | public function testThrowExceptionOnEmptyRequest() 83 | { 84 | $bot = new SlackBot($this->url); 85 | $bot->send(); 86 | } 87 | 88 | /** 89 | * @return SlackBot 90 | */ 91 | public function defaultTestBot() 92 | { 93 | return $this->slackbot; 94 | } 95 | } --------------------------------------------------------------------------------