markenwerk/php-slack-client

View on GitHub
src/SlackClient.php

Summary

Maintainability
D
2 days
Test Coverage
<?php

namespace Markenwerk\SlackClient;

use Markenwerk\BasicHttpClient\Request\Message\Body\Body;
use Markenwerk\BasicHttpClient\Request\Message\Header\Header;
use Markenwerk\BasicHttpClient\Request\Message\Message;
use Markenwerk\BasicHttpClient\Request\Request;
use Markenwerk\BasicHttpClient\Request\Transport\HttpsTransport;
use Markenwerk\CommonException\ApiException\UnexpectedResponseException;
use Markenwerk\CommonException\NetworkException\ConnectionTimeoutException;
use Markenwerk\CommonException\NetworkException\CurlException;
use Markenwerk\CommonException\ParserException\StringifyException;
use Markenwerk\UrlUtil\Url;

/**
 * Class SlackClient
 *
 * @package Markenwerk\SlackClient
 */
class SlackClient
{

    /**
     * @var string
     */
    private $subdomainName;

    /**
     * @var string
     */
    private $token;

    /**
     * @var string
     */
    private $username = 'PHP Slack Client';

    /**
     * @return string
     */
    public function getSubdomainName()
    {
        return $this->subdomainName;
    }

    /**
     * @param string $subdomainName
     * @return $this
     */
    public function setSubdomainName($subdomainName)
    {
        if (!is_string($subdomainName)) {
            $argumentType = (is_object($subdomainName)) ? get_class($subdomainName) : gettype($subdomainName);
            throw new \InvalidArgumentException('Expected the subdomain name as string. Got ' . $argumentType);
        }
        $this->subdomainName = $subdomainName;
        return $this;
    }

    /**
     * @return string
     */
    public function getToken()
    {
        return $this->token;
    }

    /**
     * @param string $token
     * @return $this
     */
    public function setToken($token)
    {
        if (!is_string($token)) {
            $argumentType = (is_object($token)) ? get_class($token) : gettype($token);
            throw new \InvalidArgumentException('Expected the token as string. Got ' . $argumentType);
        }
        $this->token = $token;
        return $this;
    }

    /**
     * @return string
     */
    public function getUsername()
    {
        return $this->username;
    }

    /**
     * @param string $username
     * @return $this
     */
    public function setUsername($username)
    {
        if (!is_string($username)) {
            $argumentType = (is_object($username)) ? get_class($username) : gettype($username);
            throw new \InvalidArgumentException('Expected the username as string. Got ' . $argumentType);
        }
        $this->username = $username;
        return $this;
    }

    /**
     * @param string $channel
     * @param SlackMessageInterface $slackMessage
     * @return $this
     * @throws StringifyException
     * @throws UnexpectedResponseException
     * @throws ConnectionTimeoutException
     * @throws CurlException
     */
    public function postToChannel($channel, SlackMessageInterface $slackMessage)
    {
        if (!is_string($channel)) {
            $argumentType = (is_object($channel)) ? get_class($channel) : gettype($channel);
            throw new \InvalidArgumentException('Expected the channel name as string. Got ' . $argumentType);
        }
        if (mb_substr($channel, 0, 1) != '#') {
            throw new \InvalidArgumentException('The channel name is invalid. It has to start with "#".');
        }
        $payload = $this->buildPayload($channel, $slackMessage);
        $endpoint = $this->buildEndpoint();
        $this->performRequest($endpoint, $payload);
        return $this;
    }

    /**
     * @param string $member
     * @param SlackMessageInterface $slackMessage
     * @return $this
     * @throws StringifyException
     * @throws UnexpectedResponseException
     * @throws ConnectionTimeoutException
     * @throws CurlException
     */
    public function postToMember($member, SlackMessageInterface $slackMessage)
    {
        if (!is_string($member)) {
            $argumentType = (is_object($member)) ? get_class($member) : gettype($member);
            throw new \InvalidArgumentException('Expected the channel name as string. Got ' . $argumentType);
        }
        if (mb_substr($member, 0, 1) != '@') {
            throw new \InvalidArgumentException('The mamber name is invalid. It has to start with "@".');
        }
        $payload = $this->buildPayload($member, $slackMessage);
        $endpoint = $this->buildEndpoint();
        $this->performRequest($endpoint, $payload);
        return $this;
    }

    /**
     * @param string $receiver
     * @param SlackMessageInterface $slackMessage
     * @return array
     */
    protected function buildPayload($receiver, SlackMessageInterface $slackMessage)
    {
        $payload = array(
            'channel' => $receiver,
            'username' => $this->getUsername(),
            'text' => $slackMessage->getText(),
            'unfurl_links' => $slackMessage->getUnfurlLinks(),
            'unfurl_media' => $slackMessage->getUnfurlMedia(),
        );
        if (!is_null($slackMessage->getIconUrl())) {
            $payload['icon_url'] = $slackMessage->getIconUrl();
        }
        if ($slackMessage->hasAttachments()) {
            foreach ($slackMessage->getAttachments() as $attachment) {
                if (!isset($payload['attachments'])) {
                    $payload['attachments'] = array();
                }
                $payload['attachments'][] = $attachment->toArray();
            }
        }
        return $payload;
    }

    /**
     * @return string
     */
    protected function buildEndpoint()
    {
        return 'https://' . $this->getSubdomainName() . '.slack.com/services/hooks/incoming-webhook?token='
        . $this->getToken();
    }

    /**
     * @param $endpoint
     * @param array $payload
     * @throws StringifyException
     * @throws UnexpectedResponseException
     * @throws ConnectionTimeoutException
     * @throws CurlException
     */
    protected function performRequest($endpoint, array $payload)
    {
        $requestBody = json_encode($payload);
        if ($requestBody === false) {
            throw new StringifyException('Building payload failed.');
        }
        $message = new Message();
        $message
            ->addHeader(new Header('Content-Type', array('application/json')))
            ->addHeader(new Header('Accept', array('application/json')))
            ->setBody(new Body($requestBody));
        $request = new Request();
        $response = $request
            ->setTransport(new HttpsTransport())
            ->setUrl(new Url($endpoint))
            ->setMethod(Request::REQUEST_METHOD_POST)
            ->setMessage($message)
            ->perform()
            ->getResponse();
        if ($response->getStatusCode() < 200 || $response->getStatusCode() >= 300) {
            throw new UnexpectedResponseException(
                'Slack API responded unexpected with HTTP status "' . (string)$response->getStatusText() . '"'
                . ' and message "' . $response->getBody() . '"'
            );
        }
    }

}