https://github.com/ravendb/ravendb-php-client
https://github.com/ravendb/ravendb-php-client
Last synced: over 1 year ago
JSON representation
- Host: GitHub
- URL: https://github.com/ravendb/ravendb-php-client
- Owner: ravendb
- License: mit
- Created: 2020-09-28T09:25:25.000Z (almost 6 years ago)
- Default Branch: v5.4
- Last Pushed: 2025-03-18T11:15:11.000Z (over 1 year ago)
- Last Synced: 2025-04-09T16:15:12.457Z (over 1 year ago)
- Language: PHP
- Size: 2.22 MB
- Stars: 9
- Watchers: 9
- Forks: 5
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- License: LICENSE.md
Awesome Lists containing this project
README
# PHP client for RavenDB NoSQL Database
## Installation
You can install library to your project via [Composer](https://getcomposer.org/)
``` bash
$ composer require ravendb/ravendb-php-client
```
## Releases
* All client versions 5.4.x are fully compatible with and support RavenDB server releases 5.4 and 6.0.
* [Click here](https://github.com/ravendb/ravendb-php-client/releases) to view all Releases and Changelog.
## Documentation
This readme provides short examples for the following:
[Getting started](#getting-started),
[Crud example](#crud-example),
[Query documents](#query-documents),
[Attachments](#attachments),
[Time series](#timeseries),
[Revisions](#revisions),
[Suggestions](#suggestions),
[Patching](#advanced-patching),
[Using classes](#using-classes-for-entities),
[PHP usage](#usage-with-php),
[Working with secure server](#working-with-a-secure-server),
[Running tests](#running-tests)
For more information go to the online [RavenDB Documentation](https://ravendb.net/docs/article-page/latest/nodejs/client-api/what-is-a-document-store).
For more information on how to use **RavenDB** with **Laravel**
check out the [Raven Laravel Demo Application](https://github.com/ravendb/samples-php-laravel)
## Getting started
1. Require the `DocumentStore` class from the ravendb package
```php
use RavenDB\Documents\DocumentStore;
```
2. Initialize the document store (you should have a single DocumentStore instance per application)
```php
$store = new DocumentStore('http://live-test.ravendb.net', 'databaseName');
$store->initialize();
```
3. Open a session
```php
$session = $store->openSession();
```
4. Call `saveChanges()` when you're done
```php
$user = $session->load('users/1-A'); // Load document
$user->setPassword(PBKDF2('new password')); // Update data
$session->saveChanges(); // Save changes
// Data is now persisted
// You can proceed e.g. finish web request
```
## CRUD example
### Store documents
```php
$product = new Product();
$product->setTitle("iPhone X");
$product->setPrice(999.99);
$product->setCurrency("USD");
$product->setStorage(64);
$product->setManufacturer("Apple");
$product->setInStock(true);
$session->store($product, 'products/1-A');
echo $product->id; // products/1-A
$session->saveChanges();
```
>##### Related tests:
>
>
>
> [storing docs with same ID in same session should throw](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/TrackEntityTest.php#L80)
### Load documents
```php
$product = $session->load(Product::class, 'products/1-A');
echo $product->getTitle(); // iPhone X
echo $product->getId(); // products/1-A
```
### Load documents with include
```php
// users/1
// {
// "name": "John",
// "kids": ["users/2", "users/3"]
// }
$session = $store->openSession();
try {
$user1 = $session
->include("kids")
->load("users/1");
// Document users/1 and all docs referenced in "kids"
// will be fetched from the server in a single request.
$user2 = $session->load("users/2"); // this won't call server again
$this->assertNotNull($user1);
$this->assertNotNull($user2);
$this->assertEqual(1, $session->advanced()->getNumberOfRequests());
} finally {
$session->close();
}
```
>##### Related tests:
> [can load with includes](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/Documents/LoadTest/LoadTest.php#L10)
### Update documents
```php
$product = $session->load(Product::class, 'products/1-A');
$product->setInStock(false);
$product->setLastUpdate(new Date());
$session->saveChanges();
// ...
$product = $session->load(Product::class, 'products/1-A');
echo $product->getInStock(); // false
echo $product->getLastUpdate(); // the current date
```
### Delete documents
1. Using entity
```php
$product = $session->load('products/1-A');
$session->delete($product);
$session->saveChanges();
$product = $session->load('products/1-A');
$this->assertNull($product); // null
```
2. Using document ID
```php
$session->delete('products/1-A');
```
>##### Related tests:
> [delete doc by entity](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/DeleteTest.php#L10)
> [delete doc by ID](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/DeleteTest.php#L38)
> [onBeforeDelete is called before delete by ID](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Issues/RavenDB_15492Test.php#L9)
> [cannot delete untracked entity](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/TrackEntityTest.php#L15)
> [loading deleted doc returns null](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/TrackEntityTest.php#L37)
## Query documents
1. Use `query()` session method:
Query by collection:
```php
$query = $session->query(Product::class, Query::collection('products'));
```
Query by index name:
```php
$query = $session->query(Product::class, Query::indexName('productsByCategory'));
```
Query by index:
```php
$query = $session->query(Product::class, Products_ByCategory::class);
```
Query by entity type:
```php
$query = $session->query(Product::class);
```
2. Build up the query - apply search conditions, set ordering, etc.
Query supports chaining calls:
```php
$query
->waitForNonStaleResults()
->usingDefaultOperator('AND')
->whereEquals('manufacturer', 'Apple')
->whereEquals('in_stock', true)
->whereBetween('last_update', new DateTime('- 1 week'), new DateTime())
->orderBy('price');
```
3. Execute the query to get results:
```php
$results = $query->toList(); // get all results
// ...
$firstResult = $query->first(); // gets first result
// ...
$single = $query->single(); // gets single result
```
### Query methods overview
#### selectFields() - projections using a single field
```php
// RQL
// from users select name
// Query
$userNames = $session->query(User::class)
->selectFields("name")
->toList();
// Sample results
// John, Stefanie, Thomas
```
>##### Related tests:
>
> [query single property](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/_QueryTest/QueryTest.php#L368)
>
> [can_project_id_field](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Issues/RavenDB_14811Test/RavenDB_14811Test.php#L58)
#### selectFields() - projections using multiple fields
```php
// RQL
// from users select name, age
// Query
$session->query(User::class)
->selectFields([ "name", "age" ])
->toList();
// Sample results
// [ [ name: 'John', age: 30 ],
// [ name: 'Stefanie', age: 25 ],
// [ name: 'Thomas', age: 25 ] ]
```
>##### Related tests:
>
> [query with projection](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/_QueryTest/QueryTest.php#L555)
> [can_project_id_field](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Issues/RavenDB_14811Test/RavenDB_14811Test.php#L58)
#### distinct()
```php
// RQL
// from users select distinct age
// Query
$session->query(User::class)
->selectFields("age")
->distinct()
->toList();
// Sample results
// [ 30, 25 ]
```
>##### Related tests:
>
> [query distinct](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/_QueryTest/QueryTest.php#L611)
#### whereEquals() / whereNotEquals()
```php
// RQL
// from users where age = 30
// Query
$session->query(User::class)
->whereEquals("age", 30)
->toList();
// Sample results
// [ User {
// name: 'John',
// age: 30,
// kids: [...],
// registeredAt: 2017-11-10T23:00:00.000Z } ]
```
>##### Related tests:
>
> [where equals](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/_QueryTest/QueryTest.php#L784)
> [where not equals](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/_QueryTest/QueryTest.php#L817)
#### whereIn()
```php
// RQL
// from users where name in ("John", "Thomas")
// Query
$session->query(User::class)
->whereIn("name", ["John", "Thomas"])
->toList();
// Sample results
// [ User {
// name: 'John',
// age: 30,
// registeredAt: 2017-11-10T23:00:00.000Z,
// kids: [...],
// id: 'users/1-A' },
// User {
// name: 'Thomas',
// age: 25,
// registeredAt: 2016-04-24T22:00:00.000Z,
// id: 'users/3-A' } ]
```
>##### Related tests:
>
> [query with where in](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/_QueryTest/QueryTest.php#L416)
#### whereStartsWith() / whereEndsWith()
```php
// RQL
// from users where startsWith(name, 'J')
// Query
$session->query(User::class)
->whereStartsWith("name", "J")
->toList();
// Sample results
// [ User {
// name: 'John',
// age: 30,
// kids: [...],
// registeredAt: 2017-11-10T23:00:00.000Z } ]
```
>##### Related tests:
> [query with where clause](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/_QueryTest/QueryTest.php#L233)
#### whereBetween()
```php
// RQL
// from users where registeredAt between '2016-01-01' and '2017-01-01'
// Query
$session->query({ collection: "users" })
->whereBetween("registeredAt", DateTime::createFromFormat('Y-m-d', '2016-01-01'), DateTime::createFromFormat('Y-m-d', '2017-01-01'))
->toList();
// Sample results
// [ User {
// name: 'Thomas',
// age: 25,
// registeredAt: 2016-04-24T22:00:00.000Z,
// id: 'users/3-A' } ]
```
>##### Related tests:
>
> [query with where between](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/_QueryTest/QueryTest.php#L438)
#### whereGreaterThan() / whereGreaterThanOrEqual() / whereLessThan() / whereLessThanOrEqual()
```php
// RQL
// from users where age > 29
// Query
$session->query(User::class)
->whereGreaterThan("age", 29)
->toList();
// Sample results
// [ User {
// name: 'John',
// age: 30,
// registeredAt: 2017-11-10T23:00:00.000Z,
// kids: [...],
// id: 'users/1-A' } ]
```
>##### Related tests:
>
> [query with where less than](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/_QueryTest/QueryTest.php#L463)
> [query with where less than or equal](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/_QueryTest/QueryTest.php#L486)
> [query with where greater than](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/_QueryTest/QueryTest.php#L507)
> [query with where greater than or equal](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/_QueryTest/QueryTest.php#L532)
#### whereExists()
Checks if the field exists.
```php
// RQL
// from users where exists("age")
// Query
$session->query(User::class)
->whereExists("kids")
->toList();
// Sample results
// [ User {
// name: 'John',
// age: 30,
// registeredAt: 2017-11-10T23:00:00.000Z,
// kids: [...],
// id: 'users/1-A' } ]
```
>##### Related tests:
>
> [query where exists](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/_QueryTest/QueryTest.php#L997)
#### containsAny() / containsAll()
```php
// RQL
// from users where kids in ('Mara')
// Query
$session->query(User::class)
->containsAll("kids", ["Mara", "Dmitri"])
->toList();
// Sample results
// [ User {
// name: 'John',
// age: 30,
// registeredAt: 2017-11-10T23:00:00.000Z,
// kids: ["Dmitri", "Mara"]
// id: 'users/1-A' } ]
```
>##### Related tests:
>
> [queries with contains](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/ContainsTest/ContainsTest.php#L12)
#### search()
Perform full-text search.
```php
// RQL
// from users where search(kids, 'Mara')
// Query
$session->query(User::class)
->search("kids", "Mara Dmitri")
->toList();
// Sample results
// [ User {
// name: 'John',
// age: 30,
// registeredAt: 2017-11-10T23:00:00.000Z,
// kids: ["Dmitri", "Mara"]
// id: 'users/1-A' } ]
```
>##### Related tests:
>
> [query search with or](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/_QueryTest/QueryTest.php#L636)
> [query_CreateClausesForQueryDynamicallyWithOnBeforeQueryEvent](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/_QueryTest/QueryTest.php#L35)
#### openSubclause() / closeSubclause()
```php
// RQL
// from users where exists(kids) or (age = 25 and name != Thomas)
// Query
$session->query(User::class)
->whereExists("kids")
->orElse()
->openSubclause()
->whereEquals("age", 25)
->whereNotEquals("name", "Thomas")
->closeSubclause()
->toList();
// Sample results
// [ User {
// name: 'John',
// age: 30,
// registeredAt: 2017-11-10T23:00:00.000Z,
// kids: ["Dmitri", "Mara"]
// id: 'users/1-A' },
// User {
// name: 'Stefanie',
// age: 25,
// registeredAt: 2015-07-29T22:00:00.000Z,
// id: 'users/2-A' } ]
```
>##### Related tests:
>
> [working with subclause](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/Issues/RavenDB_5669Test/RavenDB_5669Test.php#L44)
#### not()
```php
// RQL
// from users where age != 25
// Query
$session->query(User::class)
->not()
->whereEquals("age", 25)
->toList();
// Sample results
// [ User {
// name: 'John',
// age: 30,
// registeredAt: 2017-11-10T23:00:00.000Z,
// kids: ["Dmitri", "Mara"]
// id: 'users/1-A' } ]
```
>##### Related tests:
>
> [query where not](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/_QueryTest/QueryTest.php#L817)
#### orElse() / andAlso()
```php
// RQL
// from users where exists(kids) or age < 30
// Query
$session->query(User::class)
->whereExists("kids")
->orElse()
->whereLessThan("age", 30)
->toList();
// Sample results
// [ User {
// name: 'John',
// age: 30,
// registeredAt: 2017-11-10T23:00:00.000Z,
// kids: [ 'Dmitri', 'Mara' ],
// id: 'users/1-A' },
// User {
// name: 'Thomas',
// age: 25,
// registeredAt: 2016-04-24T22:00:00.000Z,
// id: 'users/3-A' },
// User {
// name: 'Stefanie',
// age: 25,
// registeredAt: 2015-07-29T22:00:00.000Z,
// id: 'users/2-A' } ]
```
>##### Related tests:
>
> [working with subclause](https://github.com/ravendb/ravendb-nodejs-client/blob/5c14565d0c307d22e134530c8d63b09dfddcfb5b/test/Ported/Issues/RavenDB_5669.ts#L40)
#### usingDefaultOperator()
If neither `andAlso()` nor `orElse()` is called then the default operator between the query filtering conditions will be `AND` .
You can override that with `usingDefaultOperator` which must be called before any other where conditions.
```php
// RQL
// from users where exists(kids) or age < 29
// Query
$session->query(User::class)
->usingDefaultOperator("OR") // override the default 'AND' operator
->whereExists("kids")
->whereLessThan("age", 29)
->toList();
// Sample results
// [ User {
// name: 'John',
// age: 30,
// registeredAt: 2017-11-10T23:00:00.000Z,
// kids: [ 'Dmitri', 'Mara' ],
// id: 'users/1-A' },
// User {
// name: 'Thomas',
// age: 25,
// registeredAt: 2016-04-24T22:00:00.000Z,
// id: 'users/3-A' },
// User {
// name: 'Stefanie',
// age: 25,
// registeredAt: 2015-07-29T22:00:00.000Z,
// id: 'users/2-A' } ]
```
>
>
>
#### orderBy() / orderByDesc() / orderByScore() / randomOrdering()
```php
// RQL
// from users order by age
// Query
$session->query(User::class)
->orderBy("age")
->toList();
// Sample results
// [ User {
// name: 'Stefanie',
// age: 25,
// registeredAt: 2015-07-29T22:00:00.000Z,
// id: 'users/2-A' },
// User {
// name: 'Thomas',
// age: 25,
// registeredAt: 2016-04-24T22:00:00.000Z,
// id: 'users/3-A' },
// User {
// name: 'John',
// age: 30,
// registeredAt: 2017-11-10T23:00:00.000Z,
// kids: [ 'Dmitri', 'Mara' ],
// id: 'users/1-A' } ]
```
>##### Related tests:
>
>
> [query random order](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/_QueryTest/QueryTest.php#L817)
> [order by AlphaNumeric](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/_QueryTest/QueryTest.php#L1103)
> [query with boost - order by score](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/_QueryTest/QueryTest.php#L1026)
#### take()
Limit the number of query results.
```php
// RQL
// from users order by age
// Query
$session->query(User::class)
->orderBy("age")
->take(2) // only the first 2 entries will be returned
->toList();
// Sample results
// [ User {
// name: 'Stefanie',
// age: 25,
// registeredAt: 2015-07-29T22:00:00.000Z,
// id: 'users/2-A' },
// User {
// name: 'Thomas',
// age: 25,
// registeredAt: 2016-04-24T22:00:00.000Z,
// id: 'users/3-A' } ]
```
>##### Related tests:
>
> [query skip take](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/_QueryTest/QueryTest.php#L685)
>
#### skip()
Skip a specified number of results from the start.
```php
// RQL
// from users order by age
// Query
$session->query(User::class)
->orderBy("age")
->take(1) // return only 1 result
->skip(1) // skip the first result, return the second result
->toList();
// Sample results
// [ User {
// name: 'Thomas',
// age: 25,
// registeredAt: 2016-04-24T22:00:00.000Z,
// id: 'users/3-A' } ]
```
>##### Related tests:
>
> [query skip take](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/_QueryTest/QueryTest.php#L685)
>
#### Getting query statistics
Use the `statistics()` method to obtain query statistics.
```php
// Query
$stats = new QueryStatistics();
$results = $session->query(User::class)
->whereGreaterThan("age", 29)
->statistics($stats)
->toList();
// Sample results
// QueryStatistics {
// isStale: false,
// durationInMs: 744,
// totalResults: 1,
// skippedResults: 0,
// timestamp: 2018-09-24T05:34:15.260Z,
// indexName: 'Auto/users/Byage',
// indexTimestamp: 2018-09-24T05:34:15.260Z,
// lastQueryTime: 2018-09-24T05:34:15.260Z,
// resultEtag: 8426908718162809000 }
```
>
#### all() / first() / single() / count()
`all()` - returns all results
`first()` - first result only
`single()` - first result, throws error if there's more entries
`count()` - returns the number of entries in the results (not affected by `take()`)
>##### Related tests:
> [query first and single](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/_QueryTest/QueryTest.php#L917)
> [query count](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/_QueryTest/QueryTest.php#L951)
## Attachments
#### Store attachments
```php
$doc = new User();
$doc->setName('John');
// Store a document, the entity will be tracked.
$session->store($doc);
// Get read stream or buffer to store
$fileStream = file_get_contents("../photo.png");
// Store attachment using entity
$session->advanced()->attachments()->store($doc, "photo.png", $fileStream, "image/png");
// OR store attachment using document ID
$session->advanced()->attachments()->store($doc->getId(), "photo.png", $fileStream, "image/png");
// Persist all changes
$session->saveChanges();
```
>##### Related tests:
>
> [can put attachments](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/Attachments/AttachmentsSessionTest.php#L15)
>
>
#### Get attachments
```php
// Get an attachment
$attachment = $session->advanced()->attachments()->get($documentId, "photo.png")
// Attachment.details contains information about the attachment:
// {
// name: 'photo.png',
// documentId: 'users/1-A',
// contentType: 'image/png',
// hash: 'MvUEcrFHSVDts5ZQv2bQ3r9RwtynqnyJzIbNYzu1ZXk=',
// changeVector: '"A:3-K5TR36dafUC98AItzIa6ow"',
// size: 4579
// }
// Attachment.data is a Readable.
$fileBytes = $attachment->getData();
file_put_contents('../photo.png', $fileBytes);
```
>##### Related tests:
>
> [can get & delete attachments](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/Attachments/AttachmentsSessionTest.php#L144)
#### Check if attachment exists
```php
$session->advanced()->attachments()->exists($doc->getId(), "photo.png");
// true
$session->advanced()->attachments()->exists($doc->getId(), "not_there.avi");
// false
```
>##### Related tests:
>
> [attachment exists 2](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/Attachments/AttachmentsSessionTest.php#L419)
#### Get attachment names
```php
// Use a loaded entity to determine attachments' names
$session->advanced()->attachments()->getNames($doc);
// Sample results:
// [ { name: 'photo.png',
// hash: 'MvUEcrFHSVDts5ZQv2bQ3r9RwtynqnyJzIbNYzu1ZXk=',
// contentType: 'image/png',
// size: 4579 } ]
```
>##### Related tests:
>
> [get attachment names 2](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/Attachments/AttachmentsSessionTest.php#L376)
## TimeSeries
#### Store time series
```php
$session = $store->openSession();
// Create a document with time series
$session->store(new User(), "users/1");
$tsf = $session->timeSeriesFor("users/1", "heartbeat");
// Append a new time series entry
$tsf->append(new DateTime(), 120);
$session->saveChanges();
```
>##### Related tests:
>
> [canCreateSimpleTimeSeries](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/TimeSeries/TimeSeriesSessionTest.php#L16)
> [usingDifferentTags](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/TimeSeries/TimeSeriesSessionTest.php#L244)
> [canStoreAndReadMultipleTimestamps](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/TimeSeries/TimeSeriesSessionTest.php#L384)
> [canStoreLargeNumberOfValues](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/TimeSeries/TimeSeriesSessionTest.php#L441)
> [shouldDeleteTimeSeriesUponDocumentDeletion](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/TimeSeries/TimeSeriesSessionTest.php#L796)
#### Get time series for document
```php
$session = $store->openSession();
// Get time series for document by time series name
$tsf = $session->timeSeriesFor("users/1", "heartbeat");
// Get all time series entries
$heartbeats = $tsf->get();
```
>##### Related tests:
> [canCreateSimpleTimeSeries](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/TimeSeries/TimeSeriesSessionTest.php#L16)
> [canStoreLargeNumberOfValues](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/TimeSeries/TimeSeriesSessionTest.php#L441)
> [canRequestNonExistingTimeSeriesRange](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/TimeSeries/TimeSeriesSessionTest.php#L574)
> [canGetTimeSeriesNames2](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/TimeSeries/TimeSeriesSessionTest.php#L701)
> [canSkipAndTakeTimeSeries](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/TimeSeries/TimeSeriesSessionTest.php#L850)
## Revisions
NOTE: Please make sure revisions are enabled before trying the below.
```php
$user = new User();
$user->setName("Marcin");
$user->setAge(30);
$user->setPet("Cat");
$session = $store->openSession();
// Store a document
$session->store($user, "users/1");
$session->saveChanges();
// Modify the document to create a new revision
$user->setName("Roman");
$user->setAge(40);
$session->saveChanges();
// Get revisions
$revisions = $session->advanced()->revisions()->getFor("users/1");
// Sample results:
// [ { name: 'Roman',
// age: 40,
// pet: 'Cat',
// '@metadata': [Object],
// id: 'users/1' },
// { name: 'Marcin',
// age: 30,
// pet: 'Cat',
// '@metadata': [Object],
// id: 'users/1' }
// ]
```
## Suggestions
Suggest options for similar/misspelled terms
```php
// Some documents in users collection with misspelled name term
// [ User {
// name: 'Johne',
// age: 30,
// ...
// id: 'users/1-A' },
// User {
// name: 'Johm',
// age: 31,
// ...
// id: 'users/2-A' },
// User {
// name: 'Jon',
// age: 32,
// ...
// id: 'users/3-A' },
// ]
// Static index definition
class UsersIndex extends AbstractJavaScriptIndexCreationTask {
public function __construct() {
parent::__construct();
$this->map = "from user in docs.users select new { user.name }";
// Enable the suggestion feature on index-field 'name'
$this->suggestion("name");
}
}
// ...
$session = $store->openSession();
// Query for similar terms to 'John'
// Note: the term 'John' itself will Not be part of the results
$suggestedNameTerms = $session->query(User::class, UsersIndex::class)
->suggestUsing(function($x) { return $x->byField("name", "John"); })
->execute();
// Sample results:
// { name: { name: 'name', suggestions: [ 'johne', 'johm', 'jon' ] } }
```
## Advanced patching
```php
// Increment 'age' field by 1
$session->advanced()->increment("users/1", "age", 1);
// Set 'underAge' field to false
$session->advanced->patch("users/1", "underAge", false);
$session->saveChanges();
```
>##### Related tests:
>
> [can patch](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/_FirstClassPatchTest/FirstClassPatchTest.php#L19)
> [can patch complex](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/_FirstClassPatchTest/FirstClassPatchTest.php#L112)
> [can add to array](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/_FirstClassPatchTest/FirstClassPatchTest.php#L206)
> [can increment](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/_FirstClassPatchTest/FirstClassPatchTest.php#L368)
> [patchWillUpdateTrackedDocumentAfterSaveChanges](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Issues/RavenDB_11552Test.php#L17)
> [can patch single document](https://github.com/ravendb/ravendb-php-client/blob/282c7bf6d2580ba446e878498d215a38caa67799/tests/Test/Client/PatchTest.php#L17)
>
## Using classes for entities
1. Define your model as class. Attributes should be just public properties:
```php
class Product {
public ?string $id = null,
public string $title = '',
public int $price = 0,
public string $currency = 'USD',
public int $storage = 0,
public string $manufacturer = '',
public bool $in_stock = false,
public ?DateTime $last_update = null
public function __construct(
$id = null,
$title = '',
$price = 0,
$currency = 'USD',
$storage = 0,
$manufacturer = '',
$in_stock = false,
$last_update = null
) {
$this->id = $id;
$this->title = $title;
$this->price = $price;
$this->currency = $currency;
$this->storage = $storage;
$this->manufacturer = $manufacturer;
$this->in_stock = $in_stock;
$this->last_update = $last_update ?? new DateTime();
}
}
```
2. To store a document pass its instance to `store()`.
The collection name will automatically be detected from the entity's class name.
```php
use models\Product;
$product = new Product(
null, 'iPhone X', 999.99, 'USD', 64, 'Apple', true, new Date('2017-10-01T00:00:00'));
$product = $session->store($product);
var_dump($product instanceof Product); // true
var_dump(str_starts_with($product->id, 'products/')); // true
$session->saveChanges();
```
3. Loading a document
```php
$product = $session->load('products/1-A');
var_dump($product instanceof Product); // true
var_dump($product->id); // products/1-A
```
4. Querying for documents
```php
$products = $session->query(Product::class)->toList();
foreach($products as $product) {
var_dump($product instanceof Product); // true
var_dump(str_starts_with($product->id, 'products/')); // true
});
```
>
## Usage with PHP
PHP typings are embedded into the package. Make sure to close session when you finish your work with it.
```php
// file models/product.php
class Product {
public ?string $id = null,
public string $title = '',
public int $price = 0,
public string $currency = 'USD',
public int $storage = 0,
public string $manufacturer = '',
public bool $in_stock = false,
public ?DateTime $last_update = null
public function __construct(
$id = null,
$title = '',
$price = 0,
$currency = 'USD',
$storage = 0,
$manufacturer = '',
$in_stock = false,
$last_update = null
) {
$this->id = $id;
$this->title = $title;
$this->price = $price;
$this->currency = $currency;
$this->storage = $storage;
$this->manufacturer = $manufacturer;
$this->in_stock = $in_stock;
$this->last_update = $last_update ?? new DateTime();
}
}
// file app.php
use models\Product;
use RavenDB\Documents\DocumentStore;
use RavenDB\Documents\Session\DocumentSession;
$store = new DocumentStore('url', 'database name');
try {
$store->initialize();
$productId = null;
/** @var DocumentSession $session */
$session = $store->openSession();
try {
$product = new Product(
null, 'iPhone X', 999.99, 'USD', 64, 'Apple', true, new Date('2017-10-01T00:00:00'));
$session->store($product);
$session->saveChanges();
var_dump($product instanceof Product); // true
var_dump(str_starts_with($product->id, 'products/')); // true
$productId = $product->id;
} finally {
$session->close();
}
$session = $store->openSession();
try {
/** @var Product $product */
$product = $session->load(Product::class, $productId);
var_dump($product instanceof Product); // true
var_dump($product->id); // products/1-A
/** @var array $products */
$products = $session->query(Query::collection('Products'))
->waitForNonStaleResults()
->whereEquals('manufacturer', 'Apple')
->whereEquals('in_stock', true)
->whereBetween('last_update', new DateTime('- 1 week'), new DateTime())
->whereGreaterThanOrEqual('storage', 64)
->toList();
foreach ($products as $product) {
var_dump($product instanceof Product); // true
var_dump(str_starts_with($product->id, 'products/')); // true
}
} finally {
$session->close();
}
} finally {
$store->close();
}
```
## Working with a secure server
Your certificate and server certificate should be saved in PEM format to your machine.
1. Create AuthOptions:
```php
$authOptions = AuthOptions::pem(
'../clientCertPath.pem',
'clientCertPass',
'../serverCaCertPath.pem'
);
```
2. Pass auth options to `DocumentStore` object:
```php
$store = new DocumentStore('url', 'databaseName');
$store->setAuthOptions($authOptions); // use auth options to connect on database
$store->initialize();
```
## Running tests
Clone the repository:
```bash
git clone https://github.com/ravendb/ravendb-php-client
```
Install dependencies:
```bash
composer install
```
Run RavenDB server
```bash
https://a.phptest.development.run
```
Set environment variables.
```bash
# Set the following environment variables:
#
# - Certificate hostname
# RAVENDB_PHP_TEST_HTTPS_SERVER_URL=https://a.phptest.development.run
#
# RAVENDB_PHP_TEST_CA_PATH=
#
# - Certificate path for tests requiring a secure server:
# RAVENDB_PHP_TEST_CERTIFICATE_PATH=
#
# - Certificate for client
# RAVENDB_TEST_CLIENT_CERT_PATH=
# RAVENDB_TEST_CLIENT_CERT_PASSPHRASE=
#
# - For some tests, Developers licence is required in order to run them all
# RAVEN_LICENSE=
```
Run PHPUnit
```bash
./vendor/bin/phpunit
```
-----
##### Bug Tracker
[http://issues.hibernatingrhinos.com/issues/RDBC](http://issues.hibernatingrhinos.com/issues/RDBC)
-----
##### License
The MIT License (MIT). Please see [License File](LICENSE.md) for more information.