Skip to content

Commit fb91725

Browse files
authored
Release 1.0.0
Initial base functionality.
2 parents 2fcac45 + f1ce4c0 commit fb91725

36 files changed

+1981
-5
lines changed

.github/CODEOWNERS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Global owners.
2+
* @othercodes
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
---
2+
name: Bug report
3+
about: Create a report to help us improve
4+
title: ''
5+
labels: bug
6+
assignees: othercodes
7+
8+
---
9+
10+
**Describe the bug**
11+
A clear and concise description of what the bug is.
12+
13+
**To Reproduce**
14+
Steps to reproduce the behavior:
15+
1. Go to '...'
16+
2. Click on '....'
17+
3. Scroll down to '....'
18+
4. See error
19+
20+
**Expected behavior**
21+
A clear and concise description of what you expected to happen.
22+
23+
**Additional context**
24+
Add any other context about the problem here.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
name: Feature request
3+
about: Suggest an idea for this project
4+
title: ''
5+
labels: enhancement
6+
assignees: othercodes
7+
8+
---
9+
10+
**Is your feature request related to a problem? Please describe.**
11+
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12+
13+
**Describe the solution you'd like**
14+
A clear and concise description of what you want to happen.
15+
16+
**Describe alternatives you've considered**
17+
A clear and concise description of any alternative solutions or features you've considered.
18+
19+
**Additional context**
20+
Add any other context or screenshots about the feature request here.
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
name: Documentation
2+
3+
on:
4+
pull_request:
5+
types: [ closed ]
6+
7+
jobs:
8+
publish:
9+
if: github.event.pull_request.merged == true
10+
runs-on: ubuntu-latest
11+
12+
strategy:
13+
matrix:
14+
php-version:
15+
- "7.4"
16+
17+
steps:
18+
- name: Checkout source code
19+
uses: actions/checkout@v2
20+
21+
- name: Install PHP
22+
uses: shivammathur/setup-php@v2
23+
with:
24+
php-version: ${{ matrix.php-version }}
25+
extensions: mbstring
26+
coverage: xdebug
27+
tools: composer:v2
28+
29+
- name: Cache dependencies
30+
uses: actions/cache@v2
31+
with:
32+
path: ~/.composer/cache
33+
key: php-${{ matrix.php-version }}-composer-${{ hashFiles('**/composer.json') }}
34+
restore-keys: php-${{ matrix.php-version }}-composer-
35+
36+
- name: Validate composer.json and composer.lock
37+
run: composer validate
38+
39+
- name: Install Dependencies
40+
run: composer install --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist
41+
42+
- name: Pusblish documentation to Wiki
43+
uses: SwiftDocOrg/github-wiki-publish-action@v1
44+
with:
45+
path: "wiki/"
46+
env:
47+
GH_PERSONAL_ACCESS_TOKEN: ${{ secrets.GH_PERSONAL_ACCESS_TOKEN }}

.github/workflows/test.yml

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
name: Test
2+
3+
on:
4+
pull_request:
5+
types: [ opened, synchronize, reopened ]
6+
7+
jobs:
8+
test:
9+
runs-on: ubuntu-latest
10+
11+
strategy:
12+
matrix:
13+
php-version:
14+
- "7.4"
15+
- "8.0"
16+
17+
steps:
18+
- name: Checkout source code
19+
uses: actions/checkout@v2
20+
21+
- name: Install PHP
22+
uses: shivammathur/setup-php@v2
23+
with:
24+
php-version: ${{ matrix.php-version }}
25+
coverage: xdebug
26+
tools: composer:v2
27+
28+
- name: Cache dependencies
29+
uses: actions/cache@v2
30+
with:
31+
path: ~/.composer/cache
32+
key: php-${{ matrix.php-version }}-composer-${{ hashFiles('**/composer.json') }}
33+
restore-keys: php-${{ matrix.php-version }}-composer-
34+
35+
- name: Validate composer.json and composer.lock
36+
run: composer validate
37+
38+
- name: Install Dependencies
39+
run: composer install --no-ansi --no-interaction --no-scripts --no-progress --prefer-dist
40+
41+
- name: Execute Unit, Integration and Acceptance Tests
42+
run: composer test
43+
44+
- name: Upload coverage report
45+
uses: codecov/codecov-action@v1.0.14
46+
with:
47+
token: ${{ secrets.CODECOV_TOKEN }}
48+
file: ./coverage.xml
49+
flags: unittests
50+
fail_ci_if_error: true
51+
52+
- name: Execute Static Code analysis
53+
run: composer analyse

.gitignore

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
composer.phar
22
/vendor/
3-
4-
# Commit your application's lock file https://getcomposer.org/doc/01-basic-usage.md#commit-your-composer-lock-file-to-version-control
5-
# You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file
6-
# composer.lock
3+
.idea/
4+
/infrastructure
5+
*[N|n]o[G|g]it*
6+
*coverage*
7+
.phpunit.result.cache
8+
composer.lock

README.md

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,66 @@
1-
# php-domain-model
1+
# Domain Model
2+
3+
[![Tests](https://github.com/ComplexHeart/php-domain-model/actions/workflows/test.yml/badge.svg)](https://github.com/ComplexHeart/php-domain-model/actions/workflows/test.yml)
4+
[![codecov](https://codecov.io/gh/ComplexHeart/php-domain-model/branch/main/graph/badge.svg?token=MFBVoMPYwi)](https://codecov.io/gh/ComplexHeart/php-domain-model)
5+
6+
## Modeling Aggregates, Entities and Value Objects
7+
8+
Complex Heart allows you to model your domain Aggregates, Entities, and Value Objects using a set of traits. Great, but
9+
why traits and not classes? Well, sometimes you have some kind of inheritance in your classes. Being forced to use a
10+
certain base class is too invasive and personally, I don't like it. By using a set of traits and interfaces you have all
11+
the functionality you need without compromising the essence of your own domain.
12+
13+
Let's see a very basic example:
14+
15+
```php
16+
use ComplexHeart\Contracts\Domain\Model\ValueObject;
17+
use ComplexHeart\Domain\Model\Traits\IsValueObject;
18+
19+
/**
20+
* Class Color
21+
* @method string value()
22+
*/
23+
final class Color implements ValueObject
24+
{
25+
use IsValueObject;
26+
27+
private string $value;
28+
29+
public function __construct(string $value) {
30+
$this->initialize(['value' => $value]);
31+
}
32+
33+
protected function invariantValueMustBeHexadecimal(): bool {
34+
return preg_match('/^#(?:[0-9a-fA-F]{3}){1,2}$/', $this->value) === 1;
35+
}
36+
37+
public function __toString(): string {
38+
return $this->value();
39+
}
40+
}
41+
42+
$red = new Color('#ff0000');
43+
$red->equals(new Color('#00ff00')); // false
44+
$red->value(); // #ff0000
45+
$magenta = new Color('ff00ff'); // Exception InvariantViolation: Value must be hexadecimal.
46+
```
47+
48+
To define a Value Object you only need to use the `IsValueObject` trait. This trait will allow you to use some functions
49+
like `equals()` that will automatically compare the value of the objects. The `initialize()` is also available, it will
50+
allow you to run invariant validations against the object values. Optionally, and recommended, you can use
51+
the `ValueObject` interface.
52+
53+
The available traits are:
54+
55+
- `HasAttributes` Provide some functionality to manage attributes.
56+
- `HasEquality` Provide functionality to handle equality between objects.
57+
- `HasInvariants` Allow invariant checking on instantiation (Guard Clause).
58+
- `HasIdentity` Define the Entity/Aggregate identity.
59+
- `HasDomainEvents` Provide domain event management.
60+
61+
On top of those base traits **Complex Heart** provide ready to use compositions:
62+
63+
- `IsModel` composed by `HasAttributes` and `HasInvariants`.
64+
- `IsValueObject` composed by `IsModel` and `HasEquality`.
65+
- `IsEntity` composed by `IsModel`, `HasIdentity`, `HasEquality`.
66+
- `IsAggregate` composed by `IsEntity`, `HasDomainEvents`.

composer.json

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{
2+
"name": "complex-heart/domain-model",
3+
"description": "Domain model toolset to properly build Value Objects, Entities, Aggregates and Services.",
4+
"type": "library",
5+
"license": "MIT",
6+
"authors": [
7+
{
8+
"name": "Unay Santisteban",
9+
"email": "usantisteban@othercode.es"
10+
}
11+
],
12+
"minimum-stability": "stable",
13+
"require": {
14+
"php": "^7.4|^8.0",
15+
"ext-json": "*",
16+
"ramsey/uuid": "^4.1",
17+
"nesbot/carbon": "^2.40",
18+
"illuminate/collections": "^8.20",
19+
"lambdish/phunctional": "^2.1",
20+
"doctrine/instantiator": "^1.4",
21+
"complex-heart/contracts": "^0.1.0"
22+
},
23+
"require-dev": {
24+
"mockery/mockery": "^1.4",
25+
"phpunit/phpunit": "^9.3",
26+
"fakerphp/faker": "^1.9.1",
27+
"phpstan/phpstan": "^0.12.64",
28+
"pestphp/pest": "^1.4"
29+
},
30+
"autoload": {
31+
"psr-4": {
32+
"ComplexHeart\\Domain\\Model\\": "src/"
33+
}
34+
},
35+
"scripts": {
36+
"test": "vendor/bin/pest --configuration=phpunit.xml --coverage-clover=coverage.xml",
37+
"analyse": "vendor/bin/phpstan analyse src --no-progress --level=5"
38+
}
39+
}

phpunit.xml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
bootstrap="vendor/autoload.php"
4+
colors="true"
5+
verbose="true"
6+
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
7+
<coverage processUncoveredFiles="true">
8+
<include>
9+
<directory suffix=".php">./src</directory>
10+
</include>
11+
<report>
12+
<clover outputFile="./coverage.xml"/>
13+
</report>
14+
</coverage>
15+
<testsuites>
16+
<testsuite name="unit">
17+
<directory>./tests</directory>
18+
</testsuite>
19+
</testsuites>
20+
<logging/>
21+
</phpunit>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace ComplexHeart\Domain\Model\Exceptions;
6+
7+
use RuntimeException;
8+
9+
/**
10+
* Class ImmutableException
11+
*
12+
* @author Unay Santisteban <usantisteban@othercode.es>
13+
* @package ComplexHeart\Domain\Model\Exceptions
14+
*/
15+
class ImmutableException extends RuntimeException
16+
{
17+
18+
}

0 commit comments

Comments
 (0)