diff --git a/.travis.yml b/.travis.yml index 26069f085f..b1cb9be100 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,11 +1,5 @@ language: php sudo: require -env: - - TEST_SUITE=1 - - TEST_SUITE=2 -php: - - 5.5 - - 5.6 branches: except: @@ -14,14 +8,33 @@ branches: matrix: fast_finish: true + allow_failures: + - php: 7.0 + env: TEST_SUITE=1 + - php: 7.0 + env: TEST_SUITE=2 + include: + - php: 5.5 + env: TEST_SUITE=1 + - php: 5.6 + env: TEST_SUITE=1 + - php: 7.0 + env: TEST_SUITE=1 + - php: 5.5 + env: TEST_SUITE=2 + - php: 5.6 + env: TEST_SUITE=2 + - php: 7.0 + env: TEST_SUITE=2 services: - mysql - memcached - redis + - rabbitmq before_install: - - nvm install 0.12.0 + - nvm install stable - phpenv config-rm xdebug.ini - composer self-update --no-progress --no-interaction - sudo apt-get purge elasticsearch @@ -30,12 +43,15 @@ before_install: - sudo service elasticsearch start - echo 'session.cache_limiter = ""' >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini - echo 'extension="redis.so"' >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini - - echo 'extension="memcache.so"' >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini + - if [[ $TRAVIS_PHP_VERSION = 5.* ]];then echo 'extension="memcache.so"' >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini; fi; - echo 'extension="memcached.so"' >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini - echo "extension=zmq.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/travis.ini - - yes | pecl install imagick + - yes | pecl install imagick-beta + - sudo apt-get install librabbitmq-dev + - pecl install amqp-1.4.0 install: - - travis_retry composer install --no-progress --no-interaction --optimize-autoloader + - if [[ $TRAVIS_PHP_VERSION = 5.* ]];then travis_retry composer install --no-progress --no-interaction --optimize-autoloader; fi; + - if [[ $TRAVIS_PHP_VERSION = 7.* ]];then travis_retry composer update --no-progress --no-interaction --optimize-autoloader; fi; - travis_retry npm install before_script: - mysql -e 'CREATE DATABASE update39_test;CREATE DATABASE ab_test;CREATE DATABASE db_test;SET @@global.sql_mode=STRICT_ALL_TABLES;SET @@global.max_allowed_packet=33554432;SET @@global.wait_timeout=999999;' @@ -51,7 +67,6 @@ before_script: - "./bin/developer phraseanet:generate-js-fixtures" script: - - "./node_modules/.bin/gulp test" - | echo "$TEST_SUITE"; case "$TEST_SUITE" in diff --git a/README.md b/README.md index c1f410d211..7062458798 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,3 @@ See https://docs.phraseanet.com/Devel/ #License : Phraseanet is licensed under GPL-v3 license. - - -[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/alchemy-fr/phraseanet/trend.png)](https://bitdeli.com/free "Bitdeli Badge") - diff --git a/bin/console b/bin/console index d32d3e625d..4e14beff24 100755 --- a/bin/console +++ b/bin/console @@ -11,15 +11,22 @@ namespace KonsoleKommander; +use Alchemy\Phrasea\CLI; +use Alchemy\Phrasea\Command\BuildMissingSubdefs; use Alchemy\Phrasea\Command\BuildSubdefs; +use Alchemy\Phrasea\Command\CheckConfig; +use Alchemy\Phrasea\Command\Compile\Configuration; +use Alchemy\Phrasea\Command\CreateCollection; +use Alchemy\Phrasea\Command\MailTest; +use Alchemy\Phrasea\Command\Plugin\AddPlugin; use Alchemy\Phrasea\Command\Plugin\ListPlugin; -use Alchemy\Phrasea\Command\Setup\H264ConfigurationDumper; -use Alchemy\Phrasea\Command\Setup\H264MappingGenerator; +use Alchemy\Phrasea\Command\Plugin\RemovePlugin; +use Alchemy\Phrasea\Command\RecordAdd; +use Alchemy\Phrasea\Command\RescanTechnicalDatas; use Alchemy\Phrasea\Command\SearchEngine\Debug\QueryParseCommand; use Alchemy\Phrasea\Command\SearchEngine\Debug\QuerySampleCommand; use Alchemy\Phrasea\Command\SearchEngine\IndexCreateCommand; use Alchemy\Phrasea\Command\SearchEngine\IndexDropCommand; -use Alchemy\Phrasea\Command\SearchEngine\MappingUpdateCommand; use Alchemy\Phrasea\Command\SearchEngine\IndexPopulateCommand; use Alchemy\Phrasea\Command\Thesaurus\FindConceptsCommand; use Alchemy\Phrasea\Command\WebsocketServer; @@ -37,17 +44,23 @@ use Alchemy\Phrasea\Command\Plugin\AddPlugin; use Alchemy\Phrasea\Command\Plugin\RemovePlugin; use Alchemy\Phrasea\Command\CheckConfig; use Alchemy\Phrasea\Command\Setup\XSendFileMappingGenerator; +use Alchemy\Phrasea\Command\SearchEngine\MappingUpdateCommand; +use Alchemy\Phrasea\Command\Setup\H264ConfigurationDumper; +use Alchemy\Phrasea\Command\Setup\H264MappingGenerator; use Alchemy\Phrasea\Command\Setup\XSendFileConfigurationDumper; -use Alchemy\Phrasea\Command\Task\SchedulerResumeTasks; -use Alchemy\Phrasea\Command\Task\SchedulerState; +use Alchemy\Phrasea\Command\Setup\XSendFileMappingGenerator; use Alchemy\Phrasea\Command\Task\SchedulerPauseTasks; +use Alchemy\Phrasea\Command\Task\SchedulerResumeTasks; use Alchemy\Phrasea\Command\Task\SchedulerRun; +use Alchemy\Phrasea\Command\Task\SchedulerState; use Alchemy\Phrasea\Command\Task\TaskList; use Alchemy\Phrasea\Command\Task\TaskRun; use Alchemy\Phrasea\Command\Task\TaskStart; -use Alchemy\Phrasea\Command\Task\TaskStop; use Alchemy\Phrasea\Command\Task\TaskState; -use Alchemy\Phrasea\SearchEngine\SearchEngineInterface; +use Alchemy\Phrasea\Command\Task\TaskStop; +use Alchemy\Phrasea\Command\Thesaurus\FindConceptsCommand; +use Alchemy\Phrasea\Command\UpgradeDBDatas; +use Alchemy\Phrasea\Core\Version; require_once __DIR__ . '/../lib/autoload.php'; @@ -68,11 +81,12 @@ $cli = new CLI(" This program comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under certain conditions; type `about:license' for details.\n\n" - . ' KONSOLE KOMMANDER', $version->getName() . ' ' . $version->getNumber()); + . ' KONSOLE KOMMANDER', $version->getName() . ' ' . $version->getNumber()); if (!$cli['phraseanet.configuration-tester']->isInstalled()) { throw new \RuntimeException('Phraseanet is not installed, use setup command instead'); } + if (!$cli['phraseanet.configuration-tester']->isUpToDate()) { throw new \RuntimeException('Phraseanet is not up-to-date, use setup command instead'); } @@ -132,6 +146,10 @@ $cli->command(new QueryParseCommand()); $cli->command(new QuerySampleCommand()); $cli->command(new FindConceptsCommand()); +$cli->command($cli['alchemy_worker.commands.run_dispatcher_command']); +$cli->command($cli['alchemy_worker.commands.run_worker_command']); +$cli->command($cli['alchemy_worker.commands.show_configuration']); + $cli->loadPlugins(); -exit(is_int($cli->run()) ? : 1); +$cli->run(); diff --git a/bin/developer b/bin/developer index fba04bd369..7a1f0888ae 100755 --- a/bin/developer +++ b/bin/developer @@ -122,4 +122,4 @@ if ($cli['configuration.store']->isSetup()) { } } -exit(is_int($cli->run()) ? : 1); +$cli->run(); diff --git a/bin/setup b/bin/setup index b0d7defead..d9ce659816 100755 --- a/bin/setup +++ b/bin/setup @@ -79,4 +79,4 @@ $app->command(new CrossDomainGenerator()); $app['phraseanet.setup_mode'] = true; -exit(is_int($app->run()) ? : 1); +$app->run(); diff --git a/bower.json b/bower.json index 172a3bc945..7af7759e69 100644 --- a/bower.json +++ b/bower.json @@ -27,7 +27,7 @@ "bootstrap-sass": "v2.3.2.2", "jquery.lazyload": "~1.9.7", "jquery-treeview": "~1.4.2", - "alchemy-embed-medias": "~0.3.2" + "html5shiv": "^3.7.3" }, "devDependencies": { "mocha": "latest", diff --git a/circle.yml b/circle.yml index 112204549b..8d48c3e9fa 100644 --- a/circle.yml +++ b/circle.yml @@ -9,11 +9,12 @@ machine: php: version: 5.5.21 node: - version: 0.12.0 + version: stable services: - memcached - redis - mysql + - rabbitmq-server dependencies: cache_directories: @@ -21,10 +22,13 @@ dependencies: - node_modules - ~/.composer pre: + - sudo apt-get install librabbitmq-dev + - pecl install amqp-1.4.0 - yes '' | pecl install imagick - pecl install json - yes '' | pecl install zmq-beta - sed -i 's/^\(session.cache_limiter = \).*/\1""/' ~/.phpenv/versions/$(phpenv global)/etc/php.ini + - npm rebuild node-sass override: - composer install --no-progress --no-interaction --optimize-autoloader post: @@ -32,7 +36,6 @@ dependencies: - if [[ ! -e elasticsearch-1.6.0 ]]; then wget --no-check-certificate https://download.elastic.co/elasticsearch/elasticsearch/elasticsearch-1.6.0.tar.gz && tar -xvf elasticsearch-1.6.0.tar.gz && elasticsearch-1.6.0/bin/plugin install elasticsearch/elasticsearch-analysis-icu/2.6.0; fi - elasticsearch-1.6.0/bin/elasticsearch: {background: true} - database: override: - mysql -u ubuntu -e 'CREATE DATABASE update39_test;CREATE DATABASE ab_test;CREATE DATABASE db_test;SET @@global.sql_mode=STRICT_ALL_TABLES;SET @@global.max_allowed_packet=33554432;SET @@global.wait_timeout=999999;'; @@ -46,5 +49,5 @@ database: test: override: - - case $CIRCLE_NODE_INDEX in 0) EXIT=0; php -d memory_limit=-1 bin/phpunit --log-junit $CIRCLE_TEST_REPORTS/phpunit/junit-unit.xml --exclude-group legacy || EXIT=$?; ./node_modules/.bin/gulp test || EXIT=$?; php -d memory_limit=-1 bin/phpunit --log-junit $CIRCLE_TEST_REPORTS/phpunit/junit-legacy-no-web.xml --group legacy --exclude-group web || EXIT=$?; exit $EXIT;; 1) php -d memory_limit=-1 bin/phpunit --log-junit $CIRCLE_TEST_REPORTS/phpunit/junit-legacy-web.xml --group web ;; esac: + - case $CIRCLE_NODE_INDEX in 0) EXIT=0; php -d memory_limit=-1 bin/phpunit --log-junit $CIRCLE_TEST_REPORTS/phpunit/junit-unit.xml --exclude-group legacy || EXIT=$?; php -d memory_limit=-1 bin/phpunit --log-junit $CIRCLE_TEST_REPORTS/phpunit/junit-legacy-no-web.xml --group legacy --exclude-group web || EXIT=$?; exit $EXIT;; 1) php -d memory_limit=-1 bin/phpunit --log-junit $CIRCLE_TEST_REPORTS/phpunit/junit-legacy-web.xml --group web ;; esac: parallel: true diff --git a/composer.json b/composer.json index fb3ffae859..6a0d9d964d 100644 --- a/composer.json +++ b/composer.json @@ -1,125 +1,123 @@ { - "name": "phraseanet/phraseanet", - "description": "Phraseanet", - "license": "GPL-3.0", - "config": { - "bin-dir": "bin/" + "name": "phraseanet/phraseanet", + "description": "Phraseanet", + "license": "GPL-3.0", + "config": { + "bin-dir": "bin/" + }, + "repositories": [ + { + "type": "vcs", + "url": "https://github.com/alchemy-fr/tcpdf-clone" }, - "repositories": [ - { - "type": "vcs", - "url": "https://github.com/alchemy-fr/tcpdf-clone" - }, - { - "type": "git", - "url": "https://github.com/romainneutron/ProcessManager.git" - }, - { - "type": "vcs", - "url": "https://github.com/alchemy-fr/imagine" - }, - { - "type": "vcs", - "url": "https://github.com/alchemy-fr/JMSTranslationBundle" - }, - { - "type": "vcs", - "url": "https://github.com/alchemy-fr/embed-bundle.git" - }, - { - "type": "git", - "url": "https://github.com/bburnichon/fractal.git" - } - ], - "require": { - "php": ">=5.5.9", - "ext-intl": "*", - "alchemy-fr/tcpdf-clone": "~6.0", - "alchemy/embed-bundle": "^0.3.2", - "alchemy/geonames-api-consumer": "~0.1.0", - "alchemy/google-plus-api-client": "~0.6.2", - "alchemy/mediavorus": "^0.4.4", - "alchemy/oauth2php": "1.0.0", - "alchemy/phlickr": "0.2.9", - "alchemy/phpexiftool": "^0.5.0", - "alchemy/rest-bundle": "^0.0.5", - "alchemy/symfony-cors": "^0.1.0", - "alchemy/task-manager": "2.0.x-dev@dev", - "alchemy/zippy": "^0.3.0", - "beberlei/assert": "^2.3", - "cocur/slugify": "^2.0", - "dailymotion/sdk": "~1.5", - "data-uri/data-uri": "~0.1.0", - "dflydev/doctrine-orm-service-provider": "~1.0", - "doctrine/cache": "1.6.x-dev", - "doctrine/dbal": "^2.4.0", - "doctrine/migrations": "^1.0.0", - "doctrine/orm": "^2.4.0", - "elasticsearch/elasticsearch": "~2.0", - "facebook/php-sdk": "~3.0", - "firebase/php-jwt": "^3.0.0", - "gedmo/doctrine-extensions": "~2.3.0", - "goodby/csv": "^1.3.0", - "guzzle/guzzle": "~3.0", - "hoa/compiler": "~2.0", - "hoa/console": "~2.0", - "hoa/dispatcher": "~0.0", - "hoa/router": "~2.0", - "igorw/get-in": "~1.0", - "imagine/imagine": "0.6.x-dev", - "ircmaxell/random-lib": "~1.0", - "jms/serializer": "~0.10", - "jms/translation-bundle": "dev-rebase-2015-10-20", - "justinrainbow/json-schema": "2.0.3 as 1.6.1", - "league/flysystem": "^1.0", - "league/flysystem-aws-s3-v2": "^1.0", - "league/fractal": "dev-bug/null-resource-serialization#891856f as 0.13.0", - "media-alchemyst/media-alchemyst": "^0.5", - "monolog/monolog": "~1.3", - "mrclay/minify": "~2.1.6", - "neutron/process-manager": "2.0.x-dev@dev", - "neutron/recaptcha": "~0.1.0", - "neutron/silex-filesystem-provider": "~1.0", - "neutron/silex-imagine-provider": "~0.1.0", - "neutron/temporary-filesystem": "~2.1", - "pagerfanta/pagerfanta": "^1.0", - "php-ffmpeg/php-ffmpeg": "~0.5.0", - "php-xpdf/php-xpdf": "~0.2.1", - "phpexiftool/exiftool": "10.07", - "ramsey/uuid": "^3.0", - "roave/security-advisories": "dev-master", - "silex/silex": "^1.3.0", - "silex/web-profiler": "~1.0", - "simple-bus/doctrine-orm-bridge": "^4.0", - "simple-bus/jms-serializer-bridge": "^1.0", - "simple-bus/message-bus": "^2.1", - "simple-bus/serialization": "^2.0", - "sorien/silex-dbal-profiler": "^1.1", - "sorien/silex-pimple-dumper": "^1.0", - "swiftmailer/swiftmailer": "~5.3.0", - "symfony/symfony": "~2.7.10|~2.8.3", - "themattharris/tmhoauth": "~0.7", - "twig/extensions": "^1.2.0", - "twig/twig": "~1.14, >=1.14.2", - "vierbergenlars/php-semver": "~2.1", - "webmozart/json": "^1.1", - "willdurand/negotiation": "^2.0.0-alpha1", - "zend/gdata": "~1.12.1" + { + "type": "git", + "url": "https://github.com/romainneutron/ProcessManager.git" }, - "require-dev": { - "phpunit/phpunit": "~4.5", - "mikey179/vfsStream": "~1.5" + { + "type": "vcs", + "url": "https://github.com/alchemy-fr/imagine" }, - "autoload": { - "psr-0": { - "Alchemy\\": "lib", - "": "lib/classes" - } + { + "type": "vcs", + "url": "https://github.com/alchemy-fr/JMSTranslationBundle" }, - "include-path": ["vendor/zend/gdata/library"], - "extra": { - "branch-alias": { - "dev-master": "4.0.x-dev" - } + { + "type": "git", + "url": "https://github.com/bburnichon/fractal.git" } + ], + "require": { + "php": ">=5.5.9", + "ext-intl": "*", + "alchemy-fr/tcpdf-clone": "~6.0", + "alchemy/embed-bundle": "^0.4.1", + "alchemy/geonames-api-consumer": "~0.1.0", + "alchemy/google-plus-api-client": "~0.6.2", + "alchemy/mediavorus": "^0.4.4", + "alchemy/oauth2php": "1.0.0", + "alchemy/phlickr": "0.2.9", + "alchemy/phpexiftool": "^0.5.0", + "alchemy/rest-bundle": "^0.0.5", + "alchemy/symfony-cors": "^0.1.0", + "alchemy/task-manager": "2.0.x-dev@dev", + "alchemy/zippy": "^0.3.0", + "beberlei/assert": "^2.3", + "cocur/slugify": "^2.0", + "dailymotion/sdk": "~1.5", + "data-uri/data-uri": "~0.1.0", + "dflydev/doctrine-orm-service-provider": "~1.0", + "doctrine/cache": "1.6.x-dev", + "doctrine/dbal": "^2.4.0", + "doctrine/migrations": "^1.0.0", + "doctrine/orm": "^2.4.0", + "elasticsearch/elasticsearch": "~2.0", + "facebook/php-sdk": "~3.0", + "firebase/php-jwt": "^3.0.0", + "gedmo/doctrine-extensions": "~2.3.0", + "goodby/csv": "^1.3.0", + "guzzle/guzzle": "~3.0", + "hoa/compiler": "~2.0", + "hoa/console": "~2.0", + "hoa/dispatcher": "~0.0", + "hoa/router": "~2.0", + "igorw/get-in": "~1.0", + "imagine/imagine": "0.6.x-dev", + "ircmaxell/random-lib": "~1.0", + "jms/serializer": "~0.10", + "jms/translation-bundle": "dev-rebase-2015-10-20", + "justinrainbow/json-schema": "2.0.3 as 1.6.1", + "league/flysystem": "^1.0", + "league/flysystem-aws-s3-v2": "^1.0", + "league/fractal": "dev-bug/null-resource-serialization#891856f as 0.13.0", + "media-alchemyst/media-alchemyst": "^0.5", + "monolog/monolog": "~1.3", + "mrclay/minify": "~2.1.6", + "neutron/process-manager": "2.0.x-dev@dev", + "neutron/recaptcha": "~0.1.0", + "neutron/silex-filesystem-provider": "~1.0", + "neutron/silex-imagine-provider": "~0.1.0", + "neutron/temporary-filesystem": "~2.1", + "pagerfanta/pagerfanta": "^1.0", + "php-ffmpeg/php-ffmpeg": "~0.5.0", + "php-xpdf/php-xpdf": "~0.2.1", + "phpexiftool/exiftool": "10.07", + "ramsey/uuid": "^3.0", + "roave/security-advisories": "dev-master", + "silex/silex": "^1.3.0", + "silex/web-profiler": "~1.0", + "simple-bus/doctrine-orm-bridge": "^4.0", + "simple-bus/jms-serializer-bridge": "^1.0", + "simple-bus/message-bus": "^2.1", + "simple-bus/serialization": "^2.0", + "sorien/silex-dbal-profiler": "^1.1", + "sorien/silex-pimple-dumper": "^1.0", + "swiftmailer/swiftmailer": "~5.3.0", + "symfony/symfony": "~2.7.10|~2.8.3", + "themattharris/tmhoauth": "~0.7", + "twig/extensions": "^1.2.0", + "twig/twig": "~1.14, >=1.14.2", + "vierbergenlars/php-semver": "~2.1", + "webmozart/json": "^1.1", + "willdurand/negotiation": "^2.0.0-alpha1", + "zend/gdata": "~1.12.1", + "alchemy/worker-bundle": "^0.1.5", + "alchemy/queue-bundle": "^0.1.5" + }, + "require-dev": { + "mikey179/vfsStream": "~1.5", + "phpunit/phpunit": "^4.8|^5.0" + }, + "autoload": { + "psr-0": { + "Alchemy\\": "lib", + "": "lib/classes" + } + }, + "include-path": ["vendor/zend/gdata/library"], + "extra": { + "branch-alias": { + "dev-master": "4.1.x-dev" + } + } } diff --git a/composer.lock b/composer.lock index 316a3973d4..c732b8be5c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,8 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "hash": "1b102f9b60789a197a29c15c52767326", - "content-hash": "b6baa316987eb18f33c731ed8bf9fcff", + "hash": "788aff3c7b034924087312e62bfc3404", + "content-hash": "1f181a08f1f3b13817268ea12994be3a", "packages": [ { "name": "alchemy-fr/tcpdf-clone", @@ -132,16 +132,16 @@ }, { "name": "alchemy/embed-bundle", - "version": "v0.3.3", + "version": "v0.4.4", "source": { "type": "git", "url": "https://github.com/alchemy-fr/embed-bundle.git", - "reference": "2eedc22e0030f6b4a166de2b93ffb108193c43dd" + "reference": "2eea6602825f41ac7e24f293305b73145823d5b1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/alchemy-fr/embed-bundle/zipball/2eedc22e0030f6b4a166de2b93ffb108193c43dd", - "reference": "2eedc22e0030f6b4a166de2b93ffb108193c43dd", + "url": "https://api.github.com/repos/alchemy-fr/embed-bundle/zipball/2eea6602825f41ac7e24f293305b73145823d5b1", + "reference": "2eea6602825f41ac7e24f293305b73145823d5b1", "shasum": "" }, "require-dev": { @@ -163,11 +163,7 @@ "Alchemy\\EmbedProvider\\": "src/Provider" } }, - "autoload-dev": { - "psr-4": { - "Alchemy\\EmbedBundle\\Tests\\": "tests/unit/Bundle" - } - }, + "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], @@ -178,11 +174,7 @@ } ], "description": "Embed resources bundle", - "support": { - "source": "https://github.com/alchemy-fr/embed-bundle/tree/v0.3.3", - "issues": "https://github.com/alchemy-fr/embed-bundle/issues" - }, - "time": "2016-06-14 13:51:50" + "time": "2016-07-07 10:02:43" }, { "name": "alchemy/geonames-api-consumer", @@ -276,16 +268,16 @@ }, { "name": "alchemy/google-plus-api-client", - "version": "0.6.5", + "version": "0.6.6", "source": { "type": "git", "url": "https://github.com/alchemy-fr/google-plus-api-client.git", - "reference": "54dd23b7b5a3e78db9182acbe46c773fd5020a40" + "reference": "d375b00e963984744b8a91bde2c8b87b3ee7d6f1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/alchemy-fr/google-plus-api-client/zipball/54dd23b7b5a3e78db9182acbe46c773fd5020a40", - "reference": "54dd23b7b5a3e78db9182acbe46c773fd5020a40", + "url": "https://api.github.com/repos/alchemy-fr/google-plus-api-client/zipball/d375b00e963984744b8a91bde2c8b87b3ee7d6f1", + "reference": "d375b00e963984744b8a91bde2c8b87b3ee7d6f1", "shasum": "" }, "require": { @@ -310,34 +302,36 @@ ], "description": "PHP Client for Google APIs", "homepage": "https://code.google.com/p/google-api-php-client/", - "time": "2013-08-06 09:10:01" + "time": "2016-07-06 13:47:16" }, { "name": "alchemy/mediavorus", - "version": "0.4.4", + "version": "0.4.5", "source": { "type": "git", "url": "https://github.com/alchemy-fr/MediaVorus.git", - "reference": "2df98b5b180c50b1bc7be838e36bc6ecc573e646" + "reference": "ee7d1279a024130fc82fde9eabad86a667ed3630" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/alchemy-fr/MediaVorus/zipball/2df98b5b180c50b1bc7be838e36bc6ecc573e646", - "reference": "2df98b5b180c50b1bc7be838e36bc6ecc573e646", + "url": "https://api.github.com/repos/alchemy-fr/MediaVorus/zipball/ee7d1279a024130fc82fde9eabad86a667ed3630", + "reference": "ee7d1279a024130fc82fde9eabad86a667ed3630", "shasum": "" }, "require": { + "alchemy/phpexiftool": "~0.1", "doctrine/collections": "~1.0", "monolog/monolog": "~1.0", "php": ">=5.3.0", "php-ffmpeg/php-ffmpeg": "~0.3", - "phpexiftool/phpexiftool": "~0.1", "symfony/console": "~2.0", "symfony/http-foundation": "~2.0" }, + "replace": { + "mediavorus/mediavorus": "<=0.4.4" + }, "require-dev": { "jms/serializer": "~0.12.0", - "phpunit/phpunit": "~3.7", "silex/silex": "~1.0", "symfony/yaml": "~2.0" }, @@ -346,6 +340,11 @@ "symfony/yaml": "To serialize Medias in Yaml format" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.4.x-dev" + } + }, "autoload": { "psr-0": { "MediaVorus": "src" @@ -366,7 +365,7 @@ "keywords": [ "metadata" ], - "time": "2014-08-26 12:32:10" + "time": "2016-05-02 15:08:36" }, { "name": "alchemy/oauth2php", @@ -487,6 +486,99 @@ ], "time": "2015-11-30 14:00:23" }, + { + "name": "alchemy/queue-bundle", + "version": "0.1.5", + "source": { + "type": "git", + "url": "https://github.com/alchemy-fr/queue-bundle.git", + "reference": "dcc64ac5e888250cf29a80570df66cdb5dc3857f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/alchemy-fr/queue-bundle/zipball/dcc64ac5e888250cf29a80570df66cdb5dc3857f", + "reference": "dcc64ac5e888250cf29a80570df66cdb5dc3857f", + "shasum": "" + }, + "require": { + "alchemy/queue-component": "^0.1.4", + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4|^5", + "silex/silex": "^1.3.0", + "symfony/symfony": "^2.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Alchemy\\QueueBundle\\": "src/QueueBundle", + "Alchemy\\QueueProvider\\": "src/QueueProvider" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Thibaud Fabre", + "email": "thibaud@aztech.io" + } + ], + "description": "Symfony bundle for alchemy/queue-component", + "time": "2016-10-04 14:19:39" + }, + { + "name": "alchemy/queue-component", + "version": "0.1.5", + "source": { + "type": "git", + "url": "https://github.com/alchemy-fr/queue-component.git", + "reference": "5506445a5770e23075e78e02510752106ee284b0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/alchemy-fr/queue-component/zipball/5506445a5770e23075e78e02510752106ee284b0", + "reference": "5506445a5770e23075e78e02510752106ee284b0", + "shasum": "" + }, + "require": { + "php": ">=5.5", + "psr/log": "^1.0", + "ramsey/uuid": "^3.3" + }, + "require-dev": { + "empi89/php-amqp-stubs": "dev-master", + "mikey179/vfsstream": "^1.6", + "phpunit/phpunit": "^4.0|^5.0" + }, + "suggest": { + "ext-amqp": "To use the AMQP extension adapters" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Alchemy\\Queue\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Message queue component", + "time": "2016-10-05 10:41:36" + }, { "name": "alchemy/rest-bundle", "version": "0.0.5", @@ -592,12 +684,12 @@ "source": { "type": "git", "url": "https://github.com/alchemy-fr/task-manager.git", - "reference": "2b199e842551a1137640c822f433751a9f402099" + "reference": "6185ab425922580c3f7a6f0ae1b364e6a4626aae" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/alchemy-fr/task-manager/zipball/2b199e842551a1137640c822f433751a9f402099", - "reference": "2b199e842551a1137640c822f433751a9f402099", + "url": "https://api.github.com/repos/alchemy-fr/task-manager/zipball/6185ab425922580c3f7a6f0ae1b364e6a4626aae", + "reference": "6185ab425922580c3f7a6f0ae1b364e6a4626aae", "shasum": "" }, "require": { @@ -647,7 +739,102 @@ "parallel", "process" ], - "time": "2016-03-11 12:13:53" + "time": "2016-11-30 13:34:30" + }, + { + "name": "alchemy/worker-bundle", + "version": "0.1.5", + "source": { + "type": "git", + "url": "https://github.com/alchemy-fr/worker-bundle.git", + "reference": "ae83862104fcb0873370b237c93fdd744e33d800" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/alchemy-fr/worker-bundle/zipball/ae83862104fcb0873370b237c93fdd744e33d800", + "reference": "ae83862104fcb0873370b237c93fdd744e33d800", + "shasum": "" + }, + "require": { + "alchemy/queue-bundle": "^0.1.5", + "alchemy/worker-component": "^0.1.0", + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "^5.4", + "silex/silex": "^1.3.0", + "symfony/symfony": "^2.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Alchemy\\WorkerBundle\\": "src/WorkerBundle", + "Alchemy\\WorkerProvider\\": "src/WorkerProvider" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Thibaud Fabre", + "email": "thibaud@aztech.io" + } + ], + "description": "Symfony bundle for alchemy/worker-component", + "time": "2016-11-14 16:42:58" + }, + { + "name": "alchemy/worker-component", + "version": "0.1.4", + "source": { + "type": "git", + "url": "https://github.com/alchemy-fr/worker-component.git", + "reference": "239927775b9097e6f1a540a975d2ea49bda550f4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/alchemy-fr/worker-component/zipball/239927775b9097e6f1a540a975d2ea49bda550f4", + "reference": "239927775b9097e6f1a540a975d2ea49bda550f4", + "shasum": "" + }, + "require": { + "alchemy/queue-component": "^0.1.4", + "php": ">=5.5", + "psr/log": "^1.0", + "ramsey/uuid": "^3.3" + }, + "require-dev": { + "empi89/php-amqp-stubs": "dev-master", + "mikey179/vfsstream": "^1.6", + "phpunit/phpunit": "^4.0|^5.0" + }, + "suggest": { + "ext-amqp": "To use the AMQP extension adapters" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "0.2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Alchemy\\Worker\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Message queue worker component", + "time": "2016-11-14 16:41:16" }, { "name": "alchemy/zippy", @@ -713,16 +900,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "2.8.30", + "version": "2.8.31", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "2d7183cd22381237bce25f11d741a77bdeb2d0b8" + "reference": "64fa4b07f056e338a5f0f29eece75babaa83af68" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/2d7183cd22381237bce25f11d741a77bdeb2d0b8", - "reference": "2d7183cd22381237bce25f11d741a77bdeb2d0b8", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/64fa4b07f056e338a5f0f29eece75babaa83af68", + "reference": "64fa4b07f056e338a5f0f29eece75babaa83af68", "shasum": "" }, "require": { @@ -772,20 +959,20 @@ "s3", "sdk" ], - "time": "2016-05-03 17:42:24" + "time": "2016-07-25 18:03:20" }, { "name": "beberlei/assert", - "version": "v2.5", + "version": "v2.6.7", "source": { "type": "git", "url": "https://github.com/beberlei/assert.git", - "reference": "91e2690c4ecc8a4e3e2d333430069f6a0c694a7a" + "reference": "2b4c9249a7ceef51402d39bd797aae16cfd8f36f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/beberlei/assert/zipball/91e2690c4ecc8a4e3e2d333430069f6a0c694a7a", - "reference": "91e2690c4ecc8a4e3e2d333430069f6a0c694a7a", + "url": "https://api.github.com/repos/beberlei/assert/zipball/2b4c9249a7ceef51402d39bd797aae16cfd8f36f", + "reference": "2b4c9249a7ceef51402d39bd797aae16cfd8f36f", "shasum": "" }, "require": { @@ -793,14 +980,10 @@ "php": ">=5.3" }, "require-dev": { + "friendsofphp/php-cs-fixer": "2.0.0-alpha", "phpunit/phpunit": "@stable" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.3-dev" - } - }, "autoload": { "psr-0": { "Assert": "lib/" @@ -816,7 +999,13 @@ "authors": [ { "name": "Benjamin Eberlei", - "email": "kontakt@beberlei.de" + "email": "kontakt@beberlei.de", + "role": "Lead Developer" + }, + { + "name": "Richard Quadling", + "email": "rquadling@gmail.com", + "role": "Collaborator" } ], "description": "Thin assertion library for input validation in business models.", @@ -825,7 +1014,7 @@ "assertion", "validation" ], - "time": "2016-03-22 14:34:51" + "time": "2016-11-14 16:46:13" }, { "name": "behat/transliterator", @@ -869,16 +1058,16 @@ }, { "name": "cocur/slugify", - "version": "v2.1.1", + "version": "v2.3", "source": { "type": "git", "url": "https://github.com/cocur/slugify.git", - "reference": "eee9879958875921082293dbdbf4866b641864f2" + "reference": "57a00e06a382928e350cc7bbb13b19f1b8f4e73a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/cocur/slugify/zipball/eee9879958875921082293dbdbf4866b641864f2", - "reference": "eee9879958875921082293dbdbf4866b641864f2", + "url": "https://api.github.com/repos/cocur/slugify/zipball/57a00e06a382928e350cc7bbb13b19f1b8f4e73a", + "reference": "57a00e06a382928e350cc7bbb13b19f1b8f4e73a", "shasum": "" }, "require": { @@ -887,6 +1076,7 @@ "require-dev": { "laravel/framework": "~5.1", "latte/latte": "~2.2", + "league/container": "^2.2.0", "mikey179/vfsstream": "~1.6", "mockery/mockery": "~0.9", "nette/di": "~2.2", @@ -928,7 +1118,7 @@ "slug", "slugify" ], - "time": "2016-04-08 18:57:21" + "time": "2016-08-09 20:10:17" }, { "name": "dailymotion/sdk", @@ -1072,35 +1262,35 @@ }, { "name": "doctrine/annotations", - "version": "v1.2.7", + "version": "v1.3.0", "source": { "type": "git", "url": "https://github.com/doctrine/annotations.git", - "reference": "f25c8aab83e0c3e976fd7d19875f198ccf2f7535" + "reference": "30e07cf03edc3cd3ef579d0dd4dd8c58250799a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/annotations/zipball/f25c8aab83e0c3e976fd7d19875f198ccf2f7535", - "reference": "f25c8aab83e0c3e976fd7d19875f198ccf2f7535", + "url": "https://api.github.com/repos/doctrine/annotations/zipball/30e07cf03edc3cd3ef579d0dd4dd8c58250799a5", + "reference": "30e07cf03edc3cd3ef579d0dd4dd8c58250799a5", "shasum": "" }, "require": { "doctrine/lexer": "1.*", - "php": ">=5.3.2" + "php": "^5.6 || ^7.0" }, "require-dev": { "doctrine/cache": "1.*", - "phpunit/phpunit": "4.*" + "phpunit/phpunit": "^5.6.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.3.x-dev" + "dev-master": "1.4.x-dev" } }, "autoload": { - "psr-0": { - "Doctrine\\Common\\Annotations\\": "lib/" + "psr-4": { + "Doctrine\\Common\\Annotations\\": "lib/Doctrine/Common/Annotations" } }, "notification-url": "https://packagist.org/downloads/", @@ -1136,7 +1326,7 @@ "docblock", "parser" ], - "time": "2015-08-31 12:32:49" + "time": "2016-10-24 11:45:47" }, { "name": "doctrine/cache", @@ -1144,12 +1334,12 @@ "source": { "type": "git", "url": "https://github.com/doctrine/cache.git", - "reference": "fe3020b50c70ced4562edc04cdf8d0857008502b" + "reference": "b6f544a20f4807e81f7044d31e679ccbb1866dc3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/cache/zipball/fe3020b50c70ced4562edc04cdf8d0857008502b", - "reference": "fe3020b50c70ced4562edc04cdf8d0857008502b", + "url": "https://api.github.com/repos/doctrine/cache/zipball/b6f544a20f4807e81f7044d31e679ccbb1866dc3", + "reference": "b6f544a20f4807e81f7044d31e679ccbb1866dc3", "shasum": "" }, "require": { @@ -1206,7 +1396,7 @@ "cache", "caching" ], - "time": "2016-03-11 16:30:42" + "time": "2016-10-29 11:16:17" }, { "name": "doctrine/collections", @@ -1276,16 +1466,16 @@ }, { "name": "doctrine/common", - "version": "v2.6.1", + "version": "v2.6.2", "source": { "type": "git", "url": "https://github.com/doctrine/common.git", - "reference": "a579557bc689580c19fee4e27487a67fe60defc0" + "reference": "7bce00698899aa2c06fe7365c76e4d78ddb15fa3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/common/zipball/a579557bc689580c19fee4e27487a67fe60defc0", - "reference": "a579557bc689580c19fee4e27487a67fe60defc0", + "url": "https://api.github.com/repos/doctrine/common/zipball/7bce00698899aa2c06fe7365c76e4d78ddb15fa3", + "reference": "7bce00698899aa2c06fe7365c76e4d78ddb15fa3", "shasum": "" }, "require": { @@ -1345,20 +1535,20 @@ "persistence", "spl" ], - "time": "2015-12-25 13:18:31" + "time": "2016-11-30 16:50:46" }, { "name": "doctrine/dbal", - "version": "v2.5.4", + "version": "v2.5.5", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "abbdfd1cff43a7b99d027af3be709bc8fc7d4769" + "reference": "9f8c05cd5225a320d56d4bfdb4772f10d045a0c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/abbdfd1cff43a7b99d027af3be709bc8fc7d4769", - "reference": "abbdfd1cff43a7b99d027af3be709bc8fc7d4769", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/9f8c05cd5225a320d56d4bfdb4772f10d045a0c9", + "reference": "9f8c05cd5225a320d56d4bfdb4772f10d045a0c9", "shasum": "" }, "require": { @@ -1367,7 +1557,7 @@ }, "require-dev": { "phpunit/phpunit": "4.*", - "symfony/console": "2.*" + "symfony/console": "2.*||^3.0" }, "suggest": { "symfony/console": "For helpful console commands such as SQL execution and import of files." @@ -1416,7 +1606,7 @@ "persistence", "queryobject" ], - "time": "2016-01-05 22:11:12" + "time": "2016-09-09 19:13:33" }, { "name": "doctrine/inflector", @@ -1668,16 +1858,16 @@ }, { "name": "doctrine/orm", - "version": "v2.5.4", + "version": "v2.5.5", "source": { "type": "git", "url": "https://github.com/doctrine/doctrine2.git", - "reference": "bc4ddbfb0114cb33438cc811c9a740d8aa304aab" + "reference": "73e4be7c7b3ba26f96b781a40b33feba4dfa6d45" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/doctrine2/zipball/bc4ddbfb0114cb33438cc811c9a740d8aa304aab", - "reference": "bc4ddbfb0114cb33438cc811c9a740d8aa304aab", + "url": "https://api.github.com/repos/doctrine/doctrine2/zipball/73e4be7c7b3ba26f96b781a40b33feba4dfa6d45", + "reference": "73e4be7c7b3ba26f96b781a40b33feba4dfa6d45", "shasum": "" }, "require": { @@ -1740,20 +1930,20 @@ "database", "orm" ], - "time": "2016-01-05 21:34:58" + "time": "2016-09-10 18:51:13" }, { "name": "elasticsearch/elasticsearch", - "version": "v2.2.0", + "version": "v2.3.0", "source": { "type": "git", "url": "https://github.com/elastic/elasticsearch-php.git", - "reference": "11ebdf2c847d0e2c4a47ac993485beb5a19d5dc4" + "reference": "12a400656e4cf4c231d83cb56af3f50a27dcde93" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/elastic/elasticsearch-php/zipball/11ebdf2c847d0e2c4a47ac993485beb5a19d5dc4", - "reference": "11ebdf2c847d0e2c4a47ac993485beb5a19d5dc4", + "url": "https://api.github.com/repos/elastic/elasticsearch-php/zipball/12a400656e4cf4c231d83cb56af3f50a27dcde93", + "reference": "12a400656e4cf4c231d83cb56af3f50a27dcde93", "shasum": "" }, "require": { @@ -1794,7 +1984,7 @@ "elasticsearch", "search" ], - "time": "2016-06-03 21:09:29" + "time": "2016-11-30 17:15:05" }, { "name": "evenement/evenement", @@ -2154,6 +2344,7 @@ "rest", "web service" ], + "abandoned": "guzzlehttp/guzzle", "time": "2015-03-18 18:23:50" }, { @@ -3137,30 +3328,31 @@ }, { "name": "ircmaxell/random-lib", - "version": "v1.1.0", + "version": "v1.2.0", "source": { "type": "git", "url": "https://github.com/ircmaxell/RandomLib.git", - "reference": "13efa4368bb2ac88bb3b1459b487d907de4dbf7c" + "reference": "e9e0204f40e49fa4419946c677eccd3fa25b8cf4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ircmaxell/RandomLib/zipball/13efa4368bb2ac88bb3b1459b487d907de4dbf7c", - "reference": "13efa4368bb2ac88bb3b1459b487d907de4dbf7c", + "url": "https://api.github.com/repos/ircmaxell/RandomLib/zipball/e9e0204f40e49fa4419946c677eccd3fa25b8cf4", + "reference": "e9e0204f40e49fa4419946c677eccd3fa25b8cf4", "shasum": "" }, "require": { - "ircmaxell/security-lib": "1.0.*@dev", + "ircmaxell/security-lib": "^1.1", "php": ">=5.3.2" }, "require-dev": { - "mikey179/vfsstream": "1.1.*", - "phpunit/phpunit": "3.7.*" + "friendsofphp/php-cs-fixer": "^1.11", + "mikey179/vfsstream": "^1.6", + "phpunit/phpunit": "^4.8|^5.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.1.x-dev" } }, "autoload": { @@ -3187,20 +3379,20 @@ "random-numbers", "random-strings" ], - "time": "2015-01-15 16:31:45" + "time": "2016-09-07 15:52:06" }, { "name": "ircmaxell/security-lib", - "version": "1.0.0", + "version": "v1.1.0", "source": { "type": "git", "url": "https://github.com/ircmaxell/SecurityLib.git", - "reference": "80934de3c482dcafb46b5756e59ebece082b6dc7" + "reference": "f3db6de12c20c9bcd1aa3db4353a1bbe0e44e1b5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ircmaxell/SecurityLib/zipball/80934de3c482dcafb46b5756e59ebece082b6dc7", - "reference": "80934de3c482dcafb46b5756e59ebece082b6dc7", + "url": "https://api.github.com/repos/ircmaxell/SecurityLib/zipball/f3db6de12c20c9bcd1aa3db4353a1bbe0e44e1b5", + "reference": "f3db6de12c20c9bcd1aa3db4353a1bbe0e44e1b5", "shasum": "" }, "require": { @@ -3210,6 +3402,11 @@ "mikey179/vfsstream": "1.1.*" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, "autoload": { "psr-0": { "SecurityLib": "lib" @@ -3227,28 +3424,29 @@ } ], "description": "A Base Security Library", - "homepage": "https://github.com/ircmaxell/PHP-SecurityLib", - "time": "2013-04-30 18:00:34" + "homepage": "https://github.com/ircmaxell/SecurityLib", + "time": "2015-03-20 14:31:23" }, { "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": { @@ -3263,14 +3461,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", @@ -3280,7 +3476,7 @@ "xml", "yaml" ], - "time": "2014-07-12 07:13:19" + "time": "2016-12-05 10:18:33" }, { "name": "jms/parser-lib", @@ -3531,20 +3727,20 @@ }, { "name": "league/flysystem", - "version": "1.0.24", + "version": "1.0.32", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "9aca859a303fdca30370f42b8c611d9cf0dedf4b" + "reference": "1b5c4a0031697f46e779a9d1b309c2e1b24daeab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/9aca859a303fdca30370f42b8c611d9cf0dedf4b", - "reference": "9aca859a303fdca30370f42b8c611d9cf0dedf4b", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/1b5c4a0031697f46e779a9d1b309c2e1b24daeab", + "reference": "1b5c4a0031697f46e779a9d1b309c2e1b24daeab", "shasum": "" }, "require": { - "php": ">=5.4.0" + "php": ">=5.5.9" }, "conflict": { "league/flysystem-sftp": "<1.0.6" @@ -3553,7 +3749,7 @@ "ext-fileinfo": "*", "mockery/mockery": "~0.9", "phpspec/phpspec": "^2.2", - "phpunit/phpunit": "~4.8 || ~5.0" + "phpunit/phpunit": "~4.8" }, "suggest": { "ext-fileinfo": "Required for MimeType", @@ -3610,7 +3806,7 @@ "sftp", "storage" ], - "time": "2016-06-03 19:11:39" + "time": "2016-10-19 20:38:46" }, { "name": "league/flysystem-aws-s3-v2", @@ -3796,16 +3992,16 @@ }, { "name": "monolog/monolog", - "version": "1.19.0", + "version": "1.22.0", "source": { "type": "git", "url": "https://github.com/Seldaek/monolog.git", - "reference": "5f56ed5212dc509c8dc8caeba2715732abb32dbf" + "reference": "bad29cb8d18ab0315e6c477751418a82c850d558" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/monolog/zipball/5f56ed5212dc509c8dc8caeba2715732abb32dbf", - "reference": "5f56ed5212dc509c8dc8caeba2715732abb32dbf", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/bad29cb8d18ab0315e6c477751418a82c850d558", + "reference": "bad29cb8d18ab0315e6c477751418a82c850d558", "shasum": "" }, "require": { @@ -3816,7 +4012,7 @@ "psr/log-implementation": "1.0.0" }, "require-dev": { - "aws/aws-sdk-php": "^2.4.9", + "aws/aws-sdk-php": "^2.4.9 || ^3.0", "doctrine/couchdb": "~1.0@dev", "graylog2/gelf-php": "~1.0", "jakub-onderka/php-parallel-lint": "0.9", @@ -3824,8 +4020,8 @@ "php-console/php-console": "^3.1.3", "phpunit/phpunit": "~4.5", "phpunit/phpunit-mock-objects": "2.3.0", - "raven/raven": "^0.13", "ruflin/elastica": ">=0.90 <3.0", + "sentry/sentry": "^0.13", "swiftmailer/swiftmailer": "~5.3" }, "suggest": { @@ -3837,9 +4033,9 @@ "mongodb/mongodb": "Allow sending log messages to a MongoDB server via PHP Driver", "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", "php-console/php-console": "Allow sending log messages to Google Chrome", - "raven/raven": "Allow sending log messages to a Sentry server", "rollbar/rollbar": "Allow sending log messages to Rollbar", - "ruflin/elastica": "Allow sending log messages to an Elastic Search server" + "ruflin/elastica": "Allow sending log messages to an Elastic Search server", + "sentry/sentry": "Allow sending log messages to a Sentry server" }, "type": "library", "extra": { @@ -3870,7 +4066,7 @@ "logging", "psr-3" ], - "time": "2016-04-12 18:29:35" + "time": "2016-11-26 00:15:39" }, { "name": "mrclay/minify", @@ -4279,16 +4475,16 @@ }, { "name": "pagerfanta/pagerfanta", - "version": "v1.0.3", + "version": "v1.0.4", "source": { "type": "git", "url": "https://github.com/whiteoctober/Pagerfanta.git", - "reference": "a874d3612d954dcbbb49e5ffe178890918fb76fb" + "reference": "f846c5e06bb66df659a688ea4734aab49de589d6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/whiteoctober/Pagerfanta/zipball/a874d3612d954dcbbb49e5ffe178890918fb76fb", - "reference": "a874d3612d954dcbbb49e5ffe178890918fb76fb", + "url": "https://api.github.com/repos/whiteoctober/Pagerfanta/zipball/f846c5e06bb66df659a688ea4734aab49de589d6", + "reference": "f846c5e06bb66df659a688ea4734aab49de589d6", "shasum": "" }, "require": { @@ -4301,7 +4497,7 @@ "jmikola/geojson": "~1.0", "mandango/mandango": "~1.0@dev", "mandango/mondator": "~1.0@dev", - "phpunit/phpunit": "~4", + "phpunit/phpunit": "~4 | ~5", "propel/propel1": "~1.6", "ruflin/elastica": "~1.3", "solarium/solarium": "~3.1" @@ -4342,20 +4538,20 @@ "paginator", "paging" ], - "time": "2014-10-06 10:57:25" + "time": "2016-11-28 09:17:04" }, { "name": "paragonie/random_compat", - "version": "v2.0.2", + "version": "v2.0.4", "source": { "type": "git", "url": "https://github.com/paragonie/random_compat.git", - "reference": "088c04e2f261c33bed6ca5245491cfca69195ccf" + "reference": "a9b97968bcde1c4de2a5ec6cbd06a0f6c919b46e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paragonie/random_compat/zipball/088c04e2f261c33bed6ca5245491cfca69195ccf", - "reference": "088c04e2f261c33bed6ca5245491cfca69195ccf", + "url": "https://api.github.com/repos/paragonie/random_compat/zipball/a9b97968bcde1c4de2a5ec6cbd06a0f6c919b46e", + "reference": "a9b97968bcde1c4de2a5ec6cbd06a0f6c919b46e", "shasum": "" }, "require": { @@ -4390,7 +4586,7 @@ "pseudorandom", "random" ], - "time": "2016-04-03 06:00:07" + "time": "2016-11-07 23:38:38" }, { "name": "php-ffmpeg/php-ffmpeg", @@ -4564,16 +4760,16 @@ }, { "name": "php-xpdf/php-xpdf", - "version": "0.2.2", + "version": "0.2.3", "source": { "type": "git", "url": "https://github.com/alchemy-fr/PHP-XPDF.git", - "reference": "61633a5cba2bf3bfc800a9c10f8e525bda35dde1" + "reference": "d5e73960108704e0063b81ae777d01b8fb91ae08" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/alchemy-fr/PHP-XPDF/zipball/61633a5cba2bf3bfc800a9c10f8e525bda35dde1", - "reference": "61633a5cba2bf3bfc800a9c10f8e525bda35dde1", + "url": "https://api.github.com/repos/alchemy-fr/PHP-XPDF/zipball/d5e73960108704e0063b81ae777d01b8fb91ae08", + "reference": "d5e73960108704e0063b81ae777d01b8fb91ae08", "shasum": "" }, "require": { @@ -4612,20 +4808,20 @@ "pdf", "xpdf" ], - "time": "2015-12-10 16:22:47" + "time": "2016-07-04 07:30:16" }, { "name": "phpcollection/phpcollection", - "version": "0.4.0", + "version": "0.5.0", "source": { "type": "git", "url": "https://github.com/schmittjoh/php-collection.git", - "reference": "b8bf55a0a929ca43b01232b36719f176f86c7e83" + "reference": "f2bcff45c0da7c27991bbc1f90f47c4b7fb434a6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-collection/zipball/b8bf55a0a929ca43b01232b36719f176f86c7e83", - "reference": "b8bf55a0a929ca43b01232b36719f176f86c7e83", + "url": "https://api.github.com/repos/schmittjoh/php-collection/zipball/f2bcff45c0da7c27991bbc1f90f47c4b7fb434a6", + "reference": "f2bcff45c0da7c27991bbc1f90f47c4b7fb434a6", "shasum": "" }, "require": { @@ -4634,7 +4830,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "0.3-dev" + "dev-master": "0.4-dev" } }, "autoload": { @@ -4648,10 +4844,8 @@ ], "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": "General-Purpose Collection Library for PHP", @@ -4662,7 +4856,7 @@ "sequence", "set" ], - "time": "2014-03-11 13:46:42" + "time": "2015-05-17 12:39:23" }, { "name": "phpexiftool/exiftool", @@ -4795,22 +4989,30 @@ }, { "name": "psr/log", - "version": "1.0.0", + "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/php-fig/log.git", - "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b" + "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b", - "reference": "fe0936ee26643249e916849d48e3a51d5f5e278b", + "url": "https://api.github.com/repos/php-fig/log/zipball/4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", + "reference": "4ebe3a8bf773a19edfe0a84b6585ba3d401b724d", "shasum": "" }, + "require": { + "php": ">=5.3.0" + }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, "autoload": { - "psr-0": { - "Psr\\Log\\": "" + "psr-4": { + "Psr\\Log\\": "Psr/Log/" } }, "notification-url": "https://packagist.org/downloads/", @@ -4824,25 +5026,26 @@ } ], "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", "keywords": [ "log", "psr", "psr-3" ], - "time": "2012-12-21 11:40:51" + "time": "2016-10-10 12:19:37" }, { "name": "ramsey/uuid", - "version": "3.4.1", + "version": "3.5.2", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "b4fe3b7387cb323fd15ad5837cae992422c9fa5c" + "reference": "5677cfe02397dd6b58c861870dfaa5d9007d3954" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/b4fe3b7387cb323fd15ad5837cae992422c9fa5c", - "reference": "b4fe3b7387cb323fd15ad5837cae992422c9fa5c", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/5677cfe02397dd6b58c861870dfaa5d9007d3954", + "reference": "5677cfe02397dd6b58c861870dfaa5d9007d3954", "shasum": "" }, "require": { @@ -4855,12 +5058,14 @@ "require-dev": { "apigen/apigen": "^4.1", "codeception/aspect-mock": "1.0.0", + "doctrine/annotations": "~1.2.0", "goaop/framework": "1.0.0-alpha.2", "ircmaxell/random-lib": "^1.1", "jakub-onderka/php-parallel-lint": "^0.9.0", "mockery/mockery": "^0.9.4", "moontoast/math": "^1.1", - "phpunit/phpunit": "^4.7|^5.0", + "php-mock/php-mock-phpunit": "^0.3|^1.1", + "phpunit/phpunit": "^4.7|>=5.0 <5.4", "satooshi/php-coveralls": "^0.6.1", "squizlabs/php_codesniffer": "^2.3" }, @@ -4909,7 +5114,7 @@ "identifier", "uuid" ], - "time": "2016-04-24 00:30:41" + "time": "2016-11-22 19:21:44" }, { "name": "react/promise", @@ -4961,20 +5166,25 @@ "source": { "type": "git", "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "96f1ef760845211c8acbb15970e706db1e4b2c5e" + "reference": "3c25700b65ba5e34a5ec8fd05b5cdc7a68d9385a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/96f1ef760845211c8acbb15970e706db1e4b2c5e", - "reference": "96f1ef760845211c8acbb15970e706db1e4b2c5e", + "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/3c25700b65ba5e34a5ec8fd05b5cdc7a68d9385a", + "reference": "3c25700b65ba5e34a5ec8fd05b5cdc7a68d9385a", "shasum": "" }, "conflict": { + "adodb/adodb-php": "<5.20.6", + "amphp/artax": ">=2,<2.0.4|>0.7.1,<1.0.4", "aws/aws-sdk-php": ">=3,<3.2.1", - "cakephp/cakephp": ">=3,<3.0.15|>=2,<2.4.99|>=2.5,<2.5.90|>=2.6,<2.6.12|>=1.3,<1.3.18|>=2.7,<2.7.6|>=3.1,<3.1.3", - "codeigniter/framework": "<3.0.3", + "bugsnag/bugsnag-laravel": ">=2,<2.0.2", + "cakephp/cakephp": ">=3,<3.0.15|>=2,<2.4.99|>=2.5,<2.5.99|>=2.6,<2.6.12|>=1.3,<1.3.18|>=2.7,<2.7.6|>=3.1,<3.1.4", + "cartalyst/sentry": "<2.1", + "codeigniter/framework": "<=3.0.6", "composer/composer": "<=1.0.0-alpha11", - "contao/core": ">=2.11,<3|>=3,<3.1|>=3.1,<3.2|>=3.2,<3.2.19|>=3.3,<3.4|>=3.4,<3.4.4", + "contao-components/mediaelement": ">=2.14.2,<2.21.1", + "contao/core": ">=2.11,<3.5.15", "doctrine/annotations": ">=1,<1.2.7", "doctrine/cache": ">=1,<1.3.2|>=1.4,<1.4.2", "doctrine/common": ">=2,<2.4.3|>=2.5,<2.5.1", @@ -4985,14 +5195,19 @@ "doctrine/mongodb-odm-bundle": ">=2,<3.0.1", "doctrine/orm": ">=2,<2.4.8|>=2.5,<2.5.1", "dompdf/dompdf": ">=0.6,<0.6.2", + "drupal/core": ">=8,<8.2.3", + "drupal/drupal": ">=8,<8.2.3", "firebase/php-jwt": "<2", "friendsofsymfony/rest-bundle": ">=1.2,<1.2.2", - "friendsofsymfony/user-bundle": ">=1.2,<1.3|>=1.3,<1.3.5", + "friendsofsymfony/user-bundle": ">=1.2,<1.3.5", + "gregwar/rst": "<1.0.3", + "guzzlehttp/guzzle": ">=6,<6.2.1|>=4.0.0-rc2,<4.2.4|>=5,<5.3.1", "illuminate/auth": ">=4,<4.0.99|>=4.1,<4.1.26", "illuminate/database": ">=4,<4.0.99|>=4.1,<4.1.29", "joomla/session": "<1.3.1", "laravel/framework": ">=4,<4.0.99|>=4.1,<4.1.29", "laravel/socialite": ">=1,<1.0.99|>=2,<2.0.10", + "magento/magento2ce": ">=2,<2.2", "monolog/monolog": ">=1.8,<1.12", "namshi/jose": "<2.2", "oro/crm": ">=1.7,<1.7.4", @@ -5000,34 +5215,35 @@ "phpmailer/phpmailer": ">=5,<5.2.14", "pusher/pusher-php-server": "<2.2.1", "sabre/dav": ">=1.6,<1.6.99|>=1.7,<1.7.11|>=1.8,<1.8.9", - "shopware/shopware": "<4.3.7|>=5,<5.1|>=5.1,<5.1.5", + "shopware/shopware": "<4.3.7|>=5,<5.1.5", "silverstripe/cms": ">=3.1,<3.1.11|>=3,<=3.0.11", "silverstripe/forum": "<=0.6.1|>=0.7,<=0.7.3", - "silverstripe/framework": ">=3,<3.1|>=3.1,<3.2|>=3.2,<3.3", + "silverstripe/framework": ">=3,<3.3", "silverstripe/userforms": "<3", - "simplesamlphp/simplesamlphp": "<=1.14.1", + "simplesamlphp/saml2": ">=1.9,<1.9.1|>=1.10,<1.10.3|>=2.3,<2.3.3", + "simplesamlphp/simplesamlphp": "<1.14.4", "socalnick/scn-social-auth": "<1.15.2", "swiftmailer/swiftmailer": ">=4,<4.99.99|>=5,<5.2.1", "symfony/dependency-injection": ">=2,<2.0.17", - "symfony/form": ">=2.3,<2.3.35|>=2.4,<2.5|>=2.5,<2.6|>=2.6,<2.6.12|>=2.7,<2.7.7", - "symfony/framework-bundle": ">=2,<2.1|>=2.1,<2.2|>=2.2,<2.3|>=2.3,<2.3.18|>=2.4,<2.4.8|>=2.5,<2.5.2", - "symfony/http-foundation": ">=2,<2.1|>=2.1,<2.2|>=2.2,<2.3|>=2.3,<2.3.27|>=2.4,<2.5|>=2.5,<2.5.11|>=2.6,<2.6.6", - "symfony/http-kernel": ">=2,<2.1|>=2.1,<2.2|>=2.2,<2.3|>=2.3,<2.3.29|>=2.4,<2.5|>=2.5,<2.5.12|>=2.6,<2.6.8", + "symfony/form": ">=2.3,<2.3.35|>=2.4,<2.6.12|>=2.7,<2.7.7", + "symfony/framework-bundle": ">=2,<2.3.18|>=2.4,<2.4.8|>=2.5,<2.5.2", + "symfony/http-foundation": ">=2,<2.3.27|>=2.4,<2.5.11|>=2.6,<2.6.6", + "symfony/http-kernel": ">=2,<2.3.29|>=2.4,<2.5.12|>=2.6,<2.6.8", "symfony/routing": ">=2,<2.0.19", - "symfony/security": ">=2.3,<2.3.37|>=2.4,<2.5|>=2.5,<2.6|>=2.6,<2.6.13|>=2.7,<2.7.9|>=2,<2.0.25|>=2.1,<2.1.13|>=2.2,<2.2.9", - "symfony/security-core": ">=2.8,<2.8.6|>=3,<3.0.6|>=2.4,<2.5|>=2.5,<2.6|>=2.6,<2.6.13|>=2.7,<2.7.9", - "symfony/security-http": ">=2.4,<2.5|>=2.5,<2.6|>=2.6,<2.7|>=2.7,<2.7.13|>=2.3,<2.3.41|>=2.8,<2.8.6|>=3,<3.0.6", + "symfony/security": ">=2.3,<2.3.37|>=2.4,<2.6.13|>=2.7,<2.7.9|>=2,<2.0.25|>=2.1,<2.1.13|>=2.2,<2.2.9", + "symfony/security-core": ">=2.8,<2.8.6|>=3,<3.0.6|>=2.4,<2.6.13|>=2.7,<2.7.9", + "symfony/security-http": ">=2.4,<2.7.13|>=2.3,<2.3.41|>=2.8,<2.8.6|>=3,<3.0.6", "symfony/serializer": ">=2,<2.0.11", - "symfony/symfony": ">=2,<2.1|>=2.1,<2.2|>=2.2,<2.3|>=2.3,<2.3.41|>=2.4,<2.5|>=2.5,<2.6|>=2.6,<2.7|>=2.7,<2.7.13|>=2.8,<2.8.6|>=3,<3.0.6", + "symfony/symfony": ">=2,<2.3.41|>=2.4,<2.7.13|>=2.8,<2.8.6|>=3,<3.0.6", "symfony/translation": ">=2,<2.0.17", "symfony/validator": ">=2,<2.0.24|>=2.1,<2.1.12|>=2.2,<2.2.5|>=2.3,<2.3.3", - "symfony/web-profiler-bundle": ">=2,<2.1|>=2.1,<2.2|>=2.2,<2.3|>=2.3,<2.3.19|>=2.4,<2.4.9|>=2.5,<2.5.4", + "symfony/web-profiler-bundle": ">=2,<2.3.19|>=2.4,<2.4.9|>=2.5,<2.5.4", "symfony/yaml": ">=2,<2.0.22|>=2.1,<2.1.7", "thelia/backoffice-default-template": ">=2.1,<2.1.2", "thelia/thelia": ">=2.1.0-beta1,<2.1.3|>=2.1,<2.1.2", "twig/twig": "<1.20", - "typo3/cms": ">=6.2,<6.2.25|>=7,<7.1|>=7.1,<7.2|>=7.2,<7.3|>=7.3,<7.4|>=7.4,<7.5|>=7.5,<7.6|>=7.6,<7.6.8|>=8,<8.1.1", - "typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.7|>=3,<3.0.1", + "typo3/cms": ">=6.2,<6.2.29|>=8,<8.4.1|>=7,<7.6.13", + "typo3/flow": ">=2.3,<2.3.16|>=3,<3.0.10|>=3.1,<3.1.7|>=3.2,<3.2.7|>=3.3,<3.3.5|>=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1", "typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4", "willdurand/js-translation-bundle": "<2.1.1", "yiisoft/yii": ">=1.1.14,<1.1.15", @@ -5052,7 +5268,7 @@ "zendframework/zend-view": ">=2,<2.2.7|>=2.3,<2.3.1", "zendframework/zend-xmlrpc": ">=2.1,<2.1.6|>=2.2,<2.2.6", "zendframework/zendframework": ">=2,<2.4.9|>=2.5,<2.5.1", - "zendframework/zendframework1": ">=1,<1.11.15|>=1.12,<1.12.18", + "zendframework/zendframework1": "<1.12.20", "zendframework/zendopenid": ">=2,<2.0.2", "zendframework/zendxml": ">=1,<1.0.1", "zf-commons/zfc-user": "<1.2.2", @@ -5072,20 +5288,20 @@ } ], "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it", - "time": "2016-05-25 05:33:34" + "time": "2016-12-04 13:54:33" }, { "name": "seld/jsonlint", - "version": "1.4.0", + "version": "1.5.0", "source": { "type": "git", "url": "https://github.com/Seldaek/jsonlint.git", - "reference": "66834d3e3566bb5798db7294619388786ae99394" + "reference": "19495c181d6d53a0a13414154e52817e3b504189" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/66834d3e3566bb5798db7294619388786ae99394", - "reference": "66834d3e3566bb5798db7294619388786ae99394", + "url": "https://api.github.com/repos/Seldaek/jsonlint/zipball/19495c181d6d53a0a13414154e52817e3b504189", + "reference": "19495c181d6d53a0a13414154e52817e3b504189", "shasum": "" }, "require": { @@ -5118,7 +5334,7 @@ "parser", "validator" ], - "time": "2015-11-21 02:21:41" + "time": "2016-11-14 17:59:58" }, { "name": "silex/silex", @@ -5445,16 +5661,16 @@ }, { "name": "sorien/silex-dbal-profiler", - "version": "1.1.2", + "version": "1.1.3", "source": { "type": "git", "url": "https://github.com/Sorien/silex-dbal-profiler.git", - "reference": "4d3f642144e96685270f7ffb1648a081d0c5eb7e" + "reference": "1df811da6cc2eb4abec4562e8000ca9eb998f7dd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Sorien/silex-dbal-profiler/zipball/4d3f642144e96685270f7ffb1648a081d0c5eb7e", - "reference": "4d3f642144e96685270f7ffb1648a081d0c5eb7e", + "url": "https://api.github.com/repos/Sorien/silex-dbal-profiler/zipball/1df811da6cc2eb4abec4562e8000ca9eb998f7dd", + "reference": "1df811da6cc2eb4abec4562e8000ca9eb998f7dd", "shasum": "" }, "require": { @@ -5489,7 +5705,7 @@ "profiler", "silex" ], - "time": "2015-03-12 09:26:42" + "time": "2016-10-26 11:08:02" }, { "name": "sorien/silex-pimple-dumper", @@ -5641,16 +5857,16 @@ }, { "name": "symfony/polyfill-apcu", - "version": "v1.2.0", + "version": "v1.3.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-apcu.git", - "reference": "6d58bceaeea2c2d3eb62503839b18646e161cd6b" + "reference": "5d4474f447403c3348e37b70acc2b95475b7befa" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-apcu/zipball/6d58bceaeea2c2d3eb62503839b18646e161cd6b", - "reference": "6d58bceaeea2c2d3eb62503839b18646e161cd6b", + "url": "https://api.github.com/repos/symfony/polyfill-apcu/zipball/5d4474f447403c3348e37b70acc2b95475b7befa", + "reference": "5d4474f447403c3348e37b70acc2b95475b7befa", "shasum": "" }, "require": { @@ -5659,7 +5875,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2-dev" + "dev-master": "1.3-dev" } }, "autoload": { @@ -5690,20 +5906,20 @@ "portable", "shim" ], - "time": "2016-05-18 14:26:46" + "time": "2016-11-14 01:06:16" }, { "name": "symfony/polyfill-intl-icu", - "version": "v1.2.0", + "version": "v1.3.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-icu.git", - "reference": "0f8dc2c45f69f8672379e9210bca4a115cd5146f" + "reference": "2d6e2b20d457603eefb6e614286c22efca30fdb4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-icu/zipball/0f8dc2c45f69f8672379e9210bca4a115cd5146f", - "reference": "0f8dc2c45f69f8672379e9210bca4a115cd5146f", + "url": "https://api.github.com/repos/symfony/polyfill-intl-icu/zipball/2d6e2b20d457603eefb6e614286c22efca30fdb4", + "reference": "2d6e2b20d457603eefb6e614286c22efca30fdb4", "shasum": "" }, "require": { @@ -5716,7 +5932,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2-dev" + "dev-master": "1.3-dev" } }, "autoload": { @@ -5748,20 +5964,20 @@ "portable", "shim" ], - "time": "2016-05-18 14:26:46" + "time": "2016-11-14 01:06:16" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.2.0", + "version": "v1.3.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "dff51f72b0706335131b00a7f49606168c582594" + "reference": "e79d363049d1c2128f133a2667e4f4190904f7f4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/dff51f72b0706335131b00a7f49606168c582594", - "reference": "dff51f72b0706335131b00a7f49606168c582594", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/e79d363049d1c2128f133a2667e4f4190904f7f4", + "reference": "e79d363049d1c2128f133a2667e4f4190904f7f4", "shasum": "" }, "require": { @@ -5773,7 +5989,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2-dev" + "dev-master": "1.3-dev" } }, "autoload": { @@ -5807,20 +6023,20 @@ "portable", "shim" ], - "time": "2016-05-18 14:26:46" + "time": "2016-11-14 01:06:16" }, { "name": "symfony/polyfill-php54", - "version": "v1.2.0", + "version": "v1.3.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php54.git", - "reference": "34d761992f6f2cc6092cc0e5e93f38b53ba5e4f1" + "reference": "90e085822963fdcc9d1c5b73deb3d2e5783b16a0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php54/zipball/34d761992f6f2cc6092cc0e5e93f38b53ba5e4f1", - "reference": "34d761992f6f2cc6092cc0e5e93f38b53ba5e4f1", + "url": "https://api.github.com/repos/symfony/polyfill-php54/zipball/90e085822963fdcc9d1c5b73deb3d2e5783b16a0", + "reference": "90e085822963fdcc9d1c5b73deb3d2e5783b16a0", "shasum": "" }, "require": { @@ -5829,7 +6045,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2-dev" + "dev-master": "1.3-dev" } }, "autoload": { @@ -5865,20 +6081,20 @@ "portable", "shim" ], - "time": "2016-05-18 14:26:46" + "time": "2016-11-14 01:06:16" }, { "name": "symfony/polyfill-php55", - "version": "v1.2.0", + "version": "v1.3.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php55.git", - "reference": "bf2ff9ad6be1a4772cb873e4eea94d70daa95c6d" + "reference": "03e3f0350bca2220e3623a0e340eef194405fc67" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php55/zipball/bf2ff9ad6be1a4772cb873e4eea94d70daa95c6d", - "reference": "bf2ff9ad6be1a4772cb873e4eea94d70daa95c6d", + "url": "https://api.github.com/repos/symfony/polyfill-php55/zipball/03e3f0350bca2220e3623a0e340eef194405fc67", + "reference": "03e3f0350bca2220e3623a0e340eef194405fc67", "shasum": "" }, "require": { @@ -5888,7 +6104,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2-dev" + "dev-master": "1.3-dev" } }, "autoload": { @@ -5921,20 +6137,20 @@ "portable", "shim" ], - "time": "2016-05-18 14:26:46" + "time": "2016-11-14 01:06:16" }, { "name": "symfony/polyfill-php56", - "version": "v1.2.0", + "version": "v1.3.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php56.git", - "reference": "3edf57a8fbf9a927533344cef65ad7e1cf31030a" + "reference": "1dd42b9b89556f18092f3d1ada22cb05ac85383c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/3edf57a8fbf9a927533344cef65ad7e1cf31030a", - "reference": "3edf57a8fbf9a927533344cef65ad7e1cf31030a", + "url": "https://api.github.com/repos/symfony/polyfill-php56/zipball/1dd42b9b89556f18092f3d1ada22cb05ac85383c", + "reference": "1dd42b9b89556f18092f3d1ada22cb05ac85383c", "shasum": "" }, "require": { @@ -5944,7 +6160,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2-dev" + "dev-master": "1.3-dev" } }, "autoload": { @@ -5977,20 +6193,20 @@ "portable", "shim" ], - "time": "2016-05-18 14:26:46" + "time": "2016-11-14 01:06:16" }, { "name": "symfony/polyfill-php70", - "version": "v1.2.0", + "version": "v1.3.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php70.git", - "reference": "a42f4b6b05ed458910f8af4c4e1121b0101b2d85" + "reference": "13ce343935f0f91ca89605a2f6ca6f5c2f3faac2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/a42f4b6b05ed458910f8af4c4e1121b0101b2d85", - "reference": "a42f4b6b05ed458910f8af4c4e1121b0101b2d85", + "url": "https://api.github.com/repos/symfony/polyfill-php70/zipball/13ce343935f0f91ca89605a2f6ca6f5c2f3faac2", + "reference": "13ce343935f0f91ca89605a2f6ca6f5c2f3faac2", "shasum": "" }, "require": { @@ -6000,7 +6216,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2-dev" + "dev-master": "1.3-dev" } }, "autoload": { @@ -6036,20 +6252,20 @@ "portable", "shim" ], - "time": "2016-05-18 14:26:46" + "time": "2016-11-14 01:06:16" }, { "name": "symfony/polyfill-util", - "version": "v1.2.0", + "version": "v1.3.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-util.git", - "reference": "ef830ce3d218e622b221d6bfad42c751d974bf99" + "reference": "746bce0fca664ac0a575e465f65c6643faddf7fb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-util/zipball/ef830ce3d218e622b221d6bfad42c751d974bf99", - "reference": "ef830ce3d218e622b221d6bfad42c751d974bf99", + "url": "https://api.github.com/repos/symfony/polyfill-util/zipball/746bce0fca664ac0a575e465f65c6643faddf7fb", + "reference": "746bce0fca664ac0a575e465f65c6643faddf7fb", "shasum": "" }, "require": { @@ -6058,7 +6274,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2-dev" + "dev-master": "1.3-dev" } }, "autoload": { @@ -6088,7 +6304,7 @@ "polyfill", "shim" ], - "time": "2016-05-18 14:26:46" + "time": "2016-11-14 01:06:16" }, { "name": "symfony/security-acl", @@ -6153,16 +6369,16 @@ }, { "name": "symfony/symfony", - "version": "v2.8.7", + "version": "v2.8.14", "source": { "type": "git", "url": "https://github.com/symfony/symfony.git", - "reference": "663b2d6202c3149515b39cfe50a174a130acb8e2" + "reference": "6ceca5b4154c80839270c38aa65373de76127df7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/symfony/zipball/663b2d6202c3149515b39cfe50a174a130acb8e2", - "reference": "663b2d6202c3149515b39cfe50a174a130acb8e2", + "url": "https://api.github.com/repos/symfony/symfony/zipball/6ceca5b4154c80839270c38aa65373de76127df7", + "reference": "6ceca5b4154c80839270c38aa65373de76127df7", "shasum": "" }, "require": { @@ -6178,7 +6394,7 @@ "symfony/polyfill-php70": "~1.0", "symfony/polyfill-util": "~1.0", "symfony/security-acl": "~2.7|~3.0.0", - "twig/twig": "~1.23|~2.0" + "twig/twig": "~1.28|~2.0" }, "conflict": { "phpdocumentor/reflection": "<1.0.7" @@ -6236,10 +6452,11 @@ "doctrine/dbal": "~2.4", "doctrine/doctrine-bundle": "~1.2", "doctrine/orm": "~2.4,>=2.4.5", - "egulias/email-validator": "~1.2", + "egulias/email-validator": "~1.2,>=1.2.1", "monolog/monolog": "~1.11", "ocramius/proxy-manager": "~0.4|~1.0|~2.0", - "phpdocumentor/reflection": "^1.0.7" + "phpdocumentor/reflection": "^1.0.7", + "symfony/phpunit-bridge": "~3.2" }, "type": "library", "extra": { @@ -6283,7 +6500,7 @@ "keywords": [ "framework" ], - "time": "2016-06-06 16:05:37" + "time": "2016-11-21 02:24:51" }, { "name": "themattharris/tmhoauth", @@ -6329,16 +6546,16 @@ }, { "name": "twig/extensions", - "version": "v1.3.0", + "version": "v1.4.1", "source": { "type": "git", "url": "https://github.com/twigphp/Twig-extensions.git", - "reference": "449e3c8a9ffad7c2479c7864557275a32b037499" + "reference": "f0bb8431c8691f5a39f1017d9a5967a082bf01ff" }, "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/f0bb8431c8691f5a39f1017d9a5967a082bf01ff", + "reference": "f0bb8431c8691f5a39f1017d9a5967a082bf01ff", "shasum": "" }, "require": { @@ -6353,7 +6570,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.3-dev" + "dev-master": "1.4-dev" } }, "autoload": { @@ -6377,20 +6594,20 @@ "i18n", "text" ], - "time": "2015-08-22 16:38:35" + "time": "2016-10-25 17:34:14" }, { "name": "twig/twig", - "version": "v1.24.1", + "version": "v1.28.2", "source": { "type": "git", "url": "https://github.com/twigphp/Twig.git", - "reference": "3566d311a92aae4deec6e48682dc5a4528c4a512" + "reference": "b22ce0eb070e41f7cba65d78fe216de29726459c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/twigphp/Twig/zipball/3566d311a92aae4deec6e48682dc5a4528c4a512", - "reference": "3566d311a92aae4deec6e48682dc5a4528c4a512", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/b22ce0eb070e41f7cba65d78fe216de29726459c", + "reference": "b22ce0eb070e41f7cba65d78fe216de29726459c", "shasum": "" }, "require": { @@ -6398,12 +6615,12 @@ }, "require-dev": { "symfony/debug": "~2.7", - "symfony/phpunit-bridge": "~2.7" + "symfony/phpunit-bridge": "~3.2@dev" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.24-dev" + "dev-master": "1.28-dev" } }, "autoload": { @@ -6438,7 +6655,7 @@ "keywords": [ "templating" ], - "time": "2016-05-30 09:11:59" + "time": "2016-11-23 18:41:40" }, { "name": "vierbergenlars/php-semver", @@ -6490,28 +6707,29 @@ }, { "name": "webmozart/assert", - "version": "1.0.2", + "version": "1.2.0", "source": { "type": "git", "url": "https://github.com/webmozart/assert.git", - "reference": "30eed06dd6bc88410a4ff7f77b6d22f3ce13dbde" + "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/30eed06dd6bc88410a4ff7f77b6d22f3ce13dbde", - "reference": "30eed06dd6bc88410a4ff7f77b6d22f3ce13dbde", + "url": "https://api.github.com/repos/webmozart/assert/zipball/2db61e59ff05fe5126d152bd0655c9ea113e550f", + "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": "^5.3.3 || ^7.0" }, "require-dev": { - "phpunit/phpunit": "^4.6" + "phpunit/phpunit": "^4.6", + "sebastian/version": "^1.0.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0-dev" + "dev-master": "1.3-dev" } }, "autoload": { @@ -6535,7 +6753,7 @@ "check", "validate" ], - "time": "2015-08-24 13:29:44" + "time": "2016-11-23 20:04:58" }, { "name": "webmozart/json", @@ -6634,25 +6852,28 @@ }, { "name": "willdurand/negotiation", - "version": "v2.0.2", + "version": "v2.2.1", "source": { "type": "git", "url": "https://github.com/willdurand/Negotiation.git", - "reference": "a8ce6da7acdf07351ccd6a9359c571ebc0725a21" + "reference": "1f210db45723b21edd69f39794662b8d64656b93" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/willdurand/Negotiation/zipball/a8ce6da7acdf07351ccd6a9359c571ebc0725a21", - "reference": "a8ce6da7acdf07351ccd6a9359c571ebc0725a21", + "url": "https://api.github.com/repos/willdurand/Negotiation/zipball/1f210db45723b21edd69f39794662b8d64656b93", + "reference": "1f210db45723b21edd69f39794662b8d64656b93", "shasum": "" }, "require": { "php": ">=5.4.0" }, + "require-dev": { + "phpunit/phpunit": "~4.5" + }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "2.2-dev" } }, "autoload": { @@ -6679,7 +6900,7 @@ "header", "negotiation" ], - "time": "2015-11-21 14:23:02" + "time": "2016-10-14 09:17:47" }, { "name": "zend/gdata", @@ -6832,16 +7053,16 @@ "packages-dev": [ { "name": "mikey179/vfsStream", - "version": "v1.6.3", + "version": "v1.6.4", "source": { "type": "git", "url": "https://github.com/mikey179/vfsStream.git", - "reference": "c19925cd0390d3c436a0203ae859afa460d0474b" + "reference": "0247f57b2245e8ad2e689d7cee754b45fbabd592" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mikey179/vfsStream/zipball/c19925cd0390d3c436a0203ae859afa460d0474b", - "reference": "c19925cd0390d3c436a0203ae859afa460d0474b", + "url": "https://api.github.com/repos/mikey179/vfsStream/zipball/0247f57b2245e8ad2e689d7cee754b45fbabd592", + "reference": "0247f57b2245e8ad2e689d7cee754b45fbabd592", "shasum": "" }, "require": { @@ -6874,7 +7095,49 @@ ], "description": "Virtual file system to mock the real file system in unit tests.", "homepage": "http://vfs.bovigo.org/", - "time": "2016-04-09 09:42:01" + "time": "2016-07-18 14:02:57" + }, + { + "name": "myclabs/deep-copy", + "version": "1.5.5", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "399c1f9781e222f6eb6cc238796f5200d1b7f108" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/399c1f9781e222f6eb6cc238796f5200d1b7f108", + "reference": "399c1f9781e222f6eb6cc238796f5200d1b7f108", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "doctrine/collections": "1.*", + "phpunit/phpunit": "~4.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "homepage": "https://github.com/myclabs/DeepCopy", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "time": "2016-10-31 17:19:45" }, { "name": "phpdocumentor/reflection-common", @@ -6932,16 +7195,16 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "3.1.0", + "version": "3.1.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "9270140b940ff02e58ec577c237274e92cd40cdd" + "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/9270140b940ff02e58ec577c237274e92cd40cdd", - "reference": "9270140b940ff02e58ec577c237274e92cd40cdd", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/8331b5efe816ae05461b7ca1e721c01b46bafb3e", + "reference": "8331b5efe816ae05461b7ca1e721c01b46bafb3e", "shasum": "" }, "require": { @@ -6973,20 +7236,20 @@ } ], "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2016-06-10 09:48:41" + "time": "2016-09-30 07:12:33" }, { "name": "phpdocumentor/type-resolver", - "version": "0.2", + "version": "0.2.1", "source": { "type": "git", "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443" + "reference": "e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/b39c7a5b194f9ed7bd0dd345c751007a41862443", - "reference": "b39c7a5b194f9ed7bd0dd345c751007a41862443", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb", + "reference": "e224fb2ea2fba6d3ad6fdaef91cd09a172155ccb", "shasum": "" }, "require": { @@ -7020,20 +7283,20 @@ "email": "me@mikevanriel.com" } ], - "time": "2016-06-10 07:14:17" + "time": "2016-11-25 06:54:22" }, { "name": "phpspec/prophecy", - "version": "v1.6.1", + "version": "v1.6.2", "source": { "type": "git", "url": "https://github.com/phpspec/prophecy.git", - "reference": "58a8137754bc24b25740d4281399a4a3596058e0" + "reference": "6c52c2722f8460122f96f86346600e1077ce22cb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/58a8137754bc24b25740d4281399a4a3596058e0", - "reference": "58a8137754bc24b25740d4281399a4a3596058e0", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/6c52c2722f8460122f96f86346600e1077ce22cb", + "reference": "6c52c2722f8460122f96f86346600e1077ce22cb", "shasum": "" }, "require": { @@ -7041,10 +7304,11 @@ "php": "^5.3|^7.0", "phpdocumentor/reflection-docblock": "^2.0|^3.0.2", "sebastian/comparator": "^1.1", - "sebastian/recursion-context": "^1.0" + "sebastian/recursion-context": "^1.0|^2.0" }, "require-dev": { - "phpspec/phpspec": "^2.0" + "phpspec/phpspec": "^2.0", + "phpunit/phpunit": "^4.8 || ^5.6.5" }, "type": "library", "extra": { @@ -7082,43 +7346,44 @@ "spy", "stub" ], - "time": "2016-06-07 08:13:47" + "time": "2016-11-21 14:58:47" }, { "name": "phpunit/php-code-coverage", - "version": "2.2.4", + "version": "4.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979" + "reference": "903fd6318d0a90b4770a009ff73e4a4e9c437929" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979", - "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/903fd6318d0a90b4770a009ff73e4a4e9c437929", + "reference": "903fd6318d0a90b4770a009ff73e4a4e9c437929", "shasum": "" }, "require": { - "php": ">=5.3.3", + "php": "^5.6 || ^7.0", "phpunit/php-file-iterator": "~1.3", "phpunit/php-text-template": "~1.2", - "phpunit/php-token-stream": "~1.3", - "sebastian/environment": "^1.3.2", - "sebastian/version": "~1.0" + "phpunit/php-token-stream": "^1.4.2", + "sebastian/code-unit-reverse-lookup": "~1.0", + "sebastian/environment": "^1.3.2 || ^2.0", + "sebastian/version": "~1.0|~2.0" }, "require-dev": { "ext-xdebug": ">=2.1.4", - "phpunit/phpunit": "~4" + "phpunit/phpunit": "^5.4" }, "suggest": { "ext-dom": "*", - "ext-xdebug": ">=2.2.1", + "ext-xdebug": ">=2.4.0", "ext-xmlwriter": "*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.2.x-dev" + "dev-master": "4.0.x-dev" } }, "autoload": { @@ -7144,20 +7409,20 @@ "testing", "xunit" ], - "time": "2015-10-06 15:47:00" + "time": "2016-11-28 16:00:31" }, { "name": "phpunit/php-file-iterator", - "version": "1.4.1", + "version": "1.4.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0" + "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/6150bf2c35d3fc379e50c7602b75caceaa39dbf0", - "reference": "6150bf2c35d3fc379e50c7602b75caceaa39dbf0", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3cc8f69b3028d0f96a9078e6295d86e9bf019be5", + "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5", "shasum": "" }, "require": { @@ -7191,7 +7456,7 @@ "filesystem", "iterator" ], - "time": "2015-06-21 13:08:43" + "time": "2016-10-03 07:40:28" }, { "name": "phpunit/php-text-template", @@ -7280,16 +7545,16 @@ }, { "name": "phpunit/php-token-stream", - "version": "1.4.8", + "version": "1.4.9", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da" + "reference": "3b402f65a4cc90abf6e1104e388b896ce209631b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da", - "reference": "3144ae21711fb6cac0b1ab4cbe63b75ce3d4e8da", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/3b402f65a4cc90abf6e1104e388b896ce209631b", + "reference": "3b402f65a4cc90abf6e1104e388b896ce209631b", "shasum": "" }, "require": { @@ -7325,44 +7590,54 @@ "keywords": [ "tokenizer" ], - "time": "2015-09-15 10:49:45" + "time": "2016-11-15 14:06:22" }, { "name": "phpunit/phpunit", - "version": "4.8.26", + "version": "5.7.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "fc1d8cd5b5de11625979125c5639347896ac2c74" + "reference": "336aff0ac52e306c98e7455bc3e8d7b0bf777a5e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/fc1d8cd5b5de11625979125c5639347896ac2c74", - "reference": "fc1d8cd5b5de11625979125c5639347896ac2c74", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/336aff0ac52e306c98e7455bc3e8d7b0bf777a5e", + "reference": "336aff0ac52e306c98e7455bc3e8d7b0bf777a5e", "shasum": "" }, "require": { "ext-dom": "*", "ext-json": "*", - "ext-pcre": "*", - "ext-reflection": "*", - "ext-spl": "*", - "php": ">=5.3.3", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "myclabs/deep-copy": "~1.3", + "php": "^5.6 || ^7.0", "phpspec/prophecy": "^1.3.1", - "phpunit/php-code-coverage": "~2.1", + "phpunit/php-code-coverage": "^4.0.3", "phpunit/php-file-iterator": "~1.4", "phpunit/php-text-template": "~1.2", "phpunit/php-timer": "^1.0.6", - "phpunit/phpunit-mock-objects": "~2.3", - "sebastian/comparator": "~1.1", + "phpunit/phpunit-mock-objects": "^3.2", + "sebastian/comparator": "~1.2.2", "sebastian/diff": "~1.2", - "sebastian/environment": "~1.3", - "sebastian/exporter": "~1.2", + "sebastian/environment": "^1.3.4 || ^2.0", + "sebastian/exporter": "~2.0", "sebastian/global-state": "~1.0", - "sebastian/version": "~1.0", + "sebastian/object-enumerator": "~2.0", + "sebastian/resource-operations": "~1.0", + "sebastian/version": "~1.0|~2.0", "symfony/yaml": "~2.1|~3.0" }, + "conflict": { + "phpdocumentor/reflection-docblock": "3.0.2" + }, + "require-dev": { + "ext-pdo": "*" + }, "suggest": { + "ext-xdebug": "*", "phpunit/php-invoker": "~1.1" }, "bin": [ @@ -7371,7 +7646,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.8.x-dev" + "dev-master": "5.7.x-dev" } }, "autoload": { @@ -7397,30 +7672,33 @@ "testing", "xunit" ], - "time": "2016-05-17 03:09:28" + "time": "2016-12-03 08:33:00" }, { "name": "phpunit/phpunit-mock-objects", - "version": "2.3.8", + "version": "3.4.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", - "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983" + "reference": "90a08f5deed5f7ac35463c161f2e8fa0e5652faf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983", - "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/90a08f5deed5f7ac35463c161f2e8fa0e5652faf", + "reference": "90a08f5deed5f7ac35463c161f2e8fa0e5652faf", "shasum": "" }, "require": { "doctrine/instantiator": "^1.0.2", - "php": ">=5.3.3", - "phpunit/php-text-template": "~1.2", - "sebastian/exporter": "~1.2" + "php": "^5.6 || ^7.0", + "phpunit/php-text-template": "^1.2", + "sebastian/exporter": "^1.2 || ^2.0" + }, + "conflict": { + "phpunit/phpunit": "<5.4.0" }, "require-dev": { - "phpunit/phpunit": "~4.4" + "phpunit/phpunit": "^5.4" }, "suggest": { "ext-soap": "*" @@ -7428,7 +7706,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.3.x-dev" + "dev-master": "3.2.x-dev" } }, "autoload": { @@ -7453,26 +7731,71 @@ "mock", "xunit" ], - "time": "2015-10-02 06:51:40" + "time": "2016-11-27 07:52:03" }, { - "name": "sebastian/comparator", - "version": "1.2.0", + "name": "sebastian/code-unit-reverse-lookup", + "version": "1.0.0", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "937efb279bd37a375bcadf584dec0726f84dbf22" + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "c36f5e7cfce482fde5bf8d10d41a53591e0198fe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/937efb279bd37a375bcadf584dec0726f84dbf22", - "reference": "937efb279bd37a375bcadf584dec0726f84dbf22", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/c36f5e7cfce482fde5bf8d10d41a53591e0198fe", + "reference": "c36f5e7cfce482fde5bf8d10d41a53591e0198fe", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "phpunit/phpunit": "~5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "time": "2016-02-13 06:45:14" + }, + { + "name": "sebastian/comparator", + "version": "1.2.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "6a1ed12e8b2409076ab22e3897126211ff8b1f7f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/6a1ed12e8b2409076ab22e3897126211ff8b1f7f", + "reference": "6a1ed12e8b2409076ab22e3897126211ff8b1f7f", "shasum": "" }, "require": { "php": ">=5.3.3", "sebastian/diff": "~1.2", - "sebastian/exporter": "~1.2" + "sebastian/exporter": "~1.2 || ~2.0" }, "require-dev": { "phpunit/phpunit": "~4.4" @@ -7517,7 +7840,7 @@ "compare", "equality" ], - "time": "2015-07-26 15:48:44" + "time": "2016-11-19 09:18:40" }, { "name": "sebastian/diff", @@ -7573,28 +7896,28 @@ }, { "name": "sebastian/environment", - "version": "1.3.7", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "4e8f0da10ac5802913afc151413bc8c53b6c2716" + "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/4e8f0da10ac5802913afc151413bc8c53b6c2716", - "reference": "4e8f0da10ac5802913afc151413bc8c53b6c2716", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/5795ffe5dc5b02460c3e34222fee8cbe245d8fac", + "reference": "5795ffe5dc5b02460c3e34222fee8cbe245d8fac", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": "^5.6 || ^7.0" }, "require-dev": { - "phpunit/phpunit": "~4.4" + "phpunit/phpunit": "^5.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.3.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { @@ -7619,33 +7942,34 @@ "environment", "hhvm" ], - "time": "2016-05-17 03:18:57" + "time": "2016-11-26 07:53:53" }, { "name": "sebastian/exporter", - "version": "1.2.1", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "7ae5513327cb536431847bcc0c10edba2701064e" + "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/7ae5513327cb536431847bcc0c10edba2701064e", - "reference": "7ae5513327cb536431847bcc0c10edba2701064e", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4", + "reference": "ce474bdd1a34744d7ac5d6aad3a46d48d9bac4c4", "shasum": "" }, "require": { "php": ">=5.3.3", - "sebastian/recursion-context": "~1.0" + "sebastian/recursion-context": "~2.0" }, "require-dev": { + "ext-mbstring": "*", "phpunit/phpunit": "~4.4" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.2.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { @@ -7685,7 +8009,7 @@ "export", "exporter" ], - "time": "2015-06-21 07:55:53" + "time": "2016-11-19 08:54:04" }, { "name": "sebastian/global-state", @@ -7739,17 +8063,63 @@ "time": "2015-10-12 03:26:01" }, { - "name": "sebastian/recursion-context", - "version": "1.0.2", + "name": "sebastian/object-enumerator", + "version": "2.0.0", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "913401df809e99e4f47b27cdd781f4a258d58791" + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "96f8a3f257b69e8128ad74d3a7fd464bcbaa3b35" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/913401df809e99e4f47b27cdd781f4a258d58791", - "reference": "913401df809e99e4f47b27cdd781f4a258d58791", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/96f8a3f257b69e8128ad74d3a7fd464bcbaa3b35", + "reference": "96f8a3f257b69e8128ad74d3a7fd464bcbaa3b35", + "shasum": "" + }, + "require": { + "php": ">=5.6", + "sebastian/recursion-context": "~2.0" + }, + "require-dev": { + "phpunit/phpunit": "~5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "time": "2016-11-19 07:35:10" + }, + { + "name": "sebastian/recursion-context", + "version": "2.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/2c3ba150cbec723aa057506e73a8d33bdb286c9a", + "reference": "2c3ba150cbec723aa057506e73a8d33bdb286c9a", "shasum": "" }, "require": { @@ -7761,7 +8131,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { @@ -7789,23 +8159,73 @@ ], "description": "Provides functionality to recursively process PHP variables", "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "time": "2015-11-11 19:50:13" + "time": "2016-11-19 07:33:16" }, { - "name": "sebastian/version", - "version": "1.0.6", + "name": "sebastian/resource-operations", + "version": "1.0.0", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/version.git", - "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6" + "url": "https://github.com/sebastianbergmann/resource-operations.git", + "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", - "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", + "reference": "ce990bb21759f94aeafd30209e8cfcdfa8bc3f52", "shasum": "" }, + "require": { + "php": ">=5.6.0" + }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides a list of PHP built-in functions that operate on resources", + "homepage": "https://www.github.com/sebastianbergmann/resource-operations", + "time": "2015-07-28 20:34:47" + }, + { + "name": "sebastian/version", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", + "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, "autoload": { "classmap": [ "src/" @@ -7824,7 +8244,7 @@ ], "description": "Library that helps with managing the version number of Git-hosted PHP projects", "homepage": "https://github.com/sebastianbergmann/version", - "time": "2015-06-21 13:59:46" + "time": "2016-10-03 07:35:21" } ], "aliases": [ diff --git a/config/configuration.sample.yml b/config/configuration.sample.yml index 19bd3242d2..499c631812 100644 --- a/config/configuration.sample.yml +++ b/config/configuration.sample.yml @@ -236,3 +236,16 @@ embed_bundle: document: player: flexpaper enable-pdfjs: true +geocoding-providers: + - + name: 'mapBox' + public-key: '' +workers: + queue: + worker-queue: + registry: alchemy_worker.queue_registry + host: localhost + port: 5672 + user: guest + password: guest + vhost: / diff --git a/lib/Alchemy/Phrasea/Application.php b/lib/Alchemy/Phrasea/Application.php index dea7992be8..e680a0bd79 100644 --- a/lib/Alchemy/Phrasea/Application.php +++ b/lib/Alchemy/Phrasea/Application.php @@ -73,6 +73,7 @@ use Alchemy\Phrasea\Core\Provider\TasksServiceProvider; use Alchemy\Phrasea\Core\Provider\TokensServiceProvider; use Alchemy\Phrasea\Core\Provider\UnicodeServiceProvider; use Alchemy\Phrasea\Core\Provider\WebhookServiceProvider; +use Alchemy\Phrasea\Core\Provider\WorkerConfigurationServiceProvider; use Alchemy\Phrasea\Core\Provider\ZippyServiceProvider; use Alchemy\Phrasea\Core\Provider\WebProfilerServiceProvider as PhraseaWebProfilerServiceProvider; use Alchemy\Phrasea\Databox\Caption\CaptionServiceProvider; @@ -86,6 +87,8 @@ use Alchemy\Phrasea\Media\MediaAccessorResolver; use Alchemy\Phrasea\Media\PermalinkMediaResolver; use Alchemy\Phrasea\Media\TechnicalDataServiceProvider; use Alchemy\Phrasea\Model\Entities\User; +use Alchemy\QueueProvider\QueueServiceProvider; +use Alchemy\WorkerProvider\WorkerServiceProvider; use Doctrine\DBAL\Event\ConnectionEventArgs; use MediaVorus\Media\MediaInterface; use MediaVorus\MediaVorus; @@ -243,6 +246,10 @@ class Application extends SilexApplication $this->setupEventDispatcher(); $this->register(new DataboxServiceProvider()); + $this->register(new QueueServiceProvider()); + $this->register(new WorkerServiceProvider()); + $this->register(new WorkerConfigurationServiceProvider()); + $this->register(new OrderServiceProvider()); $this->register(new WebhookServiceProvider()); diff --git a/lib/Alchemy/Phrasea/Authentication/Provider/GooglePlus.php b/lib/Alchemy/Phrasea/Authentication/Provider/GooglePlus.php index 55482acc68..2d519571b6 100644 --- a/lib/Alchemy/Phrasea/Authentication/Provider/GooglePlus.php +++ b/lib/Alchemy/Phrasea/Authentication/Provider/GooglePlus.php @@ -178,7 +178,7 @@ class GooglePlus extends AbstractProvider $token = @json_decode($this->client->getAccessToken(), true); if (JSON_ERROR_NONE !== json_last_error()) { - throw new NotAuthenticatedException('Unable to parse Google+ JSON', $e->getCode(), $e); + throw new NotAuthenticatedException('Unable to parse Google+ JSON'); } $ticket = $this->client->verifyIdToken($token['id_token']); diff --git a/lib/Alchemy/Phrasea/CLI.php b/lib/Alchemy/Phrasea/CLI.php index e5a10eac5e..0d6fc27774 100644 --- a/lib/Alchemy/Phrasea/CLI.php +++ b/lib/Alchemy/Phrasea/CLI.php @@ -23,6 +23,7 @@ use Alchemy\Phrasea\Core\CLIProvider\DoctrineMigrationServiceProvider; use Alchemy\Phrasea\Core\CLIProvider\PluginServiceProvider; use Alchemy\Phrasea\Core\CLIProvider\SignalHandlerServiceProvider; use Alchemy\Phrasea\Core\CLIProvider\TaskManagerServiceProvider; +use Symfony\Component\Console\Command\Command; use Symfony\Component\Debug\ErrorHandler; use Symfony\Component\EventDispatcher\EventDispatcher; @@ -72,6 +73,10 @@ class CLI extends Application $this->bindRoutes(); + $this['logger'] = $this->extend('logger', function () { + return new Console\Logger\ConsoleLogger(new Console\Output\ConsoleOutput(Console\Output\ConsoleOutput::VERBOSITY_DEBUG)); + }); + error_reporting(-1); ErrorHandler::register(); PhraseaCLIExceptionHandler::register(); @@ -87,6 +92,7 @@ class CLI extends Application $this->boot(); $app = $this['console']; + if ($interactive) { $app = new Console\Shell($app); } @@ -115,11 +121,14 @@ class CLI extends Application * * If a command with the same name already exists, it will be overridden. * - * @param CommandInterface $command A Command object + * @param Command|CommandInterface $command A Command object */ - public function command(CommandInterface $command) + public function command($command) { - $command->setContainer($this); + if ($command instanceof CommandInterface) { + $command->setContainer($this); + } + $this['console']->add($command); } diff --git a/lib/Alchemy/Phrasea/Collection/CollectionService.php b/lib/Alchemy/Phrasea/Collection/CollectionService.php index 8a2a8bc2f1..238aad9b47 100644 --- a/lib/Alchemy/Phrasea/Collection/CollectionService.php +++ b/lib/Alchemy/Phrasea/Collection/CollectionService.php @@ -139,7 +139,6 @@ class CollectionService . "WHERE r.coll_id = :coll_id\n" . "AND r.type='image' AND s.name IN ('preview', 'document')"; - $params = [':coll_id' => $collection->getCollectionId()]; if ($record_id) { diff --git a/lib/Alchemy/Phrasea/Command/CommandInterface.php b/lib/Alchemy/Phrasea/Command/CommandInterface.php index 241adf4897..cfb7c91cb4 100644 --- a/lib/Alchemy/Phrasea/Command/CommandInterface.php +++ b/lib/Alchemy/Phrasea/Command/CommandInterface.php @@ -24,6 +24,8 @@ interface CommandInterface /** * Factory for the command. + * + * @deprecated Will be removed in a future release. */ public static function create(); } diff --git a/lib/Alchemy/Phrasea/Command/Compile/Configuration.php b/lib/Alchemy/Phrasea/Command/Compile/Configuration.php index 9e84e3330b..76527bc46f 100644 --- a/lib/Alchemy/Phrasea/Command/Compile/Configuration.php +++ b/lib/Alchemy/Phrasea/Command/Compile/Configuration.php @@ -26,7 +26,7 @@ class Configuration extends Command protected function doExecute(InputInterface $input, OutputInterface $output) { $this->container['configuration.store']->compileAndWrite(); - $output->writeln("Confguration compiled."); + $output->writeln("Configuration compiled."); return 0; } diff --git a/lib/Alchemy/Phrasea/Controller/Admin/FieldsController.php b/lib/Alchemy/Phrasea/Controller/Admin/FieldsController.php index c13efa100d..02822d9228 100644 --- a/lib/Alchemy/Phrasea/Controller/Admin/FieldsController.php +++ b/lib/Alchemy/Phrasea/Controller/Admin/FieldsController.php @@ -210,7 +210,7 @@ class FieldsController extends Controller $this->validateTagField($data); try { - $field = \databox_field::create($this->app, $databox, $data['name'], $data['multi']); + $field = \databox_field::create($this->app, $databox, $data['name']); $this->updateFieldWithData($field, $data); $field->save(); } catch (\Exception $e) { @@ -308,6 +308,7 @@ class FieldsController extends Controller ->set_business($data['business']) ->set_aggregable($data['aggregable']) ->set_indexable($data['indexable']) + ->set_multi($data['multi']) ->set_required($data['required']) ->set_separator($data['separator']) ->set_readonly($data['readonly']) diff --git a/lib/Alchemy/Phrasea/Controller/Admin/SubdefsController.php b/lib/Alchemy/Phrasea/Controller/Admin/SubdefsController.php index 840feca115..166ee61c56 100644 --- a/lib/Alchemy/Phrasea/Controller/Admin/SubdefsController.php +++ b/lib/Alchemy/Phrasea/Controller/Admin/SubdefsController.php @@ -11,6 +11,7 @@ namespace Alchemy\Phrasea\Controller\Admin; use Alchemy\Phrasea\Controller\Controller; +use Alchemy\Phrasea\Databox\SubdefGroup; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -25,7 +26,7 @@ class SubdefsController extends Controller return $this->render('admin/subdefs.html.twig', [ 'databox' => $databox, - 'subdefs' => $databox->get_subdef_structure() + 'subdefs' => $databox->get_subdef_structure(), ]); } @@ -70,6 +71,8 @@ class SubdefsController extends Controller } else { $subdefs = $databox->get_subdef_structure(); + $this->updateSubdefGroups($subdefs, $request); + foreach ($Parmsubdefs as $post_sub) { $options = []; @@ -80,6 +83,7 @@ class SubdefsController extends Controller $class = $request->request->get($post_sub . '_class'); $downloadable = $request->request->get($post_sub . '_downloadable'); + $orderable = $request->request->get($post_sub . '_orderable'); $defaults = ['path', 'meta', 'mediatype']; @@ -107,7 +111,7 @@ class SubdefsController extends Controller $labels = $request->request->get($post_sub . '_label', []); - $subdefs->set_subdef($group, $name, $class, $downloadable, $options, $labels); + $subdefs->set_subdef($group, $name, $class, $downloadable, $options, $labels, $orderable); } } @@ -115,4 +119,37 @@ class SubdefsController extends Controller 'sbas_id' => $databox->get_sbas_id(), ]); } + + /** + * Update Databox subdefsStructure DOM according to defined groups. + * + * @param \databox_subdefsStructure $subdefs + * @param Request $request + */ + private function updateSubdefGroups(\databox_subdefsStructure $subdefs, Request $request) + { + $subdefsGroups = $request->request->get('subdefsgroups', []); + $changedGroups = []; + + /** @var SubdefGroup $subdefsGroup */ + foreach ($subdefs as $groupName => $subdefsGroup) { + $documentOrderable = isset($subdefsGroups[$groupName]['document_orderable']) + ? \p4field::isyes($subdefsGroups[$groupName]['document_orderable']) + : false; + + if ($subdefsGroup->isDocumentOrderable() !== $documentOrderable) { + if ($documentOrderable) { + $subdefsGroup->allowDocumentOrdering(); + } else { + $subdefsGroup->disallowDocumentOrdering(); + } + + $changedGroups[] = $subdefsGroup; + } + } + + if ($changedGroups) { + $subdefs->updateSubdefGroups($changedGroups); + } + } } diff --git a/lib/Alchemy/Phrasea/Controller/Api/LazaretController.php b/lib/Alchemy/Phrasea/Controller/Api/LazaretController.php index 299433b96e..579e5bf5a3 100644 --- a/lib/Alchemy/Phrasea/Controller/Api/LazaretController.php +++ b/lib/Alchemy/Phrasea/Controller/Api/LazaretController.php @@ -8,10 +8,12 @@ * file that was distributed with this source code. */ namespace Alchemy\Phrasea\Controller\Api; + use Alchemy\Phrasea\Controller\Controller; use Alchemy\Phrasea\Model\Manipulator\LazaretManipulator; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; + class LazaretController extends Controller { /** @@ -23,7 +25,9 @@ class LazaretController extends Controller { /** @var LazaretManipulator $lazaretManipulator */ $lazaretManipulator = $this->app['manipulator.lazaret']; + $ret = $lazaretManipulator->deny($lazaret_id); + return Result::create($request, $ret)->createResponse(); } @@ -31,7 +35,9 @@ class LazaretController extends Controller { /** @var LazaretManipulator $lazaretManipulator */ $lazaretManipulator = $this->app['manipulator.lazaret']; + $ret = $lazaretManipulator->add($lazaret_id); + return Result::create($request, $ret)->createResponse(); } @@ -44,9 +50,12 @@ class LazaretController extends Controller if( $maxTodo <= 0) { $maxTodo = -1; // all } + /** @var LazaretManipulator $lazaretManipulator */ $lazaretManipulator = $this->app['manipulator.lazaret']; + $ret = $lazaretManipulator->clear($maxTodo); + return Result::create($request, $ret)->createResponse(); } -} \ No newline at end of file +} diff --git a/lib/Alchemy/Phrasea/Controller/Api/V1Controller.php b/lib/Alchemy/Phrasea/Controller/Api/V1Controller.php index cafb22a062..770bf18a54 100644 --- a/lib/Alchemy/Phrasea/Controller/Api/V1Controller.php +++ b/lib/Alchemy/Phrasea/Controller/Api/V1Controller.php @@ -85,6 +85,7 @@ use Alchemy\Phrasea\Status\StatusStructure; use Alchemy\Phrasea\TaskManager\LiveInformation; use Alchemy\Phrasea\Utilities\NullableDateTime; use Doctrine\ORM\EntityManager; + use JMS\TranslationBundle\Annotation\Ignore; use League\Fractal\Resource\Item; use Symfony\Component\Form\Form; diff --git a/lib/Alchemy/Phrasea/Controller/LightboxController.php b/lib/Alchemy/Phrasea/Controller/LightboxController.php index a23776605f..7c3fdf6463 100644 --- a/lib/Alchemy/Phrasea/Controller/LightboxController.php +++ b/lib/Alchemy/Phrasea/Controller/LightboxController.php @@ -42,11 +42,7 @@ class LightboxController extends Controller $repository->findActiveValidationByUser($this->getAuthenticatedUser()) ); - $template = $this->isBrowserNewGenerationOrMobile() - ? 'lightbox/index.html.twig' - : 'lightbox/IE6/index.html.twig'; - - return $this->renderResponse($template, [ + return $this->renderResponse('lightbox/index.html.twig', [ 'baskets_collection' => $basket_collection, 'module_name' => 'Lightbox', 'module' => 'lightbox', @@ -92,7 +88,6 @@ class LightboxController extends Controller ]); } - $isNewGenerationBrowser = $this->app['browser']->isNewGeneration(); $basket = $basketElement->getBasket(); $ret = []; @@ -104,11 +99,11 @@ class LightboxController extends Controller ['record' => $basketElement->getRecord($this->app), 'not_wrapped' => true] ); $ret['options_html'] = $this->render( - $isNewGenerationBrowser ? 'lightbox/sc_options_box.html.twig' : 'lightbox/IE6/sc_options_box.html.twig', + 'lightbox/sc_options_box.html.twig', ['basket_element' => $basketElement] ); $ret['agreement_html'] = $this->render( - $isNewGenerationBrowser ? 'lightbox/agreement_box.html.twig' : 'lightbox/IE6/agreement_box.html.twig', + 'lightbox/agreement_box.html.twig', ['basket' => $basket, 'basket_element' => $basketElement] ); $ret['selector_html'] = $this->render('lightbox/selector_box.html.twig', ['basket_element' => $basketElement]); @@ -149,10 +144,7 @@ class LightboxController extends Controller 'record' => $record, 'not_wrapped' => true, ]); - $template_options = $browser->isNewGeneration() - ? 'lightbox/feed_options_box.html.twig' - : 'lightbox/IE6/feed_options_box.html.twig'; - $ret['options_html'] = $this->render($template_options, ['feed_element' => $item]); + $ret['options_html'] = $this->render('lightbox/feed_options_box.html.twig', ['feed_element' => $item]); $ret['caption'] = $this->render( 'common/caption.html.twig', [ 'view' => 'preview', @@ -213,7 +205,7 @@ class LightboxController extends Controller $basket = $this->markBasketRead($basket); $basket = $this->markBasketUserAwareOfValidation($basket); - + $response = $this->renderResponse($this->getValidationTemplate(), [ 'baskets_collection' => $basket_collection, 'basket' => $basket, @@ -238,28 +230,16 @@ class LightboxController extends Controller $basket->markRead(); $this->app['orm.em']->flush(); } - + return $basket; } - /** - * @return bool - */ - private function isBrowserNewGenerationOrMobile() - { - /** @var \Browser $browser */ - $browser = $this->app['browser']; - return $browser->isNewGeneration() || $browser->isMobile(); - } - /** * @return string */ private function getValidationTemplate() { - return $this->isBrowserNewGenerationOrMobile() - ? 'lightbox/validate.html.twig' - : 'lightbox/IE6/validate.html.twig'; + return 'lightbox/validate.html.twig'; } /** @@ -280,7 +260,7 @@ class LightboxController extends Controller ; $this->app['orm.em']->flush(); } - + return $basket; } @@ -300,14 +280,10 @@ class LightboxController extends Controller /** @var FeedEntry $feed_entry */ $feed_entry = $app['repo.feed-entries']->find($entry_id); - $template = $this->isBrowserNewGenerationOrMobile() - ? 'lightbox/feed.html.twig' - : 'lightbox/IE6/feed.html.twig'; - $content = $feed_entry->getItems(); $first = $content->first(); - $response = $this->renderResponse($template, [ + $response = $this->renderResponse('lightbox/feed.html.twig', [ 'feed_entry' => $feed_entry, 'first_item' => $first, 'local_title' => $feed_entry->getTitle(), @@ -359,7 +335,7 @@ class LightboxController extends Controller return $this->app->json($output); } - + public function ajaxSetElementAgreementAction(Request $request, $sselcont_id) { $agreement = $request->request->get('agreement'); diff --git a/lib/Alchemy/Phrasea/Controller/Prod/EditController.php b/lib/Alchemy/Phrasea/Controller/Prod/EditController.php index d0730f9b03..4d2ce9a6fd 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/EditController.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/EditController.php @@ -22,6 +22,7 @@ use Alchemy\Phrasea\Model\Entities\Preset; use Alchemy\Phrasea\Model\Entities\User; use Alchemy\Phrasea\Model\Manipulator\PresetManipulator; use Alchemy\Phrasea\Model\Repositories\PresetRepository; +use Alchemy\Phrasea\Twig\PhraseanetExtension; use Alchemy\Phrasea\Vocabulary\ControlProvider\ControlProviderInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -156,7 +157,9 @@ class EditController extends Controller ]; $elements[$indice]['statbits'] = []; + $elements[$indice]['editableStatus'] = false; if ($this->getAclForUser()->has_right_on_base($record->getBaseId(), 'chgstatus')) { + $elements[$indice]['editableStatus'] = true; foreach ($status as $n => $s) { $tmp_val = substr(strrev($record->getStatus()), $n, 1); $elements[$indice]['statbits'][$n]['value'] = ($tmp_val == '1') ? '1' : '0'; @@ -206,18 +209,21 @@ class EditController extends Controller 'h' => $thumbnail->get_height(), ]; - $elements[$indice]['preview'] = $this->render( + $elements[$indice]['template'] = $this->render( 'common/preview.html.twig', - ['record' => $record] + ['record' => $record, 'not_wrapped' => true] ); + $elements[$indice]['data'] = $this->getRecordElementData($record); + $elements[$indice]['type'] = $record->getType(); } } - + $conf = $this->getConf(); $params = [ 'multipleDataboxes' => $multipleDataboxes, 'recordsRequest' => $records, + 'videoEditorConfig' => $conf->get(['video-editor']), 'databox' => $databox, 'JSonStatus' => json_encode($status), 'JSonRecords' => json_encode($elements), @@ -529,4 +535,35 @@ class EditController extends Controller return $this->app['manipulator.preset']; } + /** + * @param \record_adapter $record + * @return array + */ + private function getRecordElementData($record) { + $helpers = new PhraseanetExtension($this->app); + $recordData = [ + 'databoxId' => $record->getBaseId(), + 'id' => $record->getId(), + 'isGroup' => $record->isStory(), + 'url' => (string)$helpers->getThumbnailUrl($record), + ]; + $userHaveAccess = $this->app->getAclForUser($this->getAuthenticatedUser())->has_access_to_subdef($record, 'preview'); + if ($userHaveAccess) { + $recordPreview = $record->get_preview(); + } else { + $recordPreview = $record->get_thumbnail(); + } + + $recordData['preview'] = [ + 'width' => $recordPreview->get_width(), + 'height' => $recordPreview->get_height(), + 'url' => $this->app->url('alchemy_embed_view', [ + 'url' => (string)($this->getAuthenticatedUser() ? $recordPreview->get_url() : $recordPreview->get_permalink()->get_url()), + 'autoplay' => false + ]) + ]; + + return $recordData; + } + } diff --git a/lib/Alchemy/Phrasea/Controller/Prod/FeedController.php b/lib/Alchemy/Phrasea/Controller/Prod/FeedController.php index 6c51b0fe5c..055af2b1d5 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/FeedController.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/FeedController.php @@ -54,7 +54,7 @@ class FeedController extends Controller $user = $this->getAuthenticatedUser(); $publisher = $this->getFeedPublisherRepository()->findOneBy([ - 'feed' => $feed, + 'feed' => $feed, 'user' => $user, ]); @@ -148,7 +148,7 @@ class FeedController extends Controller $entry->setFeed($new_feed); } - $items = explode(';', $request->request->get('sorted_lst')); + $items = explode(';', $request->request->get('lst')); $item_repository = $this->getFeedItemRepository(); $manager = $this->getEntityManager(); @@ -167,7 +167,7 @@ class FeedController extends Controller return $this->app->json([ 'error' => false, - 'message' => 'succes', + 'message' => 'success', 'datas' => $this->render('prod/results/entry.html.twig', ['entry' => $entry]), ]); } diff --git a/lib/Alchemy/Phrasea/Controller/Prod/LanguageController.php b/lib/Alchemy/Phrasea/Controller/Prod/LanguageController.php index 12e4360c18..41c1eaa8a8 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/LanguageController.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/LanguageController.php @@ -17,13 +17,13 @@ class LanguageController /** @var TranslatorInterface */ private $translator; private $serverName; - + public function __construct(TranslatorInterface $translator, $serverName) { $this->translator = $translator; $this->serverName = $serverName; } - + public function getTranslationsAction() { $translator = $this->translator; @@ -111,6 +111,39 @@ class LanguageController 'toolbox' => $translator->trans('Tool box'), 'print' => $translator->trans('Print'), 'attention' => $translator->trans('Attention !'), + 'mapMarkerEdit' => $translator->trans('Edit position'), + 'mapMarkerAdd' => $translator->trans('Add a position'), + 'mapMarkerMoveLabel' => $translator->trans('Drag and drop the pin to move position'), + 'mapMarkerEditCancel' => $translator->trans('Cancel'), + 'mapMarkerEditSubmit' => $translator->trans('Submit'), + 'Keyboard shortcuts' => $translator->trans('Keyboard shortcuts'), + 'Play' => $translator->trans('Play'), + 'Change play speed' => $translator->trans('Change play speed'), + 'Pause' => $translator->trans('Pause'), + 'One frame forward' => $translator->trans('One frame forward'), + 'One frame backward' => $translator->trans('One frame backward'), + 'Add an entry point' => $translator->trans('Add an entry point'), + 'Add an end point' => $translator->trans('Add an end point'), + 'Navigate to entry point' => $translator->trans('Navigate to entry point'), + 'Navigate to end point' => $translator->trans('Navigate to end point'), + 'Delete current' => $translator->trans('Delete current'), + 'Toggle loop' => $translator->trans('Toggle loop'), + 'Shift' => $translator->trans('Shift'), + 'Ctrl' => $translator->trans('Ctrl'), + 'Space bar' => $translator->trans('Space bar'), + 'or' => $translator->trans('or'), + 'Suppr' => $translator->trans('Suppr'), + 'Add new range' => $translator->trans('Add new range'), + 'Export ranges' => $translator->trans('Export ranges'), + 'Start Range' => $translator->trans('Start Range'), + 'End Range' => $translator->trans('End Range'), + 'Remove current Range' => $translator->trans('Remove current Range'), + 'Go to start point' => $translator->trans('Go to start point'), + 'Go 1 frame backward' => $translator->trans('Go 1 frame backward'), + 'Go 1 frame forward' => $translator->trans('Go 1 frame forward'), + 'Go to end point' => $translator->trans('Go to end point'), + 'Move up range' => $translator->trans('Move up range'), + 'Move down range' => $translator->trans('Move down range'), ]); } } diff --git a/lib/Alchemy/Phrasea/Controller/Prod/LazaretController.php b/lib/Alchemy/Phrasea/Controller/Prod/LazaretController.php index 465687a060..626df230c7 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/LazaretController.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/LazaretController.php @@ -16,14 +16,11 @@ use Alchemy\Phrasea\Application\Helper\EntityManagerAware; use Alchemy\Phrasea\Application\Helper\FilesystemAware; use Alchemy\Phrasea\Application\Helper\SubDefinitionSubstituerAware; use Alchemy\Phrasea\Border; -use Alchemy\Phrasea\Border\Attribute\AttributeInterface; use Alchemy\Phrasea\Controller\Controller; use Alchemy\Phrasea\Http\DeliverDataInterface; -use Alchemy\Phrasea\Media\SubdefSubstituer; use Alchemy\Phrasea\Model\Entities\LazaretFile; use Alchemy\Phrasea\Model\Manipulator\LazaretManipulator; use Alchemy\Phrasea\Model\Repositories\LazaretFileRepository; -use PHPExiftool\Driver\Metadata\Metadata; use Symfony\Component\Filesystem\Exception\IOException; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; diff --git a/lib/Alchemy/Phrasea/Controller/Prod/MoveCollectionController.php b/lib/Alchemy/Phrasea/Controller/Prod/MoveCollectionController.php index 14833a2edb..3ec8de1d08 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/MoveCollectionController.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/MoveCollectionController.php @@ -23,15 +23,34 @@ class MoveCollectionController extends Controller return $databox->get_sbas_id(); }, $records->databoxes()); + $message = ''; + $template = ''; $collections = $this->getAclForUser()->get_granted_base(['canaddrecord'], $sbas_ids); - $parameters = [ - 'records' => $records, - 'message' => '', - 'collections' => $collections, + if (count($records->databoxes()) > 1) { + $success = false; + $message = $this->app->trans('prod::Les enregistrements ne provienent pas tous de la meme base et ne peuvent donc etre traites ensemble'); + } elseif (count($records) == 0) { + $success = false; + $message = $this->app->trans('prod::Vous n\'avez le droit d\'effectuer l\'operation sur aucun document'); + } else { + // is able to move: + $success = true; + $parameters = [ + 'records' => $records, + 'message' => '', + 'collections' => $collections, + ]; + $template = $this->render('prod/actions/collection_default.html.twig', $parameters); + } + + $datas = [ + 'success' => $success, + 'message' => $message, + 'template' => $template ]; - return $this->render('prod/actions/collection_default.html.twig', $parameters); + return $this->app->json($datas); } public function apply(Request $request) diff --git a/lib/Alchemy/Phrasea/Controller/Prod/QueryController.php b/lib/Alchemy/Phrasea/Controller/Prod/QueryController.php index f15af9afb0..e6b0337602 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/QueryController.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/QueryController.php @@ -97,41 +97,41 @@ class QueryController extends Controller } for ($i = 1; ($i <= 4 && (($i <= $npages) === true)); $i++) { if ($i == $page) - $string .= ''; + $string .= ''; else - $string .= "" . $i . ""; + $string .= '' . $i . ''; } if ($npages > 4) $string .= ""; - $string .= ""; + $string .= ''; } else { $start = $npages - 4; if (($start) > 0){ - $string .= ""; - $string .= ""; + $string .= ''; + $string .= ''; }else $start = 1; for ($i = ($start); $i <= $npages; $i++) { if ($i == $page) - $string .= ''; + $string .= ''; else - $string .= "" . $i . ""; + $string .= '' . $i . ''; } if($page < $npages){ $string .= ""; } } } else { - $string .= ""; + $string .= ''; for ($i = ($page - 2); $i <= ($page + 2); $i++) { if ($i == $page) - $string .= ''; + $string .= ''; else - $string .= "" . $i . ""; + $string .= '' . $i . ''; } - $string .= ""; + $string .= ''; } } $string .= '
'; @@ -152,7 +152,7 @@ class QueryController extends Controller $infoResult = '
' . $this->app->trans('%number% documents
selectionnes', ['%number%' => '']) - . '
' + . '' . $this->app->trans('%total% reponses', ['%total%' => ''.$result->getTotal().'']) . ''; $json['infos'] = $infoResult; diff --git a/lib/Alchemy/Phrasea/Controller/Prod/RecordController.php b/lib/Alchemy/Phrasea/Controller/Prod/RecordController.php index dece366e83..4d18de4bfd 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/RecordController.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/RecordController.php @@ -14,9 +14,12 @@ use Alchemy\Phrasea\Application\Helper\EntityManagerAware; use Alchemy\Phrasea\Application\Helper\SearchEngineAware; use Alchemy\Phrasea\Controller\Controller; use Alchemy\Phrasea\Controller\RecordsRequest; +use Alchemy\Phrasea\Model\Entities\BasketElement; use Alchemy\Phrasea\Model\Repositories\BasketElementRepository; use Alchemy\Phrasea\Model\Repositories\StoryWZRepository; use Alchemy\Phrasea\SearchEngine\SearchEngineOptions; +use Alchemy\Phrasea\Twig\Fit; +use Alchemy\Phrasea\Twig\PhraseanetExtension; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -68,16 +71,20 @@ class RecordController extends Controller $options ); + $currentRecord = $this->getContainerResult($record); + if ($record->is_from_reg()) { $train = $this->render('prod/preview/reg_train.html.twig', ['record' => $record]); - } - - if ($record->is_from_basket() && $reloadTrain) { + } else if ($record->is_from_basket() && $reloadTrain) { $train = $this->render('prod/preview/basket_train.html.twig', ['record' => $record]); + } else if ($record->is_from_feed()) { + $train = $this->render('prod/preview/feed_train.html.twig', ['record' => $record]); } - if ($record->is_from_feed()) { - $train = $this->render('prod/preview/feed_train.html.twig', ['record' => $record]); + $recordCaptions = []; + foreach ($record->get_caption()->get_fields(null, true) as $field) { + // get field's values + $recordCaptions[$field->get_name()] = $field->get_serialized_values(); } return $this->app->json([ @@ -87,6 +94,7 @@ class RecordController extends Controller 'searchEngine' => $searchEngine, 'searchOptions' => $options, ]), + "recordCaptions"=> $recordCaptions, "html_preview" => $this->render('common/preview.html.twig', [ 'record' => $record ]), @@ -95,6 +103,7 @@ class RecordController extends Controller 'baskets' => $record->get_container_baskets($this->getEntityManager(), $this->getAuthenticatedUser()), ]), "current" => $train, + "record" => $currentRecord, "history" => $this->render('prod/preview/short_history.html.twig', [ 'record' => $record, ]), @@ -209,4 +218,38 @@ class RecordController extends Controller { return $this->app['repo.story-wz']; } + + /** + * @param \record_preview $recordContainer + * @return array + */ + private function getContainerResult(\record_preview $recordContainer) + { + /* @var $recordPreview \media_subdef */ + $helpers = new PhraseanetExtension($this->app); + + $recordData = [ + 'databoxId' => $recordContainer->getBaseId(), + 'id' => $recordContainer->getId(), + 'isGroup' => $recordContainer->isStory(), + 'url' => (string)$helpers->getThumbnailUrl($recordContainer), + ]; + $userHaveAccess = $this->app->getAclForUser($this->getAuthenticatedUser())->has_access_to_subdef($recordContainer, 'preview'); + if ($userHaveAccess) { + $recordPreview = $recordContainer->get_preview(); + } else { + $recordPreview = $recordContainer->get_thumbnail(); + } + + $recordData['preview'] = [ + 'width' => $recordPreview->get_width(), + 'height' => $recordPreview->get_height(), + 'url' => $this->app->url('alchemy_embed_view', [ + 'url' => (string)($this->getAuthenticatedUser() ? $recordPreview->get_url() : $recordPreview->get_permalink()->get_url()), + 'autoplay' => false + ]) + ]; + + return $recordData; + } } diff --git a/lib/Alchemy/Phrasea/Controller/Prod/RootController.php b/lib/Alchemy/Phrasea/Controller/Prod/RootController.php index be23d9ba4f..70890e219c 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/RootController.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/RootController.php @@ -45,29 +45,12 @@ class RootController extends Controller return $this->app->redirectPath('logout'); } - $cssPath = $this->app['root.path'] . '/www/assets/prod/skins'; - $css = []; - $finder = new Finder(); - /** @var SplFileInfo[] $iterator */ - $iterator = $finder - ->directories() - ->depth(0) - ->filter(function (\SplFileInfo $fileinfo) { - return ctype_xdigit($fileinfo->getBasename()); - }) - ->in($cssPath); - - foreach ($iterator as $dir) { - $baseName = $dir->getBaseName(); - $css[$baseName] = $baseName; - } - $user = $this->getAuthenticatedUser(); $cssfile = $this->getSettings()->getUserSetting($user, 'css'); - if (!$cssfile && isset($css['000000'])) { + if (!$cssfile) { $cssfile = '000000'; } @@ -76,14 +59,7 @@ class RootController extends Controller $thjslist = ""; - $queries_topics = ''; - $conf = $this->getConf(); - if ($conf->get(['registry', 'classic', 'render-topics']) == 'popups') { - $queries_topics = \queries::dropdown_topics($this->app['translator'], $this->app['locale']); - } elseif ($conf->get(['registry', 'classic', 'render-topics']) == 'tree') { - $queries_topics = \queries::tree_topics($this->app['locale']); - } $sbas = $bas2sbas = []; @@ -126,13 +102,11 @@ class RootController extends Controller 'GV_multiAndReport' => $conf->get(['registry', 'modules', 'stories']), 'GV_thesaurus' => $conf->get(['registry', 'modules', 'thesaurus']), 'cgus_agreement' => \databox_cgu::askAgreement($this->app), - 'css' => $css, 'feeds' => $feeds, 'aggregate' => $aggregate, 'GV_google_api' => $conf->get(['registry', 'webservices', 'google-charts-enabled']), - 'queries_topics' => $queries_topics, + 'geocodingProviders' => $conf->get(['geocoding-providers']), 'search_status' => \databox_status::getSearchStatus($this->app), - 'queries_history' => \queries::history($this->app, $user->getId()), 'thesau_js_list' => $thjslist, 'thesau_json_sbas' => json_encode($sbas), 'thesau_json_bas2sbas' => json_encode($bas2sbas), diff --git a/lib/Alchemy/Phrasea/Controller/Prod/ToolsController.php b/lib/Alchemy/Phrasea/Controller/Prod/ToolsController.php index cd22dc8740..e91485e0ec 100644 --- a/lib/Alchemy/Phrasea/Controller/Prod/ToolsController.php +++ b/lib/Alchemy/Phrasea/Controller/Prod/ToolsController.php @@ -95,10 +95,12 @@ class ToolsController extends Controller } } } + $conf = $this->getConf(); return $this->render('prod/actions/Tools/index.html.twig', [ 'records' => $records, 'record' => $record, + 'videoEditorConfig' => $conf->get(['video-editor']), 'recordSubdefs' => $recordAccessibleSubdefs, 'metadatas' => $metadata, ]); diff --git a/lib/Alchemy/Phrasea/Controller/Root/DeveloperController.php b/lib/Alchemy/Phrasea/Controller/Root/DeveloperController.php index e46bb5bf4a..e39c8f8cd5 100644 --- a/lib/Alchemy/Phrasea/Controller/Root/DeveloperController.php +++ b/lib/Alchemy/Phrasea/Controller/Root/DeveloperController.php @@ -19,6 +19,7 @@ use Alchemy\Phrasea\Model\Manipulator\ApiOauthTokenManipulator; use Alchemy\Phrasea\Model\Repositories\ApiAccountRepository; use Alchemy\Phrasea\Model\Repositories\ApiApplicationRepository; use Alchemy\Phrasea\Model\Repositories\ApiOauthTokenRepository; +use Alchemy\Phrasea\Model\Repositories\WebhookEventDeliveryRepository; use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -244,8 +245,12 @@ class DeveloperController extends Controller throw new AccessDeniedHttpException(); } + $deliveries = $this->getWebhookDeliveryRepository() + ->findLastDeliveries($account->getApplication(), 10); + return $this->render('developers/application.html.twig', [ "application" => $application, + "deliveries" => $deliveries, "user" => $user, "token" => $token, ]); @@ -298,4 +303,12 @@ class DeveloperController extends Controller { return $this->app['repo.api-applications']; } + + /** + * @return WebhookEventDeliveryRepository + */ + private function getWebhookDeliveryRepository() + { + return $this->app['webhook.delivery_repository']; + } } diff --git a/lib/Alchemy/Phrasea/Controller/Thesaurus/ThesaurusXmlHttpController.php b/lib/Alchemy/Phrasea/Controller/Thesaurus/ThesaurusXmlHttpController.php index 0bfa6e912e..2500a7dc23 100644 --- a/lib/Alchemy/Phrasea/Controller/Thesaurus/ThesaurusXmlHttpController.php +++ b/lib/Alchemy/Phrasea/Controller/Thesaurus/ThesaurusXmlHttpController.php @@ -1294,6 +1294,8 @@ class ThesaurusXmlHttpController extends Controller public function replaceCandidateJson(Request $request) { + $tsbas = []; + $ret = [ 'ctermsDeleted' => [], 'maxRecsUpdatable' => self::SEARCH_REPLACE_MAXREC, @@ -1302,48 +1304,158 @@ class ThesaurusXmlHttpController extends Controller 'msg' => '' ]; - // group ids by base - $tsbas = []; foreach ($request->get('id') as $id) { $id = explode('.', $id); $sbas_id = array_shift($id); - if (!array_key_exists($sbas_id, $tsbas)) { - $tsbas[$sbas_id] = []; + if (!array_key_exists('b' . $sbas_id, $tsbas)) { + $tsbas['b' . $sbas_id] = [ + 'sbas_id' => (int) $sbas_id, + 'tids' => [], + 'domct' => null, + 'tvals' => [], + 'lid' => '', + 'trids' => [] + ]; } - $tsbas[$sbas_id][] = implode('.', $id); + $tsbas['b' . $sbas_id]['tids'][] = implode('.', $id); } - // loop on bases - foreach ($tsbas as $sbas_id => $sbas) { + // first, count the number of records to update + foreach ($tsbas as $ksbas => $sbas) { try { - $databox = $this->findDataboxById($sbas_id); - $domct = $databox->get_dom_cterms(); + $databox = $this->findDataboxById($sbas['sbas_id']); + $connbas = $databox->get_connection(); + $tsbas[$ksbas]['domct'] = $databox->get_dom_cterms(); } catch (\Exception $e) { continue; } - if (!$domct) { + if (!$tsbas[$ksbas]['domct']) { continue; } - $domct_changed = false; - $xpathct = new \DOMXPath($domct); + $lids = []; + $xpathct = new \DOMXPath($tsbas[$ksbas]['domct']); - foreach ($sbas as $tid) { + foreach ($sbas['tids'] as $tid) { $xp = '//te[@id="' . $tid . '"]/sy'; $nodes = $xpathct->query($xp); if ($nodes->length == 1) { $sy = $nodes->item(0); - $te = $sy->parentNode; - $ret['ctermsDeleted'][] = $sbas_id . '.' . $te->getAttribute('id'); - $te->parentNode->removeChild($te); - $domct_changed = true; + $syid = str_replace('.', 'd', $sy->getAttribute('id')) . 'd'; + $lids[] = $syid; + $field = $sy->parentNode->parentNode->getAttribute('field'); + + if (!array_key_exists($field, $tsbas[$ksbas]['tvals'])) { + $tsbas[$ksbas]['tvals'][$field] = []; + } + $tsbas[$ksbas]['tvals'][$field][] = $sy; } } - if ($domct_changed && !$request->get('debug')) { - $databox->saveCterms($domct); + if (empty($lids)) { + // no cterm was found + continue; } + $tsbas[$ksbas]['lid'] = "'" . implode("','", $lids) . "'"; + + // count records + $sql = 'SELECT DISTINCT record_id AS r' + . ' FROM thit WHERE value IN (:lids)' + . ' ORDER BY record_id'; + $stmt = $connbas->prepare($sql); + $stmt->execute(['lids' => $lids]); + $tsbas[$ksbas]['trids'] = $stmt->fetchAll(\PDO::FETCH_COLUMN, 0); + $stmt->closeCursor(); + + $ret['nRecsToUpdate'] += count($tsbas[$ksbas]['trids']); + } + + if ($ret['nRecsToUpdate'] <= self::SEARCH_REPLACE_MAXREC) { + foreach ($tsbas as $sbas) { + + try { + $databox = $this->findDataboxById($sbas['sbas_id']); + } catch (\Exception $e) { + continue; + } + + // fix caption of records + foreach ($sbas['trids'] as $rid) { + try { + $record = $databox->get_record($rid); + + $metadatask = []; // datas to keep + $metadatasd = []; // datas to delete + + /* @var $field caption_field */ + foreach ($record->get_caption()->get_fields(null, true) as $field) { + $meta_struct_id = $field->get_meta_struct_id(); + /* @var $v caption_Field_Value */ + $fname = $field->get_name(); + if (!array_key_exists($fname, $sbas['tvals'])) { + foreach ($field->get_values() as $v) { + $metadatask[] = [ + 'meta_struct_id' => $meta_struct_id, + 'meta_id' => $v->getId(), + 'value' => $v->getValue() + ]; + } + } else { + foreach ($field->get_values() as $v) { + $keep = true; + $vtxt = $this->getUnicode()->remove_indexer_chars($v->getValue()); + /** @var DOMElement $sy */ + foreach ($sbas['tvals'][$fname] as $sy) { + if ($sy->getAttribute('w') == $vtxt) { + $keep = false; + } + } + + if ($keep) { + $metadatask[] = [ + 'meta_struct_id' => $meta_struct_id, + 'meta_id' => $v->getId(), + 'value' => $v->getValue() + ]; + } else { + $metadatasd[] = [ + 'meta_struct_id' => $meta_struct_id, + 'meta_id' => $v->getId(), + 'value' => $request->get('t') ? $request->get('t') : '' + ]; + } + } + } + } + + if (count($metadatasd) > 0) { + if (!$request->get('debug')) { + $record->set_metadatas($metadatasd, true); + $ret['nRecsUpdated']++; + } + } + } catch (\Exception $e) { + continue; + } + } + + foreach ($sbas['tvals'] as $tval) { + foreach ($tval as $sy) { + // remove candidate from cterms + $te = $sy->parentNode; + $te->parentNode->removeChild($te); + $ret['ctermsDeleted'][] = $sbas['sbas_id'] . '.' . $te->getAttribute('id'); + } + } + if (!$request->get('debug')) { + $databox->saveCterms($sbas['domct']); + } + } + $ret['msg'] = $this->app->trans('prod::thesaurusTab:dlg:%number% record(s) updated', ['%number%' => $ret['nRecsUpdated']]); + } else { + // too many records to update + $ret['msg'] = $this->app->trans('prod::thesaurusTab:dlg:too many (%number%) records to update (limit=%maximum%)', ['%number%' => $ret['nRecsToUpdate'], '%maximum%' => self::SEARCH_REPLACE_MAXREC]); } return $this->app->json($ret); @@ -1397,12 +1509,12 @@ class ThesaurusXmlHttpController extends Controller $t = $this->splitTermAndContext($request->get('t')); $unicode = $this->getUnicode(); $q2 = 'starts-with(@w, \'' . \thesaurus::xquery_escape($unicode->remove_indexer_chars($t[0])) . '\')'; - if ($t[1]) - $q2 .= ' and starts-with(@k, \'' . \thesaurus::xquery_escape( - $unicode->remove_indexer_chars($t[1])) . '\')'; - $q2 = '//sy[' . $q2 . ' and @lng=\'' . $lng . '\']'; - - $q .= $q2; + if ($t[1]) { + $q2 .= ' and starts-with(@k, \'' . \thesaurus::xquery_escape($unicode->remove_indexer_chars($t[1])) . '\')'; + } + + $q2 .= ' and @lng=\'' . \thesaurus::xquery_escape($lng) . '\''; + $q .= ('//sy[' . $q2 . ']'); $nodes = $xpath->query($q); diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Api/V2.php b/lib/Alchemy/Phrasea/ControllerProvider/Api/V2.php index 53eee150b5..c1b0651b3d 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Api/V2.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Api/V2.php @@ -39,7 +39,6 @@ class V2 extends Api implements ControllerProviderInterface, ServiceProviderInte ->setJsonBodyHelper($app['json.body_helper']); } ); - $app['controller.api.v2.lazaret'] = $app->share( function (PhraseaApplication $app) { return (new LazaretController($app)); diff --git a/lib/Alchemy/Phrasea/Core/Event/AuthenticationEvent.php b/lib/Alchemy/Phrasea/Core/Event/AuthenticationEvent.php new file mode 100644 index 0000000000..47f85e7622 --- /dev/null +++ b/lib/Alchemy/Phrasea/Core/Event/AuthenticationEvent.php @@ -0,0 +1,37 @@ +request = $request; + $this->context = $context; + } + + public function getRequest() + { + return $this->request; + } + + public function getContext() + { + return $this->context; + } +} diff --git a/lib/Alchemy/Phrasea/Core/Event/PostAuthenticate.php b/lib/Alchemy/Phrasea/Core/Event/PostAuthenticate.php index 93ef333c3b..9ce9e80d50 100644 --- a/lib/Alchemy/Phrasea/Core/Event/PostAuthenticate.php +++ b/lib/Alchemy/Phrasea/Core/Event/PostAuthenticate.php @@ -15,21 +15,18 @@ use Alchemy\Phrasea\Authentication\Context; use Alchemy\Phrasea\Model\Entities\User; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\EventDispatcher\Event as SfEvent; -class PostAuthenticate extends SfEvent +class PostAuthenticate extends AuthenticationEvent { - private $context; private $user; - private $request; private $response; public function __construct(Request $request, Response $response, User $user, Context $context) { - $this->request = $request; + parent::__construct($request, $context); + $this->response = $response; $this->user = $user; - $this->context = $context; } public function getUser() @@ -37,11 +34,6 @@ class PostAuthenticate extends SfEvent return $this->user; } - public function getRequest() - { - return $this->request; - } - public function getResponse() { return $this->response; @@ -51,9 +43,4 @@ class PostAuthenticate extends SfEvent { $this->response = $response; } - - public function getContext() - { - return $this->context; - } } diff --git a/lib/Alchemy/Phrasea/Core/Event/PreAuthenticate.php b/lib/Alchemy/Phrasea/Core/Event/PreAuthenticate.php index bf597055d0..4a457fea2b 100644 --- a/lib/Alchemy/Phrasea/Core/Event/PreAuthenticate.php +++ b/lib/Alchemy/Phrasea/Core/Event/PreAuthenticate.php @@ -11,28 +11,6 @@ namespace Alchemy\Phrasea\Core\Event; -use Alchemy\Phrasea\Authentication\Context; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\EventDispatcher\Event as SfEvent; - -class PreAuthenticate extends SfEvent +class PreAuthenticate extends AuthenticationEvent { - private $request; - private $context; - - public function __construct(Request $request, Context $context) - { - $this->request = $request; - $this->context = $context; - } - - public function getRequest() - { - return $this->request; - } - - public function getContext() - { - return $this->context; - } } diff --git a/lib/Alchemy/Phrasea/Core/Provider/ManipulatorServiceProvider.php b/lib/Alchemy/Phrasea/Core/Provider/ManipulatorServiceProvider.php index 4b0b86c79b..fdeb34849e 100644 --- a/lib/Alchemy/Phrasea/Core/Provider/ManipulatorServiceProvider.php +++ b/lib/Alchemy/Phrasea/Core/Provider/ManipulatorServiceProvider.php @@ -108,7 +108,11 @@ class ManipulatorServiceProvider implements ServiceProviderInterface }); $app['manipulator.webhook-event'] = $app->share(function (Application $app) { - return new WebhookEventManipulator($app['orm.em'], $app['repo.webhook-event']); + return new WebhookEventManipulator( + $app['orm.em'], + $app['repo.webhook-event'], + $app['webhook.publisher'] + ); }); $app['manipulator.webhook-delivery'] = $app->share(function (Application $app) { @@ -122,6 +126,7 @@ class ManipulatorServiceProvider implements ServiceProviderInterface $app['manipulator.lazaret'] = $app->share(function (Application $app) { return new LazaretManipulator($app, $app['repo.lazaret-files'], $app['filesystem'], $app['orm.em']); }); + } public function boot(SilexApplication $app) diff --git a/lib/Alchemy/Phrasea/Core/Provider/SearchEngineServiceProvider.php b/lib/Alchemy/Phrasea/Core/Provider/SearchEngineServiceProvider.php index fbc99a8d4f..d1d4f10d39 100644 --- a/lib/Alchemy/Phrasea/Core/Provider/SearchEngineServiceProvider.php +++ b/lib/Alchemy/Phrasea/Core/Provider/SearchEngineServiceProvider.php @@ -219,7 +219,7 @@ class SearchEngineServiceProvider implements ServiceProviderInterface $clientBuilder = ClientBuilder::create() ->setHosts($clientParams['hosts']); - if (array_key_exists('logObject', $clientParams)) { + if(array_key_exists('logObject', $clientParams)) { $clientBuilder->setLogger($clientParams['logObject']); } diff --git a/lib/Alchemy/Phrasea/Core/Provider/WebhookServiceProvider.php b/lib/Alchemy/Phrasea/Core/Provider/WebhookServiceProvider.php index e224d8a43d..4b280c92f0 100644 --- a/lib/Alchemy/Phrasea/Core/Provider/WebhookServiceProvider.php +++ b/lib/Alchemy/Phrasea/Core/Provider/WebhookServiceProvider.php @@ -3,6 +3,11 @@ namespace Alchemy\Phrasea\Core\Provider; use Alchemy\Phrasea\Webhook\EventProcessorFactory; +use Alchemy\Phrasea\Webhook\EventProcessorWorker; +use Alchemy\Phrasea\Webhook\WebhookInvoker; +use Alchemy\Phrasea\Webhook\WebhookPublisher; +use Alchemy\Worker\CallableWorkerFactory; +use Alchemy\Worker\TypeBasedWorkerResolver; use Silex\Application; use Silex\ServiceProviderInterface; @@ -11,9 +16,55 @@ class WebhookServiceProvider implements ServiceProviderInterface public function register(Application $app) { + $this->createAlias($app, 'webhook.event_repository', 'repo.webhook-event'); + $this->createAlias($app, 'webhook.event_manipulator', 'manipulator.webhook-event'); + $this->createAlias($app, 'webhook.delivery_repository', 'repo.webhook-delivery'); + $this->createAlias($app, 'webhook.delivery_manipulator', 'manipulator.webhook-delivery'); + + $app['webhook.delivery_payload_repository'] = $app->share(function ($app) { + return $app['orm.em']->getRepository('Phraseanet:WebhookEventPayload'); + }); + $app['webhook.processor_factory'] = $app->share(function ($app) { return new EventProcessorFactory($app); }); + + $app['webhook.invoker'] = $app->share(function ($app) { + return new WebhookInvoker( + $app['repo.api-applications'], + $app['webhook.processor_factory'], + $app['webhook.event_repository'], + $app['webhook.event_manipulator'], + $app['webhook.delivery_repository'], + $app['webhook.delivery_manipulator'], + $app['webhook.delivery_payload_repository'] + ); + }); + + $app['webhook.publisher'] = $app->share(function ($app) { + return new WebhookPublisher($app['alchemy_worker.queue_registry'], $app['alchemy_worker.queue_name']); + }); + + $app['alchemy_worker.worker_resolver'] = $app->extend( + 'alchemy_worker.type_based_worker_resolver', + function (TypeBasedWorkerResolver $resolver, Application $app) { + $resolver->setFactory('webhook', new CallableWorkerFactory(function () use ($app) { + return new EventProcessorWorker( + $app['webhook.event_repository'], + $app['webhook.invoker'] + ); + })); + + return $resolver; + } + ); + } + + private function createAlias(Application $app, $alias, $targetServiceKey) + { + $app[$alias] = $app->share(function () use ($app, $targetServiceKey) { + return $app[$targetServiceKey]; + }); } public function boot(Application $app) diff --git a/lib/Alchemy/Phrasea/Core/Provider/WorkerConfigurationServiceProvider.php b/lib/Alchemy/Phrasea/Core/Provider/WorkerConfigurationServiceProvider.php new file mode 100644 index 0000000000..1b2e15d4f0 --- /dev/null +++ b/lib/Alchemy/Phrasea/Core/Provider/WorkerConfigurationServiceProvider.php @@ -0,0 +1,81 @@ +share(function (Application $app) { + $queues = $app['alchemy_queues.queues']; + + reset($queues); + + return key($queues); + }); + + $app['alchemy_queues.queues'] = $app->share(function (Application $app) { + $defaultConfiguration = [ + 'worker-queue' => [ + 'registry' => 'alchemy_worker.queue_registry', + 'host' => 'localhost', + 'port' => 5672, + 'user' => 'guest', + 'vhost' => '/' + ] + ]; + + try { + /** @var PropertyAccess $configuration */ + $configuration = $app['conf']; + + $queueConfigurations = $configuration->get(['workers', 'queue'], $defaultConfiguration); + + $queueConfiguration = reset($queueConfigurations); + $queueKey = key($queueConfigurations); + + if (! isset($queueConfiguration['name'])) { + if (! is_string($queueKey)) { + throw new \RuntimeException('Invalid queue configuration: configuration has no key or name.'); + } + + $queueConfiguration['name'] = $queueKey; + } + + $config = [ $queueConfiguration['name'] => $queueConfiguration ]; + + return $config; + } + catch (RuntimeException $exception) { + return []; + } + }); + } + + /** + * Bootstraps the application. + * + * This method is called after all services are registered + * and should be used for "dynamic" configuration (whenever + * a service must be requested). + */ + public function boot(Application $app) + { + // No-op + } +} diff --git a/lib/Alchemy/Phrasea/Databox/SubdefGroup.php b/lib/Alchemy/Phrasea/Databox/SubdefGroup.php index 0cc82d7f51..80ed8bcd56 100644 --- a/lib/Alchemy/Phrasea/Databox/SubdefGroup.php +++ b/lib/Alchemy/Phrasea/Databox/SubdefGroup.php @@ -56,6 +56,16 @@ class SubdefGroup implements \IteratorAggregate, \Countable return $this->type; } + public function allowDocumentOrdering() + { + $this->isDocumentOrderable = true; + } + + public function disallowDocumentOrdering() + { + $this->isDocumentOrderable = false; + } + /** * @return bool */ diff --git a/lib/Alchemy/Phrasea/Form/Login/PhraseaRegisterForm.php b/lib/Alchemy/Phrasea/Form/Login/PhraseaRegisterForm.php index 363143b745..136b4e7e76 100644 --- a/lib/Alchemy/Phrasea/Form/Login/PhraseaRegisterForm.php +++ b/lib/Alchemy/Phrasea/Form/Login/PhraseaRegisterForm.php @@ -62,7 +62,7 @@ class PhraseaRegisterForm extends AbstractType 'label' => 'Terms of Use', 'mapped' => false, "constraints" => [ - new Assert\True([ + new Assert\IsTrue([ "message" => "Please accept the Terms and conditions in order to register." ])], ]); diff --git a/lib/Alchemy/Phrasea/Model/Entities/WebhookEventDelivery.php b/lib/Alchemy/Phrasea/Model/Entities/WebhookEventDelivery.php index 9e63da730e..8e871a5d46 100644 --- a/lib/Alchemy/Phrasea/Model/Entities/WebhookEventDelivery.php +++ b/lib/Alchemy/Phrasea/Model/Entities/WebhookEventDelivery.php @@ -56,6 +56,11 @@ class WebhookEventDelivery */ private $created; + /** + * @ORM\OneToOne(targetEntity="WebhookEventPayload", mappedBy="delivery") + */ + private $payload; + /** * @param \DateTime $created * @@ -163,4 +168,12 @@ class WebhookEventDelivery { return $this->event; } + + /** + * @return WebhookEventPayload + */ + public function getPayload() + { + return $this->payload; + } } diff --git a/lib/Alchemy/Phrasea/Model/Entities/WebhookEventPayload.php b/lib/Alchemy/Phrasea/Model/Entities/WebhookEventPayload.php new file mode 100644 index 0000000000..1befac1843 --- /dev/null +++ b/lib/Alchemy/Phrasea/Model/Entities/WebhookEventPayload.php @@ -0,0 +1,127 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Alchemy\Phrasea\Model\Entities; + +use Doctrine\ORM\Mapping as ORM; +use Ramsey\Uuid\Uuid; + +/** + * @ORM\Table(name="WebhookEventPayloads") + * @ORM\Entity(repositoryClass="Alchemy\Phrasea\Model\Repositories\WebhookEventPayloadRepository") + */ +class WebhookEventPayload +{ + /** + * @ORM\Column(type="guid") + * @ORM\Id + * @ORM\GeneratedValue(strategy="NONE") + * + * @var string + */ + private $id; + + /** + * @ORM\OneToOne(targetEntity="WebhookEventDelivery") + * @ORM\JoinColumn(name="delivery_id", referencedColumnName="id") + */ + private $delivery; + + /** + * @ORM\Column(type="text", name="request") + * @var string + */ + private $requestPayload; + + /** + * @ORM\Column(type="text", name="response") + * @var string + */ + private $responsePayload; + + /** + * @ORM\Column(type="integer", name="status") + * @var int + */ + private $statusCode; + + /** + * @ORM\Column(type="text") + * @var string + */ + private $headers; + + /** + * @param WebhookEventDelivery $eventDelivery + * @param string $requestPayload + * @param string $responsePayload + * @param int $statusCode + * @param string $headers + */ + public function __construct(WebhookEventDelivery $eventDelivery, $requestPayload, $responsePayload, $statusCode, $headers) + { + $this->id = Uuid::uuid4()->toString(); + + $this->delivery = $eventDelivery; + $this->requestPayload = $requestPayload; + $this->responsePayload = $responsePayload; + $this->statusCode = $statusCode; + $this->headers = $headers; + } + + /** + * @return string + */ + public function getId() + { + return $this->id; + } + + /** + * @return WebhookEventDelivery + */ + public function getDelivery() + { + return $this->delivery; + } + + /** + * @return string + */ + public function getRequestPayload() + { + return $this->requestPayload; + } + + /** + * @return string + */ + public function getResponsePayload() + { + return $this->responsePayload; + } + + /** + * @return int + */ + public function getStatusCode() + { + return $this->statusCode; + } + + /** + * @return string + */ + public function getResponseHeaders() + { + return $this->headers; + } +} diff --git a/lib/Alchemy/Phrasea/Model/Manipulator/LazaretManipulator.php b/lib/Alchemy/Phrasea/Model/Manipulator/LazaretManipulator.php index 8e0b0d1553..fff97be4bd 100644 --- a/lib/Alchemy/Phrasea/Model/Manipulator/LazaretManipulator.php +++ b/lib/Alchemy/Phrasea/Model/Manipulator/LazaretManipulator.php @@ -147,7 +147,8 @@ class LazaretManipulator $this->app, $lazaretFile->getOriginalName() ); - } catch (\Exception $e) { + } + catch(\Exception $e) { // the file is not in tmp anymore ? // delete the quarantine item $this->denyLazaretFile($lazaretFile); @@ -196,6 +197,7 @@ class LazaretManipulator case AttributeInterface::NAME_METADATA: /** @var Metadata $value */ $value = $attribute->getValue(); + // $metadataBag->set($value->getTag()->getTagname(), new Metadata($value->getTag(), $value->getValue())); $metadataBag->set($value->getTag()->getTagname(), $value); break; case AttributeInterface::NAME_STORY: diff --git a/lib/Alchemy/Phrasea/Model/Manipulator/UserManipulator.php b/lib/Alchemy/Phrasea/Model/Manipulator/UserManipulator.php index adfebb6f4f..21fca40d6d 100644 --- a/lib/Alchemy/Phrasea/Model/Manipulator/UserManipulator.php +++ b/lib/Alchemy/Phrasea/Model/Manipulator/UserManipulator.php @@ -35,21 +35,52 @@ use Alchemy\Phrasea\Core\Event\User\DeletedEvent; */ class UserManipulator implements ManipulatorInterface { - /** @var PasswordEncoderInterface */ + /** + * @var PasswordEncoderInterface + */ protected $passwordEncoder; - /** @var UserManager */ + + /** + * @var UserManager + */ private $manager; - /** @var GeonamesConnector */ + + /** + * @var GeonamesConnector + */ private $geonamesConnector; - /** @var Generator */ + + /** + * @var Generator + */ private $generator; - /** @var EntityRepository */ + + /** + * @var EntityRepository + */ private $repository; - /** @var EventDispatcherInterface */ + + /** + * @var EventDispatcherInterface + */ private $dispatcher; - - public function __construct(UserManager $manager, PasswordEncoderInterface $passwordEncoder, GeonamesConnector $connector, EntityRepository $repo, Generator $generator, EventDispatcherInterface $dispatcher) + /** + * @param UserManager $manager + * @param PasswordEncoderInterface $passwordEncoder + * @param GeonamesConnector $connector + * @param EntityRepository $repo + * @param Generator $generator + * @param EventDispatcherInterface $dispatcher + */ + public function __construct( + UserManager $manager, + PasswordEncoderInterface $passwordEncoder, + GeonamesConnector $connector, + EntityRepository $repo, + Generator $generator, + EventDispatcherInterface $dispatcher + ) { $this->manager = $manager; $this->generator = $generator; diff --git a/lib/Alchemy/Phrasea/Model/Manipulator/WebhookEventManipulator.php b/lib/Alchemy/Phrasea/Model/Manipulator/WebhookEventManipulator.php index 9fe2c59779..40e7f812a7 100644 --- a/lib/Alchemy/Phrasea/Model/Manipulator/WebhookEventManipulator.php +++ b/lib/Alchemy/Phrasea/Model/Manipulator/WebhookEventManipulator.php @@ -12,29 +12,46 @@ namespace Alchemy\Phrasea\Model\Manipulator; use Alchemy\Phrasea\Model\Entities\WebhookEvent; +use Alchemy\Phrasea\Webhook\WebhookPublisher; use Doctrine\Common\Persistence\ObjectManager; use Doctrine\ORM\EntityRepository; class WebhookEventManipulator implements ManipulatorInterface { + /** + * @var ObjectManager + */ private $om; + + /** + * @var EntityRepository + */ private $repository; - public function __construct(ObjectManager $om, EntityRepository $repo) + /** + * @var WebhookPublisher + */ + private $publisher; + + public function __construct(ObjectManager $om, EntityRepository $repo, WebhookPublisher $publisher) { $this->om = $om; $this->repository = $repo; + $this->publisher = $publisher; } public function create($eventName, $type, array $data) { $event = new WebhookEvent(); + $event->setName($eventName); $event->setType($type); $event->setData($data); $this->update($event); + $this->publisher->publishWebhookEvent($event); + return $event; } diff --git a/lib/Alchemy/Phrasea/Model/Repositories/WebhookEventDeliveryRepository.php b/lib/Alchemy/Phrasea/Model/Repositories/WebhookEventDeliveryRepository.php index e8e965be01..f162a12ff3 100644 --- a/lib/Alchemy/Phrasea/Model/Repositories/WebhookEventDeliveryRepository.php +++ b/lib/Alchemy/Phrasea/Model/Repositories/WebhookEventDeliveryRepository.php @@ -11,6 +11,7 @@ namespace Alchemy\Phrasea\Model\Repositories; +use Alchemy\Phrasea\Model\Entities\ApiApplication; use Alchemy\Phrasea\Model\Entities\WebhookEventDelivery; use Doctrine\ORM\EntityRepository; @@ -22,6 +23,10 @@ use Doctrine\ORM\EntityRepository; */ class WebhookEventDeliveryRepository extends EntityRepository { + + /** + * @return WebhookEventDelivery[] + */ public function findUndeliveredEvents() { $qb = $this->createQueryBuilder('e'); @@ -34,4 +39,22 @@ class WebhookEventDeliveryRepository extends EntityRepository return $qb->getQuery()->getResult(); } + + /** + * @param ApiApplication $apiApplication + * @param int $count + * @return WebhookEventDelivery[] + */ + public function findLastDeliveries(ApiApplication $apiApplication, $count = 10) + { + $qb = $this->createQueryBuilder('e'); + + $qb + ->where('e.application = :app') + ->setMaxResults(max(0, (int) $count)) + ->orderBy('e.created', 'DESC') + ->setParameters([ 'app' => $apiApplication ]); + + return $qb->getQuery()->getResult(); + } } diff --git a/lib/Alchemy/Phrasea/Model/Repositories/WebhookEventPayloadRepository.php b/lib/Alchemy/Phrasea/Model/Repositories/WebhookEventPayloadRepository.php new file mode 100644 index 0000000000..1b3c028454 --- /dev/null +++ b/lib/Alchemy/Phrasea/Model/Repositories/WebhookEventPayloadRepository.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Alchemy\Phrasea\Model\Repositories; + +use Alchemy\Phrasea\Model\Entities\WebhookEventPayload; +use Doctrine\ORM\EntityRepository; + +class WebhookEventPayloadRepository extends EntityRepository +{ + + public function save(WebhookEventPayload $payload) + { + $this->_em->persist($payload); + $this->_em->persist($payload->getDelivery()); + + $this->_em->flush([ $payload, $payload->getDelivery() ]); + } +} diff --git a/lib/Alchemy/Phrasea/Order/Controller/ApiOrderController.php b/lib/Alchemy/Phrasea/Order/Controller/ApiOrderController.php index 61c6a2172f..5c81b9fb0e 100644 --- a/lib/Alchemy/Phrasea/Order/Controller/ApiOrderController.php +++ b/lib/Alchemy/Phrasea/Order/Controller/ApiOrderController.php @@ -242,7 +242,7 @@ class ApiOrderController extends BaseOrderController $filtered = []; foreach ($records as $index => $record) { - if ($acl->has_right_on_base($record->getBaseId(), 'cancmd')) { + if (!$record->isStory() && $acl->has_right_on_base($record->getBaseId(), 'cancmd')) { $filtered[$index] = $record; } } diff --git a/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticSearchEngine.php b/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticSearchEngine.php index a7064561f6..a90e433a1f 100644 --- a/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticSearchEngine.php +++ b/lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticSearchEngine.php @@ -287,7 +287,6 @@ class ElasticSearchEngine implements SearchEngineInterface } $aggs = $this->getAggregationQueryParams($options); - if ($aggs) { $params['body']['aggs'] = $aggs; } diff --git a/lib/Alchemy/Phrasea/SearchEngine/Elastic/Indexer.php b/lib/Alchemy/Phrasea/SearchEngine/Elastic/Indexer.php index 48396902de..2b28ca5d82 100644 --- a/lib/Alchemy/Phrasea/SearchEngine/Elastic/Indexer.php +++ b/lib/Alchemy/Phrasea/SearchEngine/Elastic/Indexer.php @@ -139,6 +139,8 @@ class Indexer // everything ready to search $bulk->flush(); $this->client->indices()->refresh(); + $this->client->indices()->clearCache(); + $this->client->indices()->flushSynced(); } if ($what & self::RECORDS) { diff --git a/lib/Alchemy/Phrasea/SearchEngine/Elastic/Indexer/Record/Hydrator/ThesaurusHydrator.php b/lib/Alchemy/Phrasea/SearchEngine/Elastic/Indexer/Record/Hydrator/ThesaurusHydrator.php index 66b6d2cc6d..4107285ac2 100644 --- a/lib/Alchemy/Phrasea/SearchEngine/Elastic/Indexer/Record/Hydrator/ThesaurusHydrator.php +++ b/lib/Alchemy/Phrasea/SearchEngine/Elastic/Indexer/Record/Hydrator/ThesaurusHydrator.php @@ -78,7 +78,9 @@ class ThesaurusHydrator implements HydratorInterface } } } - + if(empty($terms)) { + return; + } $bulk = $this->thesaurus->findConceptsBulk($terms, null, $filters, true); foreach ($bulk as $offset => $item_concepts) { diff --git a/lib/Alchemy/Phrasea/SearchEngine/Elastic/Thesaurus.php b/lib/Alchemy/Phrasea/SearchEngine/Elastic/Thesaurus.php index 85f99fa1d8..51942b5c28 100644 --- a/lib/Alchemy/Phrasea/SearchEngine/Elastic/Thesaurus.php +++ b/lib/Alchemy/Phrasea/SearchEngine/Elastic/Thesaurus.php @@ -79,19 +79,138 @@ class Thesaurus * @return Concept[] Matching concepts */ public function findConcepts($term, $lang = null, Filter $filter = null, $strict = false) + { + return $strict ? + $this->findConceptsStrict($term, $lang, $filter) + : + $this->findConceptsFuzzy($term, $lang, $filter) + ; + } + + private function findConceptsStrict($term, $lang = null, Filter $filter = null) { if (!($term instanceof TermInterface)) { $term = new Term($term); } $this->logger->info(sprintf('Searching for term %s', $term), array( - 'strict' => $strict, + 'strict' => true, 'lang' => $lang )); - if ($strict) { - $field_suffix = '.strict'; - } elseif ($lang) { + $must = []; + $filters = []; + + $must[] = [ + 'match' => [ + 'value.strict' => [ + 'query' => $term->getValue(), + 'operator' => 'and', + ], + ], + ]; + if ($term->hasContext()) { + $must[] = [ + 'match' => [ + 'context.strict' => [ + 'query' => $term->getContext(), + 'operator' => 'and', + ], + ], + ]; + } else { + $filters[] = [ + 'missing' => [ + 'field' => 'context' + ] + ]; + } + if ($lang) { + $filters[] = [ + 'term' => [ + 'lang' => $lang + ] + ]; + } + if ($filter) { + $filters = array_merge($filters, $filter->getQueryFilters()); + } + if(!empty($filters)) { + if (count($filters) > 1) { + $must[] = [ + 'constant_score' => [ + 'filter' => [ + 'and' => $filters + ] + ] + ]; + } + else { + $must[] = [ + 'constant_score' => [ + 'filter' => $filters[0] + ] + ]; + } + } + + if(count($must) > 1) { + $query = [ + 'bool' => [ + 'must' => $must + ] + ]; + } + else { + $query = $must[0]; + } + + // Path deduplication + $aggs = array(); + $aggs['dedup']['terms']['field'] = 'path.raw'; + + // Search request + $params = array(); + $params['index'] = $this->options->getIndexName(); + $params['type'] = TermIndexer::TYPE_NAME; + $params['body']['query'] = $query; + $params['body']['aggs'] = $aggs; + // No need to get any hits since we extract data from aggs + $params['body']['size'] = 0; + + $this->logger->debug('Sending search', $params['body']); + $response = $this->client->search($params); + + // Extract concept paths from response + $concepts = array(); + $buckets = \igorw\get_in($response, ['aggregations', 'dedup', 'buckets'], []); + $keys = array(); + foreach ($buckets as $bucket) { + if (isset($bucket['key'])) { + $keys[] = $bucket['key']; + $concepts[] = new Concept($bucket['key']); + } + } + + $this->logger->info(sprintf('Found %d matching concepts', count($concepts)), + array('concepts' => $keys) + ); + + return $concepts; + } + + private function findConceptsFuzzy($term, $lang = null, Filter $filter = null) + { + if (!($term instanceof TermInterface)) { + $term = new Term($term); + } + + $this->logger->info(sprintf('Searching for term %s', $term), array( + 'strict' => false, + 'lang' => $lang + )); + + if($lang) { $field_suffix = sprintf('.%s', $lang); } else { $field_suffix = ''; @@ -114,10 +233,6 @@ class Thesaurus $query = array(); $query['bool']['must'][0] = $value_query; $query['bool']['must'][1] = $context_query; - } elseif ($strict) { - $context_filter = array(); - $context_filter['missing']['field'] = 'context'; - $query = self::applyQueryFilter($query, $context_filter); } if ($lang) { diff --git a/lib/Alchemy/Phrasea/SearchEngine/Elastic/Thesaurus/Filter.php b/lib/Alchemy/Phrasea/SearchEngine/Elastic/Thesaurus/Filter.php index 7e24307a83..f8ac7030e5 100644 --- a/lib/Alchemy/Phrasea/SearchEngine/Elastic/Thesaurus/Filter.php +++ b/lib/Alchemy/Phrasea/SearchEngine/Elastic/Thesaurus/Filter.php @@ -46,4 +46,34 @@ class Filter return $filter; } + + public function getQueryFilters() + { + $filters = [ + [ + 'term' => [ + 'databox_id' => $this->databox_id + ] + ] + ]; + if(!empty($this->paths)) { + if (count($this->paths) == 1) { + $filters[] = [ + 'term' => [ + 'path' => $this->paths[0] + ] + ]; + } + else { + $filters[] = [ + 'terms' => [ + 'path' => $this->paths + ] + ]; + } + } + + return $filters; + } + } diff --git a/lib/Alchemy/Phrasea/SearchEngine/SearchEngineOptions.php b/lib/Alchemy/Phrasea/SearchEngine/SearchEngineOptions.php index 77bfecd071..eae2a6b225 100644 --- a/lib/Alchemy/Phrasea/SearchEngine/SearchEngineOptions.php +++ b/lib/Alchemy/Phrasea/SearchEngine/SearchEngineOptions.php @@ -130,7 +130,7 @@ class SearchEngineOptions /** @var string */ protected $record_type = self::TYPE_ALL; - protected $search_type = self::RECORD_RECORD; + protected $search_type = self::RECORD_RECORD; /** @var \collection[] */ protected $collections = []; /** @var null|\databox[] */ diff --git a/lib/Alchemy/Phrasea/Setup/DoctrineMigrations/Version20161013115559.php b/lib/Alchemy/Phrasea/Setup/DoctrineMigrations/Version20161013115559.php new file mode 100644 index 0000000000..0877e87c90 --- /dev/null +++ b/lib/Alchemy/Phrasea/Setup/DoctrineMigrations/Version20161013115559.php @@ -0,0 +1,40 @@ +tableExists('Orders'); + } + + /** + * @param Schema $schema + */ + public function doUpSql(Schema $schema) + { + // this up() migration is auto-generated, please modify it to your needs + $this->abortIf($this->connection->getDatabasePlatform()->getName() != 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + + $this->addSql("CREATE TABLE WebhookEventPayloads (id CHAR(36) NOT NULL COMMENT '(DC2Type:guid)', delivery_id INT DEFAULT NULL, request LONGTEXT NOT NULL, response LONGTEXT NOT NULL, status INT NOT NULL, headers LONGTEXT NOT NULL, UNIQUE INDEX UNIQ_B949629612136921 (delivery_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB;"); + $this->addSql("ALTER TABLE WebhookEventPayloads ADD CONSTRAINT FK_B949629612136921 FOREIGN KEY (delivery_id) REFERENCES WebhookEventDeliveries (id);"); + } + + /** + * @param Schema $schema + */ + public function doDownSql(Schema $schema) + { + // this down() migration is auto-generated, please modify it to your needs + $this->abortIf($this->connection->getDatabasePlatform()->getName() != 'mysql', 'Migration can only be executed safely on \'mysql\'.'); + + $this->addSql('DROP TABLE WebhookEventPayloads'); + } +} diff --git a/lib/Alchemy/Phrasea/TaskManager/Job/WebhookJob.php b/lib/Alchemy/Phrasea/TaskManager/Job/WebhookJob.php index 8d56af93d1..dbe4d7bd41 100644 --- a/lib/Alchemy/Phrasea/TaskManager/Job/WebhookJob.php +++ b/lib/Alchemy/Phrasea/TaskManager/Job/WebhookJob.php @@ -12,21 +12,11 @@ namespace Alchemy\Phrasea\TaskManager\Job; use Alchemy\Phrasea\Core\Version; -use Alchemy\Phrasea\Model\Entities\WebhookEvent; -use Alchemy\Phrasea\Model\Entities\WebhookEventDelivery; -use Alchemy\Phrasea\Model\Entities\ApiApplication; use Alchemy\Phrasea\TaskManager\Editor\DefaultEditor; use Alchemy\Phrasea\Webhook\EventProcessorFactory; use Guzzle\Http\Client as GuzzleClient; -use Guzzle\Batch\BatchBuilder; -use Guzzle\Http\Message\Request; -use Silex\Application; -use Guzzle\Common\Event; -use Guzzle\Plugin\Backoff\BackoffPlugin; -use Guzzle\Plugin\Backoff\TruncatedBackoffStrategy; -use Guzzle\Plugin\Backoff\CallbackBackoffStrategy; -use Guzzle\Plugin\Backoff\CurlBackoffStrategy; use Psr\Log\LoggerInterface; +use Silex\Application; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Translation\TranslatorInterface; @@ -34,15 +24,12 @@ class WebhookJob extends AbstractJob { private $httpClient; - private $firstRun = true; - public function __construct( TranslatorInterface $translator, EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null, GuzzleClient $httpClient = null - ) - { + ) { parent::__construct($translator, $dispatcher, $logger); $this->httpClient = $httpClient ?: new GuzzleClient(); @@ -89,57 +76,6 @@ class WebhookJob extends AbstractJob { $app = $data->getApplication(); $thirdPartyApplications = $app['repo.api-applications']->findWithDefinedWebhookCallback(); - $that = $this; - - if ($this->firstRun) { - $this->httpClient->getEventDispatcher()->addListener('request.error', function (Event $event) { - // override guzzle default behavior of throwing exceptions - // when 4xx & 5xx responses are encountered - $event->stopPropagation(); - }, -254); - - // Set callback which logs success or failure - $subscriber = new CallbackBackoffStrategy(function ($retries, Request $request, $response, $e) use ($app, $that) { - $retry = true; - if ($response && (null !== $deliverId = parse_url($request->getUrl(), PHP_URL_FRAGMENT))) { - $delivery = $app['repo.webhook-delivery']->find($deliverId); - - $logContext = [ 'host' => $request->getHost() ]; - - if ($response->isSuccessful()) { - $app['manipulator.webhook-delivery']->deliverySuccess($delivery); - - $logType = 'info'; - $logEntry = sprintf('Deliver success event "%d:%s" for app "%s"', - $delivery->getWebhookEvent()->getId(), $delivery->getWebhookEvent()->getName(), - $delivery->getThirdPartyApplication()->getName() - ); - - $retry = false; - } else { - $app['manipulator.webhook-delivery']->deliveryFailure($delivery); - - $logType = 'error'; - $logEntry = sprintf('Deliver failure event "%d:%s" for app "%s"', - $delivery->getWebhookEvent()->getId(), $delivery->getWebhookEvent()->getName(), - $delivery->getThirdPartyApplication()->getName() - ); - } - - $that->log($logType, $logEntry, $logContext); - - return $retry; - } - }, true, new CurlBackoffStrategy()); - - // set max retries - $subscriber = new TruncatedBackoffStrategy(WebhookEventDelivery::MAX_DELIVERY_TRIES, $subscriber); - $subscriber = new BackoffPlugin($subscriber); - - $this->httpClient->addSubscriber($subscriber); - - $this->firstRun = false; - } /** @var EventProcessorFactory $eventFactory */ $eventFactory = $app['webhook.processor_factory']; @@ -155,41 +91,4 @@ class WebhookJob extends AbstractJob $this->deliverEvent($eventFactory, $app, $thirdPartyApplications, $event); } } - - private function deliverEvent(EventProcessorFactory $eventFactory, Application $app, array $thirdPartyApplications, WebhookEvent $event) - { - if (count($thirdPartyApplications) === 0) { - $this->log('info', sprintf('No applications defined to listen for webhook events')); - - return; - } - - // format event data - $eventProcessor = $eventFactory->get($event); - $data = $eventProcessor->process($event); - - // batch requests - $batch = BatchBuilder::factory() - ->transferRequests(10) - ->build(); - - foreach ($thirdPartyApplications as $thirdPartyApplication) { - $delivery = $app['manipulator.webhook-delivery']->create($thirdPartyApplication, $event); - - // append delivery id as url anchor - $uniqueUrl = $this->getUrl($thirdPartyApplication, $delivery); - - // create http request with data as request body - $batch->add($this->httpClient->createRequest('POST', $uniqueUrl, [ - 'Content-Type' => 'application/vnd.phraseanet.event+json' - ], json_encode($data))); - } - - $batch->flush(); - } - - private function getUrl(ApiApplication $application, WebhookEventDelivery $delivery) - { - return sprintf('%s#%s', $application->getWebhookUrl(), $delivery->getId()); - } } diff --git a/lib/Alchemy/Phrasea/Webhook/EventProcessorFactory.php b/lib/Alchemy/Phrasea/Webhook/EventProcessorFactory.php index 06e3e3379f..a48cbdfd74 100644 --- a/lib/Alchemy/Phrasea/Webhook/EventProcessorFactory.php +++ b/lib/Alchemy/Phrasea/Webhook/EventProcessorFactory.php @@ -16,7 +16,7 @@ class EventProcessorFactory { /** - * @var ProcessorFactory + * @var ProcessorFactory[] */ private $processorFactories = []; @@ -59,10 +59,20 @@ class EventProcessorFactory /** * @param WebhookEvent $event * @return Processor\ProcessorInterface + * @deprecated Use getProcessor() instead */ public function get(WebhookEvent $event) { - if (! isset($this->processorFactories[$event->getType()])) { + return $this->getProcessor($event); + } + + /** + * @param WebhookEvent $event + * @return ProcessorInterface + */ + public function getProcessor(WebhookEvent $event) + { + if (!isset($this->processorFactories[$event->getType()])) { throw new \RuntimeException(sprintf('No processor found for %s', $event->getType())); } diff --git a/lib/Alchemy/Phrasea/Webhook/EventProcessorWorker.php b/lib/Alchemy/Phrasea/Webhook/EventProcessorWorker.php new file mode 100644 index 0000000000..be78a8e5ad --- /dev/null +++ b/lib/Alchemy/Phrasea/Webhook/EventProcessorWorker.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Alchemy\Phrasea\Webhook; + +use Alchemy\Phrasea\Model\Entities\WebhookEvent; +use Alchemy\Phrasea\Model\Repositories\WebhookEventRepository; +use Alchemy\Worker\Worker; + +class EventProcessorWorker implements Worker +{ + + /** + * @var WebhookEventRepository + */ + private $eventRepository; + + /** + * @var WebhookInvoker + */ + private $invoker; + + /** + * @param WebhookEventRepository $eventRepository + * @param WebhookInvoker $invoke + */ + public function __construct(WebhookEventRepository $eventRepository, WebhookInvoker $invoke) + { + $this->eventRepository = $eventRepository; + $this->invoker = $invoke; + } + + /** + * @param array $payload + * @return void + */ + public function process(array $payload) + { + $eventId = $payload['id']; + /** @var WebhookEvent $event */ + $event = $this->eventRepository->find($eventId); + + if ($event === null || $event->isProcessed()) { + return; + } + + $this->invoker->invoke($event); + } +} diff --git a/lib/Alchemy/Phrasea/Webhook/WebhookInvoker.php b/lib/Alchemy/Phrasea/Webhook/WebhookInvoker.php new file mode 100644 index 0000000000..3a2935a87a --- /dev/null +++ b/lib/Alchemy/Phrasea/Webhook/WebhookInvoker.php @@ -0,0 +1,292 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Alchemy\Phrasea\Webhook; + +use Alchemy\Phrasea\Model\Entities\ApiApplication; +use Alchemy\Phrasea\Model\Entities\WebhookEvent; +use Alchemy\Phrasea\Model\Entities\WebhookEventDelivery; +use Alchemy\Phrasea\Model\Entities\WebhookEventPayload; +use Alchemy\Phrasea\Model\Manipulator\WebhookEventDeliveryManipulator; +use Alchemy\Phrasea\Model\Manipulator\WebhookEventManipulator; +use Alchemy\Phrasea\Model\Repositories\ApiApplicationRepository; +use Alchemy\Phrasea\Model\Repositories\WebhookEventDeliveryRepository; +use Alchemy\Phrasea\Model\Repositories\WebhookEventPayloadRepository; +use Alchemy\Phrasea\Model\Repositories\WebhookEventRepository; +use Guzzle\Common\Event; +use Guzzle\Http\Client; +use Guzzle\Http\Message\EntityEnclosingRequestInterface; +use Guzzle\Http\Message\Request; +use Guzzle\Http\Message\Response; +use Guzzle\Plugin\Backoff\BackoffPlugin; +use Guzzle\Plugin\Backoff\CallbackBackoffStrategy; +use Guzzle\Plugin\Backoff\CurlBackoffStrategy; +use Guzzle\Plugin\Backoff\TruncatedBackoffStrategy; +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerInterface; +use Psr\Log\NullLogger; + +/** + * Class WebhookInvoker invokes remote endpoints with webhook event data + * @package Alchemy\Phrasea\Webhook + */ +class WebhookInvoker implements LoggerAwareInterface +{ + + /** + * @var ApiApplicationRepository + */ + private $applicationRepository; + + /** + * @var WebhookEventDeliveryManipulator + */ + private $eventDeliveryManipulator; + + /** + * @var WebhookEventDeliveryRepository + */ + private $eventDeliveryRepository; + + /** + * @var Client + */ + private $client; + + /** + * @var LoggerInterface + */ + private $logger; + + /** + * @var EventProcessorFactory + */ + private $processorFactory; + + /** + * @var WebhookEventRepository + */ + private $eventRepository; + + /** + * @var WebhookEventManipulator + */ + private $eventManipulator; + + /** + * @var WebhookEventPayloadRepository + */ + private $eventPayloadRepository; + + /** + * @param ApiApplicationRepository $applicationRepository + * @param EventProcessorFactory $processorFactory + * @param WebhookEventRepository $eventRepository + * @param WebhookEventManipulator $eventManipulator + * @param WebhookEventDeliveryRepository $eventDeliveryRepository + * @param WebhookEventDeliveryManipulator $eventDeliveryManipulator + * @param WebhookEventPayloadRepository $eventPayloadRepository + * @param Client $client + * + * @todo Extract classes to reduce number of required dependencies + */ + public function __construct( + ApiApplicationRepository $applicationRepository, + EventProcessorFactory $processorFactory, + WebhookEventRepository $eventRepository, + WebhookEventManipulator $eventManipulator, + WebhookEventDeliveryRepository $eventDeliveryRepository, + WebhookEventDeliveryManipulator $eventDeliveryManipulator, + WebhookEventPayloadRepository $eventPayloadRepository, + Client $client = null + ) { + $this->applicationRepository = $applicationRepository; + $this->processorFactory = $processorFactory; + $this->eventRepository = $eventRepository; + $this->eventManipulator = $eventManipulator; + $this->eventDeliveryManipulator = $eventDeliveryManipulator; + $this->eventDeliveryRepository = $eventDeliveryRepository; + $this->eventPayloadRepository = $eventPayloadRepository; + + $this->client = $client ?: new Client(); + $this->logger = new NullLogger(); + + $this->configureClient(); + } + + /** + * Sets a logger instance on the object. + * + * @param LoggerInterface $logger + * + * @return null + */ + public function setLogger(LoggerInterface $logger) + { + $this->logger = $logger; + } + + public function invoke(WebhookEvent $event) + { + $this->doInvoke($event, $this->applicationRepository->findWithDefinedWebhookCallback()); + } + + public function invokeUnprocessedEvents() + { + $targetApplications = $this->applicationRepository->findWithDefinedWebhookCallback(); + + foreach ($this->eventRepository->getUnprocessedEventIterator() as $row) { + /** @var WebhookEvent $event */ + $event = $row[0]; + + $this->doInvoke($event, $targetApplications); + } + } + + /** + * @param WebhookEvent $event + * @param ApiApplication[] $targets + */ + private function doInvoke(WebhookEvent $event, array $targets) + { + $this->eventManipulator->processed($event); + $this->logger->info(sprintf('Processing event "%s" with id %d', $event->getName(), $event->getId())); + + // send requests + $this->doHttpDelivery($event, $targets); + } + + private function configureClient() + { + $this->client->getEventDispatcher()->addListener('request.error', function (Event $event) { + // Override guzzle default behavior of throwing exceptions + // when 4xx & 5xx responses are encountered + $event->stopPropagation(); + }, -254); + + // Set callback which logs success or failure + $subscriber = new CallbackBackoffStrategy(function ($retries, Request $request, $response, $e) { + $retry = true; + if ($response && (null !== $deliverId = parse_url($request->getUrl(), PHP_URL_FRAGMENT))) { + $delivery = $this->eventDeliveryRepository->find($deliverId); + + $logContext = ['host' => $request->getHost()]; + + if ($response->isSuccessful()) { + $this->eventDeliveryManipulator->deliverySuccess($delivery); + + $logType = 'info'; + $logEntry = sprintf('Deliver success event "%d:%s" for app "%s"', + $delivery->getWebhookEvent()->getId(), $delivery->getWebhookEvent()->getName(), + $delivery->getThirdPartyApplication()->getName() + ); + + $retry = false; + } else { + $this->eventDeliveryManipulator->deliveryFailure($delivery); + + $logType = 'error'; + $logEntry = sprintf('Deliver failure event "%d:%s" for app "%s"', + $delivery->getWebhookEvent()->getId(), $delivery->getWebhookEvent()->getName(), + $delivery->getThirdPartyApplication()->getName() + ); + } + + $this->logger->log($logType, $logEntry, $logContext); + + return $retry; + } + }, true, new CurlBackoffStrategy()); + + // Set max retries + $subscriber = new TruncatedBackoffStrategy(WebhookEventDelivery::MAX_DELIVERY_TRIES, $subscriber); + $subscriber = new BackoffPlugin($subscriber); + + $this->client->addSubscriber($subscriber); + } + + /** + * @param WebhookEvent $event + * @param ApiApplication[] $targets + */ + private function doHttpDelivery( + WebhookEvent $event, + array $targets + ) { + if (count($targets) === 0) { + $this->logger->info(sprintf('No applications defined to listen for webhook events')); + + return; + } + + // Format event data + $eventProcessor = $this->processorFactory->getProcessor($event); + $data = $eventProcessor->process($event); + + foreach ($targets as $thirdPartyApplication) { + $delivery = $this->eventDeliveryManipulator->create($thirdPartyApplication, $event); + // Append delivery id as url anchor + $uniqueUrl = $this->buildUrl($thirdPartyApplication, $delivery); + + // Create http request with data as request body + $request = $this->client->createRequest('POST', $uniqueUrl, [ + 'Content-Type' => 'application/vnd.phraseanet.event+json' + ], json_encode($data)); + + $requestBody = $request instanceof EntityEnclosingRequestInterface ? $request->getBody() : ''; + + try { + $response = $request->send(); + + $responseBody = $response->getBody(true); + $statusCode = $response->getStatusCode(); + $headers = $this->extractResponseHeaders($response); + } + catch (\Exception $exception) { + $responseBody = $exception->getMessage(); + $statusCode = -1; + $headers = ''; + } + + $deliveryPayload = new WebhookEventPayload( + $delivery, + $requestBody, + $responseBody, + $statusCode, + $headers + ); + + $this->eventPayloadRepository->save($deliveryPayload); + } + } + + /** + * @param ApiApplication $application + * @param WebhookEventDelivery $delivery + * @return string + */ + private function buildUrl(ApiApplication $application, WebhookEventDelivery $delivery) + { + return sprintf('%s#%s', $application->getWebhookUrl(), $delivery->getId()); + } + + private function extractResponseHeaders(Response $response) + { + $headerCollection = $response->getHeaders()->toArray(); + $headers = ''; + + foreach ($headerCollection as $name => $value) { + $headers .= sprintf('%s: %s', $name, $value) . PHP_EOL; + } + + return trim($headers); + } +} diff --git a/lib/Alchemy/Phrasea/Webhook/WebhookPublisher.php b/lib/Alchemy/Phrasea/Webhook/WebhookPublisher.php new file mode 100644 index 0000000000..4304a5319f --- /dev/null +++ b/lib/Alchemy/Phrasea/Webhook/WebhookPublisher.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Alchemy\Phrasea\Webhook; + +use Alchemy\Phrasea\Model\Entities\WebhookEvent; +use Alchemy\Queue\Message; +use Alchemy\Queue\MessageQueueRegistry; + +/** + * Class WebhookPublisher publishes webhook event notifications in message queues + * @package Alchemy\Phrasea\Webhook + */ +class WebhookPublisher +{ + /** + * @var MessageQueueRegistry + */ + private $queueRegistry; + + /** + * @var string + */ + private $queueName; + + /** + * @param MessageQueueRegistry $queueRegistry + * @param $queueName + */ + public function __construct(MessageQueueRegistry $queueRegistry, $queueName) + { + $this->queueRegistry = $queueRegistry; + $this->queueName = $queueName; + } + + /** + * @param WebhookEvent $event + */ + public function publishWebhookEvent(WebhookEvent $event) + { + $queue = $this->queueRegistry->getQueue($this->queueName); + $payload = [ + 'message_type' => 'webhook', + 'payload' => [ 'id' => $event->getId() ] + ]; + + $queue->publish(new Message(json_encode($payload))); + } +} diff --git a/lib/classes/API/Webhook.php b/lib/classes/API/Webhook.php deleted file mode 100644 index 8d347a9322..0000000000 --- a/lib/classes/API/Webhook.php +++ /dev/null @@ -1,95 +0,0 @@ -appbox = $appbox; - $this->id = $id; - $sql = 'SELECT `type`, `data`, created - FROM api_webhooks - WHERE id = :id'; - $stmt = $this->appbox->get_connection()->prepare($sql); - $stmt->execute([':id' => $id]); - $row = $stmt->fetch(\PDO::FETCH_ASSOC); - - if (!$row) { - throw new RuntimeException('Webhooks not found'); - } - - $stmt->closeCursor(); - - $this->type = $row['type']; - $this->data = json_decode($row['data']); - $this->created = new \DateTime($row['created']); - } - - public function delete() - { - $sql = 'DELETE FROM api_webhooks WHERE id = :id'; - - $stmt = $this->appbox->get_connection()->prepare($sql); - $stmt->execute([':id' => $this->id]); - $stmt->closeCursor(); - - return; - } - - public static function create(appbox $appbox, $type, array $data) - { - $sql = 'INSERT INTO api_webhooks (id, `type`, `data`, created) - VALUES (null, :type, :data, NOW())'; - - $stmt = $appbox->get_connection()->prepare($sql); - $stmt->execute([ - 'type' => $type, - 'data' => json_encode($data), - ]); - $stmt->closeCursor(); - - return new API_Webhook($appbox, $appbox->get_connection()->lastInsertId()); - } - - /** - * @return \DateTime - */ - public function getCreated() - { - return $this->created; - } - - /** - * @return mixed - */ - public function getData() - { - return $this->data; - } - - /** - * @return mixed - */ - public function getType() - { - return $this->type; - } -} diff --git a/lib/classes/Bridge/Api/Dailymotion.php b/lib/classes/Bridge/Api/Dailymotion.php index aefa57cd42..acc2fae8ff 100644 --- a/lib/classes/Bridge/Api/Dailymotion.php +++ b/lib/classes/Bridge/Api/Dailymotion.php @@ -523,22 +523,16 @@ class Bridge_Api_Dailymotion extends Bridge_Api_Abstract implements Bridge_Api_I switch ($connector_status) { case self::UPLOAD_STATE_DELETED: return $this->translator->trans('La video a ete supprimee'); - break; case self::UPLOAD_STATE_REJECTED: return $this->translator->trans('La video a ete rejetee'); - break; case self::UPLOAD_STATE_ENCODING_ERROR: return $this->translator->trans('Erreur d\'encodage'); - break; case self::UPLOAD_STATE_PROCESSING: return $this->translator->trans('En cours d\'encodage'); - break; default: return ''; - break; case self::UPLOAD_STATE_DONE: return $this->translator->trans('OK'); - break; } } diff --git a/lib/classes/Bridge/Api/Flickr.php b/lib/classes/Bridge/Api/Flickr.php index 7d51eba91d..bfb74ee5c9 100644 --- a/lib/classes/Bridge/Api/Flickr.php +++ b/lib/classes/Bridge/Api/Flickr.php @@ -484,11 +484,9 @@ class Bridge_Api_Flickr extends Bridge_Api_Abstract implements Bridge_Api_Interf switch ($connector_status) { case self::UPLOAD_STATE_FAILED: return $this->translator->trans('L\'upload a echoue'); - break; default: case self::UPLOAD_STATE_DONE: return ''; - break; } } diff --git a/lib/classes/databox.php b/lib/classes/databox.php index 9e8c32ad33..b9e82c00c5 100644 --- a/lib/classes/databox.php +++ b/lib/classes/databox.php @@ -17,6 +17,7 @@ use Alchemy\Phrasea\Core\Thumbnail\ThumbnailedElement; use Alchemy\Phrasea\Core\Version\DataboxVersionRepository; use Alchemy\Phrasea\Databox\DataboxRepository; use Alchemy\Phrasea\Databox\Record\RecordRepository; +use Alchemy\Phrasea\Databox\SubdefGroup; use Alchemy\Phrasea\Exception\InvalidArgumentException; use Alchemy\Phrasea\Model\Entities\User; use Alchemy\Phrasea\Status\StatusStructure; @@ -450,8 +451,9 @@ class databox extends base implements ThumbnailedElement $multi = isset($field['multi']) ? (Boolean) (string) $field['multi'] : false; - $meta_struct_field = databox_field::create($this->app, $this, $fname, $multi); + $meta_struct_field = databox_field::create($this->app, $this, $fname); $meta_struct_field + ->set_multi($multi) ->set_readonly(isset($field['readonly']) ? (string) $field['readonly'] : 0) ->set_indexable(isset($field['index']) ? (string) $field['index'] : '1') ->set_separator(isset($field['separator']) ? (string) $field['separator'] : '') @@ -892,7 +894,7 @@ class databox extends base implements ThumbnailedElement } /** - * @return databox_subdefsStructure|\Alchemy\Phrasea\Databox\SubdefGroup[]|databox_subdef[][] + * @return databox_subdefsStructure|SubdefGroup[] */ public function get_subdef_structure() { diff --git a/lib/classes/databox/field.php b/lib/classes/databox/field.php index 4e4eb70970..2cbdc9679b 100644 --- a/lib/classes/databox/field.php +++ b/lib/classes/databox/field.php @@ -564,6 +564,18 @@ class databox_field implements cache_cacheableInterface return $this; } + /** + * + * @param boolean $bool + * @return databox_field + */ + public function set_multi($bool) + { + $this->multi = (bool)$bool; + $this->separator = self::checkMultiSeparator($this->separator, $this->multi); + return $this; + } + /** * Set a vocabulary * @@ -892,7 +904,7 @@ class databox_field implements cache_cacheableInterface * * @throws \Exception_InvalidArgument */ - public static function create(Application $app, databox $databox, $name, $multi) + public static function create(Application $app, databox $databox, $name) { $sorter = 0; @@ -911,8 +923,8 @@ class databox_field implements cache_cacheableInterface `thumbtitle`, `multi`, `business`, `aggregable`, `report`, `sorter`, `separator`) VALUES (null, :name, '', 0, 0, 1, 'string', '', - null, :multi, - 0, 0, 1, :sorter, '')"; + null, 0, 0, 0, + 1, :sorter, '')"; $name = self::generateName($name); @@ -920,10 +932,8 @@ class databox_field implements cache_cacheableInterface throw new \Exception_InvalidArgument(); } - $multi = $multi ? 1 : 0; - $stmt = $databox->get_connection()->prepare($sql); - $stmt->execute([':name' => $name, ':sorter' => $sorter, ':multi' => $multi]); + $stmt->execute([':name' => $name, ':sorter' => $sorter]); $id = $databox->get_connection()->lastInsertId(); $stmt->closeCursor(); diff --git a/lib/classes/databox/subdef.php b/lib/classes/databox/subdef.php index e64ca7fb08..78dda05862 100644 --- a/lib/classes/databox/subdef.php +++ b/lib/classes/databox/subdef.php @@ -1,5 +1,4 @@ [SubdefSpecs::TYPE_IMAGE, SubdefSpecs::TYPE_AUDIO], + SubdefType::TYPE_DOCUMENT => [SubdefSpecs::TYPE_IMAGE, SubdefSpecs::TYPE_FLEXPAPER], + SubdefType::TYPE_FLASH => [SubdefSpecs::TYPE_IMAGE], + SubdefType::TYPE_IMAGE => [SubdefSpecs::TYPE_IMAGE], + SubdefType::TYPE_VIDEO => [SubdefSpecs::TYPE_IMAGE, SubdefSpecs::TYPE_VIDEO, SubdefSpecs::TYPE_ANIMATION], + ]; + /** * The class type of the subdef * Is null or one of the CLASS_* constants @@ -33,37 +51,23 @@ class databox_subdef protected $path; protected $subdef_group; protected $labels = []; + protected $downloadable; + protected $translator; /** * @var bool */ private $requiresMetadataUpdate; - protected $downloadable; - protected $translator; - protected static $mediaTypeToSubdefTypes = [ - SubdefType::TYPE_AUDIO => [SubdefSpecs::TYPE_IMAGE, SubdefSpecs::TYPE_AUDIO], - SubdefType::TYPE_DOCUMENT => [SubdefSpecs::TYPE_IMAGE, SubdefSpecs::TYPE_FLEXPAPER], - SubdefType::TYPE_FLASH => [SubdefSpecs::TYPE_IMAGE], - SubdefType::TYPE_IMAGE => [SubdefSpecs::TYPE_IMAGE], - SubdefType::TYPE_VIDEO => [SubdefSpecs::TYPE_IMAGE, SubdefSpecs::TYPE_VIDEO, SubdefSpecs::TYPE_ANIMATION], - ]; - - const CLASS_THUMBNAIL = 'thumbnail'; - const CLASS_PREVIEW = 'preview'; - const CLASS_DOCUMENT = 'document'; - const DEVICE_ALL = 'all'; - const DEVICE_HANDHELD = 'handheld'; - const DEVICE_PRINT = 'print'; - const DEVICE_PROJECTION = 'projection'; - const DEVICE_SCREEN = 'screen'; - const DEVICE_TV = 'tv'; /** - * - * @param SubdefType $type + * @var bool + */ + private $orderable; + + /** + * @param SubdefType $type * @param SimpleXMLElement $sd - * - * @return databox_subdef + * @param TranslatorInterface $translator */ public function __construct(SubdefType $type, SimpleXMLElement $sd, TranslatorInterface $translator) { @@ -77,6 +81,7 @@ class databox_subdef $this->name = strtolower($sd->attributes()->name); $this->downloadable = p4field::isyes($sd->attributes()->downloadable); + $this->orderable = isset($sd->attributes()->orderable) ? p4field::isyes($sd->attributes()->orderable) : true; $this->path = trim($sd->path) !== '' ? p4string::addEndSlash(trim($sd->path)) : ''; $this->requiresMetadataUpdate = p4field::isyes((string) $sd->meta); @@ -110,7 +115,130 @@ class databox_subdef } /** + * Build Image Subdef object depending the SimpleXMLElement * + * @param SimpleXMLElement $sd + * @return Image + */ + protected function buildImageSubdef(SimpleXMLElement $sd) + { + $image = new Image($this->translator); + + if ($sd->icodec) { + $image->setOptionValue(Image::OPTION_ICODEC, (string) $sd->icodec); + } + if ($sd->size) { + $image->setOptionValue(Image::OPTION_SIZE, (int) $sd->size); + } + if ($sd->quality) { + $image->setOptionValue(Image::OPTION_QUALITY, (int) $sd->quality); + } + if ($sd->strip) { + $image->setOptionValue(Image::OPTION_STRIP, p4field::isyes($sd->strip)); + } + if ($sd->dpi) { + $image->setOptionValue(Image::OPTION_RESOLUTION, (int) $sd->dpi); + } + if ($sd->flatten) { + $image->setOptionValue(Image::OPTION_FLATTEN, p4field::isyes($sd->flatten)); + } + + return $image; + } + + /** + * Build Audio Subdef object depending the SimpleXMLElement + * + * @param SimpleXMLElement $sd + * @return Audio + */ + protected function buildAudioSubdef(SimpleXMLElement $sd) + { + $audio = new Audio($this->translator); + + if ($sd->acodec) { + $audio->setOptionValue(Audio::OPTION_ACODEC, (string) $sd->acodec); + } + if ($sd->audiobitrate) { + $audio->setOptionValue(Audio::OPTION_AUDIOBITRATE, (int) $sd->audiobitrate); + } + if ($sd->audiosamplerate) { + $audio->setOptionValue(Audio::OPTION_AUDIOSAMPLERATE, (int) $sd->audiosamplerate); + } + + return $audio; + } + + /** + * Build Video Subdef object depending the SimpleXMLElement + * + * @param SimpleXMLElement $sd + * @return Video + */ + protected function buildVideoSubdef(SimpleXMLElement $sd) + { + $video = new Video($this->translator); + + if ($sd->size) { + $video->setOptionValue(Video::OPTION_SIZE, (int) $sd->size); + } + if ($sd->acodec) { + $video->setOptionValue(Video::OPTION_ACODEC, (string) $sd->acodec); + } + if ($sd->vcodec) { + $video->setOptionValue(Video::OPTION_VCODEC, (string) $sd->vcodec); + } + if ($sd->fps) { + $video->setOptionValue(Video::OPTION_FRAMERATE, (int) $sd->fps); + } + if ($sd->bitrate) { + $video->setOptionValue(Video::OPTION_BITRATE, (int) $sd->bitrate); + } + if ($sd->audiobitrate) { + $video->setOptionValue(Video::OPTION_AUDIOBITRATE, (int) $sd->audiobitrate); + } + if ($sd->audiosamplerate) { + $video->setOptionValue(Video::OPTION_AUDIOSAMPLERATE, (int) $sd->audiosamplerate); + } + if ($sd->GOPsize) { + $video->setOptionValue(Video::OPTION_GOPSIZE, (int) $sd->GOPsize); + } + + return $video; + } + + /** + * Build GIF Subdef object depending the SimpleXMLElement + * + * @param SimpleXMLElement $sd + * @return Gif + */ + protected function buildGifSubdef(SimpleXMLElement $sd) + { + $gif = new Gif($this->translator); + + if ($sd->size) { + $gif->setOptionValue(Gif::OPTION_SIZE, (int) $sd->size); + } + if ($sd->delay) { + $gif->setOptionValue(Gif::OPTION_DELAY, (int) $sd->delay); + } + + return $gif; + } + + /** + * Build Flexpaper Subdef object depending the SimpleXMLElement + * + * @param SimpleXMLElement $sd + * @return FlexPaper + */ + protected function buildFlexPaperSubdef(SimpleXMLElement $sd) + { + return new FlexPaper($this->translator); + } + + /** * @return string */ public function get_class() @@ -119,7 +247,6 @@ class databox_subdef } /** - * * @return string */ public function get_path() @@ -130,7 +257,7 @@ class databox_subdef /** * The devices matching this subdefinition * - * @return Array + * @return array */ public function getDevices() { @@ -140,7 +267,7 @@ class databox_subdef /** * The current SubdefType the subdef converts documents * - * @return Alchemy\Phrasea\Media\Subdef\Subdef + * @return \Alchemy\Phrasea\Media\Subdef\Subdef */ public function getSubdefType() { @@ -160,7 +287,7 @@ class databox_subdef /** * An associative label ; keys are i18n languages * - * @return Array + * @return array */ public function get_labels() { @@ -179,15 +306,31 @@ class databox_subdef } /** - * boolean + * The name of the subdef * - * @return type + * @return string */ - public function is_downloadable() + public function get_name() + { + return $this->name; + } + + /** + * @return bool + */ + public function isDownloadable() { return $this->downloadable; } + /** + * @return bool + */ + public function isOrderable() + { + return $this->orderable; + } + /** * Get an array of Alchemy\Phrasea\Media\Subdef\Subdef available for the current Media Type * @@ -254,16 +397,6 @@ class databox_subdef return $this->requiresMetadataUpdate; } - /** - * The name of the subdef - * - * @return string - */ - public function get_name() - { - return $this->name; - } - /** * Get the MediaAlchemyst specs for the current subdef * @@ -283,128 +416,4 @@ class databox_subdef { return $this->subdef_type->getOptions(); } - - /** - * Build Image Subdef object depending the SimpleXMLElement - * - * @param SimpleXMLElement $sd - * @return Image - */ - protected function buildImageSubdef(SimpleXMLElement $sd) - { - $image = new Image($this->translator); - - if ($sd->icodec) { - $image->setOptionValue(Image::OPTION_ICODEC, (string) $sd->icodec); - } - if ($sd->size) { - $image->setOptionValue(Image::OPTION_SIZE, (int) $sd->size); - } - if ($sd->quality) { - $image->setOptionValue(Image::OPTION_QUALITY, (int) $sd->quality); - } - if ($sd->strip) { - $image->setOptionValue(Image::OPTION_STRIP, p4field::isyes($sd->strip)); - } - if ($sd->dpi) { - $image->setOptionValue(Image::OPTION_RESOLUTION, (int) $sd->dpi); - } - if ($sd->flatten) { - $image->setOptionValue(Image::OPTION_FLATTEN, p4field::isyes($sd->flatten)); - } - - return $image; - } - - /** - * Build Audio Subdef object depending the SimpleXMLElement - * - * @param SimpleXMLElement $sd - * @return Audio - */ - protected function buildAudioSubdef(SimpleXMLElement $sd) - { - $audio = new Audio($this->translator); - - if ($sd->acodec) { - $audio->setOptionValue(Audio::OPTION_ACODEC, (string) $sd->acodec); - } - if ($sd->audiobitrate) { - $audio->setOptionValue(Audio::OPTION_AUDIOBITRATE, (int) $sd->audiobitrate); - } - if ($sd->audiosamplerate) { - $audio->setOptionValue(Audio::OPTION_AUDIOSAMPLERATE, (int) $sd->audiosamplerate); - } - - return $audio; - } - - /** - * Build Flexpaper Subdef object depending the SimpleXMLElement - * - * @param SimpleXMLElement $sd - * @return \Alchemy\Phrasea\Media\Subdef\Video - */ - protected function buildFlexPaperSubdef(SimpleXMLElement $sd) - { - return new FlexPaper($this->translator); - } - - /** - * Build GIF Subdef object depending the SimpleXMLElement - * - * @param SimpleXMLElement $sd - * @return Gif - */ - protected function buildGifSubdef(SimpleXMLElement $sd) - { - $gif = new Gif($this->translator); - - if ($sd->size) { - $gif->setOptionValue(Gif::OPTION_SIZE, (int) $sd->size); - } - if ($sd->delay) { - $gif->setOptionValue(Gif::OPTION_DELAY, (int) $sd->delay); - } - - return $gif; - } - - /** - * Build Video Subdef object depending the SimpleXMLElement - * - * @param SimpleXMLElement $sd - * @return Video - */ - protected function buildVideoSubdef(SimpleXMLElement $sd) - { - $video = new Video($this->translator); - - if ($sd->size) { - $video->setOptionValue(Video::OPTION_SIZE, (int) $sd->size); - } - if ($sd->acodec) { - $video->setOptionValue(Video::OPTION_ACODEC, (string) $sd->acodec); - } - if ($sd->vcodec) { - $video->setOptionValue(Video::OPTION_VCODEC, (string) $sd->vcodec); - } - if ($sd->fps) { - $video->setOptionValue(Video::OPTION_FRAMERATE, (int) $sd->fps); - } - if ($sd->bitrate) { - $video->setOptionValue(Video::OPTION_BITRATE, (int) $sd->bitrate); - } - if ($sd->audiobitrate) { - $video->setOptionValue(Video::OPTION_AUDIOBITRATE, (int) $sd->audiobitrate); - } - if ($sd->audiosamplerate) { - $video->setOptionValue(Video::OPTION_AUDIOSAMPLERATE, (int) $sd->audiosamplerate); - } - if ($sd->GOPsize) { - $video->setOptionValue(Video::OPTION_GOPSIZE, (int) $sd->GOPsize); - } - - return $video; - } } diff --git a/lib/classes/databox/subdefsStructure.php b/lib/classes/databox/subdefsStructure.php index 1135f8a613..1f856f5bf3 100644 --- a/lib/classes/databox/subdefsStructure.php +++ b/lib/classes/databox/subdefsStructure.php @@ -10,6 +10,7 @@ use Alchemy\Phrasea\Databox\SubdefGroup; use Alchemy\Phrasea\Media\MediaTypeFactory; +use Assert\Assertion; use Symfony\Component\Translation\TranslatorInterface; class databox_subdefsStructure implements IteratorAggregate, Countable @@ -215,6 +216,25 @@ class databox_subdefsStructure implements IteratorAggregate, Countable return $this; } + /** + * @param SubdefGroup[] $groups + */ + public function updateSubdefGroups($groups) + { + Assertion::allIsInstanceOf($groups, SubdefGroup::class); + + $dom_xp = $this->databox->get_xpath_structure(); + + foreach ($groups as $group) { + $nodes = $dom_xp->query('//record/subdefs/subdefgroup[@name="' . $group->getName() . '"]'); + + /** @var DOMElement $node */ + foreach ($nodes as $node) { + $node->setAttribute('document_orderable', ($group->isDocumentOrderable() ? 'true' : 'false')); + } + } + } + /** * @param string $group * @param string $name @@ -222,10 +242,11 @@ class databox_subdefsStructure implements IteratorAggregate, Countable * @param boolean $downloadable * @param array $options * @param array $labels + * @param bool $orderable * @return databox_subdefsStructure * @throws Exception */ - public function set_subdef($group, $name, $class, $downloadable, $options, $labels) + public function set_subdef($group, $name, $class, $downloadable, $options, $labels, $orderable = true) { $dom_struct = $this->databox->get_dom_structure(); @@ -233,6 +254,7 @@ class databox_subdefsStructure implements IteratorAggregate, Countable $subdef->setAttribute('class', $class); $subdef->setAttribute('name', mb_strtolower($name)); $subdef->setAttribute('downloadable', ($downloadable ? 'true' : 'false')); + $subdef->setAttribute('orderable', ($orderable ? 'true' : 'false')); foreach ($labels as $code => $label) { $child = $dom_struct->createElement('label'); diff --git a/lib/classes/eventsmanager/broker.php b/lib/classes/eventsmanager/broker.php index c7d9601bdc..55d974d6b1 100644 --- a/lib/classes/eventsmanager/broker.php +++ b/lib/classes/eventsmanager/broker.php @@ -165,7 +165,7 @@ class eventsmanager_broker } if (((int) $page + 1) * $n < $total) { - $data['next'] = '' . $this->app->trans('charger d\'avantages de notifications') . ''; + $data['next'] = '' . $this->app->trans('charger d\'avantages de notifications') . ''; } return $data; diff --git a/lib/classes/eventsmanager/notify/push.php b/lib/classes/eventsmanager/notify/push.php index 2bb3fbeb85..367ab499cb 100644 --- a/lib/classes/eventsmanager/notify/push.php +++ b/lib/classes/eventsmanager/notify/push.php @@ -39,8 +39,11 @@ class eventsmanager_notify_push extends eventsmanager_notifyAbstract $sender = $user->getDisplayName(); $ret = [ - 'text' => $this->app->trans('%user% vous a envoye un %before_link% panier %after_link%', ['%user%' => $sender, '%before_link%' => '', '%after_link%' => '']) + 'text' => $this->app->trans('%user% vous a envoye un %before_link% panier %after_link%', ['%user%' => $sender, '%before_link%' => '', '%after_link%' => '']) , 'class' => ($unread == 1 ? 'reload_baskets' : '') ]; diff --git a/lib/classes/eventsmanager/notify/validationreminder.php b/lib/classes/eventsmanager/notify/validationreminder.php index f80bd29d8e..aab62e4b83 100644 --- a/lib/classes/eventsmanager/notify/validationreminder.php +++ b/lib/classes/eventsmanager/notify/validationreminder.php @@ -53,8 +53,7 @@ class eventsmanager_notify_validationreminder extends eventsmanager_notifyAbstra $basket_name = $this->app->trans('Une selection'); } - $bask_link = '' + $bask_link = '' . $basket_name . ''; $ret = [ diff --git a/lib/classes/p4field.php b/lib/classes/p4field.php index f3a65d5bf1..c27ca2ea88 100644 --- a/lib/classes/p4field.php +++ b/lib/classes/p4field.php @@ -1,9 +1,8 @@ isMetadataUpdateRequired() ? 'yes' : 'no'; $options['devices'] = [databox_subdef::DEVICE_SCREEN]; - $root->set_subdef($groupname, $subdef->get_name(), $subdef->get_class(), $subdef->is_downloadable(), $options, []); + $root->set_subdef($groupname, $subdef->get_name(), $subdef->get_class(), $subdef->isDownloadable(), $options, []); } protected function addMobileSubdefVideo($root, $baseSubdef, $groupname) diff --git a/lib/classes/patch/390alpha13a.php b/lib/classes/patch/390alpha13a.php index 3b96e50b46..6b6a3a054b 100644 --- a/lib/classes/patch/390alpha13a.php +++ b/lib/classes/patch/390alpha13a.php @@ -77,7 +77,7 @@ class patch_390alpha13a implements patchInterface foreach ($rs as $row) { try { - $user = $em->createQuery('SELECT PARTIAL u.{id} FROM Phraseanet:User s WHERE u.id = :id') + $user = $em->createQuery('SELECT PARTIAL u.{id} FROM Phraseanet:User u WHERE u.id = :id') ->setParameters(['id' => $row['usr_id']]) ->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true) ->getSingleResult(); diff --git a/lib/classes/patch/390alpha6a.php b/lib/classes/patch/390alpha6a.php index c558bc6b3a..19fa31685d 100644 --- a/lib/classes/patch/390alpha6a.php +++ b/lib/classes/patch/390alpha6a.php @@ -122,18 +122,18 @@ class patch_390alpha6a extends patchAbstract $stmt->execute(['export_id' => $row['id']]); $rs = $stmt->fetchAll(\PDO::FETCH_ASSOC); - foreach ($rs as $element) { + foreach ($rs as $element_row) { $element = new FtpExportElement(); - $element->setBaseId($row['base_id']) - ->setRecordId($row['record_id']) - ->setBusinessfields($row['businessfields']) + $element->setBaseId($element_row['base_id']) + ->setRecordId($element_row['record_id']) + ->setBusinessfields($element_row['businessfields']) ->setCreated(new \DateTime($row['date'])) ->setUpdated(new \DateTime($row['date'])) - ->setDone(!!$row['done']) - ->setError(!!$row['error']) - ->setFilename($row['filename']) - ->setFolder($row['folder']) - ->setSubdef($row['subdef']) + ->setDone(!!$element_row['done']) + ->setError(!!$element_row['error']) + ->setFilename($element_row['filename']) + ->setFolder($element_row['folder']) + ->setSubdef($element_row['subdef']) ->setExport($export); $export->addElement($element); diff --git a/lib/classes/queries.php b/lib/classes/queries.php deleted file mode 100644 index bec526933c..0000000000 --- a/lib/classes/queries.php +++ /dev/null @@ -1,286 +0,0 @@ -display->css; - } - - $out .= ''; - - $out .='
-
'; - - if ($sxTopics) { - $defaultview = mb_strtolower($sxTopics->display->defaultview); - if ( ! $defaultview) - $defaultview = 'static'; - $out .= ( "\n"); - } - - $out .= '
-
'; - - return $out; - } - - public static function topics_exists($I18n) - { - if (file_exists(__DIR__ . '/../../config/topics/topics_' . $I18n . '.xml')) { - return true; - } - - if (file_exists(__DIR__ . '/../../config/topics/topics.xml')) { - return true; - } - - return false; - } - - public static function dropdown_topics(TranslatorInterface $translator, $I18n) - { - $out = ''; - - $xmlTopics = ''; - $sxTopics = null; - - if (file_exists(__DIR__ . '/../../config/topics/topics_' . $I18n . '.xml')) - $xmlTopics = __DIR__ . '/../../config/topics/topics_' . $I18n . '.xml'; - - if ($xmlTopics == '') { - if (file_exists(__DIR__ . '/../../config/topics/topics.xml')) { - $xmlTopics = __DIR__ . '/../../config/topics/topics.xml'; - } - } - - if ($xmlTopics == '') { - return ''; - } - - $jsTopics = 'null'; - $maxdepth = 0; - if (false !== $sxTopics = simplexml_load_file($xmlTopics)) { - $jsTopics = self::topicsAsJS($sxTopics->topics, 0, $maxdepth); - } - - $out .= ' '; - - $out .= '
-
-
- - - - -
' . $translator->trans('boutton::chercher') . ' : -
- ' . $translator->trans('client::recherche: dans les categories') . '
'; - - for ($i = 0; $i <= $maxdepth; $i ++) { - $out .= '

- -

'; - } - $out .= '
- -
-
-
-
- '; - - return $out; - } - - public static function history(Application $app, $usrId) - { - $history = '