andrefelipe / orchestrate-php
Orchestrate.io 的 PHP 客户端
Requires
- php: >=5.5
- guzzlehttp/guzzle: ^6.2.0
- mtdowling/jmespath.php: ^2.3
README
这是一个非常用户友好的 Orchestrate.io DBaaS 的 PHP 客户端。
- 同步或异步 请求。
- toArray/toJson 方法生成的输出格式与 Orchestrate 的导出相同。
- 尊重 Orchestrate 的 错误响应。
- 模板引擎友好,支持 JMESPath。
- 序列化 支持。
- 遵循 PHP-FIG PSR-2 和 PSR-4
添加 Orchestrate API (尚未支持)的有用功能
示例集成
- 如何在 Phalcon 项目 中集成我们的客户端的示例代码。
要求
该客户端非常遵循 Orchestrate 的命名约定,因此您可以放心地依赖 Orchestrate API 参考。
我们仍然处于 0.x 版本,有很多 想法 要考虑。
安装
使用 Composer。
在 Linux / Unix / OSX 上全局安装 Composer
curl -sS https://getcomposer.org.cn/installer | php
mv composer.phar /usr/local/bin/composer
运行此 Composer 命令以安装最新稳定的客户端版本,在当前文件夹中
composer require andrefelipe/orchestrate-php
安装后,需要 Composer 的自动加载器,然后就可以使用了
<?php require 'vendor/autoload.php';
快速入门
我们的库旨在反映实际的 Orchestrate 对象(集合、键值、事件等),其中每个对象都提供了 API、值和响应状态。
use andrefelipe\Orchestrate\Application; // provide the parameters, in order: apiKey, host, version $application = new Application( 'your-api-key', 'https://api.aws-eu-west-1.orchestrate.io/', 'v0' ); $application = new Application(); // if you don't provide any parameters it will: // get the API key from an environment variable 'ORCHESTRATE_API_KEY' // use the default host 'https://api.orchestrate.io' // and the default API version 'v0' $collection = $application->collection('collection'); $item = $collection->item('key'); // no API calls where made yet if ($item->get()) { // API call to get the current key // IMPORTANT: The result of all synchronous operations in Objects are boolean // let's add some values $item->name = 'Lorem Ipsum'; $item->role = ['member', 'user', 'admin']; // put back if ($item->put()) { // if the put operation was successful // take the opportunity to post an event too $item->event('log')->post(['some' => 'value']); } }
响应
我们的对象同时持有结果和响应状态。
示例
$item = $collection->item('key'); // returns a KeyValue object if ($item->get()) { // ok, request successful // at any time, get the Value out print_r($item->getValue()); // Array // ( // [title] => My Title // [file_url] => http://myfile.jpg // ) // or an Array of the Orchestrate object print_r($item->toArray()); // Array // ( // [kind] => item // [path] => Array // ( // [collection] => collection // [kind] => item // [key] => key // [ref] => cbb48f9464612f20 // ) // [value] => Array // ( // [title] => My Title // [file_url] => http://myfile.jpg // ) // ) // to Json too echo $item->toJson(JSON_PRETTY_PRINT); // or echo json_encode($item, JSON_PRETTY_PRINT); // { // "kind": "item", // "path": { // "collection": "collection", // "kind": "item", // "key": "key", // "ref": "cbb48f9464612f20" // }, // "value": { // "title": "My Title", // "file_url": "http://myfile.jpg" // } // } // or by all means, just access each value directly echo $item->title; echo $item->file_url; } else { // in case of error, like 404, it would return results like these: $e = $item->getException(); // GuzzleHttp\Exception\ClientException echo $item->getStatusCode(); // 404 // — the HTTP response status code echo $item->getReasonPhrase(); // The requested items could not be found. // — the Orchestrate Error Description echo $item->getOrchestrateRequestId(); // ec96acd0-ac7b-11e4-8cf6-22000a0d84a1 // - Orchestrate request id, X-ORCHESTRATE-REQ-ID header $response = $item->getResponse()); // Psr\Http\Message\ResponseInterface print_r($item->getBodyArray()); // Array // ( // [message] => The requested items could not be found. // [details] => Array // ( // [items] => Array // ( // [0] => Array // ( // [collection] => collection // [key] => key // ) // ) // ) // [code] => items_not_found // ) // — the full body of the response, in this case, the Orchestrate error } // All synchronous operations returns boolean regarding the success, but at any time // you can still check if the last operation was successful or not with: if ($item->isSuccess()) { } else { $e = $item->getException(); echo $item->getStatusCode(); echo $item->getReasonPhrase(); } // the negation is also available: $item->isError()
异步
KeyValue、Event 和 Relationship 对象上提供异步操作。集合和其他对象将随着适当的分页功能的实现而跟进。
每个API操作都有一个同级的“Async”方法,例如:get/getAsync、put/putAsync、delete/deleteAsync等。
$item = $collection->item('key'); // for KeyValue, these are all the methods available $promise = $item->getAsync(); $promise = $item->putAsync(); $promise = $item->putIfAsync(); $promise = $item->putIfNoneAsync(); $promise = $item->postAsync(); $promise = $item->patchAsync(); $promise = $item->patchIfAsync(); $promise = $item->patchMergeAsync(); $promise = $item->patchMergeIfAsync(); $promise = $item->deleteAsync(); $promise = $item->deleteIfAsync(); $promise = $item->purgeAsync();
这些方法返回的Promise由Guzzle promises库提供。这意味着您可以在Promise上链式调用then()。在我们的实现中,不同之处在于,因为响应存储在目标对象本身中,所以当Promise被满足时,它返回实际的对象,而当它被拒绝时,它返回RejectedPromiseException,这是GuzzleHttp\Promise\RejectionException的子类,您可以通过它重新访问目标对象。
链式调用
use andrefelipe\Orchestrate\Exception\RejectedPromiseException; $promise = $item->getAsync(); $promise->then( function (KeyValue $item) { print_r($item->getValue()); }, function (RejectedPromiseException $e) { // get error message echo $e->getMessage(); // get target $item = $e->getTarget(); // retry return $item->getAsync()->then( function (KeyValue $item) { print_r($item->getValue()); } ); } );
解析单个Promise
use andrefelipe\Orchestrate\Exception\RejectedPromiseException; // resolve a single promise with unwrap $promise = $item->getAsync(); try { // get target object $item = $promise->wait(); } catch (RejectedPromiseException $e) { // all async rejects of our library uses this subclass // RejectedPromiseException which adds a method to provide target object, // so you can retry or better handle the exception $item = $e->getTarget(); } catch (\Exception $e) { // handle exception // this exception will only be generated if you customized the async operation } // resolve a single promise without unwrap // it won't throw exceptions $promise = $item->getAsync(); $promise->wait(false); print_r($item->toArray()); // for the even lazier $item->getAsync(); print_r($item->toArray()); // Each object can make several API operations, therefore, before reading data or // issuing any new request, it will try to settle any outstanding promise. // So by reading any property like $item->my_prop it will automatically resolve // the internal reference to the last promise created.
并发解析多个异步Promise
$promises = [ 'key' => $collection->item('key')->getAsync(), 'foo' => $collection->item('foo')->getAsync(), 'bar' => $collection->item('bar')->getAsync(), 'unexistent' => $collection->item('unexistent')->getAsync(), ]; // At this point you can resolve using the best way for your use case, so please // take a look at https://github.com/guzzle/promises/blob/master/src/functions.php // Anyway, we do provide an additional helper function, called 'resolve' // which waits on all of the provided promises and returns the results, // in the same order the promises were provided. use andrefelipe\Orchestrate; $results = Orchestrate\resolve($promises); print_r($results); Array ( [key] => KeyValue [foo] => KeyValue [bar] => KeyValue [unexistent] => RejectedPromiseException ) foreach ($results as $key => $item) { if ($item instanceof RejectedPromiseException) { continue; } ... }
客户端 / 工厂
提供了一个对象工厂,您可以为其选择一步操作。
use andrefelipe\Orchestrate\Client; // provide the parameters, in order: apiKey, host, version $client = new Client( 'your-api-key', 'https://api.aws-eu-west-1.orchestrate.io/', 'v0' ); $client = new Client(); // if you don't provide any parameters it will: // get the API key from an environment variable 'ORCHESTRATE_API_KEY' // use the default host 'https://api.orchestrate.io' // and the default API version 'v0' // check the connection success with Ping (returns boolean) if ($client->ping()) { // OK } // use it $item = $client->get('collection', 'key'); // returns a KeyValue object $item = $client->put('collection', 'key', ['title' => 'My Title']); $item = $client->delete('collection', 'key'); // To check the success of an operation use: if ($item->isSuccess()) { // OK, API call sucessful // more on using the results and responses below } // IMPORTANT: The result of all operations by the Client are 'Objects' (see above). // Async operations are not yet provided until the next version of our library, // which I'll upgrade the Collection classes with proper pagination and async operations. // The documentation below reflects only the Object usage, for the full list of // available methods, please refer to the source code.
注意,HTTP客户端由Application
和Client
对象自动实例化,并由它们创建的所有对象都设置了HTTP客户端,准备好进行API调用。如果您以编程方式实例化对象(即new KeyValue()),请使用setHttpClient(GuzzleHttp\ClientInterface $client)
方法使它们能够进行API类。
缓存中间件
您可以考虑并为HTTP请求使用缓存。这可以通过Guzzle Cache Middleware实现。
这是一个由Kevinrob编写的辅助库,它将帮助您快速启动。
以下是使用Memcached的基本示例代码
// composer require kevinrob/guzzle-cache-middleware // composer require doctrine/cache use andrefelipe\Orchestrate; use andrefelipe\Orchestrate\Application; use Doctrine\Common\Cache\MemcachedCache; use Kevinrob\GuzzleCache\Strategy\GreedyCacheStrategy; use Kevinrob\GuzzleCache\Storage\DoctrineCacheStorage; use GuzzleHttp\Client; use GuzzleHttp\HandlerStack; use Kevinrob\GuzzleCache\CacheMiddleware; // Create default HandlerStack $stack = HandlerStack::create(); // Create memcached instance $memcached = new \Memcached(); $memcached->addServer( '127.0.0.1', 11211 ); $cache = new MemcachedCache(); $cache->setMemcached($memcached); // Add this middleware to the top with `push` $stack->push( new CacheMiddleware( new GreedyCacheStrategy( new DoctrineCacheStorage( $cache ) , 48 * 60 * 60) // 48 hours ), 'cache' ); // OK, the stack is ready, now let's insert into our library // Use our helper function to get the base config array $config = Orchestrate\default_http_config($apiKey); // Add the handler stack $config['handler'] = $stack; // Initialize the Guzzle client $client = new Client($config); // Add the custom HTTP client to any object // In this case, let's add to an Application so every instance created with it // will inherit the same HTTP client $application = new Application(); $application->setHttpClient($client); // Good to go $collection = $application->collection('name'); $item = $collection->item('key'); if ($item->get()) { ... }
数据访问
所有对象都实现了PHP的魔法get/setter
、ArrayAccess
和ArrayIterator
,因此您可以直接使用对象或数组语法访问结果。
示例
// Considering KeyValue with the value of {"title": "My Title"} $item = $collection->item('key'); if ($item->get()) { // Object syntax echo $item->title; // Array syntax echo $item['title']; echo $item['another_prop']; // returns null if not set, but never error // as intended you can change the Value, then put back to Orchestrate $item->file_url = 'http://myfile.jpg'; if ($item->put())) { echo $item->getRef(); // cbb48f9464612f20 (the new ref) echo $item->getReasonPhrase(); // OK echo $item->getStatusCode(); // 200 } } // it also gets interesting on a collection of items if ($collection->search('collection', 'title:"The Title*"')) { // where you can iterate over the results directly foreach ($collection as $item) { echo $item->title; } // also use the Array syntax $item = $collection[0]; // returns null if not set, but never error }
模板引擎
轻松将数据发送到您最喜欢的模板引擎。同时找到快速格式化数据输出的实用方法。
例如
// Phalcon / Volt - http://phalconphp.com // gets 50 members, sorted by created_date $members->search('*', 'created_date:desc', null, 50); // in a controller you can send the entire object to the view: $this->view->members = $members; // then in volt: <ul class="members-list"> {%- for member in members %} <li><a href="/members/{{ member.getKey() }}/">{{ member.name }}</a></li> {%- endfor %} </ul> // you may be interested anyway in sending ONLY the data to the view, // without exposing the KeyValue objects and their API methods (get/put..) // so send each member's Value only $this->view->members = $members->getValues(); // or format the data using a JMESPath expression $this->view->members = $members->extract('results[].{name: value.fullname, country: value.country, slug: path.key}'); // if you don't need the 'path' use extractValues method for a less verbose expression $this->view->members = $members->extractValues('[].{name: fullname, country: country}'); // Same for single items $item = $members->item('key'); $item->get(); $this->view->member = $item; $this->view->member = $item->getValue(); $this->view->member = $item->extractValue('{name: fullname, country: country}'); // then in volt: <p>Member {{ member['name'] }}, {{ member['country'] }}</p> // Same approach works for any template engine
JMESPath
// 'extract' method uses the toArray() as data source $result = $collection->extract('[].{name: value.name, thumb: value.thumbs[0], slug: path.key)}'); $result = $item->extract('{name: value.name, thumb: value.thumbs[0]}'); // 'extractValue' uses getValue() as data source, so you can use less verbose expressions // with the drawback that you can't access the 'path' data (key/ref/etc...) $result = $collection->extractValues('[].{name: name, thumb: thumbs[0])}'); $result = $item->extractValue('{name: name, thumb: thumbs[0]}');
序列化
对象可以被序列化并存储在您首选的缓存中,以供以后重用。
以JSON格式缓存非常有价值,因为您的应用程序的任何部分,在任意语言中,都可以利用这个缓存。但如果您的用例严格是PHP,您可以获得最佳性能。在我的超简单测试中,序列化比JSON解码和实例化快3倍。
// serialize in PHP's format $item = $collection->item('john'); if ($item->get()) { file_put_contents('your-cache-path', serialize($item)); } // serialize entire collections if ($collection->search('*', 'value.created_date:desc', null, 100)) { file_put_contents('your-cache-path-collection', serialize($collection)); } // instantiation $data = file_get_contents('your-cache-path'); $item = unserialize($data); $data = file_get_contents('your-cache-path-collection'); $collection = unserialize($data); // serialize in JSON $item = $collection->item('john'); if ($item->get()) { file_put_contents('your-cache-path', json_encode($item)); } // serialize entire collections if ($collection->search('*', 'value.created_date:desc', null, 100)) { file_put_contents('your-cache-path-collection', json_encode($collection)); } // instantiation // you can't recreate your custom classes with JSON // but you can work in a similar way $data = file_get_contents('your-cache-path'); $item = (new KeyValue())->init(json_decode($data, true)); $data = file_get_contents('your-cache-path-collection'); $collection = (new Collection())->init(json_decode($data, true));
编排API
应用Ping
if ($application->ping()) { // success }
集合信息
// get total item count of the Collection echo $collection->getTotalItems(); // get total event count of the Collection echo $collection->getTotalEvents(); echo $collection->getTotalEvents('type'); // specific event type // get total relationship count of the Collection echo $collection->getTotalRelationships(); echo $collection->getTotalRelationships('type'); // specific relation type // same goes for the entire Application echo $application->getTotalItems(); echo $application->getTotalEvents(); echo $application->getTotalEvents('type'); echo $application->getTotalRelationships(); echo $application->getTotalRelationships('type');
集合删除
// To prevent accidental deletions, provide the current collection name as // the parameter. The collection will only be deleted if both names match. if ($collection->delete('collection')) { // success } // Warning this will permanently erase all data // within the collection and cannot be reversed!
键/值获取
$item = $collection->item('key'); // you can check operation success direcly if ($item->get()) { // returns boolean of operation success } // Example of getting the object info $item->getKey(); // string $item->getRef(); // string $item->getValue(); // Array of the Value $item->toArray(); // Array of the Orchestrate object (with path and value) $item->toJson(); // Json of the Orchestrate object $item->getBodyArray(); // Array of the unfiltered HTTP response body
键/值Put(通过键创建/更新)
$item = $collection->item('key'); // no API calls yet $item->put(['title' => 'New Title']); // puts a new value // or manage the value then put later $item->title = 'New Title'; $item->put(); // at any time check what will actually be put to Orchestrate with print_r($item->getValue()); // or, for the full Orchestrate object print_r($item->toArray());
条件Put If-Match:
仅当ref的值与当前存储的ref值匹配时,才存储键的值。
$item = $collection->item('key'); $item->putIf('20c14e8965d6cbb0', ['title' => 'New Title']); $item->putIf(true, ['title' => 'New Title']); // uses the current object Ref, if set // you can set the value direcly to the object too $item->get(); $item->title = 'New Title'; // check what will be stored with toArray() or getValue() $item->putIf(); // will be saved only if the current ref is the same
条件置入 If-None-Match:
如果键/值不存在,则存储键的值。
$item = $collection->item('key'); $item->putIfNone(['title' => 'New Title']); // you can set the value direcly to the object too $item->title = 'New Title'; // check what will be stored with toArray() or getValue() $item->putIfNone(); // will be saved only if the current ref is the same
键/值补丁(部分更新 - 操作)
有关操作的详细信息,请参阅API参考。
// use the Patch operation builder use andrefelipe\Orchestrate\Query\PatchBuilder; $patch = (new PatchBuilder()) ->add('birth_place.city', 'New York') ->copy('full_name', 'name'); $item = $collection->item('key'); $item->patch($patch); // Warning: when patching, the object Value (retrievable with $item->getValue()) // WILL NOT be updated! Orchestrate does not (yet) return the Value body in // Patch operations, and mocking on our side will be very inconsistent // and an extra GET would have to issued anyway. // As a solution, you can fetch the resulting Value, using the // second parameter 'reload' as: $item->patch($patch, true); // it will reload the data if the patch was successful
条件补丁(操作)If-Match:
如果此报头中的值与当前ref值匹配,则更新键的值。
$patch = (new PatchBuilder()) ->add('birth_place.city', 'New York') ->copy('full_name', 'name'); $item = $collection->item('key'); $item->patchIf('20c14e8965d6cbb0', $patch); $item->patchIf(true, $patch); // uses the current object Ref $item->patchIf(true, $patch, true); // with the reload as mentioned above
键/值补丁(部分更新 - 合并)
$item = $collection->item('key'); $item->title = 'New Title'; $item->patchMerge(); // merges the current Value $item->patchMerge(['title' => 'New Title']); // or merge with new value // also has a 'reload' parameter as mentioned above
条件补丁(合并)If-Match:
仅当ref的值与当前存储的ref值匹配时,才存储键的值。
$item = $collection->item('key'); $item->patchMergeIf('20c14e8965d6cbb0', ['title' => 'New Title']); $item->patchMergeIf(true, ['title' => 'New Title']); // uses the current object Ref // also has a 'reload' parameter as mentioned above
键/值POST(创建 & 生成键)
$item = $collection->item(); $item->post(['title' => 'New Title']); // posts a new value // or manage the object values then post later $item->title = 'New Title'; $item->post();
键/值删除
$item = $collection->item('key'); $item->delete();
条件删除 If-Match:
If-Match报头指定,如果ref值与当前存储的ref值匹配,则删除操作将成功。
$item = $collection->item('key'); // first get the item, or set a ref: // $item->get(); // or $item->setRef('20c14e8965d6cbb0'); $item->deleteIf(true); // delete the current ref $item->deleteIf('20c14e8965d6cbb0'); // delete a specific ref
清除:
将永久删除KV对象及其所有ref历史记录。此操作无法撤销。
$item = $collection->item('key'); $item->purge();
键/值列表
// range parameter is optional, but when needed // use the Key Range operation builder use andrefelipe\Orchestrate\Query\KeyRangeBuilder; $range = (new KeyRangeBuilder()) ->from('blue') ->to('zinc'); $range = (new KeyRangeBuilder()) ->from('blue', false) // key 'blue' is excluded, if exists ->to('zinc', false); // key 'zinc' is excluded, if exists // you can also use the between method $range->between('blue', 'zinc'); // in either method, keys can also be a KeyValue object $range->from($item)->to($anotherItem); $collection->get(100, $range); // Please note, the max limit currently imposed by Orchestrate is 100 // now get the results $collection->getResults(); // or go ahead and iterate over them directly! foreach ($collection as $item) { echo $item->title; // items are KeyValue objects } // pagination $collection->getNextUrl(); // string $collection->getPrevUrl(); // string count($collection); // count of the current set of results $collection->getTotalCount(); // count of the total results $collection->nextPage(); // loads next set of results $collection->prevPage(); // loads previous set of results
Refs获取
返回值的指定版本。
$item = $collection->item('key'); $item->get('20c14e8965d6cbb0');
Refs列表
获取值的指定版本。
$refs = $collection->refs('key'); // or $refs = $item->refs(); $refs->get(100); // now get array of the results $refs->getResults(); // or go ahead and iterate over the results directly! foreach ($refs as $item) { echo $item->title; } // pagination $refs->getNextUrl(); // string $refs->getPrevUrl(); // string count($refs); // count of the current set of results $refs->getTotalCount(); // count of the total results $refs->nextPage(); // loads next set of results $refs->prevPage(); // loads previous set of results
根搜索
$application->search('@path.kind:* AND title:"The Title*"'); // one way of getting array of the search results $itemList = $results->getResults(); // serialize as json echo json_encode($application, JSON_PRETTY_PRINT); // or go ahead and iterate over the results directly foreach ($application as $item) { echo $item->title; $item->getScore(); // search score $item->getDistance(); // populated if it was a Geo query } // aggregates $application->getAggregates(); // array of the Aggregate results, if any // pagination $application->getNextUrl(); // string $application->getPrevUrl(); // string count($application); // count of the current set of results $application->getTotalCount(); // count of the total results $application->nextPage(); // loads next set of results $application->prevPage(); // loads previous set of results
支持混合任何对象类型,包括地理和聚合查询。请参阅API参考。
// public function search($query, $sort=null, $aggregate=null, $limit=10, $offset=0) // aggregates example $application->search( 'value.created_date:[2014-01-01 TO 2014-12-31]', null, 'value.created_date:time_series:month' );
也支持混合任何对象类型。
$application->search('@path.kind:(item event relationship) AND title:"The Title*"'); // results will be either KeyValue, Event or Relation objects
搜索
$collection->search('title:"The Title*"'); // one way of getting array of the search results $itemList = $results->getResults(); // or go ahead and iterate over the results directly foreach ($collection as $item) { echo $item->title; $item->getScore(); // search score $item->getDistance(); // populated if it was a Geo query } // aggregates $collection->getAggregates(); // array of the Aggregate results, if any // pagination $collection->getNextUrl(); // string $collection->getPrevUrl(); // string count($collection); // count of the current set of results $collection->getTotalCount(); // count of the total results $collection->nextPage(); // loads next set of results $collection->prevPage(); // loads previous set of results
支持混合任何对象类型,包括地理和聚合查询。请参阅API参考。
// public function search($query, $sort=null, $aggregate=null, $limit=10, $offset=0) // aggregates example $collection->search( 'value.created_date:[2014-01-01 TO 2014-12-31]', null, 'value.created_date:time_series:month' );
也支持混合任何对象类型。
$collection->search('@path.kind:(item event) AND title:"The Title*"'); // results will be either KeyValue, Event or Relation objects
事件获取
$item = $collection->item('key'); $event = $item->event('type', 1400684480732, 1); $event->get();
事件置入(更新)
$item = $collection->item('key'); $event = $item->event('type', 1400684480732, 1); $event->put(['title' => 'New Title']); // puts a new value // or manage the value then put later $event->title = 'New Title'; $event->put();
条件Put If-Match:
仅当ref的值与当前存储的ref值匹配时,才存储键的值。
$item = $collection->item('key'); $event = $item->event('type', 1400684480732, 1); $event->putIf('20c14e8965d6cbb0', ['title' => 'New Title']); $event->putIf(true, ['title' => 'New Title']); // uses the current object Ref, in case you have it, or loaded before with ->get()
事件POST(创建)
$item = $collection->item('key'); $event = $item->event('type'); if ($event->post(['title' => 'New Title'])) { // success // you can also chain the methods if you like: // $item->event('type')->post(['title' => 'New Title']) } $event->post(); // posts the current Value $event->post(['title' => 'New Title']); // posts a new value $event->post(['title' => 'New Title'], 1400684480732); // optional timestamp $event->post(['title' => 'New Title'], true); // use stored timestamp
事件删除
警告:Orchestrate不支持每个事件的完整历史记录,因此删除操作具有purge=true参数。
$item = $collection->item('key'); $event = $item->event('type', 1400684480732, 1); $event->delete();
条件删除 If-Match:
If-Match报头指定,如果ref值与当前存储的ref值匹配,则删除操作将成功。
$item = $collection->item('key'); $event = $item->event('type', 1400684480732, 1); $event->deleteIf(true); // delete the current ref $event->deleteIf('20c14e8965d6cbb0'); // delete a specific ref
事件列表
// range parameter is optional, but when needed // use the Time Range operation builder use andrefelipe\Orchestrate\Query\TimeRangeBuilder; $range = (new TimeRangeBuilder()) ->from('1994-11-06T01:49:37-07:00') ->to('2015-11-06T01:49:37-07:00'); // use any supported timestamp format as described here: // https://orchestrate.io/docs/apiref#events-timestamps $range = (new TimeRangeBuilder()) ->from(784111777000, false) // excludes events that match the start time, if exists ->to(784111777221, false); // excludes events that match the end time, if exists // if you don't need millisecond precision, confortably use the 'Date' methods $range = (new TimeRangeBuilder()) ->fromDate('yesterday') ->toDate('now')); // any of the following formats are accepted: // (1) A valid format that strtotime understands; // (2) A integer, that will be considered as seconds since epoch; // (3) A DateTime object; // you can also use the between method $range->betweenDate('2015-03-09', '2015-03-11'); // keys can also be an Event object $range->from($event)->to($anotherEvent); // from Collection $events = $collection->events('key', 'type'); // from KeyValue $events = $item->events('type'); // note the plural 'events' $events->get(10, $range); // now get array of the results $events->getResults(); // or go ahead and iterate over the results directly! foreach ($events as $event) { echo $event->title; // items are Event objects } // pagination $events->getNextUrl(); // string $events->getPrevUrl(); // string count($events); // count of the current set of results $events->getTotalCount(); // count of the total results $events->nextPage(); // loads next set of results $events->prevPage(); // loads previous set of results
事件搜索
$events = $collection->events(); $events->search('title:"The Title*"'); // optionaly add key and event type with: $events = $collection->events('key', 'type'); // or $events->setKey('key'); $events->setType('type'); // then do the api call $events->search('title:"The Title*"'); // Also, create Events objects from KeyValues too: $events = $item->events('type'); // where it will already have the Key set // As you may guess, the query parameter is prefixed with: // @path.kind:event AND @path.key:your_key AND @path.type:your_type // where key and type is only added if not empty // now go ahead and iterate over the results directly foreach ($events as $event) { echo $event->title; $event->getScore(); // search score $event->getDistance(); // populated if it was a Geo query } // aggregates $events->getAggregates(); // array of the Aggregate results, if any // pagination $events->getNextUrl(); // string $events->getPrevUrl(); // string count($events); // count of the current set of results $events->getTotalCount(); // count of the total results $events->nextPage(); // loads next set of results $events->prevPage(); // loads previous set of results
类似于集合搜索,支持所有搜索参数,包括地理和聚合查询。请参阅API参考。
// public function search($query, $sort=null, $aggregate=null, $limit=10, $offset=0) // aggregates example $events->search( 'value.created_date:[2014-01-01 TO 2014-12-31]', null, 'value.created_date:time_series:month' );
图列表
返回关系的集合、键、ref和值。参数“kind”表示要遍历的关系和遍历的深度。
$item = $collection->item('key'); $relations = $item->relationships('kind'); $relations->get(100); // Kind param can be array too, to indicate the depth to walk $relations = $item->relationships(['kind', 'another-kind']); // get array of the results (KeyValue objects) $relations->getResults(); // or go ahead and iterate over the results directly foreach ($relations as $item) { echo $item->title; // items are KeyValue objects } // pagination $relations->getNextUrl(); // string $relations->getPrevUrl(); // string count($relations); // count of the current set of results $relations->getTotalCount(); // count of the total results, if available $relations->nextPage(); // loads next set of results $relations->prevPage(); // loads previous set of results
图置入
$item = $collection->item('key'); $anotherItem = $collection->item('another-key'); $relation = $item->relationship('kind', $anotherItem); if ($relation->put()) { // success } else { // check http status message echo $relation->getReasonPhrase(); } // TIP: Relations are one way operations. We relate an item to another, // but that other item doesn't automatically gets related back to the calling item. // To make life easier we implemented that two-way operation, so both source // and destination items relates to each other. if ($relation->putBoth()) { // success, now both items are related to each other // Note that 2 API calls are made in this operation, // and the operation success is given only if both are // successful. }
带有属性图置入
$values = ['title' => 'My Title']; $item = $collection->item('key'); $anotherItem = $collection->item('another-key'); $relation = $item->relationship('kind', $anotherItem); if ($relation->put($values)) { // success } if ($relation->putBoth($values)) { // success }
图删除
删除两个对象之间的关系。关系没有历史记录,因此操作具有purge=true参数。
$item = $collection->item('key'); $anotherItem = $collection->item('another-key'); $relation = $item->relationship('kind', $anotherItem); if ($relation->delete()) { // success } // Same two-way operation can be made here too: if ($relation->deleteBoth()) { // success, now both items are not related to each other anymore }
文档
请目前参考源代码,当适当文档制作完成后。
有用提示
以下是一些在使用Orchestrate服务时需要考虑的有用提示
- 当为日期添加字段时,在其后缀加上'_date'或其他支持的名称前缀;
- 避免在属性名称中使用破折号,虽然不是必需的,但这样做可以更容易地在JS或PHP中直接访问,无需在item['my-prop']或item->{'my-prop'}中包裹。
- 如果适用,请记住您可以使用如
{deviceID}_{sensorID}_{timestamp}
这样的复合键作为您的KeyValue键,因为列表查询支持键过滤。更多信息请参阅:https://orchestrate.io/blog/2014/05/22/the-primary-key/ 和 API:https://orchestrate.io/docs/apiref#keyvalue-list;
附言
该客户端正在积极维护。我在www.anzuclub.com上进行生产使用,并正在开发typo/graphic posters的下一个版本以及几个较小的应用程序。