The server returned a "{{ status_code }} {{ status_text }}".
10 |
11 |
12 | Something is broken. Please let us know what you were doing when this error occurred.
13 | We will fix it as soon as possible. Sorry for any inconvenience caused.
14 |
The server returned a "{{ status_code }} {{ status_text }}".
10 |
11 |
12 | Something is broken. Please let us know what you were doing when this error occurred.
13 | We will fix it as soon as possible. Sorry for any inconvenience caused.
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/app/config/config_prod.yml:
--------------------------------------------------------------------------------
1 | imports:
2 | - { resource: config.yml }
3 |
4 | #doctrine:
5 | # orm:
6 | # metadata_cache_driver: apc
7 | # result_cache_driver: apc
8 | # query_cache_driver: apc
9 |
10 | monolog:
11 | handlers:
12 | main:
13 | type: fingers_crossed
14 | action_level: error
15 | handler: nested
16 | nested:
17 | type: stream
18 | path: "%kernel.logs_dir%/%kernel.environment%.log"
19 | level: debug
20 | console:
21 | type: console
22 |
--------------------------------------------------------------------------------
/features/bootstrap/FeatureContext.php:
--------------------------------------------------------------------------------
1 | loadClassCache();
11 | //$kernel = new AppCache($kernel);
12 |
13 | // When using the HttpCache, you need to call the method in your front controller instead of relying on the configuration parameter
14 | //Request::enableHttpMethodParameterOverride();
15 | $request = Request::createFromGlobals();
16 | $response = $kernel->handle($request);
17 | $response->send();
18 | $kernel->terminate($request, $response);
19 |
--------------------------------------------------------------------------------
/.php_cs:
--------------------------------------------------------------------------------
1 |
9 | EOF;
10 |
11 | Symfony\CS\Fixer\Contrib\HeaderCommentFixer::setHeader($header);
12 |
13 | return Symfony\CS\Config\Config::create()
14 | ->level(Symfony\CS\FixerInterface::SYMFONY_LEVEL)
15 | ->fixers([
16 | '-concat_without_spaces',
17 | '-phpdoc_short_description',
18 | '-pre_increment',
19 | 'concat_with_spaces',
20 | 'header_comment',
21 | 'ordered_use',
22 | 'phpdoc_order',
23 | 'short_array_syntax',
24 | ])
25 | ->setUsingCache(true)
26 | ->finder(
27 | Symfony\CS\Finder\DefaultFinder::create()
28 | ->in('src')
29 | )
30 | ;
31 |
--------------------------------------------------------------------------------
/app/config/parameters.yml.dist:
--------------------------------------------------------------------------------
1 | # This file is a "template" of what your parameters.yml file should look like
2 | # Set parameters here that may be different on each deployment target of the app, e.g. development, staging, production.
3 | # http://symfony.com/doc/current/best_practices/configuration.html#infrastructure-related-configuration
4 | parameters:
5 | database_host: 127.0.0.1
6 | database_port: ~
7 | database_name: symfony
8 | database_user: root
9 | database_password: ~
10 | # You should uncomment this if you want use pdo_sqlite
11 | # database_path: "%kernel.root_dir%/data.db3"
12 |
13 | mailer_transport: smtp
14 | mailer_host: 127.0.0.1
15 | mailer_user: ~
16 | mailer_password: ~
17 |
18 | # A secret key that's used to generate certain security-related tokens
19 | secret: ThisTokenIsNotSoSecretChangeIt
20 |
--------------------------------------------------------------------------------
/app/config/security.yml:
--------------------------------------------------------------------------------
1 | # To get started with security, check out the documentation:
2 | # http://symfony.com/doc/current/security.html
3 | security:
4 |
5 | # http://symfony.com/doc/current/security.html#b-configuring-how-users-are-loaded
6 | providers:
7 | in_memory:
8 | memory: ~
9 |
10 | firewalls:
11 | # disables authentication for assets and the profiler, adapt it according to your needs
12 | dev:
13 | pattern: ^/(_(profiler|wdt)|css|images|js)/
14 | security: false
15 |
16 | main:
17 | anonymous: ~
18 | # activate different ways to authenticate
19 |
20 | # http_basic: ~
21 | # http://symfony.com/doc/current/security.html#a-configuring-how-your-users-will-authenticate
22 |
23 | # form_login: ~
24 | # http://symfony.com/doc/current/cookbook/security/form_login_setup.html
25 |
--------------------------------------------------------------------------------
/ansible/group_vars/deploy.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | #######
4 | # Dir #
5 | #######
6 |
7 | manala_deploy_dir: /srv/app
8 |
9 | ############
10 | # Releases #
11 | ############
12 |
13 | manala_deploy_releases: 5
14 |
15 | ############
16 | # Strategy #
17 | ############
18 |
19 | manala_deploy_strategy: git
20 |
21 | manala_deploy_strategy_git_repo: git@github.com:vendor/app.git
22 | manala_deploy_strategy_git_version: master
23 |
24 | ##########
25 | # Copied #
26 | ##########
27 |
28 | manala_deploy_copied:
29 | - vendor
30 |
31 | ##########
32 | # Shared #
33 | ##########
34 |
35 | manala_deploy_shared_files:
36 | - app/config/parameters.yml
37 |
38 | manala_deploy_shared_dirs:
39 | - var/logs
40 | - var/sessions
41 |
42 | ############
43 | # Writable #
44 | ############
45 |
46 | #manala_deploy_writable_dirs_default:
47 | # mode: ug=rwx,o=rx
48 | #manala_deploy_writable_dirs:
49 | # - var/cache
50 | # - var/logs
51 | # - var/sessions
52 |
--------------------------------------------------------------------------------
/bin/console:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env php
2 | getParameterOption(['--env', '-e'], getenv('SYMFONY_ENV') ?: 'dev');
20 | $debug = getenv('SYMFONY_DEBUG') !== '0' && !$input->hasParameterOption(['--no-debug', '']) && $env !== 'prod';
21 |
22 | if ($debug) {
23 | Debug::enable();
24 | }
25 |
26 | $kernel = new AppKernel($env, $debug);
27 | $application = new Application($kernel);
28 | $application->run($input);
29 |
--------------------------------------------------------------------------------
/app/config/config_dev.yml:
--------------------------------------------------------------------------------
1 | imports:
2 | - { resource: config.yml }
3 |
4 | framework:
5 | router:
6 | resource: "%kernel.root_dir%/config/routing_dev.yml"
7 | strict_requirements: true
8 | profiler: { only_exceptions: false }
9 |
10 | web_profiler:
11 | toolbar: true
12 | intercept_redirects: false
13 |
14 | monolog:
15 | handlers:
16 | main:
17 | type: stream
18 | path: "%kernel.logs_dir%/%kernel.environment%.log"
19 | level: debug
20 | channels: [!event]
21 | console:
22 | type: console
23 | channels: [!event, !doctrine]
24 | # uncomment to get logging in your browser
25 | # you may have to allow bigger header sizes in your Web server configuration
26 | #firephp:
27 | # type: firephp
28 | # level: info
29 | #chromephp:
30 | # type: chromephp
31 | # level: info
32 |
33 | #swiftmailer:
34 | # delivery_addresses: ['me@example.com']
35 |
--------------------------------------------------------------------------------
/ansible/group_vars/app_local.yml.sample:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | app_local_patterns:
4 |
5 | ###############
6 | # Environment #
7 | ###############
8 |
9 | #environment_variables:
10 | # - XDEBUG_CONFIG: remote_host={{ ansible_eth1.ipv4.address|regex_replace('^(.*)\.\d+$', '\1') }}.1 idekey=app
11 | # - PHP_IDE_CONFIG: serverName={{ ansible_fqdn }}
12 |
13 | #######
14 | # Apt #
15 | #######
16 |
17 | #apt_repositories:
18 | # - blackfire
19 |
20 | ###################
21 | # Php - Blackfire #
22 | ###################
23 |
24 | #php_blackfire: false
25 |
26 | #php_blackfire_agent_config:
27 | # - server-id: ...
28 | # - server-token: ...
29 |
30 | #php_blackfire_client_config:
31 | # - client-id: ...
32 | # - client-token: ...
33 |
34 | #######
35 | # Php #
36 | #######
37 |
38 | #php_configs:
39 | # - file: app_local.ini
40 | # config:
41 | # # Symfony ide integration, see: http://symfony.com/doc/current/reference/configuration/framework.html#ide
42 | # - xdebug.file_link_format: "'phpstorm://open?file=%f&line=%l&/srv/app/>/Users/manala/workspace/vendor/app/'"
43 |
--------------------------------------------------------------------------------
/README.app.md:
--------------------------------------------------------------------------------
1 | # App
2 |
3 | ## Development
4 |
5 | > Note: The `$` stands for your machine CLI, while the `⇒` stands for the VM CLI
6 |
7 | ### Requirements
8 |
9 | * Make
10 | * [VirtualBox 5.0.20+](https://www.virtualbox.org/wiki/Downloads)
11 | * [Vagrant 1.8.4+](https://www.vagrantup.com/downloads.html)
12 | * [Vagrant Landrush 1.0.0+](https://github.com/vagrant-landrush/landrush)
13 |
14 | ### Setup
15 |
16 | Clone the project in your workspace, and launch setup
17 |
18 | $ make setup
19 |
20 | You should access the project via http://app.dev/app_dev.php
21 |
22 | ### Usage
23 |
24 | Start/Stop/Ssh
25 |
26 | $ vagrant up/halt/ssh
27 |
28 | Build
29 |
30 | ⇒ make build
31 |
32 | Admin
33 |
34 | * [MailHog](http://app.dev:8025)
35 | * [Supervisor](http://app.dev:9001)
36 | * [RTail](http://app.dev:8888)
37 | * [OPcache Dashboard](http://app.dev:2013)
38 | * [PhpMyAdmin](http://app.dev:1979)
39 | * [PhpPgAdmin](http://app.dev:1980)
40 | * [PhpRedisAdmin](http://app.dev:1981)
41 | * [MongoExpress](http://app.dev:8081)
42 | * [Elasticsearch](http://app.dev:9200/_plugin/head/)
43 | * [Ngrok](http://app.dev:4040)
44 | * [InfluxDB](http://app.dev:8083)
45 |
--------------------------------------------------------------------------------
/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/app_test.php:
--------------------------------------------------------------------------------
1 | loadClassCache();
29 | $request = Request::createFromGlobals();
30 | $response = $kernel->handle($request);
31 | $response->send();
32 | $kernel->terminate($request, $response);
33 |
--------------------------------------------------------------------------------
/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/DataFixtures
27 | src/*/*Bundle/Resources
28 | src/*/*Bundle/DataFixtures
29 | src/*/Bundle/*Bundle/Resources
30 | src/*/Bundle/*Bundle/DataFixtures
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/app/AppKernel.php:
--------------------------------------------------------------------------------
1 | getEnvironment(), ['dev', 'test'], true)) {
21 | $bundles[] = new Symfony\Bundle\DebugBundle\DebugBundle();
22 | $bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle();
23 | $bundles[] = new Sensio\Bundle\DistributionBundle\SensioDistributionBundle();
24 | $bundles[] = new Sensio\Bundle\GeneratorBundle\SensioGeneratorBundle();
25 |
26 | // Fixtures
27 | $bundles[] = new Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle();
28 | }
29 |
30 | return $bundles;
31 | }
32 |
33 | public function getRootDir()
34 | {
35 | return __DIR__;
36 | }
37 |
38 | public function getCacheDir()
39 | {
40 | return dirname(__DIR__).'/var/cache/'.$this->getEnvironment();
41 | }
42 |
43 | public function getLogDir()
44 | {
45 | return dirname(__DIR__).'/var/logs';
46 | }
47 |
48 | public function registerContainerConfiguration(LoaderInterface $loader)
49 | {
50 | $loader->load($this->getRootDir().'/config/config_'.$this->getEnvironment().'.yml');
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Vagrantfile:
--------------------------------------------------------------------------------
1 | # -*- mode: ruby -*-
2 | # vi: set ft=ruby :
3 |
4 | app = {
5 | :name => 'app',
6 | :box => 'manala/app-dev-debian',
7 | :box_version => '~> 3.0.11',
8 | :box_memory => 1024
9 | }
10 |
11 | Vagrant.require_version '>= 2.0.1'
12 |
13 | Vagrant.configure(2) do |config|
14 |
15 | # Ssh
16 | config.ssh.username = 'app'
17 | config.ssh.forward_agent = true
18 |
19 | # Vm
20 | config.vm.box = app[:box]
21 | config.vm.box_version = app[:box_version]
22 | config.vm.hostname = app[:name] + '.dev'
23 | config.vm.network 'private_network', type: 'dhcp'
24 | config.vm.define 'localhost' do |localhost| end
25 | config.vm.synced_folder '.', '/srv/app',
26 | type: 'nfs',
27 | mount_options: ['nolock', 'actimeo=1', 'fsc']
28 |
29 | # Vm - Provider - Virtualbox
30 | config.vm.provider 'virtualbox' # Force provider
31 | config.vm.provider :virtualbox do |virtualbox|
32 | virtualbox.name = app[:name]
33 | virtualbox.memory = app[:box_memory]
34 | virtualbox.customize ['modifyvm', :id, '--natdnshostresolver1', 'on']
35 | virtualbox.customize ['modifyvm', :id, '--natdnsproxy1', 'on']
36 | end
37 |
38 | # Vm - Provision - Dotfiles
39 | for dotfile in ['.ssh/config', '.gitconfig', '.gitignore', '.composer/auth.json']
40 | if File.exists?(File.join(Dir.home, dotfile)) then
41 | config.vm.provision dotfile, type: 'file', run: 'always' do |file|
42 | file.source = '~/' + dotfile
43 | file.destination = '/home/' + config.ssh.username + '/' + dotfile
44 | end
45 | end
46 | end
47 |
48 | # Vm - Provision - Setup
49 | for playbook in ['ansible', 'app']
50 | config.vm.provision playbook, type: 'ansible_local' do |ansible|
51 | ansible.version = (playbook == 'ansible') ? 'latest' : ''
52 | ansible.compatibility_mode = '2.0'
53 | ansible.provisioning_path = '/srv/app/ansible'
54 | ansible.playbook = playbook + '.yml'
55 | ansible.inventory_path = '/etc/ansible/hosts'
56 | ansible.tags = ENV['ANSIBLE_TAGS']
57 | ansible.extra_vars = JSON.parse(ENV['ANSIBLE_EXTRA_VARS'] || '{"manala":{"update":true}}')
58 | end
59 | end
60 |
61 | # Plugins - Landrush
62 | if Vagrant.has_plugin?('landrush')
63 | config.landrush.enabled = true
64 | config.landrush.tld = config.vm.hostname
65 | config.landrush.guest_redirect_dns = false
66 | end
67 |
68 | end
69 |
--------------------------------------------------------------------------------
/app/config/config.yml:
--------------------------------------------------------------------------------
1 | imports:
2 | - { resource: parameters.yml }
3 | - { resource: security.yml }
4 | - { resource: services.yml }
5 |
6 | # Put parameters here that don't need to change on each machine where the app is deployed
7 | # http://symfony.com/doc/current/best_practices/configuration.html#application-related-configuration
8 | parameters:
9 | locale: en
10 |
11 | framework:
12 | #esi: ~
13 | #translator: { fallbacks: ["%locale%"] }
14 | secret: "%secret%"
15 | router:
16 | resource: "%kernel.root_dir%/config/routing.yml"
17 | strict_requirements: ~
18 | form: ~
19 | csrf_protection: ~
20 | validation: { enable_annotations: true }
21 | #serializer: { enable_annotations: true }
22 | templating:
23 | engines: ['twig']
24 | default_locale: "%locale%"
25 | trusted_hosts: ~
26 | trusted_proxies: ~
27 | session:
28 | # http://symfony.com/doc/current/reference/configuration/framework.html#handler-id
29 | handler_id: session.handler.native_file
30 | save_path: "%kernel.root_dir%/../var/sessions/%kernel.environment%"
31 | name: app
32 | fragments: ~
33 | http_method_override: true
34 | assets: ~
35 | php_errors:
36 | log: true
37 |
38 | # Twig Configuration
39 | twig:
40 | debug: "%kernel.debug%"
41 | strict_variables: "%kernel.debug%"
42 |
43 | # Doctrine Configuration
44 | doctrine:
45 | dbal:
46 | driver: pdo_mysql
47 | host: "%database_host%"
48 | port: "%database_port%"
49 | dbname: "%database_name%"
50 | user: "%database_user%"
51 | password: "%database_password%"
52 | charset: UTF8
53 | # if using pdo_sqlite as your database driver:
54 | # 1. add the path in parameters.yml
55 | # e.g. database_path: "%kernel.root_dir%/../var/data/data.sqlite"
56 | # 2. Uncomment database_path in parameters.yml.dist
57 | # 3. Uncomment next line:
58 | #path: "%database_path%"
59 |
60 | orm:
61 | auto_generate_proxy_classes: "%kernel.debug%"
62 | naming_strategy: doctrine.orm.naming_strategy.underscore
63 | auto_mapping: true
64 |
65 | # Swiftmailer Configuration
66 | swiftmailer:
67 | transport: "%mailer_transport%"
68 | host: "%mailer_host%"
69 | username: "%mailer_user%"
70 | password: "%mailer_password%"
71 | spool: { type: memory }
72 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Elao Symfony Standard Edition
2 |
3 | ## This project is deprecated, please use https://github.com/manala/manalize instead.
4 |
5 | 
6 | [](https://gitter.im/Elao/symfony-standard?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
7 |
8 | ## Requirements
9 |
10 | * Make
11 | * [VirtualBox 5.0.32+](https://www.virtualbox.org/wiki/Downloads)
12 | * [Vagrant 2.0.1+](https://www.vagrantup.com/downloads.html)
13 | * [Vagrant Landrush 1.2.0+](https://github.com/vagrant-landrush/landrush)
14 |
15 | > Note: The `$` stands for your machine CLI, while the `⇒` stands for the VM CLI
16 |
17 | ## Installation
18 |
19 | Create the project and access to its directory (where [app] is your application name)
20 |
21 | $ composer create-project elao/symfony-standard [app] dev-master --prefer-dist --no-install
22 | $ cd [app]
23 |
24 | Install and prepare the project dependencies
25 |
26 | $ make setup
27 |
28 | ## Customize
29 |
30 | TODO
31 |
32 | ## Usage
33 |
34 | Your app is accessible via [http://app.vendor.dev/app_dev.php](http://app.vendor.dev/app_dev.php)
35 |
36 | ## Faq
37 |
38 | ### VirtualBox DHCP Server
39 |
40 | > A host only network interface you're attempting to configure via DHCP already
41 | > has a conflicting host only adapter with DHCP enabled. The DHCP on this
42 | > adapter is...
43 |
44 | $ VBoxManage dhcpserver remove --netname HostInterfaceNetworking-vboxnet0
45 |
46 | ### OSX DNS Cache
47 |
48 | If you virtual machine does not answer, or ping to `127.0.53.53`
49 |
50 | On Yosemite 10.10 to 10.10.3
51 |
52 | $ sudo discoveryutil mdnsflushcache
53 | $ sudo discoveryutil udnsflushcaches
54 |
55 | Before Yosemite and on Yosemite 10.10.4
56 |
57 | $ sudo killall -HUP mDNSResponder
58 |
59 | See: https://support.apple.com/kb/HT202516
60 |
61 | ### OSX ssh key forwarding
62 |
63 | $ ssh-add -K ~/.ssh/[your_private_key]
64 |
65 | ### Vagrant process crash
66 |
67 | > An action '*foo*' was attempted on the machine '*bar*',
68 | > but another process is already executing an action on the machine.
69 | > Vagrant locks each machine for access by only one process at a time.
70 | > Please wait until the other Vagrant process finishes modifying this
71 | > machine, then try again.
72 |
73 | Kill vagrant ruby process, and try again
74 |
75 | $ killall ruby
76 |
77 | ### Nfs shares without password confirmation
78 |
79 | Edit /etc/sudoers.d/vagrant
80 |
81 | $ sudo vi /etc/sudoers.d/vagrant
82 |
83 | Copy/paste the following lines:
84 |
85 | Cmnd_Alias VAGRANT_EXPORTS_ADD = /usr/bin/tee -a /etc/exports
86 | Cmnd_Alias VAGRANT_NFSD = /sbin/nfsd restart
87 | Cmnd_Alias VAGRANT_EXPORTS_REMOVE = /usr/bin/sed -E -e /*/ d -ibak /etc/exports
88 | %admin ALL=(root) NOPASSWD: VAGRANT_EXPORTS_ADD, VAGRANT_NFSD, VAGRANT_EXPORTS_REMOVE
89 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "elao/symfony-standard",
3 | "description": "The elao/symfony-standard project",
4 | "license": "proprietary",
5 | "type": "project",
6 | "autoload": {
7 | "psr-4": {
8 | "": "src/",
9 | "SymfonyStandard\\": "app/SymfonyStandard/"
10 | },
11 | "classmap": [
12 | "app/AppKernel.php",
13 | "app/AppCache.php"
14 | ]
15 | },
16 | "autoload-dev": {
17 | "psr-4": {
18 | "Tests\\": "tests/"
19 | }
20 | },
21 | "require": {
22 | "php": ">=5.5.9",
23 | "symfony/symfony": "3.2.*",
24 | "doctrine/orm": "^2.5",
25 | "doctrine/doctrine-bundle": "^1.6",
26 | "doctrine/doctrine-cache-bundle": "^1.2",
27 | "symfony/swiftmailer-bundle": "^2.3.10",
28 | "symfony/monolog-bundle": "^3.0.2",
29 | "symfony/polyfill-apcu": "^1.0",
30 | "sensio/distribution-bundle": "^5.0",
31 | "sensio/framework-extra-bundle": "^3.0.2",
32 | "incenteev/composer-parameter-handler": "^2.0"
33 | },
34 | "require-dev": {
35 | "sensio/generator-bundle": "^3.0",
36 | "symfony/phpunit-bridge": "^3.0",
37 |
38 | "phpunit/phpunit": "^5.3",
39 |
40 | "doctrine/doctrine-fixtures-bundle": "^2.3",
41 |
42 | "behat/behat": "^3.1",
43 | "behat/mink": "^1.7",
44 | "behat/mink-selenium2-driver": "^1.3",
45 | "behat/mink-browserkit-driver": "^1.3",
46 | "behat/symfony2-extension": "^2.1",
47 | "behat/mink-extension": "^2.2"
48 | },
49 | "scripts": {
50 | "post-create-project-cmd": [
51 | "SymfonyStandard\\Composer::hookCreateProject"
52 | ],
53 | "symfony-scripts": [
54 | "Incenteev\\ParameterHandler\\ScriptHandler::buildParameters",
55 | "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::buildBootstrap",
56 | "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::clearCache",
57 | "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets",
58 | "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installRequirementsFile",
59 | "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::removeSymfonyStandardFiles"
60 | ],
61 | "post-install-cmd": [
62 | "@symfony-scripts"
63 | ],
64 | "post-update-cmd": [
65 | "@symfony-scripts"
66 | ]
67 | },
68 | "extra": {
69 | "symfony-app-dir": "app",
70 | "symfony-bin-dir": "bin",
71 | "symfony-var-dir": "var",
72 | "symfony-web-dir": "web",
73 | "symfony-tests-dir": "tests",
74 | "symfony-assets-install": "relative",
75 | "incenteev-parameters": {
76 | "file": "app/config/parameters.yml",
77 | "env-map": {
78 | "secret": "APP_SECRET",
79 | "database_host": "APP_DATABASE_HOST",
80 | "database_port": "APP_DATABASE_PORT",
81 | "database_name": "APP_DATABASE_NAME",
82 | "database_user": "APP_DATABASE_USER",
83 | "database_password": "APP_DATABASE_PASSWORD"
84 | }
85 | }
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/ansible/group_vars/app.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | app_options:
4 |
5 | php_version: '7.1' #5.4|5.5|5.6|7.0|7.1
6 | nodejs_version: '8' #4|5|6|7|8|9
7 |
8 | #mysql: false
9 | #mysql_version: '5.6' #5.6|5.7
10 | #mariadb: false
11 | #mariadb_version: '10.1' #10.0|10.1|10.2
12 | #postgresql: false
13 | #postgresql_version: '9.5' #9.4|9.5
14 | #redis: false
15 | #mongodb: false
16 | #mongodb_version: '3.2' #3.0|3.2
17 | #influxdb: false
18 | #sqlite: false
19 | #elasticsearch: false
20 | #elasticsearch_version: '5' #1.5|1.6|1.7|2|5
21 | #java: false
22 |
23 | app_patterns:
24 |
25 | ############
26 | # Timezone #
27 | ############
28 |
29 | timezone_default: Etc/UTC
30 |
31 | ###############
32 | # Environment #
33 | ###############
34 |
35 | environment_variables:
36 | - SYMFONY_ENV: "{{ app.env }}"
37 | - APP_SECRET: ThisTokenIsNotSoSecretChangeIt
38 | - APP_DATABASE_HOST: 127.0.0.1
39 | - APP_DATABASE_PORT: ~
40 | - APP_DATABASE_NAME: app
41 | - APP_DATABASE_USER: "{{ app.user }}"
42 | - APP_DATABASE_PASSWORD: ~
43 |
44 | #########
45 | # Files #
46 | #########
47 |
48 | files_attributes:
49 | - path: "{{ app.dir }}{{ app.dir_release }}/var/logs"
50 | src: "{{ app.log_dir }}"
51 | state: link_directory
52 | - path: "{{ app.dir }}{{ app.dir_release }}/var/cache"
53 | src: "{{ app.cache_dir }}"
54 | state: link_directory
55 | - path: "{{ app.dir }}{{ app.dir_release }}/var/sessions"
56 | src: "{{ app.sessions_dir }}"
57 | state: link_directory
58 |
59 | #######
60 | # Npm #
61 | #######
62 |
63 | #npm_packages:
64 | # - package: gulp
65 | # version: 3
66 | # - gulpjs/gulp-cli#4.0
67 | # - package: webpack
68 | # version: 1
69 | # - package: webpack
70 | # version: 2.1.0-beta.13
71 |
72 | #######
73 | # Php #
74 | #######
75 |
76 | php_extensions:
77 | # Symfony
78 | - intl
79 | - curl
80 | - mbstring
81 | - xml
82 | # Composer
83 | - zip
84 | # App
85 |
86 | php_configs:
87 | - file: app_opcache.ini
88 | template: configs/app_opcache.{{ env }}.j2
89 | - file: app.ini
90 | template: configs/app.{{ env }}.j2
91 | config:
92 | - date.timezone: UTC
93 |
94 | #########
95 | # Nginx #
96 | #########
97 |
98 | nginx_configs:
99 | # Php fpm
100 | - file: app_php_fpm
101 | template: configs/app_php_fpm.{{ env }}.j2
102 | # Gzip
103 | - file: app_gzip
104 | template: configs/app_gzip.{{ env }}.j2
105 | # App
106 | - file: app.conf
107 | config:
108 | - server:
109 | - server_name: "{{ app.host }}"
110 | #- server_name: "*.ngrok.io"
111 | - root: "{{ app.dir }}{{ app.dir_release }}/web"
112 | - access_log: "{{ app.log_dir }}/nginx.access.log"
113 | - error_log: "{{ app.log_dir }}/nginx.error.log"
114 | - include: conf.d/app_gzip
115 | - location /:
116 | - try_files: $uri /app.php$is_args$args
117 | - location ~ ^/(app(_[-\w]+)?)\.php(/|$):
118 | - include: conf.d/app_php_fpm
119 | #- internal;
120 |
121 | ########
122 | # Cron #
123 | ########
124 |
125 | #cron_files:
126 | # - file: app
127 | # user: "{{ app.user }}"
128 | # environment:
129 | # - SYMFONY_ENV: "{{ app.env }}"
130 | # jobs:
131 | # - name: foo-bar
132 | # job: "cd {{ app.dir }}{{ app.dir_release }} && php bin/console app:foo:bar --no-interaction -vv >> {{ app.log_dir }}/cron.foo-bar.log 2>&1"
133 | # minute: 0
134 | # hour: 7
135 | # # Dev
136 | # state: absent
137 |
138 | ##############
139 | # Supervisor #
140 | ##############
141 |
142 | #supervisor_configs:
143 | # - file: app.conf
144 | # template: configs/app_program.{{ env }}.j2
145 | # config:
146 | # - foo-bar:
147 | # - command: php bin/console app:foo:bar --no-interaction -vv
148 | # - directory: "{{ app.dir }}{{ app.dir_release }}"
149 | # - user: "{{ app.user }}"
150 | # - stdout_logfile: "{{ app.log_dir }}/supervisor.foo-bar.log"
151 | # - environment: "SYMFONY_ENV=\"{{ app.env }}\""
152 | # # Dev
153 | # - autostart: false
154 |
--------------------------------------------------------------------------------
/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('yellow', ' 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 | if ($helpText = get_error_message($req, $lineSize)) {
26 | echo_style('red', 'E');
27 | $messages['error'][] = $helpText;
28 | } else {
29 | echo_style('green', '.');
30 | }
31 | }
32 |
33 | $checkPassed = empty($messages['error']);
34 |
35 | foreach ($symfonyRequirements->getRecommendations() as $req) {
36 | if ($helpText = get_error_message($req, $lineSize)) {
37 | echo_style('yellow', 'W');
38 | $messages['warning'][] = $helpText;
39 | } else {
40 | echo_style('green', '.');
41 | }
42 | }
43 |
44 | if ($checkPassed) {
45 | echo_block('success', 'OK', 'Your system is ready to run Symfony projects');
46 | } else {
47 | echo_block('error', 'ERROR', 'Your system is not ready to run Symfony projects');
48 |
49 | echo_title('Fix the following mandatory requirements', 'red');
50 |
51 | foreach ($messages['error'] as $helpText) {
52 | echo ' * '.$helpText.PHP_EOL;
53 | }
54 | }
55 |
56 | if (!empty($messages['warning'])) {
57 | echo_title('Optional recommendations to improve your setup', 'yellow');
58 |
59 | foreach ($messages['warning'] as $helpText) {
60 | echo ' * '.$helpText.PHP_EOL;
61 | }
62 | }
63 |
64 | echo PHP_EOL;
65 | echo_style('title', 'Note');
66 | echo ' The command console could use a different php.ini file'.PHP_EOL;
67 | echo_style('title', '~~~~');
68 | echo ' than the one used with your web server. To be on the'.PHP_EOL;
69 | echo ' safe side, please check the requirements from your web'.PHP_EOL;
70 | echo ' server using the ';
71 | echo_style('yellow', 'web/config.php');
72 | echo ' script.'.PHP_EOL;
73 | echo PHP_EOL;
74 |
75 | exit($checkPassed ? 0 : 1);
76 |
77 | function get_error_message(Requirement $requirement, $lineSize)
78 | {
79 | if ($requirement->isFulfilled()) {
80 | return;
81 | }
82 |
83 | $errorMessage = wordwrap($requirement->getTestMessage(), $lineSize - 3, PHP_EOL.' ').PHP_EOL;
84 | $errorMessage .= ' > '.wordwrap($requirement->getHelpText(), $lineSize - 5, PHP_EOL.' > ').PHP_EOL;
85 |
86 | return $errorMessage;
87 | }
88 |
89 | function echo_title($title, $style = null)
90 | {
91 | $style = $style ?: 'title';
92 |
93 | echo PHP_EOL;
94 | echo_style($style, $title.PHP_EOL);
95 | echo_style($style, str_repeat('~', strlen($title)).PHP_EOL);
96 | echo PHP_EOL;
97 | }
98 |
99 | function echo_style($style, $message)
100 | {
101 | // ANSI color codes
102 | $styles = array(
103 | 'reset' => "\033[0m",
104 | 'red' => "\033[31m",
105 | 'green' => "\033[32m",
106 | 'yellow' => "\033[33m",
107 | 'error' => "\033[37;41m",
108 | 'success' => "\033[37;42m",
109 | 'title' => "\033[34m",
110 | );
111 | $supports = has_color_support();
112 |
113 | echo($supports ? $styles[$style] : '').$message.($supports ? $styles['reset'] : '');
114 | }
115 |
116 | function echo_block($style, $title, $message)
117 | {
118 | $message = ' '.trim($message).' ';
119 | $width = strlen($message);
120 |
121 | echo PHP_EOL.PHP_EOL;
122 |
123 | echo_style($style, str_repeat(' ', $width));
124 | echo PHP_EOL;
125 | echo_style($style, str_pad(' ['.$title.']', $width, ' ', STR_PAD_RIGHT));
126 | echo PHP_EOL;
127 | echo_style($style, $message);
128 | echo PHP_EOL;
129 | echo_style($style, str_repeat(' ', $width));
130 | echo PHP_EOL;
131 | }
132 |
133 | function has_color_support()
134 | {
135 | static $support;
136 |
137 | if (null === $support) {
138 | if (DIRECTORY_SEPARATOR == '\\') {
139 | $support = false !== getenv('ANSICON') || 'ON' === getenv('ConEmuANSI');
140 | } else {
141 | $support = function_exists('posix_isatty') && @posix_isatty(STDOUT);
142 | }
143 | }
144 |
145 | return $support;
146 | }
147 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | .SILENT:
2 | .PHONY: build test
3 |
4 | ## Colors
5 | COLOR_RESET = \033[0m
6 | COLOR_INFO = \033[32m
7 | COLOR_COMMENT = \033[33m
8 |
9 | ## Help
10 | help:
11 | printf "${COLOR_COMMENT}Usage:${COLOR_RESET}\n"
12 | printf " make [target]\n\n"
13 | printf "${COLOR_COMMENT}Available targets:${COLOR_RESET}\n"
14 | awk '/^[a-zA-Z\-\_0-9\.@]+:/ { \
15 | helpMessage = match(lastLine, /^## (.*)/); \
16 | if (helpMessage) { \
17 | helpCommand = substr($$1, 0, index($$1, ":")); \
18 | helpMessage = substr(lastLine, RSTART + 3, RLENGTH); \
19 | printf " ${COLOR_INFO}%-16s${COLOR_RESET} %s\n", helpCommand, helpMessage; \
20 | } \
21 | } \
22 | { lastLine = $$0 }' $(MAKEFILE_LIST)
23 |
24 | ###############
25 | # Environment #
26 | ###############
27 |
28 | ## Setup environment & Install & Build application
29 | setup:
30 | vagrant up --no-provision
31 | vagrant provision
32 | vagrant ssh -- "cd /srv/app && make install build"
33 |
34 | ## Update environment
35 | update: export ANSIBLE_TAGS = manala.update
36 | update:
37 | vagrant provision
38 |
39 | ## Update ansible
40 | update-ansible: export ANSIBLE_TAGS = manala.update
41 | update-ansible:
42 | vagrant provision --provision-with ansible
43 |
44 | ## Provision environment
45 | provision: export ANSIBLE_EXTRA_VARS = {"manala":{"update":false}}
46 | provision:
47 | vagrant provision --provision-with app
48 |
49 | ## Provision nginx
50 | provision-nginx: export ANSIBLE_TAGS = manala_nginx
51 | provision-nginx: provision
52 |
53 | ## Provision php
54 | provision-php: export ANSIBLE_TAGS = manala_php
55 | provision-php: provision
56 |
57 | ###########
58 | # Install #
59 | ###########
60 |
61 | ## Install application
62 | install:
63 | # Composer
64 | composer install --verbose
65 | # Db
66 | bin/console doctrine:database:create --if-not-exists
67 | bin/console doctrine:schema:update --force
68 | # Db - Test
69 | bin/console doctrine:database:create --if-not-exists --env=test
70 | bin/console doctrine:schema:update --force --env=test
71 | # Db - Fixtures
72 | #bin/console doctrine:fixtures:load --no-interaction
73 | # Db - Fixtures - Test
74 | #bin/console doctrine:fixtures:load --no-interaction --env=test
75 |
76 | install@test: export SYMFONY_ENV = test
77 | install@test:
78 | # Composer
79 | composer install --verbose --no-progress --no-interaction
80 | # Db
81 | bin/console doctrine:database:drop --force --if-exists
82 | bin/console doctrine:database:create --if-not-exists
83 | bin/console doctrine:schema:update --force
84 | # Db - Fixtures
85 | #bin/console doctrine:fixtures:load --no-interaction
86 |
87 | install@demo: export SYMFONY_ENV = prod
88 | install@demo:
89 | # Composer
90 | composer install --verbose --no-progress --no-interaction --prefer-dist --optimize-autoloader
91 | # Symfony cache
92 | bin/console cache:warmup --no-debug
93 |
94 | install@prod: export SYMFONY_ENV = prod
95 | install@prod:
96 | # Composer
97 | composer install --verbose --no-progress --no-interaction --prefer-dist --optimize-autoloader --no-dev
98 | # Symfony cache
99 | bin/console cache:warmup --no-debug
100 |
101 | #########
102 | # Build #
103 | #########
104 |
105 | ## Build application
106 | build:
107 |
108 | build@demo: export SYMFONY_ENV = prod
109 | build@demo:
110 |
111 | build@prod: export SYMFONY_ENV = prod
112 | build@prod:
113 |
114 | ############
115 | # Security #
116 | ############
117 |
118 | ## Run security checks
119 | security:
120 | security-checker security:check
121 |
122 | security@test: export SYMFONY_ENV = test
123 | security@test: security
124 |
125 | ########
126 | # Lint #
127 | ########
128 |
129 | ## Run lint tools
130 | lint:
131 | php-cs-fixer fix --config-file=.php_cs --dry-run --diff
132 |
133 | lint@test: export SYMFONY_ENV = test
134 | lint@test: lint
135 |
136 | ########
137 | # Test #
138 | ########
139 |
140 | ## Run tests
141 | test: export SYMFONY_ENV = test
142 | test:
143 | # PHPUnit
144 | vendor/bin/phpunit
145 | # Behat
146 | bin/console cache:clear && vendor/bin/behat
147 |
148 | test@test: export SYMFONY_ENV = test
149 | test@test:
150 | # PHPUnit
151 | rm -Rf build/phpunit && mkdir -p build/phpunit
152 | stty cols 80 && vendor/bin/phpunit --log-junit build/phpunit/junit.xml --coverage-clover build/phpunit/clover.xml --coverage-html build/phpunit/coverage
153 | # Behat
154 | rm -Rf build/behat && mkdir -p build/behat
155 | bin/console cache:clear && vendor/bin/behat --format=junit --out=build/behat --no-interaction
156 |
157 | ##########
158 | # Deploy #
159 | ##########
160 |
161 | ## Deploy application (demo)
162 | deploy@demo:
163 | ansible-playbook ansible/deploy.yml --inventory-file=ansible/hosts --limit=deploy_demo
164 |
165 | ## Deploy application (prod)
166 | deploy@prod:
167 | ansible-playbook ansible/deploy.yml --inventory-file=ansible/hosts --limit=deploy_prod
168 |
169 | ##########
170 | # Custom #
171 | ##########
172 |
--------------------------------------------------------------------------------
/app/SymfonyStandard/Composer.php:
--------------------------------------------------------------------------------
1 |
9 | */
10 |
11 | namespace SymfonyStandard;
12 |
13 | use Composer\Script\CommandEvent;
14 |
15 | /**
16 | * Class Composer
17 | * @package SymfonyStandard
18 | */
19 | class Composer
20 | {
21 | /**
22 | * @const ANSIBLE_FILE : path to the ansible app.yml file
23 | */
24 | const ANSIBLE_FILE = 'ansible/group_vars/app.yml';
25 |
26 | /**
27 | * @var array
28 | */
29 | public static $fileMap = [
30 | 'README.app.md' => [
31 | 'label' => '/App/',
32 | 'name' => '/()app(\.dev)/',
33 | ],
34 | 'Vagrantfile' => [
35 | 'name' => '/(:name.+\')app(\')/',
36 | ],
37 | 'behat.yml.dist' => [
38 | 'name' => '/()app(\.dev)/',
39 | ],
40 | '.php_cs' => [
41 | 'label' => '/App/',
42 | 'vendor' => '/Vendor/',
43 | ],
44 | 'composer.json' => [
45 | 'composerVendor' => '/elao\/symfony-standard/',
46 | 'composerName' => '/The elao\/symfony-standard project/',
47 | ],
48 | ];
49 |
50 | /**
51 | * Create the project.
52 | *
53 | * @param CommandEvent $event
54 | */
55 | public static function hookCreateProject(CommandEvent $event)
56 | {
57 | $files = array_keys(self::$fileMap);
58 |
59 | $event->getIO()->write([
60 | 'Configure application',
61 | 'The following files will be updated:',
62 | '- composer.json',
63 | '- README.md',
64 | ]);
65 |
66 | foreach ($files as $filename) {
67 | $event->getIO()->write('- ' . $filename);
68 | }
69 |
70 | $confirmation = $event->getIO()
71 | ->askConfirmation(
72 | 'Do you want to continue? [Y,n]',
73 | true
74 | );
75 |
76 | if (!$confirmation) {
77 | return;
78 | }
79 |
80 | $event->getIO()->write([
81 | 'You are going to define your project\'s vendor and app name, it will look something like this : app.vendor',
82 | ]);
83 |
84 | $projectInfos = self::askAppVendorName($event);
85 | $vendor = $projectInfos['vendor'];
86 | $app = $projectInfos['appName'];
87 |
88 | $appName = $app . ($vendor ? '.' . $vendor : '');
89 | $appLabel = ucwords(str_replace('.', ' - ', str_replace('-', ' ', $appName)));
90 |
91 | $appComposerName = str_replace('.', '/', $appName);
92 |
93 | $userValues = [
94 | 'label' => $appLabel,
95 | 'name' => '$1' . $appName . '$2',
96 | 'vendor' => $vendor ? ucwords(str_replace('-', ' ', $vendor)) : $appLabel,
97 | 'composerVendor' => ($vendor ? $vendor : $app) . '/' . $app,
98 | 'composerName' => ($vendor ? str_replace('-', ' ', $vendor) . ' - ' : '') . str_replace('-', ' ', $app),
99 | ];
100 |
101 | foreach (self::$fileMap as $filename => $values) {
102 | if (file_exists($filename)) {
103 | $patterns = array_values($values);
104 | $replacements = array_intersect_key($userValues, $values);
105 |
106 | self::replaceValueInFile($filename, $patterns, $replacements);
107 | }
108 | }
109 |
110 | $content = file_get_contents('README.app.md');
111 | file_put_contents('README.md', $content);
112 | unlink('README.app.md');
113 |
114 | self::installDependencies($event);
115 | }
116 |
117 | /**
118 | * Ask for the vendor and the app name, calls itself back if not confirmed.
119 | *
120 | * @param CommandEvent $event
121 | *
122 | * @return array
123 | */
124 | private static function askAppVendorName(CommandEvent $event)
125 | {
126 | $projectInfos = [];
127 |
128 | $projectInfos['vendor'] = self::askVendor($event);
129 | $projectInfos['appName'] = self::askAppName($event);
130 |
131 | $confirmation = $event->getIO()
132 | ->askConfirmation(
133 | 'Your project’s vendor will be "' . $projectInfos['vendor'] . '" and your app name will be "' . $projectInfos['appName'] .
134 | '". Do you want to continue? [Y,n]',
135 | true
136 | );
137 |
138 | if (!$confirmation) {
139 | self::askAppVendorName($event);
140 | }
141 |
142 | return $projectInfos;
143 | }
144 |
145 | /**
146 | * Ask for the vendor.
147 | *
148 | * @param CommandEvent $event
149 | *
150 | * @return string
151 | */
152 | private static function askVendor(CommandEvent $event)
153 | {
154 | return $event->getIO()
155 | ->askAndValidate(
156 | 'Vendor name (optional): ',
157 | function ($value) {
158 | if (!preg_match('/^([-A-Z0-9])*$/i', $value)) {
159 | throw new \InvalidArgumentException('The name should only contains alphanumeric characters (and hyphens)');
160 | }
161 |
162 | return $value;
163 | },
164 | 5,
165 | null
166 | );
167 | }
168 |
169 | /**
170 | * Ask for the App name.
171 | *
172 | * @param CommandEvent $event
173 | *
174 | * @return string
175 | */
176 | private static function askAppName(CommandEvent $event)
177 | {
178 | return $event->getIO()
179 | ->askAndValidate(
180 | 'Application name [app]: ',
181 | function ($value) {
182 | if (!preg_match('/^([-A-Z0-9])*$/i', $value)) {
183 | throw new \InvalidArgumentException('The name should only contains alphanumeric characters (and hyphens)');
184 | }
185 |
186 | return $value;
187 | },
188 | 5,
189 | 'app'
190 | );
191 | }
192 |
193 | /**
194 | * Install the dependencies (roles) listed in the ansible/group_vars/app.yml config file.
195 | *
196 | * @param CommandEvent $event
197 | */
198 | private static function installDependencies(CommandEvent $event)
199 | {
200 | $content = file_get_contents(self::ANSIBLE_FILE);
201 | $dependencies = self::getDependenciesList($content);
202 | $versionList = self::getDependenciesVersionList($content);
203 |
204 | self::handleDependencyVersion($event, 'php', $content);
205 | self::handleDependencyVersion($event, 'nodejs', $content);
206 |
207 | foreach ($dependencies as $dependency) {
208 | self::handleDependency($event, $dependency, $content, $versionList);
209 | }
210 | }
211 |
212 | /**
213 | * Handle a single dependency.
214 | *
215 | * @param CommandEvent $event
216 | * @param string $dependency
217 | * @param string $content
218 | * @param string $versionList
219 | */
220 | private static function handleDependency(CommandEvent $event, $dependency, $content, $versionList)
221 | {
222 | preg_match('/#' . $dependency . '.*false/', $content, $activationMatches);
223 | preg_match('/#' . $dependency . '_version.*\r?\n/', $content, $versionMatches);
224 |
225 | $dependencyValue = $event->getIO()
226 | ->askAndValidate(
227 | 'Do you wish to install ' . $dependency . ' ? [y/N]: ',
228 | function ($value) {
229 | if (!preg_match('/^(?:Y|N|^$)$/i', $value)) {
230 | throw new \InvalidArgumentException('Invalid input');
231 | }
232 |
233 | return $value;
234 | },
235 | 5,
236 | null
237 | );
238 |
239 | preg_match('/^Y/i', $dependencyValue) ?
240 | self::replaceValueInFile(self::ANSIBLE_FILE, '/#(' . $dependency . ':.+)false/', '$1 ' . 'true')
241 | :
242 | self::replaceValueInFile(self::ANSIBLE_FILE, '/#' . $dependency . ':.+false\r?\n/', '');
243 |
244 | if (preg_match('/^Y/i', $dependencyValue) && 'postgresql' === $dependency) {
245 | $confirmation = $event->getIO()
246 | ->askConfirmation(
247 | 'Do you want to use postgresql as your default connection for Doctrine ? [y,N]',
248 | false
249 | );
250 |
251 | if ($confirmation) {
252 | self::replaceValueInFile('app/config/config.yml', '/(doctrine:\s+dbal:\s+driver: +).+(\S)/', '$1pdo_pgsql');
253 | }
254 | }
255 |
256 | if (preg_match('/^Y/i', $dependencyValue) && in_array($dependency . '_version', $versionList)) {
257 | self::handleDependencyVersion($event, $dependency, $content);
258 | } elseif (in_array($dependency . '_version', $versionList)) {
259 | self::replaceValueInFile(self::ANSIBLE_FILE, '/.*#' . $dependency . '_version:.+\r?\n/', '');
260 | }
261 | }
262 |
263 | /**
264 | * Handle the dependency version.
265 | *
266 | * @param CommandEvent $event
267 | * @param string $dependency
268 | * @param string $content
269 | */
270 | private static function handleDependencyVersion(CommandEvent $event, $dependency, $content)
271 | {
272 | $versions = self::getAvailableDependencyVersions($content, $dependency . '_version');
273 | $defaultVersion = self::getDefaultVersion($content, $dependency);
274 | preg_match('/#' . $dependency . '_version.*\r?\n/', $content, $versionMatches);
275 |
276 | $versionValidator = function ($value) use ($versions) {
277 | if (!in_array($value, $versions)) {
278 | throw new \InvalidArgumentException('This version is not valid');
279 | }
280 |
281 | return $value;
282 | };
283 |
284 | $chosenVersion = $event->getIO()
285 | ->askAndValidate(
286 | '' . $dependency . ' version (' . implode(', ', $versions) . ') [' . $defaultVersion . '] : ',
287 | $versionValidator,
288 | 5,
289 | $defaultVersion
290 | );
291 |
292 | if ('php' === $dependency OR 'nodejs' === $dependency) {
293 | if ('php' === $dependency) {
294 | $boxVersion = (('7.0' === $chosenVersion) || ('7.1' === $chosenVersion)) ? '3.0.0' : '2.0.0';
295 | self::replaceValueInFile('Vagrantfile', '/(box_version\s+=>\s+)\'.+(\',)/', '$1\'~> ' . $boxVersion . '$2');
296 | }
297 |
298 | self::replaceValueInFile(self::ANSIBLE_FILE, '/(' . $dependency . '_version:.+)\'.+(\').+(\S)/', '$1 \'' . $chosenVersion . '$2');
299 | }
300 | else{
301 | self::replaceValueInFile(self::ANSIBLE_FILE, '/#(' . $dependency . '_version:.+)\'.+(\').+(\S)/', '$1 \'' . $chosenVersion . '$2');
302 | }
303 |
304 | }
305 |
306 | /**
307 | * Get the dependency default version.
308 | *
309 | * @param string $content
310 | * @param string $dependency
311 | *
312 | * @throws \InvalidArgumentException
313 | * @return array
314 | */
315 | private static function getDefaultVersion($content, $dependency)
316 | {
317 | preg_match('/' . $dependency . '.*\'(.*)\'/', $content, $matches);
318 |
319 | if (!isset($matches[1]) || empty($matches[1])) {
320 | throw new \InvalidArgumentException(sprintf('A default version of %s is missing in your ansible/groupe_vars/app.yml file', $dependency));
321 | }
322 |
323 | return $matches[1];
324 | }
325 |
326 | /**
327 | * Get the list of dependencies having versions defined.
328 | *
329 | * @param string $content
330 | *
331 | * @return array
332 | */
333 | private static function getDependenciesVersionList($content)
334 | {
335 | $content = substr($content, 0, strpos($content, 'app_patterns'));
336 | preg_match_all('/#(.*_version):/', $content, $matches);
337 |
338 | return $matches[1];
339 | }
340 |
341 | /**
342 | * Get the list of available dependencies.
343 | *
344 | * @param string $content
345 | *
346 | * @return array
347 | */
348 | private static function getDependenciesList($content)
349 | {
350 | $content = substr($content, 0, strpos($content, 'app_patterns'));
351 | preg_match_all('/#(\w*(?
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 | /**
172 | * @var Requirement[]
173 | */
174 | private $requirements = array();
175 |
176 | /**
177 | * Gets the current RequirementCollection as an Iterator.
178 | *
179 | * @return Traversable A Traversable interface
180 | */
181 | public function getIterator()
182 | {
183 | return new ArrayIterator($this->requirements);
184 | }
185 |
186 | /**
187 | * Adds a Requirement.
188 | *
189 | * @param Requirement $requirement A Requirement instance
190 | */
191 | public function add(Requirement $requirement)
192 | {
193 | $this->requirements[] = $requirement;
194 | }
195 |
196 | /**
197 | * Adds a mandatory requirement.
198 | *
199 | * @param bool $fulfilled Whether the requirement is fulfilled
200 | * @param string $testMessage The message for testing the requirement
201 | * @param string $helpHtml The help text formatted in HTML for resolving the problem
202 | * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags)
203 | */
204 | public function addRequirement($fulfilled, $testMessage, $helpHtml, $helpText = null)
205 | {
206 | $this->add(new Requirement($fulfilled, $testMessage, $helpHtml, $helpText, false));
207 | }
208 |
209 | /**
210 | * Adds an optional recommendation.
211 | *
212 | * @param bool $fulfilled Whether the recommendation is fulfilled
213 | * @param string $testMessage The message for testing the recommendation
214 | * @param string $helpHtml The help text formatted in HTML for resolving the problem
215 | * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags)
216 | */
217 | public function addRecommendation($fulfilled, $testMessage, $helpHtml, $helpText = null)
218 | {
219 | $this->add(new Requirement($fulfilled, $testMessage, $helpHtml, $helpText, true));
220 | }
221 |
222 | /**
223 | * Adds a mandatory requirement in form of a php.ini configuration.
224 | *
225 | * @param string $cfgName The configuration name used for ini_get()
226 | * @param bool|callback $evaluation Either a boolean indicating whether the configuration should evaluate to true or false,
227 | * or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement
228 | * @param bool $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false.
229 | * This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin.
230 | * Example: You require a config to be true but PHP later removes this config and defaults it to true internally.
231 | * @param string $testMessage The message for testing the requirement (when null and $evaluation is a boolean a default message is derived)
232 | * @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)
233 | * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags)
234 | */
235 | public function addPhpIniRequirement($cfgName, $evaluation, $approveCfgAbsence = false, $testMessage = null, $helpHtml = null, $helpText = null)
236 | {
237 | $this->add(new PhpIniRequirement($cfgName, $evaluation, $approveCfgAbsence, $testMessage, $helpHtml, $helpText, false));
238 | }
239 |
240 | /**
241 | * Adds an optional recommendation in form of a php.ini configuration.
242 | *
243 | * @param string $cfgName The configuration name used for ini_get()
244 | * @param bool|callback $evaluation Either a boolean indicating whether the configuration should evaluate to true or false,
245 | * or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement
246 | * @param bool $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false.
247 | * This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin.
248 | * Example: You require a config to be true but PHP later removes this config and defaults it to true internally.
249 | * @param string $testMessage The message for testing the requirement (when null and $evaluation is a boolean a default message is derived)
250 | * @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)
251 | * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags)
252 | */
253 | public function addPhpIniRecommendation($cfgName, $evaluation, $approveCfgAbsence = false, $testMessage = null, $helpHtml = null, $helpText = null)
254 | {
255 | $this->add(new PhpIniRequirement($cfgName, $evaluation, $approveCfgAbsence, $testMessage, $helpHtml, $helpText, true));
256 | }
257 |
258 | /**
259 | * Adds a requirement collection to the current set of requirements.
260 | *
261 | * @param RequirementCollection $collection A RequirementCollection instance
262 | */
263 | public function addCollection(RequirementCollection $collection)
264 | {
265 | $this->requirements = array_merge($this->requirements, $collection->all());
266 | }
267 |
268 | /**
269 | * Returns both requirements and recommendations.
270 | *
271 | * @return Requirement[]
272 | */
273 | public function all()
274 | {
275 | return $this->requirements;
276 | }
277 |
278 | /**
279 | * Returns all mandatory requirements.
280 | *
281 | * @return Requirement[]
282 | */
283 | public function getRequirements()
284 | {
285 | $array = array();
286 | foreach ($this->requirements as $req) {
287 | if (!$req->isOptional()) {
288 | $array[] = $req;
289 | }
290 | }
291 |
292 | return $array;
293 | }
294 |
295 | /**
296 | * Returns the mandatory requirements that were not met.
297 | *
298 | * @return Requirement[]
299 | */
300 | public function getFailedRequirements()
301 | {
302 | $array = array();
303 | foreach ($this->requirements as $req) {
304 | if (!$req->isFulfilled() && !$req->isOptional()) {
305 | $array[] = $req;
306 | }
307 | }
308 |
309 | return $array;
310 | }
311 |
312 | /**
313 | * Returns all optional recommendations.
314 | *
315 | * @return Requirement[]
316 | */
317 | public function getRecommendations()
318 | {
319 | $array = array();
320 | foreach ($this->requirements as $req) {
321 | if ($req->isOptional()) {
322 | $array[] = $req;
323 | }
324 | }
325 |
326 | return $array;
327 | }
328 |
329 | /**
330 | * Returns the recommendations that were not met.
331 | *
332 | * @return Requirement[]
333 | */
334 | public function getFailedRecommendations()
335 | {
336 | $array = array();
337 | foreach ($this->requirements as $req) {
338 | if (!$req->isFulfilled() && $req->isOptional()) {
339 | $array[] = $req;
340 | }
341 | }
342 |
343 | return $array;
344 | }
345 |
346 | /**
347 | * Returns whether a php.ini configuration is not correct.
348 | *
349 | * @return bool php.ini configuration problem?
350 | */
351 | public function hasPhpIniConfigIssue()
352 | {
353 | foreach ($this->requirements as $req) {
354 | if (!$req->isFulfilled() && $req instanceof PhpIniRequirement) {
355 | return true;
356 | }
357 | }
358 |
359 | return false;
360 | }
361 |
362 | /**
363 | * Returns the PHP configuration file (php.ini) path.
364 | *
365 | * @return string|false php.ini file path
366 | */
367 | public function getPhpIniConfigPath()
368 | {
369 | return get_cfg_var('cfg_file_path');
370 | }
371 | }
372 |
373 | /**
374 | * This class specifies all requirements and optional recommendations that
375 | * are necessary to run the Symfony Standard Edition.
376 | *
377 | * @author Tobias Schultze
378 | * @author Fabien Potencier
379 | */
380 | class SymfonyRequirements extends RequirementCollection
381 | {
382 | const LEGACY_REQUIRED_PHP_VERSION = '5.3.3';
383 | const REQUIRED_PHP_VERSION = '5.5.9';
384 |
385 | /**
386 | * Constructor that initializes the requirements.
387 | */
388 | public function __construct()
389 | {
390 | /* mandatory requirements follow */
391 |
392 | $installedPhpVersion = phpversion();
393 | $requiredPhpVersion = $this->getPhpRequiredVersion();
394 |
395 | $this->addRecommendation(
396 | $requiredPhpVersion,
397 | 'Vendors should be installed in order to check all requirements.',
398 | 'Run the composer install command.',
399 | 'Run the "composer install" command.'
400 | );
401 |
402 | if (false !== $requiredPhpVersion) {
403 | $this->addRequirement(
404 | version_compare($installedPhpVersion, $requiredPhpVersion, '>='),
405 | sprintf('PHP version must be at least %s (%s installed)', $requiredPhpVersion, $installedPhpVersion),
406 | sprintf('You are running PHP version "%s", but Symfony needs at least PHP "%s" to run.
407 | Before using Symfony, upgrade your PHP installation, preferably to the latest version.',
408 | $installedPhpVersion, $requiredPhpVersion),
409 | sprintf('Install PHP %s or newer (installed version is %s)', $requiredPhpVersion, $installedPhpVersion)
410 | );
411 | }
412 |
413 | $this->addRequirement(
414 | version_compare($installedPhpVersion, '5.3.16', '!='),
415 | 'PHP version must not be 5.3.16 as Symfony won\'t work properly with it',
416 | 'Install PHP 5.3.17 or newer (or downgrade to an earlier PHP version)'
417 | );
418 |
419 | $this->addRequirement(
420 | is_dir(__DIR__.'/../vendor/composer'),
421 | 'Vendor libraries must be installed',
422 | 'Vendor libraries are missing. Install composer following instructions from http://getcomposer.org/. '.
423 | 'Then run "php composer.phar install" to install them.'
424 | );
425 |
426 | $cacheDir = is_dir(__DIR__.'/../var/cache') ? __DIR__.'/../var/cache' : __DIR__.'/cache';
427 |
428 | $this->addRequirement(
429 | is_writable($cacheDir),
430 | 'app/cache/ or var/cache/ directory must be writable',
431 | 'Change the permissions of either "app/cache/" or "var/cache/" directory so that the web server can write into it.'
432 | );
433 |
434 | $logsDir = is_dir(__DIR__.'/../var/logs') ? __DIR__.'/../var/logs' : __DIR__.'/logs';
435 |
436 | $this->addRequirement(
437 | is_writable($logsDir),
438 | 'app/logs/ or var/logs/ directory must be writable',
439 | 'Change the permissions of either "app/logs/" or "var/logs/" directory so that the web server can write into it.'
440 | );
441 |
442 | if (version_compare($installedPhpVersion, '7.0.0', '<')) {
443 | $this->addPhpIniRequirement(
444 | 'date.timezone', true, false,
445 | 'date.timezone setting must be set',
446 | 'Set the "date.timezone" setting in php.ini* (like Europe/Paris).'
447 | );
448 | }
449 |
450 | if (false !== $requiredPhpVersion && version_compare($installedPhpVersion, $requiredPhpVersion, '>=')) {
451 | $timezones = array();
452 | foreach (DateTimeZone::listAbbreviations() as $abbreviations) {
453 | foreach ($abbreviations as $abbreviation) {
454 | $timezones[$abbreviation['timezone_id']] = true;
455 | }
456 | }
457 |
458 | $this->addRequirement(
459 | isset($timezones[@date_default_timezone_get()]),
460 | sprintf('Configured default timezone "%s" must be supported by your installation of PHP', @date_default_timezone_get()),
461 | '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.'
462 | );
463 | }
464 |
465 | $this->addRequirement(
466 | function_exists('iconv'),
467 | 'iconv() must be available',
468 | 'Install and enable the iconv extension.'
469 | );
470 |
471 | $this->addRequirement(
472 | function_exists('json_encode'),
473 | 'json_encode() must be available',
474 | 'Install and enable the JSON extension.'
475 | );
476 |
477 | $this->addRequirement(
478 | function_exists('session_start'),
479 | 'session_start() must be available',
480 | 'Install and enable the session extension.'
481 | );
482 |
483 | $this->addRequirement(
484 | function_exists('ctype_alpha'),
485 | 'ctype_alpha() must be available',
486 | 'Install and enable the ctype extension.'
487 | );
488 |
489 | $this->addRequirement(
490 | function_exists('token_get_all'),
491 | 'token_get_all() must be available',
492 | 'Install and enable the Tokenizer extension.'
493 | );
494 |
495 | $this->addRequirement(
496 | function_exists('simplexml_import_dom'),
497 | 'simplexml_import_dom() must be available',
498 | 'Install and enable the SimpleXML extension.'
499 | );
500 |
501 | if (function_exists('apc_store') && ini_get('apc.enabled')) {
502 | if (version_compare($installedPhpVersion, '5.4.0', '>=')) {
503 | $this->addRequirement(
504 | version_compare(phpversion('apc'), '3.1.13', '>='),
505 | 'APC version must be at least 3.1.13 when using PHP 5.4',
506 | 'Upgrade your APC extension (3.1.13+).'
507 | );
508 | } else {
509 | $this->addRequirement(
510 | version_compare(phpversion('apc'), '3.0.17', '>='),
511 | 'APC version must be at least 3.0.17',
512 | 'Upgrade your APC extension (3.0.17+).'
513 | );
514 | }
515 | }
516 |
517 | $this->addPhpIniRequirement('detect_unicode', false);
518 |
519 | if (extension_loaded('suhosin')) {
520 | $this->addPhpIniRequirement(
521 | 'suhosin.executor.include.whitelist',
522 | create_function('$cfgValue', 'return false !== stripos($cfgValue, "phar");'),
523 | false,
524 | 'suhosin.executor.include.whitelist must be configured correctly in php.ini',
525 | 'Add "phar" to suhosin.executor.include.whitelist in php.ini*.'
526 | );
527 | }
528 |
529 | if (extension_loaded('xdebug')) {
530 | $this->addPhpIniRequirement(
531 | 'xdebug.show_exception_trace', false, true
532 | );
533 |
534 | $this->addPhpIniRequirement(
535 | 'xdebug.scream', false, true
536 | );
537 |
538 | $this->addPhpIniRecommendation(
539 | 'xdebug.max_nesting_level',
540 | create_function('$cfgValue', 'return $cfgValue > 100;'),
541 | true,
542 | 'xdebug.max_nesting_level should be above 100 in php.ini',
543 | '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.'
544 | );
545 | }
546 |
547 | $pcreVersion = defined('PCRE_VERSION') ? (float) PCRE_VERSION : null;
548 |
549 | $this->addRequirement(
550 | null !== $pcreVersion,
551 | 'PCRE extension must be available',
552 | 'Install the PCRE extension (version 8.0+).'
553 | );
554 |
555 | if (extension_loaded('mbstring')) {
556 | $this->addPhpIniRequirement(
557 | 'mbstring.func_overload',
558 | create_function('$cfgValue', 'return (int) $cfgValue === 0;'),
559 | true,
560 | 'string functions should not be overloaded',
561 | 'Set "mbstring.func_overload" to 0 in php.ini* to disable function overloading by the mbstring extension.'
562 | );
563 | }
564 |
565 | /* optional recommendations follow */
566 |
567 | if (file_exists(__DIR__.'/../vendor/composer')) {
568 | require_once __DIR__.'/../vendor/autoload.php';
569 |
570 | try {
571 | $r = new ReflectionClass('Sensio\Bundle\DistributionBundle\SensioDistributionBundle');
572 |
573 | $contents = file_get_contents(dirname($r->getFileName()).'/Resources/skeleton/app/SymfonyRequirements.php');
574 | } catch (ReflectionException $e) {
575 | $contents = '';
576 | }
577 | $this->addRecommendation(
578 | file_get_contents(__FILE__) === $contents,
579 | 'Requirements file should be up-to-date',
580 | 'Your requirements file is outdated. Run composer install and re-check your configuration.'
581 | );
582 | }
583 |
584 | $this->addRecommendation(
585 | version_compare($installedPhpVersion, '5.3.4', '>='),
586 | 'You should use at least PHP 5.3.4 due to PHP bug #52083 in earlier versions',
587 | '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.'
588 | );
589 |
590 | $this->addRecommendation(
591 | version_compare($installedPhpVersion, '5.3.8', '>='),
592 | 'When using annotations you should have at least PHP 5.3.8 due to PHP bug #55156',
593 | 'Install PHP 5.3.8 or newer if your project uses annotations.'
594 | );
595 |
596 | $this->addRecommendation(
597 | version_compare($installedPhpVersion, '5.4.0', '!='),
598 | 'You should not use PHP 5.4.0 due to the PHP bug #61453',
599 | '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.'
600 | );
601 |
602 | $this->addRecommendation(
603 | version_compare($installedPhpVersion, '5.4.11', '>='),
604 | '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)',
605 | 'Install PHP 5.4.11 or newer if your project uses the logout handler from the Symfony Security Component.'
606 | );
607 |
608 | $this->addRecommendation(
609 | (version_compare($installedPhpVersion, '5.3.18', '>=') && version_compare($installedPhpVersion, '5.4.0', '<'))
610 | ||
611 | version_compare($installedPhpVersion, '5.4.8', '>='),
612 | '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',
613 | 'Install PHP 5.3.18+ or PHP 5.4.8+ if you want nice error messages for all fatal errors in the development environment.'
614 | );
615 |
616 | if (null !== $pcreVersion) {
617 | $this->addRecommendation(
618 | $pcreVersion >= 8.0,
619 | sprintf('PCRE extension should be at least version 8.0 (%s installed)', $pcreVersion),
620 | '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.'
621 | );
622 | }
623 |
624 | $this->addRecommendation(
625 | class_exists('DomDocument'),
626 | 'PHP-DOM and PHP-XML modules should be installed',
627 | 'Install and enable the PHP-DOM and the PHP-XML modules.'
628 | );
629 |
630 | $this->addRecommendation(
631 | function_exists('mb_strlen'),
632 | 'mb_strlen() should be available',
633 | 'Install and enable the mbstring extension.'
634 | );
635 |
636 | $this->addRecommendation(
637 | function_exists('iconv'),
638 | 'iconv() should be available',
639 | 'Install and enable the iconv extension.'
640 | );
641 |
642 | $this->addRecommendation(
643 | function_exists('utf8_decode'),
644 | 'utf8_decode() should be available',
645 | 'Install and enable the XML extension.'
646 | );
647 |
648 | $this->addRecommendation(
649 | function_exists('filter_var'),
650 | 'filter_var() should be available',
651 | 'Install and enable the filter extension.'
652 | );
653 |
654 | if (!defined('PHP_WINDOWS_VERSION_BUILD')) {
655 | $this->addRecommendation(
656 | function_exists('posix_isatty'),
657 | 'posix_isatty() should be available',
658 | 'Install and enable the php_posix extension (used to colorize the CLI output).'
659 | );
660 | }
661 |
662 | $this->addRecommendation(
663 | extension_loaded('intl'),
664 | 'intl extension should be available',
665 | 'Install and enable the intl extension (used for validators).'
666 | );
667 |
668 | if (extension_loaded('intl')) {
669 | // in some WAMP server installations, new Collator() returns null
670 | $this->addRecommendation(
671 | null !== new Collator('fr_FR'),
672 | 'intl extension should be correctly configured',
673 | 'The intl extension does not behave properly. This problem is typical on PHP 5.3.X x64 WIN builds.'
674 | );
675 |
676 | // check for compatible ICU versions (only done when you have the intl extension)
677 | if (defined('INTL_ICU_VERSION')) {
678 | $version = INTL_ICU_VERSION;
679 | } else {
680 | $reflector = new ReflectionExtension('intl');
681 |
682 | ob_start();
683 | $reflector->info();
684 | $output = strip_tags(ob_get_clean());
685 |
686 | preg_match('/^ICU version +(?:=> )?(.*)$/m', $output, $matches);
687 | $version = $matches[1];
688 | }
689 |
690 | $this->addRecommendation(
691 | version_compare($version, '4.0', '>='),
692 | 'intl ICU version should be at least 4+',
693 | 'Upgrade your intl extension with a newer ICU version (4+).'
694 | );
695 |
696 | if (class_exists('Symfony\Component\Intl\Intl')) {
697 | $this->addRecommendation(
698 | \Symfony\Component\Intl\Intl::getIcuDataVersion() <= \Symfony\Component\Intl\Intl::getIcuVersion(),
699 | sprintf('intl ICU version installed on your system is outdated (%s) and does not match the ICU data bundled with Symfony (%s)', \Symfony\Component\Intl\Intl::getIcuVersion(), \Symfony\Component\Intl\Intl::getIcuDataVersion()),
700 | 'To get the latest internationalization data upgrade the ICU system package and the intl PHP extension.'
701 | );
702 | if (\Symfony\Component\Intl\Intl::getIcuDataVersion() <= \Symfony\Component\Intl\Intl::getIcuVersion()) {
703 | $this->addRecommendation(
704 | \Symfony\Component\Intl\Intl::getIcuDataVersion() === \Symfony\Component\Intl\Intl::getIcuVersion(),
705 | sprintf('intl ICU version installed on your system (%s) does not match the ICU data bundled with Symfony (%s)', \Symfony\Component\Intl\Intl::getIcuVersion(), \Symfony\Component\Intl\Intl::getIcuDataVersion()),
706 | 'To avoid internationalization data inconsistencies upgrade the symfony/intl component.'
707 | );
708 | }
709 | }
710 |
711 | $this->addPhpIniRecommendation(
712 | 'intl.error_level',
713 | create_function('$cfgValue', 'return (int) $cfgValue === 0;'),
714 | true,
715 | 'intl.error_level should be 0 in php.ini',
716 | 'Set "intl.error_level" to "0" in php.ini* to inhibit the messages when an error occurs in ICU functions.'
717 | );
718 | }
719 |
720 | $accelerator =
721 | (extension_loaded('eaccelerator') && ini_get('eaccelerator.enable'))
722 | ||
723 | (extension_loaded('apc') && ini_get('apc.enabled'))
724 | ||
725 | (extension_loaded('Zend Optimizer+') && ini_get('zend_optimizerplus.enable'))
726 | ||
727 | (extension_loaded('Zend OPcache') && ini_get('opcache.enable'))
728 | ||
729 | (extension_loaded('xcache') && ini_get('xcache.cacher'))
730 | ||
731 | (extension_loaded('wincache') && ini_get('wincache.ocenabled'))
732 | ;
733 |
734 | $this->addRecommendation(
735 | $accelerator,
736 | 'a PHP accelerator should be installed',
737 | 'Install and/or enable a PHP accelerator (highly recommended).'
738 | );
739 |
740 | if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
741 | $this->addRecommendation(
742 | $this->getRealpathCacheSize() >= 5 * 1024 * 1024,
743 | 'realpath_cache_size should be at least 5M in php.ini',
744 | 'Setting "realpath_cache_size" to e.g. "5242880" or "5M" in php.ini* may improve performance on Windows significantly in some cases.'
745 | );
746 | }
747 |
748 | $this->addPhpIniRecommendation('short_open_tag', false);
749 |
750 | $this->addPhpIniRecommendation('magic_quotes_gpc', false, true);
751 |
752 | $this->addPhpIniRecommendation('register_globals', false, true);
753 |
754 | $this->addPhpIniRecommendation('session.auto_start', false);
755 |
756 | $this->addRecommendation(
757 | class_exists('PDO'),
758 | 'PDO should be installed',
759 | 'Install PDO (mandatory for Doctrine).'
760 | );
761 |
762 | if (class_exists('PDO')) {
763 | $drivers = PDO::getAvailableDrivers();
764 | $this->addRecommendation(
765 | count($drivers) > 0,
766 | sprintf('PDO should have some drivers installed (currently available: %s)', count($drivers) ? implode(', ', $drivers) : 'none'),
767 | 'Install PDO drivers (mandatory for Doctrine).'
768 | );
769 | }
770 | }
771 |
772 | /**
773 | * Loads realpath_cache_size from php.ini and converts it to int.
774 | *
775 | * (e.g. 16k is converted to 16384 int)
776 | *
777 | * @return int
778 | */
779 | protected function getRealpathCacheSize()
780 | {
781 | $size = ini_get('realpath_cache_size');
782 | $size = trim($size);
783 | $unit = '';
784 | if (!ctype_digit($size)) {
785 | $unit = strtolower(substr($size, -1, 1));
786 | $size = (int) substr($size, 0, -1);
787 | }
788 | switch ($unit) {
789 | case 'g':
790 | return $size * 1024 * 1024 * 1024;
791 | case 'm':
792 | return $size * 1024 * 1024;
793 | case 'k':
794 | return $size * 1024;
795 | default:
796 | return (int) $size;
797 | }
798 | }
799 |
800 | /**
801 | * Defines PHP required version from Symfony version.
802 | *
803 | * @return string|false The PHP required version or false if it could not be guessed
804 | */
805 | protected function getPhpRequiredVersion()
806 | {
807 | if (!file_exists($path = __DIR__.'/../composer.lock')) {
808 | return false;
809 | }
810 |
811 | $composerLock = json_decode(file_get_contents($path), true);
812 | foreach ($composerLock['packages'] as $package) {
813 | $name = $package['name'];
814 | if ('symfony/symfony' !== $name && 'symfony/http-kernel' !== $name) {
815 | continue;
816 | }
817 |
818 | return (int) $package['version'][1] > 2 ? self::REQUIRED_PHP_VERSION : self::LEGACY_REQUIRED_PHP_VERSION;
819 | }
820 |
821 | return false;
822 | }
823 | }
824 |
--------------------------------------------------------------------------------