├── .github ├── ISSUE_TEMPLATE.md └── release_drafter.yml ├── .gitignore ├── .travis.yml ├── LICENSE ├── composer.json ├── composer.lock ├── phpspec.yml ├── readme.md ├── spec └── Migrations │ ├── NameParserSpec.php │ ├── SchemaParserSpec.php │ └── SyntaxBuilderSpec.php └── src ├── Commands ├── MigrationMakeCommand.php └── PivotMigrationMakeCommand.php ├── GeneratorException.php ├── GeneratorsServiceProvider.php ├── Migrations ├── NameParser.php ├── SchemaParser.php └── SyntaxBuilder.php └── stubs ├── migration.stub ├── pivot.stub ├── schema-change.stub └── schema-create.stub /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | - Laravel Version: #.#.# 2 | - PHP Version: 3 | - Laravel-5-Generators-Extended Version: 4 | - Command: 5 | 6 | ### What I did 7 | 8 | ?? 9 | 10 | ### What I expected to happen 11 | 12 | ?? 13 | 14 | ### What happened 15 | 16 | ?? 17 | 18 | ### What I've already tried to fix it 19 | 20 | ?? 21 | -------------------------------------------------------------------------------- /.github/release_drafter.yml: -------------------------------------------------------------------------------- 1 | name: Release Drafter 2 | uses: release-drafter/release-drafter@v5.11.0 3 | 4 | on: 5 | push: 6 | # branches to consider in the event; optional, defaults to all 7 | branches: 8 | - master 9 | 10 | jobs: 11 | update_release_draft: 12 | runs-on: ubuntu-latest 13 | steps: 14 | # Drafts your next Release notes as Pull Requests are merged into "master" 15 | - uses: release-drafter/release-drafter@v5 16 | env: 17 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 18 | 19 | name-template: '$NEXT_PATCH_VERSION 🌈' 20 | tag-template: '$NEXT_PATCH_VERSION' 21 | categories: 22 | - title: '🚀 Features' 23 | labels: 24 | - 'feature' 25 | - 'enhancement' 26 | - 'added' 27 | - title: '🐛 Bug Fixes' 28 | labels: 29 | - 'fix' 30 | - 'bugfix' 31 | - 'bug' 32 | - 'fixed' 33 | - title: '⚙️ Changes' 34 | labels: 35 | - 'changed' 36 | - 'dependencies' 37 | - title: '🧰 Removed' 38 | label: 'removed' 39 | change-template: '- $TITLE (#$NUMBER - thanks to @$AUTHOR)' 40 | template: | 41 | ## Changes 42 | $CHANGES 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | vendor 2 | .idea -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 7.2 5 | - 7.3 6 | - 7.4 7 | - 8.0 8 | - nightly 9 | 10 | matrix: 11 | allow_failures: 12 | - php: nightly 13 | - php: 8.0 14 | 15 | before_script: 16 | - composer self-update 17 | - composer install --prefer-source --no-interaction --dev 18 | 19 | script: 20 | - vendor/bin/phpspec run 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Jeffrey Way 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 13 | all 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 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "laracasts/generators", 3 | "description": "Advanced Laravel generators, that include schema information.", 4 | "keywords": ["laravel", "generators"], 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Jeffrey Way", 9 | "email": "jeffrey@laracasts.com" 10 | }, 11 | { 12 | "name": "Cristian Tabacitu", 13 | "email": "hello@tabaciu.ro" 14 | } 15 | ], 16 | "require": { 17 | "illuminate/support": "~6.0|~7.0|~8.0|~9.0|^10.0" 18 | }, 19 | "require-dev": { 20 | "phpspec/phpspec": "~6.0" 21 | }, 22 | "autoload": { 23 | "psr-4": { 24 | "Laracasts\\Generators\\": "src/" 25 | } 26 | }, 27 | "scripts": { 28 | "test": "vendor/bin/phpspec run" 29 | }, 30 | "extra": { 31 | "laravel": { 32 | "providers": [ 33 | "Laracasts\\Generators\\GeneratorsServiceProvider" 34 | ] 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /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#installing-dependencies", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "2b747f77c7d7f2906cbd968c1819a522", 8 | "packages": [ 9 | { 10 | "name": "doctrine/inflector", 11 | "version": "2.0.3", 12 | "source": { 13 | "type": "git", 14 | "url": "https://github.com/doctrine/inflector.git", 15 | "reference": "9cf661f4eb38f7c881cac67c75ea9b00bf97b210" 16 | }, 17 | "dist": { 18 | "type": "zip", 19 | "url": "https://api.github.com/repos/doctrine/inflector/zipball/9cf661f4eb38f7c881cac67c75ea9b00bf97b210", 20 | "reference": "9cf661f4eb38f7c881cac67c75ea9b00bf97b210", 21 | "shasum": "" 22 | }, 23 | "require": { 24 | "php": "^7.2 || ^8.0" 25 | }, 26 | "require-dev": { 27 | "doctrine/coding-standard": "^7.0", 28 | "phpstan/phpstan": "^0.11", 29 | "phpstan/phpstan-phpunit": "^0.11", 30 | "phpstan/phpstan-strict-rules": "^0.11", 31 | "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" 32 | }, 33 | "type": "library", 34 | "extra": { 35 | "branch-alias": { 36 | "dev-master": "2.0.x-dev" 37 | } 38 | }, 39 | "autoload": { 40 | "psr-4": { 41 | "Doctrine\\Inflector\\": "lib/Doctrine/Inflector" 42 | } 43 | }, 44 | "notification-url": "https://packagist.org/downloads/", 45 | "license": [ 46 | "MIT" 47 | ], 48 | "authors": [ 49 | { 50 | "name": "Guilherme Blanco", 51 | "email": "guilhermeblanco@gmail.com" 52 | }, 53 | { 54 | "name": "Roman Borschel", 55 | "email": "roman@code-factory.org" 56 | }, 57 | { 58 | "name": "Benjamin Eberlei", 59 | "email": "kontakt@beberlei.de" 60 | }, 61 | { 62 | "name": "Jonathan Wage", 63 | "email": "jonwage@gmail.com" 64 | }, 65 | { 66 | "name": "Johannes Schmitt", 67 | "email": "schmittjoh@gmail.com" 68 | } 69 | ], 70 | "description": "PHP Doctrine Inflector is a small library that can perform string manipulations with regard to upper/lowercase and singular/plural forms of words.", 71 | "homepage": "https://www.doctrine-project.org/projects/inflector.html", 72 | "keywords": [ 73 | "inflection", 74 | "inflector", 75 | "lowercase", 76 | "manipulation", 77 | "php", 78 | "plural", 79 | "singular", 80 | "strings", 81 | "uppercase", 82 | "words" 83 | ], 84 | "funding": [ 85 | { 86 | "url": "https://www.doctrine-project.org/sponsorship.html", 87 | "type": "custom" 88 | }, 89 | { 90 | "url": "https://www.patreon.com/phpdoctrine", 91 | "type": "patreon" 92 | }, 93 | { 94 | "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finflector", 95 | "type": "tidelift" 96 | } 97 | ], 98 | "time": "2020-05-29T15:13:26+00:00" 99 | }, 100 | { 101 | "name": "illuminate/collections", 102 | "version": "v8.0.3", 103 | "source": { 104 | "type": "git", 105 | "url": "https://github.com/illuminate/collections.git", 106 | "reference": "446310d53bf58905bf2fb0152d9df9a169fc3aa9" 107 | }, 108 | "dist": { 109 | "type": "zip", 110 | "url": "https://api.github.com/repos/illuminate/collections/zipball/446310d53bf58905bf2fb0152d9df9a169fc3aa9", 111 | "reference": "446310d53bf58905bf2fb0152d9df9a169fc3aa9", 112 | "shasum": "" 113 | }, 114 | "require": { 115 | "illuminate/contracts": "^8.0", 116 | "illuminate/macroable": "^8.0", 117 | "php": "^7.3" 118 | }, 119 | "type": "library", 120 | "extra": { 121 | "branch-alias": { 122 | "dev-master": "8.x-dev" 123 | } 124 | }, 125 | "autoload": { 126 | "psr-4": { 127 | "Illuminate\\Support\\": "" 128 | }, 129 | "files": [ 130 | "helpers.php" 131 | ] 132 | }, 133 | "notification-url": "https://packagist.org/downloads/", 134 | "license": [ 135 | "MIT" 136 | ], 137 | "authors": [ 138 | { 139 | "name": "Taylor Otwell", 140 | "email": "taylor@laravel.com" 141 | } 142 | ], 143 | "description": "The Illuminate Collections package.", 144 | "homepage": "https://laravel.com", 145 | "time": "2020-09-08T12:37:36+00:00" 146 | }, 147 | { 148 | "name": "illuminate/contracts", 149 | "version": "v8.0.3", 150 | "source": { 151 | "type": "git", 152 | "url": "https://github.com/illuminate/contracts.git", 153 | "reference": "8420ad4a55c85a106d560408239fd72a64057df6" 154 | }, 155 | "dist": { 156 | "type": "zip", 157 | "url": "https://api.github.com/repos/illuminate/contracts/zipball/8420ad4a55c85a106d560408239fd72a64057df6", 158 | "reference": "8420ad4a55c85a106d560408239fd72a64057df6", 159 | "shasum": "" 160 | }, 161 | "require": { 162 | "php": "^7.3", 163 | "psr/container": "^1.0", 164 | "psr/simple-cache": "^1.0" 165 | }, 166 | "type": "library", 167 | "extra": { 168 | "branch-alias": { 169 | "dev-master": "8.x-dev" 170 | } 171 | }, 172 | "autoload": { 173 | "psr-4": { 174 | "Illuminate\\Contracts\\": "" 175 | } 176 | }, 177 | "notification-url": "https://packagist.org/downloads/", 178 | "license": [ 179 | "MIT" 180 | ], 181 | "authors": [ 182 | { 183 | "name": "Taylor Otwell", 184 | "email": "taylor@laravel.com" 185 | } 186 | ], 187 | "description": "The Illuminate Contracts package.", 188 | "homepage": "https://laravel.com", 189 | "time": "2020-09-08T11:21:59+00:00" 190 | }, 191 | { 192 | "name": "illuminate/macroable", 193 | "version": "v8.0.3", 194 | "source": { 195 | "type": "git", 196 | "url": "https://github.com/illuminate/macroable.git", 197 | "reference": "561442f134eaf4d3f710bf523ecfe1537fa53f64" 198 | }, 199 | "dist": { 200 | "type": "zip", 201 | "url": "https://api.github.com/repos/illuminate/macroable/zipball/561442f134eaf4d3f710bf523ecfe1537fa53f64", 202 | "reference": "561442f134eaf4d3f710bf523ecfe1537fa53f64", 203 | "shasum": "" 204 | }, 205 | "require": { 206 | "php": "^7.3" 207 | }, 208 | "type": "library", 209 | "extra": { 210 | "branch-alias": { 211 | "dev-master": "8.x-dev" 212 | } 213 | }, 214 | "autoload": { 215 | "psr-4": { 216 | "Illuminate\\Support\\": "" 217 | } 218 | }, 219 | "notification-url": "https://packagist.org/downloads/", 220 | "license": [ 221 | "MIT" 222 | ], 223 | "authors": [ 224 | { 225 | "name": "Taylor Otwell", 226 | "email": "taylor@laravel.com" 227 | } 228 | ], 229 | "description": "The Illuminate Macroable package.", 230 | "homepage": "https://laravel.com", 231 | "time": "2020-06-08T14:13:16+00:00" 232 | }, 233 | { 234 | "name": "illuminate/support", 235 | "version": "v8.0.3", 236 | "source": { 237 | "type": "git", 238 | "url": "https://github.com/illuminate/support.git", 239 | "reference": "a7499132c366cf1c8ddfe6f26bba603767b1b560" 240 | }, 241 | "dist": { 242 | "type": "zip", 243 | "url": "https://api.github.com/repos/illuminate/support/zipball/a7499132c366cf1c8ddfe6f26bba603767b1b560", 244 | "reference": "a7499132c366cf1c8ddfe6f26bba603767b1b560", 245 | "shasum": "" 246 | }, 247 | "require": { 248 | "doctrine/inflector": "^1.4|^2.0", 249 | "ext-json": "*", 250 | "ext-mbstring": "*", 251 | "illuminate/collections": "^8.0", 252 | "illuminate/contracts": "^8.0", 253 | "illuminate/macroable": "^8.0", 254 | "nesbot/carbon": "^2.17", 255 | "php": "^7.3", 256 | "voku/portable-ascii": "^1.4.8" 257 | }, 258 | "conflict": { 259 | "tightenco/collect": "<5.5.33" 260 | }, 261 | "suggest": { 262 | "illuminate/filesystem": "Required to use the composer class (^8.0).", 263 | "ramsey/uuid": "Required to use Str::uuid() (^4.0).", 264 | "symfony/process": "Required to use the composer class (^5.1).", 265 | "symfony/var-dumper": "Required to use the dd function (^5.1).", 266 | "vlucas/phpdotenv": "Required to use the Env class and env helper (^5.0)." 267 | }, 268 | "type": "library", 269 | "extra": { 270 | "branch-alias": { 271 | "dev-master": "8.x-dev" 272 | } 273 | }, 274 | "autoload": { 275 | "psr-4": { 276 | "Illuminate\\Support\\": "" 277 | }, 278 | "files": [ 279 | "helpers.php" 280 | ] 281 | }, 282 | "notification-url": "https://packagist.org/downloads/", 283 | "license": [ 284 | "MIT" 285 | ], 286 | "authors": [ 287 | { 288 | "name": "Taylor Otwell", 289 | "email": "taylor@laravel.com" 290 | } 291 | ], 292 | "description": "The Illuminate Support package.", 293 | "homepage": "https://laravel.com", 294 | "time": "2020-09-09T15:54:22+00:00" 295 | }, 296 | { 297 | "name": "nesbot/carbon", 298 | "version": "2.39.2", 299 | "source": { 300 | "type": "git", 301 | "url": "https://github.com/briannesbitt/Carbon.git", 302 | "reference": "326efde1bc09077a26cb77f6e2e32e13f06c27f2" 303 | }, 304 | "dist": { 305 | "type": "zip", 306 | "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/326efde1bc09077a26cb77f6e2e32e13f06c27f2", 307 | "reference": "326efde1bc09077a26cb77f6e2e32e13f06c27f2", 308 | "shasum": "" 309 | }, 310 | "require": { 311 | "ext-json": "*", 312 | "php": "^7.1.8 || ^8.0", 313 | "symfony/polyfill-mbstring": "^1.0", 314 | "symfony/translation": "^3.4 || ^4.0 || ^5.0" 315 | }, 316 | "require-dev": { 317 | "doctrine/orm": "^2.7", 318 | "friendsofphp/php-cs-fixer": "^2.14 || ^3.0", 319 | "kylekatarnls/multi-tester": "^2.0", 320 | "phpmd/phpmd": "^2.9", 321 | "phpstan/extension-installer": "^1.0", 322 | "phpstan/phpstan": "^0.12.35", 323 | "phpunit/phpunit": "^7.5 || ^8.0", 324 | "squizlabs/php_codesniffer": "^3.4" 325 | }, 326 | "bin": [ 327 | "bin/carbon" 328 | ], 329 | "type": "library", 330 | "extra": { 331 | "branch-alias": { 332 | "dev-master": "2.x-dev", 333 | "dev-3.x": "3.x-dev" 334 | }, 335 | "laravel": { 336 | "providers": [ 337 | "Carbon\\Laravel\\ServiceProvider" 338 | ] 339 | }, 340 | "phpstan": { 341 | "includes": [ 342 | "extension.neon" 343 | ] 344 | } 345 | }, 346 | "autoload": { 347 | "psr-4": { 348 | "Carbon\\": "src/Carbon/" 349 | } 350 | }, 351 | "notification-url": "https://packagist.org/downloads/", 352 | "license": [ 353 | "MIT" 354 | ], 355 | "authors": [ 356 | { 357 | "name": "Brian Nesbitt", 358 | "email": "brian@nesbot.com", 359 | "homepage": "http://nesbot.com" 360 | }, 361 | { 362 | "name": "kylekatarnls", 363 | "homepage": "http://github.com/kylekatarnls" 364 | } 365 | ], 366 | "description": "An API extension for DateTime that supports 281 different languages.", 367 | "homepage": "http://carbon.nesbot.com", 368 | "keywords": [ 369 | "date", 370 | "datetime", 371 | "time" 372 | ], 373 | "funding": [ 374 | { 375 | "url": "https://opencollective.com/Carbon", 376 | "type": "open_collective" 377 | }, 378 | { 379 | "url": "https://tidelift.com/funding/github/packagist/nesbot/carbon", 380 | "type": "tidelift" 381 | } 382 | ], 383 | "time": "2020-09-10T12:16:42+00:00" 384 | }, 385 | { 386 | "name": "psr/container", 387 | "version": "1.0.0", 388 | "source": { 389 | "type": "git", 390 | "url": "https://github.com/php-fig/container.git", 391 | "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" 392 | }, 393 | "dist": { 394 | "type": "zip", 395 | "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", 396 | "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", 397 | "shasum": "" 398 | }, 399 | "require": { 400 | "php": ">=5.3.0" 401 | }, 402 | "type": "library", 403 | "extra": { 404 | "branch-alias": { 405 | "dev-master": "1.0.x-dev" 406 | } 407 | }, 408 | "autoload": { 409 | "psr-4": { 410 | "Psr\\Container\\": "src/" 411 | } 412 | }, 413 | "notification-url": "https://packagist.org/downloads/", 414 | "license": [ 415 | "MIT" 416 | ], 417 | "authors": [ 418 | { 419 | "name": "PHP-FIG", 420 | "homepage": "http://www.php-fig.org/" 421 | } 422 | ], 423 | "description": "Common Container Interface (PHP FIG PSR-11)", 424 | "homepage": "https://github.com/php-fig/container", 425 | "keywords": [ 426 | "PSR-11", 427 | "container", 428 | "container-interface", 429 | "container-interop", 430 | "psr" 431 | ], 432 | "time": "2017-02-14T16:28:37+00:00" 433 | }, 434 | { 435 | "name": "psr/simple-cache", 436 | "version": "1.0.1", 437 | "source": { 438 | "type": "git", 439 | "url": "https://github.com/php-fig/simple-cache.git", 440 | "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b" 441 | }, 442 | "dist": { 443 | "type": "zip", 444 | "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", 445 | "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", 446 | "shasum": "" 447 | }, 448 | "require": { 449 | "php": ">=5.3.0" 450 | }, 451 | "type": "library", 452 | "extra": { 453 | "branch-alias": { 454 | "dev-master": "1.0.x-dev" 455 | } 456 | }, 457 | "autoload": { 458 | "psr-4": { 459 | "Psr\\SimpleCache\\": "src/" 460 | } 461 | }, 462 | "notification-url": "https://packagist.org/downloads/", 463 | "license": [ 464 | "MIT" 465 | ], 466 | "authors": [ 467 | { 468 | "name": "PHP-FIG", 469 | "homepage": "http://www.php-fig.org/" 470 | } 471 | ], 472 | "description": "Common interfaces for simple caching", 473 | "keywords": [ 474 | "cache", 475 | "caching", 476 | "psr", 477 | "psr-16", 478 | "simple-cache" 479 | ], 480 | "time": "2017-10-23T01:57:42+00:00" 481 | }, 482 | { 483 | "name": "symfony/polyfill-mbstring", 484 | "version": "v1.18.1", 485 | "source": { 486 | "type": "git", 487 | "url": "https://github.com/symfony/polyfill-mbstring.git", 488 | "reference": "a6977d63bf9a0ad4c65cd352709e230876f9904a" 489 | }, 490 | "dist": { 491 | "type": "zip", 492 | "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/a6977d63bf9a0ad4c65cd352709e230876f9904a", 493 | "reference": "a6977d63bf9a0ad4c65cd352709e230876f9904a", 494 | "shasum": "" 495 | }, 496 | "require": { 497 | "php": ">=5.3.3" 498 | }, 499 | "suggest": { 500 | "ext-mbstring": "For best performance" 501 | }, 502 | "type": "library", 503 | "extra": { 504 | "branch-alias": { 505 | "dev-master": "1.18-dev" 506 | }, 507 | "thanks": { 508 | "name": "symfony/polyfill", 509 | "url": "https://github.com/symfony/polyfill" 510 | } 511 | }, 512 | "autoload": { 513 | "psr-4": { 514 | "Symfony\\Polyfill\\Mbstring\\": "" 515 | }, 516 | "files": [ 517 | "bootstrap.php" 518 | ] 519 | }, 520 | "notification-url": "https://packagist.org/downloads/", 521 | "license": [ 522 | "MIT" 523 | ], 524 | "authors": [ 525 | { 526 | "name": "Nicolas Grekas", 527 | "email": "p@tchwork.com" 528 | }, 529 | { 530 | "name": "Symfony Community", 531 | "homepage": "https://symfony.com/contributors" 532 | } 533 | ], 534 | "description": "Symfony polyfill for the Mbstring extension", 535 | "homepage": "https://symfony.com", 536 | "keywords": [ 537 | "compatibility", 538 | "mbstring", 539 | "polyfill", 540 | "portable", 541 | "shim" 542 | ], 543 | "funding": [ 544 | { 545 | "url": "https://symfony.com/sponsor", 546 | "type": "custom" 547 | }, 548 | { 549 | "url": "https://github.com/fabpot", 550 | "type": "github" 551 | }, 552 | { 553 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 554 | "type": "tidelift" 555 | } 556 | ], 557 | "time": "2020-07-14T12:35:20+00:00" 558 | }, 559 | { 560 | "name": "symfony/polyfill-php80", 561 | "version": "v1.18.1", 562 | "source": { 563 | "type": "git", 564 | "url": "https://github.com/symfony/polyfill-php80.git", 565 | "reference": "d87d5766cbf48d72388a9f6b85f280c8ad51f981" 566 | }, 567 | "dist": { 568 | "type": "zip", 569 | "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/d87d5766cbf48d72388a9f6b85f280c8ad51f981", 570 | "reference": "d87d5766cbf48d72388a9f6b85f280c8ad51f981", 571 | "shasum": "" 572 | }, 573 | "require": { 574 | "php": ">=7.0.8" 575 | }, 576 | "type": "library", 577 | "extra": { 578 | "branch-alias": { 579 | "dev-master": "1.18-dev" 580 | }, 581 | "thanks": { 582 | "name": "symfony/polyfill", 583 | "url": "https://github.com/symfony/polyfill" 584 | } 585 | }, 586 | "autoload": { 587 | "psr-4": { 588 | "Symfony\\Polyfill\\Php80\\": "" 589 | }, 590 | "files": [ 591 | "bootstrap.php" 592 | ], 593 | "classmap": [ 594 | "Resources/stubs" 595 | ] 596 | }, 597 | "notification-url": "https://packagist.org/downloads/", 598 | "license": [ 599 | "MIT" 600 | ], 601 | "authors": [ 602 | { 603 | "name": "Ion Bazan", 604 | "email": "ion.bazan@gmail.com" 605 | }, 606 | { 607 | "name": "Nicolas Grekas", 608 | "email": "p@tchwork.com" 609 | }, 610 | { 611 | "name": "Symfony Community", 612 | "homepage": "https://symfony.com/contributors" 613 | } 614 | ], 615 | "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", 616 | "homepage": "https://symfony.com", 617 | "keywords": [ 618 | "compatibility", 619 | "polyfill", 620 | "portable", 621 | "shim" 622 | ], 623 | "funding": [ 624 | { 625 | "url": "https://symfony.com/sponsor", 626 | "type": "custom" 627 | }, 628 | { 629 | "url": "https://github.com/fabpot", 630 | "type": "github" 631 | }, 632 | { 633 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 634 | "type": "tidelift" 635 | } 636 | ], 637 | "time": "2020-07-14T12:35:20+00:00" 638 | }, 639 | { 640 | "name": "symfony/translation", 641 | "version": "v5.1.5", 642 | "source": { 643 | "type": "git", 644 | "url": "https://github.com/symfony/translation.git", 645 | "reference": "917b02cdc5f33e0309b8e9d33ee1480b20687413" 646 | }, 647 | "dist": { 648 | "type": "zip", 649 | "url": "https://api.github.com/repos/symfony/translation/zipball/917b02cdc5f33e0309b8e9d33ee1480b20687413", 650 | "reference": "917b02cdc5f33e0309b8e9d33ee1480b20687413", 651 | "shasum": "" 652 | }, 653 | "require": { 654 | "php": ">=7.2.5", 655 | "symfony/polyfill-mbstring": "~1.0", 656 | "symfony/polyfill-php80": "^1.15", 657 | "symfony/translation-contracts": "^2" 658 | }, 659 | "conflict": { 660 | "symfony/config": "<4.4", 661 | "symfony/dependency-injection": "<5.0", 662 | "symfony/http-kernel": "<5.0", 663 | "symfony/twig-bundle": "<5.0", 664 | "symfony/yaml": "<4.4" 665 | }, 666 | "provide": { 667 | "symfony/translation-implementation": "2.0" 668 | }, 669 | "require-dev": { 670 | "psr/log": "~1.0", 671 | "symfony/config": "^4.4|^5.0", 672 | "symfony/console": "^4.4|^5.0", 673 | "symfony/dependency-injection": "^5.0", 674 | "symfony/finder": "^4.4|^5.0", 675 | "symfony/http-kernel": "^5.0", 676 | "symfony/intl": "^4.4|^5.0", 677 | "symfony/service-contracts": "^1.1.2|^2", 678 | "symfony/yaml": "^4.4|^5.0" 679 | }, 680 | "suggest": { 681 | "psr/log-implementation": "To use logging capability in translator", 682 | "symfony/config": "", 683 | "symfony/yaml": "" 684 | }, 685 | "type": "library", 686 | "extra": { 687 | "branch-alias": { 688 | "dev-master": "5.1-dev" 689 | } 690 | }, 691 | "autoload": { 692 | "psr-4": { 693 | "Symfony\\Component\\Translation\\": "" 694 | }, 695 | "exclude-from-classmap": [ 696 | "/Tests/" 697 | ] 698 | }, 699 | "notification-url": "https://packagist.org/downloads/", 700 | "license": [ 701 | "MIT" 702 | ], 703 | "authors": [ 704 | { 705 | "name": "Fabien Potencier", 706 | "email": "fabien@symfony.com" 707 | }, 708 | { 709 | "name": "Symfony Community", 710 | "homepage": "https://symfony.com/contributors" 711 | } 712 | ], 713 | "description": "Symfony Translation Component", 714 | "homepage": "https://symfony.com", 715 | "funding": [ 716 | { 717 | "url": "https://symfony.com/sponsor", 718 | "type": "custom" 719 | }, 720 | { 721 | "url": "https://github.com/fabpot", 722 | "type": "github" 723 | }, 724 | { 725 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 726 | "type": "tidelift" 727 | } 728 | ], 729 | "time": "2020-08-17T10:01:29+00:00" 730 | }, 731 | { 732 | "name": "symfony/translation-contracts", 733 | "version": "v2.2.0", 734 | "source": { 735 | "type": "git", 736 | "url": "https://github.com/symfony/translation-contracts.git", 737 | "reference": "77ce1c3627c9f39643acd9af086631f842c50c4d" 738 | }, 739 | "dist": { 740 | "type": "zip", 741 | "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/77ce1c3627c9f39643acd9af086631f842c50c4d", 742 | "reference": "77ce1c3627c9f39643acd9af086631f842c50c4d", 743 | "shasum": "" 744 | }, 745 | "require": { 746 | "php": ">=7.2.5" 747 | }, 748 | "suggest": { 749 | "symfony/translation-implementation": "" 750 | }, 751 | "type": "library", 752 | "extra": { 753 | "branch-alias": { 754 | "dev-master": "2.2-dev" 755 | }, 756 | "thanks": { 757 | "name": "symfony/contracts", 758 | "url": "https://github.com/symfony/contracts" 759 | } 760 | }, 761 | "autoload": { 762 | "psr-4": { 763 | "Symfony\\Contracts\\Translation\\": "" 764 | } 765 | }, 766 | "notification-url": "https://packagist.org/downloads/", 767 | "license": [ 768 | "MIT" 769 | ], 770 | "authors": [ 771 | { 772 | "name": "Nicolas Grekas", 773 | "email": "p@tchwork.com" 774 | }, 775 | { 776 | "name": "Symfony Community", 777 | "homepage": "https://symfony.com/contributors" 778 | } 779 | ], 780 | "description": "Generic abstractions related to translation", 781 | "homepage": "https://symfony.com", 782 | "keywords": [ 783 | "abstractions", 784 | "contracts", 785 | "decoupling", 786 | "interfaces", 787 | "interoperability", 788 | "standards" 789 | ], 790 | "funding": [ 791 | { 792 | "url": "https://symfony.com/sponsor", 793 | "type": "custom" 794 | }, 795 | { 796 | "url": "https://github.com/fabpot", 797 | "type": "github" 798 | }, 799 | { 800 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 801 | "type": "tidelift" 802 | } 803 | ], 804 | "time": "2020-09-07T11:33:47+00:00" 805 | }, 806 | { 807 | "name": "voku/portable-ascii", 808 | "version": "1.5.3", 809 | "source": { 810 | "type": "git", 811 | "url": "https://github.com/voku/portable-ascii.git", 812 | "reference": "25bcbf01678930251fd572891447d9e318a6e2b8" 813 | }, 814 | "dist": { 815 | "type": "zip", 816 | "url": "https://api.github.com/repos/voku/portable-ascii/zipball/25bcbf01678930251fd572891447d9e318a6e2b8", 817 | "reference": "25bcbf01678930251fd572891447d9e318a6e2b8", 818 | "shasum": "" 819 | }, 820 | "require": { 821 | "php": ">=7.0.0" 822 | }, 823 | "require-dev": { 824 | "phpunit/phpunit": "~6.0 || ~7.0" 825 | }, 826 | "suggest": { 827 | "ext-intl": "Use Intl for transliterator_transliterate() support" 828 | }, 829 | "type": "library", 830 | "autoload": { 831 | "psr-4": { 832 | "voku\\": "src/voku/" 833 | } 834 | }, 835 | "notification-url": "https://packagist.org/downloads/", 836 | "license": [ 837 | "MIT" 838 | ], 839 | "authors": [ 840 | { 841 | "name": "Lars Moelleken", 842 | "homepage": "http://www.moelleken.org/" 843 | } 844 | ], 845 | "description": "Portable ASCII library - performance optimized (ascii) string functions for php.", 846 | "homepage": "https://github.com/voku/portable-ascii", 847 | "keywords": [ 848 | "ascii", 849 | "clean", 850 | "php" 851 | ], 852 | "funding": [ 853 | { 854 | "url": "https://www.paypal.me/moelleken", 855 | "type": "custom" 856 | }, 857 | { 858 | "url": "https://github.com/voku", 859 | "type": "github" 860 | }, 861 | { 862 | "url": "https://opencollective.com/portable-ascii", 863 | "type": "open_collective" 864 | }, 865 | { 866 | "url": "https://www.patreon.com/voku", 867 | "type": "patreon" 868 | }, 869 | { 870 | "url": "https://tidelift.com/funding/github/packagist/voku/portable-ascii", 871 | "type": "tidelift" 872 | } 873 | ], 874 | "time": "2020-07-22T23:32:04+00:00" 875 | } 876 | ], 877 | "packages-dev": [ 878 | { 879 | "name": "doctrine/instantiator", 880 | "version": "1.3.1", 881 | "source": { 882 | "type": "git", 883 | "url": "https://github.com/doctrine/instantiator.git", 884 | "reference": "f350df0268e904597e3bd9c4685c53e0e333feea" 885 | }, 886 | "dist": { 887 | "type": "zip", 888 | "url": "https://api.github.com/repos/doctrine/instantiator/zipball/f350df0268e904597e3bd9c4685c53e0e333feea", 889 | "reference": "f350df0268e904597e3bd9c4685c53e0e333feea", 890 | "shasum": "" 891 | }, 892 | "require": { 893 | "php": "^7.1 || ^8.0" 894 | }, 895 | "require-dev": { 896 | "doctrine/coding-standard": "^6.0", 897 | "ext-pdo": "*", 898 | "ext-phar": "*", 899 | "phpbench/phpbench": "^0.13", 900 | "phpstan/phpstan-phpunit": "^0.11", 901 | "phpstan/phpstan-shim": "^0.11", 902 | "phpunit/phpunit": "^7.0" 903 | }, 904 | "type": "library", 905 | "extra": { 906 | "branch-alias": { 907 | "dev-master": "1.2.x-dev" 908 | } 909 | }, 910 | "autoload": { 911 | "psr-4": { 912 | "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" 913 | } 914 | }, 915 | "notification-url": "https://packagist.org/downloads/", 916 | "license": [ 917 | "MIT" 918 | ], 919 | "authors": [ 920 | { 921 | "name": "Marco Pivetta", 922 | "email": "ocramius@gmail.com", 923 | "homepage": "http://ocramius.github.com/" 924 | } 925 | ], 926 | "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", 927 | "homepage": "https://www.doctrine-project.org/projects/instantiator.html", 928 | "keywords": [ 929 | "constructor", 930 | "instantiate" 931 | ], 932 | "funding": [ 933 | { 934 | "url": "https://www.doctrine-project.org/sponsorship.html", 935 | "type": "custom" 936 | }, 937 | { 938 | "url": "https://www.patreon.com/phpdoctrine", 939 | "type": "patreon" 940 | }, 941 | { 942 | "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", 943 | "type": "tidelift" 944 | } 945 | ], 946 | "time": "2020-05-29T17:27:14+00:00" 947 | }, 948 | { 949 | "name": "phpdocumentor/reflection-common", 950 | "version": "2.2.0", 951 | "source": { 952 | "type": "git", 953 | "url": "https://github.com/phpDocumentor/ReflectionCommon.git", 954 | "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" 955 | }, 956 | "dist": { 957 | "type": "zip", 958 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", 959 | "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", 960 | "shasum": "" 961 | }, 962 | "require": { 963 | "php": "^7.2 || ^8.0" 964 | }, 965 | "type": "library", 966 | "extra": { 967 | "branch-alias": { 968 | "dev-2.x": "2.x-dev" 969 | } 970 | }, 971 | "autoload": { 972 | "psr-4": { 973 | "phpDocumentor\\Reflection\\": "src/" 974 | } 975 | }, 976 | "notification-url": "https://packagist.org/downloads/", 977 | "license": [ 978 | "MIT" 979 | ], 980 | "authors": [ 981 | { 982 | "name": "Jaap van Otterdijk", 983 | "email": "opensource@ijaap.nl" 984 | } 985 | ], 986 | "description": "Common reflection classes used by phpdocumentor to reflect the code structure", 987 | "homepage": "http://www.phpdoc.org", 988 | "keywords": [ 989 | "FQSEN", 990 | "phpDocumentor", 991 | "phpdoc", 992 | "reflection", 993 | "static analysis" 994 | ], 995 | "time": "2020-06-27T09:03:43+00:00" 996 | }, 997 | { 998 | "name": "phpdocumentor/reflection-docblock", 999 | "version": "5.2.1", 1000 | "source": { 1001 | "type": "git", 1002 | "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", 1003 | "reference": "d870572532cd70bc3fab58f2e23ad423c8404c44" 1004 | }, 1005 | "dist": { 1006 | "type": "zip", 1007 | "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/d870572532cd70bc3fab58f2e23ad423c8404c44", 1008 | "reference": "d870572532cd70bc3fab58f2e23ad423c8404c44", 1009 | "shasum": "" 1010 | }, 1011 | "require": { 1012 | "ext-filter": "*", 1013 | "php": "^7.2 || ^8.0", 1014 | "phpdocumentor/reflection-common": "^2.2", 1015 | "phpdocumentor/type-resolver": "^1.3", 1016 | "webmozart/assert": "^1.9.1" 1017 | }, 1018 | "require-dev": { 1019 | "mockery/mockery": "~1.3.2" 1020 | }, 1021 | "type": "library", 1022 | "extra": { 1023 | "branch-alias": { 1024 | "dev-master": "5.x-dev" 1025 | } 1026 | }, 1027 | "autoload": { 1028 | "psr-4": { 1029 | "phpDocumentor\\Reflection\\": "src" 1030 | } 1031 | }, 1032 | "notification-url": "https://packagist.org/downloads/", 1033 | "license": [ 1034 | "MIT" 1035 | ], 1036 | "authors": [ 1037 | { 1038 | "name": "Mike van Riel", 1039 | "email": "me@mikevanriel.com" 1040 | }, 1041 | { 1042 | "name": "Jaap van Otterdijk", 1043 | "email": "account@ijaap.nl" 1044 | } 1045 | ], 1046 | "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", 1047 | "time": "2020-08-15T11:14:08+00:00" 1048 | }, 1049 | { 1050 | "name": "phpdocumentor/type-resolver", 1051 | "version": "1.3.0", 1052 | "source": { 1053 | "type": "git", 1054 | "url": "https://github.com/phpDocumentor/TypeResolver.git", 1055 | "reference": "e878a14a65245fbe78f8080eba03b47c3b705651" 1056 | }, 1057 | "dist": { 1058 | "type": "zip", 1059 | "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/e878a14a65245fbe78f8080eba03b47c3b705651", 1060 | "reference": "e878a14a65245fbe78f8080eba03b47c3b705651", 1061 | "shasum": "" 1062 | }, 1063 | "require": { 1064 | "php": "^7.2 || ^8.0", 1065 | "phpdocumentor/reflection-common": "^2.0" 1066 | }, 1067 | "require-dev": { 1068 | "ext-tokenizer": "*" 1069 | }, 1070 | "type": "library", 1071 | "extra": { 1072 | "branch-alias": { 1073 | "dev-1.x": "1.x-dev" 1074 | } 1075 | }, 1076 | "autoload": { 1077 | "psr-4": { 1078 | "phpDocumentor\\Reflection\\": "src" 1079 | } 1080 | }, 1081 | "notification-url": "https://packagist.org/downloads/", 1082 | "license": [ 1083 | "MIT" 1084 | ], 1085 | "authors": [ 1086 | { 1087 | "name": "Mike van Riel", 1088 | "email": "me@mikevanriel.com" 1089 | } 1090 | ], 1091 | "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", 1092 | "time": "2020-06-27T10:12:23+00:00" 1093 | }, 1094 | { 1095 | "name": "phpspec/php-diff", 1096 | "version": "v1.1.0", 1097 | "source": { 1098 | "type": "git", 1099 | "url": "https://github.com/phpspec/php-diff.git", 1100 | "reference": "0464787bfa7cd13576c5a1e318709768798bec6a" 1101 | }, 1102 | "dist": { 1103 | "type": "zip", 1104 | "url": "https://api.github.com/repos/phpspec/php-diff/zipball/0464787bfa7cd13576c5a1e318709768798bec6a", 1105 | "reference": "0464787bfa7cd13576c5a1e318709768798bec6a", 1106 | "shasum": "" 1107 | }, 1108 | "type": "library", 1109 | "extra": { 1110 | "branch-alias": { 1111 | "dev-master": "1.0.x-dev" 1112 | } 1113 | }, 1114 | "autoload": { 1115 | "psr-0": { 1116 | "Diff": "lib/" 1117 | } 1118 | }, 1119 | "notification-url": "https://packagist.org/downloads/", 1120 | "license": [ 1121 | "BSD-3-Clause" 1122 | ], 1123 | "authors": [ 1124 | { 1125 | "name": "Chris Boulton", 1126 | "homepage": "http://github.com/chrisboulton" 1127 | } 1128 | ], 1129 | "description": "A comprehensive library for generating differences between two hashable objects (strings or arrays).", 1130 | "time": "2016-04-07T12:29:16+00:00" 1131 | }, 1132 | { 1133 | "name": "phpspec/phpspec", 1134 | "version": "6.2.1", 1135 | "source": { 1136 | "type": "git", 1137 | "url": "https://github.com/phpspec/phpspec.git", 1138 | "reference": "a40d53c8564f97eca75919769f93410dd3dba5e8" 1139 | }, 1140 | "dist": { 1141 | "type": "zip", 1142 | "url": "https://api.github.com/repos/phpspec/phpspec/zipball/a40d53c8564f97eca75919769f93410dd3dba5e8", 1143 | "reference": "a40d53c8564f97eca75919769f93410dd3dba5e8", 1144 | "shasum": "" 1145 | }, 1146 | "require": { 1147 | "doctrine/instantiator": "^1.0.5", 1148 | "ext-tokenizer": "*", 1149 | "php": "^7.2, <7.5", 1150 | "phpspec/php-diff": "^1.0.0", 1151 | "phpspec/prophecy": "^1.9", 1152 | "sebastian/exporter": "^1.0 || ^2.0 || ^3.0 || ^4.0", 1153 | "symfony/console": "^3.4 || ^4.0 || ^5.0", 1154 | "symfony/event-dispatcher": "^3.4 || ^4.0 || ^5.0", 1155 | "symfony/finder": "^3.4 || ^4.0 || ^5.0", 1156 | "symfony/process": "^3.4 || ^4.0 || ^5.0", 1157 | "symfony/yaml": "^3.4 || ^4.0 || ^5.0" 1158 | }, 1159 | "conflict": { 1160 | "sebastian/comparator": "<1.2.4" 1161 | }, 1162 | "require-dev": { 1163 | "behat/behat": "^3.3", 1164 | "phpunit/phpunit": "^7.0", 1165 | "symfony/filesystem": "^3.4 || ^4.0 || ^5.0" 1166 | }, 1167 | "suggest": { 1168 | "phpspec/nyan-formatters": "Adds Nyan formatters" 1169 | }, 1170 | "bin": [ 1171 | "bin/phpspec" 1172 | ], 1173 | "type": "library", 1174 | "extra": { 1175 | "branch-alias": { 1176 | "dev-master": "6.2.x-dev" 1177 | } 1178 | }, 1179 | "autoload": { 1180 | "psr-0": { 1181 | "PhpSpec": "src/" 1182 | } 1183 | }, 1184 | "notification-url": "https://packagist.org/downloads/", 1185 | "license": [ 1186 | "MIT" 1187 | ], 1188 | "authors": [ 1189 | { 1190 | "name": "Konstantin Kudryashov", 1191 | "email": "ever.zet@gmail.com", 1192 | "homepage": "http://everzet.com" 1193 | }, 1194 | { 1195 | "name": "Marcello Duarte", 1196 | "homepage": "http://marcelloduarte.net/" 1197 | }, 1198 | { 1199 | "name": "Ciaran McNulty", 1200 | "homepage": "https://ciaranmcnulty.com/" 1201 | } 1202 | ], 1203 | "description": "Specification-oriented BDD framework for PHP 7.1+", 1204 | "homepage": "http://phpspec.net/", 1205 | "keywords": [ 1206 | "BDD", 1207 | "SpecBDD", 1208 | "TDD", 1209 | "spec", 1210 | "specification", 1211 | "testing", 1212 | "tests" 1213 | ], 1214 | "time": "2020-07-08T14:05:47+00:00" 1215 | }, 1216 | { 1217 | "name": "phpspec/prophecy", 1218 | "version": "1.11.1", 1219 | "source": { 1220 | "type": "git", 1221 | "url": "https://github.com/phpspec/prophecy.git", 1222 | "reference": "b20034be5efcdab4fb60ca3a29cba2949aead160" 1223 | }, 1224 | "dist": { 1225 | "type": "zip", 1226 | "url": "https://api.github.com/repos/phpspec/prophecy/zipball/b20034be5efcdab4fb60ca3a29cba2949aead160", 1227 | "reference": "b20034be5efcdab4fb60ca3a29cba2949aead160", 1228 | "shasum": "" 1229 | }, 1230 | "require": { 1231 | "doctrine/instantiator": "^1.2", 1232 | "php": "^7.2", 1233 | "phpdocumentor/reflection-docblock": "^5.0", 1234 | "sebastian/comparator": "^3.0 || ^4.0", 1235 | "sebastian/recursion-context": "^3.0 || ^4.0" 1236 | }, 1237 | "require-dev": { 1238 | "phpspec/phpspec": "^6.0", 1239 | "phpunit/phpunit": "^8.0" 1240 | }, 1241 | "type": "library", 1242 | "extra": { 1243 | "branch-alias": { 1244 | "dev-master": "1.11.x-dev" 1245 | } 1246 | }, 1247 | "autoload": { 1248 | "psr-4": { 1249 | "Prophecy\\": "src/Prophecy" 1250 | } 1251 | }, 1252 | "notification-url": "https://packagist.org/downloads/", 1253 | "license": [ 1254 | "MIT" 1255 | ], 1256 | "authors": [ 1257 | { 1258 | "name": "Konstantin Kudryashov", 1259 | "email": "ever.zet@gmail.com", 1260 | "homepage": "http://everzet.com" 1261 | }, 1262 | { 1263 | "name": "Marcello Duarte", 1264 | "email": "marcello.duarte@gmail.com" 1265 | } 1266 | ], 1267 | "description": "Highly opinionated mocking framework for PHP 5.3+", 1268 | "homepage": "https://github.com/phpspec/prophecy", 1269 | "keywords": [ 1270 | "Double", 1271 | "Dummy", 1272 | "fake", 1273 | "mock", 1274 | "spy", 1275 | "stub" 1276 | ], 1277 | "time": "2020-07-08T12:44:21+00:00" 1278 | }, 1279 | { 1280 | "name": "psr/event-dispatcher", 1281 | "version": "1.0.0", 1282 | "source": { 1283 | "type": "git", 1284 | "url": "https://github.com/php-fig/event-dispatcher.git", 1285 | "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" 1286 | }, 1287 | "dist": { 1288 | "type": "zip", 1289 | "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", 1290 | "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", 1291 | "shasum": "" 1292 | }, 1293 | "require": { 1294 | "php": ">=7.2.0" 1295 | }, 1296 | "type": "library", 1297 | "extra": { 1298 | "branch-alias": { 1299 | "dev-master": "1.0.x-dev" 1300 | } 1301 | }, 1302 | "autoload": { 1303 | "psr-4": { 1304 | "Psr\\EventDispatcher\\": "src/" 1305 | } 1306 | }, 1307 | "notification-url": "https://packagist.org/downloads/", 1308 | "license": [ 1309 | "MIT" 1310 | ], 1311 | "authors": [ 1312 | { 1313 | "name": "PHP-FIG", 1314 | "homepage": "http://www.php-fig.org/" 1315 | } 1316 | ], 1317 | "description": "Standard interfaces for event handling.", 1318 | "keywords": [ 1319 | "events", 1320 | "psr", 1321 | "psr-14" 1322 | ], 1323 | "time": "2019-01-08T18:20:26+00:00" 1324 | }, 1325 | { 1326 | "name": "sebastian/comparator", 1327 | "version": "4.0.3", 1328 | "source": { 1329 | "type": "git", 1330 | "url": "https://github.com/sebastianbergmann/comparator.git", 1331 | "reference": "dcc580eadfaa4e7f9d2cf9ae1922134ea962e14f" 1332 | }, 1333 | "dist": { 1334 | "type": "zip", 1335 | "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/dcc580eadfaa4e7f9d2cf9ae1922134ea962e14f", 1336 | "reference": "dcc580eadfaa4e7f9d2cf9ae1922134ea962e14f", 1337 | "shasum": "" 1338 | }, 1339 | "require": { 1340 | "php": "^7.3 || ^8.0", 1341 | "sebastian/diff": "^4.0", 1342 | "sebastian/exporter": "^4.0" 1343 | }, 1344 | "require-dev": { 1345 | "phpunit/phpunit": "^9.0" 1346 | }, 1347 | "type": "library", 1348 | "extra": { 1349 | "branch-alias": { 1350 | "dev-master": "4.0-dev" 1351 | } 1352 | }, 1353 | "autoload": { 1354 | "classmap": [ 1355 | "src/" 1356 | ] 1357 | }, 1358 | "notification-url": "https://packagist.org/downloads/", 1359 | "license": [ 1360 | "BSD-3-Clause" 1361 | ], 1362 | "authors": [ 1363 | { 1364 | "name": "Sebastian Bergmann", 1365 | "email": "sebastian@phpunit.de" 1366 | }, 1367 | { 1368 | "name": "Jeff Welch", 1369 | "email": "whatthejeff@gmail.com" 1370 | }, 1371 | { 1372 | "name": "Volker Dusch", 1373 | "email": "github@wallbash.com" 1374 | }, 1375 | { 1376 | "name": "Bernhard Schussek", 1377 | "email": "bschussek@2bepublished.at" 1378 | } 1379 | ], 1380 | "description": "Provides the functionality to compare PHP values for equality", 1381 | "homepage": "https://github.com/sebastianbergmann/comparator", 1382 | "keywords": [ 1383 | "comparator", 1384 | "compare", 1385 | "equality" 1386 | ], 1387 | "funding": [ 1388 | { 1389 | "url": "https://github.com/sebastianbergmann", 1390 | "type": "github" 1391 | } 1392 | ], 1393 | "time": "2020-06-26T12:05:46+00:00" 1394 | }, 1395 | { 1396 | "name": "sebastian/diff", 1397 | "version": "4.0.2", 1398 | "source": { 1399 | "type": "git", 1400 | "url": "https://github.com/sebastianbergmann/diff.git", 1401 | "reference": "1e90b4cf905a7d06c420b1d2e9d11a4dc8a13113" 1402 | }, 1403 | "dist": { 1404 | "type": "zip", 1405 | "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/1e90b4cf905a7d06c420b1d2e9d11a4dc8a13113", 1406 | "reference": "1e90b4cf905a7d06c420b1d2e9d11a4dc8a13113", 1407 | "shasum": "" 1408 | }, 1409 | "require": { 1410 | "php": "^7.3 || ^8.0" 1411 | }, 1412 | "require-dev": { 1413 | "phpunit/phpunit": "^9.0", 1414 | "symfony/process": "^4.2 || ^5" 1415 | }, 1416 | "type": "library", 1417 | "extra": { 1418 | "branch-alias": { 1419 | "dev-master": "4.0-dev" 1420 | } 1421 | }, 1422 | "autoload": { 1423 | "classmap": [ 1424 | "src/" 1425 | ] 1426 | }, 1427 | "notification-url": "https://packagist.org/downloads/", 1428 | "license": [ 1429 | "BSD-3-Clause" 1430 | ], 1431 | "authors": [ 1432 | { 1433 | "name": "Sebastian Bergmann", 1434 | "email": "sebastian@phpunit.de" 1435 | }, 1436 | { 1437 | "name": "Kore Nordmann", 1438 | "email": "mail@kore-nordmann.de" 1439 | } 1440 | ], 1441 | "description": "Diff implementation", 1442 | "homepage": "https://github.com/sebastianbergmann/diff", 1443 | "keywords": [ 1444 | "diff", 1445 | "udiff", 1446 | "unidiff", 1447 | "unified diff" 1448 | ], 1449 | "funding": [ 1450 | { 1451 | "url": "https://github.com/sebastianbergmann", 1452 | "type": "github" 1453 | } 1454 | ], 1455 | "time": "2020-06-30T04:46:02+00:00" 1456 | }, 1457 | { 1458 | "name": "sebastian/exporter", 1459 | "version": "4.0.2", 1460 | "source": { 1461 | "type": "git", 1462 | "url": "https://github.com/sebastianbergmann/exporter.git", 1463 | "reference": "571d721db4aec847a0e59690b954af33ebf9f023" 1464 | }, 1465 | "dist": { 1466 | "type": "zip", 1467 | "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/571d721db4aec847a0e59690b954af33ebf9f023", 1468 | "reference": "571d721db4aec847a0e59690b954af33ebf9f023", 1469 | "shasum": "" 1470 | }, 1471 | "require": { 1472 | "php": "^7.3 || ^8.0", 1473 | "sebastian/recursion-context": "^4.0" 1474 | }, 1475 | "require-dev": { 1476 | "ext-mbstring": "*", 1477 | "phpunit/phpunit": "^9.2" 1478 | }, 1479 | "type": "library", 1480 | "extra": { 1481 | "branch-alias": { 1482 | "dev-master": "4.0-dev" 1483 | } 1484 | }, 1485 | "autoload": { 1486 | "classmap": [ 1487 | "src/" 1488 | ] 1489 | }, 1490 | "notification-url": "https://packagist.org/downloads/", 1491 | "license": [ 1492 | "BSD-3-Clause" 1493 | ], 1494 | "authors": [ 1495 | { 1496 | "name": "Sebastian Bergmann", 1497 | "email": "sebastian@phpunit.de" 1498 | }, 1499 | { 1500 | "name": "Jeff Welch", 1501 | "email": "whatthejeff@gmail.com" 1502 | }, 1503 | { 1504 | "name": "Volker Dusch", 1505 | "email": "github@wallbash.com" 1506 | }, 1507 | { 1508 | "name": "Adam Harvey", 1509 | "email": "aharvey@php.net" 1510 | }, 1511 | { 1512 | "name": "Bernhard Schussek", 1513 | "email": "bschussek@gmail.com" 1514 | } 1515 | ], 1516 | "description": "Provides the functionality to export PHP variables for visualization", 1517 | "homepage": "http://www.github.com/sebastianbergmann/exporter", 1518 | "keywords": [ 1519 | "export", 1520 | "exporter" 1521 | ], 1522 | "funding": [ 1523 | { 1524 | "url": "https://github.com/sebastianbergmann", 1525 | "type": "github" 1526 | } 1527 | ], 1528 | "time": "2020-06-26T12:08:55+00:00" 1529 | }, 1530 | { 1531 | "name": "sebastian/recursion-context", 1532 | "version": "4.0.2", 1533 | "source": { 1534 | "type": "git", 1535 | "url": "https://github.com/sebastianbergmann/recursion-context.git", 1536 | "reference": "062231bf61d2b9448c4fa5a7643b5e1829c11d63" 1537 | }, 1538 | "dist": { 1539 | "type": "zip", 1540 | "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/062231bf61d2b9448c4fa5a7643b5e1829c11d63", 1541 | "reference": "062231bf61d2b9448c4fa5a7643b5e1829c11d63", 1542 | "shasum": "" 1543 | }, 1544 | "require": { 1545 | "php": "^7.3 || ^8.0" 1546 | }, 1547 | "require-dev": { 1548 | "phpunit/phpunit": "^9.0" 1549 | }, 1550 | "type": "library", 1551 | "extra": { 1552 | "branch-alias": { 1553 | "dev-master": "4.0-dev" 1554 | } 1555 | }, 1556 | "autoload": { 1557 | "classmap": [ 1558 | "src/" 1559 | ] 1560 | }, 1561 | "notification-url": "https://packagist.org/downloads/", 1562 | "license": [ 1563 | "BSD-3-Clause" 1564 | ], 1565 | "authors": [ 1566 | { 1567 | "name": "Sebastian Bergmann", 1568 | "email": "sebastian@phpunit.de" 1569 | }, 1570 | { 1571 | "name": "Jeff Welch", 1572 | "email": "whatthejeff@gmail.com" 1573 | }, 1574 | { 1575 | "name": "Adam Harvey", 1576 | "email": "aharvey@php.net" 1577 | } 1578 | ], 1579 | "description": "Provides functionality to recursively process PHP variables", 1580 | "homepage": "http://www.github.com/sebastianbergmann/recursion-context", 1581 | "funding": [ 1582 | { 1583 | "url": "https://github.com/sebastianbergmann", 1584 | "type": "github" 1585 | } 1586 | ], 1587 | "time": "2020-06-26T12:14:17+00:00" 1588 | }, 1589 | { 1590 | "name": "symfony/console", 1591 | "version": "v5.1.5", 1592 | "source": { 1593 | "type": "git", 1594 | "url": "https://github.com/symfony/console.git", 1595 | "reference": "186f395b256065ba9b890c0a4e48a91d598fa2cf" 1596 | }, 1597 | "dist": { 1598 | "type": "zip", 1599 | "url": "https://api.github.com/repos/symfony/console/zipball/186f395b256065ba9b890c0a4e48a91d598fa2cf", 1600 | "reference": "186f395b256065ba9b890c0a4e48a91d598fa2cf", 1601 | "shasum": "" 1602 | }, 1603 | "require": { 1604 | "php": ">=7.2.5", 1605 | "symfony/polyfill-mbstring": "~1.0", 1606 | "symfony/polyfill-php73": "^1.8", 1607 | "symfony/polyfill-php80": "^1.15", 1608 | "symfony/service-contracts": "^1.1|^2", 1609 | "symfony/string": "^5.1" 1610 | }, 1611 | "conflict": { 1612 | "symfony/dependency-injection": "<4.4", 1613 | "symfony/dotenv": "<5.1", 1614 | "symfony/event-dispatcher": "<4.4", 1615 | "symfony/lock": "<4.4", 1616 | "symfony/process": "<4.4" 1617 | }, 1618 | "provide": { 1619 | "psr/log-implementation": "1.0" 1620 | }, 1621 | "require-dev": { 1622 | "psr/log": "~1.0", 1623 | "symfony/config": "^4.4|^5.0", 1624 | "symfony/dependency-injection": "^4.4|^5.0", 1625 | "symfony/event-dispatcher": "^4.4|^5.0", 1626 | "symfony/lock": "^4.4|^5.0", 1627 | "symfony/process": "^4.4|^5.0", 1628 | "symfony/var-dumper": "^4.4|^5.0" 1629 | }, 1630 | "suggest": { 1631 | "psr/log": "For using the console logger", 1632 | "symfony/event-dispatcher": "", 1633 | "symfony/lock": "", 1634 | "symfony/process": "" 1635 | }, 1636 | "type": "library", 1637 | "extra": { 1638 | "branch-alias": { 1639 | "dev-master": "5.1-dev" 1640 | } 1641 | }, 1642 | "autoload": { 1643 | "psr-4": { 1644 | "Symfony\\Component\\Console\\": "" 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 Console Component", 1665 | "homepage": "https://symfony.com", 1666 | "funding": [ 1667 | { 1668 | "url": "https://symfony.com/sponsor", 1669 | "type": "custom" 1670 | }, 1671 | { 1672 | "url": "https://github.com/fabpot", 1673 | "type": "github" 1674 | }, 1675 | { 1676 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 1677 | "type": "tidelift" 1678 | } 1679 | ], 1680 | "time": "2020-09-02T07:07:40+00:00" 1681 | }, 1682 | { 1683 | "name": "symfony/deprecation-contracts", 1684 | "version": "v2.2.0", 1685 | "source": { 1686 | "type": "git", 1687 | "url": "https://github.com/symfony/deprecation-contracts.git", 1688 | "reference": "5fa56b4074d1ae755beb55617ddafe6f5d78f665" 1689 | }, 1690 | "dist": { 1691 | "type": "zip", 1692 | "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/5fa56b4074d1ae755beb55617ddafe6f5d78f665", 1693 | "reference": "5fa56b4074d1ae755beb55617ddafe6f5d78f665", 1694 | "shasum": "" 1695 | }, 1696 | "require": { 1697 | "php": ">=7.1" 1698 | }, 1699 | "type": "library", 1700 | "extra": { 1701 | "branch-alias": { 1702 | "dev-master": "2.2-dev" 1703 | }, 1704 | "thanks": { 1705 | "name": "symfony/contracts", 1706 | "url": "https://github.com/symfony/contracts" 1707 | } 1708 | }, 1709 | "autoload": { 1710 | "files": [ 1711 | "function.php" 1712 | ] 1713 | }, 1714 | "notification-url": "https://packagist.org/downloads/", 1715 | "license": [ 1716 | "MIT" 1717 | ], 1718 | "authors": [ 1719 | { 1720 | "name": "Nicolas Grekas", 1721 | "email": "p@tchwork.com" 1722 | }, 1723 | { 1724 | "name": "Symfony Community", 1725 | "homepage": "https://symfony.com/contributors" 1726 | } 1727 | ], 1728 | "description": "A generic function and convention to trigger deprecation notices", 1729 | "homepage": "https://symfony.com", 1730 | "funding": [ 1731 | { 1732 | "url": "https://symfony.com/sponsor", 1733 | "type": "custom" 1734 | }, 1735 | { 1736 | "url": "https://github.com/fabpot", 1737 | "type": "github" 1738 | }, 1739 | { 1740 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 1741 | "type": "tidelift" 1742 | } 1743 | ], 1744 | "time": "2020-09-07T11:33:47+00:00" 1745 | }, 1746 | { 1747 | "name": "symfony/event-dispatcher", 1748 | "version": "v5.1.5", 1749 | "source": { 1750 | "type": "git", 1751 | "url": "https://github.com/symfony/event-dispatcher.git", 1752 | "reference": "94871fc0a69c3c5da57764187724cdce0755899c" 1753 | }, 1754 | "dist": { 1755 | "type": "zip", 1756 | "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/94871fc0a69c3c5da57764187724cdce0755899c", 1757 | "reference": "94871fc0a69c3c5da57764187724cdce0755899c", 1758 | "shasum": "" 1759 | }, 1760 | "require": { 1761 | "php": ">=7.2.5", 1762 | "symfony/deprecation-contracts": "^2.1", 1763 | "symfony/event-dispatcher-contracts": "^2", 1764 | "symfony/polyfill-php80": "^1.15" 1765 | }, 1766 | "conflict": { 1767 | "symfony/dependency-injection": "<4.4" 1768 | }, 1769 | "provide": { 1770 | "psr/event-dispatcher-implementation": "1.0", 1771 | "symfony/event-dispatcher-implementation": "2.0" 1772 | }, 1773 | "require-dev": { 1774 | "psr/log": "~1.0", 1775 | "symfony/config": "^4.4|^5.0", 1776 | "symfony/dependency-injection": "^4.4|^5.0", 1777 | "symfony/expression-language": "^4.4|^5.0", 1778 | "symfony/http-foundation": "^4.4|^5.0", 1779 | "symfony/service-contracts": "^1.1|^2", 1780 | "symfony/stopwatch": "^4.4|^5.0" 1781 | }, 1782 | "suggest": { 1783 | "symfony/dependency-injection": "", 1784 | "symfony/http-kernel": "" 1785 | }, 1786 | "type": "library", 1787 | "extra": { 1788 | "branch-alias": { 1789 | "dev-master": "5.1-dev" 1790 | } 1791 | }, 1792 | "autoload": { 1793 | "psr-4": { 1794 | "Symfony\\Component\\EventDispatcher\\": "" 1795 | }, 1796 | "exclude-from-classmap": [ 1797 | "/Tests/" 1798 | ] 1799 | }, 1800 | "notification-url": "https://packagist.org/downloads/", 1801 | "license": [ 1802 | "MIT" 1803 | ], 1804 | "authors": [ 1805 | { 1806 | "name": "Fabien Potencier", 1807 | "email": "fabien@symfony.com" 1808 | }, 1809 | { 1810 | "name": "Symfony Community", 1811 | "homepage": "https://symfony.com/contributors" 1812 | } 1813 | ], 1814 | "description": "Symfony EventDispatcher Component", 1815 | "homepage": "https://symfony.com", 1816 | "funding": [ 1817 | { 1818 | "url": "https://symfony.com/sponsor", 1819 | "type": "custom" 1820 | }, 1821 | { 1822 | "url": "https://github.com/fabpot", 1823 | "type": "github" 1824 | }, 1825 | { 1826 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 1827 | "type": "tidelift" 1828 | } 1829 | ], 1830 | "time": "2020-08-13T14:19:42+00:00" 1831 | }, 1832 | { 1833 | "name": "symfony/event-dispatcher-contracts", 1834 | "version": "v2.2.0", 1835 | "source": { 1836 | "type": "git", 1837 | "url": "https://github.com/symfony/event-dispatcher-contracts.git", 1838 | "reference": "0ba7d54483095a198fa51781bc608d17e84dffa2" 1839 | }, 1840 | "dist": { 1841 | "type": "zip", 1842 | "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/0ba7d54483095a198fa51781bc608d17e84dffa2", 1843 | "reference": "0ba7d54483095a198fa51781bc608d17e84dffa2", 1844 | "shasum": "" 1845 | }, 1846 | "require": { 1847 | "php": ">=7.2.5", 1848 | "psr/event-dispatcher": "^1" 1849 | }, 1850 | "suggest": { 1851 | "symfony/event-dispatcher-implementation": "" 1852 | }, 1853 | "type": "library", 1854 | "extra": { 1855 | "branch-alias": { 1856 | "dev-master": "2.2-dev" 1857 | }, 1858 | "thanks": { 1859 | "name": "symfony/contracts", 1860 | "url": "https://github.com/symfony/contracts" 1861 | } 1862 | }, 1863 | "autoload": { 1864 | "psr-4": { 1865 | "Symfony\\Contracts\\EventDispatcher\\": "" 1866 | } 1867 | }, 1868 | "notification-url": "https://packagist.org/downloads/", 1869 | "license": [ 1870 | "MIT" 1871 | ], 1872 | "authors": [ 1873 | { 1874 | "name": "Nicolas Grekas", 1875 | "email": "p@tchwork.com" 1876 | }, 1877 | { 1878 | "name": "Symfony Community", 1879 | "homepage": "https://symfony.com/contributors" 1880 | } 1881 | ], 1882 | "description": "Generic abstractions related to dispatching event", 1883 | "homepage": "https://symfony.com", 1884 | "keywords": [ 1885 | "abstractions", 1886 | "contracts", 1887 | "decoupling", 1888 | "interfaces", 1889 | "interoperability", 1890 | "standards" 1891 | ], 1892 | "funding": [ 1893 | { 1894 | "url": "https://symfony.com/sponsor", 1895 | "type": "custom" 1896 | }, 1897 | { 1898 | "url": "https://github.com/fabpot", 1899 | "type": "github" 1900 | }, 1901 | { 1902 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 1903 | "type": "tidelift" 1904 | } 1905 | ], 1906 | "time": "2020-09-07T11:33:47+00:00" 1907 | }, 1908 | { 1909 | "name": "symfony/finder", 1910 | "version": "v5.1.5", 1911 | "source": { 1912 | "type": "git", 1913 | "url": "https://github.com/symfony/finder.git", 1914 | "reference": "2b765f0cf6612b3636e738c0689b29aa63088d5d" 1915 | }, 1916 | "dist": { 1917 | "type": "zip", 1918 | "url": "https://api.github.com/repos/symfony/finder/zipball/2b765f0cf6612b3636e738c0689b29aa63088d5d", 1919 | "reference": "2b765f0cf6612b3636e738c0689b29aa63088d5d", 1920 | "shasum": "" 1921 | }, 1922 | "require": { 1923 | "php": ">=7.2.5" 1924 | }, 1925 | "type": "library", 1926 | "extra": { 1927 | "branch-alias": { 1928 | "dev-master": "5.1-dev" 1929 | } 1930 | }, 1931 | "autoload": { 1932 | "psr-4": { 1933 | "Symfony\\Component\\Finder\\": "" 1934 | }, 1935 | "exclude-from-classmap": [ 1936 | "/Tests/" 1937 | ] 1938 | }, 1939 | "notification-url": "https://packagist.org/downloads/", 1940 | "license": [ 1941 | "MIT" 1942 | ], 1943 | "authors": [ 1944 | { 1945 | "name": "Fabien Potencier", 1946 | "email": "fabien@symfony.com" 1947 | }, 1948 | { 1949 | "name": "Symfony Community", 1950 | "homepage": "https://symfony.com/contributors" 1951 | } 1952 | ], 1953 | "description": "Symfony Finder Component", 1954 | "homepage": "https://symfony.com", 1955 | "funding": [ 1956 | { 1957 | "url": "https://symfony.com/sponsor", 1958 | "type": "custom" 1959 | }, 1960 | { 1961 | "url": "https://github.com/fabpot", 1962 | "type": "github" 1963 | }, 1964 | { 1965 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 1966 | "type": "tidelift" 1967 | } 1968 | ], 1969 | "time": "2020-08-17T10:01:29+00:00" 1970 | }, 1971 | { 1972 | "name": "symfony/polyfill-ctype", 1973 | "version": "v1.18.1", 1974 | "source": { 1975 | "type": "git", 1976 | "url": "https://github.com/symfony/polyfill-ctype.git", 1977 | "reference": "1c302646f6efc070cd46856e600e5e0684d6b454" 1978 | }, 1979 | "dist": { 1980 | "type": "zip", 1981 | "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/1c302646f6efc070cd46856e600e5e0684d6b454", 1982 | "reference": "1c302646f6efc070cd46856e600e5e0684d6b454", 1983 | "shasum": "" 1984 | }, 1985 | "require": { 1986 | "php": ">=5.3.3" 1987 | }, 1988 | "suggest": { 1989 | "ext-ctype": "For best performance" 1990 | }, 1991 | "type": "library", 1992 | "extra": { 1993 | "branch-alias": { 1994 | "dev-master": "1.18-dev" 1995 | }, 1996 | "thanks": { 1997 | "name": "symfony/polyfill", 1998 | "url": "https://github.com/symfony/polyfill" 1999 | } 2000 | }, 2001 | "autoload": { 2002 | "psr-4": { 2003 | "Symfony\\Polyfill\\Ctype\\": "" 2004 | }, 2005 | "files": [ 2006 | "bootstrap.php" 2007 | ] 2008 | }, 2009 | "notification-url": "https://packagist.org/downloads/", 2010 | "license": [ 2011 | "MIT" 2012 | ], 2013 | "authors": [ 2014 | { 2015 | "name": "Gert de Pagter", 2016 | "email": "BackEndTea@gmail.com" 2017 | }, 2018 | { 2019 | "name": "Symfony Community", 2020 | "homepage": "https://symfony.com/contributors" 2021 | } 2022 | ], 2023 | "description": "Symfony polyfill for ctype functions", 2024 | "homepage": "https://symfony.com", 2025 | "keywords": [ 2026 | "compatibility", 2027 | "ctype", 2028 | "polyfill", 2029 | "portable" 2030 | ], 2031 | "funding": [ 2032 | { 2033 | "url": "https://symfony.com/sponsor", 2034 | "type": "custom" 2035 | }, 2036 | { 2037 | "url": "https://github.com/fabpot", 2038 | "type": "github" 2039 | }, 2040 | { 2041 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 2042 | "type": "tidelift" 2043 | } 2044 | ], 2045 | "time": "2020-07-14T12:35:20+00:00" 2046 | }, 2047 | { 2048 | "name": "symfony/polyfill-intl-grapheme", 2049 | "version": "v1.18.1", 2050 | "source": { 2051 | "type": "git", 2052 | "url": "https://github.com/symfony/polyfill-intl-grapheme.git", 2053 | "reference": "b740103edbdcc39602239ee8860f0f45a8eb9aa5" 2054 | }, 2055 | "dist": { 2056 | "type": "zip", 2057 | "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b740103edbdcc39602239ee8860f0f45a8eb9aa5", 2058 | "reference": "b740103edbdcc39602239ee8860f0f45a8eb9aa5", 2059 | "shasum": "" 2060 | }, 2061 | "require": { 2062 | "php": ">=5.3.3" 2063 | }, 2064 | "suggest": { 2065 | "ext-intl": "For best performance" 2066 | }, 2067 | "type": "library", 2068 | "extra": { 2069 | "branch-alias": { 2070 | "dev-master": "1.18-dev" 2071 | }, 2072 | "thanks": { 2073 | "name": "symfony/polyfill", 2074 | "url": "https://github.com/symfony/polyfill" 2075 | } 2076 | }, 2077 | "autoload": { 2078 | "psr-4": { 2079 | "Symfony\\Polyfill\\Intl\\Grapheme\\": "" 2080 | }, 2081 | "files": [ 2082 | "bootstrap.php" 2083 | ] 2084 | }, 2085 | "notification-url": "https://packagist.org/downloads/", 2086 | "license": [ 2087 | "MIT" 2088 | ], 2089 | "authors": [ 2090 | { 2091 | "name": "Nicolas Grekas", 2092 | "email": "p@tchwork.com" 2093 | }, 2094 | { 2095 | "name": "Symfony Community", 2096 | "homepage": "https://symfony.com/contributors" 2097 | } 2098 | ], 2099 | "description": "Symfony polyfill for intl's grapheme_* functions", 2100 | "homepage": "https://symfony.com", 2101 | "keywords": [ 2102 | "compatibility", 2103 | "grapheme", 2104 | "intl", 2105 | "polyfill", 2106 | "portable", 2107 | "shim" 2108 | ], 2109 | "funding": [ 2110 | { 2111 | "url": "https://symfony.com/sponsor", 2112 | "type": "custom" 2113 | }, 2114 | { 2115 | "url": "https://github.com/fabpot", 2116 | "type": "github" 2117 | }, 2118 | { 2119 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 2120 | "type": "tidelift" 2121 | } 2122 | ], 2123 | "time": "2020-07-14T12:35:20+00:00" 2124 | }, 2125 | { 2126 | "name": "symfony/polyfill-intl-normalizer", 2127 | "version": "v1.18.1", 2128 | "source": { 2129 | "type": "git", 2130 | "url": "https://github.com/symfony/polyfill-intl-normalizer.git", 2131 | "reference": "37078a8dd4a2a1e9ab0231af7c6cb671b2ed5a7e" 2132 | }, 2133 | "dist": { 2134 | "type": "zip", 2135 | "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/37078a8dd4a2a1e9ab0231af7c6cb671b2ed5a7e", 2136 | "reference": "37078a8dd4a2a1e9ab0231af7c6cb671b2ed5a7e", 2137 | "shasum": "" 2138 | }, 2139 | "require": { 2140 | "php": ">=5.3.3" 2141 | }, 2142 | "suggest": { 2143 | "ext-intl": "For best performance" 2144 | }, 2145 | "type": "library", 2146 | "extra": { 2147 | "branch-alias": { 2148 | "dev-master": "1.18-dev" 2149 | }, 2150 | "thanks": { 2151 | "name": "symfony/polyfill", 2152 | "url": "https://github.com/symfony/polyfill" 2153 | } 2154 | }, 2155 | "autoload": { 2156 | "psr-4": { 2157 | "Symfony\\Polyfill\\Intl\\Normalizer\\": "" 2158 | }, 2159 | "files": [ 2160 | "bootstrap.php" 2161 | ], 2162 | "classmap": [ 2163 | "Resources/stubs" 2164 | ] 2165 | }, 2166 | "notification-url": "https://packagist.org/downloads/", 2167 | "license": [ 2168 | "MIT" 2169 | ], 2170 | "authors": [ 2171 | { 2172 | "name": "Nicolas Grekas", 2173 | "email": "p@tchwork.com" 2174 | }, 2175 | { 2176 | "name": "Symfony Community", 2177 | "homepage": "https://symfony.com/contributors" 2178 | } 2179 | ], 2180 | "description": "Symfony polyfill for intl's Normalizer class and related functions", 2181 | "homepage": "https://symfony.com", 2182 | "keywords": [ 2183 | "compatibility", 2184 | "intl", 2185 | "normalizer", 2186 | "polyfill", 2187 | "portable", 2188 | "shim" 2189 | ], 2190 | "funding": [ 2191 | { 2192 | "url": "https://symfony.com/sponsor", 2193 | "type": "custom" 2194 | }, 2195 | { 2196 | "url": "https://github.com/fabpot", 2197 | "type": "github" 2198 | }, 2199 | { 2200 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 2201 | "type": "tidelift" 2202 | } 2203 | ], 2204 | "time": "2020-07-14T12:35:20+00:00" 2205 | }, 2206 | { 2207 | "name": "symfony/polyfill-php73", 2208 | "version": "v1.18.1", 2209 | "source": { 2210 | "type": "git", 2211 | "url": "https://github.com/symfony/polyfill-php73.git", 2212 | "reference": "fffa1a52a023e782cdcc221d781fe1ec8f87fcca" 2213 | }, 2214 | "dist": { 2215 | "type": "zip", 2216 | "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/fffa1a52a023e782cdcc221d781fe1ec8f87fcca", 2217 | "reference": "fffa1a52a023e782cdcc221d781fe1ec8f87fcca", 2218 | "shasum": "" 2219 | }, 2220 | "require": { 2221 | "php": ">=5.3.3" 2222 | }, 2223 | "type": "library", 2224 | "extra": { 2225 | "branch-alias": { 2226 | "dev-master": "1.18-dev" 2227 | }, 2228 | "thanks": { 2229 | "name": "symfony/polyfill", 2230 | "url": "https://github.com/symfony/polyfill" 2231 | } 2232 | }, 2233 | "autoload": { 2234 | "psr-4": { 2235 | "Symfony\\Polyfill\\Php73\\": "" 2236 | }, 2237 | "files": [ 2238 | "bootstrap.php" 2239 | ], 2240 | "classmap": [ 2241 | "Resources/stubs" 2242 | ] 2243 | }, 2244 | "notification-url": "https://packagist.org/downloads/", 2245 | "license": [ 2246 | "MIT" 2247 | ], 2248 | "authors": [ 2249 | { 2250 | "name": "Nicolas Grekas", 2251 | "email": "p@tchwork.com" 2252 | }, 2253 | { 2254 | "name": "Symfony Community", 2255 | "homepage": "https://symfony.com/contributors" 2256 | } 2257 | ], 2258 | "description": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", 2259 | "homepage": "https://symfony.com", 2260 | "keywords": [ 2261 | "compatibility", 2262 | "polyfill", 2263 | "portable", 2264 | "shim" 2265 | ], 2266 | "funding": [ 2267 | { 2268 | "url": "https://symfony.com/sponsor", 2269 | "type": "custom" 2270 | }, 2271 | { 2272 | "url": "https://github.com/fabpot", 2273 | "type": "github" 2274 | }, 2275 | { 2276 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 2277 | "type": "tidelift" 2278 | } 2279 | ], 2280 | "time": "2020-07-14T12:35:20+00:00" 2281 | }, 2282 | { 2283 | "name": "symfony/process", 2284 | "version": "v5.1.5", 2285 | "source": { 2286 | "type": "git", 2287 | "url": "https://github.com/symfony/process.git", 2288 | "reference": "1864216226af21eb76d9477f691e7cbf198e0402" 2289 | }, 2290 | "dist": { 2291 | "type": "zip", 2292 | "url": "https://api.github.com/repos/symfony/process/zipball/1864216226af21eb76d9477f691e7cbf198e0402", 2293 | "reference": "1864216226af21eb76d9477f691e7cbf198e0402", 2294 | "shasum": "" 2295 | }, 2296 | "require": { 2297 | "php": ">=7.2.5", 2298 | "symfony/polyfill-php80": "^1.15" 2299 | }, 2300 | "type": "library", 2301 | "extra": { 2302 | "branch-alias": { 2303 | "dev-master": "5.1-dev" 2304 | } 2305 | }, 2306 | "autoload": { 2307 | "psr-4": { 2308 | "Symfony\\Component\\Process\\": "" 2309 | }, 2310 | "exclude-from-classmap": [ 2311 | "/Tests/" 2312 | ] 2313 | }, 2314 | "notification-url": "https://packagist.org/downloads/", 2315 | "license": [ 2316 | "MIT" 2317 | ], 2318 | "authors": [ 2319 | { 2320 | "name": "Fabien Potencier", 2321 | "email": "fabien@symfony.com" 2322 | }, 2323 | { 2324 | "name": "Symfony Community", 2325 | "homepage": "https://symfony.com/contributors" 2326 | } 2327 | ], 2328 | "description": "Symfony Process Component", 2329 | "homepage": "https://symfony.com", 2330 | "funding": [ 2331 | { 2332 | "url": "https://symfony.com/sponsor", 2333 | "type": "custom" 2334 | }, 2335 | { 2336 | "url": "https://github.com/fabpot", 2337 | "type": "github" 2338 | }, 2339 | { 2340 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 2341 | "type": "tidelift" 2342 | } 2343 | ], 2344 | "time": "2020-07-23T08:36:24+00:00" 2345 | }, 2346 | { 2347 | "name": "symfony/service-contracts", 2348 | "version": "v2.2.0", 2349 | "source": { 2350 | "type": "git", 2351 | "url": "https://github.com/symfony/service-contracts.git", 2352 | "reference": "d15da7ba4957ffb8f1747218be9e1a121fd298a1" 2353 | }, 2354 | "dist": { 2355 | "type": "zip", 2356 | "url": "https://api.github.com/repos/symfony/service-contracts/zipball/d15da7ba4957ffb8f1747218be9e1a121fd298a1", 2357 | "reference": "d15da7ba4957ffb8f1747218be9e1a121fd298a1", 2358 | "shasum": "" 2359 | }, 2360 | "require": { 2361 | "php": ">=7.2.5", 2362 | "psr/container": "^1.0" 2363 | }, 2364 | "suggest": { 2365 | "symfony/service-implementation": "" 2366 | }, 2367 | "type": "library", 2368 | "extra": { 2369 | "branch-alias": { 2370 | "dev-master": "2.2-dev" 2371 | }, 2372 | "thanks": { 2373 | "name": "symfony/contracts", 2374 | "url": "https://github.com/symfony/contracts" 2375 | } 2376 | }, 2377 | "autoload": { 2378 | "psr-4": { 2379 | "Symfony\\Contracts\\Service\\": "" 2380 | } 2381 | }, 2382 | "notification-url": "https://packagist.org/downloads/", 2383 | "license": [ 2384 | "MIT" 2385 | ], 2386 | "authors": [ 2387 | { 2388 | "name": "Nicolas Grekas", 2389 | "email": "p@tchwork.com" 2390 | }, 2391 | { 2392 | "name": "Symfony Community", 2393 | "homepage": "https://symfony.com/contributors" 2394 | } 2395 | ], 2396 | "description": "Generic abstractions related to writing services", 2397 | "homepage": "https://symfony.com", 2398 | "keywords": [ 2399 | "abstractions", 2400 | "contracts", 2401 | "decoupling", 2402 | "interfaces", 2403 | "interoperability", 2404 | "standards" 2405 | ], 2406 | "funding": [ 2407 | { 2408 | "url": "https://symfony.com/sponsor", 2409 | "type": "custom" 2410 | }, 2411 | { 2412 | "url": "https://github.com/fabpot", 2413 | "type": "github" 2414 | }, 2415 | { 2416 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 2417 | "type": "tidelift" 2418 | } 2419 | ], 2420 | "time": "2020-09-07T11:33:47+00:00" 2421 | }, 2422 | { 2423 | "name": "symfony/string", 2424 | "version": "v5.1.5", 2425 | "source": { 2426 | "type": "git", 2427 | "url": "https://github.com/symfony/string.git", 2428 | "reference": "0de4cc1e18bb596226c06a82e2e7e9bc6001a63a" 2429 | }, 2430 | "dist": { 2431 | "type": "zip", 2432 | "url": "https://api.github.com/repos/symfony/string/zipball/0de4cc1e18bb596226c06a82e2e7e9bc6001a63a", 2433 | "reference": "0de4cc1e18bb596226c06a82e2e7e9bc6001a63a", 2434 | "shasum": "" 2435 | }, 2436 | "require": { 2437 | "php": ">=7.2.5", 2438 | "symfony/polyfill-ctype": "~1.8", 2439 | "symfony/polyfill-intl-grapheme": "~1.0", 2440 | "symfony/polyfill-intl-normalizer": "~1.0", 2441 | "symfony/polyfill-mbstring": "~1.0", 2442 | "symfony/polyfill-php80": "~1.15" 2443 | }, 2444 | "require-dev": { 2445 | "symfony/error-handler": "^4.4|^5.0", 2446 | "symfony/http-client": "^4.4|^5.0", 2447 | "symfony/translation-contracts": "^1.1|^2", 2448 | "symfony/var-exporter": "^4.4|^5.0" 2449 | }, 2450 | "type": "library", 2451 | "extra": { 2452 | "branch-alias": { 2453 | "dev-master": "5.1-dev" 2454 | } 2455 | }, 2456 | "autoload": { 2457 | "psr-4": { 2458 | "Symfony\\Component\\String\\": "" 2459 | }, 2460 | "files": [ 2461 | "Resources/functions.php" 2462 | ], 2463 | "exclude-from-classmap": [ 2464 | "/Tests/" 2465 | ] 2466 | }, 2467 | "notification-url": "https://packagist.org/downloads/", 2468 | "license": [ 2469 | "MIT" 2470 | ], 2471 | "authors": [ 2472 | { 2473 | "name": "Nicolas Grekas", 2474 | "email": "p@tchwork.com" 2475 | }, 2476 | { 2477 | "name": "Symfony Community", 2478 | "homepage": "https://symfony.com/contributors" 2479 | } 2480 | ], 2481 | "description": "Symfony String component", 2482 | "homepage": "https://symfony.com", 2483 | "keywords": [ 2484 | "grapheme", 2485 | "i18n", 2486 | "string", 2487 | "unicode", 2488 | "utf-8", 2489 | "utf8" 2490 | ], 2491 | "funding": [ 2492 | { 2493 | "url": "https://symfony.com/sponsor", 2494 | "type": "custom" 2495 | }, 2496 | { 2497 | "url": "https://github.com/fabpot", 2498 | "type": "github" 2499 | }, 2500 | { 2501 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 2502 | "type": "tidelift" 2503 | } 2504 | ], 2505 | "time": "2020-08-17T07:48:54+00:00" 2506 | }, 2507 | { 2508 | "name": "symfony/yaml", 2509 | "version": "v5.1.5", 2510 | "source": { 2511 | "type": "git", 2512 | "url": "https://github.com/symfony/yaml.git", 2513 | "reference": "a44bd3a91bfbf8db12367fa6ffac9c3eb1a8804a" 2514 | }, 2515 | "dist": { 2516 | "type": "zip", 2517 | "url": "https://api.github.com/repos/symfony/yaml/zipball/a44bd3a91bfbf8db12367fa6ffac9c3eb1a8804a", 2518 | "reference": "a44bd3a91bfbf8db12367fa6ffac9c3eb1a8804a", 2519 | "shasum": "" 2520 | }, 2521 | "require": { 2522 | "php": ">=7.2.5", 2523 | "symfony/deprecation-contracts": "^2.1", 2524 | "symfony/polyfill-ctype": "~1.8" 2525 | }, 2526 | "conflict": { 2527 | "symfony/console": "<4.4" 2528 | }, 2529 | "require-dev": { 2530 | "symfony/console": "^4.4|^5.0" 2531 | }, 2532 | "suggest": { 2533 | "symfony/console": "For validating YAML files using the lint command" 2534 | }, 2535 | "bin": [ 2536 | "Resources/bin/yaml-lint" 2537 | ], 2538 | "type": "library", 2539 | "extra": { 2540 | "branch-alias": { 2541 | "dev-master": "5.1-dev" 2542 | } 2543 | }, 2544 | "autoload": { 2545 | "psr-4": { 2546 | "Symfony\\Component\\Yaml\\": "" 2547 | }, 2548 | "exclude-from-classmap": [ 2549 | "/Tests/" 2550 | ] 2551 | }, 2552 | "notification-url": "https://packagist.org/downloads/", 2553 | "license": [ 2554 | "MIT" 2555 | ], 2556 | "authors": [ 2557 | { 2558 | "name": "Fabien Potencier", 2559 | "email": "fabien@symfony.com" 2560 | }, 2561 | { 2562 | "name": "Symfony Community", 2563 | "homepage": "https://symfony.com/contributors" 2564 | } 2565 | ], 2566 | "description": "Symfony Yaml Component", 2567 | "homepage": "https://symfony.com", 2568 | "funding": [ 2569 | { 2570 | "url": "https://symfony.com/sponsor", 2571 | "type": "custom" 2572 | }, 2573 | { 2574 | "url": "https://github.com/fabpot", 2575 | "type": "github" 2576 | }, 2577 | { 2578 | "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", 2579 | "type": "tidelift" 2580 | } 2581 | ], 2582 | "time": "2020-08-26T08:30:57+00:00" 2583 | }, 2584 | { 2585 | "name": "webmozart/assert", 2586 | "version": "1.9.1", 2587 | "source": { 2588 | "type": "git", 2589 | "url": "https://github.com/webmozart/assert.git", 2590 | "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389" 2591 | }, 2592 | "dist": { 2593 | "type": "zip", 2594 | "url": "https://api.github.com/repos/webmozart/assert/zipball/bafc69caeb4d49c39fd0779086c03a3738cbb389", 2595 | "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389", 2596 | "shasum": "" 2597 | }, 2598 | "require": { 2599 | "php": "^5.3.3 || ^7.0 || ^8.0", 2600 | "symfony/polyfill-ctype": "^1.8" 2601 | }, 2602 | "conflict": { 2603 | "phpstan/phpstan": "<0.12.20", 2604 | "vimeo/psalm": "<3.9.1" 2605 | }, 2606 | "require-dev": { 2607 | "phpunit/phpunit": "^4.8.36 || ^7.5.13" 2608 | }, 2609 | "type": "library", 2610 | "autoload": { 2611 | "psr-4": { 2612 | "Webmozart\\Assert\\": "src/" 2613 | } 2614 | }, 2615 | "notification-url": "https://packagist.org/downloads/", 2616 | "license": [ 2617 | "MIT" 2618 | ], 2619 | "authors": [ 2620 | { 2621 | "name": "Bernhard Schussek", 2622 | "email": "bschussek@gmail.com" 2623 | } 2624 | ], 2625 | "description": "Assertions to validate method input/output with nice error messages.", 2626 | "keywords": [ 2627 | "assert", 2628 | "check", 2629 | "validate" 2630 | ], 2631 | "time": "2020-07-08T17:02:28+00:00" 2632 | } 2633 | ], 2634 | "aliases": [], 2635 | "minimum-stability": "stable", 2636 | "stability-flags": [], 2637 | "prefer-stable": false, 2638 | "prefer-lowest": false, 2639 | "platform": [], 2640 | "platform-dev": [], 2641 | "plugin-api-version": "1.1.0" 2642 | } 2643 | -------------------------------------------------------------------------------- /phpspec.yml: -------------------------------------------------------------------------------- 1 | suites: 2 | main: 3 | namespace: Laracasts\Generators 4 | psr4_prefix: Laracasts\Generators 5 | src_path: src -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Extended Migration Generators for Laravel 6, 7, 8 and 9 2 | 3 | 4 | 5 | 6 | 7 | 8 | Easily define the migration schema right in your `make:migration` command. The new commands this package provides are: 9 | - `make:migration:schema` 10 | - `make:migration:pivot` 11 | 12 | Which allows you to do `php artisan make:migration:schema create_dogs_table --schema="name:string:nullable, description:text, age:integer, email:string:unique"` and get a full migration that you can run using `php artisan migrate`. For simple cases like this one, no need to tinker inside the migration file itself. And if you do need to change anything, it's easier because the bulk of the code has already been generated. 13 | 14 | Created in 2015 by [Jeffrey Way](https://github.com/jeffreyway) as a natural progression of his [JeffreyWay/Laravel-4-Generators](https://github.com/JeffreyWay/Laravel-4-Generators) package, to provide the same features for Laravel 5. Since 2017 it's been maintained by the [Backpack for Laravel](https://github.com/laravel-backpack/crud) team, with features and fixes added by community members like you. So feel free to pitch in. 15 | 16 | ![https://user-images.githubusercontent.com/1032474/92732702-cd8b3700-f344-11ea-8e3b-ae86501d66fe.gif](https://user-images.githubusercontent.com/1032474/92732702-cd8b3700-f344-11ea-8e3b-ae86501d66fe.gif) 17 | 18 | ## Table of Contents 19 | 20 | * [Versions](#versions) 21 | * [Installation](#installation) 22 | * [Examples](#examples) 23 | + [Migrations With Schema](#migrations-with-schema) 24 | - [Foreign Constraints](#foreign-constraints) 25 | + [Pivot Tables](#pivot-tables) 26 | 27 | ## Versions 28 | 29 | Depending on your Laravel version, you should: 30 | - use [JeffreyWay/Laravel-4-Generators](https://github.com/JeffreyWay/Laravel-4-Generators) for Laravel 4; 31 | - use [`v1` of this package](https://github.com/laracasts/Laravel-5-Generators-Extended/tree/v1) for Laravel 5.0 - 5.8; 32 | - use `v2` of this package for Laravel 6-8; 33 | 34 | ## Installation 35 | 36 | You can install v2 of this project using composer, the service provider will be automatically loaded by Laravel itself: 37 | 38 | ``` 39 | composer require --dev laracasts/generators 40 | ``` 41 | 42 | You're all set. Run `php artisan` from the console, and you'll see the new commands in the `make:*` namespace section. 43 | 44 | 45 | ## Examples 46 | 47 | - [Migrations With Schema](#migrations-with-schema) 48 | - [Pivot Tables](#pivot-tables) 49 | 50 | ### Migrations With Schema 51 | 52 | ``` 53 | php artisan make:migration:schema create_users_table --schema="username:string, email:string:unique" 54 | ``` 55 | 56 | Notice the format that we use, when declaring any applicable schema: a comma-separated list... 57 | 58 | ``` 59 | COLUMN_NAME:COLUMN_TYPE 60 | ``` 61 | 62 | So any of these will do: 63 | 64 | ``` 65 | username:string 66 | body:text 67 | age:integer 68 | published_at:date 69 | excerpt:text:nullable 70 | email:string:unique:default('foo@example.com') 71 | ``` 72 | 73 | Using the schema from earlier... 74 | 75 | ``` 76 | --schema="username:string, email:string:unique" 77 | ``` 78 | 79 | ...this will give you: 80 | 81 | ```php 82 | increments('id'); 98 | $table->string('username'); 99 | $table->string('email')->unique(); 100 | $table->timestamps(); 101 | }); 102 | } 103 | 104 | /** 105 | * Reverse the migrations. 106 | * 107 | * @return void 108 | */ 109 | public function down() 110 | { 111 | Schema::drop('users'); 112 | } 113 | 114 | } 115 | ``` 116 | 117 | When generating migrations with schema, the name of your migration (like, "create_users_table") matters. We use it to figure out what you're trying to accomplish. In this case, we began with the "create" keyword, which signals that we want to create a 118 | new table. 119 | 120 | Alternatively, we can use the "remove" or "add" keywords, and the generated boilerplate will adapt, as needed. Let's create a migration to remove a column. 121 | 122 | ``` 123 | php artisan make:migration:schema remove_user_id_from_posts_table --schema="user_id:integer" 124 | ``` 125 | 126 | Now, notice that we're using the correct Schema methods. 127 | 128 | ```php 129 | dropColumn('user_id'); 145 | }); 146 | } 147 | 148 | /** 149 | * Reverse the migrations. 150 | * 151 | * @return void 152 | */ 153 | public function down() 154 | { 155 | Schema::table('posts', function(Blueprint $table) { 156 | $table->integer('user_id'); 157 | }); 158 | } 159 | 160 | } 161 | ``` 162 | 163 | Here's a few other examples of commands that you might write: 164 | 165 | - `php artisan make:migration:schema create_posts_table` 166 | - `php artisan make:migration:schema create_posts_table --schema="title:string, body:text, excerpt:string:nullable"` 167 | - `php artisan make:migration:schema remove_excerpt_from_posts_table --schema="excerpt:string:nullable"` 168 | 169 | #### Models 170 | 171 | Now, when you create a migration, you typically want a model to go with it, right? By default, this package won't create a model to go with the migration. But it could. Just specify `--model=true` and it will do that for you: 172 | 173 | ``` 174 | php artisan make:migration:schema create_dogs_table --schema="name:string" --model=true 175 | ``` 176 | 177 | #### Migration Path 178 | 179 | If you wish to specify a different path for your migration file, you can use the `--path` option like so: 180 | 181 | ``` 182 | php artisan make:migration:schema create_dogs_table --path=\database\migrations\pets 183 | ``` 184 | 185 | #### Foreign Constraints 186 | 187 | There's also a secret bit of sugar for when you need to generate foreign constraints. Imagine that you have a posts table, where each post belongs to a user. Let's try: 188 | 189 | ``` 190 | php artisan make:migration:schema create_posts_table --schema="user_id:unsignedInteger:foreign, title:string, body:text" 191 | ``` 192 | 193 | Notice that "foreign" option (`user_id:unsignedInteger:foreign`)? That's special. It signals that `user_id` should receive a foreign constraint. Following conventions, this will give us: 194 | 195 | ``` 196 | $table->unsignedInteger('user_id'); 197 | $table->foreign('user_id')->references('id')->on('users'); 198 | ``` 199 | 200 | As such, for that full command, our schema should look like so: 201 | 202 | ``` 203 | Schema::create('posts', function(Blueprint $table) { 204 | $table->increments('id'); 205 | $table->unsignedInteger('user_id'); 206 | $table->foreign('user_id')->references('id')->on('users'); 207 | $table->string('title'); 208 | $table->text('body'); 209 | $table->timestamps(); 210 | ); 211 | ``` 212 | 213 | Neato. 214 | 215 | ### Pivot Tables 216 | 217 | So you need a migration to setup a pivot table in your database? Easy. We can scaffold the whole class with a single command. 218 | 219 | ``` 220 | php artisan make:migration:pivot tags posts 221 | ``` 222 | 223 | Here we pass, in any order, the names of the two tables that we need a joining/pivot table for. This will give you: 224 | 225 | ```php 226 | integer('post_id')->unsigned()->index(); 242 | $table->foreign('post_id')->references('id')->on('posts')->onDelete('cascade'); 243 | $table->integer('tag_id')->unsigned()->index(); 244 | $table->foreign('tag_id')->references('id')->on('tags')->onDelete('cascade'); 245 | }); 246 | } 247 | 248 | /** 249 | * Reverse the migrations. 250 | * 251 | * @return void 252 | */ 253 | public function down() 254 | { 255 | Schema::drop('post_tag'); 256 | } 257 | 258 | } 259 | ``` 260 | 261 | > Notice that the naming conventions are being followed here, regardless of what order you pass the table names. 262 | -------------------------------------------------------------------------------- /spec/Migrations/NameParserSpec.php: -------------------------------------------------------------------------------- 1 | shouldHaveType('Laracasts\Generators\Migrations\NameParser'); 12 | } 13 | 14 | function it_parses_a_migration_name_into_an_array() 15 | { 16 | $this->parse('create_posts_table')->shouldReturn([ 17 | 'action' => 'create', 18 | 'table' => 'posts' 19 | ]); 20 | } 21 | 22 | function it_parses_a_migration_name_where_the_table_is_two_words() 23 | { 24 | $this->parse('create_yearly_reports_table')->shouldReturn([ 25 | 'action' => 'create', 26 | 'table' => 'yearly_reports' 27 | ]); 28 | } 29 | 30 | function it_parses_a_complex_migration_name() 31 | { 32 | $this->parse('add_user_id_to_reports_table')->shouldReturn([ 33 | 'action' => 'add', 34 | 'table' => 'reports' 35 | ]); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /spec/Migrations/SchemaParserSpec.php: -------------------------------------------------------------------------------- 1 | shouldHaveType('Laracasts\Generators\Migrations\SchemaParser'); 12 | } 13 | 14 | function it_parses_a_basic_string_schema() 15 | { 16 | $this->parse('name:string')->shouldReturn([ 17 | ['name' => 'name', 'type' => 'string', 'arguments' => [], 'options' => []] 18 | ]); 19 | } 20 | 21 | function it_parses_schema_with_multiple_fields() 22 | { 23 | $this->parse('name:string, age:integer')->shouldReturn([ 24 | ['name' => 'name', 'type' => 'string', 'arguments' => [], 'options' => []], 25 | ['name' => 'age', 'type' => 'integer', 'arguments' => [], 'options' => []], 26 | ]); 27 | } 28 | 29 | function it_parses_schema_that_includes_extras() 30 | { 31 | $this->parse('age:integer:nullable:default(21)')->shouldReturn([ 32 | ['name' => 'age', 'type' => 'integer', 'arguments' => [], 'options' => ['nullable' => true, 'default' => '21']] 33 | ]); 34 | } 35 | 36 | function it_parses_correctly_when_the_type_contains_method_arguments() 37 | { 38 | $this->parse('amount:decimal(5,2)')->shouldReturn([ 39 | ['name' => 'amount', 'type' => 'decimal', 'arguments' => ['5', '2'], 'options' => []] 40 | ]); 41 | } 42 | 43 | function it_parses_schema_with_multiple_fields_using_no_spaces() 44 | { 45 | $this->parse('name:string,amount:decimal(5,2)')->shouldReturn([ 46 | ['name' => 'name', 'type' => 'string', 'arguments' => [], 'options' => []], 47 | ['name' => 'amount', 'type' => 'decimal', 'arguments' => ['5', '2'], 'options' => []] 48 | ]); 49 | } 50 | 51 | function it_parses_schema_fields_that_want_foreign_constraints() 52 | { 53 | $this->parse('user_id:integer:foreign')->shouldReturn([ 54 | ['name' => 'user_id', 'type' => 'integer', 'arguments' => [], 'options' => []], 55 | ['name' => 'user_id', 'type' => 'foreign', 'arguments' => [], 'options' => ['references' => "'id'", 'on' => "'users'"]] 56 | ]); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /spec/Migrations/SyntaxBuilderSpec.php: -------------------------------------------------------------------------------- 1 | shouldHaveType('Laracasts\Generators\Migrations\SyntaxBuilder'); 12 | } 13 | 14 | function it_creates_the_php_syntax_for_the_schema() 15 | { 16 | $schema = [[ 17 | "name" => "email", 18 | "type" => "string", 19 | "arguments" => ["100"], 20 | "options" => [ 21 | "unique" => true, 22 | "nullable" => true, 23 | "default" => '"foo@example.com"' 24 | ] 25 | ]]; 26 | 27 | $this->create($schema, ['table' => 'posts', 'action' => 'create'])['up']->shouldBe(getStub()); 28 | $this->create($schema, ['table' => 'posts', 'action' => 'create'])['down']->shouldBe("Schema::dropIfExists('posts');"); 29 | } 30 | 31 | } 32 | 33 | function getStub() 34 | { 35 | return <<bigIncrements('id'); 38 | \$table->string('email', 100)->unique()->nullable()->default("foo@example.com"); 39 | \$table->timestamps(); 40 | }); 41 | EOT; 42 | } 43 | -------------------------------------------------------------------------------- /src/Commands/MigrationMakeCommand.php: -------------------------------------------------------------------------------- 1 | files = $files; 61 | $this->composer = app()['composer']; 62 | } 63 | 64 | /** 65 | * Alias for the fire method. 66 | * 67 | * In Laravel 5.5 the fire() method has been renamed to handle(). 68 | * This alias provides support for both Laravel 5.4 and 5.5. 69 | */ 70 | public function handle() 71 | { 72 | $this->fire(); 73 | } 74 | 75 | /** 76 | * Execute the console command. 77 | * 78 | * @return mixed 79 | */ 80 | public function fire() 81 | { 82 | $this->meta = (new NameParser)->parse($this->argument('name')); 83 | 84 | $this->makeMigration(); 85 | $this->makeModel(); 86 | 87 | $this->composer->dumpAutoloads(); 88 | } 89 | 90 | /** 91 | * Get the application namespace. 92 | * 93 | * @return string 94 | */ 95 | protected function getAppNamespace() 96 | { 97 | return Container::getInstance()->getNamespace(); 98 | } 99 | 100 | /** 101 | * Generate the desired migration. 102 | */ 103 | protected function makeMigration() 104 | { 105 | $name = $this->argument('name'); 106 | 107 | if ($this->files->exists($path = $this->getPath($name))) { 108 | return $this->error($this->type . ' already exists!'); 109 | } 110 | 111 | $this->makeDirectory($path); 112 | 113 | $this->files->put($path, $this->compileMigrationStub()); 114 | 115 | $filename = pathinfo($path, PATHINFO_FILENAME); 116 | $this->line("Created Migration: {$filename}"); 117 | } 118 | 119 | /** 120 | * Generate an Eloquent model, if the user wishes. 121 | */ 122 | protected function makeModel() 123 | { 124 | $modelPath = $this->getModelPath($this->getModelName()); 125 | 126 | if ($this->option('model') && !$this->files->exists($modelPath)) { 127 | $this->call('make:model', [ 128 | 'name' => $this->getModelName() 129 | ]); 130 | } 131 | } 132 | 133 | /** 134 | * Build the directory for the class if necessary. 135 | * 136 | * @param string $path 137 | * @return string 138 | */ 139 | protected function makeDirectory($path) 140 | { 141 | if (!$this->files->isDirectory(dirname($path))) { 142 | $this->files->makeDirectory(dirname($path), 0777, true, true); 143 | } 144 | } 145 | 146 | /** 147 | * Get the path to where we should store the migration. 148 | * 149 | * @param string $name 150 | * @return string 151 | */ 152 | protected function getPath($name) 153 | { 154 | $path = ($this->option('path')) 155 | ? base_path().$this->option('path').'/'.date('Y_m_d_His').'_'.$name.'.php' 156 | : base_path().'/database/migrations/'.date('Y_m_d_His').'_'.$name.'.php'; 157 | 158 | return $path; 159 | } 160 | 161 | /** 162 | * Get the destination class path. 163 | * 164 | * @param string $name 165 | * @return string 166 | */ 167 | protected function getModelPath($name) 168 | { 169 | $name = str_replace($this->getAppNamespace(), '', $name); 170 | 171 | return $this->laravel['path'] . '/' . str_replace('\\', '/', $name) . '.php'; 172 | } 173 | 174 | /** 175 | * Compile the migration stub. 176 | * 177 | * @return string 178 | */ 179 | protected function compileMigrationStub() 180 | { 181 | $stub = $this->files->get(__DIR__ . '/../stubs/migration.stub'); 182 | 183 | $this->replaceClassName($stub) 184 | ->replaceSchema($stub) 185 | ->replaceTableName($stub); 186 | 187 | return $stub; 188 | } 189 | 190 | /** 191 | * Replace the class name in the stub. 192 | * 193 | * @param string $stub 194 | * @return $this 195 | */ 196 | protected function replaceClassName(&$stub) 197 | { 198 | $className = ucwords(Str::camel($this->argument('name'))); 199 | 200 | $stub = str_replace('{{class}}', $className, $stub); 201 | 202 | return $this; 203 | } 204 | 205 | /** 206 | * Replace the table name in the stub. 207 | * 208 | * @param string $stub 209 | * @return $this 210 | */ 211 | protected function replaceTableName(&$stub) 212 | { 213 | $table = $this->meta['table']; 214 | 215 | $stub = str_replace('{{table}}', $table, $stub); 216 | 217 | return $this; 218 | } 219 | 220 | /** 221 | * Replace the schema for the stub. 222 | * 223 | * @param string $stub 224 | * @return $this 225 | */ 226 | protected function replaceSchema(&$stub) 227 | { 228 | if ($schema = $this->option('schema')) { 229 | $schema = (new SchemaParser)->parse($schema); 230 | } 231 | 232 | $schema = (new SyntaxBuilder)->create($schema, $this->meta); 233 | 234 | $stub = str_replace(['{{schema_up}}', '{{schema_down}}'], $schema, $stub); 235 | 236 | return $this; 237 | } 238 | 239 | /** 240 | * Get the class name for the Eloquent model generator. 241 | * 242 | * @return string 243 | */ 244 | protected function getModelName() 245 | { 246 | return ucwords(Str::singular(Str::camel($this->meta['table']))); 247 | } 248 | 249 | /** 250 | * Get the console command arguments. 251 | * 252 | * @return array 253 | */ 254 | protected function getArguments() 255 | { 256 | return [ 257 | ['name', InputArgument::REQUIRED, 'The name of the migration'], 258 | ]; 259 | } 260 | 261 | /** 262 | * Get the console command options. 263 | * 264 | * @return array 265 | */ 266 | protected function getOptions() 267 | { 268 | return [ 269 | ['schema', 's', InputOption::VALUE_OPTIONAL, 'Optional schema to be attached to the migration', null], 270 | ['model', null, InputOption::VALUE_OPTIONAL, 'Want a model for this table?', false], 271 | ['path', null, InputOption::VALUE_OPTIONAL, 'Optional path for a migration.', false], 272 | ]; 273 | } 274 | } 275 | -------------------------------------------------------------------------------- /src/Commands/PivotMigrationMakeCommand.php: -------------------------------------------------------------------------------- 1 | getSortedSingularTableNames())); 49 | 50 | $name = preg_replace_callback('/(\_)([a-z]{1})/', function ($matches) { 51 | return Str::studly($matches[0]); 52 | }, $name); 53 | 54 | return "Create{$name}PivotTable"; 55 | } 56 | 57 | /** 58 | * Get the stub file for the generator. 59 | * 60 | * @return string 61 | */ 62 | protected function getStub() 63 | { 64 | return __DIR__ . '/../stubs/pivot.stub'; 65 | } 66 | 67 | /** 68 | * Get the destination class path. 69 | * 70 | * @param string $name 71 | * @return string 72 | */ 73 | protected function getPath($name = null) 74 | { 75 | return base_path() . '/database/migrations/' . date('Y_m_d_His') . 76 | '_create_' . $this->getPivotTableName() . '_pivot_table.php'; 77 | } 78 | 79 | /** 80 | * Build the class with the given name. 81 | * 82 | * @param string $name 83 | * @return string 84 | */ 85 | protected function buildClass($name = null) 86 | { 87 | $stub = $this->files->get($this->getStub()); 88 | 89 | return $this->replacePivotTableName($stub) 90 | ->replaceSchema($stub) 91 | ->replaceClass($stub, $this->getClassName()); 92 | } 93 | 94 | /** 95 | * Apply the name of the pivot table to the stub. 96 | * 97 | * @param string $stub 98 | * @return $this 99 | */ 100 | protected function replacePivotTableName(&$stub) 101 | { 102 | $stub = str_replace('{{pivotTableName}}', $this->getPivotTableName(), $stub); 103 | 104 | return $this; 105 | } 106 | 107 | /** 108 | * Apply the correct schema to the stub. 109 | * 110 | * @param string $stub 111 | * @return $this 112 | */ 113 | protected function replaceSchema(&$stub) 114 | { 115 | $tables = array_merge( 116 | $this->getSortedSingularTableNames(), 117 | $this->getSortedTableNames() 118 | ); 119 | 120 | $stub = str_replace( 121 | ['{{columnOne}}', '{{columnTwo}}', '{{tableOne}}', '{{tableTwo}}'], 122 | $tables, 123 | $stub 124 | ); 125 | 126 | return $this; 127 | } 128 | 129 | /** 130 | * Replace the class name for the given stub. 131 | * 132 | * @param string $stub 133 | * @param string $name 134 | * @return string 135 | */ 136 | protected function replaceClass($stub, $name) 137 | { 138 | $stub = str_replace('{{class}}', $name, $stub); 139 | 140 | return $stub; 141 | } 142 | 143 | /** 144 | * Get the name of the pivot table. 145 | * 146 | * @return string 147 | */ 148 | protected function getPivotTableName() 149 | { 150 | return implode('_', $this->getSortedSingularTableNames()); 151 | } 152 | 153 | /** 154 | * Sort the two tables in alphabetical order. 155 | * 156 | * @return array 157 | */ 158 | protected function getSortedTableNames() 159 | { 160 | $tables = $this->getTableNamesFromInput(); 161 | 162 | sort($tables); 163 | 164 | return $tables; 165 | } 166 | 167 | /** 168 | * Sort the two tables in alphabetical order, in singular form. 169 | * @return array 170 | */ 171 | protected function getSortedSingularTableNames() 172 | { 173 | $tables = array_map('Str::singular', $this->getTableNamesFromInput()); 174 | 175 | sort($tables); 176 | 177 | return $tables; 178 | } 179 | 180 | /** 181 | * Get the table names from input. 182 | * 183 | * @return array 184 | */ 185 | protected function getTableNamesFromInput() 186 | { 187 | return [ 188 | strtolower($this->argument('tableOne')), 189 | strtolower($this->argument('tableTwo')) 190 | ]; 191 | } 192 | 193 | /** 194 | * Get the console command arguments. 195 | * 196 | * @return array 197 | */ 198 | protected function getArguments() 199 | { 200 | return [ 201 | ['tableOne', InputArgument::REQUIRED, 'The name of the first table.'], 202 | ['tableTwo', InputArgument::REQUIRED, 'The name of the second table.'] 203 | ]; 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /src/GeneratorException.php: -------------------------------------------------------------------------------- 1 | registerMigrationGenerator(); 27 | $this->registerPivotMigrationGenerator(); 28 | } 29 | 30 | /** 31 | * Register the make:migration generator. 32 | */ 33 | private function registerMigrationGenerator() 34 | { 35 | $this->app->singleton('command.laracasts.migrate', function ($app) { 36 | return $app['Laracasts\Generators\Commands\MigrationMakeCommand']; 37 | }); 38 | 39 | $this->commands('command.laracasts.migrate'); 40 | } 41 | 42 | /** 43 | * Register the make:pivot generator. 44 | */ 45 | private function registerPivotMigrationGenerator() 46 | { 47 | $this->app->singleton('command.laracasts.migrate.pivot', function ($app) { 48 | return $app['Laracasts\Generators\Commands\PivotMigrationMakeCommand']; 49 | }); 50 | 51 | $this->commands('command.laracasts.migrate.pivot'); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Migrations/NameParser.php: -------------------------------------------------------------------------------- 1 | $this->getAction($segments), 23 | 'table' => $this->getTableName($segments) 24 | ]; 25 | } 26 | 27 | /** 28 | * Calculate the table name. 29 | * 30 | * @param array $segments 31 | * @return array 32 | */ 33 | private function getTableName($segments) 34 | { 35 | $tableName = []; 36 | 37 | foreach ($segments as $segment) { 38 | if ($this->isConnectingWord($segment)) { 39 | break; 40 | } 41 | 42 | $tableName[] = $segment; 43 | } 44 | 45 | return implode('_', array_reverse($tableName)); 46 | } 47 | 48 | /** 49 | * Determine the user's desired action for the migration. 50 | * 51 | * @param array $segments 52 | * @return mixed 53 | */ 54 | private function getAction(&$segments) 55 | { 56 | return $this->normalizeActionName(array_pop($segments)); 57 | } 58 | 59 | /** 60 | * Normalize the user's chosen action to name to 61 | * something that we recognize. 62 | * 63 | * @param string $action 64 | * @return string 65 | */ 66 | private function normalizeActionName($action) 67 | { 68 | switch ($action) { 69 | case 'create': 70 | case 'make': 71 | return 'create'; 72 | case 'delete': 73 | case 'destroy': 74 | case 'drop': 75 | return 'remove'; 76 | case 'add': 77 | case 'append': 78 | case 'update': 79 | case 'insert': 80 | return 'add'; 81 | default: 82 | return $action; 83 | } 84 | } 85 | 86 | /** 87 | * Determine if the current segment is a connecting word. 88 | * 89 | * @param string $segment 90 | * @return bool 91 | */ 92 | private function isConnectingWord($segment) 93 | { 94 | $connectors = ['to', 'from', 'and', 'with', 'for', 'in', 'of', 'on']; 95 | 96 | return in_array($segment, $connectors); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /src/Migrations/SchemaParser.php: -------------------------------------------------------------------------------- 1 | splitIntoFields($schema); 26 | 27 | foreach ($fields as $field) { 28 | $segments = $this->parseSegments($field); 29 | 30 | if ($this->fieldNeedsForeignConstraint($segments)) { 31 | unset($segments['options']['foreign']); 32 | 33 | // If the user wants a foreign constraint, then 34 | // we'll first add the regular field. 35 | $this->addField($segments); 36 | 37 | // And then add another field for the constraint. 38 | $this->addForeignConstraint($segments); 39 | 40 | continue; 41 | } 42 | 43 | $this->addField($segments); 44 | } 45 | 46 | return $this->schema; 47 | } 48 | 49 | /** 50 | * Add a field to the schema array. 51 | * 52 | * @param array $field 53 | * @return $this 54 | */ 55 | private function addField($field) 56 | { 57 | $this->schema[] = $field; 58 | 59 | return $this; 60 | } 61 | 62 | /** 63 | * Get an array of fields from the given schema. 64 | * 65 | * @param string $schema 66 | * @return array 67 | */ 68 | private function splitIntoFields($schema) 69 | { 70 | return preg_split('/,\s?(?![^()]*\))/', $schema); 71 | } 72 | 73 | /** 74 | * Get the segments of the schema field. 75 | * 76 | * @param string $field 77 | * @return array 78 | */ 79 | private function parseSegments($field) 80 | { 81 | $segments = explode(':', $field); 82 | 83 | $name = array_shift($segments); 84 | $type = array_shift($segments); 85 | $arguments = []; 86 | $options = $this->parseOptions($segments); 87 | 88 | // Do we have arguments being used here? 89 | // Like: string(100) 90 | if (preg_match('/(.+?)\(([^)]+)\)/', $type, $matches)) { 91 | $type = $matches[1]; 92 | $arguments = explode(',', $matches[2]); 93 | } 94 | 95 | return compact('name', 'type', 'arguments', 'options'); 96 | } 97 | 98 | /** 99 | * Parse any given options into something usable. 100 | * 101 | * @param array $options 102 | * @return array 103 | */ 104 | private function parseOptions($options) 105 | { 106 | if (empty($options)) return []; 107 | 108 | foreach ($options as $option) { 109 | if (Str::contains($option, '(')) { 110 | preg_match('/([a-z]+)\(([^\)]+)\)/i', $option, $matches); 111 | 112 | $results[$matches[1]] = $matches[2]; 113 | } else { 114 | $results[$option] = true; 115 | } 116 | } 117 | 118 | return $results; 119 | } 120 | 121 | /** 122 | * Add a foreign constraint field to the schema. 123 | * 124 | * @param array $segments 125 | */ 126 | private function addForeignConstraint($segments) 127 | { 128 | $string = sprintf( 129 | "%s:foreign:references('id'):on('%s')", 130 | $segments['name'], 131 | $this->getTableNameFromForeignKey($segments['name']) 132 | ); 133 | 134 | $this->addField($this->parseSegments($string)); 135 | } 136 | 137 | /** 138 | * Try to figure out the name of a table from a foreign key. 139 | * Ex: user_id => users 140 | * 141 | * @param string $key 142 | * @return string 143 | */ 144 | private function getTableNameFromForeignKey($key) 145 | { 146 | return Str::plural(str_replace('_id', '', $key)); 147 | } 148 | 149 | /** 150 | * Determine if the user wants a foreign constraint for the field. 151 | * 152 | * @param array $segments 153 | * @return bool 154 | */ 155 | private function fieldNeedsForeignConstraint($segments) 156 | { 157 | return array_key_exists('foreign', $segments['options']); 158 | } 159 | } 160 | 161 | -------------------------------------------------------------------------------- /src/Migrations/SyntaxBuilder.php: -------------------------------------------------------------------------------- 1 | createSchemaForUpMethod($schema, $meta); 27 | $down = $this->createSchemaForDownMethod($schema, $meta); 28 | 29 | return compact('up', 'down'); 30 | } 31 | 32 | /** 33 | * Create the schema for the "up" method. 34 | * 35 | * @param string $schema 36 | * @param array $meta 37 | * @return string 38 | * @throws GeneratorException 39 | */ 40 | private function createSchemaForUpMethod($schema, $meta) 41 | { 42 | $fields = $this->constructSchema($schema); 43 | 44 | if ($meta['action'] == 'create') { 45 | return $this->insert($fields)->into($this->getCreateSchemaWrapper()); 46 | } 47 | 48 | if ($meta['action'] == 'add') { 49 | return $this->insert($fields)->into($this->getChangeSchemaWrapper()); 50 | } 51 | 52 | if ($meta['action'] == 'remove') { 53 | $fields = $this->constructSchema($schema, 'Drop'); 54 | 55 | return $this->insert($fields)->into($this->getChangeSchemaWrapper()); 56 | } 57 | 58 | // Otherwise, we have no idea how to proceed. 59 | throw new GeneratorException; 60 | } 61 | 62 | /** 63 | * Construct the syntax for a down field. 64 | * 65 | * @param array $schema 66 | * @param array $meta 67 | * @return string 68 | * @throws GeneratorException 69 | */ 70 | private function createSchemaForDownMethod($schema, $meta) 71 | { 72 | // If the user created a table, then for the down 73 | // method, we should drop it. 74 | if ($meta['action'] == 'create') { 75 | return sprintf("Schema::dropIfExists('%s');", $meta['table']); 76 | } 77 | 78 | // If the user added columns to a table, then for 79 | // the down method, we should remove them. 80 | if ($meta['action'] == 'add') { 81 | $fields = $this->constructSchema($schema, 'Drop'); 82 | 83 | return $this->insert($fields)->into($this->getChangeSchemaWrapper()); 84 | } 85 | 86 | // If the user removed columns from a table, then for 87 | // the down method, we should add them back on. 88 | if ($meta['action'] == 'remove') { 89 | $fields = $this->constructSchema($schema); 90 | 91 | return $this->insert($fields)->into($this->getChangeSchemaWrapper()); 92 | } 93 | 94 | // Otherwise, we have no idea how to proceed. 95 | throw new GeneratorException; 96 | } 97 | 98 | /** 99 | * Store the given template, to be inserted somewhere. 100 | * 101 | * @param string $template 102 | * @return $this 103 | */ 104 | private function insert($template) 105 | { 106 | $this->template = $template; 107 | 108 | return $this; 109 | } 110 | 111 | /** 112 | * Get the stored template, and insert into the given wrapper. 113 | * 114 | * @param string $wrapper 115 | * @param string $placeholder 116 | * @return mixed 117 | */ 118 | private function into($wrapper, $placeholder = 'schema_up') 119 | { 120 | return str_replace('{{' . $placeholder . '}}', $this->template, $wrapper); 121 | } 122 | 123 | /** 124 | * Get the wrapper template for a "create" action. 125 | * 126 | * @return string 127 | */ 128 | private function getCreateSchemaWrapper() 129 | { 130 | return file_get_contents(__DIR__ . '/../stubs/schema-create.stub'); 131 | } 132 | 133 | /** 134 | * Get the wrapper template for an "add" action. 135 | * 136 | * @return string 137 | */ 138 | private function getChangeSchemaWrapper() 139 | { 140 | return file_get_contents(__DIR__ . '/../stubs/schema-change.stub'); 141 | } 142 | 143 | /** 144 | * Construct the schema fields. 145 | * 146 | * @param array $schema 147 | * @param string $direction 148 | * @return array 149 | */ 150 | private function constructSchema($schema, $direction = 'Add') 151 | { 152 | if (!$schema) return ''; 153 | 154 | $fields = array_map(function ($field) use ($direction) { 155 | $method = "{$direction}Column"; 156 | 157 | return $this->$method($field); 158 | }, $schema); 159 | 160 | return implode("\n" . str_repeat(' ', 12), $fields); 161 | } 162 | 163 | 164 | /** 165 | * Construct the syntax to add a column. 166 | * 167 | * @param string $field 168 | * @return string 169 | */ 170 | private function addColumn($field) 171 | { 172 | $syntax = sprintf("\$table->%s('%s')", $field['type'], $field['name']); 173 | 174 | // If there are arguments for the schema type, like decimal('amount', 5, 2) 175 | // then we have to remember to work those in. 176 | if ($field['arguments']) { 177 | $syntax = substr($syntax, 0, -1) . ', '; 178 | 179 | $syntax .= implode(', ', $field['arguments']) . ')'; 180 | } 181 | 182 | foreach ($field['options'] as $method => $value) { 183 | $syntax .= sprintf("->%s(%s)", $method, $value === true ? '' : $value); 184 | } 185 | 186 | return $syntax .= ';'; 187 | } 188 | 189 | /** 190 | * Construct the syntax to drop a column. 191 | * 192 | * @param string $field 193 | * @return string 194 | */ 195 | private function dropColumn($field) 196 | { 197 | return sprintf("\$table->dropColumn('%s');", $field['name']); 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /src/stubs/migration.stub: -------------------------------------------------------------------------------- 1 | unsignedBigInteger('{{columnOne}}_id')->index(); 17 | $table->foreign('{{columnOne}}_id')->references('id')->on('{{tableOne}}')->onDelete('cascade'); 18 | $table->unsignedBigInteger('{{columnTwo}}_id')->index(); 19 | $table->foreign('{{columnTwo}}_id')->references('id')->on('{{tableTwo}}')->onDelete('cascade'); 20 | $table->primary(['{{columnOne}}_id', '{{columnTwo}}_id']); 21 | }); 22 | } 23 | 24 | /** 25 | * Reverse the migrations. 26 | * 27 | * @return void 28 | */ 29 | public function down() 30 | { 31 | Schema::dropIfExists('{{pivotTableName}}'); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/stubs/schema-change.stub: -------------------------------------------------------------------------------- 1 | Schema::table('{{table}}', function (Blueprint $table) { 2 | {{schema_up}} 3 | }); -------------------------------------------------------------------------------- /src/stubs/schema-create.stub: -------------------------------------------------------------------------------- 1 | Schema::create('{{table}}', function (Blueprint $table) { 2 | $table->bigIncrements('id'); 3 | {{schema_up}} 4 | $table->timestamps(); 5 | }); --------------------------------------------------------------------------------