diff --git a/README.md b/README.md index 5b37cf6..5cfa844 100644 --- a/README.md +++ b/README.md @@ -41,13 +41,25 @@ composer require nexylan/slack php-http/guzzle6-adapter Why `php-http/guzzle6-adapter`? We are decoupled from any HTTP messaging client thanks to [HTTPlug](http://httplug.io/). -Then [create an incoming webhook](https://my.slack.com/services/new/incoming-webhook) on your Slack account for the package to use. -You'll need the webhook URL to instantiate the client (or for the configuration file if using Laravel). +Then [create an app](https://api.slack.com/slack-apps) on your Slack account for the package to use. +You'll need to need to enable the [chat:write:bot](https://api.slack.com/scopes/chat:write:bot) [scope](https://api.slack.com/docs/oauth-scopes) for your app and get the "OAuth Access Token". ## Basic Usage ### Instantiate the client +Using Slack's [OAuth token](https://api.slack.com/docs/oauth) method: + +```php +$client = (new Nexy\Slack\Client()) + ->setOptions([ + 'username' => 'Cyril', + 'oauth_token' => 'xoxp-3845764387563....' + ]); +``` + +To use Slack's deprecated Webhook functionality: + ```php // Instantiate without defaults $client = new Nexy\Slack\Client('https://hooks.slack.com/...'); @@ -231,6 +243,31 @@ $attachment = new Attachment(); $attachment->setFields($bigArrayOfFields); ``` +### Blocks + +Slack has deprecated message attachments in favour of Blocks. Blocks give you a lot more control over the layout of your message and allow you to create interactive messages like this. + +![Interactive Slack message](doc/interactive-message.png?raw=true "EcomHQ") + +You can read about it in the [Slack Messaging Reference](https://api.slack.com/reference/messaging/block-elements). + +An example of sending a message with Blocks: + +```php +$message = $this->slackClient->createMessage() + ->setText('This is the fallback text') + ->addBlock + ( + (new SectionBlock()) + ->setMarkdown(':smiley: Hi! :wave:') + ) + ->addBlock + ( + (new ButtonBlock()) + ->setPlainText('Wave back?') + ); +``` + ## Contributing If you're having problems, spot a bug, or have a feature suggestion, please log and issue on Github. If you'd like to have a crack yourself, fork the package and make a pull request. Please include tests for any added or changed functionality. If it's a bug, include a regression test. diff --git a/doc/interactive-message.png b/doc/interactive-message.png new file mode 100644 index 0000000..2c1d750 Binary files /dev/null and b/doc/interactive-message.png differ diff --git a/src/ActionsBlock.php b/src/ActionsBlock.php new file mode 100644 index 0000000..d51eaef --- /dev/null +++ b/src/ActionsBlock.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Nexy\Slack; + +/** + * @author Sullivan Senechal + * @author Mikey McLellan + */ +final class ActionsBlock extends ElementsBlock +{ + public function __construct() + { + parent::__construct('actions'); + } +} diff --git a/src/Block.php b/src/Block.php new file mode 100644 index 0000000..6d29b9d --- /dev/null +++ b/src/Block.php @@ -0,0 +1,99 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Nexy\Slack; + +/** + * @author Sullivan Senechal + * @author Mikey McLellan + */ +class Block +{ + /** + * @var string + */ + protected $type; + + /** + * @var string + */ + private $blockId; + + public function __construct(?string $type) + { + $this->setType($type); + } + + /** + * @return string + */ + public function getType(): string + { + return $this->type; + } + + /** + * @param string $type + * + * @return $this + */ + public function setType(string $type): self + { + $this->type = $type; + + return $this; + } + + /** + * Convert this block to its array representation. + * + * @return array + */ + public function toArray(): array + { + $data = [ + 'type' => $this->type, + 'block_id' => $this->blockId + ]; + + return $this->removeNulls($data); + } + + /** + * @param string $blockId + */ + public function setBlockId(string $blockId): self + { + $this->blockId = $blockId; + + return $this; + } + + /** + * @return string + */ + public function getBlockId(): string + { + return $this->blockId; + } + + protected function removeNulls(array $data): array + { + foreach($data as $k => $v) { + if ($v === null || (is_array($v) && count($v) === 0)) { + unset($data[$k]); + } + } + return $data; + } +} diff --git a/src/ButtonBlock.php b/src/ButtonBlock.php new file mode 100644 index 0000000..5f55e7f --- /dev/null +++ b/src/ButtonBlock.php @@ -0,0 +1,135 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Nexy\Slack; + +/** + * @author Sullivan Senechal + * @author Mikey McLellan + */ +final class ButtonBlock extends SectionBlock +{ + const STYLE_PRIMARY = 'primary'; + const STYLE_DANGER = 'danger'; + + /** @var string */ + private $url; + + /** @var string */ + private $value; + + /** @var string */ + private $actionId; + + /** @var string */ + private $style; + + public function __construct() + { + parent::__construct('button'); + } + + /** + * @return string + */ + public function getUrl(): string + { + return $this->url; + } + + /** + * @param string $url + */ + public function setUrl(string $url): self + { + $this->url = $url; + + return $this; + } + + /** + * @return string + */ + public function getValue(): string + { + return $this->value; + } + + /** + * @param string $value + */ + public function setValue(string $value): self + { + $this->value = $value; + + return $this; + } + + /** + * @param string $actionId + */ + public function setActionId(string $actionId): self + { + $this->actionId = $actionId; + + return $this; + } + + /** + * @return string + */ + public function getActionId(): string + { + return $this->actionId; + } + + /** + * @return string + */ + public function getStyle(): string + { + return $this->style; + } + + /** + * @param string $style + */ + public function setStyle(string $style): self + { + $this->style = $style; + + return $this; + } + + public function setMarkdown(string $string): SectionBlock + { + throw new \InvalidArgumentException('ButtonBlock must use plain_text'); + } + + /** + * Convert this block to its array representation. + * + * @return array + */ + public function toArray(): array + { + $data = [ + 'url' => $this->url, + 'value' => $this->value, + 'action_id' => $this->actionId, + 'style' => $this->style + ]; + + return array_merge(parent::toArray(), $this->removeNulls($data)); + } +} diff --git a/src/Client.php b/src/Client.php index 70dd688..32073f5 100644 --- a/src/Client.php +++ b/src/Client.php @@ -15,19 +15,24 @@ use Http\Client\Common\HttpMethodsClient; use Http\Client\Common\Plugin\BaseUriPlugin; +use Http\Client\Common\Plugin\HeaderAppendPlugin; use Http\Client\Common\PluginClient; use Http\Client\Exception; use Http\Client\HttpClient; use Http\Discovery\HttpClientDiscovery; use Http\Discovery\MessageFactoryDiscovery; use Http\Discovery\UriFactoryDiscovery; +use Nexy\Slack\Exception\SlackErrorException; use Symfony\Component\OptionsResolver\OptionsResolver; +use Psr\Http\Message\ResponseInterface; /** * @author Sullivan Senechal */ final class Client { + const SLACK_POST_MESSAGE_URL = 'https://slack.com/api/chat.postMessage'; + /** * @var array */ @@ -38,6 +43,8 @@ final class Client */ private $httpClient; + private $optionsResolver; + /** * Instantiate a new Client. * @@ -45,9 +52,9 @@ final class Client * @param array $options * @param HttpClient|null $httpClient */ - public function __construct(string $endpoint, array $options = [], HttpClient $httpClient = null) + public function __construct(string $endpoint = self::SLACK_POST_MESSAGE_URL, array $options = [], HttpClient $httpClient = null) { - $resolver = (new OptionsResolver()) + $this->optionsResolver = (new OptionsResolver()) ->setDefaults([ 'channel' => null, 'sticky_channel' => false, @@ -58,6 +65,7 @@ public function __construct(string $endpoint, array $options = [], HttpClient $h 'unfurl_media' => true, 'allow_markdown' => true, 'markdown_in_attachments' => [], + 'oauth_token' => null ]) ->setAllowedTypes('channel', ['string', 'null']) ->setAllowedTypes('sticky_channel', ['bool']) @@ -68,20 +76,42 @@ public function __construct(string $endpoint, array $options = [], HttpClient $h ->setAllowedTypes('unfurl_media', 'bool') ->setAllowedTypes('allow_markdown', 'bool') ->setAllowedTypes('markdown_in_attachments', 'array') + ->setAllowedTypes('oauth_token', ['string', 'null']) ; - $this->options = $resolver->resolve($options); + + $this->setOptions($options, $endpoint, $httpClient); + } + + public function setEndpoint($endpoint, HttpClient $httpClient = null): self + { + $plugins = [ + new BaseUriPlugin( + UriFactoryDiscovery::find()->createUri($endpoint) + ), + ]; + + if ($this->options['oauth_token']) { + $plugins[] = new HeaderAppendPlugin([ + 'Authorization' => 'Bearer ' . $this->options['oauth_token'], + 'Content-Type' => 'application/json' + ]); + } $this->httpClient = new HttpMethodsClient( new PluginClient( $httpClient ?: HttpClientDiscovery::find(), - [ - new BaseUriPlugin( - UriFactoryDiscovery::find()->createUri($endpoint) - ), - ] + $plugins ), MessageFactoryDiscovery::find() ); + return $this; + } + + public function setOptions(array $options, string $endpoint = self::SLACK_POST_MESSAGE_URL, HttpClient $httpClient = null): self + { + $this->options = $this->optionsResolver->resolve($options); + $this->setEndpoint($endpoint, $httpClient); + return $this; } /** @@ -144,7 +174,19 @@ public function sendMessage(Message $message): void throw new \RuntimeException(\sprintf('JSON encoding error %s: %s', \json_last_error(), \json_last_error_msg())); } - $this->httpClient->post('', [], $encoded); + $response = $this->httpClient->post('', [], $encoded); + + if ($this->isErrorResponse($response)) { + throw new SlackErrorException($response); + } + } + + protected function isErrorResponse(ResponseInterface $response) + { + $data = json_decode($response->getBody()->getContents(), true); + $response->getBody()->rewind(); + + return $response->getStatusCode() !== 200 || !$data['ok']; } /** @@ -171,6 +213,7 @@ private function preparePayload(Message $message): array } $payload['attachments'] = $this->getAttachmentsAsArrays($message); + $payload['blocks'] = $this->getBlocksAsArrays($message); return $payload; } @@ -192,4 +235,22 @@ private function getAttachmentsAsArrays(Message $message): array return $attachments; } + + /** + * Get the attachments in array form. + * + * @param \Nexy\Slack\Message $message + * + * @return array + */ + private function getBlocksAsArrays(Message $message): array + { + $blocks = []; + + foreach ($message->getBlocks() as $block) { + $blocks[] = $block->toArray(); + } + + return $blocks; + } } diff --git a/src/ConfirmationDialogBlock.php b/src/ConfirmationDialogBlock.php new file mode 100644 index 0000000..35c234f --- /dev/null +++ b/src/ConfirmationDialogBlock.php @@ -0,0 +1,135 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Nexy\Slack; + +/** + * @author Sullivan Senechal + * @author Mikey McLellan + */ +final class ConfirmationDialogBlock extends Block +{ + /** + * @var TextBlock + */ + protected $title; + + /** + * @var TextBlock + */ + protected $text; + + /** + * @var TextBlock + */ + protected $confirm; + + /** + * @var TextBlock + */ + protected $deny; + + public function __construct() + { + parent::__construct(null); + } + + /** + * @param TextBlock $text + */ + public function setText(TextBlock $text): self + { + $this->text = $text; + + return $this; + } + + /** + * @return TextBlock + */ + public function getText(): TextBlock + { + return $this->text; + } + + /** + * @param TextBlock $confirm + */ + public function setConfirm(TextBlock $confirm): self + { + $this->confirm = $confirm; + + return $this; + } + + /** + * @return TextBlock + */ + public function getConfirm(): TextBlock + { + return $this->confirm; + } + + /** + * @param TextBlock $deny + */ + public function setDeny(TextBlock $deny): self + { + $this->deny = $deny; + + return $this; + } + + /** + * @return TextBlock + */ + public function getDeny(): TextBlock + { + return $this->deny; + } + + /** + * @param TextBlock $title + */ + public function setTitle(TextBlock $title): self + { + $this->title = $title; + + return $this; + } + + /** + * @return TextBlock + */ + public function getTitle(): TextBlock + { + return $this->title; + } + + /** + * Convert this block to its array representation. + * + * @return array + */ + public function toArray(): array + { + $data = [ + 'title' => $this->title->toArray(), + 'text' => $this->text->toArray(), + 'confirm' => $this->confirm->toArray(), + 'deny' => $this->deny->toArray(), + ]; + + return array_merge(parent::toArray(), $this->removeNulls($data)); + } +} diff --git a/src/ContextBlock.php b/src/ContextBlock.php new file mode 100644 index 0000000..2b5589c --- /dev/null +++ b/src/ContextBlock.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Nexy\Slack; + +/** + * @author Sullivan Senechal + * @author Mikey McLellan + */ +final class ContextBlock extends ElementsBlock +{ + public function __construct() + { + parent::__construct('context'); + } +} diff --git a/src/DatePickerBlock.php b/src/DatePickerBlock.php new file mode 100644 index 0000000..d0ff7f5 --- /dev/null +++ b/src/DatePickerBlock.php @@ -0,0 +1,133 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Nexy\Slack; + +/** + * @author Sullivan Senechal + * @author Mikey McLellan + */ +final class DatePickerBlock extends Block +{ + /** + * @var string + */ + private $actionId; + + /** + * @var string + */ + private $initialDate; + + /** + * @var TextBlock + */ + private $placeholder; + + /** + * @var ConfirmationDialogBlock + */ + private $confirm; + + public function __construct() + { + parent::__construct('datepicker'); + } + + /** + * @param string $actionId + */ + public function setActionId(string $actionId): ButtonBlock + { + $this->actionId = $actionId; + + return $this; + } + + /** + * @return string + */ + public function getActionId(): string + { + return $this->actionId; + } + + /** + * @param string $initialDate + */ + public function setInitialDate(string $initialDate): self + { + $this->initialDate = $initialDate; + + return $this; + } + + /** + * @return string + */ + public function getInitialDate(): string + { + return $this->initialDate; + } + + /** + * @param ConfirmationDialogBlock $confirm + */ + public function setConfirm(ConfirmationDialogBlock $confirm): self + { + $this->confirm = $confirm; + + return $this; + } + + /** + * @return ConfirmationDialogBlock + */ + public function getConfirm(): ConfirmationDialogBlock + { + return $this->confirm; + } + + /** + * @return array + */ + public function getPlaceholder(): TextBlock + { + return $this->placeholder; + } + + /** + * @param array $placeholder + */ + public function setPlaceholder(TextBlock $placeholder): self + { + $this->placeholder = $placeholder; + + return $this; + } + + /** + * Convert this block to its array representation. + * + * @return array + */ + public function toArray(): array + { + $data = [ + 'image_url' => $this->imageUrl, + 'alt_text' => $this->altText + ]; + + return array_merge(parent::toArray(), $this->removeNulls($data)); + } +} diff --git a/src/DividerBlock.php b/src/DividerBlock.php new file mode 100644 index 0000000..5a7f9d9 --- /dev/null +++ b/src/DividerBlock.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Nexy\Slack; + +/** + * @author Sullivan Senechal + * @author Mikey McLellan + */ +final class DividerBlock extends Block +{ + public function __construct() + { + parent::__construct('divider'); + } +} diff --git a/src/ElementsBlock.php b/src/ElementsBlock.php new file mode 100644 index 0000000..3fb4c60 --- /dev/null +++ b/src/ElementsBlock.php @@ -0,0 +1,115 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Nexy\Slack; + +/** + * @author Sullivan Senechal + * @author Mikey McLellan + */ +class ElementsBlock extends Block +{ + /** + * @var array + */ + private $elements; + + public function __construct($type = 'actions') + { + parent::__construct($type); + } + + /** + * Convert this block to its array representation. + * + * @return array + */ + public function toArray(): array + { + $data = [ + 'elements' => $this->getElementsAsArrays() + ]; + + return array_merge(parent::toArray(), $data); + } + + /** + * Add an element to the message. + * + * @param Block $element + * + * @return $this + */ + public function addElement(Block $element): self + { + $this->elements[] = $element; + + return $this; + } + + /** + * @return Block[] + */ + public function getElements(): array + { + return $this->elements; + } + + /** + * Set the elements for the message. + * + * @param array $elements + * + * @return $this + */ + public function setElements(array $elements): self + { + $this->clearElements(); + + foreach ($elements as $element) { + $this->addElement($element); + } + + return $this; + } + + /** + * Remove all elements for the message. + * + * @return $this + */ + public function clearElements(): self + { + $this->elements = []; + + return $this; + } + + + /** + * Iterates over all fields in this attachment and returns + * them in their array form. + * + * @return array + */ + private function getElementsAsArrays(): array + { + $elements = []; + + foreach ($this->elements as $element) { + $elements[] = $element->toArray(); + } + + return $elements; + } +} diff --git a/src/Exception/SlackErrorException.php b/src/Exception/SlackErrorException.php new file mode 100644 index 0000000..c1c12c6 --- /dev/null +++ b/src/Exception/SlackErrorException.php @@ -0,0 +1,33 @@ +response = $response; + parent::__construct($this->getMessageFromResponse(), $response->getStatusCode()); + } + + public function getResponse(): ResponseInterface + { + return $this->response; + } + + protected function getMessageFromResponse() + { + $data = json_decode($this->response->getBody()->getContents(), true); + $message = 'Slack error: '; + + foreach($data['response_metadata']['messages']??[] as $item) { + $message .= $item.'.'; + } + return $message; + } +} \ No newline at end of file diff --git a/src/ImageBlock.php b/src/ImageBlock.php new file mode 100644 index 0000000..3c53fc1 --- /dev/null +++ b/src/ImageBlock.php @@ -0,0 +1,87 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Nexy\Slack; + +/** + * @author Sullivan Senechal + * @author Mikey McLellan + */ +final class ImageBlock extends Block +{ + /** + * @var string + */ + private $imageUrl; + + /** + * @var string + */ + private $altText; + + public function __construct() + { + parent::__construct('image'); + } + + /** + * @return string + */ + public function getAltText(): string + { + return $this->altText; + } + + /** + * @param string $altText + */ + public function setAltText(string $altText): self + { + $this->altText = $altText; + + return $this; + } + + /** + * @return string + */ + public function getImageUrl(): string + { + return $this->imageUrl; + } + + /** + * @param string $imageUrl + */ + public function setImageUrl(string $imageUrl): self + { + $this->imageUrl = $imageUrl; + + return $this; + } + + /** + * Convert this block to its array representation. + * + * @return array + */ + public function toArray(): array + { + $data = [ + 'image_url' => $this->imageUrl, + 'alt_text' => $this->altText + ]; + + return array_merge(parent::toArray(), $this->removeNulls($data)); + } +} diff --git a/src/Message.php b/src/Message.php index 7424339..5ac36e6 100644 --- a/src/Message.php +++ b/src/Message.php @@ -69,6 +69,15 @@ final class Message */ private $allowMarkdown = true; + /** + * Any messages published via `response_url` will leave the source message untouched. You can however use + * `response_url` to update the source message of an interaction by including an attribute `replace_original` and + * set it to true. + * + * @var bool|null + */ + private $replaceOriginal; + /** * The attachment fields which should be formatted with * Slack's Markdown-like language. @@ -84,6 +93,13 @@ final class Message */ private $attachments = []; + /** + * An array of blocks to send. + * + * @var array + */ + private $blocks = []; + /** * @var string */ @@ -245,6 +261,30 @@ public function disableMarkdown(): self return $this->setAllowMarkdown(false); } + /** + * @return bool + */ + public function getReplaceOriginal():? bool + { + return $this->replaceOriginal; + } + + /** + * @param bool $value + * @return Message + */ + public function setReplaceOriginal(bool $value): self + { + $this->replaceOriginal = $value; + + return $this; + } + + public function enableReplaceOriginal(): self + { + return $this->setReplaceOriginal(true); + } + /** * @return array */ @@ -356,6 +396,58 @@ public function clearAttachments(): self return $this; } + /** + * Add an block to the message. + * + * @param Block $block + * + * @return $this + */ + public function addBlock(Block $block): self + { + $this->blocks[] = $block; + + return $this; + } + + /** + * @return Block[] + */ + public function getBlocks(): array + { + return $this->blocks; + } + + /** + * Set the blocks for the message. + * + * @param array $blocks + * + * @return $this + */ + public function setBlocks(array $blocks): self + { + $this->clearBlocks(); + + foreach ($blocks as $block) { + $this->addBlock($block); + } + + return $this; + } + + /** + * Remove all blocks for the message. + * + * @return $this + */ + public function clearBlocks(): self + { + $this->blocks = []; + + return $this; + } + /** * Send the message. * diff --git a/src/SectionBlock.php b/src/SectionBlock.php new file mode 100644 index 0000000..d2c507a --- /dev/null +++ b/src/SectionBlock.php @@ -0,0 +1,176 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Nexy\Slack; + +/** + * @author Sullivan Senechal + * @author Mikey McLellan + */ +class SectionBlock extends Block +{ + /** + * @var TextBlock + */ + private $text; + + /** + * @var Block + */ + private $accessory; + + /** + * @var TextBlock[] + */ + private $fields = []; + + public function __construct($type = 'section') + { + parent::__construct($type); + } + + /** + * @param string $text + */ + public function setText(TextBlock $text): self + { + $this->text = $text; + + return $this; + } + + public function getText(): TextBlock + { + return $this->text; + } + + public function setPlainText(string $string): self + { + return $this->setText((new TextBlock()) + ->setType(TextBlock::PLAIN_TEXT) + ->setText($string)); + } + + public function setMarkdown(string $string): self + { + return $this->setText((new TextBlock()) + ->setType(TextBlock::MARKDOWN) + ->setText($string)); + } + + /** + * @return array + */ + public function getAccessory(): Block + { + return $this->accessory; + } + + /** + * @param array $accessory + */ + public function setAccessory(Block $accessory): self + { + $this->accessory = $accessory; + + return $this; + } + + /** + * Convert this block to its array representation. + * + * @return array + */ + public function toArray(): array + { + $data = [ + 'text' => $this->text->toArray(), + 'fields' => $this->getFieldsAsArrays() + ]; + + if ($this->accessory) { + $data['accessory'] = $this->accessory->toArray(); + } + + return array_merge(parent::toArray(), $this->removeNulls($data)); + } + + /** + * Add an field to the message. + * + * @param TextBlock $field + * + * @return $this + */ + public function addField(TextBlock $field): self + { + $this->fields[] = $field; + + return $this; + } + + /** + * @return TextBlock[] + */ + public function getFields(): array + { + return $this->fields; + } + + /** + * Set the fields for the message. + * + * @param TextBlock[] $fields + * + * @return $this + */ + public function setFields(array $fields): self + { + $this->clearFields(); + + foreach ($fields as $field) { + $this->addField($field); + } + + return $this; + } + + /** + * Remove all fields for the message. + * + * @return $this + */ + public function clearFields(): self + { + $this->fields = []; + + return $this; + } + + /** + * Iterates over all fields in this attachment and returns + * them in their array form. + * + * @return array + */ + private function getFieldsAsArrays(): array + { + $fields = []; + + foreach ($this->fields as $field) { + $fields[] = $field->toArray(); + } + + return $fields; + } +} diff --git a/src/TextBlock.php b/src/TextBlock.php new file mode 100644 index 0000000..bf8a870 --- /dev/null +++ b/src/TextBlock.php @@ -0,0 +1,78 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Nexy\Slack; + +/** + * @author Sullivan Senechal + * @author Mikey McLellan + */ +class TextBlock extends Block +{ + const PLAIN_TEXT = 'plain_text'; + const MARKDOWN = 'mrkdwn'; + + /** + * @var string + */ + protected $text; + + /** @var boolean */ + protected $emoji = false; + + /** @var bool */ + protected $verbatim = false; + + public function __construct($type = self::MARKDOWN) + { + parent::__construct($type); + } + + /** + * @param string $text + */ + public function setText(string $text): self + { + $this->text = $text; + + return $this; + } + + /** + * @return string + */ + public function getText(): string + { + return $this->text; + } + + /** + * Convert this block to its array representation. + * + * @return array + */ + public function toArray(): array + { + $data = [ + 'text' => $this->text, + 'type' => $this->type]; + + if ($this->type === self::MARKDOWN) { + $data['verbatim'] = $this->verbatim; + } + if ($this->type === self::PLAIN_TEXT) { + $data['emoji'] = $this->emoji; + } + return $data; + } +}