diff --git a/src/API.php b/src/API.php index 4e798d0..bd0a7a7 100644 --- a/src/API.php +++ b/src/API.php @@ -24,7 +24,7 @@ use Slack\Response\User as ResponseUser; use Slack\Response\Team as ResponseTeam; use Slack\Response\Test; -class API +final class API { private const LOGKEY = 'API'; diff --git a/src/Base.php b/src/Base.php index baee426..adf32ad 100644 --- a/src/Base.php +++ b/src/Base.php @@ -110,4 +110,4 @@ abstract class Base return $o; } -} +} \ No newline at end of file diff --git a/src/BlockKit.php b/src/BlockKit.php index 6344e00..c8489d0 100644 --- a/src/BlockKit.php +++ b/src/BlockKit.php @@ -2,6 +2,7 @@ namespace Slack; +use Illuminate\Support\Arr; use Illuminate\Support\Collection; /** @@ -9,7 +10,7 @@ use Illuminate\Support\Collection; * * @package Slack */ -class BlockKit implements \JsonSerializable +abstract class BlockKit implements \JsonSerializable { protected Collection $_data; @@ -18,6 +19,14 @@ class BlockKit implements \JsonSerializable $this->_data = collect(); } + public function __get($key) { + return $this->_data->get($key); + } + + public function __set(string $key,$value) { + return $this->_data->put($key,$value); + } + public function count() { return $this->_data->count(); @@ -27,4 +36,12 @@ class BlockKit implements \JsonSerializable { return $this->_data; } -} + + protected function validate(string $key,$value) + { + if (Arr::get(static::LIMITS,$key) && (strlen($value) > static::LIMITS[$key])) + throw new Exception(sprintf('%s must be %d chars or less for buttons %s',$key,self::LIMITS[$key],get_class($this))); + + return $value; + } +} \ No newline at end of file diff --git a/src/Blockkit/BlockAction.php b/src/Blockkit/BlockAction.php deleted file mode 100644 index 1c8dbcf..0000000 --- a/src/Blockkit/BlockAction.php +++ /dev/null @@ -1,40 +0,0 @@ -_data->put('type','button'); - $this->_data->put('action_id',$action); - $this->_data->put('text',$text); - $this->_data->put('value',$value); - - if ($style) - $this->_data->put('style',$style); - - return $this; - } -} diff --git a/src/Blockkit/Blocks.php b/src/Blockkit/Blocks.php index b6614b6..c295185 100644 --- a/src/Blockkit/Blocks.php +++ b/src/Blockkit/Blocks.php @@ -2,350 +2,8 @@ namespace Slack\Blockkit; -use Illuminate\Support\Collection; use Slack\BlockKit; -use Slack\Exceptions\SlackException; -use Slack\Blockkit\Blocks\{Button,Text,TextEmoji}; -/** - * Class Blockkit Block - * Represents a list of Blockit blocks - * - * @package Slack\Blockkit - */ -class Blocks extends BlockKit +abstract class Blocks extends BlockKit { - /** - * Actions - * - * @param array $items - * @return Blocks - */ - private function actions(array $items): self - { - $this->_data->push(array_merge(['type'=>'actions'],$items)); - - return $this; - } - - /** - * Add actions block - * - * @param Collection $elements - * @return Blocks - */ - public function addActionElements(Collection $elements): self - { - $this->actions(['elements'=>$elements]); - - return $this; - } - - /** - * Add context items - * - * @param Collection $items - * @return Blocks - */ - public function addContextElements(Collection $items): self - { - return $this->context(['elements'=>$items]); - } - - /** - * Add a bock divider - * - * @returns Blocks - */ - public function addDivider(): self - { - $this->_data->push(['type'=>'divider']); - - return $this; - } - - /** - * Add a block header - * - * @param string $text - * @return Blocks - */ - public function addHeader(string $text): self - { - $this->_data->push(['type'=>'header','text'=>TextEmoji::item($text,TRUE)]); - - return $this; - } - - /** - * @param Collection $options - * @param string $action_id - * @return Collection - * @todo To Check - */ - public function addOverflow(Collection $options,string $action_id): Collection - { - return collect([ - 'type'=>'overflow', - 'options'=>$options, - 'action_id'=>$action_id, - ]); - } - - /** - * Add a section with accessories - * - * @param Text $text - * @param Button $accessory - * @return Blocks - */ - public function addSectionAccessoryButton(Text $text,Button $accessory): self - { - return $this->section([ - 'text'=>$text, - 'accessory'=>$accessory, - ]); - } - - /** - * @param Text $label - * @param string $action - * @param Collection $options - * @param string|null $default - * @return Blocks - * @deprecated - * @todo Look at addSectionAccessory - */ - public function addSelect(Text $label,string $action,Collection $options,string $default=NULL): self - { - $this->_data->put('type','section'); - $this->_data->put('text',$label); - - // Accessories - $x = collect(); - $x->put('action_id',$action); - $x->put('type','static_select'); - $x->put('options',$options->map(function ($item) { - if (is_array($item)) - $item = (object)$item; - - return [ - 'text'=>[ - 'type'=>'plain_text', - 'text'=>(string)$item->name, - ], - 'value'=>(string)($item->value ?: $item->id) - ]; - })); - - if ($default) { - $choice = $options->filter(function($item) use ($default) { - if (is_array($item)) - $item = (object)$item; - - return ($item->value == $default) ? $item : NULL; - })->filter()->pop(); - - if ($choice) { - $x->put('initial_option',[ - 'text'=>TextEmoji::item($choice['name']), - 'value'=>(string)$choice['value'] - ]); - } - } - - $this->_data->put('accessory',$x); - - return $this; - } - - /** - * Add a section with fields - * @param Collection $items - * @return Blocks - */ - public function addSectionFields(Collection $items): self - { - return $this->section(['fields'=>$items]); - } - - /** - * Generates a multiselect that queries back to the server for values - * - * @param Text $label - * @param string $action - * @return Blocks - * @todo To Change - and rename addSectionMultiSelectInput() - * @deprecated - */ - public function addMultiSelectInput(Text $label,string $action): self - { - $this->_data->put('type','section'); - $this->_data->put('text',$label); - $this->_data->put('accessory',[ - 'action_id'=>$action, - 'type'=>'multi_external_select', - ]); - - return $this; - } - - /** - * Add a section with a multi select list - * - * @param Text $label - * @param string $action - * @param Collection $options - * @param Collection|null $selected - * @param int|null $maximum - * @return Blocks - * @throws \Exception - * @note Slack only allows 100 items - */ - public function addSectionMultiSelectStaticInput(Text $label,string $action,Collection $options,Collection $selected=NULL,int $maximum=NULL): self - { - if ($options->count() > 100) - throw new SlackException('Selection list cannot have more than 100 items.'); - - $x = collect(); - $x->put('action_id',$action); - $x->put('type','multi_static_select'); - $x->put('options',$options->transform(function ($item) { - return ['text'=>TextEmoji::item($item->name),'value'=>(string)$item->id]; - })); - - if ($selected and $selected->count()) - $x->put('initial_options',$selected->transform(function ($item) { - return ['text'=>TextEmoji::item($item->name),'value'=>(string)$item->id]; - })); - - if ($maximum) - $x->put('max_selected_items',$maximum); - - return $this->section([ - 'text' => $label, - 'accessory' => $x - ]); - } - - /** - * Add a section with just text - * - * @param Text $text - * @return Blocks - */ - public function addSectionText(Text $text): self - { - return $this->section(['text'=>$text]); - } - - /** - * Add a spacer line - * - * @return $this - */ - public function addSpacer(): self - { - return $this->section(['text'=>Text::item(' ')]); - } - - /** - * A context block - * - * @param array $items - * @return Blocks - */ - private function context(array $items): self - { - $this->_data->push(array_merge(['type'=>'context'],$items)); - - return $this; - } - - /** - * Render the input dialog - * - * @param string $label - * @param string $action - * @param int $minlength - * @param string $placeholder - * @param bool $multiline - * @param string $hint - * @param string $initial - * @return $this - * @throws \Exception - * @deprecated - to optimize - */ - protected function input(string $label,string $action,int $minlength,string $placeholder='',bool $multiline=FALSE,string $hint='',string $initial='') - { - $this->_data->put('type','input'); - $this->_data->put('element',[ - 'type'=>'plain_text_input', - 'action_id'=>$action, - 'placeholder'=>$this->text($placeholder ?: ' ','plain_text'), - 'multiline'=>$multiline, - 'min_length'=>$minlength, - 'initial_value'=>$initial, - ]); - $this->_data->put('label',[ - 'type'=>'plain_text', - 'text'=>$label, - 'emoji'=>true, - ]); - $this->_data->put('optional',$minlength ? FALSE : TRUE); - - if ($hint) - $this->_data->put('hint',$this->text($hint,'plain_text')); - - return $this; - } - - /** - * A section block - * - * @param array $items - * @return Blocks - */ - private function section(array $items): self - { - $this->_data->push(array_merge(['type'=>'section'],$items)); - - return $this; - } - - /** - * Generates a single-line input dialog - * - * @param string $label - * @param string $action - * @param string $placeholder - * @param int $minlength - * @param string $hint - * @param string $initial - * @return Blocks - * @throws \Exception - * @deprecated - to optimize - */ - public function addSingleLineInput(string $label,string $action,string $placeholder='',int $minlength=5,string $hint='',string $initial=''): self - { - return $this->input($label,$action,$minlength,$placeholder,FALSE,$hint,$initial); - } - - /** - * Generates a multi-line input dialog - * - * @param string $label - * @param string $action - * @param string $placeholder - * @param int $minlength - * @param string $hint - * @param string $initial - * @return Blocks - * @throws \Exception - * @deprecated - to optimize - */ - public function addMultiLineInput(string $label,string $action,string $placeholder='',int $minlength=20,string $hint='',string $initial=''): self - { - return $this->input($label,$action,$minlength,$placeholder,TRUE,$hint,$initial); - } -} +} \ No newline at end of file diff --git a/src/Blockkit/Blocks/Actions.php b/src/Blockkit/Blocks/Actions.php new file mode 100644 index 0000000..73182b9 --- /dev/null +++ b/src/Blockkit/Blocks/Actions.php @@ -0,0 +1,54 @@ + 255, // @todo Should be unique for each message + ]; + + private const MAX_ELEMENTS = 5; + + /** + * @param Text $text + * @throws Exception + */ + public function __construct() + { + parent::__construct(); + + // Defaults + $this->type = 'actions'; + } + + public static function item(): self + { + return new self(); + } + + /* OPTIONAL ITEMS */ + + public function block_id(string $string): self + { + $this->block_id = $this->validate('block_id',$string); + + return $this; + } + + public function elements(Collection $collection): self + { + if (count($collection) > self::MAX_ELEMENTS) + throw new Exception(sprintf('Can only have maximum %d elements',self::MAX_ELEMENTS)); + + $this->elements = $collection; + + return $this; + } +} \ No newline at end of file diff --git a/src/Blockkit/Blocks/Button.php b/src/Blockkit/Blocks/Button.php deleted file mode 100644 index 35756cb..0000000 --- a/src/Blockkit/Blocks/Button.php +++ /dev/null @@ -1,30 +0,0 @@ -type = 'button'; - $this->text = $text; - $this->value = $value ?: '-'; - $this->action_id = $action_id; - if ($url) - $this->url = $url; - if ($style) - $this->style = $style; - } - - public static function item(TextEmoji $text,string $value,string $action_id,string $url=NULL,string $style=NULL): self - { - return new self($text,$value,$action_id,$url,$style); - } -} \ No newline at end of file diff --git a/src/Blockkit/Blocks/Context.php b/src/Blockkit/Blocks/Context.php new file mode 100644 index 0000000..60f51bd --- /dev/null +++ b/src/Blockkit/Blocks/Context.php @@ -0,0 +1,48 @@ + 255, // @todo Should be unique for each message + ]; + + private const MAX_ELEMENTS = 10; + + /** + * @param Collection $collection + * @throws Exception + * @todo Collection can only be image or text elements + */ + public function __construct(Collection $collection) + { + parent::__construct(); + + // Defaults + $this->type = 'context'; + + if (count($collection) > self::MAX_ELEMENTS) + throw new Exception(sprintf('Can only have maximum %d elements',self::MAX_ELEMENTS)); + + $this->elements = $collection; + } + + public static function item(Collection $collection): self + { + return new self($collection); + } + + /* OPTIONAL ITEMS */ + + public function block_id(string $string): self + { + $this->block_id = $this->validate('block_id',$string); + + return $this; + } +} \ No newline at end of file diff --git a/src/Blockkit/Blocks/Divider.php b/src/Blockkit/Blocks/Divider.php new file mode 100644 index 0000000..d6f73f2 --- /dev/null +++ b/src/Blockkit/Blocks/Divider.php @@ -0,0 +1,40 @@ + 255, // @todo Should be unique for each message + ]; + + /** + * @param Text|NULL $text + * @throws Exception + */ + public function __construct() + { + parent::__construct(); + + // Defaults + $this->type = 'divider'; + } + + public static function item(): self + { + return new self(); + } + + /* OPTIONAL ITEMS */ + + public function block_id(string $string): self + { + $this->block_id = $this->validate('block_id',$string); + + return $this; + } +} \ No newline at end of file diff --git a/src/Blockkit/Blocks/Elements/Button.php b/src/Blockkit/Blocks/Elements/Button.php new file mode 100644 index 0000000..be9be9e --- /dev/null +++ b/src/Blockkit/Blocks/Elements/Button.php @@ -0,0 +1,67 @@ + 255, + 'text' => 75, + 'url' => 3000, + 'value' => 2000, + ]; + + public function __construct(Text $text,string $value,string $action_id) + { + parent::__construct(); + + // Defaults + $this->type = 'button'; + + if ($text->type != 'plain_text') + throw new Exception(sprintf('Text must be plain_text not %s',$text->type)); + + if (strlen($text->text) > self::LIMITS['text']) + throw new Exception(sprintf('Text must be %d chars or less',self::LIMITS['text'])); + + $this->text = $text; + + $this->value = $this->validate('value',$value); + $this->action_id = $this->validate('action_id',$action_id); + } + + public static function item(Text $text,string $value,string $action_id): self + { + return new self($text,$value,$action_id); + } + + /* OPTIONAL ITEMS */ + + public function confirm(Confirm $confirm): self + { + $this->confirm = $confirm; + + return $this; + } + + public function style(string $string): self + { + if (! in_array($string,['default','primary','danger'])) + throw new Exception(sprintf('Unknown style %s',$string)); + + $this->style = $string; + + return $this; + } + + public function url(string $string): self + { + $this->url = $this->validate('url',$string); + + return $this; + } +} \ No newline at end of file diff --git a/src/Blockkit/Blocks/Elements/Confirm.php b/src/Blockkit/Blocks/Elements/Confirm.php new file mode 100644 index 0000000..1a6a1c3 --- /dev/null +++ b/src/Blockkit/Blocks/Elements/Confirm.php @@ -0,0 +1,20 @@ + 255, + 'placeholder' => 150, + ]; + + private const MAX_OPTIONS = 100; + + /** + * @param Text $placeholder + * @param string $action_id + * @param Collection $options + * @throws Exception + * @todo We dont handle option_groups yet. + */ + public function __construct(Text $placeholder,string $action_id,Collection $options) + { + parent::__construct(); + + // Defaults + $this->type = 'multi_static_select'; + + if ($placeholder->type != 'plain_text') + throw new Exception(sprintf('Text must be plain_text not %s',$placeholder->type)); + + if (strlen($placeholder->text) > self::LIMITS['placeholder']) + throw new Exception(sprintf('Text must be %d chars or less',self::LIMITS['placeholder'])); + + $this->placeholder = $placeholder; + + $this->action_id = $this->validate('action_id',$action_id); + + if (count($options) > self::MAX_OPTIONS) + throw new Exception(sprintf('Can only have maximum %d options',self::MAX_OPTIONS)); + + $this->options = $options->transform(function($item) { + return ['text'=>Text::item($item->name,'plain_text'),'value'=>(string)$item->id]; + }); + } + + public static function item(Text $placeholder,string $action_id,Collection $options): self + { + return new self($placeholder,$action_id,$options); + } + + /* OPTIONAL ITEMS */ + + public function confirm(Confirm $confirm): self + { + $this->confirm = $confirm; + + return $this; + } + + public function focus_on_load(bool $bool): self + { + $this->focus_on_load = $bool ? 'true' : 'false'; + + return $this; + } + + public function initial_options(Collection $collection): self + { + // No initial options. + if (! count($collection)) + return $this; + + if (count($collection) > self::MAX_OPTIONS) + throw new Exception(sprintf('Can only have maximum %d options',self::MAX_OPTIONS)); + + $this->initial_options = $collection->transform(function($item) { + return ['text'=>Text::item($item->name,'plain_text'),'value'=>(string)$item->id]; + }); + + return $this; + } + + public function max_selected_items(int $int): self + { + if ($int < 1) + throw new Exception('Minimum 1 options must be configured'); + + $this->max_selected_items = $int; + + return $this; + } +} \ No newline at end of file diff --git a/src/Blockkit/Blocks/Elements/Options.php b/src/Blockkit/Blocks/Elements/Options.php new file mode 100644 index 0000000..7cc8c2c --- /dev/null +++ b/src/Blockkit/Blocks/Elements/Options.php @@ -0,0 +1,57 @@ + 75, + 'text' => 75, + 'value' => 75, + 'url' => 3000, + ]; + + public function __construct(Text $text,string $value) + { + if (strlen($text->text) > self::LIMITS['text']) + throw new Exception(sprintf('Text must be %d chars or less',self::LIMITS['text'])); + + $this->text = $text; + $this->value = $this->validate('value',$value); + } + + public static function item(Text $text,string $value): self + { + return new self($text,$value); + } + + /* OPTIONAL ITEMS */ + + public function description(Text $text): self + { + if ($text->type != 'plain_text') + throw new Exception(sprintf('Text must be plain_text not %s',$text->type)); + + if (strlen($text->text) > self::LIMITS['description']) + throw new Exception(sprintf('Text must be %d chars or less',self::LIMITS['description'])); + + $this->description = $text; + + return $this; + } + + public function url(string $string): self + { + $this->url = $this->validate('url',$string); + + return $this; + } +} \ No newline at end of file diff --git a/src/Blockkit/Blocks/Elements/Text.php b/src/Blockkit/Blocks/Elements/Text.php new file mode 100644 index 0000000..73adb4f --- /dev/null +++ b/src/Blockkit/Blocks/Elements/Text.php @@ -0,0 +1,47 @@ +type = $type; + $this->text = $text; + } + + public static function item(string $text,string $type='mrkdwn'): self + { + return new self($text,$type); + } + + /* OPTIONAL ITEMS */ + + public function emoji(bool $bool): self + { + if ($x=$this->type != 'plain_text') + throw new Exception(sprintf('Cannnot use emoji when type is [%s]',$x)); + + $this->emoji = $bool ? 'true' : 'false'; + + return $this; + } + + public function verbatim(bool $bool): self + { + $this->verbatim = $bool ? 'true' : 'false'; + + return $this; + } +} \ No newline at end of file diff --git a/src/Blockkit/Blocks/Header.php b/src/Blockkit/Blocks/Header.php new file mode 100644 index 0000000..6e7eac5 --- /dev/null +++ b/src/Blockkit/Blocks/Header.php @@ -0,0 +1,49 @@ + 255, // @todo Should be unique for each message + 'text' => 150, + ]; + + /** + * @param Text $text + * @throws Exception + */ + public function __construct(Text $text) + { + parent::__construct(); + + // Defaults + $this->type = 'header'; + + if ($text->type != 'plain_text') + throw new Exception(sprintf('Text must be plain_text not %s',$text->type)); + + if (strlen($text->text) > self::LIMITS['text']) + throw new Exception(sprintf('Text must be %d chars or less',self::LIMITS['text'])); + + $this->text = $text; + } + + public static function item(Text $text): self + { + return new self($text); + } + + /* OPTIONAL ITEMS */ + + public function block_id(string $string): self + { + $this->block_id = $this->validate('block_id',$string); + + return $this; + } +} \ No newline at end of file diff --git a/src/Blockkit/Blocks/Input.php b/src/Blockkit/Blocks/Input.php deleted file mode 100644 index eb04389..0000000 --- a/src/Blockkit/Blocks/Input.php +++ /dev/null @@ -1,24 +0,0 @@ -type = 'input'; - $this->element = $element; - $this->label = $label; - } - - public static function item(Element $element,TextEmoji $label): self - { - return new self($element,$label); - } -} \ No newline at end of file diff --git a/src/Blockkit/Blocks/Section.php b/src/Blockkit/Blocks/Section.php new file mode 100644 index 0000000..56c0e2f --- /dev/null +++ b/src/Blockkit/Blocks/Section.php @@ -0,0 +1,80 @@ + 255, // @todo Should be unique for each message + 'text' => 3000, + ]; + + private const MAX_FIELDS = 10; + private const MAX_FIELDS_TEXT = 2000; + + /** + * @param Text|NULL $text not required if fields is provided + * @throws Exception + */ + public function __construct(Text $text=NULL) + { + parent::__construct(); + + // Defaults + $this->type = 'section'; + + if ($text) { + if (strlen($text->text) > self::LIMITS['text']) + throw new Exception(sprintf('Text must be %d chars or less',self::LIMITS['text'])); + + $this->text = $text; + } + } + + public static function item(Text $text=NULL): self + { + return new self($text); + } + + public function jsonSerialize() + { + if (! $this->text && ! $this->fields) + throw new Exception('Must define text or fields'); + + return parent::jsonSerialize(); + } + + /* OPTIONAL ITEMS */ + + public function accessory(Element $object): self + { + $this->accessory = $object; + + return $this; + } + + public function block_id(string $string): self + { + $this->block_id = $this->validate('block_id',$string); + + return $this; + } + + public function fields(Collection $collection): self + { + if (count($collection) > self::MAX_FIELDS) + throw new Exception(sprintf('Can only have maximum %d fields',self::MAX_FIELDS)); + + if ($collection->map(function($item) { return strlen($item->text); })->max() > self::MAX_FIELDS_TEXT) + throw new Exception(sprintf('The maximum size of text in a field is %d',self::MAX_FIELDS_TEXT)); + + $this->fields = $collection; + + return $this; + } +} \ No newline at end of file diff --git a/src/Blockkit/Blocks/Text.php b/src/Blockkit/Blocks/Text.php deleted file mode 100644 index 7200e10..0000000 --- a/src/Blockkit/Blocks/Text.php +++ /dev/null @@ -1,20 +0,0 @@ -type = $type; - $this->text = $text; - } - - public static function item(string $text,string $type='mrkdwn'): self - { - return new self($text,$type); - } -} \ No newline at end of file diff --git a/src/Blockkit/Blocks/TextEmoji.php b/src/Blockkit/Blocks/TextEmoji.php deleted file mode 100644 index 830ab6f..0000000 --- a/src/Blockkit/Blocks/TextEmoji.php +++ /dev/null @@ -1,22 +0,0 @@ -emoji = $emoji; - $this->text = $text; - $this->type = 'plain_text'; - } - - public static function item(string $text,bool $emoji=TRUE): self - { - return new self($text,$emoji); - } -} \ No newline at end of file diff --git a/src/Blockkit/Element.php b/src/Blockkit/Element.php new file mode 100644 index 0000000..ad14235 --- /dev/null +++ b/src/Blockkit/Element.php @@ -0,0 +1,9 @@ + 255, + 'close' => 24, + 'private_metadata' => 3000, + 'text' => 24, + ]; + + private const MAX_BLOCKS = 100; + private $action = NULL; - public function __construct(TextEmoji $title) + public function __construct(Text $title=NULL,string $type='modal') { parent::__construct(); - $this->_data->put('type','modal'); - $this->_data->put('title',$title); + if (! in_array($type,['modal','home'])) + throw new Exception(sprintf('Unknown type %s',$type)); + + if ($type != 'modal' && $title) + throw new Exception(sprintf('Titles are not required for %s',$type)); + + if ($title) { + if ($title->type != 'plain_text') + throw new Exception(sprintf('Text must be plain_text not %s',$title->type)); + + if (strlen($title->text) > self::LIMITS['text']) + throw new Exception(sprintf('Text must be %d chars or less',self::LIMITS['text'])); + + $this->title = $title; + } + + $this->type = $type; + + $this->blocks = collect(); } - /* - public function action(string $action) + /** + * Add a block to this modal + * + * @param BlockKit $block + * @return $this + */ + public function addBlock(Blocks $block): self { - $this->action = $action; + $this->blocks->push($block); + + if ($x=$this->blocks->count() > self::MAX_BLOCKS) + throw new Exception(sprintf('Modal can only have %d blocks',self::MAX_BLOCKS)); + + return $this; } - */ /** * The data that will be returned when converted to JSON. @@ -37,18 +75,133 @@ class Modal extends BlockKit return ['response_action'=>'clear']; case 'update': - return ['response_action'=>'update','view'=>$this->_data]; + return ['response_action'=>'update','view'=>parent::jsonSerialize()]; default: - return $this->_data; + return parent::jsonSerialize(); } } + /* OPTIONAL ITEMS */ + + public function action(string $string) + { + if (! in_array($string,['clear','update'])) + throw new Exception(sprintf('Unknown action %s',$string)); + + $this->action = $string; + } + + public function clear_on_close(bool $bool): self + { + if ($this->type != 'modal') + throw new Exception(sprintf('clear_on_close is not required for %s',$type)); + + $this->clear_on_close = $bool ? 'true' : 'false'; + + return $this; + } + + public function callback_id(string $string): self + { + $this->callback_id = $this->validate('callback_id',$string); + + return $this; + } + + public function close(Text $text): self + { + if ($this->type != 'modal') + throw new Exception(sprintf('Close is not required for %s',$type)); + + if ($text->type != 'plain_text') + throw new Exception(sprintf('Text must be plain_text not %s',$text->type)); + + if (strlen($text->text) > self::LIMITS['close']) + throw new Exception(sprintf('Text must be %d chars or less',self::LIMITS['close'])); + + $this->close = $text; + + return $this; + } + + // This is a helper method + public function divider(): self + { + $this->blocks->push(Divider::item()); + + return $this; + } + + /** + * @param string $string + * @return $this + * @note A custom identifier that must be unique for all views on a per-team basis. + */ + public function external_id(string $string): self + { + $this->external_id = $string; + + return $this; + } + + public function notify_on_close(bool $bool): self + { + if ($this->type != 'modal') + throw new Exception(sprintf('notify_on_close is not required for %s',$type)); + + $this->notify_on_close = $bool ? 'true' : 'false'; + + return $this; + } + + public function private_metadata(string $string): self + { + $this->private_metadata = $this->validate('private_metadata',$string); + + return $this; + } + + // This is a helper method + public function spacer(): self + { + $this->blocks->push(Section::item(Text::item(' '))); + + return $this; + } + + public function submit(Text $text): self + { + if ($this->type != 'modal') + throw new Exception(sprintf('Submit is not required for %s',$type)); + + if ($text->type != 'plain_text') + throw new Exception(sprintf('Text must be plain_text not %s',$text->type)); + + if (strlen($text->text) > self::LIMITS['submit']) + throw new Exception(sprintf('Text must be %d chars or less',self::LIMITS['submit'])); + + $this->submit = $text; + + return $this; + } + + public function submit_disabled(bool $bool): self + { + if ($this->type != 'modal') + throw new Exception(sprintf('submit_disabled is not required for %s',$type)); + + $this->submit_disabled = $bool ? 'true' : 'false'; + + return $this; + } + /** * Add a block to the modal * * @param Blocks $blocks * @return $this + * @deprecated use addBlock() instead */ public function setBlocks(Blocks $blocks): self { @@ -56,58 +209,4 @@ class Modal extends BlockKit return $this; } - - public function setCallback(string $id): self - { - $this->_data->put('callback_id',$id); - - return $this; - } - - /* - public function close(string $text='Cancel'): self - { - $this->_data->put('close', - [ - 'type'=>'plain_text', - 'text'=>$text, - 'emoji'=>true, - ]); - - return $this; - } - - public function meta(string $id): self - { - $this->_data->put('private_metadata',$id); - - return $this; - } - - public function notifyClose(): self - { - $this->_data->put('notify_on_close',TRUE); - - return $this; - } - - public function private(array $data): self - { - $this->_data->put('private_metadata',json_encode($data)); - - return $this; - } - - public function submit(string $text='Submit'): self - { - $this->_data->put('submit', - [ - 'type'=>'plain_text', - 'text'=>$text, - 'emoji'=>true, - ]); - - return $this; - } - */ -} +} \ No newline at end of file diff --git a/src/Command/Base.php b/src/Command/Base.php index d73b23c..51e6b5d 100644 --- a/src/Command/Base.php +++ b/src/Command/Base.php @@ -60,12 +60,14 @@ abstract class Base extends SlackBase if (! $this->channel() || ! $this->channel()->active) { $blocks = new Blocks; - $blocks->addHeader(':robot_face: Bot not in this channel'); - $blocks->addSectionText(Blocks\Text::item(sprintf('Please add %s to this channel and try this again.',$this->team()->bot->name ?: 'the BOT'))); - - $o->setAttachments((new Message\Attachments())->setBlocks($blocks)->setColor('#ff0000')); + $o->addAttachment( + Message\Attachment::item() + ->title(':robot_face: Bot not in this channel') + ->text(sprintf('Please add %s to this channel and try this again.',$this->team()->bot->name ?: 'the BOT')) + ->color('#ff0000') + ); } return $o->isEmpty() ? NULL : $o; } -} +} \ No newline at end of file diff --git a/src/Command/Factory.php b/src/Command/Factory.php index f5512ee..f6cabd1 100644 --- a/src/Command/Factory.php +++ b/src/Command/Factory.php @@ -42,4 +42,4 @@ class Factory { return self::create($command ?: 'help',Arr::get($request->getData(),'payload')); } -} +} \ No newline at end of file diff --git a/src/Command/Help.php b/src/Command/Help.php index 1868fcb..585dbcd 100644 --- a/src/Command/Help.php +++ b/src/Command/Help.php @@ -3,7 +3,6 @@ namespace Slack\Command; use Slack\Message; -use Slack\Message\Attachments; class Help extends Base { @@ -13,13 +12,14 @@ class Help extends Base { $o = new Message; - $o->setText('Hi, I am a *NEW* Bot'); + $o->text('Hi, I am a *NEW* Bot'); // Version - $a = new Attachments; - $a->addField('Version',config('app.version','unknown'),TRUE); - $o->setAttachments($a); + $o->addAttachment( + Message\Attachment::item() + ->addField('Version',config('app.version','unknown'),TRUE) + ); return $o; } -} +} \ No newline at end of file diff --git a/src/Command/Unknown.php b/src/Command/Unknown.php index cf03919..7a66e5b 100644 --- a/src/Command/Unknown.php +++ b/src/Command/Unknown.php @@ -24,8 +24,8 @@ final class Unknown extends Base { $o = new Message; - $o->setText(sprintf('I didnt understand your command "%s". You might like to try `%s help` instead.',$this->command,$this->slashcommand)); + $o->text(sprintf('I didnt understand your command "%s". You might like to try `%s help` instead.',$this->command,$this->slashcommand)); return $o; } -} +} \ No newline at end of file diff --git a/src/Listeners/ShortcutListener.php b/src/Listeners/ShortcutListener.php index 18529e4..d4c22c1 100644 --- a/src/Listeners/ShortcutListener.php +++ b/src/Listeners/ShortcutListener.php @@ -3,7 +3,8 @@ namespace App\Listeners; use Illuminate\Support\Facades\Log; -use Slack\Blockkit\Blocks; +use Slack\Blockkit\Blocks\Elements\Text; +use Slack\Blockkit\Blocks\{Header,Section}; use Slack\Blockkit\Modal; use Slack\Interactive\Shortcut; use Slack\Message; @@ -25,13 +26,15 @@ class ShortcutListener //implements ShouldQueue public function handle(Shortcut $event): Message { if (! $event->channel() || ! $event->channel()->active) { - $modal = new Modal(Blocks\TextEmoji::item(config('app.name'))); + $modal = new Modal(Text::item(config('app.name'),'plain_text')); $blocks = new Blocks; - $blocks->addHeader(':robot_face: Bot not in this channel'); - $blocks->addSectionText(Blocks\Text::item('Please add the BOT to this channel and try this again.')); - - $modal->setBlocks($blocks); + $modal->addBlock( + Header::item(Text::item(':robot_face: Bot not in this channel','plain_text')) + ) + ->addBlock( + Section::item(Text::item('Please add the BOT to this channel and try this again.')) + ); try { $event->team()->slackAPI()->viewOpen($event->trigger_id,json_encode($modal)); diff --git a/src/Message.php b/src/Message.php index aff59ec..aab4399 100644 --- a/src/Message.php +++ b/src/Message.php @@ -5,23 +5,28 @@ namespace Slack; use Carbon\Carbon; use Carbon\CarbonInterface; use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Arr; +use Illuminate\Support\Collection; use Illuminate\Support\Facades\Log; use Slack\Blockkit\Blocks; +use Slack\Blockkit\Blocks\Context; +use Slack\Blockkit\Blocks\Elements\Text; use Slack\Exceptions\SlackException; use Slack\Jobs\DeleteChat; -use Slack\Message\Attachments; +use Slack\Message\Attachment; use Slack\Models\{Channel,User}; use Slack\Response\Generic; /** * This class is used when composing a message to send to Slack. */ -class Message implements \JsonSerializable +final class Message extends BlockKit { protected const LOGKEY = 'SM-'; + private const MAX_ATTACHMENTS = 20; + private Model $o; - private Blocks $blocks; private ?Carbon $selfdestruct = NULL; /** @@ -32,7 +37,7 @@ class Message implements \JsonSerializable */ public function __construct(Model $o=NULL) { - $this->_data = collect(); + parent::__construct(); if ($o) { // Message is to a channel @@ -49,10 +54,10 @@ class Message implements \JsonSerializable $this->o = $o; } - - $this->blocks = new Blocks; } + /* HELPER METHODS */ + /** * Add a block to the message * @@ -60,9 +65,25 @@ class Message implements \JsonSerializable * @return Message * @todo to test */ - public function addBlock(Blocks $blocks): self + public function addAttachment(Attachment $attachment): self { - $this->blocks = $blocks; + if (! Arr::get($this->_data,'attachments')) + $this->attachments = collect(); + + $this->attachments->push($attachment); + + if (count($this->attachments) > self::MAX_ATTACHMENTS) + throw new Exception(sprintf('Messages should not have more than %d attachments',self::MAX_ATTACHMENTS)); + + return $this; + } + + public function addBlock(Blocks $block): self + { + if (! Arr::get($this->_data,'blocks')) + $this->blocks = collect(); + + $this->blocks->push($block); return $this; } @@ -75,21 +96,10 @@ class Message implements \JsonSerializable public function blank(): self { $this->_data = collect(); - $this->blocks = new Blocks; return $this; } - /* - * @todo This doesnt appear to work - public function ephemeral(): self - { - $this->_data->put('ephemeral',TRUE); - - return $this; - } - */ - public function forgetTS(): self { $this->_data->forget('ts'); @@ -112,11 +122,8 @@ class Message implements \JsonSerializable */ public function jsonSerialize() { - if ($this->blocks->count()) - $this->_data->put('blocks',$this->blocks); - // For interactive messages that generate a dialog, we need to return NULL - return $this->_data->count() ? $this->_data : NULL; + return $this->_data->count() ? parent::jsonSerialize() : NULL; } /** @@ -134,7 +141,7 @@ class Message implements \JsonSerializable if ($this->_data->has('ephemeral')) abort('500','Cannot post ephemeral messages.'); - if ($this->blocks->count() && $this->_data->get('attachments')) + if ($this->_data->get('blocks') && $this->_data->get('attachments')) throw new SlackException('Message cannot have blocks and attachments.'); $api = $this->o->team->slackAPI(); @@ -150,42 +157,6 @@ class Message implements \JsonSerializable return $response; } - /** - * Schedule a message - * - * @param Carbon $time - * @return Generic - */ - public function schedule(Carbon $time): Generic - { - $this->_data->put('post_at',$time->timestamp); - - $api = $this->o->team->slackAPI(); - $response = $this->_data->has('ts') ? $api->updateMessage($this) : $api->scheduleMessage($this); - - return $response; - } - - public function setReplace(bool $replace=TRUE): self - { - $this->_data->put('replace_original',$replace ? 'true' : 'false'); - - return $this; - } - - /** - * To slack from rendering URLs in the message - * - * @param bool $unfurl - * @return $this - */ - public function setUnfurlLinks(bool $unfurl): self - { - $this->_data->put('unfurl_links',$unfurl ? 'true' : 'false'); - - return $this; - } - /** * Post a message to slack using the respond_url * @@ -228,6 +199,22 @@ class Message implements \JsonSerializable return $result; } + /** + * Schedule a message + * + * @param Carbon $time + * @return Generic + */ + public function schedule(Carbon $time): Generic + { + $this->_data->put('post_at',$time->timestamp); + + $api = $this->o->team->slackAPI(); + $response = $this->_data->has('ts') ? $api->updateMessage($this) : $api->scheduleMessage($this); + + return $response; + } + /** * Make the message self destruct * @@ -236,21 +223,161 @@ class Message implements \JsonSerializable */ public function selfdestruct(Carbon $time): self { - $this->blocks->addContextElements(collect([ - Blocks\Text::item(sprintf('This message will self destruct in %s...',$time->diffForHumans(Carbon::now(),['syntax' => CarbonInterface::DIFF_RELATIVE_TO_NOW]))) - ])); + $this->addBlock( + Context::item(collect([ + Text::item(sprintf('This message will self destruct in %s...',$time->diffForHumans(Carbon::now(),['syntax' => CarbonInterface::DIFF_RELATIVE_TO_NOW]))) + ])) + ); $this->selfdestruct = $time; return $this; } /** - * Add an attachment to a message + * Set our channel * - * @param Attachments $attachments + * @param Channel $o * @return Message */ - public function setAttachments(Attachments $attachments): self + public function setChannel(Channel $o): self + { + $this->channel = $o->channel_id; + $this->o = $o; + + return $this; + } + + /** + * Set our channel + * + * @param User $o + * @return Message + */ + public function setUser(User $o): self + { + $this->channel = $o->user_id; + $this->o = $o; + + return $this; + } + + /* CONFIGURATION METHODS */ + + /** + * @return Message + * @todo - Check this is a valid option + */ + public function ephemeral(): self + { + $this->ephemeral = 'true'; + + return $this; + } + + /** + * Set the icon next to the message + * + * @param string $icon + * @return Message + * @deprecated + */ + public function icon_emoji(string $icon): self + { + $this->icon_emoji = $icon; + + return $this; + } + + /** + * Option groups are used by the interactive Options controller and hold no other attributes + * + * @param Collection $collection + * @return Message + * @todo - Check this is a valid option + */ + public function option_groups(Collection $collection): self + { + $this->option_groups = $collection; + } + + /** + * @return Message + * @todo - Check this is a valid option + */ + public function replace_original(bool $bool=TRUE): self + { + $this->replace_original = $bool ? 'true' : 'false'; + + return $this; + } + + /** + * Message text + * + * @param string $string + * @return Message + */ + public function text(string $string): self + { + $this->text = $string; + + return $this; + } + + /** + * Set the thread timestamp, used when adding a threaded response + * + * @param string $string + * @return Message + */ + public function thread_ts(string $string): self + { + $this->thread_ts = $string; + + return $this; + } + + /** + * Set the timestamp, used when replacing messages + * + * @param string $string + * @return Message + */ + public function ts(string $string): self + { + $this->ts = $string; + + return $this; + } + + /** + * To slack from rendering URLs in the message + * + * @param bool $bool + * @return $this + */ + public function unfurl_links(bool $bool): self + { + $this->unfurl_links = $bool ? 'true' : 'false'; + + return $this; + } + + public function username(string $user): self + { + $this->username = $user; + + return $this; + } + + /** + * Add an attachment to a message + * + * @param Attachment $attachments + * @return Message + * @deprecated use addAttachment() + */ + public function setAttachments(Attachment $attachments): self { $this->_data->put('attachments',[$attachments]); @@ -263,6 +390,7 @@ class Message implements \JsonSerializable * @param Blocks $blocks * @return Message * @throws \Exception + * @deprecated use addBlocks() */ public function setBlocks(Blocks $blocks): self { @@ -274,55 +402,16 @@ class Message implements \JsonSerializable return $this; } - /** - * Set our channel - * - * @param Channel $o - * @return Message - */ - public function setChannel(Channel $o): self - { - $this->_data->put('channel',$o->channel_id); - $this->o = $o; - - return $this; - } - - /** - * Set the icon next to the message - * - * @param string $icon - * @return Message - * @deprecated - */ - public function setIcon(string $icon): self - { - $this->_data->put('icon_emoji',$icon); - - return $this; - } - - /** - * Option groups are used by the interactive Options controller and hold no other attributes - * - * @param array $array - * @return void - */ - public function setOptionGroup(array $array): void - { - $this->_data = collect(); // @todo Why are clearing our data? - $this->_data->put('option_groups',$array); - } - /** * Message text * * @param string $string * @return Message + * @deprecated use text() */ public function setText(string $string): self { - $this->_data->put('text',$string); + $this->text = $string; return $this; } @@ -332,6 +421,7 @@ class Message implements \JsonSerializable * * @param string $string * @return Message + * @deprecated use ts() */ public function setTS(string $string): self { @@ -345,6 +435,7 @@ class Message implements \JsonSerializable * * @param string $string * @return Message + * @deprecated use thead_ts() */ public function setThreadTS(string $string): self { @@ -352,25 +443,4 @@ class Message implements \JsonSerializable return $this; } - - /** - * Set our channel - * - * @param User $o - * @return Message - */ - public function setUser(User $o): self - { - $this->_data->put('channel',$o->user_id); - $this->o = $o; - - return $this; - } - - public function setUserName(string $user): self - { - $this->_data->put('username',$user); - - return $this; - } } diff --git a/src/Message/Attachment.php b/src/Message/Attachment.php new file mode 100644 index 0000000..e4cb762 --- /dev/null +++ b/src/Message/Attachment.php @@ -0,0 +1,168 @@ + 300, + ]; + + /** + * @param Text $text + * @throws Exception + */ + public function __construct() + { + parent::__construct(); + } + + public static function item(): self + { + return new self(); + } + + /* OPTIONAL ITEMS */ + + /** + * @note These are now legacy - use blocks instead + * @note more information on this available https://api.slack.com/legacy/interactive-message-field-guide + */ + public function addAction(string $name,string $text,string $type,string $value,string $style=NULL,array $confirm=NULL): self + { + if (! Arr::get($this->_data,'actions')) { + $this->actions = collect(); + $this->attachment_type = 'default'; + } + + $action = ['name'=>$name,'text'=>$text,'type'=>$type,'value'=>$value]; + if ($style) + $action['style'] = $style; + + // Confirm dialog is an array of 'title','text','ok_text','dismiss_text' + if ($confirm) + $action['confirm'] = $confirm; + + $this->actions->push(); + + return $this; + } + + public function addBlock(Blocks $block): self + { + if (! Arr::get($this->_data,'blocks')) + $this->blocks = collect(); + + $this->blocks->push($block); + + return $this; + } + + public function addField(string $title,string $value,bool $short): self + { + if (! Arr::get($this->_data,'fields')) + $this->fields = collect(); + + $this->fields->push(['title'=>$title,'value'=>$value,'short'=>$short ? 'true' : 'false']); + + return $this; + } + + /** + * @param string $string + * @return $this + * @note Can either be one of good (green), warning (yellow), danger (red), or any hex color code (eg. #439FE0) + */ + public function color(string $string): self + { + $this->color = $string; + + return $this; + } + + /** + * @param string $string + * @return $this + * @note Appears to be only used with actions + */ + public function callback_id(string $string): self + { + $this->callback_id = $string; + + return $this; + } + + public function fallback(string $string): self + { + $this->fallback = $string; + + return $this; + } + + public function footer(string $string): self + { + $this->footer = $this->validate('footer',$string); + + return $this; + } + + public function footer_icon(string $string): self + { + $this->footer_icon = $string; + + return $this; + } + + /** + * Set where markdown should be parsed by slack + * + * @param array $array + */ + public function mrkdwn_in(array $array): self + { + // @todo Add array check to make sure it has valid items + $this->mrkdwn_in = $array; + + return $this; + } + + public function pretext(string $string): self + { + $this->pretext = $string; + + return $this; + } + + public function text(string $string): self + { + $this->text = $string; + + return $this; + } + + public function title(string $string): self + { + $this->title = $string; + + return $this; + } + + public function title_link(string $string): self + { + $this->title_link = $string; + + return $this; + } + + public function ts(string $string): self + { + $this->ts = $string; + + return $this; + } +} \ No newline at end of file diff --git a/src/Message/AttachmentAction.php b/src/Message/AttachmentAction.php deleted file mode 100644 index ce73c5d..0000000 --- a/src/Message/AttachmentAction.php +++ /dev/null @@ -1,133 +0,0 @@ -_data = collect(); - } - - public function jsonSerialize() - { - return $this->_data; - } - - public function minSize(int $int): self - { - $this->_data->put('min_query_length',$int); - - return $this; - } - - /** - * Set a confirmation diaglog when this action is selected - * - * @param string $title - * @param string $text - * @param string $ok_text - * @param string $dismiss_text - * @return $this - */ - public function setConfirm(string $title,string $text,string $ok_text,string $dismiss_text): self - { - $this->_data->put('confirm',[ - 'title'=>$title, - 'text'=>$text, - 'ok_text'=>$ok_text, - 'dismiss_text'=>$dismiss_text - ]); - - return $this; - } - - /** - * Set the name of the action - * - * @param string $string - * @return $this - */ - public function setName(string $string): self - { - $this->_data->put('name',$string); - - return $this; - } - - /** - * Set the text displayed in the action - * - * @param string $type - * @return $this - */ - public function setStyle(string $style): self - { - if (! in_array($style,['danger','primary'])) - abort(500,'Style not supported: '.$style); - - $this->_data->put('style',$style); - - return $this; - } - - /** - * Set the text displayed in the action - * - * @param string $string - * @return $this - */ - public function setText(string $string): self - { - $this->_data->put('text',$string); - - return $this; - } - - /** - * Set the text displayed in the action - * - * @param string $type - * @return $this - */ - public function setType(string $type): self - { - if (! in_array($type,['button','select'])) - abort(500,'Type not supported: '.$type); - - $this->_data->put('type',$type); - - return $this; - } - - /** - * Set the value for the action - * - * @param string $string - * @return $this - */ - public function setValue(string $string): self - { - $this->_data->put('value',$string); - - return $this; - } - - public function source(string $string): self - { - if (! in_array($string,['external'])) - abort(500,'Dont know how to handle: '.$string); - - $this->_data->put('data_source',$string); - - return $this; - } -} diff --git a/src/Message/Attachments.php b/src/Message/Attachments.php deleted file mode 100644 index 5d94df3..0000000 --- a/src/Message/Attachments.php +++ /dev/null @@ -1,227 +0,0 @@ -actions = collect(); - //$this->blocks = collect(); - $this->blockactions = collect(); - $this->_data = collect(); - } - - // @todo To rework - - public function jsonSerialize() - { - /* - if ($this->actions->count() AND ! $this->_data->has('callback_id')) - abort(500,'Actions without a callback ID'); - - if ($this->blockactions->count()) { - $x = collect(); - $x->put('type','actions'); - $x->put('elements',$this->blockactions); - - $this->blocks->push($x); - - // Empty out our blockactions, incase we are converted to json a second time. - $this->blockactions = collect(); - } - - if ($this->actions->count()) - $this->_data->put('actions',$this->actions); - - if ($this->blocks->count()) - $this->_data->put('blocks',$this->blocks); - */ - - return $this->_data; - } - /** - * Add an attachment to a message - * - * @param AttachmentAction $action - * @return Attachment - * @todo To rework - */ - public function addAction(AttachmentAction $action): self - { - $this->actions->push($action); - - return $this; - } - - /** - * Add a block to message - * - * @param BlockKit $block - * @return Attachment - * @deprecated - */ - public function addBlock(BlockKit $block): self - { - $this->blocks->push($block); - - return $this; - } - - /** - * Add a BlockAction to a Block - * - * @param BlockAction $action - * @return $this - * @todo To rework - */ - public function addBlockAction(BlockAction $action): self - { - $this->blockactions->push($action); - - return $this; - } - - //* @todo To rework - - public function addField(string $title,string $value,bool $short): self - { - if (! $this->_data->has('fields')) - $this->_data->put('fields',collect()); - - $this->_data->get('fields')->push([ - 'title'=>$title, - 'value'=>$value, - 'short'=>$short - ]); - - return $this; - } - /** - * Set where markdown should be parsed by slack - * - * @param array $array - * @return $this - * @todo To rework - */ - public function markdownIn(array $array): self - { - // @todo Add array check to make sure it has valid items - $this->_data->put('mrkdown_in',$array); - - return $this; - } - - /** - * Configure the attachment color (on the left of the attachment) - * - * @param string $string - * @return $this - * @todo To rework - */ - public function setCallbackID(string $string): self - { - $this->_data->put('callback_id',$string); - - return $this; - } - - /** - * Add a blocks to the message attachment - * - * @param Blocks $blocks - * @return self - */ - public function setBlocks(Blocks $blocks): self - { - $this->_data->put('blocks',$blocks); - - return $this; - } - - /** - * Configure the attachment color (on the left of the attachment) - * - * @param string $string - * @return $this - * @todo To rework - */ - public function setColor(string $string): self - { - $this->_data->put('color',$string); - - return $this; - } - - /** - * Set the text used in the attachments footer - * - * @param string $string - * @return $this - * @todo To rework - */ - public function setFooter(string $string): self - { - $this->_data->put('footer',$string); - - return $this; - } - - /** - * Add the pre-text, displayed after the title. - * - * @param string $string - * @return $this - * @todo To rework - */ - public function setPretext(string $string): self - { - $this->_data->put('pretext',$string); - - return $this; - } - - /** - * Set the text used in the attachment - * - * @param string $string - * @return $this - * @todo To rework - */ - public function setText(string $string): self - { - $this->_data->put('text',$string); - - return $this; - } - - /** - * Set the Title used in the attachment - * - * @param string $string - * @return $this - * @todo To rework - */ - public function setTitle(string $string): self - { - $this->_data->put('title',$string); - - return $this; - } -}