├── Application ├── Assembler │ ├── Assembler.php │ ├── CollectionAssembler.php │ ├── DefaultAssembler.php │ └── DefaultCollectionAssembler.php └── Dto │ ├── DefaultDto.php │ └── Dto.php ├── Domain ├── Collection │ ├── ArrayCollection.php │ └── Collection.php ├── Contract │ ├── HasClassName.php │ ├── HasEqualsTo.php │ ├── HasId.php │ ├── HasSameTypeAs.php │ └── HasTypeOf.php ├── Event │ ├── DefaultEvent.php │ ├── DefaultMessage.php │ ├── DefaultStream.php │ ├── Event.php │ ├── Message.php │ ├── Metadata.php │ └── Stream.php ├── Exception │ ├── InvalidArgumentException.php │ └── NotMatchTypeException.php ├── Model │ ├── AggregateRoot.php │ ├── DefaultEntity.php │ ├── DefaultValueObject.php │ ├── Entity.php │ ├── Id │ │ └── Id.php │ └── ValueObject.php ├── Object │ ├── DefaultObject.php │ └── Object.php ├── Repository │ ├── ReadRepository.php │ └── Repository.php ├── Service │ ├── IdentityGenerator │ │ └── IdentityGenerator.php │ ├── MessageSerializer │ │ ├── Message.php │ │ ├── MessageSerializer.php │ │ └── MessageSerializerData.php │ ├── Serializer │ │ └── Serializer.php │ └── Service.php └── Traits │ ├── ClassName.php │ ├── SameTypeAs.php │ └── TypeOf.php ├── Infrastructure ├── Repository │ ├── MemoryReadRepository.php │ └── MemoryRepository.php └── Service │ ├── IdentityGenerator │ ├── CombUuid4Generator.php │ ├── RandomUuidGenerator.php │ └── Uuid4Generator.php │ └── MessageSerializer │ └── MessageSerializer.php ├── LICENSE ├── composer.json └── readme.md /Application/Assembler/Assembler.php: -------------------------------------------------------------------------------- 1 | assembler = $assembler; 21 | } 22 | 23 | /** 24 | * @param Entity[] $entities 25 | * 26 | * @return Dto[] 27 | */ 28 | public function toDto(array $entities) 29 | { 30 | return array_map(function (Entity $entity) { 31 | return $this->assembler->toDto($entity); 32 | }, $entities); 33 | } 34 | 35 | /** 36 | * @param Dto[] $dtos 37 | * 38 | * @return Entity[] 39 | */ 40 | public function toEntity(array $dtos) 41 | { 42 | return array_map(function (Dto $dto) { 43 | return $this->assembler->toEntity($dto); 44 | }, $dtos); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Application/Dto/DefaultDto.php: -------------------------------------------------------------------------------- 1 | items = $items; 20 | } 21 | 22 | /** 23 | * @param $item 24 | */ 25 | public function add($item) 26 | { 27 | $this->items[] = $item; 28 | } 29 | 30 | /** 31 | * @param $key 32 | * @param $value 33 | */ 34 | public function set($key, $value) 35 | { 36 | $this->items[$key] = $value; 37 | } 38 | 39 | /** 40 | * @param $key 41 | * 42 | * @return mixed 43 | */ 44 | public function remove($key) 45 | { 46 | if (!$this->containsKey($key)) { 47 | return null; 48 | } 49 | 50 | $item = $this->items[$key]; 51 | unset($this->items[$key]); 52 | 53 | return $item; 54 | } 55 | 56 | /** 57 | * @param $item 58 | * 59 | * @return bool 60 | */ 61 | public function removeItem($item) 62 | { 63 | $key = array_search($item, $this->items, true); 64 | 65 | if ($key === false) { 66 | return false; 67 | } 68 | 69 | unset($this->items[$key]); 70 | 71 | return true; 72 | } 73 | 74 | /** 75 | * @param $key 76 | * 77 | * @return mixed 78 | */ 79 | public function get($key) 80 | { 81 | return $this->containsKey($key) ? $this->items[$key] : null; 82 | } 83 | 84 | public function clear() 85 | { 86 | $this->items = []; 87 | } 88 | 89 | /** 90 | * @return bool 91 | */ 92 | public function isEmpty() 93 | { 94 | return $this->count() === 0; 95 | } 96 | 97 | /** 98 | * @return array 99 | */ 100 | public function getKeys() 101 | { 102 | return array_keys($this->items); 103 | } 104 | 105 | /** 106 | * @return array 107 | */ 108 | public function getValues() 109 | { 110 | return array_values($this->items); 111 | } 112 | 113 | /** 114 | * @return int 115 | */ 116 | public function count() 117 | { 118 | return count($this->items); 119 | } 120 | 121 | /** 122 | * @param $key 123 | * 124 | * @return bool 125 | */ 126 | public function containsKey($key) 127 | { 128 | return array_key_exists($key, $this->items); 129 | } 130 | 131 | /** 132 | * @return array 133 | */ 134 | public function toArray() 135 | { 136 | return $this->items; 137 | } 138 | 139 | /** 140 | * @param callable $callback 141 | * 142 | * @return static 143 | */ 144 | public function filter(callable $callback) 145 | { 146 | return new static(array_filter($this->items, $callback)); 147 | } 148 | 149 | /** 150 | * @param callable $callback 151 | * 152 | * @return static 153 | */ 154 | public function map(callable $callback) 155 | { 156 | return new static(array_map($callback, $this->items)); 157 | } 158 | 159 | /** 160 | * @param callable $keyCallback 161 | * @param callable $valueCallback 162 | * 163 | * @return static 164 | */ 165 | public function mapWithKeys(callable $keyCallback, callable $valueCallback) 166 | { 167 | $keys = array_map($keyCallback, $this->getValues()); 168 | $values = array_map($valueCallback, $this->getValues()); 169 | return new static(array_combine($keys, $values)); 170 | } 171 | 172 | /** 173 | * @return ArrayIterator 174 | */ 175 | public function getIterator() 176 | { 177 | return new ArrayIterator($this->items); 178 | } 179 | 180 | /** 181 | * @param mixed $offset 182 | * 183 | * @return bool 184 | */ 185 | public function offsetExists($offset) 186 | { 187 | return $this->containsKey($offset); 188 | } 189 | 190 | /** 191 | * @param mixed $offset 192 | * 193 | * @return mixed 194 | */ 195 | public function offsetGet($offset) 196 | { 197 | return $this->get($offset); 198 | } 199 | 200 | /** 201 | * @param mixed $offset 202 | * @param mixed $value 203 | */ 204 | public function offsetSet($offset, $value) 205 | { 206 | if ($offset === null) { 207 | $this->add($value); 208 | } else { 209 | $this->set($offset, $value); 210 | } 211 | } 212 | 213 | /** 214 | * @param mixed $offset 215 | * 216 | * @return mixed 217 | */ 218 | public function offsetUnset($offset) 219 | { 220 | return $this->remove($offset); 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /Domain/Collection/Collection.php: -------------------------------------------------------------------------------- 1 | getShortName(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Domain/Event/DefaultMessage.php: -------------------------------------------------------------------------------- 1 | type = $type; 48 | $this->name = $data->name(); 49 | $this->aggregateRootId = $aggregateRootId; 50 | $this->dateTime = DateTimeOfDay::now(); 51 | $this->metadata = $metadata; 52 | $this->data = $data; 53 | } 54 | 55 | /** 56 | * @return string 57 | */ 58 | public function type() 59 | { 60 | return $this->type; 61 | } 62 | 63 | /** 64 | * @return string 65 | */ 66 | public function name() 67 | { 68 | return $this->name; 69 | } 70 | 71 | /** 72 | * @return Id 73 | */ 74 | public function aggregateRootId() 75 | { 76 | return $this->aggregateRootId; 77 | } 78 | 79 | /** 80 | * @return DateTimeOfDay 81 | */ 82 | public function dateTime() 83 | { 84 | return $this->dateTime; 85 | } 86 | 87 | /** 88 | * @return Metadata 89 | */ 90 | public function metaData() 91 | { 92 | return $this->metadata; 93 | } 94 | 95 | /** 96 | * @return Event 97 | */ 98 | public function data() 99 | { 100 | return $this->data; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /Domain/Event/DefaultStream.php: -------------------------------------------------------------------------------- 1 | events = $events; 20 | } 21 | 22 | /** 23 | * @return ArrayIterator 24 | */ 25 | public function getIterator() 26 | { 27 | return new ArrayIterator($this->events); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Domain/Event/Event.php: -------------------------------------------------------------------------------- 1 | value = $value; 22 | } 23 | 24 | /** 25 | * @return array 26 | */ 27 | public function value() 28 | { 29 | return $this->value; 30 | } 31 | 32 | /** 33 | * @param static $metadata 34 | * 35 | * @return static 36 | */ 37 | public function addMetadata(Metadata $metadata) 38 | { 39 | $value = array_merge($this->value(), $metadata->value()); 40 | 41 | return new static($value); 42 | } 43 | 44 | /** 45 | * @return array 46 | */ 47 | public function serialize() 48 | { 49 | return $this->value(); 50 | } 51 | 52 | /** 53 | * @param array $data 54 | * 55 | * @return self 56 | */ 57 | public static function deserialize(array $data) 58 | { 59 | return new static($data); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Domain/Event/Stream.php: -------------------------------------------------------------------------------- 1 | unCommittedEvents); 25 | $this->unCommittedEvents = []; 26 | return $stream; 27 | } 28 | 29 | /** 30 | * @param Event $event 31 | */ 32 | protected function apply(Event $event) 33 | { 34 | $method = sprintf('apply%s', $event->name()); 35 | 36 | if (!method_exists($this, $method)) { 37 | throw new BadMethodCallException(sprintf('Method %s::%s is not found.', static::className(), $method)); 38 | } 39 | 40 | $this->$method($event); 41 | 42 | $this->unCommittedEvents[] = new DefaultMessage(static::className(), $this->getId(), new Metadata(), $event); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Domain/Model/DefaultEntity.php: -------------------------------------------------------------------------------- 1 | sameTypeAs($object)) { 25 | throw new NotMatchTypeException($this); 26 | } 27 | 28 | return $this->getId()->id() === $object->getId()->id(); 29 | } 30 | 31 | /** 32 | * @return Id 33 | */ 34 | public function getId() 35 | { 36 | return $this->id; 37 | } 38 | 39 | /** 40 | * @param Id $id 41 | */ 42 | public function setId(Id $id) 43 | { 44 | $this->id = $id; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Domain/Model/DefaultValueObject.php: -------------------------------------------------------------------------------- 1 | className = $className; 24 | $this->data = $data; 25 | } 26 | 27 | /** 28 | * @param array $array 29 | * 30 | * @return static 31 | */ 32 | public static function createFromArray(array $array) 33 | { 34 | return new static($array['class'], $array['data']); 35 | } 36 | 37 | /** 38 | * @return string 39 | */ 40 | public function className() 41 | { 42 | return $this->className; 43 | } 44 | 45 | /** 46 | * @return array 47 | */ 48 | public function data() 49 | { 50 | return $this->data; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Domain/Service/Serializer/Serializer.php: -------------------------------------------------------------------------------- 1 | storage = new ArrayCollection($array); 23 | } 24 | 25 | /** 26 | * @param Id $id 27 | * 28 | * @return mixed 29 | */ 30 | public function get(Id $id) 31 | { 32 | return $this->storage->get($id->id()); 33 | } 34 | 35 | /** 36 | * @return array|ArrayCollection 37 | */ 38 | public function getAll() 39 | { 40 | return $this->storage; 41 | } 42 | 43 | /** 44 | * @return int 45 | */ 46 | public function count() 47 | { 48 | return $this->storage->count(); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Infrastructure/Repository/MemoryRepository.php: -------------------------------------------------------------------------------- 1 | storage->set($object->getId()->id(), $object); 17 | } 18 | 19 | /** 20 | * @param HasId $object 21 | */ 22 | public function remove(HasId $object) 23 | { 24 | $this->storage->remove($object->getId()->id()); 25 | } 26 | 27 | /** 28 | * @param HasId $object 29 | */ 30 | public function save(HasId $object) 31 | { 32 | $this->add($object); 33 | } 34 | 35 | /** 36 | * @return Id 37 | */ 38 | abstract public function nextIdentity(); 39 | } 40 | -------------------------------------------------------------------------------- /Infrastructure/Service/IdentityGenerator/CombUuid4Generator.php: -------------------------------------------------------------------------------- 1 | getTimestamp()), 6 * 2, '0', STR_PAD_LEFT); 21 | 22 | $fields = [ 23 | 'time_low' => substr($hex, 0, 8), 24 | 'time_mid' => substr($hex, 8, 4), 25 | 'time_hi_and_version' => substr($hex, 12, 4), 26 | 'clock_seq_hi_and_reserved' => substr($hex, 16, 2), 27 | 'clock_seq_low' => substr($hex, 18, 2), 28 | 'node' => substr($hex, 20, 12), 29 | ]; 30 | 31 | return vsprintf( 32 | '%08s-%04s-%04s-%02s%02s-%012s', 33 | $fields 34 | ); 35 | } 36 | 37 | /** 38 | * @return string 39 | */ 40 | private function getTimestamp() 41 | { 42 | $time = explode(' ', microtime(false)); 43 | 44 | return $time[1] . substr($time[0], 2, 5); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Infrastructure/Service/IdentityGenerator/RandomUuidGenerator.php: -------------------------------------------------------------------------------- 1 | generate(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Infrastructure/Service/IdentityGenerator/Uuid4Generator.php: -------------------------------------------------------------------------------- 1 | substr($hex, 0, 8), 23 | 'time_mid' => substr($hex, 8, 4), 24 | 'time_hi_and_version' => substr($hex, 12, 4), 25 | 'clock_seq_hi_and_reserved' => substr($hex, 16, 2), 26 | 'clock_seq_low' => substr($hex, 18, 2), 27 | 'node' => substr($hex, 20, 12), 28 | ]; 29 | 30 | return vsprintf( 31 | '%08s-%04s-%04s-%02s%02s-%012s', 32 | $fields 33 | ); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Infrastructure/Service/MessageSerializer/MessageSerializer.php: -------------------------------------------------------------------------------- 1 | serializer = $serializer; 22 | } 23 | 24 | /** 25 | * @param Message $message 26 | * 27 | * @return string 28 | */ 29 | public function serialize(Message $message) 30 | { 31 | return $this->serializer->serialize($message->serialize()); 32 | } 33 | 34 | /** 35 | * @param $string 36 | * 37 | * @return Message 38 | */ 39 | public function deserialize($string) 40 | { 41 | $data = $this->serializer->deserialize($string); 42 | $messageSerializerData = MessageSerializerData::createFromArray($data); 43 | 44 | /** @var Message $className */ 45 | $className = $messageSerializerData->className(); 46 | 47 | return $className::deserialize($messageSerializerData->data()); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Aleksandr Zelenin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zelenin/ddd-core", 3 | "description": "Core for DDD concepts", 4 | "keywords": [ 5 | "ddd" 6 | ], 7 | "homepage": "https://github.com/zelenin/ddd-core", 8 | "license": "MIT", 9 | "authors": [ 10 | { 11 | "name": "Aleksandr Zelenin", 12 | "email": "aleksandr@zelenin.me", 13 | "homepage": "http://zelenin.me", 14 | "role": "Developer" 15 | } 16 | ], 17 | "support": { 18 | "issues": "https://github.com/zelenin/ddd-core/issues", 19 | "source": "https://github.com/zelenin/ddd-core" 20 | }, 21 | "require": { 22 | "php": ">=5.5", 23 | "zelenin/value-object": "~0.2.0", 24 | "paragonie/random_compat": "~2" 25 | }, 26 | "autoload": { 27 | "psr-4": { 28 | "Zelenin\\Ddd\\Core\\": "" 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # DDD Core 2 | 3 | Core for [Domain-driven design](https://en.wikipedia.org/wiki/Domain-driven_design) concepts. 4 | 5 | ## Installation 6 | 7 | ### Composer 8 | 9 | The preferred way to install this library is through [Composer](http://getcomposer.org/). 10 | 11 | Either run 12 | 13 | ``` 14 | composer require zelenin/ddd-core "~0.0" 15 | ``` 16 | 17 | or add 18 | 19 | ``` 20 | "zelenin/ddd-core": "~0.0" 21 | ``` 22 | 23 | to the ```require``` section of your ```composer.json``` 24 | 25 | ## Author 26 | 27 | [Aleksandr Zelenin](https://github.com/zelenin/), e-mail: [aleksandr@zelenin.me](mailto:aleksandr@zelenin.me) 28 | --------------------------------------------------------------------------------