├── .gitignore ├── .php_cs ├── .styleci.yml ├── LICENSE ├── composer.json ├── composer.lock ├── docs ├── database-test-method.png └── model-test-method.png ├── readme.md └── src ├── Database ├── Column.php └── Table.php ├── DatabaseTestHelper.php ├── EloquentTestCase.php ├── ModelTestHelper.php └── RelationshipTestHelper.php /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | .phpintel 3 | .php_cs.cache -------------------------------------------------------------------------------- /.php_cs: -------------------------------------------------------------------------------- 1 | finder(DefaultFinder::create()->in(__DIR__)) 75 | ->fixers($fixers) 76 | ->level(FixerInterface::NONE_LEVEL) 77 | ->setUsingCache(true); 78 | -------------------------------------------------------------------------------- /.styleci.yml: -------------------------------------------------------------------------------- 1 | preset: laravel 2 | risky: true 3 | enabled: 4 | - align_double_arrow 5 | - blankline_after_open_tag 6 | - braces 7 | - concat_without_spaces 8 | - double_arrow_multiline_whitespaces 9 | - duplicate_semicolon 10 | - elseif 11 | - empty_return 12 | - encoding 13 | - eof_ending 14 | - extra_empty_lines 15 | - function_call_space 16 | - function_declaration 17 | - include 18 | - indentation 19 | - join_function 20 | - line_after_namespace 21 | - linefeed 22 | - list_commas 23 | - lowercase_constants 24 | - lowercase_keywords 25 | - method_argument_space 26 | - multiline_array_trailing_comma 27 | - multiline_spaces_before_semicolon 28 | - multiple_use 29 | - namespace_no_leading_whitespace 30 | - no_blank_lines_after_class_opening 31 | - no_empty_lines_after_phpdocs 32 | - object_operator 33 | - operators_spaces 34 | - parenthesis 35 | - phpdoc_inline_tag 36 | - phpdoc_no_access 37 | - phpdoc_no_package 38 | - phpdoc_scalar 39 | - phpdoc_short_description 40 | - phpdoc_to_comment 41 | - phpdoc_trim 42 | - phpdoc_type_to_var 43 | - phpdoc_var_without_name 44 | - remove_leading_slash_use 45 | - remove_lines_between_uses 46 | - return 47 | - self_accessor 48 | - short_array_syntax 49 | - short_echo_tag 50 | - short_tag 51 | - single_array_no_trailing_comma 52 | - single_blank_line_before_namespace 53 | - single_line_after_imports 54 | - single_quote 55 | - spaces_before_semicolon 56 | - spaces_cast 57 | - standardize_not_equal 58 | - ternary_spaces 59 | - trailing_spaces 60 | - trim_array_spaces 61 | - unalign_equals 62 | - unary_operators_spaces 63 | - unused_use 64 | - visibility 65 | - whitespacy_lines 66 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Erik Galloway 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, 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, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "erikgall/eloquent-phpunit", 3 | "description": "Test Eloquent models, database schemas & tables, relationships/foreign keys using PHPUnit.", 4 | "keywords": ["laravel", "eloquent", "model", "phpunit", "database-testing", "eloquent-test"], 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Erik Galloway", 9 | "email": "erik@fliplearning.com" 10 | } 11 | ], 12 | "require": { 13 | "laravel/framework": "^5.2|^5.3", 14 | "doctrine/dbal": "^2.5" 15 | }, 16 | "autoload": { 17 | "psr-4": { 18 | "EGALL\\EloquentPHPUnit\\": "src/" 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /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": "e328931c2530a1f465d37106b64b00ea", 8 | "content-hash": "3a0596e146cca4c0c07b58bf68589e80", 9 | "packages": [ 10 | { 11 | "name": "classpreloader/classpreloader", 12 | "version": "3.0.0", 13 | "source": { 14 | "type": "git", 15 | "url": "https://github.com/ClassPreloader/ClassPreloader.git", 16 | "reference": "9b10b913c2bdf90c3d2e0d726b454fb7f77c552a" 17 | }, 18 | "dist": { 19 | "type": "zip", 20 | "url": "https://api.github.com/repos/ClassPreloader/ClassPreloader/zipball/9b10b913c2bdf90c3d2e0d726b454fb7f77c552a", 21 | "reference": "9b10b913c2bdf90c3d2e0d726b454fb7f77c552a", 22 | "shasum": "" 23 | }, 24 | "require": { 25 | "nikic/php-parser": "^1.0|^2.0", 26 | "php": ">=5.5.9" 27 | }, 28 | "require-dev": { 29 | "phpunit/phpunit": "^4.8|^5.0" 30 | }, 31 | "type": "library", 32 | "extra": { 33 | "branch-alias": { 34 | "dev-master": "3.0-dev" 35 | } 36 | }, 37 | "autoload": { 38 | "psr-4": { 39 | "ClassPreloader\\": "src/" 40 | } 41 | }, 42 | "notification-url": "https://packagist.org/downloads/", 43 | "license": [ 44 | "MIT" 45 | ], 46 | "authors": [ 47 | { 48 | "name": "Michael Dowling", 49 | "email": "mtdowling@gmail.com" 50 | }, 51 | { 52 | "name": "Graham Campbell", 53 | "email": "graham@alt-three.com" 54 | } 55 | ], 56 | "description": "Helps class loading performance by generating a single PHP file containing all of the autoloaded files for a specific use case", 57 | "keywords": [ 58 | "autoload", 59 | "class", 60 | "preload" 61 | ], 62 | "time": "2015-11-09 22:51:51" 63 | }, 64 | { 65 | "name": "dnoegel/php-xdg-base-dir", 66 | "version": "0.1", 67 | "source": { 68 | "type": "git", 69 | "url": "https://github.com/dnoegel/php-xdg-base-dir.git", 70 | "reference": "265b8593498b997dc2d31e75b89f053b5cc9621a" 71 | }, 72 | "dist": { 73 | "type": "zip", 74 | "url": "https://api.github.com/repos/dnoegel/php-xdg-base-dir/zipball/265b8593498b997dc2d31e75b89f053b5cc9621a", 75 | "reference": "265b8593498b997dc2d31e75b89f053b5cc9621a", 76 | "shasum": "" 77 | }, 78 | "require": { 79 | "php": ">=5.3.2" 80 | }, 81 | "require-dev": { 82 | "phpunit/phpunit": "@stable" 83 | }, 84 | "type": "project", 85 | "autoload": { 86 | "psr-4": { 87 | "XdgBaseDir\\": "src/" 88 | } 89 | }, 90 | "notification-url": "https://packagist.org/downloads/", 91 | "license": [ 92 | "MIT" 93 | ], 94 | "description": "implementation of xdg base directory specification for php", 95 | "time": "2014-10-24 07:27:01" 96 | }, 97 | { 98 | "name": "doctrine/annotations", 99 | "version": "v1.2.7", 100 | "source": { 101 | "type": "git", 102 | "url": "https://github.com/doctrine/annotations.git", 103 | "reference": "f25c8aab83e0c3e976fd7d19875f198ccf2f7535" 104 | }, 105 | "dist": { 106 | "type": "zip", 107 | "url": "https://api.github.com/repos/doctrine/annotations/zipball/f25c8aab83e0c3e976fd7d19875f198ccf2f7535", 108 | "reference": "f25c8aab83e0c3e976fd7d19875f198ccf2f7535", 109 | "shasum": "" 110 | }, 111 | "require": { 112 | "doctrine/lexer": "1.*", 113 | "php": ">=5.3.2" 114 | }, 115 | "require-dev": { 116 | "doctrine/cache": "1.*", 117 | "phpunit/phpunit": "4.*" 118 | }, 119 | "type": "library", 120 | "extra": { 121 | "branch-alias": { 122 | "dev-master": "1.3.x-dev" 123 | } 124 | }, 125 | "autoload": { 126 | "psr-0": { 127 | "Doctrine\\Common\\Annotations\\": "lib/" 128 | } 129 | }, 130 | "notification-url": "https://packagist.org/downloads/", 131 | "license": [ 132 | "MIT" 133 | ], 134 | "authors": [ 135 | { 136 | "name": "Roman Borschel", 137 | "email": "roman@code-factory.org" 138 | }, 139 | { 140 | "name": "Benjamin Eberlei", 141 | "email": "kontakt@beberlei.de" 142 | }, 143 | { 144 | "name": "Guilherme Blanco", 145 | "email": "guilhermeblanco@gmail.com" 146 | }, 147 | { 148 | "name": "Jonathan Wage", 149 | "email": "jonwage@gmail.com" 150 | }, 151 | { 152 | "name": "Johannes Schmitt", 153 | "email": "schmittjoh@gmail.com" 154 | } 155 | ], 156 | "description": "Docblock Annotations Parser", 157 | "homepage": "http://www.doctrine-project.org", 158 | "keywords": [ 159 | "annotations", 160 | "docblock", 161 | "parser" 162 | ], 163 | "time": "2015-08-31 12:32:49" 164 | }, 165 | { 166 | "name": "doctrine/cache", 167 | "version": "v1.6.0", 168 | "source": { 169 | "type": "git", 170 | "url": "https://github.com/doctrine/cache.git", 171 | "reference": "f8af318d14bdb0eff0336795b428b547bd39ccb6" 172 | }, 173 | "dist": { 174 | "type": "zip", 175 | "url": "https://api.github.com/repos/doctrine/cache/zipball/f8af318d14bdb0eff0336795b428b547bd39ccb6", 176 | "reference": "f8af318d14bdb0eff0336795b428b547bd39ccb6", 177 | "shasum": "" 178 | }, 179 | "require": { 180 | "php": "~5.5|~7.0" 181 | }, 182 | "conflict": { 183 | "doctrine/common": ">2.2,<2.4" 184 | }, 185 | "require-dev": { 186 | "phpunit/phpunit": "~4.8|~5.0", 187 | "predis/predis": "~1.0", 188 | "satooshi/php-coveralls": "~0.6" 189 | }, 190 | "type": "library", 191 | "extra": { 192 | "branch-alias": { 193 | "dev-master": "1.6.x-dev" 194 | } 195 | }, 196 | "autoload": { 197 | "psr-4": { 198 | "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache" 199 | } 200 | }, 201 | "notification-url": "https://packagist.org/downloads/", 202 | "license": [ 203 | "MIT" 204 | ], 205 | "authors": [ 206 | { 207 | "name": "Roman Borschel", 208 | "email": "roman@code-factory.org" 209 | }, 210 | { 211 | "name": "Benjamin Eberlei", 212 | "email": "kontakt@beberlei.de" 213 | }, 214 | { 215 | "name": "Guilherme Blanco", 216 | "email": "guilhermeblanco@gmail.com" 217 | }, 218 | { 219 | "name": "Jonathan Wage", 220 | "email": "jonwage@gmail.com" 221 | }, 222 | { 223 | "name": "Johannes Schmitt", 224 | "email": "schmittjoh@gmail.com" 225 | } 226 | ], 227 | "description": "Caching library offering an object-oriented API for many cache backends", 228 | "homepage": "http://www.doctrine-project.org", 229 | "keywords": [ 230 | "cache", 231 | "caching" 232 | ], 233 | "time": "2015-12-31 16:37:02" 234 | }, 235 | { 236 | "name": "doctrine/collections", 237 | "version": "v1.3.0", 238 | "source": { 239 | "type": "git", 240 | "url": "https://github.com/doctrine/collections.git", 241 | "reference": "6c1e4eef75f310ea1b3e30945e9f06e652128b8a" 242 | }, 243 | "dist": { 244 | "type": "zip", 245 | "url": "https://api.github.com/repos/doctrine/collections/zipball/6c1e4eef75f310ea1b3e30945e9f06e652128b8a", 246 | "reference": "6c1e4eef75f310ea1b3e30945e9f06e652128b8a", 247 | "shasum": "" 248 | }, 249 | "require": { 250 | "php": ">=5.3.2" 251 | }, 252 | "require-dev": { 253 | "phpunit/phpunit": "~4.0" 254 | }, 255 | "type": "library", 256 | "extra": { 257 | "branch-alias": { 258 | "dev-master": "1.2.x-dev" 259 | } 260 | }, 261 | "autoload": { 262 | "psr-0": { 263 | "Doctrine\\Common\\Collections\\": "lib/" 264 | } 265 | }, 266 | "notification-url": "https://packagist.org/downloads/", 267 | "license": [ 268 | "MIT" 269 | ], 270 | "authors": [ 271 | { 272 | "name": "Roman Borschel", 273 | "email": "roman@code-factory.org" 274 | }, 275 | { 276 | "name": "Benjamin Eberlei", 277 | "email": "kontakt@beberlei.de" 278 | }, 279 | { 280 | "name": "Guilherme Blanco", 281 | "email": "guilhermeblanco@gmail.com" 282 | }, 283 | { 284 | "name": "Jonathan Wage", 285 | "email": "jonwage@gmail.com" 286 | }, 287 | { 288 | "name": "Johannes Schmitt", 289 | "email": "schmittjoh@gmail.com" 290 | } 291 | ], 292 | "description": "Collections Abstraction library", 293 | "homepage": "http://www.doctrine-project.org", 294 | "keywords": [ 295 | "array", 296 | "collections", 297 | "iterator" 298 | ], 299 | "time": "2015-04-14 22:21:58" 300 | }, 301 | { 302 | "name": "doctrine/common", 303 | "version": "v2.6.1", 304 | "source": { 305 | "type": "git", 306 | "url": "https://github.com/doctrine/common.git", 307 | "reference": "a579557bc689580c19fee4e27487a67fe60defc0" 308 | }, 309 | "dist": { 310 | "type": "zip", 311 | "url": "https://api.github.com/repos/doctrine/common/zipball/a579557bc689580c19fee4e27487a67fe60defc0", 312 | "reference": "a579557bc689580c19fee4e27487a67fe60defc0", 313 | "shasum": "" 314 | }, 315 | "require": { 316 | "doctrine/annotations": "1.*", 317 | "doctrine/cache": "1.*", 318 | "doctrine/collections": "1.*", 319 | "doctrine/inflector": "1.*", 320 | "doctrine/lexer": "1.*", 321 | "php": "~5.5|~7.0" 322 | }, 323 | "require-dev": { 324 | "phpunit/phpunit": "~4.8|~5.0" 325 | }, 326 | "type": "library", 327 | "extra": { 328 | "branch-alias": { 329 | "dev-master": "2.7.x-dev" 330 | } 331 | }, 332 | "autoload": { 333 | "psr-4": { 334 | "Doctrine\\Common\\": "lib/Doctrine/Common" 335 | } 336 | }, 337 | "notification-url": "https://packagist.org/downloads/", 338 | "license": [ 339 | "MIT" 340 | ], 341 | "authors": [ 342 | { 343 | "name": "Roman Borschel", 344 | "email": "roman@code-factory.org" 345 | }, 346 | { 347 | "name": "Benjamin Eberlei", 348 | "email": "kontakt@beberlei.de" 349 | }, 350 | { 351 | "name": "Guilherme Blanco", 352 | "email": "guilhermeblanco@gmail.com" 353 | }, 354 | { 355 | "name": "Jonathan Wage", 356 | "email": "jonwage@gmail.com" 357 | }, 358 | { 359 | "name": "Johannes Schmitt", 360 | "email": "schmittjoh@gmail.com" 361 | } 362 | ], 363 | "description": "Common Library for Doctrine projects", 364 | "homepage": "http://www.doctrine-project.org", 365 | "keywords": [ 366 | "annotations", 367 | "collections", 368 | "eventmanager", 369 | "persistence", 370 | "spl" 371 | ], 372 | "time": "2015-12-25 13:18:31" 373 | }, 374 | { 375 | "name": "doctrine/dbal", 376 | "version": "v2.5.5", 377 | "source": { 378 | "type": "git", 379 | "url": "https://github.com/doctrine/dbal.git", 380 | "reference": "9f8c05cd5225a320d56d4bfdb4772f10d045a0c9" 381 | }, 382 | "dist": { 383 | "type": "zip", 384 | "url": "https://api.github.com/repos/doctrine/dbal/zipball/9f8c05cd5225a320d56d4bfdb4772f10d045a0c9", 385 | "reference": "9f8c05cd5225a320d56d4bfdb4772f10d045a0c9", 386 | "shasum": "" 387 | }, 388 | "require": { 389 | "doctrine/common": ">=2.4,<2.7-dev", 390 | "php": ">=5.3.2" 391 | }, 392 | "require-dev": { 393 | "phpunit/phpunit": "4.*", 394 | "symfony/console": "2.*||^3.0" 395 | }, 396 | "suggest": { 397 | "symfony/console": "For helpful console commands such as SQL execution and import of files." 398 | }, 399 | "bin": [ 400 | "bin/doctrine-dbal" 401 | ], 402 | "type": "library", 403 | "extra": { 404 | "branch-alias": { 405 | "dev-master": "2.5.x-dev" 406 | } 407 | }, 408 | "autoload": { 409 | "psr-0": { 410 | "Doctrine\\DBAL\\": "lib/" 411 | } 412 | }, 413 | "notification-url": "https://packagist.org/downloads/", 414 | "license": [ 415 | "MIT" 416 | ], 417 | "authors": [ 418 | { 419 | "name": "Roman Borschel", 420 | "email": "roman@code-factory.org" 421 | }, 422 | { 423 | "name": "Benjamin Eberlei", 424 | "email": "kontakt@beberlei.de" 425 | }, 426 | { 427 | "name": "Guilherme Blanco", 428 | "email": "guilhermeblanco@gmail.com" 429 | }, 430 | { 431 | "name": "Jonathan Wage", 432 | "email": "jonwage@gmail.com" 433 | } 434 | ], 435 | "description": "Database Abstraction Layer", 436 | "homepage": "http://www.doctrine-project.org", 437 | "keywords": [ 438 | "database", 439 | "dbal", 440 | "persistence", 441 | "queryobject" 442 | ], 443 | "time": "2016-09-09 19:13:33" 444 | }, 445 | { 446 | "name": "doctrine/inflector", 447 | "version": "v1.1.0", 448 | "source": { 449 | "type": "git", 450 | "url": "https://github.com/doctrine/inflector.git", 451 | "reference": "90b2128806bfde671b6952ab8bea493942c1fdae" 452 | }, 453 | "dist": { 454 | "type": "zip", 455 | "url": "https://api.github.com/repos/doctrine/inflector/zipball/90b2128806bfde671b6952ab8bea493942c1fdae", 456 | "reference": "90b2128806bfde671b6952ab8bea493942c1fdae", 457 | "shasum": "" 458 | }, 459 | "require": { 460 | "php": ">=5.3.2" 461 | }, 462 | "require-dev": { 463 | "phpunit/phpunit": "4.*" 464 | }, 465 | "type": "library", 466 | "extra": { 467 | "branch-alias": { 468 | "dev-master": "1.1.x-dev" 469 | } 470 | }, 471 | "autoload": { 472 | "psr-0": { 473 | "Doctrine\\Common\\Inflector\\": "lib/" 474 | } 475 | }, 476 | "notification-url": "https://packagist.org/downloads/", 477 | "license": [ 478 | "MIT" 479 | ], 480 | "authors": [ 481 | { 482 | "name": "Roman Borschel", 483 | "email": "roman@code-factory.org" 484 | }, 485 | { 486 | "name": "Benjamin Eberlei", 487 | "email": "kontakt@beberlei.de" 488 | }, 489 | { 490 | "name": "Guilherme Blanco", 491 | "email": "guilhermeblanco@gmail.com" 492 | }, 493 | { 494 | "name": "Jonathan Wage", 495 | "email": "jonwage@gmail.com" 496 | }, 497 | { 498 | "name": "Johannes Schmitt", 499 | "email": "schmittjoh@gmail.com" 500 | } 501 | ], 502 | "description": "Common String Manipulations with regard to casing and singular/plural rules.", 503 | "homepage": "http://www.doctrine-project.org", 504 | "keywords": [ 505 | "inflection", 506 | "pluralize", 507 | "singularize", 508 | "string" 509 | ], 510 | "time": "2015-11-06 14:35:42" 511 | }, 512 | { 513 | "name": "doctrine/lexer", 514 | "version": "v1.0.1", 515 | "source": { 516 | "type": "git", 517 | "url": "https://github.com/doctrine/lexer.git", 518 | "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c" 519 | }, 520 | "dist": { 521 | "type": "zip", 522 | "url": "https://api.github.com/repos/doctrine/lexer/zipball/83893c552fd2045dd78aef794c31e694c37c0b8c", 523 | "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c", 524 | "shasum": "" 525 | }, 526 | "require": { 527 | "php": ">=5.3.2" 528 | }, 529 | "type": "library", 530 | "extra": { 531 | "branch-alias": { 532 | "dev-master": "1.0.x-dev" 533 | } 534 | }, 535 | "autoload": { 536 | "psr-0": { 537 | "Doctrine\\Common\\Lexer\\": "lib/" 538 | } 539 | }, 540 | "notification-url": "https://packagist.org/downloads/", 541 | "license": [ 542 | "MIT" 543 | ], 544 | "authors": [ 545 | { 546 | "name": "Roman Borschel", 547 | "email": "roman@code-factory.org" 548 | }, 549 | { 550 | "name": "Guilherme Blanco", 551 | "email": "guilhermeblanco@gmail.com" 552 | }, 553 | { 554 | "name": "Johannes Schmitt", 555 | "email": "schmittjoh@gmail.com" 556 | } 557 | ], 558 | "description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.", 559 | "homepage": "http://www.doctrine-project.org", 560 | "keywords": [ 561 | "lexer", 562 | "parser" 563 | ], 564 | "time": "2014-09-09 13:34:57" 565 | }, 566 | { 567 | "name": "jakub-onderka/php-console-color", 568 | "version": "0.1", 569 | "source": { 570 | "type": "git", 571 | "url": "https://github.com/JakubOnderka/PHP-Console-Color.git", 572 | "reference": "e0b393dacf7703fc36a4efc3df1435485197e6c1" 573 | }, 574 | "dist": { 575 | "type": "zip", 576 | "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Color/zipball/e0b393dacf7703fc36a4efc3df1435485197e6c1", 577 | "reference": "e0b393dacf7703fc36a4efc3df1435485197e6c1", 578 | "shasum": "" 579 | }, 580 | "require": { 581 | "php": ">=5.3.2" 582 | }, 583 | "require-dev": { 584 | "jakub-onderka/php-code-style": "1.0", 585 | "jakub-onderka/php-parallel-lint": "0.*", 586 | "jakub-onderka/php-var-dump-check": "0.*", 587 | "phpunit/phpunit": "3.7.*", 588 | "squizlabs/php_codesniffer": "1.*" 589 | }, 590 | "type": "library", 591 | "autoload": { 592 | "psr-0": { 593 | "JakubOnderka\\PhpConsoleColor": "src/" 594 | } 595 | }, 596 | "notification-url": "https://packagist.org/downloads/", 597 | "license": [ 598 | "BSD-2-Clause" 599 | ], 600 | "authors": [ 601 | { 602 | "name": "Jakub Onderka", 603 | "email": "jakub.onderka@gmail.com", 604 | "homepage": "http://www.acci.cz" 605 | } 606 | ], 607 | "time": "2014-04-08 15:00:19" 608 | }, 609 | { 610 | "name": "jakub-onderka/php-console-highlighter", 611 | "version": "v0.3.2", 612 | "source": { 613 | "type": "git", 614 | "url": "https://github.com/JakubOnderka/PHP-Console-Highlighter.git", 615 | "reference": "7daa75df45242c8d5b75a22c00a201e7954e4fb5" 616 | }, 617 | "dist": { 618 | "type": "zip", 619 | "url": "https://api.github.com/repos/JakubOnderka/PHP-Console-Highlighter/zipball/7daa75df45242c8d5b75a22c00a201e7954e4fb5", 620 | "reference": "7daa75df45242c8d5b75a22c00a201e7954e4fb5", 621 | "shasum": "" 622 | }, 623 | "require": { 624 | "jakub-onderka/php-console-color": "~0.1", 625 | "php": ">=5.3.0" 626 | }, 627 | "require-dev": { 628 | "jakub-onderka/php-code-style": "~1.0", 629 | "jakub-onderka/php-parallel-lint": "~0.5", 630 | "jakub-onderka/php-var-dump-check": "~0.1", 631 | "phpunit/phpunit": "~4.0", 632 | "squizlabs/php_codesniffer": "~1.5" 633 | }, 634 | "type": "library", 635 | "autoload": { 636 | "psr-0": { 637 | "JakubOnderka\\PhpConsoleHighlighter": "src/" 638 | } 639 | }, 640 | "notification-url": "https://packagist.org/downloads/", 641 | "license": [ 642 | "MIT" 643 | ], 644 | "authors": [ 645 | { 646 | "name": "Jakub Onderka", 647 | "email": "acci@acci.cz", 648 | "homepage": "http://www.acci.cz/" 649 | } 650 | ], 651 | "time": "2015-04-20 18:58:01" 652 | }, 653 | { 654 | "name": "jeremeamia/SuperClosure", 655 | "version": "2.2.0", 656 | "source": { 657 | "type": "git", 658 | "url": "https://github.com/jeremeamia/super_closure.git", 659 | "reference": "29a88be2a4846d27c1613aed0c9071dfad7b5938" 660 | }, 661 | "dist": { 662 | "type": "zip", 663 | "url": "https://api.github.com/repos/jeremeamia/super_closure/zipball/29a88be2a4846d27c1613aed0c9071dfad7b5938", 664 | "reference": "29a88be2a4846d27c1613aed0c9071dfad7b5938", 665 | "shasum": "" 666 | }, 667 | "require": { 668 | "nikic/php-parser": "^1.2|^2.0", 669 | "php": ">=5.4", 670 | "symfony/polyfill-php56": "^1.0" 671 | }, 672 | "require-dev": { 673 | "phpunit/phpunit": "^4.0|^5.0" 674 | }, 675 | "type": "library", 676 | "extra": { 677 | "branch-alias": { 678 | "dev-master": "2.2-dev" 679 | } 680 | }, 681 | "autoload": { 682 | "psr-4": { 683 | "SuperClosure\\": "src/" 684 | } 685 | }, 686 | "notification-url": "https://packagist.org/downloads/", 687 | "license": [ 688 | "MIT" 689 | ], 690 | "authors": [ 691 | { 692 | "name": "Jeremy Lindblom", 693 | "email": "jeremeamia@gmail.com", 694 | "homepage": "https://github.com/jeremeamia", 695 | "role": "Developer" 696 | } 697 | ], 698 | "description": "Serialize Closure objects, including their context and binding", 699 | "homepage": "https://github.com/jeremeamia/super_closure", 700 | "keywords": [ 701 | "closure", 702 | "function", 703 | "lambda", 704 | "parser", 705 | "serializable", 706 | "serialize", 707 | "tokenizer" 708 | ], 709 | "time": "2015-12-05 17:17:57" 710 | }, 711 | { 712 | "name": "laravel/framework", 713 | "version": "v5.3.10", 714 | "source": { 715 | "type": "git", 716 | "url": "https://github.com/laravel/framework.git", 717 | "reference": "6febb0ee61999cde3bc7b2963c8903032bb22691" 718 | }, 719 | "dist": { 720 | "type": "zip", 721 | "url": "https://api.github.com/repos/laravel/framework/zipball/6febb0ee61999cde3bc7b2963c8903032bb22691", 722 | "reference": "6febb0ee61999cde3bc7b2963c8903032bb22691", 723 | "shasum": "" 724 | }, 725 | "require": { 726 | "classpreloader/classpreloader": "~3.0", 727 | "doctrine/inflector": "~1.0", 728 | "ext-mbstring": "*", 729 | "ext-openssl": "*", 730 | "jeremeamia/superclosure": "~2.2", 731 | "league/flysystem": "~1.0", 732 | "monolog/monolog": "~1.11", 733 | "mtdowling/cron-expression": "~1.0", 734 | "nesbot/carbon": "~1.20", 735 | "paragonie/random_compat": "~1.4|~2.0", 736 | "php": ">=5.6.4", 737 | "psy/psysh": "0.7.*", 738 | "ramsey/uuid": "~3.0", 739 | "swiftmailer/swiftmailer": "~5.1", 740 | "symfony/console": "3.1.*", 741 | "symfony/debug": "3.1.*", 742 | "symfony/finder": "3.1.*", 743 | "symfony/http-foundation": "3.1.*", 744 | "symfony/http-kernel": "3.1.*", 745 | "symfony/process": "3.1.*", 746 | "symfony/routing": "3.1.*", 747 | "symfony/translation": "3.1.*", 748 | "symfony/var-dumper": "3.1.*", 749 | "vlucas/phpdotenv": "~2.2" 750 | }, 751 | "replace": { 752 | "illuminate/auth": "self.version", 753 | "illuminate/broadcasting": "self.version", 754 | "illuminate/bus": "self.version", 755 | "illuminate/cache": "self.version", 756 | "illuminate/config": "self.version", 757 | "illuminate/console": "self.version", 758 | "illuminate/container": "self.version", 759 | "illuminate/contracts": "self.version", 760 | "illuminate/cookie": "self.version", 761 | "illuminate/database": "self.version", 762 | "illuminate/encryption": "self.version", 763 | "illuminate/events": "self.version", 764 | "illuminate/exception": "self.version", 765 | "illuminate/filesystem": "self.version", 766 | "illuminate/hashing": "self.version", 767 | "illuminate/http": "self.version", 768 | "illuminate/log": "self.version", 769 | "illuminate/mail": "self.version", 770 | "illuminate/notifications": "self.version", 771 | "illuminate/pagination": "self.version", 772 | "illuminate/pipeline": "self.version", 773 | "illuminate/queue": "self.version", 774 | "illuminate/redis": "self.version", 775 | "illuminate/routing": "self.version", 776 | "illuminate/session": "self.version", 777 | "illuminate/support": "self.version", 778 | "illuminate/translation": "self.version", 779 | "illuminate/validation": "self.version", 780 | "illuminate/view": "self.version", 781 | "tightenco/collect": "self.version" 782 | }, 783 | "require-dev": { 784 | "aws/aws-sdk-php": "~3.0", 785 | "mockery/mockery": "~0.9.4", 786 | "pda/pheanstalk": "~3.0", 787 | "phpunit/phpunit": "~5.4", 788 | "predis/predis": "~1.0", 789 | "symfony/css-selector": "3.1.*", 790 | "symfony/dom-crawler": "3.1.*" 791 | }, 792 | "suggest": { 793 | "aws/aws-sdk-php": "Required to use the SQS queue driver and SES mail driver (~3.0).", 794 | "doctrine/dbal": "Required to rename columns and drop SQLite columns (~2.4).", 795 | "fzaninotto/faker": "Required to use the eloquent factory builder (~1.4).", 796 | "guzzlehttp/guzzle": "Required to use the Mailgun and Mandrill mail drivers and the ping methods on schedules (~5.3|~6.0).", 797 | "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (~1.0).", 798 | "league/flysystem-rackspace": "Required to use the Flysystem Rackspace driver (~1.0).", 799 | "pda/pheanstalk": "Required to use the beanstalk queue driver (~3.0).", 800 | "predis/predis": "Required to use the redis cache and queue drivers (~1.0).", 801 | "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (~2.0).", 802 | "symfony/css-selector": "Required to use some of the crawler integration testing tools (3.1.*).", 803 | "symfony/dom-crawler": "Required to use most of the crawler integration testing tools (3.1.*).", 804 | "symfony/psr-http-message-bridge": "Required to psr7 bridging features (0.2.*)." 805 | }, 806 | "type": "library", 807 | "extra": { 808 | "branch-alias": { 809 | "dev-master": "5.3-dev" 810 | } 811 | }, 812 | "autoload": { 813 | "files": [ 814 | "src/Illuminate/Foundation/helpers.php", 815 | "src/Illuminate/Support/helpers.php" 816 | ], 817 | "psr-4": { 818 | "Illuminate\\": "src/Illuminate/" 819 | } 820 | }, 821 | "notification-url": "https://packagist.org/downloads/", 822 | "license": [ 823 | "MIT" 824 | ], 825 | "authors": [ 826 | { 827 | "name": "Taylor Otwell", 828 | "email": "taylor@laravel.com" 829 | } 830 | ], 831 | "description": "The Laravel Framework.", 832 | "homepage": "https://laravel.com", 833 | "keywords": [ 834 | "framework", 835 | "laravel" 836 | ], 837 | "time": "2016-09-20 13:46:16" 838 | }, 839 | { 840 | "name": "league/flysystem", 841 | "version": "1.0.27", 842 | "source": { 843 | "type": "git", 844 | "url": "https://github.com/thephpleague/flysystem.git", 845 | "reference": "50e2045ed70a7e75a5e30bc3662904f3b67af8a9" 846 | }, 847 | "dist": { 848 | "type": "zip", 849 | "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/50e2045ed70a7e75a5e30bc3662904f3b67af8a9", 850 | "reference": "50e2045ed70a7e75a5e30bc3662904f3b67af8a9", 851 | "shasum": "" 852 | }, 853 | "require": { 854 | "php": ">=5.4.0" 855 | }, 856 | "conflict": { 857 | "league/flysystem-sftp": "<1.0.6" 858 | }, 859 | "require-dev": { 860 | "ext-fileinfo": "*", 861 | "mockery/mockery": "~0.9", 862 | "phpspec/phpspec": "^2.2", 863 | "phpunit/phpunit": "~4.8" 864 | }, 865 | "suggest": { 866 | "ext-fileinfo": "Required for MimeType", 867 | "league/flysystem-aws-s3-v2": "Allows you to use S3 storage with AWS SDK v2", 868 | "league/flysystem-aws-s3-v3": "Allows you to use S3 storage with AWS SDK v3", 869 | "league/flysystem-azure": "Allows you to use Windows Azure Blob storage", 870 | "league/flysystem-cached-adapter": "Flysystem adapter decorator for metadata caching", 871 | "league/flysystem-copy": "Allows you to use Copy.com storage", 872 | "league/flysystem-dropbox": "Allows you to use Dropbox storage", 873 | "league/flysystem-eventable-filesystem": "Allows you to use EventableFilesystem", 874 | "league/flysystem-rackspace": "Allows you to use Rackspace Cloud Files", 875 | "league/flysystem-sftp": "Allows you to use SFTP server storage via phpseclib", 876 | "league/flysystem-webdav": "Allows you to use WebDAV storage", 877 | "league/flysystem-ziparchive": "Allows you to use ZipArchive adapter" 878 | }, 879 | "type": "library", 880 | "extra": { 881 | "branch-alias": { 882 | "dev-master": "1.1-dev" 883 | } 884 | }, 885 | "autoload": { 886 | "psr-4": { 887 | "League\\Flysystem\\": "src/" 888 | } 889 | }, 890 | "notification-url": "https://packagist.org/downloads/", 891 | "license": [ 892 | "MIT" 893 | ], 894 | "authors": [ 895 | { 896 | "name": "Frank de Jonge", 897 | "email": "info@frenky.net" 898 | } 899 | ], 900 | "description": "Filesystem abstraction: Many filesystems, one API.", 901 | "keywords": [ 902 | "Cloud Files", 903 | "WebDAV", 904 | "abstraction", 905 | "aws", 906 | "cloud", 907 | "copy.com", 908 | "dropbox", 909 | "file systems", 910 | "files", 911 | "filesystem", 912 | "filesystems", 913 | "ftp", 914 | "rackspace", 915 | "remote", 916 | "s3", 917 | "sftp", 918 | "storage" 919 | ], 920 | "time": "2016-08-10 08:55:11" 921 | }, 922 | { 923 | "name": "monolog/monolog", 924 | "version": "1.21.0", 925 | "source": { 926 | "type": "git", 927 | "url": "https://github.com/Seldaek/monolog.git", 928 | "reference": "f42fbdfd53e306bda545845e4dbfd3e72edb4952" 929 | }, 930 | "dist": { 931 | "type": "zip", 932 | "url": "https://api.github.com/repos/Seldaek/monolog/zipball/f42fbdfd53e306bda545845e4dbfd3e72edb4952", 933 | "reference": "f42fbdfd53e306bda545845e4dbfd3e72edb4952", 934 | "shasum": "" 935 | }, 936 | "require": { 937 | "php": ">=5.3.0", 938 | "psr/log": "~1.0" 939 | }, 940 | "provide": { 941 | "psr/log-implementation": "1.0.0" 942 | }, 943 | "require-dev": { 944 | "aws/aws-sdk-php": "^2.4.9", 945 | "doctrine/couchdb": "~1.0@dev", 946 | "graylog2/gelf-php": "~1.0", 947 | "jakub-onderka/php-parallel-lint": "0.9", 948 | "php-amqplib/php-amqplib": "~2.4", 949 | "php-console/php-console": "^3.1.3", 950 | "phpunit/phpunit": "~4.5", 951 | "phpunit/phpunit-mock-objects": "2.3.0", 952 | "ruflin/elastica": ">=0.90 <3.0", 953 | "sentry/sentry": "^0.13", 954 | "swiftmailer/swiftmailer": "~5.3" 955 | }, 956 | "suggest": { 957 | "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", 958 | "doctrine/couchdb": "Allow sending log messages to a CouchDB server", 959 | "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", 960 | "ext-mongo": "Allow sending log messages to a MongoDB server", 961 | "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", 962 | "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver", 963 | "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", 964 | "php-console/php-console": "Allow sending log messages to Google Chrome", 965 | "rollbar/rollbar": "Allow sending log messages to Rollbar", 966 | "ruflin/elastica": "Allow sending log messages to an Elastic Search server", 967 | "sentry/sentry": "Allow sending log messages to a Sentry server" 968 | }, 969 | "type": "library", 970 | "extra": { 971 | "branch-alias": { 972 | "dev-master": "2.0.x-dev" 973 | } 974 | }, 975 | "autoload": { 976 | "psr-4": { 977 | "Monolog\\": "src/Monolog" 978 | } 979 | }, 980 | "notification-url": "https://packagist.org/downloads/", 981 | "license": [ 982 | "MIT" 983 | ], 984 | "authors": [ 985 | { 986 | "name": "Jordi Boggiano", 987 | "email": "j.boggiano@seld.be", 988 | "homepage": "http://seld.be" 989 | } 990 | ], 991 | "description": "Sends your logs to files, sockets, inboxes, databases and various web services", 992 | "homepage": "http://github.com/Seldaek/monolog", 993 | "keywords": [ 994 | "log", 995 | "logging", 996 | "psr-3" 997 | ], 998 | "time": "2016-07-29 03:23:52" 999 | }, 1000 | { 1001 | "name": "mtdowling/cron-expression", 1002 | "version": "v1.1.0", 1003 | "source": { 1004 | "type": "git", 1005 | "url": "https://github.com/mtdowling/cron-expression.git", 1006 | "reference": "c9ee7886f5a12902b225a1a12f36bb45f9ab89e5" 1007 | }, 1008 | "dist": { 1009 | "type": "zip", 1010 | "url": "https://api.github.com/repos/mtdowling/cron-expression/zipball/c9ee7886f5a12902b225a1a12f36bb45f9ab89e5", 1011 | "reference": "c9ee7886f5a12902b225a1a12f36bb45f9ab89e5", 1012 | "shasum": "" 1013 | }, 1014 | "require": { 1015 | "php": ">=5.3.2" 1016 | }, 1017 | "require-dev": { 1018 | "phpunit/phpunit": "~4.0|~5.0" 1019 | }, 1020 | "type": "library", 1021 | "autoload": { 1022 | "psr-0": { 1023 | "Cron": "src/" 1024 | } 1025 | }, 1026 | "notification-url": "https://packagist.org/downloads/", 1027 | "license": [ 1028 | "MIT" 1029 | ], 1030 | "authors": [ 1031 | { 1032 | "name": "Michael Dowling", 1033 | "email": "mtdowling@gmail.com", 1034 | "homepage": "https://github.com/mtdowling" 1035 | } 1036 | ], 1037 | "description": "CRON for PHP: Calculate the next or previous run date and determine if a CRON expression is due", 1038 | "keywords": [ 1039 | "cron", 1040 | "schedule" 1041 | ], 1042 | "time": "2016-01-26 21:23:30" 1043 | }, 1044 | { 1045 | "name": "nesbot/carbon", 1046 | "version": "1.21.0", 1047 | "source": { 1048 | "type": "git", 1049 | "url": "https://github.com/briannesbitt/Carbon.git", 1050 | "reference": "7b08ec6f75791e130012f206e3f7b0e76e18e3d7" 1051 | }, 1052 | "dist": { 1053 | "type": "zip", 1054 | "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/7b08ec6f75791e130012f206e3f7b0e76e18e3d7", 1055 | "reference": "7b08ec6f75791e130012f206e3f7b0e76e18e3d7", 1056 | "shasum": "" 1057 | }, 1058 | "require": { 1059 | "php": ">=5.3.0", 1060 | "symfony/translation": "~2.6|~3.0" 1061 | }, 1062 | "require-dev": { 1063 | "phpunit/phpunit": "~4.0|~5.0" 1064 | }, 1065 | "type": "library", 1066 | "autoload": { 1067 | "psr-4": { 1068 | "Carbon\\": "src/Carbon/" 1069 | } 1070 | }, 1071 | "notification-url": "https://packagist.org/downloads/", 1072 | "license": [ 1073 | "MIT" 1074 | ], 1075 | "authors": [ 1076 | { 1077 | "name": "Brian Nesbitt", 1078 | "email": "brian@nesbot.com", 1079 | "homepage": "http://nesbot.com" 1080 | } 1081 | ], 1082 | "description": "A simple API extension for DateTime.", 1083 | "homepage": "http://carbon.nesbot.com", 1084 | "keywords": [ 1085 | "date", 1086 | "datetime", 1087 | "time" 1088 | ], 1089 | "time": "2015-11-04 20:07:17" 1090 | }, 1091 | { 1092 | "name": "nikic/php-parser", 1093 | "version": "v2.1.1", 1094 | "source": { 1095 | "type": "git", 1096 | "url": "https://github.com/nikic/PHP-Parser.git", 1097 | "reference": "4dd659edadffdc2143e4753df655d866dbfeedf0" 1098 | }, 1099 | "dist": { 1100 | "type": "zip", 1101 | "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/4dd659edadffdc2143e4753df655d866dbfeedf0", 1102 | "reference": "4dd659edadffdc2143e4753df655d866dbfeedf0", 1103 | "shasum": "" 1104 | }, 1105 | "require": { 1106 | "ext-tokenizer": "*", 1107 | "php": ">=5.4" 1108 | }, 1109 | "require-dev": { 1110 | "phpunit/phpunit": "~4.0" 1111 | }, 1112 | "bin": [ 1113 | "bin/php-parse" 1114 | ], 1115 | "type": "library", 1116 | "extra": { 1117 | "branch-alias": { 1118 | "dev-master": "2.1-dev" 1119 | } 1120 | }, 1121 | "autoload": { 1122 | "psr-4": { 1123 | "PhpParser\\": "lib/PhpParser" 1124 | } 1125 | }, 1126 | "notification-url": "https://packagist.org/downloads/", 1127 | "license": [ 1128 | "BSD-3-Clause" 1129 | ], 1130 | "authors": [ 1131 | { 1132 | "name": "Nikita Popov" 1133 | } 1134 | ], 1135 | "description": "A PHP parser written in PHP", 1136 | "keywords": [ 1137 | "parser", 1138 | "php" 1139 | ], 1140 | "time": "2016-09-16 12:04:44" 1141 | }, 1142 | { 1143 | "name": "paragonie/random_compat", 1144 | "version": "v2.0.2", 1145 | "source": { 1146 | "type": "git", 1147 | "url": "https://github.com/paragonie/random_compat.git", 1148 | "reference": "088c04e2f261c33bed6ca5245491cfca69195ccf" 1149 | }, 1150 | "dist": { 1151 | "type": "zip", 1152 | "url": "https://api.github.com/repos/paragonie/random_compat/zipball/088c04e2f261c33bed6ca5245491cfca69195ccf", 1153 | "reference": "088c04e2f261c33bed6ca5245491cfca69195ccf", 1154 | "shasum": "" 1155 | }, 1156 | "require": { 1157 | "php": ">=5.2.0" 1158 | }, 1159 | "require-dev": { 1160 | "phpunit/phpunit": "4.*|5.*" 1161 | }, 1162 | "suggest": { 1163 | "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." 1164 | }, 1165 | "type": "library", 1166 | "autoload": { 1167 | "files": [ 1168 | "lib/random.php" 1169 | ] 1170 | }, 1171 | "notification-url": "https://packagist.org/downloads/", 1172 | "license": [ 1173 | "MIT" 1174 | ], 1175 | "authors": [ 1176 | { 1177 | "name": "Paragon Initiative Enterprises", 1178 | "email": "security@paragonie.com", 1179 | "homepage": "https://paragonie.com" 1180 | } 1181 | ], 1182 | "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", 1183 | "keywords": [ 1184 | "csprng", 1185 | "pseudorandom", 1186 | "random" 1187 | ], 1188 | "time": "2016-04-03 06:00:07" 1189 | }, 1190 | { 1191 | "name": "psr/log", 1192 | "version": "1.0.1", 1193 | "source": { 1194 | "type": "git", 1195 | "url": "https://github.com/php-fig/log.git", 1196 | "reference": "5277094ed527a1c4477177d102fe4c53551953e0" 1197 | }, 1198 | "dist": { 1199 | "type": "zip", 1200 | "url": "https://api.github.com/repos/php-fig/log/zipball/5277094ed527a1c4477177d102fe4c53551953e0", 1201 | "reference": "5277094ed527a1c4477177d102fe4c53551953e0", 1202 | "shasum": "" 1203 | }, 1204 | "require": { 1205 | "php": ">=5.3.0" 1206 | }, 1207 | "type": "library", 1208 | "extra": { 1209 | "branch-alias": { 1210 | "dev-master": "1.0.x-dev" 1211 | } 1212 | }, 1213 | "autoload": { 1214 | "psr-4": { 1215 | "Psr\\Log\\": "Psr/Log/" 1216 | } 1217 | }, 1218 | "notification-url": "https://packagist.org/downloads/", 1219 | "license": [ 1220 | "MIT" 1221 | ], 1222 | "authors": [ 1223 | { 1224 | "name": "PHP-FIG", 1225 | "homepage": "http://www.php-fig.org/" 1226 | } 1227 | ], 1228 | "description": "Common interface for logging libraries", 1229 | "homepage": "https://github.com/php-fig/log", 1230 | "keywords": [ 1231 | "log", 1232 | "psr", 1233 | "psr-3" 1234 | ], 1235 | "time": "2016-09-19 16:02:08" 1236 | }, 1237 | { 1238 | "name": "psy/psysh", 1239 | "version": "v0.7.2", 1240 | "source": { 1241 | "type": "git", 1242 | "url": "https://github.com/bobthecow/psysh.git", 1243 | "reference": "e64e10b20f8d229cac76399e1f3edddb57a0f280" 1244 | }, 1245 | "dist": { 1246 | "type": "zip", 1247 | "url": "https://api.github.com/repos/bobthecow/psysh/zipball/e64e10b20f8d229cac76399e1f3edddb57a0f280", 1248 | "reference": "e64e10b20f8d229cac76399e1f3edddb57a0f280", 1249 | "shasum": "" 1250 | }, 1251 | "require": { 1252 | "dnoegel/php-xdg-base-dir": "0.1", 1253 | "jakub-onderka/php-console-highlighter": "0.3.*", 1254 | "nikic/php-parser": "^1.2.1|~2.0", 1255 | "php": ">=5.3.9", 1256 | "symfony/console": "~2.3.10|^2.4.2|~3.0", 1257 | "symfony/var-dumper": "~2.7|~3.0" 1258 | }, 1259 | "require-dev": { 1260 | "fabpot/php-cs-fixer": "~1.5", 1261 | "phpunit/phpunit": "~3.7|~4.0|~5.0", 1262 | "squizlabs/php_codesniffer": "~2.0", 1263 | "symfony/finder": "~2.1|~3.0" 1264 | }, 1265 | "suggest": { 1266 | "ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)", 1267 | "ext-pdo-sqlite": "The doc command requires SQLite to work.", 1268 | "ext-posix": "If you have PCNTL, you'll want the POSIX extension as well.", 1269 | "ext-readline": "Enables support for arrow-key history navigation, and showing and manipulating command history." 1270 | }, 1271 | "bin": [ 1272 | "bin/psysh" 1273 | ], 1274 | "type": "library", 1275 | "extra": { 1276 | "branch-alias": { 1277 | "dev-develop": "0.8.x-dev" 1278 | } 1279 | }, 1280 | "autoload": { 1281 | "files": [ 1282 | "src/Psy/functions.php" 1283 | ], 1284 | "psr-4": { 1285 | "Psy\\": "src/Psy/" 1286 | } 1287 | }, 1288 | "notification-url": "https://packagist.org/downloads/", 1289 | "license": [ 1290 | "MIT" 1291 | ], 1292 | "authors": [ 1293 | { 1294 | "name": "Justin Hileman", 1295 | "email": "justin@justinhileman.info", 1296 | "homepage": "http://justinhileman.com" 1297 | } 1298 | ], 1299 | "description": "An interactive shell for modern PHP.", 1300 | "homepage": "http://psysh.org", 1301 | "keywords": [ 1302 | "REPL", 1303 | "console", 1304 | "interactive", 1305 | "shell" 1306 | ], 1307 | "time": "2016-03-09 05:03:14" 1308 | }, 1309 | { 1310 | "name": "ramsey/uuid", 1311 | "version": "3.5.0", 1312 | "source": { 1313 | "type": "git", 1314 | "url": "https://github.com/ramsey/uuid.git", 1315 | "reference": "a6d15c8618ea3951fd54d34e326b68d3d0bc0786" 1316 | }, 1317 | "dist": { 1318 | "type": "zip", 1319 | "url": "https://api.github.com/repos/ramsey/uuid/zipball/a6d15c8618ea3951fd54d34e326b68d3d0bc0786", 1320 | "reference": "a6d15c8618ea3951fd54d34e326b68d3d0bc0786", 1321 | "shasum": "" 1322 | }, 1323 | "require": { 1324 | "paragonie/random_compat": "^1.0|^2.0", 1325 | "php": ">=5.4" 1326 | }, 1327 | "replace": { 1328 | "rhumsaa/uuid": "self.version" 1329 | }, 1330 | "require-dev": { 1331 | "apigen/apigen": "^4.1", 1332 | "codeception/aspect-mock": "1.0.0", 1333 | "goaop/framework": "1.0.0-alpha.2", 1334 | "ircmaxell/random-lib": "^1.1", 1335 | "jakub-onderka/php-parallel-lint": "^0.9.0", 1336 | "mockery/mockery": "^0.9.4", 1337 | "moontoast/math": "^1.1", 1338 | "phpunit/phpunit": "^4.7|>=5.0 <5.4", 1339 | "satooshi/php-coveralls": "^0.6.1", 1340 | "squizlabs/php_codesniffer": "^2.3" 1341 | }, 1342 | "suggest": { 1343 | "ext-libsodium": "Provides the PECL libsodium extension for use with the SodiumRandomGenerator", 1344 | "ext-uuid": "Provides the PECL UUID extension for use with the PeclUuidTimeGenerator and PeclUuidRandomGenerator", 1345 | "ircmaxell/random-lib": "Provides RandomLib for use with the RandomLibAdapter", 1346 | "moontoast/math": "Provides support for converting UUID to 128-bit integer (in string form).", 1347 | "ramsey/uuid-console": "A console application for generating UUIDs with ramsey/uuid", 1348 | "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type." 1349 | }, 1350 | "type": "library", 1351 | "extra": { 1352 | "branch-alias": { 1353 | "dev-master": "3.x-dev" 1354 | } 1355 | }, 1356 | "autoload": { 1357 | "psr-4": { 1358 | "Ramsey\\Uuid\\": "src/" 1359 | } 1360 | }, 1361 | "notification-url": "https://packagist.org/downloads/", 1362 | "license": [ 1363 | "MIT" 1364 | ], 1365 | "authors": [ 1366 | { 1367 | "name": "Marijn Huizendveld", 1368 | "email": "marijn.huizendveld@gmail.com" 1369 | }, 1370 | { 1371 | "name": "Thibaud Fabre", 1372 | "email": "thibaud@aztech.io" 1373 | }, 1374 | { 1375 | "name": "Ben Ramsey", 1376 | "email": "ben@benramsey.com", 1377 | "homepage": "https://benramsey.com" 1378 | } 1379 | ], 1380 | "description": "Formerly rhumsaa/uuid. A PHP 5.4+ library for generating RFC 4122 version 1, 3, 4, and 5 universally unique identifiers (UUID).", 1381 | "homepage": "https://github.com/ramsey/uuid", 1382 | "keywords": [ 1383 | "guid", 1384 | "identifier", 1385 | "uuid" 1386 | ], 1387 | "time": "2016-08-02 18:39:32" 1388 | }, 1389 | { 1390 | "name": "swiftmailer/swiftmailer", 1391 | "version": "v5.4.3", 1392 | "source": { 1393 | "type": "git", 1394 | "url": "https://github.com/swiftmailer/swiftmailer.git", 1395 | "reference": "4cc92842069c2bbc1f28daaaf1d2576ec4dfe153" 1396 | }, 1397 | "dist": { 1398 | "type": "zip", 1399 | "url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/4cc92842069c2bbc1f28daaaf1d2576ec4dfe153", 1400 | "reference": "4cc92842069c2bbc1f28daaaf1d2576ec4dfe153", 1401 | "shasum": "" 1402 | }, 1403 | "require": { 1404 | "php": ">=5.3.3" 1405 | }, 1406 | "require-dev": { 1407 | "mockery/mockery": "~0.9.1" 1408 | }, 1409 | "type": "library", 1410 | "extra": { 1411 | "branch-alias": { 1412 | "dev-master": "5.4-dev" 1413 | } 1414 | }, 1415 | "autoload": { 1416 | "files": [ 1417 | "lib/swift_required.php" 1418 | ] 1419 | }, 1420 | "notification-url": "https://packagist.org/downloads/", 1421 | "license": [ 1422 | "MIT" 1423 | ], 1424 | "authors": [ 1425 | { 1426 | "name": "Chris Corbyn" 1427 | }, 1428 | { 1429 | "name": "Fabien Potencier", 1430 | "email": "fabien@symfony.com" 1431 | } 1432 | ], 1433 | "description": "Swiftmailer, free feature-rich PHP mailer", 1434 | "homepage": "http://swiftmailer.org", 1435 | "keywords": [ 1436 | "email", 1437 | "mail", 1438 | "mailer" 1439 | ], 1440 | "time": "2016-07-08 11:51:25" 1441 | }, 1442 | { 1443 | "name": "symfony/console", 1444 | "version": "v3.1.4", 1445 | "source": { 1446 | "type": "git", 1447 | "url": "https://github.com/symfony/console.git", 1448 | "reference": "8ea494c34f0f772c3954b5fbe00bffc5a435e563" 1449 | }, 1450 | "dist": { 1451 | "type": "zip", 1452 | "url": "https://api.github.com/repos/symfony/console/zipball/8ea494c34f0f772c3954b5fbe00bffc5a435e563", 1453 | "reference": "8ea494c34f0f772c3954b5fbe00bffc5a435e563", 1454 | "shasum": "" 1455 | }, 1456 | "require": { 1457 | "php": ">=5.5.9", 1458 | "symfony/polyfill-mbstring": "~1.0" 1459 | }, 1460 | "require-dev": { 1461 | "psr/log": "~1.0", 1462 | "symfony/event-dispatcher": "~2.8|~3.0", 1463 | "symfony/process": "~2.8|~3.0" 1464 | }, 1465 | "suggest": { 1466 | "psr/log": "For using the console logger", 1467 | "symfony/event-dispatcher": "", 1468 | "symfony/process": "" 1469 | }, 1470 | "type": "library", 1471 | "extra": { 1472 | "branch-alias": { 1473 | "dev-master": "3.1-dev" 1474 | } 1475 | }, 1476 | "autoload": { 1477 | "psr-4": { 1478 | "Symfony\\Component\\Console\\": "" 1479 | }, 1480 | "exclude-from-classmap": [ 1481 | "/Tests/" 1482 | ] 1483 | }, 1484 | "notification-url": "https://packagist.org/downloads/", 1485 | "license": [ 1486 | "MIT" 1487 | ], 1488 | "authors": [ 1489 | { 1490 | "name": "Fabien Potencier", 1491 | "email": "fabien@symfony.com" 1492 | }, 1493 | { 1494 | "name": "Symfony Community", 1495 | "homepage": "https://symfony.com/contributors" 1496 | } 1497 | ], 1498 | "description": "Symfony Console Component", 1499 | "homepage": "https://symfony.com", 1500 | "time": "2016-08-19 06:48:39" 1501 | }, 1502 | { 1503 | "name": "symfony/debug", 1504 | "version": "v3.1.4", 1505 | "source": { 1506 | "type": "git", 1507 | "url": "https://github.com/symfony/debug.git", 1508 | "reference": "34f6ac18c2974ca5fce68adf419ee7d15def6f11" 1509 | }, 1510 | "dist": { 1511 | "type": "zip", 1512 | "url": "https://api.github.com/repos/symfony/debug/zipball/34f6ac18c2974ca5fce68adf419ee7d15def6f11", 1513 | "reference": "34f6ac18c2974ca5fce68adf419ee7d15def6f11", 1514 | "shasum": "" 1515 | }, 1516 | "require": { 1517 | "php": ">=5.5.9", 1518 | "psr/log": "~1.0" 1519 | }, 1520 | "conflict": { 1521 | "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" 1522 | }, 1523 | "require-dev": { 1524 | "symfony/class-loader": "~2.8|~3.0", 1525 | "symfony/http-kernel": "~2.8|~3.0" 1526 | }, 1527 | "type": "library", 1528 | "extra": { 1529 | "branch-alias": { 1530 | "dev-master": "3.1-dev" 1531 | } 1532 | }, 1533 | "autoload": { 1534 | "psr-4": { 1535 | "Symfony\\Component\\Debug\\": "" 1536 | }, 1537 | "exclude-from-classmap": [ 1538 | "/Tests/" 1539 | ] 1540 | }, 1541 | "notification-url": "https://packagist.org/downloads/", 1542 | "license": [ 1543 | "MIT" 1544 | ], 1545 | "authors": [ 1546 | { 1547 | "name": "Fabien Potencier", 1548 | "email": "fabien@symfony.com" 1549 | }, 1550 | { 1551 | "name": "Symfony Community", 1552 | "homepage": "https://symfony.com/contributors" 1553 | } 1554 | ], 1555 | "description": "Symfony Debug Component", 1556 | "homepage": "https://symfony.com", 1557 | "time": "2016-08-23 13:39:15" 1558 | }, 1559 | { 1560 | "name": "symfony/event-dispatcher", 1561 | "version": "v3.1.4", 1562 | "source": { 1563 | "type": "git", 1564 | "url": "https://github.com/symfony/event-dispatcher.git", 1565 | "reference": "c0c00c80b3a69132c4e55c3e7db32b4a387615e5" 1566 | }, 1567 | "dist": { 1568 | "type": "zip", 1569 | "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/c0c00c80b3a69132c4e55c3e7db32b4a387615e5", 1570 | "reference": "c0c00c80b3a69132c4e55c3e7db32b4a387615e5", 1571 | "shasum": "" 1572 | }, 1573 | "require": { 1574 | "php": ">=5.5.9" 1575 | }, 1576 | "require-dev": { 1577 | "psr/log": "~1.0", 1578 | "symfony/config": "~2.8|~3.0", 1579 | "symfony/dependency-injection": "~2.8|~3.0", 1580 | "symfony/expression-language": "~2.8|~3.0", 1581 | "symfony/stopwatch": "~2.8|~3.0" 1582 | }, 1583 | "suggest": { 1584 | "symfony/dependency-injection": "", 1585 | "symfony/http-kernel": "" 1586 | }, 1587 | "type": "library", 1588 | "extra": { 1589 | "branch-alias": { 1590 | "dev-master": "3.1-dev" 1591 | } 1592 | }, 1593 | "autoload": { 1594 | "psr-4": { 1595 | "Symfony\\Component\\EventDispatcher\\": "" 1596 | }, 1597 | "exclude-from-classmap": [ 1598 | "/Tests/" 1599 | ] 1600 | }, 1601 | "notification-url": "https://packagist.org/downloads/", 1602 | "license": [ 1603 | "MIT" 1604 | ], 1605 | "authors": [ 1606 | { 1607 | "name": "Fabien Potencier", 1608 | "email": "fabien@symfony.com" 1609 | }, 1610 | { 1611 | "name": "Symfony Community", 1612 | "homepage": "https://symfony.com/contributors" 1613 | } 1614 | ], 1615 | "description": "Symfony EventDispatcher Component", 1616 | "homepage": "https://symfony.com", 1617 | "time": "2016-07-19 10:45:57" 1618 | }, 1619 | { 1620 | "name": "symfony/finder", 1621 | "version": "v3.1.4", 1622 | "source": { 1623 | "type": "git", 1624 | "url": "https://github.com/symfony/finder.git", 1625 | "reference": "e568ef1784f447a0e54dcb6f6de30b9747b0f577" 1626 | }, 1627 | "dist": { 1628 | "type": "zip", 1629 | "url": "https://api.github.com/repos/symfony/finder/zipball/e568ef1784f447a0e54dcb6f6de30b9747b0f577", 1630 | "reference": "e568ef1784f447a0e54dcb6f6de30b9747b0f577", 1631 | "shasum": "" 1632 | }, 1633 | "require": { 1634 | "php": ">=5.5.9" 1635 | }, 1636 | "type": "library", 1637 | "extra": { 1638 | "branch-alias": { 1639 | "dev-master": "3.1-dev" 1640 | } 1641 | }, 1642 | "autoload": { 1643 | "psr-4": { 1644 | "Symfony\\Component\\Finder\\": "" 1645 | }, 1646 | "exclude-from-classmap": [ 1647 | "/Tests/" 1648 | ] 1649 | }, 1650 | "notification-url": "https://packagist.org/downloads/", 1651 | "license": [ 1652 | "MIT" 1653 | ], 1654 | "authors": [ 1655 | { 1656 | "name": "Fabien Potencier", 1657 | "email": "fabien@symfony.com" 1658 | }, 1659 | { 1660 | "name": "Symfony Community", 1661 | "homepage": "https://symfony.com/contributors" 1662 | } 1663 | ], 1664 | "description": "Symfony Finder Component", 1665 | "homepage": "https://symfony.com", 1666 | "time": "2016-08-26 12:04:02" 1667 | }, 1668 | { 1669 | "name": "symfony/http-foundation", 1670 | "version": "v3.1.4", 1671 | "source": { 1672 | "type": "git", 1673 | "url": "https://github.com/symfony/http-foundation.git", 1674 | "reference": "63592e00fd90632b57ee50220a1ddb29b6bf3bb4" 1675 | }, 1676 | "dist": { 1677 | "type": "zip", 1678 | "url": "https://api.github.com/repos/symfony/http-foundation/zipball/63592e00fd90632b57ee50220a1ddb29b6bf3bb4", 1679 | "reference": "63592e00fd90632b57ee50220a1ddb29b6bf3bb4", 1680 | "shasum": "" 1681 | }, 1682 | "require": { 1683 | "php": ">=5.5.9", 1684 | "symfony/polyfill-mbstring": "~1.1" 1685 | }, 1686 | "require-dev": { 1687 | "symfony/expression-language": "~2.8|~3.0" 1688 | }, 1689 | "type": "library", 1690 | "extra": { 1691 | "branch-alias": { 1692 | "dev-master": "3.1-dev" 1693 | } 1694 | }, 1695 | "autoload": { 1696 | "psr-4": { 1697 | "Symfony\\Component\\HttpFoundation\\": "" 1698 | }, 1699 | "exclude-from-classmap": [ 1700 | "/Tests/" 1701 | ] 1702 | }, 1703 | "notification-url": "https://packagist.org/downloads/", 1704 | "license": [ 1705 | "MIT" 1706 | ], 1707 | "authors": [ 1708 | { 1709 | "name": "Fabien Potencier", 1710 | "email": "fabien@symfony.com" 1711 | }, 1712 | { 1713 | "name": "Symfony Community", 1714 | "homepage": "https://symfony.com/contributors" 1715 | } 1716 | ], 1717 | "description": "Symfony HttpFoundation Component", 1718 | "homepage": "https://symfony.com", 1719 | "time": "2016-08-22 12:11:19" 1720 | }, 1721 | { 1722 | "name": "symfony/http-kernel", 1723 | "version": "v3.1.4", 1724 | "source": { 1725 | "type": "git", 1726 | "url": "https://github.com/symfony/http-kernel.git", 1727 | "reference": "aeda215d6b01f119508c090d2a09ebb5b0bc61f3" 1728 | }, 1729 | "dist": { 1730 | "type": "zip", 1731 | "url": "https://api.github.com/repos/symfony/http-kernel/zipball/aeda215d6b01f119508c090d2a09ebb5b0bc61f3", 1732 | "reference": "aeda215d6b01f119508c090d2a09ebb5b0bc61f3", 1733 | "shasum": "" 1734 | }, 1735 | "require": { 1736 | "php": ">=5.5.9", 1737 | "psr/log": "~1.0", 1738 | "symfony/debug": "~2.8|~3.0", 1739 | "symfony/event-dispatcher": "~2.8|~3.0", 1740 | "symfony/http-foundation": "~2.8.8|~3.0.8|~3.1.2|~3.2" 1741 | }, 1742 | "conflict": { 1743 | "symfony/config": "<2.8" 1744 | }, 1745 | "require-dev": { 1746 | "symfony/browser-kit": "~2.8|~3.0", 1747 | "symfony/class-loader": "~2.8|~3.0", 1748 | "symfony/config": "~2.8|~3.0", 1749 | "symfony/console": "~2.8|~3.0", 1750 | "symfony/css-selector": "~2.8|~3.0", 1751 | "symfony/dependency-injection": "~2.8|~3.0", 1752 | "symfony/dom-crawler": "~2.8|~3.0", 1753 | "symfony/expression-language": "~2.8|~3.0", 1754 | "symfony/finder": "~2.8|~3.0", 1755 | "symfony/process": "~2.8|~3.0", 1756 | "symfony/routing": "~2.8|~3.0", 1757 | "symfony/stopwatch": "~2.8|~3.0", 1758 | "symfony/templating": "~2.8|~3.0", 1759 | "symfony/translation": "~2.8|~3.0", 1760 | "symfony/var-dumper": "~2.8|~3.0" 1761 | }, 1762 | "suggest": { 1763 | "symfony/browser-kit": "", 1764 | "symfony/class-loader": "", 1765 | "symfony/config": "", 1766 | "symfony/console": "", 1767 | "symfony/dependency-injection": "", 1768 | "symfony/finder": "", 1769 | "symfony/var-dumper": "" 1770 | }, 1771 | "type": "library", 1772 | "extra": { 1773 | "branch-alias": { 1774 | "dev-master": "3.1-dev" 1775 | } 1776 | }, 1777 | "autoload": { 1778 | "psr-4": { 1779 | "Symfony\\Component\\HttpKernel\\": "" 1780 | }, 1781 | "exclude-from-classmap": [ 1782 | "/Tests/" 1783 | ] 1784 | }, 1785 | "notification-url": "https://packagist.org/downloads/", 1786 | "license": [ 1787 | "MIT" 1788 | ], 1789 | "authors": [ 1790 | { 1791 | "name": "Fabien Potencier", 1792 | "email": "fabien@symfony.com" 1793 | }, 1794 | { 1795 | "name": "Symfony Community", 1796 | "homepage": "https://symfony.com/contributors" 1797 | } 1798 | ], 1799 | "description": "Symfony HttpKernel Component", 1800 | "homepage": "https://symfony.com", 1801 | "time": "2016-09-03 15:28:24" 1802 | }, 1803 | { 1804 | "name": "symfony/polyfill-mbstring", 1805 | "version": "v1.2.0", 1806 | "source": { 1807 | "type": "git", 1808 | "url": "https://github.com/symfony/polyfill-mbstring.git", 1809 | "reference": "dff51f72b0706335131b00a7f49606168c582594" 1810 | }, 1811 | "dist": { 1812 | "type": "zip", 1813 | "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/dff51f72b0706335131b00a7f49606168c582594", 1814 | "reference": "dff51f72b0706335131b00a7f49606168c582594", 1815 | "shasum": "" 1816 | }, 1817 | "require": { 1818 | "php": ">=5.3.3" 1819 | }, 1820 | "suggest": { 1821 | "ext-mbstring": "For best performance" 1822 | }, 1823 | "type": "library", 1824 | "extra": { 1825 | "branch-alias": { 1826 | "dev-master": "1.2-dev" 1827 | } 1828 | }, 1829 | "autoload": { 1830 | "psr-4": { 1831 | "Symfony\\Polyfill\\Mbstring\\": "" 1832 | }, 1833 | "files": [ 1834 | "bootstrap.php" 1835 | ] 1836 | }, 1837 | "notification-url": "https://packagist.org/downloads/", 1838 | "license": [ 1839 | "MIT" 1840 | ], 1841 | "authors": [ 1842 | { 1843 | "name": "Nicolas Grekas", 1844 | "email": "p@tchwork.com" 1845 | }, 1846 | { 1847 | "name": "Symfony Community", 1848 | "homepage": "https://symfony.com/contributors" 1849 | } 1850 | ], 1851 | "description": "Symfony polyfill for the Mbstring extension", 1852 | "homepage": "https://symfony.com", 1853 | "keywords": [ 1854 | "compatibility", 1855 | "mbstring", 1856 | "polyfill", 1857 | "portable", 1858 | "shim" 1859 | ], 1860 | "time": "2016-05-18 14:26:46" 1861 | }, 1862 | { 1863 | "name": "symfony/polyfill-php56", 1864 | "version": "v1.2.0", 1865 | "source": { 1866 | "type": "git", 1867 | "url": "https://github.com/symfony/polyfill-php56.git", 1868 | "reference": "3edf57a8fbf9a927533344cef65ad7e1cf31030a" 1869 | }, 1870 | "dist": { 1871 | "type": "zip", 1872 | "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/3edf57a8fbf9a927533344cef65ad7e1cf31030a", 1873 | "reference": "3edf57a8fbf9a927533344cef65ad7e1cf31030a", 1874 | "shasum": "" 1875 | }, 1876 | "require": { 1877 | "php": ">=5.3.3", 1878 | "symfony/polyfill-util": "~1.0" 1879 | }, 1880 | "type": "library", 1881 | "extra": { 1882 | "branch-alias": { 1883 | "dev-master": "1.2-dev" 1884 | } 1885 | }, 1886 | "autoload": { 1887 | "psr-4": { 1888 | "Symfony\\Polyfill\\Php56\\": "" 1889 | }, 1890 | "files": [ 1891 | "bootstrap.php" 1892 | ] 1893 | }, 1894 | "notification-url": "https://packagist.org/downloads/", 1895 | "license": [ 1896 | "MIT" 1897 | ], 1898 | "authors": [ 1899 | { 1900 | "name": "Nicolas Grekas", 1901 | "email": "p@tchwork.com" 1902 | }, 1903 | { 1904 | "name": "Symfony Community", 1905 | "homepage": "https://symfony.com/contributors" 1906 | } 1907 | ], 1908 | "description": "Symfony polyfill backporting some PHP 5.6+ features to lower PHP versions", 1909 | "homepage": "https://symfony.com", 1910 | "keywords": [ 1911 | "compatibility", 1912 | "polyfill", 1913 | "portable", 1914 | "shim" 1915 | ], 1916 | "time": "2016-05-18 14:26:46" 1917 | }, 1918 | { 1919 | "name": "symfony/polyfill-util", 1920 | "version": "v1.2.0", 1921 | "source": { 1922 | "type": "git", 1923 | "url": "https://github.com/symfony/polyfill-util.git", 1924 | "reference": "ef830ce3d218e622b221d6bfad42c751d974bf99" 1925 | }, 1926 | "dist": { 1927 | "type": "zip", 1928 | "url": "https://api.github.com/repos/symfony/polyfill-util/zipball/ef830ce3d218e622b221d6bfad42c751d974bf99", 1929 | "reference": "ef830ce3d218e622b221d6bfad42c751d974bf99", 1930 | "shasum": "" 1931 | }, 1932 | "require": { 1933 | "php": ">=5.3.3" 1934 | }, 1935 | "type": "library", 1936 | "extra": { 1937 | "branch-alias": { 1938 | "dev-master": "1.2-dev" 1939 | } 1940 | }, 1941 | "autoload": { 1942 | "psr-4": { 1943 | "Symfony\\Polyfill\\Util\\": "" 1944 | } 1945 | }, 1946 | "notification-url": "https://packagist.org/downloads/", 1947 | "license": [ 1948 | "MIT" 1949 | ], 1950 | "authors": [ 1951 | { 1952 | "name": "Nicolas Grekas", 1953 | "email": "p@tchwork.com" 1954 | }, 1955 | { 1956 | "name": "Symfony Community", 1957 | "homepage": "https://symfony.com/contributors" 1958 | } 1959 | ], 1960 | "description": "Symfony utilities for portability of PHP codes", 1961 | "homepage": "https://symfony.com", 1962 | "keywords": [ 1963 | "compat", 1964 | "compatibility", 1965 | "polyfill", 1966 | "shim" 1967 | ], 1968 | "time": "2016-05-18 14:26:46" 1969 | }, 1970 | { 1971 | "name": "symfony/process", 1972 | "version": "v3.1.4", 1973 | "source": { 1974 | "type": "git", 1975 | "url": "https://github.com/symfony/process.git", 1976 | "reference": "e64e93041c80e77197ace5ab9385dedb5a143697" 1977 | }, 1978 | "dist": { 1979 | "type": "zip", 1980 | "url": "https://api.github.com/repos/symfony/process/zipball/e64e93041c80e77197ace5ab9385dedb5a143697", 1981 | "reference": "e64e93041c80e77197ace5ab9385dedb5a143697", 1982 | "shasum": "" 1983 | }, 1984 | "require": { 1985 | "php": ">=5.5.9" 1986 | }, 1987 | "type": "library", 1988 | "extra": { 1989 | "branch-alias": { 1990 | "dev-master": "3.1-dev" 1991 | } 1992 | }, 1993 | "autoload": { 1994 | "psr-4": { 1995 | "Symfony\\Component\\Process\\": "" 1996 | }, 1997 | "exclude-from-classmap": [ 1998 | "/Tests/" 1999 | ] 2000 | }, 2001 | "notification-url": "https://packagist.org/downloads/", 2002 | "license": [ 2003 | "MIT" 2004 | ], 2005 | "authors": [ 2006 | { 2007 | "name": "Fabien Potencier", 2008 | "email": "fabien@symfony.com" 2009 | }, 2010 | { 2011 | "name": "Symfony Community", 2012 | "homepage": "https://symfony.com/contributors" 2013 | } 2014 | ], 2015 | "description": "Symfony Process Component", 2016 | "homepage": "https://symfony.com", 2017 | "time": "2016-08-16 14:58:24" 2018 | }, 2019 | { 2020 | "name": "symfony/routing", 2021 | "version": "v3.1.4", 2022 | "source": { 2023 | "type": "git", 2024 | "url": "https://github.com/symfony/routing.git", 2025 | "reference": "8edf62498a1a4c57ba317664a4b698339c10cdf6" 2026 | }, 2027 | "dist": { 2028 | "type": "zip", 2029 | "url": "https://api.github.com/repos/symfony/routing/zipball/8edf62498a1a4c57ba317664a4b698339c10cdf6", 2030 | "reference": "8edf62498a1a4c57ba317664a4b698339c10cdf6", 2031 | "shasum": "" 2032 | }, 2033 | "require": { 2034 | "php": ">=5.5.9" 2035 | }, 2036 | "conflict": { 2037 | "symfony/config": "<2.8" 2038 | }, 2039 | "require-dev": { 2040 | "doctrine/annotations": "~1.0", 2041 | "doctrine/common": "~2.2", 2042 | "psr/log": "~1.0", 2043 | "symfony/config": "~2.8|~3.0", 2044 | "symfony/expression-language": "~2.8|~3.0", 2045 | "symfony/http-foundation": "~2.8|~3.0", 2046 | "symfony/yaml": "~2.8|~3.0" 2047 | }, 2048 | "suggest": { 2049 | "doctrine/annotations": "For using the annotation loader", 2050 | "symfony/config": "For using the all-in-one router or any loader", 2051 | "symfony/dependency-injection": "For loading routes from a service", 2052 | "symfony/expression-language": "For using expression matching", 2053 | "symfony/http-foundation": "For using a Symfony Request object", 2054 | "symfony/yaml": "For using the YAML loader" 2055 | }, 2056 | "type": "library", 2057 | "extra": { 2058 | "branch-alias": { 2059 | "dev-master": "3.1-dev" 2060 | } 2061 | }, 2062 | "autoload": { 2063 | "psr-4": { 2064 | "Symfony\\Component\\Routing\\": "" 2065 | }, 2066 | "exclude-from-classmap": [ 2067 | "/Tests/" 2068 | ] 2069 | }, 2070 | "notification-url": "https://packagist.org/downloads/", 2071 | "license": [ 2072 | "MIT" 2073 | ], 2074 | "authors": [ 2075 | { 2076 | "name": "Fabien Potencier", 2077 | "email": "fabien@symfony.com" 2078 | }, 2079 | { 2080 | "name": "Symfony Community", 2081 | "homepage": "https://symfony.com/contributors" 2082 | } 2083 | ], 2084 | "description": "Symfony Routing Component", 2085 | "homepage": "https://symfony.com", 2086 | "keywords": [ 2087 | "router", 2088 | "routing", 2089 | "uri", 2090 | "url" 2091 | ], 2092 | "time": "2016-08-16 14:58:24" 2093 | }, 2094 | { 2095 | "name": "symfony/translation", 2096 | "version": "v3.1.4", 2097 | "source": { 2098 | "type": "git", 2099 | "url": "https://github.com/symfony/translation.git", 2100 | "reference": "a35edc277513c9bc0f063ca174c36b346f974528" 2101 | }, 2102 | "dist": { 2103 | "type": "zip", 2104 | "url": "https://api.github.com/repos/symfony/translation/zipball/a35edc277513c9bc0f063ca174c36b346f974528", 2105 | "reference": "a35edc277513c9bc0f063ca174c36b346f974528", 2106 | "shasum": "" 2107 | }, 2108 | "require": { 2109 | "php": ">=5.5.9", 2110 | "symfony/polyfill-mbstring": "~1.0" 2111 | }, 2112 | "conflict": { 2113 | "symfony/config": "<2.8" 2114 | }, 2115 | "require-dev": { 2116 | "psr/log": "~1.0", 2117 | "symfony/config": "~2.8|~3.0", 2118 | "symfony/intl": "~2.8|~3.0", 2119 | "symfony/yaml": "~2.8|~3.0" 2120 | }, 2121 | "suggest": { 2122 | "psr/log": "To use logging capability in translator", 2123 | "symfony/config": "", 2124 | "symfony/yaml": "" 2125 | }, 2126 | "type": "library", 2127 | "extra": { 2128 | "branch-alias": { 2129 | "dev-master": "3.1-dev" 2130 | } 2131 | }, 2132 | "autoload": { 2133 | "psr-4": { 2134 | "Symfony\\Component\\Translation\\": "" 2135 | }, 2136 | "exclude-from-classmap": [ 2137 | "/Tests/" 2138 | ] 2139 | }, 2140 | "notification-url": "https://packagist.org/downloads/", 2141 | "license": [ 2142 | "MIT" 2143 | ], 2144 | "authors": [ 2145 | { 2146 | "name": "Fabien Potencier", 2147 | "email": "fabien@symfony.com" 2148 | }, 2149 | { 2150 | "name": "Symfony Community", 2151 | "homepage": "https://symfony.com/contributors" 2152 | } 2153 | ], 2154 | "description": "Symfony Translation Component", 2155 | "homepage": "https://symfony.com", 2156 | "time": "2016-08-05 08:37:39" 2157 | }, 2158 | { 2159 | "name": "symfony/var-dumper", 2160 | "version": "v3.1.4", 2161 | "source": { 2162 | "type": "git", 2163 | "url": "https://github.com/symfony/var-dumper.git", 2164 | "reference": "62ee73706c421654a4c840028954510277f7dfc8" 2165 | }, 2166 | "dist": { 2167 | "type": "zip", 2168 | "url": "https://api.github.com/repos/symfony/var-dumper/zipball/62ee73706c421654a4c840028954510277f7dfc8", 2169 | "reference": "62ee73706c421654a4c840028954510277f7dfc8", 2170 | "shasum": "" 2171 | }, 2172 | "require": { 2173 | "php": ">=5.5.9", 2174 | "symfony/polyfill-mbstring": "~1.0" 2175 | }, 2176 | "require-dev": { 2177 | "twig/twig": "~1.20|~2.0" 2178 | }, 2179 | "suggest": { 2180 | "ext-symfony_debug": "" 2181 | }, 2182 | "type": "library", 2183 | "extra": { 2184 | "branch-alias": { 2185 | "dev-master": "3.1-dev" 2186 | } 2187 | }, 2188 | "autoload": { 2189 | "files": [ 2190 | "Resources/functions/dump.php" 2191 | ], 2192 | "psr-4": { 2193 | "Symfony\\Component\\VarDumper\\": "" 2194 | }, 2195 | "exclude-from-classmap": [ 2196 | "/Tests/" 2197 | ] 2198 | }, 2199 | "notification-url": "https://packagist.org/downloads/", 2200 | "license": [ 2201 | "MIT" 2202 | ], 2203 | "authors": [ 2204 | { 2205 | "name": "Nicolas Grekas", 2206 | "email": "p@tchwork.com" 2207 | }, 2208 | { 2209 | "name": "Symfony Community", 2210 | "homepage": "https://symfony.com/contributors" 2211 | } 2212 | ], 2213 | "description": "Symfony mechanism for exploring and dumping PHP variables", 2214 | "homepage": "https://symfony.com", 2215 | "keywords": [ 2216 | "debug", 2217 | "dump" 2218 | ], 2219 | "time": "2016-08-31 09:05:42" 2220 | }, 2221 | { 2222 | "name": "vlucas/phpdotenv", 2223 | "version": "v2.4.0", 2224 | "source": { 2225 | "type": "git", 2226 | "url": "https://github.com/vlucas/phpdotenv.git", 2227 | "reference": "3cc116adbe4b11be5ec557bf1d24dc5e3a21d18c" 2228 | }, 2229 | "dist": { 2230 | "type": "zip", 2231 | "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/3cc116adbe4b11be5ec557bf1d24dc5e3a21d18c", 2232 | "reference": "3cc116adbe4b11be5ec557bf1d24dc5e3a21d18c", 2233 | "shasum": "" 2234 | }, 2235 | "require": { 2236 | "php": ">=5.3.9" 2237 | }, 2238 | "require-dev": { 2239 | "phpunit/phpunit": "^4.8 || ^5.0" 2240 | }, 2241 | "type": "library", 2242 | "extra": { 2243 | "branch-alias": { 2244 | "dev-master": "2.4-dev" 2245 | } 2246 | }, 2247 | "autoload": { 2248 | "psr-4": { 2249 | "Dotenv\\": "src/" 2250 | } 2251 | }, 2252 | "notification-url": "https://packagist.org/downloads/", 2253 | "license": [ 2254 | "BSD-3-Clause-Attribution" 2255 | ], 2256 | "authors": [ 2257 | { 2258 | "name": "Vance Lucas", 2259 | "email": "vance@vancelucas.com", 2260 | "homepage": "http://www.vancelucas.com" 2261 | } 2262 | ], 2263 | "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", 2264 | "keywords": [ 2265 | "dotenv", 2266 | "env", 2267 | "environment" 2268 | ], 2269 | "time": "2016-09-01 10:05:43" 2270 | } 2271 | ], 2272 | "packages-dev": [], 2273 | "aliases": [], 2274 | "minimum-stability": "stable", 2275 | "stability-flags": [], 2276 | "prefer-stable": false, 2277 | "prefer-lowest": false, 2278 | "platform": [], 2279 | "platform-dev": [] 2280 | } 2281 | -------------------------------------------------------------------------------- /docs/database-test-method.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erikgall/eloquent-phpunit/bb3eb18098c967ec0398af6b3e2d6865e387e3bb/docs/database-test-method.png -------------------------------------------------------------------------------- /docs/model-test-method.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/erikgall/eloquent-phpunit/bb3eb18098c967ec0398af6b3e2d6865e387e3bb/docs/model-test-method.png -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Eloquent PHPUnit 2 | 3 | [![StyleCI](https://styleci.io/repos/65038313/shield)](https://styleci.io/repos/65038313) 4 | 5 | #### Test your Laravel Eloquent model's and database schema 6 | 7 | This package was inspired by the Ruby on Rails world and the testing framework RSpec. The Ruby on Rails community (for the most part) write tests for their models in a way that they check the model's attributes, relationships, database table and columns settings (defaults, nullable, etc.). 8 | 9 | ## Table of Contents 10 | 11 | 1. [What can be tested](#what-can-be-tested) 12 | 2. [Installation](#installation) 13 | 3. [Requirements](#requirements) 14 | 4. [Documentation](#documentation) 15 | 1. [Properties](#test-class-properties) 16 | 2. [Table Testing Methods](#database-testing-methods) 17 | 3. [Model Testing Methods](#model-testing-methods) 18 | 5. [Example Model Test Class](#example-model-test) 19 | 6. [Contributing](#contributing) 20 | 7. [Version Release History](#history) 21 | 8. [Projects using Eloquent-PHPUnit](#projects-using-eloquent-phpunit) 22 | 9. [Author](#author) 23 | 10. [License](#license) 24 | 25 | ![Test a database table](docs/database-test-method.png "Test a database table.") 26 | 27 | ![Test an eloquent model's attributes/relationships](docs/model-test-method.png "Test an eloquent model's attributes/relationships.") 28 | 29 | ## What can be tested 30 | 31 | - Casted attribute array 32 | - Fillable attribute array 33 | - Hidden attribute array 34 | - Dates attribute array 35 | - Relationship methods 36 | 37 | You can also test your database tables such as: 38 | - Table exists 39 | - Table column exists 40 | - Table column type (string, text, date, datetime, boolean, etc.). 41 | - Column default value 42 | - Null/Not Null 43 | - Auto-incremented primary keys. 44 | - Table indexes 45 | - Unique indexes 46 | - Foreign Key relationships 47 | 48 | ## Installation 49 | 50 | 1. The easiest way to use/install this package is by using composer in your terminal: 51 | ``` 52 | composer require erikgall/eloquent-phpunit 53 | ``` 54 | 2. Or you can add the following line to your `require-dev` dependencies in your `composer.json` file 55 | ```json 56 | { 57 | "require-dev": { 58 | "erikgall/eloquent-phpunit": "~1.0" 59 | } 60 | } 61 | ``` 62 | 63 | ## Requirements 64 | 65 | This package requires `PHP 5.6` or `PHP 7+`. It has been tested and used with `Laravel 5.2` and `Laravel 5.3`. There should not be a problem using it with `Laravel 5.0/1` but it has not been tested or confirmed 100%. 66 | 67 | ## Documentation 68 | 69 | ### Test Class Properties 70 | 71 | | Name | Type | Required | Default | Description | 72 | |---------------|-------------------------------------|----------|----------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 73 | | defaultSeeder | string | false | DatabaseSeeder | The database seeder class name that calls the rest of your seeders (only used if seedDatabase property is not set to false). | 74 | | data | array | false | - | Do not overwrite this property. It is used to store the model's data. You can access this data by calling any of the data array's keys like a class property ($this->fillable, $this->casts, $this->table) | 75 | | model | string | true | - | The FQCN of the eloquent model that is to be tested (ex. App\User) | 76 | | seedDatabase | boolean | false | true | Should the database be seeded before each test. If you are not running tests that require data in the database, you should set this to false to speed up your tests. | 77 | | seeders | array | false | - | If you wish to only call certain seeder classes you can set them here (ex. `['UsersTableSeeder', 'PostsTableSeeder']` (only used if seedDatabase property is not set to false). | 78 | | subject | Model** | false | - | This is the instance of the model class that is being tested. When setting up a test, the EloquentTestCase class initializes a new empty model. | 79 | 80 | **These settings are only used if the seedDatabase property is not set to false (the default value for the seedDatabase property is true).* 81 | 82 | ** The subject property is an instance of \Illuminate\Database\Eloquent\Model. 83 | 84 | ### Database Testing Methods 85 | 86 | #### \EGALL\EloquentPHPUnit\Database\Table 87 | 88 | Get the `EGALL\EloquentPHPUnit\Database\Table` class instance by calling the table property. 89 | 90 | **Usage:** 91 | 92 | ```php 93 | $this->table 94 | ``` 95 | 96 | #### Table methods 97 | --- 98 | 99 | ##### column($columnName) 100 | 101 | Initializes a new `EGALL\EloquentPHPUnit\Database\Column` class instance for table's column name that is passed in. 102 | 103 | **Usage:** 104 | 105 | ```php 106 | $this->table->column('column_name') 107 | ``` 108 | 109 | Returns: `EGALL\EloquentPHPUnit\Database\Column` 110 | 111 | --- 112 | 113 | ##### exists() 114 | 115 | Assert that the table exists in the database. 116 | 117 | **Usage:** 118 | 119 | ```php 120 | $this->table->exists(); 121 | ``` 122 | 123 | **Returns:** `EGALL\EloquentPHPUnit\Database\Table` 124 | 125 | --- 126 | 127 | ##### hasTimestamps() 128 | 129 | Assert that the table has timestamp columns. 130 | 131 | **Usage:** 132 | 133 | ```php 134 | $this->table->hasTimestamps(); 135 | ``` 136 | 137 | **Returns:** `EGALL\EloquentPHPUnit\Database\Table` 138 | 139 | --- 140 | 141 | ##### resetTable($tableName) 142 | 143 | Using this method it is possible to test multiple tables in one test class. 144 | 145 | 146 | **Usage:** 147 | 148 | The usage code below is using a user/user-roles, example. The relationship is as follows: A user can have many role and a role can have many users (many-to-many). In eloquent, we would describe this relationship as a user `belongsToMany` roles through the user_role table and vice-versa. 149 | 150 | ```php 151 | 152 | protected $model = 'App\Role'; 153 | 154 | 155 | public function testDatabase() { 156 | 157 | // We are testing the roles table below 158 | $this->table->column('id')->increments(); 159 | $this->table->column('name')->string()->notNull()->unique(); 160 | $this->table->column('label')->string()->notNull(); 161 | $this->table->hasTimestamps(); 162 | 163 | // To switch to the user_role table we must reset the table. 164 | // You can method chain off of the resetTable() method as well. 165 | $this->resetTable('user_role'); 166 | 167 | // Begin testing user_role table like normal. 168 | $this->table->column('role_id')->integer()->primary()->foreign('roles'); 169 | $this->table->column('user_id')->integer()->primary()->foreign('roles'); 170 | $this->table->hasTimestamps(); 171 | 172 | 173 | } 174 | ``` 175 | 176 | **Returns:** `EGALL\EloquentPHPUnit\EloquentTestCase` / `$this` 177 | 178 | --- 179 | ### Model Testing Methods 180 | 181 | // TODO 182 | 183 | ## Example Model Test 184 | 185 | ```php 186 | Class UserModelTest extends \EGALL\EloquentPHPUnit\EloquentTestCase { 187 | 188 | protected $model = 'App\User'; 189 | 190 | // If you want to run the DatabaseSeeder class 191 | protected $seedDatabase = true; 192 | 193 | // If you only want to run a specific seeder 194 | protected $seeders = ['UsersTableSeeder', 'SchoolsTableSeeder']; 195 | 196 | // Change the default seeder that calls the rest of your seeders. 197 | // The default is the default Laravel Seeder named: DatabaseSeeder. 198 | // Ex. (You have a TestDatabaseSeeder and the default DatabaseSeeder). 199 | protected $defaultSeeder = 'TestDatabaseSeeder' 200 | 201 | /** 202 | * Test the database table. 203 | */ 204 | public function testDatabaseTable() { 205 | $this->table->column('id')->integer()->increments(); 206 | $this->table->column('name')->string()->nullable(); 207 | $this->table->column('email')->string()->notNullable()->unique(); 208 | $this->table->column('password')->string()->notNullable(); 209 | $this->table->column('dob')->date()->nullable(); 210 | $this->table->column('avatar_id')->integer()->foreign('images', 'id', $onUpdate = 'cascade', $onDelete = 'cascade'); 211 | $this->table->column('is_verified')->boolean()->defaults(false); 212 | $this->table->column('is_admin')->boolean()->defaults(false); 213 | $this->table->column('verification_sent_at')->dateTime()->nullable(); 214 | $this->table->column('invite_sent_at')->dateTime()->nullable(); 215 | $this->table->column('api_token')->string()->index(); 216 | $this->table->column('remember_token')->string()->nullable(); 217 | $this->table->hasTimestamps(); 218 | } 219 | 220 | /** 221 | * Test the model's properties. 222 | */ 223 | public function testModelProperties() { 224 | $this->hasFillable('name', 'email', 'password', 'dob', 'avatar_id') 225 | ->hasHidden('password', 'remember_token') 226 | ->hasCasts('is_verified', 'boolean') 227 | // or 228 | ->hasCasts(['is_verified' => 'boolean', 'is_admin' => 'boolean']) 229 | ->hasDates('verification_sent_at', 'invite_sent_at') 230 | ->belongsTo(Image::class) 231 | // if method name = 'image()' or 232 | ->belongsTo(Image::class, $customMethod = 'avatar') 233 | ->hasMany(Profile::class) 234 | ->morphsTo($method = 'slug', $morphTo = 'sluggable') 235 | // or: example below assumes the db fields are: 'sluggable_id' and 'sluggable_type' 236 | ->morphsTo('sluggable'); 237 | } 238 | } 239 | ``` 240 | 241 | ## Contributing 242 | 243 | 1. Fork it. 244 | 2. Create your branch: `git checkout -b my-new-feature` 245 | 3. Commit your changes: `git commit -am 'Add some feature'` 246 | 4. Push to the branch: `git push origin my-new-feature` 247 | 5. Submit a pull request. 248 | 249 | ## History 250 | 251 | - v1.0.0 Released: 8/5/2016 252 | - v1.0.3 Released: 8/9/2016 253 | - v1.0.6 Released: 9/21/2016 254 | 255 | ## Projects using Eloquent-PHPUnit 256 | 257 | - [Canvas ★803](https://github.com/austintoddj/canvas): A simple, powerful blog publishing platform built on top of Laravel 5 by [@austintoddj](https://github.com/austintoddj) 258 | 259 | ## Author 260 | 261 | - [Erik Galloway](https://github.com/erikgall) 262 | 263 | 264 | ## License 265 | 266 | Eloquent-PHPUnit is an open-sourced software licensed under the [MIT license](https://github.com/erikgall/eloquent-phpunit/blob/master/LICENSE). 267 | -------------------------------------------------------------------------------- /src/Database/Column.php: -------------------------------------------------------------------------------- 1 | 17 | */ 18 | class Column 19 | { 20 | /** 21 | * The test instance. 22 | * 23 | * @var EloquentTestCase 24 | */ 25 | protected $context; 26 | 27 | /** 28 | * The column's database data. 29 | * 30 | * @var array 31 | */ 32 | protected $data; 33 | 34 | /** 35 | * The table test case instance. 36 | * 37 | * @var \Doctrine\DBAL\Schema\Table 38 | */ 39 | protected $table; 40 | 41 | /** 42 | * The column name. 43 | * 44 | * @var string 45 | */ 46 | protected $name; 47 | 48 | /** 49 | * The column types array. 50 | * 51 | * @var array 52 | */ 53 | protected $types = [ 54 | 'boolean' => BooleanType::class, 55 | 'date' => DateType::class, 56 | 'dateTime' => DateTimeType::class, 57 | 'integer' => IntegerType::class, 58 | 'string' => StringType::class, 59 | 'text' => TextType::class, 60 | ]; 61 | 62 | /** 63 | * Table column test case constructor. 64 | * 65 | * @param \EGALL\EloquentPHPUnit\EloquentTestCase $context 66 | * @param \Doctrine\DBAL\Schema\Table $table 67 | * @param string $name 68 | */ 69 | public function __construct($context, $table, $name) 70 | { 71 | $this->context = $context; 72 | $this->table = $table; 73 | $this->name = $name; 74 | } 75 | 76 | /** 77 | * Assert that the table has a foreign key relationship. 78 | * 79 | * @param string $table 80 | * @param string $column 81 | * @param string $onUpdate 82 | * @param string $onDelete 83 | * @return $this 84 | */ 85 | public function foreign($table, $column = 'id', $onUpdate = 'cascade', $onDelete = 'cascade') 86 | { 87 | if (DB::connection() instanceof \Illuminate\Database\SQLiteConnection) { 88 | $this->context->markTestIncomplete('Foreign keys cannot be tested with a SQLite database.'); 89 | 90 | return $this; 91 | } 92 | 93 | $name = $this->getIndexName('foreign'); 94 | $this->assertTrue($this->table->hasForeignKey($name), "The foreign key {$name} does not exist."); 95 | 96 | $key = $this->table->getForeignKey($name); 97 | $onUpdate && $this->context->assertEquals(strtoupper($onUpdate), $key->onUpdate()); 98 | $onDelete && $this->context->assertEquals(strtoupper($onDelete), $key->onDelete()); 99 | 100 | $this->context->assertEquals($table, $key->getForeignTableName()); 101 | $this->context->assertContains($column, $key->getForeignColumns()); 102 | 103 | return $this; 104 | } 105 | 106 | /** 107 | * Get a data key by name. 108 | * 109 | * @param string $key 110 | * @return mixed 111 | */ 112 | public function get($key) 113 | { 114 | if (is_null($this->data)) { 115 | $this->data = $this->table->getColumn($this->name)->toArray(); 116 | } 117 | 118 | return $this->data[$key]; 119 | } 120 | 121 | /** 122 | * Test the default value. 123 | * 124 | * @param mixed 125 | * @return $this 126 | */ 127 | public function defaults($value) 128 | { 129 | $this->context->assertEquals( 130 | $value, $this->get('default'), "The default value ({$this->get('default')}) does not equal {$value}" 131 | ); 132 | 133 | return $this; 134 | } 135 | 136 | /** 137 | * Test that a column exists. 138 | * 139 | * @return $this 140 | */ 141 | public function exists() 142 | { 143 | $this->assertTrue( 144 | $this->table->hasColumn($this->name), "The table column `{$this->name}` does not exist." 145 | ); 146 | 147 | return $this; 148 | } 149 | 150 | /** 151 | * Assert that the column is auto-incremented. 152 | * 153 | * @return $this 154 | */ 155 | public function increments() 156 | { 157 | $message = "The column {$this->name} is not auto-incremented."; 158 | 159 | return $this->integer()->assertTrue($this->get('autoincrement'), $message)->primary(); 160 | } 161 | 162 | /** 163 | * Assert that the column is indexed. 164 | * 165 | * @return $this 166 | */ 167 | public function index() 168 | { 169 | $index = $this->getIndexName(); 170 | 171 | $this->assertTrue( 172 | $this->table->hasIndex($index), "The {$this->name} column is not indexed." 173 | ); 174 | 175 | $this->assertTrue( 176 | $this->table->getIndex($index)->isSimpleIndex(), "The {$this->name} column is not a simple index." 177 | ); 178 | } 179 | 180 | /** 181 | * Assert a column is of a certain type. 182 | * 183 | * @return $this 184 | */ 185 | public function ofType($type) 186 | { 187 | $this->context->assertInstanceOf( 188 | $type, $this->get('type'), "The {$this->name} column is not of type {$type}" 189 | ); 190 | 191 | return $this; 192 | } 193 | 194 | /** 195 | * Assert that the column is a primary key. 196 | * 197 | * @return $this 198 | */ 199 | public function primary() 200 | { 201 | $key = $this->tableHasPrimary()->getPrimaryKey(); 202 | $message = "The column {$this->name} is not a primary key."; 203 | 204 | return $this->assertTrue(in_array($this->name, $key->getColumns()), $message) 205 | ->assertTrue($key->isPrimary()) 206 | ->assertTrue($key->isUnique()); 207 | } 208 | 209 | /** 210 | * Assert that the column has a unique index. 211 | * 212 | * @return $this 213 | */ 214 | public function unique() 215 | { 216 | $this->assertUniqueIndex($this->getIndexName('unique'), $this->table->getIndexes()); 217 | } 218 | 219 | public function __call($method, $args) 220 | { 221 | if (method_exists($this, $method)) { 222 | return $this->$method($args); 223 | } 224 | 225 | return $this->assertColumn($method, $args); 226 | } 227 | 228 | /** 229 | * Assert the column is nullable. 230 | * 231 | * @param bool $negate 232 | * @return $this 233 | */ 234 | protected function assertNullable($negate = false) 235 | { 236 | if ($negate) { 237 | return $this->assertTrue($this->get('notnull'), "The table column `{$this->name}` is nullable"); 238 | } 239 | 240 | return $this->assertFalse($this->get('notnull'), "The table column `{$this->name}` is not nullable"); 241 | } 242 | 243 | /** 244 | * Call a column assertion method. 245 | * 246 | * @param string $method 247 | * @param array $args 248 | * @return $this 249 | */ 250 | protected function assertColumn($method, $args) 251 | { 252 | if (array_key_exists($method, $this->types)) { 253 | return $this->ofType($this->types[$method]); 254 | } 255 | 256 | if (str_contains($method, ['default', 'Default'])) { 257 | return $this->defaults($args[0]); 258 | } 259 | 260 | if (str_contains($method, ['null', 'Null'])) { 261 | return $this->assertNullable(str_contains($method, 'not')); 262 | } 263 | 264 | throw new \Exception("The database table column assertion {$method} does not exist."); 265 | } 266 | 267 | /** 268 | * Assert a condition is false alias. 269 | * 270 | * @param bool $condition 271 | * @param string|null $message 272 | * @return $this 273 | */ 274 | protected function assertFalse($condition, $message = null) 275 | { 276 | $this->context->assertFalse($condition, $message); 277 | 278 | return $this; 279 | } 280 | 281 | /** 282 | * Assert a condition is true alias. 283 | * 284 | * @param bool $condition 285 | * @param string|null $message 286 | * @return $this 287 | */ 288 | protected function assertTrue($condition, $message = null) 289 | { 290 | $this->context->assertTrue($condition, $message); 291 | 292 | return $this; 293 | } 294 | 295 | /** 296 | * Assert a key is a unique index. 297 | * 298 | * @param string $key 299 | * @param array $indexes 300 | * @return void 301 | */ 302 | protected function assertUniqueIndex($key, $indexes) 303 | { 304 | $this->context->assertArrayHasKey($key, $indexes, "The {$this->name} column is not indexed."); 305 | $this->assertTrue($indexes[$key]->isUnique(), "The {$this->name} is not a unique index."); 306 | } 307 | 308 | /** 309 | * Get the column's index key/name. 310 | * 311 | * @param string $suffix 312 | * @return string 313 | */ 314 | protected function getIndexName($suffix = 'index') 315 | { 316 | return "{$this->table->getName()}_{$this->name}_{$suffix}"; 317 | } 318 | 319 | /** 320 | * Assert the table has a primary key. 321 | * 322 | * @param \Doctrine\DBAL\Schema\Table $table 323 | * @return $this 324 | */ 325 | protected function tableHasPrimary() 326 | { 327 | $this->assertTrue( 328 | $this->table->hasPrimaryKey(), "The table {$this->table->getName()} does not have a primary key." 329 | ); 330 | 331 | return $this->table; 332 | } 333 | } 334 | -------------------------------------------------------------------------------- /src/Database/Table.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | class Table 14 | { 15 | /** 16 | * The database table instance. 17 | * 18 | * @var \Doctrine\DBAL\Schema\Table 19 | */ 20 | public $table; 21 | 22 | /** 23 | * The test instance. 24 | * 25 | * @var EloquentTestCase 26 | */ 27 | protected $context; 28 | 29 | /** 30 | * The database table name. 31 | * 32 | * @var string 33 | */ 34 | protected $name; 35 | 36 | /** 37 | * Table test case constructor. 38 | * 39 | * @param EloquentTestCase $context 40 | * @param string $name 41 | */ 42 | public function __construct($context, $name) 43 | { 44 | $this->context = $context; 45 | $this->name = $name; 46 | } 47 | 48 | /** 49 | * Get a column test case instance. 50 | * 51 | * @param string $column 52 | * @return \EGALL\EloquentPHPUnit\Database\TableColumnTestCase 53 | */ 54 | public function column($column) 55 | { 56 | return $this->tableColumn($column)->exists(); 57 | } 58 | 59 | /** 60 | * Assert that the table exists in the database. 61 | * 62 | * @return $this 63 | */ 64 | public function exists() 65 | { 66 | $this->context->assertTrue(Schema::hasTable($this->name), "The table {$this->name} does not exist."); 67 | 68 | return $this; 69 | } 70 | 71 | /** 72 | * Get the table name. 73 | * 74 | * @return string 75 | */ 76 | public function getName() 77 | { 78 | return $this->table->getName(); 79 | } 80 | 81 | /** 82 | * Assert the table has timestamp columns. 83 | * 84 | * @return $this 85 | */ 86 | public function hasTimestamps() 87 | { 88 | $this->column('created_at')->dateTime()->nullable(); 89 | $this->column('updated_at')->dateTime()->nullable(); 90 | 91 | return $this; 92 | } 93 | 94 | /** 95 | * Get a column's test case instance. 96 | * 97 | * @param $column 98 | * @return \EGALL\EloquentPHPUnit\Database\TableColumnTestCase 99 | */ 100 | protected function tableColumn($column) 101 | { 102 | if (is_null($this->table)) { 103 | $this->setTable(); 104 | } 105 | 106 | return new Column($this->context, $this->table, $column); 107 | } 108 | 109 | /** 110 | * Set the table details instance. 111 | */ 112 | protected function setTable() 113 | { 114 | $this->table = DB::getDoctrineSchemaManager()->listTableDetails($this->name); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /src/DatabaseTestHelper.php: -------------------------------------------------------------------------------- 1 | 11 | */ 12 | trait DatabaseTestHelper 13 | { 14 | use DatabaseTransactions; 15 | 16 | /** 17 | * Run the test database migrations. 18 | * 19 | * @return $this 20 | */ 21 | public function runDatabaseMigrations() 22 | { 23 | $this->artisan('migrate'); 24 | 25 | $this->beforeApplicationDestroyed(function () { 26 | $this->artisan('migrate:reset'); 27 | }); 28 | 29 | return $this; 30 | } 31 | 32 | /** 33 | * Get the default seeder class name. 34 | * 35 | * @return string 36 | */ 37 | protected function getDefaultSeeder() 38 | { 39 | if (property_exists($this, 'defaultSeeder')) { 40 | return $this->defaultSeeder; 41 | } 42 | 43 | return 'DatabaseSeeder'; 44 | } 45 | 46 | /** 47 | * Get the database seeders. 48 | * 49 | * @return array 50 | */ 51 | protected function getSeeders() 52 | { 53 | if (property_exists($this, 'seeders')) { 54 | return $this->seeders; 55 | } 56 | 57 | return [$this->getDefaultSeeder()]; 58 | } 59 | 60 | /** 61 | * Run the app's database seeders. 62 | * 63 | * @return void 64 | */ 65 | protected function runDatabaseSeeders() 66 | { 67 | foreach ($this->getSeeders() as $seeder) { 68 | $this->seed($seeder); 69 | } 70 | } 71 | 72 | /** 73 | * Setup the database before the tests. 74 | * 75 | * @return void 76 | */ 77 | protected function setUp() 78 | { 79 | parent::setUp(); 80 | 81 | $this->setUpDatabase(); 82 | } 83 | 84 | /** 85 | * Check if we should seed the database and call the seeders. 86 | * 87 | * @return void 88 | */ 89 | protected function seedDatabase() 90 | { 91 | if ($this->shouldSeedDatabase()) { 92 | $this->runDatabaseSeeders(); 93 | } 94 | } 95 | 96 | /** 97 | * Setup the database. 98 | * 99 | * @return void 100 | */ 101 | protected function setUpDatabase() 102 | { 103 | $this->runDatabaseMigrations()->seedDatabase(); 104 | } 105 | 106 | /** 107 | * Should the database seeders be run. 108 | * 109 | * @return bool 110 | */ 111 | protected function shouldSeedDatabase() 112 | { 113 | if (property_exists($this, 'seedDatabase')) { 114 | return $this->seedDatabase; 115 | } 116 | 117 | return true; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/EloquentTestCase.php: -------------------------------------------------------------------------------- 1 | 12 | */ 13 | class EloquentTestCase extends LaravelTestCase 14 | { 15 | use DatabaseTestHelper, ModelTestHelper, RelationshipTestHelper; 16 | 17 | /** 18 | * The base URL to use while testing the application. 19 | * 20 | * @var string 21 | */ 22 | protected $baseUrl = 'http://localhost'; 23 | 24 | /** 25 | * The subject's data. 26 | * 27 | * @var array 28 | */ 29 | protected $data = [ 30 | 'casts' => null, 31 | 'dates' => null, 32 | 'fillable' => null, 33 | 'hidden' => null, 34 | 'table' => null, 35 | ]; 36 | 37 | /** 38 | * The test subject. 39 | * 40 | * @var \Illuminate\Database\Eloquent\Model 41 | */ 42 | protected $subject; 43 | 44 | /** 45 | * Creates the application. 46 | * 47 | * @return \Illuminate\Foundation\Application 48 | */ 49 | public function createApplication() 50 | { 51 | $app = require $this->getBootstrapFilePath(); 52 | 53 | $app->make(\Illuminate\Contracts\Console\Kernel::class)->bootstrap(); 54 | 55 | return $app; 56 | } 57 | 58 | /** 59 | * Reset the table to a new testable table. 60 | * 61 | * @param string $tableName 62 | * @return $this 63 | */ 64 | public function resetTable($tableName) 65 | { 66 | $this->tableName = $tableName; 67 | 68 | $this->data['table'] = null; 69 | 70 | return $this; 71 | } 72 | 73 | /** 74 | * Set the test data. 75 | * 76 | * @before 77 | * @return void 78 | */ 79 | public function setUpEloquentModel() 80 | { 81 | $this->subject = new $this->model(); 82 | 83 | $this->setTable(); 84 | } 85 | 86 | /** 87 | * Get the table test case instance. 88 | * 89 | * @return TableTestCase 90 | */ 91 | public function table() 92 | { 93 | if (is_null($this->data['table'])) { 94 | $this->data['table'] = (new Table($this, $this->tableName))->exists(); 95 | } 96 | 97 | return $this->data['table']; 98 | } 99 | 100 | /** 101 | * Allow access to some methods as properties. 102 | * 103 | * @param string $key 104 | * @return mixed 105 | */ 106 | public function __get($key) 107 | { 108 | if (array_key_exists($key, $this->data)) { 109 | return $this->getKey($key); 110 | } elseif (property_exists($this, $key)) { 111 | return $this->{$key}; 112 | } 113 | } 114 | 115 | /** 116 | * Get the applications bootstrap file path. 117 | * 118 | * @return string 119 | */ 120 | protected function getBootstrapFilePath() 121 | { 122 | return __DIR__.'/../../../../bootstrap/app.php'; 123 | } 124 | 125 | /** 126 | * Get a data item by key. 127 | * 128 | * @param string $key 129 | * @return mixed 130 | */ 131 | protected function getKey($key) 132 | { 133 | if (method_exists($this, $key)) { 134 | return $this->$key(); 135 | } 136 | 137 | return $this->data[$key]; 138 | } 139 | 140 | /** 141 | * Set the model's database table. 142 | * 143 | * @return void 144 | */ 145 | protected function setTable() 146 | { 147 | if (! property_exists($this, 'tableName')) { 148 | $this->tableName = $this->subject->getTable(); 149 | } 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /src/ModelTestHelper.php: -------------------------------------------------------------------------------- 1 | 9 | */ 10 | trait ModelTestHelper 11 | { 12 | /** 13 | * Assert that fields exist with in an array. 14 | * 15 | * @param array $expected 16 | * @param array $actual 17 | * @param string $array 18 | * @return $this 19 | */ 20 | public function hasAttributes(array $expected, array $actual, $array) 21 | { 22 | foreach ($expected as $field) { 23 | $this->assertTrue( 24 | in_array($field, $actual), "The {$field} attribute was not found in the {$array} array" 25 | ); 26 | } 27 | 28 | return $this; 29 | } 30 | 31 | /** 32 | * Assert the model casts fields to their native type. 33 | * 34 | * @param string|array 35 | * @param string|null 36 | * @return $this 37 | */ 38 | public function hasCasts() 39 | { 40 | if (count($args = func_get_args()) == 2) { 41 | $casts = [$args[0] => $args[1]]; 42 | } elseif (is_array($args[0])) { 43 | $casts = $args[0]; 44 | } 45 | 46 | foreach ($casts as $field => $type) { 47 | $this->assertArrayHasKey($field, $this->casts, "The {$field} attribute is not located in the casts array."); 48 | $this->assertEquals($type, $this->casts[$field]); 49 | } 50 | 51 | return $this; 52 | } 53 | 54 | /** 55 | * Assert the model casts the attributes to a carbon instance. 56 | * 57 | * @param array|string $dates 58 | * @param string|bool|null $timestamps 59 | * @return $this 60 | */ 61 | public function hasDates($dates = [], $timestamps = true) 62 | { 63 | if (func_num_args() > 2) { 64 | $dates = func_get_args(); 65 | $timestamps = true; 66 | } 67 | 68 | if (is_string($dates)) { 69 | $dates = (array) $dates; 70 | } 71 | 72 | $fields = $timestamps ? array_merge($dates, ['created_at', 'updated_at']) : $dates; 73 | 74 | return $this->hasAttributes($fields, $this->dates, 'dates'); 75 | } 76 | 77 | /** 78 | * Assert the model has the fillable fields. 79 | * 80 | * @return $this 81 | */ 82 | public function hasFillable() 83 | { 84 | $fields = func_get_args(); 85 | 86 | if (count($fields) == 1) { 87 | $fields = $fields[0]; 88 | } 89 | 90 | return $this->hasAttributes($fields, $this->fillable, 'fillable'); 91 | } 92 | 93 | /** 94 | * Assert that a model has the hidden fields. 95 | * 96 | * @return $this 97 | */ 98 | public function hasHidden() 99 | { 100 | $fields = func_get_args(); 101 | if (count($fields) == 1) { 102 | $fields = is_array($fields[0]) ? $fields[0] : (array) $fields[0]; 103 | } 104 | 105 | return $this->hasAttributes($fields, $this->hidden, 'hidden'); 106 | } 107 | 108 | /** 109 | * Get the model's casts' array. 110 | * 111 | * @return array 112 | */ 113 | protected function casts() 114 | { 115 | return $this->dataKey('casts'); 116 | } 117 | 118 | /** 119 | * Get the model's dates array. 120 | * 121 | * @return array 122 | */ 123 | protected function dates() 124 | { 125 | return $this->dataKey('dates'); 126 | } 127 | 128 | /** 129 | * Get a data key by name. 130 | * 131 | * @param string $key 132 | * @return array|string 133 | */ 134 | protected function dataKey($key) 135 | { 136 | if ($this->keyNeedsSet($key)) { 137 | $method = 'get'.ucfirst($key); 138 | 139 | $this->data[$key] = $this->subject->$method(); 140 | } 141 | 142 | return $this->data[$key]; 143 | } 144 | 145 | /** 146 | * Get the model's fillable attributes array. 147 | * 148 | * @return array 149 | */ 150 | protected function fillable() 151 | { 152 | return $this->dataKey('fillable'); 153 | } 154 | 155 | /** 156 | * Get the model's hidden attributes array. 157 | * 158 | * @return array 159 | */ 160 | protected function hidden() 161 | { 162 | return $this->dataKey('hidden'); 163 | } 164 | 165 | /** 166 | * Check if a key in the data array is null. 167 | * 168 | * @param string $key 169 | * @return bool 170 | */ 171 | protected function keyNeedsSet($key) 172 | { 173 | return is_null($this->data[$key]); 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /src/RelationshipTestHelper.php: -------------------------------------------------------------------------------- 1 | 16 | */ 17 | trait RelationshipTestHelper 18 | { 19 | /** 20 | * Assert the subject has a relationship with another model. 21 | * 22 | * @param string $relationship 23 | * @param string $model 24 | * @param string $method 25 | * @return $this 26 | */ 27 | public function assertHasRelationship($relationship, $model, $method) 28 | { 29 | $this->assertInstanceOf($relationship, $this->subject->{$method}()); 30 | $this->assertInstanceOf($model, $this->subject->{$method}()->getModel()); 31 | 32 | return $this; 33 | } 34 | 35 | /** 36 | * Assert the model has a belongs to relationship. 37 | * 38 | * @param string $model 39 | * @param string|null $name 40 | * @return $this 41 | */ 42 | public function belongsTo($model, $name = null) 43 | { 44 | $method = $name ?: $this->getRelationshipMethodName($model); 45 | 46 | return $this->assertHasRelationship(BelongsTo::class, $model, $method); 47 | } 48 | 49 | /** 50 | * Assert the model has a belongs to many relationship. 51 | * 52 | * @param string $class 53 | * @param null $method 54 | * @return $this 55 | */ 56 | public function belongsToMany($model, $name = null) 57 | { 58 | $method = $name ?: $this->getRelationshipMethodName($model, false); 59 | 60 | return $this->assertHasRelationship(BelongsToMany::class, $model, $method); 61 | } 62 | 63 | /** 64 | * Assert the model has a has many relationship. 65 | * 66 | * @param string $model 67 | * @param string|null $name 68 | * @return bool 69 | */ 70 | public function hasMany($model, $name = null) 71 | { 72 | return $this->assertHasRelationship( 73 | HasMany::class, $model, $name ?: $this->getRelationshipMethodName($model, false) 74 | ); 75 | } 76 | 77 | /** 78 | * Assert the model has a has one relationship. 79 | * 80 | * @param string $model 81 | * @param string|null $name 82 | * @return bool 83 | */ 84 | public function hasOne($model, $name = null) 85 | { 86 | return $this->assertHasRelationship( 87 | HasOne::class, $model, $name ?: $this->getRelationshipMethodName($model, false) 88 | ); 89 | } 90 | 91 | /** 92 | * Assert the model has a morphs to relationship. 93 | * 94 | * @param string $method 95 | * @param string|null 96 | * @return $this 97 | */ 98 | public function morphsTo($method, $morphTo = null) 99 | { 100 | $this->assertInstanceOf(MorphTo::class, $this->subject->$method()); 101 | $this->assertEquals($this->subject->$method()->getMorphType(), ($morphTo ?: $method).'_type'); 102 | 103 | return $this; 104 | } 105 | 106 | /** 107 | * Assert the model has a morph many relationship. 108 | * 109 | * @param string $method 110 | * @param string|null 111 | * @return $this 112 | */ 113 | public function morphMany($model, $name = null) 114 | { 115 | return $this->assertHasRelationship( 116 | MorphMany::class, $model, $name ?: $this->getRelationshipMethodName($model, false) 117 | ); 118 | } 119 | 120 | /** 121 | * Get a relationship's method name. 122 | * 123 | * @param string $model 124 | * @param bool $singular 125 | * @return string 126 | */ 127 | protected function getRelationshipMethodName($model, $singular = true) 128 | { 129 | $name = camel_case(class_basename($model)); 130 | 131 | return $singular ? $name : str_plural($name); 132 | } 133 | } 134 | --------------------------------------------------------------------------------