From 0a7da2ae15b2e914a1d67aad624a9a6a9de3aae8 Mon Sep 17 00:00:00 2001 From: Matus Petrofcik - behemoth Date: Wed, 11 Oct 2017 09:51:52 +0200 Subject: [PATCH 1/3] Added file for things to do. --- TODO.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 TODO.md diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..79cbcb0 --- /dev/null +++ b/TODO.md @@ -0,0 +1 @@ +# Things to do... From 7939e2f36c779ce00ce504b528f4bf1054640967 Mon Sep 17 00:00:00 2001 From: Matus Petrofcik - behemoth Date: Tue, 24 Oct 2017 13:49:03 +0200 Subject: [PATCH 2/3] Update. --- config-dist/slack-module.local.php | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 config-dist/slack-module.local.php diff --git a/config-dist/slack-module.local.php b/config-dist/slack-module.local.php new file mode 100644 index 0000000..092c444 --- /dev/null +++ b/config-dist/slack-module.local.php @@ -0,0 +1,9 @@ + [ + 'slack_module' => [ + // todo + ], + ], +]; From 861c94e93e0aeb0036b91d6b773da5c1e6296695 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Josef=20Sou=C5=A1ek?= Date: Wed, 21 Mar 2018 16:45:43 +0100 Subject: [PATCH 3/3] progress - 2018-03-21 --- README.md | 129 +++++++ composer.json | 3 +- config-dist/slack-module.local.php | 26 +- config/module.config.php | 8 +- src/Model/Attachment.php | 115 ++++++ src/Model/AttachmentAction.php | 388 ++++++++++++++++++++ src/Model/AttachmentActionConfirm.php | 135 +++++++ src/Service/Factory/SlackServiceFactory.php | 49 +++ src/Service/SlackService.php | 98 +++++ src/Service/SlackServiceInterface.php | 13 + 10 files changed, 961 insertions(+), 3 deletions(-) create mode 100644 src/Model/Attachment.php create mode 100644 src/Model/AttachmentAction.php create mode 100644 src/Model/AttachmentActionConfirm.php create mode 100644 src/Service/Factory/SlackServiceFactory.php create mode 100644 src/Service/SlackService.php create mode 100644 src/Service/SlackServiceInterface.php diff --git a/README.md b/README.md index d72770f..c512bbd 100644 --- a/README.md +++ b/README.md @@ -5,3 +5,132 @@ ZF3 module for Slack communication [![Packagist](https://img.shields.io/packagist/v/massimo-filippi/slack-module.svg)](https://packagist.org/packages/massimo-filippi/slack-module) [![License](http://img.shields.io/:license-mit-blue.svg)](http://doge.mit-license.org) + +## Introduction + +There will be more info soon... + +## Installation + +### 1. Install via Composer + +Install the latest stable version via Composer: + +``` +composer require massimo-filippi/slack-module +``` + +Install the latest develop version via Composer: + +``` +composer require massimo-filippi/slack-module:dev-master +``` + +### 2. Enable module in your application + +Composer should enable `MassimoFilippi\SlackModule` in your project automatically during installation. + +In case it does not, you can enable module manually by adding value `'MassimoFilippi\SlackModule'` to array in file `config/modules.config.php`. At the end, it should look like PHP array below. + +```php + [ + 'slack_module' => [ + 'config' => [ + 'webhook_url' => 'https://hooks.slack.com/services/#########/#########/########################', + // Whether names like @regan should be converted into links by Slack, default: false + 'link_names' => false, + // Whether Slack should unfurl links to text-based content, default: false + 'unfurl_links' => false, + // Whether Slack should unfurl links to media content such as images and YouTube videos, default: true + 'unfurl_media' => true, + // Whether message text should be interpreted in Slack's Markdown-like language. For formatting options, see Slack's help article: http://goo.gl/r4fsdO, default: true + 'allow_markdown' => true, + // Which attachment fields should be interpreted in Slack's Markdown-like language. By default, Slack assumes that no fields in an attachment should be formatted as Markdown. // default: [] + 'markdown_in_attachments' => [], + + // Allow Markdown in just the text and title fields + //// 'markdown_in_attachments' => ['text', 'title'] + // Allow Markdown in all fields + //// 'markdown_in_attachments' => ['pretext', 'text', 'title', 'fields', 'fallback'] + + 'defaults' => [ + // default username, set to null to use the default set on the Slack webhook, default: null + 'username' => 'Slack module', + // default channel, channel: #general, user: @john.doe, set to null to use the default set on the Slack webhook, default: null + 'channel' => '#general', + // URL to an image or Slack emoji like :ghost: or :+1:, set null to use the default set on the Slack webhook, default: null + 'icon' => null + ], + ], + ], + ], +]; + +``` + +## Usage + +Somewhere in business logic classes. + +```php +slackService->createMessage(); +$slackMessage->to('#general') + ->from('John Doe') + ->withIcon(':ghost:') + ->setText('This is an amazing message!'); + +/** @var SlackAttachment $slackAttachment */ +$slackAttachment = $this->slackService->createAttachment([ + 'fallback' => 'Some fallback text', + 'text' => 'The attachment text' + ]); +$slackMessage->attach($slackAttachment); + +try { + // Injected MassimoFilippi\SlackModule\Service\SlackService. + $this->slackService->sendMessage($slackMessage); +} catch (\Exception $exception) { + var_dump($exception->getMessage()); +} +``` + +## Methods + +* Create message: + * ```$this->slackService->createMessage();``` +* Create attachment: + * ```$this->slackService->createAttachment($arguments);``` + * See Slack documentation: https://api.slack.com/docs/message-attachments +* Create attachment field: + * ```$this->slackService->createAttachementField($arguments);``` + * See Slack documentation: https://api.slack.com/docs/message-attachments + +* Create attachment action: + * ```$this->slackService->createAttachementAction($arguments);``` + * See Slack documentation: https://api.slack.com/docs/message-attachments diff --git a/composer.json b/composer.json index 5c9af20..f2828db 100644 --- a/composer.json +++ b/composer.json @@ -14,7 +14,8 @@ "minimum-stability": "dev", "prefer-stable": true, "require": { - "php": "^5.6 || ^7.0" + "php": "^5.6 || ^7.0", + "maknz/slack": "^1.7" }, "autoload": { "psr-4": { diff --git a/config-dist/slack-module.local.php b/config-dist/slack-module.local.php index 092c444..019b324 100644 --- a/config-dist/slack-module.local.php +++ b/config-dist/slack-module.local.php @@ -3,7 +3,31 @@ return [ 'massimo_filippi' => [ 'slack_module' => [ - // todo + 'webhook_url' => 'https://hooks.slack.com/services/#########/#########/########################', + // Whether names like @regan should be converted into links by Slack, default: false + 'link_names' => false, + // Whether Slack should unfurl links to text-based content, default: false + 'unfurl_links' => false, + // Whether Slack should unfurl links to media content such as images and YouTube videos, default: true + 'unfurl_media' => true, + // Whether message text should be interpreted in Slack's Markdown-like language. For formatting options, see Slack's help article: http://goo.gl/r4fsdO, default: true + 'allow_markdown' => true, + // Which attachment fields should be interpreted in Slack's Markdown-like language. By default, Slack assumes that no fields in an attachment should be formatted as Markdown. // default: [] + 'markdown_in_attachments' => [], + + // Allow Markdown in just the text and title fields + //// 'markdown_in_attachments' => ['text', 'title'] + // Allow Markdown in all fields + //// 'markdown_in_attachments' => ['pretext', 'text', 'title', 'fields', 'fallback'] + + 'defaults' => [ + // default username, set to null to use the default set on the Slack webhook, default: null + 'username' => 'Slack module', + // default channel, channel: #general, user: @john.doe, set to null to use the default set on the Slack webhook, default: null + 'channel' => '#general', + // URL to an image or Slack emoji like :ghost: or :+1:, set null to use the default set on the Slack webhook, default: null + 'icon' => null + ], ], ], ]; diff --git a/config/module.config.php b/config/module.config.php index 3981bc2..7bcc46f 100644 --- a/config/module.config.php +++ b/config/module.config.php @@ -2,4 +2,10 @@ namespace MassimoFilippi\SlackModule; -return []; +return [ + 'service_manager' => [ + 'factories' => [ + Service\SlackService::class => Service\Factory\SlackServiceFactory::class, + ] + ] +]; diff --git a/src/Model/Attachment.php b/src/Model/Attachment.php new file mode 100644 index 0000000..6d954cb --- /dev/null +++ b/src/Model/Attachment.php @@ -0,0 +1,115 @@ +setActions($attributes['actions']); + } + + /** + * Get the actions for the attachment + * + * @return array + */ + public function getActions() + { + return $this->actions; + } + + /** + * Set the actions for the attachment + * + * @param array $actions + * @return $this + */ + public function setActions(array $actions) + { + $this->clearActions(); + + foreach ($actions as $action) { + $this->addAction($action); + } + + return $this; + } + + /** + * Add a action to the attachment + * + * @param mixed $action + * @return $this + */ + public function addAction($action) + { + if ($action instanceof AttachmentAction) { + $this->actions[] = $action; + + return $this; + } elseif (is_array($action)) { + $this->actions[] = new AttachmentAction($action); + + return $this; + } + + throw new \InvalidArgumentException('The attachment action must be an instance of '. AttachmentAction::class .' or a keyed array'); + } + + /** + * Clear the actions for the attachment + * + * @return $this + */ + public function clearActions() { + $this->actions = []; + + return $this; + } + + /** + * Convert this attachment to its array representation + * + * @return array + */ + public function toArray() + { + $data = parent::toArray(); + + $data['actions'] = $this->getActionsAsArrays(); + + return $data; + } + + /** + * Iterates over all actions in this attachment and returns + * them in their array form + * + * @return array + */ + protected function getActionsAsArrays() + { + $actions = []; + + foreach ($this->getActions() as $action) $actions[] = $action->toArray(); + + return $actions; + } +} \ No newline at end of file diff --git a/src/Model/AttachmentAction.php b/src/Model/AttachmentAction.php new file mode 100644 index 0000000..8e8d550 --- /dev/null +++ b/src/Model/AttachmentAction.php @@ -0,0 +1,388 @@ +setName($attributes['name']); else throw new \InvalidArgumentException('The name field of the action is required.'); + if(isset($attributes['text'])) $this->setText($attributes['text']); else throw new \InvalidArgumentException('The text field of the action is required.'); + if(isset($attributes['type'])) $this->setType($attributes['type']); else throw new \InvalidArgumentException('The type field of the action is required.'); + if(isset($attributes['url'])) $this->setUrl($attributes['url']); + if(isset($attributes['value'])) $this->setValue($attributes['value']); + if(isset($attributes['confirm'])) $this->setConfirm($attributes['confirm']); + if(isset($attributes['style'])) $this->setStyle($attributes['style']); + if(isset($attributes['options'])) $this->setOptions($attributes['options']); + if(isset($attributes['option_groups'])) $this->setOptionGroups($attributes['option_groups']); + if(isset($attributes['data_source'])) $this->setDataSource($attributes['data_source']); + if(isset($attributes['selected_options'])) $this->setSelectedOptions($attributes['selected_options']); + if(isset($attributes['min_query_length'])) $this->setMinQueryLength($attributes['min_query_length']); + } + + /** + * @return string + */ + public function getName(): string + { + return $this->name; + } + + /** + * @param string $name + * @return $this + */ + public function setName(string $name) + { + $this->name = $name; + + return $this; + } + + /** + * @return string + */ + public function getText(): string + { + return $this->text; + } + + /** + * @param string $text + * @return $this + */ + public function setText(string $text) + { + $this->text = $text; + + return $this; + } + + /** + * @return string + */ + public function getType(): string + { + return $this->type; + } + + /** + * @param string $type + * @return $this + */ + public function setType(string $type) + { + $this->type = $type; + + return $this; + } + + /** + * @return string + */ + public function getUrl() + { + return $this->url; + } + + /** + * @param string $url + * @return $this + */ + public function setUrl(string $url) + { + $this->url = $url; + + return $this; + } + + /** + * @return string + */ + public function getValue() + { + return $this->value; + } + + /** + * @param string $value + * @return $this + */ + public function setValue(string $value) + { + $this->value = $value; + + return $this; + } + + /** + * @return AttachmentActionConfirm + */ + public function getConfirm() + { + return $this->confirm; + } + + /** + * @param AttachmentActionConfirm|array $confirm + * @return $this + */ + public function setConfirm($confirm) + { + if($confirm instanceof AttachmentActionConfirm) { + $this->confirm = $confirm; + + return $this; + } elseif(is_array($confirm)) { + $this->confirm = new AttachmentActionConfirm($confirm); + + return $this; + } + + throw new \InvalidArgumentException('The confirm must be an instance of '. AttachmentActionConfirm::class .' or a keyed array'); + } + + /** + * @return string + */ + public function getStyle() + { + return $this->style; + } + + /** + * @param string $style + * @return $this + */ + public function setStyle(string $style) + { + $this->style = $style; + + return $this; + } + + /** + * @return array + */ + public function getOptions() + { + return $this->options; + } + + /** + * @param array $options + * @return $this + */ + public function setOptions(array $options) + { + $this->options = $options; + + return $this; + } + + /** + * @return array + */ + public function getOptionGroups() + { + return $this->option_groups; + } + + /** + * @param array $option_groups + * @return $this + */ + public function setOptionGroups(array $option_groups) + { + $this->option_groups = $option_groups; + + return $this; + } + + /** + * @return string + */ + public function getDataSource() + { + return $this->data_source; + } + + /** + * @param string $data_source + * @return $this + */ + public function setDataSource(string $data_source) + { + $this->data_source = $data_source; + + return $this; + } + + /** + * @return string + */ + public function getSelectedOptions() + { + return $this->selected_options; + } + + /** + * @param string $selected_options + * @return $this + */ + public function setSelectedOptions(string $selected_options) + { + $this->selected_options = $selected_options; + + return $this; + } + + /** + * @return int + */ + public function getMinQueryLength() + { + return $this->min_query_length; + } + + /** + * @param int $min_query_length + * @return $this + */ + public function setMinQueryLength(int $min_query_length) + { + $this->min_query_length = $min_query_length; + + return $this; + } + + /** + * Get the array representation of this attachment action + * + * @return array + */ + public function toArray() + { + $data = [ + 'name' => $this->getName(), + 'text' => $this->getText(), + 'type' => $this->getType(), + 'style' => $this->getStyle(), + ]; + + if($this->getUrl()) $data['url'] = $this->getUrl(); + if($this->getValue()) $data['value'] = $this->getValue(); + if($this->getConfirm()) $data['confirm'] = $this->getConfirm()->toArray(); + if($this->getOptions()) $data['options'] = $this->getOptions(); + if($this->getOptionGroups()) $data['option_groups'] = $this->getOptionGroups(); + if($this->getDataSource()) $data['data_source'] = $this->getDataSource(); + if($this->getSelectedOptions()) $data['selected_options'] = $this->getSelectedOptions(); + if($this->getMinQueryLength()) $data['min_query_length'] = $this->getMinQueryLength(); + + return $data; + } +} \ No newline at end of file diff --git a/src/Model/AttachmentActionConfirm.php b/src/Model/AttachmentActionConfirm.php new file mode 100644 index 0000000..438e5f5 --- /dev/null +++ b/src/Model/AttachmentActionConfirm.php @@ -0,0 +1,135 @@ +setTitle($attributes['title']); + if(isset($attributes['text'])) $this->setText($attributes['text']); else throw new \InvalidArgumentException('The text field of the confirm is required.'); + if(isset($attributes['ok_text'])) $this->setOkText($attributes['ok_text']); + if(isset($attributes['dismiss_text'])) $this->setDismissText($attributes['dismiss_text']); + } + + /** + * @return string + */ + public function getTitle(): string + { + return $this->title; + } + + /** + * @param string $title + */ + public function setTitle(string $title) + { + $this->title = $title; + } + + /** + * @return string + */ + public function getText(): string + { + return $this->text; + } + + /** + * @param string $text + */ + public function setText(string $text) + { + $this->text = $text; + } + + /** + * @return string + */ + public function getOkText(): string + { + return $this->okText; + } + + /** + * @param string $okText + */ + public function setOkText(string $okText) + { + $this->okText = $okText; + } + + /** + * @return string + */ + public function getDismissText(): string + { + return $this->dismissText; + } + + /** + * @param string $dismissText + */ + public function setDismissText(string $dismissText) + { + $this->dismissText = $dismissText; + } + + /** + * Get the array representation of this confirm + * + * @return array + */ + public function toArray() + { + $data = [ + 'text' => $this->getText(), + ]; + + if($this->getTitle()) $data['title'] = $this->getTitle(); + if($this->getTitle()) $data['ok_text'] = $this->getOkText(); + if($this->getTitle()) $data['dismiss_text'] = $this->getDismissText(); + + return $data; + } +} \ No newline at end of file diff --git a/src/Service/Factory/SlackServiceFactory.php b/src/Service/Factory/SlackServiceFactory.php new file mode 100644 index 0000000..89f39b1 --- /dev/null +++ b/src/Service/Factory/SlackServiceFactory.php @@ -0,0 +1,49 @@ +get('config'); + + if (false === isset($config['massimo_filippi']['slack_module'])) { + throw new ServiceNotCreatedException('Missing configuration for slack module.'); + } + + /** @var array $slackModuleConfig */ + $slackModuleConfig = $config['massimo_filippi']['slack_module']; + + /** @var Client $slackClient */ + $slackClient = new Client($slackModuleConfig['webhook_url'], [ + 'channel' => $slackModuleConfig['defaults']['channel'] ?: null, + 'username' => $slackModuleConfig['defaults']['username'] ?: null, + 'icon' => $slackModuleConfig['defaults']['icon'] ?: null, + 'link_names' => $slackModuleConfig['link_names'] ?: false, + 'unfurl_links' => $slackModuleConfig['unfurl_links'] ?: false, + 'unfurl_media' => $slackModuleConfig['unfurl_media'] ?: true, + 'allow_markdown' => $slackModuleConfig['allow_markdown'] ?: true, + 'markdown_in_attachments' => $slackModuleConfig['markdown_in_attachments'] ?: [], + ]); + + return new SlackService($slackClient); + } +} \ No newline at end of file diff --git a/src/Service/SlackService.php b/src/Service/SlackService.php new file mode 100644 index 0000000..091c823 --- /dev/null +++ b/src/Service/SlackService.php @@ -0,0 +1,98 @@ +slackClient = $slackClient; + } + + /** + * @param Message $slackMessage + */ + public function sendMessage(Message $slackMessage) + { + $this->slackClient->sendMessage($slackMessage); + } + + /** + * @return \Maknz\Slack\Message + */ + public function createMessage() + { + return $this->slackClient->createMessage(); + } + + /** + * @param array $attributes + * @return Attachment + */ + public function createAttachment(array $attributes) { + return new Attachment($attributes); + } + + /** + * @param array $attributes + * @return AttachmentField + */ + public function createAttachmentField(array $attributes) { + return new AttachmentField($attributes); + } + + /** + * @param array $attributes + * @return AttachmentAction + */ + public function createAttachmentAction(array $attributes) { + return new AttachmentAction($attributes); + } + + /** + * Pass any unhandled methods through to a new Message + * instance + * + * @param string $name The name of the method + * @param array $arguments The method arguments + * @return \Maknz\Slack\Message + */ + public function __call($name, $arguments) + { + return $this->slackClient->__call($name, $arguments); + } + + /** + * @return Client + */ + public function getSlackClient(): Client + { + return $this->slackClient; + } + + /** + * @param Client $slackClient + */ + public function setSlackClient(Client $slackClient) + { + $this->slackClient = $slackClient; + } +} \ No newline at end of file diff --git a/src/Service/SlackServiceInterface.php b/src/Service/SlackServiceInterface.php new file mode 100644 index 0000000..ecb33f4 --- /dev/null +++ b/src/Service/SlackServiceInterface.php @@ -0,0 +1,13 @@ +