├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── composer.json └── src ├── ActionConfirmation.php ├── Attachment.php ├── AttachmentAction.php ├── AttachmentField.php ├── Block.php ├── Block ├── Actions.php ├── Context.php ├── Divider.php ├── ElementsBlock.php ├── File.php ├── Header.php ├── Image.php ├── Input.php └── Section.php ├── BlockElement.php ├── BlockElement ├── AbstractDynamicSelect.php ├── AbstractSelect.php ├── AbstractStaticSelect.php ├── Button.php ├── ChannelsSelect.php ├── Checkboxes.php ├── Confirmable.php ├── ConversationsSelect.php ├── DatePicker.php ├── ExternalSelect.php ├── Image.php ├── MultiChannelsSelect.php ├── MultiConversationsSelect.php ├── MultiDynamicSelect.php ├── MultiExternalSelect.php ├── MultiSelect.php ├── MultiStaticSelect.php ├── MultiUsersSelect.php ├── Options.php ├── Overflow.php ├── RadioButtons.php ├── RespondableSelect.php ├── Select.php ├── StaticSelect.php ├── Temporalpicker.php ├── Text.php ├── TextInput.php ├── Timepicker.php └── UsersSelect.php ├── Client.php ├── Field.php ├── FieldsTrait.php ├── FilterTrait.php ├── ImageTrait.php ├── MaxItemsTrait.php ├── Message.php ├── Object ├── CompositionObject.php ├── Confirmation.php ├── Filter.php ├── Option.php └── OptionGroup.php ├── OptionsTrait.php ├── Payload.php └── PlaceholderTrait.php /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## [2.3.0](https://github.com/php-slack/slack/releases/tag/2.3.0) 4 | - Support PHP 8.1, 8.2, 8.3, 8.4 5 | - Arguments with a null default must be nullable 6 | - Test PHP 8.1 through 8.4 7 | - Fix warnings for PHPUnit 8 | 9 | ## [2.2.1](https://github.com/php-slack/slack/releases/tag/2.2.1) 10 | - Update `.gitattributes`: Added /.styleci.yml export-ignore 11 | - Fix empty initial values in multi dynamic selects (fix #74) 12 | - Add Scrutinizer config with multiple php versions 13 | 14 | ## [2.2.0](https://github.com/php-slack/slack/releases/tag/2.2.0) 15 | - Fix invitation link. Ralates to php-slack/slack#67 16 | - Change fieldClass property to trait abstract 17 | - Fix minor Scrutinizer issue with legacy Client injection to Message 18 | - autoload-dev for tests directory to keep it out of production autoloader 19 | - Set Content-Type header to application/json (#71). Closes #70 20 | - Apply fixes from StyleCI (#73). Relates to #71, #70 21 | - New Block Types (#75) 22 | - Commit styleci yml (#77) 23 | 24 | ## [2.1.1](https://github.com/php-slack/slack/releases/tag/2.1.1) 25 | - Add .gitattributes (#66) 26 | 27 | ## [2.1.0](https://github.com/php-slack/slack/releases/tag/2.1.0) 28 | - Add "header" as a valid block type (#65) 29 | 30 | ## [2.0.2](https://github.com/php-slack/slack/releases/tag/2.0.2) 31 | - Fix to PSR-4 32 | - Update README.md compatible with guzzle 7.0 33 | 34 | ## [2.0.1](https://github.com/php-slack/slack/releases/tag/2.0.1) 35 | - Add tests for all BlockElement factory types 36 | - Fix BlockElement factory spec for Checkboxes (Fixes #60) 37 | 38 | ## [2.0.0](https://github.com/php-slack/slack/releases/tag/2.0.0) 39 | - ignore phpunit.xml & rename to phpunit.xml.dist fix #16 40 | - exclude 'tests' & 'vendor' from calc code coverage. closes #18 41 | - code style rules; add .editorconfig 42 | - migrate to phpunit 6.5. closes #7. & Update PhpUnit to 7.5. Closes #27 43 | - migrate to mockery 1.0. closes #19 44 | - drop support for php 5, 7.0 & hhvm (fixes builds) 45 | - php docblocks for tests. closes #8 46 | - decrease Attachment::__contruct() complexity. closes #9 47 | - rename attributes to options 48 | - decrease Client::__construct() complexity. closes #12 49 | - Added response_type to allow for 'in_channel' vs 'emphemeral' messages in channel 50 | - Blocks support (Integrate Blocks with main `Message/Client`) by @cmbuckley: 51 | - Button element and Confirmation object 52 | - Checkboxes element and Option object 53 | - DatePicker element 54 | - Image element 55 | - Overflow element 56 | - TextInput element 57 | - RadioButtons element 58 | - Select element and OptionGroup object 59 | - MultiSelect element 60 | - Actions block 61 | - Context block 62 | - Divider block 63 | - File block 64 | - Image block 65 | - Input block 66 | - Fix php doc-blocks. Closes #39. 67 | - correct initial option check (fixes #40) 68 | - add travis notification to Slack. Closes #17. 69 | - fix class name. fix #45 70 | - Improve test coverage for Block kit 71 | - Added callback_id to Attachment.php (#50) to allow for working with the interactivity callback api in slack 72 | - bugfix: prevent call on non-object 73 | - Update Composer and PHPUnit to PHP 8.0 (#56) 74 | - reuse `Payload` for `fillProperties()` (decrease complexity). resolves #13 75 | - decouple `Message` from `Client`. Closes #15, fixes maknz/slack#70 76 | 77 | ## [1.12.0](https://github.com/php-slack/slack/releases/tag/1.12.0) 78 | - add guzzle 7 support (by @esetnik) 79 | 80 | ## [1.11.0](https://github.com/alek13/slack/compare/1.10.1...1.11.0) 81 | - fix `AttachmentAction::__toArray`: no default confirmation popup if no `confirm` specified (fixes #41) 82 | - remove `5.5` & `hhvm` support, add `7.3` & `7.4` support; also remove builds for `nightly` 83 | - change travis & scrutinizer badge urls in readme 84 | - add `ext-json` dependency to `composer.json` 85 | - add Playground info in readme 86 | 87 | ## [1.10.1](https://github.com/alek13/slack/compare/1.10.0...1.10.1) 88 | - mark `Message::send` deprecated for #15 89 | - mark Laravel Provider as deprecated with link to new [separate package](https://github.com/alek13/slack-laravel) 90 | - add `Questions` section in readme 91 | - add `Quick Tour` section in readme 92 | 93 | ## [1.10.0](https://github.com/alek13/slack/compare/1.9.1...1.10.0) 94 | - Support of `url` field in `AttachmentAction` (by @rasmusdencker) 95 | 96 | ## [1.9.1](https://github.com/alek13/slack/compare/1.9.0...1.9.1) 97 | - improve & fix doc-block: right types + @throws added 98 | - fix Attachment::setIcon() return value 99 | 100 | ## [1.9.0](https://github.com/alek13/slack/compare/1.8.1...1.9.0) 101 | - Added optional footer attachments. Closes maknz/slack#87, closes #2 George* 6/15/16 12:08 AM 102 | - Php doc-blocks fixes. (Mesut Vatansever* 10/20/16 12:06 PM, Michal Vyšinský* 10/19/16 10:58 AM, Freek Van der Herten* 7/18/16 10:51 PM) 103 | 104 | ## [1.8.1](https://github.com/alek13/slack/compare/1.8.0...1.8.1) 105 | 106 | - Fix bug where message wouldn't get returned on send, closes maknz/slack#47 maknz* 6/26/16 8:06 AM 107 | - integrated Gemnasium; add dependency status badge Alexander Chibrikin 1/9/18 3:38 AM 108 | - integrated Scrutinizer-CI; change badge Alexander Chibrikin 1/9/18 3:36 AM 109 | - add slack welcome badge for community slack workspace Alexander Chibrikin 1/8/18 11:55 PM 110 | 111 | ## [1.8.0](https://github.com/alek13/slack/compare/1.7.0...1.8.0) 112 | - speed up builds: store composer cache Alexander Chibrikin 1/8/18 4:11 AM 113 | - add extra branch-alias for packagist Alexander Chibrikin 1/8/18 3:52 AM 114 | - bugfix: fail on build AttachmentAction without confirm (fixes #1, fixes maknz/slack#61) Alexander Chibrikin 1/7/18 5:33 PM 115 | - fix travis build; add builds for php 7.1, 7.2, nightly Alexander Chibrikin 1/6/18 8:48 PM 116 | - rename & publish new package on Packagist.org 117 | - add CHANGELOG.md Alexander Chibrikin 1/8/18 1:39 AM 118 | - Better Travis version testing maknz 6/25/16 5:43 AM 119 | - Drop PHP 5.4, throw an exception if JSON encoding fails maknz 5/28/16 8:29 AM 120 | - fixed code style Ion Bazan 6/22/16 12:04 PM 121 | - added Attachment Actions (buttons) with confirmations Ion Bazan 6/22/16 11:56 AM 122 | - StyleCI config, add badge to README maknz 5/28/16 7:36 AM 123 | - Code style fixes to abide by StyleCI laravel preset maknz 5/28/16 7:29 AM 124 | - Suggest nexylan/slack-bundle for Symfony support Regan McEntyre 3/8/16 10:45 PM 125 | - Update README with NexySlackBundle Regan McEntyre 3/8/16 10:41 PM 126 | - Fixed documentation color values Quentin McRee 1/20/16 4:37 AM 127 | - Removes unused Guzzle class reference from service provider Raj Abishek 12/21/15 8:01 AM 128 | - Fix Laravel 5 config publish instructions Regan McEntyre 6/15/15 10:59 AM 129 | - Add Scrutinizer badge Regan McEntyre 6/4/15 12:24 PM 130 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017-20xx, Alexander Chibrikin (alek13) 2 | Copyright (c) 2014-2017, Regan McEntyre (maknz) 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | 8 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | 10 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Slack for PHP 2 | 3 | [![Build Status](https://travis-ci.org/php-slack/slack.svg?branch=master)](https://travis-ci.org/php-slack/slack) 4 | [![Code Coverage](https://scrutinizer-ci.com/g/php-slack/slack/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/php-slack/slack/?branch=master) 5 | [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/php-slack/slack/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/php-slack/slack/?branch=master) 6 | [![StyleCI](https://styleci.io/repos/116497800/shield)](https://styleci.io/repos/116497800) | 7 | [![Slack Welcome](https://img.shields.io/badge/slack-welcome-brightgreen.svg)](https://join.slack.com/t/php-slack/shared_invite/zt-3rxu29id-1xPR5QZdqtUBuJxhmibjWw) 8 | 9 | A simple PHP package for sending messages to [Slack](https://slack.com) 10 | with [incoming webhooks](https://my.slack.com/services/new/incoming-webhook), 11 | focused on ease-of-use and elegant syntax. 12 | 13 | **supports:** PHP `7.1`, `7.2`, `7.3`, `7.4` or `8.0`, `8.1`, `8.2`, `8.3`, `8.4` 14 | **require:** `guzzlehttp/guzzle` any of versions `~7.0|~6.0|~5.0|~4.0` 15 | 16 | > This is the fork of popular, great, but abandoned package [`maknz/slack`](https://github.com/maknz/slack) 17 | 18 | # Quick Tour 19 | - [create an incoming webhook](https://my.slack.com/services/new/incoming-webhook) & copy `hook_url` 20 | - `composer require alek13/slack` 21 | - add the following code 22 | 23 | use Maknz\Slack\Client; 24 | 25 | require(__DIR__ .'/vendor/autoload.php'); 26 | 27 | $client = new Client('https://hook_url'); 28 | $client->to('#general')->send('Good morning'); 29 | 30 | Done! 31 | 32 | ------------------------------------------------- 33 | ------------------------------------------------- 34 | ------------------------------------------------- 35 | 36 | ## Installation 37 | 38 | You can install the package using the [Composer](https://getcomposer.org/) package manager by running in your project root: 39 | 40 | ```sh 41 | composer require alek13/slack 42 | ``` 43 | 44 | ## Incoming WebHook 45 | 46 | Then [create an incoming webhook](https://my.slack.com/services/new/incoming-webhook) on your Slack account for the package to use. 47 | You'll need the webhook URL to instantiate the client (or for the configuration file if using Laravel). 48 | 49 | ## Basic Usage 50 | 51 | ### Instantiate the client 52 | 53 | ```php 54 | // Instantiate without defaults 55 | $client = new Maknz\Slack\Client('https://hooks.slack.com/...'); 56 | 57 | // Instantiate with defaults, so all messages created 58 | // will be sent from 'Cyril' and to the #accounting channel 59 | // by default. Any names like @regan or #channel will also be linked. 60 | // use response_type (in_channel | ephemeral) to denote whether the message will be visible 61 | // to others in the channel. 62 | $settings = [ 63 | 'username' => 'Cyril', 64 | 'channel' => '#accounting', 65 | 'reponse_type' => 'in_channel', 66 | 'link_names' => true 67 | ]; 68 | 69 | $client = new Maknz\Slack\Client('https://hooks.slack.com/...', $settings); 70 | ``` 71 | 72 | #### Settings 73 | 74 | The default settings are pretty good, but you may wish to set up default behaviour for your client to be used for all messages sent. **All settings are optional and you don't need to provide any**. Where not provided, we'll fallback to what is configured on the webhook integration, which are [managed at Slack](https://my.slack.com/apps/manage/custom-integrations), or our sensible defaults. 75 | 76 | Field | Type | Description 77 | ----- | ---- | ----------- 78 | `channel` | string | The default channel that messages will be sent to 79 | `username` | string | The default username for your bot 80 | `icon` | string | The default icon that messages will be sent with, either `:emoji:` or a URL to an image 81 | `response_type` | string | Whether to show the response in the channel to all members or privately ('ephemeral' | 'in_channel') 82 | `link_names` | bool | Whether names like `@regan` or `#accounting` should be linked in the message (defaults to false) 83 | `unfurl_links` | bool | Whether Slack should unfurl text-based URLs (defaults to false) 84 | `unfurl_media` | bool | Whether Slack should unfurl media-based URLs, like tweets or Youtube videos (defaults to true) 85 | `allow_markdown` | bool | Whether markdown should be parsed in messages, or left as plain text (defaults to true) 86 | `markdown_in_attachments` | array | Which attachment fields should have markdown parsed (defaults to none) 87 | 88 | ### Sending messages 89 | 90 | #### Sending a basic message ([preview](https://goo.gl/fY43nw)) 91 | 92 | ```php 93 | $client->send('Hello world!'); 94 | ``` 95 | 96 | #### Sending a message to a non-default channel 97 | ```php 98 | $client->to('#accounting')->send('Are we rich yet?'); 99 | ``` 100 | 101 | #### Sending a message to a user 102 | ```php 103 | $client->to('@regan')->send('Yo!'); 104 | ``` 105 | 106 | #### Sending a message to a channel as a different bot name ([preview](https://goo.gl/xCeEfY)) 107 | ```php 108 | $client->from('Jake the Dog')->to('@FinnTheHuman')->send('Adventure time!'); 109 | ``` 110 | 111 | #### Sending a message with a different icon ([preview](https://goo.gl/lff21l)) 112 | ```php 113 | // Either with a Slack emoji 114 | $client->to('@regan')->withIcon(':ghost:')->send('Boo!'); 115 | 116 | // or a URL 117 | $client->to('#accounting')->withIcon('http://example.com/accounting.png')->send('Some accounting notification'); 118 | ``` 119 | 120 | #### Send an attachment ([preview](https://goo.gl/fp3iaY)) 121 | 122 | ```php 123 | $client->to('#operations')->attach([ 124 | 'fallback' => 'Server health: good', 125 | 'text' => 'Server health: good', 126 | 'color' => 'danger', 127 | ])->send('New alert from the monitoring system'); // no message, but can be provided if you'd like 128 | ``` 129 | 130 | #### Send an attachment with fields ([preview](https://goo.gl/264mhU)) 131 | 132 | ```php 133 | $client->to('#operations')->attach([ 134 | 'fallback' => 'Current server stats', 135 | 'text' => 'Current server stats', 136 | 'color' => 'danger', 137 | 'fields' => [ 138 | [ 139 | 'title' => 'CPU usage', 140 | 'value' => '90%', 141 | 'short' => true // whether the field is short enough to sit side-by-side other fields, defaults to false 142 | ], 143 | [ 144 | 'title' => 'RAM usage', 145 | 'value' => '2.5GB of 4GB', 146 | 'short' => true 147 | ] 148 | ] 149 | ])->send('New alert from the monitoring system'); // no message, but can be provided if you'd like 150 | ``` 151 | 152 | #### Send an attachment with an author ([preview](https://goo.gl/CKd1zJ)) 153 | 154 | ```php 155 | $client->to('@regan')->attach([ 156 | 'fallback' => 'Keep up the great work! I really love how the app works.', 157 | 'text' => 'Keep up the great work! I really love how the app works.', 158 | 'author_name' => 'Jane Appleseed', 159 | 'author_link' => 'https://yourapp.com/feedback/5874601', 160 | 'author_icon' => 'https://static.pexels.com/photos/61120/pexels-photo-61120-large.jpeg' 161 | ])->send('New user feedback'); 162 | ``` 163 | 164 | #### Using blocks ([Block Kit](https://api.slack.com/block-kit)) 165 | 166 | ```php 167 | $client->to('@regan') 168 | ->withBlock([ 169 | 'type' => 'section', 170 | 'text' => 'Do you love the app?' 171 | ]) 172 | ->withBlock([ 173 | 'type' => 'actions', 174 | 'elements' => [[ 175 | 'type' => 'button', 176 | 'text' => 'Love it', 177 | 'style' => 'primary', 178 | 'action_id' => 'love', 179 | ], [ 180 | 'type' => 'button', 181 | 'text' => 'Hate it', 182 | 'style' => 'danger', 183 | 'action_id' => 'hate', 184 | ],] 185 | ]) 186 | ->send('Notification fallback message'); 187 | ``` 188 | 189 | ## Advanced usage 190 | 191 | ### Markdown 192 | 193 | By default, Markdown is enabled for message text, but disabled for attachment fields. This behaviour can be configured in settings, or on the fly: 194 | 195 | #### Send a message enabling or disabling Markdown 196 | 197 | ```php 198 | $client->to('#weird')->disableMarkdown()->send('Disable *markdown* just for this message'); 199 | 200 | $client->to('#general')->enableMarkdown()->send('Enable _markdown_ just for this message'); 201 | ``` 202 | 203 | #### Send an attachment specifying which fields should have Markdown enabled 204 | 205 | ```php 206 | $client->to('#operations')->attach([ 207 | 'fallback' => 'It is all broken, man', 208 | 'text' => 'It is _all_ broken, man', 209 | 'pretext' => 'From user: *JimBob*', 210 | 'color' => 'danger', 211 | 'mrkdwn_in' => ['pretext', 'text'] 212 | ])->send('New alert from the monitoring system'); 213 | ``` 214 | 215 | ### Explicit message creation 216 | 217 | For convenience, message objects are created implicitly by calling message methods on the client. We can however do this explicitly to avoid hitting the magic method. 218 | 219 | ```php 220 | // Implicitly 221 | $client->to('@regan')->send('I am sending this implicitly'); 222 | 223 | // Explicitly 224 | $message = $client->createMessage(); 225 | $message 226 | ->to('@regan') 227 | ->setText('I am sending this explicitly') 228 | ; 229 | 230 | $client->send($message); 231 | ``` 232 | 233 | ### Attachments 234 | 235 | When using attachments, the easiest way is to provide an array of data as shown in the examples, which is actually converted to an Attachment object under the hood. You can also attach an Attachment object to the message: 236 | 237 | ```php 238 | $attachment = new Attachment([ 239 | 'fallback' => 'Some fallback text', 240 | 'text' => 'The attachment text' 241 | ]); 242 | 243 | // Explicitly create a message from the client 244 | // rather than using the magic passthrough methods 245 | $message = $client->createMessage(); 246 | 247 | $message->attach($attachment); 248 | // Explicitly set the message text rather than 249 | // implicitly through the send method 250 | $message->setText('Hello world'); 251 | 252 | $client->send($message); 253 | ``` 254 | 255 | Each attachment field is also an object, an AttachmentField. They can be used as well instead of their data in array form: 256 | 257 | ```php 258 | $attachment = new Attachment([ 259 | 'fallback' => 'Some fallback text', 260 | 'text' => 'The attachment text', 261 | 'fields' => [ 262 | new AttachmentField([ 263 | 'title' => 'A title', 264 | 'value' => 'A value', 265 | 'short' => true 266 | ]) 267 | ] 268 | ]); 269 | ``` 270 | 271 | You can also set the attachments and fields directly if you have a whole lot of them: 272 | 273 | ```php 274 | // implicitly create a message and set the attachments 275 | $client->setAttachments($bigArrayOfAttachments); 276 | 277 | // or explicitly 278 | $client->createMessage()->setAttachments($bigArrayOfAttachments); 279 | ``` 280 | 281 | ```php 282 | $attachment = new Attachment([]); 283 | 284 | $attachment->setFields($bigArrayOfFields); 285 | ``` 286 | 287 | # Playground 288 | 289 | There is the [`php-slack/playground`](https://github.com/php-slack/playground) simple console script to test messaging and to see how messages looks really. 290 | 291 | # Questions 292 | 293 | [![Slack Welcome](https://img.shields.io/badge/slack-welcome-brightgreen.svg)](https://join.slack.com/t/php-slack/shared_invite/zt-3rxu29id-1xPR5QZdqtUBuJxhmibjWw) 294 | 295 | If you have any questions how to use or contribute, 296 | you are welcome in our [Slack Workspace](https://join.slack.com/t/php-slack/shared_invite/zt-3rxu29id-1xPR5QZdqtUBuJxhmibjWw). 297 | 298 | ## Contributing 299 | 300 | [![Slack Welcome](https://img.shields.io/badge/slack-welcome-brightgreen.svg)](https://join.slack.com/t/php-slack/shared_invite/zt-3rxu29id-1xPR5QZdqtUBuJxhmibjWw) 301 | 302 | If you're having problems, spot a bug, or have a feature suggestion, please log and issue on Github. 303 | If you'd like to have a crack yourself, fork the package and make a pull request. 304 | Please include tests for any added or changed functionality. 305 | If it's a bug, include a regression test. 306 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "alek13/slack", 3 | "description": "A simple PHP package (fork of maknz/slack) for sending messages to Slack, with a focus on ease of use and elegant syntax.", 4 | "keywords": ["laravel", "slack"], 5 | "license": "BSD-2-Clause", 6 | "authors": [ 7 | { 8 | "name": "maknz", 9 | "email": "github@mak.geek.nz" 10 | }, 11 | { 12 | "name": "Alexander Chibrikin", 13 | "email": "alek13.me@gmail.com" 14 | } 15 | ], 16 | "require": { 17 | "php": "^7.1|^8.0", 18 | "guzzlehttp/guzzle": "~7.0|~6.0|~5.0|~4.0", 19 | "ext-mbstring": "*", 20 | "ext-json": "*" 21 | }, 22 | "require-dev": { 23 | "phpunit/phpunit": ">=7.5", 24 | "mockery/mockery": "^1.0" 25 | }, 26 | "autoload": { 27 | "psr-4": { 28 | "Maknz\\Slack\\": "src/" 29 | } 30 | }, 31 | "autoload-dev": { 32 | "psr-4": { 33 | "Slack\\Tests\\": "tests/" 34 | } 35 | }, 36 | "extra": { 37 | "branch-alias": { 38 | "dev-master": "2.x-dev" 39 | } 40 | }, 41 | "minimum-stability": "stable" 42 | } 43 | -------------------------------------------------------------------------------- /src/ActionConfirmation.php: -------------------------------------------------------------------------------- 1 | 'title', 41 | 'text' => 'text', 42 | 'ok_text' => 'ok_text', 43 | 'dismiss_text' => 'dismiss_text', 44 | ]; 45 | 46 | /** 47 | * Instantiate a new ActionConfirmation. 48 | * 49 | * @param array $attributes 50 | */ 51 | public function __construct(array $attributes) 52 | { 53 | parent::__construct($attributes); 54 | } 55 | 56 | /** 57 | * @return string 58 | */ 59 | public function getTitle() 60 | { 61 | return $this->title; 62 | } 63 | 64 | /** 65 | * @param string $title 66 | * @return ActionConfirmation 67 | */ 68 | public function setTitle($title) 69 | { 70 | $this->title = $title; 71 | 72 | return $this; 73 | } 74 | 75 | /** 76 | * @return string 77 | */ 78 | public function getText() 79 | { 80 | return $this->text; 81 | } 82 | 83 | /** 84 | * @param string $text 85 | * @return ActionConfirmation 86 | */ 87 | public function setText($text) 88 | { 89 | $this->text = $text; 90 | 91 | return $this; 92 | } 93 | 94 | /** 95 | * @return string 96 | */ 97 | public function getOkText() 98 | { 99 | return $this->okText; 100 | } 101 | 102 | /** 103 | * @param string $okText 104 | * @return ActionConfirmation 105 | */ 106 | public function setOkText($okText) 107 | { 108 | $this->okText = $okText; 109 | 110 | return $this; 111 | } 112 | 113 | /** 114 | * @return string 115 | */ 116 | public function getDismissText() 117 | { 118 | return $this->dismissText; 119 | } 120 | 121 | /** 122 | * @param string $dismissText 123 | * @return ActionConfirmation 124 | */ 125 | public function setDismissText($dismissText) 126 | { 127 | $this->dismissText = $dismissText; 128 | 129 | return $this; 130 | } 131 | 132 | /** 133 | * Get the array representation of this action confirmation. 134 | * 135 | * @return array 136 | */ 137 | public function toArray() 138 | { 139 | return [ 140 | 'title' => $this->getTitle(), 141 | 'text' => $this->getText(), 142 | 'ok_text' => $this->getOkText(), 143 | 'dismiss_text' => $this->getDismissText(), 144 | ]; 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/Attachment.php: -------------------------------------------------------------------------------- 1 | 'fallback', 138 | 'text' => 'text', 139 | 'image_url' => 'image_url', 140 | 'thumb_url' => 'thumb_url', 141 | 'pretext' => 'pretext', 142 | 'color' => 'color', 143 | 'footer' => 'footer', 144 | 'footer_icon' => 'footer_icon', 145 | 'timestamp' => 'timestamp', 146 | 'fields' => 'fields', 147 | 'mrkdwn_in' => 'markdown_fields', 148 | 'title' => 'title', 149 | 'title_link' => 'title_link', 150 | 'author_name' => 'author_name', 151 | 'author_link' => 'author_link', 152 | 'author_icon' => 'author_icon', 153 | 'callback_id' => 'callback_id', 154 | 'actions' => 'actions', 155 | ]; 156 | 157 | /** 158 | * Get the class name of valid fields. 159 | * 160 | * @return string 161 | */ 162 | protected function getFieldClass() 163 | { 164 | return AttachmentField::class; 165 | } 166 | 167 | /** 168 | * Get the fallback text. 169 | * 170 | * @return string 171 | */ 172 | public function getFallback() 173 | { 174 | return $this->fallback; 175 | } 176 | 177 | /** 178 | * Set the fallback text. 179 | * 180 | * @param string $fallback 181 | * 182 | * @return $this 183 | */ 184 | public function setFallback($fallback) 185 | { 186 | $this->fallback = $fallback; 187 | 188 | return $this; 189 | } 190 | 191 | /** 192 | * Get the optional text to appear within the attachment. 193 | * 194 | * @return string 195 | */ 196 | public function getText() 197 | { 198 | return $this->text; 199 | } 200 | 201 | /** 202 | * Set the optional text to appear within the attachment. 203 | * 204 | * @param string $text 205 | * 206 | * @return $this 207 | */ 208 | public function setText($text) 209 | { 210 | $this->text = $text; 211 | 212 | return $this; 213 | } 214 | 215 | /** 216 | * Get the optional image to appear within the attachment. 217 | * 218 | * @return string 219 | */ 220 | public function getImageUrl() 221 | { 222 | return $this->image_url; 223 | } 224 | 225 | /** 226 | * Set the optional image to appear within the attachment. 227 | * 228 | * @param string $image_url 229 | * 230 | * @return $this 231 | */ 232 | public function setImageUrl($image_url) 233 | { 234 | $this->image_url = $image_url; 235 | 236 | return $this; 237 | } 238 | 239 | /** 240 | * Get the optional thumbnail to appear within the attachment. 241 | * 242 | * @return string 243 | */ 244 | public function getThumbUrl() 245 | { 246 | return $this->thumb_url; 247 | } 248 | 249 | /** 250 | * Set the optional thumbnail to appear within the attachment. 251 | * 252 | * @param string $thumb_url 253 | * 254 | * @return $this 255 | */ 256 | public function setThumbUrl($thumb_url) 257 | { 258 | $this->thumb_url = $thumb_url; 259 | 260 | return $this; 261 | } 262 | 263 | /** 264 | * Get the text that should appear above the formatted data. 265 | * 266 | * @return string 267 | */ 268 | public function getPretext() 269 | { 270 | return $this->pretext; 271 | } 272 | 273 | /** 274 | * Set the text that should appear above the formatted data. 275 | * 276 | * @param string $pretext 277 | * 278 | * @return $this 279 | */ 280 | public function setPretext($pretext) 281 | { 282 | $this->pretext = $pretext; 283 | 284 | return $this; 285 | } 286 | 287 | /** 288 | * Get the color to use for the attachment. 289 | * 290 | * @return string 291 | */ 292 | public function getColor() 293 | { 294 | return $this->color; 295 | } 296 | 297 | /** 298 | * Set the color to use for the attachment. 299 | * 300 | * @param string $color 301 | * 302 | * @return $this 303 | */ 304 | public function setColor($color) 305 | { 306 | $this->color = $color; 307 | 308 | return $this; 309 | } 310 | 311 | /** 312 | * Get the footer to use for the attachment. 313 | * 314 | * @return string 315 | */ 316 | public function getFooter() 317 | { 318 | return $this->footer; 319 | } 320 | 321 | /** 322 | * Set the footer text to use for the attachment. 323 | * 324 | * @param string $footer 325 | * 326 | * @return $this 327 | */ 328 | public function setFooter($footer) 329 | { 330 | $this->footer = $footer; 331 | 332 | return $this; 333 | } 334 | 335 | /** 336 | * Get the footer icon to use for the attachment. 337 | * 338 | * @return string 339 | */ 340 | public function getFooterIcon() 341 | { 342 | return $this->footer_icon; 343 | } 344 | 345 | /** 346 | * Set the footer icon to use for the attachment. 347 | * 348 | * @param string $footerIcon 349 | * 350 | * @return $this 351 | */ 352 | public function setFooterIcon($footerIcon) 353 | { 354 | $this->footer_icon = $footerIcon; 355 | 356 | return $this; 357 | } 358 | 359 | /** 360 | * Get the timestamp to use for the attachment. 361 | * 362 | * @return \DateTime 363 | */ 364 | public function getTimestamp() 365 | { 366 | return $this->timestamp; 367 | } 368 | 369 | /** 370 | * Set the timestamp to use for the attachment. 371 | * 372 | * @param \DateTime $timestamp 373 | * 374 | * @return $this 375 | */ 376 | public function setTimestamp($timestamp) 377 | { 378 | $this->timestamp = $timestamp; 379 | 380 | return $this; 381 | } 382 | 383 | /** 384 | * Get the title to use for the attachment. 385 | * 386 | * @return string 387 | */ 388 | public function getTitle() 389 | { 390 | return $this->title; 391 | } 392 | 393 | /** 394 | * Set the title to use for the attachment. 395 | * 396 | * @param string $title 397 | * 398 | * @return $this 399 | */ 400 | public function setTitle($title) 401 | { 402 | $this->title = $title; 403 | 404 | return $this; 405 | } 406 | 407 | /** 408 | * Get the title link to use for the attachment. 409 | * 410 | * @return string 411 | */ 412 | public function getTitleLink() 413 | { 414 | return $this->title_link; 415 | } 416 | 417 | /** 418 | * Set the title link to use for the attachment. 419 | * 420 | * @param string $title_link 421 | * 422 | * @return $this 423 | */ 424 | public function setTitleLink($title_link) 425 | { 426 | $this->title_link = $title_link; 427 | 428 | return $this; 429 | } 430 | 431 | /** 432 | * Get the author name to use for the attachment. 433 | * 434 | * @return string 435 | */ 436 | public function getAuthorName() 437 | { 438 | return $this->author_name; 439 | } 440 | 441 | /** 442 | * Set the author name to use for the attachment. 443 | * 444 | * @param string $author_name 445 | * 446 | * @return $this 447 | */ 448 | public function setAuthorName($author_name) 449 | { 450 | $this->author_name = $author_name; 451 | 452 | return $this; 453 | } 454 | 455 | /** 456 | * Get the author link to use for the attachment. 457 | * 458 | * @return string 459 | */ 460 | public function getAuthorLink() 461 | { 462 | return $this->author_link; 463 | } 464 | 465 | /** 466 | * Set the author link to use for the attachment. 467 | * 468 | * @param string $author_link 469 | * 470 | * @return $this 471 | */ 472 | public function setAuthorLink($author_link) 473 | { 474 | $this->author_link = $author_link; 475 | 476 | return $this; 477 | } 478 | 479 | /** 480 | * Get the author icon to use for the attachment. 481 | * 482 | * @return string 483 | */ 484 | public function getAuthorIcon() 485 | { 486 | return $this->author_icon; 487 | } 488 | 489 | /** 490 | * Set the author icon to use for the attachment. 491 | * 492 | * @param string $author_icon 493 | * 494 | * @return $this 495 | */ 496 | public function setAuthorIcon($author_icon) 497 | { 498 | $this->author_icon = $author_icon; 499 | 500 | return $this; 501 | } 502 | 503 | /** 504 | * Get the callback id for use with interactivity. 505 | * 506 | * @return string 507 | */ 508 | public function getCallbackId() 509 | { 510 | return $this->callback_id; 511 | } 512 | 513 | /** 514 | * Set the callback id to use with interactivity. 515 | * 516 | * @param string $callback_id 517 | * 518 | * @return $this 519 | */ 520 | public function setCallbackId($callback_id) 521 | { 522 | $this->callback_id = $callback_id; 523 | 524 | return $this; 525 | } 526 | 527 | /** 528 | * Clear the actions for the attachment. 529 | * 530 | * @return $this 531 | */ 532 | public function clearActions() 533 | { 534 | $this->actions = []; 535 | 536 | return $this; 537 | } 538 | 539 | /** 540 | * Get the fields Slack should interpret in its 541 | * Markdown-like language. 542 | * 543 | * @return array 544 | */ 545 | public function getMarkdownFields() 546 | { 547 | return $this->markdown_fields; 548 | } 549 | 550 | /** 551 | * Set the fields Slack should interpret in its 552 | * Markdown-like language. 553 | * 554 | * @param array $fields 555 | * 556 | * @return $this 557 | */ 558 | public function setMarkdownFields(array $fields) 559 | { 560 | $this->markdown_fields = $fields; 561 | 562 | return $this; 563 | } 564 | 565 | /** 566 | * Get the collection of actions (buttons) to include in the attachment. 567 | * 568 | * @return AttachmentAction[] 569 | */ 570 | public function getActions() 571 | { 572 | return $this->actions; 573 | } 574 | 575 | /** 576 | * Set the collection of actions (buttons) to include in the attachment. 577 | * 578 | * @param array $actions 579 | * 580 | * @return Attachment 581 | * 582 | * @throws \InvalidArgumentException 583 | */ 584 | public function setActions($actions) 585 | { 586 | $this->clearActions(); 587 | 588 | foreach ($actions as $action) { 589 | $this->addAction($action); 590 | } 591 | 592 | return $this; 593 | } 594 | 595 | /** 596 | * Add an action to the attachment. 597 | * 598 | * @param mixed $action 599 | * 600 | * @return $this 601 | * 602 | * @throws \InvalidArgumentException 603 | */ 604 | public function addAction($action) 605 | { 606 | if ($action instanceof AttachmentAction) { 607 | $this->actions[] = $action; 608 | 609 | return $this; 610 | } elseif (is_array($action)) { 611 | $this->actions[] = new AttachmentAction($action); 612 | 613 | return $this; 614 | } 615 | 616 | throw new InvalidArgumentException('The attachment action must be an instance of Maknz\Slack\AttachmentAction or a keyed array'); 617 | } 618 | 619 | /** 620 | * Convert this attachment to its array representation. 621 | * 622 | * @return array 623 | */ 624 | public function toArray() 625 | { 626 | $data = [ 627 | 'fallback' => $this->getFallback(), 628 | 'text' => $this->getText(), 629 | 'pretext' => $this->getPretext(), 630 | 'color' => $this->getColor(), 631 | 'footer' => $this->getFooter(), 632 | 'footer_icon' => $this->getFooterIcon(), 633 | 'ts' => $this->getTimestamp() ? $this->getTimestamp()->getTimestamp() : null, 634 | 'mrkdwn_in' => $this->getMarkdownFields(), 635 | 'image_url' => $this->getImageUrl(), 636 | 'thumb_url' => $this->getThumbUrl(), 637 | 'title' => $this->getTitle(), 638 | 'title_link' => $this->getTitleLink(), 639 | 'author_name' => $this->getAuthorName(), 640 | 'author_link' => $this->getAuthorLink(), 641 | 'author_icon' => $this->getAuthorIcon(), 642 | 'callback_id' => $this->getCallbackId(), 643 | ]; 644 | 645 | $data['fields'] = $this->getFieldsAsArrays(); 646 | $data['actions'] = $this->getActionsAsArrays(); 647 | 648 | return $data; 649 | } 650 | 651 | /** 652 | * Iterates over all actions in this attachment and returns 653 | * them in their array form. 654 | * 655 | * @return array 656 | */ 657 | protected function getActionsAsArrays() 658 | { 659 | $actions = []; 660 | 661 | foreach ($this->getActions() as $action) { 662 | $actions[] = $action->toArray(); 663 | } 664 | 665 | return $actions; 666 | } 667 | } 668 | -------------------------------------------------------------------------------- /src/AttachmentAction.php: -------------------------------------------------------------------------------- 1 | 'name', 70 | 'text' => 'text', 71 | 'style' => 'style', 72 | 'type' => 'type', 73 | 'url' => 'url', 74 | 'value' => 'value', 75 | 'confirm' => 'confirm', 76 | ]; 77 | 78 | /** 79 | * Instantiate a new AttachmentAction. 80 | * 81 | * @param array $attributes 82 | * 83 | * @throws InvalidArgumentException 84 | */ 85 | public function __construct(array $attributes) 86 | { 87 | parent::__construct($attributes); 88 | } 89 | 90 | /** 91 | * @return string 92 | */ 93 | public function getName() 94 | { 95 | return $this->name; 96 | } 97 | 98 | /** 99 | * @param string $name 100 | * @return AttachmentAction 101 | */ 102 | public function setName($name) 103 | { 104 | $this->name = $name; 105 | 106 | return $this; 107 | } 108 | 109 | /** 110 | * @return string 111 | */ 112 | public function getText() 113 | { 114 | return $this->text; 115 | } 116 | 117 | /** 118 | * @param string $text 119 | * @return AttachmentAction 120 | */ 121 | public function setText($text) 122 | { 123 | $this->text = $text; 124 | 125 | return $this; 126 | } 127 | 128 | /** 129 | * @return string 130 | */ 131 | public function getUrl() 132 | { 133 | return $this->url; 134 | } 135 | 136 | /** 137 | * @param string $url 138 | * @return AttachmentAction 139 | */ 140 | public function setUrl($url) 141 | { 142 | $this->url = $url; 143 | 144 | return $this; 145 | } 146 | 147 | /** 148 | * @return string 149 | */ 150 | public function getStyle() 151 | { 152 | return $this->style; 153 | } 154 | 155 | /** 156 | * @param string $style 157 | * @return AttachmentAction 158 | */ 159 | public function setStyle($style) 160 | { 161 | $this->style = $style; 162 | 163 | return $this; 164 | } 165 | 166 | /** 167 | * @return string 168 | */ 169 | public function getType() 170 | { 171 | return $this->type; 172 | } 173 | 174 | /** 175 | * @param string $type 176 | * @return AttachmentAction 177 | */ 178 | public function setType($type) 179 | { 180 | $this->type = $type; 181 | 182 | return $this; 183 | } 184 | 185 | /** 186 | * @return string 187 | */ 188 | public function getValue() 189 | { 190 | return $this->value; 191 | } 192 | 193 | /** 194 | * @param string $value 195 | * @return AttachmentAction 196 | */ 197 | public function setValue($value) 198 | { 199 | $this->value = $value; 200 | 201 | return $this; 202 | } 203 | 204 | /** 205 | * @return ActionConfirmation 206 | */ 207 | public function getConfirm() 208 | { 209 | return $this->confirm; 210 | } 211 | 212 | /** 213 | * @param ActionConfirmation|array $confirm 214 | * 215 | * @return AttachmentAction 216 | * 217 | * @throws InvalidArgumentException 218 | */ 219 | public function setConfirm($confirm) 220 | { 221 | if ($confirm instanceof ActionConfirmation) { 222 | $this->confirm = $confirm; 223 | 224 | return $this; 225 | } elseif (is_array($confirm)) { 226 | $this->confirm = new ActionConfirmation($confirm); 227 | 228 | return $this; 229 | } 230 | 231 | throw new InvalidArgumentException('The action confirmation must be an instance of Maknz\Slack\ActionConfirmation or a keyed array'); 232 | } 233 | 234 | /** 235 | * Get the array representation of this attachment action. 236 | * 237 | * @return array 238 | */ 239 | public function toArray() 240 | { 241 | $array = [ 242 | 'name' => $this->getName(), 243 | 'text' => $this->getText(), 244 | 'style' => $this->getStyle(), 245 | 'type' => $this->getType(), 246 | 'value' => $this->getValue(), 247 | 'url' => $this->getUrl(), 248 | ]; 249 | 250 | if (($confirm = $this->getConfirm()) !== null) { 251 | $array['confirm'] = $confirm->toArray(); 252 | } 253 | 254 | return $array; 255 | } 256 | } 257 | -------------------------------------------------------------------------------- /src/AttachmentField.php: -------------------------------------------------------------------------------- 1 | 'title', 35 | 'value' => 'value', 36 | 'short' => 'short', 37 | ]; 38 | 39 | /** 40 | * Instantiate a new AttachmentField. 41 | * 42 | * @param array $attributes 43 | */ 44 | public function __construct(array $attributes) 45 | { 46 | parent::__construct($attributes); 47 | } 48 | 49 | /** 50 | * Get the title of the field. 51 | * 52 | * @return string 53 | */ 54 | public function getTitle() 55 | { 56 | return $this->title; 57 | } 58 | 59 | /** 60 | * Set the title of the field. 61 | * 62 | * @param string $title 63 | * @return $this 64 | */ 65 | public function setTitle($title) 66 | { 67 | $this->title = $title; 68 | 69 | return $this; 70 | } 71 | 72 | /** 73 | * Get the value of the field. 74 | * 75 | * @return string 76 | */ 77 | public function getValue() 78 | { 79 | return $this->value; 80 | } 81 | 82 | /** 83 | * Set the value of the field. 84 | * 85 | * @param string $value 86 | * @return $this 87 | */ 88 | public function setValue($value) 89 | { 90 | $this->value = $value; 91 | 92 | return $this; 93 | } 94 | 95 | /** 96 | * Get whether this field is short enough for displaying 97 | * side-by-side with other fields. 98 | * 99 | * @return bool 100 | */ 101 | public function getShort() 102 | { 103 | return $this->short; 104 | } 105 | 106 | /** 107 | * Set whether this field is short enough for displaying 108 | * side-by-side with other fields. 109 | * 110 | * @param string $value 111 | * @return $this 112 | */ 113 | public function setShort($value) 114 | { 115 | $this->short = (bool) $value; 116 | 117 | return $this; 118 | } 119 | 120 | /** 121 | * Get the array representation of this attachment field. 122 | * 123 | * @return array 124 | */ 125 | public function toArray() 126 | { 127 | return [ 128 | 'title' => $this->getTitle(), 129 | 'value' => $this->getValue(), 130 | 'short' => $this->getShort(), 131 | ]; 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/Block.php: -------------------------------------------------------------------------------- 1 | type; 30 | } 31 | 32 | /** 33 | * Get the block identifier. 34 | * 35 | * @return string 36 | */ 37 | public function getBlockId() 38 | { 39 | return $this->block_id; 40 | } 41 | 42 | /** 43 | * Set the block identifier. 44 | * 45 | * @param string $blockId 46 | * 47 | * @return $this 48 | */ 49 | public function setBlockId($blockId) 50 | { 51 | $this->block_id = $blockId; 52 | 53 | return $this; 54 | } 55 | 56 | /** 57 | * Create a Block element from a keyed array of attributes. 58 | * 59 | * @param array $attributes 60 | * 61 | * @return Block 62 | * 63 | * @throws \InvalidArgumentException 64 | */ 65 | public static function factory(array $attributes) 66 | { 67 | if ( ! isset($attributes['type'])) { 68 | throw new InvalidArgumentException('Cannot create Block without a type attribute'); 69 | } 70 | 71 | $validBlocks = [ 72 | 'actions', 73 | 'context', 74 | 'divider', 75 | 'file', 76 | 'header', 77 | 'image', 78 | 'input', 79 | 'section', 80 | ]; 81 | 82 | if ( ! in_array($attributes['type'], $validBlocks)) { 83 | throw new InvalidArgumentException('Block type must be one of: '.implode(', ', $validBlocks).'.'); 84 | } 85 | 86 | $className = __NAMESPACE__.'\\Block\\'.ucfirst($attributes['type']); 87 | 88 | return new $className($attributes); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/Block/Actions.php: -------------------------------------------------------------------------------- 1 | 'block_id', 22 | ]; 23 | 24 | /** 25 | * Convert the block to its array representation. 26 | * 27 | * @return array 28 | */ 29 | public function toArray() 30 | { 31 | $data = [ 32 | 'type' => $this->getType(), 33 | ]; 34 | 35 | if ($this->getBlockId()) { 36 | $data['block_id'] = $this->getBlockId(); 37 | } 38 | 39 | return $data; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Block/ElementsBlock.php: -------------------------------------------------------------------------------- 1 | 'elements', 24 | 'block_id' => 'block_id', 25 | ]; 26 | 27 | /** 28 | * Get the elements included in the block. 29 | * 30 | * @return BlockElement[] 31 | */ 32 | public function getElements() 33 | { 34 | return $this->elements; 35 | } 36 | 37 | /** 38 | * Get the elements included in the block in an array representation. 39 | * 40 | * @return array 41 | */ 42 | public function getElementsAsArrays() 43 | { 44 | $elements = []; 45 | 46 | foreach ($this->getElements() as $element) { 47 | $elements[] = $element->toArray(); 48 | } 49 | 50 | return $elements; 51 | } 52 | 53 | /** 54 | * Set the elements included in the block. 55 | * 56 | * @param array $elements 57 | * 58 | * @return $this 59 | * 60 | * @throws \InvalidArgumentException 61 | */ 62 | public function setElements(array $elements) 63 | { 64 | $this->clearElements(); 65 | 66 | foreach ($elements as $element) { 67 | $this->addElement($element); 68 | } 69 | 70 | return $this; 71 | } 72 | 73 | /** 74 | * Remove all elements from the block. 75 | * 76 | * @return $this 77 | */ 78 | public function clearElements() 79 | { 80 | $this->elements = []; 81 | 82 | return $this; 83 | } 84 | 85 | /** 86 | * Add an element to the block. 87 | * 88 | * @param array|BlockElement $element 89 | * 90 | * @return $this 91 | * 92 | * @throws \InvalidArgumentException 93 | */ 94 | public function addElement($element) 95 | { 96 | $element = BlockElement::factory($element); 97 | 98 | if ( ! $element->isValidFor($this)) { 99 | throw new InvalidArgumentException('Block element '.get_class($element).' is not valid for '.static::class); 100 | } 101 | 102 | $this->elements[] = $element; 103 | 104 | return $this; 105 | } 106 | 107 | /** 108 | * Convert the block to its array representation. 109 | * 110 | * @return array 111 | */ 112 | public function toArray() 113 | { 114 | $data = [ 115 | 'type' => $this->getType(), 116 | 'elements' => $this->getElementsAsArrays(), 117 | ]; 118 | 119 | if ($this->getBlockId()) { 120 | $data['block_id'] = $this->getBlockId(); 121 | } 122 | 123 | return $data; 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/Block/File.php: -------------------------------------------------------------------------------- 1 | 'external_id', 36 | 'source' => 'source', 37 | 'block_id' => 'block_id', 38 | ]; 39 | 40 | /** 41 | * Get the external identifier for the file. 42 | * 43 | * @return string 44 | */ 45 | public function getExternalId() 46 | { 47 | return $this->external_id; 48 | } 49 | 50 | /** 51 | * Set the external identifier for the file. 52 | * 53 | * @param string $externalId 54 | * 55 | * @return File 56 | */ 57 | public function setExternalId($externalId) 58 | { 59 | $this->external_id = $externalId; 60 | 61 | return $this; 62 | } 63 | 64 | /** 65 | * Get the file source. 66 | * 67 | * @return string 68 | */ 69 | public function getSource() 70 | { 71 | return $this->source; 72 | } 73 | 74 | /** 75 | * Set the file source. 76 | * 77 | * @param string $source 78 | * 79 | * @return File 80 | */ 81 | public function setSource($source) 82 | { 83 | $this->source = $source; 84 | 85 | return $this; 86 | } 87 | 88 | /** 89 | * Convert the block to its array representation. 90 | * 91 | * @return array 92 | */ 93 | public function toArray() 94 | { 95 | $data = [ 96 | 'type' => $this->getType(), 97 | 'external_id' => $this->getExternalId(), 98 | 'source' => $this->getSource(), 99 | ]; 100 | 101 | if ($this->getBlockId()) { 102 | $data['block_id'] = $this->getBlockId(); 103 | } 104 | 105 | return $data; 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/Block/Header.php: -------------------------------------------------------------------------------- 1 | 'text', 30 | 'block_id' => 'block_id', 31 | ]; 32 | 33 | /** 34 | * Get the header text. 35 | * 36 | * @return \Maknz\Slack\BlockElement\Text 37 | */ 38 | public function getText() 39 | { 40 | return $this->text; 41 | } 42 | 43 | /** 44 | * Set the header text. 45 | * 46 | * @param mixed $text 47 | * 48 | * @return $this 49 | * 50 | * @throws \InvalidArgumentException 51 | */ 52 | public function setText($text) 53 | { 54 | $this->text = Text::create($text); 55 | 56 | return $this; 57 | } 58 | 59 | /** 60 | * Convert the block to its array representation. 61 | * 62 | * @return array 63 | */ 64 | public function toArray() 65 | { 66 | $data = [ 67 | 'type' => $this->getType(), 68 | 'text' => $this->getText()->toArray(), 69 | ]; 70 | 71 | if ($this->getBlockId()) { 72 | $data['block_id'] = $this->getBlockId(); 73 | } 74 | 75 | return $data; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/Block/Image.php: -------------------------------------------------------------------------------- 1 | 'url', 25 | 'alt_text' => 'alt_text', 26 | 'title' => 'title', 27 | 'block_id' => 'block_id', 28 | ]; 29 | 30 | /** 31 | * Convert the block to its array representation. 32 | * 33 | * @return array 34 | */ 35 | public function toArray() 36 | { 37 | $data = [ 38 | 'type' => $this->getType(), 39 | 'image_url' => $this->getUrl(), 40 | 'alt_text' => $this->getAltText(), 41 | ]; 42 | 43 | if ($this->getTitle()) { 44 | $data['title'] = $this->getTitle()->toArray(); 45 | } 46 | 47 | if ($this->getBlockId()) { 48 | $data['block_id'] = $this->getBlockId(); 49 | } 50 | 51 | return $data; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Block/Input.php: -------------------------------------------------------------------------------- 1 | 'label', 53 | 'element' => 'element', 54 | 'block_id' => 'block_id', 55 | 'hint' => 'hint', 56 | 'optional' => 'optional', 57 | ]; 58 | 59 | /** 60 | * Get the input label. 61 | * 62 | * @return \Maknz\Slack\BlockElement\Text 63 | */ 64 | public function getLabel() 65 | { 66 | return $this->label; 67 | } 68 | 69 | /** 70 | * Set the input label. 71 | * 72 | * @param mixed $label 73 | * 74 | * @return $this 75 | */ 76 | public function setLabel($label) 77 | { 78 | $this->label = Text::create($label); 79 | 80 | return $this; 81 | } 82 | 83 | /** 84 | * Get the input element. 85 | * 86 | * @return \Maknz\Slack\BlockElement 87 | */ 88 | public function getElement() 89 | { 90 | return $this->element; 91 | } 92 | 93 | /** 94 | * Set the input element. 95 | * 96 | * @param mixed $element 97 | * 98 | * @return $this 99 | * 100 | * @throws \InvalidArgumentException 101 | */ 102 | public function setElement($element) 103 | { 104 | $element = BlockElement::factory($element); 105 | 106 | if ( ! $element->isValidFor($this)) { 107 | throw new InvalidArgumentException('Block element '.get_class($element).' is not valid for '.static::class); 108 | } 109 | 110 | $this->element = $element; 111 | 112 | return $this; 113 | } 114 | 115 | /** 116 | * Get the input hint. 117 | * 118 | * @return \Maknz\Slack\BlockElement\Text 119 | */ 120 | public function getHint() 121 | { 122 | return $this->hint; 123 | } 124 | 125 | /** 126 | * Set the input hint. 127 | * 128 | * @param mixed $hint 129 | * 130 | * @return $this 131 | */ 132 | public function setHint($hint) 133 | { 134 | $this->hint = Text::create($hint); 135 | 136 | return $this; 137 | } 138 | 139 | /** 140 | * Get whether the input is optional. 141 | * 142 | * @return bool 143 | */ 144 | public function getOptional() 145 | { 146 | return $this->optional; 147 | } 148 | 149 | /** 150 | * Set whether the input is optional. 151 | * 152 | * @param bool $optional 153 | * 154 | * @return $this 155 | */ 156 | public function setOptional($optional) 157 | { 158 | $this->optional = (bool)$optional; 159 | 160 | return $this; 161 | } 162 | 163 | /** 164 | * Convert the block to its array representation. 165 | * 166 | * @return array 167 | */ 168 | public function toArray() 169 | { 170 | $data = [ 171 | 'type' => $this->getType(), 172 | 'label' => $this->getLabel()->toArray(), 173 | 'element' => $this->getElement()->toArray(), 174 | ]; 175 | 176 | if ($this->getBlockId()) { 177 | $data['block_id'] = $this->getBlockId(); 178 | } 179 | 180 | if ($this->getHint()) { 181 | $data['hint'] = $this->getHint()->toArray(); 182 | } 183 | 184 | if ($this->getOptional() != null) { 185 | $data['optional'] = $this->getOptional(); 186 | } 187 | 188 | return $data; 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /src/Block/Section.php: -------------------------------------------------------------------------------- 1 | 'text', 50 | 'block_id' => 'block_id', 51 | 'fields' => 'fields', 52 | 'accessory' => 'accessory', 53 | ]; 54 | 55 | /** 56 | * Get the class name of valid fields. 57 | * 58 | * @return string 59 | */ 60 | protected function getFieldClass() 61 | { 62 | return Text::class; 63 | } 64 | 65 | /** 66 | * Get the section text. 67 | * 68 | * @return \Maknz\Slack\BlockElement\Text 69 | */ 70 | public function getText() 71 | { 72 | return $this->text; 73 | } 74 | 75 | /** 76 | * Set the section text. 77 | * 78 | * @param mixed $text 79 | * 80 | * @return $this 81 | * 82 | * @throws \InvalidArgumentException 83 | */ 84 | public function setText($text) 85 | { 86 | $this->text = Text::create($text); 87 | 88 | return $this; 89 | } 90 | 91 | /** 92 | * Add a field to the block. 93 | * 94 | * @param mixed $field 95 | * 96 | * @return $this 97 | * 98 | * @throws \InvalidArgumentException 99 | */ 100 | public function addField($field) 101 | { 102 | $field = $this->getFieldClass()::create($field); 103 | 104 | $this->fields[] = $field; 105 | 106 | return $this; 107 | } 108 | 109 | /** 110 | * Get the section accessory. 111 | * 112 | * @return \Maknz\Slack\BlockElement 113 | */ 114 | public function getAccessory() 115 | { 116 | return $this->accessory; 117 | } 118 | 119 | /** 120 | * Set the section accessory. 121 | * 122 | * @param mixed $accessory 123 | * 124 | * @return $this 125 | * 126 | * @throws \InvalidArgumentException 127 | */ 128 | public function setAccessory($accessory) 129 | { 130 | $accessory = BlockElement::factory($accessory); 131 | 132 | if ( ! $accessory->isValidFor($this)) { 133 | throw new InvalidArgumentException('Block element '.get_class($accessory).' is not valid for '.static::class); 134 | } 135 | 136 | $this->accessory = $accessory; 137 | 138 | return $this; 139 | } 140 | 141 | /** 142 | * Convert the block to its array representation. 143 | * 144 | * @return array 145 | */ 146 | public function toArray() 147 | { 148 | $data = [ 149 | 'type' => $this->getType(), 150 | ]; 151 | 152 | if ($this->getText()) { 153 | $data['text'] = $this->getText()->toArray(); 154 | } 155 | 156 | if (count($this->getFields())) { 157 | $data['fields'] = $this->getFieldsAsArrays(); 158 | } elseif ( ! $this->getText()) { 159 | throw new UnexpectedValueException('Section requires text attribute if no fields attribute is provided'); 160 | } 161 | 162 | if ($this->getBlockId()) { 163 | $data['block_id'] = $this->getBlockId(); 164 | } 165 | 166 | if ($this->getAccessory()) { 167 | $data['accessory'] = $this->getAccessory()->toArray(); 168 | } 169 | 170 | return $data; 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /src/BlockElement.php: -------------------------------------------------------------------------------- 1 | ['Button', ['section', 'actions']], 22 | 'checkboxes' => ['Checkboxes', ['section', 'actions', 'input']], 23 | 'datepicker' => ['DatePicker', ['section', 'actions', 'input']], 24 | 'timepicker' => ['Timepicker', ['section', 'actions', 'input']], 25 | 'image' => ['Image', ['section', 'context']], 26 | 'multi_static_select' => ['MultiStaticSelect', ['section', 'input']], 27 | 'multi_external_select' => ['MultiExternalSelect', ['section', 'input']], 28 | 'multi_users_select' => ['MultiUsersSelect', ['section', 'input']], 29 | 'multi_conversations_select' => ['MultiConversationsSelect', ['section', 'input']], 30 | 'multi_channels_select' => ['MultiChannelsSelect', ['section', 'input']], 31 | 'overflow' => ['Overflow', ['section', 'actions']], 32 | 'plain_text_input' => ['TextInput', ['input']], 33 | 'radio_buttons' => ['RadioButtons', ['section', 'actions', 'input']], 34 | 'static_select' => ['StaticSelect', ['section', 'actions', 'input']], 35 | 'external_select' => ['ExternalSelect', ['section', 'actions', 'input']], 36 | 'users_select' => ['UsersSelect', ['section', 'actions', 'input']], 37 | 'conversations_select' => ['ConversationsSelect', ['section', 'actions', 'input']], 38 | 'channels_select' => ['ChannelsSelect', ['section', 'actions', 'input']], 39 | 40 | // Context Block allows a Text object to be used directly, so need to map types here 41 | 'plain_text' => ['Text', ['context']], 42 | 'mrkdwn' => ['Text', ['context']], 43 | ]; 44 | 45 | /** 46 | * Create a Block element from a keyed array of attributes. 47 | * 48 | * @param mixed $attributes 49 | * 50 | * @return BlockElement 51 | * 52 | * @throws \InvalidArgumentException 53 | */ 54 | public static function factory($attributes) 55 | { 56 | if ($attributes instanceof static) { 57 | return $attributes; 58 | } 59 | 60 | if ( ! is_array($attributes)) { 61 | throw new InvalidArgumentException('The attributes must be a '.static::class.' or keyed array'); 62 | } 63 | 64 | if ( ! isset($attributes['type'])) { 65 | throw new InvalidArgumentException('Cannot create BlockElement without a type attribute'); 66 | } 67 | 68 | $validElements = array_keys(static::$validFor); 69 | 70 | if ( ! in_array($attributes['type'], $validElements)) { 71 | throw new InvalidArgumentException('Invalid Block type "'.$attributes['type'].'". Must be one of: '.implode(', ', $validElements).'.'); 72 | } 73 | 74 | $className = __NAMESPACE__.'\\BlockElement\\'.static::$validFor[$attributes['type']][0]; 75 | 76 | return new $className($attributes); 77 | } 78 | 79 | /** 80 | * Check if an element is valid for a Block. 81 | * 82 | * @param Block $block 83 | * 84 | * @return bool 85 | */ 86 | public function isValidFor(Block $block) 87 | { 88 | $blockType = $block->getType(); 89 | $validBlocks = static::$validFor[$this->getType()][1]; 90 | 91 | return in_array($blockType, $validBlocks); 92 | } 93 | 94 | /** 95 | * Get the block type. 96 | * 97 | * @return string 98 | */ 99 | public function getType() 100 | { 101 | return $this->type; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/BlockElement/AbstractDynamicSelect.php: -------------------------------------------------------------------------------- 1 | clearOptionGroups(); 31 | 32 | return parent::setOptions($options); 33 | } 34 | 35 | /** 36 | * Add an option to the block. 37 | * 38 | * @param mixed $option 39 | * 40 | * @return $this 41 | * 42 | * @throws \InvalidArgumentException 43 | */ 44 | public function addOption($option) 45 | { 46 | parent::addOption($option); 47 | $this->clearOptionGroups(); 48 | 49 | return $this; 50 | } 51 | 52 | /** 53 | * Get the option groups. 54 | * 55 | * @return \Maknz\Slack\Object\OptionGroup[] 56 | */ 57 | public function getOptionGroups() 58 | { 59 | return $this->option_groups; 60 | } 61 | 62 | /** 63 | * Get the option groups in array format. 64 | * 65 | * @return array 66 | */ 67 | public function getOptionGroupsAsArrays() 68 | { 69 | $groups = []; 70 | 71 | foreach ($this->getOptionGroups() as $group) { 72 | $groups[] = $group->toArray(); 73 | } 74 | 75 | return $groups; 76 | } 77 | 78 | /** 79 | * Set the option groups. 80 | * 81 | * @param array $groups 82 | * 83 | * @return $this 84 | * 85 | * @throws \InvalidArgumentException 86 | */ 87 | public function setOptionGroups(array $groups) 88 | { 89 | $this->clearOptions(); 90 | $this->clearOptionGroups(); 91 | 92 | foreach ($groups as $group) { 93 | $this->addOptionGroup($group); 94 | } 95 | 96 | return $this; 97 | } 98 | 99 | /** 100 | * Clear option groups in the block. 101 | * 102 | * @return $this 103 | */ 104 | public function clearOptionGroups() 105 | { 106 | $this->option_groups = []; 107 | 108 | return $this; 109 | } 110 | 111 | /** 112 | * Clear options and option groups. 113 | * 114 | * @return $this 115 | */ 116 | public function clearAllOptions() 117 | { 118 | $this->clearOptions(); 119 | $this->clearOptionGroups(); 120 | 121 | return $this; 122 | } 123 | 124 | /** 125 | * Add an option group to the block. 126 | * 127 | * @param mixed $group 128 | * 129 | * @return $this 130 | * 131 | * @throws \InvalidArgumentException 132 | */ 133 | public function addOptionGroup($group) 134 | { 135 | if (is_array($group)) { 136 | $group = new OptionGroup($group); 137 | } 138 | 139 | if ($group instanceof OptionGroup) { 140 | $this->clearOptions(); 141 | $this->option_groups[] = $group; 142 | 143 | return $this; 144 | } 145 | 146 | throw new InvalidArgumentException('The option group must be an instance of '.OptionGroup::class.' or a keyed array'); 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /src/BlockElement/Button.php: -------------------------------------------------------------------------------- 1 | 'text', 52 | 'action_id' => 'action_id', 53 | 'url' => 'url', 54 | 'value' => 'value', 55 | 'style' => 'style', 56 | 'confirm' => 'confirm', 57 | ]; 58 | 59 | /** 60 | * Get the button text. 61 | * 62 | * @return \Maknz\Slack\BlockElement\Text 63 | */ 64 | public function getText() 65 | { 66 | return $this->text; 67 | } 68 | 69 | /** 70 | * Set the button text. 71 | * 72 | * @param mixed $text 73 | * 74 | * @return $this 75 | * 76 | * @throws \InvalidArgumentException 77 | */ 78 | public function setText($text) 79 | { 80 | $this->text = Text::create($text, Text::TYPE_PLAIN); 81 | 82 | return $this; 83 | } 84 | 85 | /** 86 | * Get the button URL. 87 | * 88 | * @return string 89 | */ 90 | public function getUrl() 91 | { 92 | return $this->url; 93 | } 94 | 95 | /** 96 | * Set the button URL. 97 | * 98 | * @param string $url 99 | * 100 | * @return $this 101 | */ 102 | public function setUrl($url) 103 | { 104 | $this->url = $url; 105 | 106 | return $this; 107 | } 108 | 109 | /** 110 | * Get the button value. 111 | * 112 | * @return string 113 | */ 114 | public function getValue() 115 | { 116 | return $this->value; 117 | } 118 | 119 | /** 120 | * Set the button value. 121 | * 122 | * @param string $value 123 | * 124 | * @return $this 125 | */ 126 | public function setValue($value) 127 | { 128 | $this->value = $value; 129 | 130 | return $this; 131 | } 132 | 133 | /** 134 | * Get the button style. 135 | * 136 | * @return string 137 | */ 138 | public function getStyle() 139 | { 140 | return $this->style; 141 | } 142 | 143 | /** 144 | * Set the button style. 145 | * 146 | * @param string $style 147 | * 148 | * @return $this 149 | */ 150 | public function setStyle($style) 151 | { 152 | $this->style = $style; 153 | 154 | return $this; 155 | } 156 | 157 | /** 158 | * Convert the block to its array representation. 159 | * 160 | * @return array 161 | */ 162 | public function toArray() 163 | { 164 | $data = [ 165 | 'type' => $this->getType(), 166 | 'text' => $this->getText()->toArray(), 167 | 'action_id' => $this->getActionId(), 168 | ]; 169 | 170 | if ($this->getUrl()) { 171 | $data['url'] = $this->getUrl(); 172 | } 173 | 174 | if ($this->getValue()) { 175 | $data['value'] = $this->getValue(); 176 | } 177 | 178 | if ($this->getStyle()) { 179 | $data['style'] = $this->getStyle(); 180 | } 181 | 182 | if ($this->getConfirm()) { 183 | $data['confirm'] = $this->getConfirm()->toArray(); 184 | } 185 | 186 | return $data; 187 | } 188 | } 189 | -------------------------------------------------------------------------------- /src/BlockElement/ChannelsSelect.php: -------------------------------------------------------------------------------- 1 | 'placeholder', 29 | 'action_id' => 'action_id', 30 | 'initial_channel' => 'initial_channel', 31 | 'confirm' => 'confirm', 32 | 'response_url_enabled' => 'response_url_enabled', 33 | ]; 34 | 35 | /** 36 | * Get the initially selected channel. 37 | * 38 | * @return string 39 | */ 40 | public function getInitialChannel() 41 | { 42 | return $this->initial_channel; 43 | } 44 | 45 | /** 46 | * Set the initially selected channel. 47 | * 48 | * @param string $initialChannel 49 | * 50 | * @return $this 51 | * 52 | * @throws InvalidArgumentException 53 | */ 54 | public function setInitialChannel($initialChannel) 55 | { 56 | if (is_string($initialChannel)) { 57 | $this->initial_channel = $initialChannel; 58 | 59 | return $this; 60 | } 61 | 62 | throw new InvalidArgumentException('The initial channel ID must be a string'); 63 | } 64 | 65 | /** 66 | * Convert the block to its array representation. 67 | * 68 | * @return array 69 | */ 70 | public function toArray() 71 | { 72 | $data = [ 73 | 'type' => $this->getType(), 74 | 'placeholder' => $this->getPlaceholder()->toArray(), 75 | 'action_id' => $this->getActionId(), 76 | ]; 77 | 78 | if ($this->getInitialChannel()) { 79 | $data['initial_channel'] = $this->getInitialChannel(); 80 | } 81 | 82 | if ($this->getConfirm()) { 83 | $data['confirm'] = $this->getConfirm()->toArray(); 84 | } 85 | 86 | if ($this->isResponseUrlEnabled()) { 87 | $data['response_url_enabled'] = true; 88 | } 89 | 90 | return $data; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/BlockElement/Checkboxes.php: -------------------------------------------------------------------------------- 1 | 'action_id', 22 | 'options' => 'options', 23 | 'confirm' => 'confirm', 24 | ]; 25 | 26 | /** 27 | * Get the intially selected options. 28 | * 29 | * @return \Maknz\Slack\Object\Option[] 30 | */ 31 | public function getInitialOptions() 32 | { 33 | return array_values(array_filter($this->getOptions(), function (Option $o) { 34 | return $o->isInitiallySelected(); 35 | })); 36 | } 37 | 38 | /** 39 | * Convert the block to its array representation. 40 | * 41 | * @return array 42 | */ 43 | public function toArray() 44 | { 45 | $initialOptions = []; 46 | 47 | $data = [ 48 | 'type' => $this->getType(), 49 | 'action_id' => $this->getActionId(), 50 | 'options' => $this->getOptionsAsArrays(), 51 | ]; 52 | 53 | foreach ($this->getOptions() as $option) { 54 | if ($option->isInitiallySelected()) { 55 | $initialOptions[] = $option->toArray(); 56 | } 57 | } 58 | 59 | if (count($initialOptions)) { 60 | $data['initial_options'] = $initialOptions; 61 | } 62 | 63 | if ($this->getConfirm()) { 64 | $data['confirm'] = $this->getConfirm()->toArray(); 65 | } 66 | 67 | return $data; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/BlockElement/Confirmable.php: -------------------------------------------------------------------------------- 1 | action_id; 32 | } 33 | 34 | /** 35 | * Set the element's action identifier. 36 | * 37 | * @param string $actionId 38 | * 39 | * @return $this 40 | */ 41 | public function setActionId($actionId) 42 | { 43 | $this->action_id = $actionId; 44 | 45 | return $this; 46 | } 47 | 48 | /** 49 | * Get the confirmation object. 50 | * 51 | * @return \Maknz\Slack\Object\Confirmation 52 | */ 53 | public function getConfirm() 54 | { 55 | return $this->confirm; 56 | } 57 | 58 | /** 59 | * Set the confirmation object. 60 | * 61 | * @param mixed $confirm 62 | * 63 | * @return $this 64 | * 65 | * @throws \InvalidArgumentException 66 | */ 67 | public function setConfirm($confirm) 68 | { 69 | if (is_array($confirm)) { 70 | $confirm = new Confirmation($confirm); 71 | } 72 | 73 | if ($confirm instanceof Confirmation) { 74 | $this->confirm = $confirm; 75 | 76 | return $this; 77 | } 78 | 79 | throw new InvalidArgumentException('Confirm must be a keyed array or '.Confirmation::class.' object'); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/BlockElement/ConversationsSelect.php: -------------------------------------------------------------------------------- 1 | 'placeholder', 39 | 'action_id' => 'action_id', 40 | 'initial_conversation' => 'initial_conversation', 41 | 'default_to_current_conversation' => 'default_to_current_conversation', 42 | 'confirm' => 'confirm', 43 | 'response_url_enabled' => 'response_url_enabled', 44 | 'filter' => 'filter', 45 | ]; 46 | 47 | /** 48 | * Get the initially selected conversation. 49 | * 50 | * @return string 51 | */ 52 | public function getInitialConversation() 53 | { 54 | return $this->initial_conversation; 55 | } 56 | 57 | /** 58 | * Set the initially selected conversation. 59 | * 60 | * @param string $initialConversation 61 | * 62 | * @return $this 63 | * 64 | * @throws InvalidArgumentException 65 | */ 66 | public function setInitialConversation($initialConversation) 67 | { 68 | if (is_string($initialConversation)) { 69 | $this->initial_conversation = $initialConversation; 70 | 71 | return $this; 72 | } 73 | 74 | throw new InvalidArgumentException('The initial conversation ID must be a string'); 75 | } 76 | 77 | /** 78 | * Get whether to default to the current conversation. 79 | * 80 | * @return bool 81 | */ 82 | public function getDefaultToCurrentConversation() 83 | { 84 | return $this->default_to_current_conversation; 85 | } 86 | 87 | /** 88 | * Set whether to default to the current conversation. 89 | * 90 | * @param string $defaultToCurrentConversation 91 | * 92 | * @return $this 93 | */ 94 | public function setDefaultToCurrentConversation($defaultToCurrentConversation) 95 | { 96 | $this->default_to_current_conversation = (bool)$defaultToCurrentConversation; 97 | 98 | return $this; 99 | } 100 | 101 | /** 102 | * Convert the block to its array representation. 103 | * 104 | * @return array 105 | */ 106 | public function toArray() 107 | { 108 | $data = [ 109 | 'type' => $this->getType(), 110 | 'placeholder' => $this->getPlaceholder()->toArray(), 111 | 'action_id' => $this->getActionId(), 112 | ]; 113 | 114 | if ($this->getInitialConversation()) { 115 | $data['initial_conversation'] = $this->getInitialConversation(); 116 | } elseif ($this->getDefaultToCurrentConversation()) { 117 | $data['default_to_current_conversation'] = true; 118 | } 119 | 120 | if ($this->getConfirm()) { 121 | $data['confirm'] = $this->getConfirm()->toArray(); 122 | } 123 | 124 | if ($this->isResponseUrlEnabled()) { 125 | $data['response_url_enabled'] = true; 126 | } 127 | 128 | if ($this->getFilter()) { 129 | $data['filter'] = $this->getFilter()->toArray(); 130 | } 131 | 132 | return $data; 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /src/BlockElement/DatePicker.php: -------------------------------------------------------------------------------- 1 | 'action_id', 22 | 'placeholder' => 'placeholder', 23 | 'initial_date' => 'initial_value', 24 | 'confirm' => 'confirm', 25 | ]; 26 | 27 | /** 28 | * Get the name of the initial value field. 29 | * 30 | * @return string 31 | */ 32 | public function getInitialValueField() 33 | { 34 | return 'initial_date'; 35 | } 36 | 37 | /** 38 | * Get the initial value format. 39 | * 40 | * @return string 41 | */ 42 | public function getInitialValueFormat() 43 | { 44 | return 'Y-m-d'; 45 | } 46 | 47 | /** 48 | * Get the initial date. 49 | * 50 | * @return \DateTime 51 | */ 52 | public function getInitialDate() 53 | { 54 | return $this->getInitialValue(); 55 | } 56 | 57 | /** 58 | * Set the initial date. 59 | * 60 | * @param \DateTime $initialDate 61 | * 62 | * @return $this 63 | */ 64 | public function setInitialDate(DateTime $initialDate) 65 | { 66 | return $this->setInitialValue($initialDate); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/BlockElement/ExternalSelect.php: -------------------------------------------------------------------------------- 1 | 'placeholder', 37 | 'action_id' => 'action_id', 38 | 'initial_option' => 'initial_option', 39 | 'min_query_length' => 'min_query_length', 40 | 'confirm' => 'confirm', 41 | ]; 42 | 43 | /** 44 | * Get the number of characters before query is dispatched. 45 | * 46 | * @return int 47 | */ 48 | public function getMinQueryLength() 49 | { 50 | return $this->min_query_length; 51 | } 52 | 53 | /** 54 | * Set the number of characters before query is dispatched. 55 | * 56 | * @param int $minQueryLength 57 | * 58 | * @return $this 59 | * 60 | * @throws InvalidArgumentException 61 | */ 62 | public function setMinQueryLength($minQueryLength) 63 | { 64 | if (is_int($minQueryLength)) { 65 | $this->min_query_length = $minQueryLength; 66 | 67 | return $this; 68 | } 69 | 70 | throw new InvalidArgumentException('The minimum query length must be an integer'); 71 | } 72 | 73 | /** 74 | * Get the initially selected option. 75 | * 76 | * @return \Maknz\Slack\Object\Option 77 | */ 78 | public function getInitialOption() 79 | { 80 | return $this->initial_option; 81 | } 82 | 83 | /** 84 | * Set the initially selected option. 85 | * 86 | * @param mixed $initialOption 87 | * 88 | * @return $this 89 | * 90 | * @throws InvalidArgumentException 91 | */ 92 | public function setInitialOption($initialOption) 93 | { 94 | if (is_array($initialOption)) { 95 | $initialOption = new Option($initialOption); 96 | } 97 | 98 | if ($initialOption instanceof Option) { 99 | $this->initial_option = $initialOption; 100 | 101 | return $this; 102 | } 103 | 104 | throw new InvalidArgumentException('The initial option must be an instance of '.Option::class.' or a keyed array'); 105 | } 106 | 107 | /** 108 | * Clear the initially selected option. 109 | * 110 | * @return $this 111 | */ 112 | public function clearInitialOption() 113 | { 114 | $this->initial_option = null; 115 | 116 | return $this; 117 | } 118 | 119 | /** 120 | * Convert the block to its array representation. 121 | * 122 | * @return array 123 | */ 124 | public function toArray() 125 | { 126 | $data = [ 127 | 'type' => $this->getType(), 128 | 'placeholder' => $this->getPlaceholder()->toArray(), 129 | 'action_id' => $this->getActionId(), 130 | ]; 131 | 132 | if ($this->getInitialOption()) { 133 | $data['initial_option'] = $this->getInitialOption()->toArray(); 134 | } 135 | 136 | if ($this->getMinQueryLength()) { 137 | $data['min_query_length'] = $this->getMinQueryLength(); 138 | } 139 | 140 | if ($this->getConfirm()) { 141 | $data['confirm'] = $this->getConfirm()->toArray(); 142 | } 143 | 144 | return $data; 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /src/BlockElement/Image.php: -------------------------------------------------------------------------------- 1 | 'url', 25 | 'alt_text' => 'alt_text', 26 | 'title' => 'title', 27 | ]; 28 | 29 | /** 30 | * Convert the block to its array representation. 31 | * 32 | * @return array 33 | */ 34 | public function toArray() 35 | { 36 | $data = [ 37 | 'type' => $this->getType(), 38 | 'image_url' => $this->getUrl(), 39 | 'alt_text' => $this->getAltText(), 40 | ]; 41 | 42 | if ($this->getTitle()) { 43 | $data['title'] = $this->getTitle()->toArray(); 44 | } 45 | 46 | return $data; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/BlockElement/MultiChannelsSelect.php: -------------------------------------------------------------------------------- 1 | 'placeholder', 29 | 'action_id' => 'action_id', 30 | 'initial_channels' => 'initial_channels', 31 | 'confirm' => 'confirm', 32 | 'max_selected_items' => 'max_selected_items', 33 | ]; 34 | 35 | /** 36 | * Get the initially selected channels. 37 | * 38 | * @return string[] 39 | */ 40 | public function getInitialChannels() 41 | { 42 | return $this->initial_channels; 43 | } 44 | 45 | /** 46 | * Set the initially selected channels. 47 | * 48 | * @param string[] $initialChannels 49 | * 50 | * @return $this 51 | * 52 | * @throws InvalidArgumentException 53 | */ 54 | public function setInitialChannels(array $initialChannels) 55 | { 56 | $this->clearInitialChannels(); 57 | 58 | foreach ($initialChannels as $initialChannel) { 59 | $this->addInitialChannel($initialChannel); 60 | } 61 | 62 | return $this; 63 | } 64 | 65 | /** 66 | * Clear the initially selected channels. 67 | * 68 | * @return $this 69 | */ 70 | public function clearInitialChannels() 71 | { 72 | $this->initial_channels = []; 73 | 74 | return $this; 75 | } 76 | 77 | /** 78 | * Add an initially selected channel. 79 | * 80 | * @param string $initialChannels 81 | * 82 | * @return $this 83 | * 84 | * @throws InvalidArgumentException 85 | */ 86 | public function addInitialChannel($initialChannel) 87 | { 88 | if (is_string($initialChannel)) { 89 | $this->initial_channels[] = $initialChannel; 90 | 91 | return $this; 92 | } 93 | 94 | throw new InvalidArgumentException('The initial channel ID must be a string'); 95 | } 96 | 97 | /** 98 | * Convert the block to its array representation. 99 | * 100 | * @return array 101 | */ 102 | public function toArray() 103 | { 104 | $data = [ 105 | 'type' => $this->getType(), 106 | 'placeholder' => $this->getPlaceholder()->toArray(), 107 | 'action_id' => $this->getActionId(), 108 | ]; 109 | 110 | $initialChannels = $this->getInitialChannels(); 111 | 112 | if (count($initialChannels)) { 113 | $data['initial_channels'] = $initialChannels; 114 | } 115 | 116 | if ($this->getConfirm()) { 117 | $data['confirm'] = $this->getConfirm()->toArray(); 118 | } 119 | 120 | if ($this->getMaxSelectedItems()) { 121 | $data['max_selected_items'] = $this->getMaxSelectedItems(); 122 | } 123 | 124 | return $data; 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/BlockElement/MultiConversationsSelect.php: -------------------------------------------------------------------------------- 1 | 'placeholder', 39 | 'action_id' => 'action_id', 40 | 'initial_conversations' => 'initial_conversations', 41 | 'default_to_current_conversation' => 'default_to_current_conversation', 42 | 'confirm' => 'confirm', 43 | 'max_selected_items' => 'max_selected_items', 44 | 'filter' => 'filter', 45 | ]; 46 | 47 | /** 48 | * Get the initially selected conversations. 49 | * 50 | * @return string[] 51 | */ 52 | public function getInitialConversations() 53 | { 54 | return $this->initial_conversations; 55 | } 56 | 57 | /** 58 | * Set the initially selected conversations. 59 | * 60 | * @param string[] $initialConversations 61 | * 62 | * @return $this 63 | * 64 | * @throws InvalidArgumentException 65 | */ 66 | public function setInitialConversations(array $initialConversations) 67 | { 68 | $this->clearInitialConversations(); 69 | 70 | foreach ($initialConversations as $initialConversation) { 71 | $this->addInitialConversation($initialConversation); 72 | } 73 | 74 | return $this; 75 | } 76 | 77 | /** 78 | * Clear the initially selected conversations. 79 | * 80 | * @return $this 81 | */ 82 | public function clearInitialConversations() 83 | { 84 | $this->initial_conversations = []; 85 | 86 | return $this; 87 | } 88 | 89 | /** 90 | * Add an initially selected conversation. 91 | * 92 | * @param string $initialConversation 93 | * 94 | * @return $this 95 | * 96 | * @throws InvalidArgumentException 97 | */ 98 | public function addInitialConversation($initialConversation) 99 | { 100 | if (is_string($initialConversation)) { 101 | $this->initial_conversations[] = $initialConversation; 102 | 103 | return $this; 104 | } 105 | 106 | throw new InvalidArgumentException('The initial conversation ID must be a string'); 107 | } 108 | 109 | /** 110 | * Get whether to default to the current conversation. 111 | * 112 | * @return bool 113 | */ 114 | public function getDefaultToCurrentConversation() 115 | { 116 | return $this->default_to_current_conversation; 117 | } 118 | 119 | /** 120 | * Set whether to default to the current conversation. 121 | * 122 | * @param bool $defaultToCurrentConversation 123 | * 124 | * @return $this 125 | */ 126 | public function setDefaultToCurrentConversation($defaultToCurrentConversation) 127 | { 128 | $this->default_to_current_conversation = (bool)$defaultToCurrentConversation; 129 | 130 | return $this; 131 | } 132 | 133 | /** 134 | * Convert the block to its array representation. 135 | * 136 | * @return array 137 | */ 138 | public function toArray() 139 | { 140 | $data = [ 141 | 'type' => $this->getType(), 142 | 'placeholder' => $this->getPlaceholder()->toArray(), 143 | 'action_id' => $this->getActionId(), 144 | ]; 145 | 146 | $initialConversations = $this->getInitialConversations(); 147 | 148 | if ($this->getDefaultToCurrentConversation()) { 149 | $data['default_to_current_conversation'] = true; 150 | } elseif (count($initialConversations)) { 151 | $data['initial_conversations'] = $initialConversations; 152 | } 153 | 154 | if ($this->getConfirm()) { 155 | $data['confirm'] = $this->getConfirm()->toArray(); 156 | } 157 | 158 | if ($this->getMaxSelectedItems()) { 159 | $data['max_selected_items'] = $this->getMaxSelectedItems(); 160 | } 161 | 162 | if ($this->getFilter()) { 163 | $data['filter'] = $this->getFilter()->toArray(); 164 | } 165 | 166 | return $data; 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /src/BlockElement/MultiDynamicSelect.php: -------------------------------------------------------------------------------- 1 | 'placeholder', 37 | 'action_id' => 'action_id', 38 | 'min_query_length' => 'min_query_length', 39 | 'initial_options' => 'initial_options', 40 | 'confirm' => 'confirm', 41 | 'max_selected_items' => 'max_selected_items', 42 | ]; 43 | 44 | /** 45 | * Get the number of characters before query is dispatched. 46 | * 47 | * @return int 48 | */ 49 | public function getMinQueryLength() 50 | { 51 | return $this->min_query_length; 52 | } 53 | 54 | /** 55 | * Set the number of characters before query is dispatched. 56 | * 57 | * @param int $minQueryLength 58 | * 59 | * @return $this 60 | * 61 | * @throws InvalidArgumentException 62 | */ 63 | public function setMinQueryLength($minQueryLength) 64 | { 65 | if (is_int($minQueryLength)) { 66 | $this->min_query_length = $minQueryLength; 67 | 68 | return $this; 69 | } 70 | 71 | throw new InvalidArgumentException('The minimum query length must be an integer'); 72 | } 73 | 74 | /** 75 | * Get the initially selected options. 76 | * 77 | * @return \Maknz\Slack\Object\Option[] 78 | */ 79 | public function getInitialOptions() 80 | { 81 | return $this->initial_options; 82 | } 83 | 84 | /** 85 | * Set the initially selected options. 86 | * 87 | * @param array $initialOption 88 | * 89 | * @return $this 90 | * 91 | * @throws InvalidArgumentException 92 | */ 93 | public function setInitialOptions(array $initialOptions) 94 | { 95 | $this->clearInitialOptions(); 96 | 97 | foreach ($initialOptions as $initialOption) { 98 | $this->addInitialOption($initialOption); 99 | } 100 | 101 | return $this; 102 | } 103 | 104 | /** 105 | * Clear the initially selected options. 106 | * 107 | * @return $this 108 | */ 109 | public function clearInitialOptions() 110 | { 111 | $this->initial_options = []; 112 | 113 | return $this; 114 | } 115 | 116 | /** 117 | * Add an initially selected option. 118 | * 119 | * @param mixed $initialOption 120 | * 121 | * @return $this 122 | * 123 | * @throws InvalidArgumentException 124 | */ 125 | public function addInitialOption($initialOption) 126 | { 127 | if (is_array($initialOption)) { 128 | $initialOption = new Option($initialOption); 129 | } 130 | 131 | if ($initialOption instanceof Option) { 132 | $this->initial_options[] = $initialOption; 133 | 134 | return $this; 135 | } 136 | 137 | throw new InvalidArgumentException('The initial option must be an instance of '.Option::class.' or a keyed array'); 138 | } 139 | 140 | /** 141 | * Convert the block to its array representation. 142 | * 143 | * @return array 144 | */ 145 | public function toArray() 146 | { 147 | $data = [ 148 | 'type' => $this->getType(), 149 | 'placeholder' => $this->getPlaceholder()->toArray(), 150 | 'action_id' => $this->getActionId(), 151 | ]; 152 | 153 | if ($this->getMinQueryLength()) { 154 | $data['min_query_length'] = $this->getMinQueryLength(); 155 | } 156 | 157 | $initialOptions = $this->getInitialOptions(); 158 | 159 | if (count($initialOptions)) { 160 | $data['initial_options'] = array_map(function (Option $o) { 161 | return $o->toArray(); 162 | }, $initialOptions); 163 | } 164 | 165 | if ($this->getConfirm()) { 166 | $data['confirm'] = $this->getConfirm()->toArray(); 167 | } 168 | 169 | if ($this->getMaxSelectedItems()) { 170 | $data['max_selected_items'] = $this->getMaxSelectedItems(); 171 | } 172 | 173 | return $data; 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /src/BlockElement/MultiSelect.php: -------------------------------------------------------------------------------- 1 | 'placeholder', 25 | 'action_id' => 'action_id', 26 | 'options' => 'options', 27 | 'option_groups' => 'option_groups', 28 | 'confirm' => 'confirm', 29 | 'max_selected_items' => 'max_selected_items', 30 | ]; 31 | 32 | /** 33 | * Get the intially selected options. 34 | * 35 | * @return \Maknz\Slack\Object\Option[] 36 | */ 37 | public function getInitialOptions() 38 | { 39 | $initialOptions = []; 40 | 41 | foreach ($this->getOptions() as $option) { 42 | if ($option->isInitiallySelected()) { 43 | $initialOptions[] = $option; 44 | } 45 | } 46 | 47 | foreach ($this->getOptionGroups() as $group) { 48 | foreach ($group->getOptions() as $option) { 49 | if ($option->isInitiallySelected()) { 50 | $initialOptions[] = $option; 51 | } 52 | } 53 | } 54 | 55 | return $initialOptions; 56 | } 57 | 58 | /** 59 | * Convert the block to its array representation. 60 | * 61 | * @return array 62 | */ 63 | public function toArray() 64 | { 65 | $data = [ 66 | 'type' => $this->getType(), 67 | 'placeholder' => $this->getPlaceholder()->toArray(), 68 | 'action_id' => $this->getActionId(), 69 | ]; 70 | 71 | if (count($this->getOptions())) { 72 | $data['options'] = $this->getOptionsAsArrays(); 73 | } else { 74 | $data['option_groups'] = $this->getOptionGroupsAsArrays(); 75 | } 76 | 77 | $initialOptions = $this->getInitialOptions(); 78 | 79 | if (count($initialOptions)) { 80 | $data['initial_options'] = array_map(function (Option $o) { 81 | return $o->toArray(); 82 | }, $initialOptions); 83 | } 84 | 85 | if ($this->getConfirm()) { 86 | $data['confirm'] = $this->getConfirm()->toArray(); 87 | } 88 | 89 | return $data; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/BlockElement/MultiUsersSelect.php: -------------------------------------------------------------------------------- 1 | 'placeholder', 29 | 'action_id' => 'action_id', 30 | 'initial_users' => 'initial_users', 31 | 'confirm' => 'confirm', 32 | 'max_selected_items' => 'max_selected_items', 33 | ]; 34 | 35 | /** 36 | * Get the initially selected users. 37 | * 38 | * @return string[] 39 | */ 40 | public function getInitialUsers() 41 | { 42 | return $this->initial_users; 43 | } 44 | 45 | /** 46 | * Set the initially selected users. 47 | * 48 | * @param string[] $initialUsers 49 | * 50 | * @return $this 51 | * 52 | * @throws InvalidArgumentException 53 | */ 54 | public function setInitialUsers(array $initialUsers) 55 | { 56 | $this->clearInitialUsers(); 57 | 58 | foreach ($initialUsers as $initialUser) { 59 | $this->addInitialUser($initialUser); 60 | } 61 | 62 | return $this; 63 | } 64 | 65 | /** 66 | * Clear the initially selected users. 67 | * 68 | * @return $this 69 | */ 70 | public function clearInitialUsers() 71 | { 72 | $this->initial_users = []; 73 | 74 | return $this; 75 | } 76 | 77 | /** 78 | * Add an initially selected user. 79 | * 80 | * @param string $initialUsers 81 | * 82 | * @return $this 83 | * 84 | * @throws InvalidArgumentException 85 | */ 86 | public function addInitialUser($initialUser) 87 | { 88 | if (is_string($initialUser)) { 89 | $this->initial_users[] = $initialUser; 90 | 91 | return $this; 92 | } 93 | 94 | throw new InvalidArgumentException('The initial user ID must be a string'); 95 | } 96 | 97 | /** 98 | * Convert the block to its array representation. 99 | * 100 | * @return array 101 | */ 102 | public function toArray() 103 | { 104 | $data = [ 105 | 'type' => $this->getType(), 106 | 'placeholder' => $this->getPlaceholder()->toArray(), 107 | 'action_id' => $this->getActionId(), 108 | ]; 109 | 110 | $initialUsers = $this->getInitialUsers(); 111 | 112 | if (count($initialUsers)) { 113 | $data['initial_users'] = $initialUsers; 114 | } 115 | 116 | if ($this->getConfirm()) { 117 | $data['confirm'] = $this->getConfirm()->toArray(); 118 | } 119 | 120 | if ($this->getMaxSelectedItems()) { 121 | $data['max_selected_items'] = $this->getMaxSelectedItems(); 122 | } 123 | 124 | return $data; 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/BlockElement/Options.php: -------------------------------------------------------------------------------- 1 | 'action_id', 20 | 'options' => 'options', 21 | 'confirm' => 'confirm', 22 | ]; 23 | 24 | /** 25 | * Convert the block to its array representation. 26 | * 27 | * @return array 28 | */ 29 | public function toArray() 30 | { 31 | $data = [ 32 | 'type' => $this->getType(), 33 | 'action_id' => $this->getActionId(), 34 | 'options' => $this->getOptionsAsArrays(), 35 | ]; 36 | 37 | if ($this->getConfirm()) { 38 | $data['confirm'] = $this->getConfirm()->toArray(); 39 | } 40 | 41 | return $data; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/BlockElement/RadioButtons.php: -------------------------------------------------------------------------------- 1 | 'action_id', 30 | 'options' => 'options', 31 | 'confirm' => 'confirm', 32 | ]; 33 | 34 | /** 35 | * Get the intially selected option. 36 | * 37 | * @return \Maknz\Slack\Object\Option|null 38 | */ 39 | public function getInitialOption() 40 | { 41 | foreach ($this->getOptions() as $option) { 42 | if ($option->isInitiallySelected()) { 43 | return $option; 44 | } 45 | } 46 | 47 | return null; 48 | } 49 | 50 | /** 51 | * Add an option to the radio buttons. 52 | * 53 | * @param mixed $option 54 | * 55 | * @return $this 56 | * 57 | * @throws \InvalidArgumentException 58 | */ 59 | public function addOption($option) 60 | { 61 | if ((is_array($option) && ! empty($option['selected'])) 62 | || ($option instanceof Option && ! $option->isInitiallySelected()) 63 | ) { 64 | if ($this->hasInitialOption) { 65 | throw new InvalidArgumentException('Only one option can be initially selected'); 66 | } 67 | 68 | $this->hasInitialOption = true; 69 | } 70 | 71 | return parent::addOption($option); 72 | } 73 | 74 | /** 75 | * Clear options available. 76 | * 77 | * @return $this 78 | */ 79 | public function clearOptions() 80 | { 81 | $this->hasInitialOption = false; 82 | 83 | return parent::clearOptions(); 84 | } 85 | 86 | /** 87 | * Convert the block to its array representation. 88 | * 89 | * @return array 90 | */ 91 | public function toArray() 92 | { 93 | $data = [ 94 | 'type' => $this->getType(), 95 | 'action_id' => $this->getActionId(), 96 | 'options' => $this->getOptionsAsArrays(), 97 | ]; 98 | 99 | if ($this->hasInitialOption) { 100 | $initialOption = $this->getInitialOption(); 101 | if ($initialOption !== null) { 102 | $data['initial_option'] = $initialOption->toArray(); 103 | } 104 | } 105 | 106 | $confirm = $this->getConfirm(); 107 | if ($confirm !== null) { 108 | $data['confirm'] = $confirm->toArray(); 109 | } 110 | 111 | return $data; 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/BlockElement/RespondableSelect.php: -------------------------------------------------------------------------------- 1 | response_url_enabled; 21 | } 22 | 23 | /** 24 | * Set whether to include a response URL in submission payload. 25 | * 26 | * @param bool $enabled 27 | * 28 | * @return $this 29 | */ 30 | public function setResponseUrlEnabled($enabled = true) 31 | { 32 | $this->response_url_enabled = (bool)$enabled; 33 | 34 | return $this; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/BlockElement/Select.php: -------------------------------------------------------------------------------- 1 | 'placeholder', 31 | 'action_id' => 'action_id', 32 | 'options' => 'options', 33 | 'option_groups' => 'option_groups', 34 | 'confirm' => 'confirm', 35 | ]; 36 | 37 | /** 38 | * Add an option to the select. 39 | * 40 | * @param mixed $option 41 | * 42 | * @return $this 43 | * 44 | * @throws \InvalidArgumentException 45 | */ 46 | public function addOption($option) 47 | { 48 | if ((is_array($option) && ! empty($option['selected'])) 49 | || ($option instanceof Option && ! $option->isInitiallySelected()) 50 | ) { 51 | if ($this->hasInitialOption) { 52 | throw new InvalidArgumentException('Only one option can be initially selected'); 53 | } 54 | 55 | $this->hasInitialOption = true; 56 | } 57 | 58 | return parent::addOption($option); 59 | } 60 | 61 | /** 62 | * Clear option groups in the select. 63 | * 64 | * @return $this 65 | */ 66 | public function clearOptionGroups() 67 | { 68 | if (count($this->getOptions()) == 0) { 69 | $this->hasInitialOption = false; 70 | } 71 | 72 | return parent::clearOptionGroups(); 73 | } 74 | 75 | /** 76 | * Clear options in the select. 77 | * 78 | * @return $this 79 | */ 80 | public function clearOptions() 81 | { 82 | if (count($this->getOptionGroups()) == 0) { 83 | $this->hasInitialOption = false; 84 | } 85 | 86 | return parent::clearOptions(); 87 | } 88 | 89 | /** 90 | * Add an option group to the select. 91 | * 92 | * @param mixed $group 93 | * 94 | * @return $this 95 | * 96 | * @throws \InvalidArgumentException 97 | */ 98 | public function addOptionGroup($group) 99 | { 100 | if (is_array($group)) { 101 | $group = new OptionGroup($group); 102 | } 103 | 104 | parent::addOptionGroup($group); 105 | 106 | if ($group->hasSelectedOption()) { 107 | if ($this->hasInitialOption) { 108 | throw new InvalidArgumentException('Only one option can be initially selected'); 109 | } 110 | 111 | $this->hasInitialOption = true; 112 | } 113 | 114 | return $this; 115 | } 116 | 117 | /** 118 | * Get the intially selected option. 119 | * 120 | * @return \Maknz\Slack\Object\Option 121 | */ 122 | public function getInitialOption() 123 | { 124 | foreach ($this->getOptions() as $option) { 125 | if ($option->isInitiallySelected()) { 126 | return $option; 127 | } 128 | } 129 | 130 | foreach ($this->getOptionGroups() as $group) { 131 | foreach ($group->getOptions() as $option) { 132 | if ($option->isInitiallySelected()) { 133 | return $option; 134 | } 135 | } 136 | } 137 | } 138 | 139 | /** 140 | * Convert the block to its array representation. 141 | * 142 | * @return array 143 | */ 144 | public function toArray() 145 | { 146 | $data = [ 147 | 'type' => $this->getType(), 148 | 'placeholder' => $this->getPlaceholder()->toArray(), 149 | 'action_id' => $this->getActionId(), 150 | ]; 151 | 152 | if (count($this->getOptions())) { 153 | $data['options'] = $this->getOptionsAsArrays(); 154 | } else { 155 | $data['option_groups'] = $this->getOptionGroupsAsArrays(); 156 | } 157 | 158 | if ($this->hasInitialOption) { 159 | $data['initial_option'] = $this->getInitialOption()->toArray(); 160 | } 161 | 162 | if ($this->getConfirm()) { 163 | $data['confirm'] = $this->getConfirm()->toArray(); 164 | } 165 | 166 | return $data; 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /src/BlockElement/Temporalpicker.php: -------------------------------------------------------------------------------- 1 | initial_value; 26 | } 27 | 28 | /** 29 | * Set the initial value. 30 | * 31 | * @param \DateTime $initialValue 32 | * 33 | * @return $this 34 | */ 35 | protected function setInitialValue(DateTime $initialValue) 36 | { 37 | $this->initial_value = $initialValue; 38 | 39 | return $this; 40 | } 41 | 42 | /** 43 | * Get the name of the initial value field. 44 | * 45 | * @return string 46 | */ 47 | abstract protected function getInitialValueField(); 48 | 49 | /** 50 | * Get the initial value format. 51 | * 52 | * @return string 53 | */ 54 | abstract protected function getInitialValueFormat(); 55 | 56 | /** 57 | * Convert the block to its array representation. 58 | * 59 | * @return array 60 | */ 61 | public function toArray() 62 | { 63 | $data = [ 64 | 'type' => $this->getType(), 65 | 'action_id' => $this->getActionId(), 66 | ]; 67 | 68 | if ($this->getPlaceholder()) { 69 | $data['placeholder'] = $this->getPlaceholder()->toArray(); 70 | } 71 | 72 | if ($this->getInitialValue()) { 73 | $data[$this->getInitialValueField()] = $this->getInitialValue()->format($this->getInitialValueFormat()); 74 | } 75 | 76 | if ($this->getConfirm()) { 77 | $data['confirm'] = $this->getConfirm()->toArray(); 78 | } 79 | 80 | return $data; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /src/BlockElement/Text.php: -------------------------------------------------------------------------------- 1 | 'type', 48 | 'text' => 'text', 49 | 'emoji' => 'escape_emojis', 50 | 'verbatim' => 'verbatim', 51 | ]; 52 | 53 | /** 54 | * Get the text format type. 55 | * 56 | * @return string 57 | */ 58 | public function getType() 59 | { 60 | return $this->type; 61 | } 62 | 63 | /** 64 | * Set the text format type. 65 | * 66 | * @param string $type 67 | * 68 | * @return $this 69 | */ 70 | public function setType($type) 71 | { 72 | $this->type = $type; 73 | 74 | return $this; 75 | } 76 | 77 | /** 78 | * Get the text content. 79 | * 80 | * @return string 81 | */ 82 | public function getText() 83 | { 84 | return $this->text; 85 | } 86 | 87 | /** 88 | * Set the text content. 89 | * 90 | * @param string $text 91 | * 92 | * @return $this 93 | */ 94 | public function setText($text) 95 | { 96 | $this->text = $text; 97 | 98 | return $this; 99 | } 100 | 101 | /** 102 | * Get whether to escape emojis. 103 | * 104 | * @return bool 105 | */ 106 | public function getEscapeEmojis() 107 | { 108 | return $this->escape_emojis; 109 | } 110 | 111 | /** 112 | * Set whether to escape emojis. 113 | * 114 | * @param bool $escape 115 | * 116 | * @return $this 117 | */ 118 | public function setEscapeEmojis($escape) 119 | { 120 | $this->escape_emojis = (bool)$escape; 121 | 122 | return $this; 123 | } 124 | 125 | /** 126 | * Get whether to treat text as-is. 127 | * 128 | * @return bool 129 | */ 130 | public function getVerbatim() 131 | { 132 | return $this->verbatim; 133 | } 134 | 135 | /** 136 | * Set whether to treat text as-is. 137 | * 138 | * @param bool $verbatim 139 | * 140 | * @return $this 141 | */ 142 | public function setVerbatim($verbatim) 143 | { 144 | $this->verbatim = (bool)$verbatim; 145 | 146 | return $this; 147 | } 148 | 149 | /** 150 | * Convert the block to its array representation. 151 | * 152 | * @return array 153 | */ 154 | public function toArray() 155 | { 156 | $data = [ 157 | 'type' => $this->getType(), 158 | 'text' => $this->getText(), 159 | ]; 160 | 161 | if ($data['type'] == static::TYPE_PLAIN) { 162 | $data['emoji'] = $this->getEscapeEmojis(); 163 | } else { 164 | $data['verbatim'] = $this->getVerbatim(); 165 | } 166 | 167 | return $data; 168 | } 169 | 170 | /** 171 | * Create a Text block from various formats. 172 | * 173 | * @param mixed $text 174 | * @param string $type If passed, the Text object will be of this type. 175 | * 176 | * @return $this 177 | * 178 | * @throws \InvalidArgumentException 179 | */ 180 | public static function create($text, $type = null) 181 | { 182 | if (is_string($text)) { 183 | $text = [ 184 | 'type' => $type ?? static::TYPE_PLAIN, 185 | 'text' => $text, 186 | ]; 187 | } 188 | 189 | if (is_array($text)) { 190 | $text = new static($text); 191 | } 192 | 193 | if ($text instanceof static) { 194 | if ($type && $text->getType() != $type) { 195 | throw new InvalidArgumentException('Text type must be '.$type); 196 | } 197 | 198 | return $text; 199 | } 200 | 201 | throw new InvalidArgumentException('Text must be a string, keyed array or '.static::class.' object'); 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /src/BlockElement/TextInput.php: -------------------------------------------------------------------------------- 1 | 'action_id', 68 | 'placeholder' => 'placeholder', 69 | 'initial_value' => 'initial_value', 70 | 'multiline' => 'multiline', 71 | 'min_length' => 'min_length', 72 | 'max_length' => 'max_length', 73 | 'dispatch_action_config' => 'dispatch_config', 74 | ]; 75 | 76 | /** 77 | * Get the action. 78 | * 79 | * @return string 80 | */ 81 | public function getActionId() 82 | { 83 | return $this->action_id; 84 | } 85 | 86 | /** 87 | * Set the action. 88 | * 89 | * @param string $actionId 90 | * 91 | * @return $this 92 | */ 93 | public function setActionId($actionId) 94 | { 95 | $this->action_id = $actionId; 96 | 97 | return $this; 98 | } 99 | 100 | /** 101 | * Get the initial value. 102 | * 103 | * @return string 104 | */ 105 | public function getInitialValue() 106 | { 107 | return $this->initial_value; 108 | } 109 | 110 | /** 111 | * Set the initial value. 112 | * 113 | * @param string $initialValue 114 | * 115 | * @return $this 116 | */ 117 | public function setInitialValue($initialValue) 118 | { 119 | $this->initial_value = $initialValue; 120 | 121 | return $this; 122 | } 123 | 124 | /** 125 | * Get whether the input spans multiple lines. 126 | * 127 | * @return bool 128 | */ 129 | public function getMultiline() 130 | { 131 | return $this->multiline; 132 | } 133 | 134 | /** 135 | * Set whether the input spans multiple lines. 136 | * 137 | * @param bool $multiline 138 | * 139 | * @return $this 140 | */ 141 | public function setMultiline($multiline) 142 | { 143 | $this->multiline = (bool)$multiline; 144 | 145 | return $this; 146 | } 147 | 148 | /** 149 | * Get the input minimum length. 150 | * 151 | * @return int 152 | */ 153 | public function getMinLength() 154 | { 155 | return $this->min_length; 156 | } 157 | 158 | /** 159 | * Set the input minimum length. 160 | * 161 | * @param int $minLength 162 | * 163 | * @return $this 164 | */ 165 | public function setMinLength($minLength) 166 | { 167 | $this->min_length = $minLength; 168 | 169 | return $this; 170 | } 171 | 172 | /** 173 | * Get the input maximum length. 174 | * 175 | * @return int 176 | */ 177 | public function getMaxLength() 178 | { 179 | return $this->max_length; 180 | } 181 | 182 | /** 183 | * Set the input maximum length. 184 | * 185 | * @param int $maxLength 186 | * 187 | * @return $this 188 | */ 189 | public function setMaxLength($maxLength) 190 | { 191 | $this->max_length = $maxLength; 192 | 193 | return $this; 194 | } 195 | 196 | /** 197 | * Get the input dispatch config. 198 | * 199 | * @return string[] 200 | */ 201 | public function getDispatchConfig() 202 | { 203 | return $this->dispatch_config; 204 | } 205 | 206 | /** 207 | * Set the input dispatch config. 208 | * 209 | * @param string[] $dispatchConfig 210 | * 211 | * @return $this 212 | * 213 | * @throws InvalidArgumentException 214 | */ 215 | public function setDispatchConfig(array $dispatchConfig) 216 | { 217 | $validConfig = ['on_enter_pressed', 'on_character_entered']; 218 | 219 | foreach ($dispatchConfig as $config) { 220 | if ( ! in_array($config, $validConfig)) { 221 | throw new InvalidArgumentException("Invalid dispatch config '$config'; must be one of: ".implode(',', $validConfig)); 222 | } 223 | } 224 | 225 | $this->dispatch_config = $dispatchConfig; 226 | 227 | return $this; 228 | } 229 | 230 | /** 231 | * Convert the block to its array representation. 232 | * 233 | * @return array 234 | */ 235 | public function toArray() 236 | { 237 | $data = [ 238 | 'type' => $this->getType(), 239 | 'action_id' => $this->getActionId(), 240 | ]; 241 | 242 | if ($this->getPlaceholder()) { 243 | $data['placeholder'] = $this->getPlaceholder()->toArray(); 244 | } 245 | 246 | if ($this->getInitialValue()) { 247 | $data['initial_value'] = $this->getInitialValue(); 248 | } 249 | 250 | if ($this->getMultiline() != null) { 251 | $data['multiline'] = $this->getMultiline(); 252 | } 253 | 254 | if ($this->getMinLength()) { 255 | $data['min_length'] = $this->getMinLength(); 256 | } 257 | 258 | if ($this->getMaxLength()) { 259 | $data['max_length'] = $this->getMaxLength(); 260 | } 261 | 262 | if ($this->getDispatchConfig()) { 263 | $data['dispatch_action_config'] = [ 264 | 'trigger_actions_on' => $this->getDispatchConfig(), 265 | ]; 266 | } 267 | 268 | return $data; 269 | } 270 | } 271 | -------------------------------------------------------------------------------- /src/BlockElement/Timepicker.php: -------------------------------------------------------------------------------- 1 | 'action_id', 22 | 'placeholder' => 'placeholder', 23 | 'initial_time' => 'initial_value', 24 | 'confirm' => 'confirm', 25 | ]; 26 | 27 | /** 28 | * Get the name of the initial value field. 29 | * 30 | * @return string 31 | */ 32 | public function getInitialValueField() 33 | { 34 | return 'initial_time'; 35 | } 36 | 37 | /** 38 | * Get the initial value format. 39 | * 40 | * @return string 41 | */ 42 | public function getInitialValueFormat() 43 | { 44 | return 'H:i'; 45 | } 46 | 47 | /** 48 | * Get the initial time. 49 | * 50 | * @return \DateTime 51 | */ 52 | public function getInitialTime() 53 | { 54 | return $this->getInitialValue(); 55 | } 56 | 57 | /** 58 | * Set the initial time. 59 | * 60 | * @param \DateTime $initialTime 61 | * 62 | * @return $this 63 | */ 64 | public function setInitialTime(DateTime $initialTime) 65 | { 66 | return $this->setInitialValue($initialTime); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/BlockElement/UsersSelect.php: -------------------------------------------------------------------------------- 1 | 'placeholder', 29 | 'action_id' => 'action_id', 30 | 'initial_user' => 'initial_user', 31 | 'confirm' => 'confirm', 32 | ]; 33 | 34 | /** 35 | * Get the initially selected user. 36 | * 37 | * @return string 38 | */ 39 | public function getInitialUser() 40 | { 41 | return $this->initial_user; 42 | } 43 | 44 | /** 45 | * Set the initially selected user. 46 | * 47 | * @param string $initialUser 48 | * 49 | * @return $this 50 | * 51 | * @throws InvalidArgumentException 52 | */ 53 | public function setInitialUser($initialUser) 54 | { 55 | if (is_string($initialUser)) { 56 | $this->initial_user = $initialUser; 57 | 58 | return $this; 59 | } 60 | 61 | throw new InvalidArgumentException('The initial user ID must be a string'); 62 | } 63 | 64 | /** 65 | * Convert the block to its array representation. 66 | * 67 | * @return array 68 | */ 69 | public function toArray() 70 | { 71 | $data = [ 72 | 'type' => $this->getType(), 73 | 'placeholder' => $this->getPlaceholder()->toArray(), 74 | 'action_id' => $this->getActionId(), 75 | ]; 76 | 77 | if ($this->getInitialUser()) { 78 | $data['initial_user'] = $this->getInitialUser(); 79 | } 80 | 81 | if ($this->getConfirm()) { 82 | $data['confirm'] = $this->getConfirm()->toArray(); 83 | } 84 | 85 | return $data; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/Client.php: -------------------------------------------------------------------------------- 1 | 'setDefaultChannel', 100 | 'username' => 'setDefaultUsername', 101 | 'icon' => 'setDefaultIcon', 102 | 'response_type' => 'setResponseType', 103 | 'link_names' => 'setLinkNames', 104 | 'unfurl_links' => 'setUnfurlLinks', 105 | 'unfurl_media' => 'setUnfurlMedia', 106 | 'allow_markdown' => 'setAllowMarkdown', 107 | 'markdown_in_attachments' => 'setMarkdownInAttachments', 108 | ]; 109 | 110 | /** 111 | * @var Message 112 | */ 113 | protected $message; 114 | 115 | /** 116 | * Instantiate a new Client. 117 | * 118 | * @param string $endpoint 119 | * @param array $options 120 | * @param \GuzzleHttp\Client|null $guzzle 121 | * 122 | * @throws \InvalidArgumentException 123 | * @throws \RuntimeException 124 | */ 125 | public function __construct($endpoint, array $options = [], ?Guzzle $guzzle = null) 126 | { 127 | $this->endpoint = $endpoint; 128 | 129 | $this->setOptions($options); 130 | 131 | $this->guzzle = $guzzle ?: new Guzzle(); 132 | } 133 | 134 | /** 135 | * Returns property setter method by given option name. 136 | * 137 | * @param string $option 138 | * 139 | * @return mixed|null 140 | */ 141 | private static function getOptionSetter(string $option) 142 | { 143 | return static::$optionSetter[$option] ?? null; 144 | } 145 | 146 | /** 147 | * @param array $options 148 | * 149 | * @return \Maknz\Slack\Client 150 | */ 151 | public function setOptions(array $options) 152 | { 153 | foreach ($options as $option => $value) { 154 | $this->setOption($option, $value); 155 | } 156 | 157 | return $this; 158 | } 159 | 160 | /** 161 | * @param $option 162 | * @param $value 163 | */ 164 | public function setOption($option, $value) 165 | { 166 | $setter = self::getOptionSetter($option); 167 | if ($setter !== null) { 168 | $this->$setter($value); 169 | } 170 | } 171 | 172 | /** 173 | * Pass any unhandled methods through to a new Message 174 | * instance. 175 | * 176 | * @param string $name The name of the method 177 | * @param array $arguments The method arguments 178 | * 179 | * @return $this|mixed 180 | */ 181 | public function __call($name, $arguments) 182 | { 183 | /** @var Message $message */ 184 | $message = $this->getOrCreateMessage(); 185 | $value = $message->$name(...$arguments); 186 | 187 | return strpos($name, 'get') === 0 ? $value : $this; 188 | } 189 | 190 | /** 191 | * Get the Slack endpoint. 192 | * 193 | * @return string 194 | */ 195 | public function getEndpoint() 196 | { 197 | return $this->endpoint; 198 | } 199 | 200 | /** 201 | * Set the Slack endpoint. 202 | * 203 | * @param string $endpoint 204 | * 205 | * @return void 206 | */ 207 | public function setEndpoint($endpoint) 208 | { 209 | $this->endpoint = $endpoint; 210 | } 211 | 212 | /** 213 | * Get the default channel messages will be created for. 214 | * 215 | * @return string 216 | */ 217 | public function getDefaultChannel() 218 | { 219 | return $this->channel; 220 | } 221 | 222 | /** 223 | * Set the default channel messages will be created for. 224 | * 225 | * @param string $channel 226 | * 227 | * @return void 228 | */ 229 | public function setDefaultChannel($channel) 230 | { 231 | $this->channel = $channel; 232 | } 233 | 234 | /** 235 | * Get the default username messages will be created for. 236 | * 237 | * @return string 238 | */ 239 | public function getDefaultUsername() 240 | { 241 | return $this->username; 242 | } 243 | 244 | /** 245 | * Set the default username messages will be created for. 246 | * 247 | * @param string $username 248 | * 249 | * @return void 250 | */ 251 | public function setDefaultUsername($username) 252 | { 253 | $this->username = $username; 254 | } 255 | 256 | /** 257 | * Get the default icon messages will be created with. 258 | * 259 | * @return string 260 | */ 261 | public function getDefaultIcon() 262 | { 263 | return $this->icon; 264 | } 265 | 266 | /** 267 | * Set the default icon messages will be created with. 268 | * 269 | * @param string $icon 270 | * 271 | * @return void 272 | */ 273 | public function setDefaultIcon($icon) 274 | { 275 | $this->icon = $icon; 276 | } 277 | 278 | /** 279 | * Get whether the response should be viewable by others 280 | * when posted to a channel. 'ephemeral' | 'in_channel'. 281 | * 282 | * @return string 283 | */ 284 | public function getResponseType() 285 | { 286 | return $this->response_type; 287 | } 288 | 289 | /** 290 | * Set whether the response should be viewable by others 291 | * when posted to a channel. 'ephemeral' | 'in_channel'. 292 | * 293 | * @param string $value 294 | * 295 | * @return void 296 | */ 297 | public function setResponseType($value) 298 | { 299 | $this->response_type = $value; 300 | } 301 | 302 | /** 303 | * Get whether messages sent will have names (like @regan) 304 | * will be converted into links. 305 | * 306 | * @return bool 307 | */ 308 | public function getLinkNames() 309 | { 310 | return $this->link_names; 311 | } 312 | 313 | /** 314 | * Set whether messages sent will have names (like @regan) 315 | * will be converted into links. 316 | * 317 | * @param bool $value 318 | * 319 | * @return void 320 | */ 321 | public function setLinkNames($value) 322 | { 323 | $this->link_names = (bool)$value; 324 | } 325 | 326 | /** 327 | * Get whether text links should be unfurled. 328 | * 329 | * @return bool 330 | */ 331 | public function getUnfurlLinks() 332 | { 333 | return $this->unfurl_links; 334 | } 335 | 336 | /** 337 | * Set whether text links should be unfurled. 338 | * 339 | * @param bool $value 340 | * 341 | * @return void 342 | */ 343 | public function setUnfurlLinks($value) 344 | { 345 | $this->unfurl_links = (bool)$value; 346 | } 347 | 348 | /** 349 | * Get whether media links should be unfurled. 350 | * 351 | * @return bool 352 | */ 353 | public function getUnfurlMedia() 354 | { 355 | return $this->unfurl_media; 356 | } 357 | 358 | /** 359 | * Set whether media links should be unfurled. 360 | * 361 | * @param bool $value 362 | * 363 | * @return void 364 | */ 365 | public function setUnfurlMedia($value) 366 | { 367 | $this->unfurl_media = (bool)$value; 368 | } 369 | 370 | /** 371 | * Get whether message text should be formatted with 372 | * Slack's Markdown-like language. 373 | * 374 | * @return bool 375 | */ 376 | public function getAllowMarkdown() 377 | { 378 | return $this->allow_markdown; 379 | } 380 | 381 | /** 382 | * Set whether message text should be formatted with 383 | * Slack's Markdown-like language. 384 | * 385 | * @param bool $value 386 | * 387 | * @return void 388 | */ 389 | public function setAllowMarkdown($value) 390 | { 391 | $this->allow_markdown = (bool)$value; 392 | } 393 | 394 | /** 395 | * Get the attachment fields which should be formatted 396 | * in Slack's Markdown-like language. 397 | * 398 | * @return array 399 | */ 400 | public function getMarkdownInAttachments() 401 | { 402 | return $this->markdown_in_attachments; 403 | } 404 | 405 | /** 406 | * Set the attachment fields which should be formatted 407 | * in Slack's Markdown-like language. 408 | * 409 | * @param array $fields 410 | * 411 | * @return void 412 | */ 413 | public function setMarkdownInAttachments(array $fields) 414 | { 415 | $this->markdown_in_attachments = $fields; 416 | } 417 | 418 | /** 419 | * @return Message 420 | */ 421 | public function getMessage() 422 | { 423 | return $this->message; 424 | } 425 | 426 | /** 427 | * Create a new message with defaults. 428 | * 429 | * @return \Maknz\Slack\Message 430 | */ 431 | public function createMessage() 432 | { 433 | $message = new Message(); 434 | 435 | $message->setChannel($this->getDefaultChannel()); 436 | 437 | $message->setUsername($this->getDefaultUsername()); 438 | 439 | $message->setIcon($this->getDefaultIcon()); 440 | 441 | $message->setAllowMarkdown($this->getAllowMarkdown()); 442 | 443 | $message->setMarkdownInAttachments($this->getMarkdownInAttachments()); 444 | 445 | return $message; 446 | } 447 | 448 | /** 449 | * @return Message 450 | */ 451 | protected function getOrCreateMessage() 452 | { 453 | return $this->message ?? $this->message = $this->createMessage(); 454 | } 455 | 456 | /** 457 | * Send a message. 458 | * 459 | * @internal will become protected 460 | * 461 | * @param \Maknz\Slack\Message $message 462 | * 463 | * @throws \RuntimeException 464 | */ 465 | public function sendMessage(Message $message) 466 | { 467 | $payload = $this->preparePayload($message); 468 | 469 | $encoded = json_encode($payload, JSON_UNESCAPED_UNICODE); 470 | 471 | if ($encoded === false) { 472 | throw new RuntimeException(sprintf('JSON encoding error %s: %s', json_last_error(), json_last_error_msg())); 473 | } 474 | 475 | $this->guzzle->post($this->endpoint, [ 476 | 'headers' => [ 477 | 'Content-Type' => 'application/json', 478 | ], 479 | 'body' => $encoded, 480 | ]); 481 | } 482 | 483 | /** 484 | * Send the message. 485 | * 486 | * @param string|\Maknz\Slack\Message $text The text to send 487 | * 488 | * @return \Maknz\Slack\Message 489 | * 490 | * @throws \RuntimeException 491 | */ 492 | public function send($text = null) 493 | { 494 | if ($text instanceof Message) { 495 | $message = $text; 496 | } else { 497 | $message = $this->getOrCreateMessage(); 498 | if ($text !== null) { 499 | $message->setText($text); 500 | } 501 | } 502 | 503 | $this->sendMessage($message); 504 | 505 | $this->message = null; 506 | 507 | return $message; 508 | } 509 | 510 | /** 511 | * Prepares the payload to be sent to the webhook. 512 | * 513 | * @param \Maknz\Slack\Message $message The message to send 514 | * 515 | * @return array 516 | */ 517 | public function preparePayload(Message $message) 518 | { 519 | $payload = [ 520 | 'text' => $message->getText(), 521 | 'channel' => $message->getChannel(), 522 | 'username' => $message->getUsername(), 523 | 'response_type'=> $this->getResponseType(), 524 | 'link_names' => $this->getLinkNames() ? 1 : 0, 525 | 'unfurl_links' => $this->getUnfurlLinks(), 526 | 'unfurl_media' => $this->getUnfurlMedia(), 527 | 'mrkdwn' => $message->getAllowMarkdown(), 528 | ]; 529 | 530 | if ($icon = $message->getIcon()) { 531 | $payload[$message->getIconType()] = $icon; 532 | } 533 | 534 | if (count($message->getBlocks())) { 535 | $payload['blocks'] = $message->getBlocksAsArrays(); 536 | } else { 537 | $payload['attachments'] = $this->getAttachmentsAsArrays($message); 538 | } 539 | 540 | return $payload; 541 | } 542 | 543 | /** 544 | * Get the attachments in array form. 545 | * 546 | * @param \Maknz\Slack\Message $message 547 | * 548 | * @return array 549 | */ 550 | protected function getAttachmentsAsArrays(Message $message) 551 | { 552 | $attachments = []; 553 | 554 | foreach ($message->getAttachments() as $attachment) { 555 | $attachments[] = $attachment->toArray(); 556 | } 557 | 558 | return $attachments; 559 | } 560 | } 561 | -------------------------------------------------------------------------------- /src/Field.php: -------------------------------------------------------------------------------- 1 | fields; 30 | } 31 | 32 | /** 33 | * Set the fields for the block/attachment. 34 | * 35 | * @param array $fields 36 | * 37 | * @return $this 38 | * 39 | * @throws \InvalidArgumentException 40 | */ 41 | public function setFields(array $fields) 42 | { 43 | $this->clearFields(); 44 | 45 | foreach ($fields as $field) { 46 | $this->addField($field); 47 | } 48 | 49 | return $this; 50 | } 51 | 52 | /** 53 | * Add a field to the block/attachment. 54 | * 55 | * @param Field|array $field 56 | * 57 | * @return $this 58 | * 59 | * @throws \InvalidArgumentException 60 | */ 61 | public function addField($field) 62 | { 63 | $fieldClass = $this->getFieldClass(); 64 | 65 | if ($field instanceof $fieldClass) { 66 | $this->fields[] = $field; 67 | 68 | return $this; 69 | } elseif (is_array($field)) { 70 | $this->fields[] = new $fieldClass($field); 71 | 72 | return $this; 73 | } 74 | 75 | throw new InvalidArgumentException('The field must be an instance of '.$fieldClass.' or a keyed array'); 76 | } 77 | 78 | /** 79 | * Clear the fields for the block/attachment. 80 | * 81 | * @return $this 82 | */ 83 | public function clearFields() 84 | { 85 | $this->fields = []; 86 | 87 | return $this; 88 | } 89 | 90 | /** 91 | * Iterates over all fields in this block/attachment and returns 92 | * them in their array form. 93 | * 94 | * @return array 95 | */ 96 | protected function getFieldsAsArrays() 97 | { 98 | $fields = []; 99 | 100 | foreach ($this->getFields() as $field) { 101 | $fields[] = $field->toArray(); 102 | } 103 | 104 | return $fields; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/FilterTrait.php: -------------------------------------------------------------------------------- 1 | filter; 24 | } 25 | 26 | /** 27 | * Set the filter for the list of options. 28 | * 29 | * @param mixed $filter 30 | * 31 | * @return $this 32 | * 33 | * @throws \InvalidArgumentException 34 | */ 35 | public function setFilter($filter) 36 | { 37 | if (is_array($filter)) { 38 | $filter = new Filter($filter); 39 | } 40 | 41 | if ($filter instanceof Filter) { 42 | $this->filter = $filter; 43 | 44 | return $this; 45 | } 46 | 47 | throw new InvalidArgumentException('The filter must be an instance of '.Filter::class.' or a keyed array'); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/ImageTrait.php: -------------------------------------------------------------------------------- 1 | url; 37 | } 38 | 39 | /** 40 | * Set the image URL. 41 | * 42 | * @param string $url 43 | * 44 | * @return $this 45 | */ 46 | public function setUrl($url) 47 | { 48 | $this->url = $url; 49 | 50 | return $this; 51 | } 52 | 53 | /** 54 | * Get the alternative text for the image. 55 | * 56 | * @return string 57 | */ 58 | public function getAltText() 59 | { 60 | return $this->alt_text; 61 | } 62 | 63 | /** 64 | * Set the alternative text for the image. 65 | * 66 | * @param mixed $text 67 | * 68 | * @return $this 69 | */ 70 | public function setAltText($text) 71 | { 72 | $this->alt_text = $text; 73 | 74 | return $this; 75 | } 76 | 77 | /** 78 | * Get the image title. 79 | * 80 | * @return \Maknz\Slack\BlockElement\Text 81 | */ 82 | public function getTitle() 83 | { 84 | return $this->title; 85 | } 86 | 87 | /** 88 | * Set the image title. 89 | * 90 | * @param mixed $title 91 | * 92 | * @return $this 93 | * 94 | * @throws \InvalidArgumentException 95 | */ 96 | public function setTitle($title) 97 | { 98 | $this->title = Text::create($title, Text::TYPE_PLAIN); 99 | 100 | return $this; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/MaxItemsTrait.php: -------------------------------------------------------------------------------- 1 | max_selected_items; 23 | } 24 | 25 | /** 26 | * Set the maximum number of selected items. 27 | * 28 | * @param int $maxSelectedItems 29 | * 30 | * @return $this 31 | * 32 | * @throws \InvalidArgumentException 33 | */ 34 | public function setMaxSelectedItems($maxSelectedItems) 35 | { 36 | if (is_int($maxSelectedItems) && $maxSelectedItems >= 1) { 37 | $this->max_selected_items = $maxSelectedItems; 38 | 39 | return $this; 40 | } 41 | 42 | throw new InvalidArgumentException('The max selected items must be a positive integer'); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Message.php: -------------------------------------------------------------------------------- 1 | text; 91 | } 92 | 93 | /** 94 | * Set the message text. 95 | * 96 | * @param string $text 97 | * 98 | * @return $this 99 | */ 100 | public function setText($text) 101 | { 102 | $this->text = $text; 103 | 104 | return $this; 105 | } 106 | 107 | /** 108 | * Get the channel we will post to. 109 | * 110 | * @return string 111 | */ 112 | public function getChannel() 113 | { 114 | return $this->channel; 115 | } 116 | 117 | /** 118 | * Set the channel we will post to. 119 | * 120 | * @param string $channel 121 | * 122 | * @return $this 123 | */ 124 | public function setChannel($channel) 125 | { 126 | $this->channel = $channel; 127 | 128 | return $this; 129 | } 130 | 131 | /** 132 | * Get the username we will post as. 133 | * 134 | * @return string 135 | */ 136 | public function getUsername() 137 | { 138 | return $this->username; 139 | } 140 | 141 | /** 142 | * Set the username we will post as. 143 | * 144 | * @param string $username 145 | * 146 | * @return $this 147 | */ 148 | public function setUsername($username) 149 | { 150 | $this->username = $username; 151 | 152 | return $this; 153 | } 154 | 155 | /** 156 | * Get the icon (either URL or emoji) we will post as. 157 | * 158 | * @return string 159 | */ 160 | public function getIcon() 161 | { 162 | return $this->icon; 163 | } 164 | 165 | /** 166 | * Set the icon (either URL or emoji) we will post as. 167 | * 168 | * @param string $icon 169 | * 170 | * @return $this 171 | */ 172 | public function setIcon($icon) 173 | { 174 | if ($icon == null) { 175 | $this->icon = $this->iconType = null; 176 | 177 | return $this; 178 | } 179 | 180 | if (mb_substr($icon, 0, 1) == ':' && mb_substr($icon, mb_strlen($icon) - 1, 1) == ':') { 181 | $this->iconType = self::ICON_TYPE_EMOJI; 182 | } else { 183 | $this->iconType = self::ICON_TYPE_URL; 184 | } 185 | 186 | $this->icon = $icon; 187 | 188 | return $this; 189 | } 190 | 191 | /** 192 | * Get the icon type being used, if an icon is set. 193 | * 194 | * @return string 195 | */ 196 | public function getIconType() 197 | { 198 | return $this->iconType; 199 | } 200 | 201 | /** 202 | * Get whether message text should be formatted with 203 | * Slack's Markdown-like language. 204 | * 205 | * @return bool 206 | */ 207 | public function getAllowMarkdown() 208 | { 209 | return $this->allow_markdown; 210 | } 211 | 212 | /** 213 | * Set whether message text should be formatted with 214 | * Slack's Markdown-like language. 215 | * 216 | * @param bool $value 217 | * 218 | * @return $this 219 | */ 220 | public function setAllowMarkdown($value) 221 | { 222 | $this->allow_markdown = (bool)$value; 223 | 224 | return $this; 225 | } 226 | 227 | /** 228 | * Enable Markdown formatting for the message. 229 | * 230 | * @return $this 231 | */ 232 | public function enableMarkdown() 233 | { 234 | $this->setAllowMarkdown(true); 235 | 236 | return $this; 237 | } 238 | 239 | /** 240 | * Disable Markdown formatting for the message. 241 | * 242 | * @return $this 243 | */ 244 | public function disableMarkdown() 245 | { 246 | $this->setAllowMarkdown(false); 247 | 248 | return $this; 249 | } 250 | 251 | /** 252 | * Get the attachment fields which should be formatted 253 | * in Slack's Markdown-like language. 254 | * 255 | * @return array 256 | */ 257 | public function getMarkdownInAttachments() 258 | { 259 | return $this->markdown_in_attachments; 260 | } 261 | 262 | /** 263 | * Set the attachment fields which should be formatted 264 | * in Slack's Markdown-like language. 265 | * 266 | * @param array $fields 267 | * 268 | * @return $this 269 | */ 270 | public function setMarkdownInAttachments(array $fields) 271 | { 272 | $this->markdown_in_attachments = $fields; 273 | 274 | return $this; 275 | } 276 | 277 | /** 278 | * Change the name of the user the post will be made as. 279 | * 280 | * @param string $username 281 | * 282 | * @return $this 283 | */ 284 | public function from($username) 285 | { 286 | $this->setUsername($username); 287 | 288 | return $this; 289 | } 290 | 291 | /** 292 | * Change the channel the post will be made to. 293 | * 294 | * @param string $channel 295 | * 296 | * @return $this 297 | */ 298 | public function to($channel) 299 | { 300 | $this->setChannel($channel); 301 | 302 | return $this; 303 | } 304 | 305 | /** 306 | * Chainable method for setting the icon. 307 | * 308 | * @param string $icon 309 | * 310 | * @return $this 311 | */ 312 | public function withIcon($icon) 313 | { 314 | $this->setIcon($icon); 315 | 316 | return $this; 317 | } 318 | 319 | /** 320 | * Add an attachment to the message. 321 | * 322 | * @param mixed $attachment 323 | * 324 | * @return $this 325 | * 326 | * @throws \InvalidArgumentException 327 | */ 328 | public function attach($attachment) 329 | { 330 | if ($attachment instanceof Attachment) { 331 | $this->attachments[] = $attachment; 332 | 333 | return $this; 334 | } elseif (is_array($attachment)) { 335 | $attachmentObject = new Attachment($attachment); 336 | 337 | if ( ! isset($attachment['mrkdwn_in'])) { 338 | $attachmentObject->setMarkdownFields($this->getMarkdownInAttachments()); 339 | } 340 | 341 | $this->attachments[] = $attachmentObject; 342 | 343 | return $this; 344 | } 345 | 346 | throw new InvalidArgumentException('Attachment must be an instance of Maknz\\Slack\\Attachment or a keyed array'); 347 | } 348 | 349 | /** 350 | * Get the attachments for the message. 351 | * 352 | * @return Attachment[] 353 | */ 354 | public function getAttachments() 355 | { 356 | return $this->attachments; 357 | } 358 | 359 | /** 360 | * Set the attachments for the message. 361 | * 362 | * @param array $attachments 363 | * 364 | * @return $this 365 | * 366 | * @throws \InvalidArgumentException 367 | */ 368 | public function setAttachments(array $attachments) 369 | { 370 | $this->clearAttachments(); 371 | 372 | foreach ($attachments as $attachment) { 373 | $this->attach($attachment); 374 | } 375 | 376 | return $this; 377 | } 378 | 379 | /** 380 | * Remove all attachments for the message. 381 | * 382 | * @return $this 383 | */ 384 | public function clearAttachments() 385 | { 386 | $this->attachments = []; 387 | 388 | return $this; 389 | } 390 | 391 | /** 392 | * Add a block to the message. 393 | * 394 | * @param mixed $block 395 | * 396 | * @return $this 397 | * 398 | * @throws \InvalidArgumentException 399 | */ 400 | public function withBlock($block) 401 | { 402 | if ($block instanceof Block) { 403 | $this->blocks[] = $block; 404 | 405 | return $this; 406 | } elseif (is_array($block)) { 407 | $blockObject = Block::factory($block); 408 | $this->blocks[] = $blockObject; 409 | 410 | return $this; 411 | } 412 | 413 | throw new InvalidArgumentException('Block must be an instance of Maknz\\Slack\\Block or a keyed array'); 414 | } 415 | 416 | /** 417 | * Get the blocks for the message. 418 | * 419 | * @return Block[] 420 | */ 421 | public function getBlocks() 422 | { 423 | return $this->blocks; 424 | } 425 | 426 | /** 427 | * Get the blocks for the message in array format. 428 | * 429 | * @return array 430 | */ 431 | public function getBlocksAsArrays() 432 | { 433 | $blocks = []; 434 | 435 | foreach ($this->getBlocks() as $block) { 436 | $blocks[] = $block->toArray(); 437 | } 438 | 439 | return $blocks; 440 | } 441 | 442 | /** 443 | * Set the blocks for the message. 444 | * 445 | * @param array $blocks 446 | * 447 | * @return $this 448 | * 449 | * @throws \InvalidArgumentException 450 | */ 451 | public function setBlocks(array $blocks) 452 | { 453 | $this->clearBlocks(); 454 | 455 | foreach ($blocks as $block) { 456 | $this->withBlock($block); 457 | } 458 | 459 | return $this; 460 | } 461 | 462 | /** 463 | * Remove all blocks for the message. 464 | * 465 | * @return $this 466 | */ 467 | public function clearBlocks() 468 | { 469 | $this->blocks = []; 470 | 471 | return $this; 472 | } 473 | } 474 | -------------------------------------------------------------------------------- /src/Object/CompositionObject.php: -------------------------------------------------------------------------------- 1 | 'title', 43 | 'text' => 'text', 44 | 'confirm' => 'confirm', 45 | 'deny' => 'deny', 46 | ]; 47 | 48 | /** 49 | * Get the confirmation title. 50 | * 51 | * @return \Maknz\Slack\BlockElement\Text 52 | */ 53 | public function getTitle() 54 | { 55 | return $this->title; 56 | } 57 | 58 | /** 59 | * Set the confirmation title. 60 | * 61 | * @param mixed $title 62 | * 63 | * @return $this 64 | * 65 | * @throws \InvalidArgumentException 66 | */ 67 | public function setTitle($title) 68 | { 69 | $this->title = Text::create($title, Text::TYPE_PLAIN); 70 | 71 | return $this; 72 | } 73 | 74 | /** 75 | * Get the confirmation explanatory text. 76 | * 77 | * @return \Maknz\Slack\BlockElement\Text 78 | */ 79 | public function getText() 80 | { 81 | return $this->text; 82 | } 83 | 84 | /** 85 | * Set the confirmation explanatory text. 86 | * 87 | * @param mixed $text 88 | * 89 | * @return $this 90 | * 91 | * @throws \InvalidArgumentException 92 | */ 93 | public function setText($text) 94 | { 95 | $this->text = Text::create($text); 96 | 97 | return $this; 98 | } 99 | 100 | /** 101 | * Get the text that confirms the action. 102 | * 103 | * @return \Maknz\Slack\BlockElement\Text 104 | */ 105 | public function getConfirm() 106 | { 107 | return $this->confirm; 108 | } 109 | 110 | /** 111 | * Set the text that confirms the action. 112 | * 113 | * @param mixed $confirm 114 | * 115 | * @return $this 116 | * 117 | * @throws \InvalidArgumentException 118 | */ 119 | public function setConfirm($confirm) 120 | { 121 | $this->confirm = Text::create($confirm, Text::TYPE_PLAIN); 122 | 123 | return $this; 124 | } 125 | 126 | /** 127 | * Get the text that denies the action. 128 | * 129 | * @return \Maknz\Slack\BlockElement\Text 130 | */ 131 | public function getDeny() 132 | { 133 | return $this->deny; 134 | } 135 | 136 | /** 137 | * Set the text that denies the action. 138 | * 139 | * @param mixed $deny 140 | * 141 | * @return $this 142 | * 143 | * @throws \InvalidArgumentException 144 | */ 145 | public function setDeny($deny) 146 | { 147 | $this->deny = Text::Create($deny, Text::TYPE_PLAIN); 148 | 149 | return $this; 150 | } 151 | 152 | /** 153 | * Convert the block to its array representation. 154 | * 155 | * @return array 156 | */ 157 | public function toArray() 158 | { 159 | $data = [ 160 | 'title' => $this->getTitle()->toArray(), 161 | 'text' => $this->getText()->toArray(), 162 | 'confirm' => $this->getConfirm()->toArray(), 163 | 'deny' => $this->getDeny()->toArray(), 164 | ]; 165 | 166 | return $data; 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /src/Object/Filter.php: -------------------------------------------------------------------------------- 1 | 'types', 36 | 'exclude_external_shared_channels' => 'exclude_shared_channels', 37 | 'exclude_bot_users' => 'exclude_bots', 38 | ]; 39 | 40 | /** 41 | * Get the types of conversations to be included. 42 | * 43 | * @return string[] 44 | */ 45 | public function getTypes() 46 | { 47 | return $this->types; 48 | } 49 | 50 | /** 51 | * Set the types of conversations to be included. 52 | * 53 | * @param string[] $text 54 | * 55 | * @return $this 56 | * 57 | * @throws \InvalidArgumentException 58 | */ 59 | public function setTypes(array $types) 60 | { 61 | $validTypes = ['im', 'mpim', 'private', 'public']; 62 | 63 | foreach ($types as $type) { 64 | if ( ! in_array($type, $validTypes)) { 65 | throw new InvalidArgumentException("Invalid filter include type '$type'; must be one of: ".implode(',', $validTypes)); 66 | } 67 | } 68 | 69 | $this->types = $types; 70 | 71 | return $this; 72 | } 73 | 74 | /** 75 | * Get whether shared channels from other organisations are excluded. 76 | * 77 | * @return bool 78 | */ 79 | public function areSharedChannelsExcluded() 80 | { 81 | return $this->exclude_shared_channels; 82 | } 83 | 84 | /** 85 | * Set whether shared channels from other organisations are excluded. 86 | * 87 | * @param bool $excludeSharedChannels 88 | * 89 | * @return $this 90 | */ 91 | public function setExcludeSharedChannels($excludeSharedChannels = true) 92 | { 93 | $this->exclude_shared_channels = (bool)$excludeSharedChannels; 94 | 95 | return $this; 96 | } 97 | 98 | /** 99 | * Get whether bots are excluded. 100 | * 101 | * @return bool 102 | */ 103 | public function areBotsExcluded() 104 | { 105 | return $this->exclude_bots; 106 | } 107 | 108 | /** 109 | * Set whether bots are excluded. 110 | * 111 | * @param bool $excludeBots 112 | * 113 | * @return $this 114 | */ 115 | public function setExcludeBots($excludeBots = true) 116 | { 117 | $this->exclude_bots = (bool)$excludeBots; 118 | 119 | return $this; 120 | } 121 | 122 | /** 123 | * Convert the block to its array representation. 124 | * 125 | * @return array 126 | */ 127 | public function toArray() 128 | { 129 | $data = [ 130 | 'include' => $this->getTypes(), 131 | 'exclude_external_shared_channels' => $this->areSharedChannelsExcluded(), 132 | 'exclude_bot_users' => $this->areBotsExcluded(), 133 | ]; 134 | 135 | return $data; 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/Object/Option.php: -------------------------------------------------------------------------------- 1 | 'text', 50 | 'value' => 'value', 51 | 'description' => 'description', 52 | 'url' => 'url', 53 | 'selected' => 'initially_selected', 54 | ]; 55 | 56 | /** 57 | * Get the option text. 58 | * 59 | * @return \Maknz\Slack\BlockElement\Text 60 | */ 61 | public function getText() 62 | { 63 | return $this->text; 64 | } 65 | 66 | /** 67 | * Set the option text. 68 | * 69 | * @param mixed $text 70 | * 71 | * @return $this 72 | * 73 | * @throws \InvalidArgumentException 74 | */ 75 | public function setText($text) 76 | { 77 | $this->text = Text::create($text, Text::TYPE_PLAIN); 78 | 79 | return $this; 80 | } 81 | 82 | /** 83 | * Get the option value. 84 | * 85 | * @return string 86 | */ 87 | public function getValue() 88 | { 89 | return $this->value; 90 | } 91 | 92 | /** 93 | * Set the option value. 94 | * 95 | * @param string $value 96 | * 97 | * @return $this 98 | */ 99 | public function setValue($value) 100 | { 101 | $this->value = $value; 102 | 103 | return $this; 104 | } 105 | 106 | /** 107 | * Get the option description. 108 | * 109 | * @return \Maknz\Slack\BlockElement\Text 110 | */ 111 | public function getDescription() 112 | { 113 | return $this->description; 114 | } 115 | 116 | /** 117 | * Set the option description. 118 | * 119 | * @param mixed $description 120 | * 121 | * @return $this 122 | * 123 | * @throws \InvalidArgumentException 124 | */ 125 | public function setDescription($description) 126 | { 127 | $this->description = Text::create($description, Text::TYPE_PLAIN); 128 | 129 | return $this; 130 | } 131 | 132 | /** 133 | * Get the option URL. 134 | * 135 | * @return string 136 | */ 137 | public function getUrl() 138 | { 139 | return $this->url; 140 | } 141 | 142 | /** 143 | * Set the option URL. 144 | * 145 | * @param string $url 146 | * 147 | * @return $this 148 | */ 149 | public function setUrl($url) 150 | { 151 | $this->url = $url; 152 | 153 | return $this; 154 | } 155 | 156 | /** 157 | * Get whether the option group has a selected option. 158 | * 159 | * @return bool 160 | */ 161 | public function isInitiallySelected() 162 | { 163 | return $this->initially_selected; 164 | } 165 | 166 | /** 167 | * Set whether the option group has a selected option. 168 | * 169 | * @param bool $selected 170 | * 171 | * @return $this 172 | */ 173 | public function setInitiallySelected($selected) 174 | { 175 | $this->initially_selected = (bool)$selected; 176 | 177 | return $this; 178 | } 179 | 180 | /** 181 | * Convert the block to its array representation. 182 | * 183 | * @return array 184 | */ 185 | public function toArray() 186 | { 187 | $data = [ 188 | 'text' => $this->getText()->toArray(), 189 | 'value' => $this->getValue(), 190 | ]; 191 | 192 | if ($this->getDescription()) { 193 | $data['description'] = $this->getDescription()->toArray(); 194 | } 195 | 196 | if ($this->getUrl()) { 197 | $data['url'] = $this->getUrl(); 198 | } 199 | 200 | return $data; 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /src/Object/OptionGroup.php: -------------------------------------------------------------------------------- 1 | 'label', 25 | 'options' => 'options', 26 | ]; 27 | 28 | /** 29 | * Get the option group label. 30 | * 31 | * @return \Maknz\Slack\BlockElement\Text 32 | */ 33 | public function getLabel() 34 | { 35 | return $this->label; 36 | } 37 | 38 | /** 39 | * Set the option group label. 40 | * 41 | * @param mixed $label 42 | * 43 | * @return $this 44 | * 45 | * @throws \InvalidArgumentException 46 | */ 47 | public function setLabel($label) 48 | { 49 | $this->label = Text::create($label, Text::TYPE_PLAIN); 50 | 51 | return $this; 52 | } 53 | 54 | /** 55 | * Get whether the option group has a selected option. 56 | * 57 | * @return bool 58 | */ 59 | public function hasSelectedOption() 60 | { 61 | foreach ($this->getOptions() as $option) { 62 | if ($option->isInitiallySelected()) { 63 | return true; 64 | } 65 | } 66 | 67 | return false; 68 | } 69 | 70 | /** 71 | * Convert the block to its array representation. 72 | * 73 | * @return array 74 | */ 75 | public function toArray() 76 | { 77 | $data = [ 78 | 'label' => $this->getLabel()->toArray(), 79 | 'options' => $this->getOptionsAsArrays(), 80 | ]; 81 | 82 | return $data; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/OptionsTrait.php: -------------------------------------------------------------------------------- 1 | options; 24 | } 25 | 26 | /** 27 | * Get options available within the block in array format. 28 | * 29 | * @return array 30 | */ 31 | public function getOptionsAsArrays() 32 | { 33 | $options = []; 34 | 35 | foreach ($this->getOptions() as $option) { 36 | $options[] = $option->toArray(); 37 | } 38 | 39 | return $options; 40 | } 41 | 42 | /** 43 | * Set options available within the block. 44 | * 45 | * @param array $options 46 | * 47 | * @return $this 48 | * 49 | * @throws \InvalidArgumentException 50 | */ 51 | public function setOptions(array $options) 52 | { 53 | $this->clearOptions(); 54 | 55 | foreach ($options as $option) { 56 | $this->addOption($option); 57 | } 58 | 59 | return $this; 60 | } 61 | 62 | /** 63 | * Clear options available within the block. 64 | * 65 | * @return $this 66 | */ 67 | public function clearOptions() 68 | { 69 | $this->options = []; 70 | 71 | return $this; 72 | } 73 | 74 | /** 75 | * Add an option to the block. 76 | * 77 | * @param mixed $option 78 | * 79 | * @return $this 80 | * 81 | * @throws \InvalidArgumentException 82 | */ 83 | public function addOption($option) 84 | { 85 | if (is_array($option)) { 86 | $option = new Option($option); 87 | } 88 | 89 | if ($option instanceof Option) { 90 | $this->options[] = $option; 91 | 92 | return $this; 93 | } 94 | 95 | throw new InvalidArgumentException('The option must be an instance of '.Option::class.' or a keyed array'); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/Payload.php: -------------------------------------------------------------------------------- 1 | fillProperties($attributes); 21 | } 22 | 23 | /** 24 | * @param array $attributes 25 | * 26 | * @return $this 27 | */ 28 | protected function fillProperties(array $attributes): self 29 | { 30 | foreach ($attributes as $attribute => $value) { 31 | $setter = self::getAttributeSetter($attribute); 32 | if ($setter !== null) { 33 | $this->$setter($value); 34 | } 35 | } 36 | 37 | return $this; 38 | } 39 | 40 | /** 41 | * Returns property setter method by given attribute name. 42 | * 43 | * @param string $attribute 44 | * 45 | * @return null|string 46 | */ 47 | private static function getAttributeSetter(string $attribute) 48 | { 49 | $property = self::getAttributeProperty($attribute); 50 | 51 | return $property !== null ? self::propertyToSetter($property) : null; 52 | } 53 | 54 | /** 55 | * Returns property name by given attribute name. 56 | * 57 | * @param string $attribute 58 | * 59 | * @return string|null 60 | */ 61 | private static function getAttributeProperty(string $attribute) 62 | { 63 | return static::$availableAttributes[$attribute] ?? null; 64 | } 65 | 66 | /** 67 | * Converts property name to setter method name. 68 | * 69 | * @param string $property 70 | * 71 | * @return string 72 | */ 73 | private static function propertyToSetter(string $property): string 74 | { 75 | $property = str_replace('_', ' ', $property); 76 | $property = ucwords($property); 77 | $property = str_replace(' ', '', $property); 78 | 79 | return 'set'.$property; 80 | } 81 | 82 | /** 83 | * Convert this payload to its array representation. 84 | * 85 | * @return array 86 | */ 87 | abstract public function toArray(); 88 | } 89 | -------------------------------------------------------------------------------- /src/PlaceholderTrait.php: -------------------------------------------------------------------------------- 1 | placeholder; 23 | } 24 | 25 | /** 26 | * Set the placeholder. 27 | * 28 | * @param mixed $placeholder 29 | * 30 | * @return $this 31 | * 32 | * @throws \InvalidArgumentException 33 | */ 34 | public function setPlaceholder($placeholder) 35 | { 36 | $this->placeholder = Text::create($placeholder, Text::TYPE_PLAIN); 37 | 38 | return $this; 39 | } 40 | } 41 | --------------------------------------------------------------------------------