├── .gitignore ├── README.md ├── bootstrap.php ├── cli-config.php ├── composer.json ├── composer.lock └── src ├── Controller └── RecipeController.php ├── Entity └── Recipe.php ├── Form └── Type │ └── RecipeType.php ├── NanoFramework.php ├── Security ├── LoginTokenAuthenticator.php └── TokenAuthenticator.php ├── Serializer ├── FormErrorNormalizer.php └── SerializerFactory.php ├── ValidatorFactory.php └── index.php /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/ 2 | /var/ 3 | !var/.gitkeep 4 | *~ 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Code example using Symfony Components to create a RESTful API. Created for the talk "Building a RESTful APIs with Symfony Components", given at PHP UK Conference (Feb. 16th., 2017). 2 | 3 | It can be considered a very basic implementation of a tiny framework -only for educational purposes and with no advantage at all over any real framework out there. 4 | -------------------------------------------------------------------------------- /bootstrap.php: -------------------------------------------------------------------------------- 1 | 2.2,<2.4" 97 | }, 98 | "require-dev": { 99 | "phpunit/phpunit": "~4.8|~5.0", 100 | "predis/predis": "~1.0", 101 | "satooshi/php-coveralls": "~0.6" 102 | }, 103 | "type": "library", 104 | "extra": { 105 | "branch-alias": { 106 | "dev-master": "1.6.x-dev" 107 | } 108 | }, 109 | "autoload": { 110 | "psr-4": { 111 | "Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache" 112 | } 113 | }, 114 | "notification-url": "https://packagist.org/downloads/", 115 | "license": [ 116 | "MIT" 117 | ], 118 | "authors": [ 119 | { 120 | "name": "Roman Borschel", 121 | "email": "roman@code-factory.org" 122 | }, 123 | { 124 | "name": "Benjamin Eberlei", 125 | "email": "kontakt@beberlei.de" 126 | }, 127 | { 128 | "name": "Guilherme Blanco", 129 | "email": "guilhermeblanco@gmail.com" 130 | }, 131 | { 132 | "name": "Jonathan Wage", 133 | "email": "jonwage@gmail.com" 134 | }, 135 | { 136 | "name": "Johannes Schmitt", 137 | "email": "schmittjoh@gmail.com" 138 | } 139 | ], 140 | "description": "Caching library offering an object-oriented API for many cache backends", 141 | "homepage": "http://www.doctrine-project.org", 142 | "keywords": [ 143 | "cache", 144 | "caching" 145 | ], 146 | "time": "2016-10-29 11:16:17" 147 | }, 148 | { 149 | "name": "doctrine/collections", 150 | "version": "v1.4.0", 151 | "source": { 152 | "type": "git", 153 | "url": "https://github.com/doctrine/collections.git", 154 | "reference": "1a4fb7e902202c33cce8c55989b945612943c2ba" 155 | }, 156 | "dist": { 157 | "type": "zip", 158 | "url": "https://api.github.com/repos/doctrine/collections/zipball/1a4fb7e902202c33cce8c55989b945612943c2ba", 159 | "reference": "1a4fb7e902202c33cce8c55989b945612943c2ba", 160 | "shasum": "" 161 | }, 162 | "require": { 163 | "php": "^5.6 || ^7.0" 164 | }, 165 | "require-dev": { 166 | "doctrine/coding-standard": "~0.1@dev", 167 | "phpunit/phpunit": "^5.7" 168 | }, 169 | "type": "library", 170 | "extra": { 171 | "branch-alias": { 172 | "dev-master": "1.3.x-dev" 173 | } 174 | }, 175 | "autoload": { 176 | "psr-0": { 177 | "Doctrine\\Common\\Collections\\": "lib/" 178 | } 179 | }, 180 | "notification-url": "https://packagist.org/downloads/", 181 | "license": [ 182 | "MIT" 183 | ], 184 | "authors": [ 185 | { 186 | "name": "Roman Borschel", 187 | "email": "roman@code-factory.org" 188 | }, 189 | { 190 | "name": "Benjamin Eberlei", 191 | "email": "kontakt@beberlei.de" 192 | }, 193 | { 194 | "name": "Guilherme Blanco", 195 | "email": "guilhermeblanco@gmail.com" 196 | }, 197 | { 198 | "name": "Jonathan Wage", 199 | "email": "jonwage@gmail.com" 200 | }, 201 | { 202 | "name": "Johannes Schmitt", 203 | "email": "schmittjoh@gmail.com" 204 | } 205 | ], 206 | "description": "Collections Abstraction library", 207 | "homepage": "http://www.doctrine-project.org", 208 | "keywords": [ 209 | "array", 210 | "collections", 211 | "iterator" 212 | ], 213 | "time": "2017-01-03 10:49:41" 214 | }, 215 | { 216 | "name": "doctrine/common", 217 | "version": "v2.7.2", 218 | "source": { 219 | "type": "git", 220 | "url": "https://github.com/doctrine/common.git", 221 | "reference": "930297026c8009a567ac051fd545bf6124150347" 222 | }, 223 | "dist": { 224 | "type": "zip", 225 | "url": "https://api.github.com/repos/doctrine/common/zipball/930297026c8009a567ac051fd545bf6124150347", 226 | "reference": "930297026c8009a567ac051fd545bf6124150347", 227 | "shasum": "" 228 | }, 229 | "require": { 230 | "doctrine/annotations": "1.*", 231 | "doctrine/cache": "1.*", 232 | "doctrine/collections": "1.*", 233 | "doctrine/inflector": "1.*", 234 | "doctrine/lexer": "1.*", 235 | "php": "~5.6|~7.0" 236 | }, 237 | "require-dev": { 238 | "phpunit/phpunit": "^5.4.6" 239 | }, 240 | "type": "library", 241 | "extra": { 242 | "branch-alias": { 243 | "dev-master": "2.7.x-dev" 244 | } 245 | }, 246 | "autoload": { 247 | "psr-4": { 248 | "Doctrine\\Common\\": "lib/Doctrine/Common" 249 | } 250 | }, 251 | "notification-url": "https://packagist.org/downloads/", 252 | "license": [ 253 | "MIT" 254 | ], 255 | "authors": [ 256 | { 257 | "name": "Roman Borschel", 258 | "email": "roman@code-factory.org" 259 | }, 260 | { 261 | "name": "Benjamin Eberlei", 262 | "email": "kontakt@beberlei.de" 263 | }, 264 | { 265 | "name": "Guilherme Blanco", 266 | "email": "guilhermeblanco@gmail.com" 267 | }, 268 | { 269 | "name": "Jonathan Wage", 270 | "email": "jonwage@gmail.com" 271 | }, 272 | { 273 | "name": "Johannes Schmitt", 274 | "email": "schmittjoh@gmail.com" 275 | } 276 | ], 277 | "description": "Common Library for Doctrine projects", 278 | "homepage": "http://www.doctrine-project.org", 279 | "keywords": [ 280 | "annotations", 281 | "collections", 282 | "eventmanager", 283 | "persistence", 284 | "spl" 285 | ], 286 | "time": "2017-01-13 14:02:13" 287 | }, 288 | { 289 | "name": "doctrine/dbal", 290 | "version": "v2.5.10", 291 | "source": { 292 | "type": "git", 293 | "url": "https://github.com/doctrine/dbal.git", 294 | "reference": "fc376f7a61498e18520cd6fa083752a4ca08072b" 295 | }, 296 | "dist": { 297 | "type": "zip", 298 | "url": "https://api.github.com/repos/doctrine/dbal/zipball/fc376f7a61498e18520cd6fa083752a4ca08072b", 299 | "reference": "fc376f7a61498e18520cd6fa083752a4ca08072b", 300 | "shasum": "" 301 | }, 302 | "require": { 303 | "doctrine/common": ">=2.4,<2.8-dev", 304 | "php": ">=5.3.2" 305 | }, 306 | "require-dev": { 307 | "phpunit/phpunit": "4.*", 308 | "symfony/console": "2.*||^3.0" 309 | }, 310 | "suggest": { 311 | "symfony/console": "For helpful console commands such as SQL execution and import of files." 312 | }, 313 | "bin": [ 314 | "bin/doctrine-dbal" 315 | ], 316 | "type": "library", 317 | "extra": { 318 | "branch-alias": { 319 | "dev-master": "2.5.x-dev" 320 | } 321 | }, 322 | "autoload": { 323 | "psr-0": { 324 | "Doctrine\\DBAL\\": "lib/" 325 | } 326 | }, 327 | "notification-url": "https://packagist.org/downloads/", 328 | "license": [ 329 | "MIT" 330 | ], 331 | "authors": [ 332 | { 333 | "name": "Roman Borschel", 334 | "email": "roman@code-factory.org" 335 | }, 336 | { 337 | "name": "Benjamin Eberlei", 338 | "email": "kontakt@beberlei.de" 339 | }, 340 | { 341 | "name": "Guilherme Blanco", 342 | "email": "guilhermeblanco@gmail.com" 343 | }, 344 | { 345 | "name": "Jonathan Wage", 346 | "email": "jonwage@gmail.com" 347 | } 348 | ], 349 | "description": "Database Abstraction Layer", 350 | "homepage": "http://www.doctrine-project.org", 351 | "keywords": [ 352 | "database", 353 | "dbal", 354 | "persistence", 355 | "queryobject" 356 | ], 357 | "time": "2017-01-23 23:17:10" 358 | }, 359 | { 360 | "name": "doctrine/inflector", 361 | "version": "v1.1.0", 362 | "source": { 363 | "type": "git", 364 | "url": "https://github.com/doctrine/inflector.git", 365 | "reference": "90b2128806bfde671b6952ab8bea493942c1fdae" 366 | }, 367 | "dist": { 368 | "type": "zip", 369 | "url": "https://api.github.com/repos/doctrine/inflector/zipball/90b2128806bfde671b6952ab8bea493942c1fdae", 370 | "reference": "90b2128806bfde671b6952ab8bea493942c1fdae", 371 | "shasum": "" 372 | }, 373 | "require": { 374 | "php": ">=5.3.2" 375 | }, 376 | "require-dev": { 377 | "phpunit/phpunit": "4.*" 378 | }, 379 | "type": "library", 380 | "extra": { 381 | "branch-alias": { 382 | "dev-master": "1.1.x-dev" 383 | } 384 | }, 385 | "autoload": { 386 | "psr-0": { 387 | "Doctrine\\Common\\Inflector\\": "lib/" 388 | } 389 | }, 390 | "notification-url": "https://packagist.org/downloads/", 391 | "license": [ 392 | "MIT" 393 | ], 394 | "authors": [ 395 | { 396 | "name": "Roman Borschel", 397 | "email": "roman@code-factory.org" 398 | }, 399 | { 400 | "name": "Benjamin Eberlei", 401 | "email": "kontakt@beberlei.de" 402 | }, 403 | { 404 | "name": "Guilherme Blanco", 405 | "email": "guilhermeblanco@gmail.com" 406 | }, 407 | { 408 | "name": "Jonathan Wage", 409 | "email": "jonwage@gmail.com" 410 | }, 411 | { 412 | "name": "Johannes Schmitt", 413 | "email": "schmittjoh@gmail.com" 414 | } 415 | ], 416 | "description": "Common String Manipulations with regard to casing and singular/plural rules.", 417 | "homepage": "http://www.doctrine-project.org", 418 | "keywords": [ 419 | "inflection", 420 | "pluralize", 421 | "singularize", 422 | "string" 423 | ], 424 | "time": "2015-11-06 14:35:42" 425 | }, 426 | { 427 | "name": "doctrine/instantiator", 428 | "version": "1.0.5", 429 | "source": { 430 | "type": "git", 431 | "url": "https://github.com/doctrine/instantiator.git", 432 | "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" 433 | }, 434 | "dist": { 435 | "type": "zip", 436 | "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", 437 | "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", 438 | "shasum": "" 439 | }, 440 | "require": { 441 | "php": ">=5.3,<8.0-DEV" 442 | }, 443 | "require-dev": { 444 | "athletic/athletic": "~0.1.8", 445 | "ext-pdo": "*", 446 | "ext-phar": "*", 447 | "phpunit/phpunit": "~4.0", 448 | "squizlabs/php_codesniffer": "~2.0" 449 | }, 450 | "type": "library", 451 | "extra": { 452 | "branch-alias": { 453 | "dev-master": "1.0.x-dev" 454 | } 455 | }, 456 | "autoload": { 457 | "psr-4": { 458 | "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" 459 | } 460 | }, 461 | "notification-url": "https://packagist.org/downloads/", 462 | "license": [ 463 | "MIT" 464 | ], 465 | "authors": [ 466 | { 467 | "name": "Marco Pivetta", 468 | "email": "ocramius@gmail.com", 469 | "homepage": "http://ocramius.github.com/" 470 | } 471 | ], 472 | "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", 473 | "homepage": "https://github.com/doctrine/instantiator", 474 | "keywords": [ 475 | "constructor", 476 | "instantiate" 477 | ], 478 | "time": "2015-06-14 21:17:01" 479 | }, 480 | { 481 | "name": "doctrine/lexer", 482 | "version": "v1.0.1", 483 | "source": { 484 | "type": "git", 485 | "url": "https://github.com/doctrine/lexer.git", 486 | "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c" 487 | }, 488 | "dist": { 489 | "type": "zip", 490 | "url": "https://api.github.com/repos/doctrine/lexer/zipball/83893c552fd2045dd78aef794c31e694c37c0b8c", 491 | "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c", 492 | "shasum": "" 493 | }, 494 | "require": { 495 | "php": ">=5.3.2" 496 | }, 497 | "type": "library", 498 | "extra": { 499 | "branch-alias": { 500 | "dev-master": "1.0.x-dev" 501 | } 502 | }, 503 | "autoload": { 504 | "psr-0": { 505 | "Doctrine\\Common\\Lexer\\": "lib/" 506 | } 507 | }, 508 | "notification-url": "https://packagist.org/downloads/", 509 | "license": [ 510 | "MIT" 511 | ], 512 | "authors": [ 513 | { 514 | "name": "Roman Borschel", 515 | "email": "roman@code-factory.org" 516 | }, 517 | { 518 | "name": "Guilherme Blanco", 519 | "email": "guilhermeblanco@gmail.com" 520 | }, 521 | { 522 | "name": "Johannes Schmitt", 523 | "email": "schmittjoh@gmail.com" 524 | } 525 | ], 526 | "description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.", 527 | "homepage": "http://www.doctrine-project.org", 528 | "keywords": [ 529 | "lexer", 530 | "parser" 531 | ], 532 | "time": "2014-09-09 13:34:57" 533 | }, 534 | { 535 | "name": "doctrine/orm", 536 | "version": "v2.5.6", 537 | "source": { 538 | "type": "git", 539 | "url": "https://github.com/doctrine/doctrine2.git", 540 | "reference": "e6c434196c8ef058239aaa0724b4aadb0107940b" 541 | }, 542 | "dist": { 543 | "type": "zip", 544 | "url": "https://api.github.com/repos/doctrine/doctrine2/zipball/e6c434196c8ef058239aaa0724b4aadb0107940b", 545 | "reference": "e6c434196c8ef058239aaa0724b4aadb0107940b", 546 | "shasum": "" 547 | }, 548 | "require": { 549 | "doctrine/cache": "~1.4", 550 | "doctrine/collections": "~1.2", 551 | "doctrine/common": ">=2.5-dev,<2.8-dev", 552 | "doctrine/dbal": ">=2.5-dev,<2.6-dev", 553 | "doctrine/instantiator": "~1.0.1", 554 | "ext-pdo": "*", 555 | "php": ">=5.4", 556 | "symfony/console": "~2.5|~3.0" 557 | }, 558 | "require-dev": { 559 | "phpunit/phpunit": "~4.0", 560 | "symfony/yaml": "~2.3|~3.0" 561 | }, 562 | "suggest": { 563 | "symfony/yaml": "If you want to use YAML Metadata Mapping Driver" 564 | }, 565 | "bin": [ 566 | "bin/doctrine", 567 | "bin/doctrine.php" 568 | ], 569 | "type": "library", 570 | "extra": { 571 | "branch-alias": { 572 | "dev-master": "2.6.x-dev" 573 | } 574 | }, 575 | "autoload": { 576 | "psr-0": { 577 | "Doctrine\\ORM\\": "lib/" 578 | } 579 | }, 580 | "notification-url": "https://packagist.org/downloads/", 581 | "license": [ 582 | "MIT" 583 | ], 584 | "authors": [ 585 | { 586 | "name": "Roman Borschel", 587 | "email": "roman@code-factory.org" 588 | }, 589 | { 590 | "name": "Benjamin Eberlei", 591 | "email": "kontakt@beberlei.de" 592 | }, 593 | { 594 | "name": "Guilherme Blanco", 595 | "email": "guilhermeblanco@gmail.com" 596 | }, 597 | { 598 | "name": "Jonathan Wage", 599 | "email": "jonwage@gmail.com" 600 | } 601 | ], 602 | "description": "Object-Relational-Mapper for PHP", 603 | "homepage": "http://www.doctrine-project.org", 604 | "keywords": [ 605 | "database", 606 | "orm" 607 | ], 608 | "time": "2016-12-18 15:42:34" 609 | }, 610 | { 611 | "name": "lcobucci/jwt", 612 | "version": "3.2.1", 613 | "source": { 614 | "type": "git", 615 | "url": "https://github.com/lcobucci/jwt.git", 616 | "reference": "ddce703826f9c5229781933b1a39069e38e6a0f3" 617 | }, 618 | "dist": { 619 | "type": "zip", 620 | "url": "https://api.github.com/repos/lcobucci/jwt/zipball/ddce703826f9c5229781933b1a39069e38e6a0f3", 621 | "reference": "ddce703826f9c5229781933b1a39069e38e6a0f3", 622 | "shasum": "" 623 | }, 624 | "require": { 625 | "ext-openssl": "*", 626 | "php": ">=5.5" 627 | }, 628 | "require-dev": { 629 | "mdanter/ecc": "~0.3.1", 630 | "mikey179/vfsstream": "~1.5", 631 | "phpmd/phpmd": "~2.2", 632 | "phpunit/php-invoker": "~1.1", 633 | "phpunit/phpunit": "~4.5", 634 | "squizlabs/php_codesniffer": "~2.3" 635 | }, 636 | "suggest": { 637 | "mdanter/ecc": "Required to use Elliptic Curves based algorithms." 638 | }, 639 | "type": "library", 640 | "extra": { 641 | "branch-alias": { 642 | "dev-master": "3.1-dev" 643 | } 644 | }, 645 | "autoload": { 646 | "psr-4": { 647 | "Lcobucci\\JWT\\": "src" 648 | } 649 | }, 650 | "notification-url": "https://packagist.org/downloads/", 651 | "license": [ 652 | "BSD-3-Clause" 653 | ], 654 | "authors": [ 655 | { 656 | "name": "Luís Otávio Cobucci Oblonczyk", 657 | "email": "lcobucci@gmail.com", 658 | "role": "Developer" 659 | } 660 | ], 661 | "description": "A simple library to work with JSON Web Token and JSON Web Signature", 662 | "keywords": [ 663 | "JWS", 664 | "jwt" 665 | ], 666 | "time": "2016-10-31 20:09:32" 667 | }, 668 | { 669 | "name": "paragonie/random_compat", 670 | "version": "v2.0.4", 671 | "source": { 672 | "type": "git", 673 | "url": "https://github.com/paragonie/random_compat.git", 674 | "reference": "a9b97968bcde1c4de2a5ec6cbd06a0f6c919b46e" 675 | }, 676 | "dist": { 677 | "type": "zip", 678 | "url": "https://api.github.com/repos/paragonie/random_compat/zipball/a9b97968bcde1c4de2a5ec6cbd06a0f6c919b46e", 679 | "reference": "a9b97968bcde1c4de2a5ec6cbd06a0f6c919b46e", 680 | "shasum": "" 681 | }, 682 | "require": { 683 | "php": ">=5.2.0" 684 | }, 685 | "require-dev": { 686 | "phpunit/phpunit": "4.*|5.*" 687 | }, 688 | "suggest": { 689 | "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes." 690 | }, 691 | "type": "library", 692 | "autoload": { 693 | "files": [ 694 | "lib/random.php" 695 | ] 696 | }, 697 | "notification-url": "https://packagist.org/downloads/", 698 | "license": [ 699 | "MIT" 700 | ], 701 | "authors": [ 702 | { 703 | "name": "Paragon Initiative Enterprises", 704 | "email": "security@paragonie.com", 705 | "homepage": "https://paragonie.com" 706 | } 707 | ], 708 | "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", 709 | "keywords": [ 710 | "csprng", 711 | "pseudorandom", 712 | "random" 713 | ], 714 | "time": "2016-11-07 23:38:38" 715 | }, 716 | { 717 | "name": "psr/log", 718 | "version": "1.0.2", 719 | "source": { 720 | "type": "git", 721 | "url": "https://github.com/php-fig/log.git", 722 | "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d" 723 | }, 724 | "dist": { 725 | "type": "zip", 726 | "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", 727 | "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", 728 | "shasum": "" 729 | }, 730 | "require": { 731 | "php": ">=5.3.0" 732 | }, 733 | "type": "library", 734 | "extra": { 735 | "branch-alias": { 736 | "dev-master": "1.0.x-dev" 737 | } 738 | }, 739 | "autoload": { 740 | "psr-4": { 741 | "Psr\\Log\\": "Psr/Log/" 742 | } 743 | }, 744 | "notification-url": "https://packagist.org/downloads/", 745 | "license": [ 746 | "MIT" 747 | ], 748 | "authors": [ 749 | { 750 | "name": "PHP-FIG", 751 | "homepage": "http://www.php-fig.org/" 752 | } 753 | ], 754 | "description": "Common interface for logging libraries", 755 | "homepage": "https://github.com/php-fig/log", 756 | "keywords": [ 757 | "log", 758 | "psr", 759 | "psr-3" 760 | ], 761 | "time": "2016-10-10 12:19:37" 762 | }, 763 | { 764 | "name": "symfony/console", 765 | "version": "v3.2.2", 766 | "source": { 767 | "type": "git", 768 | "url": "https://github.com/symfony/console.git", 769 | "reference": "4f9e449e76996adf310498a8ca955c6deebe29dd" 770 | }, 771 | "dist": { 772 | "type": "zip", 773 | "url": "https://api.github.com/repos/symfony/console/zipball/4f9e449e76996adf310498a8ca955c6deebe29dd", 774 | "reference": "4f9e449e76996adf310498a8ca955c6deebe29dd", 775 | "shasum": "" 776 | }, 777 | "require": { 778 | "php": ">=5.5.9", 779 | "symfony/debug": "~2.8|~3.0", 780 | "symfony/polyfill-mbstring": "~1.0" 781 | }, 782 | "require-dev": { 783 | "psr/log": "~1.0", 784 | "symfony/event-dispatcher": "~2.8|~3.0", 785 | "symfony/filesystem": "~2.8|~3.0", 786 | "symfony/process": "~2.8|~3.0" 787 | }, 788 | "suggest": { 789 | "psr/log": "For using the console logger", 790 | "symfony/event-dispatcher": "", 791 | "symfony/filesystem": "", 792 | "symfony/process": "" 793 | }, 794 | "type": "library", 795 | "extra": { 796 | "branch-alias": { 797 | "dev-master": "3.2-dev" 798 | } 799 | }, 800 | "autoload": { 801 | "psr-4": { 802 | "Symfony\\Component\\Console\\": "" 803 | }, 804 | "exclude-from-classmap": [ 805 | "/Tests/" 806 | ] 807 | }, 808 | "notification-url": "https://packagist.org/downloads/", 809 | "license": [ 810 | "MIT" 811 | ], 812 | "authors": [ 813 | { 814 | "name": "Fabien Potencier", 815 | "email": "fabien@symfony.com" 816 | }, 817 | { 818 | "name": "Symfony Community", 819 | "homepage": "https://symfony.com/contributors" 820 | } 821 | ], 822 | "description": "Symfony Console Component", 823 | "homepage": "https://symfony.com", 824 | "time": "2017-01-08 20:47:33" 825 | }, 826 | { 827 | "name": "symfony/debug", 828 | "version": "v3.2.2", 829 | "source": { 830 | "type": "git", 831 | "url": "https://github.com/symfony/debug.git", 832 | "reference": "810ba5c1c5352a4ddb15d4719e8936751dff0b05" 833 | }, 834 | "dist": { 835 | "type": "zip", 836 | "url": "https://api.github.com/repos/symfony/debug/zipball/810ba5c1c5352a4ddb15d4719e8936751dff0b05", 837 | "reference": "810ba5c1c5352a4ddb15d4719e8936751dff0b05", 838 | "shasum": "" 839 | }, 840 | "require": { 841 | "php": ">=5.5.9", 842 | "psr/log": "~1.0" 843 | }, 844 | "conflict": { 845 | "symfony/http-kernel": ">=2.3,<2.3.24|~2.4.0|>=2.5,<2.5.9|>=2.6,<2.6.2" 846 | }, 847 | "require-dev": { 848 | "symfony/class-loader": "~2.8|~3.0", 849 | "symfony/http-kernel": "~2.8|~3.0" 850 | }, 851 | "type": "library", 852 | "extra": { 853 | "branch-alias": { 854 | "dev-master": "3.2-dev" 855 | } 856 | }, 857 | "autoload": { 858 | "psr-4": { 859 | "Symfony\\Component\\Debug\\": "" 860 | }, 861 | "exclude-from-classmap": [ 862 | "/Tests/" 863 | ] 864 | }, 865 | "notification-url": "https://packagist.org/downloads/", 866 | "license": [ 867 | "MIT" 868 | ], 869 | "authors": [ 870 | { 871 | "name": "Fabien Potencier", 872 | "email": "fabien@symfony.com" 873 | }, 874 | { 875 | "name": "Symfony Community", 876 | "homepage": "https://symfony.com/contributors" 877 | } 878 | ], 879 | "description": "Symfony Debug Component", 880 | "homepage": "https://symfony.com", 881 | "time": "2017-01-02 20:32:22" 882 | }, 883 | { 884 | "name": "symfony/event-dispatcher", 885 | "version": "v3.2.2", 886 | "source": { 887 | "type": "git", 888 | "url": "https://github.com/symfony/event-dispatcher.git", 889 | "reference": "9137eb3a3328e413212826d63eeeb0217836e2b6" 890 | }, 891 | "dist": { 892 | "type": "zip", 893 | "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/9137eb3a3328e413212826d63eeeb0217836e2b6", 894 | "reference": "9137eb3a3328e413212826d63eeeb0217836e2b6", 895 | "shasum": "" 896 | }, 897 | "require": { 898 | "php": ">=5.5.9" 899 | }, 900 | "require-dev": { 901 | "psr/log": "~1.0", 902 | "symfony/config": "~2.8|~3.0", 903 | "symfony/dependency-injection": "~2.8|~3.0", 904 | "symfony/expression-language": "~2.8|~3.0", 905 | "symfony/stopwatch": "~2.8|~3.0" 906 | }, 907 | "suggest": { 908 | "symfony/dependency-injection": "", 909 | "symfony/http-kernel": "" 910 | }, 911 | "type": "library", 912 | "extra": { 913 | "branch-alias": { 914 | "dev-master": "3.2-dev" 915 | } 916 | }, 917 | "autoload": { 918 | "psr-4": { 919 | "Symfony\\Component\\EventDispatcher\\": "" 920 | }, 921 | "exclude-from-classmap": [ 922 | "/Tests/" 923 | ] 924 | }, 925 | "notification-url": "https://packagist.org/downloads/", 926 | "license": [ 927 | "MIT" 928 | ], 929 | "authors": [ 930 | { 931 | "name": "Fabien Potencier", 932 | "email": "fabien@symfony.com" 933 | }, 934 | { 935 | "name": "Symfony Community", 936 | "homepage": "https://symfony.com/contributors" 937 | } 938 | ], 939 | "description": "Symfony EventDispatcher Component", 940 | "homepage": "https://symfony.com", 941 | "time": "2017-01-02 20:32:22" 942 | }, 943 | { 944 | "name": "symfony/form", 945 | "version": "v3.2.2", 946 | "source": { 947 | "type": "git", 948 | "url": "https://github.com/symfony/form.git", 949 | "reference": "99c7065a3faacc3e2a532a43acfcc7d3ebb63703" 950 | }, 951 | "dist": { 952 | "type": "zip", 953 | "url": "https://api.github.com/repos/symfony/form/zipball/99c7065a3faacc3e2a532a43acfcc7d3ebb63703", 954 | "reference": "99c7065a3faacc3e2a532a43acfcc7d3ebb63703", 955 | "shasum": "" 956 | }, 957 | "require": { 958 | "php": ">=5.5.9", 959 | "symfony/event-dispatcher": "~2.8|~3.0", 960 | "symfony/intl": "~2.8|~3.0", 961 | "symfony/options-resolver": "~2.8|~3.0", 962 | "symfony/polyfill-mbstring": "~1.0", 963 | "symfony/property-access": "~2.8|~3.0" 964 | }, 965 | "conflict": { 966 | "symfony/doctrine-bridge": "<2.7", 967 | "symfony/framework-bundle": "<2.7", 968 | "symfony/twig-bridge": "<2.7" 969 | }, 970 | "require-dev": { 971 | "doctrine/collections": "~1.0", 972 | "symfony/dependency-injection": "~2.8|~3.0", 973 | "symfony/http-foundation": "~2.8|~3.0", 974 | "symfony/http-kernel": "~2.8|~3.0", 975 | "symfony/security-csrf": "~2.8|~3.0", 976 | "symfony/translation": "~2.8|~3.0", 977 | "symfony/validator": "~2.8|~3.0", 978 | "symfony/var-dumper": "~3.2" 979 | }, 980 | "suggest": { 981 | "symfony/framework-bundle": "For templating with PHP.", 982 | "symfony/security-csrf": "For protecting forms against CSRF attacks.", 983 | "symfony/twig-bridge": "For templating with Twig.", 984 | "symfony/validator": "For form validation." 985 | }, 986 | "type": "library", 987 | "extra": { 988 | "branch-alias": { 989 | "dev-master": "3.2-dev" 990 | } 991 | }, 992 | "autoload": { 993 | "psr-4": { 994 | "Symfony\\Component\\Form\\": "" 995 | }, 996 | "exclude-from-classmap": [ 997 | "/Tests/" 998 | ] 999 | }, 1000 | "notification-url": "https://packagist.org/downloads/", 1001 | "license": [ 1002 | "MIT" 1003 | ], 1004 | "authors": [ 1005 | { 1006 | "name": "Fabien Potencier", 1007 | "email": "fabien@symfony.com" 1008 | }, 1009 | { 1010 | "name": "Symfony Community", 1011 | "homepage": "https://symfony.com/contributors" 1012 | } 1013 | ], 1014 | "description": "Symfony Form Component", 1015 | "homepage": "https://symfony.com", 1016 | "time": "2017-01-12 19:27:47" 1017 | }, 1018 | { 1019 | "name": "symfony/http-foundation", 1020 | "version": "v3.2.2", 1021 | "source": { 1022 | "type": "git", 1023 | "url": "https://github.com/symfony/http-foundation.git", 1024 | "reference": "33eb76bf1d833c705433e5361a646c164696394b" 1025 | }, 1026 | "dist": { 1027 | "type": "zip", 1028 | "url": "https://api.github.com/repos/symfony/http-foundation/zipball/33eb76bf1d833c705433e5361a646c164696394b", 1029 | "reference": "33eb76bf1d833c705433e5361a646c164696394b", 1030 | "shasum": "" 1031 | }, 1032 | "require": { 1033 | "php": ">=5.5.9", 1034 | "symfony/polyfill-mbstring": "~1.1" 1035 | }, 1036 | "require-dev": { 1037 | "symfony/expression-language": "~2.8|~3.0" 1038 | }, 1039 | "type": "library", 1040 | "extra": { 1041 | "branch-alias": { 1042 | "dev-master": "3.2-dev" 1043 | } 1044 | }, 1045 | "autoload": { 1046 | "psr-4": { 1047 | "Symfony\\Component\\HttpFoundation\\": "" 1048 | }, 1049 | "exclude-from-classmap": [ 1050 | "/Tests/" 1051 | ] 1052 | }, 1053 | "notification-url": "https://packagist.org/downloads/", 1054 | "license": [ 1055 | "MIT" 1056 | ], 1057 | "authors": [ 1058 | { 1059 | "name": "Fabien Potencier", 1060 | "email": "fabien@symfony.com" 1061 | }, 1062 | { 1063 | "name": "Symfony Community", 1064 | "homepage": "https://symfony.com/contributors" 1065 | } 1066 | ], 1067 | "description": "Symfony HttpFoundation Component", 1068 | "homepage": "https://symfony.com", 1069 | "time": "2017-01-08 20:47:33" 1070 | }, 1071 | { 1072 | "name": "symfony/http-kernel", 1073 | "version": "v3.2.2", 1074 | "source": { 1075 | "type": "git", 1076 | "url": "https://github.com/symfony/http-kernel.git", 1077 | "reference": "8a898e340a89022246645b1288d295f49c9381e4" 1078 | }, 1079 | "dist": { 1080 | "type": "zip", 1081 | "url": "https://api.github.com/repos/symfony/http-kernel/zipball/8a898e340a89022246645b1288d295f49c9381e4", 1082 | "reference": "8a898e340a89022246645b1288d295f49c9381e4", 1083 | "shasum": "" 1084 | }, 1085 | "require": { 1086 | "php": ">=5.5.9", 1087 | "psr/log": "~1.0", 1088 | "symfony/debug": "~2.8|~3.0", 1089 | "symfony/event-dispatcher": "~2.8|~3.0", 1090 | "symfony/http-foundation": "~2.8.13|~3.1.6|~3.2" 1091 | }, 1092 | "conflict": { 1093 | "symfony/config": "<2.8" 1094 | }, 1095 | "require-dev": { 1096 | "symfony/browser-kit": "~2.8|~3.0", 1097 | "symfony/class-loader": "~2.8|~3.0", 1098 | "symfony/config": "~2.8|~3.0", 1099 | "symfony/console": "~2.8|~3.0", 1100 | "symfony/css-selector": "~2.8|~3.0", 1101 | "symfony/dependency-injection": "~2.8|~3.0", 1102 | "symfony/dom-crawler": "~2.8|~3.0", 1103 | "symfony/expression-language": "~2.8|~3.0", 1104 | "symfony/finder": "~2.8|~3.0", 1105 | "symfony/process": "~2.8|~3.0", 1106 | "symfony/routing": "~2.8|~3.0", 1107 | "symfony/stopwatch": "~2.8|~3.0", 1108 | "symfony/templating": "~2.8|~3.0", 1109 | "symfony/translation": "~2.8|~3.0", 1110 | "symfony/var-dumper": "~3.2" 1111 | }, 1112 | "suggest": { 1113 | "symfony/browser-kit": "", 1114 | "symfony/class-loader": "", 1115 | "symfony/config": "", 1116 | "symfony/console": "", 1117 | "symfony/dependency-injection": "", 1118 | "symfony/finder": "", 1119 | "symfony/var-dumper": "" 1120 | }, 1121 | "type": "library", 1122 | "extra": { 1123 | "branch-alias": { 1124 | "dev-master": "3.2-dev" 1125 | } 1126 | }, 1127 | "autoload": { 1128 | "psr-4": { 1129 | "Symfony\\Component\\HttpKernel\\": "" 1130 | }, 1131 | "exclude-from-classmap": [ 1132 | "/Tests/" 1133 | ] 1134 | }, 1135 | "notification-url": "https://packagist.org/downloads/", 1136 | "license": [ 1137 | "MIT" 1138 | ], 1139 | "authors": [ 1140 | { 1141 | "name": "Fabien Potencier", 1142 | "email": "fabien@symfony.com" 1143 | }, 1144 | { 1145 | "name": "Symfony Community", 1146 | "homepage": "https://symfony.com/contributors" 1147 | } 1148 | ], 1149 | "description": "Symfony HttpKernel Component", 1150 | "homepage": "https://symfony.com", 1151 | "time": "2017-01-12 21:36:33" 1152 | }, 1153 | { 1154 | "name": "symfony/inflector", 1155 | "version": "v3.2.2", 1156 | "source": { 1157 | "type": "git", 1158 | "url": "https://github.com/symfony/inflector.git", 1159 | "reference": "20a37c39c1f29badc188e4c50a061b79c8bf3ff6" 1160 | }, 1161 | "dist": { 1162 | "type": "zip", 1163 | "url": "https://api.github.com/repos/symfony/inflector/zipball/20a37c39c1f29badc188e4c50a061b79c8bf3ff6", 1164 | "reference": "20a37c39c1f29badc188e4c50a061b79c8bf3ff6", 1165 | "shasum": "" 1166 | }, 1167 | "require": { 1168 | "php": ">=5.5.9" 1169 | }, 1170 | "type": "library", 1171 | "extra": { 1172 | "branch-alias": { 1173 | "dev-master": "3.2-dev" 1174 | } 1175 | }, 1176 | "autoload": { 1177 | "psr-4": { 1178 | "Symfony\\Component\\Inflector\\": "" 1179 | }, 1180 | "exclude-from-classmap": [ 1181 | "/Tests/" 1182 | ] 1183 | }, 1184 | "notification-url": "https://packagist.org/downloads/", 1185 | "license": [ 1186 | "MIT" 1187 | ], 1188 | "authors": [ 1189 | { 1190 | "name": "Bernhard Schussek", 1191 | "email": "bschussek@gmail.com" 1192 | }, 1193 | { 1194 | "name": "Symfony Community", 1195 | "homepage": "https://symfony.com/contributors" 1196 | } 1197 | ], 1198 | "description": "Symfony Inflector Component", 1199 | "homepage": "https://symfony.com", 1200 | "keywords": [ 1201 | "inflection", 1202 | "pluralize", 1203 | "singularize", 1204 | "string", 1205 | "symfony", 1206 | "words" 1207 | ], 1208 | "time": "2017-01-02 20:32:22" 1209 | }, 1210 | { 1211 | "name": "symfony/intl", 1212 | "version": "v3.2.2", 1213 | "source": { 1214 | "type": "git", 1215 | "url": "https://github.com/symfony/intl.git", 1216 | "reference": "6102349d68bb6b5a1e02593714189fdf8656ab62" 1217 | }, 1218 | "dist": { 1219 | "type": "zip", 1220 | "url": "https://api.github.com/repos/symfony/intl/zipball/6102349d68bb6b5a1e02593714189fdf8656ab62", 1221 | "reference": "6102349d68bb6b5a1e02593714189fdf8656ab62", 1222 | "shasum": "" 1223 | }, 1224 | "require": { 1225 | "php": ">=5.5.9", 1226 | "symfony/polyfill-intl-icu": "~1.0" 1227 | }, 1228 | "require-dev": { 1229 | "symfony/filesystem": "~2.8|~3.0" 1230 | }, 1231 | "suggest": { 1232 | "ext-intl": "to use the component with locales other than \"en\"" 1233 | }, 1234 | "type": "library", 1235 | "extra": { 1236 | "branch-alias": { 1237 | "dev-master": "3.2-dev" 1238 | } 1239 | }, 1240 | "autoload": { 1241 | "psr-4": { 1242 | "Symfony\\Component\\Intl\\": "" 1243 | }, 1244 | "classmap": [ 1245 | "Resources/stubs" 1246 | ], 1247 | "exclude-from-classmap": [ 1248 | "/Tests/" 1249 | ] 1250 | }, 1251 | "notification-url": "https://packagist.org/downloads/", 1252 | "license": [ 1253 | "MIT" 1254 | ], 1255 | "authors": [ 1256 | { 1257 | "name": "Bernhard Schussek", 1258 | "email": "bschussek@gmail.com" 1259 | }, 1260 | { 1261 | "name": "Eriksen Costa", 1262 | "email": "eriksen.costa@infranology.com.br" 1263 | }, 1264 | { 1265 | "name": "Igor Wiedler", 1266 | "email": "igor@wiedler.ch" 1267 | }, 1268 | { 1269 | "name": "Symfony Community", 1270 | "homepage": "https://symfony.com/contributors" 1271 | } 1272 | ], 1273 | "description": "A PHP replacement layer for the C intl extension that includes additional data from the ICU library.", 1274 | "homepage": "https://symfony.com", 1275 | "keywords": [ 1276 | "i18n", 1277 | "icu", 1278 | "internationalization", 1279 | "intl", 1280 | "l10n", 1281 | "localization" 1282 | ], 1283 | "time": "2017-01-02 20:32:22" 1284 | }, 1285 | { 1286 | "name": "symfony/options-resolver", 1287 | "version": "v3.2.2", 1288 | "source": { 1289 | "type": "git", 1290 | "url": "https://github.com/symfony/options-resolver.git", 1291 | "reference": "855429e3e9014b9dafee2a667de304c3aaa86fe6" 1292 | }, 1293 | "dist": { 1294 | "type": "zip", 1295 | "url": "https://api.github.com/repos/symfony/options-resolver/zipball/855429e3e9014b9dafee2a667de304c3aaa86fe6", 1296 | "reference": "855429e3e9014b9dafee2a667de304c3aaa86fe6", 1297 | "shasum": "" 1298 | }, 1299 | "require": { 1300 | "php": ">=5.5.9" 1301 | }, 1302 | "type": "library", 1303 | "extra": { 1304 | "branch-alias": { 1305 | "dev-master": "3.2-dev" 1306 | } 1307 | }, 1308 | "autoload": { 1309 | "psr-4": { 1310 | "Symfony\\Component\\OptionsResolver\\": "" 1311 | }, 1312 | "exclude-from-classmap": [ 1313 | "/Tests/" 1314 | ] 1315 | }, 1316 | "notification-url": "https://packagist.org/downloads/", 1317 | "license": [ 1318 | "MIT" 1319 | ], 1320 | "authors": [ 1321 | { 1322 | "name": "Fabien Potencier", 1323 | "email": "fabien@symfony.com" 1324 | }, 1325 | { 1326 | "name": "Symfony Community", 1327 | "homepage": "https://symfony.com/contributors" 1328 | } 1329 | ], 1330 | "description": "Symfony OptionsResolver Component", 1331 | "homepage": "https://symfony.com", 1332 | "keywords": [ 1333 | "config", 1334 | "configuration", 1335 | "options" 1336 | ], 1337 | "time": "2017-01-02 20:32:22" 1338 | }, 1339 | { 1340 | "name": "symfony/polyfill-intl-icu", 1341 | "version": "v1.3.0", 1342 | "source": { 1343 | "type": "git", 1344 | "url": "https://github.com/symfony/polyfill-intl-icu.git", 1345 | "reference": "2d6e2b20d457603eefb6e614286c22efca30fdb4" 1346 | }, 1347 | "dist": { 1348 | "type": "zip", 1349 | "url": "https://api.github.com/repos/symfony/polyfill-intl-icu/zipball/2d6e2b20d457603eefb6e614286c22efca30fdb4", 1350 | "reference": "2d6e2b20d457603eefb6e614286c22efca30fdb4", 1351 | "shasum": "" 1352 | }, 1353 | "require": { 1354 | "php": ">=5.3.3", 1355 | "symfony/intl": "~2.3|~3.0" 1356 | }, 1357 | "suggest": { 1358 | "ext-intl": "For best performance" 1359 | }, 1360 | "type": "library", 1361 | "extra": { 1362 | "branch-alias": { 1363 | "dev-master": "1.3-dev" 1364 | } 1365 | }, 1366 | "autoload": { 1367 | "files": [ 1368 | "bootstrap.php" 1369 | ] 1370 | }, 1371 | "notification-url": "https://packagist.org/downloads/", 1372 | "license": [ 1373 | "MIT" 1374 | ], 1375 | "authors": [ 1376 | { 1377 | "name": "Nicolas Grekas", 1378 | "email": "p@tchwork.com" 1379 | }, 1380 | { 1381 | "name": "Symfony Community", 1382 | "homepage": "https://symfony.com/contributors" 1383 | } 1384 | ], 1385 | "description": "Symfony polyfill for intl's ICU-related data and classes", 1386 | "homepage": "https://symfony.com", 1387 | "keywords": [ 1388 | "compatibility", 1389 | "icu", 1390 | "intl", 1391 | "polyfill", 1392 | "portable", 1393 | "shim" 1394 | ], 1395 | "time": "2016-11-14 01:06:16" 1396 | }, 1397 | { 1398 | "name": "symfony/polyfill-mbstring", 1399 | "version": "v1.3.0", 1400 | "source": { 1401 | "type": "git", 1402 | "url": "https://github.com/symfony/polyfill-mbstring.git", 1403 | "reference": "e79d363049d1c2128f133a2667e4f4190904f7f4" 1404 | }, 1405 | "dist": { 1406 | "type": "zip", 1407 | "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/e79d363049d1c2128f133a2667e4f4190904f7f4", 1408 | "reference": "e79d363049d1c2128f133a2667e4f4190904f7f4", 1409 | "shasum": "" 1410 | }, 1411 | "require": { 1412 | "php": ">=5.3.3" 1413 | }, 1414 | "suggest": { 1415 | "ext-mbstring": "For best performance" 1416 | }, 1417 | "type": "library", 1418 | "extra": { 1419 | "branch-alias": { 1420 | "dev-master": "1.3-dev" 1421 | } 1422 | }, 1423 | "autoload": { 1424 | "psr-4": { 1425 | "Symfony\\Polyfill\\Mbstring\\": "" 1426 | }, 1427 | "files": [ 1428 | "bootstrap.php" 1429 | ] 1430 | }, 1431 | "notification-url": "https://packagist.org/downloads/", 1432 | "license": [ 1433 | "MIT" 1434 | ], 1435 | "authors": [ 1436 | { 1437 | "name": "Nicolas Grekas", 1438 | "email": "p@tchwork.com" 1439 | }, 1440 | { 1441 | "name": "Symfony Community", 1442 | "homepage": "https://symfony.com/contributors" 1443 | } 1444 | ], 1445 | "description": "Symfony polyfill for the Mbstring extension", 1446 | "homepage": "https://symfony.com", 1447 | "keywords": [ 1448 | "compatibility", 1449 | "mbstring", 1450 | "polyfill", 1451 | "portable", 1452 | "shim" 1453 | ], 1454 | "time": "2016-11-14 01:06:16" 1455 | }, 1456 | { 1457 | "name": "symfony/polyfill-php56", 1458 | "version": "v1.3.0", 1459 | "source": { 1460 | "type": "git", 1461 | "url": "https://github.com/symfony/polyfill-php56.git", 1462 | "reference": "1dd42b9b89556f18092f3d1ada22cb05ac85383c" 1463 | }, 1464 | "dist": { 1465 | "type": "zip", 1466 | "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/1dd42b9b89556f18092f3d1ada22cb05ac85383c", 1467 | "reference": "1dd42b9b89556f18092f3d1ada22cb05ac85383c", 1468 | "shasum": "" 1469 | }, 1470 | "require": { 1471 | "php": ">=5.3.3", 1472 | "symfony/polyfill-util": "~1.0" 1473 | }, 1474 | "type": "library", 1475 | "extra": { 1476 | "branch-alias": { 1477 | "dev-master": "1.3-dev" 1478 | } 1479 | }, 1480 | "autoload": { 1481 | "psr-4": { 1482 | "Symfony\\Polyfill\\Php56\\": "" 1483 | }, 1484 | "files": [ 1485 | "bootstrap.php" 1486 | ] 1487 | }, 1488 | "notification-url": "https://packagist.org/downloads/", 1489 | "license": [ 1490 | "MIT" 1491 | ], 1492 | "authors": [ 1493 | { 1494 | "name": "Nicolas Grekas", 1495 | "email": "p@tchwork.com" 1496 | }, 1497 | { 1498 | "name": "Symfony Community", 1499 | "homepage": "https://symfony.com/contributors" 1500 | } 1501 | ], 1502 | "description": "Symfony polyfill backporting some PHP 5.6+ features to lower PHP versions", 1503 | "homepage": "https://symfony.com", 1504 | "keywords": [ 1505 | "compatibility", 1506 | "polyfill", 1507 | "portable", 1508 | "shim" 1509 | ], 1510 | "time": "2016-11-14 01:06:16" 1511 | }, 1512 | { 1513 | "name": "symfony/polyfill-php70", 1514 | "version": "v1.3.0", 1515 | "source": { 1516 | "type": "git", 1517 | "url": "https://github.com/symfony/polyfill-php70.git", 1518 | "reference": "13ce343935f0f91ca89605a2f6ca6f5c2f3faac2" 1519 | }, 1520 | "dist": { 1521 | "type": "zip", 1522 | "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/13ce343935f0f91ca89605a2f6ca6f5c2f3faac2", 1523 | "reference": "13ce343935f0f91ca89605a2f6ca6f5c2f3faac2", 1524 | "shasum": "" 1525 | }, 1526 | "require": { 1527 | "paragonie/random_compat": "~1.0|~2.0", 1528 | "php": ">=5.3.3" 1529 | }, 1530 | "type": "library", 1531 | "extra": { 1532 | "branch-alias": { 1533 | "dev-master": "1.3-dev" 1534 | } 1535 | }, 1536 | "autoload": { 1537 | "psr-4": { 1538 | "Symfony\\Polyfill\\Php70\\": "" 1539 | }, 1540 | "files": [ 1541 | "bootstrap.php" 1542 | ], 1543 | "classmap": [ 1544 | "Resources/stubs" 1545 | ] 1546 | }, 1547 | "notification-url": "https://packagist.org/downloads/", 1548 | "license": [ 1549 | "MIT" 1550 | ], 1551 | "authors": [ 1552 | { 1553 | "name": "Nicolas Grekas", 1554 | "email": "p@tchwork.com" 1555 | }, 1556 | { 1557 | "name": "Symfony Community", 1558 | "homepage": "https://symfony.com/contributors" 1559 | } 1560 | ], 1561 | "description": "Symfony polyfill backporting some PHP 7.0+ features to lower PHP versions", 1562 | "homepage": "https://symfony.com", 1563 | "keywords": [ 1564 | "compatibility", 1565 | "polyfill", 1566 | "portable", 1567 | "shim" 1568 | ], 1569 | "time": "2016-11-14 01:06:16" 1570 | }, 1571 | { 1572 | "name": "symfony/polyfill-util", 1573 | "version": "v1.3.0", 1574 | "source": { 1575 | "type": "git", 1576 | "url": "https://github.com/symfony/polyfill-util.git", 1577 | "reference": "746bce0fca664ac0a575e465f65c6643faddf7fb" 1578 | }, 1579 | "dist": { 1580 | "type": "zip", 1581 | "url": "https://api.github.com/repos/symfony/polyfill-util/zipball/746bce0fca664ac0a575e465f65c6643faddf7fb", 1582 | "reference": "746bce0fca664ac0a575e465f65c6643faddf7fb", 1583 | "shasum": "" 1584 | }, 1585 | "require": { 1586 | "php": ">=5.3.3" 1587 | }, 1588 | "type": "library", 1589 | "extra": { 1590 | "branch-alias": { 1591 | "dev-master": "1.3-dev" 1592 | } 1593 | }, 1594 | "autoload": { 1595 | "psr-4": { 1596 | "Symfony\\Polyfill\\Util\\": "" 1597 | } 1598 | }, 1599 | "notification-url": "https://packagist.org/downloads/", 1600 | "license": [ 1601 | "MIT" 1602 | ], 1603 | "authors": [ 1604 | { 1605 | "name": "Nicolas Grekas", 1606 | "email": "p@tchwork.com" 1607 | }, 1608 | { 1609 | "name": "Symfony Community", 1610 | "homepage": "https://symfony.com/contributors" 1611 | } 1612 | ], 1613 | "description": "Symfony utilities for portability of PHP codes", 1614 | "homepage": "https://symfony.com", 1615 | "keywords": [ 1616 | "compat", 1617 | "compatibility", 1618 | "polyfill", 1619 | "shim" 1620 | ], 1621 | "time": "2016-11-14 01:06:16" 1622 | }, 1623 | { 1624 | "name": "symfony/property-access", 1625 | "version": "v3.2.2", 1626 | "source": { 1627 | "type": "git", 1628 | "url": "https://github.com/symfony/property-access.git", 1629 | "reference": "370a5276e00885648f6dde3cabc7c61eaab57bd8" 1630 | }, 1631 | "dist": { 1632 | "type": "zip", 1633 | "url": "https://api.github.com/repos/symfony/property-access/zipball/370a5276e00885648f6dde3cabc7c61eaab57bd8", 1634 | "reference": "370a5276e00885648f6dde3cabc7c61eaab57bd8", 1635 | "shasum": "" 1636 | }, 1637 | "require": { 1638 | "php": ">=5.5.9", 1639 | "symfony/inflector": "~3.1", 1640 | "symfony/polyfill-php70": "~1.0" 1641 | }, 1642 | "require-dev": { 1643 | "symfony/cache": "~3.1" 1644 | }, 1645 | "suggest": { 1646 | "psr/cache-implementation": "To cache access methods." 1647 | }, 1648 | "type": "library", 1649 | "extra": { 1650 | "branch-alias": { 1651 | "dev-master": "3.2-dev" 1652 | } 1653 | }, 1654 | "autoload": { 1655 | "psr-4": { 1656 | "Symfony\\Component\\PropertyAccess\\": "" 1657 | }, 1658 | "exclude-from-classmap": [ 1659 | "/Tests/" 1660 | ] 1661 | }, 1662 | "notification-url": "https://packagist.org/downloads/", 1663 | "license": [ 1664 | "MIT" 1665 | ], 1666 | "authors": [ 1667 | { 1668 | "name": "Fabien Potencier", 1669 | "email": "fabien@symfony.com" 1670 | }, 1671 | { 1672 | "name": "Symfony Community", 1673 | "homepage": "https://symfony.com/contributors" 1674 | } 1675 | ], 1676 | "description": "Symfony PropertyAccess Component", 1677 | "homepage": "https://symfony.com", 1678 | "keywords": [ 1679 | "access", 1680 | "array", 1681 | "extraction", 1682 | "index", 1683 | "injection", 1684 | "object", 1685 | "property", 1686 | "property path", 1687 | "reflection" 1688 | ], 1689 | "time": "2017-01-02 20:32:22" 1690 | }, 1691 | { 1692 | "name": "symfony/routing", 1693 | "version": "v3.2.2", 1694 | "source": { 1695 | "type": "git", 1696 | "url": "https://github.com/symfony/routing.git", 1697 | "reference": "fda2c67d47ec801726ca888c95d701d31b27b444" 1698 | }, 1699 | "dist": { 1700 | "type": "zip", 1701 | "url": "https://api.github.com/repos/symfony/routing/zipball/fda2c67d47ec801726ca888c95d701d31b27b444", 1702 | "reference": "fda2c67d47ec801726ca888c95d701d31b27b444", 1703 | "shasum": "" 1704 | }, 1705 | "require": { 1706 | "php": ">=5.5.9" 1707 | }, 1708 | "conflict": { 1709 | "symfony/config": "<2.8" 1710 | }, 1711 | "require-dev": { 1712 | "doctrine/annotations": "~1.0", 1713 | "doctrine/common": "~2.2", 1714 | "psr/log": "~1.0", 1715 | "symfony/config": "~2.8|~3.0", 1716 | "symfony/expression-language": "~2.8|~3.0", 1717 | "symfony/http-foundation": "~2.8|~3.0", 1718 | "symfony/yaml": "~2.8|~3.0" 1719 | }, 1720 | "suggest": { 1721 | "doctrine/annotations": "For using the annotation loader", 1722 | "symfony/config": "For using the all-in-one router or any loader", 1723 | "symfony/dependency-injection": "For loading routes from a service", 1724 | "symfony/expression-language": "For using expression matching", 1725 | "symfony/http-foundation": "For using a Symfony Request object", 1726 | "symfony/yaml": "For using the YAML loader" 1727 | }, 1728 | "type": "library", 1729 | "extra": { 1730 | "branch-alias": { 1731 | "dev-master": "3.2-dev" 1732 | } 1733 | }, 1734 | "autoload": { 1735 | "psr-4": { 1736 | "Symfony\\Component\\Routing\\": "" 1737 | }, 1738 | "exclude-from-classmap": [ 1739 | "/Tests/" 1740 | ] 1741 | }, 1742 | "notification-url": "https://packagist.org/downloads/", 1743 | "license": [ 1744 | "MIT" 1745 | ], 1746 | "authors": [ 1747 | { 1748 | "name": "Fabien Potencier", 1749 | "email": "fabien@symfony.com" 1750 | }, 1751 | { 1752 | "name": "Symfony Community", 1753 | "homepage": "https://symfony.com/contributors" 1754 | } 1755 | ], 1756 | "description": "Symfony Routing Component", 1757 | "homepage": "https://symfony.com", 1758 | "keywords": [ 1759 | "router", 1760 | "routing", 1761 | "uri", 1762 | "url" 1763 | ], 1764 | "time": "2017-01-02 20:32:22" 1765 | }, 1766 | { 1767 | "name": "symfony/security-core", 1768 | "version": "v3.2.2", 1769 | "source": { 1770 | "type": "git", 1771 | "url": "https://github.com/symfony/security-core.git", 1772 | "reference": "72b310c5d510ca48d7a8c4cd5e4af95c8896dd25" 1773 | }, 1774 | "dist": { 1775 | "type": "zip", 1776 | "url": "https://api.github.com/repos/symfony/security-core/zipball/72b310c5d510ca48d7a8c4cd5e4af95c8896dd25", 1777 | "reference": "72b310c5d510ca48d7a8c4cd5e4af95c8896dd25", 1778 | "shasum": "" 1779 | }, 1780 | "require": { 1781 | "php": ">=5.5.9", 1782 | "symfony/polyfill-php56": "~1.0", 1783 | "symfony/polyfill-util": "~1.0" 1784 | }, 1785 | "require-dev": { 1786 | "psr/log": "~1.0", 1787 | "symfony/event-dispatcher": "~2.8|~3.0", 1788 | "symfony/expression-language": "~2.8|~3.0", 1789 | "symfony/http-foundation": "~2.8|~3.0", 1790 | "symfony/ldap": "~3.1", 1791 | "symfony/validator": "~2.8|~3.0" 1792 | }, 1793 | "suggest": { 1794 | "symfony/event-dispatcher": "", 1795 | "symfony/expression-language": "For using the expression voter", 1796 | "symfony/http-foundation": "", 1797 | "symfony/ldap": "For using LDAP integration", 1798 | "symfony/validator": "For using the user password constraint" 1799 | }, 1800 | "type": "library", 1801 | "extra": { 1802 | "branch-alias": { 1803 | "dev-master": "3.2-dev" 1804 | } 1805 | }, 1806 | "autoload": { 1807 | "psr-4": { 1808 | "Symfony\\Component\\Security\\Core\\": "" 1809 | }, 1810 | "exclude-from-classmap": [ 1811 | "/Tests/" 1812 | ] 1813 | }, 1814 | "notification-url": "https://packagist.org/downloads/", 1815 | "license": [ 1816 | "MIT" 1817 | ], 1818 | "authors": [ 1819 | { 1820 | "name": "Fabien Potencier", 1821 | "email": "fabien@symfony.com" 1822 | }, 1823 | { 1824 | "name": "Symfony Community", 1825 | "homepage": "https://symfony.com/contributors" 1826 | } 1827 | ], 1828 | "description": "Symfony Security Component - Core Library", 1829 | "homepage": "https://symfony.com", 1830 | "time": "2017-01-02 20:32:22" 1831 | }, 1832 | { 1833 | "name": "symfony/security-guard", 1834 | "version": "v3.2.2", 1835 | "source": { 1836 | "type": "git", 1837 | "url": "https://github.com/symfony/security-guard.git", 1838 | "reference": "9c627b9465f16a72aed038e3dd7e26b4b095988c" 1839 | }, 1840 | "dist": { 1841 | "type": "zip", 1842 | "url": "https://api.github.com/repos/symfony/security-guard/zipball/9c627b9465f16a72aed038e3dd7e26b4b095988c", 1843 | "reference": "9c627b9465f16a72aed038e3dd7e26b4b095988c", 1844 | "shasum": "" 1845 | }, 1846 | "require": { 1847 | "php": ">=5.5.9", 1848 | "symfony/security-core": "~2.8|~3.0", 1849 | "symfony/security-http": "~3.1" 1850 | }, 1851 | "require-dev": { 1852 | "psr/log": "~1.0" 1853 | }, 1854 | "type": "library", 1855 | "extra": { 1856 | "branch-alias": { 1857 | "dev-master": "3.2-dev" 1858 | } 1859 | }, 1860 | "autoload": { 1861 | "psr-4": { 1862 | "Symfony\\Component\\Security\\Guard\\": "" 1863 | }, 1864 | "exclude-from-classmap": [ 1865 | "/Tests/" 1866 | ] 1867 | }, 1868 | "notification-url": "https://packagist.org/downloads/", 1869 | "license": [ 1870 | "MIT" 1871 | ], 1872 | "authors": [ 1873 | { 1874 | "name": "Fabien Potencier", 1875 | "email": "fabien@symfony.com" 1876 | }, 1877 | { 1878 | "name": "Symfony Community", 1879 | "homepage": "https://symfony.com/contributors" 1880 | } 1881 | ], 1882 | "description": "Symfony Security Component - Guard", 1883 | "homepage": "https://symfony.com", 1884 | "time": "2017-01-02 20:32:22" 1885 | }, 1886 | { 1887 | "name": "symfony/security-http", 1888 | "version": "v3.2.2", 1889 | "source": { 1890 | "type": "git", 1891 | "url": "https://github.com/symfony/security-http.git", 1892 | "reference": "bd2250a97046d995c183ae4dc51e3c97d23d605f" 1893 | }, 1894 | "dist": { 1895 | "type": "zip", 1896 | "url": "https://api.github.com/repos/symfony/security-http/zipball/bd2250a97046d995c183ae4dc51e3c97d23d605f", 1897 | "reference": "bd2250a97046d995c183ae4dc51e3c97d23d605f", 1898 | "shasum": "" 1899 | }, 1900 | "require": { 1901 | "php": ">=5.5.9", 1902 | "symfony/event-dispatcher": "~2.8|~3.0", 1903 | "symfony/http-foundation": "~2.8|~3.0", 1904 | "symfony/http-kernel": "~2.8|~3.0", 1905 | "symfony/polyfill-php56": "~1.0", 1906 | "symfony/polyfill-php70": "~1.0", 1907 | "symfony/property-access": "~2.8|~3.0", 1908 | "symfony/security-core": "~3.2" 1909 | }, 1910 | "require-dev": { 1911 | "psr/log": "~1.0", 1912 | "symfony/routing": "~2.8|~3.0", 1913 | "symfony/security-csrf": "~2.8|~3.0" 1914 | }, 1915 | "suggest": { 1916 | "symfony/routing": "For using the HttpUtils class to create sub-requests, redirect the user, and match URLs", 1917 | "symfony/security-csrf": "For using tokens to protect authentication/logout attempts" 1918 | }, 1919 | "type": "library", 1920 | "extra": { 1921 | "branch-alias": { 1922 | "dev-master": "3.2-dev" 1923 | } 1924 | }, 1925 | "autoload": { 1926 | "psr-4": { 1927 | "Symfony\\Component\\Security\\Http\\": "" 1928 | }, 1929 | "exclude-from-classmap": [ 1930 | "/Tests/" 1931 | ] 1932 | }, 1933 | "notification-url": "https://packagist.org/downloads/", 1934 | "license": [ 1935 | "MIT" 1936 | ], 1937 | "authors": [ 1938 | { 1939 | "name": "Fabien Potencier", 1940 | "email": "fabien@symfony.com" 1941 | }, 1942 | { 1943 | "name": "Symfony Community", 1944 | "homepage": "https://symfony.com/contributors" 1945 | } 1946 | ], 1947 | "description": "Symfony Security Component - HTTP Integration", 1948 | "homepage": "https://symfony.com", 1949 | "time": "2017-01-02 20:32:22" 1950 | }, 1951 | { 1952 | "name": "symfony/serializer", 1953 | "version": "v3.2.2", 1954 | "source": { 1955 | "type": "git", 1956 | "url": "https://github.com/symfony/serializer.git", 1957 | "reference": "1538e02db55d8ba5b0c29f5062f471fe5b283704" 1958 | }, 1959 | "dist": { 1960 | "type": "zip", 1961 | "url": "https://api.github.com/repos/symfony/serializer/zipball/1538e02db55d8ba5b0c29f5062f471fe5b283704", 1962 | "reference": "1538e02db55d8ba5b0c29f5062f471fe5b283704", 1963 | "shasum": "" 1964 | }, 1965 | "require": { 1966 | "php": ">=5.5.9" 1967 | }, 1968 | "conflict": { 1969 | "symfony/property-access": ">=3.0,<3.0.4|>=2.8,<2.8.4", 1970 | "symfony/yaml": "<3.1" 1971 | }, 1972 | "require-dev": { 1973 | "doctrine/annotations": "~1.0", 1974 | "doctrine/cache": "~1.0", 1975 | "phpdocumentor/reflection-docblock": "~3.0", 1976 | "symfony/cache": "~3.1", 1977 | "symfony/config": "~2.8|~3.0", 1978 | "symfony/http-foundation": "~2.8|~3.0", 1979 | "symfony/property-access": "~2.8|~3.0", 1980 | "symfony/property-info": "~3.1", 1981 | "symfony/yaml": "~3.1" 1982 | }, 1983 | "suggest": { 1984 | "doctrine/annotations": "For using the annotation mapping. You will also need doctrine/cache.", 1985 | "doctrine/cache": "For using the default cached annotation reader and metadata cache.", 1986 | "psr/cache-implementation": "For using the metadata cache.", 1987 | "symfony/config": "For using the XML mapping loader.", 1988 | "symfony/http-foundation": "To use the DataUriNormalizer.", 1989 | "symfony/property-access": "For using the ObjectNormalizer.", 1990 | "symfony/property-info": "To deserialize relations.", 1991 | "symfony/yaml": "For using the default YAML mapping loader." 1992 | }, 1993 | "type": "library", 1994 | "extra": { 1995 | "branch-alias": { 1996 | "dev-master": "3.2-dev" 1997 | } 1998 | }, 1999 | "autoload": { 2000 | "psr-4": { 2001 | "Symfony\\Component\\Serializer\\": "" 2002 | }, 2003 | "exclude-from-classmap": [ 2004 | "/Tests/" 2005 | ] 2006 | }, 2007 | "notification-url": "https://packagist.org/downloads/", 2008 | "license": [ 2009 | "MIT" 2010 | ], 2011 | "authors": [ 2012 | { 2013 | "name": "Fabien Potencier", 2014 | "email": "fabien@symfony.com" 2015 | }, 2016 | { 2017 | "name": "Symfony Community", 2018 | "homepage": "https://symfony.com/contributors" 2019 | } 2020 | ], 2021 | "description": "Symfony Serializer Component", 2022 | "homepage": "https://symfony.com", 2023 | "time": "2017-01-08 20:47:33" 2024 | }, 2025 | { 2026 | "name": "symfony/translation", 2027 | "version": "v3.2.2", 2028 | "source": { 2029 | "type": "git", 2030 | "url": "https://github.com/symfony/translation.git", 2031 | "reference": "6520f3d4cce604d9dd1e86cac7af954984dd9bda" 2032 | }, 2033 | "dist": { 2034 | "type": "zip", 2035 | "url": "https://api.github.com/repos/symfony/translation/zipball/6520f3d4cce604d9dd1e86cac7af954984dd9bda", 2036 | "reference": "6520f3d4cce604d9dd1e86cac7af954984dd9bda", 2037 | "shasum": "" 2038 | }, 2039 | "require": { 2040 | "php": ">=5.5.9", 2041 | "symfony/polyfill-mbstring": "~1.0" 2042 | }, 2043 | "conflict": { 2044 | "symfony/config": "<2.8" 2045 | }, 2046 | "require-dev": { 2047 | "psr/log": "~1.0", 2048 | "symfony/config": "~2.8|~3.0", 2049 | "symfony/intl": "~2.8|~3.0", 2050 | "symfony/yaml": "~2.8|~3.0" 2051 | }, 2052 | "suggest": { 2053 | "psr/log": "To use logging capability in translator", 2054 | "symfony/config": "", 2055 | "symfony/yaml": "" 2056 | }, 2057 | "type": "library", 2058 | "extra": { 2059 | "branch-alias": { 2060 | "dev-master": "3.2-dev" 2061 | } 2062 | }, 2063 | "autoload": { 2064 | "psr-4": { 2065 | "Symfony\\Component\\Translation\\": "" 2066 | }, 2067 | "exclude-from-classmap": [ 2068 | "/Tests/" 2069 | ] 2070 | }, 2071 | "notification-url": "https://packagist.org/downloads/", 2072 | "license": [ 2073 | "MIT" 2074 | ], 2075 | "authors": [ 2076 | { 2077 | "name": "Fabien Potencier", 2078 | "email": "fabien@symfony.com" 2079 | }, 2080 | { 2081 | "name": "Symfony Community", 2082 | "homepage": "https://symfony.com/contributors" 2083 | } 2084 | ], 2085 | "description": "Symfony Translation Component", 2086 | "homepage": "https://symfony.com", 2087 | "time": "2017-01-02 20:32:22" 2088 | }, 2089 | { 2090 | "name": "symfony/validator", 2091 | "version": "v3.2.2", 2092 | "source": { 2093 | "type": "git", 2094 | "url": "https://github.com/symfony/validator.git", 2095 | "reference": "506e0fe69ecdc595850c76081137116c0537d6e9" 2096 | }, 2097 | "dist": { 2098 | "type": "zip", 2099 | "url": "https://api.github.com/repos/symfony/validator/zipball/506e0fe69ecdc595850c76081137116c0537d6e9", 2100 | "reference": "506e0fe69ecdc595850c76081137116c0537d6e9", 2101 | "shasum": "" 2102 | }, 2103 | "require": { 2104 | "php": ">=5.5.9", 2105 | "symfony/polyfill-mbstring": "~1.0", 2106 | "symfony/translation": "~2.8|~3.0" 2107 | }, 2108 | "require-dev": { 2109 | "doctrine/annotations": "~1.0", 2110 | "doctrine/cache": "~1.0", 2111 | "egulias/email-validator": "~1.2,>=1.2.8|~2.0", 2112 | "symfony/cache": "~3.1", 2113 | "symfony/config": "~2.8|~3.0", 2114 | "symfony/expression-language": "~2.8|~3.0", 2115 | "symfony/http-foundation": "~2.8|~3.0", 2116 | "symfony/intl": "~2.8|~3.0", 2117 | "symfony/yaml": "~2.8|~3.0" 2118 | }, 2119 | "suggest": { 2120 | "doctrine/annotations": "For using the annotation mapping. You will also need doctrine/cache.", 2121 | "doctrine/cache": "For using the default cached annotation reader and metadata cache.", 2122 | "egulias/email-validator": "Strict (RFC compliant) email validation", 2123 | "psr/cache-implementation": "For using the metadata cache.", 2124 | "symfony/config": "", 2125 | "symfony/expression-language": "For using the Expression validator", 2126 | "symfony/http-foundation": "", 2127 | "symfony/intl": "", 2128 | "symfony/property-access": "For using the Expression validator", 2129 | "symfony/yaml": "" 2130 | }, 2131 | "type": "library", 2132 | "extra": { 2133 | "branch-alias": { 2134 | "dev-master": "3.2-dev" 2135 | } 2136 | }, 2137 | "autoload": { 2138 | "psr-4": { 2139 | "Symfony\\Component\\Validator\\": "" 2140 | }, 2141 | "exclude-from-classmap": [ 2142 | "/Tests/" 2143 | ] 2144 | }, 2145 | "notification-url": "https://packagist.org/downloads/", 2146 | "license": [ 2147 | "MIT" 2148 | ], 2149 | "authors": [ 2150 | { 2151 | "name": "Fabien Potencier", 2152 | "email": "fabien@symfony.com" 2153 | }, 2154 | { 2155 | "name": "Symfony Community", 2156 | "homepage": "https://symfony.com/contributors" 2157 | } 2158 | ], 2159 | "description": "Symfony Validator Component", 2160 | "homepage": "https://symfony.com", 2161 | "time": "2017-01-12 19:27:47" 2162 | } 2163 | ], 2164 | "packages-dev": [], 2165 | "aliases": [], 2166 | "minimum-stability": "stable", 2167 | "stability-flags": [], 2168 | "prefer-stable": false, 2169 | "prefer-lowest": false, 2170 | "platform": [], 2171 | "platform-dev": [] 2172 | } 2173 | -------------------------------------------------------------------------------- /src/Controller/RecipeController.php: -------------------------------------------------------------------------------- 1 | buildSerializer(); 28 | 29 | $validatorFactory = new ValidatorFactory(); 30 | $validator = $validatorFactory->buildValidator(); 31 | 32 | $formFactory = Forms::createFormFactoryBuilder() 33 | ->addExtension(new ValidatorExtension($validator)) 34 | ->getFormFactory(); 35 | 36 | $data = json_decode($request->getContent(), true); 37 | $recipe = new Recipe(); 38 | $form = $formFactory->create(RecipeType::class, $recipe); 39 | $form->submit($data); 40 | 41 | if (!$form->isValid()) { 42 | $response = new Response($serializer->serialize($form, 'json'), 400); 43 | $response->headers->set('Content-Type', 'application/json'); 44 | return $response; 45 | } 46 | 47 | $entityManager = $this->dummyContainer['entityManager']; 48 | $entityManager->persist($recipe); 49 | $entityManager->flush(); 50 | 51 | //$response = new JsonResponse($serializer->normalize($recipe), 201); 52 | $groups = ['groups' => ['overview']]; 53 | $response = new Response($serializer->serialize($recipe, 'json', $groups), 201); 54 | 55 | $response->headers->set('Content-Type', 'application/json'); 56 | $response->headers->set('Location', '/myapi/recipes/'.$recipe->getId()); 57 | 58 | return $response; 59 | } 60 | 61 | public function get(Request $request, $id) 62 | { 63 | $serializerFactory = new SerializerFactory(); 64 | $serializer = $serializerFactory->buildSerializer(); 65 | 66 | $entityManager = $this->dummyContainer['entityManager']; 67 | $recipes = $entityManager->getRepository('MyApi\Entity\Recipe')->find($id); 68 | 69 | $groups = ['groups' => ['detail']]; 70 | $response = new Response($serializer->serialize($recipes, 'json', $groups), 201); 71 | $response->headers->set('Content-Type', 'application/json'); 72 | 73 | return $response; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/Entity/Recipe.php: -------------------------------------------------------------------------------- 1 | id; 56 | } 57 | 58 | /** 59 | * Set name 60 | * 61 | * @param string $name 62 | * 63 | * @return Recipe 64 | */ 65 | public function setName($name) 66 | { 67 | $this->name = $name; 68 | 69 | return $this; 70 | } 71 | 72 | /** 73 | * Get name 74 | * 75 | * @return string 76 | */ 77 | public function getName() 78 | { 79 | return $this->name; 80 | } 81 | 82 | /** 83 | * Set energy 84 | * 85 | * @param integer $energy 86 | * 87 | * @return Recipe 88 | */ 89 | public function setEnergy($energy) 90 | { 91 | $this->energy = $energy; 92 | 93 | return $this; 94 | } 95 | 96 | /** 97 | * Get energy 98 | * 99 | * @return integer 100 | */ 101 | public function getEnergy() 102 | { 103 | return $this->energy; 104 | } 105 | 106 | 107 | /** 108 | * Set servings 109 | * 110 | * @param integer $servings 111 | * 112 | * @return Recipe 113 | */ 114 | public function setServings($servings) 115 | { 116 | $this->servings = $servings; 117 | 118 | return $this; 119 | } 120 | 121 | /** 122 | * Get servings 123 | * 124 | * @return integer 125 | */ 126 | public function getServings() 127 | { 128 | return $this->servings; 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/Form/Type/RecipeType.php: -------------------------------------------------------------------------------- 1 | add('name') 16 | ->add('energy', null) 17 | ->add('servings', ChoiceType::class, [ 18 | 'choices' => [1, 2, 4], 19 | 'invalid_message' => 'Invalid value: Possible choices are 1, 2 or 4', 20 | ]) 21 | ; 22 | } 23 | 24 | public function setDefaultOptions(OptionsResolver $resolver) 25 | { 26 | $resolver->setDefaults(array( 27 | 'data_class' => 'MyApi\Entity\Recipe' 28 | )); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/NanoFramework.php: -------------------------------------------------------------------------------- 1 | matcher = $matcher; 31 | $this->dummyContainer = $dummyContainer; 32 | $this->firewallMap = new Http\FirewallMap(); 33 | $this->dispatcher = new EventDispatcher(); 34 | } 35 | 36 | 37 | public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true) 38 | { 39 | $this->secure(); 40 | $this->firewall = new Http\Firewall($this->firewallMap, $this->dispatcher); 41 | $this->dispatcher->addListener(HttpKernel\KernelEvents::REQUEST, array($this->firewall, 'onKernelRequest')); 42 | $event = new HttpKernel\Event\GetResponseEvent($this, $request, $type); 43 | $this->dispatcher->dispatch(HttpKernel\KernelEvents::REQUEST, $event); 44 | if ($event->hasResponse()) { 45 | return $event->getResponse(); 46 | } 47 | 48 | $controllerResolver = new ControllerResolver(); 49 | $argumentResolver = new ArgumentResolver(); 50 | try { 51 | $request->attributes->add($this->matcher->match($request->getPathInfo())); 52 | $controller = $controllerResolver->getController($request); 53 | $controller[0]->dummyContainer = $this->dummyContainer; 54 | $arguments = $argumentResolver->getArguments($request, $controller); 55 | 56 | return call_user_func_array($controller, $arguments); 57 | } catch ( Routing\Exception\ResourceNotFoundException $e ) { 58 | return new Response('Not Found', 404); 59 | } catch (Exception $e) { 60 | return new Response('An error occurred', 500); 61 | } 62 | } 63 | 64 | private function secure() 65 | { 66 | $requestMatcher = new HttpFoundation\RequestMatcher(); 67 | //Possible new HttpFoundation\RequestMatcher('^/securearea'); 68 | $firewallListeners = array(); 69 | $tokenStorage = new Authentication\Token\Storage\TokenStorage(); 70 | $guardHandler = new Guard\GuardAuthenticatorHandler($tokenStorage, $this->dispatcher); 71 | $guardAuthenticators = [new Security\LoginTokenAuthenticator(), new Security\TokenAuthenticator()]; 72 | $userProvider = new InMemoryUserProvider(['victoria' => ['password' => 'hola']]); 73 | $providers = array(new Guard\Provider\GuardAuthenticationProvider($guardAuthenticators, $userProvider, 'guard', new UserChecker())); 74 | 75 | $firewallListeners[] = new Guard\Firewall\GuardAuthenticationListener($guardHandler, new Authentication\AuthenticationProviderManager($providers), 'guard', $guardAuthenticators); 76 | $this->firewallMap->add($requestMatcher, $firewallListeners); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/Security/LoginTokenAuthenticator.php: -------------------------------------------------------------------------------- 1 | getPathInfo() != '/login_check') { 26 | return; 27 | } 28 | if (($username = $request->request->get('_username')) && 29 | ($password = $request->request->get('_password'))) { 30 | 31 | return [ 32 | 'username' => $username, 33 | 'password' => $password, 34 | ]; 35 | } 36 | 37 | return null; 38 | } 39 | 40 | public function getUser($credentials, UserProviderInterface $userProvider) 41 | { 42 | $username = $credentials['username']; 43 | return $userProvider->loadUserByUsername($username); 44 | } 45 | 46 | public function checkCredentials($credentials, UserInterface $user) 47 | { 48 | if ($credentials['username'] === 'victoria' && $credentials['password'] === 'hola') { 49 | return true; 50 | } 51 | 52 | // User could not be restored from session due to a wrong password 53 | throw new \Symfony\Component\Security\Core\Exception\BadCredentialsException(); 54 | } 55 | 56 | public function onAuthenticationFailure(Request $request, AuthenticationException $exception) 57 | { 58 | return new JsonResponse(['error' => 'unauthorized'], 401); 59 | } 60 | 61 | public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey) 62 | { 63 | return new JSONResponse([ 64 | 'token' => $this->generateToken($token->getUsername()), 65 | ]); 66 | } 67 | 68 | public function supportsRememberMe() 69 | { 70 | return false; 71 | } 72 | 73 | public function start(Request $request, AuthenticationException $authException = null) 74 | { 75 | return new RedirectResponse('/'); 76 | } 77 | 78 | private function generateToken($username) 79 | { 80 | $signer = new Sha256(); 81 | $keychain = new Keychain(); 82 | 83 | $token = (new Builder())->setIssuer('http://mydomain.com') // Configures the issuer (iss claim) 84 | ->setAudience('http://mydomain.org') // Configures the audience (aud claim) 85 | ->setId('4f1g23a12aa', true) // Configures the id (jti claim), replicating as a header item 86 | ->setIssuedAt(time()) // Configures the time that the token was issue (iat claim) 87 | //->setNotBefore(time() + 60) // Configures the time that the token can be used (nbf claim) 88 | ->setExpiration(time() + 3600) // Configures the expiration time of the token (nbf claim) 89 | ->set('username', $username) // Configures a new claim, called "username" 90 | ->sign($signer, $keychain->getPrivateKey('file://'.__DIR__.'/../../var/jwt/private.pem', 'patata')) 91 | ->getToken(); // creates a signature using your private key 92 | 93 | return (string)$token; 94 | 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /src/Security/TokenAuthenticator.php: -------------------------------------------------------------------------------- 1 | getPathInfo() == '/login_check') { 24 | return; 25 | } 26 | if ($token = $request->headers->get('Authentication')) { 27 | return [ 'token' => $token ]; 28 | } 29 | 30 | throw new \Symfony\Component\Security\Core\Exception\BadCredentialsException(); 31 | } 32 | 33 | public function getUser($credentials, UserProviderInterface $userProvider) 34 | { 35 | $token = $credentials['token']; 36 | $token = (new Parser())->parse((string) $token); 37 | $signer = new Sha256(); 38 | $keychain = new Keychain(); 39 | if ($token->verify($signer, $keychain->getPublicKey('file://'.__DIR__.'/../../var/jwt/public.pem'))) { 40 | $username = $token->getClaim('username'); 41 | return $userProvider->loadUserByUsername($username); 42 | } 43 | } 44 | 45 | public function checkCredentials($credentials, UserInterface $user) 46 | { 47 | if ($user) { 48 | return true; 49 | } 50 | 51 | // User could not be restored from session due to a wrong token 52 | throw new \Symfony\Component\Security\Core\Exception\BadCredentialsException(); 53 | } 54 | 55 | public function onAuthenticationFailure(Request $request, AuthenticationException $exception) 56 | { 57 | //$request->getSession()->set(Security::AUTHENTICATION_ERROR, $exception); 58 | 59 | return new JsonResponse(['error' => 'unauthorized'], 401); 60 | } 61 | 62 | public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey) 63 | { 64 | return; 65 | } 66 | 67 | public function supportsRememberMe() 68 | { 69 | return false; 70 | } 71 | 72 | public function start(Request $request, AuthenticationException $authException = null) 73 | { 74 | return new JsonResponse( 75 | array('message' => 'Authentication required'), 76 | 401 77 | ); 78 | } 79 | 80 | } 81 | -------------------------------------------------------------------------------- /src/Serializer/FormErrorNormalizer.php: -------------------------------------------------------------------------------- 1 | 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | namespace MyApi\Serializer; 11 | 12 | use Symfony\Component\Form\FormError; 13 | use Symfony\Component\Form\FormInterface; 14 | use Symfony\Component\Serializer\Normalizer\NormalizerInterface; 15 | use Symfony\Component\Translation\TranslatorInterface; 16 | 17 | /** 18 | * Normalizes invalid Form instances. 19 | * 20 | * @author Ener-Getick 21 | */ 22 | class FormErrorNormalizer implements NormalizerInterface 23 | { 24 | /** 25 | * {@inheritdoc} 26 | */ 27 | public function normalize($object, $format = null, array $context = []) 28 | { 29 | return [ 30 | 'code' => isset($context['status_code']) ? $context['status_code'] : null, 31 | 'message' => 'Validation Failed', 32 | 'errors' => $this->convertFormToArray($object), 33 | ]; 34 | } 35 | /** 36 | * {@inheritdoc} 37 | */ 38 | public function supportsNormalization($data, $format = null) 39 | { 40 | return $data instanceof FormInterface && $data->isSubmitted() && !$data->isValid(); 41 | } 42 | 43 | /** 44 | * This code has been taken from JMSSerializer. 45 | */ 46 | private function convertFormToArray(FormInterface $data) 47 | { 48 | $form = $errors = []; 49 | foreach ($data->getErrors() as $error) { 50 | $errors[] = $error->getMessage(); 51 | } 52 | if ($errors) { 53 | $form['errors'] = $errors; 54 | } 55 | $children = []; 56 | foreach ($data->all() as $child) { 57 | if ($child instanceof FormInterface) { 58 | $children[$child->getName()] = $this->convertFormToArray($child); 59 | } 60 | } 61 | if ($children) { 62 | $form['children'] = $children; 63 | } 64 | return $form; 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /src/Serializer/SerializerFactory.php: -------------------------------------------------------------------------------- 1 | enableAnnotationMapping(); 12 | return $validatorBuilder->getValidator(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/index.php: -------------------------------------------------------------------------------- 1 | 'pdo_sqlite', 26 | 'path' => __DIR__ . '/../var/db.sqlite', 27 | ); 28 | 29 | // obtaining the entity manager 30 | $entityManager = EntityManager::create($conn, $config); 31 | 32 | // This is why we use real frameworks. In a real application you should 33 | // provide access to a Dependency Injection Container or something you fancy 34 | $dummyContainer = ['entityManager' => $entityManager]; 35 | 36 | // ROUTES CONFIG 37 | $routes = new RouteCollection(); 38 | $routes->add('recipe_post', new Route('/recipes', ['_controller' => 'MyApi\Controller\RecipeController::post'], [], [], '', [], ['POST'])); 39 | $routes->add('recipe_get', new Route('/recipes/{id}', [ '_controller' => 'MyApi\Controller\RecipeController::get' ], [], [], '', [], ['GET'])); 40 | $routes->add('login_check', new Route('/login_check', [], [], [], '', [], ['POST'])); 41 | 42 | $request = Request::createFromGlobals(); 43 | $context = new RequestContext(); 44 | $context->fromRequest($request); 45 | $matcher = new UrlMatcher($routes, $context); 46 | 47 | $framework = new NanoFramework($matcher, $dummyContainer); 48 | $response = $framework->handle($request); 49 | 50 | $response->send(); 51 | --------------------------------------------------------------------------------