mindtouch / mindtouch-http
用于与 MindTouch REST API 交互的 PHP 库
3.1.3
2021-04-08 20:31 UTC
Requires
- php: ^7.2.0
- ext-curl: *
- ext-fileinfo: *
- ext-json: *
- modethirteen/hyperplug: ^1.1.3
- modethirteen/type-ex: ^1.0.0
- modethirteen/xarray: ^1.2.2
Requires (Dev)
- phpstan/phpstan: ~0.12.0
- phpunit/phpunit: ~7.4.3
This package is auto-updated.
Last update: 2024-09-26 19:06:44 UTC
README
一个用于与 MindTouch API 交互的 PHP 库。
支持
此库由开源社区提供和支持。受支持的 MindTouch 网站所有者可以通过 GitHub 提交错误报告,但支持计划不包括此库的使用。
要求
- PHP 5.5, 5.6 (1.x)
- PHP 7.2, 7.3, 7.4 (main, 2.x, 3.x)
安装
使用 Composer。有两种方法可以将此库添加到您的项目中。
从 composer CLI
./composer.phar require mindtouch/mindtouch-http
或将 mindtouch/mindtouch-http 添加到您项目的 composer.json 中
{ "require": { "mindtouch/mindtouch-http": "dev-main" } }
dev-main
是主要开发分支。如果您在生产环境中使用此库,建议您使用稳定版本。
假设您已设置 Composer 的自动加载器,该库位于 MindTouch\Http\
命名空间。
入门
快速示例
$plug = new ApiPlug(XUri::newFromString('https://mindtouch.example.com/@api/deki')); $result = $plug->at('pages', 'home', 'contents')->get(); if($result->isSuccess()) { // great job! echo $result->getVal('body/contents'); }
常见场景
访问页面和内容
$plug = new ApiPlug(XUri::newFromString('https://mindtouch.example.com/@api/deki')); $pagesPlug = $plug->at('pages')->with('include', 'contents'); // request page id 7239 with contents $result = $pagesPlug->at('7239')->get(); // extract page content body $content = $result->getVal('body/page/contents/body');
列出所有标签
$plug = new ApiPlug(XUri::newFromString('https://mindtouch.example.com/@api/deki')); // request all site tags $result = $plug->at('site', 'tags')->get(); // extract tags $tags = $result->getAll('body/tags/tag');
列出带有标签的页面
$plug = new ApiPlug(XUri::newFromString('https://mindtouch.example.com/@api/deki')); $tagsPlug = $plug->at('site', 'tags'); // request all pages that are tagged "access" $result = $plug->at('=access')->get(); // extract pages $pages = $result->getAll('body/tag/page');
列出页面子页面
$plug = new ApiPlug(XUri::newFromString('https://mindtouch.example.com/@api/deki')); $pagesPlug = $plug->at('pages'); // request all immediate subpages of page id 7795 $result = $pagesPlug->at('7795', 'subpages')->get(); // extract subpages $pages = $result->getAll('body/subpages/page.subpage');
列出页面文件
$plug = new ApiPlug(XUri::newFromString('https://mindtouch.example.com/@api/deki')); $pagesPlug = $plug->at('pages'); // request a list of all files attached to page path 'lorem/ipsum/dolor' $result = $pagesPlug->at('=lorem/ipsum/dolor', 'files')->get(); // extract list of files $files = $result->getAll('body/files/file');
列出页面标签
$plug = new ApiPlug(XUri::newFromString('https://mindtouch.example.com/@api/deki')); $pagesPlug = $plug->at('pages'); // request a list of all tags on page id 619 $result = $pagesPlug->at('619', 'tags')->get(); // extract list of tags $tags = []; foreach($result->getAll('body/tags/tag') as $tag) { $tags[] = $tag['@value']; }
高级使用
此库是 modethirteen/HyperPlug 的扩展,并从它那里继承了大部分功能。然而,此库的 ApiPlug
类为与 MindTouch API 交互提供了专门的行为。
// the library allows for programmatic URL construction and parsing $uri = XUri::newFromString('http://mindtouch.example.com/@api') // every step in a URL builder returns an immutable XUri object ->withScheme('https') ->at('scim', 'v2', 'users') ->withQueryParam('xyzzy', 'plugh') ->withQueryParams(QueryParams::newFromArray([ 'bar' => 'qux', 'baz' => 'fred' ])) ->withoutQueryParam('bar'); // QueryParams objects are normally immutable $params = $uri->getQueryParams(); // we can change the data structure of a QueryParams object if we must $params = $params->toMutableQueryParams(); $params->set('baz', 'abc'); // QueryParams are also iterable foreach($params as $param => $value) { $uri = $uri->withReplacedQueryParam($param, $value); } // what does our URL look like now? $result = $uri->toString(); // https://mindtouch.example.com/@api/scim/v2/users?xyzzy=plugh&baz=abc // we can give our XUri object to a Plug or an ApiPlug to create a client $plug = new \modethirteen\Http\Plug($uri); // Plug holds the main HTTP client functionality which can technically be used with any HTTP server // ...however ApiPlug provides a layer of MindTouch API-specific request formatting and response handling // ...and is highly recommended when connecting to the MindTouch API $plug = new ApiPlug($uri); // like every object in this library, attaching new values or behaviors to plugs is by default immutable // ...and returns a new object reference // add a Server API Token for administrator authorization // ... which calculates Server API Token hash at HTTP request invocation $plug->withApiToken((new ApiToken('rabbits', 'hasen'))->withUsername('admin')); // we can add some additional URL path segements and query parameters that weren't part of the constructing URL $plug = $plug->at('another', 'additional', 'endpoint', 'segment')->with('more', 'params'); // how many redirects will we follow? $plug = $plug->withAutoRedirects(2); // HTTP requests often need HTTP headers $plug = $plug->withHeader('X-FcStPauli', 'hells') ->withAddedHeader('X-FcStPauli', 'bells') ->withHeader('X-HSV', 'you\'ll never walk again'); // ...or not $plug = $plug->withoutHeader('X-HSV'); // the Headers object, like XUri and QueryParams, is normally immutable $headers = $plug->getHeaders(); $result = $headers->getHeader('X-FcStPauli'); // ['hells', 'bells'] $result = $headers->getHeaderLine('X-FcStPauli'); // X-HSV: hells, bells // but if you really want to... $mutableHeaders = $headers->toMutableHeaders(); $mutableHeaders->set('X-HSV', 'keiner mag den hsv'); // a Headers object is iterable foreach($mutableHeaders as $header => $values) { foreach($values as $value) { // HTTP headers can have multiple stored values // ...though normally sent via an HTTP client as comma separated on a single HTTP header line echo "{$header}: {$value}"; } } // also we can merge the two sets of Headers (the original and the mutated one) // ...to create a brand new object containing the values of both $mergedHeaders = $headers->toMergedHeaders($mutableHeaders); // we've built out a pretty complex HTTP client now // ...but what if we want a client with a different URL but everything else the same? $alternateApiPlug = $plug->withUri(XUri::newFromString('https://deki.example.com/@api/deki')); // we are going to invoke an HTTP request // ...pre and post invocation callbacks can attach special logic and handlers // ...intended to be executed whenever or wherever this HTTP client is used // ...maybe there is some logic we want to always perform at the moment the HTTP request is about to be sent? $plug = $plug->withPreInvokeCallback(function(XUri $uri, IHeaders $headers) { // last chance to change the URL or HTTP headers before the request is made // ...URL and HTTP headers for the single request invocation can be mutated // ...this will not affect the URL or HTTP headers configured in the plug $headers->toMutableHeaders()->addHeader('something', 'contextual'); }); // multiple callbacks can be attached (they are executed in the order they are attached) $plug = $plug->withPreInvokeCallback(function(XUri $uri, IHeaders $headers) { }); // maybe we want to attach some special handling that always executes when we receive an HTTP response? $plug = $plug->withPostInvokeCallback(function(HttpResult $result) { // perhaps there is special behavior to always trigger based on the HTTP response status code? if($result->is(403)) { } }); // HTTP responses can be parsed from text into traversable data structures by attaching one or more HttpResultParser objects // ...parsing can be possibly memory intensive, so limits can be put on the allowed size of a response to parse $plug = $plug->withHttpResultParser((new JsonParser())->withMaxContentLength(640000)); // fetching HTTP data is handled via HTTP GET $result = $plug->get(); // POST or PUT can optionally send data, in a several different content types as needed $result = $plug->post( (new MultiPartFormDataContent([ 'a' => 'b', 'c' => 'd' ])) ->withFileContent(new FileContent('/path/to/file')) ); $result = $plug->put(new FileContent('/path/to/file')); $result = $plug->post(new UrlEncodedFormDataContent([ 'e' => 'f', 'g' => 'h' ])); $result = $plug->post(JsonContent::newFromArray([ 'a' => [ 'multi-dimensional' => [ 'data', 'structure' ] ] ])); $result = $plug->post(XmlContent::newFromArray([ 'another' => [ 'multi-dimensional' => [ 'data', 'structure' ], 'formatted' => 'as xml' ] ])); $result = $plug->put(new TextContent('good old text!')); // during the invocation process, an ApiResultException may be raised // ...such as a max HTTP response content length exceeded or an HTTP response parser failure // ...exceptions can bubble up to the HTTP client callsite, or handled in the HTTP client internally $plug = $plug->withResultErrorHandler(function(ApiResultException $e) : bool { if($e instanceof HttpResultParserException) { // always suppress this exception return false; } return true; });
开发和测试
尽管此库由 MindTouch, Inc. 赞助,但社区(有待解决的缺陷和增强)的贡献始终受到欢迎。
此库通过结合使用 PHPUnit 和 MockPlug
(一个匹配 ApiPlug
调用并返回模拟响应的拦截器)进行测试。进一步使用 PHPStan(PHP 静态分析工具)检查代码质量。
# fork and clone the mindtouch-http.php repository git clone git@github.com:{username}/mindtouch-http.php.git # install dependencies composer install # run static analysis checks vendor/bin/phpstan analyse --level 7 src # run tests vendor/bin/phpunit --configuration phpunit.xml.dist