Skip to content

Commit

Permalink
No commit message
Browse files Browse the repository at this point in the history
  • Loading branch information
2 parents 35f5a73 + 0640326 commit 342b5ec
Show file tree
Hide file tree
Showing 14 changed files with 1,068 additions and 98 deletions.
34 changes: 34 additions & 0 deletions README-PSR16.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Momento PSR-16 Client Library

The Momento PSR-16 client library, `Psr16SimpleCache`, implements the [PHP PSR-16 common interface for caching
libraries](https://www.php-fig.org/psr/psr-16/) for the Momento Serverless Cache. Note that the client library
is under development and may be subject to backward-incompatible changes.

## Getting Started :running:

### Requirements

- A Momento Auth Token is required, you can generate one using
the [Momento CLI](https://github.com/momentohq/momento-cli)
- At least PHP 8.0
- The grpc PHP extension. See the [gRPC docs](https://github.com/grpc/grpc/blob/v1.46.3/src/php/README.md) section on
installing the extension.

**IDE Notes**: You'll most likely want to use an IDE that supports PHP development, such
as [PhpStorm](https://www.jetbrains.com/phpstorm/) or [Microsoft Visual Studio Code](https://code.visualstudio.com/).

### Examples

Check out the
full [PSR-16 library example](https://github.com/momentohq/client-sdk-php/blob/main/examples/psr16-example.php) in the
[examples directory](https://github.com/momentohq/client-sdk-php/blob/main/examples) of this repository!

### Implementation Notes

- Please note that this library is under active development and may be subject to backward-incompatible changes.
- The `clear()` function defined in the PSR-16 specification is currently unimplemented in this client
library and throws a `Momento\Cache\Errors\NotImplementedException` if called. It is coming soon, though, so stay
tuned!
- The `getMultiple()`, `setMultiple()`, and `deleteMultiple()` functionality is currently implemented client-side and
may exhibit slower performance than expected. These methods will be replaced with calls to server-side implementations
in the near future.
94 changes: 74 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ as [PhpStorm](https://www.jetbrains.com/phpstorm/) or [Microsoft Visual Studio C

Check out full working code in [the examples directory](examples/) of this repository!

In addition to the primary Momento `SimpleCacheClient` library used in most of the examples, a PHP PSR-16
implementation and corresponding example are also included in the SDK. See the PSR-16 client [README](README-PSR16.md)
and [example](https://github.com/momentohq/client-sdk-php/blob/psr16-library/examples/psr16-example.php) for more
details.

### Installation

Install composer [as described on the composer website](https://getcomposer.org/doc/00-intro.md).
Expand Down Expand Up @@ -69,90 +74,139 @@ Here is an example to get you started:

```php
<?php
declare(strict_types=1);

require "vendor/autoload.php";

use Momento\Auth\EnvMomentoTokenProvider;
use Momento\Cache\SimpleCacheClient;
use Momento\Utilities\LoggingHelper;
use Monolog\Logger;

$MOMENTO_AUTH_TOKEN = getenv("MOMENTO_AUTH_TOKEN");
$CACHE_NAME = getenv("CACHE_NAME");
if (!$CACHE_NAME) {
print "Error: Environment variable CACHE_NAME was not found.\n";
exit;
}
$ITEM_DEFAULT_TTL_SECONDS = 60;
$KEY = "MyKey";
$VALUE = "MyValue";
$logger = LoggingHelper::getMinimalLogger("example.php");

function printBanner(string $message): void
function printBanner(string $message, Logger $logger): void
{
$line = "******************************************************************";
print "$line\n$message\n$line\n";
$logger->info($line);
$logger->info($message);
$logger->info($line);
}

printBanner("* Momento Example Start *");
printBanner("* Momento Example Start *", $logger);
// Setup
$authProvider = new EnvMomentoTokenProvider("MOMENTO_AUTH_TOKEN");
$client = new SimpleCacheClient($authProvider, $ITEM_DEFAULT_TTL_SECONDS);

// Ensure test cache exists
$response = $client->createCache($CACHE_NAME);
if ($response->asSuccess()) {
print "Created cache " . $CACHE_NAME . "\n";
$logger->info("Created cache " . $CACHE_NAME . "\n");
} elseif ($response->asError()) {
print "Error creating cache: " . $response->asError()->message() . "\n";
$logger->info("Error creating cache: " . $response->asError()->message() . "\n");
exit;
} elseif ($response->asAlreadyExists()) {
print "Cache " . $CACHE_NAME . " already exists.\n";
$logger->info("Cache " . $CACHE_NAME . " already exists.\n");
}

// List cache
$response = $client->listCaches();
if ($response->asSuccess()) {
while (true) {
print "SUCCESS: List caches: \n";
$logger->info("SUCCESS: List caches: \n");
foreach ($response->asSuccess()->caches() as $cache) {
$cacheName = $cache->name();
print "$cacheName\n";
$logger->info("$cacheName\n");
}
$nextToken = $response->asSuccess()->nextToken();
if (!$nextToken) {
break;
}
$response = $client->listCaches($nextToken);
}
print "\n";
$logger->info("\n");
} elseif ($response->asError()) {
print "Error listing cache: " . $response->asError()->message() . "\n";
$logger->info("Error listing cache: " . $response->asError()->message() . "\n");
exit;
}

// Set
print "Setting key: $KEY to value: $VALUE\n";
$logger->info("Setting key: $KEY to value: $VALUE\n");
$response = $client->set($CACHE_NAME, $KEY, $VALUE);
if ($response->asSuccess()) {
print "SUCCESS: - Set key: " . $KEY . " value: " . $VALUE . " cache: " . $CACHE_NAME . "\n";
$logger->info("SUCCESS: - Set key: " . $KEY . " value: " . $VALUE . " cache: " . $CACHE_NAME . "\n");
} elseif ($response->asError()) {
print "Error setting key: " . $response->asError()->message() . "\n";
$logger->info("Error setting key: " . $response->asError()->message() . "\n");
exit;
}

// Get
print "Getting value for key: $KEY\n";
$logger->info("Getting value for key: $KEY\n");
$response = $client->get($CACHE_NAME, $KEY);
if ($response->asHit()) {
print "SUCCESS: - Get key: " . $KEY . " value: " . $response->asHit()->value() . " cache: " . $CACHE_NAME . "\n";
$logger->info("SUCCESS: - Get key: " . $KEY . " value: " . $response->asHit()->value() . " cache: " . $CACHE_NAME . "\n");
} elseif ($response->asMiss()) {
print "Get operation was a MISS\n";
$logger->info("Get operation was a MISS\n");
} elseif ($response->asError()) {
print "Error getting cache: " . $response->asError()->message() . "\n";
$logger->info("Error getting cache: " . $response->asError()->message() . "\n");
exit;
}

printBanner("* Momento Example End *");
printBanner("* Momento Example End *", $logger);

```

### Error Handling

Coming soon!
Errors that occur in calls to `SimpleCacheClient` methods are surfaced to developers as part of the return values of
the calls, as opposed to by throwing exceptions. This makes them more visible, and allows your IDE to be more
helpful in ensuring that you've handled the ones you care about. (For more on our philosophy about this, see our
blog post on why [Exceptions are bugs](https://www.gomomento.com/blog/exceptions-are-bugs). And send us any
feedback you have!)

The preferred way of interpreting the return values from `SimpleCacheClient` methods is
using `as` methods to match and handle the specific response type. Here's a quick example:

```php
$getResponse = $client->get($CACHE_NAME, $KEY);
if ($hitResponse = $getResponse->asHit())
{
print "Looked up value: {$hitResponse->value()}\n");
} else {
// you can handle other cases via pattern matching in `else if` blocks, or a default case
// via the `else` block. For each return value your IDE should be able to give you code
// completion indicating the other possible "as" methods; in this case, `$getResponse->asMiss()`
// and `$getResponse->asError()`.
}
```

Using this approach, you get a type-safe `hitResponse` object in the case of a cache hit. But if the cache read
results in a Miss or an error, you'll also get a type-safe object that you can use to get more info about what happened.

In cases where you get an error response, it will always include an `ErrorCode` that you can use to check
the error type:

```php
$getResponse = $client->get($CACHE_NAME, $KEY);
if ($errorResponse = $getResponse->asError())
{
if ($errorResponse->errorCode() == MomentoErrorCode::TIMEOUT_ERROR) {
// this would represent a client-side timeout, and you could fall back to your original data source
}
}
```

Note that, outside of `SimpleCacheClient` responses, exceptions can occur and should be handled as usual. For example,
trying to instantiate a `SimpleCacheClient` with an invalid authentication token will result in an
`IllegalArgumentException` being thrown.

### Tuning

Expand Down
47 changes: 46 additions & 1 deletion README.template.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ as [PhpStorm](https://www.jetbrains.com/phpstorm/) or [Microsoft Visual Studio C

Check out full working code in [the examples directory](examples/) of this repository!

In addition to the primary Momento `SimpleCacheClient` library used in most of the examples, a PHP PSR-16
implementation and corresponding example are also included in the SDK. See the PSR-16 client [README](README-PSR16.md)
and [example](https://github.com/momentohq/client-sdk-php/blob/psr16-library/examples/psr16-example.php) for more
details.

### Installation

Install composer [as described on the composer website](https://getcomposer.org/doc/00-intro.md).
Expand Down Expand Up @@ -53,7 +58,47 @@ Here is an example to get you started:

### Error Handling

Coming soon!
Errors that occur in calls to `SimpleCacheClient` methods are surfaced to developers as part of the return values of
the calls, as opposed to by throwing exceptions. This makes them more visible, and allows your IDE to be more
helpful in ensuring that you've handled the ones you care about. (For more on our philosophy about this, see our
blog post on why [Exceptions are bugs](https://www.gomomento.com/blog/exceptions-are-bugs). And send us any
feedback you have!)

The preferred way of interpreting the return values from `SimpleCacheClient` methods is
using `as` methods to match and handle the specific response type. Here's a quick example:

```php
$getResponse = $client->get($CACHE_NAME, $KEY);
if ($hitResponse = $getResponse->asHit())
{
print "Looked up value: {$hitResponse->value()}\n");
} else {
// you can handle other cases via pattern matching in `else if` blocks, or a default case
// via the `else` block. For each return value your IDE should be able to give you code
// completion indicating the other possible "as" methods; in this case, `$getResponse->asMiss()`
// and `$getResponse->asError()`.
}
```

Using this approach, you get a type-safe `hitResponse` object in the case of a cache hit. But if the cache read
results in a Miss or an error, you'll also get a type-safe object that you can use to get more info about what happened.

In cases where you get an error response, it will always include an `ErrorCode` that you can use to check
the error type:

```php
$getResponse = $client->get($CACHE_NAME, $KEY);
if ($errorResponse = $getResponse->asError())
{
if ($errorResponse->errorCode() == MomentoErrorCode::TIMEOUT_ERROR) {
// this would represent a client-side timeout, and you could fall back to your original data source
}
}
```

Note that, outside of `SimpleCacheClient` responses, exceptions can occur and should be handled as usual. For example,
trying to instantiate a `SimpleCacheClient` with an invalid authentication token will result in an
`IllegalArgumentException` being thrown.

### Tuning

Expand Down
4 changes: 3 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@
"ext-grpc": "*",
"firebase/php-jwt": "^6.3",
"google/protobuf": "3.21.5",
"grpc/grpc": "1.42.0"
"grpc/grpc": "1.42.0",
"monolog/monolog": "^2.5",
"psr/simple-cache": "^3.0"
},
"require-dev": {
"composer/composer": "^2.4.1",
Expand Down
Loading

0 comments on commit 342b5ec

Please sign in to comment.