6 API
, Exception\InvalidArgumentException
, Exception\UnexpectedValueException
12 final class ContentType
18 static private $version = 3;
21 * Content type handler map
24 static private $types = [
25 "json" => "self::fromJson",
26 "base64" => "self::fromBase64",
27 "sha" => "self::fromData",
28 "raw" => "self::fromData",
29 "html" => "self::fromData",
30 "diff" => "self::fromData",
31 "patch" => "self::fromData",
32 "text/plain"=> "self::fromData",
33 "application/octet-stream" => "self::fromStream",
37 * Content type abbreviation
43 * Register a content type handler
44 * @param string $type The content type (abbreviation)
45 * @param callable $handler The handler as function(Body $body):mixed;
47 static function register(string $type, callable
$handler) {
48 self
::$types[$type] = $handler;
52 * Check whether a handler is registered for a particular content type
53 * @param string $type The (abbreviated) content type
56 static function registered(string $type) : bool {
57 return isset(self
::$types[$type]);
61 * Unregister a content type handler
64 static function unregister(string $type) {
65 unset(self
::$types[$type]);
69 * Get/set the API version to use
70 * @param int $v if not null, update the API version
71 * @return int the previously set version
73 static function version(int $v = null) : int {
74 $api = self
::$version;
86 static function apply(API
$api, string $type) : API
{
87 $part = "[^()<>@,;:\\\"\/\[\]?.=[:space:][:cntrl:]]+";
88 if (preg_match("/^$part\/$part\$/", $type)) {
89 $that = $api->withHeader("Accept", $type);
91 switch (substr($type, 0, 1)) {
100 $vapi = static::version();
101 $that = $api->withHeader("Accept", "application/vnd.github.v$vapi$type");
109 * @throws UnexpectedValueException
111 private static function fromJson(Body
$json) {
112 $decoded = json_decode($json);
113 if (!isset($decoded) && json_last_error()) {
114 throw new UnexpectedValueException("Could not decode JSON: ".
115 json_last_error_msg());
121 * @param Body $base64
123 * @throws UnexpectedValueException
125 private static function fromBase64(Body
$base64) : string {
126 if (false === ($decoded = base64_decode($base64, true))) {
127 throw new UnexpectedValueException("Could not decode BASE64");
134 * @param Body $stream
135 * @return resource stream
137 private static function fromStream(Body
$stream) {
138 return $stream->getResource();
145 private static function fromData(Body
$data) : string {
146 return (string) $data;
150 * @param Header $contentType
151 * @throws InvalidArgumentException
153 function __construct(Header
$contentType) {
154 if (strcasecmp($contentType->name
, "Content-Type")) {
155 throw new InvalidArgumentException(
156 "Expected Content-Type header, got ". $contentType->name
);
158 $vapi = static::version();
159 $this->type
= preg_replace("/
160 (?:application\/(?:vnd\.github(?:\.v$vapi)?)?)
163 | (?:\.[^.+]+)?\+? (json)
164 )/x", "\\1", current(array_keys($contentType->getParams()->params
)));
168 * Get the (abbreviated) content type name
171 function getType() : string {
176 * Parse a response message's body according to its content type
179 * @throws UnexpectedValueException
181 function parseBody(Body
$data) {
182 $type = $this->getType();
183 if (static::registered($type)) {
184 return call_user_func(self
::$types[$type], $data, $type);
186 throw new UnexpectedValueException("Unhandled content type '$type'");