├── .gitignore ├── CONTRIBUTING.md ├── Dockerfile ├── LICENSE ├── README.md ├── app ├── .htaccess ├── AppCache.php ├── AppKernel.php ├── autoload.php └── config │ ├── config.yml │ ├── config_dev.yml │ ├── config_prod.yml │ ├── config_test.yml │ ├── parameters.yml.dist │ ├── routing.yml │ ├── routing_dev.yml │ ├── schema.yml │ ├── security.yml │ └── services.yml ├── behat.yml ├── bin ├── console └── symfony_requirements ├── composer.json ├── composer.lock ├── docker-compose.yml ├── docker ├── apache │ ├── run.sh │ ├── start_safe_perms │ └── vhost.conf └── php │ └── php.ini ├── features └── bootstrap │ └── FeatureContext.php ├── phpunit.xml.dist ├── src ├── .htaccess └── AppBundle │ ├── AppBundle.php │ └── Entity │ ├── Book.php │ ├── Organization.php │ └── Person.php ├── tests └── AppBundle │ └── Controller │ └── DefaultControllerTest.php ├── var ├── SymfonyRequirements.php ├── cache │ └── .gitkeep ├── logs │ └── .gitkeep └── sessions │ └── .gitkeep └── web ├── .htaccess ├── app.php ├── app_dev.php ├── apple-touch-icon.png ├── config.php ├── favicon.ico └── robots.txt /.gitignore: -------------------------------------------------------------------------------- 1 | /app/config/parameters.yml 2 | /build/ 3 | /phpunit.xml 4 | /var/* 5 | !/var/cache 6 | /var/cache/* 7 | !var/cache/.gitkeep 8 | !/var/logs 9 | /var/logs/* 10 | !var/logs/.gitkeep 11 | !/var/sessions 12 | /var/sessions/* 13 | !var/sessions/.gitkeep 14 | !var/SymfonyRequirements.php 15 | /vendor/ 16 | /web/bundles/ 17 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to API Platform 2 | 3 | First of all, thank you for contributing, you're awesome! 4 | 5 | To have your code integrated in the API Platform project, there is some rules to follow, but don't panic, it's easy! 6 | 7 | ## Reporting bugs 8 | 9 | If you happen to find a bug, we kindly request you to report it. However, before submitting it, please: 10 | 11 | * Check the [project documentation available online](https://api-platform.com/doc/) 12 | 13 | Then, if it appears that it's a real bug, you may report it using Github by following these 3 points: 14 | 15 | * Check if the bug is not already reported! 16 | * A clear title to resume the issue 17 | * A description of the workflow needed to reproduce the bug, 18 | 19 | > _NOTE:_ Don’t hesitate giving as much information as you can (OS, PHP version extensions...) 20 | 21 | ## Pull requests 22 | 23 | ### Writing a Pull Request 24 | 25 | First of all, you must decide on what branch your changes will be based. If the changes your are going to make are 26 | fully backward-compatible, you should base your changes on the latest stable branch (`1.0` at the moment). 27 | Otherwise, you should base your changes on the `master` branch. 28 | 29 | ### Matching coding standards 30 | 31 | The API Platform project follows [Symfony coding standards](https://symfony.com/doc/current/contributing/code/standards.html). 32 | But don't worry, you can fix CS issues automatically using the [PHP CS Fixer](http://cs.sensiolabs.org/) tool 33 | 34 | ```bash 35 | php-cs-fixer.phar fix 36 | ``` 37 | 38 | And then, add fixed file to your commit before push. 39 | Be sure to add only **your modified files**. If another files are fixed by cs tools, just revert it before commit. 40 | 41 | ### Sending a Pull Request 42 | 43 | When you send a PR, just make sure that: 44 | 45 | * You add valid test cases (Behat and PHPUnit). 46 | * Tests are green. 47 | * You make a PR on the related documentation in the [api-platform/doc](https://github.com/api-platform/doc) repository. 48 | * You make the PR on the same branch you based your changes on. If you see commits 49 | that you did not make in your PR, you're doing it wrong. 50 | * Also don't forget to add a comment when you update a PR with a ping to the maintainer (`@dunglas`, `@sroze` or `@theofidry`), so he/she will get a notification. 51 | * Squash your commits into one commit. (see the next chapter) 52 | 53 | All Pull Requests must include the following header: 54 | 55 | ```markdown 56 | | Q | A 57 | | ------------- | --- 58 | | Bug fix? | yes/no 59 | | New feature? | yes/no 60 | | BC breaks? | no 61 | | Deprecations? | no 62 | | Tests pass? | yes 63 | | Fixed tickets | #1234, #5678 64 | | License | MIT 65 | | Doc PR | api-platform/doc#1234 66 | ``` 67 | 68 | ## Squash your commits 69 | 70 | If you have 3 commits. So start with: 71 | 72 | ```bash 73 | git rebase -i HEAD~3 74 | ``` 75 | 76 | An editor will be opened with your 3 commits, all prefixed by `pick`. 77 | 78 | Replace all `pick` prefixes by `fixup` (or `f`) **except the first commit** of the list. 79 | 80 | Save and quit the editor. 81 | 82 | After that, all your commits where squashed into the first one and the commit message of the first commit. 83 | 84 | If you would like to rename your commit message type: 85 | 86 | ```bash 87 | git commit --amend 88 | ``` 89 | 90 | Now force push to update your PR: 91 | 92 | ```bash 93 | git push --force 94 | ``` 95 | 96 | # License and copyright attribution 97 | 98 | When you open a Pull Request to the API Platform project, you agree to license your code under the [MIT license](LICENSE) 99 | and to transfer the copyright on the submitted code to Kévin Dunglas. 100 | 101 | Be sure to you have the right to do that (if you are a professional, ask your company)! 102 | 103 | If you include code from another project, please mention it in the Pull Request description and credit the original author. 104 | 105 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:7.0-apache 2 | 3 | # PHP extensions 4 | RUN docker-php-ext-install mbstring 5 | 6 | # Apache & PHP configuration 7 | RUN a2enmod rewrite 8 | ADD docker/apache/vhost.conf /etc/apache2/sites-enabled/default.conf 9 | ADD docker/php/php.ini /usr/local/etc/php/php.ini 10 | 11 | # Install composer 12 | RUN curl -sS https://getcomposer.org/installer | php \ 13 | && mv composer.phar /usr/bin/composer 14 | 15 | # Add the application 16 | ADD . /app 17 | WORKDIR /app 18 | 19 | # Remove cache and logs if some and fixes permissions 20 | RUN ((rm -rf var/cache/* && rm -rf var/logs/* && rm -rf var/sessions/*) || true) \ 21 | 22 | # Install dependencies 23 | && composer install -o && app/console cache:warmup -e=prod \ 24 | 25 | # Fixes permissions issues in non-dev mode 26 | && chown -R www-data . var/cache var/logs var/sessions 27 | 28 | CMD ["/app/docker/apache/run.sh"] 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 Kévin Dunglas 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | The API Platform framework 2 | ========================== 3 | 4 | [![Join the chat at https://gitter.im/api-platform/api-platform](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/api-platform/api-platform?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 5 | 6 | *The new breed of web frameworks* 7 | 8 | [![API Platform](https://api-platform.com/images/api-platform-logo.27a08537.png)](https://api-platform.com) 9 | 10 | The official project documentation is available **[on the API Platform website][31]**. 11 | 12 | API Platform is a next-generation PHP web framework designed to create 13 | API-first projects easily but without compromise in the field of extensibility and 14 | flexibility: 15 | 16 | * Use our awesome code generator to **bootstrap a fully-functional data model from 17 | [Schema.org][8] vocabularies** with ORM mapping and validation (you can also do 18 | it manually) 19 | * **Expose in minutes an hypermedia REST API** that works out of the box by reusing 20 | entity metadata (ORM mapping, validation and serialization) ; that embraces [JSON-LD][1], 21 | [Hydra][2] and provides a ton of features (CRUD, validation and error handling, 22 | relation embedding, filters, ordering...) 23 | * Enjoy the **beautiful automatically generated API documentation** (Swagger-like) 24 | * Add easily **[JSON Web Token][25] or [OAuth][26] authentication** 25 | * Create specs and tests with a **developer friendly API context system** on top 26 | of [Behat][10] 27 | * Develop your website UI, webapp, mobile app or anything else you want using 28 | **your preferred client-side technologies**! Tested and approved with **AngularJS** 29 | (integration included), **Ionic**, **React** and **native mobile** apps 30 | 31 | API Platform embraces open web standards (JSON-LD, Hydra, JWT, OAuth, 32 | HTTP, HTML5...) and the [Linked Data][27] movement. Your API will automatically 33 | expose structured data in Schema.org/JSON-LD. It means that your API Platform application 34 | is usable **out of the box** with technologies of the semantic 35 | web. 36 | 37 | It also means that **your SEO will be improved** because **[Google recommends these 38 | formats][28]**. 39 | And yes, Google crawls full-Javascript applications [as well as old-fashioned ones][29]. 40 | 41 | Last but not least, API Platform is built on top of the [Symfony][5] 42 | full-stack framework and follows its best practices. It means than you can: 43 | 44 | * use **thousands of Symfony bundles** with API Platform 45 | * integrate API Platform in **any existing Symfony application** 46 | * reuse **all your Symfony skills** and benefit of the incredible 47 | amount of Symfony documentation available 48 | * enjoy the popular [Doctrine ORM][6] (used by default, but fully optional: you can 49 | use the data provider you want, including but not limited to MongoDB ODM and ElasticSearch) 50 | 51 | Install 52 | ------- 53 | 54 | Use [Composer][3] to create your new project: 55 | 56 | composer create-project api-platform/api-platform my-api 57 | 58 | Start to hack 59 | ------------- 60 | 61 | A demo application (a bookstore) is pre-installed. 62 | 63 | * Run `app/console server:start` and open `http://localhost:8000` in any 64 | HTTP client to access the API 65 | * Open `http://localhost:8000/doc` to read the HTML documentation an play 66 | with the sandbox 67 | * Give a try to the [HydraConsole][4] client to leverage JSON-LD and Hydra 68 | features 69 | * Build your first custom client using Javascript, CORS headers are already 70 | configured 71 | 72 | What's inside? 73 | -------------- 74 | 75 | API Platform provides rock solid foundations to build your project: 76 | 77 | * [**The Schema Generator**][7] to generate PHP entities from [Schema.org][8] types with 78 | Doctrine ORM mappings, Symfony validation and extended PHPDoc 79 | * [**The API bundle**][9] to expose in minutes your entities as a JSON-LD and 80 | Hydra enabled hypermedia REST API 81 | * [**NelmioApiDocBundle**][24] integrated with the API bundle to 82 | automatically generate a beautiful human-readable documentation and a 83 | sandbox to test the API 84 | * [Behat][10] and [Behatch][11] configured to easily test the API 85 | * The full power of the [**Symfony**][5] framework and its ecosystem 86 | * **[Doctrine][6] ORM/DBAL** 87 | * An AppBundle you can use to start coding 88 | * Annotations enabled for everything 89 | * Swiftmailer and Twig to create beautiful emails 90 | 91 | It comes pre-configured with the following bundles: 92 | 93 | * [**Symfony**][5] - API Platform is built on top of the full-stack 94 | Symfony framework 95 | * [**API Platform's API bundle**][9] - Creates powerful Hypermedia APIs supporting JSON-LD 96 | and Hydra 97 | * [**NelmioCorsBundle**][12] - Support for CORS headers 98 | * [**NelmioApiDocBundle**][24] - Generates a human-readable documentation 99 | * [**FosHttpCacheBundle**][13] - Add powerful caching capacities, supports Varnish, 100 | Nginx a built-in PHP reverse proxy 101 | * [**SensioFrameworkExtraBundle**][14] - Adds several enhancements, including 102 | template and routing annotation capability 103 | * [**DoctrineBundle**][15] - Adds support for the Doctrine ORM 104 | * [**TwigBundle**][16] - Adds support for the Twig templating engine (useful 105 | in emails) 106 | * [**SecurityBundle**][17] - Authentication and roles by integrating Symfony's 107 | security component 108 | * [**SwiftmailerBundle**][18] - Adds support for Swiftmailer, a library for sending 109 | emails 110 | * [**MonologBundle**][19] - Adds support for Monolog, a logging library 111 | * **WebProfilerBundle** (in dev/test env) - Adds profiling functionality and 112 | the web debug toolbar 113 | * **SensioDistributionBundle** (in dev/test env) - Adds functionality for configuring 114 | and working with Symfony distributions 115 | * [**SensioGeneratorBundle**][20] (in dev/test env) - Adds code generation capabilities 116 | 117 | All libraries and bundles included in API Platform are released under 118 | the MIT or BSD license. 119 | 120 | Authentication support 121 | ---------------------- 122 | 123 | Json Web Token is a lightweight and popular way to handle authentication in a 124 | stateless way. Install [**LexikJWTAuthenticationBundle**][21] to adds JWT support 125 | to API Platform. 126 | 127 | Oauth support can also be easily added using [**FOSOAuthServerBundle**][22]. 128 | 129 | Verifying release signature 130 | --------------------------- 131 | 132 | Software released by the API Platform project [can be verified with `git`](https://git-scm.com/book/tr/v2/Git-Tools-Signing-Your-Work#Verifying-Tags) 133 | using the following GPG public signature: 134 | 135 | ``` 136 | -----BEGIN PGP PUBLIC KEY BLOCK----- 137 | Version: GnuPG v1 138 | 139 | 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 185 | xA== 186 | =RO9E 187 | -----END PGP PUBLIC KEY BLOCK----- 188 | ``` 189 | 190 | Enjoy! 191 | 192 | Credits 193 | ------- 194 | 195 | Created by [Kévin Dunglas][23]. Sponsored by [Les-Tilleuls.coop][30] 196 | Commercial support available upon request. 197 | 198 | [1]: http://json-ld.org 199 | [2]: http://hydra-cg.com 200 | [3]: https://getcomposer.org 201 | [4]: http://www.hydra-cg.com/ 202 | [5]: https://symfony.com 203 | [6]: http://www.doctrine-project.org 204 | [7]: https://api-platform.com/doc/1.0/schema-generator/ 205 | [8]: http://schema.org 206 | [9]: https://api-platform.com/doc/1.0/api-bundle/ 207 | [10]: https://behat.readthedocs.org 208 | [11]: https://github.com/Behatch/contexts 209 | [12]: https://github.com/nelmio/NelmioCorsBundle 210 | [13]: https://foshttpcachebundle.readthedocs.org 211 | [14]: https://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/index.html 212 | [15]: https://symfony.com/doc/current/book/doctrine.html 213 | [16]: https://symfony.com/doc/current/book/templating.html 214 | [17]: https://symfony.com/doc/current/book/security.html 215 | [18]: https://symfony.com/doc/current/cookbook/email.html 216 | [19]: https://symfony.com/doc/current/cookbook/logging/monolog.html 217 | [20]: https://symfony.com/doc/current/bundles/SensioGeneratorBundle/index.html 218 | [21]: https://github.com/lexik/LexikJWTAuthenticationBundle 219 | [22]: https://github.com/FriendsOfSymfony/FOSOAuthServerBundle 220 | [23]: https://dunglas.fr 221 | [24]: https://github.com/nelmio/NelmioApiDocBundle 222 | [25]: http://jwt.io/ 223 | [26]: http://oauth.net/ 224 | [27]: https://en.wikipedia.org/wiki/Linked_data 225 | [28]: https://developers.google.com/structured-data/ 226 | [29]: http://searchengineland.com/tested-googlebot-crawls-javascript-heres-learned-220157 227 | [30]: https://les-tilleuls.coop 228 | [31]: https://api-platform.com 229 | -------------------------------------------------------------------------------- /app/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | Require all denied 3 | 4 | 5 | Order deny,allow 6 | Deny from all 7 | 8 | -------------------------------------------------------------------------------- /app/AppCache.php: -------------------------------------------------------------------------------- 1 | getEnvironment(), ['dev', 'test'], true)) { 25 | $bundles[] = new Symfony\Bundle\DebugBundle\DebugBundle(); 26 | $bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle(); 27 | $bundles[] = new Sensio\Bundle\DistributionBundle\SensioDistributionBundle(); 28 | $bundles[] = new Sensio\Bundle\GeneratorBundle\SensioGeneratorBundle(); 29 | } 30 | 31 | return $bundles; 32 | } 33 | 34 | public function getRootDir() 35 | { 36 | return __DIR__; 37 | } 38 | 39 | public function getCacheDir() 40 | { 41 | return dirname(__DIR__).'/var/cache/'.$this->getEnvironment(); 42 | } 43 | 44 | public function getLogDir() 45 | { 46 | return dirname(__DIR__).'/var/logs'; 47 | } 48 | 49 | public function registerContainerConfiguration(LoaderInterface $loader) 50 | { 51 | $loader->load($this->getRootDir().'/config/config_'.$this->getEnvironment().'.yml'); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/autoload.php: -------------------------------------------------------------------------------- 1 | getParameterOption(['--env', '-e'], getenv('SYMFONY_ENV') ?: 'dev'); 21 | $debug = getenv('SYMFONY_DEBUG') !== '0' && !$input->hasParameterOption(['--no-debug', '']) && $env !== 'prod'; 22 | 23 | if ($debug) { 24 | Debug::enable(); 25 | } 26 | 27 | $kernel = new AppKernel($env, $debug); 28 | $application = new Application($kernel); 29 | $application->run($input); 30 | -------------------------------------------------------------------------------- /bin/symfony_requirements: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | getPhpIniConfigPath(); 9 | 10 | echo_title('Symfony Requirements Checker'); 11 | 12 | echo '> PHP is using the following php.ini file:'.PHP_EOL; 13 | if ($iniPath) { 14 | echo_style('green', ' '.$iniPath); 15 | } else { 16 | echo_style('warning', ' WARNING: No configuration file (php.ini) used by PHP!'); 17 | } 18 | 19 | echo PHP_EOL.PHP_EOL; 20 | 21 | echo '> Checking Symfony requirements:'.PHP_EOL.' '; 22 | 23 | $messages = array(); 24 | foreach ($symfonyRequirements->getRequirements() as $req) { 25 | /** @var $req Requirement */ 26 | if ($helpText = get_error_message($req, $lineSize)) { 27 | echo_style('red', 'E'); 28 | $messages['error'][] = $helpText; 29 | } else { 30 | echo_style('green', '.'); 31 | } 32 | } 33 | 34 | $checkPassed = empty($messages['error']); 35 | 36 | foreach ($symfonyRequirements->getRecommendations() as $req) { 37 | if ($helpText = get_error_message($req, $lineSize)) { 38 | echo_style('yellow', 'W'); 39 | $messages['warning'][] = $helpText; 40 | } else { 41 | echo_style('green', '.'); 42 | } 43 | } 44 | 45 | if ($checkPassed) { 46 | echo_block('success', 'OK', 'Your system is ready to run Symfony projects'); 47 | } else { 48 | echo_block('error', 'ERROR', 'Your system is not ready to run Symfony projects'); 49 | 50 | echo_title('Fix the following mandatory requirements', 'red'); 51 | 52 | foreach ($messages['error'] as $helpText) { 53 | echo ' * '.$helpText.PHP_EOL; 54 | } 55 | } 56 | 57 | if (!empty($messages['warning'])) { 58 | echo_title('Optional recommendations to improve your setup', 'yellow'); 59 | 60 | foreach ($messages['warning'] as $helpText) { 61 | echo ' * '.$helpText.PHP_EOL; 62 | } 63 | } 64 | 65 | echo PHP_EOL; 66 | echo_style('title', 'Note'); 67 | echo ' The command console could use a different php.ini file'.PHP_EOL; 68 | echo_style('title', '~~~~'); 69 | echo ' than the one used with your web server. To be on the'.PHP_EOL; 70 | echo ' safe side, please check the requirements from your web'.PHP_EOL; 71 | echo ' server using the '; 72 | echo_style('yellow', 'web/config.php'); 73 | echo ' script.'.PHP_EOL; 74 | echo PHP_EOL; 75 | 76 | exit($checkPassed ? 0 : 1); 77 | 78 | function get_error_message(Requirement $requirement, $lineSize) 79 | { 80 | if ($requirement->isFulfilled()) { 81 | return; 82 | } 83 | 84 | $errorMessage = wordwrap($requirement->getTestMessage(), $lineSize - 3, PHP_EOL.' ').PHP_EOL; 85 | $errorMessage .= ' > '.wordwrap($requirement->getHelpText(), $lineSize - 5, PHP_EOL.' > ').PHP_EOL; 86 | 87 | return $errorMessage; 88 | } 89 | 90 | function echo_title($title, $style = null) 91 | { 92 | $style = $style ?: 'title'; 93 | 94 | echo PHP_EOL; 95 | echo_style($style, $title.PHP_EOL); 96 | echo_style($style, str_repeat('~', strlen($title)).PHP_EOL); 97 | echo PHP_EOL; 98 | } 99 | 100 | function echo_style($style, $message) 101 | { 102 | // ANSI color codes 103 | $styles = array( 104 | 'reset' => "\033[0m", 105 | 'red' => "\033[31m", 106 | 'green' => "\033[32m", 107 | 'yellow' => "\033[33m", 108 | 'error' => "\033[37;41m", 109 | 'success' => "\033[37;42m", 110 | 'title' => "\033[34m", 111 | ); 112 | $supports = has_color_support(); 113 | 114 | echo($supports ? $styles[$style] : '').$message.($supports ? $styles['reset'] : ''); 115 | } 116 | 117 | function echo_block($style, $title, $message) 118 | { 119 | $message = ' '.trim($message).' '; 120 | $width = strlen($message); 121 | 122 | echo PHP_EOL.PHP_EOL; 123 | 124 | echo_style($style, str_repeat(' ', $width).PHP_EOL); 125 | echo_style($style, str_pad(' ['.$title.']', $width, ' ', STR_PAD_RIGHT).PHP_EOL); 126 | echo_style($style, str_pad($message, $width, ' ', STR_PAD_RIGHT).PHP_EOL); 127 | echo_style($style, str_repeat(' ', $width).PHP_EOL); 128 | } 129 | 130 | function has_color_support() 131 | { 132 | static $support; 133 | 134 | if (null === $support) { 135 | if (DIRECTORY_SEPARATOR == '\\') { 136 | $support = false !== getenv('ANSICON') || 'ON' === getenv('ConEmuANSI'); 137 | } else { 138 | $support = function_exists('posix_isatty') && @posix_isatty(STDOUT); 139 | } 140 | } 141 | 142 | return $support; 143 | } 144 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "api-platform/api-platform", 3 | "license": "MIT", 4 | "type": "project", 5 | "description": "The API Platform framework", 6 | "authors": [ 7 | { 8 | "name": "Kévin Dunglas", 9 | "email": "dunglas@gmail.com", 10 | "homepage": "https://dunglas.fr" 11 | } 12 | ], 13 | "repositories": [ 14 | { 15 | "type": "vcs", 16 | "url": "https://github.com/dunglas/DoctrineBundle" 17 | } 18 | ], 19 | "autoload": { 20 | "psr-4": { "": "src/" }, 21 | "classmap": [ "app/AppKernel.php", "app/AppCache.php" ] 22 | }, 23 | "autoload-dev": { 24 | "psr-4": { "Tests\\": "tests/" } 25 | }, 26 | "require": { 27 | "php": ">=7.0", 28 | "symfony/symfony": "3.1.*@dev", 29 | "doctrine/orm": "^2.5", 30 | "doctrine/doctrine-bundle": "dev-property_info", 31 | "doctrine/doctrine-cache-bundle": "^1.2", 32 | "symfony/swiftmailer-bundle": "^2.3", 33 | "symfony/monolog-bundle": "^2.8", 34 | "sensio/distribution-bundle": "^5.0", 35 | "sensio/framework-extra-bundle": "^3.0.2", 36 | "incenteev/composer-parameter-handler": "^2.0", 37 | "api-platform/core": "^2.0@dev", 38 | "nelmio/cors-bundle": "^1.4", 39 | "nelmio/api-doc-bundle": "^2.10", 40 | "phpdocumentor/reflection-docblock": "^3.0" 41 | }, 42 | "require-dev": { 43 | "sensio/generator-bundle": "^3.0", 44 | "symfony/phpunit-bridge": "^3.0", 45 | "api-platform/schema-generator": "dev-master", 46 | "behat/behat": "~3.1@dev", 47 | "behat/symfony2-extension": "~2.1@dev", 48 | "behat/mink": "~1.7@dev", 49 | "behat/mink-extension": "~2.2", 50 | "behat/mink-browserkit-driver": "^1.3.1", 51 | "behatch/contexts": "~2.5" 52 | }, 53 | "scripts": { 54 | "post-install-cmd": [ 55 | "Incenteev\\ParameterHandler\\ScriptHandler::buildParameters", 56 | "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::buildBootstrap", 57 | "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::clearCache", 58 | "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets", 59 | "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installRequirementsFile", 60 | "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::prepareDeploymentTarget" 61 | ], 62 | "post-update-cmd": [ 63 | "Incenteev\\ParameterHandler\\ScriptHandler::buildParameters", 64 | "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::buildBootstrap", 65 | "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::clearCache", 66 | "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets", 67 | "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installRequirementsFile", 68 | "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::prepareDeploymentTarget" 69 | ] 70 | }, 71 | "extra": { 72 | "symfony-app-dir": "app", 73 | "symfony-bin-dir": "bin", 74 | "symfony-var-dir": "var", 75 | "symfony-web-dir": "web", 76 | "symfony-tests-dir": "tests", 77 | "symfony-assets-install": "relative", 78 | "incenteev-parameters": { 79 | "file": "app/config/parameters.yml" 80 | }, 81 | "branch-alias": { 82 | "dev-master": "2.0-dev" 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | web: 2 | build: . 3 | links: 4 | - database 5 | volumes: 6 | - .:/app 7 | 8 | database: 9 | image: mysql 10 | environment: 11 | MYSQL_ROOT_PASSWORD: changeme 12 | MYSQL_DATABASE: api-platform 13 | MYSQL_USER: api-platform 14 | MYSQL_PASSWORD: api-platform 15 | 16 | -------------------------------------------------------------------------------- /docker/apache/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -xe 3 | 4 | # Start Apache with the right permissions 5 | /app/docker/apache/start_safe_perms -DFOREGROUND 6 | -------------------------------------------------------------------------------- /docker/apache/start_safe_perms: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ## 4 | # Detect the ownership of the webroot 5 | # and run apache as that user. 6 | # 7 | main() { 8 | local owner group owner_id group_id tmp 9 | read owner group owner_id group_id < <(stat -c '%U %G %u %g' .) 10 | if [[ $owner = UNKNOWN ]]; then 11 | owner=$(randname) 12 | if [[ $group = UNKNOWN ]]; then 13 | group=$owner 14 | addgroup --system --gid "$group_id" "$group" 15 | fi 16 | adduser --system --uid=$owner_id --gid=$group_id "$owner" 17 | fi 18 | tmp=/tmp/$RANDOM 19 | { 20 | echo "User $owner" 21 | echo "Group $group" 22 | grep -v '^User' /etc/apache2/apache2.conf | 23 | grep -v '^Group' 24 | } >> "$tmp" && 25 | cat "$tmp" > /etc/apache2/apache2.conf && 26 | rm "$tmp" 27 | # Not volumes, so need to be chowned 28 | chown -R "$owner:$group" /var/{lock,log,run}/apache* 29 | exec /usr/sbin/apache2ctl "$@" 30 | } 31 | 32 | ## 33 | # Generate a random sixteen-character 34 | # string of alphabetical characters 35 | randname() { 36 | local -x LC_ALL=C 37 | tr -dc '[:lower:]' < /dev/urandom | 38 | dd count=1 bs=16 2>/dev/null 39 | } 40 | 41 | main "$@" 42 | -------------------------------------------------------------------------------- /docker/apache/vhost.conf: -------------------------------------------------------------------------------- 1 | 2 | ServerAdmin webmaster@localhost 3 | DocumentRoot /app/web 4 | 5 | 6 | Options Indexes FollowSymLinks 7 | AllowOverride All 8 | Require all granted 9 | 10 | 11 | -------------------------------------------------------------------------------- /docker/php/php.ini: -------------------------------------------------------------------------------- 1 | date.timezone = Europe/London 2 | 3 | -------------------------------------------------------------------------------- /features/bootstrap/FeatureContext.php: -------------------------------------------------------------------------------- 1 | doctrine = $doctrine; 32 | $this->manager = $doctrine->getManager(); 33 | $this->schemaTool = new SchemaTool($this->manager); 34 | $this->classes = $this->manager->getMetadataFactory()->getAllMetadata(); 35 | } 36 | 37 | /** 38 | * @BeforeScenario @createSchema 39 | */ 40 | public function createDatabase() 41 | { 42 | $this->schemaTool->createSchema($this->classes); 43 | } 44 | 45 | /** 46 | * @AfterScenario @dropSchema 47 | */ 48 | public function dropDatabase() 49 | { 50 | $this->schemaTool->dropSchema($this->classes); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | tests 18 | 19 | 20 | 21 | 22 | 23 | src 24 | 25 | src/*Bundle/Resources 26 | src/*/*Bundle/Resources 27 | src/*/Bundle/*Bundle/Resources 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | Require all denied 3 | 4 | 5 | Order deny,allow 6 | Deny from all 7 | 8 | -------------------------------------------------------------------------------- /src/AppBundle/AppBundle.php: -------------------------------------------------------------------------------- 1 | The author of this content. Please note that author is special in that HTML 5 provides a special mechanism for indicating authorship via the rel tag. That is equivalent to this and may be used interchangeably. 31 | * 32 | * @ORM\ManyToMany(targetEntity="AppBundle\Entity\Person") 33 | * @Property(iri="http://schema.org/author") 34 | */ 35 | private $author; 36 | /** 37 | * @var \DateTime Date of first broadcast/publication. 38 | * 39 | * @ORM\Column(type="date", nullable=true) 40 | * @Assert\Date 41 | * @Property(iri="http://schema.org/datePublished") 42 | */ 43 | private $datePublished; 44 | /** 45 | * @var string A short description of the item. 46 | * 47 | * @ORM\Column(nullable=true) 48 | * @Assert\Type(type="string") 49 | * @Property(iri="http://schema.org/description") 50 | */ 51 | private $description; 52 | /** 53 | * @var string Genre of the creative work or group. 54 | * 55 | * @ORM\Column(nullable=true) 56 | * @Assert\Type(type="string") 57 | * @Property(iri="http://schema.org/genre") 58 | */ 59 | private $genre; 60 | /** 61 | * @var string The ISBN of the book. 62 | * 63 | * @ORM\Column(nullable=true) 64 | * @Assert\Type(type="string") 65 | * @Property(iri="http://schema.org/isbn") 66 | */ 67 | private $isbn; 68 | /** 69 | * @var string The name of the item. 70 | * 71 | * @ORM\Column(nullable=true) 72 | * @Assert\Type(type="string") 73 | * @Property(iri="http://schema.org/name") 74 | */ 75 | private $name; 76 | /** 77 | * @var int The number of pages in the book. 78 | * 79 | * @ORM\Column(type="integer", nullable=true) 80 | * @Assert\Type(type="integer") 81 | * @Property(iri="http://schema.org/numberOfPages") 82 | */ 83 | private $numberOfPages; 84 | /** 85 | * @var Organization The publisher of the creative work. 86 | * 87 | * @ORM\OneToOne(targetEntity="AppBundle\Entity\Organization") 88 | * @Property(iri="http://schema.org/publisher") 89 | */ 90 | private $publisher; 91 | 92 | public function __construct() 93 | { 94 | $this->author = new ArrayCollection(); 95 | } 96 | 97 | /** 98 | * Sets id. 99 | * 100 | * @param int $id 101 | * 102 | * @return $this 103 | */ 104 | public function setId($id) 105 | { 106 | $this->id = $id; 107 | 108 | return $this; 109 | } 110 | 111 | /** 112 | * Gets id. 113 | * 114 | * @return int 115 | */ 116 | public function getId() 117 | { 118 | return $this->id; 119 | } 120 | 121 | /** 122 | * Adds author. 123 | * 124 | * @param Person $author 125 | * 126 | * @return $this 127 | */ 128 | public function addAuthor(Person $author) 129 | { 130 | $this->author[] = $author; 131 | 132 | return $this; 133 | } 134 | 135 | /** 136 | * Removes author. 137 | * 138 | * @param Person $author 139 | * 140 | * @return $this 141 | */ 142 | public function removeAuthor(Person $author) 143 | { 144 | $this->author->removeElement($author); 145 | 146 | return $this; 147 | } 148 | 149 | /** 150 | * Gets author. 151 | * 152 | * @return ArrayCollection 153 | */ 154 | public function getAuthor() 155 | { 156 | return $this->author; 157 | } 158 | 159 | /** 160 | * Sets datePublished. 161 | * 162 | * @param \DateTime $datePublished 163 | * 164 | * @return $this 165 | */ 166 | public function setDatePublished(\DateTime $datePublished = null) 167 | { 168 | $this->datePublished = $datePublished; 169 | 170 | return $this; 171 | } 172 | 173 | /** 174 | * Gets datePublished. 175 | * 176 | * @return \DateTime 177 | */ 178 | public function getDatePublished() 179 | { 180 | return $this->datePublished; 181 | } 182 | 183 | /** 184 | * Sets description. 185 | * 186 | * @param string $description 187 | * 188 | * @return $this 189 | */ 190 | public function setDescription($description) 191 | { 192 | $this->description = $description; 193 | 194 | return $this; 195 | } 196 | 197 | /** 198 | * Gets description. 199 | * 200 | * @return string 201 | */ 202 | public function getDescription() 203 | { 204 | return $this->description; 205 | } 206 | 207 | /** 208 | * Sets genre. 209 | * 210 | * @param string $genre 211 | * 212 | * @return $this 213 | */ 214 | public function setGenre($genre) 215 | { 216 | $this->genre = $genre; 217 | 218 | return $this; 219 | } 220 | 221 | /** 222 | * Gets genre. 223 | * 224 | * @return string 225 | */ 226 | public function getGenre() 227 | { 228 | return $this->genre; 229 | } 230 | 231 | /** 232 | * Sets isbn. 233 | * 234 | * @param string $isbn 235 | * 236 | * @return $this 237 | */ 238 | public function setIsbn($isbn) 239 | { 240 | $this->isbn = $isbn; 241 | 242 | return $this; 243 | } 244 | 245 | /** 246 | * Gets isbn. 247 | * 248 | * @return string 249 | */ 250 | public function getIsbn() 251 | { 252 | return $this->isbn; 253 | } 254 | 255 | /** 256 | * Sets name. 257 | * 258 | * @param string $name 259 | * 260 | * @return $this 261 | */ 262 | public function setName($name) 263 | { 264 | $this->name = $name; 265 | 266 | return $this; 267 | } 268 | 269 | /** 270 | * Gets name. 271 | * 272 | * @return string 273 | */ 274 | public function getName() 275 | { 276 | return $this->name; 277 | } 278 | 279 | /** 280 | * Sets numberOfPages. 281 | * 282 | * @param int $numberOfPages 283 | * 284 | * @return $this 285 | */ 286 | public function setNumberOfPages($numberOfPages) 287 | { 288 | $this->numberOfPages = $numberOfPages; 289 | 290 | return $this; 291 | } 292 | 293 | /** 294 | * Gets numberOfPages. 295 | * 296 | * @return int 297 | */ 298 | public function getNumberOfPages() 299 | { 300 | return $this->numberOfPages; 301 | } 302 | 303 | /** 304 | * Sets publisher. 305 | * 306 | * @param Organization $publisher 307 | * 308 | * @return $this 309 | */ 310 | public function setPublisher(Organization $publisher = null) 311 | { 312 | $this->publisher = $publisher; 313 | 314 | return $this; 315 | } 316 | 317 | /** 318 | * Gets publisher. 319 | * 320 | * @return Organization 321 | */ 322 | public function getPublisher() 323 | { 324 | return $this->publisher; 325 | } 326 | } 327 | -------------------------------------------------------------------------------- /src/AppBundle/Entity/Organization.php: -------------------------------------------------------------------------------- 1 | id = $id; 63 | 64 | return $this; 65 | } 66 | 67 | /** 68 | * Gets id. 69 | * 70 | * @return int 71 | */ 72 | public function getId() 73 | { 74 | return $this->id; 75 | } 76 | 77 | /** 78 | * Sets description. 79 | * 80 | * @param string $description 81 | * 82 | * @return $this 83 | */ 84 | public function setDescription($description) 85 | { 86 | $this->description = $description; 87 | 88 | return $this; 89 | } 90 | 91 | /** 92 | * Gets description. 93 | * 94 | * @return string 95 | */ 96 | public function getDescription() 97 | { 98 | return $this->description; 99 | } 100 | 101 | /** 102 | * Sets name. 103 | * 104 | * @param string $name 105 | * 106 | * @return $this 107 | */ 108 | public function setName($name) 109 | { 110 | $this->name = $name; 111 | 112 | return $this; 113 | } 114 | 115 | /** 116 | * Gets name. 117 | * 118 | * @return string 119 | */ 120 | public function getName() 121 | { 122 | return $this->name; 123 | } 124 | 125 | /** 126 | * Sets url. 127 | * 128 | * @param string $url 129 | * 130 | * @return $this 131 | */ 132 | public function setUrl($url) 133 | { 134 | $this->url = $url; 135 | 136 | return $this; 137 | } 138 | 139 | /** 140 | * Gets url. 141 | * 142 | * @return string 143 | */ 144 | public function getUrl() 145 | { 146 | return $this->url; 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /src/AppBundle/Entity/Person.php: -------------------------------------------------------------------------------- 1 | id = $id; 79 | 80 | return $this; 81 | } 82 | 83 | /** 84 | * Gets id. 85 | * 86 | * @return int 87 | */ 88 | public function getId() 89 | { 90 | return $this->id; 91 | } 92 | 93 | /** 94 | * Sets birthDate. 95 | * 96 | * @param \DateTime $birthDate 97 | * 98 | * @return $this 99 | */ 100 | public function setBirthDate(\DateTime $birthDate = null) 101 | { 102 | $this->birthDate = $birthDate; 103 | 104 | return $this; 105 | } 106 | 107 | /** 108 | * Gets birthDate. 109 | * 110 | * @return \DateTime 111 | */ 112 | public function getBirthDate() 113 | { 114 | return $this->birthDate; 115 | } 116 | 117 | /** 118 | * Sets description. 119 | * 120 | * @param string $description 121 | * 122 | * @return $this 123 | */ 124 | public function setDescription($description) 125 | { 126 | $this->description = $description; 127 | 128 | return $this; 129 | } 130 | 131 | /** 132 | * Gets description. 133 | * 134 | * @return string 135 | */ 136 | public function getDescription() 137 | { 138 | return $this->description; 139 | } 140 | 141 | /** 142 | * Sets gender. 143 | * 144 | * @param string $gender 145 | * 146 | * @return $this 147 | */ 148 | public function setGender($gender) 149 | { 150 | $this->gender = $gender; 151 | 152 | return $this; 153 | } 154 | 155 | /** 156 | * Gets gender. 157 | * 158 | * @return string 159 | */ 160 | public function getGender() 161 | { 162 | return $this->gender; 163 | } 164 | 165 | /** 166 | * Sets name. 167 | * 168 | * @param string $name 169 | * 170 | * @return $this 171 | */ 172 | public function setName($name) 173 | { 174 | $this->name = $name; 175 | 176 | return $this; 177 | } 178 | 179 | /** 180 | * Gets name. 181 | * 182 | * @return string 183 | */ 184 | public function getName() 185 | { 186 | return $this->name; 187 | } 188 | 189 | /** 190 | * Sets url. 191 | * 192 | * @param string $url 193 | * 194 | * @return $this 195 | */ 196 | public function setUrl($url) 197 | { 198 | $this->url = $url; 199 | 200 | return $this; 201 | } 202 | 203 | /** 204 | * Gets url. 205 | * 206 | * @return string 207 | */ 208 | public function getUrl() 209 | { 210 | return $this->url; 211 | } 212 | } 213 | -------------------------------------------------------------------------------- /tests/AppBundle/Controller/DefaultControllerTest.php: -------------------------------------------------------------------------------- 1 | request('GET', '/'); 14 | 15 | $this->assertEquals(200, $client->getResponse()->getStatusCode()); 16 | $this->assertContains('Welcome to Symfony', $crawler->filter('#container h1')->text()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /var/SymfonyRequirements.php: -------------------------------------------------------------------------------- 1 | 7 | * 8 | * For the full copyright and license information, please view the LICENSE 9 | * file that was distributed with this source code. 10 | */ 11 | 12 | /* 13 | * Users of PHP 5.2 should be able to run the requirements checks. 14 | * This is why the file and all classes must be compatible with PHP 5.2+ 15 | * (e.g. not using namespaces and closures). 16 | * 17 | * ************** CAUTION ************** 18 | * 19 | * DO NOT EDIT THIS FILE as it will be overridden by Composer as part of 20 | * the installation/update process. The original file resides in the 21 | * SensioDistributionBundle. 22 | * 23 | * ************** CAUTION ************** 24 | */ 25 | 26 | /** 27 | * Represents a single PHP requirement, e.g. an installed extension. 28 | * It can be a mandatory requirement or an optional recommendation. 29 | * There is a special subclass, named PhpIniRequirement, to check a php.ini configuration. 30 | * 31 | * @author Tobias Schultze 32 | */ 33 | class Requirement 34 | { 35 | private $fulfilled; 36 | private $testMessage; 37 | private $helpText; 38 | private $helpHtml; 39 | private $optional; 40 | 41 | /** 42 | * Constructor that initializes the requirement. 43 | * 44 | * @param bool $fulfilled Whether the requirement is fulfilled 45 | * @param string $testMessage The message for testing the requirement 46 | * @param string $helpHtml The help text formatted in HTML for resolving the problem 47 | * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) 48 | * @param bool $optional Whether this is only an optional recommendation not a mandatory requirement 49 | */ 50 | public function __construct($fulfilled, $testMessage, $helpHtml, $helpText = null, $optional = false) 51 | { 52 | $this->fulfilled = (bool) $fulfilled; 53 | $this->testMessage = (string) $testMessage; 54 | $this->helpHtml = (string) $helpHtml; 55 | $this->helpText = null === $helpText ? strip_tags($this->helpHtml) : (string) $helpText; 56 | $this->optional = (bool) $optional; 57 | } 58 | 59 | /** 60 | * Returns whether the requirement is fulfilled. 61 | * 62 | * @return bool true if fulfilled, otherwise false 63 | */ 64 | public function isFulfilled() 65 | { 66 | return $this->fulfilled; 67 | } 68 | 69 | /** 70 | * Returns the message for testing the requirement. 71 | * 72 | * @return string The test message 73 | */ 74 | public function getTestMessage() 75 | { 76 | return $this->testMessage; 77 | } 78 | 79 | /** 80 | * Returns the help text for resolving the problem. 81 | * 82 | * @return string The help text 83 | */ 84 | public function getHelpText() 85 | { 86 | return $this->helpText; 87 | } 88 | 89 | /** 90 | * Returns the help text formatted in HTML. 91 | * 92 | * @return string The HTML help 93 | */ 94 | public function getHelpHtml() 95 | { 96 | return $this->helpHtml; 97 | } 98 | 99 | /** 100 | * Returns whether this is only an optional recommendation and not a mandatory requirement. 101 | * 102 | * @return bool true if optional, false if mandatory 103 | */ 104 | public function isOptional() 105 | { 106 | return $this->optional; 107 | } 108 | } 109 | 110 | /** 111 | * Represents a PHP requirement in form of a php.ini configuration. 112 | * 113 | * @author Tobias Schultze 114 | */ 115 | class PhpIniRequirement extends Requirement 116 | { 117 | /** 118 | * Constructor that initializes the requirement. 119 | * 120 | * @param string $cfgName The configuration name used for ini_get() 121 | * @param bool|callback $evaluation Either a boolean indicating whether the configuration should evaluate to true or false, 122 | * or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement 123 | * @param bool $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false. 124 | * This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin. 125 | * Example: You require a config to be true but PHP later removes this config and defaults it to true internally. 126 | * @param string|null $testMessage The message for testing the requirement (when null and $evaluation is a boolean a default message is derived) 127 | * @param string|null $helpHtml The help text formatted in HTML for resolving the problem (when null and $evaluation is a boolean a default help is derived) 128 | * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) 129 | * @param bool $optional Whether this is only an optional recommendation not a mandatory requirement 130 | */ 131 | public function __construct($cfgName, $evaluation, $approveCfgAbsence = false, $testMessage = null, $helpHtml = null, $helpText = null, $optional = false) 132 | { 133 | $cfgValue = ini_get($cfgName); 134 | 135 | if (is_callable($evaluation)) { 136 | if (null === $testMessage || null === $helpHtml) { 137 | throw new InvalidArgumentException('You must provide the parameters testMessage and helpHtml for a callback evaluation.'); 138 | } 139 | 140 | $fulfilled = call_user_func($evaluation, $cfgValue); 141 | } else { 142 | if (null === $testMessage) { 143 | $testMessage = sprintf('%s %s be %s in php.ini', 144 | $cfgName, 145 | $optional ? 'should' : 'must', 146 | $evaluation ? 'enabled' : 'disabled' 147 | ); 148 | } 149 | 150 | if (null === $helpHtml) { 151 | $helpHtml = sprintf('Set %s to %s in php.ini*.', 152 | $cfgName, 153 | $evaluation ? 'on' : 'off' 154 | ); 155 | } 156 | 157 | $fulfilled = $evaluation == $cfgValue; 158 | } 159 | 160 | parent::__construct($fulfilled || ($approveCfgAbsence && false === $cfgValue), $testMessage, $helpHtml, $helpText, $optional); 161 | } 162 | } 163 | 164 | /** 165 | * A RequirementCollection represents a set of Requirement instances. 166 | * 167 | * @author Tobias Schultze 168 | */ 169 | class RequirementCollection implements IteratorAggregate 170 | { 171 | private $requirements = array(); 172 | 173 | /** 174 | * Gets the current RequirementCollection as an Iterator. 175 | * 176 | * @return Traversable A Traversable interface 177 | */ 178 | public function getIterator() 179 | { 180 | return new ArrayIterator($this->requirements); 181 | } 182 | 183 | /** 184 | * Adds a Requirement. 185 | * 186 | * @param Requirement $requirement A Requirement instance 187 | */ 188 | public function add(Requirement $requirement) 189 | { 190 | $this->requirements[] = $requirement; 191 | } 192 | 193 | /** 194 | * Adds a mandatory requirement. 195 | * 196 | * @param bool $fulfilled Whether the requirement is fulfilled 197 | * @param string $testMessage The message for testing the requirement 198 | * @param string $helpHtml The help text formatted in HTML for resolving the problem 199 | * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) 200 | */ 201 | public function addRequirement($fulfilled, $testMessage, $helpHtml, $helpText = null) 202 | { 203 | $this->add(new Requirement($fulfilled, $testMessage, $helpHtml, $helpText, false)); 204 | } 205 | 206 | /** 207 | * Adds an optional recommendation. 208 | * 209 | * @param bool $fulfilled Whether the recommendation is fulfilled 210 | * @param string $testMessage The message for testing the recommendation 211 | * @param string $helpHtml The help text formatted in HTML for resolving the problem 212 | * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) 213 | */ 214 | public function addRecommendation($fulfilled, $testMessage, $helpHtml, $helpText = null) 215 | { 216 | $this->add(new Requirement($fulfilled, $testMessage, $helpHtml, $helpText, true)); 217 | } 218 | 219 | /** 220 | * Adds a mandatory requirement in form of a php.ini configuration. 221 | * 222 | * @param string $cfgName The configuration name used for ini_get() 223 | * @param bool|callback $evaluation Either a boolean indicating whether the configuration should evaluate to true or false, 224 | * or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement 225 | * @param bool $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false. 226 | * This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin. 227 | * Example: You require a config to be true but PHP later removes this config and defaults it to true internally. 228 | * @param string $testMessage The message for testing the requirement (when null and $evaluation is a boolean a default message is derived) 229 | * @param string $helpHtml The help text formatted in HTML for resolving the problem (when null and $evaluation is a boolean a default help is derived) 230 | * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) 231 | */ 232 | public function addPhpIniRequirement($cfgName, $evaluation, $approveCfgAbsence = false, $testMessage = null, $helpHtml = null, $helpText = null) 233 | { 234 | $this->add(new PhpIniRequirement($cfgName, $evaluation, $approveCfgAbsence, $testMessage, $helpHtml, $helpText, false)); 235 | } 236 | 237 | /** 238 | * Adds an optional recommendation in form of a php.ini configuration. 239 | * 240 | * @param string $cfgName The configuration name used for ini_get() 241 | * @param bool|callback $evaluation Either a boolean indicating whether the configuration should evaluate to true or false, 242 | * or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement 243 | * @param bool $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false. 244 | * This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin. 245 | * Example: You require a config to be true but PHP later removes this config and defaults it to true internally. 246 | * @param string $testMessage The message for testing the requirement (when null and $evaluation is a boolean a default message is derived) 247 | * @param string $helpHtml The help text formatted in HTML for resolving the problem (when null and $evaluation is a boolean a default help is derived) 248 | * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) 249 | */ 250 | public function addPhpIniRecommendation($cfgName, $evaluation, $approveCfgAbsence = false, $testMessage = null, $helpHtml = null, $helpText = null) 251 | { 252 | $this->add(new PhpIniRequirement($cfgName, $evaluation, $approveCfgAbsence, $testMessage, $helpHtml, $helpText, true)); 253 | } 254 | 255 | /** 256 | * Adds a requirement collection to the current set of requirements. 257 | * 258 | * @param RequirementCollection $collection A RequirementCollection instance 259 | */ 260 | public function addCollection(RequirementCollection $collection) 261 | { 262 | $this->requirements = array_merge($this->requirements, $collection->all()); 263 | } 264 | 265 | /** 266 | * Returns both requirements and recommendations. 267 | * 268 | * @return array Array of Requirement instances 269 | */ 270 | public function all() 271 | { 272 | return $this->requirements; 273 | } 274 | 275 | /** 276 | * Returns all mandatory requirements. 277 | * 278 | * @return array Array of Requirement instances 279 | */ 280 | public function getRequirements() 281 | { 282 | $array = array(); 283 | foreach ($this->requirements as $req) { 284 | if (!$req->isOptional()) { 285 | $array[] = $req; 286 | } 287 | } 288 | 289 | return $array; 290 | } 291 | 292 | /** 293 | * Returns the mandatory requirements that were not met. 294 | * 295 | * @return array Array of Requirement instances 296 | */ 297 | public function getFailedRequirements() 298 | { 299 | $array = array(); 300 | foreach ($this->requirements as $req) { 301 | if (!$req->isFulfilled() && !$req->isOptional()) { 302 | $array[] = $req; 303 | } 304 | } 305 | 306 | return $array; 307 | } 308 | 309 | /** 310 | * Returns all optional recommendations. 311 | * 312 | * @return array Array of Requirement instances 313 | */ 314 | public function getRecommendations() 315 | { 316 | $array = array(); 317 | foreach ($this->requirements as $req) { 318 | if ($req->isOptional()) { 319 | $array[] = $req; 320 | } 321 | } 322 | 323 | return $array; 324 | } 325 | 326 | /** 327 | * Returns the recommendations that were not met. 328 | * 329 | * @return array Array of Requirement instances 330 | */ 331 | public function getFailedRecommendations() 332 | { 333 | $array = array(); 334 | foreach ($this->requirements as $req) { 335 | if (!$req->isFulfilled() && $req->isOptional()) { 336 | $array[] = $req; 337 | } 338 | } 339 | 340 | return $array; 341 | } 342 | 343 | /** 344 | * Returns whether a php.ini configuration is not correct. 345 | * 346 | * @return bool php.ini configuration problem? 347 | */ 348 | public function hasPhpIniConfigIssue() 349 | { 350 | foreach ($this->requirements as $req) { 351 | if (!$req->isFulfilled() && $req instanceof PhpIniRequirement) { 352 | return true; 353 | } 354 | } 355 | 356 | return false; 357 | } 358 | 359 | /** 360 | * Returns the PHP configuration file (php.ini) path. 361 | * 362 | * @return string|false php.ini file path 363 | */ 364 | public function getPhpIniConfigPath() 365 | { 366 | return get_cfg_var('cfg_file_path'); 367 | } 368 | } 369 | 370 | /** 371 | * This class specifies all requirements and optional recommendations that 372 | * are necessary to run the Symfony Standard Edition. 373 | * 374 | * @author Tobias Schultze 375 | * @author Fabien Potencier 376 | */ 377 | class SymfonyRequirements extends RequirementCollection 378 | { 379 | const REQUIRED_PHP_VERSION = '5.3.3'; 380 | 381 | /** 382 | * Constructor that initializes the requirements. 383 | */ 384 | public function __construct() 385 | { 386 | /* mandatory requirements follow */ 387 | 388 | $installedPhpVersion = phpversion(); 389 | 390 | $this->addRequirement( 391 | version_compare($installedPhpVersion, self::REQUIRED_PHP_VERSION, '>='), 392 | sprintf('PHP version must be at least %s (%s installed)', self::REQUIRED_PHP_VERSION, $installedPhpVersion), 393 | sprintf('You are running PHP version "%s", but Symfony needs at least PHP "%s" to run. 394 | Before using Symfony, upgrade your PHP installation, preferably to the latest version.', 395 | $installedPhpVersion, self::REQUIRED_PHP_VERSION), 396 | sprintf('Install PHP %s or newer (installed version is %s)', self::REQUIRED_PHP_VERSION, $installedPhpVersion) 397 | ); 398 | 399 | $this->addRequirement( 400 | version_compare($installedPhpVersion, '5.3.16', '!='), 401 | 'PHP version must not be 5.3.16 as Symfony won\'t work properly with it', 402 | 'Install PHP 5.3.17 or newer (or downgrade to an earlier PHP version)' 403 | ); 404 | 405 | $this->addRequirement( 406 | is_dir(__DIR__.'/../vendor/composer'), 407 | 'Vendor libraries must be installed', 408 | 'Vendor libraries are missing. Install composer following instructions from http://getcomposer.org/. '. 409 | 'Then run "php composer.phar install" to install them.' 410 | ); 411 | 412 | $cacheDir = is_dir(__DIR__.'/../var/cache') ? __DIR__.'/../var/cache' : __DIR__.'/cache'; 413 | 414 | $this->addRequirement( 415 | is_writable($cacheDir), 416 | 'app/cache/ or var/cache/ directory must be writable', 417 | 'Change the permissions of either "app/cache/" or "var/cache/" directory so that the web server can write into it.' 418 | ); 419 | 420 | $logsDir = is_dir(__DIR__.'/../var/logs') ? __DIR__.'/../var/logs' : __DIR__.'/logs'; 421 | 422 | $this->addRequirement( 423 | is_writable($logsDir), 424 | 'app/logs/ or var/logs/ directory must be writable', 425 | 'Change the permissions of either "app/logs/" or "var/logs/" directory so that the web server can write into it.' 426 | ); 427 | 428 | $this->addPhpIniRequirement( 429 | 'date.timezone', true, false, 430 | 'date.timezone setting must be set', 431 | 'Set the "date.timezone" setting in php.ini* (like Europe/Paris).' 432 | ); 433 | 434 | if (version_compare($installedPhpVersion, self::REQUIRED_PHP_VERSION, '>=')) { 435 | $timezones = array(); 436 | foreach (DateTimeZone::listAbbreviations() as $abbreviations) { 437 | foreach ($abbreviations as $abbreviation) { 438 | $timezones[$abbreviation['timezone_id']] = true; 439 | } 440 | } 441 | 442 | $this->addRequirement( 443 | isset($timezones[@date_default_timezone_get()]), 444 | sprintf('Configured default timezone "%s" must be supported by your installation of PHP', @date_default_timezone_get()), 445 | 'Your default timezone is not supported by PHP. Check for typos in your php.ini file and have a look at the list of deprecated timezones at http://php.net/manual/en/timezones.others.php.' 446 | ); 447 | } 448 | 449 | $this->addRequirement( 450 | function_exists('iconv'), 451 | 'iconv() must be available', 452 | 'Install and enable the iconv extension.' 453 | ); 454 | 455 | $this->addRequirement( 456 | function_exists('json_encode'), 457 | 'json_encode() must be available', 458 | 'Install and enable the JSON extension.' 459 | ); 460 | 461 | $this->addRequirement( 462 | function_exists('session_start'), 463 | 'session_start() must be available', 464 | 'Install and enable the session extension.' 465 | ); 466 | 467 | $this->addRequirement( 468 | function_exists('ctype_alpha'), 469 | 'ctype_alpha() must be available', 470 | 'Install and enable the ctype extension.' 471 | ); 472 | 473 | $this->addRequirement( 474 | function_exists('token_get_all'), 475 | 'token_get_all() must be available', 476 | 'Install and enable the Tokenizer extension.' 477 | ); 478 | 479 | $this->addRequirement( 480 | function_exists('simplexml_import_dom'), 481 | 'simplexml_import_dom() must be available', 482 | 'Install and enable the SimpleXML extension.' 483 | ); 484 | 485 | if (function_exists('apc_store') && ini_get('apc.enabled')) { 486 | if (version_compare($installedPhpVersion, '5.4.0', '>=')) { 487 | $this->addRequirement( 488 | version_compare(phpversion('apc'), '3.1.13', '>='), 489 | 'APC version must be at least 3.1.13 when using PHP 5.4', 490 | 'Upgrade your APC extension (3.1.13+).' 491 | ); 492 | } else { 493 | $this->addRequirement( 494 | version_compare(phpversion('apc'), '3.0.17', '>='), 495 | 'APC version must be at least 3.0.17', 496 | 'Upgrade your APC extension (3.0.17+).' 497 | ); 498 | } 499 | } 500 | 501 | $this->addPhpIniRequirement('detect_unicode', false); 502 | 503 | if (extension_loaded('suhosin')) { 504 | $this->addPhpIniRequirement( 505 | 'suhosin.executor.include.whitelist', 506 | create_function('$cfgValue', 'return false !== stripos($cfgValue, "phar");'), 507 | false, 508 | 'suhosin.executor.include.whitelist must be configured correctly in php.ini', 509 | 'Add "phar" to suhosin.executor.include.whitelist in php.ini*.' 510 | ); 511 | } 512 | 513 | if (extension_loaded('xdebug')) { 514 | $this->addPhpIniRequirement( 515 | 'xdebug.show_exception_trace', false, true 516 | ); 517 | 518 | $this->addPhpIniRequirement( 519 | 'xdebug.scream', false, true 520 | ); 521 | 522 | $this->addPhpIniRecommendation( 523 | 'xdebug.max_nesting_level', 524 | create_function('$cfgValue', 'return $cfgValue > 100;'), 525 | true, 526 | 'xdebug.max_nesting_level should be above 100 in php.ini', 527 | 'Set "xdebug.max_nesting_level" to e.g. "250" in php.ini* to stop Xdebug\'s infinite recursion protection erroneously throwing a fatal error in your project.' 528 | ); 529 | } 530 | 531 | $pcreVersion = defined('PCRE_VERSION') ? (float) PCRE_VERSION : null; 532 | 533 | $this->addRequirement( 534 | null !== $pcreVersion, 535 | 'PCRE extension must be available', 536 | 'Install the PCRE extension (version 8.0+).' 537 | ); 538 | 539 | if (extension_loaded('mbstring')) { 540 | $this->addPhpIniRequirement( 541 | 'mbstring.func_overload', 542 | create_function('$cfgValue', 'return (int) $cfgValue === 0;'), 543 | true, 544 | 'string functions should not be overloaded', 545 | 'Set "mbstring.func_overload" to 0 in php.ini* to disable function overloading by the mbstring extension.' 546 | ); 547 | } 548 | 549 | /* optional recommendations follow */ 550 | 551 | if (file_exists(__DIR__.'/../vendor/composer')) { 552 | require_once __DIR__.'/../vendor/autoload.php'; 553 | 554 | try { 555 | $r = new ReflectionClass('Sensio\Bundle\DistributionBundle\SensioDistributionBundle'); 556 | 557 | $contents = file_get_contents(dirname($r->getFileName()).'/Resources/skeleton/app/SymfonyRequirements.php'); 558 | } catch (ReflectionException $e) { 559 | $contents = ''; 560 | } 561 | $this->addRecommendation( 562 | file_get_contents(__FILE__) === $contents, 563 | 'Requirements file should be up-to-date', 564 | 'Your requirements file is outdated. Run composer install and re-check your configuration.' 565 | ); 566 | } 567 | 568 | $this->addRecommendation( 569 | version_compare($installedPhpVersion, '5.3.4', '>='), 570 | 'You should use at least PHP 5.3.4 due to PHP bug #52083 in earlier versions', 571 | 'Your project might malfunction randomly due to PHP bug #52083 ("Notice: Trying to get property of non-object"). Install PHP 5.3.4 or newer.' 572 | ); 573 | 574 | $this->addRecommendation( 575 | version_compare($installedPhpVersion, '5.3.8', '>='), 576 | 'When using annotations you should have at least PHP 5.3.8 due to PHP bug #55156', 577 | 'Install PHP 5.3.8 or newer if your project uses annotations.' 578 | ); 579 | 580 | $this->addRecommendation( 581 | version_compare($installedPhpVersion, '5.4.0', '!='), 582 | 'You should not use PHP 5.4.0 due to the PHP bug #61453', 583 | 'Your project might not work properly due to the PHP bug #61453 ("Cannot dump definitions which have method calls"). Install PHP 5.4.1 or newer.' 584 | ); 585 | 586 | $this->addRecommendation( 587 | version_compare($installedPhpVersion, '5.4.11', '>='), 588 | 'When using the logout handler from the Symfony Security Component, you should have at least PHP 5.4.11 due to PHP bug #63379 (as a workaround, you can also set invalidate_session to false in the security logout handler configuration)', 589 | 'Install PHP 5.4.11 or newer if your project uses the logout handler from the Symfony Security Component.' 590 | ); 591 | 592 | $this->addRecommendation( 593 | (version_compare($installedPhpVersion, '5.3.18', '>=') && version_compare($installedPhpVersion, '5.4.0', '<')) 594 | || 595 | version_compare($installedPhpVersion, '5.4.8', '>='), 596 | 'You should use PHP 5.3.18+ or PHP 5.4.8+ to always get nice error messages for fatal errors in the development environment due to PHP bug #61767/#60909', 597 | 'Install PHP 5.3.18+ or PHP 5.4.8+ if you want nice error messages for all fatal errors in the development environment.' 598 | ); 599 | 600 | if (null !== $pcreVersion) { 601 | $this->addRecommendation( 602 | $pcreVersion >= 8.0, 603 | sprintf('PCRE extension should be at least version 8.0 (%s installed)', $pcreVersion), 604 | 'PCRE 8.0+ is preconfigured in PHP since 5.3.2 but you are using an outdated version of it. Symfony probably works anyway but it is recommended to upgrade your PCRE extension.' 605 | ); 606 | } 607 | 608 | $this->addRecommendation( 609 | class_exists('DomDocument'), 610 | 'PHP-DOM and PHP-XML modules should be installed', 611 | 'Install and enable the PHP-DOM and the PHP-XML modules.' 612 | ); 613 | 614 | $this->addRecommendation( 615 | function_exists('mb_strlen'), 616 | 'mb_strlen() should be available', 617 | 'Install and enable the mbstring extension.' 618 | ); 619 | 620 | $this->addRecommendation( 621 | function_exists('iconv'), 622 | 'iconv() should be available', 623 | 'Install and enable the iconv extension.' 624 | ); 625 | 626 | $this->addRecommendation( 627 | function_exists('utf8_decode'), 628 | 'utf8_decode() should be available', 629 | 'Install and enable the XML extension.' 630 | ); 631 | 632 | $this->addRecommendation( 633 | function_exists('filter_var'), 634 | 'filter_var() should be available', 635 | 'Install and enable the filter extension.' 636 | ); 637 | 638 | if (!defined('PHP_WINDOWS_VERSION_BUILD')) { 639 | $this->addRecommendation( 640 | function_exists('posix_isatty'), 641 | 'posix_isatty() should be available', 642 | 'Install and enable the php_posix extension (used to colorize the CLI output).' 643 | ); 644 | } 645 | 646 | $this->addRecommendation( 647 | extension_loaded('intl'), 648 | 'intl extension should be available', 649 | 'Install and enable the intl extension (used for validators).' 650 | ); 651 | 652 | if (extension_loaded('intl')) { 653 | // in some WAMP server installations, new Collator() returns null 654 | $this->addRecommendation( 655 | null !== new Collator('fr_FR'), 656 | 'intl extension should be correctly configured', 657 | 'The intl extension does not behave properly. This problem is typical on PHP 5.3.X x64 WIN builds.' 658 | ); 659 | 660 | // check for compatible ICU versions (only done when you have the intl extension) 661 | if (defined('INTL_ICU_VERSION')) { 662 | $version = INTL_ICU_VERSION; 663 | } else { 664 | $reflector = new ReflectionExtension('intl'); 665 | 666 | ob_start(); 667 | $reflector->info(); 668 | $output = strip_tags(ob_get_clean()); 669 | 670 | preg_match('/^ICU version +(?:=> )?(.*)$/m', $output, $matches); 671 | $version = $matches[1]; 672 | } 673 | 674 | $this->addRecommendation( 675 | version_compare($version, '4.0', '>='), 676 | 'intl ICU version should be at least 4+', 677 | 'Upgrade your intl extension with a newer ICU version (4+).' 678 | ); 679 | 680 | $this->addPhpIniRecommendation( 681 | 'intl.error_level', 682 | create_function('$cfgValue', 'return (int) $cfgValue === 0;'), 683 | true, 684 | 'intl.error_level should be 0 in php.ini', 685 | 'Set "intl.error_level" to "0" in php.ini* to inhibit the messages when an error occurs in ICU functions.' 686 | ); 687 | } 688 | 689 | $accelerator = 690 | (extension_loaded('eaccelerator') && ini_get('eaccelerator.enable')) 691 | || 692 | (extension_loaded('apc') && ini_get('apc.enabled')) 693 | || 694 | (extension_loaded('Zend Optimizer+') && ini_get('zend_optimizerplus.enable')) 695 | || 696 | (extension_loaded('Zend OPcache') && ini_get('opcache.enable')) 697 | || 698 | (extension_loaded('xcache') && ini_get('xcache.cacher')) 699 | || 700 | (extension_loaded('wincache') && ini_get('wincache.ocenabled')) 701 | ; 702 | 703 | $this->addRecommendation( 704 | $accelerator, 705 | 'a PHP accelerator should be installed', 706 | 'Install and/or enable a PHP accelerator (highly recommended).' 707 | ); 708 | 709 | if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { 710 | $this->addRecommendation( 711 | $this->getRealpathCacheSize() > 1000, 712 | 'realpath_cache_size should be above 1024 in php.ini', 713 | 'Set "realpath_cache_size" to e.g. "1024" in php.ini* to improve performance on windows.' 714 | ); 715 | } 716 | 717 | $this->addPhpIniRecommendation('short_open_tag', false); 718 | 719 | $this->addPhpIniRecommendation('magic_quotes_gpc', false, true); 720 | 721 | $this->addPhpIniRecommendation('register_globals', false, true); 722 | 723 | $this->addPhpIniRecommendation('session.auto_start', false); 724 | 725 | $this->addRecommendation( 726 | class_exists('PDO'), 727 | 'PDO should be installed', 728 | 'Install PDO (mandatory for Doctrine).' 729 | ); 730 | 731 | if (class_exists('PDO')) { 732 | $drivers = PDO::getAvailableDrivers(); 733 | $this->addRecommendation( 734 | count($drivers) > 0, 735 | sprintf('PDO should have some drivers installed (currently available: %s)', count($drivers) ? implode(', ', $drivers) : 'none'), 736 | 'Install PDO drivers (mandatory for Doctrine).' 737 | ); 738 | } 739 | } 740 | 741 | /** 742 | * Loads realpath_cache_size from php.ini and converts it to int. 743 | * 744 | * (e.g. 16k is converted to 16384 int) 745 | * 746 | * @return int 747 | */ 748 | protected function getRealpathCacheSize() 749 | { 750 | $size = ini_get('realpath_cache_size'); 751 | $size = trim($size); 752 | $unit = strtolower(substr($size, -1, 1)); 753 | switch ($unit) { 754 | case 'g': 755 | return $size * 1024 * 1024 * 1024; 756 | case 'm': 757 | return $size * 1024 * 1024; 758 | case 'k': 759 | return $size * 1024; 760 | default: 761 | return (int) $size; 762 | } 763 | } 764 | } 765 | -------------------------------------------------------------------------------- /var/cache/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dunglas/api-platform/11d0f1324bdaf8b0a5e19991dfd72db2681066d8/var/cache/.gitkeep -------------------------------------------------------------------------------- /var/logs/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dunglas/api-platform/11d0f1324bdaf8b0a5e19991dfd72db2681066d8/var/logs/.gitkeep -------------------------------------------------------------------------------- /var/sessions/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dunglas/api-platform/11d0f1324bdaf8b0a5e19991dfd72db2681066d8/var/sessions/.gitkeep -------------------------------------------------------------------------------- /web/.htaccess: -------------------------------------------------------------------------------- 1 | # Use the front controller as index file. It serves as a fallback solution when 2 | # every other rewrite/redirect fails (e.g. in an aliased environment without 3 | # mod_rewrite). Additionally, this reduces the matching process for the 4 | # start page (path "/") because otherwise Apache will apply the rewriting rules 5 | # to each configured DirectoryIndex file (e.g. index.php, index.html, index.pl). 6 | DirectoryIndex app.php 7 | 8 | # By default, Apache does not evaluate symbolic links if you did not enable this 9 | # feature in your server configuration. Uncomment the following line if you 10 | # install assets as symlinks or if you experience problems related to symlinks 11 | # when compiling LESS/Sass/CoffeScript assets. 12 | # Options FollowSymlinks 13 | 14 | # Disabling MultiViews prevents unwanted negotiation, e.g. "/app" should not resolve 15 | # to the front controller "/app.php" but be rewritten to "/app.php/app". 16 | 17 | Options -MultiViews 18 | 19 | 20 | 21 | RewriteEngine On 22 | 23 | # Determine the RewriteBase automatically and set it as environment variable. 24 | # If you are using Apache aliases to do mass virtual hosting or installed the 25 | # project in a subdirectory, the base path will be prepended to allow proper 26 | # resolution of the app.php file and to redirect to the correct URI. It will 27 | # work in environments without path prefix as well, providing a safe, one-size 28 | # fits all solution. But as you do not need it in this case, you can comment 29 | # the following 2 lines to eliminate the overhead. 30 | RewriteCond %{REQUEST_URI}::$1 ^(/.+)/(.*)::\2$ 31 | RewriteRule ^(.*) - [E=BASE:%1] 32 | 33 | # Sets the HTTP_AUTHORIZATION header removed by Apache 34 | RewriteCond %{HTTP:Authorization} . 35 | RewriteRule ^ - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] 36 | 37 | # Redirect to URI without front controller to prevent duplicate content 38 | # (with and without `/app.php`). Only do this redirect on the initial 39 | # rewrite by Apache and not on subsequent cycles. Otherwise we would get an 40 | # endless redirect loop (request -> rewrite to front controller -> 41 | # redirect -> request -> ...). 42 | # So in case you get a "too many redirects" error or you always get redirected 43 | # to the start page because your Apache does not expose the REDIRECT_STATUS 44 | # environment variable, you have 2 choices: 45 | # - disable this feature by commenting the following 2 lines or 46 | # - use Apache >= 2.3.9 and replace all L flags by END flags and remove the 47 | # following RewriteCond (best solution) 48 | RewriteCond %{ENV:REDIRECT_STATUS} ^$ 49 | RewriteRule ^app\.php(?:/(.*)|$) %{ENV:BASE}/$1 [R=301,L] 50 | 51 | # If the requested filename exists, simply serve it. 52 | # We only want to let Apache serve files and not directories. 53 | RewriteCond %{REQUEST_FILENAME} -f 54 | RewriteRule ^ - [L] 55 | 56 | # Rewrite all other queries to the front controller. 57 | RewriteRule ^ %{ENV:BASE}/app.php [L] 58 | 59 | 60 | 61 | 62 | # When mod_rewrite is not available, we instruct a temporary redirect of 63 | # the start page to the front controller explicitly so that the website 64 | # and the generated links can still be used. 65 | RedirectMatch 302 ^/$ /app.php/ 66 | # RedirectTemp cannot be used instead 67 | 68 | 69 | -------------------------------------------------------------------------------- /web/app.php: -------------------------------------------------------------------------------- 1 | unregister(); 18 | $apcLoader->register(true); 19 | */ 20 | 21 | $kernel = new AppKernel('prod', false); 22 | $kernel->loadClassCache(); 23 | //$kernel = new AppCache($kernel); 24 | 25 | // When using the HttpCache, you need to call the method in your front controller instead of relying on the configuration parameter 26 | //Request::enableHttpMethodParameterOverride(); 27 | $request = Request::createFromGlobals(); 28 | $response = $kernel->handle($request); 29 | $response->send(); 30 | $kernel->terminate($request, $response); 31 | -------------------------------------------------------------------------------- /web/app_dev.php: -------------------------------------------------------------------------------- 1 | loadClassCache(); 29 | $request = Request::createFromGlobals(); 30 | $response = $kernel->handle($request); 31 | $response->send(); 32 | $kernel->terminate($request, $response); 33 | -------------------------------------------------------------------------------- /web/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dunglas/api-platform/11d0f1324bdaf8b0a5e19991dfd72db2681066d8/web/apple-touch-icon.png -------------------------------------------------------------------------------- /web/config.php: -------------------------------------------------------------------------------- 1 | getFailedRequirements(); 30 | $minorProblems = $symfonyRequirements->getFailedRecommendations(); 31 | 32 | ?> 33 | 34 | 35 | 36 | 37 | 38 | Symfony Configuration Checker 39 | 40 | 41 | 118 | 119 | 120 |
121 |
122 | 125 | 126 | 146 |
147 | 148 |
149 |
150 |
151 |

Configuration Checker

152 |

153 | This script analyzes your system to check whether is 154 | ready to run Symfony applications. 155 |

156 | 157 | 158 |

Major problems

159 |

Major problems have been detected and must be fixed before continuing:

160 |
    161 | 162 |
  1. getHelpHtml() ?>
  2. 163 | 164 |
165 | 166 | 167 | 168 |

Recommendations

169 |

170 | Additionally, toTo enhance your Symfony experience, 171 | it’s recommended that you fix the following: 172 |

173 |
    174 | 175 |
  1. getHelpHtml() ?>
  2. 176 | 177 |
178 | 179 | 180 | hasPhpIniConfigIssue()): ?> 181 |

* 182 | getPhpIniConfigPath()): ?> 183 | Changes to the php.ini file must be done in "getPhpIniConfigPath() ?>". 184 | 185 | To change settings, create a "php.ini". 186 | 187 |

188 | 189 | 190 | 191 |

All checks passed successfully. Your system is ready to run Symfony applications.

192 | 193 | 194 | 199 |
200 |
201 |
202 |
Symfony Standard Edition
203 |
204 | 205 | 206 | -------------------------------------------------------------------------------- /web/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dunglas/api-platform/11d0f1324bdaf8b0a5e19991dfd72db2681066d8/web/favicon.ico -------------------------------------------------------------------------------- /web/robots.txt: -------------------------------------------------------------------------------- 1 | # www.robotstxt.org/ 2 | # www.google.com/support/webmasters/bin/answer.py?hl=en&answer=156449 3 | 4 | User-agent: * 5 | Disallow: 6 | --------------------------------------------------------------------------------