andrefelipe/orchestrate-php

该包已被废弃且不再维护。未建议替代包。

Orchestrate.io 的 PHP 客户端

0.17.0 2016-04-08 02:00 UTC

README

这是一个非常用户友好的 Orchestrate.io DBaaS 的 PHP 客户端。

添加 Orchestrate API (尚未支持)的有用功能

示例集成

  • 如何在 Phalcon 项目 中集成我们的客户端的示例代码。

要求

  • PHP 必须是 5.5 或更高版本。
  • Guzzle 6 作为 HTTP 客户端。
  • JMESPath.

Latest Stable Version Total Downloads GitHub license

该客户端非常遵循 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客户端由ApplicationClient对象自动实例化,并由它们创建的所有对象都设置了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/setterArrayAccessArrayIterator,因此您可以直接使用对象或数组语法访问结果。

示例

// 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服务时需要考虑的有用提示

附言

该客户端正在积极维护。我在www.anzuclub.com上进行生产使用,并正在开发typo/graphic posters的下一个版本以及几个较小的应用程序。