PHPackages                             jlucki/spark - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. jlucki/spark

ActiveLibrary[Database &amp; ORM](/categories/database)

jlucki/spark
============

Spark is an Object Document Mapper (ODM) for use with Amazon DynamoDB.

v0.1.2(4y ago)290[2 issues](https://github.com/jlucki/spark/issues)MITPHPPHP &gt;=8.0

Since Jan 4Pushed 4y ago2 watchersCompare

[ Source](https://github.com/jlucki/spark)[ Packagist](https://packagist.org/packages/jlucki/spark)[ Docs](https://www.lucki.dev)[ RSS](/packages/jlucki-spark/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (3)Dependencies (5)Versions (5)Used By (0)

Spark Object Document Mapper
============================

[](#spark-object-document-mapper)

[![GitHub license](https://camo.githubusercontent.com/f8df3091bbe1149f398a5369b2c39e896766f9f6efba3477c63e9b4aa940ef14/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d677265656e)](https://choosealicense.com/licenses/mit/)[![Code coverage](https://camo.githubusercontent.com/3d33a7ebccb0fe6dd3bdddc127bfebe36a11388e4f2bce3d15e5b57d12f6b53c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f636f7665726167652d31312e37302532352d726564)](https://camo.githubusercontent.com/3d33a7ebccb0fe6dd3bdddc127bfebe36a11388e4f2bce3d15e5b57d12f6b53c/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f636f7665726167652d31312e37302532352d726564)

**Spark ODM is currently in its infancy and may not be suitable for all applications. Please consider your use case carefully before deploying it to any critical systems.**

### Test Drive DynamoDB

[](#test-drive-dynamodb)

If you're looking for an easy, model driven way to get started with DynamoDB, look no further. This ODM comes equipped with [Docker](https://docs.docker.com/get-docker/) configuration files. Download the library and run `docker-compose up` to spin up a local development environment, including a local instance of DynamoDB.

Once the containers are running, simply visit `localhost` in your browser. Refresh a couple of times to get additional example blog entries. Have a look at `public/index.php` to see what's happening under the hood.

You can also download the [NoSQL Workbench from AWS](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/workbench.settingup.html), to easily browse your DynamoDB data. Once installed, open the workbench, click on `Operation builder` on the left hand side menu. Click on `+ Add connection`, switch to `DynamoDB local`, give the connection a name, leave the port on 8000, and click on `Connect`.

### Requirements

[](#requirements)

This library only works with PHP 8.0 and up.

Documentation
-------------

[](#documentation)

Spark is a PHP ODM library for use with Amazon DynamoDB.

### How to install using Composer:

[](#how-to-install-using-composer)

```
composer require jlucki/spark

```

### How to create a Spark connection:

[](#how-to-create-a-spark-connection)

If you're using Symfony, you can make use of Symfony's autowiring and add Spark to your service's constructor.

```
public function __construct(
    private Spark $spark,
) {}
```

Otherwise, you can simply create a new Spark class, passing in the required credentials.

```
$spark = new Spark(
    'latest', // version
    'us-east-1', // region
    'http://dynamodb:8000', // endpoint, use 'regional' for production
    'aws_access_key_id', // your aws access key
    'aws_access_key_secret', // your aws access key secret
);
```

*Tip: You can use an empty string for the id and secret for local development.*

### How to create a data model:

[](#how-to-create-a-data-model)

See [Article.php](https://github.com/jlucki/spark/blob/master/src/Spark/Model/Article.php) for an example table/item data model.

### How to create a global secondary index:

[](#how-to-create-a-global-secondary-index)

To create a GSI on your table add the `GlobalSecondaryIndex` attribute to the property. The GSI name will default to the value of `AttributeName`. Alternatively, you can assign a custom name by passing a string into the GSI attribute `GlobalSecondaryIndex('customName')`.

**Note:** You must provide a custom name for a GSI if the GSI has both `HASH` and `RANGE` keys, otherwise the two keys will not be recognised as a single GSI. See example below.

The default projection type is `KEYS_ONLY`. To change the projection type add the `ProjectionType` attribute to the property, and pass in one of the following values: `ProjectionType::KEYS_ONLY`, `ProjectionType::INCLUDE`, or `ProjectionType::ALL`.

When using `ProjectionType::INCLUDE`, you will also have to add the `NonKeyAttributes` attribute to the property, and pass in an array that contains the names of any attributes you want to project into the index. For example: `NonKeyAttributes(['title', 'content'])`

```
#[
    KeyType('HASH'),
    AttributeName('slug'),
    AttributeType('S'),
    GlobalSecondaryIndex('slugIndex'),
    ProjectionType(ProjectionType::ALL),
]
private string $slug;

#[
    KeyType('RANGE'),
    AttributeName('slugDatetime'),
    AttributeType('N'),
    GlobalSecondaryIndex('slugIndex'),
    ProjectionType(ProjectionType::ALL),
]
private DateTime $newSlugDatetime;
```

### How to create a table:

[](#how-to-create-a-table)

```
$table = $spark->createTable(Article::class);
```

### How to get or check if a table exists:

[](#how-to-get-or-check-if-a-table-exists)

```
$table = $spark->getTable(Article::class);
```

### How to update a table:

[](#how-to-update-a-table)

```
$result = $spark->updateTable(Article::class);
```

The `updateTable()` method will compare the described table schema as provided by DynamoDB to your local file schema, and compute any required changes. The `updateTable()` method supports:

- Creating a new GSI
- Removing an existing GSI
- Uptading a GSI, but only if you're also updating the ProvisionedThroughput. This is an apparent limitation of the AWS PHP SDK.

*Tip: You can add open attributes to your model without running the `updateTable()` method. This data will be automatically added to your table next time you put or update the item.*

### How to delete a table:

[](#how-to-delete-a-table)

```
$result = $spark->deleteTable(Article::class);
```

*Warning: This will also delete all items in the table. This cannot be undone.*

### How to put a new item into the database:

[](#how-to-put-a-new-item-into-the-database)

```
$date = new DateTime();

$blog = (new Article())
    ->setType('blog')
    ->setDatetime($date)
    ->setSlug('my-blog-post-' . $date->format('y-m-d-H-i-s'))
    ->setTitle('My Blog Post ' . $date->format('Y-m-d H:i:s'))
    ->setContent('Hello, this is the blog post content.');

// putItem() will return the same object that it persisted to DynamoDB
$blog = $spark->putItem($blog);
```

### How to get an item from the database:

[](#how-to-get-an-item-from-the-database)

```
$itemByKey = $spark->getItem(Article::class, [
    'datetime' => $timestamp,
    'type' => 'blog',
]);
```

### How to get an item from the database using a secondary index:

[](#how-to-get-an-item-from-the-database-using-a-secondary-index)

You cannot use `getItem()` to retrieve an item from DynamoDB using a secondary index. This is because a secondary index's hash and range keys are not unique. You can however, query the table using the secondary index, and get the first result. See [here](#how-to-query-specific-items-using-a-secondary-index) for more details.

### How to update an item in the database:

[](#how-to-update-an-item-in-the-database)

```
$blog->setContent('Updated content!');

try {
    $blog = $spark->updateItem($blog);
} catch (ItemActionFailedException $e) {
    // handle the error
}

if ($blog instanceof Article) {
    // success
}
```

### How to delete an item from the database:

[](#how-to-delete-an-item-from-the-database)

```
try {
    $result = $spark->deleteItem($blog);
} catch (ItemActionFailedException $e) {
    // handle the error
}
```

### How to scan the whole table:

[](#how-to-scan-the-whole-table)

```
$allItems = $spark->scan(Article::class);
```

### How to query specific items:

[](#how-to-query-specific-items)

```
$from = (new DateTime())->setDate(2010, 1, 1)->getTimestamp();

$blogs = $spark
    ->query(Article::class)
    ->findBy(
        (new Expression())
            ->attribute('datetime')
            ->comparison('>=')
            ->value($from)
    )
    ->findBy(
        (new Expression())
            ->attribute('type')
            ->value('blog')
    )
    ->consistentRead(false)
    ->sortOrder('desc')
    ->getItems();
```

*Tip: `findBy()` only works on table index attributes. You can use `filterBy()`, also passing in an `Expression` object, to additionally filter by other attributes.*

*Tip: You can also return the raw `AWS\Result` with `getRaw()` or return all details, including the LastEvaluatedKey in an easy to use object with `getHeap()`.*

### How to query specific items using a secondary index:

[](#how-to-query-specific-items-using-a-secondary-index)

```
$slug = 'my-blog-post-20-12-28-14-46-01';

$foundBySlug = $spark
    ->query(Article::class)
    ->indexName('slug')
    ->findBy(
        (new Expression())
            ->attribute('slug')
            ->value($slug)
    )
    ->getItems();
```

*Tip: If you're expecting a single item result with your query, you can use `getFirst()` instead of `getItems()`. This will return the first `ItemInterface` object from your results, or `null` if nothing is found.*

### How to get a count of your queried items:

[](#how-to-get-a-count-of-your-queried-items)

```
// getCount() will automatically loop through any additional results
// if the first query result contains a LastEvaluatedKey to get the full count
$totalBlogs = $spark
    ->query(Article::class)
    ->findBy(
        (new Expression())
            ->attribute('datetime')
            ->comparison('>=')
            ->value($from)
    )
    ->findBy(
        (new Expression())
            ->attribute('type')
            ->value('blog')
    )
    ->getCount();
```

### How to query the DynamoDbClient directly:

[](#how-to-query-the-dynamodbclient-directly)

The scope of the ODM doesn't cover the entire AWS SDK for PHP for DynamoDB. You can access the DynamoDbClient and all its methods, and run your own custom queries, with the method below.

```
$dynamoDbClient = $spark->client();
```

###  Health Score

20

—

LowBetter than 14% of packages

Maintenance0

Infrequent updates — may be unmaintained

Popularity12

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity51

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~236 days

Total

3

Last Release

1478d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/166e9750b5ae6192f2bc60b0c71db361cadb38d37f381d5f767236a5c00eacc9?d=identicon)[jlucki](/maintainers/jlucki)

---

Top Contributors

[![jlucki](https://avatars.githubusercontent.com/u/30590452?v=4)](https://github.com/jlucki "jlucki (3 commits)")

---

Tags

phpawsdynamodbdatadatabaseobjectnosqlmappingmapperodm

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan, Psalm

Type Coverage Yes

### Embed Badge

![Health badge](/badges/jlucki-spark/health.svg)

```
[![Health](https://phpackages.com/badges/jlucki-spark/health.svg)](https://phpackages.com/packages/jlucki-spark)
```

###  Alternatives

[doctrine/mongodb-odm

PHP Doctrine MongoDB Object Document Mapper (ODM) provides transparent persistence for PHP objects to MongoDB.

1.1k23.3M299](/packages/doctrine-mongodb-odm)[doctrine/phpcr-odm

PHP Doctrine Content Repository Object Document Mapper (ODM) provides transparent persistence for PHP objects.

1811.5M97](/packages/doctrine-phpcr-odm)[basho/riak

Official Riak client for PHP

159246.7k7](/packages/basho-riak)[event4u/data-helpers

Framework-agnostic PHP library for data mapping, DTOs and utilities. Includes DataMapper, SimpleDto/LiteDto, DataAccessor/Mutator/Filter and helper classes (MathHelper, EnvHelper, etc.). Works with Laravel, Symfony/Doctrine or standalone PHP.

1421.5k](/packages/event4u-data-helpers)[f21/paradox

Paradox is an elegant Object Document Mananger (ODM) to use with the ArangoDB Document/Graph database server.

256.8k](/packages/f21-paradox)[tbolier/php-rethink-ql

A clean and solid RethinkDB driver for PHP.

5211.7k](/packages/tbolier-php-rethink-ql)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
