{"id":15027419,"url":"https://github.com/autoprotect-group/php-dynamodb-odm","last_synced_at":"2025-10-14T03:17:35.511Z","repository":{"id":171604186,"uuid":"646782478","full_name":"AutoProtect-Group/php-dynamodb-odm","owner":"AutoProtect-Group","description":"This is a PHP library and an Object Document Mapper to use with AWS DynamoDB in a more convenient way","archived":false,"fork":false,"pushed_at":"2024-08-27T14:52:44.000Z","size":194,"stargazers_count":3,"open_issues_count":0,"forks_count":2,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-03-23T22:13:57.723Z","etag":null,"topics":["aws","dynamodb","object-document-mapper","odm","php","php81"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AutoProtect-Group.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-05-29T10:28:36.000Z","updated_at":"2024-08-27T14:51:51.000Z","dependencies_parsed_at":"2025-02-15T20:33:24.866Z","dependency_job_id":"f398cd1a-45da-4d09-bc5a-d3afea3603a2","html_url":"https://github.com/AutoProtect-Group/php-dynamodb-odm","commit_stats":null,"previous_names":["autoprotect-group/php-dynamodb-odm"],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AutoProtect-Group%2Fphp-dynamodb-odm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AutoProtect-Group%2Fphp-dynamodb-odm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AutoProtect-Group%2Fphp-dynamodb-odm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AutoProtect-Group%2Fphp-dynamodb-odm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AutoProtect-Group","download_url":"https://codeload.github.com/AutoProtect-Group/php-dynamodb-odm/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248104636,"owners_count":21048373,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws","dynamodb","object-document-mapper","odm","php","php81"],"created_at":"2024-09-24T20:06:24.236Z","updated_at":"2025-10-14T03:17:30.486Z","avatar_url":"https://github.com/AutoProtect-Group.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# AWS Dynamodb ODM for PHP\n\n![Code style, unit and functional tests](https://github.com/AutoProtect-Group/php-dynamodb-odm/actions/workflows/ci.yml/badge.svg)\n\nThis is a library and an Object Document Mapper to use with AWS DynamoDB in a more convenient way.\n\n## Usage\n\n### Configure the ODM\n\nSet up native client:\n\n```php\n$dynamoDbClient = new DynamoDbClient(array_merge(\n    [\n        'region' =\u003e 'eu-west-2',\n        'version' =\u003e 'latest',\n    ]\n));\n```\n\nSet up the main operations lib client:\n\n```php\n$client = new DynamodbOperationsClient($dynamoDbClient);\n```\n\nSet up the marshaller. Native AWS marshaller may be taken:\n```php\n$marshaler = new Marshaler();\n```\nSet up the Query builder:\n\n```php\n$queryBuilder = new QueryBuilder($marshaler, new ExpressionFactory($marshaler));\n```\n\nSet up annotation reader and annotation manager:\n\n```php\n// annotation reader\n$annotationReader = new AnnotationReader();\n\n// annotation manager\n$annotationManager = new AnnotationManager($annotationReader);\n```\n\nThe hydrators for the models:\n\n```php\n$newModelHydrator = new Hydrator(NewModel::class, $annotationManager);\n$sortKeyModelHydrator = new Hydrator(SortKeyModel::class, $annotationManager);\n```\nSerializer for inserting records into DB:\n\n```php\n// serializer for\n$serializer = new Serializer($annotationManager);\n```\n\nThe full example is in [here](examples/initialise_client.php).\n\n### Model\n\n#### Model field types\n\nThe lib operates with models. Each model may have various supported field types. Here is a list of types which correlate with PHP and Dynamodb types:\n\n- `BooleanType`: boolean for DynamoDb and for php\n- `CollectionType`: list for DynamoDb, in php it's an array list of items of specific model\n- `DateType`: string for DynamoDb, DateTime for php\n- `EnumType`: string for DynamoDb, enum for php\n- `FloatType`: number for DynamoDb, float for php\n- `HashMapType`: map for DynamoDb, in php it's associative array of items of specific model\n- `IntegerType`:  number for DynamoDb, int for php\n- `ModelType`: map for DynamoDb, instance of model for php\n- `Money`: map for DynamoDb, special MoneyObject for PHP. [Money value](https://martinfowler.com/eaaCatalog/money.html) as a concept\n- `NumberType`: number for DynamoDb. An abstract type, not a handy one. My be used occasionally\n- `ScalarCollectionType`: map for DynamoDb. in php it's associative array of any dynamodb compatible types excluding `CollectionType`, `HashMapType` or `ModelType`\n- `StringType`: string for DynamoDb and for php\n\nHere is a model example:\n\n```php\nclass ExampleDemoModel extends Model\n{\n    protected const TABLE_NAME = 'test-table';\n    \n    // Primary means that this is a partition key for the DynamoDb table\n    #[StringType, Primary]  protected string $id;\n    #[StringType]           protected string $name;\n    #[FloatType]            protected float $price;\n    #[Money]                protected Money $priceNet;\n    #[FloatType]            protected float $percent;\n    #[IntegerType]          protected int $itemsAmount;\n    #[DateType]             protected DateTime $createdAt;\n    #[BooleanType]          protected bool $isDeleted;\n    #[BooleanType]          protected bool $isPhoneNumber;\n    #[ModelType([ModelType::MODEL_CLASS_NAME =\u003e RelatedModel::class])]\n    protected RelatedModel $buyer;\n    #[CollectionType([CollectionType::MODEL_CLASS_NAME =\u003e RelatedModel::class])]\n    protected array $buyers;\n    #[ModelType([Asset::MODEL_CLASS_NAME =\u003e Asset::class])]\n    protected Asset $asset;\n    #[HashMapType([HashMapType::MODEL_CLASS_NAME =\u003e RelatedModel::class])]\n    protected array $buyersMap;\n    \n    // getter and setters should be here    \n }\n```\nModel full example is here: [model.php](examples/model.php)\n\n#### Enumerations example\n\nEnumerations are also supported. Here is an example of the model with enumeration fields:\n\n```php\nclass ModelWithEnumeration extends Model\n{\n    #[Primary, StringType]\n    protected string $id;\n\n    #[EnumType]\n    protected OrderStatus $orderStatus;\n    \n    // union types\n    #[EnumType]\n    protected OrderStatus|ApplicationStatus $unionStatus;\n\n    // union types with null\n    #[EnumType]\n    protected OrderStatus|ApplicationStatus|null $unionNullableStatus;\n\n    // isStrict means the value will be null in case wrong value comes from the DB\n    #[EnumType(isStrict: false)]\n    protected ?OrderStatus $orderStatusAdditional = null;\n\n    #[EnumType]\n    protected CustomerType $customerType;\n}\n```\n\n#### Fields encryption\n\nCertain types custom encryption is supported. In case there are some fields which needs to be encrypted.\n\nFirst of all we need to create a custom encryptor:\n\n```php\nMyEncryptor implements EncryptorInterface {\n    protected const ENCRYPTION_KEY = 'def000008053addc0f94b14c0e480a10631a0a970b3565e5a7a2aeaeeb51a39e2d139a8977bc02be0195f0036a29aefff9df6d2ddb81432d14b4dce82b83b3a95c6d0205';\n\n    public function decrypt(string|array $encryptedData, array $options = []): string|array\n    {\n        // any decryption way may be implemented\n        if (is_array($encryptedData)) {\n            // ...specific property decryption operations...\n            return $encryptedData;\n        }\n        \n        return Crypto::decrypt(\n            $encryptedData,\n            Key::loadFromAsciiSafeString(static::ENCRYPTION_KEY)\n        );\n    }\n}\n```\n\nThen the decryptor should be passed into the hydrator:\n\n```php\n$newModelHydrator = new Hydrator(\n    EncryptionDemoModel::class,\n    $annotationManager,\n    new MyEncryptor(),\n);\n```\nAnd the model may be the following:\n\n```php\nclass EncryptionDemoModel extends Model\n{\n    #[Key\\Primary, Types\\StringType]\n    protected string $id;\n\n    // ability to encrypt a specific property in a scalar associative  array \n    #[Types\\ScalarCollectionType, Encrypted([\"encryptedProperty\" =\u003e \"secretProperty\"])]\n    protected array $encryptedArray;\n\n    #[Types\\StringType, Encrypted]\n    protected string $encryptedName;\n}\n```\n\n### Set up the repository for your model\n\nThe best way to operate with records is to create a repository. There is a built-in already:\n\n```php\n$newModelDynamoDbRepository = new DynamoDBRepository(\n    NewModel::class,\n    $client,\n    $queryBuilder,\n    $newModelHydrator,\n    $annotationManager,\n    $marshaler,\n    $serializer\n);\n```\nThere are built-in operation in the default repository.\n\n#### Get model by partition Id\n\n##### Just by partition key \n```php\n$foundModel = $newModelDynamoDbRepository-\u003eget($id);\n```\n\n##### By partition key and sort key\n```php\n$foundModel = $newModelDynamoDbRepository-\u003eget($id, $sortKey);\n```\n\n##### Non-consistent read\n```php\n$foundModel = $newModelDynamoDbRepository-\u003eget($id, $sortKey, false);\n```\n\n##### Get one item\n```php\n$foundModel = $newModelDynamoDbRepository-\u003egetOneById($id, $sortKey, false);\n```\n\n#### Insert model\n```php\n$newModelDynamoDbRepository-\u003esave($model);\n```\n\n#### Delete item\n```php\n$newModelDynamoDbRepository-\u003edelete($model);\n```\n\n### Document repository\n\nSometimes we need to fetch not the whole model, but just a part of it. For this purpose there is such called `DocumentRepository`. The part of the document may be technically fetched using native DynamoDb projection expressions.\n\nSetting `DocumentRepository` up:\n\n```php\n$documentRepository = new DocumentRepository(\n    NewModelNested::class,\n    $client,\n    $this-\u003equeryBuilder,\n    $this-\u003enewModelHydrator,\n    $annotationManager,\n    $marshaler,\n    $serializer\n);\n```\n\n#### Get a model by projection expression\n\n```php\n\n$projectionExpression = \"property.subPropertyModel\";\n\n$model = $documentRepository-\u003egetDocument()\n    -\u003esetConsistentRead(true)\n    -\u003ewithAttrPath($projectionExpression)\n    -\u003ewithPrKey($keyValue)\n    -\u003eexecute()\n;\n```\n\n#### Get a specific scalar property by projection expression\n\n```php\n$projectionExpression = \"property.subPropertyModel.name\";\n\n$name = $this-\u003edocumentRepository-\u003egetDocumentProperty()\n    -\u003esetConsistentRead(true)\n    -\u003ewithAttrPath($projection)\n    -\u003ewithPrKey($keyValue)\n    -\u003eexecute()\n;\n```\n\n#### Get/create/update/delete operations\n\nDocument repository supports specific property get/create/update/delete operations:\n\n- `createDocument()`\n- `updateDocument()`\n- `removeDocument()`\n- `getDocumentCollection()`\n- `updateDocumentCollection()`\n- `createDocumentCollection()`\n\n### Query builder\n\nAnother powerful feature is query builders. This adds flexibility to fetch items by specific criteria which is supported by DynamoDB.\n\nThis is a way to work with the Dynamodb using raw queries and results\n\n#### Get query builder\n\nFetch items:\n\n```php\n$getItemQuery = $queryBuilder\n    -\u003egetItem(self::DB_TABLE)\n    -\u003eitemKey([$itemKey =\u003e $keyValue])\n    -\u003egetQuery();\n    \n$item = $this-\u003edynamoDbClient\n    -\u003egetItem($getItemQuery)-\u003eget('Item');\n```\n#### Update query builder\n\nAbility to update specific attributes.\n\n```php\n$attributesForUpdate = [\n   \"numberProp\" =\u003e 2, \n   \"stringProp\" =\u003e \"updated string value\", \n   \"hashMapProp.map-id-1.type\" =\u003e \"updated map-type-1\", \n   \"hashMapProp.map-id-1.mapProp\" =\u003e \"updated mapProp\", \n   \"listProp\" =\u003e [\n         \"updated listProp 1\", \n         \"updated listProp 2\" \n      ] \n]; \n\n$getItemQuery = $queryBuilder\n    -\u003eupdateItem(self::DB_TABLE)\n    -\u003eitemKey([$itemKey =\u003e $keyValue])\n    -\u003eattributes($attributesForUpdate)\n    -\u003egetQuery();\n\n$dynamoDbClient-\u003eupdateItem($getItemQuery);\n```\n\n## Local dev environment installation\n\n1. In order to build a dev image, please, run: \n```bash\ndocker-compose build\n```\n2. Then run to install dependencies: \n```bash\ndocker-compose run --no-deps dynamodb-odm composer install\n```\n\n## Running tests\n\n### Unit tests\n\nThis package uses phpspec for running unit tests.\n\nRun them using the following way:\n```bash\ndocker-compose run --no-deps dynamodb-odm vendor/bin/phpspec run\n```\n\nOne can use environment variables in the `.env.local` file to be able to debug the library. For this just Copy file [.env.local.sample](.env.local.sample) into [.env.local](.env.local) and set up the variable according to your OS.\n\nAnd then run the tests with:\n\n```bash\ndocker-compose --env-file ./.env.local run  --no-deps dynamodb-odm vendor/bin/phpspec run\n```\n\n### Functional tests\n\nThis package uses behat for running functional tests.\n \nThen just run the tests:\n \n```bash\ndocker-compose run dynamodb-odm vendor/bin/behat -c behat.yml --stop-on-failure\n```\n\n### Syntax check tests\n\nYou need to check if the code style is OK by running:\n```bash\ndocker-compose run --no-deps dynamodb-odm vendor/bin/phpcs --standard=/application/phpcs.xml\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fautoprotect-group%2Fphp-dynamodb-odm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fautoprotect-group%2Fphp-dynamodb-odm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fautoprotect-group%2Fphp-dynamodb-odm/lists"}