{"id":21540484,"url":"https://github.com/othercodes/ddd-value-object","last_synced_at":"2025-03-17T21:45:54.832Z","repository":{"id":56295659,"uuid":"299267889","full_name":"othercodes/ddd-value-object","owner":"othercodes","description":"Small library to easily apply the Value Object Pattern.","archived":false,"fork":false,"pushed_at":"2020-11-16T10:35:44.000Z","size":27,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-24T08:12:30.203Z","etag":null,"topics":["ddd-architecture","ddd-patterns","value-object"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/othercodes.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}},"created_at":"2020-09-28T10:09:32.000Z","updated_at":"2023-12-21T11:24:27.000Z","dependencies_parsed_at":"2022-08-15T16:10:34.747Z","dependency_job_id":null,"html_url":"https://github.com/othercodes/ddd-value-object","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/othercodes%2Fddd-value-object","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/othercodes%2Fddd-value-object/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/othercodes%2Fddd-value-object/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/othercodes%2Fddd-value-object/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/othercodes","download_url":"https://codeload.github.com/othercodes/ddd-value-object/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244117101,"owners_count":20400739,"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":["ddd-architecture","ddd-patterns","value-object"],"created_at":"2024-11-24T04:19:06.200Z","updated_at":"2025-03-17T21:45:54.808Z","avatar_url":"https://github.com/othercodes.png","language":"PHP","readme":"# DDD Value Object\n\n![Tests](https://github.com/othercodes/ddd-value-object/workflows/Tests/badge.svg) [![License](https://poser.pugx.org/othercodes/ddd-value-object/license)](https://packagist.org/packages/othercodes/ddd-value-object) [![codecov](https://codecov.io/gh/othercodes/ddd-value-object/branch/master/graph/badge.svg)](https://codecov.io/gh/othercodes/ddd-value-object) \n\nSmall library to easily manage the Value Object Pattern.\n\n## Installation\n\nUse the following command to install with `composer`:\n\n```bash\ncomposer require othercode/ddd-value-object\n```\n\nThis will automatically get the latest version and configure a `composer.json` file.\n\nAlternatively you can create the following `composer.json` file and run `composer install` to install it.\n\n```bash\n{\n    \"require\": {\n        \"othercode/ddd-value-object\": \"*\"\n    }\n}\n```\n\n## Usage\n\nBuild a Value object is quite simple, you just need to extend the `ValueObject` Next, initialize the values in the \nconstructor by using the `initialize` method. Finally, add invariant rules as protected method, using the  prefix \n`invariant` (this prefix can be customized) and execute them with the `checkInvariants` method.\n\n```php\n\u003c?php \n\ndeclare(strict_types=1);\n\nclass Speed extends OtherCode\\DDDValueObject\\ValueObject\n{\n    public const KILOMETERS_PER_HOUR = 'km/h';\n    public const MILES_PER_HOUR = 'm/h';\n\n    public function __construct(int $amount, string $magnitude)\n    {\n        $this-\u003einitialize([\n            'amount' =\u003e $amount,\n            'magnitude' =\u003e $magnitude\n        ]);\n\n        $this-\u003echeckInvariants();\n    }\n\n    protected function invariantSpeedMustBeGreaterThanZero(): bool\n    {\n        return $this-\u003eamount() \u003e 0;\n    }\n\n    protected function invariantMagnitudeMustBeValid(): bool\n    {\n        return in_array($this-\u003emagnitude(), [\n            self::KILOMETERS_PER_HOUR,\n            self::MILES_PER_HOUR\n        ]);\n    }\n\n    public function amount(): int\n    {\n        return $this-\u003eget('amount');\n    }\n\n    public function magnitude(): string\n    {\n        return $this-\u003eget('magnitude');\n    }\n\n    public function increase(Speed $speed): self\n    {\n        if ($speed-\u003emagnitude() !== $this-\u003emagnitude()) {\n            throw new InvalidArgumentException('The given magnitude is not valid.');\n        }\n\n        return new self($this-\u003eamount() + $speed-\u003eamount(), $this-\u003emagnitude());\n    }\n\n    public function __toString(): string\n    {\n        return $this-\u003eamount() . $this-\u003emagnitude();\n    }\n}\n```\n\n### Equality\n\nValue equality is computed by serializing the object and hashing it with the sha256 algorithm. Alternatively, you can \noverride `equalityHash` to calculate a proper hash for the object. This hash is used to check if the value objects are \nequals or not.\n\n```php\n\u003c?php\n\ndeclare(strict_types=1);\n\nclass Speed extends OtherCode\\DDDValueObject\\ValueObject\n{\n// ...\n    public function equalityHash(): string\n    {\n        return md5(sprintf('$s %s', $this-\u003eamount(), $this-\u003emagnitude());\n    }\n// ...\n}\n```\n\n### Immutability\n\nThe immutability property blocks any attempt of value modification, that will end in exception:\n\n```php\n$s = new Speed(120, 'km/h');\n$s-\u003eamount = 123;\n\n// PHP Fatal error:  Uncaught OtherCode\\DDDValueObject\\Exceptions\\ImmutableValueException: Illegal attempt to change immutable value.\n```\n\nYou can customize the exception that will be thrown by overriding the `immutabilityException` property. The same happens \nwith the error message, you just need to override the `immutabilityMessages` property.\n\n```php\n\u003c?php\n\ndeclare(strict_types=1);\n\nclass Speed extends OtherCode\\DDDValueObject\\ValueObject\n{\n// ...\n    protected string $immutabilityException = SomeCustomException::class;\n\n    protected array $immutabilityMessages = [\n        'default' =\u003e 'You shall not update this value!.',\n    ];\n// ...\n}\n```\n\n### Invariants\n\nThe invariants methods must return a boolean value, `true` if the invariant is successfully, `false` otherwise. If any\nin variant is violated you will get an exception: \n\n```php\n\u003c?php\n$s = new Speed(-1, 'm/s');\n\n// PHP Fatal error:  Uncaught InvalidArgumentException: Unable to create Speed value object due: \n// invariant speed must be greater than zero\n// invariant magnitude must be valid\n```\n\nBy default, the invariant name is parsed and used as message error on invariant violation, but this can be easily\ncustomized, you just need to throw an exception with your custom message instead returning `false` in the invariants:\n\n```php\n\u003c?php\n\ndeclare(strict_types=1);\n\nclass Speed extends OtherCode\\DDDValueObject\\ValueObject\n{\n// ...\n    protected function invariantSpeedMustBeGreaterThanZero(): bool\n    {\n        if($this-\u003eamount() \u003c 0) {\n            throw new InvalidArgumentException('The given speed value is not valid');\n        }\n\n        return true;\n    }\n// ...\n}\n\n$s = new Speed(-1, 'm/s');\n\n// PHP Fatal error:  Uncaught InvalidArgumentException: Unable to create Speed value object due: \n// The given speed value is not valid\n// invariant magnitude must be valid\n```\n\nAdditionally, you can fully customize how the invariant violation are managed by passing a custom function to the\n`checkInvariants` method:\n\n```php\n\u003c?php \n\ndeclare(strict_types=1);\n\nclass Speed extends OtherCode\\DDDValueObject\\ValueObject\n{\n// ...\n    public function __construct(int $amount, string $magnitude)\n    {\n        $this-\u003einitialize([\n            'amount' =\u003e $amount,\n            'magnitude' =\u003e $magnitude\n        ]);\n\n        $this-\u003echeckInvariants(function (array $violations) {\n           throw new RuntimeException(\"Epic fail due:\\n-\" . implode(\"\\n-\", $violations) . \"\\n\");\n       });\n    }\n\n    protected function invariantSpeedMustBeGreaterThanZero(): bool\n    {\n        if($this-\u003eamount() \u003c 0) {\n            throw new InvalidArgumentException('The given speed value is not valid');\n        }\n\n        return true;\n    }\n// ...\n}\n\n$s = new Speed(-120, 'clicks/s');\n\n// PHP Fatal error:  Uncaught RuntimeException: Epic fail due:\n// - The given speed value is not valid\n// - invariant magnitude must be valid\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fothercodes%2Fddd-value-object","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fothercodes%2Fddd-value-object","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fothercodes%2Fddd-value-object/lists"}