Overview
  • Namespace
  • Class

Namespaces

  • Slack
    • Message

Classes

  • Slack\ApiClient
  • Slack\Bot
  • Slack\Channel
  • Slack\ClientObject
  • Slack\DataObject
  • Slack\DirectMessageChannel
  • Slack\Group
  • Slack\Message\Attachment
  • Slack\Message\AttachmentBuilder
  • Slack\Message\AttachmentField
  • Slack\Message\Message
  • Slack\Message\MessageBuilder
  • Slack\Payload
  • Slack\RealTimeClient
  • Slack\Team
  • Slack\User

Interfaces

  • Slack\ChannelInterface
  • Slack\Exception

Exceptions

  • Slack\ApiException
  • Slack\ConnectionException
  • Slack\UserNotFoundException
  1 <?php
  2 namespace Slack;
  3 
  4 use GuzzleHttp;
  5 use Psr\Http\Message\ResponseInterface;
  6 use React\EventLoop\LoopInterface;
  7 use React\Promise\Deferred;
  8 use Slack\Message\Message;
  9 use Slack\Message\MessageBuilder;
 10 
 11 /**
 12  * A client for connecting to the Slack Web API and calling remote API methods.
 13  */
 14 class ApiClient
 15 {
 16     /**
 17      * The base URL for API requests.
 18      */
 19     const BASE_URL = 'https://slack.com/api/';
 20 
 21     /**
 22      * @var string The Slack API token string.
 23      */
 24     protected $token;
 25 
 26     /**
 27      * @var GuzzleHttp\ClientInterface A Guzzle HTTP client.
 28      */
 29     protected $httpClient;
 30 
 31     /**
 32      * @var LoopInterface An event loop instance.
 33      */
 34     protected $loop;
 35 
 36     /**
 37      * Creates a new API client instance.
 38      *
 39      * @param GuzzleHttp\ClientInterface $httpClient A Guzzle client instance to
 40      *                                               send requests with.
 41      */
 42     public function __construct(LoopInterface $loop, GuzzleHttp\ClientInterface $httpClient = null)
 43     {
 44         $this->loop = $loop;
 45         $this->httpClient = $httpClient ?: new GuzzleHttp\Client();
 46     }
 47 
 48     /**
 49      * Sets the Slack API token to be used during method calls.
 50      *
 51      * @param string $token The API token string.
 52      */
 53     public function setToken($token)
 54     {
 55         $this->token = $token;
 56     }
 57 
 58     /**
 59      * Gets a message builder for creating a new message object.
 60      *
 61      * @return \Slack\Message\MessageBuilder
 62      */
 63     public function getMessageBuilder()
 64     {
 65         return new MessageBuilder($this);
 66     }
 67 
 68     /**
 69      * Gets the currently authenticated user.
 70      *
 71      * @return \React\Promise\PromiseInterface A promise for the currently authenticated user.
 72      */
 73     public function getAuthedUser()
 74     {
 75         return $this->apiCall('auth.test')->then(function (Payload $response) {
 76             return $this->getUserById($response['user_id']);
 77         });
 78     }
 79 
 80     /**
 81      * Gets information about the current Slack team logged in to.
 82      *
 83      * @return \React\Promise\PromiseInterface A promise for the current Slack team.
 84      */
 85     public function getTeam()
 86     {
 87         return $this->apiCall('team.info')->then(function (Payload $response) {
 88             return new Team($this, $response['team']);
 89         });
 90     }
 91 
 92     /**
 93      * Gets a channel, group, or DM channel by ID.
 94      *
 95      * @param string $id The channel ID.
 96      *
 97      * @return \React\Promise\PromiseInterface A promise for a channel interface.
 98      */
 99     public function getChannelGroupOrDMByID($id)
100     {
101         if ($id[0] === 'D') {
102             return $this->getDMById($id);
103         }
104 
105         if ($id[0] === 'G') {
106             return $this->getGroupById($id);
107         }
108 
109         return $this->getChannelById($id);
110     }
111 
112     /**
113      * Gets all channels in the team.
114      *
115      * @return \React\Promise\PromiseInterface
116      */
117     public function getChannels()
118     {
119         return $this->apiCall('channels.list')->then(function ($response) {
120             $channels = [];
121             foreach ($response['channels'] as $channel) {
122                 $channels[] = new Channel($this, $channel);
123             }
124             return $channels;
125         });
126     }
127 
128     /**
129      * Gets a channel by its ID.
130      *
131      * @param string $id A channel ID.
132      *
133      * @return \React\Promise\PromiseInterface A promise for a channel object.
134      */
135     public function getChannelById($id)
136     {
137         return $this->apiCall('channels.info', [
138             'channel' => $id,
139         ])->then(function (Payload $response) {
140             return new Channel($this, $response['channel']);
141         });
142     }
143 
144     /**
145      * Gets a channel by its name.
146      *
147      * @param string $name The name of the channel.
148      *
149      * @return \React\Promise\PromiseInterface
150      */
151     public function getChannelByName($name)
152     {
153         return $this->getChannels()->then(function (array $channels) use ($name) {
154             foreach ($channels as $channel) {
155                 if ($channel->getName() === $name) {
156                     return $channel;
157                 }
158             }
159 
160             throw new ApiException('Channel ' . $name . ' not found.');
161         });
162     }
163 
164     /**
165      * Gets all groups the authenticated user is a member of.
166      *
167      * @return \React\Promise\PromiseInterface
168      */
169     public function getGroups()
170     {
171         return $this->apiCall('groups.list')->then(function ($response) {
172             $groups = [];
173             foreach ($response['groups'] as $group) {
174                 $groups[] = new Group($this, $group);
175             }
176             return $groups;
177         });
178     }
179 
180     /**
181      * Gets a group by its ID.
182      *
183      * @param string $id A group ID.
184      *
185      * @return \React\Promise\PromiseInterface A promise for a group object.
186      */
187     public function getGroupById($id)
188     {
189         return $this->apiCall('groups.info', [
190             'channel' => $id,
191         ])->then(function (Payload $response) {
192             return new Group($this, $response['group']);
193         });
194     }
195 
196     /**
197      * Gets a group by its name.
198      *
199      * @param string $name The name of the group.
200      *
201      * @return \React\Promise\PromiseInterface
202      */
203     public function getGroupByName($name)
204     {
205         return $this->getGroups()->then(function (array $groups) use ($name) {
206             foreach ($groups as $group) {
207                 if ($group->getName() === $name) {
208                     return $group;
209                 }
210             }
211 
212             throw new ApiException('Group ' . $name . ' not found.');
213         });
214     }
215 
216     /**
217      * Gets all DMs the authenticated user has.
218      *
219      * @return \React\Promise\PromiseInterface
220      */
221     public function getDMs()
222     {
223         return $this->apiCall('im.list')->then(function ($response) {
224             $dms = [];
225             foreach ($response['ims'] as $dm) {
226                 $dms[] = new DirectMessageChannel($this, $dm);
227             }
228             return $dms;
229         });
230     }
231 
232     /**
233      * Gets a direct message channel by its ID.
234      *
235      * @param string $id A DM channel ID.
236      *
237      * @return \React\Promise\PromiseInterface A promise for a DM object.
238      */
239     public function getDMById($id)
240     {
241         return $this->getDMs()->then(function (array $dms) use ($id) {
242             foreach ($dms as $dm) {
243                 if ($dm->getId() === $id) {
244                     return $dm;
245                 }
246             }
247 
248             throw new ApiException('DM ' . $id . ' not found.');
249         });
250     }
251 
252     /**
253      * Gets a direct message channel for a given user.
254      *
255      * @param User $user The user to get a DM for.
256      *
257      * @return \React\Promise\PromiseInterface A promise for a DM object.
258      */
259     public function getDMByUser(User $user)
260     {
261         return $this->getDMByUserId($user->getId());
262     }
263 
264     /**
265      * Gets a direct message channel by user's ID.
266      *
267      * @param string $id A user ID.
268      *
269      * @return \React\Promise\PromiseInterface A promise for a DM object.
270      */
271     public function getDMByUserId($id)
272     {
273         return $this->apiCall('im.open', [
274             'user' => $id,
275         ])->then(function (Payload $response) {
276             return $this->getDMById($response['channel']['id']);
277         });
278     }
279 
280     /**
281      * Gets all users in the Slack team.
282      *
283      * @return \React\Promise\PromiseInterface A promise for an array of users.
284      */
285     public function getUsers()
286     {
287         // get the user list
288         return $this->apiCall('users.list')->then(function (Payload $response) {
289             $users = [];
290             foreach ($response['members'] as $member) {
291                 $users[] = new User($this, $member);
292             }
293             return $users;
294         });
295     }
296 
297     /**
298      * Gets a user by its ID.
299      *
300      * @param string $id A user ID.
301      *
302      * @return \React\Promise\PromiseInterface A promise for a user object.
303      */
304     public function getUserById($id)
305     {
306         return $this->apiCall('users.info', [
307             'user' => $id,
308         ])->then(function (Payload $response) {
309             return new User($this, $response['user']);
310         });
311     }
312 
313     /**
314      * Gets a user by username.
315      *
316      * If the user could not be found, the returned promise is rejected with a
317      * `UserNotFoundException` exception.
318      *
319      * @return \React\Promise\PromiseInterface A promise for a user object.
320      */
321     public function getUserByName($username)
322     {
323         return $this->getUsers()->then(function (array $users) use ($username) {
324             foreach ($users as $user) {
325                 if ($user->getUsername() === $username) {
326                     return $user;
327                 }
328             }
329 
330             throw new UserNotFoundException("The user \"$username\" does not exist.");
331         });
332     }
333 
334     /**
335      * Sends a regular text message to a given channel.
336      *
337      * @param  string                          $text    The message text.
338      * @param  ChannelInterface                $channel The channel to send the message to.
339      * @return \React\Promise\PromiseInterface
340      */
341     public function send($text, ChannelInterface $channel)
342     {
343         $message = $this->getMessageBuilder()
344                         ->setText($text)
345                         ->setChannel($channel)
346                         ->create();
347 
348         return $this->postMessage($message);
349     }
350 
351     /**
352      * Posts a message.
353      *
354      * @param \Slack\Message\Message $message The message to post.
355      *
356      * @return \React\Promise\PromiseInterface
357      */
358     public function postMessage(Message $message)
359     {
360         $options = [
361             'text' => $message->getText(),
362             'channel' => $message->data['channel'],
363             'as_user' => true,
364         ];
365 
366         if ($message->hasAttachments()) {
367             $options['attachments'] = json_encode($message->getAttachments());
368         }
369 
370         return $this->apiCall('chat.postMessage', $options);
371     }
372 
373     /**
374      * Sends an API request.
375      *
376      * @param string $method The API method to call.
377      * @param array  $args   An associative array of arguments to pass to the
378      *                       method call.
379      *
380      * @return \React\Promise\PromiseInterface A promise for an API response.
381      */
382     public function apiCall($method, array $args = [])
383     {
384         // create the request url
385         $requestUrl = self::BASE_URL . $method;
386 
387         // set the api token
388         $args['token'] = $this->token;
389 
390         // send a post request with all arguments
391         $promise = $this->httpClient->postAsync($requestUrl, [
392             'form_params' => $args,
393         ]);
394 
395         // Add requests to the event loop to be handled at a later date.
396         $this->loop->futureTick(function () use ($promise) {
397             $promise->wait();
398         });
399 
400         // When the response has arrived, parse it and resolve. Note that our
401         // promises aren't pretty; Guzzle promises are not compatible with React
402         // promises, so the only Guzzle promises ever used die in here and it is
403         // React from here on out.
404         $deferred = new Deferred();
405         $promise->then(function (ResponseInterface $response) use ($deferred) {
406             // get the response as a json object
407             $payload = Payload::fromJson((string) $response->getBody());
408 
409             // check if there was an error
410             if (isset($payload['ok']) && $payload['ok'] === true) {
411                 $deferred->resolve($payload);
412             } else {
413                 // make a nice-looking error message and throw an exception
414                 $niceMessage = ucfirst(str_replace('_', ' ', $payload['error']));
415                 $deferred->reject(new ApiException($niceMessage));
416             }
417         });
418 
419         return $deferred->promise();
420     }
421 }
422 
API documentation generated by ApiGen