diff --git a/.gitignore b/.gitignore index 649243bf..ed5e730e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,18 +1,31 @@ -web/bundles/ -web/packages*.json -web/providers-*.json -web/p/ -app/config/parameters.yml -app/bootstrap* -app/cache/* -app/logs/* -bin/ -build/ -vendor/ -/.settings -/.buildpath -/.project -/.idea -composer.phar -/nbproject -.php_cs.cache +/web/bundles +/web/css +/web/js +/web/composer +/web/images +/web/uploads/users/* +/web/media/cache +/web/build.js +/var/password.dat +/var/password.json +/password.json +behat.yml +/.web-server-pid +/app/config/parameters.yml +/build/ +.idea +/phpunit.xml +/var/* +/var/cache/* +!var/cache/.gitkeep +!var/hook/.gitkeep +!var/hook/* +/var/logs/* +!var/logs/.gitkeep +!/var/sessions +/var/sessions/* +!var/sessions/.gitkeep +!var/SymfonyRequirements.php +/vendor/ +/web/bundles/ +/var/bin/ diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 00000000..249cf8f0 --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/zipball/ diff --git a/app/AppKernel.php b/app/AppKernel.php index a0e3351c..4645f398 100644 --- a/app/AppKernel.php +++ b/app/AppKernel.php @@ -17,12 +17,9 @@ public function registerBundles() new Doctrine\Bundle\DoctrineCacheBundle\DoctrineCacheBundle(), new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(), new FOS\UserBundle\FOSUserBundle(), - new HWI\Bundle\OAuthBundle\HWIOAuthBundle(), new Snc\RedisBundle\SncRedisBundle(), new WhiteOctober\PagerfantaBundle\WhiteOctoberPagerfantaBundle(), - new Nelmio\SecurityBundle\NelmioSecurityBundle(), new Knp\Bundle\MenuBundle\KnpMenuBundle(), - new Nelmio\CorsBundle\NelmioCorsBundle(), new Packagist\WebBundle\PackagistWebBundle(), ); @@ -34,8 +31,29 @@ public function registerBundles() return $bundles; } + public function getRootDir() + { + return __DIR__; + } + + public function getCacheDir() + { + return dirname(__DIR__).'/var/cache/'.$this->getEnvironment(); + } + + public function getLogDir() + { + return dirname(__DIR__).'/var/logs'; + } + public function registerContainerConfiguration(LoaderInterface $loader) { - $loader->load(__DIR__.'/config/config_'.$this->getEnvironment().'.yml'); + $loader->load(function (\Symfony\Component\DependencyInjection\ContainerBuilder $container) { + $container->setParameter('container.autowiring.strict_mode', true); + $container->setParameter('container.dumper.inline_class_loader', true); + + $container->addObjectResource($this); + }); + $loader->load($this->getRootDir().'/config/config_'.$this->getEnvironment().'.yml'); } } diff --git a/app/Resources/FOSUserBundle/views/Profile/edit_content.html.twig b/app/Resources/FOSUserBundle/views/Profile/edit_content.html.twig index 0dc16820..0ee2f394 100644 --- a/app/Resources/FOSUserBundle/views/Profile/edit_content.html.twig +++ b/app/Resources/FOSUserBundle/views/Profile/edit_content.html.twig @@ -1,4 +1,4 @@ -
+{{ form_start(form, {'attr': {'class': 'fos_user_profile_edit col-md-6', 'action': path('fos_user_profile_edit') }}) }} {{ form_errors(form) }}
@@ -40,15 +40,7 @@ -
- -
Using GitHub:
- - - - {{ (app.user.githubId ? 'profile.accounts_connected' : 'profile.connect_accounts')|trans }} - - +{{ form_end(form) }}
diff --git a/app/Resources/FOSUserBundle/views/Profile/show.html.twig b/app/Resources/FOSUserBundle/views/Profile/show.html.twig index 9dd48acb..0f7bd9a6 100644 --- a/app/Resources/FOSUserBundle/views/Profile/show.html.twig +++ b/app/Resources/FOSUserBundle/views/Profile/show.html.twig @@ -4,22 +4,25 @@ {% block fos_user_content %}
+ {% set isAdmin = is_granted('ROLE_ADMIN') %} {%- if app.user.apiToken %}

{{ 'profile.your_api_token'|trans }}

- +
-

{{ 'profile.api_token_explain'|trans({ '%path_about%':path('about') })|raw }}

- -
+

You need to authenticate to access their Composer repository, for example to enter credentials run command:

+
+composer config --global --auth http-basic.{{ app.request.getHttpHost() }} {{ user.username }} {{ user.apiToken }}
+        
+

The storage can be done either globally in the COMPOSER_HOME/auth.json file


{%- endif %} - {% if is_granted('ROLE_ADMIN') %} + {% if isAdmin %} {% embed "PackagistWebBundle:Web:list.html.twig" with {noLayout: 'true', showAutoUpdateWarning: true} %} {% block content_title %}

{{ 'packages.yours'|trans }}

diff --git a/app/Resources/HWIOAuthBundle/views/Connect/login.html.twig b/app/Resources/FOSUserBundle/views/Security/login.html.twig similarity index 81% rename from app/Resources/HWIOAuthBundle/views/Connect/login.html.twig rename to app/Resources/FOSUserBundle/views/Security/login.html.twig index 173c1243..0abcccc8 100644 --- a/app/Resources/HWIOAuthBundle/views/Connect/login.html.twig +++ b/app/Resources/FOSUserBundle/views/Security/login.html.twig @@ -18,11 +18,11 @@
{% if error is defined and error is not empty %}
- {{ error }} + {{ error.messageKey|trans(error.messageData, 'security') }}
{% endif %} -
+
@@ -58,13 +58,4 @@
{% endif %} - - {% for owner in hwi_oauth_resource_owners() %} - {% if not app.user %} -
- {% endif %} -
- Login with {{ owner | trans({}, 'HWIOAuthBundle') }}{% if not loop.last %}
{% endif %} -
- {% endfor %} {% endblock %} diff --git a/app/Resources/HWIOAuthBundle/views/Connect/connect_success.html.twig b/app/Resources/HWIOAuthBundle/views/Connect/connect_success.html.twig deleted file mode 100644 index 649eb53d..00000000 --- a/app/Resources/HWIOAuthBundle/views/Connect/connect_success.html.twig +++ /dev/null @@ -1,9 +0,0 @@ -{% extends 'HWIOAuthBundle::layout.html.twig' %} - -{% block hwi_oauth_content %} -
-

GitHub Login

-

{{ 'header.success' | trans({'%name%': userInformation.realName}, 'HWIOAuthBundle') }}

-

Continue to your profile.

-
-{% endblock hwi_oauth_content %} diff --git a/app/Resources/HWIOAuthBundle/views/Connect/registration.html.twig b/app/Resources/HWIOAuthBundle/views/Connect/registration.html.twig deleted file mode 100644 index 2e95adb3..00000000 --- a/app/Resources/HWIOAuthBundle/views/Connect/registration.html.twig +++ /dev/null @@ -1,21 +0,0 @@ -{% extends 'HWIOAuthBundle::layout.html.twig' %} - -{% block hwi_oauth_content %} -
-

{{ 'header.register' | trans({'%name%': userInformation.realName}, 'HWIOAuthBundle') }}

-
-
- - {{ form_widget(form) }} -
- - {{ 'connect.registration.cancel' | trans({}, 'HWIOAuthBundle') }} -
- -
-
- {% if userInformation.profilePicture is not empty %} - - {% endif %} -
-{% endblock hwi_oauth_content %} diff --git a/app/Resources/HWIOAuthBundle/views/Connect/registration_success.html.twig b/app/Resources/HWIOAuthBundle/views/Connect/registration_success.html.twig deleted file mode 100644 index fd03e59d..00000000 --- a/app/Resources/HWIOAuthBundle/views/Connect/registration_success.html.twig +++ /dev/null @@ -1,9 +0,0 @@ -{% extends 'HWIOAuthBundle::layout.html.twig' %} - -{% block hwi_oauth_content %} -
-

GitHub Login

-

{{ 'header.registration_success' | trans({'%username%': app.user.username}, 'HWIOAuthBundle') }}

-

Continue to your profile.

-
-{% endblock hwi_oauth_content %} diff --git a/app/Resources/HWIOAuthBundle/views/layout.html.twig b/app/Resources/HWIOAuthBundle/views/layout.html.twig deleted file mode 100644 index 236d8bde..00000000 --- a/app/Resources/HWIOAuthBundle/views/layout.html.twig +++ /dev/null @@ -1,7 +0,0 @@ -{% extends 'PackagistWebBundle::layout.html.twig' %} - -{% block content %} -
- {% block hwi_oauth_content %}{% endblock %} -
-{% endblock %} diff --git a/app/autoload.php b/app/autoload.php deleted file mode 100644 index f101d984..00000000 --- a/app/autoload.php +++ /dev/null @@ -1,23 +0,0 @@ -You must set up the project dependencies by running composer install

- -EOF; - - if (PHP_SAPI === 'cli') { - $message = strip_tags($message); - } - - die($message); -} - -AnnotationRegistry::registerLoader(array($loader, 'loadClass')); - -return $loader; diff --git a/app/check.php b/app/check.php deleted file mode 100644 index c10f1ab2..00000000 --- a/app/check.php +++ /dev/null @@ -1,84 +0,0 @@ -='), sprintf('Checking that PHP version is at least 5.3.2 (%s installed)', phpversion()), 'Install PHP 5.3.2 or newer (current version is '.phpversion(), true); -check(ini_get('date.timezone'), 'Checking that the "date.timezone" setting is set', 'Set the "date.timezone" setting in php.ini (like Europe/Paris)', true); -check(is_writable(__DIR__.'/../app/cache'), sprintf('Checking that app/cache/ directory is writable'), 'Change the permissions of the app/cache/ directory so that the web server can write in it', true); -check(is_writable(__DIR__.'/../app/logs'), sprintf('Checking that the app/logs/ directory is writable'), 'Change the permissions of the app/logs/ directory so that the web server can write in it', true); -check(function_exists('json_encode'), 'Checking that the json_encode() is available', 'Install and enable the json extension', true); - -// warnings -echo_title("Optional checks"); -check(class_exists('DomDocument'), 'Checking that the PHP-XML module is installed', 'Install and enable the php-xml module', false); -check(defined('LIBXML_COMPACT'), 'Checking that the libxml version is at least 2.6.21', 'Upgrade your php-xml module with a newer libxml', false); -check(function_exists('token_get_all'), 'Checking that the token_get_all() function is available', 'Install and enable the Tokenizer extension (highly recommended)', false); -check(function_exists('mb_strlen'), 'Checking that the mb_strlen() function is available', 'Install and enable the mbstring extension', false); -check(function_exists('iconv'), 'Checking that the iconv() function is available', 'Install and enable the iconv extension', false); -check(function_exists('utf8_decode'), 'Checking that the utf8_decode() is available', 'Install and enable the XML extension', false); -check(function_exists('posix_isatty'), 'Checking that the posix_isatty() is available', 'Install and enable the php_posix extension (used to colorized the CLI output)', false); -check(class_exists('Locale'), 'Checking that the intl extension is available', 'Install and enable the intl extension (used for validators)', false); - -$accelerator = - (function_exists('apc_store') && ini_get('apc.enabled')) - || - function_exists('eaccelerator_put') && ini_get('eaccelerator.enable') - || - function_exists('xcache_set') -; -check($accelerator, 'Checking that a PHP accelerator is installed', 'Install a PHP accelerator like APC (highly recommended)', false); - -check(!ini_get('short_open_tag'), 'Checking that php.ini has short_open_tag set to off', 'Set short_open_tag to off in php.ini', false); -check(!ini_get('magic_quotes_gpc'), 'Checking that php.ini has magic_quotes_gpc set to off', 'Set magic_quotes_gpc to off in php.ini', false); -check(!ini_get('register_globals'), 'Checking that php.ini has register_globals set to off', 'Set register_globals to off in php.ini', false); -check(!ini_get('session.auto_start'), 'Checking that php.ini has session.auto_start set to off', 'Set session.auto_start to off in php.ini', false); - -echo_title("Optional checks (Doctrine)"); - -check(class_exists('PDO'), 'Checking that PDO is installed', 'Install PDO (mandatory for Doctrine)', false); -if (class_exists('PDO')) { - $drivers = PDO::getAvailableDrivers(); - check(count($drivers), 'Checking that PDO has some drivers installed: '.implode(', ', $drivers), 'Install PDO drivers (mandatory for Doctrine)'); -} - -/** - * Checks a configuration. - */ -function check($boolean, $message, $help = '', $fatal = false) -{ - echo $boolean ? " OK " : sprintf("\n\n[[%s]] ", $fatal ? ' ERROR ' : 'WARNING'); - echo sprintf("$message%s\n", $boolean ? '' : ': FAILED'); - - if (!$boolean) { - echo " *** $help ***\n"; - if ($fatal) { - die("You must fix this problem before resuming the check.\n"); - } - } -} - -function echo_title($title) -{ - echo "\n** $title **\n\n"; -} diff --git a/app/config/config.yml b/app/config/config.yml index 3efe2b65..53ebd72d 100644 --- a/app/config/config.yml +++ b/app/config/config.yml @@ -33,7 +33,6 @@ twig: debug: '%kernel.debug%' strict_variables: '%kernel.debug%' globals: - google_analytics: '%google_analytics%' packagist_host: '%packagist_host%' # Doctrine Configuration @@ -44,6 +43,7 @@ doctrine: dbname: '%database_name%' user: '%database_user%' password: '%database_password%' + port: '%database_port%' # See https://github.com/sonata-project/SonataAdminBundle/issues/3342 orm: auto_generate_proxy_classes: '%kernel.debug%' @@ -105,6 +105,7 @@ swiftmailer: password: '%mailer_password%' encryption: '%mailer_encryption%' auth_mode: '%mailer_auth_mode%' + port: '%mailer_port%' spool: { type: memory } fos_user: @@ -117,40 +118,7 @@ fos_user: sender_name: '%mailer_from_name%' profile: form: - type: packagist_user_profile - -hwi_oauth: - firewall_names: [main] - connect: - account_connector: packagist.user_provider - registration_form_handler: packagist.oauth.registration_form_handler - registration_form: packagist.oauth.registration_form - fosub: - username_iterations: 30 - properties: - github: githubId - resource_owners: - github: - type: github - client_id: '%github.client_id%' - client_secret: '%github.client_secret%' - options: - csrf: true - -nelmio_cors: - defaults: - allow_origin: ['*'] - allow_headers: ['*'] - max_age: 3600 - paths: - '^/packages/list\.json$': - allow_methods: ['GET'] - forced_allow_origin_value: '*' - '^/search\.json$': - allow_methods: ['GET'] - '^/packages/[^/]+/[^/]+\.json$': - allow_methods: ['GET'] - forced_allow_origin_value: '*' + type: Packagist\WebBundle\Form\Type\ProfileFormType packagist_web: archive: true diff --git a/app/config/config_dev.yml b/app/config/config_dev.yml index 28aa7c6d..47855aa0 100644 --- a/app/config/config_dev.yml +++ b/app/config/config_dev.yml @@ -42,9 +42,5 @@ monolog: VERBOSITY_DEBUG: DEBUG channels: ["doctrine"] -hwi_oauth: - http_client: - verify_peer: false - #assetic: # use_controller: true diff --git a/app/config/config_prod.yml b/app/config/config_prod.yml index aea91841..b219ca72 100644 --- a/app/config/config_prod.yml +++ b/app/config/config_prod.yml @@ -64,51 +64,3 @@ framework: cookie_secure: '%force_ssl%' validation: cache: '%validation_cache_backend%' - -nelmio_security: - clickjacking: - paths: - '^/.*': DENY - forced_ssl: - enabled: '%force_ssl%' - hsts_max_age: 31104000 # 1y - csp: - enabled: true - report_logger_service: logger - hosts: [] - content_types: [] - enforce: - browser_adaptive: - enabled: false - default-src: - - 'self' - script-src: - - 'self' - - 'unsafe-inline' - - 'unsafe-eval' - - 'https://cdn.jsdelivr.net/' - - 'https://ssl.google-analytics.com/' - connect-src: - - 'self' - - '*.algolia.net' - - '*.algolianet.com' - img-src: - - 'self' - - 'https://www.gravatar.com/' - - 'https://camo.githubusercontent.com/' - - 'https://user-images.githubusercontent.com/' - - 'https://raw.githubusercontent.com/' - - 'https://raw.github.com/' - - 'https://github.com/' - - 'https://gitlab.com/' - - 'https://ssl.google-analytics.com/' - - 'http://www.google-analytics.com/' - style-src: - - 'self' - - 'unsafe-inline' - - 'https://cdn.jsdelivr.net/' - - 'https://fonts.googleapis.com/' - font-src: - - 'self' - - 'https://fonts.gstatic.com/' - block-all-mixed-content: true # defaults to false, blocks HTTP content over HTTPS transport diff --git a/app/config/parameters.yml.dist b/app/config/parameters.yml.dist index 22a159cd..e256ed51 100644 --- a/app/config/parameters.yml.dist +++ b/app/config/parameters.yml.dist @@ -1,9 +1,10 @@ parameters: - database_driver: pdo_mysql + database_driver: pdo_pgsql database_host: localhost database_name: packagist - database_user: root - database_password: + database_user: postgres + database_password: ~ + database_port: ~ database_name_test: packagist_test mailer_transport: @@ -13,12 +14,9 @@ parameters: mailer_from_email: admin@example.org mailer_from_name: Admin Team mailer_encryption: tls + mailer_port: ~ mailer_auth_mode: login - # packagist_host: example.org - # router.request_context.host: '%packagist_host%' - # router.request_context.scheme: https - redis_dsn: redis://localhost/1 redis_dsn_test: redis://127.0.0.1/14 redis_session_dsn: redis://localhost/2 @@ -28,10 +26,6 @@ parameters: google_analytics: ga_key: - # set those to values obtained by creating an application at https://github.com/settings/applications - github.client_id: CHANGE_ME_IN_PROD - github.client_secret: CHANGE_ME_IN_PROD - # -- performance features -- # set both to apc to optimize things if it is available validation_cache_backend: ~ @@ -48,8 +42,5 @@ parameters: # e.g. ['.*\.?packagist\.org$'] to allow packagist.org and all subdomains as valid hosts trusted_hosts: ~ - # -- Algolia credentials -- - algolia.app_id: CHANGE_ME - algolia.admin_key: CHANGE_ME - algolia.search_key: CHANGE_ME - algolia.index_name: 'packagist' + # Host for download zip + packagist_dist_host: ~ diff --git a/app/config/routing.yml b/app/config/routing.yml index cc18a330..c73d7ca6 100644 --- a/app/config/routing.yml +++ b/app/config/routing.yml @@ -18,25 +18,5 @@ fos_user_resetting: fos_user_change_password: resource: '@FOSUserBundle/Resources/config/routing/change_password.xml' - -hwi_oauth_connect: - resource: '@HWIOAuthBundle/Resources/config/routing/connect.xml' - prefix: /connect - -# overrides the fosub /login page -hwi_oauth_login: - resource: '@HWIOAuthBundle/Resources/config/routing/login.xml' - prefix: /login - -hwi_oauth_redirect: - resource: '@HWIOAuthBundle/Resources/config/routing/redirect.xml' - prefix: /login - -github_check: - path: /login/check-github - -logout: - path: /logout - -login_check: - path: /login_check +fos_user: + resource: "@FOSUserBundle/Resources/config/routing/security.xml" diff --git a/app/config/security.yml b/app/config/security.yml index 67398fb8..9e94b275 100644 --- a/app/config/security.yml +++ b/app/config/security.yml @@ -11,14 +11,8 @@ security: firewalls: packages: - pattern: (^(/packages.json$|/p/|/zipball/|/downloads/))+ + pattern: (^(/packages.json$|/p/|/zipball/|/downloads/|/api/))+ api_basic: true - remember_me: - secret: '%remember_me.secret%' - user_providers: packagist - name: pauth - always_remember_me: true - lifetime: 31104000 # 1y main: pattern: .* @@ -36,13 +30,6 @@ security: lifetime: 31104000 # 1y logout: true anonymous: true - oauth: - resource_owners: - github: '/login/check-github' - login_path: /login - failure_path: /login - oauth_user_provider: - service: packagist.user_provider switch_user: provider: packagist @@ -56,10 +43,12 @@ security: # URL of FOSUserBundle which need to be available to anonymous users - { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY } - { path: ^/login/, role: IS_AUTHENTICATED_ANONYMOUSLY } + - { path: ^/resetting/, role: IS_AUTHENTICATED_ANONYMOUSLY } # Packagist - - { path: (^(/change-password|/profile/))+, role: ROLE_USER } + - { path: (^(/change-password|/profile/|/search|/logout|/packages/|/versions/))+, role: ROLE_USER } - { path: (^(/packages.json$|/p/|/zipball/|/downloads/))+, role: ROLE_USER } + - { path: ^/$, role: ROLE_USER } # Secured part of the site # This config requires being logged for the whole site and having the admin role for the admin part. diff --git a/app/console b/bin/console similarity index 60% rename from app/console rename to bin/console index ed6d4ad1..0629023a 100755 --- a/app/console +++ b/bin/console @@ -1,25 +1,22 @@ #!/usr/bin/env php getParameterOption(array('--env', '-e'), getenv('SYMFONY_ENV') ?: 'dev'); -$debug = getenv('SYMFONY_DEBUG') !== '0' && !$input->hasParameterOption(array('--no-debug', '')) && $env !== 'prod'; +$env = $input->getParameterOption(['--env', '-e'], getenv('SYMFONY_ENV') ?: 'dev'); +$debug = getenv('SYMFONY_DEBUG') !== '0' && !$input->hasParameterOption(['--no-debug', '']) && $env !== 'prod'; if ($debug) { Debug::enable(); diff --git a/bin/symfony_requirements b/bin/symfony_requirements new file mode 100755 index 00000000..a7bf65a1 --- /dev/null +++ b/bin/symfony_requirements @@ -0,0 +1,146 @@ +#!/usr/bin/env php +getPhpIniConfigPath(); + +echo_title('Symfony Requirements Checker'); + +echo '> PHP is using the following php.ini file:'.PHP_EOL; +if ($iniPath) { + echo_style('green', ' '.$iniPath); +} else { + echo_style('yellow', ' WARNING: No configuration file (php.ini) used by PHP!'); +} + +echo PHP_EOL.PHP_EOL; + +echo '> Checking Symfony requirements:'.PHP_EOL.' '; + +$messages = array(); +foreach ($symfonyRequirements->getRequirements() as $req) { + if ($helpText = get_error_message($req, $lineSize)) { + echo_style('red', 'E'); + $messages['error'][] = $helpText; + } else { + echo_style('green', '.'); + } +} + +$checkPassed = empty($messages['error']); + +foreach ($symfonyRequirements->getRecommendations() as $req) { + if ($helpText = get_error_message($req, $lineSize)) { + echo_style('yellow', 'W'); + $messages['warning'][] = $helpText; + } else { + echo_style('green', '.'); + } +} + +if ($checkPassed) { + echo_block('success', 'OK', 'Your system is ready to run Symfony projects'); +} else { + echo_block('error', 'ERROR', 'Your system is not ready to run Symfony projects'); + + echo_title('Fix the following mandatory requirements', 'red'); + + foreach ($messages['error'] as $helpText) { + echo ' * '.$helpText.PHP_EOL; + } +} + +if (!empty($messages['warning'])) { + echo_title('Optional recommendations to improve your setup', 'yellow'); + + foreach ($messages['warning'] as $helpText) { + echo ' * '.$helpText.PHP_EOL; + } +} + +echo PHP_EOL; +echo_style('title', 'Note'); +echo ' The command console could use a different php.ini file'.PHP_EOL; +echo_style('title', '~~~~'); +echo ' than the one used with your web server. To be on the'.PHP_EOL; +echo ' safe side, please check the requirements from your web'.PHP_EOL; +echo ' server using the '; +echo_style('yellow', 'web/config.php'); +echo ' script.'.PHP_EOL; +echo PHP_EOL; + +exit($checkPassed ? 0 : 1); + +function get_error_message(Requirement $requirement, $lineSize) +{ + if ($requirement->isFulfilled()) { + return; + } + + $errorMessage = wordwrap($requirement->getTestMessage(), $lineSize - 3, PHP_EOL.' ').PHP_EOL; + $errorMessage .= ' > '.wordwrap($requirement->getHelpText(), $lineSize - 5, PHP_EOL.' > ').PHP_EOL; + + return $errorMessage; +} + +function echo_title($title, $style = null) +{ + $style = $style ?: 'title'; + + echo PHP_EOL; + echo_style($style, $title.PHP_EOL); + echo_style($style, str_repeat('~', strlen($title)).PHP_EOL); + echo PHP_EOL; +} + +function echo_style($style, $message) +{ + // ANSI color codes + $styles = array( + 'reset' => "\033[0m", + 'red' => "\033[31m", + 'green' => "\033[32m", + 'yellow' => "\033[33m", + 'error' => "\033[37;41m", + 'success' => "\033[37;42m", + 'title' => "\033[34m", + ); + $supports = has_color_support(); + + echo($supports ? $styles[$style] : '').$message.($supports ? $styles['reset'] : ''); +} + +function echo_block($style, $title, $message) +{ + $message = ' '.trim($message).' '; + $width = strlen($message); + + echo PHP_EOL.PHP_EOL; + + echo_style($style, str_repeat(' ', $width)); + echo PHP_EOL; + echo_style($style, str_pad(' ['.$title.']', $width, ' ', STR_PAD_RIGHT)); + echo PHP_EOL; + echo_style($style, $message); + echo PHP_EOL; + echo_style($style, str_repeat(' ', $width)); + echo PHP_EOL; +} + +function has_color_support() +{ + static $support; + + if (null === $support) { + if (DIRECTORY_SEPARATOR == '\\') { + $support = false !== getenv('ANSICON') || 'ON' === getenv('ConEmuANSI'); + } else { + $support = function_exists('posix_isatty') && @posix_isatty(STDOUT); + } + } + + return $support; +} diff --git a/composer.json b/composer.json index 2dad07f1..ca5fc6f9 100644 --- a/composer.json +++ b/composer.json @@ -31,8 +31,8 @@ }, "require": { "php": ">=7.0", - "symfony/symfony": "^2.8", - "doctrine/orm": "^2.4", + "symfony/symfony": "^3.4", + "doctrine/orm": "^2.6", "doctrine/doctrine-bundle": "^1.2", "doctrine/doctrine-cache-bundle": "^1.3", "twig/extensions": "^1.0", @@ -44,9 +44,8 @@ "jms/security-extra-bundle": "^1.5", "jms/di-extra-bundle": "^1.4", "oro/doctrine-extensions": "^1.2", - "composer/composer": "^1.3@dev", - "friendsofsymfony/user-bundle": "^2.0@dev", - "nelmio/security-bundle": "^2.4", + "composer/composer": "^1.6", + "friendsofsymfony/user-bundle": "^2.1", "predis/predis": "^1.0", "snc/redis-bundle": "^2.0", "white-october/pagerfanta-bundle": "^1.0", @@ -56,30 +55,32 @@ "pagerfanta/pagerfanta": "^1.0", "knplabs/knp-menu-bundle": "^2.1", "ezyang/htmlpurifier": "^4.6", - "nelmio/cors-bundle": "^1.4", "cebe/markdown": "^1.1", - "algolia/algoliasearch-client-php": "^1.18", "seld/signal-handler": "^1.1" }, - "_comment": ["fos user bundle 2.0.0 tag needed"], "require-dev": { "symfony/phpunit-bridge": "^2.7 || ^3.0", "phpunit/phpunit": "^6.5" }, "scripts": { - "post-install-cmd": [ + "symfony-scripts": [ "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::buildBootstrap", "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::clearCache", - "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets" + "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets", + "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installRequirementsFile", + "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::prepareDeploymentTarget" + ], + "post-install-cmd": [ + "@symfony-scripts" ], "post-update-cmd": [ - "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::buildBootstrap", - "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::clearCache", - "Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets" + "@symfony-scripts" ] }, "extra": { "symfony-app-dir": "app", + "symfony-bin-dir": "bin", + "symfony-var-dir": "var", "symfony-web-dir": "web", "symfony-assets-install": "symlink" } diff --git a/composer.lock b/composer.lock index 2597220e..66ac9357 100644 --- a/composer.lock +++ b/composer.lock @@ -4,71 +4,20 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "42db6730d583728ee1aef7f053b4a196", + "content-hash": "05de88095f996480c00ec77c2893fb7b", "packages": [ - { - "name": "algolia/algoliasearch-client-php", - "version": "1.20.0", - "source": { - "type": "git", - "url": "https://github.com/algolia/algoliasearch-client-php.git", - "reference": "3daee8d55c1d84eff227fd99054e78ddc196f309" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/algolia/algoliasearch-client-php/zipball/3daee8d55c1d84eff227fd99054e78ddc196f309", - "reference": "3daee8d55c1d84eff227fd99054e78ddc196f309", - "shasum": "" - }, - "require": { - "ext-mbstring": "*", - "php": ">=5.3" - }, - "require-dev": { - "phpunit/phpunit": "^4.8 || ^5.0", - "satooshi/php-coveralls": "0.6.*" - }, - "type": "library", - "autoload": { - "psr-0": { - "AlgoliaSearch": "src/", - "AlgoliaSearch\\Tests": "tests/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Algolia Team", - "email": "contact@algolia.com" - }, - { - "name": "Ryan T. Catlin", - "email": "ryan.catlin@gmail.com" - }, - { - "name": "Jonathan H. Wage", - "email": "jonwage@gmail.com" - } - ], - "description": "Algolia Search API Client for PHP", - "homepage": "https://github.com/algolia/algoliasearch-client-php", - "time": "2017-08-30T08:28:40+00:00" - }, { "name": "cebe/markdown", - "version": "1.1.1", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/cebe/markdown.git", - "reference": "c30eb5e01fe021cc5bba2f9ee0eeef96d4931166" + "reference": "9bac5e971dd391e2802dca5400bbeacbaea9eb86" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cebe/markdown/zipball/c30eb5e01fe021cc5bba2f9ee0eeef96d4931166", - "reference": "c30eb5e01fe021cc5bba2f9ee0eeef96d4931166", + "url": "https://api.github.com/repos/cebe/markdown/zipball/9bac5e971dd391e2802dca5400bbeacbaea9eb86", + "reference": "9bac5e971dd391e2802dca5400bbeacbaea9eb86", "shasum": "" }, "require": { @@ -86,7 +35,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1.x-dev" + "dev-master": "1.2.x-dev" } }, "autoload": { @@ -115,7 +64,7 @@ "markdown", "markdown-extra" ], - "time": "2016-09-14T20:40:20+00:00" + "time": "2018-03-26T11:24:36+00:00" }, { "name": "composer/ca-bundle", @@ -175,23 +124,22 @@ }, { "name": "composer/composer", - "version": "dev-master", + "version": "1.6.5", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "22025f2e29dbcae962efaec49e3c8677edde8a6f" + "reference": "b184a92419cc9a9c4c6a09db555a94d441cb11c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/22025f2e29dbcae962efaec49e3c8677edde8a6f", - "reference": "22025f2e29dbcae962efaec49e3c8677edde8a6f", + "url": "https://api.github.com/repos/composer/composer/zipball/b184a92419cc9a9c4c6a09db555a94d441cb11c9", + "reference": "b184a92419cc9a9c4c6a09db555a94d441cb11c9", "shasum": "" }, "require": { "composer/ca-bundle": "^1.0", "composer/semver": "^1.0", "composer/spdx-licenses": "^1.2", - "composer/xdebug-handler": "^1.1", "justinrainbow/json-schema": "^3.0 || ^4.0 || ^5.0", "php": "^5.3.2 || ^7.0", "psr/log": "^1.0", @@ -221,7 +169,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.7-dev" + "dev-master": "1.6-dev" } }, "autoload": { @@ -252,7 +200,7 @@ "dependency", "package" ], - "time": "2018-05-04T09:47:45+00:00" + "time": "2018-05-04T09:44:59+00:00" }, { "name": "composer/semver", @@ -377,64 +325,23 @@ ], "time": "2018-04-30T10:33:04+00:00" }, - { - "name": "composer/xdebug-handler", - "version": "1.1.0", - "source": { - "type": "git", - "url": "https://github.com/composer/xdebug-handler.git", - "reference": "c919dc6c62e221fc6406f861ea13433c0aa24f08" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/c919dc6c62e221fc6406f861ea13433c0aa24f08", - "reference": "c919dc6c62e221fc6406f861ea13433c0aa24f08", - "shasum": "" - }, - "require": { - "php": "^5.3.2 || ^7.0", - "psr/log": "^1.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5" - }, - "type": "library", - "autoload": { - "psr-4": { - "Composer\\XdebugHandler\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "John Stevenson", - "email": "john-stevenson@blueyonder.co.uk" - } - ], - "description": "Restarts a process without xdebug.", - "keywords": [ - "Xdebug", - "performance" - ], - "time": "2018-04-11T15:42:36+00:00" - }, { "name": "container-interop/container-interop", - "version": "1.1.0", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/container-interop/container-interop.git", - "reference": "fc08354828f8fd3245f77a66b9e23a6bca48297e" + "reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/container-interop/container-interop/zipball/fc08354828f8fd3245f77a66b9e23a6bca48297e", - "reference": "fc08354828f8fd3245f77a66b9e23a6bca48297e", + "url": "https://api.github.com/repos/container-interop/container-interop/zipball/79cbf1341c22ec75643d841642dd5d6acd83bdb8", + "reference": "79cbf1341c22ec75643d841642dd5d6acd83bdb8", "shasum": "" }, + "require": { + "psr/container": "^1.0" + }, "type": "library", "autoload": { "psr-4": { @@ -446,34 +353,35 @@ "MIT" ], "description": "Promoting the interoperability of container objects (DIC, SL, etc.)", - "time": "2014-12-30T15:22:37+00:00" + "homepage": "https://github.com/container-interop/container-interop", + "time": "2017-02-14T19:40:03+00:00" }, { "name": "doctrine/annotations", - "version": "v1.4.0", + "version": "v1.6.0", "source": { "type": "git", "url": "https://github.com/doctrine/annotations.git", - "reference": "54cacc9b81758b14e3ce750f205a393d52339e97" + "reference": "c7f2050c68a9ab0bdb0f98567ec08d80ea7d24d5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/54cacc9b81758b14e3ce750f205a393d52339e97", - "reference": "54cacc9b81758b14e3ce750f205a393d52339e97", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/c7f2050c68a9ab0bdb0f98567ec08d80ea7d24d5", + "reference": "c7f2050c68a9ab0bdb0f98567ec08d80ea7d24d5", "shasum": "" }, "require": { "doctrine/lexer": "1.*", - "php": "^5.6 || ^7.0" + "php": "^7.1" }, "require-dev": { "doctrine/cache": "1.*", - "phpunit/phpunit": "^5.7" + "phpunit/phpunit": "^6.4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.4.x-dev" + "dev-master": "1.6.x-dev" } }, "autoload": { @@ -514,37 +422,41 @@ "docblock", "parser" ], - "time": "2017-02-24T16:22:25+00:00" + "time": "2017-12-06T07:11:42+00:00" }, { "name": "doctrine/cache", - "version": "v1.6.2", + "version": "v1.7.1", "source": { "type": "git", "url": "https://github.com/doctrine/cache.git", - "reference": "eb152c5100571c7a45470ff2a35095ab3f3b900b" + "reference": "b3217d58609e9c8e661cd41357a54d926c4a2a1a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/cache/zipball/eb152c5100571c7a45470ff2a35095ab3f3b900b", - "reference": "eb152c5100571c7a45470ff2a35095ab3f3b900b", + "url": "https://api.github.com/repos/doctrine/cache/zipball/b3217d58609e9c8e661cd41357a54d926c4a2a1a", + "reference": "b3217d58609e9c8e661cd41357a54d926c4a2a1a", "shasum": "" }, "require": { - "php": "~5.5|~7.0" + "php": "~7.1" }, "conflict": { "doctrine/common": ">2.2,<2.4" }, "require-dev": { - "phpunit/phpunit": "~4.8|~5.0", - "predis/predis": "~1.0", - "satooshi/php-coveralls": "~0.6" + "alcaeus/mongo-php-adapter": "^1.1", + "mongodb/mongodb": "^1.1", + "phpunit/phpunit": "^5.7", + "predis/predis": "~1.0" + }, + "suggest": { + "alcaeus/mongo-php-adapter": "Required to use legacy MongoDB driver" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.6.x-dev" + "dev-master": "1.7.x-dev" } }, "autoload": { @@ -584,24 +496,24 @@ "cache", "caching" ], - "time": "2017-07-22T12:49:21+00:00" + "time": "2017-08-25T07:02:50+00:00" }, { "name": "doctrine/collections", - "version": "v1.4.0", + "version": "v1.5.0", "source": { "type": "git", "url": "https://github.com/doctrine/collections.git", - "reference": "1a4fb7e902202c33cce8c55989b945612943c2ba" + "reference": "a01ee38fcd999f34d9bfbcee59dbda5105449cbf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/collections/zipball/1a4fb7e902202c33cce8c55989b945612943c2ba", - "reference": "1a4fb7e902202c33cce8c55989b945612943c2ba", + "url": "https://api.github.com/repos/doctrine/collections/zipball/a01ee38fcd999f34d9bfbcee59dbda5105449cbf", + "reference": "a01ee38fcd999f34d9bfbcee59dbda5105449cbf", "shasum": "" }, "require": { - "php": "^5.6 || ^7.0" + "php": "^7.1" }, "require-dev": { "doctrine/coding-standard": "~0.1@dev", @@ -651,37 +563,43 @@ "collections", "iterator" ], - "time": "2017-01-03T10:49:41+00:00" + "time": "2017-07-22T10:37:32+00:00" }, { "name": "doctrine/common", - "version": "v2.7.3", + "version": "v2.9.0", "source": { "type": "git", "url": "https://github.com/doctrine/common.git", - "reference": "4acb8f89626baafede6ee5475bc5844096eba8a9" + "reference": "a210246d286c77d2b89040f8691ba7b3a713d2c1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/common/zipball/4acb8f89626baafede6ee5475bc5844096eba8a9", - "reference": "4acb8f89626baafede6ee5475bc5844096eba8a9", + "url": "https://api.github.com/repos/doctrine/common/zipball/a210246d286c77d2b89040f8691ba7b3a713d2c1", + "reference": "a210246d286c77d2b89040f8691ba7b3a713d2c1", "shasum": "" }, "require": { - "doctrine/annotations": "1.*", - "doctrine/cache": "1.*", - "doctrine/collections": "1.*", - "doctrine/inflector": "1.*", - "doctrine/lexer": "1.*", - "php": "~5.6|~7.0" + "doctrine/annotations": "^1.0", + "doctrine/cache": "^1.0", + "doctrine/collections": "^1.0", + "doctrine/event-manager": "^1.0", + "doctrine/inflector": "^1.0", + "doctrine/lexer": "^1.0", + "doctrine/persistence": "^1.0", + "doctrine/reflection": "^1.0", + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "^5.4.6" + "doctrine/coding-standard": "^1.0", + "phpunit/phpunit": "^6.3", + "squizlabs/php_codesniffer": "^3.0", + "symfony/phpunit-bridge": "^4.0.5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.7.x-dev" + "dev-master": "2.9.x-dev" } }, "autoload": { @@ -713,10 +631,14 @@ { "name": "Johannes Schmitt", "email": "schmittjoh@gmail.com" + }, + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" } ], "description": "Common Library for Doctrine projects", - "homepage": "http://www.doctrine-project.org", + "homepage": "https://www.doctrine-project.org", "keywords": [ "annotations", "collections", @@ -724,29 +646,36 @@ "persistence", "spl" ], - "time": "2017-07-22T08:35:12+00:00" + "time": "2018-07-12T21:16:12+00:00" }, { "name": "doctrine/dbal", - "version": "v2.5.13", + "version": "v2.8.0", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "729340d8d1eec8f01bff708e12e449a3415af873" + "reference": "5140a64c08b4b607b9bedaae0cedd26f04a0e621" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/729340d8d1eec8f01bff708e12e449a3415af873", - "reference": "729340d8d1eec8f01bff708e12e449a3415af873", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/5140a64c08b4b607b9bedaae0cedd26f04a0e621", + "reference": "5140a64c08b4b607b9bedaae0cedd26f04a0e621", "shasum": "" }, "require": { - "doctrine/common": ">=2.4,<2.8-dev", - "php": ">=5.3.2" + "doctrine/cache": "^1.0", + "doctrine/event-manager": "^1.0", + "ext-pdo": "*", + "php": "^7.1" }, "require-dev": { - "phpunit/phpunit": "4.*", - "symfony/console": "2.*||^3.0" + "doctrine/coding-standard": "^4.0", + "jetbrains/phpstorm-stubs": "^2018.1.2", + "phpstan/phpstan": "^0.10.1", + "phpunit/phpunit": "^7.1.2", + "phpunit/phpunit-mock-objects": "!=3.2.4,!=3.2.5", + "symfony/console": "^2.0.5|^3.0|^4.0", + "symfony/phpunit-bridge": "^3.4.5|^4.0.5" }, "suggest": { "symfony/console": "For helpful console commands such as SQL execution and import of files." @@ -757,7 +686,8 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.5.x-dev" + "dev-master": "2.8.x-dev", + "dev-develop": "3.0.x-dev" } }, "autoload": { @@ -795,20 +725,20 @@ "persistence", "queryobject" ], - "time": "2017-07-22T20:44:48+00:00" + "time": "2018-07-13T03:16:35+00:00" }, { "name": "doctrine/doctrine-bundle", - "version": "1.8.1", + "version": "1.9.1", "source": { "type": "git", "url": "https://github.com/doctrine/DoctrineBundle.git", - "reference": "eb6e4fb904a459be28872765ab6e2d246aac7c87" + "reference": "703fad32e4c8cbe609caf45a71a1d4266c830f0f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/eb6e4fb904a459be28872765ab6e2d246aac7c87", - "reference": "eb6e4fb904a459be28872765ab6e2d246aac7c87", + "url": "https://api.github.com/repos/doctrine/DoctrineBundle/zipball/703fad32e4c8cbe609caf45a71a1d4266c830f0f", + "reference": "703fad32e4c8cbe609caf45a71a1d4266c830f0f", "shasum": "" }, "require": { @@ -819,13 +749,13 @@ "symfony/console": "~2.7|~3.0|~4.0", "symfony/dependency-injection": "~2.7|~3.0|~4.0", "symfony/doctrine-bridge": "~2.7|~3.0|~4.0", - "symfony/framework-bundle": "~2.7|~3.0|~4.0" + "symfony/framework-bundle": "^2.7.22|~3.0|~4.0" }, "conflict": { "symfony/http-foundation": "<2.6" }, "require-dev": { - "doctrine/orm": "~2.3", + "doctrine/orm": "~2.4", "phpunit/phpunit": "^4.8.36|^5.7|^6.4", "satooshi/php-coveralls": "^1.0", "symfony/phpunit-bridge": "~2.7|~3.0|~4.0", @@ -880,43 +810,43 @@ "orm", "persistence" ], - "time": "2017-11-24T13:09:19+00:00" + "time": "2018-04-19T14:07:39+00:00" }, { "name": "doctrine/doctrine-cache-bundle", - "version": "1.3.2", + "version": "1.3.3", "source": { "type": "git", "url": "https://github.com/doctrine/DoctrineCacheBundle.git", - "reference": "9baecbd6bfdd1123b0cf8c1b88fee0170a84ddd1" + "reference": "4c8e363f96427924e7e519c5b5119b4f54512697" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/DoctrineCacheBundle/zipball/9baecbd6bfdd1123b0cf8c1b88fee0170a84ddd1", - "reference": "9baecbd6bfdd1123b0cf8c1b88fee0170a84ddd1", + "url": "https://api.github.com/repos/doctrine/DoctrineCacheBundle/zipball/4c8e363f96427924e7e519c5b5119b4f54512697", + "reference": "4c8e363f96427924e7e519c5b5119b4f54512697", "shasum": "" }, "require": { "doctrine/cache": "^1.4.2", "doctrine/inflector": "~1.0", "php": ">=5.3.2", - "symfony/doctrine-bridge": "~2.2|~3.0|~4.0" + "symfony/doctrine-bridge": "~2.7|~3.3|~4.0" }, "require-dev": { "instaclick/coding-standard": "~1.1", "instaclick/object-calisthenics-sniffs": "dev-master", "instaclick/symfony2-coding-standard": "dev-remaster", - "phpunit/phpunit": "~4", + "phpunit/phpunit": "~4|~5", "predis/predis": "~0.8", "satooshi/php-coveralls": "^1.0", "squizlabs/php_codesniffer": "~1.5", - "symfony/console": "~2.2|~3.0|~4.0", - "symfony/finder": "~2.2|~3.0|~4.0", - "symfony/framework-bundle": "~2.2|~3.0|~4.0", - "symfony/phpunit-bridge": "~2.7|~3.0|~4.0", - "symfony/security-acl": "~2.3|~3.0", - "symfony/validator": "~2.2|~3.0|~4.0", - "symfony/yaml": "~2.2|~3.0|~4.0" + "symfony/console": "~2.7|~3.3|~4.0", + "symfony/finder": "~2.7|~3.3|~4.0", + "symfony/framework-bundle": "~2.7|~3.3|~4.0", + "symfony/phpunit-bridge": "~2.7|~3.3|~4.0", + "symfony/security-acl": "~2.7|~3.3", + "symfony/validator": "~2.7|~3.3|~4.0", + "symfony/yaml": "~2.7|~3.3|~4.0" }, "suggest": { "symfony/security-acl": "For using this bundle to cache ACLs" @@ -968,24 +898,98 @@ "cache", "caching" ], - "time": "2017-10-12T17:23:29+00:00" + "time": "2018-03-27T09:22:12+00:00" + }, + { + "name": "doctrine/event-manager", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/doctrine/event-manager.git", + "reference": "a520bc093a0170feeb6b14e9d83f3a14452e64b3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/event-manager/zipball/a520bc093a0170feeb6b14e9d83f3a14452e64b3", + "reference": "a520bc093a0170feeb6b14e9d83f3a14452e64b3", + "shasum": "" + }, + "require": { + "php": "^7.1" + }, + "conflict": { + "doctrine/common": "<2.9@dev" + }, + "require-dev": { + "doctrine/coding-standard": "^4.0", + "phpunit/phpunit": "^7.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Common\\": "lib/Doctrine/Common" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + }, + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" + } + ], + "description": "Doctrine Event Manager component", + "homepage": "https://www.doctrine-project.org/projects/event-manager.html", + "keywords": [ + "event", + "eventdispatcher", + "eventmanager" + ], + "time": "2018-06-11T11:59:03+00:00" }, { "name": "doctrine/inflector", - "version": "v1.2.0", + "version": "v1.3.0", "source": { "type": "git", "url": "https://github.com/doctrine/inflector.git", - "reference": "e11d84c6e018beedd929cff5220969a3c6d1d462" + "reference": "5527a48b7313d15261292c149e55e26eae771b0a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/inflector/zipball/e11d84c6e018beedd929cff5220969a3c6d1d462", - "reference": "e11d84c6e018beedd929cff5220969a3c6d1d462", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/5527a48b7313d15261292c149e55e26eae771b0a", + "reference": "5527a48b7313d15261292c149e55e26eae771b0a", "shasum": "" }, "require": { - "php": "^7.0" + "php": "^7.1" }, "require-dev": { "phpunit/phpunit": "^6.2" @@ -993,7 +997,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2.x-dev" + "dev-master": "1.3.x-dev" } }, "autoload": { @@ -1035,36 +1039,36 @@ "singularize", "string" ], - "time": "2017-07-22T12:18:28+00:00" + "time": "2018-01-09T20:05:19+00:00" }, { "name": "doctrine/instantiator", - "version": "1.0.5", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" + "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", - "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", + "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", "shasum": "" }, "require": { - "php": ">=5.3,<8.0-DEV" + "php": "^7.1" }, "require-dev": { "athletic/athletic": "~0.1.8", "ext-pdo": "*", "ext-phar": "*", - "phpunit/phpunit": "~4.0", - "squizlabs/php_codesniffer": "~2.0" + "phpunit/phpunit": "^6.2.3", + "squizlabs/php_codesniffer": "^3.0.2" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.2.x-dev" } }, "autoload": { @@ -1089,7 +1093,7 @@ "constructor", "instantiate" ], - "time": "2015-06-14T21:17:01+00:00" + "time": "2017-07-22T11:58:36+00:00" }, { "name": "doctrine/lexer", @@ -1147,38 +1151,40 @@ }, { "name": "doctrine/orm", - "version": "v2.5.14", + "version": "v2.6.2", "source": { "type": "git", "url": "https://github.com/doctrine/doctrine2.git", - "reference": "810a7baf81462a5ddf10e8baa8cb94b6eec02754" + "reference": "d2b4dd71d2a276edd65d0c170375b445f8a4a4a8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/doctrine2/zipball/810a7baf81462a5ddf10e8baa8cb94b6eec02754", - "reference": "810a7baf81462a5ddf10e8baa8cb94b6eec02754", + "url": "https://api.github.com/repos/doctrine/doctrine2/zipball/d2b4dd71d2a276edd65d0c170375b445f8a4a4a8", + "reference": "d2b4dd71d2a276edd65d0c170375b445f8a4a4a8", "shasum": "" }, "require": { - "doctrine/cache": "~1.4", - "doctrine/collections": "~1.2", - "doctrine/common": ">=2.5-dev,<2.9-dev", - "doctrine/dbal": ">=2.5-dev,<2.7-dev", - "doctrine/instantiator": "^1.0.1", + "doctrine/annotations": "~1.5", + "doctrine/cache": "~1.6", + "doctrine/collections": "^1.4", + "doctrine/common": "^2.7.1", + "doctrine/dbal": "^2.6", + "doctrine/instantiator": "~1.1", "ext-pdo": "*", - "php": ">=5.4", - "symfony/console": "~2.5|~3.0|~4.0" + "php": "^7.1", + "symfony/console": "~3.0|~4.0" }, "require-dev": { - "phpunit/phpunit": "~4.0", - "symfony/yaml": "~2.3|~3.0|~4.0" + "doctrine/coding-standard": "^1.0", + "phpunit/phpunit": "^6.5", + "squizlabs/php_codesniffer": "^3.2", + "symfony/yaml": "~3.4|~4.0" }, "suggest": { "symfony/yaml": "If you want to use YAML Metadata Mapping Driver" }, "bin": [ - "bin/doctrine", - "bin/doctrine.php" + "bin/doctrine" ], "type": "library", "extra": { @@ -1187,8 +1193,8 @@ } }, "autoload": { - "psr-0": { - "Doctrine\\ORM\\": "lib/" + "psr-4": { + "Doctrine\\ORM\\": "lib/Doctrine/ORM" } }, "notification-url": "https://packagist.org/downloads/", @@ -1211,6 +1217,10 @@ { "name": "Jonathan Wage", "email": "jonwage@gmail.com" + }, + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" } ], "description": "Object-Relational-Mapper for PHP", @@ -1219,100 +1229,122 @@ "database", "orm" ], - "time": "2017-12-17T02:57:51+00:00" + "time": "2018-07-12T20:47:13+00:00" }, { - "name": "ezyang/htmlpurifier", - "version": "v4.10.0", + "name": "doctrine/persistence", + "version": "v1.0.0", "source": { "type": "git", - "url": "https://github.com/ezyang/htmlpurifier.git", - "reference": "d85d39da4576a6934b72480be6978fb10c860021" + "url": "https://github.com/doctrine/persistence.git", + "reference": "17896f6d56a2794a1619e019596ae627aabd8fd5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/d85d39da4576a6934b72480be6978fb10c860021", - "reference": "d85d39da4576a6934b72480be6978fb10c860021", + "url": "https://api.github.com/repos/doctrine/persistence/zipball/17896f6d56a2794a1619e019596ae627aabd8fd5", + "reference": "17896f6d56a2794a1619e019596ae627aabd8fd5", "shasum": "" }, "require": { - "php": ">=5.2" + "doctrine/annotations": "^1.0", + "doctrine/cache": "^1.0", + "doctrine/collections": "^1.0", + "doctrine/event-manager": "^1.0", + "doctrine/reflection": "^1.0", + "php": "^7.1" + }, + "conflict": { + "doctrine/common": "<2.9@dev" }, "require-dev": { - "simpletest/simpletest": "^1.1" + "doctrine/coding-standard": "^4.0", + "phpstan/phpstan": "^0.8", + "phpunit/phpunit": "^7.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, "autoload": { - "psr-0": { - "HTMLPurifier": "library/" - }, - "files": [ - "library/HTMLPurifier.composer.php" - ] + "psr-4": { + "Doctrine\\Common\\": "lib/Doctrine/Common" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "LGPL" + "MIT" ], "authors": [ { - "name": "Edward Z. Yang", - "email": "admin@htmlpurifier.org", - "homepage": "http://ezyang.com" + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + }, + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" } ], - "description": "Standards compliant HTML filter written in PHP", - "homepage": "http://htmlpurifier.org/", + "description": "Doctrine Persistence abstractions.", + "homepage": "https://doctrine-project.org/projects/persistence.html", "keywords": [ - "html" + "persistence" ], - "time": "2018-02-23T01:58:20+00:00" + "time": "2018-06-14T18:57:48+00:00" }, { - "name": "friendsofsymfony/user-bundle", - "version": "dev-master", + "name": "doctrine/reflection", + "version": "v1.0.0", "source": { "type": "git", - "url": "https://github.com/FriendsOfSymfony/FOSUserBundle.git", - "reference": "528f0a93aebb641a0bc6471cc24562fbd01432cb" + "url": "https://github.com/doctrine/reflection.git", + "reference": "02538d3f95e88eb397a5f86274deb2c6175c2ab6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/FriendsOfSymfony/FOSUserBundle/zipball/528f0a93aebb641a0bc6471cc24562fbd01432cb", - "reference": "528f0a93aebb641a0bc6471cc24562fbd01432cb", + "url": "https://api.github.com/repos/doctrine/reflection/zipball/02538d3f95e88eb397a5f86274deb2c6175c2ab6", + "reference": "02538d3f95e88eb397a5f86274deb2c6175c2ab6", "shasum": "" }, "require": { - "php": ">=5.3.9", - "symfony/form": "~2.3|~3.0", - "symfony/framework-bundle": "~2.3|~3.0", - "symfony/security-bundle": "~2.3|~3.0", - "symfony/twig-bundle": "~2.3|~3.0" - }, - "conflict": { - "symfony/doctrine-bridge": "<2.3" + "doctrine/annotations": "^1.0", + "ext-tokenizer": "*", + "php": "^7.1" }, "require-dev": { - "doctrine/doctrine-bundle": "~1.3", - "swiftmailer/swiftmailer": "~4.3|~5", - "symfony/console": "~2.3|~3.0", - "symfony/phpunit-bridge": "~2.7|~3.0", - "symfony/validator": "~2.3|~3.0", - "symfony/yaml": "~2.3|~3.0", - "willdurand/propel-typehintable-behavior": "~1.0" - }, - "suggest": { - "willdurand/propel-typehintable-behavior": "Needed when using the propel implementation" + "doctrine/coding-standard": "^4.0", + "doctrine/common": "^2.8", + "phpstan/phpstan": "^0.9.2", + "phpstan/phpstan-phpunit": "^0.9.4", + "phpunit/phpunit": "^7.0", + "squizlabs/php_codesniffer": "^3.0" }, - "type": "symfony-bundle", + "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "1.0.x-dev" } }, "autoload": { "psr-4": { - "FOS\\UserBundle\\": "" + "Doctrine\\Common\\": "lib/Doctrine/Common" } }, "notification-url": "https://packagist.org/downloads/", @@ -1321,75 +1353,115 @@ ], "authors": [ { - "name": "Christophe Coevoet", - "email": "stof@notk.org" + "name": "Roman Borschel", + "email": "roman@code-factory.org" }, { - "name": "FriendsOfSymfony Community", - "homepage": "https://github.com/friendsofsymfony/FOSUserBundle/contributors" - }, + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, { - "name": "Thibault Duplessis", - "email": "thibault.duplessis@gmail.com" + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + }, + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com" } ], - "description": "Symfony FOSUserBundle", - "homepage": "http://friendsofsymfony.github.com", + "description": "Doctrine Reflection component", + "homepage": "https://www.doctrine-project.org/projects/reflection.html", "keywords": [ - "User management" + "reflection" ], - "time": "2016-09-09T10:00:40+00:00" + "time": "2018-06-14T14:45:07+00:00" }, { - "name": "hwi/oauth-bundle", - "version": "0.4.2", + "name": "ezyang/htmlpurifier", + "version": "v4.10.0", "source": { "type": "git", - "url": "https://github.com/hwi/HWIOAuthBundle.git", - "reference": "2554f2b2947d1614d9e8b04800967b175b0afd8a" + "url": "https://github.com/ezyang/htmlpurifier.git", + "reference": "d85d39da4576a6934b72480be6978fb10c860021" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/hwi/HWIOAuthBundle/zipball/2554f2b2947d1614d9e8b04800967b175b0afd8a", - "reference": "2554f2b2947d1614d9e8b04800967b175b0afd8a", + "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/d85d39da4576a6934b72480be6978fb10c860021", + "reference": "d85d39da4576a6934b72480be6978fb10c860021", "shasum": "" }, "require": { - "kriswallsmith/buzz": "~0.13", - "php": ">=5.3.3", - "symfony/form": "~2.3", - "symfony/framework-bundle": "~2.3", - "symfony/options-resolver": "~2.3", - "symfony/security-bundle": "~2.3", - "symfony/yaml": "~2.3" - }, - "conflict": { - "twig/twig": "<1.12" + "php": ">=5.2" }, "require-dev": { - "doctrine/orm": "~2.3", - "friendsofsymfony/user-bundle": "~1.3|~2.0", - "phpunit/phpunit": "~4.8|~5.0", - "symfony/phpunit-bridge": "~2.7", - "symfony/property-access": "~2.3", - "symfony/twig-bundle": "~2.3", - "symfony/validator": "~2.3" + "simpletest/simpletest": "^1.1" }, - "suggest": { - "doctrine/doctrine-bundle": "to use Doctrine user provider", - "friendsofsymfony/user-bundle": "to connect FOSUB with this bundle", - "symfony/property-access": "to use FOSUB integration with this bundle", - "symfony/twig-bundle": "to use the Twig hwi_oauth_* functions" + "type": "library", + "autoload": { + "psr-0": { + "HTMLPurifier": "library/" + }, + "files": [ + "library/HTMLPurifier.composer.php" + ] }, - "type": "symfony-bundle", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL" + ], + "authors": [ + { + "name": "Edward Z. Yang", + "email": "admin@htmlpurifier.org", + "homepage": "http://ezyang.com" + } + ], + "description": "Standards compliant HTML filter written in PHP", + "homepage": "http://htmlpurifier.org/", + "keywords": [ + "html" + ], + "time": "2018-02-23T01:58:20+00:00" + }, + { + "name": "fig/link-util", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/link-util.git", + "reference": "1a07821801a148be4add11ab0603e4af55a72fac" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/link-util/zipball/1a07821801a148be4add11ab0603e4af55a72fac", + "reference": "1a07821801a148be4add11ab0603e4af55a72fac", + "shasum": "" + }, + "require": { + "php": ">=5.5.0", + "psr/link": "~1.0@dev" + }, + "require-dev": { + "phpunit/phpunit": "^5.1", + "squizlabs/php_codesniffer": "^2.3.1" + }, + "type": "library", "extra": { "branch-alias": { - "dev-master": "0.4-dev" + "dev-master": "1.0.x-dev" } }, "autoload": { "psr-4": { - "HWI\\Bundle\\OAuthBundle\\": "" + "Fig\\Link\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -1398,109 +1470,71 @@ ], "authors": [ { - "name": "Contributors", - "homepage": "https://github.com/hwi/HWIOAuthBundle/contributors" - }, - { - "name": "Joseph Bielawski", - "email": "stloyd@gmail.com" - }, - { - "name": "Alexander", - "email": "iam.asm89@gmail.com" - }, - { - "name": "Geoffrey Bachelet", - "email": "geoffrey.bachelet@gmail.com" + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" } ], - "description": "Support for authenticating users using both OAuth1.0a and OAuth2 in Symfony2.", - "homepage": "http://github.com/hwi/HWIOAuthBundle", + "description": "Common utility implementations for HTTP links", "keywords": [ - "37signals", - "Authentication", - "Deezer", - "EVE Online", - "amazon", - "auth0", - "azure", - "bitbucket", - "bitly", - "box", - "bufferapp", - "dailymotion", - "deviantart", - "discogs", - "disqus", - "dropbox", - "eventbrite", - "facebook", - "firewall", - "fiware", - "flickr", - "foursquare", - "github", - "google", - "hubic", - "instagram", - "jira", - "linkedin", - "mail.ru", - "oauth", - "oauth1", - "oauth2", - "odnoklassniki", - "paypal", - "qq", - "reddit", - "runkeeper", - "salesforce", - "security", - "sensio connect", - "sina weibo", - "slack", - "sound cloud", - "spotify", - "stack exchange", - "stereomood", - "strava", - "toshl", - "trakt", - "trello", - "twitch", - "twitter", - "vkontakte", - "wechat", - "windows live", - "wordpress", - "xing", - "yahoo", - "yandex", - "youtube" - ], - "time": "2016-07-27T14:43:30+00:00" + "http", + "http-link", + "link", + "psr", + "psr-13", + "rest" + ], + "time": "2016-10-17T18:31:11+00:00" }, { - "name": "ircmaxell/password-compat", - "version": "v1.0.4", + "name": "friendsofsymfony/user-bundle", + "version": "v2.1.2", "source": { "type": "git", - "url": "https://github.com/ircmaxell/password_compat.git", - "reference": "5c5cde8822a69545767f7c7f3058cb15ff84614c" + "url": "https://github.com/FriendsOfSymfony/FOSUserBundle.git", + "reference": "1049935edd24ec305cc6cfde1875372fa9600446" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ircmaxell/password_compat/zipball/5c5cde8822a69545767f7c7f3058cb15ff84614c", - "reference": "5c5cde8822a69545767f7c7f3058cb15ff84614c", + "url": "https://api.github.com/repos/FriendsOfSymfony/FOSUserBundle/zipball/1049935edd24ec305cc6cfde1875372fa9600446", + "reference": "1049935edd24ec305cc6cfde1875372fa9600446", "shasum": "" }, + "require": { + "paragonie/random_compat": "^1 || ^2", + "php": "^5.5.9 || ^7.0", + "symfony/form": "^2.8 || ^3.0 || ^4.0", + "symfony/framework-bundle": "^2.8 || ^3.0 || ^4.0", + "symfony/security-bundle": "^2.8 || ^3.0 || ^4.0", + "symfony/templating": "^2.8 || ^3.0 || ^4.0", + "symfony/twig-bundle": "^2.8 || ^3.0 || ^4.0", + "symfony/validator": "^2.8 || ^3.0 || ^4.0", + "twig/twig": "^1.28 || ^2.0" + }, + "conflict": { + "doctrine/doctrine-bundle": "<1.3", + "symfony/doctrine-bridge": "<2.7" + }, "require-dev": { - "phpunit/phpunit": "4.*" + "doctrine/doctrine-bundle": "^1.3", + "friendsofphp/php-cs-fixer": "^2.2", + "phpunit/phpunit": "^4.8.35|^5.7.11|^6.5", + "swiftmailer/swiftmailer": "^4.3 || ^5.0 || ^6.0", + "symfony/console": "^2.8 || ^3.0 || ^4.0", + "symfony/phpunit-bridge": "^2.8 || ^3.0 || ^4.0", + "symfony/yaml": "^2.8 || ^3.0 || ^4.0" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-master": "2.1.x-dev" + } }, - "type": "library", "autoload": { - "files": [ - "lib/password.php" + "psr-4": { + "FOS\\UserBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -1509,18 +1543,23 @@ ], "authors": [ { - "name": "Anthony Ferrara", - "email": "ircmaxell@php.net", - "homepage": "http://blog.ircmaxell.com" + "name": "Christophe Coevoet", + "email": "stof@notk.org" + }, + { + "name": "FriendsOfSymfony Community", + "homepage": "https://github.com/friendsofsymfony/FOSUserBundle/contributors" + }, + { + "name": "Thibault Duplessis" } ], - "description": "A compatibility library for the proposed simplified password hashing algorithm: https://wiki.php.net/rfc/password_hash", - "homepage": "https://github.com/ircmaxell/password_compat", + "description": "Symfony FOSUserBundle", + "homepage": "http://friendsofsymfony.github.com", "keywords": [ - "hashing", - "password" + "User management" ], - "time": "2014-11-20T16:49:30+00:00" + "time": "2018-03-08T08:59:27+00:00" }, { "name": "jdorn/sql-formatter", @@ -1574,25 +1613,26 @@ }, { "name": "jms/aop-bundle", - "version": "1.2.0", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/schmittjoh/JMSAopBundle.git", - "reference": "78000d007e74283cc564a58e184d7f62548ad394" + "reference": "4ee2089a81b54ce94a8c94e95b48d5bb353dd8d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/JMSAopBundle/zipball/78000d007e74283cc564a58e184d7f62548ad394", - "reference": "78000d007e74283cc564a58e184d7f62548ad394", + "url": "https://api.github.com/repos/schmittjoh/JMSAopBundle/zipball/4ee2089a81b54ce94a8c94e95b48d5bb353dd8d0", + "reference": "4ee2089a81b54ce94a8c94e95b48d5bb353dd8d0", "shasum": "" }, "require": { "jms/cg": "^1.1", "php": ">=5.3.9", - "symfony/framework-bundle": "^2.3|^3.0" + "symfony/framework-bundle": "^2.3 || ^3.0 || ^4.0" }, "require-dev": { - "symfony/phpunit-bridge": "^2.7" + "phpunit/phpunit": "^4.8.36 | ^5.0", + "symfony/phpunit-bridge": "^2.7 || ^4.0" }, "type": "symfony-bundle", "extra": { @@ -1620,7 +1660,7 @@ "annotations", "aop" ], - "time": "2015-12-09T16:30:46+00:00" + "time": "2018-01-16T10:22:28+00:00" }, { "name": "jms/cg", @@ -1671,16 +1711,16 @@ }, { "name": "jms/di-extra-bundle", - "version": "1.8.0", + "version": "1.9.2", "source": { "type": "git", "url": "https://github.com/schmittjoh/JMSDiExtraBundle.git", - "reference": "7c8e23ffd65eb05f7b76869aa8ef1949e90789c7" + "reference": "fa82a4e6c9dc84df8015805028575217c0be4a54" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/JMSDiExtraBundle/zipball/7c8e23ffd65eb05f7b76869aa8ef1949e90789c7", - "reference": "7c8e23ffd65eb05f7b76869aa8ef1949e90789c7", + "url": "https://api.github.com/repos/schmittjoh/JMSDiExtraBundle/zipball/fa82a4e6c9dc84df8015805028575217c0be4a54", + "reference": "fa82a4e6c9dc84df8015805028575217c0be4a54", "shasum": "" }, "require": { @@ -1699,13 +1739,16 @@ "doctrine/orm": "~2.3", "jms/security-extra-bundle": "~1.0", "phpcollection/phpcollection": ">=0.2,<0.3-dev", + "phpunit/phpunit": "^4.8.35|^5.4.4|^6.0.0", "sensio/framework-extra-bundle": "~2.0|~3.0", + "symfony/asset": "~2.3|^3.3", "symfony/browser-kit": "~2.3|~3.0", "symfony/class-loader": "~2.3|~3.0", "symfony/expression-language": "~2.6|~3.0", "symfony/form": "~2.3|~3.0", - "symfony/phpunit-bridge": "~2.7", - "symfony/security-bundle": "~2.3", + "symfony/phpunit-bridge": "~3.3", + "symfony/security-bundle": "~2.3|^3.0", + "symfony/templating": "~2.3|^3.3", "symfony/twig-bundle": "~2.3|~3.0", "symfony/validator": "~2.3|~3.0", "symfony/yaml": "~2.3|~3.0" @@ -1713,7 +1756,7 @@ "type": "symfony-bundle", "extra": { "branch-alias": { - "dev-master": "1.7-dev" + "dev-master": "1.8-dev" } }, "autoload": { @@ -1737,27 +1780,28 @@ "annotations", "dependency injection" ], - "time": "2016-09-09T12:35:58+00:00" + "time": "2018-01-12T19:04:30+00:00" }, { "name": "jms/metadata", - "version": "1.5.1", + "version": "1.6.0", "source": { "type": "git", "url": "https://github.com/schmittjoh/metadata.git", - "reference": "22b72455559a25777cfd28c4ffda81ff7639f353" + "reference": "6a06970a10e0a532fb52d3959547123b84a3b3ab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/metadata/zipball/22b72455559a25777cfd28c4ffda81ff7639f353", - "reference": "22b72455559a25777cfd28c4ffda81ff7639f353", + "url": "https://api.github.com/repos/schmittjoh/metadata/zipball/6a06970a10e0a532fb52d3959547123b84a3b3ab", + "reference": "6a06970a10e0a532fb52d3959547123b84a3b3ab", "shasum": "" }, "require": { "php": ">=5.3.0" }, "require-dev": { - "doctrine/cache": "~1.0" + "doctrine/cache": "~1.0", + "symfony/cache": "~3.1" }, "type": "library", "extra": { @@ -1772,14 +1816,12 @@ }, "notification-url": "https://packagist.org/downloads/", "license": [ - "Apache" + "Apache-2.0" ], "authors": [ { - "name": "Johannes Schmitt", - "email": "schmittjoh@gmail.com", - "homepage": "https://github.com/schmittjoh", - "role": "Developer of wrapped JMSSerializerBundle" + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com" } ], "description": "Class/method/property metadata management in PHP", @@ -1789,7 +1831,7 @@ "xml", "yaml" ], - "time": "2014-07-12T07:13:19+00:00" + "time": "2016-12-05T10:18:33+00:00" }, { "name": "jms/parser-lib", @@ -1828,16 +1870,16 @@ }, { "name": "jms/security-extra-bundle", - "version": "1.6.0", + "version": "1.6.1", "source": { "type": "git", "url": "https://github.com/schmittjoh/JMSSecurityExtraBundle.git", - "reference": "d70399b25f41afd8277335cedc3c9b3acdc3759d" + "reference": "8d3b81d62601dcbafafc5e0c2d20f3383e475525" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/JMSSecurityExtraBundle/zipball/d70399b25f41afd8277335cedc3c9b3acdc3759d", - "reference": "d70399b25f41afd8277335cedc3c9b3acdc3759d", + "url": "https://api.github.com/repos/schmittjoh/JMSSecurityExtraBundle/zipball/8d3b81d62601dcbafafc5e0c2d20f3383e475525", + "reference": "8d3b81d62601dcbafafc5e0c2d20f3383e475525", "shasum": "" }, "require": { @@ -1900,29 +1942,29 @@ "secure", "security" ], - "time": "2016-02-03T15:29:16+00:00" + "time": "2016-08-04T14:40:55+00:00" }, { "name": "justinrainbow/json-schema", - "version": "5.1.0", + "version": "5.2.7", "source": { "type": "git", "url": "https://github.com/justinrainbow/json-schema.git", - "reference": "48817e5f95c9d29e11513f12e43cc0223fa5eb6c" + "reference": "8560d4314577199ba51bf2032f02cd1315587c23" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/48817e5f95c9d29e11513f12e43cc0223fa5eb6c", - "reference": "48817e5f95c9d29e11513f12e43cc0223fa5eb6c", + "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/8560d4314577199ba51bf2032f02cd1315587c23", + "reference": "8560d4314577199ba51bf2032f02cd1315587c23", "shasum": "" }, "require": { "php": ">=5.3.3" }, "require-dev": { + "friendsofphp/php-cs-fixer": "^2.1", "json-schema/json-schema-test-suite": "1.2.0", - "phpdocumentor/phpdocumentor": "~2", - "phpunit/phpunit": "^4.8.22" + "phpunit/phpunit": "^4.8.35" }, "bin": [ "bin/validate-json" @@ -1966,41 +2008,39 @@ "json", "schema" ], - "time": "2017-02-22T03:28:16+00:00" + "time": "2018-02-14T22:26:30+00:00" }, { "name": "knplabs/knp-menu", - "version": "v2.1.1", + "version": "2.3.0", "source": { "type": "git", "url": "https://github.com/KnpLabs/KnpMenu.git", - "reference": "9917b999a3c3d3901386d60c4888b07679291031" + "reference": "655630a1db0b72108262d1a844de3b1ba0885be5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/KnpLabs/KnpMenu/zipball/9917b999a3c3d3901386d60c4888b07679291031", - "reference": "9917b999a3c3d3901386d60c4888b07679291031", + "url": "https://api.github.com/repos/KnpLabs/KnpMenu/zipball/655630a1db0b72108262d1a844de3b1ba0885be5", + "reference": "655630a1db0b72108262d1a844de3b1ba0885be5", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=5.6.0" }, "require-dev": { - "pimple/pimple": "~1.0", - "silex/silex": "~1.0", - "symfony/phpunit-bridge": "~2.7|~3.0", - "symfony/routing": "~2.3|~3.0", + "psr/container": "^1.0", + "symfony/http-foundation": "~2.4|~3.0|^4.0", + "symfony/phpunit-bridge": "~3.3|^4.0", + "symfony/routing": "~2.3|~3.0|^4.0", "twig/twig": "~1.16|~2.0" }, "suggest": { - "pimple/pimple": "for the built-in implementations of the menu provider and renderer provider", - "silex/silex": "for the integration with your silex application", "twig/twig": "for the TwigRenderer and the integration with your templates" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.1-dev" + "dev-master": "2.3-dev" } }, "autoload": { @@ -2017,54 +2057,56 @@ "name": "Christophe Coevoet", "email": "stof@notk.org" }, - { - "name": "KnpLabs", - "homepage": "http://knplabs.com" - }, { "name": "Symfony Community", "homepage": "https://github.com/KnpLabs/KnpMenu/contributors" + }, + { + "name": "KnpLabs", + "homepage": "https://knplabs.com" } ], "description": "An object oriented menu library", - "homepage": "http://knplabs.com", + "homepage": "https://knplabs.com", "keywords": [ "menu", "tree" ], - "time": "2016-01-08T15:42:54+00:00" + "time": "2017-11-18T20:49:26+00:00" }, { "name": "knplabs/knp-menu-bundle", - "version": "2.1.2", + "version": "v2.2.1", "source": { "type": "git", "url": "https://github.com/KnpLabs/KnpMenuBundle.git", - "reference": "42ff1953c3a79d0b31aba2ece8c03fbd70e7f1ca" + "reference": "6bea43eb84fc67c43ab2b43709194efffa8a8ac0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/KnpLabs/KnpMenuBundle/zipball/42ff1953c3a79d0b31aba2ece8c03fbd70e7f1ca", - "reference": "42ff1953c3a79d0b31aba2ece8c03fbd70e7f1ca", + "url": "https://api.github.com/repos/KnpLabs/KnpMenuBundle/zipball/6bea43eb84fc67c43ab2b43709194efffa8a8ac0", + "reference": "6bea43eb84fc67c43ab2b43709194efffa8a8ac0", "shasum": "" }, "require": { - "knplabs/knp-menu": "~2.1", - "symfony/framework-bundle": "~2.3|~3.0" + "knplabs/knp-menu": "~2.3", + "php": "^5.6 || ^7", + "symfony/framework-bundle": "~2.7|~3.0 | ^4.0" }, "require-dev": { - "symfony/expression-language": "~2.4|~3.0", - "symfony/phpunit-bridge": "~2.7|~3.0" + "symfony/expression-language": "~2.7|~3.0 | ^4.0", + "symfony/phpunit-bridge": "^3.3 | ^4.0", + "symfony/templating": "~2.7|~3.0 | ^4.0" }, "type": "symfony-bundle", "extra": { "branch-alias": { - "dev-master": "2.1.x-dev" + "dev-master": "2.2.x-dev" } }, "autoload": { "psr-4": { - "Knp\\Bundle\\MenuBundle\\": "" + "Knp\\Bundle\\MenuBundle\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -2089,55 +2131,7 @@ "keywords": [ "menu" ], - "time": "2016-06-21T06:53:03+00:00" - }, - { - "name": "kriswallsmith/buzz", - "version": "v0.15", - "source": { - "type": "git", - "url": "https://github.com/kriswallsmith/Buzz.git", - "reference": "d4041666c3ffb379af02a92dabe81c904b35fab8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/kriswallsmith/Buzz/zipball/d4041666c3ffb379af02a92dabe81c904b35fab8", - "reference": "d4041666c3ffb379af02a92dabe81c904b35fab8", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "require-dev": { - "phpunit/phpunit": "3.7.*" - }, - "suggest": { - "ext-curl": "*" - }, - "type": "library", - "autoload": { - "psr-0": { - "Buzz": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Kris Wallsmith", - "email": "kris.wallsmith@gmail.com", - "homepage": "http://kriswallsmith.net/" - } - ], - "description": "Lightweight HTTP client", - "homepage": "https://github.com/kriswallsmith/Buzz", - "keywords": [ - "curl", - "http client" - ], - "time": "2015-06-25T17:26:56+00:00" + "time": "2017-12-24T16:32:39+00:00" }, { "name": "monolog/monolog", @@ -2217,124 +2211,6 @@ ], "time": "2017-06-19T01:22:40+00:00" }, - { - "name": "nelmio/cors-bundle", - "version": "1.5.3", - "source": { - "type": "git", - "url": "https://github.com/nelmio/NelmioCorsBundle.git", - "reference": "ac6576a599d7db9c2c6022602c188a5594216056" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nelmio/NelmioCorsBundle/zipball/ac6576a599d7db9c2c6022602c188a5594216056", - "reference": "ac6576a599d7db9c2c6022602c188a5594216056", - "shasum": "" - }, - "require": { - "symfony/framework-bundle": "^2.7 || ^3.0" - }, - "require-dev": { - "matthiasnoback/symfony-dependency-injection-test": "^0.7.6", - "mockery/mockery": "0.9.*" - }, - "type": "symfony-bundle", - "extra": { - "branch-alias": { - "dev-master": "1.5.x-dev" - } - }, - "autoload": { - "psr-4": { - "Nelmio\\CorsBundle\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nelmio", - "homepage": "http://nelm.io" - }, - { - "name": "Symfony Community", - "homepage": "https://github.com/nelmio/NelmioCorsBundle/contributors" - } - ], - "description": "Adds CORS (Cross-Origin Resource Sharing) headers support in your Symfony2 application", - "keywords": [ - "api", - "cors", - "crossdomain" - ], - "time": "2017-04-24T09:12:42+00:00" - }, - { - "name": "nelmio/security-bundle", - "version": "2.4.0", - "source": { - "type": "git", - "url": "https://github.com/nelmio/NelmioSecurityBundle.git", - "reference": "d0d7b151eda5f0ebe80562528f78b56954c1aec7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nelmio/NelmioSecurityBundle/zipball/d0d7b151eda5f0ebe80562528f78b56954c1aec7", - "reference": "d0d7b151eda5f0ebe80562528f78b56954c1aec7", - "shasum": "" - }, - "require": { - "paragonie/random_compat": "~1.0|~2.0", - "symfony/framework-bundle": "~2.3|~3.0", - "symfony/security": "~2.3|~3.0", - "ua-parser/uap-php": "^3.4.4" - }, - "require-dev": { - "doctrine/cache": "^1.0", - "psr/cache": "^1.0", - "symfony/phpunit-bridge": "^3.2", - "symfony/yaml": "~2.3|~3.0", - "twig/twig": "^1.24" - }, - "suggest": { - "ua-parser/uap-php": "To allow adapt CSP directives given the user-agent" - }, - "type": "symfony-bundle", - "extra": { - "branch-alias": { - "dev-master": "2.4.x-dev" - } - }, - "autoload": { - "psr-4": { - "Nelmio\\SecurityBundle\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nelmio", - "homepage": "http://nelm.io" - }, - { - "name": "Symfony Community", - "homepage": "https://github.com/nelmio/NelmioSecurityBundle/contributors" - } - ], - "description": "Extra security-related features for Symfony: signed/encrypted cookies, HTTPS/SSL/HSTS handling, cookie session storage, ...", - "keywords": [ - "security" - ], - "time": "2017-06-22T08:11:46+00:00" - }, { "name": "oro/doctrine-extensions", "version": "1.2.0", @@ -2392,16 +2268,16 @@ }, { "name": "pagerfanta/pagerfanta", - "version": "v1.0.3", + "version": "v1.1.0", "source": { "type": "git", "url": "https://github.com/whiteoctober/Pagerfanta.git", - "reference": "a874d3612d954dcbbb49e5ffe178890918fb76fb" + "reference": "8400ab498e500018cff9a099ac22555e7949aa9a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/whiteoctober/Pagerfanta/zipball/a874d3612d954dcbbb49e5ffe178890918fb76fb", - "reference": "a874d3612d954dcbbb49e5ffe178890918fb76fb", + "url": "https://api.github.com/repos/whiteoctober/Pagerfanta/zipball/8400ab498e500018cff9a099ac22555e7949aa9a", + "reference": "8400ab498e500018cff9a099ac22555e7949aa9a", "shasum": "" }, "require": { @@ -2414,7 +2290,8 @@ "jmikola/geojson": "~1.0", "mandango/mandango": "~1.0@dev", "mandango/mondator": "~1.0@dev", - "phpunit/phpunit": "~4", + "phpunit/phpunit": "^4.8.35 | ^5.7", + "propel/propel": "~2.0@dev", "propel/propel1": "~1.6", "ruflin/elastica": "~1.3", "solarium/solarium": "~3.1" @@ -2424,6 +2301,7 @@ "doctrine/orm": "To use the DoctrineORMAdapter.", "doctrine/phpcr-odm": "To use the DoctrineODMPhpcrAdapter. >= 1.1.0", "mandango/mandango": "To use the MandangoAdapter.", + "propel/propel": "To use the Propel2Adapter", "propel/propel1": "To use the PropelAdapter", "solarium/solarium": "To use the SolariumAdapter." }, @@ -2455,20 +2333,20 @@ "paginator", "paging" ], - "time": "2014-10-06T10:57:25+00:00" + "time": "2018-05-01T10:49:10+00:00" }, { "name": "paragonie/random_compat", - "version": "v2.0.12", + "version": "v2.0.17", "source": { "type": "git", "url": "https://github.com/paragonie/random_compat.git", - "reference": "258c89a6b97de7dfaf5b8c7607d0478e236b04fb" + "reference": "29af24f25bab834fcbb38ad2a69fa93b867e070d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/random_compat/zipball/258c89a6b97de7dfaf5b8c7607d0478e236b04fb", - "reference": "258c89a6b97de7dfaf5b8c7607d0478e236b04fb", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/29af24f25bab834fcbb38ad2a69fa93b867e070d", + "reference": "29af24f25bab834fcbb38ad2a69fa93b867e070d", "shasum": "" }, "require": { @@ -2500,89 +2378,282 @@ "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7", "keywords": [ "csprng", + "polyfill", "pseudorandom", "random" ], - "time": "2018-04-04T21:24:14+00:00" + "time": "2018-07-04T16:31:37+00:00" }, { "name": "phpoption/phpoption", "version": "1.5.0", "source": { "type": "git", - "url": "https://github.com/schmittjoh/php-option.git", - "reference": "94e644f7d2051a5f0fcf77d81605f152eecff0ed" + "url": "https://github.com/schmittjoh/php-option.git", + "reference": "94e644f7d2051a5f0fcf77d81605f152eecff0ed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/94e644f7d2051a5f0fcf77d81605f152eecff0ed", + "reference": "94e644f7d2051a5f0fcf77d81605f152eecff0ed", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "4.7.*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "psr-0": { + "PhpOption\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache2" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "Option Type for PHP", + "keywords": [ + "language", + "option", + "php", + "type" + ], + "time": "2015-07-25T16:39:46+00:00" + }, + { + "name": "predis/predis", + "version": "v1.1.1", + "source": { + "type": "git", + "url": "https://github.com/nrk/predis.git", + "reference": "f0210e38881631afeafb56ab43405a92cafd9fd1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nrk/predis/zipball/f0210e38881631afeafb56ab43405a92cafd9fd1", + "reference": "f0210e38881631afeafb56ab43405a92cafd9fd1", + "shasum": "" + }, + "require": { + "php": ">=5.3.9" + }, + "require-dev": { + "phpunit/phpunit": "~4.8" + }, + "suggest": { + "ext-curl": "Allows access to Webdis when paired with phpiredis", + "ext-phpiredis": "Allows faster serialization and deserialization of the Redis protocol" + }, + "type": "library", + "autoload": { + "psr-4": { + "Predis\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Daniele Alessandri", + "email": "suppakilla@gmail.com", + "homepage": "http://clorophilla.net" + } + ], + "description": "Flexible and feature-complete Redis client for PHP and HHVM", + "homepage": "http://github.com/nrk/predis", + "keywords": [ + "nosql", + "predis", + "redis" + ], + "time": "2016-06-16T16:22:20+00:00" + }, + { + "name": "psr/cache", + "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/d11b50ad223250cf17b86e38383413f5a6764bf8", + "reference": "d11b50ad223250cf17b86e38383413f5a6764bf8", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "time": "2016-08-06T20:24:11+00:00" + }, + { + "name": "psr/container", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "reference": "b7ce3b176482dbbc1245ebf52b181af44c2cf55f", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "time": "2017-02-14T16:28:37+00:00" + }, + { + "name": "psr/link", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/link.git", + "reference": "eea8e8662d5cd3ae4517c9b864493f59fca95562" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/94e644f7d2051a5f0fcf77d81605f152eecff0ed", - "reference": "94e644f7d2051a5f0fcf77d81605f152eecff0ed", + "url": "https://api.github.com/repos/php-fig/link/zipball/eea8e8662d5cd3ae4517c9b864493f59fca95562", + "reference": "eea8e8662d5cd3ae4517c9b864493f59fca95562", "shasum": "" }, "require": { "php": ">=5.3.0" }, - "require-dev": { - "phpunit/phpunit": "4.7.*" - }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.3-dev" + "dev-master": "1.0.x-dev" } }, "autoload": { - "psr-0": { - "PhpOption\\": "src/" + "psr-4": { + "Psr\\Link\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "Apache2" + "MIT" ], "authors": [ { - "name": "Johannes M. Schmitt", - "email": "schmittjoh@gmail.com" + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" } ], - "description": "Option Type for PHP", + "description": "Common interfaces for HTTP links", "keywords": [ - "language", - "option", - "php", - "type" + "http", + "http-link", + "link", + "psr", + "psr-13", + "rest" ], - "time": "2015-07-25T16:39:46+00:00" + "time": "2016-10-28T16:06:13+00:00" }, { - "name": "predis/predis", - "version": "v1.1.1", + "name": "psr/log", + "version": "1.0.2", "source": { "type": "git", - "url": "https://github.com/nrk/predis.git", - "reference": "f0210e38881631afeafb56ab43405a92cafd9fd1" + "url": "https://github.com/php-fig/log.git", + "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nrk/predis/zipball/f0210e38881631afeafb56ab43405a92cafd9fd1", - "reference": "f0210e38881631afeafb56ab43405a92cafd9fd1", + "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", "shasum": "" }, "require": { - "php": ">=5.3.9" - }, - "require-dev": { - "phpunit/phpunit": "~4.8" - }, - "suggest": { - "ext-curl": "Allows access to Webdis when paired with phpiredis", - "ext-phpiredis": "Allows faster serialization and deserialization of the Redis protocol" + "php": ">=5.3.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, "autoload": { "psr-4": { - "Predis\\": "src/" + "Psr\\Log\\": "Psr/Log/" } }, "notification-url": "https://packagist.org/downloads/", @@ -2591,32 +2662,31 @@ ], "authors": [ { - "name": "Daniele Alessandri", - "email": "suppakilla@gmail.com", - "homepage": "http://clorophilla.net" + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" } ], - "description": "Flexible and feature-complete Redis client for PHP and HHVM", - "homepage": "http://github.com/nrk/predis", + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", "keywords": [ - "nosql", - "predis", - "redis" + "log", + "psr", + "psr-3" ], - "time": "2016-06-16T16:22:20+00:00" + "time": "2016-10-10T12:19:37+00:00" }, { - "name": "psr/log", - "version": "1.0.2", + "name": "psr/simple-cache", + "version": "1.0.1", "source": { "type": "git", - "url": "https://github.com/php-fig/log.git", - "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d" + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", - "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", + "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b", "shasum": "" }, "require": { @@ -2630,7 +2700,7 @@ }, "autoload": { "psr-4": { - "Psr\\Log\\": "Psr/Log/" + "Psr\\SimpleCache\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -2643,14 +2713,15 @@ "homepage": "http://www.php-fig.org/" } ], - "description": "Common interface for logging libraries", - "homepage": "https://github.com/php-fig/log", + "description": "Common interfaces for simple caching", "keywords": [ - "log", + "cache", + "caching", "psr", - "psr-3" + "psr-16", + "simple-cache" ], - "time": "2016-10-10T12:19:37+00:00" + "time": "2017-10-23T01:57:42+00:00" }, { "name": "seld/cli-prompt", @@ -2702,16 +2773,16 @@ }, { "name": "seld/jsonlint", - "version": "1.7.0", + "version": "1.7.1", "source": { "type": "git", "url": "https://github.com/Seldaek/jsonlint.git", - "reference": "9b355654ea99460397b89c132b5c1087b6bf4473" + "reference": "d15f59a67ff805a44c50ea0516d2341740f81a38" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/9b355654ea99460397b89c132b5c1087b6bf4473", - "reference": "9b355654ea99460397b89c132b5c1087b6bf4473", + "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/d15f59a67ff805a44c50ea0516d2341740f81a38", + "reference": "d15f59a67ff805a44c50ea0516d2341740f81a38", "shasum": "" }, "require": { @@ -2747,7 +2818,7 @@ "parser", "validator" ], - "time": "2018-01-03T12:13:57+00:00" + "time": "2018-01-24T12:46:19+00:00" }, { "name": "seld/phar-utils", @@ -2843,16 +2914,16 @@ }, { "name": "sensio/distribution-bundle", - "version": "v5.0.21", + "version": "v5.0.22", "source": { "type": "git", "url": "https://github.com/sensiolabs/SensioDistributionBundle.git", - "reference": "eb6266b3b472e4002538610b28a0a04bcf94891a" + "reference": "209b11f8cee5bf71986dd703e45e27d3ed7a6d15" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sensiolabs/SensioDistributionBundle/zipball/eb6266b3b472e4002538610b28a0a04bcf94891a", - "reference": "eb6266b3b472e4002538610b28a0a04bcf94891a", + "url": "https://api.github.com/repos/sensiolabs/SensioDistributionBundle/zipball/209b11f8cee5bf71986dd703e45e27d3ed7a6d15", + "reference": "209b11f8cee5bf71986dd703e45e27d3ed7a6d15", "shasum": "" }, "require": { @@ -2891,7 +2962,7 @@ "configuration", "distribution" ], - "time": "2017-08-25T16:55:44+00:00" + "time": "2018-06-07T06:22:12+00:00" }, { "name": "sensio/framework-extra-bundle", @@ -3064,29 +3135,29 @@ }, { "name": "snc/redis-bundle", - "version": "2.0.0", + "version": "2.1.4", "source": { "type": "git", "url": "https://github.com/snc/SncRedisBundle.git", - "reference": "b8aa1a966b32c4fba6b7dac4532d5eeb1d890afb" + "reference": "3f3c233ebbfba43d3abd2403be0bc34c11e6dc06" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/snc/SncRedisBundle/zipball/b8aa1a966b32c4fba6b7dac4532d5eeb1d890afb", - "reference": "b8aa1a966b32c4fba6b7dac4532d5eeb1d890afb", + "url": "https://api.github.com/repos/snc/SncRedisBundle/zipball/3f3c233ebbfba43d3abd2403be0bc34c11e6dc06", + "reference": "3f3c233ebbfba43d3abd2403be0bc34c11e6dc06", "shasum": "" }, "require": { "php": ">=5.3.3", - "symfony/framework-bundle": "^2.7 || ^3.0", - "symfony/yaml": "^2.7 || ^3.0" + "symfony/framework-bundle": "^2.7 || ^3.0 || ^4.0", + "symfony/yaml": "^2.7 || ^3.0 || ^4.0" }, "require-dev": { "doctrine/cache": "1.*", - "phpunit/phpunit": "4.8.*", + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5", "predis/predis": "^1.0", - "symfony/console": "^2.7 || ^3.0", - "symfony/phpunit-bridge": "^2.7 || ^3.0" + "symfony/console": "^2.7 || ^3.0 || ^4.0", + "symfony/phpunit-bridge": "^2.7 || ^3.0 || ^4.0" }, "suggest": { "monolog/monolog": "If you want to use the monolog redis handler.", @@ -3125,7 +3196,7 @@ "redis", "symfony" ], - "time": "2016-06-17T11:50:26+00:00" + "time": "2018-06-25T15:31:46+00:00" }, { "name": "swiftmailer/swiftmailer", @@ -3298,83 +3369,22 @@ "time": "2018-04-26T10:06:28+00:00" }, { - "name": "symfony/polyfill-intl-icu", - "version": "v1.8.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-intl-icu.git", - "reference": "80ee17ae83c10cd513e5144f91a73607a21edb4e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-icu/zipball/80ee17ae83c10cd513e5144f91a73607a21edb4e", - "reference": "80ee17ae83c10cd513e5144f91a73607a21edb4e", - "shasum": "" - }, - "require": { - "php": ">=5.3.3", - "symfony/intl": "~2.3|~3.0|~4.0" - }, - "suggest": { - "ext-intl": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.8-dev" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for intl's ICU-related data and classes", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "icu", - "intl", - "polyfill", - "portable", - "shim" - ], - "time": "2018-04-25T14:53:50+00:00" - }, - { - "name": "symfony/polyfill-mbstring", + "name": "symfony/polyfill-ctype", "version": "v1.8.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "3296adf6a6454a050679cde90f95350ad604b171" + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "7cc359f1b7b80fc25ed7796be7d96adc9b354bae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/3296adf6a6454a050679cde90f95350ad604b171", - "reference": "3296adf6a6454a050679cde90f95350ad604b171", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/7cc359f1b7b80fc25ed7796be7d96adc9b354bae", + "reference": "7cc359f1b7b80fc25ed7796be7d96adc9b354bae", "shasum": "" }, "require": { "php": ">=5.3.3" }, - "suggest": { - "ext-mbstring": "For best performance" - }, "type": "library", "extra": { "branch-alias": { @@ -3383,7 +3393,7 @@ }, "autoload": { "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" + "Symfony\\Polyfill\\Ctype\\": "" }, "files": [ "bootstrap.php" @@ -3394,42 +3404,45 @@ "MIT" ], "authors": [ - { - "name": "Nicolas Grekas", - "email": "p@tchwork.com" - }, { "name": "Symfony Community", "homepage": "https://symfony.com/contributors" + }, + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" } ], - "description": "Symfony polyfill for the Mbstring extension", + "description": "Symfony polyfill for ctype functions", "homepage": "https://symfony.com", "keywords": [ "compatibility", - "mbstring", + "ctype", "polyfill", - "portable", - "shim" + "portable" ], - "time": "2018-04-26T10:06:28+00:00" + "time": "2018-04-30T19:57:29+00:00" }, { - "name": "symfony/polyfill-php54", + "name": "symfony/polyfill-intl-icu", "version": "v1.8.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php54.git", - "reference": "6c3a2b84c6025e4ea3f6a19feac35408c64b22e1" + "url": "https://github.com/symfony/polyfill-intl-icu.git", + "reference": "80ee17ae83c10cd513e5144f91a73607a21edb4e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php54/zipball/6c3a2b84c6025e4ea3f6a19feac35408c64b22e1", - "reference": "6c3a2b84c6025e4ea3f6a19feac35408c64b22e1", + "url": "https://api.github.com/repos/symfony/polyfill-intl-icu/zipball/80ee17ae83c10cd513e5144f91a73607a21edb4e", + "reference": "80ee17ae83c10cd513e5144f91a73607a21edb4e", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=5.3.3", + "symfony/intl": "~2.3|~3.0|~4.0" + }, + "suggest": { + "ext-intl": "For best performance" }, "type": "library", "extra": { @@ -3438,14 +3451,8 @@ } }, "autoload": { - "psr-4": { - "Symfony\\Polyfill\\Php54\\": "" - }, "files": [ "bootstrap.php" - ], - "classmap": [ - "Resources/stubs" ] }, "notification-url": "https://packagist.org/downloads/", @@ -3462,34 +3469,38 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 5.4+ features to lower PHP versions", + "description": "Symfony polyfill for intl's ICU-related data and classes", "homepage": "https://symfony.com", "keywords": [ "compatibility", + "icu", + "intl", "polyfill", "portable", "shim" ], - "time": "2018-04-26T10:06:28+00:00" + "time": "2018-04-25T14:53:50+00:00" }, { - "name": "symfony/polyfill-php55", + "name": "symfony/polyfill-mbstring", "version": "v1.8.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-php55.git", - "reference": "a39456128377a85f2c5707fcae458678560cba46" + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "3296adf6a6454a050679cde90f95350ad604b171" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php55/zipball/a39456128377a85f2c5707fcae458678560cba46", - "reference": "a39456128377a85f2c5707fcae458678560cba46", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/3296adf6a6454a050679cde90f95350ad604b171", + "reference": "3296adf6a6454a050679cde90f95350ad604b171", "shasum": "" }, "require": { - "ircmaxell/password-compat": "~1.0", "php": ">=5.3.3" }, + "suggest": { + "ext-mbstring": "For best performance" + }, "type": "library", "extra": { "branch-alias": { @@ -3498,7 +3509,7 @@ }, "autoload": { "psr-4": { - "Symfony\\Polyfill\\Php55\\": "" + "Symfony\\Polyfill\\Mbstring\\": "" }, "files": [ "bootstrap.php" @@ -3518,10 +3529,11 @@ "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill backporting some PHP 5.5+ features to lower PHP versions", + "description": "Symfony polyfill for the Mbstring extension", "homepage": "https://symfony.com", "keywords": [ "compatibility", + "mbstring", "polyfill", "portable", "shim" @@ -3817,41 +3829,51 @@ }, { "name": "symfony/symfony", - "version": "v2.8.39", + "version": "v3.4.12", "source": { "type": "git", "url": "https://github.com/symfony/symfony.git", - "reference": "9b75ffe7b3adf2dad279e968787b71f829c1c404" + "reference": "c36f8cb21b5f1661a14fdb8cef9cc611d54a3494" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/symfony/zipball/9b75ffe7b3adf2dad279e968787b71f829c1c404", - "reference": "9b75ffe7b3adf2dad279e968787b71f829c1c404", + "url": "https://api.github.com/repos/symfony/symfony/zipball/c36f8cb21b5f1661a14fdb8cef9cc611d54a3494", + "reference": "c36f8cb21b5f1661a14fdb8cef9cc611d54a3494", "shasum": "" }, "require": { - "doctrine/common": "~2.4", + "doctrine/common": "~2.4@stable", "ext-xml": "*", - "php": ">=5.3.9", + "fig/link-util": "^1.0", + "php": "^5.5.9|>=7.0.8", + "psr/cache": "~1.0", + "psr/container": "^1.0", + "psr/link": "^1.0", "psr/log": "~1.0", + "psr/simple-cache": "^1.0", "symfony/polyfill-apcu": "~1.1", + "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-intl-icu": "~1.0", "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php54": "~1.0", - "symfony/polyfill-php55": "~1.0", "symfony/polyfill-php56": "~1.0", - "symfony/polyfill-php70": "~1.0", - "symfony/polyfill-util": "~1.0", - "symfony/security-acl": "~2.7|~3.0.0", - "twig/twig": "~1.34|~2.4" + "symfony/polyfill-php70": "~1.6", + "twig/twig": "^1.35|^2.4.4" }, "conflict": { - "phpdocumentor/reflection": "<1.0.7", + "phpdocumentor/reflection-docblock": "<3.0||>=3.2.0,<3.2.2", + "phpdocumentor/type-resolver": "<0.2.1", "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0" }, + "provide": { + "psr/cache-implementation": "1.0", + "psr/container-implementation": "1.0", + "psr/log-implementation": "1.0", + "psr/simple-cache-implementation": "1.0" + }, "replace": { "symfony/asset": "self.version", "symfony/browser-kit": "self.version", + "symfony/cache": "self.version", "symfony/class-loader": "self.version", "symfony/config": "self.version", "symfony/console": "self.version", @@ -3861,6 +3883,7 @@ "symfony/dependency-injection": "self.version", "symfony/doctrine-bridge": "self.version", "symfony/dom-crawler": "self.version", + "symfony/dotenv": "self.version", "symfony/event-dispatcher": "self.version", "symfony/expression-language": "self.version", "symfony/filesystem": "self.version", @@ -3869,9 +3892,10 @@ "symfony/framework-bundle": "self.version", "symfony/http-foundation": "self.version", "symfony/http-kernel": "self.version", + "symfony/inflector": "self.version", "symfony/intl": "self.version", "symfony/ldap": "self.version", - "symfony/locale": "self.version", + "symfony/lock": "self.version", "symfony/monolog-bridge": "self.version", "symfony/options-resolver": "self.version", "symfony/process": "self.version", @@ -3887,33 +3911,38 @@ "symfony/security-http": "self.version", "symfony/serializer": "self.version", "symfony/stopwatch": "self.version", - "symfony/swiftmailer-bridge": "self.version", "symfony/templating": "self.version", "symfony/translation": "self.version", "symfony/twig-bridge": "self.version", "symfony/twig-bundle": "self.version", "symfony/validator": "self.version", "symfony/var-dumper": "self.version", + "symfony/web-link": "self.version", "symfony/web-profiler-bundle": "self.version", + "symfony/web-server-bundle": "self.version", + "symfony/workflow": "self.version", "symfony/yaml": "self.version" }, "require-dev": { + "cache/integration-tests": "dev-master", "doctrine/annotations": "~1.0", + "doctrine/cache": "~1.6", "doctrine/data-fixtures": "1.0.*", "doctrine/dbal": "~2.4", - "doctrine/doctrine-bundle": "~1.2", + "doctrine/doctrine-bundle": "~1.4", "doctrine/orm": "~2.4,>=2.4.5", - "egulias/email-validator": "~1.2,>=1.2.1", + "egulias/email-validator": "~1.2,>=1.2.8|~2.0", "monolog/monolog": "~1.11", "ocramius/proxy-manager": "~0.4|~1.0|~2.0", - "phpdocumentor/reflection": "^1.0.7", - "sensio/framework-extra-bundle": "^3.0.2", - "symfony/phpunit-bridge": "~3.4|~4.0" + "phpdocumentor/reflection-docblock": "^3.0|^4.0", + "predis/predis": "~1.0", + "symfony/phpunit-bridge": "~3.4|~4.0", + "symfony/security-acl": "~2.8|~3.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.8-dev" + "dev-master": "3.4-dev" } }, "autoload": { @@ -3921,7 +3950,6 @@ "Symfony\\Bridge\\Doctrine\\": "src/Symfony/Bridge/Doctrine/", "Symfony\\Bridge\\Monolog\\": "src/Symfony/Bridge/Monolog/", "Symfony\\Bridge\\ProxyManager\\": "src/Symfony/Bridge/ProxyManager/", - "Symfony\\Bridge\\Swiftmailer\\": "src/Symfony/Bridge/Swiftmailer/", "Symfony\\Bridge\\Twig\\": "src/Symfony/Bridge/Twig/", "Symfony\\Bundle\\": "src/Symfony/Bundle/", "Symfony\\Component\\": "src/Symfony/Component/" @@ -3952,27 +3980,28 @@ "keywords": [ "framework" ], - "time": "2018-04-30T05:53:09+00:00" + "time": "2018-06-25T12:29:33+00:00" }, { "name": "twig/extensions", - "version": "v1.3.0", + "version": "v1.5.1", "source": { "type": "git", "url": "https://github.com/twigphp/Twig-extensions.git", - "reference": "449e3c8a9ffad7c2479c7864557275a32b037499" + "reference": "d188c76168b853481cc75879ea045bf93d718e9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig-extensions/zipball/449e3c8a9ffad7c2479c7864557275a32b037499", - "reference": "449e3c8a9ffad7c2479c7864557275a32b037499", + "url": "https://api.github.com/repos/twigphp/Twig-extensions/zipball/d188c76168b853481cc75879ea045bf93d718e9c", + "reference": "d188c76168b853481cc75879ea045bf93d718e9c", "shasum": "" }, "require": { - "twig/twig": "~1.20|~2.0" + "twig/twig": "~1.27|~2.0" }, "require-dev": { - "symfony/translation": "~2.3" + "symfony/phpunit-bridge": "~3.3@dev", + "symfony/translation": "~2.3|~3.0" }, "suggest": { "symfony/translation": "Allow the time_diff output to be translated" @@ -3980,12 +4009,15 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.3-dev" + "dev-master": "1.5-dev" } }, "autoload": { "psr-0": { "Twig_Extensions_": "lib/" + }, + "psr-4": { + "Twig\\Extensions\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -4004,24 +4036,25 @@ "i18n", "text" ], - "time": "2015-08-22T16:38:35+00:00" + "time": "2017-06-08T18:19:53+00:00" }, { "name": "twig/twig", - "version": "v2.4.8", + "version": "v2.5.0", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "7b604c89da162034bdf4bb66310f358d313dd16d" + "reference": "6a5f676b77a90823c2d4eaf76137b771adf31323" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/7b604c89da162034bdf4bb66310f358d313dd16d", - "reference": "7b604c89da162034bdf4bb66310f358d313dd16d", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/6a5f676b77a90823c2d4eaf76137b771adf31323", + "reference": "6a5f676b77a90823c2d4eaf76137b771adf31323", "shasum": "" }, "require": { "php": "^7.0", + "symfony/polyfill-ctype": "^1.8", "symfony/polyfill-mbstring": "~1.0" }, "require-dev": { @@ -4032,7 +4065,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.4-dev" + "dev-master": "2.5-dev" } }, "autoload": { @@ -4061,90 +4094,41 @@ }, { "name": "Twig Team", - "homepage": "http://twig.sensiolabs.org/contributors", + "homepage": "https://twig.symfony.com/contributors", "role": "Contributors" } ], "description": "Twig, the flexible, fast, and secure template language for PHP", - "homepage": "http://twig.sensiolabs.org", + "homepage": "https://twig.symfony.com", "keywords": [ "templating" ], - "time": "2018-04-02T09:24:19+00:00" - }, - { - "name": "ua-parser/uap-php", - "version": "v3.5.0", - "source": { - "type": "git", - "url": "https://github.com/ua-parser/uap-php.git", - "reference": "c8b31e5b8215a0c6dab4dd304050526a1907b17c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/ua-parser/uap-php/zipball/c8b31e5b8215a0c6dab4dd304050526a1907b17c", - "reference": "c8b31e5b8215a0c6dab4dd304050526a1907b17c", - "shasum": "" - }, - "require": { - "php": ">=5.3.0", - "symfony/console": "^2.0 || ^3.0 || ^4.0", - "symfony/filesystem": "^2.0 || ^3.0 || ^4.0", - "symfony/finder": "^2.0 || ^3.0 || ^4.0", - "symfony/yaml": "^2.0 || ^3.0 || ^4.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.0 || ^5.0" - }, - "bin": [ - "bin/uaparser" - ], - "type": "library", - "autoload": { - "psr-4": { - "UAParser\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Lars Strojny", - "email": "lars@strojny.net" - }, - { - "name": "Dave Olsen", - "email": "dmolsen@gmail.com" - } - ], - "description": "A multi-language port of Browserscope's user agent parser.", - "time": "2017-12-13T11:03:50+00:00" + "time": "2018-07-13T07:18:09+00:00" }, { "name": "white-october/pagerfanta-bundle", - "version": "v1.0.7", + "version": "v1.2.1", "source": { "type": "git", "url": "https://github.com/whiteoctober/WhiteOctoberPagerfantaBundle.git", - "reference": "f7e0fdf94a763a21a7c4c36ec9d9b5bcf4e12521" + "reference": "3f97e71c9d3f75e7a6179aa82c863497bf298b2d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/whiteoctober/WhiteOctoberPagerfantaBundle/zipball/f7e0fdf94a763a21a7c4c36ec9d9b5bcf4e12521", - "reference": "f7e0fdf94a763a21a7c4c36ec9d9b5bcf4e12521", + "url": "https://api.github.com/repos/whiteoctober/WhiteOctoberPagerfantaBundle/zipball/3f97e71c9d3f75e7a6179aa82c863497bf298b2d", + "reference": "3f97e71c9d3f75e7a6179aa82c863497bf298b2d", "shasum": "" }, "require": { - "pagerfanta/pagerfanta": "1.0.*", - "symfony/framework-bundle": "~2.3|~3.0", - "symfony/property-access": "~2.3|~3.0", - "symfony/twig-bundle": "~2.3|~3.0" + "pagerfanta/pagerfanta": "^1.1.0|^2.0.0", + "php": ">=5.3", + "symfony/framework-bundle": "~2.3|~3.0|~4.0", + "symfony/property-access": "~2.3|~3.0|~4.0", + "symfony/twig-bundle": "~2.3|~3.0|~4.0" }, "require-dev": { - "phpunit/phpunit": "~3.7", - "symfony/symfony": "~2.3|~3.0" + "phpunit/phpunit": "~3.7|~4.0|^5.0", + "symfony/symfony": "~2.3|~3.0|~4.0" }, "type": "symfony-bundle", "extra": { @@ -4153,8 +4137,14 @@ } }, "autoload": { + "classmap": [ + "WhiteOctoberPagerfantaBundle.php" + ], "psr-4": { - "WhiteOctober\\PagerfantaBundle\\": "" + "WhiteOctober\\PagerfantaBundle\\DependencyInjection\\": "DependencyInjection", + "WhiteOctober\\PagerfantaBundle\\EventListener\\": "EventListener", + "WhiteOctober\\PagerfantaBundle\\Twig\\": "Twig", + "WhiteOctober\\PagerfantaBundle\\View\\": "View" } }, "notification-url": "https://packagist.org/downloads/", @@ -4172,7 +4162,7 @@ "page", "paging" ], - "time": "2016-08-04T15:48:14+00:00" + "time": "2018-06-20T09:32:42+00:00" }, { "name": "zendframework/zend-escaper", @@ -4221,16 +4211,16 @@ }, { "name": "zendframework/zend-feed", - "version": "2.9.0", + "version": "2.10.2", "source": { "type": "git", "url": "https://github.com/zendframework/zend-feed.git", - "reference": "abe88686124d492e0a2a84656f15e5482bfbe030" + "reference": "5253f949f4ad999086ab9b408908b6c6776f24db" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-feed/zipball/abe88686124d492e0a2a84656f15e5482bfbe030", - "reference": "abe88686124d492e0a2a84656f15e5482bfbe030", + "url": "https://api.github.com/repos/zendframework/zend-feed/zipball/5253f949f4ad999086ab9b408908b6c6776f24db", + "reference": "5253f949f4ad999086ab9b408908b6c6776f24db", "shasum": "" }, "require": { @@ -4259,8 +4249,8 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.9-dev", - "dev-develop": "2.10-dev" + "dev-master": "2.10.x-dev", + "dev-develop": "2.11.x-dev" } }, "autoload": { @@ -4278,20 +4268,20 @@ "feed", "zf" ], - "time": "2017-12-04T17:59:38+00:00" + "time": "2018-06-18T20:14:01+00:00" }, { "name": "zendframework/zend-servicemanager", - "version": "2.7.10", + "version": "2.7.11", "source": { "type": "git", "url": "https://github.com/zendframework/zend-servicemanager.git", - "reference": "ba7069c94c9af93122be9fa31cddd37f7707d5b4" + "reference": "99ec9ed5d0f15aed9876433c74c2709eb933d4c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/zendframework/zend-servicemanager/zipball/ba7069c94c9af93122be9fa31cddd37f7707d5b4", - "reference": "ba7069c94c9af93122be9fa31cddd37f7707d5b4", + "url": "https://api.github.com/repos/zendframework/zend-servicemanager/zipball/99ec9ed5d0f15aed9876433c74c2709eb933d4c7", + "reference": "99ec9ed5d0f15aed9876433c74c2709eb933d4c7", "shasum": "" }, "require": { @@ -4330,7 +4320,7 @@ "servicemanager", "zf2" ], - "time": "2017-12-05T16:27:36+00:00" + "time": "2018-06-22T14:49:54+00:00" }, { "name": "zendframework/zend-stdlib", @@ -4500,25 +4490,28 @@ "packages-dev": [ { "name": "myclabs/deep-copy", - "version": "1.7.0", + "version": "1.8.1", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e" + "reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", - "reference": "3b8a3a99ba1f6a3952ac2747d989303cbd6b7a3e", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8", + "reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8", "shasum": "" }, "require": { - "php": "^5.6 || ^7.0" + "php": "^7.1" + }, + "replace": { + "myclabs/deep-copy": "self.version" }, "require-dev": { "doctrine/collections": "^1.0", "doctrine/common": "^2.6", - "phpunit/phpunit": "^4.1" + "phpunit/phpunit": "^7.1" }, "type": "library", "autoload": { @@ -4541,7 +4534,7 @@ "object", "object graph" ], - "time": "2017-10-19T19:58:43+00:00" + "time": "2018-06-11T23:09:50+00:00" }, { "name": "phar-io/manifest", @@ -5111,16 +5104,16 @@ }, { "name": "phpunit/phpunit", - "version": "6.5.8", + "version": "6.5.9", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "4f21a3c6b97c42952fd5c2837bb354ec0199b97b" + "reference": "093ca5508174cd8ab8efe44fd1dde447adfdec8f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/4f21a3c6b97c42952fd5c2837bb354ec0199b97b", - "reference": "4f21a3c6b97c42952fd5c2837bb354ec0199b97b", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/093ca5508174cd8ab8efe44fd1dde447adfdec8f", + "reference": "093ca5508174cd8ab8efe44fd1dde447adfdec8f", "shasum": "" }, "require": { @@ -5191,20 +5184,20 @@ "testing", "xunit" ], - "time": "2018-04-10T11:38:34+00:00" + "time": "2018-07-03T06:40:40+00:00" }, { "name": "phpunit/phpunit-mock-objects", - "version": "5.0.6", + "version": "5.0.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "33fd41a76e746b8fa96d00b49a23dadfa8334cdf" + "reference": "6f9a3c8bf34188a2b53ce2ae7a126089c53e0a9f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/33fd41a76e746b8fa96d00b49a23dadfa8334cdf", - "reference": "33fd41a76e746b8fa96d00b49a23dadfa8334cdf", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/6f9a3c8bf34188a2b53ce2ae7a126089c53e0a9f", + "reference": "6f9a3c8bf34188a2b53ce2ae7a126089c53e0a9f", "shasum": "" }, "require": { @@ -5250,7 +5243,7 @@ "mock", "xunit" ], - "time": "2018-01-06T05:45:45+00:00" + "time": "2018-07-13T03:27:23+00:00" }, { "name": "sebastian/code-unit-reverse-lookup", @@ -5813,28 +5806,39 @@ }, { "name": "symfony/phpunit-bridge", - "version": "v3.1.4", + "version": "v3.4.12", "source": { "type": "git", "url": "https://github.com/symfony/phpunit-bridge.git", - "reference": "1f4e2059cf4ecae1053b9c3027b3fc548fd077b9" + "reference": "8a21eb6bedad38bf1f15d529c65eb9e17d0242fd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/1f4e2059cf4ecae1053b9c3027b3fc548fd077b9", - "reference": "1f4e2059cf4ecae1053b9c3027b3fc548fd077b9", + "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/8a21eb6bedad38bf1f15d529c65eb9e17d0242fd", + "reference": "8a21eb6bedad38bf1f15d529c65eb9e17d0242fd", "shasum": "" }, "require": { "php": ">=5.3.3" }, + "conflict": { + "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0" + }, "suggest": { + "ext-zip": "Zip support is required when using bin/simple-phpunit", "symfony/debug": "For tracking deprecated interfaces usages at runtime with DebugClassLoader" }, + "bin": [ + "bin/simple-phpunit" + ], "type": "symfony-bridge", "extra": { "branch-alias": { - "dev-master": "3.1-dev" + "dev-master": "3.4-dev" + }, + "thanks": { + "name": "phpunit/phpunit", + "url": "https://github.com/sebastianbergmann/phpunit" } }, "autoload": { @@ -5864,7 +5868,7 @@ ], "description": "Symfony PHPUnit Bridge", "homepage": "https://symfony.com", - "time": "2016-08-19T06:48:39+00:00" + "time": "2018-06-10T07:25:02+00:00" }, { "name": "theseer/tokenizer", @@ -5959,17 +5963,11 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "composer/composer": 20, - "friendsofsymfony/user-bundle": 20 - }, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { "php": ">=7.0" }, - "platform-dev": [], - "platform-overrides": { - "php": "7.0.27" - } + "platform-dev": [] } diff --git a/src/Packagist/WebBundle/Command/DumpPackagesCommand.php b/src/Packagist/WebBundle/Command/DumpPackagesCommand.php deleted file mode 100644 index d9292fef..00000000 --- a/src/Packagist/WebBundle/Command/DumpPackagesCommand.php +++ /dev/null @@ -1,95 +0,0 @@ - - * Nils Adermann - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Packagist\WebBundle\Command; - -use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Input\InputOption; -use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Filesystem\LockHandler; - -/** - * @author Jordi Boggiano - */ -class DumpPackagesCommand extends ContainerAwareCommand -{ - /** - * {@inheritdoc} - */ - protected function configure() - { - $this - ->setName('packagist:dump') - ->setDefinition(array( - new InputOption('force', null, InputOption::VALUE_NONE, 'Force a dump of all packages'), - )) - ->setDescription('Dumps the packages into a packages.json + included files') - ; - } - - /** - * {@inheritdoc} - */ - protected function execute(InputInterface $input, OutputInterface $output) - { - $force = (Boolean) $input->getOption('force'); - $verbose = (Boolean) $input->getOption('verbose'); - - $deployLock = $this->getContainer()->getParameter('kernel.cache_dir').'/deploy.globallock'; - if (file_exists($deployLock)) { - if ($verbose) { - $output->writeln('Aborting, '.$deployLock.' file present'); - } - return; - } - - // another dumper is still active - $lock = new LockHandler('packagist_package_dumper'); - if (!$lock->lock()) { - if ($verbose) { - $output->writeln('Aborting, another dumper is still active'); - } - return; - } - - $doctrine = $this->getContainer()->get('doctrine'); - - if ($force) { - $packages = $doctrine->getManager()->getConnection()->fetchAll('SELECT id FROM package ORDER BY id ASC'); - } else { - $packages = $doctrine->getRepository('PackagistWebBundle:Package')->getStalePackagesForDumping(); - } - - $ids = array(); - foreach ($packages as $package) { - $ids[] = $package['id']; - } - if (!$ids && !$force) { - if ($verbose) { - $output->writeln('Aborting, no packages to dump and not doing a forced run'); - } - return 0; - } - - ini_set('memory_limit', -1); - gc_enable(); - - try { - $result = $this->getContainer()->get('packagist.package_dumper')->dump($ids, $force, $verbose); - } finally { - $lock->release(); - } - - return $result ? 0 : 1; - } -} diff --git a/src/Packagist/WebBundle/Command/IndexPackagesCommand.php b/src/Packagist/WebBundle/Command/IndexPackagesCommand.php deleted file mode 100644 index 47bbc9ec..00000000 --- a/src/Packagist/WebBundle/Command/IndexPackagesCommand.php +++ /dev/null @@ -1,298 +0,0 @@ - - * Nils Adermann - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Packagist\WebBundle\Command; - -use Packagist\WebBundle\Entity\Package; -use Packagist\WebBundle\Model\DownloadManager; -use Packagist\WebBundle\Model\FavoriteManager; -use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand; -use Symfony\Component\Console\Input\InputArgument; -use Symfony\Component\Console\Input\InputInterface; -use Symfony\Component\Console\Input\InputOption; -use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Filesystem\LockHandler; -use Doctrine\DBAL\Connection; - -class IndexPackagesCommand extends ContainerAwareCommand -{ - /** - * {@inheritdoc} - */ - protected function configure() - { - $this - ->setName('packagist:index') - ->setDefinition(array( - new InputOption('force', null, InputOption::VALUE_NONE, 'Force a re-indexing of all packages'), - new InputOption('all', null, InputOption::VALUE_NONE, 'Index all packages without clearing the index first'), - new InputArgument('package', InputArgument::OPTIONAL, 'Package name to index'), - )) - ->setDescription('Indexes packages in Algolia') - ; - } - - /** - * {@inheritdoc} - */ - protected function execute(InputInterface $input, OutputInterface $output) - { - $verbose = $input->getOption('verbose'); - $force = $input->getOption('force'); - $indexAll = $input->getOption('all'); - $package = $input->getArgument('package'); - $indexName = $this->getContainer()->getParameter('algolia.index_name'); - - $deployLock = $this->getContainer()->getParameter('kernel.cache_dir').'/deploy.globallock'; - if (file_exists($deployLock)) { - if ($verbose) { - $output->writeln('Aborting, '.$deployLock.' file present'); - } - return; - } - - $doctrine = $this->getContainer()->get('doctrine'); - $algolia = $this->getContainer()->get('packagist.algolia.client'); - $index = $algolia->initIndex($indexName); - - $redis = $this->getContainer()->get('snc_redis.default'); - $downloadManager = $this->getContainer()->get('packagist.download_manager'); - $favoriteManager = $this->getContainer()->get('packagist.favorite_manager'); - - $lock = new LockHandler('packagist_algolia_indexer'); - - // another dumper is still active - if (!$lock->lock()) { - if ($verbose) { - $output->writeln('Aborting, another indexer is still active'); - } - return; - } - - if ($package) { - $packages = array(array('id' => $doctrine->getRepository('PackagistWebBundle:Package')->findOneByName($package)->getId())); - } elseif ($force || $indexAll) { - $packages = $doctrine->getManager()->getConnection()->fetchAll('SELECT id FROM package ORDER BY id ASC'); - $doctrine->getManager()->getConnection()->executeQuery('UPDATE package SET indexedAt = NULL'); - } else { - $packages = $doctrine->getRepository('PackagistWebBundle:Package')->getStalePackagesForIndexing(); - } - - $ids = array(); - foreach ($packages as $row) { - $ids[] = $row['id']; - } - - // clear index before a full-update - if ($force && !$package) { - if ($verbose) { - $output->writeln('Deleting existing index'); - } - - $index->clearIndex(); - } - - $total = count($ids); - $current = 0; - - // update package index - while ($ids) { - $indexTime = new \DateTime; - $idsSlice = array_splice($ids, 0, 50); - $packages = $doctrine->getRepository('PackagistWebBundle:Package')->findById($idsSlice); - - $idsToUpdate = []; - $records = []; - - foreach ($packages as $package) { - $current++; - if ($verbose) { - $output->writeln('['.sprintf('%'.strlen($total).'d', $current).'/'.$total.'] Indexing '.$package->getName()); - } - - // delete spam packages from the search index - if ($package->isAbandoned() && $package->getReplacementPackage() === 'spam/spam') { - try { - $index->deleteObject($package->getName()); - $idsToUpdate[] = $package->getId(); - continue; - } catch (\AlgoliaSearch\AlgoliaException $e) { - } - } - - try { - $tags = $this->getTags($doctrine, $package); - - $records[] = $this->packageToSearchableArray($package, $tags, $redis, $downloadManager, $favoriteManager); - - $idsToUpdate[] = $package->getId(); - } catch (\Exception $e) { - $output->writeln('Exception: '.$e->getMessage().', skipping package '.$package->getName().'.'); - - continue; - } - - $providers = $this->getProviders($doctrine, $package); - foreach ($providers as $provided) { - $records[] = $this->createSearchableProvider($provided['packageName']); - } - } - - try { - $index->addObjects($records); - } catch (\Exception $e) { - $output->writeln(''.get_class($e).': '.$e->getMessage().', occurred while processing packages: '.implode(',', $idsSlice).''); - continue; - } - - $doctrine->getManager()->clear(); - unset($packages); - - if ($verbose) { - $output->writeln('Updating package indexedAt column'); - } - - $this->updateIndexedAt($idsToUpdate, $doctrine, $indexTime->format('Y-m-d H:i:s')); - } - - $lock->release(); - } - - private function packageToSearchableArray( - Package $package, - array $tags, - $redis, - DownloadManager $downloadManager, - FavoriteManager $favoriteManager - ) { - $faversCount = $favoriteManager->getFaverCount($package); - $downloads = $downloadManager->getDownloads($package); - $downloadsLog = $downloads['monthly'] > 0 ? log($downloads['monthly'], 10) : 0; - $starsLog = $package->getGitHubStars() > 0 ? log($package->getGitHubStars(), 10) : 0; - $popularity = round($downloadsLog + $starsLog); - $trendiness = $redis->zscore('downloads:trending', $package->getId()); - - $record = [ - 'id' => $package->getId(), - 'objectID' => $package->getName(), - 'name' => $package->getName(), - 'package_organisation' => $package->getVendor(), - 'package_name' => $package->getPackageName(), - 'description' => preg_replace('{[\x00-\x1f]+}u', '', strip_tags($package->getDescription())), - 'type' => $package->getType(), - 'repository' => $package->getRepository(), - 'language' => $package->getLanguage(), - # log10 of downloads over the last 7days - 'trendiness' => $trendiness > 0 ? log($trendiness, 10) : 0, - # log10 of downloads + gh stars - 'popularity' => $popularity, - 'meta' => [ - 'downloads' => $downloads['total'], - 'downloads_formatted' => number_format($downloads['total'], 0, ',', ' '), - 'favers' => $faversCount, - 'favers_formatted' => number_format($faversCount, 0, ',', ' '), - ], - ]; - - if ($package->isAbandoned()) { - $record['abandoned'] = 1; - $record['replacementPackage'] = $package->getReplacementPackage() ?: ''; - } else { - $record['abandoned'] = 0; - $record['replacementPackage'] = ''; - } - - $record['tags'] = $tags; - - return $record; - } - - private function createSearchableProvider(string $provided) - { - $record = [ - 'id' => $provided, - 'objectID' => 'virtual:'.$provided, - 'name' => $provided, - 'package_organisation' => preg_replace('{/.*$}', '', $provided), - 'package_name' => preg_replace('{^[^/]*/}', '', $provided), - 'description' => '', - 'type' => 'virtual-package', - 'repository' => '', - 'language' => '', - 'trendiness' => 100, - 'popularity' => 4, - 'abandoned' => 0, - 'replacementPackage' => '', - 'tags' => [], - ]; - - return $record; - } - - private function getProviders($doctrine, Package $package) - { - return $doctrine->getManager()->getConnection()->fetchAll( - 'SELECT lp.packageName - FROM package p - JOIN package_version pv ON p.id = pv.package_id - JOIN link_provide lp ON lp.version_id = pv.id - WHERE p.id = :id - AND pv.development = true - GROUP BY lp.packageName', - ['id' => $package->getId()] - ); - } - - private function getTags($doctrine, Package $package) - { - $tags = $doctrine->getManager()->getConnection()->fetchAll( - 'SELECT t.name FROM package p - JOIN package_version pv ON p.id = pv.package_id - JOIN version_tag vt ON vt.version_id = pv.id - JOIN tag t ON t.id = vt.tag_id - WHERE p.id = :id - GROUP BY t.id, t.name', - ['id' => $package->getId()] - ); - - foreach ($tags as $idx => $tag) { - $tags[$idx] = $tag['name']; - } - - return array_map(function ($tag) { - return mb_strtolower(preg_replace('{[\x00-\x1f]+}u', '', $tag), 'UTF-8'); - }, $tags); - } - - private function updateIndexedAt(array $idsToUpdate, $doctrine, string $time) - { - $retries = 5; - // retry loop in case of a lock timeout - while ($retries--) { - try { - $doctrine->getManager()->getConnection()->executeQuery( - 'UPDATE package SET indexedAt=:indexed WHERE id IN (:ids)', - [ - 'ids' => $idsToUpdate, - 'indexed' => $time, - ], - ['ids' => Connection::PARAM_INT_ARRAY] - ); - } catch (\Exception $e) { - if (!$retries) { - throw $e; - } - sleep(2); - } - } - } -} diff --git a/src/Packagist/WebBundle/Command/RunWorkersCommand.php b/src/Packagist/WebBundle/Command/RunWorkersCommand.php index c6f7c94e..ea9140b2 100644 --- a/src/Packagist/WebBundle/Command/RunWorkersCommand.php +++ b/src/Packagist/WebBundle/Command/RunWorkersCommand.php @@ -7,7 +7,6 @@ use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Filesystem\LockHandler; use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand; -use Seld\Signal\SignalHandler; class RunWorkersCommand extends ContainerAwareCommand { diff --git a/src/Packagist/WebBundle/Command/UpdatePackagesCommand.php b/src/Packagist/WebBundle/Command/UpdatePackagesCommand.php index 1c0b9152..8cb0bdcd 100644 --- a/src/Packagist/WebBundle/Command/UpdatePackagesCommand.php +++ b/src/Packagist/WebBundle/Command/UpdatePackagesCommand.php @@ -12,14 +12,6 @@ namespace Packagist\WebBundle\Command; -use Composer\Factory; -use Composer\IO\BufferIO; -use Composer\IO\ConsoleIO; -use Composer\Package\Loader\ArrayLoader; -use Composer\Package\Loader\ValidatingArrayLoader; -use Composer\Repository\InvalidRepositoryException; -use Composer\Repository\VcsRepository; -use Packagist\WebBundle\Package\Updater; use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; @@ -58,7 +50,6 @@ protected function execute(InputInterface $input, OutputInterface $output) $package = $input->getArgument('package'); $doctrine = $this->getContainer()->get('doctrine'); - $router = $this->getContainer()->get('router'); $deleteBefore = false; $updateEqualRefs = false; $randomTimes = true; @@ -113,5 +104,7 @@ protected function execute(InputInterface $input, OutputInterface $output) } $locker->unlockCommand($this->getName()); + + return 0; } } diff --git a/src/Packagist/WebBundle/Controller/ApiController.php b/src/Packagist/WebBundle/Controller/ApiController.php index 84e91747..c64ed96f 100644 --- a/src/Packagist/WebBundle/Controller/ApiController.php +++ b/src/Packagist/WebBundle/Controller/ApiController.php @@ -14,11 +14,9 @@ use Packagist\WebBundle\Entity\Package; use Packagist\WebBundle\Entity\User; -use Packagist\WebBundle\Entity\Version; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method; use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; -use Symfony\Component\HttpFoundation\BinaryFileResponse; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -43,7 +41,7 @@ public function createPackageAction(Request $request) $package = new Package; $package->setEntityRepository($this->getDoctrine()->getRepository('PackagistWebBundle:Package')); $package->setRouter($this->get('router')); - $user = $this->findUser($request); + $user = $this->getUser(); $package->addMaintainer($user); $package->setRepository($url); $errors = $this->get('validator')->validate($package); @@ -116,7 +114,7 @@ public function updatePackageAction(Request $request) */ public function editPackageAction(Request $request, Package $package) { - $user = $this->findUser($request); + $user = $this->getUser(); if (!$package->getMaintainers()->contains($user) && !$this->isGranted('ROLE_EDIT_PACKAGES')) { throw new AccessDeniedException; } @@ -254,14 +252,13 @@ protected function receivePost(Request $request, $url, $urlRegex) } // find the user - $user = $this->findUser($request); - + $user = $this->getUser(); if (!$user) { return new Response(json_encode(array('status' => 'error', 'message' => 'Invalid credentials')), 403); } - // try to find the user package - $packages = $this->findPackagesByUrl($user, $url, $urlRegex); + // try to find the all package + $packages = $this->findPackagesByUrl($url, $urlRegex); if (!$packages) { return new Response(json_encode(array('status' => 'error', 'message' => 'Could not find a package that matches this request (does user maintain the package?)')), 404); @@ -312,19 +309,19 @@ protected function findUser(Request $request) /** * Find a user package given by its full URL * - * @param User $user * @param string $url * @param string $urlRegex * @return array the packages found */ - protected function findPackagesByUrl(User $user, $url, $urlRegex) + protected function findPackagesByUrl($url, $urlRegex) { if (!preg_match($urlRegex, $url, $matched)) { - return array(); + return []; } - $packages = array(); - foreach ($user->getPackages() as $package) { + $packages = []; + $repo = $this->getDoctrine()->getRepository('PackagistWebBundle:Package'); + foreach ($repo->findAll() as $package) { if (preg_match($urlRegex, $package->getRepository(), $candidate) && strtolower($candidate['host']) === strtolower($matched['host']) && strtolower($candidate['path']) === strtolower($matched['path']) diff --git a/src/Packagist/WebBundle/Controller/GroupController.php b/src/Packagist/WebBundle/Controller/GroupController.php index e90c4b2a..6ecdebd4 100644 --- a/src/Packagist/WebBundle/Controller/GroupController.php +++ b/src/Packagist/WebBundle/Controller/GroupController.php @@ -93,8 +93,8 @@ protected function handleUpdate(Request $request, Group $group, $flashMessage) { $form = $this->createForm(GroupType::class, $group); if ($request->getMethod() === 'POST') { - $form->submit($request); - if ($form->isValid()) { + $form->handleRequest($request); + if ($form->isSubmitted() && $form->isValid()) { $group = $form->getData(); $em = $this->getDoctrine()->getManager(); $em->persist($group); diff --git a/src/Packagist/WebBundle/Controller/PackageController.php b/src/Packagist/WebBundle/Controller/PackageController.php index 39f03f25..c60d003a 100644 --- a/src/Packagist/WebBundle/Controller/PackageController.php +++ b/src/Packagist/WebBundle/Controller/PackageController.php @@ -25,6 +25,7 @@ use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\Security\Core\Exception\AccessDeniedException; @@ -46,6 +47,10 @@ class PackageController extends Controller */ public function allAction(Request $req) { + if (!$this->isGranted('ROLE_ADMIN')) { + throw new AccessDeniedException; + } + return new RedirectResponse($this->generateUrl('browse'), Response::HTTP_MOVED_PERMANENTLY); } @@ -56,6 +61,10 @@ public function allAction(Request $req) */ public function listAction(Request $req) { + if (!$this->isGranted('ROLE_ADMIN')) { + throw new AccessDeniedException; + } + /** @var PackageRepository $repo */ $repo = $this->getDoctrine()->getRepository('PackagistWebBundle:Package'); $fields = (array) $req->query->get('fields', array()); @@ -88,7 +97,7 @@ public function listAction(Request $req) public function submitPackageAction(Request $req) { $user = $this->getUser(); - if (!$user->isEnabled()) { + if (!$user->isEnabled() || !$this->isGranted('ROLE_ADMIN')) { throw new AccessDeniedException(); } @@ -126,10 +135,14 @@ public function submitPackageAction(Request $req) */ public function fetchInfoAction(Request $req) { + if (!$this->isGranted('ROLE_ADMIN')) { + throw new AccessDeniedException; + } + $package = new Package; $package->setEntityRepository($this->getDoctrine()->getRepository('PackagistWebBundle:Package')); $package->setRouter($this->get('router')); - $form = $this->createForm(new PackageType, $package); + $form = $this->createForm(PackageType::class, $package); $user = $this->getUser(); $package->addMaintainer($user); @@ -183,6 +196,10 @@ public function fetchInfoAction(Request $req) */ public function viewVendorAction($vendor) { + if (!$this->isGranted('ROLE_ADMIN')) { + throw new AccessDeniedException; + } + $packages = $this->getDoctrine() ->getRepository('PackagistWebBundle:Package') ->getFilteredQueryBuilder(['vendor' => $vendor.'/%'], true) @@ -201,37 +218,6 @@ public function viewVendorAction($vendor) ); } - /** - * @Route( - * "/p/{name}.{_format}", - * name="view_package_alias", - * requirements={"name"="[A-Za-z0-9_.-]+(/[A-Za-z0-9_.-]+?)?", "_format"="(json)"}, - * defaults={"_format"="html"} - * ) - * @Route( - * "/packages/{name}", - * name="view_package_alias2", - * requirements={"name"="[A-Za-z0-9_.-]+(/[A-Za-z0-9_.-]+?)?/"}, - * defaults={"_format"="html"} - * ) - * @Method({"GET"}) - */ - public function viewPackageAliasAction(Request $req, $name) - { - $format = $req->getRequestFormat(); - if ($format === 'html') { - $format = null; - } - if ($format === 'json' || (!$format && substr($name, -5) === '.json')) { - throw new NotFoundHttpException('Package not found'); - } - if (false === strpos(trim($name, '/'), '/')) { - return $this->redirect($this->generateUrl('view_vendor', array('vendor' => $name, '_format' => $format))); - } - - return $this->redirect($this->generateUrl('view_package', array('name' => trim($name, '/'), '_format' => $format))); - } - /** * @Route( * "/providers/{name}", @@ -243,6 +229,10 @@ public function viewPackageAliasAction(Request $req, $name) */ public function viewProvidersAction($name) { + if (!$this->isGranted('ROLE_ADMIN')) { + throw new AccessDeniedException; + } + /** @var PackageRepository $repo */ $repo = $this->getDoctrine()->getRepository('PackagistWebBundle:Package'); $providers = $repo->findProviders($name); @@ -293,6 +283,9 @@ public function viewPackageAction(Request $req, $name) $req->getSession()->save(); if (preg_match('{^(?Pext-[a-z0-9_.-]+?)/(?Pdependents|suggesters)$}i', $name, $match)) { + if (!$this->isGranted('ROLE_ADMIN')) { + throw new AccessDeniedHttpException; + } return $this->{$match['method'].'Action'}($req, $match['pkg']); } @@ -303,19 +296,11 @@ public function viewPackageAction(Request $req, $name) /** @var Package $package */ $package = $repo->getPartialPackageByNameWithVersions($name); } catch (NoResultException $e) { - if ('json' === $req->getRequestFormat()) { - return new JsonResponse(array('status' => 'error', 'message' => 'Package not found'), 404); - } - - if ($providers = $repo->findProviders($name)) { - return $this->redirect($this->generateUrl('view_providers', array('name' => $name))); - } - - return $this->redirect($this->generateUrl('search', array('q' => $name, 'reason' => 'package_not_found'))); + throw new NotFoundHttpException; } - if ($package->isAbandoned() && $package->getReplacementPackage() === 'spam/spam') { - throw new NotFoundHttpException('This is a spam package'); + if (!$this->isGranted('ROLE_ADMIN', $package)) { + throw new NotFoundHttpException; } if ('json' === $req->getRequestFormat()) { @@ -416,6 +401,10 @@ public function viewPackageAction(Request $req, $name) */ public function viewPackageDownloadsAction(Request $req, $name) { + if (!$this->isGranted('ROLE_ADMIN')) { + throw new AccessDeniedHttpException; + } + /** @var PackageRepository $repo */ $repo = $this->getDoctrine()->getRepository('PackagistWebBundle:Package'); @@ -475,6 +464,9 @@ public function viewPackageVersionAction(Request $req, $versionId) /** @var VersionRepository $repo */ $repo = $this->getDoctrine()->getRepository('PackagistWebBundle:Version'); + if (!$this->isGranted('ROLE_ADMIN', $repo->find($versionId))) { + throw new AccessDeniedHttpException; + } $html = $this->renderView( 'PackagistWebBundle:Package:versionDetails.html.twig', @@ -494,6 +486,10 @@ public function viewPackageVersionAction(Request $req, $versionId) */ public function deletePackageVersionAction(Request $req, $versionId) { + if (!$this->isGranted('ROLE_ADMIN')) { + throw new AccessDeniedException; + } + /** @var VersionRepository $repo */ $repo = $this->getDoctrine()->getRepository('PackagistWebBundle:Version'); @@ -522,6 +518,10 @@ public function deletePackageVersionAction(Request $req, $versionId) */ public function updatePackageAction(Request $req, $name) { + if (!$this->isGranted('ROLE_ADMIN')) { + throw new AccessDeniedException; + } + $doctrine = $this->getDoctrine(); try { @@ -581,6 +581,10 @@ public function updatePackageAction(Request $req, $name) */ public function deletePackageAction(Request $req, $name) { + if (!$this->isGranted('ROLE_ADMIN')) { + throw new AccessDeniedException; + } + $doctrine = $this->getDoctrine(); try { @@ -613,6 +617,10 @@ public function deletePackageAction(Request $req, $name) */ public function createMaintainerAction(Request $req, $name) { + if (!$this->isGranted('ROLE_ADMIN')) { + throw new AccessDeniedException; + } + /** @var $package Package */ $package = $this->getDoctrine() ->getRepository('PackagistWebBundle:Package') @@ -670,6 +678,10 @@ public function createMaintainerAction(Request $req, $name) */ public function removeMaintainerAction(Request $req, $name) { + if (!$this->isGranted('ROLE_ADMIN')) { + throw new AccessDeniedException; + } + /** @var $package Package */ $package = $this->getDoctrine() ->getRepository('PackagistWebBundle:Package') @@ -831,6 +843,10 @@ public function unabandonAction(Package $package) */ public function statsAction(Request $req, Package $package) { + if (!$this->isGranted('ROLE_ADMIN')) { + throw new AccessDeniedException; + } + $versions = $package->getVersions()->toArray(); usort($versions, Package::class.'::sortVersions'); $date = $this->guessStatsStartDate($package); @@ -874,6 +890,10 @@ public function statsAction(Request $req, Package $package) */ public function dependentsAction(Request $req, $name) { + if (!$this->isGranted('ROLE_ADMIN')) { + throw new AccessDeniedException; + } + $page = $req->query->get('page', 1); /** @var PackageRepository $repo */ @@ -903,6 +923,10 @@ public function dependentsAction(Request $req, $name) */ public function suggestersAction(Request $req, $name) { + if (!$this->isGranted('ROLE_ADMIN')) { + throw new AccessDeniedException; + } + $page = $req->query->get('page', 1); /** @var PackageRepository $repo */ @@ -933,6 +957,10 @@ public function suggestersAction(Request $req, $name) */ public function overallStatsAction(Request $req, Package $package, Version $version = null) { + if (!$this->isGranted('ROLE_ADMIN')) { + throw new AccessDeniedException; + } + if ($from = $req->query->get('from')) { $from = new DateTimeImmutable($from); } else { @@ -1008,6 +1036,10 @@ public function overallStatsAction(Request $req, Package $package, Version $vers */ public function versionStatsAction(Request $req, Package $package, $version) { + if (!$this->isGranted('ROLE_ADMIN')) { + throw new AccessDeniedException; + } + $normalizer = new VersionParser; $normVersion = $normalizer->normalize($version); diff --git a/src/Packagist/WebBundle/Controller/ProviderController.php b/src/Packagist/WebBundle/Controller/ProviderController.php index be607ae6..ef2c20b5 100644 --- a/src/Packagist/WebBundle/Controller/ProviderController.php +++ b/src/Packagist/WebBundle/Controller/ProviderController.php @@ -4,6 +4,7 @@ use Packagist\WebBundle\Entity\Package; use Packagist\WebBundle\Entity\Version; +use Packagist\WebBundle\Service\DistManager; use Symfony\Component\HttpFoundation\BinaryFileResponse; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Response; @@ -22,7 +23,7 @@ public function packagesAction() $manager = $this->container->get('packagist.package_manager'); $rootPackages = $manager->getRootPackagesJson($this->getUser()); - return new JsonResponse($rootPackages); + return new Response(\json_encode($rootPackages), 200, ['Content-Type' => 'application/json']); } /** @@ -45,7 +46,7 @@ public function providersAction($hash) return $this->createNotFound(); } - return new JsonResponse($providers); + return new Response(\json_encode($providers), 200, ['Content-Type' => 'application/json']); } /** @@ -73,7 +74,7 @@ public function packageAction($package) return $this->createNotFound(); } - return new JsonResponse($package); + return new Response(\json_encode($package), 200, ['Content-Type' => 'application/json']); } /** @@ -92,6 +93,7 @@ public function packageAction($package) public function zipballAction(Package $package, $hash) { $config = $this->container->get('packagist.dist_config'); + $distManager = new DistManager($config); if (false === \preg_match('{[a-f0-9]{40}}i', $hash, $match)) { return new JsonResponse(['status' => 'error', 'message' => 'Not Found'], 404); } @@ -105,19 +107,35 @@ function (Version $version) use ($match) { } ); + // Try to download from cache + if ($versions->count() === 0) { + list($path, $versionName) = $distManager->lookupInCache($match[0], $package->getName()); + if (null !== $versionName) { + $version = $package->getVersions() + ->filter( + function (Version $version) use ($versionName) { + return $versionName === $version->getVersion(); + } + )->first(); + if ($version && $this->isGranted('ROLE_ADMIN', $version)) { + return new BinaryFileResponse($path); + } + } + } + /** @var Version $version */ foreach ($versions as $version) { - if (false === $this->isGranted('ROLE_USER', $version)) { + if (!$this->isGranted('ROLE_ADMIN', $version)) { continue; } - $dist = $version->getDist(); - if ($file = $config->generateDistFileName($version->getName(), $dist['reference']) and \file_exists($file)) { - return new BinaryFileResponse($file); + if ($path = $distManager->getDistPath($version)) { + return new BinaryFileResponse($path); } + break; } - return new JsonResponse(['status' => 'error', 'message' => 'Not Found'], 404); + return $this->createNotFound(); } protected function createNotFound() diff --git a/src/Packagist/WebBundle/Controller/UserController.php b/src/Packagist/WebBundle/Controller/UserController.php index c39790a4..260c4801 100644 --- a/src/Packagist/WebBundle/Controller/UserController.php +++ b/src/Packagist/WebBundle/Controller/UserController.php @@ -87,6 +87,7 @@ public function updateAction(Request $request, User $user) public function createAction(Request $request) { $user = new User(); + $user->generateApiToken(); return $this->handleUpdate($request, $user, 'User has been saved.'); } @@ -94,8 +95,8 @@ protected function handleUpdate(Request $request, User $user, $flashMessage) { $form = $this->createForm(CustomerUserType::class, $user); if ($request->getMethod() === 'POST') { - $form->submit($request); - if ($form->isValid()) { + $form->handleRequest($request); + if ($form->isSubmitted() && $form->isValid()) { $user = $form->getData(); $this->get('fos_user.user_manager')->updateUser($user); @@ -156,17 +157,39 @@ public function myProfileAction(Request $req) */ public function profileAction(Request $req, User $user) { + $deleteForm = $this->createFormBuilder([])->getForm(); $packages = $this->getUserPackages($req, $user); $data = [ 'packages' => $packages, 'meta' => $this->getPackagesMetadata($packages), 'user' => $user, + 'deleteForm' => $deleteForm->createView() ]; return $data; } + /** + * @Route("/users/{name}/delete", name="user_delete") + * @ParamConverter("user", options={"mapping": {"name": "username"}}) + */ + public function deleteAction(Request $request, User $user) + { + $form = $this->createFormBuilder([])->getForm(); + $form->submit($request->request->get('form')); + if ($form->isValid()) { + $request->getSession()->save(); + $em = $this->getDoctrine()->getManager(); + $em->remove($user); + $em->flush(); + + return new RedirectResponse('/'); + } + + return new Response('Invalid form input', 400); + } + /** * @Template() * @Route("/users/{name}/favorites/", name="user_favorites") diff --git a/src/Packagist/WebBundle/Controller/WebController.php b/src/Packagist/WebBundle/Controller/WebController.php index d8c6233a..94ec903a 100644 --- a/src/Packagist/WebBundle/Controller/WebController.php +++ b/src/Packagist/WebBundle/Controller/WebController.php @@ -12,18 +12,19 @@ namespace Packagist\WebBundle\Controller; +use Doctrine\ORM\QueryBuilder; +use Packagist\WebBundle\Entity\Package; use Packagist\WebBundle\Form\Model\SearchQuery; use Packagist\WebBundle\Form\Type\SearchQueryType; use Pagerfanta\Adapter\ArrayAdapter; +use Pagerfanta\Adapter\CallbackAdapter; use Pagerfanta\Pagerfanta; use Predis\Connection\ConnectionException; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Cache; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; -use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\Routing\Generator\UrlGeneratorInterface; /** * @author Jordi Boggiano @@ -33,10 +34,20 @@ class WebController extends Controller /** * @Template() * @Route("/", name="home") + * + * @param Request $request + * @return array */ - public function indexAction() + public function indexAction(Request $request) { - return array('page' => 'home'); + $page = $request->query->get('page', 1); + $paginator = new Pagerfanta($this->createAdapter()); + $paginator->setMaxPerPage(10); + $paginator->setCurrentPage($page); + + return [ + 'packages' => $paginator + ]; } /** @@ -79,9 +90,14 @@ public function searchAction(Request $req) $perPage = max(0, min(100, $perPage)); } + $allowed = $this->isGranted('ROLE_ADMIN') ? null : + $this->getDoctrine() + ->getRepository('PackagistWebBundle:Group') + ->getAllowedPackagesForUser($this->getUser(), false); + $page = $req->query->get('page', 1) - 1; $packages = $this->getDoctrine()->getRepository('PackagistWebBundle:Package') - ->searchPackage($query, $perPage, $page); + ->searchPackage($query, $perPage, $page, $allowed); } $paginator = new Pagerfanta(new ArrayAdapter($packages)); @@ -328,4 +344,47 @@ private function computeSearchQuery(Request $req, array $filteredOrderBys) ); } } + + private function createAdapter() + { + /** @var QueryBuilder $qb */ + $qb = $this->get('doctrine')->getManager()->createQueryBuilder(); + $qb->from('PackagistWebBundle:Package', 'p'); + $repo = $this->get('doctrine')->getRepository('PackagistWebBundle:Package'); + if (!$this->isGranted('ROLE_ADMIN')) { + $packages = $this->get('doctrine')->getRepository('PackagistWebBundle:Group') + ->getAllowedPackagesForUser($this->getUser()); + $qb->andWhere('p.id IN (:ids)') + ->setParameter('ids', $packages); + } + + $adapter = new CallbackAdapter( + function () use ($qb) { + $qb = clone $qb; + $qb->select('COUNT(1)'); + return $qb->getQuery()->getSingleScalarResult(); + }, + function ($offset, $length) use ($qb, $repo) { + $qb = clone $qb; + $qb->select('p') + ->setMaxResults($length) + ->setFirstResult($offset) + ->orderBy('p.id', 'DESC'); + + $packages = array_map( + function (Package $package) use ($repo) { + return [ + 'package' => $package, + 'dependencies' => $repo->getDependents($package->getName()) + ]; + }, + $qb->getQuery()->getResult() + ); + + return $packages; + } + ); + + return $adapter; + } } diff --git a/src/Packagist/WebBundle/DependencyInjection/Security/ApiHttpBasicFactory.php b/src/Packagist/WebBundle/DependencyInjection/Security/ApiHttpBasicFactory.php index 319a5d2b..a3c2806b 100644 --- a/src/Packagist/WebBundle/DependencyInjection/Security/ApiHttpBasicFactory.php +++ b/src/Packagist/WebBundle/DependencyInjection/Security/ApiHttpBasicFactory.php @@ -4,8 +4,8 @@ use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SecurityFactoryInterface; use Symfony\Component\Config\Definition\Builder\NodeDefinition; +use Symfony\Component\DependencyInjection\ChildDefinition; use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\DefinitionDecorator; use Symfony\Component\DependencyInjection\Reference; class ApiHttpBasicFactory implements SecurityFactoryInterface @@ -15,35 +15,23 @@ class ApiHttpBasicFactory implements SecurityFactoryInterface */ public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint) { - $provider = 'packagist.security.authentication.provider.'.$id; + $provider = 'packagist.security.authentication.provider.' . $id; $container - ->setDefinition($provider, new DefinitionDecorator('packagist.security.authentication.provider')); + ->setDefinition($provider, new ChildDefinition('packagist.security.authentication.provider')) + ->replaceArgument(1, new Reference('security.user_checker.'.$id)); // entry point $entryPointId = $this->createEntryPoint($container, $id, $config, $defaultEntryPoint); // listener $listenerId = 'packagist.security.authentication.listener.'.$id; - $listener = $container->setDefinition($listenerId, new DefinitionDecorator('packagist.security.authentication.listener')); + $listener = $container->setDefinition($listenerId, new ChildDefinition('packagist.security.authentication.listener')); $listener->replaceArgument(2, $id) ->replaceArgument(3, new Reference($entryPointId)); return [$provider, $listenerId, $entryPointId]; } - protected function createEntryPoint(ContainerBuilder $container, $id, $config, $defaultEntryPoint) - { - if (null !== $defaultEntryPoint) { - return $defaultEntryPoint; - } - - $entryPointId = 'packagist.authentication.entry_point.'.$id; - $container - ->setDefinition($entryPointId, new DefinitionDecorator('packagist.authentication.entry_point')); - - return $entryPointId; - } - /** * {@inheritdoc} */ @@ -63,4 +51,17 @@ public function getKey() public function addConfiguration(NodeDefinition $builder) { } + + protected function createEntryPoint(ContainerBuilder $container, $id, $config, $defaultEntryPoint) + { + if (null !== $defaultEntryPoint) { + return $defaultEntryPoint; + } + + $entryPointId = 'packagist.authentication.entry_point.'.$id; + $container + ->setDefinition($entryPointId, new ChildDefinition('packagist.authentication.entry_point')); + + return $entryPointId; + } } diff --git a/src/Packagist/WebBundle/Entity/GroupRepository.php b/src/Packagist/WebBundle/Entity/GroupRepository.php index cf9af88c..d9a9b927 100644 --- a/src/Packagist/WebBundle/Entity/GroupRepository.php +++ b/src/Packagist/WebBundle/Entity/GroupRepository.php @@ -39,10 +39,11 @@ public function getAllowedVersionByPackage(User $user, Package $package) /** * @param User $user + * @param bool $hydration * * @return Package[] */ - public function getAllowedPackagesForUser(User $user) + public function getAllowedPackagesForUser(User $user, $hydration = true) { $qb = $this->_em->createQueryBuilder(); $qb @@ -55,7 +56,7 @@ public function getAllowedPackagesForUser(User $user) ->where($qb->expr()->eq('u.id', $user->getId())); $result = $qb->getQuery()->getResult(); - if ($result) { + if ($hydration && $result) { $qb = $this->_em->createQueryBuilder(); $qb->select('p') ->from('PackagistWebBundle:Package', 'p') @@ -65,6 +66,6 @@ public function getAllowedPackagesForUser(User $user) return $qb->getQuery()->getResult(); } - return []; + return $result ? array_column($result, 'id') : []; } } diff --git a/src/Packagist/WebBundle/Entity/Package.php b/src/Packagist/WebBundle/Entity/Package.php index 2de8e0d1..d4ea4a5f 100644 --- a/src/Packagist/WebBundle/Entity/Package.php +++ b/src/Packagist/WebBundle/Entity/Package.php @@ -33,7 +33,6 @@ * } * ) * @Assert\Callback(callback="isPackageUnique") - * @Assert\Callback(callback="isVendorWritable") * @Assert\Callback(callback="isRepositoryValid", groups={"Update", "Default"}) * @author Jordi Boggiano */ @@ -609,9 +608,6 @@ public function setRepository($repoUrl) if (null === $this->getName()) { $this->setName($information['name']); } - if ($driver instanceof GitHubDriver) { - $this->repository = $driver->getRepositoryUrl(); - } } catch (\Exception $e) { $this->vcsDriverError = '['.get_class($e).'] '.$e->getMessage(); } @@ -674,6 +670,14 @@ public function getVersion($normalizedVersion) } } + /** + * @return Version|null + */ + public function getHighest() + { + return $this->getVersion('9999999-dev'); + } + /** * Set updatedAt * diff --git a/src/Packagist/WebBundle/Entity/PackageRepository.php b/src/Packagist/WebBundle/Entity/PackageRepository.php index 64d1d15d..15d0b758 100644 --- a/src/Packagist/WebBundle/Entity/PackageRepository.php +++ b/src/Packagist/WebBundle/Entity/PackageRepository.php @@ -12,6 +12,7 @@ namespace Packagist\WebBundle\Entity; +use Doctrine\DBAL\Connection; use Doctrine\DBAL\Platforms\PostgreSqlPlatform; use Doctrine\ORM\EntityRepository; use Doctrine\ORM\QueryBuilder; @@ -131,19 +132,15 @@ public function getStalePackages() WHERE p.abandoned = false AND ( p.crawledAt IS NULL - OR (p.autoUpdated = false AND p.crawledAt < :recent AND p.createdAt >= :yesterday) OR (p.autoUpdated = false AND p.crawledAt < :crawled) OR (p.crawledAt < :autocrawled) ) ORDER BY p.id ASC', array( - // crawl new packages once an hour for the first day so that dummy packages get deleted ASAP - 'recent' => date('Y-m-d H:i:s', strtotime('-1hour')), - 'yesterday' => date('Y-m-d H:i:s', strtotime('-1day')), // crawl packages without auto-update once a week - 'crawled' => date('Y-m-d H:i:s', strtotime('-1week')), - // crawl auto-updated packages once a month just in case - 'autocrawled' => date('Y-m-d H:i:s', strtotime('-1month')), + 'crawled' => date('Y-m-d H:i:s', strtotime('-4hour')), + // crawl auto-updated packages once a week just in case + 'autocrawled' => date('Y-m-d H:i:s', strtotime('-7day')), ) ); } @@ -429,33 +426,38 @@ public function getPackagesStatisticsByMonthAndYear() return $qb->getQuery()->getResult(); } - public function searchPackage(string $search, int $limit = 10, int $page = 0) + public function searchPackage(string $search, int $limit = 10, int $page = 0, array $allowed = null) { $conn = $this->getEntityManager()->getConnection(); if ($conn->getDatabasePlatform() instanceof PostgreSqlPlatform && $this->checkExtension('fuzzystrmatch')) { - $packages = []; - $sql = 'SELECT levenshtein(name, :search)/(1.0 + length(name)) AS idx, id - FROM package - ORDER BY idx LIMIT :limit OFFSET :ofs'; - $packagesId = $conn - ->executeQuery( - $sql, - ['search' => $search, 'limit' => $limit, 'ofs' => $page * $limit] - )->fetchAll(); - - if ($packagesId) { - foreach (array_column($packagesId, 'id') as $id) { - $packages[] = $this->find($id); - } + $params = ['search' => $search, 'limit' => $limit, 'ofs' => $page * $limit]; + $sql = 'SELECT levenshtein(name, :search)/(1.0 + length(name)) AS idx, id' + . ' FROM package '; + + if (null !== $allowed) { + $sql .= ' WHERE id IN (:ids) '; + $params['ids'] = $allowed; } - return $packages; + $sql .= 'ORDER BY idx LIMIT :limit OFFSET :ofs'; + + return array_map( + function ($item) { + return $this->find($item['id']); + }, + $conn->executeQuery($sql, $params, ['ids' => Connection::PARAM_INT_ARRAY])->fetchAll() + ); } $qb = $this->createQueryBuilder('p'); + if (null !== $allowed) { + $qb->andWhere('p.id IN (:ids)') + ->setParameter('ids', $allowed); + } - return $qb->where( + return $qb->andWhere( $qb->expr()->like('p.name', ':name') - )->setParameter('name', $search) + ) + ->setParameter('name', '%' . $search . '%') ->setMaxResults($limit) ->setFirstResult($limit * $page) ->getQuery()->getResult(); diff --git a/src/Packagist/WebBundle/Entity/User.php b/src/Packagist/WebBundle/Entity/User.php index 201d8a34..47f9d4b2 100644 --- a/src/Packagist/WebBundle/Entity/User.php +++ b/src/Packagist/WebBundle/Entity/User.php @@ -115,6 +115,12 @@ class User extends BaseUser */ private $failureNotifications = true; + /** + * @ORM\Column(name="expires_at", type="date", nullable=true) + * @var \DateTime + */ + private $expiresAt; + public function __construct() { $this->packages = new ArrayCollection(); @@ -324,6 +330,35 @@ public function getExpiresAt() return $this->expiresAt; } + /** + * @param \DateTime $expiresAt + * @return $this + */ + public function setExpiresAt($expiresAt) + { + $this->expiresAt = $expiresAt; + return $this; + } + + public function generateApiToken() + { + $this->apiToken = rtrim(strtr(base64_encode(random_bytes(32)), '+/', '-_'), '='); + $this->apiToken = substr($this->apiToken, 0, 20); + return $this->apiToken; + } + + /** + * {@inheritdoc} + */ + public function isAccountNonExpired() + { + if (null === $this->expiresAt) { + return true; + } + + return new \DateTime('now') < $this->expiresAt; + } + /** * @return bool */ diff --git a/src/Packagist/WebBundle/Entity/Version.php b/src/Packagist/WebBundle/Entity/Version.php index 1dc3355f..646f3948 100644 --- a/src/Packagist/WebBundle/Entity/Version.php +++ b/src/Packagist/WebBundle/Entity/Version.php @@ -211,7 +211,7 @@ public function __construct() $this->updatedAt = new \DateTime; } - public function toArray(array $versionData) + public function toArray(array $versionData = []) { $tags = array(); foreach ($this->getTags() as $tag) { diff --git a/src/Packagist/WebBundle/Form/Handler/OAuthRegistrationFormHandler.php b/src/Packagist/WebBundle/Form/Handler/OAuthRegistrationFormHandler.php deleted file mode 100644 index 9f42b80e..00000000 --- a/src/Packagist/WebBundle/Form/Handler/OAuthRegistrationFormHandler.php +++ /dev/null @@ -1,99 +0,0 @@ - - * Nils Adermann - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Packagist\WebBundle\Form\Handler; - -use FOS\UserBundle\Model\UserManagerInterface; -use FOS\UserBundle\Util\TokenGeneratorInterface; -use HWI\Bundle\OAuthBundle\Form\RegistrationFormHandlerInterface; -use HWI\Bundle\OAuthBundle\OAuth\Response\UserResponseInterface; -use Symfony\Component\Form\Form; -use Symfony\Component\HttpFoundation\Request; - -/** - * OAuthRegistrationFormHandler - * - * @author Alexander - */ -class OAuthRegistrationFormHandler implements RegistrationFormHandlerInterface -{ - private $userManager; - private $tokenGenerator; - - /** - * Constructor. - * - * @param UserManagerInterface $userManager - * @param TokenGeneratorInterface $tokenGenerator - */ - public function __construct(UserManagerInterface $userManager, TokenGeneratorInterface $tokenGenerator) - { - $this->tokenGenerator = $tokenGenerator; - $this->userManager = $userManager; - } - - /** - * {@inheritDoc} - */ - public function process(Request $request, Form $form, UserResponseInterface $userInformation) - { - $user = $this->userManager->createUser(); - - // Try to get some properties for the initial form when coming from github - if ('GET' === $request->getMethod()) { - $user->setUsername($this->getUniqueUsername($userInformation->getNickname())); - $user->setEmail($userInformation->getEmail()); - } - - $form->setData($user); - - if ('POST' === $request->getMethod()) { - $form->handleRequest($request); - - if ($form->isValid()) { - if (!$user->getPassword() && !$user->getPlainPassword()) { - $randomPassword = $this->tokenGenerator->generateToken(); - $user->setPlainPassword($randomPassword); - } - $user->setEnabled(true); - - $apiToken = substr($this->tokenGenerator->generateToken(), 0, 20); - $user->setApiToken($apiToken); - - return true; - } - } - - return false; - } - - /** - * Attempts to get a unique username for the user. - * - * @param string $name - * - * @return string Name, or empty string if it failed after 10 times - * - * @see HWI\Bundle\OAuthBundle\Form\FOSUBRegistrationHandler - */ - protected function getUniqueUserName($name) - { - $i = 0; - $testName = $name; - - do { - $user = $this->userManager->findUserByUsername($testName); - } while ($user !== null && $i < 10 && $testName = $name.++$i); - - return $user !== null ? '' : $testName; - } -} diff --git a/src/Packagist/WebBundle/Form/Type/PackagePermissionType.php b/src/Packagist/WebBundle/Form/Type/PackagePermissionType.php index 2b683c23..27ae2a52 100644 --- a/src/Packagist/WebBundle/Form/Type/PackagePermissionType.php +++ b/src/Packagist/WebBundle/Form/Type/PackagePermissionType.php @@ -28,7 +28,7 @@ public function buildForm(FormBuilderInterface $builder, array $options) 'label' => 'Version', 'required' => false, 'attr' => [ - 'placeholder' => 'Version (example ^1.0|^2.0)' + 'placeholder' => '^1.0|^2.0' ], 'constraints' => [new Callback($this->versionValidator())] ] diff --git a/src/Packagist/WebBundle/Form/Type/PackageType.php b/src/Packagist/WebBundle/Form/Type/PackageType.php index 04c7fba7..ebcc78b2 100644 --- a/src/Packagist/WebBundle/Form/Type/PackageType.php +++ b/src/Packagist/WebBundle/Form/Type/PackageType.php @@ -32,7 +32,7 @@ public function buildForm(FormBuilderInterface $builder, array $options) 'label' => 'SSH Credentials (optional)', 'required' => false, 'class' => SshCredentials::class, - 'property' => 'name' + 'choice_label' => 'name' ]) ->add('repository', TextType::class, [ 'label' => 'Repository URL (Git/Svn/Hg)', diff --git a/src/Packagist/WebBundle/Menu/MenuBuilder.php b/src/Packagist/WebBundle/Menu/MenuBuilder.php index b9f7f84a..360eb3e5 100644 --- a/src/Packagist/WebBundle/Menu/MenuBuilder.php +++ b/src/Packagist/WebBundle/Menu/MenuBuilder.php @@ -43,7 +43,7 @@ public function createUserMenu() $this->addProfileMenu($menu); $menu->addChild('hr', ['label' => '
', 'labelAttributes' => ['class' => 'normal'], 'extras' => ['safe_label' => true]]); - $menu->addChild($this->translator->trans('menu.logout'), ['label' => '' . $this->translator->trans('menu.logout'), 'route' => 'logout', 'extras' => ['safe_label' => true]]); + $menu->addChild($this->translator->trans('menu.logout'), ['label' => '' . $this->translator->trans('menu.logout'), 'route' => 'fos_user_security_logout', 'extras' => ['safe_label' => true]]); return $menu; } diff --git a/src/Packagist/WebBundle/Model/ValidatingArrayLoader.php b/src/Packagist/WebBundle/Model/ValidatingArrayLoader.php new file mode 100644 index 00000000..faebab37 --- /dev/null +++ b/src/Packagist/WebBundle/Model/ValidatingArrayLoader.php @@ -0,0 +1,32 @@ + $license) { + if ('proprietary' === $license || !$licenseValidator->validate($license)) { + unset($licenses[$key]); + }; + } + + if (!$licenses) { + unset($config['license']); + } else { + $config['license'] = \count($licenses) === 1 ? \reset($licenses) : $licenses; + } + } + + return parent::load($config, $class); + } +} diff --git a/src/Packagist/WebBundle/Package/ArchiveManager.php b/src/Packagist/WebBundle/Package/ArchiveManager.php deleted file mode 100644 index 511d8dce..00000000 --- a/src/Packagist/WebBundle/Package/ArchiveManager.php +++ /dev/null @@ -1,26 +0,0 @@ -getSourceReference())) { - return $package->getSourceReference(); - } - - return parent::getPackageFilename($package); - } -} diff --git a/src/Packagist/WebBundle/Package/InMemoryDumper.php b/src/Packagist/WebBundle/Package/InMemoryDumper.php index b8746f03..d88bcf58 100644 --- a/src/Packagist/WebBundle/Package/InMemoryDumper.php +++ b/src/Packagist/WebBundle/Package/InMemoryDumper.php @@ -38,7 +38,7 @@ private function dumpRootPackages(User $user = null) $userHash = \hash('sha256', \json_encode($providers)); $rootFile['provider-includes'] = [ - '/p/providers$%hash%.json' => [ + 'p/providers$%hash%.json' => [ 'sha256' => $userHash ] ]; @@ -71,7 +71,10 @@ private function dumpUserPackages(User $user = null) $versionData = $versionRepo->getVersionData(\array_keys($versionIds)); foreach ($versionIds as $version) { - $packageData[$version->getVersion()] = $version->toArray($versionData); + $packageData[$version->getVersion()] = \array_merge( + $version->toArray($versionData), + ['uid' => $version->getId()] + ); } $packageData = [ diff --git a/src/Packagist/WebBundle/Package/SymlinkDumper.php b/src/Packagist/WebBundle/Package/SymlinkDumper.php deleted file mode 100644 index 34d3dc35..00000000 --- a/src/Packagist/WebBundle/Package/SymlinkDumper.php +++ /dev/null @@ -1,726 +0,0 @@ - - * Nils Adermann - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Packagist\WebBundle\Package; - -use Symfony\Component\Filesystem\Filesystem; -use Composer\Util\Filesystem as ComposerFilesystem; -use Symfony\Bridge\Doctrine\RegistryInterface; -use Symfony\Component\Routing\Generator\UrlGeneratorInterface; -use Symfony\Component\Finder\Finder; -use Packagist\WebBundle\Entity\Version; -use Doctrine\DBAL\Connection; - -/** - * @author Jordi Boggiano - */ -class SymlinkDumper -{ - /** - * Doctrine - * @var RegistryInterface - */ - protected $doctrine; - - /** - * @var Filesystem - */ - protected $fs; - - /** - * @var ComposerFilesystem - */ - protected $cfs; - - /** - * @var string - */ - protected $webDir; - - /** - * @var string - */ - protected $buildDir; - - /** - * @var UrlGeneratorInterface - */ - protected $router; - - /** - * Data cache - * @var array - */ - private $rootFile; - - /** - * Data cache - * @var array - */ - private $listings = array(); - - /** - * Data cache - * @var array - */ - private $individualFiles = array(); - - /** - * Modified times of individual files - * @var array - */ - private $individualFilesMtime = array(); - - /** - * Stores all the disk writes to be replicated in the second build dir after the symlink has been swapped - * @var array - */ - private $writeLog = array(); - - /** - * Generate compressed files. - * @var int 0 disabled, 9 maximum. - */ - private $compress; - - /** - * Constructor - * - * @param RegistryInterface $doctrine - * @param Filesystem $filesystem - * @param UrlGeneratorInterface $router - * @param string $webDir web root - * @param string $targetDir - * @param int $compress - */ - public function __construct(RegistryInterface $doctrine, Filesystem $filesystem, UrlGeneratorInterface $router, $webDir, $targetDir, $compress) - { - $this->doctrine = $doctrine; - $this->fs = $filesystem; - $this->cfs = new ComposerFilesystem; - $this->router = $router; - $this->webDir = realpath($webDir); - $this->buildDir = $targetDir; - $this->compress = $compress; - } - - /** - * Dump a set of packages to the web root - * - * @param array $packageIds - * @param Boolean $force - * @param Boolean $verbose - */ - public function dump(array $packageIds, $force = false, $verbose = false) - { - $cleanUpOldFiles = date('i') == 0; - - // prepare build dir - $webDir = $this->webDir; - - $buildDirA = $this->buildDir.'/a'; - $buildDirB = $this->buildDir.'/b'; - - // initialize - $initialRun = false; - if (!is_dir($buildDirA) || !is_dir($buildDirB)) { - $initialRun = true; - if (!$this->removeDirectory($buildDirA) || !$this->removeDirectory($buildDirB)) { - throw new \RuntimeException('Failed to delete '.$buildDirA.' or '.$buildDirB); - } - $this->fs->mkdir($buildDirA); - $this->fs->mkdir($buildDirB); - } - - // set build dir to the not-active one - if (realpath($webDir.'/p') === realpath($buildDirA)) { - $buildDir = realpath($buildDirB); - $oldBuildDir = realpath($buildDirA); - } else { - $buildDir = realpath($buildDirA); - $oldBuildDir = realpath($buildDirB); - } - - // copy existing stuff for smooth BC transition - if ($initialRun && !$force) { - if (!file_exists($webDir.'/p') || is_link($webDir.'/p')) { - @rmdir($buildDir); - @rmdir($oldBuildDir); - throw new \RuntimeException('Run this again with --force the first time around to make sure it dumps all packages'); - } - if ($verbose) { - echo 'Copying existing files'.PHP_EOL; - } - - foreach (array($buildDir, $oldBuildDir) as $dir) { - $this->cloneDir($webDir.'/p', $dir); - } - } - - if ($verbose) { - echo 'Web dir is '.$webDir.'/p ('.realpath($webDir.'/p').')'.PHP_EOL; - echo 'Build dir is '.$buildDir.PHP_EOL; - } - - // clean the build dir to start over if we are re-dumping everything - if ($force) { - // disable the write log since we copy everything at the end in forced mode - $this->writeLog = false; - - if ($verbose) { - echo 'Cleaning up existing files'.PHP_EOL; - } - if (!$this->clearDirectory($buildDir)) { - return false; - } - } - - $dumpTimeUpdates = []; - - $versionRepo = $this->doctrine->getRepository('PackagistWebBundle:Version'); - - try { - $modifiedIndividualFiles = array(); - - $total = count($packageIds); - $current = 0; - $step = 50; - while ($packageIds) { - $dumpTime = new \DateTime; - $packages = $this->doctrine->getRepository('PackagistWebBundle:Package')->getPackagesWithVersions(array_splice($packageIds, 0, $step)); - - if ($verbose) { - echo '['.sprintf('%'.strlen($total).'d', $current).'/'.$total.'] Processing '.$step.' packages'.PHP_EOL; - } - - $current += $step; - - // prepare packages in memory - foreach ($packages as $package) { - // skip spam packages in the dumper in case we do a forced full dump and prevent them from being dumped for a little while - if ($package->isAbandoned() && $package->getReplacementPackage() === 'spam/spam') { - $dumpTimeUpdates['2100-01-01 00:00:00'][] = $package->getId(); - continue; - } - - $affectedFiles = array(); - $name = strtolower($package->getName()); - - // clean up versions in individual files - if (file_exists($buildDir.'/'.$name.'.files')) { - $files = json_decode(file_get_contents($buildDir.'/'.$name.'.files')); - - foreach ($files as $file) { - if (substr_count($file, '/') > 1) { // handle old .files with p/*/*.json paths - $file = preg_replace('{^p/}', '', $file); - } - $this->loadIndividualFile($buildDir.'/'.$file, $file); - if (isset($this->individualFiles[$file]['packages'][$name])) { - unset($this->individualFiles[$file]['packages'][$name]); - $modifiedIndividualFiles[$file] = true; - } - } - } - - // (re)write versions in individual files - $versionIds = []; - foreach ($package->getVersions() as $version) { - $versionIds[] = $version->getId(); - } - $versionData = $versionRepo->getVersionData($versionIds); - foreach ($package->getVersions() as $version) { - foreach (array_slice($version->getNames(), 0, 150) as $versionName) { - if (!preg_match('{^[A-Za-z0-9_-][A-Za-z0-9_.-]*/[A-Za-z0-9_-][A-Za-z0-9_.-]*$}', $versionName) || strpos($versionName, '..')) { - continue; - } - - $file = $buildDir.'/'.$versionName.'.json'; - $key = $versionName.'.json'; - $this->dumpVersionToIndividualFile($version, $file, $key, $versionData); - $modifiedIndividualFiles[$key] = true; - $affectedFiles[$key] = true; - } - } - - // store affected files to clean up properly in the next update - $this->fs->mkdir(dirname($buildDir.'/'.$name)); - $this->writeFile($buildDir.'/'.$name.'.files', json_encode(array_keys($affectedFiles))); - - $dumpTimeUpdates[$dumpTime->format('Y-m-d H:i:s')][] = $package->getId(); - } - - unset($packages, $package, $version); - $this->doctrine->getManager()->clear(); - - if ($current % 250 === 0 || !$packageIds) { - if ($verbose) { - echo 'Dumping individual files'.PHP_EOL; - } - $this->dumpIndividualFiles($buildDir); - } - } - - // prepare individual files listings - if ($verbose) { - echo 'Preparing individual files listings'.PHP_EOL; - } - $safeFiles = array(); - $individualHashedListings = array(); - $finder = Finder::create()->files()->ignoreVCS(true)->name('*.json')->in($buildDir)->depth('1'); - - foreach ($finder as $file) { - // skip hashed files - if (strpos($file, '$')) { - continue; - } - - $key = basename(dirname($file)).'/'.basename($file); - if ($force && !isset($modifiedIndividualFiles[$key])) { - continue; - } - - // add hashed provider to listing - $listing = $this->getTargetListing($file); - $hash = hash_file('sha256', $file); - $key = substr($key, 0, -5); - $safeFiles[] = $key.'$'.$hash.'.json'; - $this->listings[$listing]['providers'][$key] = array('sha256' => $hash); - $individualHashedListings[$listing] = true; - } - - // prepare root file - $rootFile = $buildDir.'/packages.json'; - $this->rootFile = array('packages' => array()); - $url = $this->router->generate('track_download', array('name' => 'VND/PKG')); - $this->rootFile['notify'] = str_replace('VND/PKG', '%package%', $url); - $this->rootFile['notify-batch'] = $this->router->generate('track_download_batch'); - $this->rootFile['providers-url'] = $this->router->generate('home') . 'p/%package%$%hash%.json'; - $this->rootFile['search'] = $this->router->generate('search', array('_format' => 'json')) . '?q=%query%&type=%type%'; - - if ($verbose) { - echo 'Dumping individual listings'.PHP_EOL; - } - - // dump listings to build dir - foreach ($individualHashedListings as $listing => $dummy) { - list($listingPath, $hash) = $this->dumpListing($buildDir.'/'.$listing); - $hashedListing = basename($listingPath); - $this->rootFile['provider-includes']['p/'.str_replace($hash, '%hash%', $hashedListing)] = array('sha256' => $hash); - $safeFiles[] = $hashedListing; - } - - if ($verbose) { - echo 'Dumping root'.PHP_EOL; - } - $this->dumpRootFile($rootFile); - } catch (\Exception $e) { - // restore files as they were before we started - $this->cloneDir($oldBuildDir, $buildDir); - throw $e; - } - - try { - if ($verbose) { - echo 'Putting new files in production'.PHP_EOL; - } - - // move away old files for BC update - if ($initialRun && file_exists($webDir.'/p') && !is_link($webDir.'/p')) { - rename($webDir.'/p', $webDir.'/p-old'); - } - - $this->switchActiveWebDir($webDir, $buildDir); - } catch (\Exception $e) { - @symlink($oldBuildDir, $webDir.'/p'); - throw $e; - } - - try { - if ($initialRun || !is_link($webDir.'/packages.json') || $force) { - if ($verbose) { - echo 'Writing/linking the packages.json'.PHP_EOL; - } - if (file_exists($webDir.'/packages.json')) { - unlink($webDir.'/packages.json'); - } - if (file_exists($webDir.'/packages.json.gz')) { - unlink($webDir.'/packages.json.gz'); - } - if (defined('PHP_WINDOWS_VERSION_BUILD')) { - $sourcePath = $buildDir.'/packages.json'; - if (!copy($sourcePath, $webDir.'/packages.json')) { - throw new \RuntimeException('Could not copy the packages.json file'); - } - } else { - $sourcePath = 'p/packages.json'; - if (!symlink($sourcePath, $webDir.'/packages.json')) { - throw new \RuntimeException('Could not symlink the packages.json file'); - } - if ($this->compress && !symlink($sourcePath.'.gz', $webDir.'/packages.json.gz')) { - throw new \RuntimeException('Could not symlink the packages.json.gz file'); - } - } - } - } catch (\Exception $e) { - $this->switchActiveWebDir($webDir, $oldBuildDir); - throw $e; - } - - // clean up old dir if present on BC update - if ($initialRun) { - $this->removeDirectory($webDir.'/p-old'); - } - - // clean the old build dir if we re-dumped everything - if ($force) { - if ($verbose) { - echo 'Cleaning up old build dir'.PHP_EOL; - } - if (!$this->clearDirectory($oldBuildDir)) { - throw new \RuntimeException('Unrecoverable inconsistent state (old build dir could not be cleared), run with --force again to retry'); - } - } - - // copy state to old active dir - if ($force) { - if ($verbose) { - echo 'Copying new contents to old build dir to sync up'.PHP_EOL; - } - $this->cloneDir($buildDir, $oldBuildDir); - } else { - if ($verbose) { - echo 'Replaying write log in old build dir'.PHP_EOL; - } - $this->copyWriteLog($buildDir, $oldBuildDir); - } - - // clean up old files once an hour - if (!$force && $cleanUpOldFiles) { - if ($verbose) { - echo 'Cleaning up old files'.PHP_EOL; - } - - $this->cleanOldFiles($buildDir, $oldBuildDir, $safeFiles); - } - - if ($verbose) { - echo 'Updating package dump times'.PHP_EOL; - } - foreach ($dumpTimeUpdates as $dt => $ids) { - $retries = 5; - // retry loop in case of a lock timeout - while ($retries--) { - try { - $this->doctrine->getManager()->getConnection()->executeQuery( - 'UPDATE package SET dumpedAt=:dumped WHERE id IN (:ids)', - [ - 'ids' => $ids, - 'dumped' => $dt, - ], - ['ids' => Connection::PARAM_INT_ARRAY] - ); - } catch (\Exception $e) { - if (!$retries) { - throw $e; - } - sleep(2); - } - } - } - - // TODO when a package is deleted, it should be removed from provider files, or marked for removal at least - return true; - } - - private function switchActiveWebDir($webDir, $buildDir) - { - $newLink = $webDir.'/p-new'; - $oldLink = $webDir.'/p'; - - if (file_exists($newLink)) { - unlink($newLink); - } - if (!symlink($buildDir, $newLink)) { - echo 'Warning: Could not symlink the build dir into the web dir'; - throw new \RuntimeException('Could not symlink the build dir into the web dir'); - } - if (!rename($newLink, $oldLink)) { - echo 'Warning: Could not replace the old symlink with the new one in the web dir'; - throw new \RuntimeException('Could not replace the old symlink with the new one in the web dir'); - } - } - - private function cloneDir($source, $target) - { - $this->removeDirectory($target); - exec('cp -rpf '.escapeshellarg($source).' '.escapeshellarg($target), $output, $exit); - if (0 !== $exit) { - echo 'Warning, cloning a directory using the php fallback does not keep filemtime, invalid behavior may occur'; - $this->fs->mirror($source, $target, null, array('override' => true)); - } - } - - private function cleanOldFiles($buildDir, $oldBuildDir, $safeFiles) - { - $finder = Finder::create()->directories()->ignoreVCS(true)->in($buildDir); - foreach ($finder as $vendorDir) { - $vendorFiles = Finder::create()->files()->ignoreVCS(true) - ->name('/\$[a-f0-9]+\.json$/') - ->date('until 10minutes ago') - ->in((string) $vendorDir); - - foreach ($vendorFiles as $file) { - $key = strtr(str_replace($buildDir.DIRECTORY_SEPARATOR, '', $file), '\\', '/'); - if (!in_array($key, $safeFiles, true)) { - unlink((string) $file); - if (file_exists($altDirFile = str_replace($buildDir, $oldBuildDir, (string) $file))) { - unlink($altDirFile); - } - } - } - } - - // clean up old provider listings - $finder = Finder::create()->depth(0)->files()->name('provider-*.json')->ignoreVCS(true)->in($buildDir)->date('until 10minutes ago'); - foreach ($finder as $provider) { - $key = strtr(str_replace($buildDir.DIRECTORY_SEPARATOR, '', $provider), '\\', '/'); - if (!in_array($key, $safeFiles, true)) { - $path = (string) $provider; - unlink($path); - if (file_exists($path.'.gz')) { - unlink($path.'.gz'); - } - if (file_exists($altDirFile = str_replace($buildDir, $oldBuildDir, $path))) { - unlink($altDirFile); - if (file_exists($altDirFile.'.gz')) { - unlink($altDirFile.'.gz'); - } - } - } - } - - // clean up old root listings - $finder = Finder::create()->depth(0)->files()->name('packages.json-*')->ignoreVCS(true)->in($buildDir)->date('until 10minutes ago'); - foreach ($finder as $rootFile) { - $path = (string) $rootFile; - unlink($path); - if (file_exists($path.'.gz')) { - unlink($path.'.gz'); - } - if (file_exists($altDirFile = str_replace($buildDir, $oldBuildDir, $path))) { - unlink($altDirFile); - if (file_exists($altDirFile.'.gz')) { - unlink($altDirFile.'.gz'); - } - } - } - } - - private function dumpRootFile($file) - { - // sort all versions and packages to make sha1 consistent - ksort($this->rootFile['packages']); - ksort($this->rootFile['provider-includes']); - foreach ($this->rootFile['packages'] as $package => $versions) { - ksort($this->rootFile['packages'][$package]); - } - - if (file_exists($file)) { - $timedFile = $file.'-'.time(); - rename($file, $timedFile); - if (file_exists($file.'.gz')) { - rename($file.'.gz', $timedFile.'.gz'); - } - } - - $json = json_encode($this->rootFile); - $time = time(); - - $this->writeFile($file, $json, $time); - if ($this->compress) { - $this->writeFile($file . '.gz', gzencode($json, $this->compress), $time); - } - } - - private function dumpListing($path) - { - $key = basename($path); - - // sort files to make hash consistent - ksort($this->listings[$key]['providers']); - - $json = json_encode($this->listings[$key]); - $hash = hash('sha256', $json); - $path = substr($path, 0, -5) . '$' . $hash . '.json'; - $time = time(); - - if (!file_exists($path)) { - $this->writeFile($path, $json, $time); - if ($this->compress) { - $this->writeFile($path . '.gz', gzencode($json, $this->compress), $time); - } - } - - return array($path, $hash); - } - - private function loadIndividualFile($path, $key) - { - if (isset($this->individualFiles[$key])) { - return; - } - - if (file_exists($path)) { - $this->individualFiles[$key] = json_decode(file_get_contents($path), true); - $this->individualFilesMtime[$key] = filemtime($path); - } else { - $this->individualFiles[$key] = array(); - $this->individualFilesMtime[$key] = 0; - } - } - - private function dumpIndividualFiles($buildDir) - { - // dump individual files to build dir - foreach ($this->individualFiles as $file => $dummy) { - $this->dumpIndividualFile($buildDir.'/'.$file, $file); - } - - $this->individualFiles = array(); - $this->individualFilesMtime = array(); - } - - private function dumpIndividualFile($path, $key) - { - // sort all versions and packages to make sha1 consistent - ksort($this->individualFiles[$key]['packages']); - foreach ($this->individualFiles[$key]['packages'] as $package => $versions) { - ksort($this->individualFiles[$key]['packages'][$package]); - } - - $this->fs->mkdir(dirname($path)); - - $json = json_encode($this->individualFiles[$key]); - $this->writeFile($path, $json, $this->individualFilesMtime[$key]); - - // write the hashed provider file - $hashedFile = substr($path, 0, -5) . '$' . hash('sha256', $json) . '.json'; - $this->writeFile($hashedFile, $json); - } - - private function dumpVersionToIndividualFile(Version $version, $file, $key, $versionData) - { - $this->loadIndividualFile($file, $key); - $data = $version->toArray($versionData); - $data['uid'] = $version->getId(); - $this->individualFiles[$key]['packages'][strtolower($version->getName())][$version->getVersion()] = $data; - $timestamp = $version->getReleasedAt() ? $version->getReleasedAt()->getTimestamp() : time(); - if (!isset($this->individualFilesMtime[$key]) || $this->individualFilesMtime[$key] < $timestamp) { - $this->individualFilesMtime[$key] = $timestamp; - } - } - - private function clearDirectory($path) - { - if (!$this->removeDirectory($path)) { - echo 'Could not remove the build dir entirely, aborting'; - - return false; - } - $this->fs->mkdir($path); - return true; - } - - private function removeDirectory($path) - { - $retries = 5; - do { - if (!$this->cfs->removeDirectory($path)) { - usleep(200); - } - clearstatcache(); - } while (is_dir($path) && $retries--); - - return !is_dir($path); - } - - private function getTargetListingBlocks($now) - { - $blocks = array(); - - // monday last week - $blocks['latest'] = strtotime('monday last week', $now); - - $month = date('n', $now); - $month = ceil($month / 3) * 3 - 2; // 1 for months 1-3, 10 for months 10-12 - $block = new \DateTime(date('Y', $now).'-'.$month.'-01'); // 1st day of current trimester - - // split last 12 months in 4 trimesters - for ($i=0; $i < 4; $i++) { - $blocks[$block->format('Y-m')] = $block->getTimestamp(); - $block->sub(new \DateInterval('P3M')); - } - - $year = (int) $block->format('Y'); - - while ($year >= 2013) { - $blocks[''.$year] = strtotime($year.'-01-01'); - $year--; - } - - return $blocks; - } - - private function getTargetListing($file) - { - static $blocks; - - if (!$blocks) { - $blocks = $this->getTargetListingBlocks(time()); - } - - $mtime = filemtime($file); - - foreach ($blocks as $label => $block) { - if ($mtime >= $block) { - return "provider-${label}.json"; - } - } - - return "provider-archived.json"; - } - - private function writeFile($path, $contents, $mtime = null) - { - file_put_contents($path, $contents); - if ($mtime !== null) { - touch($path, $mtime); - } - - if (is_array($this->writeLog)) { - $this->writeLog[$path] = array($contents, $mtime); - } - } - - private function copyWriteLog($from, $to) - { - foreach ($this->writeLog as $path => $op) { - $path = str_replace($from, $to, $path); - - $this->fs->mkdir(dirname($path)); - file_put_contents($path, $op[0]); - if ($op[1] !== null) { - touch($path, $op[1]); - } - } - } -} diff --git a/src/Packagist/WebBundle/Package/Updater.php b/src/Packagist/WebBundle/Package/Updater.php index e40b297b..b571094b 100644 --- a/src/Packagist/WebBundle/Package/Updater.php +++ b/src/Packagist/WebBundle/Package/Updater.php @@ -134,13 +134,9 @@ public function update(IOInterface $io, Config $config, Package $package, Reposi $apc = extension_loaded('apcu'); $rootIdentifier = null; - if ($this->archiveManager === null) { - $downloadManager = $this->factory->createDownloadManager($io, $config); - $archiveManager = $this->factory->createArchiveManager($config, $downloadManager); - $archiveManager->setOverwriteFiles(false); - } else { - $archiveManager = $this->archiveManager; - } + $downloadManager = $this->factory->createDownloadManager($io, $config); + $archiveManager = $this->factory->createArchiveManager($config, $downloadManager); + $archiveManager->setOverwriteFiles(false); if ($repository instanceof VcsRepository) { $cfg = $repository->getRepoConfig(); @@ -366,7 +362,7 @@ private function updateInformation( } $version->setHomepage($data->getHomepage()); - $version->setLicense($data->getLicense() ?: array()); + $version->setLicense($data->getLicense() ?: []); $version->setPackage($package); $version->setUpdatedAt(new \DateTime); @@ -568,17 +564,24 @@ private function updateArchive(ArchiveManager $archiveManager, PackageInterface return null; } - $path = $archiveManager->archive( - $data, - $this->distConfig->getArchiveFormat(), - $this->distConfig->generateTargetDir($data->getName()), - $data->getSourceReference() - ); + if (false === $this->distConfig->isLazy()) { + $fileName= $this->distConfig->getFileName( + $data->getSourceReference(), + $data->getVersion() + ); + + $path = $archiveManager->archive( + $data, + $this->distConfig->getArchiveFormat(), + $this->distConfig->generateTargetDir($data->getName()), + $fileName + ); + $dist['shasum'] = $this->distConfig->isIncludeArchiveChecksum() ? \hash_file('sha1', $path) : null; + } $dist['type'] = $this->distConfig->getArchiveFormat(); $dist['url'] = $this->distConfig->generateRoute($data->getName(), $data->getSourceReference()); $dist['reference'] = $data->getSourceReference(); - $dist['shasum'] = $this->distConfig->isIncludeArchiveChecksum() ? \hash_file('sha1', $path) : null; return $dist; } @@ -592,7 +595,11 @@ private function updateDist(array $dist, Version $version) $filesystem = new Filesystem(); $oldDist = $version->getDist(); if (isset($oldDist['reference']) && $dist['reference'] !== $oldDist['reference']) { - $targetDir = $this->distConfig->generateDistFileName($version->getName(), $oldDist['reference']); + $targetDir = $this->distConfig->generateDistFileName( + $version->getName(), + $oldDist['reference'], + $version->getVersion() + ); $filesystem->remove($targetDir); } diff --git a/src/Packagist/WebBundle/PackagistWebBundle.php b/src/Packagist/WebBundle/PackagistWebBundle.php index e90b5fad..bd53a79e 100644 --- a/src/Packagist/WebBundle/PackagistWebBundle.php +++ b/src/Packagist/WebBundle/PackagistWebBundle.php @@ -22,6 +22,9 @@ */ class PackagistWebBundle extends Bundle { + /** + * {@inheritdoc} + */ public function build(ContainerBuilder $container) { /** @var SecurityExtension $extension */ diff --git a/src/Packagist/WebBundle/Resources/config/security.yml b/src/Packagist/WebBundle/Resources/config/security.yml index 9046f4a7..582eb80c 100644 --- a/src/Packagist/WebBundle/Resources/config/security.yml +++ b/src/Packagist/WebBundle/Resources/config/security.yml @@ -19,9 +19,10 @@ services: packagist.security.authentication.provider: class: Packagist\WebBundle\Security\Api\ApiTokenProvider + public: false arguments: - '@packagist.user_provider' - public: false + - ~ packagist.security.authentication.listener: class: Packagist\WebBundle\Security\Api\ApiBasicAuthenticationListener diff --git a/src/Packagist/WebBundle/Resources/config/services.yml b/src/Packagist/WebBundle/Resources/config/services.yml index 675ef4b8..58fd0a4b 100644 --- a/src/Packagist/WebBundle/Resources/config/services.yml +++ b/src/Packagist/WebBundle/Resources/config/services.yml @@ -4,7 +4,7 @@ parameters: services: packagist.twig.extension: class: Packagist\WebBundle\Twig\PackagistExtension - arguments: [ '@packagist.provider_manager' ] + arguments: [ '@service_container' ] tags: - { name: twig.extension } @@ -32,10 +32,6 @@ services: tags: - { name: kernel.event_subscriber } - packagist.package_symlink_dumper: - class: Packagist\WebBundle\Package\SymlinkDumper - arguments: [ '@doctrine', '@filesystem', '@router', '%kernel.root_dir%/../web/', '%packagist_metadata_dir%', '%packagist_dumper_compress%' ] - packagist.user_repository: class: Packagist\WebBundle\Entity\UserRepository factory: ['@doctrine', getRepository] @@ -72,11 +68,7 @@ services: - '@fos_user.user_manager' - '@fos_user.util.token_generator' - '@event_dispatcher' - - '@service_container' - - packagist.oauth.registration_form_handler: - class: Packagist\WebBundle\Form\Handler\OAuthRegistrationFormHandler - arguments: ['@fos_user.user_manager', '@fos_user.util.token_generator'] + - '@request_stack' packagist.oauth.registration_form_type: class: Packagist\WebBundle\Form\Type\OAuthRegistrationFormType @@ -96,6 +88,7 @@ services: packagist.provider_manager: class: Packagist\WebBundle\Model\ProviderManager + public: true arguments: - '@snc_redis.default_client' - '@packagist.package_repository' @@ -123,7 +116,7 @@ services: class: Packagist\WebBundle\Form\Type\ProfileFormType arguments: ['%fos_user.model.user.class%'] tags: - - { name: form.type, alias: packagist_user_profile } + - { name: form.type } packagist.permission_collection.form.type: class: Packagist\WebBundle\Form\Type\GroupAclPermissionCollectionType @@ -153,10 +146,6 @@ services: tags: - { name: knp_menu.menu, alias: admin_menu } - packagist.algolia.client: - class: AlgoliaSearch\Client - arguments: ['%algolia.app_id%', '%algolia.admin_key%'] - packagist.queue_worker: class: Packagist\WebBundle\Service\QueueWorker arguments: @@ -185,5 +174,3 @@ services: packagist.console_stack_trace_line_formatter: class: Symfony\Bridge\Monolog\Formatter\ConsoleFormatter arguments: [] - calls: - - [includeStacktraces, [true]] diff --git a/src/Packagist/WebBundle/Resources/public/css/main.css b/src/Packagist/WebBundle/Resources/public/css/main.css index 0ce3ea6b..7868ff6a 100644 --- a/src/Packagist/WebBundle/Resources/public/css/main.css +++ b/src/Packagist/WebBundle/Resources/public/css/main.css @@ -55,7 +55,7 @@ body { position: absolute; width: 100px; left: -98px; - top: -43px; + top: -33px; } @media (min-width: 1200px) { .logo { @@ -305,6 +305,7 @@ strong { .nav-user .signin-box .signin-box-buttons { float: left; width: 100%; + padding: 10px; } .nav-user .signin-box .signin-box-register { @@ -594,7 +595,7 @@ input:focus:invalid:focus, textarea:focus:invalid:focus, select:focus:invalid:fo margin: 0 -4px 6px 0; border-right: 0; background: none; - color: #c6cacd; + color: #7e7d7b; font-size: 16px; } @@ -1663,4 +1664,23 @@ svg.chart { speak: none; } +.package-panel-info { + border-color: #f28d1a; +} +.package-panel-danger { + border-color: #cd3729; +} +.package-panel-info >.panel-heading { + background-image: linear-gradient(#f28d1a, #f59d3e); +} +.package-panel-danger >.panel-heading { + background-image: linear-gradient(#cd3729, #cd554c); +} +.panel-heading .anchor { + color: #FFF; +} +.package-permission input { + width: 100% !important; +} + .icon-mail:before { content: '\2709'; } /* '✉' */ diff --git a/src/Packagist/WebBundle/Resources/public/img/logo-small.png b/src/Packagist/WebBundle/Resources/public/img/logo-small.png index 76c0e62a..4d967ebe 100644 Binary files a/src/Packagist/WebBundle/Resources/public/img/logo-small.png and b/src/Packagist/WebBundle/Resources/public/img/logo-small.png differ diff --git a/src/Packagist/WebBundle/Resources/public/img/logo.png b/src/Packagist/WebBundle/Resources/public/img/logo.png index 289548d5..562f032d 100644 Binary files a/src/Packagist/WebBundle/Resources/public/img/logo.png and b/src/Packagist/WebBundle/Resources/public/img/logo.png differ diff --git a/src/Packagist/WebBundle/Resources/public/js/search.js b/src/Packagist/WebBundle/Resources/public/js/search.js deleted file mode 100644 index 8d966eee..00000000 --- a/src/Packagist/WebBundle/Resources/public/js/search.js +++ /dev/null @@ -1,203 +0,0 @@ -document.getElementById('search_query_query').addEventListener('keydown', function (e) { - if (e.keyCode === 13) { - e.preventDefault(); - } -}); - -var searchParameters = {}; - -if (decodeURI(location.search).match(/[<>]/)) { - location.replace(location.pathname); -} - -var searchThrottle = null; -var search = instantsearch({ - appId: algoliaConfig.app_id, - apiKey: algoliaConfig.search_key, - indexName: algoliaConfig.index_name, - routing: { - stateMapping: { - stateToRoute: function (uiState) { - return { - query: uiState.query, - type: uiState.menu && uiState.menu.type, - tags: uiState.refinementList && uiState.refinementList.tags && uiState.refinementList.tags.join('~'), - page: uiState.page, - }; - }, - routeToState: function (routeState) { - if (routeState.q) { - routeState.query = routeState.q; - } - if (routeState.query === undefined || routeState.query === '') { - return {}; - } - - return { - query: routeState.query, - menu: { - type: routeState.type - }, - refinementList: { - tags: routeState.tags && routeState.tags.split('~'), - }, - page: routeState.page - }; - }, - }, - }, - searchFunction: function(helper) { - var searchResults = $('#search-container'); - - if (helper.state.query === '' - && helper.state.hierarchicalFacetsRefinements.type === undefined - && (helper.state.disjunctiveFacetsRefinements.tags === undefined || helper.state.disjunctiveFacetsRefinements.tags.length === 0) - ) { - searchResults.addClass('hidden'); - } else { - searchResults.removeClass('hidden'); - } - - if (searchThrottle) { - clearTimeout(searchThrottle); - } - - searchThrottle = setTimeout(function () { - helper.search(); - }, 300); - }, - searchParameters: searchParameters -}); - -var autofocus = false; -if (location.pathname == "/" || location.pathname == "/app_dev.php/") { - autofocus = true; -} -search.addWidget( - instantsearch.widgets.searchBox({ - container: '#search_query_query', - magnifier: false, - reset: false, - wrapInput: false, - autofocus: autofocus - }) -); - -search.addWidget( - instantsearch.widgets.hits({ - container: '.search-list', - transformData: function (hit) { - hit.url = '/packages/' + hit.name; - if (hit.type === 'virtual-package') { - hit.virtual = true; - hit.url = '/providers/' + hit.name; - } - - if (hit._highlightResult && hit._highlightResult.description.value && hit._highlightResult.description.value.length > 200) { - hit._highlightResult.description.value = hit._highlightResult.description.value.substring(0, 200).replace(/<[a-z ]+$/, ''); - } - - return hit; - }, - templates: { - empty: 'No packages found.', - item: ` -
-
-
-

{{ language }}

-

- {{{ _highlightResult.name.value }}} - {{#virtual}} - (Virtual Package) - {{/virtual}} -

- -

{{{ _highlightResult.description.value }}}

- - {{#abandoned}} -

- Abandoned! - {{#replacementPackage}} - See {{ replacementPackage }} - {{/replacementPackage}} -

- {{/abandoned}} -
- -
- {{#meta}} - - {{/meta}} -
-
-
-` - }, - cssClasses: { - root: 'packages', - item: 'row' - } - }) -); - -search.addWidget( - instantsearch.widgets.pagination({ - container: '.pagination', - maxPages: 200, - scrollTo: false, - showFirstLast: false, - }) -); - -search.addWidget( - instantsearch.widgets.currentRefinedValues({ - container: '.search-facets-active-filters', - clearAll: 'before', - clearsQuery: false, - cssClasses: { - clearAll: 'pull-right' - }, - templates: { - header: 'Active filters', - item: function (filter) { - if ('tags' == filter.attributeName) { - return 'tag: ' + filter.name - } else { - return filter.attributeName + ': ' + filter.name - } - } - }, - onlyListedAttributes: true, - }) -); - -search.addWidget( - instantsearch.widgets.menu({ - container: '.search-facets-type', - attributeName: 'type', - limit: 15, - showMore: true, - templates: { - header: 'Package type' - } - }) -); - -search.addWidget( - instantsearch.widgets.refinementList({ - container: '.search-facets-tags', - attributeName: 'tags', - limit: 15, - showMore: true, - templates: { - header: 'Tags' - }, - searchForFacetValues:true - }) -); - -search.start(); diff --git a/src/Packagist/WebBundle/Resources/translations/messages.en.yml b/src/Packagist/WebBundle/Resources/translations/messages.en.yml index 7acde9ef..b34ce6b6 100644 --- a/src/Packagist/WebBundle/Resources/translations/messages.en.yml +++ b/src/Packagist/WebBundle/Resources/translations/messages.en.yml @@ -50,7 +50,7 @@ explore: search: claim_html: | - Packagist is the main Composer repository. It aggregates public PHP packages installable with Composer. + Packagist is the main Composer repository. It aggregates PHP packages installable with Composer. packages: mine: My packages @@ -152,7 +152,7 @@ user: 'Search packages...': 'Search packages...' brandname: Packagist -navclaim: The PHP Package Repository +navclaim: The Private Composer Repository Sort: 'Sort' Order: 'Order' Username: 'Username' diff --git a/src/Packagist/WebBundle/Resources/views/About/about.html.twig b/src/Packagist/WebBundle/Resources/views/About/about.html.twig index 29fad7a9..e5101f6c 100644 --- a/src/Packagist/WebBundle/Resources/views/About/about.html.twig +++ b/src/Packagist/WebBundle/Resources/views/About/about.html.twig @@ -99,6 +99,7 @@ v2.0.4-p1

How to update packages?

+ {% set url = app.request.getScheme() ~ '://' ~ app.request.getHttpHost() %}

GitHub Service Hook

@@ -116,15 +117,15 @@ v2.0.4-p1

Bitbucket Webhooks

-

To enable the Bitbucket web hook, go to your BitBucket repository, open the settings and select "Webhooks" in the menu. Add a new hook. You have to enter the Packagist endpoint, containing both your username and API token. Enter https://packagist.org/api/bitbucket?username={{ app.user.username|default('USERNAME') }}&apiToken=API_TOKEN as URL. Save your changes and you're done.

+

To enable the Bitbucket web hook, go to your BitBucket repository, open the settings and select "Webhooks" in the menu. Add a new hook. You have to enter the Packagist endpoint, containing both your username and API token. Enter {{ url }}/api/bitbucket?token={{ app.user.username|default('USERNAME') ~ ':' ~ app.user.apiToken|default('token') }} as URL. Save your changes and you're done.

Manual hook setup

-

If you do not use Bitbucket or GitHub there is a generic endpoint you can call manually from a git post-receive hook or similar. You have to do a POST request to https://packagist.org/api/update-package?username={{ app.user.username|default('USERNAME') }}&apiToken=API_TOKEN with a request body looking like this: {"repository":{"url":"PACKAGIST_PACKAGE_URL"}}

+

If you do not use Bitbucket or GitHub there is a generic endpoint you can call manually from a git post-receive hook or similar. You have to do a POST request to {{ url }}/api/update-package?token={{ app.user.username|default('USERNAME') ~ ':' ~ app.user.apiToken|default('token') }} with a request body looking like this: {"repository":{"url":"PACKAGIST_PACKAGE_URL"}}

You can do this using curl for example:

-
curl -XPOST -H'content-type:application/json' 'https://packagist.org/api/update-package?username={{ app.user.username|default('USERNAME') }}&apiToken=API_TOKEN' -d'{"repository":{"url":"PACKAGIST_PACKAGE_URL"}}'
+
curl -XPOST -H'content-type:application/json' '{{ url }}/api/update-package?token={{ app.user.username|default('USERNAME') ~ ':' ~ app.user.apiToken|default('token') }}' -d'{"repository":{"url":"PACKAGIST_PACKAGE_URL"}}'
diff --git a/src/Packagist/WebBundle/Resources/views/Group/index.html.twig b/src/Packagist/WebBundle/Resources/views/Group/index.html.twig index b4ce8beb..053f716f 100644 --- a/src/Packagist/WebBundle/Resources/views/Group/index.html.twig +++ b/src/Packagist/WebBundle/Resources/views/Group/index.html.twig @@ -15,16 +15,18 @@

{{ group.name }}

-
- -
+
+ +
diff --git a/src/Packagist/WebBundle/Resources/views/Package/package.html.twig b/src/Packagist/WebBundle/Resources/views/Package/package.html.twig new file mode 100644 index 00000000..a8a30824 --- /dev/null +++ b/src/Packagist/WebBundle/Resources/views/Package/package.html.twig @@ -0,0 +1,108 @@ +
+
+

+ + {{ package.name }} + +

+ + {% if package.abandoned %} +

+ Abandoned! + Package is abandoned, you should avoid using it. + {% if package.replacementPackage %} + Use {{ package.replacementPackage }} instead. + {% else %} + No replacement was suggested. + {% endif %} +

+ {% endif %} + +
+ +
+ {% if package.description %} +

{{ package.description }}

+ {% endif %} + + {% if package.highest and package.highest.tags|length %} +
+
Keywords
+
{{ package.highest.tags|join(', ') }}
+
+ {% endif %} + + {% if package.highest and package.highest.homepage %} + + {% endif %} + + {% if package.highest and package.highest.license %} +
+
License
+
{{ package.highest.license|join(', ') }}
+
+ {% endif %} + + {% if package.highest and package.highest.authors|length %} +
+
Authors
+
+ {% for author in package.highest.authors %} + {%- if author.homepage -%} + {{ author.name }} + {%- else -%} + {{ author.name }} + {%- endif -%} + {%- if not loop.last -%}, {% endif -%} + {% endfor %} +
+
+ {% endif %} + + {% if package.highest and package.highest.support %} +
+
Support
+
+
    + {% for support_type, support_url in package.highest.support %} +
  • {{ support_type|capitalize }}: {{ support_url }}
  • + {% endfor %} +
+
+
+ {% endif %} + +
+
Releases
+
+ {% for version in package.versions %} + {%- if version.dist -%} + {% set url = '?token=' ~ app.user.username ~ ':' ~ app.user.apiToken %} + + {{ version.version }} + + {%- else -%} + {{ version.version }} + {%- endif -%} + {%- if not loop.last -%}, {% endif -%} + {% endfor %} +
+
+ + {% if dependencies is defined and dependencies|length %} +
+
Required by
+
+ +
+
+ {% endif %} +
+
diff --git a/src/Packagist/WebBundle/Resources/views/Package/viewPackage.html.twig b/src/Packagist/WebBundle/Resources/views/Package/viewPackage.html.twig index ed9ecf5b..b9e73a72 100644 --- a/src/Packagist/WebBundle/Resources/views/Package/viewPackage.html.twig +++ b/src/Packagist/WebBundle/Resources/views/Package/viewPackage.html.twig @@ -37,6 +37,7 @@ {% endif %} {{ package.vendor }}/{{ package.packageName }} +

Last updated: {{ package.crawledAt ? package.crawledAt|date('Y-m-d H:i:s') ~ ' UTC': 'N/A' }}

@@ -71,11 +72,6 @@ %}
This package is in a broken state and will not update anymore. Some branches contain invalid data and until you fix them the entire package is frozen. Click "Update" below to see details.
{% endif %} - - {% if expandedVersion and not expandedVersion.license %} -
There is no license information available for the latest version ({{ expandedVersion.version }}) of this package.
- {% endif %} -

{{ package.description|truncate(300) }}

{% if hasActions %} @@ -112,7 +108,8 @@
-
+ {% if is_granted('ROLE_ADMIN') %} +

{% for maintainer in package.maintainers -%} @@ -214,6 +211,7 @@ {% endif %}

+ {% endif %}
diff --git a/src/Packagist/WebBundle/Resources/views/User/profile.html.twig b/src/Packagist/WebBundle/Resources/views/User/profile.html.twig index 9428d71e..9b17586e 100644 --- a/src/Packagist/WebBundle/Resources/views/User/profile.html.twig +++ b/src/Packagist/WebBundle/Resources/views/User/profile.html.twig @@ -16,12 +16,23 @@
-
-

Your customer needs to authenticate to access their Composer repository:
- The simplest way to provide your credentials is providing your set of credentials - inline with the repository specification such as: -

-
+
+    {% if deleteForm is defined and is_granted('ROLE_ADMIN') and user.admin == false %}
+        
+
+ {{ form_widget(deleteForm._token) }} + +
+
+ {% endif %} + + {% if user.admin == false or isActualUser %} +
+

Your customer needs to authenticate to access their Composer repository:
+ The simplest way to provide your credentials is providing your set of credentials + inline with the repository specification such as: +

+
 {
     "repositories": [
         {
@@ -30,16 +41,17 @@
         }
     ]
 }
-        
-

- When you don't want to hard code your credentials into your composer.json. - There is a second way to provide these details and it is via interaction. - If you don't provide the authentication credentials composer will prompt you upon connection - to enter the username and password. -

-
+            
+

+ When you don't want to hard code your credentials into your composer.json. + There is a second way to provide these details and it is via interaction. + If you don't provide the authentication credentials composer will prompt you upon connection + to enter the username and password. +

+
 composer config --global --auth http-basic.{{ app.request.getHttpHost() }} {{ user.username }} {{ user.apiToken }}
-        
-
+
+
+ {% endif %}
{% endblock %} diff --git a/src/Packagist/WebBundle/Resources/views/Web/index.html.twig b/src/Packagist/WebBundle/Resources/views/Web/index.html.twig index 203d2c4f..83edb5c6 100644 --- a/src/Packagist/WebBundle/Resources/views/Web/index.html.twig +++ b/src/Packagist/WebBundle/Resources/views/Web/index.html.twig @@ -2,64 +2,14 @@ {% block content %}
-
-

Getting Started

-
-

Define Your Dependencies

-

Put a file named composer.json at the root of your project, containing your project dependencies:

-
{
-    "require": {
-        "vendor/package": "1.3.2",
-        "vendor/package2": "1.*",
-        "vendor/package3": "^2.0.3"
-    }
-}
- -

For more information about packages versions usage, see the composer documentation.

- -

Install Composer In Your Project

-

Run this in your command line:

-
curl -sS https://getcomposer.org/installer | php
-

Or download composer.phar into your project root.

-

See the Composer documentation for complete installation instructions on various platforms.

- -

Install Dependencies

-

Execute this in your project root.

-
php composer.phar install
- -

Autoload Dependencies

-

If your packages specify autoloading information, you can autoload all the dependencies by adding this to your code:

-
require 'vendor/autoload.php';
-

Browse the packages we have to find more great libraries you can use in your project.

-
-
- -
-

Publishing Packages

-
-

Define Your Package

-

Put a file named composer.json at the root of your package's repository, containing this information:

-
{
-    "name": "your-vendor-name/package-name",
-    "description": "A short description of what your package does",
-    "require": {
-        "php": "^5.3.3 || ^7.0",
-        "another-vendor/package": "1.*"
-    }
-}
-

This is the strictly minimal information you have to give.

-

For more details about package naming and the fields you can use to document your package better, see the about page.

- -

Commit The File

-

Add the composer.json to your git or other VCS repository and commit it.

- -

Publish It

-

Login on this site, then hit the submit button in the menu.

-

Once you entered your public repository URL in there, your package will be automatically crawled periodically. You just have to make sure you keep the composer.json file up to date.

- -

Sharing Private Code

-

Use Private Packagist if you want to share private code as a Composer package with colleagues or customers without publishing it for everyone on Packagist.org. Private Packagist allows you to manage your own private Composer repository with per-user authentication, team management and integration in version control systems.

-
-
+ {% for packageInfo in packages %} + {% set package = packageInfo.package %} + {% set dependencies = packageInfo.dependencies %} + {% include 'PackagistWebBundle:Package:package.html.twig' %} + {% endfor %} + + {% if packages.haveToPaginate() %} + {{ pagerfanta(packages, 'twitter_bootstrap', {'proximity': 2}) }} + {% endif %}
{% endblock %} diff --git a/src/Packagist/WebBundle/Resources/views/Web/search.html.twig b/src/Packagist/WebBundle/Resources/views/Web/search.html.twig index b0252c82..f74dc47f 100644 --- a/src/Packagist/WebBundle/Resources/views/Web/search.html.twig +++ b/src/Packagist/WebBundle/Resources/views/Web/search.html.twig @@ -1,2 +1,19 @@ -{% embed "PackagistWebBundle:Web:list.html.twig" %} -{% endembed %} +{% extends noLayout|default(false) ? "::base_nolayout.html.twig" : "PackagistWebBundle::layout.html.twig" %} + +{% block content %} + {% block content_title %}

{{ 'listing.title'|trans }}

{% endblock %} +
+ {% if packages|length %} + {% for package in packages %} + {% include 'PackagistWebBundle:Package:package.html.twig' %} + {% endfor %} + {% if packages.haveToPaginate() %} + {{ pagerfanta(packages, 'twitter_bootstrap', {'proximity': 2}) }} + {% endif %} + {% else %} +
+

{{ 'listing.nopackages'|trans }}

+
+ {% endif %} +
+{% endblock %} diff --git a/src/Packagist/WebBundle/Resources/views/forms.html.twig b/src/Packagist/WebBundle/Resources/views/forms.html.twig index 37c4f07f..9f6c0070 100644 --- a/src/Packagist/WebBundle/Resources/views/forms.html.twig +++ b/src/Packagist/WebBundle/Resources/views/forms.html.twig @@ -52,11 +52,11 @@ {%- block package_permission_widget -%}
-
{% if value is not empty %}{{ value.name }}{% endif %}
- {{ form_widget(form.version) }} +
{% if value is not empty %}{{ value.name }}{% endif %}
{{ form_widget(form.selected) }}
+
{{ form_widget(form.version) }}
{{ form_widget(form.name) }}
{{ form_errors(form.version) }} diff --git a/src/Packagist/WebBundle/Resources/views/layout.html.twig b/src/Packagist/WebBundle/Resources/views/layout.html.twig index e5aa3bde..9831fbeb 100644 --- a/src/Packagist/WebBundle/Resources/views/layout.html.twig +++ b/src/Packagist/WebBundle/Resources/views/layout.html.twig @@ -22,9 +22,6 @@ {% endblock %} - - - {% block head_additions %}{% endblock %} @@ -45,13 +42,13 @@
-

Packagist maintenance and hosting is supported by Private Packagist

+

Packagist maintenance and hosting is supported by Cuantic

diff --git a/src/Packagist/WebBundle/Security/Acl/PackagesAclVoter.php b/src/Packagist/WebBundle/Security/Acl/PackagesAclVoter.php index 8e3198be..98983d6d 100644 --- a/src/Packagist/WebBundle/Security/Acl/PackagesAclVoter.php +++ b/src/Packagist/WebBundle/Security/Acl/PackagesAclVoter.php @@ -20,22 +20,6 @@ public function __construct(PackagesAclChecker $checker) $this->checker = $checker; } - /** - * {@inheritdoc} - */ - public function supportsAttribute($attribute) - { - return true; - } - - /** - * {@inheritdoc} - */ - public function supportsClass($class) - { - return true; - } - /** * {@inheritdoc} */ @@ -56,6 +40,6 @@ public function vote(TokenInterface $token, $object, array $attributes) return self::ACCESS_DENIED; } - return self::ACCESS_ABSTAIN; + return self::ACCESS_GRANTED; } } diff --git a/src/Packagist/WebBundle/Security/Api/ApiTokenProvider.php b/src/Packagist/WebBundle/Security/Api/ApiTokenProvider.php index 7e077acb..79b8db88 100644 --- a/src/Packagist/WebBundle/Security/Api/ApiTokenProvider.php +++ b/src/Packagist/WebBundle/Security/Api/ApiTokenProvider.php @@ -1,5 +1,7 @@ userProvider = $provider; + $this->userChecker = $userChecker; } /** @@ -71,6 +76,7 @@ protected function retrieveUser(string $username, TokenInterface $token): User try { $user = $this->userProvider->loadUserByUsername($username); + $this->userChecker->checkPreAuth($user); } catch (UsernameNotFoundException $e) { throw new BadCredentialsException('Bad credentials.', 0, $e); } catch (\Exception $e) { diff --git a/src/Packagist/WebBundle/Security/Provider/UserProvider.php b/src/Packagist/WebBundle/Security/Provider/UserProvider.php index d00790a4..7b6d8b56 100644 --- a/src/Packagist/WebBundle/Security/Provider/UserProvider.php +++ b/src/Packagist/WebBundle/Security/Provider/UserProvider.php @@ -13,14 +13,10 @@ namespace Packagist\WebBundle\Security\Provider; use FOS\UserBundle\Model\UserManagerInterface; -use HWI\Bundle\OAuthBundle\OAuth\Response\UserResponseInterface; -use HWI\Bundle\OAuthBundle\Security\Core\Exception\AccountNotLinkedException; -use HWI\Bundle\OAuthBundle\Security\Core\User\OAuthAwareUserProviderInterface; -use Packagist\WebBundle\Entity\User; use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Core\User\UserProviderInterface; -class UserProvider implements OAuthAwareUserProviderInterface, UserProviderInterface +class UserProvider implements UserProviderInterface { /** * @var UserManagerInterface @@ -42,56 +38,6 @@ public function __construct(UserManagerInterface $userManager, UserProviderInter $this->userProvider = $userProvider; } - /** - * {@inheritDoc} - */ - public function connect($user, UserResponseInterface $response) - { - $username = $response->getUsername(); - - /** @var User $previousUser */ - $previousUser = $this->userManager->findUserBy(array('githubId' => $username)); - - /** @var User $user */ - $user->setGithubId($username); - $user->setGithubToken($response->getAccessToken()); - - // The account is already connected. Do nothing - if ($previousUser === $user) { - return; - } - - // 'disconnect' a previous account - if (null !== $previousUser) { - $previousUser->setGithubId(null); - $previousUser->setGithubToken(null); - $this->userManager->updateUser($previousUser); - } - - $this->userManager->updateUser($user); - } - - /** - * {@inheritDoc} - */ - public function loadUserByOAuthUserResponse(UserResponseInterface $response) - { - $username = $response->getUsername(); - /** @var User $user */ - $user = $this->userManager->findUserBy(array('githubId' => $username)); - - if (!$user) { - throw new AccountNotLinkedException(sprintf('No user with github username "%s" was found.', $username)); - } - - if ($user->getGithubToken() !== $response->getAccessToken()) { - $user->setGithubToken($response->getAccessToken()); - $this->userManager->updateUser($user); - } - - return $user; - } - /** * {@inheritDoc} */ diff --git a/src/Packagist/WebBundle/Service/DistConfig.php b/src/Packagist/WebBundle/Service/DistConfig.php index 2cd39d3f..20e8b901 100644 --- a/src/Packagist/WebBundle/Service/DistConfig.php +++ b/src/Packagist/WebBundle/Service/DistConfig.php @@ -1,4 +1,6 @@ -generateTargetDir($name); - return $targetDir . '/' . $reference . '.' . $this->getArchiveFormat(); + $fileName = $this->getFileName($reference, $version); + return $targetDir . '/' . $fileName . '.' . $this->getArchiveFormat(); + } + + /** + * @param string $reference + * @param string $version + * @return string + */ + public function getFileName(string $reference, string $version): string + { + $fileName = $version . '-' . $reference; + return str_replace('/', '-', $fileName); + } + + /** + * @param string $fileName + * @return string + */ + public function guessesVersion(string $fileName) + { + $fileName = explode('-', $fileName); + $pathCount = count($fileName); + if ($pathCount > 1) { + unset($fileName[$pathCount - 1]); + } + + $fileName = implode('-', $fileName); + $fileName = preg_replace('/(ticket|feature|fix)-/i', '$1/', $fileName); + return $fileName; } /** @@ -80,4 +112,12 @@ public function isEnable(): bool { return !empty($this->config); } + + /** + * @return bool + */ + public function isLazy(): bool + { + return $this->config['lazy'] ?? true; + } } diff --git a/src/Packagist/WebBundle/Service/DistManager.php b/src/Packagist/WebBundle/Service/DistManager.php new file mode 100644 index 00000000..cdaaf7be --- /dev/null +++ b/src/Packagist/WebBundle/Service/DistManager.php @@ -0,0 +1,92 @@ +config = $config; + $this->fileSystem = new Filesystem(); + } + + public function getDistPath(Version $version): ?string + { + $dist = $version->getDist(); + if (false === isset($dist['reference'])) { + return null; + } + + $path = $this->config->generateDistFileName($version->getName(), $dist['reference'], $version->getVersion()); + if ($this->fileSystem->exists($path)) { + return $path; + } + + return $this->download($version); + } + + public function lookupInCache(string $reference, string $packageName): ?array + { + $finder = new Finder(); + $files = $finder + ->in($this->config->generateTargetDir($packageName)) + ->name("/$reference/") + ->files(); + /** @var \SplFileObject $file */ + foreach ($files as $file) { + $fileName = $file->getFilename(); + if ($version = $this->config->guessesVersion($fileName)) { + return [$file->getRealPath(), $version]; + } + } + + return [null, null]; + } + + private function download(Version $version): ?string + { + $package = $version->getPackage(); + $package->loadCredentials(); + + $io = new BufferIO('', StreamOutput::VERBOSITY_VERBOSE); + $config = Factory::createConfig(); + $io->loadConfiguration($config); + $repository = new VcsRepository(['url' => $package->getRepository()], $io, $config); + + $factory = new Factory(); + $dm = $factory->createDownloadManager($io, $config); + $archiveManager = $factory->createArchiveManager($config, $dm); + $archiveManager->setOverwriteFiles(false); + + $versions = $repository->getPackages(); + $source = $version->getSource(); + foreach ($versions as $rootVersion) { + if ($rootVersion->getSourceReference() === $source['reference']) { + $fileName = $this->config->getFileName($source['reference'], $version->getVersion()); + $path = $archiveManager->archive( + $rootVersion, + $this->config->getArchiveFormat(), + $this->config->generateTargetDir($version->getName()), + $fileName + ); + + return $path; + } + } + + return null; + } +} diff --git a/src/Packagist/WebBundle/Service/UpdaterWorker.php b/src/Packagist/WebBundle/Service/UpdaterWorker.php index d3b9e056..754dd649 100644 --- a/src/Packagist/WebBundle/Service/UpdaterWorker.php +++ b/src/Packagist/WebBundle/Service/UpdaterWorker.php @@ -2,13 +2,9 @@ namespace Packagist\WebBundle\Service; -use Composer\IO\IOInterface; -use Composer\Package\Archiver\PharArchiver; -use Composer\Package\Archiver\ZipArchiver; -use Packagist\WebBundle\Package\ArchiveManager; +use Packagist\WebBundle\Model\ValidatingArrayLoader; use Psr\Log\LoggerInterface; use Composer\Package\Loader\ArrayLoader; -use Composer\Package\Loader\ValidatingArrayLoader; use Symfony\Bridge\Doctrine\RegistryInterface; use Composer\Console\HtmlOutputFormatter; use Composer\Repository\InvalidRepositoryException; @@ -23,7 +19,6 @@ use Seld\Signal\SignalHandler; use Composer\Factory; use Composer\Downloader\TransportException; -use Composer\Util\RemoteFilesystem; class UpdaterWorker { @@ -77,7 +72,6 @@ public function process(Job $job, SignalHandler $signal): array $config = Factory::createConfig(); $io = new BufferIO('', OutputInterface::VERBOSITY_VERY_VERBOSE, new HtmlOutputFormatter(Factory::createAdditionalStyles())); $io->loadConfiguration($config); - $archiveManager = $this->createArchiveManager($io); try { $flags = 0; @@ -97,15 +91,7 @@ public function process(Job $job, SignalHandler $signal): array $repository->setLoader($loader); // perform the actual update (fetch and re-scan the repository's source) - $this->updater->setArchiveManager($archiveManager); $package = $this->updater->update($io, $config, $package, $repository, $flags); - - // github update downgraded to a git clone, this should not happen, so check through API whether the package still exists - if (preg_match('{[@/]github.com[:/]([^/]+/[^/]+?)(\.git)?$}i', $package->getRepository(), $match) && 0 === strpos($repository->getDriver()->getUrl(), 'git@')) { - if ($result = $this->checkForDeadGitHubPackage($package, $match, $io, $io->getOutput())) { - return $result; - } - } } catch (\Throwable $e) { $output = $io->getOutput(); @@ -151,13 +137,6 @@ public function process(Job $job, SignalHandler $signal): array $found404 = true; } - // github 404'ed, check through API whether the package still exists and delete if not - if ($found404 && preg_match('{[@/]github.com[:/]([^/]+/[^/]+?)(\.git)?$}i', $package->getRepository(), $match)) { - if ($result = $this->checkForDeadGitHubPackage($package, $match, $io, $output)) { - return $result; - } - } - // detected a 404 so mark the package as gone and prevent updates for 1y if ($found404) { $package->setCrawledAt(new \DateTime('+1 year')); @@ -203,52 +182,4 @@ public function process(Job $job, SignalHandler $signal): array 'details' => '
'.$io->getOutput().'
' ]; } - - private function checkForDeadGitHubPackage(Package $package, $match, $io, $output) - { - $rfs = new RemoteFilesystem($io); - try { - $rfs->getContents('github.com', 'https://api.github.com/repos/'.$match[1], false, ['retry-auth-failure' => false]); - } catch (\Throwable $e) { - if ($e instanceof TransportException && $e->getStatusCode() === 404) { - try { - if ( - // check composer repo is visible to make sure it's not github or something else glitching - $rfs->getContents('github.com', 'https://api.github.com/repos/composer/composer', false, ['retry-auth-failure' => false]) - // remove packages with very low downloads and that are 404 - && $this->downloadManager->getTotalDownloads($package) <= 100 - ) { - $name = $package->getName(); - $this->packageManager->deletePackage($package); - - return [ - 'status' => Job::STATUS_PACKAGE_DELETED, - 'message' => 'Update of '.$package->getName().' failed, package appears to be 404/gone and has been deleted', - 'details' => '
'.$output.'
', - 'exception' => $e, - ]; - } - } catch (\Throwable $e) { - // ignore failures here, we/github must be offline - } - } - } - } - - /** - * @param IOInterface $io - * @return ArchiveManager - */ - private function createArchiveManager(IOInterface $io) - { - $composer = Factory::create($io); - $downloadManager = $composer->getDownloadManager(); - - $archiveManager = new ArchiveManager($downloadManager); - $archiveManager->setOverwriteFiles(false); - $archiveManager->addArchiver(new ZipArchiver()); - $archiveManager->addArchiver(new PharArchiver()); - - return $archiveManager; - } } diff --git a/src/Packagist/WebBundle/Twig/PackagistExtension.php b/src/Packagist/WebBundle/Twig/PackagistExtension.php index 85cc2c09..9b0b9481 100644 --- a/src/Packagist/WebBundle/Twig/PackagistExtension.php +++ b/src/Packagist/WebBundle/Twig/PackagistExtension.php @@ -2,18 +2,18 @@ namespace Packagist\WebBundle\Twig; -use Packagist\WebBundle\Model\ProviderManager; +use Symfony\Component\DependencyInjection\ContainerInterface; class PackagistExtension extends \Twig_Extension { /** - * @var ProviderManager + * @var ContainerInterface */ - private $providerManager; + private $container; - public function __construct(ProviderManager $providerManager) + public function __construct(ContainerInterface $container) { - $this->providerManager = $providerManager; + $this->container = $container; } public function getTests() @@ -49,12 +49,12 @@ public function packageExistsTest($package) return false; } - return $this->providerManager->packageExists($package); + return $this->getProviderManager()->packageExists($package); } public function providerExistsTest($package) { - return $this->providerManager->packageIsProvided($package); + return $this->getProviderManager()->packageIsProvided($package); } public function prettifySourceReference($sourceReference) @@ -70,4 +70,12 @@ public function generateGravatarHash($email) { return md5(strtolower($email)); } + + /** + * @return \Packagist\WebBundle\Model\ProviderManager + */ + private function getProviderManager() + { + return $this->container->get('packagist.provider_manager'); + } } diff --git a/src/Packagist/WebBundle/Util/UserManipulator.php b/src/Packagist/WebBundle/Util/UserManipulator.php index 813a4ba8..8166e772 100644 --- a/src/Packagist/WebBundle/Util/UserManipulator.php +++ b/src/Packagist/WebBundle/Util/UserManipulator.php @@ -15,8 +15,8 @@ use FOS\UserBundle\Model\UserManagerInterface; use FOS\UserBundle\Util\TokenGeneratorInterface; use FOS\UserBundle\Util\UserManipulator as BaseManipulator; -use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Symfony\Component\HttpFoundation\RequestStack; class UserManipulator extends BaseManipulator { @@ -30,13 +30,13 @@ public function __construct( UserManagerInterface $userManager, TokenGeneratorInterface $tokenGenerator, EventDispatcherInterface $dispatcher, - ContainerInterface $container + RequestStack $requestStack ) { $this->userManager = $userManager; $this->tokenGenerator = $tokenGenerator; - parent::__construct($userManager, $dispatcher, $container); + parent::__construct($userManager, $dispatcher, $requestStack); } /** diff --git a/var/SymfonyRequirements.php b/var/SymfonyRequirements.php new file mode 100644 index 00000000..4a1fcc62 --- /dev/null +++ b/var/SymfonyRequirements.php @@ -0,0 +1,810 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/* + * Users of PHP 5.2 should be able to run the requirements checks. + * This is why the file and all classes must be compatible with PHP 5.2+ + * (e.g. not using namespaces and closures). + * + * ************** CAUTION ************** + * + * DO NOT EDIT THIS FILE as it will be overridden by Composer as part of + * the installation/update process. The original file resides in the + * SensioDistributionBundle. + * + * ************** CAUTION ************** + */ + +/** + * Represents a single PHP requirement, e.g. an installed extension. + * It can be a mandatory requirement or an optional recommendation. + * There is a special subclass, named PhpIniRequirement, to check a php.ini configuration. + * + * @author Tobias Schultze + */ +class Requirement +{ + private $fulfilled; + private $testMessage; + private $helpText; + private $helpHtml; + private $optional; + + /** + * Constructor that initializes the requirement. + * + * @param bool $fulfilled Whether the requirement is fulfilled + * @param string $testMessage The message for testing the requirement + * @param string $helpHtml The help text formatted in HTML for resolving the problem + * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) + * @param bool $optional Whether this is only an optional recommendation not a mandatory requirement + */ + public function __construct($fulfilled, $testMessage, $helpHtml, $helpText = null, $optional = false) + { + $this->fulfilled = (bool) $fulfilled; + $this->testMessage = (string) $testMessage; + $this->helpHtml = (string) $helpHtml; + $this->helpText = null === $helpText ? strip_tags($this->helpHtml) : (string) $helpText; + $this->optional = (bool) $optional; + } + + /** + * Returns whether the requirement is fulfilled. + * + * @return bool true if fulfilled, otherwise false + */ + public function isFulfilled() + { + return $this->fulfilled; + } + + /** + * Returns the message for testing the requirement. + * + * @return string The test message + */ + public function getTestMessage() + { + return $this->testMessage; + } + + /** + * Returns the help text for resolving the problem. + * + * @return string The help text + */ + public function getHelpText() + { + return $this->helpText; + } + + /** + * Returns the help text formatted in HTML. + * + * @return string The HTML help + */ + public function getHelpHtml() + { + return $this->helpHtml; + } + + /** + * Returns whether this is only an optional recommendation and not a mandatory requirement. + * + * @return bool true if optional, false if mandatory + */ + public function isOptional() + { + return $this->optional; + } +} + +/** + * Represents a PHP requirement in form of a php.ini configuration. + * + * @author Tobias Schultze + */ +class PhpIniRequirement extends Requirement +{ + /** + * Constructor that initializes the requirement. + * + * @param string $cfgName The configuration name used for ini_get() + * @param bool|callback $evaluation Either a boolean indicating whether the configuration should evaluate to true or false, + * or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement + * @param bool $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false. + * This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin. + * Example: You require a config to be true but PHP later removes this config and defaults it to true internally. + * @param string|null $testMessage The message for testing the requirement (when null and $evaluation is a boolean a default message is derived) + * @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) + * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) + * @param bool $optional Whether this is only an optional recommendation not a mandatory requirement + */ + public function __construct($cfgName, $evaluation, $approveCfgAbsence = false, $testMessage = null, $helpHtml = null, $helpText = null, $optional = false) + { + $cfgValue = ini_get($cfgName); + + if (is_callable($evaluation)) { + if (null === $testMessage || null === $helpHtml) { + throw new InvalidArgumentException('You must provide the parameters testMessage and helpHtml for a callback evaluation.'); + } + + $fulfilled = call_user_func($evaluation, $cfgValue); + } else { + if (null === $testMessage) { + $testMessage = sprintf('%s %s be %s in php.ini', + $cfgName, + $optional ? 'should' : 'must', + $evaluation ? 'enabled' : 'disabled' + ); + } + + if (null === $helpHtml) { + $helpHtml = sprintf('Set %s to %s in php.ini*.', + $cfgName, + $evaluation ? 'on' : 'off' + ); + } + + $fulfilled = $evaluation == $cfgValue; + } + + parent::__construct($fulfilled || ($approveCfgAbsence && false === $cfgValue), $testMessage, $helpHtml, $helpText, $optional); + } +} + +/** + * A RequirementCollection represents a set of Requirement instances. + * + * @author Tobias Schultze + */ +class RequirementCollection implements IteratorAggregate +{ + /** + * @var Requirement[] + */ + private $requirements = array(); + + /** + * Gets the current RequirementCollection as an Iterator. + * + * @return Traversable A Traversable interface + */ + public function getIterator() + { + return new ArrayIterator($this->requirements); + } + + /** + * Adds a Requirement. + * + * @param Requirement $requirement A Requirement instance + */ + public function add(Requirement $requirement) + { + $this->requirements[] = $requirement; + } + + /** + * Adds a mandatory requirement. + * + * @param bool $fulfilled Whether the requirement is fulfilled + * @param string $testMessage The message for testing the requirement + * @param string $helpHtml The help text formatted in HTML for resolving the problem + * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) + */ + public function addRequirement($fulfilled, $testMessage, $helpHtml, $helpText = null) + { + $this->add(new Requirement($fulfilled, $testMessage, $helpHtml, $helpText, false)); + } + + /** + * Adds an optional recommendation. + * + * @param bool $fulfilled Whether the recommendation is fulfilled + * @param string $testMessage The message for testing the recommendation + * @param string $helpHtml The help text formatted in HTML for resolving the problem + * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) + */ + public function addRecommendation($fulfilled, $testMessage, $helpHtml, $helpText = null) + { + $this->add(new Requirement($fulfilled, $testMessage, $helpHtml, $helpText, true)); + } + + /** + * Adds a mandatory requirement in form of a php.ini configuration. + * + * @param string $cfgName The configuration name used for ini_get() + * @param bool|callback $evaluation Either a boolean indicating whether the configuration should evaluate to true or false, + * or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement + * @param bool $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false. + * This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin. + * Example: You require a config to be true but PHP later removes this config and defaults it to true internally. + * @param string $testMessage The message for testing the requirement (when null and $evaluation is a boolean a default message is derived) + * @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) + * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) + */ + public function addPhpIniRequirement($cfgName, $evaluation, $approveCfgAbsence = false, $testMessage = null, $helpHtml = null, $helpText = null) + { + $this->add(new PhpIniRequirement($cfgName, $evaluation, $approveCfgAbsence, $testMessage, $helpHtml, $helpText, false)); + } + + /** + * Adds an optional recommendation in form of a php.ini configuration. + * + * @param string $cfgName The configuration name used for ini_get() + * @param bool|callback $evaluation Either a boolean indicating whether the configuration should evaluate to true or false, + * or a callback function receiving the configuration value as parameter to determine the fulfillment of the requirement + * @param bool $approveCfgAbsence If true the Requirement will be fulfilled even if the configuration option does not exist, i.e. ini_get() returns false. + * This is helpful for abandoned configs in later PHP versions or configs of an optional extension, like Suhosin. + * Example: You require a config to be true but PHP later removes this config and defaults it to true internally. + * @param string $testMessage The message for testing the requirement (when null and $evaluation is a boolean a default message is derived) + * @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) + * @param string|null $helpText The help text (when null, it will be inferred from $helpHtml, i.e. stripped from HTML tags) + */ + public function addPhpIniRecommendation($cfgName, $evaluation, $approveCfgAbsence = false, $testMessage = null, $helpHtml = null, $helpText = null) + { + $this->add(new PhpIniRequirement($cfgName, $evaluation, $approveCfgAbsence, $testMessage, $helpHtml, $helpText, true)); + } + + /** + * Adds a requirement collection to the current set of requirements. + * + * @param RequirementCollection $collection A RequirementCollection instance + */ + public function addCollection(RequirementCollection $collection) + { + $this->requirements = array_merge($this->requirements, $collection->all()); + } + + /** + * Returns both requirements and recommendations. + * + * @return Requirement[] + */ + public function all() + { + return $this->requirements; + } + + /** + * Returns all mandatory requirements. + * + * @return Requirement[] + */ + public function getRequirements() + { + $array = array(); + foreach ($this->requirements as $req) { + if (!$req->isOptional()) { + $array[] = $req; + } + } + + return $array; + } + + /** + * Returns the mandatory requirements that were not met. + * + * @return Requirement[] + */ + public function getFailedRequirements() + { + $array = array(); + foreach ($this->requirements as $req) { + if (!$req->isFulfilled() && !$req->isOptional()) { + $array[] = $req; + } + } + + return $array; + } + + /** + * Returns all optional recommendations. + * + * @return Requirement[] + */ + public function getRecommendations() + { + $array = array(); + foreach ($this->requirements as $req) { + if ($req->isOptional()) { + $array[] = $req; + } + } + + return $array; + } + + /** + * Returns the recommendations that were not met. + * + * @return Requirement[] + */ + public function getFailedRecommendations() + { + $array = array(); + foreach ($this->requirements as $req) { + if (!$req->isFulfilled() && $req->isOptional()) { + $array[] = $req; + } + } + + return $array; + } + + /** + * Returns whether a php.ini configuration is not correct. + * + * @return bool php.ini configuration problem? + */ + public function hasPhpIniConfigIssue() + { + foreach ($this->requirements as $req) { + if (!$req->isFulfilled() && $req instanceof PhpIniRequirement) { + return true; + } + } + + return false; + } + + /** + * Returns the PHP configuration file (php.ini) path. + * + * @return string|false php.ini file path + */ + public function getPhpIniConfigPath() + { + return get_cfg_var('cfg_file_path'); + } +} + +/** + * This class specifies all requirements and optional recommendations that + * are necessary to run the Symfony Standard Edition. + * + * @author Tobias Schultze + * @author Fabien Potencier + */ +class SymfonyRequirements extends RequirementCollection +{ + const LEGACY_REQUIRED_PHP_VERSION = '5.3.3'; + const REQUIRED_PHP_VERSION = '5.5.9'; + + /** + * Constructor that initializes the requirements. + */ + public function __construct() + { + /* mandatory requirements follow */ + + $installedPhpVersion = PHP_VERSION; + $requiredPhpVersion = $this->getPhpRequiredVersion(); + + $this->addRecommendation( + $requiredPhpVersion, + 'Vendors should be installed in order to check all requirements.', + 'Run the composer install command.', + 'Run the "composer install" command.' + ); + + if (false !== $requiredPhpVersion) { + $this->addRequirement( + version_compare($installedPhpVersion, $requiredPhpVersion, '>='), + sprintf('PHP version must be at least %s (%s installed)', $requiredPhpVersion, $installedPhpVersion), + sprintf('You are running PHP version "%s", but Symfony needs at least PHP "%s" to run. + Before using Symfony, upgrade your PHP installation, preferably to the latest version.', + $installedPhpVersion, $requiredPhpVersion), + sprintf('Install PHP %s or newer (installed version is %s)', $requiredPhpVersion, $installedPhpVersion) + ); + } + + $this->addRequirement( + version_compare($installedPhpVersion, '5.3.16', '!='), + 'PHP version must not be 5.3.16 as Symfony won\'t work properly with it', + 'Install PHP 5.3.17 or newer (or downgrade to an earlier PHP version)' + ); + + $this->addRequirement( + is_dir(__DIR__.'/../vendor/composer'), + 'Vendor libraries must be installed', + 'Vendor libraries are missing. Install composer following instructions from http://getcomposer.org/. '. + 'Then run "php composer.phar install" to install them.' + ); + + $cacheDir = is_dir(__DIR__.'/../var/cache') ? __DIR__.'/../var/cache' : __DIR__.'/cache'; + + $this->addRequirement( + is_writable($cacheDir), + 'app/cache/ or var/cache/ directory must be writable', + 'Change the permissions of either "app/cache/" or "var/cache/" directory so that the web server can write into it.' + ); + + $logsDir = is_dir(__DIR__.'/../var/logs') ? __DIR__.'/../var/logs' : __DIR__.'/logs'; + + $this->addRequirement( + is_writable($logsDir), + 'app/logs/ or var/logs/ directory must be writable', + 'Change the permissions of either "app/logs/" or "var/logs/" directory so that the web server can write into it.' + ); + + if (version_compare($installedPhpVersion, '7.0.0', '<')) { + $this->addPhpIniRequirement( + 'date.timezone', true, false, + 'date.timezone setting must be set', + 'Set the "date.timezone" setting in php.ini* (like Europe/Paris).' + ); + } + + if (false !== $requiredPhpVersion && version_compare($installedPhpVersion, $requiredPhpVersion, '>=')) { + $this->addRequirement( + in_array(@date_default_timezone_get(), DateTimeZone::listIdentifiers(), true), + sprintf('Configured default timezone "%s" must be supported by your installation of PHP', @date_default_timezone_get()), + '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.' + ); + } + + $this->addRequirement( + function_exists('iconv'), + 'iconv() must be available', + 'Install and enable the iconv extension.' + ); + + $this->addRequirement( + function_exists('json_encode'), + 'json_encode() must be available', + 'Install and enable the JSON extension.' + ); + + $this->addRequirement( + function_exists('session_start'), + 'session_start() must be available', + 'Install and enable the session extension.' + ); + + $this->addRequirement( + function_exists('ctype_alpha'), + 'ctype_alpha() must be available', + 'Install and enable the ctype extension.' + ); + + $this->addRequirement( + function_exists('token_get_all'), + 'token_get_all() must be available', + 'Install and enable the Tokenizer extension.' + ); + + $this->addRequirement( + function_exists('simplexml_import_dom'), + 'simplexml_import_dom() must be available', + 'Install and enable the SimpleXML extension.' + ); + + if (function_exists('apc_store') && ini_get('apc.enabled')) { + if (version_compare($installedPhpVersion, '5.4.0', '>=')) { + $this->addRequirement( + version_compare(phpversion('apc'), '3.1.13', '>='), + 'APC version must be at least 3.1.13 when using PHP 5.4', + 'Upgrade your APC extension (3.1.13+).' + ); + } else { + $this->addRequirement( + version_compare(phpversion('apc'), '3.0.17', '>='), + 'APC version must be at least 3.0.17', + 'Upgrade your APC extension (3.0.17+).' + ); + } + } + + $this->addPhpIniRequirement('detect_unicode', false); + + if (extension_loaded('suhosin')) { + $this->addPhpIniRequirement( + 'suhosin.executor.include.whitelist', + create_function('$cfgValue', 'return false !== stripos($cfgValue, "phar");'), + false, + 'suhosin.executor.include.whitelist must be configured correctly in php.ini', + 'Add "phar" to suhosin.executor.include.whitelist in php.ini*.' + ); + } + + if (extension_loaded('xdebug')) { + $this->addPhpIniRequirement( + 'xdebug.show_exception_trace', false, true + ); + + $this->addPhpIniRequirement( + 'xdebug.scream', false, true + ); + + $this->addPhpIniRecommendation( + 'xdebug.max_nesting_level', + create_function('$cfgValue', 'return $cfgValue > 100;'), + true, + 'xdebug.max_nesting_level should be above 100 in php.ini', + '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.' + ); + } + + $pcreVersion = defined('PCRE_VERSION') ? (float) PCRE_VERSION : null; + + $this->addRequirement( + null !== $pcreVersion, + 'PCRE extension must be available', + 'Install the PCRE extension (version 8.0+).' + ); + + if (extension_loaded('mbstring')) { + $this->addPhpIniRequirement( + 'mbstring.func_overload', + create_function('$cfgValue', 'return (int) $cfgValue === 0;'), + true, + 'string functions should not be overloaded', + 'Set "mbstring.func_overload" to 0 in php.ini* to disable function overloading by the mbstring extension.' + ); + } + + /* optional recommendations follow */ + + if (file_exists(__DIR__.'/../vendor/composer')) { + require_once __DIR__.'/../vendor/autoload.php'; + + try { + $r = new ReflectionClass('Sensio\Bundle\DistributionBundle\SensioDistributionBundle'); + + $contents = file_get_contents(dirname($r->getFileName()).'/Resources/skeleton/app/SymfonyRequirements.php'); + } catch (ReflectionException $e) { + $contents = ''; + } + $this->addRecommendation( + file_get_contents(__FILE__) === $contents, + 'Requirements file should be up-to-date', + 'Your requirements file is outdated. Run composer install and re-check your configuration.' + ); + } + + $this->addRecommendation( + version_compare($installedPhpVersion, '5.3.4', '>='), + 'You should use at least PHP 5.3.4 due to PHP bug #52083 in earlier versions', + '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.' + ); + + $this->addRecommendation( + version_compare($installedPhpVersion, '5.3.8', '>='), + 'When using annotations you should have at least PHP 5.3.8 due to PHP bug #55156', + 'Install PHP 5.3.8 or newer if your project uses annotations.' + ); + + $this->addRecommendation( + version_compare($installedPhpVersion, '5.4.0', '!='), + 'You should not use PHP 5.4.0 due to the PHP bug #61453', + '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.' + ); + + $this->addRecommendation( + version_compare($installedPhpVersion, '5.4.11', '>='), + '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)', + 'Install PHP 5.4.11 or newer if your project uses the logout handler from the Symfony Security Component.' + ); + + $this->addRecommendation( + (version_compare($installedPhpVersion, '5.3.18', '>=') && version_compare($installedPhpVersion, '5.4.0', '<')) + || + version_compare($installedPhpVersion, '5.4.8', '>='), + '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', + 'Install PHP 5.3.18+ or PHP 5.4.8+ if you want nice error messages for all fatal errors in the development environment.' + ); + + if (null !== $pcreVersion) { + $this->addRecommendation( + $pcreVersion >= 8.0, + sprintf('PCRE extension should be at least version 8.0 (%s installed)', $pcreVersion), + '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.' + ); + } + + $this->addRecommendation( + class_exists('DomDocument'), + 'PHP-DOM and PHP-XML modules should be installed', + 'Install and enable the PHP-DOM and the PHP-XML modules.' + ); + + $this->addRecommendation( + function_exists('mb_strlen'), + 'mb_strlen() should be available', + 'Install and enable the mbstring extension.' + ); + + $this->addRecommendation( + function_exists('utf8_decode'), + 'utf8_decode() should be available', + 'Install and enable the XML extension.' + ); + + $this->addRecommendation( + function_exists('filter_var'), + 'filter_var() should be available', + 'Install and enable the filter extension.' + ); + + if (!defined('PHP_WINDOWS_VERSION_BUILD')) { + $this->addRecommendation( + function_exists('posix_isatty'), + 'posix_isatty() should be available', + 'Install and enable the php_posix extension (used to colorize the CLI output).' + ); + } + + $this->addRecommendation( + extension_loaded('intl'), + 'intl extension should be available', + 'Install and enable the intl extension (used for validators).' + ); + + if (extension_loaded('intl')) { + // in some WAMP server installations, new Collator() returns null + $this->addRecommendation( + null !== new Collator('fr_FR'), + 'intl extension should be correctly configured', + 'The intl extension does not behave properly. This problem is typical on PHP 5.3.X x64 WIN builds.' + ); + + // check for compatible ICU versions (only done when you have the intl extension) + if (defined('INTL_ICU_VERSION')) { + $version = INTL_ICU_VERSION; + } else { + $reflector = new ReflectionExtension('intl'); + + ob_start(); + $reflector->info(); + $output = strip_tags(ob_get_clean()); + + preg_match('/^ICU version +(?:=> )?(.*)$/m', $output, $matches); + $version = $matches[1]; + } + + $this->addRecommendation( + version_compare($version, '4.0', '>='), + 'intl ICU version should be at least 4+', + 'Upgrade your intl extension with a newer ICU version (4+).' + ); + + if (class_exists('Symfony\Component\Intl\Intl')) { + $this->addRecommendation( + \Symfony\Component\Intl\Intl::getIcuDataVersion() <= \Symfony\Component\Intl\Intl::getIcuVersion(), + 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()), + 'To get the latest internationalization data upgrade the ICU system package and the intl PHP extension.' + ); + if (\Symfony\Component\Intl\Intl::getIcuDataVersion() <= \Symfony\Component\Intl\Intl::getIcuVersion()) { + $this->addRecommendation( + \Symfony\Component\Intl\Intl::getIcuDataVersion() === \Symfony\Component\Intl\Intl::getIcuVersion(), + 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()), + 'To avoid internationalization data inconsistencies upgrade the symfony/intl component.' + ); + } + } + + $this->addPhpIniRecommendation( + 'intl.error_level', + create_function('$cfgValue', 'return (int) $cfgValue === 0;'), + true, + 'intl.error_level should be 0 in php.ini', + 'Set "intl.error_level" to "0" in php.ini* to inhibit the messages when an error occurs in ICU functions.' + ); + } + + $accelerator = + (extension_loaded('eaccelerator') && ini_get('eaccelerator.enable')) + || + (extension_loaded('apc') && ini_get('apc.enabled')) + || + (extension_loaded('Zend Optimizer+') && ini_get('zend_optimizerplus.enable')) + || + (extension_loaded('Zend OPcache') && ini_get('opcache.enable')) + || + (extension_loaded('xcache') && ini_get('xcache.cacher')) + || + (extension_loaded('wincache') && ini_get('wincache.ocenabled')) + ; + + $this->addRecommendation( + $accelerator, + 'a PHP accelerator should be installed', + 'Install and/or enable a PHP accelerator (highly recommended).' + ); + + if ('WIN' === strtoupper(substr(PHP_OS, 0, 3))) { + $this->addRecommendation( + $this->getRealpathCacheSize() >= 5 * 1024 * 1024, + 'realpath_cache_size should be at least 5M in php.ini', + 'Setting "realpath_cache_size" to e.g. "5242880" or "5M" in php.ini* may improve performance on Windows significantly in some cases.' + ); + } + + $this->addPhpIniRecommendation('short_open_tag', false); + + $this->addPhpIniRecommendation('magic_quotes_gpc', false, true); + + $this->addPhpIniRecommendation('register_globals', false, true); + + $this->addPhpIniRecommendation('session.auto_start', false); + + $this->addRecommendation( + class_exists('PDO'), + 'PDO should be installed', + 'Install PDO (mandatory for Doctrine).' + ); + + if (class_exists('PDO')) { + $drivers = PDO::getAvailableDrivers(); + $this->addRecommendation( + count($drivers) > 0, + sprintf('PDO should have some drivers installed (currently available: %s)', count($drivers) ? implode(', ', $drivers) : 'none'), + 'Install PDO drivers (mandatory for Doctrine).' + ); + } + } + + /** + * Loads realpath_cache_size from php.ini and converts it to int. + * + * (e.g. 16k is converted to 16384 int) + * + * @return int + */ + protected function getRealpathCacheSize() + { + $size = ini_get('realpath_cache_size'); + $size = trim($size); + $unit = ''; + if (!ctype_digit($size)) { + $unit = strtolower(substr($size, -1, 1)); + $size = (int) substr($size, 0, -1); + } + switch ($unit) { + case 'g': + return $size * 1024 * 1024 * 1024; + case 'm': + return $size * 1024 * 1024; + case 'k': + return $size * 1024; + default: + return (int) $size; + } + } + + /** + * Defines PHP required version from Symfony version. + * + * @return string|false The PHP required version or false if it could not be guessed + */ + protected function getPhpRequiredVersion() + { + if (!file_exists($path = __DIR__.'/../composer.lock')) { + return false; + } + + $composerLock = json_decode(file_get_contents($path), true); + foreach ($composerLock['packages'] as $package) { + $name = $package['name']; + if ('symfony/symfony' !== $name && 'symfony/http-kernel' !== $name) { + continue; + } + + return (int) $package['version'][1] > 2 ? self::REQUIRED_PHP_VERSION : self::LEGACY_REQUIRED_PHP_VERSION; + } + + return false; + } +} diff --git a/web/app.php b/web/app.php index 3681a3fa..57c21828 100644 --- a/web/app.php +++ b/web/app.php @@ -2,25 +2,12 @@ use Symfony\Component\HttpFoundation\Request; -/** - * @var \Symfony\Component\ClassLoader\ClassLoader - */ -$loader = require __DIR__.'/../app/autoload.php'; -include_once __DIR__.'/../app/bootstrap.php.cache'; +require __DIR__.'/../vendor/autoload.php'; $kernel = new AppKernel('prod', false); -$kernel->loadClassCache(); - -if ($_SERVER['REMOTE_ADDR'] === '144.217.203.53') { - Request::setTrustedProxies([$_SERVER['REMOTE_ADDR']]); - // force all trusted header names - Request::setTrustedHeaderName(Request::HEADER_FORWARDED, ''); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_IP, 'X_REAL_IP'); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_HOST, ''); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_PROTO, ''); - Request::setTrustedHeaderName(Request::HEADER_CLIENT_PORT, ''); -} +// When using the HttpCache, you need to call the method in your front controller instead of relying on the configuration parameter +//Request::enableHttpMethodParameterOverride(); $request = Request::createFromGlobals(); $response = $kernel->handle($request); $response->send(); diff --git a/web/app_dev.php b/web/app_dev.php index 9a4676f3..57e1a433 100644 --- a/web/app_dev.php +++ b/web/app_dev.php @@ -1,33 +1,27 @@ loadClassCache(); $request = Request::createFromGlobals(); $response = $kernel->handle($request); $response->send(); diff --git a/web/apple-touch-icon-precomposed.png b/web/apple-touch-icon-precomposed.png deleted file mode 100644 index 8132e4ae..00000000 Binary files a/web/apple-touch-icon-precomposed.png and /dev/null differ diff --git a/web/apple-touch-icon.png b/web/apple-touch-icon.png deleted file mode 100644 index 8132e4ae..00000000 Binary files a/web/apple-touch-icon.png and /dev/null differ diff --git a/web/favicon.ico b/web/favicon.ico index 4d9cd5eb..9a5742c0 100644 Binary files a/web/favicon.ico and b/web/favicon.ico differ diff --git a/web/robots.txt b/web/robots.txt index 214e4119..1f53798b 100644 --- a/web/robots.txt +++ b/web/robots.txt @@ -1,4 +1,2 @@ -# www.robotstxt.org/ -# www.google.com/support/webmasters/bin/answer.py?hl=en&answer=156449 - User-agent: * +Disallow: / diff --git a/web/search.osd b/web/search.osd deleted file mode 100644 index 8d634421..00000000 --- a/web/search.osd +++ /dev/null @@ -1,14 +0,0 @@ - - - Packagist - Packagist PHP Package Search - Use Packagist.org to search for PHP packages. - packagist composer php - contact@packagist.org - - en-us - UTF-8 - UTF-8 - https://packagist.org/apple-touch-icon.png - https://packagist.org/favicon.ico - diff --git a/web/touch-icon-192x192.png b/web/touch-icon-192x192.png deleted file mode 100644 index 58114b8f..00000000 Binary files a/web/touch-icon-192x192.png and /dev/null differ