├── .gitignore ├── GOTCHAS.md ├── README.md ├── bootstrap.php ├── cli-config.php ├── command-bus.php ├── composer.json ├── composer.lock ├── data ├── .gitignore └── proxies │ └── .gitignore ├── mapping ├── Authentication.Entity.User.dcm.xml ├── Enforcement.Entity.EnforcementRequest.dcm.xml └── Library.BookAmount.dcm.xml ├── migrations.xml ├── migrations └── Version20160428103311.php ├── phpunit.xml.dist ├── public ├── add-book.php ├── enforcement-notices.php ├── fake-login.php ├── lend-book-to-user.php ├── list-books.php ├── remove-book.php └── return-book.php ├── run.sh ├── src ├── Authentication │ └── Entity │ │ └── User.php ├── DoctrineIntegration │ └── Library │ │ ├── AmountType.php │ │ ├── ISBNType.php │ │ └── LibraryIdType.php ├── Enforcement │ └── Entity │ │ └── EnforcementRequest.php └── Library │ ├── Amount.php │ ├── Book.php │ ├── BookAmount.php │ ├── Command │ └── AddBook.php │ ├── DoctrineLibraryRepository.php │ ├── ISBN.php │ ├── LentBook.php │ ├── Library.php │ ├── LibraryId.php │ ├── LibraryRepository.php │ └── UserId.php └── test ├── DoctrineIntegration └── BookAmountPersistenceTest.php └── Library ├── AmountTest.php ├── DoctrineLibraryRepositoryTest.php ├── ISBNTest.php ├── LibraryIdTest.php ├── LibraryTest.php └── UserIdTest.php /.gitignore: -------------------------------------------------------------------------------- 1 | vendor 2 | -------------------------------------------------------------------------------- /GOTCHAS.md: -------------------------------------------------------------------------------- 1 | * Auto-return systems may track single books, instead of just amounts 2 | * ISBNs are not necessarily unique - ancient systems may have non-unique ISBNs 3 | * Is a 0 amount allowed? 4 | * ISBNs now allow other chars too -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Maintainable Doctrine ORM tutorial 2 | 3 | This tutorial will introduce you to using Doctrine ORM in a more maintainable way. 4 | 5 | Specifically, following concepts will be covered: 6 | 7 | 1. Aggregate root (Is it an Entity?) 8 | 2. Value Object 9 | 3. Commands 10 | 4. Command bus 11 | 5. Isolating domain and application logic 12 | 6. Maintaining transactional integrity whilst keeping domain boundaries separate 13 | 7. Transactional integrity and domain boundaries 14 | 8. Maintaining schema changes versioned 15 | 16 | ## The domain 17 | 18 | The domain used as reference is a Library (books) management system. 19 | We will not focus much on DDD-style exploration, but we will instead 20 | focus on writing the logic for an already existing specification: 21 | 22 | * User management system will be mocked out 23 | * Searching for books 24 | * Lending books to users 25 | * Managing maximum number of books that can be lent by a user at any given time 26 | * Getting books back from users 27 | * Notifying users that they should return a book 28 | * Fine users that didn't return a book after a notice (communication with external "enforcement" context) 29 | 30 | ## Installation 31 | 32 | First, [install composer](https://getcomposer.org/download/). 33 | 34 | After that, you can run: 35 | 36 | ```sh 37 | composer require doctrine/orm 38 | ``` 39 | 40 | We now need to set up autoloading: 41 | 42 | ```json 43 | { 44 | "autoload": { 45 | "psr-4": { 46 | "Authentication": "src/Authentication", 47 | "Library": "src/Library", 48 | "Enforcement": "src/Enforcement", 49 | } 50 | } 51 | } 52 | ``` 53 | 54 | ## Schedule 55 | 56 | * 10m - presentation round 57 | * 10m - pairing - discussion is at the core of the process 58 | * 10m - base concepts: aggregate root/value object 59 | * 5m - domain (and the 3 boundaries - auth, library, enforcement): 60 | * library 61 | * library contains books 62 | * each book has an ISBN and some metadata 63 | * can add books to the library 64 | * can register users 65 | * can lend books to users 66 | * users have a max lent books amount 67 | * users need to be notified when a lend is overdue 68 | * overdue lend must be enforced after a certain threshold (external API) 69 | * returned books should cancel enforcement requests (external API) 70 | * ask questions - what else can a library do? Is the specification sufficient? 71 | * 5m - domain bits to be implemented: 72 | * adding books 73 | * listing available books (assuming small to large bibliotheque) 74 | * lend a book (user) 75 | * return a book 76 | * notify user of late lent return 77 | * enforce return of very late lent 78 | * logging all operations (audit log or immutable structures) 79 | * avoid lazy-loading all the book catalogue 80 | * 30m - try designing a library or repository with just "add book" and "list all books" without memory issues 81 | * 15m - writing the library object together 82 | * custom repositories 83 | * passing repositories to entities? 84 | * 10m - hardening the logic with value-objects 85 | * 15m - wiring together everything via XML mappings 86 | * 10m - installing and configuring doctrine migrations, generating first migration files 87 | * 5m - transactional safety - it is needed now that we do live-queries at all times 88 | * 10m - transactional safety at the base of every interaction via a command bus 89 | * 45m - implementing book lends and returns (with commands, VOs and serialize/unserialize) 90 | * 15m - implementing lending books/returning books together 91 | * 20m - send notifications to users with overdue returns, don't dog-pile notifications 92 | * 10m - code notifications for overdue returns together 93 | * 20m - interaction with external system: coding together the notification system 94 | * 5m - logging some queries 95 | * 15m - setting up the second level cache, seeing it in action 96 | -------------------------------------------------------------------------------- /bootstrap.php: -------------------------------------------------------------------------------- 1 | setMetadataDriverImpl(new XmlDriver([__DIR__ . '/mapping'])); 20 | 21 | // This is needed for Doctrine to generate files required for lazy-loading 22 | $configuration->setProxyDir(__DIR__ . '/data/proxies'); 23 | $configuration->setProxyNamespace('DoctrineProxies'); 24 | 25 | // We are telling Doctrine to always generate files required for lazy-loading. This is a slow operation, 26 | // and shouldn't be done in a production environment. 27 | $configuration->setAutoGenerateProxyClasses(ProxyFactory::AUTOGENERATE_ALWAYS); 28 | 29 | Type::addType(UuidType::class, UuidType::class); 30 | Type::addType(AmountType::class, AmountType::class); 31 | Type::addType(ISBNType::class, ISBNType::class); 32 | Type::addType(LibraryIdType::class, LibraryIdType::class); 33 | 34 | // Finally creating the EntityManager: our entry point for the ORM 35 | return EntityManager::create( 36 | [ 37 | 'driverClass' => Driver::class, 38 | 'path' => __DIR__ . '/data/test-db.sqlite', 39 | ], 40 | $configuration 41 | ); 42 | -------------------------------------------------------------------------------- /cli-config.php: -------------------------------------------------------------------------------- 1 | getConnection()); 11 | 12 | return new HelperSet([ 13 | 'em' => new EntityManagerHelper($entityManager), 14 | 'db' => $connectionHelper, 15 | 'connection' => $connectionHelper, 16 | ]); 17 | -------------------------------------------------------------------------------- /command-bus.php: -------------------------------------------------------------------------------- 1 | getLibraryId(), 19 | new DoctrineLibraryRepository( 20 | $entityManager->getRepository(BookAmount::class), 21 | $entityManager 22 | ) 23 | ); 24 | 25 | $library->addBook($command->getIsbn(), $command->getAmount()); 26 | return; 27 | } 28 | 29 | throw new \InvalidArgumentException(sprintf('Unknown command %s', get_class($command))); 30 | }; 31 | 32 | $logger = function ($command) { 33 | var_dump($command); 34 | }; 35 | 36 | $commandBus = function ($command) use ($commandBus, $logger) { 37 | $logger($command); 38 | 39 | return $commandBus($command); 40 | }; 41 | 42 | $commandBus = function ($command) use ($commandBus, $entityManager) { 43 | $return = $entityManager->transactional(function () use ($commandBus, $command) { 44 | return $commandBus($command); 45 | }); 46 | 47 | $entityManager->clear(); 48 | 49 | return $return; 50 | }; 51 | 52 | return $commandBus; -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": { 3 | "doctrine/orm": "^2.5", 4 | "ramsey/uuid": "^3.4", 5 | "ramsey/uuid-doctrine": "^1.2", 6 | "doctrine/migrations": "^1.4", 7 | "phpunit/phpunit": "^4.8" 8 | }, 9 | "autoload": { 10 | "psr-4": { 11 | "DoctrineIntegration\\": "src/DoctrineIntegration", 12 | "Authentication\\": "src/Authentication", 13 | "Library\\": "src/Library", 14 | "Enforcement\\": "src/Enforcement" 15 | } 16 | }, 17 | "config": { 18 | "platform": { 19 | "php": "5.5.9" 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", 5 | "This file is @generated automatically" 6 | ], 7 | "hash": "ce7f7d6ae767e1efb232cb005225c523", 8 | "content-hash": "2884309267c035d2d63be54f225c79de", 9 | "packages": [ 10 | { 11 | "name": "doctrine/annotations", 12 | "version": "v1.2.7", 13 | "source": { 14 | "type": "git", 15 | "url": "https://github.com/doctrine/annotations.git", 16 | "reference": "f25c8aab83e0c3e976fd7d19875f198ccf2f7535" 17 | }, 18 | "dist": { 19 | "type": "zip", 20 | "url": "https://api.github.com/repos/doctrine/annotations/zipball/f25c8aab83e0c3e976fd7d19875f198ccf2f7535", 21 | "reference": "f25c8aab83e0c3e976fd7d19875f198ccf2f7535", 22 | "shasum": "" 23 | }, 24 | "require": { 25 | "doctrine/lexer": "1.*", 26 | "php": ">=5.3.2" 27 | }, 28 | "require-dev": { 29 | "doctrine/cache": "1.*", 30 | "phpunit/phpunit": "4.*" 31 | }, 32 | "type": "library", 33 | "extra": { 34 | "branch-alias": { 35 | "dev-master": "1.3.x-dev" 36 | } 37 | }, 38 | "autoload": { 39 | "psr-0": { 40 | "Doctrine\\Common\\Annotations\\": "lib/" 41 | } 42 | }, 43 | "notification-url": "https://packagist.org/downloads/", 44 | "license": [ 45 | "MIT" 46 | ], 47 | "authors": [ 48 | { 49 | "name": "Roman Borschel", 50 | "email": "roman@code-factory.org" 51 | }, 52 | { 53 | "name": "Benjamin Eberlei", 54 | "email": "kontakt@beberlei.de" 55 | }, 56 | { 57 | "name": "Guilherme Blanco", 58 | "email": "guilhermeblanco@gmail.com" 59 | }, 60 | { 61 | "name": "Jonathan Wage", 62 | "email": "jonwage@gmail.com" 63 | }, 64 | { 65 | "name": "Johannes Schmitt", 66 | "email": "schmittjoh@gmail.com" 67 | } 68 | ], 69 | "description": "Docblock Annotations Parser", 70 | "homepage": "http://www.doctrine-project.org", 71 | "keywords": [ 72 | "annotations", 73 | "docblock", 74 | "parser" 75 | ], 76 | "time": "2015-08-31 12:32:49" 77 | }, 78 | { 79 | "name": "doctrine/cache", 80 | "version": "v1.6.0", 81 | "source": { 82 | "type": "git", 83 | "url": "https://github.com/doctrine/cache.git", 84 | "reference": "f8af318d14bdb0eff0336795b428b547bd39ccb6" 85 | }, 86 | "dist": { 87 | "type": "zip", 88 | "url": "https://api.github.com/repos/doctrine/cache/zipball/f8af318d14bdb0eff0336795b428b547bd39ccb6", 89 | "reference": "f8af318d14bdb0eff0336795b428b547bd39ccb6", 90 | "shasum": "" 91 | }, 92 | "require": { 93 | "php": "~5.5|~7.0" 94 | }, 95 | "conflict": { 96 | "doctrine/common": ">2.2,<2.4" 97 | }, 98 | "require-dev": { 99 | "phpunit/phpunit": "~4.8|~5.0", 100 | "predis/predis": "~1.0", 101 | "satooshi/php-coveralls": "~0.6" 102 | }, 103 | "type": "library", 104 | "extra": { 105 | "branch-alias": { 106 | "dev-master": "1.6.x-dev" 107 | } 108 | }, 109 | "autoload": { 110 | "psr-4": { 111 | "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache" 112 | } 113 | }, 114 | "notification-url": "https://packagist.org/downloads/", 115 | "license": [ 116 | "MIT" 117 | ], 118 | "authors": [ 119 | { 120 | "name": "Roman Borschel", 121 | "email": "roman@code-factory.org" 122 | }, 123 | { 124 | "name": "Benjamin Eberlei", 125 | "email": "kontakt@beberlei.de" 126 | }, 127 | { 128 | "name": "Guilherme Blanco", 129 | "email": "guilhermeblanco@gmail.com" 130 | }, 131 | { 132 | "name": "Jonathan Wage", 133 | "email": "jonwage@gmail.com" 134 | }, 135 | { 136 | "name": "Johannes Schmitt", 137 | "email": "schmittjoh@gmail.com" 138 | } 139 | ], 140 | "description": "Caching library offering an object-oriented API for many cache backends", 141 | "homepage": "http://www.doctrine-project.org", 142 | "keywords": [ 143 | "cache", 144 | "caching" 145 | ], 146 | "time": "2015-12-31 16:37:02" 147 | }, 148 | { 149 | "name": "doctrine/collections", 150 | "version": "v1.3.0", 151 | "source": { 152 | "type": "git", 153 | "url": "https://github.com/doctrine/collections.git", 154 | "reference": "6c1e4eef75f310ea1b3e30945e9f06e652128b8a" 155 | }, 156 | "dist": { 157 | "type": "zip", 158 | "url": "https://api.github.com/repos/doctrine/collections/zipball/6c1e4eef75f310ea1b3e30945e9f06e652128b8a", 159 | "reference": "6c1e4eef75f310ea1b3e30945e9f06e652128b8a", 160 | "shasum": "" 161 | }, 162 | "require": { 163 | "php": ">=5.3.2" 164 | }, 165 | "require-dev": { 166 | "phpunit/phpunit": "~4.0" 167 | }, 168 | "type": "library", 169 | "extra": { 170 | "branch-alias": { 171 | "dev-master": "1.2.x-dev" 172 | } 173 | }, 174 | "autoload": { 175 | "psr-0": { 176 | "Doctrine\\Common\\Collections\\": "lib/" 177 | } 178 | }, 179 | "notification-url": "https://packagist.org/downloads/", 180 | "license": [ 181 | "MIT" 182 | ], 183 | "authors": [ 184 | { 185 | "name": "Roman Borschel", 186 | "email": "roman@code-factory.org" 187 | }, 188 | { 189 | "name": "Benjamin Eberlei", 190 | "email": "kontakt@beberlei.de" 191 | }, 192 | { 193 | "name": "Guilherme Blanco", 194 | "email": "guilhermeblanco@gmail.com" 195 | }, 196 | { 197 | "name": "Jonathan Wage", 198 | "email": "jonwage@gmail.com" 199 | }, 200 | { 201 | "name": "Johannes Schmitt", 202 | "email": "schmittjoh@gmail.com" 203 | } 204 | ], 205 | "description": "Collections Abstraction library", 206 | "homepage": "http://www.doctrine-project.org", 207 | "keywords": [ 208 | "array", 209 | "collections", 210 | "iterator" 211 | ], 212 | "time": "2015-04-14 22:21:58" 213 | }, 214 | { 215 | "name": "doctrine/common", 216 | "version": "v2.6.1", 217 | "source": { 218 | "type": "git", 219 | "url": "https://github.com/doctrine/common.git", 220 | "reference": "a579557bc689580c19fee4e27487a67fe60defc0" 221 | }, 222 | "dist": { 223 | "type": "zip", 224 | "url": "https://api.github.com/repos/doctrine/common/zipball/a579557bc689580c19fee4e27487a67fe60defc0", 225 | "reference": "a579557bc689580c19fee4e27487a67fe60defc0", 226 | "shasum": "" 227 | }, 228 | "require": { 229 | "doctrine/annotations": "1.*", 230 | "doctrine/cache": "1.*", 231 | "doctrine/collections": "1.*", 232 | "doctrine/inflector": "1.*", 233 | "doctrine/lexer": "1.*", 234 | "php": "~5.5|~7.0" 235 | }, 236 | "require-dev": { 237 | "phpunit/phpunit": "~4.8|~5.0" 238 | }, 239 | "type": "library", 240 | "extra": { 241 | "branch-alias": { 242 | "dev-master": "2.7.x-dev" 243 | } 244 | }, 245 | "autoload": { 246 | "psr-4": { 247 | "Doctrine\\Common\\": "lib/Doctrine/Common" 248 | } 249 | }, 250 | "notification-url": "https://packagist.org/downloads/", 251 | "license": [ 252 | "MIT" 253 | ], 254 | "authors": [ 255 | { 256 | "name": "Roman Borschel", 257 | "email": "roman@code-factory.org" 258 | }, 259 | { 260 | "name": "Benjamin Eberlei", 261 | "email": "kontakt@beberlei.de" 262 | }, 263 | { 264 | "name": "Guilherme Blanco", 265 | "email": "guilhermeblanco@gmail.com" 266 | }, 267 | { 268 | "name": "Jonathan Wage", 269 | "email": "jonwage@gmail.com" 270 | }, 271 | { 272 | "name": "Johannes Schmitt", 273 | "email": "schmittjoh@gmail.com" 274 | } 275 | ], 276 | "description": "Common Library for Doctrine projects", 277 | "homepage": "http://www.doctrine-project.org", 278 | "keywords": [ 279 | "annotations", 280 | "collections", 281 | "eventmanager", 282 | "persistence", 283 | "spl" 284 | ], 285 | "time": "2015-12-25 13:18:31" 286 | }, 287 | { 288 | "name": "doctrine/dbal", 289 | "version": "v2.5.4", 290 | "source": { 291 | "type": "git", 292 | "url": "https://github.com/doctrine/dbal.git", 293 | "reference": "abbdfd1cff43a7b99d027af3be709bc8fc7d4769" 294 | }, 295 | "dist": { 296 | "type": "zip", 297 | "url": "https://api.github.com/repos/doctrine/dbal/zipball/abbdfd1cff43a7b99d027af3be709bc8fc7d4769", 298 | "reference": "abbdfd1cff43a7b99d027af3be709bc8fc7d4769", 299 | "shasum": "" 300 | }, 301 | "require": { 302 | "doctrine/common": ">=2.4,<2.7-dev", 303 | "php": ">=5.3.2" 304 | }, 305 | "require-dev": { 306 | "phpunit/phpunit": "4.*", 307 | "symfony/console": "2.*" 308 | }, 309 | "suggest": { 310 | "symfony/console": "For helpful console commands such as SQL execution and import of files." 311 | }, 312 | "bin": [ 313 | "bin/doctrine-dbal" 314 | ], 315 | "type": "library", 316 | "extra": { 317 | "branch-alias": { 318 | "dev-master": "2.5.x-dev" 319 | } 320 | }, 321 | "autoload": { 322 | "psr-0": { 323 | "Doctrine\\DBAL\\": "lib/" 324 | } 325 | }, 326 | "notification-url": "https://packagist.org/downloads/", 327 | "license": [ 328 | "MIT" 329 | ], 330 | "authors": [ 331 | { 332 | "name": "Roman Borschel", 333 | "email": "roman@code-factory.org" 334 | }, 335 | { 336 | "name": "Benjamin Eberlei", 337 | "email": "kontakt@beberlei.de" 338 | }, 339 | { 340 | "name": "Guilherme Blanco", 341 | "email": "guilhermeblanco@gmail.com" 342 | }, 343 | { 344 | "name": "Jonathan Wage", 345 | "email": "jonwage@gmail.com" 346 | } 347 | ], 348 | "description": "Database Abstraction Layer", 349 | "homepage": "http://www.doctrine-project.org", 350 | "keywords": [ 351 | "database", 352 | "dbal", 353 | "persistence", 354 | "queryobject" 355 | ], 356 | "time": "2016-01-05 22:11:12" 357 | }, 358 | { 359 | "name": "doctrine/inflector", 360 | "version": "v1.1.0", 361 | "source": { 362 | "type": "git", 363 | "url": "https://github.com/doctrine/inflector.git", 364 | "reference": "90b2128806bfde671b6952ab8bea493942c1fdae" 365 | }, 366 | "dist": { 367 | "type": "zip", 368 | "url": "https://api.github.com/repos/doctrine/inflector/zipball/90b2128806bfde671b6952ab8bea493942c1fdae", 369 | "reference": "90b2128806bfde671b6952ab8bea493942c1fdae", 370 | "shasum": "" 371 | }, 372 | "require": { 373 | "php": ">=5.3.2" 374 | }, 375 | "require-dev": { 376 | "phpunit/phpunit": "4.*" 377 | }, 378 | "type": "library", 379 | "extra": { 380 | "branch-alias": { 381 | "dev-master": "1.1.x-dev" 382 | } 383 | }, 384 | "autoload": { 385 | "psr-0": { 386 | "Doctrine\\Common\\Inflector\\": "lib/" 387 | } 388 | }, 389 | "notification-url": "https://packagist.org/downloads/", 390 | "license": [ 391 | "MIT" 392 | ], 393 | "authors": [ 394 | { 395 | "name": "Roman Borschel", 396 | "email": "roman@code-factory.org" 397 | }, 398 | { 399 | "name": "Benjamin Eberlei", 400 | "email": "kontakt@beberlei.de" 401 | }, 402 | { 403 | "name": "Guilherme Blanco", 404 | "email": "guilhermeblanco@gmail.com" 405 | }, 406 | { 407 | "name": "Jonathan Wage", 408 | "email": "jonwage@gmail.com" 409 | }, 410 | { 411 | "name": "Johannes Schmitt", 412 | "email": "schmittjoh@gmail.com" 413 | } 414 | ], 415 | "description": "Common String Manipulations with regard to casing and singular/plural rules.", 416 | "homepage": "http://www.doctrine-project.org", 417 | "keywords": [ 418 | "inflection", 419 | "pluralize", 420 | "singularize", 421 | "string" 422 | ], 423 | "time": "2015-11-06 14:35:42" 424 | }, 425 | { 426 | "name": "doctrine/instantiator", 427 | "version": "1.0.5", 428 | "source": { 429 | "type": "git", 430 | "url": "https://github.com/doctrine/instantiator.git", 431 | "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" 432 | }, 433 | "dist": { 434 | "type": "zip", 435 | "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", 436 | "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", 437 | "shasum": "" 438 | }, 439 | "require": { 440 | "php": ">=5.3,<8.0-DEV" 441 | }, 442 | "require-dev": { 443 | "athletic/athletic": "~0.1.8", 444 | "ext-pdo": "*", 445 | "ext-phar": "*", 446 | "phpunit/phpunit": "~4.0", 447 | "squizlabs/php_codesniffer": "~2.0" 448 | }, 449 | "type": "library", 450 | "extra": { 451 | "branch-alias": { 452 | "dev-master": "1.0.x-dev" 453 | } 454 | }, 455 | "autoload": { 456 | "psr-4": { 457 | "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" 458 | } 459 | }, 460 | "notification-url": "https://packagist.org/downloads/", 461 | "license": [ 462 | "MIT" 463 | ], 464 | "authors": [ 465 | { 466 | "name": "Marco Pivetta", 467 | "email": "ocramius@gmail.com", 468 | "homepage": "http://ocramius.github.com/" 469 | } 470 | ], 471 | "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", 472 | "homepage": "https://github.com/doctrine/instantiator", 473 | "keywords": [ 474 | "constructor", 475 | "instantiate" 476 | ], 477 | "time": "2015-06-14 21:17:01" 478 | }, 479 | { 480 | "name": "doctrine/lexer", 481 | "version": "v1.0.1", 482 | "source": { 483 | "type": "git", 484 | "url": "https://github.com/doctrine/lexer.git", 485 | "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c" 486 | }, 487 | "dist": { 488 | "type": "zip", 489 | "url": "https://api.github.com/repos/doctrine/lexer/zipball/83893c552fd2045dd78aef794c31e694c37c0b8c", 490 | "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c", 491 | "shasum": "" 492 | }, 493 | "require": { 494 | "php": ">=5.3.2" 495 | }, 496 | "type": "library", 497 | "extra": { 498 | "branch-alias": { 499 | "dev-master": "1.0.x-dev" 500 | } 501 | }, 502 | "autoload": { 503 | "psr-0": { 504 | "Doctrine\\Common\\Lexer\\": "lib/" 505 | } 506 | }, 507 | "notification-url": "https://packagist.org/downloads/", 508 | "license": [ 509 | "MIT" 510 | ], 511 | "authors": [ 512 | { 513 | "name": "Roman Borschel", 514 | "email": "roman@code-factory.org" 515 | }, 516 | { 517 | "name": "Guilherme Blanco", 518 | "email": "guilhermeblanco@gmail.com" 519 | }, 520 | { 521 | "name": "Johannes Schmitt", 522 | "email": "schmittjoh@gmail.com" 523 | } 524 | ], 525 | "description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.", 526 | "homepage": "http://www.doctrine-project.org", 527 | "keywords": [ 528 | "lexer", 529 | "parser" 530 | ], 531 | "time": "2014-09-09 13:34:57" 532 | }, 533 | { 534 | "name": "doctrine/migrations", 535 | "version": "1.4.1", 536 | "source": { 537 | "type": "git", 538 | "url": "https://github.com/doctrine/migrations.git", 539 | "reference": "0d0ff5da10c5d30846da32060bd9e357abf70a05" 540 | }, 541 | "dist": { 542 | "type": "zip", 543 | "url": "https://api.github.com/repos/doctrine/migrations/zipball/0d0ff5da10c5d30846da32060bd9e357abf70a05", 544 | "reference": "0d0ff5da10c5d30846da32060bd9e357abf70a05", 545 | "shasum": "" 546 | }, 547 | "require": { 548 | "doctrine/dbal": "~2.2", 549 | "ocramius/proxy-manager": "^1.0|^2.0", 550 | "php": "^5.5|^7.0", 551 | "symfony/console": "~2.3|~3.0", 552 | "symfony/yaml": "~2.3|~3.0" 553 | }, 554 | "require-dev": { 555 | "doctrine/coding-standard": "dev-master", 556 | "doctrine/orm": "2.*", 557 | "jdorn/sql-formatter": "~1.1", 558 | "johnkary/phpunit-speedtrap": "~1.0@dev", 559 | "mockery/mockery": "^0.9.4", 560 | "phpunit/phpunit": "~4.7", 561 | "satooshi/php-coveralls": "0.6.*" 562 | }, 563 | "suggest": { 564 | "jdorn/sql-formatter": "Allows to generate formatted SQL with the diff command." 565 | }, 566 | "bin": [ 567 | "bin/doctrine-migrations" 568 | ], 569 | "type": "library", 570 | "extra": { 571 | "branch-alias": { 572 | "dev-master": "v1.5.x-dev" 573 | } 574 | }, 575 | "autoload": { 576 | "psr-4": { 577 | "Doctrine\\DBAL\\Migrations\\": "lib/Doctrine/DBAL/Migrations" 578 | } 579 | }, 580 | "notification-url": "https://packagist.org/downloads/", 581 | "license": [ 582 | "LGPL-2.1" 583 | ], 584 | "authors": [ 585 | { 586 | "name": "Benjamin Eberlei", 587 | "email": "kontakt@beberlei.de" 588 | }, 589 | { 590 | "name": "Jonathan Wage", 591 | "email": "jonwage@gmail.com" 592 | }, 593 | { 594 | "name": "Michael Simonson", 595 | "email": "contact@mikesimonson.com" 596 | } 597 | ], 598 | "description": "Database Schema migrations using Doctrine DBAL", 599 | "homepage": "http://www.doctrine-project.org", 600 | "keywords": [ 601 | "database", 602 | "migrations" 603 | ], 604 | "time": "2016-03-14 12:29:11" 605 | }, 606 | { 607 | "name": "doctrine/orm", 608 | "version": "v2.5.4", 609 | "source": { 610 | "type": "git", 611 | "url": "https://github.com/doctrine/doctrine2.git", 612 | "reference": "bc4ddbfb0114cb33438cc811c9a740d8aa304aab" 613 | }, 614 | "dist": { 615 | "type": "zip", 616 | "url": "https://api.github.com/repos/doctrine/doctrine2/zipball/bc4ddbfb0114cb33438cc811c9a740d8aa304aab", 617 | "reference": "bc4ddbfb0114cb33438cc811c9a740d8aa304aab", 618 | "shasum": "" 619 | }, 620 | "require": { 621 | "doctrine/cache": "~1.4", 622 | "doctrine/collections": "~1.2", 623 | "doctrine/common": ">=2.5-dev,<2.7-dev", 624 | "doctrine/dbal": ">=2.5-dev,<2.6-dev", 625 | "doctrine/instantiator": "~1.0.1", 626 | "ext-pdo": "*", 627 | "php": ">=5.4", 628 | "symfony/console": "~2.5|~3.0" 629 | }, 630 | "require-dev": { 631 | "phpunit/phpunit": "~4.0", 632 | "symfony/yaml": "~2.3|~3.0" 633 | }, 634 | "suggest": { 635 | "symfony/yaml": "If you want to use YAML Metadata Mapping Driver" 636 | }, 637 | "bin": [ 638 | "bin/doctrine", 639 | "bin/doctrine.php" 640 | ], 641 | "type": "library", 642 | "extra": { 643 | "branch-alias": { 644 | "dev-master": "2.6.x-dev" 645 | } 646 | }, 647 | "autoload": { 648 | "psr-0": { 649 | "Doctrine\\ORM\\": "lib/" 650 | } 651 | }, 652 | "notification-url": "https://packagist.org/downloads/", 653 | "license": [ 654 | "MIT" 655 | ], 656 | "authors": [ 657 | { 658 | "name": "Roman Borschel", 659 | "email": "roman@code-factory.org" 660 | }, 661 | { 662 | "name": "Benjamin Eberlei", 663 | "email": "kontakt@beberlei.de" 664 | }, 665 | { 666 | "name": "Guilherme Blanco", 667 | "email": "guilhermeblanco@gmail.com" 668 | }, 669 | { 670 | "name": "Jonathan Wage", 671 | "email": "jonwage@gmail.com" 672 | } 673 | ], 674 | "description": "Object-Relational-Mapper for PHP", 675 | "homepage": "http://www.doctrine-project.org", 676 | "keywords": [ 677 | "database", 678 | "orm" 679 | ], 680 | "time": "2016-01-05 21:34:58" 681 | }, 682 | { 683 | "name": "ocramius/proxy-manager", 684 | "version": "1.0.2", 685 | "source": { 686 | "type": "git", 687 | "url": "https://github.com/Ocramius/ProxyManager.git", 688 | "reference": "57e9272ec0e8deccf09421596e0e2252df440e11" 689 | }, 690 | "dist": { 691 | "type": "zip", 692 | "url": "https://api.github.com/repos/Ocramius/ProxyManager/zipball/57e9272ec0e8deccf09421596e0e2252df440e11", 693 | "reference": "57e9272ec0e8deccf09421596e0e2252df440e11", 694 | "shasum": "" 695 | }, 696 | "require": { 697 | "php": ">=5.3.3", 698 | "zendframework/zend-code": ">2.2.5,<3.0" 699 | }, 700 | "require-dev": { 701 | "ext-phar": "*", 702 | "phpunit/phpunit": "~4.0", 703 | "squizlabs/php_codesniffer": "1.5.*" 704 | }, 705 | "suggest": { 706 | "ocramius/generated-hydrator": "To have very fast object to array to object conversion for ghost objects", 707 | "zendframework/zend-json": "To have the JsonRpc adapter (Remote Object feature)", 708 | "zendframework/zend-soap": "To have the Soap adapter (Remote Object feature)", 709 | "zendframework/zend-stdlib": "To use the hydrator proxy", 710 | "zendframework/zend-xmlrpc": "To have the XmlRpc adapter (Remote Object feature)" 711 | }, 712 | "type": "library", 713 | "extra": { 714 | "branch-alias": { 715 | "dev-master": "2.0.x-dev" 716 | } 717 | }, 718 | "autoload": { 719 | "psr-0": { 720 | "ProxyManager\\": "src" 721 | } 722 | }, 723 | "notification-url": "https://packagist.org/downloads/", 724 | "license": [ 725 | "MIT" 726 | ], 727 | "authors": [ 728 | { 729 | "name": "Marco Pivetta", 730 | "email": "ocramius@gmail.com", 731 | "homepage": "http://ocramius.github.com/" 732 | } 733 | ], 734 | "description": "A library providing utilities to generate, instantiate and generally operate with Object Proxies", 735 | "homepage": "https://github.com/Ocramius/ProxyManager", 736 | "keywords": [ 737 | "aop", 738 | "lazy loading", 739 | "proxy", 740 | "proxy pattern", 741 | "service proxies" 742 | ], 743 | "time": "2015-08-09 04:28:19" 744 | }, 745 | { 746 | "name": "paragonie/random_compat", 747 | "version": "v2.0.2", 748 | "source": { 749 | "type": "git", 750 | "url": "https://github.com/paragonie/random_compat.git", 751 | "reference": "088c04e2f261c33bed6ca5245491cfca69195ccf" 752 | }, 753 | "dist": { 754 | "type": "zip", 755 | "url": "https://api.github.com/repos/paragonie/random_compat/zipball/088c04e2f261c33bed6ca5245491cfca69195ccf", 756 | "reference": "088c04e2f261c33bed6ca5245491cfca69195ccf", 757 | "shasum": "" 758 | }, 759 | "require": { 760 | "php": ">=5.2.0" 761 | }, 762 | "require-dev": { 763 | "phpunit/phpunit": "4.*|5.*" 764 | }, 765 | "suggest": { 766 | "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." 767 | }, 768 | "type": "library", 769 | "autoload": { 770 | "files": [ 771 | "lib/random.php" 772 | ] 773 | }, 774 | "notification-url": "https://packagist.org/downloads/", 775 | "license": [ 776 | "MIT" 777 | ], 778 | "authors": [ 779 | { 780 | "name": "Paragon Initiative Enterprises", 781 | "email": "security@paragonie.com", 782 | "homepage": "https://paragonie.com" 783 | } 784 | ], 785 | "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", 786 | "keywords": [ 787 | "csprng", 788 | "pseudorandom", 789 | "random" 790 | ], 791 | "time": "2016-04-03 06:00:07" 792 | }, 793 | { 794 | "name": "phpdocumentor/reflection-docblock", 795 | "version": "2.0.4", 796 | "source": { 797 | "type": "git", 798 | "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", 799 | "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8" 800 | }, 801 | "dist": { 802 | "type": "zip", 803 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d68dbdc53dc358a816f00b300704702b2eaff7b8", 804 | "reference": "d68dbdc53dc358a816f00b300704702b2eaff7b8", 805 | "shasum": "" 806 | }, 807 | "require": { 808 | "php": ">=5.3.3" 809 | }, 810 | "require-dev": { 811 | "phpunit/phpunit": "~4.0" 812 | }, 813 | "suggest": { 814 | "dflydev/markdown": "~1.0", 815 | "erusev/parsedown": "~1.0" 816 | }, 817 | "type": "library", 818 | "extra": { 819 | "branch-alias": { 820 | "dev-master": "2.0.x-dev" 821 | } 822 | }, 823 | "autoload": { 824 | "psr-0": { 825 | "phpDocumentor": [ 826 | "src/" 827 | ] 828 | } 829 | }, 830 | "notification-url": "https://packagist.org/downloads/", 831 | "license": [ 832 | "MIT" 833 | ], 834 | "authors": [ 835 | { 836 | "name": "Mike van Riel", 837 | "email": "mike.vanriel@naenius.com" 838 | } 839 | ], 840 | "time": "2015-02-03 12:10:50" 841 | }, 842 | { 843 | "name": "phpspec/prophecy", 844 | "version": "v1.6.0", 845 | "source": { 846 | "type": "git", 847 | "url": "https://github.com/phpspec/prophecy.git", 848 | "reference": "3c91bdf81797d725b14cb62906f9a4ce44235972" 849 | }, 850 | "dist": { 851 | "type": "zip", 852 | "url": "https://api.github.com/repos/phpspec/prophecy/zipball/3c91bdf81797d725b14cb62906f9a4ce44235972", 853 | "reference": "3c91bdf81797d725b14cb62906f9a4ce44235972", 854 | "shasum": "" 855 | }, 856 | "require": { 857 | "doctrine/instantiator": "^1.0.2", 858 | "php": "^5.3|^7.0", 859 | "phpdocumentor/reflection-docblock": "~2.0", 860 | "sebastian/comparator": "~1.1", 861 | "sebastian/recursion-context": "~1.0" 862 | }, 863 | "require-dev": { 864 | "phpspec/phpspec": "~2.0" 865 | }, 866 | "type": "library", 867 | "extra": { 868 | "branch-alias": { 869 | "dev-master": "1.5.x-dev" 870 | } 871 | }, 872 | "autoload": { 873 | "psr-0": { 874 | "Prophecy\\": "src/" 875 | } 876 | }, 877 | "notification-url": "https://packagist.org/downloads/", 878 | "license": [ 879 | "MIT" 880 | ], 881 | "authors": [ 882 | { 883 | "name": "Konstantin Kudryashov", 884 | "email": "ever.zet@gmail.com", 885 | "homepage": "http://everzet.com" 886 | }, 887 | { 888 | "name": "Marcello Duarte", 889 | "email": "marcello.duarte@gmail.com" 890 | } 891 | ], 892 | "description": "Highly opinionated mocking framework for PHP 5.3+", 893 | "homepage": "https://github.com/phpspec/prophecy", 894 | "keywords": [ 895 | "Double", 896 | "Dummy", 897 | "fake", 898 | "mock", 899 | "spy", 900 | "stub" 901 | ], 902 | "time": "2016-02-15 07:46:21" 903 | }, 904 | { 905 | "name": "phpunit/php-code-coverage", 906 | "version": "2.2.4", 907 | "source": { 908 | "type": "git", 909 | "url": "https://github.com/sebastianbergmann/php-code-coverage.git", 910 | "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979" 911 | }, 912 | "dist": { 913 | "type": "zip", 914 | "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979", 915 | "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979", 916 | "shasum": "" 917 | }, 918 | "require": { 919 | "php": ">=5.3.3", 920 | "phpunit/php-file-iterator": "~1.3", 921 | "phpunit/php-text-template": "~1.2", 922 | "phpunit/php-token-stream": "~1.3", 923 | "sebastian/environment": "^1.3.2", 924 | "sebastian/version": "~1.0" 925 | }, 926 | "require-dev": { 927 | "ext-xdebug": ">=2.1.4", 928 | "phpunit/phpunit": "~4" 929 | }, 930 | "suggest": { 931 | "ext-dom": "*", 932 | "ext-xdebug": ">=2.2.1", 933 | "ext-xmlwriter": "*" 934 | }, 935 | "type": "library", 936 | "extra": { 937 | "branch-alias": { 938 | "dev-master": "2.2.x-dev" 939 | } 940 | }, 941 | "autoload": { 942 | "classmap": [ 943 | "src/" 944 | ] 945 | }, 946 | "notification-url": "https://packagist.org/downloads/", 947 | "license": [ 948 | "BSD-3-Clause" 949 | ], 950 | "authors": [ 951 | { 952 | "name": "Sebastian Bergmann", 953 | "email": "sb@sebastian-bergmann.de", 954 | "role": "lead" 955 | } 956 | ], 957 | "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", 958 | "homepage": "https://github.com/sebastianbergmann/php-code-coverage", 959 | "keywords": [ 960 | "coverage", 961 | "testing", 962 | "xunit" 963 | ], 964 | "time": "2015-10-06 15:47:00" 965 | }, 966 | { 967 | "name": "phpunit/php-file-iterator", 968 | "version": "1.4.1", 969 | "source": { 970 | "type": "git", 971 | "url": "https://github.com/sebastianbergmann/php-file-iterator.git", 972 | "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0" 973 | }, 974 | "dist": { 975 | "type": "zip", 976 | "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6150bf2c35d3fc379e50c7602b75caceaa39dbf0", 977 | "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0", 978 | "shasum": "" 979 | }, 980 | "require": { 981 | "php": ">=5.3.3" 982 | }, 983 | "type": "library", 984 | "extra": { 985 | "branch-alias": { 986 | "dev-master": "1.4.x-dev" 987 | } 988 | }, 989 | "autoload": { 990 | "classmap": [ 991 | "src/" 992 | ] 993 | }, 994 | "notification-url": "https://packagist.org/downloads/", 995 | "license": [ 996 | "BSD-3-Clause" 997 | ], 998 | "authors": [ 999 | { 1000 | "name": "Sebastian Bergmann", 1001 | "email": "sb@sebastian-bergmann.de", 1002 | "role": "lead" 1003 | } 1004 | ], 1005 | "description": "FilterIterator implementation that filters files based on a list of suffixes.", 1006 | "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", 1007 | "keywords": [ 1008 | "filesystem", 1009 | "iterator" 1010 | ], 1011 | "time": "2015-06-21 13:08:43" 1012 | }, 1013 | { 1014 | "name": "phpunit/php-text-template", 1015 | "version": "1.2.1", 1016 | "source": { 1017 | "type": "git", 1018 | "url": "https://github.com/sebastianbergmann/php-text-template.git", 1019 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" 1020 | }, 1021 | "dist": { 1022 | "type": "zip", 1023 | "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", 1024 | "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", 1025 | "shasum": "" 1026 | }, 1027 | "require": { 1028 | "php": ">=5.3.3" 1029 | }, 1030 | "type": "library", 1031 | "autoload": { 1032 | "classmap": [ 1033 | "src/" 1034 | ] 1035 | }, 1036 | "notification-url": "https://packagist.org/downloads/", 1037 | "license": [ 1038 | "BSD-3-Clause" 1039 | ], 1040 | "authors": [ 1041 | { 1042 | "name": "Sebastian Bergmann", 1043 | "email": "sebastian@phpunit.de", 1044 | "role": "lead" 1045 | } 1046 | ], 1047 | "description": "Simple template engine.", 1048 | "homepage": "https://github.com/sebastianbergmann/php-text-template/", 1049 | "keywords": [ 1050 | "template" 1051 | ], 1052 | "time": "2015-06-21 13:50:34" 1053 | }, 1054 | { 1055 | "name": "phpunit/php-timer", 1056 | "version": "1.0.7", 1057 | "source": { 1058 | "type": "git", 1059 | "url": "https://github.com/sebastianbergmann/php-timer.git", 1060 | "reference": "3e82f4e9fc92665fafd9157568e4dcb01d014e5b" 1061 | }, 1062 | "dist": { 1063 | "type": "zip", 1064 | "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3e82f4e9fc92665fafd9157568e4dcb01d014e5b", 1065 | "reference": "3e82f4e9fc92665fafd9157568e4dcb01d014e5b", 1066 | "shasum": "" 1067 | }, 1068 | "require": { 1069 | "php": ">=5.3.3" 1070 | }, 1071 | "type": "library", 1072 | "autoload": { 1073 | "classmap": [ 1074 | "src/" 1075 | ] 1076 | }, 1077 | "notification-url": "https://packagist.org/downloads/", 1078 | "license": [ 1079 | "BSD-3-Clause" 1080 | ], 1081 | "authors": [ 1082 | { 1083 | "name": "Sebastian Bergmann", 1084 | "email": "sb@sebastian-bergmann.de", 1085 | "role": "lead" 1086 | } 1087 | ], 1088 | "description": "Utility class for timing", 1089 | "homepage": "https://github.com/sebastianbergmann/php-timer/", 1090 | "keywords": [ 1091 | "timer" 1092 | ], 1093 | "time": "2015-06-21 08:01:12" 1094 | }, 1095 | { 1096 | "name": "phpunit/php-token-stream", 1097 | "version": "1.4.8", 1098 | "source": { 1099 | "type": "git", 1100 | "url": "https://github.com/sebastianbergmann/php-token-stream.git", 1101 | "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da" 1102 | }, 1103 | "dist": { 1104 | "type": "zip", 1105 | "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da", 1106 | "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da", 1107 | "shasum": "" 1108 | }, 1109 | "require": { 1110 | "ext-tokenizer": "*", 1111 | "php": ">=5.3.3" 1112 | }, 1113 | "require-dev": { 1114 | "phpunit/phpunit": "~4.2" 1115 | }, 1116 | "type": "library", 1117 | "extra": { 1118 | "branch-alias": { 1119 | "dev-master": "1.4-dev" 1120 | } 1121 | }, 1122 | "autoload": { 1123 | "classmap": [ 1124 | "src/" 1125 | ] 1126 | }, 1127 | "notification-url": "https://packagist.org/downloads/", 1128 | "license": [ 1129 | "BSD-3-Clause" 1130 | ], 1131 | "authors": [ 1132 | { 1133 | "name": "Sebastian Bergmann", 1134 | "email": "sebastian@phpunit.de" 1135 | } 1136 | ], 1137 | "description": "Wrapper around PHP's tokenizer extension.", 1138 | "homepage": "https://github.com/sebastianbergmann/php-token-stream/", 1139 | "keywords": [ 1140 | "tokenizer" 1141 | ], 1142 | "time": "2015-09-15 10:49:45" 1143 | }, 1144 | { 1145 | "name": "phpunit/phpunit", 1146 | "version": "4.8.24", 1147 | "source": { 1148 | "type": "git", 1149 | "url": "https://github.com/sebastianbergmann/phpunit.git", 1150 | "reference": "a1066c562c52900a142a0e2bbf0582994671385e" 1151 | }, 1152 | "dist": { 1153 | "type": "zip", 1154 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a1066c562c52900a142a0e2bbf0582994671385e", 1155 | "reference": "a1066c562c52900a142a0e2bbf0582994671385e", 1156 | "shasum": "" 1157 | }, 1158 | "require": { 1159 | "ext-dom": "*", 1160 | "ext-json": "*", 1161 | "ext-pcre": "*", 1162 | "ext-reflection": "*", 1163 | "ext-spl": "*", 1164 | "php": ">=5.3.3", 1165 | "phpspec/prophecy": "^1.3.1", 1166 | "phpunit/php-code-coverage": "~2.1", 1167 | "phpunit/php-file-iterator": "~1.4", 1168 | "phpunit/php-text-template": "~1.2", 1169 | "phpunit/php-timer": ">=1.0.6", 1170 | "phpunit/phpunit-mock-objects": "~2.3", 1171 | "sebastian/comparator": "~1.1", 1172 | "sebastian/diff": "~1.2", 1173 | "sebastian/environment": "~1.3", 1174 | "sebastian/exporter": "~1.2", 1175 | "sebastian/global-state": "~1.0", 1176 | "sebastian/version": "~1.0", 1177 | "symfony/yaml": "~2.1|~3.0" 1178 | }, 1179 | "suggest": { 1180 | "phpunit/php-invoker": "~1.1" 1181 | }, 1182 | "bin": [ 1183 | "phpunit" 1184 | ], 1185 | "type": "library", 1186 | "extra": { 1187 | "branch-alias": { 1188 | "dev-master": "4.8.x-dev" 1189 | } 1190 | }, 1191 | "autoload": { 1192 | "classmap": [ 1193 | "src/" 1194 | ] 1195 | }, 1196 | "notification-url": "https://packagist.org/downloads/", 1197 | "license": [ 1198 | "BSD-3-Clause" 1199 | ], 1200 | "authors": [ 1201 | { 1202 | "name": "Sebastian Bergmann", 1203 | "email": "sebastian@phpunit.de", 1204 | "role": "lead" 1205 | } 1206 | ], 1207 | "description": "The PHP Unit Testing framework.", 1208 | "homepage": "https://phpunit.de/", 1209 | "keywords": [ 1210 | "phpunit", 1211 | "testing", 1212 | "xunit" 1213 | ], 1214 | "time": "2016-03-14 06:16:08" 1215 | }, 1216 | { 1217 | "name": "phpunit/phpunit-mock-objects", 1218 | "version": "2.3.8", 1219 | "source": { 1220 | "type": "git", 1221 | "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", 1222 | "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983" 1223 | }, 1224 | "dist": { 1225 | "type": "zip", 1226 | "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983", 1227 | "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983", 1228 | "shasum": "" 1229 | }, 1230 | "require": { 1231 | "doctrine/instantiator": "^1.0.2", 1232 | "php": ">=5.3.3", 1233 | "phpunit/php-text-template": "~1.2", 1234 | "sebastian/exporter": "~1.2" 1235 | }, 1236 | "require-dev": { 1237 | "phpunit/phpunit": "~4.4" 1238 | }, 1239 | "suggest": { 1240 | "ext-soap": "*" 1241 | }, 1242 | "type": "library", 1243 | "extra": { 1244 | "branch-alias": { 1245 | "dev-master": "2.3.x-dev" 1246 | } 1247 | }, 1248 | "autoload": { 1249 | "classmap": [ 1250 | "src/" 1251 | ] 1252 | }, 1253 | "notification-url": "https://packagist.org/downloads/", 1254 | "license": [ 1255 | "BSD-3-Clause" 1256 | ], 1257 | "authors": [ 1258 | { 1259 | "name": "Sebastian Bergmann", 1260 | "email": "sb@sebastian-bergmann.de", 1261 | "role": "lead" 1262 | } 1263 | ], 1264 | "description": "Mock Object library for PHPUnit", 1265 | "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", 1266 | "keywords": [ 1267 | "mock", 1268 | "xunit" 1269 | ], 1270 | "time": "2015-10-02 06:51:40" 1271 | }, 1272 | { 1273 | "name": "ramsey/uuid", 1274 | "version": "3.4.1", 1275 | "source": { 1276 | "type": "git", 1277 | "url": "https://github.com/ramsey/uuid.git", 1278 | "reference": "b4fe3b7387cb323fd15ad5837cae992422c9fa5c" 1279 | }, 1280 | "dist": { 1281 | "type": "zip", 1282 | "url": "https://api.github.com/repos/ramsey/uuid/zipball/b4fe3b7387cb323fd15ad5837cae992422c9fa5c", 1283 | "reference": "b4fe3b7387cb323fd15ad5837cae992422c9fa5c", 1284 | "shasum": "" 1285 | }, 1286 | "require": { 1287 | "paragonie/random_compat": "^1.0|^2.0", 1288 | "php": ">=5.4" 1289 | }, 1290 | "replace": { 1291 | "rhumsaa/uuid": "self.version" 1292 | }, 1293 | "require-dev": { 1294 | "apigen/apigen": "^4.1", 1295 | "codeception/aspect-mock": "1.0.0", 1296 | "goaop/framework": "1.0.0-alpha.2", 1297 | "ircmaxell/random-lib": "^1.1", 1298 | "jakub-onderka/php-parallel-lint": "^0.9.0", 1299 | "mockery/mockery": "^0.9.4", 1300 | "moontoast/math": "^1.1", 1301 | "phpunit/phpunit": "^4.7|^5.0", 1302 | "satooshi/php-coveralls": "^0.6.1", 1303 | "squizlabs/php_codesniffer": "^2.3" 1304 | }, 1305 | "suggest": { 1306 | "ext-libsodium": "Provides the PECL libsodium extension for use with the SodiumRandomGenerator", 1307 | "ext-uuid": "Provides the PECL UUID extension for use with the PeclUuidTimeGenerator and PeclUuidRandomGenerator", 1308 | "ircmaxell/random-lib": "Provides RandomLib for use with the RandomLibAdapter", 1309 | "moontoast/math": "Provides support for converting UUID to 128-bit integer (in string form).", 1310 | "ramsey/uuid-console": "A console application for generating UUIDs with ramsey/uuid", 1311 | "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type." 1312 | }, 1313 | "type": "library", 1314 | "extra": { 1315 | "branch-alias": { 1316 | "dev-master": "3.x-dev" 1317 | } 1318 | }, 1319 | "autoload": { 1320 | "psr-4": { 1321 | "Ramsey\\Uuid\\": "src/" 1322 | } 1323 | }, 1324 | "notification-url": "https://packagist.org/downloads/", 1325 | "license": [ 1326 | "MIT" 1327 | ], 1328 | "authors": [ 1329 | { 1330 | "name": "Marijn Huizendveld", 1331 | "email": "marijn.huizendveld@gmail.com" 1332 | }, 1333 | { 1334 | "name": "Thibaud Fabre", 1335 | "email": "thibaud@aztech.io" 1336 | }, 1337 | { 1338 | "name": "Ben Ramsey", 1339 | "email": "ben@benramsey.com", 1340 | "homepage": "https://benramsey.com" 1341 | } 1342 | ], 1343 | "description": "Formerly rhumsaa/uuid. A PHP 5.4+ library for generating RFC 4122 version 1, 3, 4, and 5 universally unique identifiers (UUID).", 1344 | "homepage": "https://github.com/ramsey/uuid", 1345 | "keywords": [ 1346 | "guid", 1347 | "identifier", 1348 | "uuid" 1349 | ], 1350 | "time": "2016-04-24 00:30:41" 1351 | }, 1352 | { 1353 | "name": "ramsey/uuid-doctrine", 1354 | "version": "1.2.0", 1355 | "source": { 1356 | "type": "git", 1357 | "url": "https://github.com/ramsey/uuid-doctrine.git", 1358 | "reference": "503c5e0c22b17fe5a53af53124621360e9e07f41" 1359 | }, 1360 | "dist": { 1361 | "type": "zip", 1362 | "url": "https://api.github.com/repos/ramsey/uuid-doctrine/zipball/503c5e0c22b17fe5a53af53124621360e9e07f41", 1363 | "reference": "503c5e0c22b17fe5a53af53124621360e9e07f41", 1364 | "shasum": "" 1365 | }, 1366 | "require": { 1367 | "doctrine/orm": "^2.5", 1368 | "php": ">=5.4", 1369 | "ramsey/uuid": "^3.0" 1370 | }, 1371 | "require-dev": { 1372 | "jakub-onderka/php-parallel-lint": "^0.9.0", 1373 | "phpunit/phpunit": "^4.7|^5.0", 1374 | "satooshi/php-coveralls": "^0.6.1", 1375 | "squizlabs/php_codesniffer": "^2.3" 1376 | }, 1377 | "type": "library", 1378 | "autoload": { 1379 | "psr-4": { 1380 | "Ramsey\\Uuid\\Doctrine\\": "src/" 1381 | } 1382 | }, 1383 | "notification-url": "https://packagist.org/downloads/", 1384 | "license": [ 1385 | "MIT" 1386 | ], 1387 | "authors": [ 1388 | { 1389 | "name": "Marijn Huizendveld", 1390 | "email": "marijn.huizendveld@gmail.com" 1391 | }, 1392 | { 1393 | "name": "Ben Ramsey", 1394 | "email": "ben@benramsey.com", 1395 | "homepage": "http://benramsey.com" 1396 | } 1397 | ], 1398 | "description": "Allow the use of a ramsey/uuid UUID as Doctrine field type.", 1399 | "homepage": "https://github.com/ramsey/uuid-doctrine", 1400 | "keywords": [ 1401 | "doctrine", 1402 | "guid", 1403 | "identifier", 1404 | "uuid" 1405 | ], 1406 | "time": "2016-03-23 17:44:03" 1407 | }, 1408 | { 1409 | "name": "sebastian/comparator", 1410 | "version": "1.2.0", 1411 | "source": { 1412 | "type": "git", 1413 | "url": "https://github.com/sebastianbergmann/comparator.git", 1414 | "reference": "937efb279bd37a375bcadf584dec0726f84dbf22" 1415 | }, 1416 | "dist": { 1417 | "type": "zip", 1418 | "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/937efb279bd37a375bcadf584dec0726f84dbf22", 1419 | "reference": "937efb279bd37a375bcadf584dec0726f84dbf22", 1420 | "shasum": "" 1421 | }, 1422 | "require": { 1423 | "php": ">=5.3.3", 1424 | "sebastian/diff": "~1.2", 1425 | "sebastian/exporter": "~1.2" 1426 | }, 1427 | "require-dev": { 1428 | "phpunit/phpunit": "~4.4" 1429 | }, 1430 | "type": "library", 1431 | "extra": { 1432 | "branch-alias": { 1433 | "dev-master": "1.2.x-dev" 1434 | } 1435 | }, 1436 | "autoload": { 1437 | "classmap": [ 1438 | "src/" 1439 | ] 1440 | }, 1441 | "notification-url": "https://packagist.org/downloads/", 1442 | "license": [ 1443 | "BSD-3-Clause" 1444 | ], 1445 | "authors": [ 1446 | { 1447 | "name": "Jeff Welch", 1448 | "email": "whatthejeff@gmail.com" 1449 | }, 1450 | { 1451 | "name": "Volker Dusch", 1452 | "email": "github@wallbash.com" 1453 | }, 1454 | { 1455 | "name": "Bernhard Schussek", 1456 | "email": "bschussek@2bepublished.at" 1457 | }, 1458 | { 1459 | "name": "Sebastian Bergmann", 1460 | "email": "sebastian@phpunit.de" 1461 | } 1462 | ], 1463 | "description": "Provides the functionality to compare PHP values for equality", 1464 | "homepage": "http://www.github.com/sebastianbergmann/comparator", 1465 | "keywords": [ 1466 | "comparator", 1467 | "compare", 1468 | "equality" 1469 | ], 1470 | "time": "2015-07-26 15:48:44" 1471 | }, 1472 | { 1473 | "name": "sebastian/diff", 1474 | "version": "1.4.1", 1475 | "source": { 1476 | "type": "git", 1477 | "url": "https://github.com/sebastianbergmann/diff.git", 1478 | "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e" 1479 | }, 1480 | "dist": { 1481 | "type": "zip", 1482 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/13edfd8706462032c2f52b4b862974dd46b71c9e", 1483 | "reference": "13edfd8706462032c2f52b4b862974dd46b71c9e", 1484 | "shasum": "" 1485 | }, 1486 | "require": { 1487 | "php": ">=5.3.3" 1488 | }, 1489 | "require-dev": { 1490 | "phpunit/phpunit": "~4.8" 1491 | }, 1492 | "type": "library", 1493 | "extra": { 1494 | "branch-alias": { 1495 | "dev-master": "1.4-dev" 1496 | } 1497 | }, 1498 | "autoload": { 1499 | "classmap": [ 1500 | "src/" 1501 | ] 1502 | }, 1503 | "notification-url": "https://packagist.org/downloads/", 1504 | "license": [ 1505 | "BSD-3-Clause" 1506 | ], 1507 | "authors": [ 1508 | { 1509 | "name": "Kore Nordmann", 1510 | "email": "mail@kore-nordmann.de" 1511 | }, 1512 | { 1513 | "name": "Sebastian Bergmann", 1514 | "email": "sebastian@phpunit.de" 1515 | } 1516 | ], 1517 | "description": "Diff implementation", 1518 | "homepage": "https://github.com/sebastianbergmann/diff", 1519 | "keywords": [ 1520 | "diff" 1521 | ], 1522 | "time": "2015-12-08 07:14:41" 1523 | }, 1524 | { 1525 | "name": "sebastian/environment", 1526 | "version": "1.3.5", 1527 | "source": { 1528 | "type": "git", 1529 | "url": "https://github.com/sebastianbergmann/environment.git", 1530 | "reference": "dc7a29032cf72b54f36dac15a1ca5b3a1b6029bf" 1531 | }, 1532 | "dist": { 1533 | "type": "zip", 1534 | "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/dc7a29032cf72b54f36dac15a1ca5b3a1b6029bf", 1535 | "reference": "dc7a29032cf72b54f36dac15a1ca5b3a1b6029bf", 1536 | "shasum": "" 1537 | }, 1538 | "require": { 1539 | "php": ">=5.3.3" 1540 | }, 1541 | "require-dev": { 1542 | "phpunit/phpunit": "~4.4" 1543 | }, 1544 | "type": "library", 1545 | "extra": { 1546 | "branch-alias": { 1547 | "dev-master": "1.3.x-dev" 1548 | } 1549 | }, 1550 | "autoload": { 1551 | "classmap": [ 1552 | "src/" 1553 | ] 1554 | }, 1555 | "notification-url": "https://packagist.org/downloads/", 1556 | "license": [ 1557 | "BSD-3-Clause" 1558 | ], 1559 | "authors": [ 1560 | { 1561 | "name": "Sebastian Bergmann", 1562 | "email": "sebastian@phpunit.de" 1563 | } 1564 | ], 1565 | "description": "Provides functionality to handle HHVM/PHP environments", 1566 | "homepage": "http://www.github.com/sebastianbergmann/environment", 1567 | "keywords": [ 1568 | "Xdebug", 1569 | "environment", 1570 | "hhvm" 1571 | ], 1572 | "time": "2016-02-26 18:40:46" 1573 | }, 1574 | { 1575 | "name": "sebastian/exporter", 1576 | "version": "1.2.1", 1577 | "source": { 1578 | "type": "git", 1579 | "url": "https://github.com/sebastianbergmann/exporter.git", 1580 | "reference": "7ae5513327cb536431847bcc0c10edba2701064e" 1581 | }, 1582 | "dist": { 1583 | "type": "zip", 1584 | "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/7ae5513327cb536431847bcc0c10edba2701064e", 1585 | "reference": "7ae5513327cb536431847bcc0c10edba2701064e", 1586 | "shasum": "" 1587 | }, 1588 | "require": { 1589 | "php": ">=5.3.3", 1590 | "sebastian/recursion-context": "~1.0" 1591 | }, 1592 | "require-dev": { 1593 | "phpunit/phpunit": "~4.4" 1594 | }, 1595 | "type": "library", 1596 | "extra": { 1597 | "branch-alias": { 1598 | "dev-master": "1.2.x-dev" 1599 | } 1600 | }, 1601 | "autoload": { 1602 | "classmap": [ 1603 | "src/" 1604 | ] 1605 | }, 1606 | "notification-url": "https://packagist.org/downloads/", 1607 | "license": [ 1608 | "BSD-3-Clause" 1609 | ], 1610 | "authors": [ 1611 | { 1612 | "name": "Jeff Welch", 1613 | "email": "whatthejeff@gmail.com" 1614 | }, 1615 | { 1616 | "name": "Volker Dusch", 1617 | "email": "github@wallbash.com" 1618 | }, 1619 | { 1620 | "name": "Bernhard Schussek", 1621 | "email": "bschussek@2bepublished.at" 1622 | }, 1623 | { 1624 | "name": "Sebastian Bergmann", 1625 | "email": "sebastian@phpunit.de" 1626 | }, 1627 | { 1628 | "name": "Adam Harvey", 1629 | "email": "aharvey@php.net" 1630 | } 1631 | ], 1632 | "description": "Provides the functionality to export PHP variables for visualization", 1633 | "homepage": "http://www.github.com/sebastianbergmann/exporter", 1634 | "keywords": [ 1635 | "export", 1636 | "exporter" 1637 | ], 1638 | "time": "2015-06-21 07:55:53" 1639 | }, 1640 | { 1641 | "name": "sebastian/global-state", 1642 | "version": "1.1.1", 1643 | "source": { 1644 | "type": "git", 1645 | "url": "https://github.com/sebastianbergmann/global-state.git", 1646 | "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" 1647 | }, 1648 | "dist": { 1649 | "type": "zip", 1650 | "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", 1651 | "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", 1652 | "shasum": "" 1653 | }, 1654 | "require": { 1655 | "php": ">=5.3.3" 1656 | }, 1657 | "require-dev": { 1658 | "phpunit/phpunit": "~4.2" 1659 | }, 1660 | "suggest": { 1661 | "ext-uopz": "*" 1662 | }, 1663 | "type": "library", 1664 | "extra": { 1665 | "branch-alias": { 1666 | "dev-master": "1.0-dev" 1667 | } 1668 | }, 1669 | "autoload": { 1670 | "classmap": [ 1671 | "src/" 1672 | ] 1673 | }, 1674 | "notification-url": "https://packagist.org/downloads/", 1675 | "license": [ 1676 | "BSD-3-Clause" 1677 | ], 1678 | "authors": [ 1679 | { 1680 | "name": "Sebastian Bergmann", 1681 | "email": "sebastian@phpunit.de" 1682 | } 1683 | ], 1684 | "description": "Snapshotting of global state", 1685 | "homepage": "http://www.github.com/sebastianbergmann/global-state", 1686 | "keywords": [ 1687 | "global state" 1688 | ], 1689 | "time": "2015-10-12 03:26:01" 1690 | }, 1691 | { 1692 | "name": "sebastian/recursion-context", 1693 | "version": "1.0.2", 1694 | "source": { 1695 | "type": "git", 1696 | "url": "https://github.com/sebastianbergmann/recursion-context.git", 1697 | "reference": "913401df809e99e4f47b27cdd781f4a258d58791" 1698 | }, 1699 | "dist": { 1700 | "type": "zip", 1701 | "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/913401df809e99e4f47b27cdd781f4a258d58791", 1702 | "reference": "913401df809e99e4f47b27cdd781f4a258d58791", 1703 | "shasum": "" 1704 | }, 1705 | "require": { 1706 | "php": ">=5.3.3" 1707 | }, 1708 | "require-dev": { 1709 | "phpunit/phpunit": "~4.4" 1710 | }, 1711 | "type": "library", 1712 | "extra": { 1713 | "branch-alias": { 1714 | "dev-master": "1.0.x-dev" 1715 | } 1716 | }, 1717 | "autoload": { 1718 | "classmap": [ 1719 | "src/" 1720 | ] 1721 | }, 1722 | "notification-url": "https://packagist.org/downloads/", 1723 | "license": [ 1724 | "BSD-3-Clause" 1725 | ], 1726 | "authors": [ 1727 | { 1728 | "name": "Jeff Welch", 1729 | "email": "whatthejeff@gmail.com" 1730 | }, 1731 | { 1732 | "name": "Sebastian Bergmann", 1733 | "email": "sebastian@phpunit.de" 1734 | }, 1735 | { 1736 | "name": "Adam Harvey", 1737 | "email": "aharvey@php.net" 1738 | } 1739 | ], 1740 | "description": "Provides functionality to recursively process PHP variables", 1741 | "homepage": "http://www.github.com/sebastianbergmann/recursion-context", 1742 | "time": "2015-11-11 19:50:13" 1743 | }, 1744 | { 1745 | "name": "sebastian/version", 1746 | "version": "1.0.6", 1747 | "source": { 1748 | "type": "git", 1749 | "url": "https://github.com/sebastianbergmann/version.git", 1750 | "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6" 1751 | }, 1752 | "dist": { 1753 | "type": "zip", 1754 | "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", 1755 | "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", 1756 | "shasum": "" 1757 | }, 1758 | "type": "library", 1759 | "autoload": { 1760 | "classmap": [ 1761 | "src/" 1762 | ] 1763 | }, 1764 | "notification-url": "https://packagist.org/downloads/", 1765 | "license": [ 1766 | "BSD-3-Clause" 1767 | ], 1768 | "authors": [ 1769 | { 1770 | "name": "Sebastian Bergmann", 1771 | "email": "sebastian@phpunit.de", 1772 | "role": "lead" 1773 | } 1774 | ], 1775 | "description": "Library that helps with managing the version number of Git-hosted PHP projects", 1776 | "homepage": "https://github.com/sebastianbergmann/version", 1777 | "time": "2015-06-21 13:59:46" 1778 | }, 1779 | { 1780 | "name": "symfony/console", 1781 | "version": "v3.0.4", 1782 | "source": { 1783 | "type": "git", 1784 | "url": "https://github.com/symfony/console.git", 1785 | "reference": "6b1175135bc2a74c08a28d89761272de8beed8cd" 1786 | }, 1787 | "dist": { 1788 | "type": "zip", 1789 | "url": "https://api.github.com/repos/symfony/console/zipball/6b1175135bc2a74c08a28d89761272de8beed8cd", 1790 | "reference": "6b1175135bc2a74c08a28d89761272de8beed8cd", 1791 | "shasum": "" 1792 | }, 1793 | "require": { 1794 | "php": ">=5.5.9", 1795 | "symfony/polyfill-mbstring": "~1.0" 1796 | }, 1797 | "require-dev": { 1798 | "psr/log": "~1.0", 1799 | "symfony/event-dispatcher": "~2.8|~3.0", 1800 | "symfony/process": "~2.8|~3.0" 1801 | }, 1802 | "suggest": { 1803 | "psr/log": "For using the console logger", 1804 | "symfony/event-dispatcher": "", 1805 | "symfony/process": "" 1806 | }, 1807 | "type": "library", 1808 | "extra": { 1809 | "branch-alias": { 1810 | "dev-master": "3.0-dev" 1811 | } 1812 | }, 1813 | "autoload": { 1814 | "psr-4": { 1815 | "Symfony\\Component\\Console\\": "" 1816 | }, 1817 | "exclude-from-classmap": [ 1818 | "/Tests/" 1819 | ] 1820 | }, 1821 | "notification-url": "https://packagist.org/downloads/", 1822 | "license": [ 1823 | "MIT" 1824 | ], 1825 | "authors": [ 1826 | { 1827 | "name": "Fabien Potencier", 1828 | "email": "fabien@symfony.com" 1829 | }, 1830 | { 1831 | "name": "Symfony Community", 1832 | "homepage": "https://symfony.com/contributors" 1833 | } 1834 | ], 1835 | "description": "Symfony Console Component", 1836 | "homepage": "https://symfony.com", 1837 | "time": "2016-03-16 17:00:50" 1838 | }, 1839 | { 1840 | "name": "symfony/polyfill-mbstring", 1841 | "version": "v1.1.1", 1842 | "source": { 1843 | "type": "git", 1844 | "url": "https://github.com/symfony/polyfill-mbstring.git", 1845 | "reference": "1289d16209491b584839022f29257ad859b8532d" 1846 | }, 1847 | "dist": { 1848 | "type": "zip", 1849 | "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/1289d16209491b584839022f29257ad859b8532d", 1850 | "reference": "1289d16209491b584839022f29257ad859b8532d", 1851 | "shasum": "" 1852 | }, 1853 | "require": { 1854 | "php": ">=5.3.3" 1855 | }, 1856 | "suggest": { 1857 | "ext-mbstring": "For best performance" 1858 | }, 1859 | "type": "library", 1860 | "extra": { 1861 | "branch-alias": { 1862 | "dev-master": "1.1-dev" 1863 | } 1864 | }, 1865 | "autoload": { 1866 | "psr-4": { 1867 | "Symfony\\Polyfill\\Mbstring\\": "" 1868 | }, 1869 | "files": [ 1870 | "bootstrap.php" 1871 | ] 1872 | }, 1873 | "notification-url": "https://packagist.org/downloads/", 1874 | "license": [ 1875 | "MIT" 1876 | ], 1877 | "authors": [ 1878 | { 1879 | "name": "Nicolas Grekas", 1880 | "email": "p@tchwork.com" 1881 | }, 1882 | { 1883 | "name": "Symfony Community", 1884 | "homepage": "https://symfony.com/contributors" 1885 | } 1886 | ], 1887 | "description": "Symfony polyfill for the Mbstring extension", 1888 | "homepage": "https://symfony.com", 1889 | "keywords": [ 1890 | "compatibility", 1891 | "mbstring", 1892 | "polyfill", 1893 | "portable", 1894 | "shim" 1895 | ], 1896 | "time": "2016-01-20 09:13:37" 1897 | }, 1898 | { 1899 | "name": "symfony/yaml", 1900 | "version": "v3.0.4", 1901 | "source": { 1902 | "type": "git", 1903 | "url": "https://github.com/symfony/yaml.git", 1904 | "reference": "0047c8366744a16de7516622c5b7355336afae96" 1905 | }, 1906 | "dist": { 1907 | "type": "zip", 1908 | "url": "https://api.github.com/repos/symfony/yaml/zipball/0047c8366744a16de7516622c5b7355336afae96", 1909 | "reference": "0047c8366744a16de7516622c5b7355336afae96", 1910 | "shasum": "" 1911 | }, 1912 | "require": { 1913 | "php": ">=5.5.9" 1914 | }, 1915 | "type": "library", 1916 | "extra": { 1917 | "branch-alias": { 1918 | "dev-master": "3.0-dev" 1919 | } 1920 | }, 1921 | "autoload": { 1922 | "psr-4": { 1923 | "Symfony\\Component\\Yaml\\": "" 1924 | }, 1925 | "exclude-from-classmap": [ 1926 | "/Tests/" 1927 | ] 1928 | }, 1929 | "notification-url": "https://packagist.org/downloads/", 1930 | "license": [ 1931 | "MIT" 1932 | ], 1933 | "authors": [ 1934 | { 1935 | "name": "Fabien Potencier", 1936 | "email": "fabien@symfony.com" 1937 | }, 1938 | { 1939 | "name": "Symfony Community", 1940 | "homepage": "https://symfony.com/contributors" 1941 | } 1942 | ], 1943 | "description": "Symfony Yaml Component", 1944 | "homepage": "https://symfony.com", 1945 | "time": "2016-03-04 07:55:57" 1946 | }, 1947 | { 1948 | "name": "zendframework/zend-code", 1949 | "version": "2.6.3", 1950 | "source": { 1951 | "type": "git", 1952 | "url": "https://github.com/zendframework/zend-code.git", 1953 | "reference": "95033f061b083e16cdee60530ec260d7d628b887" 1954 | }, 1955 | "dist": { 1956 | "type": "zip", 1957 | "url": "https://api.github.com/repos/zendframework/zend-code/zipball/95033f061b083e16cdee60530ec260d7d628b887", 1958 | "reference": "95033f061b083e16cdee60530ec260d7d628b887", 1959 | "shasum": "" 1960 | }, 1961 | "require": { 1962 | "php": "^5.5 || 7.0.0 - 7.0.4 || ^7.0.6", 1963 | "zendframework/zend-eventmanager": "^2.6 || ^3.0" 1964 | }, 1965 | "require-dev": { 1966 | "doctrine/annotations": "~1.0", 1967 | "fabpot/php-cs-fixer": "1.7.*", 1968 | "phpunit/phpunit": "^4.8.21", 1969 | "zendframework/zend-stdlib": "^2.7 || ^3.0" 1970 | }, 1971 | "suggest": { 1972 | "doctrine/annotations": "Doctrine\\Common\\Annotations >=1.0 for annotation features", 1973 | "zendframework/zend-stdlib": "Zend\\Stdlib component" 1974 | }, 1975 | "type": "library", 1976 | "extra": { 1977 | "branch-alias": { 1978 | "dev-master": "2.6-dev", 1979 | "dev-develop": "2.7-dev" 1980 | } 1981 | }, 1982 | "autoload": { 1983 | "psr-4": { 1984 | "Zend\\Code\\": "src/" 1985 | } 1986 | }, 1987 | "notification-url": "https://packagist.org/downloads/", 1988 | "license": [ 1989 | "BSD-3-Clause" 1990 | ], 1991 | "description": "provides facilities to generate arbitrary code using an object oriented interface", 1992 | "homepage": "https://github.com/zendframework/zend-code", 1993 | "keywords": [ 1994 | "code", 1995 | "zf2" 1996 | ], 1997 | "time": "2016-04-20 17:26:42" 1998 | }, 1999 | { 2000 | "name": "zendframework/zend-eventmanager", 2001 | "version": "3.0.1", 2002 | "source": { 2003 | "type": "git", 2004 | "url": "https://github.com/zendframework/zend-eventmanager.git", 2005 | "reference": "5c80bdee0e952be112dcec0968bad770082c3a6e" 2006 | }, 2007 | "dist": { 2008 | "type": "zip", 2009 | "url": "https://api.github.com/repos/zendframework/zend-eventmanager/zipball/5c80bdee0e952be112dcec0968bad770082c3a6e", 2010 | "reference": "5c80bdee0e952be112dcec0968bad770082c3a6e", 2011 | "shasum": "" 2012 | }, 2013 | "require": { 2014 | "php": "^5.5 || ^7.0" 2015 | }, 2016 | "require-dev": { 2017 | "athletic/athletic": "^0.1", 2018 | "container-interop/container-interop": "^1.1.0", 2019 | "phpunit/phpunit": "~4.0", 2020 | "squizlabs/php_codesniffer": "^2.0", 2021 | "zendframework/zend-stdlib": "^2.7.3 || ^3.0" 2022 | }, 2023 | "suggest": { 2024 | "container-interop/container-interop": "^1.1.0, to use the lazy listeners feature", 2025 | "zendframework/zend-stdlib": "^2.7.3 || ^3.0, to use the FilterChain feature" 2026 | }, 2027 | "type": "library", 2028 | "extra": { 2029 | "branch-alias": { 2030 | "dev-master": "3.0-dev", 2031 | "dev-develop": "3.1-dev" 2032 | } 2033 | }, 2034 | "autoload": { 2035 | "psr-4": { 2036 | "Zend\\EventManager\\": "src/" 2037 | } 2038 | }, 2039 | "notification-url": "https://packagist.org/downloads/", 2040 | "license": [ 2041 | "BSD-3-Clause" 2042 | ], 2043 | "description": "Trigger and listen to events within a PHP application", 2044 | "homepage": "https://github.com/zendframework/zend-eventmanager", 2045 | "keywords": [ 2046 | "event", 2047 | "eventmanager", 2048 | "events", 2049 | "zf2" 2050 | ], 2051 | "time": "2016-02-18 20:53:00" 2052 | } 2053 | ], 2054 | "packages-dev": [], 2055 | "aliases": [], 2056 | "minimum-stability": "stable", 2057 | "stability-flags": [], 2058 | "prefer-stable": false, 2059 | "prefer-lowest": false, 2060 | "platform": [], 2061 | "platform-dev": [], 2062 | "platform-overrides": { 2063 | "php": "5.5.9" 2064 | } 2065 | } 2066 | -------------------------------------------------------------------------------- /data/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | !proxies -------------------------------------------------------------------------------- /data/proxies/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore -------------------------------------------------------------------------------- /mapping/Authentication.Entity.User.dcm.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /mapping/Enforcement.Entity.EnforcementRequest.dcm.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /mapping/Library.BookAmount.dcm.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /migrations.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | Maintainable Doctrine apps tutorial 8 | 9 | DoctrineMigrations 10 | ./migrations 11 | 12 | -------------------------------------------------------------------------------- /migrations/Version20160428103311.php: -------------------------------------------------------------------------------- 1 | abortIf($this->connection->getDatabasePlatform()->getName() != 'sqlite', 'Migration can only be executed safely on \'sqlite\'.'); 20 | 21 | $this->addSql('CREATE TABLE User (id CHAR(36) NOT NULL, PRIMARY KEY(id))'); 22 | $this->addSql('CREATE TABLE EnforcementRequest (id CHAR(36) NOT NULL, PRIMARY KEY(id))'); 23 | $this->addSql('CREATE TABLE BookAmount (isbn VARCHAR(255) NOT NULL, amount INTEGER NOT NULL, libraryId VARCHAR(255) NOT NULL, PRIMARY KEY(libraryId, isbn))'); 24 | } 25 | 26 | /** 27 | * @param Schema $schema 28 | */ 29 | public function down(Schema $schema) 30 | { 31 | // this down() migration is auto-generated, please modify it to your needs 32 | $this->abortIf($this->connection->getDatabasePlatform()->getName() != 'sqlite', 'Migration can only be executed safely on \'sqlite\'.'); 33 | 34 | $this->addSql('DROP TABLE User'); 35 | $this->addSql('DROP TABLE EnforcementRequest'); 36 | $this->addSql('DROP TABLE BookAmount'); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 15 | 16 | ./test 17 | 18 | 19 | 20 | ./src 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /public/add-book.php: -------------------------------------------------------------------------------- 1 | find(User::class, $_GET['userId']); 12 | 13 | $_SESSION['userId'] = (string) $user->getId(); 14 | -------------------------------------------------------------------------------- /public/lend-book-to-user.php: -------------------------------------------------------------------------------- 1 | id = Uuid::uuid4(); 17 | } 18 | 19 | /** 20 | * @return \Ramsey\Uuid\UuidInterface 21 | */ 22 | public function getId() 23 | { 24 | return $this->id; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/DoctrineIntegration/Library/AmountType.php: -------------------------------------------------------------------------------- 1 | toInt(), $platform); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/DoctrineIntegration/Library/ISBNType.php: -------------------------------------------------------------------------------- 1 | id = Uuid::uuid4(); 17 | } 18 | 19 | /** 20 | * @return \Ramsey\Uuid\UuidInterface 21 | */ 22 | public function getId() 23 | { 24 | return $this->id; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Library/Amount.php: -------------------------------------------------------------------------------- 1 | amount = $amount; 32 | 33 | return $instance; 34 | } 35 | 36 | public function add(Amount $other) 37 | { 38 | $instance = new self(); 39 | 40 | $instance->amount = $this->amount + $other->amount; 41 | 42 | return $instance; 43 | } 44 | 45 | public function toInt() 46 | { 47 | return $this->amount; 48 | } 49 | } -------------------------------------------------------------------------------- /src/Library/Book.php: -------------------------------------------------------------------------------- 1 | libraryId = $libraryId; 15 | $this->isbn = $isbn; 16 | $this->amount = $amount; 17 | } 18 | 19 | public function add(Amount $amount) 20 | { 21 | $this->amount = $this->amount->add($amount); 22 | 23 | return $this; 24 | } 25 | 26 | public function getLibraryId() 27 | { 28 | return $this->libraryId; 29 | } 30 | 31 | public function getIsbn() 32 | { 33 | return $this->isbn; 34 | } 35 | 36 | public function toAmount() 37 | { 38 | return $this->amount; 39 | } 40 | 41 | public function toInt() 42 | { 43 | return $this->amount->toInt(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Library/Command/AddBook.php: -------------------------------------------------------------------------------- 1 | libraryId = $libraryId; 32 | $this->isbn = $isbn; 33 | $this->amount = $amount; 34 | } 35 | 36 | /** 37 | * @return LibraryId 38 | */ 39 | public function getLibraryId() 40 | { 41 | return $this->libraryId; 42 | } 43 | 44 | /** 45 | * @return ISBN 46 | */ 47 | public function getIsbn() 48 | { 49 | return $this->isbn; 50 | } 51 | 52 | /** 53 | * @return Amount 54 | */ 55 | public function getAmount() 56 | { 57 | return $this->amount; 58 | } 59 | } -------------------------------------------------------------------------------- /src/Library/DoctrineLibraryRepository.php: -------------------------------------------------------------------------------- 1 | bookAmountRepository = $bookAmountRepository; 25 | $this->objectManager = $objectManager; 26 | } 27 | 28 | /** 29 | * {@inheritDoc} 30 | */ 31 | public function getAmount(LibraryId $libraryId, $isbn) 32 | { 33 | return $this->getOrCreateAmount($libraryId, $isbn); 34 | } 35 | 36 | public function setAmount(LibraryId $libraryId, BookAmount $amount) 37 | { 38 | $this->objectManager->persist($amount); 39 | $this->objectManager->flush(); 40 | } 41 | 42 | private function getOrCreateAmount(LibraryId $libraryId, $isbn) 43 | { 44 | $bookAmount = $this->bookAmountRepository->findOneBy([ 45 | 'libraryId' => $libraryId, 46 | 'isbn' => $isbn, 47 | ]); 48 | 49 | return $bookAmount instanceof BookAmount 50 | ? $bookAmount 51 | : new BookAmount($libraryId, $isbn, Amount::fromInteger(0)); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Library/ISBN.php: -------------------------------------------------------------------------------- 1 | isbn = $isbn; 22 | } 23 | 24 | public static function fromInt($intIsbn) 25 | { 26 | if (! is_int($intIsbn)) { 27 | throw new \InvalidArgumentException(sprintf( 28 | 'Provided ISBN expected to be int, %s given', 29 | gettype($intIsbn) 30 | )); 31 | } 32 | 33 | if (13 !== strlen((string) $intIsbn)) { 34 | throw new \InvalidArgumentException(sprintf( 35 | 'Provided ISBN is supposed to be composed of 13 integers, %s provided instead', 36 | $intIsbn 37 | )); 38 | } 39 | 40 | return new self($intIsbn); 41 | } 42 | 43 | public static function fromString($stringIsbn) 44 | { 45 | return self::fromInt((int) $stringIsbn); 46 | } 47 | 48 | public function __toString() 49 | { 50 | return (string) $this->isbn; 51 | } 52 | } -------------------------------------------------------------------------------- /src/Library/LentBook.php: -------------------------------------------------------------------------------- 1 | libraryId = $libraryId; 20 | $this->isbn = $isbn; 21 | $this->userId = $userId; 22 | $this->lentDate = $lentDate; 23 | } 24 | 25 | public function return(\DateTimeImmutable $returnDate) 26 | { 27 | // $returnDate > $this->lentDate 28 | // $this->returnDate === null 29 | $this->returnedDate = $returnDate; 30 | } 31 | } -------------------------------------------------------------------------------- /src/Library/Library.php: -------------------------------------------------------------------------------- 1 | libraryId = $libraryId; 31 | $this->repository = $repository; 32 | //$this->exclusionPolicy = $exclusionPolicy; 33 | //$this->lentBooks = $lentBooks; 34 | } 35 | 36 | public function addBook($isbn, $amount) 37 | { 38 | $currentAmount = $this->repository->getAmount($this->libraryId, $isbn); 39 | 40 | $this->repository->setAmount($this->libraryId, $currentAmount->add($amount)); 41 | } 42 | 43 | public function getBookAmount($isbn) 44 | { 45 | return $this->repository->getAmount($this->libraryId, $isbn)->toInt(); 46 | } 47 | 48 | public function lend(ISBN $isbn, UserId $userId, \DateTimeImmutable $lendStartTime) 49 | { 50 | $this->exclusionPolicy->assertUserCanLend($userId, $this->libraryId); 51 | 52 | if (! $amount = $this->getBookAmount($isbn)) { 53 | throw new \OutOfBoundsException(sprintf('Book "%s" is not available', $isbn)); 54 | } 55 | 56 | if (($amount - $this->lentBooks->countByIsbnAndLibrary($isbn, $this->libraryId)) <= 0) { 57 | throw new \OutOfBoundsException(sprintf('Book "%s" is currently not available, all books already lent', $isbn)); 58 | } 59 | 60 | $this->lentBooks->add(new LentBook($this->libraryId, $isbn, $userId, $lendStartTime)); 61 | } 62 | 63 | public function returnLentBook(ISBN $isbn, UserId $userId, \DateTimeImmutable $returnTime) 64 | { 65 | /* @var $lent LentBook */ 66 | $lent = $this->lentBooks->get($this->libraryId, $isbn, $userId); 67 | 68 | $this->lentBooks->add($lent->return($returnTime)); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/Library/LibraryId.php: -------------------------------------------------------------------------------- 1 | id = Uuid::uuid4(); 24 | 25 | return $instance; 26 | } 27 | 28 | public static function fromString($stringId) 29 | { 30 | $instance = new self(); 31 | 32 | $instance->id = Uuid::fromString($stringId); 33 | 34 | return $instance; 35 | } 36 | 37 | public function __toString() 38 | { 39 | return (string) $this->id; 40 | } 41 | } -------------------------------------------------------------------------------- /src/Library/LibraryRepository.php: -------------------------------------------------------------------------------- 1 | id = Uuid::fromString($stringId); 24 | 25 | return $instance; 26 | } 27 | 28 | public function __toString() 29 | { 30 | return (string) $this->id; 31 | } 32 | } -------------------------------------------------------------------------------- /test/DoctrineIntegration/BookAmountPersistenceTest.php: -------------------------------------------------------------------------------- 1 | setMetadataDriverImpl(new XmlDriver([__DIR__ . '/../../mapping'])); 39 | 40 | $configuration->setProxyDir(__DIR__ . '/../../data/proxies'); 41 | $configuration->setProxyNamespace('DoctrineProxies'); 42 | 43 | $configuration->setAutoGenerateProxyClasses(ProxyFactory::AUTOGENERATE_ALWAYS); 44 | 45 | Type::addType(UuidType::class, UuidType::class); 46 | Type::addType(AmountType::class, AmountType::class); 47 | Type::addType(ISBNType::class, ISBNType::class); 48 | Type::addType(LibraryIdType::class, LibraryIdType::class); 49 | 50 | $this->em = EntityManager::create( 51 | [ 52 | 'driverClass' => Driver::class, 53 | 'memory' => true, 54 | ], 55 | $configuration 56 | ); 57 | 58 | (new SchemaTool($this->em))->createSchema($this->em->getMetadataFactory()->getAllMetadata()); 59 | } 60 | 61 | public function testCanPersistABookAmount() 62 | { 63 | $libraryId = LibraryId::newLibraryId(); 64 | $isbn = ISBN::fromInt(1111111111111); 65 | 66 | $this->em->persist(new BookAmount($libraryId, $isbn, Amount::fromInteger(3))); 67 | $this->em->flush(); 68 | 69 | $this->em->clear(); 70 | 71 | /* @var $bookAmount BookAmount */ 72 | $bookAmount = $this->em->find(BookAmount::class, ['libraryId' => $libraryId, 'isbn' => $isbn]); 73 | 74 | self::assertInstanceOf(BookAmount::class, $bookAmount); 75 | self::assertInstanceOf(LibraryId::class, $bookAmount->getLibraryId()); 76 | self::assertEquals($libraryId, $bookAmount->getLibraryId()); 77 | self::assertInstanceOf(ISBN::class, $bookAmount->getIsbn()); 78 | self::assertEquals($isbn, $bookAmount->getIsbn()); 79 | } 80 | } -------------------------------------------------------------------------------- /test/Library/AmountTest.php: -------------------------------------------------------------------------------- 1 | toInt()); 18 | } 19 | 20 | public function testRejectsNonIntAmounts() 21 | { 22 | $this->setExpectedException(\InvalidArgumentException::class); 23 | 24 | Amount::fromInteger('foo'); 25 | } 26 | 27 | public function testRejectsZeroAmount() 28 | { 29 | $this->setExpectedException(\InvalidArgumentException::class); 30 | 31 | Amount::fromInteger(0); 32 | } 33 | 34 | public function testRejectsNegativeAmount() 35 | { 36 | $this->setExpectedException(\InvalidArgumentException::class); 37 | 38 | Amount::fromInteger(-1); 39 | } 40 | 41 | public function testAdd() 42 | { 43 | $intAmount1 = mt_rand(100, 200); 44 | $intAmount2 = mt_rand(100, 200); 45 | $amount1 = Amount::fromInteger($intAmount1); 46 | $amount2 = Amount::fromInteger($intAmount2); 47 | 48 | $sum = $amount1->add($amount2); 49 | 50 | self::assertNotEquals($sum, $intAmount1); 51 | self::assertNotEquals($sum, $intAmount2); 52 | self::assertInstanceOf(Amount::class, $sum); 53 | self::assertSame($intAmount1 + $intAmount2, $sum->toInt()); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /test/Library/DoctrineLibraryRepositoryTest.php: -------------------------------------------------------------------------------- 1 | doctrineRepository = $this->getMock(ObjectRepository::class); 40 | $this->objectManager = $this->getMock(ObjectManager::class); 41 | $this->repository = new DoctrineLibraryRepository($this->doctrineRepository, $this->objectManager); 42 | } 43 | 44 | public function testGetAmountWithNonExistingAmount() 45 | { 46 | $libraryId = (string) Uuid::uuid4(); 47 | $isbn = mt_rand(1234567890000, 1234567890123); 48 | 49 | // @TODO what do we do here? 50 | self::assertEquals(new BookAmount(LibraryId::fromString($libraryId), $isbn, Amount::fromInteger(0)), $this->repository->getAmount(LibraryId::fromString($libraryId), $isbn)); 51 | } 52 | 53 | public function testGetAmountWithNonMatchingAmountTypeReturned() 54 | { 55 | $libraryId = (string) Uuid::uuid4(); 56 | $isbn = mt_rand(1234567890000, 1234567890123); 57 | 58 | $this->doctrineRepository->expects(self::any())->method('findOneBy')->willReturn(new \stdClass()); 59 | 60 | // @TODO what do we do here? 61 | self::assertEquals(new BookAmount(LibraryId::fromString($libraryId), $isbn, Amount::fromInteger(0)), $this->repository->getAmount(LibraryId::fromString($libraryId), $isbn)); 62 | } 63 | 64 | public function testGetAmountWithFoundAmountOnThePersistenceLayer() 65 | { 66 | $libraryId = (string) Uuid::uuid4(); 67 | $isbn = mt_rand(1234567890000, 1234567890123); 68 | 69 | $bookAmount = new BookAmount(LibraryId::fromString($libraryId), $isbn, Amount::fromInteger(mt_rand(100, 200))); 70 | 71 | $this->doctrineRepository->expects(self::any())->method('findOneBy')->willReturn($bookAmount); 72 | 73 | self::assertEquals($bookAmount, $this->repository->getAmount(LibraryId::fromString($libraryId), $isbn)); 74 | } 75 | 76 | public function testSetAmount() 77 | { 78 | $bookAmount = new BookAmount(LibraryId::newLibraryId(), 1234567890123, Amount::fromInteger(mt_rand(100, 200))); 79 | 80 | $this->objectManager->expects(self::once())->method('persist')->with($bookAmount); 81 | $this->objectManager->expects(self::once())->method('flush'); 82 | 83 | $this->repository->setAmount(LibraryId::newLibraryId(), $bookAmount); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /test/Library/ISBNTest.php: -------------------------------------------------------------------------------- 1 | setExpectedException(\InvalidArgumentException::class); 28 | 29 | ISBN::fromInt($invalidIsbn); 30 | } 31 | 32 | /** 33 | * @dataProvider invalidIntIsbnProvider 34 | * 35 | * @param mixed $invalidIsbn 36 | */ 37 | public function testWithInvalidString($invalidIsbn) 38 | { 39 | $this->setExpectedException(\InvalidArgumentException::class); 40 | 41 | ISBN::fromString((string) $invalidIsbn); 42 | } 43 | 44 | public function invalidIntIsbnProvider() 45 | { 46 | return [ 47 | [999999999999], 48 | [10000000000000], 49 | ['aaaaaaaaaaaaa'], 50 | ]; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /test/Library/LibraryIdTest.php: -------------------------------------------------------------------------------- 1 | getMock(LibraryRepository::class); 19 | 20 | $library = new Library(LibraryId::fromString($libraryId), $libraryRepository); 21 | 22 | $isbn = mt_rand(1234567890000, 1234567890123); 23 | $previousAmount = mt_rand(100, 200); 24 | $amount = mt_rand(100, 200); 25 | 26 | $libraryRepository 27 | ->expects(self::any()) 28 | ->method('getAmount') 29 | ->with($libraryId, $isbn) 30 | ->willReturn(new BookAmount(LibraryId::fromString($libraryId), $isbn, Amount::fromInteger($previousAmount))); 31 | $libraryRepository->expects(self::once())->method('setAmount')->with( 32 | $libraryId, 33 | self::callback(function (BookAmount $setAmount) use ($previousAmount, $amount, $isbn) { 34 | self::assertSame($previousAmount + $amount, $setAmount->toInt()); 35 | self::assertEquals($isbn, $setAmount->getIsbn()); 36 | 37 | return true; 38 | }) 39 | ); 40 | 41 | $library->addBook($isbn, Amount::fromInteger($amount)); 42 | } 43 | 44 | public function testWillGetBooksFromTheLibrary() 45 | { 46 | $libraryId = (string) Uuid::uuid4(); 47 | /* @var $libraryRepository LibraryRepository|\PHPUnit_Framework_MockObject_MockObject */ 48 | $libraryRepository = $this->getMock(LibraryRepository::class); 49 | 50 | $library = new Library(LibraryId::fromString($libraryId), $libraryRepository); 51 | 52 | $isbn = mt_rand(1234567890000, 1234567890123); 53 | $amount = mt_rand(100, 200); 54 | 55 | $bookAmount = new BookAmount(LibraryId::fromString($libraryId), $isbn, Amount::fromInteger($amount)); 56 | 57 | $libraryRepository->expects(self::any())->method('getAmount')->with($libraryId, $isbn)->willReturn($bookAmount); 58 | 59 | self::assertSame($amount, $library->getBookAmount($isbn, $amount)); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /test/Library/UserIdTest.php: -------------------------------------------------------------------------------- 1 |