1<?php declare(strict_types=1); 2 3/* 4 * This file is part of the Monolog package. 5 * 6 * (c) Jordi Boggiano <j.boggiano@seld.be> 7 * 8 * For the full copyright and license information, please view the LICENSE 9 * file that was distributed with this source code. 10 */ 11 12namespace Monolog\Handler; 13 14use Monolog\Logger; 15use Monolog\Utils; 16use Monolog\Formatter\FlowdockFormatter; 17use Monolog\Formatter\FormatterInterface; 18 19/** 20 * Sends notifications through the Flowdock push API 21 * 22 * This must be configured with a FlowdockFormatter instance via setFormatter() 23 * 24 * Notes: 25 * API token - Flowdock API token 26 * 27 * @author Dominik Liebler <liebler.dominik@gmail.com> 28 * @see https://www.flowdock.com/api/push 29 * 30 * @phpstan-import-type FormattedRecord from AbstractProcessingHandler 31 */ 32class FlowdockHandler extends SocketHandler 33{ 34 /** 35 * @var string 36 */ 37 protected $apiToken; 38 39 /** 40 * @throws MissingExtensionException if OpenSSL is missing 41 */ 42 public function __construct( 43 string $apiToken, 44 $level = Logger::DEBUG, 45 bool $bubble = true, 46 bool $persistent = false, 47 float $timeout = 0.0, 48 float $writingTimeout = 10.0, 49 ?float $connectionTimeout = null, 50 ?int $chunkSize = null 51 ) { 52 if (!extension_loaded('openssl')) { 53 throw new MissingExtensionException('The OpenSSL PHP extension is required to use the FlowdockHandler'); 54 } 55 56 parent::__construct( 57 'ssl://api.flowdock.com:443', 58 $level, 59 $bubble, 60 $persistent, 61 $timeout, 62 $writingTimeout, 63 $connectionTimeout, 64 $chunkSize 65 ); 66 $this->apiToken = $apiToken; 67 } 68 69 /** 70 * {@inheritDoc} 71 */ 72 public function setFormatter(FormatterInterface $formatter): HandlerInterface 73 { 74 if (!$formatter instanceof FlowdockFormatter) { 75 throw new \InvalidArgumentException('The FlowdockHandler requires an instance of Monolog\Formatter\FlowdockFormatter to function correctly'); 76 } 77 78 return parent::setFormatter($formatter); 79 } 80 81 /** 82 * Gets the default formatter. 83 */ 84 protected function getDefaultFormatter(): FormatterInterface 85 { 86 throw new \InvalidArgumentException('The FlowdockHandler must be configured (via setFormatter) with an instance of Monolog\Formatter\FlowdockFormatter to function correctly'); 87 } 88 89 /** 90 * {@inheritDoc} 91 */ 92 protected function write(array $record): void 93 { 94 parent::write($record); 95 96 $this->closeSocket(); 97 } 98 99 /** 100 * {@inheritDoc} 101 */ 102 protected function generateDataStream(array $record): string 103 { 104 $content = $this->buildContent($record); 105 106 return $this->buildHeader($content) . $content; 107 } 108 109 /** 110 * Builds the body of API call 111 * 112 * @phpstan-param FormattedRecord $record 113 */ 114 private function buildContent(array $record): string 115 { 116 return Utils::jsonEncode($record['formatted']['flowdock']); 117 } 118 119 /** 120 * Builds the header of the API Call 121 */ 122 private function buildHeader(string $content): string 123 { 124 $header = "POST /v1/messages/team_inbox/" . $this->apiToken . " HTTP/1.1\r\n"; 125 $header .= "Host: api.flowdock.com\r\n"; 126 $header .= "Content-Type: application/json\r\n"; 127 $header .= "Content-Length: " . strlen($content) . "\r\n"; 128 $header .= "\r\n"; 129 130 return $header; 131 } 132} 133