Skip to content
41 changes: 39 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,25 @@ composer require nexylan/slack php-http/guzzle6-adapter

Why `php-http/guzzle6-adapter`? We are decoupled from any HTTP messaging client thanks to [HTTPlug](http://httplug.io/).

Then [create an incoming webhook](https://my.slack.com/services/new/incoming-webhook) on your Slack account for the package to use.
You'll need the webhook URL to instantiate the client (or for the configuration file if using Laravel).
Then [create an app](https://api.slack.com/slack-apps) on your Slack account for the package to use.
You'll need to need to enable the [chat:write:bot](https://api.slack.com/scopes/chat:write:bot) [scope](https://api.slack.com/docs/oauth-scopes) for your app and get the "OAuth Access Token".

## Basic Usage

### Instantiate the client

Using Slack's [OAuth token](https://api.slack.com/docs/oauth) method:

```php
$client = (new Nexy\Slack\Client())
->setOptions([
'username' => 'Cyril',
'oauth_token' => 'xoxp-3845764387563....'
]);
```

To use Slack's deprecated Webhook functionality:

```php
// Instantiate without defaults
$client = new Nexy\Slack\Client('https://hooks.slack.com/...');
Expand Down Expand Up @@ -231,6 +243,31 @@ $attachment = new Attachment();
$attachment->setFields($bigArrayOfFields);
```

### Blocks

Slack has deprecated message attachments in favour of Blocks. Blocks give you a lot more control over the layout of your message and allow you to create interactive messages like this.

![Interactive Slack message](doc/interactive-message.png?raw=true "EcomHQ")

You can read about it in the [Slack Messaging Reference](https://api.slack.com/reference/messaging/block-elements).

An example of sending a message with Blocks:

```php
$message = $this->slackClient->createMessage()
->setText('This is the fallback text')
->addBlock
(
(new SectionBlock())
->setMarkdown(':smiley: Hi! :wave:')
)
->addBlock
(
(new ButtonBlock())
->setPlainText('Wave back?')
);
```

## Contributing

If you're having problems, spot a bug, or have a feature suggestion, please log and issue on Github. If you'd like to have a crack yourself, fork the package and make a pull request. Please include tests for any added or changed functionality. If it's a bug, include a regression test.
Binary file added doc/interactive-message.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 26 additions & 0 deletions src/ActionsBlock.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Nexylan packages.
*
* (c) Nexylan SAS <contact@nexylan.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Nexy\Slack;

/**
* @author Sullivan Senechal <soullivaneuh@gmail.com>
* @author Mikey McLellan <mikey@mclellan.org.nz>
*/
final class ActionsBlock extends ElementsBlock
{
public function __construct()
{
parent::__construct('actions');
}
}
99 changes: 99 additions & 0 deletions src/Block.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Nexylan packages.
*
* (c) Nexylan SAS <contact@nexylan.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Nexy\Slack;

/**
* @author Sullivan Senechal <soullivaneuh@gmail.com>
* @author Mikey McLellan <mikey@mclellan.org.nz>
*/
class Block
{
/**
* @var string
*/
protected $type;

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

public function __construct(?string $type)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing PHPDoc

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not necessary, the strict typing is enough.

Except if you want to add detail about $type description.

{
$this->setType($type);
}

/**
* @return string
*/
public function getType(): string
{
return $this->type;
}

/**
* @param string $type
*
* @return $this
*/
public function setType(string $type): self
{
$this->type = $type;

return $this;
}

/**
* Convert this block to its array representation.
*
* @return array
*/
public function toArray(): array
{
$data = [
'type' => $this->type,
'block_id' => $this->blockId
];

return $this->removeNulls($data);
}

/**
* @param string $blockId
*/
public function setBlockId(string $blockId): self
{
$this->blockId = $blockId;

return $this;
}

/**
* @return string
*/
public function getBlockId(): string
{
return $this->blockId;
}

protected function removeNulls(array $data): array
{
foreach($data as $k => $v) {
if ($v === null || (is_array($v) && count($v) === 0)) {
unset($data[$k]);
}
}
return $data;
}
}
135 changes: 135 additions & 0 deletions src/ButtonBlock.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
<?php

declare(strict_types=1);

/*
* This file is part of the Nexylan packages.
*
* (c) Nexylan SAS <contact@nexylan.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Nexy\Slack;

/**
* @author Sullivan Senechal <soullivaneuh@gmail.com>
* @author Mikey McLellan <mikey@mclellan.org.nz>
*/
final class ButtonBlock extends SectionBlock
{
const STYLE_PRIMARY = 'primary';
const STYLE_DANGER = 'danger';

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

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

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

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

public function __construct()
{
parent::__construct('button');
}

/**
* @return string
*/
public function getUrl(): string
{
return $this->url;
}

/**
* @param string $url
*/
public function setUrl(string $url): self
{
$this->url = $url;

return $this;
}

/**
* @return string
*/
public function getValue(): string
{
return $this->value;
}

/**
* @param string $value
*/
public function setValue(string $value): self
{
$this->value = $value;

return $this;
}

/**
* @param string $actionId
*/
public function setActionId(string $actionId): self
{
$this->actionId = $actionId;

return $this;
}

/**
* @return string
*/
public function getActionId(): string
{
return $this->actionId;
}

/**
* @return string
*/
public function getStyle(): string
{
return $this->style;
}

/**
* @param string $style
*/
public function setStyle(string $style): self
{
$this->style = $style;

return $this;
}

public function setMarkdown(string $string): SectionBlock
{
throw new \InvalidArgumentException('ButtonBlock must use plain_text');
}

/**
* Convert this block to its array representation.
*
* @return array
*/
public function toArray(): array
{
$data = [
'url' => $this->url,
'value' => $this->value,
'action_id' => $this->actionId,
'style' => $this->style
];

return array_merge(parent::toArray(), $this->removeNulls($data));
}
}
Loading