PHRAS-1304_AUTO-COMPLETION_MASTER (#2061)

* PHRAS-1304_AUTO-COMPLETION_MASTER
ported from 4.0

* PHRAS-1304_AUTO-COMPLETION_MASTER
fix

* PHRAS-1304_AUTO-COMPLETION_MASTER
fix

* PHRAS-1304_AUTO-COMPLETION_MASTER
bump php version to 5.5.31 (5.5.21 is obsolete in cicleci)

* PHRAS-1304_AUTO-COMPLETION_MASTER
bump php version to 5.5.31 : php.ini moved in circelci

* PHRAS-1304_AUTO-COMPLETION_MASTER
add zmq & date to php for circleci

* PHRAS-1304_AUTO-COMPLETION_MASTER
add zmq

* PHRAS-1304_AUTO-COMPLETION_MASTER
bump amqp

* PHRAS-1304_AUTO-COMPLETION_MASTER
downgrade amqp to 1.2 to test compilation against old librabbit 0.4 (ubuntu)

* PHRAS-1304_AUTO-COMPLETION_MASTER
add amqp.so to php.ini, (re)bump amqp to 1.6

* PHRAS-1304_AUTO-COMPLETION_MASTER
build rabittmq from git

* PHRAS-1304_AUTO-COMPLETION_MASTER
build rabittmq from git again

* PHRAS-1304_AUTO-COMPLETION_MASTER
build rabittmq from git again and again

* PHRAS-1304_AUTO-COMPLETION_MASTER
fix test on media rotation 600*400 -> 400*599 !!!

* PHRAS-1304_AUTO-COMPLETION_MASTER
restore facebook sdk to 4.0.1 due to mistake

* PHRAS-1304_AUTO-COMPLETION_MASTER
deleted unwanted file
This commit is contained in:
jygaulier
2017-02-06 18:26:56 +01:00
committed by GitHub
parent cefb2f99f4
commit a70bf2fc70
69 changed files with 1032 additions and 593 deletions

View File

@@ -7,7 +7,7 @@ general:
machine:
php:
version: 5.5.21
version: 5.5.31
node:
version: stable
services:
@@ -22,12 +22,17 @@ dependencies:
- node_modules
- ~/.composer
pre:
- sudo apt-get install librabbitmq-dev
- pecl install amqp-1.4.0
- git clone https://github.com/alanxz/rabbitmq-c
- cd rabbitmq-c && git submodule init && git submodule update && autoreconf -i && ./configure && make && sudo make install
- pecl install amqp-1.6.0
- yes '' | pecl install imagick
- pecl install json
- sudo apt-get install libzmq-dev
- yes '' | pecl install zmq-beta
- sed -i 's/^\(session.cache_limiter = \).*/\1""/' ~/.phpenv/versions/$(phpenv global)/etc/php.ini
- echo "extension = amqp.so" > /opt/circleci/php/$(phpenv global)/etc/conf.d/amqp.ini
- echo "extension = zmq.so" > /opt/circleci/php/$(phpenv global)/etc/conf.d/zmq.ini
- echo "date.timezone = UTC" > /opt/circleci/php/$(phpenv global)/etc/conf.d/timezone.ini
- sed -i 's/^\(session.cache_limiter = \).*/\1""/' /opt/circleci/php/$(phpenv global)/etc/php.ini
- npm rebuild node-sass
override:
- composer install --no-progress --no-interaction --optimize-autoloader

View File

@@ -96,7 +96,7 @@
"simple-bus/serialization": "^2.0",
"sorien/silex-dbal-profiler": "^1.1",
"sorien/silex-pimple-dumper": "^1.0",
"swiftmailer/swiftmailer": "~5.3.0",
"swiftmailer/swiftmailer": "~5.4.5",
"symfony/symfony": "~2.7.10|~2.8.3",
"themattharris/tmhoauth": "~0.7",
"twig/extensions": "^1.2.0",

249
composer.lock generated
View File

@@ -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": "9a1955fa0102a16b25ee47148a6537a0",
"content-hash": "b19b6544330d38b28cc31554738bded3",
"hash": "bac58111d3666a1239ce66f4bfda46ff",
"content-hash": "03bc42658d3cfef4ce8fd202719e0713",
"packages": [
{
"name": "alchemy-fr/tcpdf-clone",
@@ -163,7 +163,11 @@
"Alchemy\\EmbedProvider\\": "src/Provider"
}
},
"notification-url": "https://packagist.org/downloads/",
"autoload-dev": {
"psr-4": {
"Alchemy\\EmbedBundle\\Tests\\": "tests/unit/Bundle"
}
},
"license": [
"MIT"
],
@@ -174,6 +178,10 @@
}
],
"description": "Embed resources bundle",
"support": {
"source": "https://github.com/alchemy-fr/embed-bundle/tree/v0.4.4",
"issues": "https://github.com/alchemy-fr/embed-bundle/issues"
},
"time": "2016-07-07 10:02:43"
},
{
@@ -963,16 +971,16 @@
},
{
"name": "beberlei/assert",
"version": "v2.6.8",
"version": "v2.7.3",
"source": {
"type": "git",
"url": "https://github.com/beberlei/assert.git",
"reference": "848c8f0bde97b48d1e159075e20a6667583f3978"
"reference": "5972776d6a9eedfd3c55216341434e19cb50418f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/beberlei/assert/zipball/848c8f0bde97b48d1e159075e20a6667583f3978",
"reference": "848c8f0bde97b48d1e159075e20a6667583f3978",
"url": "https://api.github.com/repos/beberlei/assert/zipball/5972776d6a9eedfd3c55216341434e19cb50418f",
"reference": "5972776d6a9eedfd3c55216341434e19cb50418f",
"shasum": ""
},
"require": {
@@ -1014,7 +1022,7 @@
"assertion",
"validation"
],
"time": "2016-12-05 11:33:17"
"time": "2017-01-24 15:14:39"
},
{
"name": "behat/transliterator",
@@ -1539,20 +1547,20 @@
},
{
"name": "doctrine/dbal",
"version": "v2.5.5",
"version": "v2.5.10",
"source": {
"type": "git",
"url": "https://github.com/doctrine/dbal.git",
"reference": "9f8c05cd5225a320d56d4bfdb4772f10d045a0c9"
"reference": "fc376f7a61498e18520cd6fa083752a4ca08072b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/dbal/zipball/9f8c05cd5225a320d56d4bfdb4772f10d045a0c9",
"reference": "9f8c05cd5225a320d56d4bfdb4772f10d045a0c9",
"url": "https://api.github.com/repos/doctrine/dbal/zipball/fc376f7a61498e18520cd6fa083752a4ca08072b",
"reference": "fc376f7a61498e18520cd6fa083752a4ca08072b",
"shasum": ""
},
"require": {
"doctrine/common": ">=2.4,<2.7-dev",
"doctrine/common": ">=2.4,<2.8-dev",
"php": ">=5.3.2"
},
"require-dev": {
@@ -1606,7 +1614,7 @@
"persistence",
"queryobject"
],
"time": "2016-09-09 19:13:33"
"time": "2017-01-23 23:17:10"
},
{
"name": "doctrine/inflector",
@@ -1785,16 +1793,16 @@
},
{
"name": "doctrine/migrations",
"version": "1.4.1",
"version": "v1.5.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/migrations.git",
"reference": "0d0ff5da10c5d30846da32060bd9e357abf70a05"
"reference": "c81147c0f2938a6566594455367e095150547f72"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/migrations/zipball/0d0ff5da10c5d30846da32060bd9e357abf70a05",
"reference": "0d0ff5da10c5d30846da32060bd9e357abf70a05",
"url": "https://api.github.com/repos/doctrine/migrations/zipball/c81147c0f2938a6566594455367e095150547f72",
"reference": "c81147c0f2938a6566594455367e095150547f72",
"shasum": ""
},
"require": {
@@ -1809,9 +1817,10 @@
"doctrine/orm": "2.*",
"jdorn/sql-formatter": "~1.1",
"johnkary/phpunit-speedtrap": "~1.0@dev",
"mikey179/vfsstream": "^1.6",
"mockery/mockery": "^0.9.4",
"phpunit/phpunit": "~4.7",
"satooshi/php-coveralls": "0.6.*"
"satooshi/php-coveralls": "^1.0"
},
"suggest": {
"jdorn/sql-formatter": "Allows to generate formatted SQL with the diff command."
@@ -1822,7 +1831,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "v1.5.x-dev"
"dev-master": "v1.6.x-dev"
}
},
"autoload": {
@@ -1854,26 +1863,26 @@
"database",
"migrations"
],
"time": "2016-03-14 12:29:11"
"time": "2016-12-25 22:54:00"
},
{
"name": "doctrine/orm",
"version": "v2.5.5",
"version": "v2.5.6",
"source": {
"type": "git",
"url": "https://github.com/doctrine/doctrine2.git",
"reference": "73e4be7c7b3ba26f96b781a40b33feba4dfa6d45"
"reference": "e6c434196c8ef058239aaa0724b4aadb0107940b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/doctrine2/zipball/73e4be7c7b3ba26f96b781a40b33feba4dfa6d45",
"reference": "73e4be7c7b3ba26f96b781a40b33feba4dfa6d45",
"url": "https://api.github.com/repos/doctrine/doctrine2/zipball/e6c434196c8ef058239aaa0724b4aadb0107940b",
"reference": "e6c434196c8ef058239aaa0724b4aadb0107940b",
"shasum": ""
},
"require": {
"doctrine/cache": "~1.4",
"doctrine/collections": "~1.2",
"doctrine/common": ">=2.5-dev,<2.7-dev",
"doctrine/common": ">=2.5-dev,<2.8-dev",
"doctrine/dbal": ">=2.5-dev,<2.6-dev",
"doctrine/instantiator": "~1.0.1",
"ext-pdo": "*",
@@ -1930,7 +1939,7 @@
"database",
"orm"
],
"time": "2016-09-10 18:51:13"
"time": "2016-12-18 15:42:34"
},
{
"name": "elasticsearch/elasticsearch",
@@ -2070,7 +2079,7 @@
"facebook",
"sdk"
],
"abandoned": "facebook/php-sdk-v4",
"abandoned": "facebook/graph-sdk",
"time": "2013-11-19 23:11:14"
},
{
@@ -3727,16 +3736,16 @@
},
{
"name": "league/flysystem",
"version": "1.0.32",
"version": "1.0.34",
"source": {
"type": "git",
"url": "https://github.com/thephpleague/flysystem.git",
"reference": "1b5c4a0031697f46e779a9d1b309c2e1b24daeab"
"reference": "469ad53c13ea19a0e54e3e5d70f61227ddcc0299"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/1b5c4a0031697f46e779a9d1b309c2e1b24daeab",
"reference": "1b5c4a0031697f46e779a9d1b309c2e1b24daeab",
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/469ad53c13ea19a0e54e3e5d70f61227ddcc0299",
"reference": "469ad53c13ea19a0e54e3e5d70f61227ddcc0299",
"shasum": ""
},
"require": {
@@ -3806,7 +3815,7 @@
"sftp",
"storage"
],
"time": "2016-10-19 20:38:46"
"time": "2017-01-30 17:41:17"
},
{
"name": "league/flysystem-aws-s3-v2",
@@ -4588,6 +4597,76 @@
],
"time": "2016-11-07 23:38:38"
},
{
"name": "php-amqplib/php-amqplib",
"version": "v2.6.3",
"source": {
"type": "git",
"url": "https://github.com/php-amqplib/php-amqplib.git",
"reference": "fa2f0d4410a11008cb36b379177291be7ee9e4f6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-amqplib/php-amqplib/zipball/fa2f0d4410a11008cb36b379177291be7ee9e4f6",
"reference": "fa2f0d4410a11008cb36b379177291be7ee9e4f6",
"shasum": ""
},
"require": {
"ext-bcmath": "*",
"ext-mbstring": "*",
"php": ">=5.3.0"
},
"replace": {
"videlalvaro/php-amqplib": "self.version"
},
"require-dev": {
"phpunit/phpunit": "^4.8",
"scrutinizer/ocular": "^1.1",
"squizlabs/php_codesniffer": "^2.5"
},
"suggest": {
"ext-sockets": "Use AMQPSocketConnection"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.7-dev"
}
},
"autoload": {
"psr-4": {
"PhpAmqpLib\\": "PhpAmqpLib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-2.1"
],
"authors": [
{
"name": "Alvaro Videla",
"role": "Original Maintainer"
},
{
"name": "John Kelly",
"email": "johnmkelly86@gmail.com",
"role": "Maintainer"
},
{
"name": "Raúl Araya",
"email": "nubeiro@gmail.com",
"role": "Maintainer"
}
],
"description": "Formerly videlalvaro/php-amqplib. This library is a pure PHP implementation of the AMQP protocol. It's been tested against RabbitMQ.",
"homepage": "https://github.com/php-amqplib/php-amqplib/",
"keywords": [
"message",
"queue",
"rabbitmq"
],
"time": "2016-04-11 14:30:01"
},
{
"name": "php-ffmpeg/php-ffmpeg",
"version": "0.5.1",
@@ -5118,27 +5197,22 @@
},
{
"name": "react/promise",
"version": "v2.4.1",
"version": "v2.5.0",
"source": {
"type": "git",
"url": "https://github.com/reactphp/promise.git",
"reference": "8025426794f1944de806618671d4fa476dc7626f"
"reference": "2760f3898b7e931aa71153852dcd48a75c9b95db"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/reactphp/promise/zipball/8025426794f1944de806618671d4fa476dc7626f",
"reference": "8025426794f1944de806618671d4fa476dc7626f",
"url": "https://api.github.com/repos/reactphp/promise/zipball/2760f3898b7e931aa71153852dcd48a75c9b95db",
"reference": "2760f3898b7e931aa71153852dcd48a75c9b95db",
"shasum": ""
},
"require": {
"php": ">=5.4.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0-dev"
}
},
"autoload": {
"psr-4": {
"React\\Promise\\": "src/"
@@ -5158,7 +5232,11 @@
}
],
"description": "A lightweight implementation of CommonJS Promises/A for PHP",
"time": "2016-05-03 17:50:52"
"keywords": [
"promise",
"promises"
],
"time": "2016-12-22 14:09:01"
},
{
"name": "roave/security-advisories",
@@ -5166,12 +5244,12 @@
"source": {
"type": "git",
"url": "https://github.com/Roave/SecurityAdvisories.git",
"reference": "3c25700b65ba5e34a5ec8fd05b5cdc7a68d9385a"
"reference": "3db4b0df21d1f527304650e717c66af48981f1c4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/3c25700b65ba5e34a5ec8fd05b5cdc7a68d9385a",
"reference": "3c25700b65ba5e34a5ec8fd05b5cdc7a68d9385a",
"url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/3db4b0df21d1f527304650e717c66af48981f1c4",
"reference": "3db4b0df21d1f527304650e717c66af48981f1c4",
"shasum": ""
},
"conflict": {
@@ -5212,18 +5290,19 @@
"namshi/jose": "<2.2",
"oro/crm": ">=1.7,<1.7.4",
"oro/platform": ">=1.7,<1.7.4",
"phpmailer/phpmailer": ">=5,<5.2.14",
"phpmailer/phpmailer": ">=5,<5.2.22",
"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",
"shopware/shopware": "<4.4|>=5,<5.2.15",
"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.3",
"silverstripe/userforms": "<3",
"simplesamlphp/saml2": ">=1.9,<1.9.1|>=1.10,<1.10.3|>=2.3,<2.3.3",
"simplesamlphp/simplesamlphp": "<1.14.4",
"simplesamlphp/saml2": "<1.8.1|>=1.9,<1.9.1|>=1.10,<1.10.3|>=2,<2.3.3",
"simplesamlphp/simplesamlphp": "<1.14.11",
"simplesamlphp/simplesamlphp-module-infocard": "<1.0.1",
"socalnick/scn-social-auth": "<1.15.2",
"swiftmailer/swiftmailer": ">=4,<4.99.99|>=5,<5.2.1",
"swiftmailer/swiftmailer": ">=4,<5.4.5",
"symfony/dependency-injection": ">=2,<2.0.17",
"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",
@@ -5242,7 +5321,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.29|>=8,<8.4.1|>=7,<7.6.13",
"typo3/cms": ">=6.2,<6.2.30|>=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",
@@ -5261,13 +5340,13 @@
"zendframework/zend-http": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.3,<2.3.8|>=2.4,<2.4.1",
"zendframework/zend-json": ">=2.1,<2.1.6|>=2.2,<2.2.6",
"zendframework/zend-ldap": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.2,<2.2.8|>=2.3,<2.3.3",
"zendframework/zend-mail": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.3,<2.3.8|>=2.4,<2.4.1",
"zendframework/zend-mail": ">=2,<2.4.11|>=2.5,<2.7.2",
"zendframework/zend-navigation": ">=2,<2.2.7|>=2.3,<2.3.1",
"zendframework/zend-session": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.2,<2.2.9|>=2.3,<2.3.4",
"zendframework/zend-validator": ">=2.3,<2.3.6",
"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/zendframework": ">=2,<2.4.11|>=2.5,<2.5.1",
"zendframework/zendframework1": "<1.12.20",
"zendframework/zendopenid": ">=2,<2.0.2",
"zendframework/zendxml": ">=1,<1.0.1",
@@ -5288,7 +5367,7 @@
}
],
"description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it",
"time": "2016-12-04 13:54:33"
"time": "2017-01-24 18:32:04"
},
{
"name": "seld/jsonlint",
@@ -5805,28 +5884,29 @@
},
{
"name": "swiftmailer/swiftmailer",
"version": "v5.3.1",
"version": "v5.4.5",
"source": {
"type": "git",
"url": "https://github.com/swiftmailer/swiftmailer.git",
"reference": "c5f963e7f9d6f6438fda4f22d5cc2db296ec621a"
"reference": "cd142238a339459b10da3d8234220963f392540c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/c5f963e7f9d6f6438fda4f22d5cc2db296ec621a",
"reference": "c5f963e7f9d6f6438fda4f22d5cc2db296ec621a",
"url": "https://api.github.com/repos/swiftmailer/swiftmailer/zipball/cd142238a339459b10da3d8234220963f392540c",
"reference": "cd142238a339459b10da3d8234220963f392540c",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"mockery/mockery": "~0.9.1"
"mockery/mockery": "~0.9.1",
"symfony/phpunit-bridge": "~3.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.3-dev"
"dev-master": "5.4-dev"
}
},
"autoload": {
@@ -5850,10 +5930,11 @@
"description": "Swiftmailer, free feature-rich PHP mailer",
"homepage": "http://swiftmailer.org",
"keywords": [
"email",
"mail",
"mailer"
],
"time": "2014-12-05 14:17:14"
"time": "2016-12-29 10:02:40"
},
{
"name": "symfony/polyfill-apcu",
@@ -6369,16 +6450,16 @@
},
{
"name": "symfony/symfony",
"version": "v2.8.14",
"version": "v2.8.16",
"source": {
"type": "git",
"url": "https://github.com/symfony/symfony.git",
"reference": "6ceca5b4154c80839270c38aa65373de76127df7"
"reference": "9fef72a3ab561c4bfa703a70369db028dec387d2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/symfony/zipball/6ceca5b4154c80839270c38aa65373de76127df7",
"reference": "6ceca5b4154c80839270c38aa65373de76127df7",
"url": "https://api.github.com/repos/symfony/symfony/zipball/9fef72a3ab561c4bfa703a70369db028dec387d2",
"reference": "9fef72a3ab561c4bfa703a70369db028dec387d2",
"shasum": ""
},
"require": {
@@ -6500,7 +6581,7 @@
"keywords": [
"framework"
],
"time": "2016-11-21 02:24:51"
"time": "2017-01-12 20:27:46"
},
{
"name": "themattharris/tmhoauth",
@@ -6598,16 +6679,16 @@
},
{
"name": "twig/twig",
"version": "v1.28.2",
"version": "v1.31.0",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
"reference": "b22ce0eb070e41f7cba65d78fe216de29726459c"
"reference": "ddc9e3e20ee9c0b6908f401ac8353635b750eca7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/b22ce0eb070e41f7cba65d78fe216de29726459c",
"reference": "b22ce0eb070e41f7cba65d78fe216de29726459c",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/ddc9e3e20ee9c0b6908f401ac8353635b750eca7",
"reference": "ddc9e3e20ee9c0b6908f401ac8353635b750eca7",
"shasum": ""
},
"require": {
@@ -6615,12 +6696,12 @@
},
"require-dev": {
"symfony/debug": "~2.7",
"symfony/phpunit-bridge": "~3.2@dev"
"symfony/phpunit-bridge": "~3.2"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.28-dev"
"dev-master": "1.31-dev"
}
},
"autoload": {
@@ -6655,7 +6736,7 @@
"keywords": [
"templating"
],
"time": "2016-11-23 18:41:40"
"time": "2017-01-11 19:36:15"
},
{
"name": "vierbergenlars/php-semver",
@@ -7551,16 +7632,16 @@
},
{
"name": "phpunit/phpunit",
"version": "4.8.30",
"version": "4.8.34",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "a534e04d0bd39c557c2881c341efd06fa6f1292a"
"reference": "7eb45205d27edd94bd2b3614085ea158bd1e2bca"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/a534e04d0bd39c557c2881c341efd06fa6f1292a",
"reference": "a534e04d0bd39c557c2881c341efd06fa6f1292a",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/7eb45205d27edd94bd2b3614085ea158bd1e2bca",
"reference": "7eb45205d27edd94bd2b3614085ea158bd1e2bca",
"shasum": ""
},
"require": {
@@ -7619,7 +7700,7 @@
"testing",
"xunit"
],
"time": "2016-12-01 17:05:48"
"time": "2017-01-26 16:15:36"
},
{
"name": "phpunit/phpunit-mock-objects",
@@ -7679,16 +7760,16 @@
},
{
"name": "sebastian/comparator",
"version": "1.2.2",
"version": "1.2.4",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/comparator.git",
"reference": "6a1ed12e8b2409076ab22e3897126211ff8b1f7f"
"reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/6a1ed12e8b2409076ab22e3897126211ff8b1f7f",
"reference": "6a1ed12e8b2409076ab22e3897126211ff8b1f7f",
"url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be",
"reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be",
"shasum": ""
},
"require": {
@@ -7739,7 +7820,7 @@
"compare",
"equality"
],
"time": "2016-11-19 09:18:40"
"time": "2017-01-29 09:50:25"
},
{
"name": "sebastian/diff",

View File

@@ -10,6 +10,7 @@
namespace Alchemy\Phrasea\Controller\Api;
use Alchemy\Phrasea\Collection\Reference\CollectionReference;
use Alchemy\Phrasea\Controller\Controller;
use Alchemy\Phrasea\Fractal\ArraySerializer;
use Alchemy\Phrasea\Model\Manipulator\UserManipulator;
@@ -60,15 +61,12 @@ class SearchController extends Controller
$this->getUserManipulator()->logQuery($this->getAuthenticatedUser(), $result->getUserQuery());
foreach ($options->getDataboxes() as $databox) {
$colls = array_map(function (\collection $collection) {
return $collection->get_coll_id();
}, array_filter($options->getCollections(), function (\collection $collection) use ($databox) {
return $collection->get_databox()->get_sbas_id() == $databox->get_sbas_id();
}));
$this->getSearchEngineLogger()
->log($databox, $result->getUserQuery(), $result->getTotal(), $colls);
// log array of collectionIds (from $options) for each databox
$collectionsReferencesByDatabox = $options->getCollectionsReferencesByDatabox();
foreach ($collectionsReferencesByDatabox as $sbid => $references) {
$databox = $this->findDataboxById($sbid);
$collectionsIds = array_map(function(CollectionReference $ref){return $ref->getCollectionId();}, $references);
$this->getSearchEngineLogger()->log($databox, $result->getUserQuery(), $result->getTotal(), $collectionsIds);
}
$this->getSearchEngine()->clearCache();

View File

@@ -26,6 +26,7 @@ use Alchemy\Phrasea\Border\File;
use Alchemy\Phrasea\Border\Manager;
use Alchemy\Phrasea\Border\Visa;
use Alchemy\Phrasea\Cache\Cache;
use Alchemy\Phrasea\Collection\Reference\CollectionReference;
use Alchemy\Phrasea\Controller\Controller;
use Alchemy\Phrasea\Core\Event\RecordEdit;
use Alchemy\Phrasea\Core\PhraseaEvents;
@@ -85,7 +86,6 @@ 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;
@@ -1500,15 +1500,12 @@ class V1Controller extends Controller
$this->getUserManipulator()->logQuery($this->getAuthenticatedUser(), $search_result->getUserQuery());
foreach ($options->getDataboxes() as $databox) {
$colls = array_map(function (\collection $collection) {
return $collection->get_coll_id();
}, array_filter($options->getCollections(), function (\collection $collection) use ($databox) {
return $collection->get_databox()->get_sbas_id() == $databox->get_sbas_id();
}));
$this->getSearchEngineLogger()
->log($databox, $search_result->getUserQuery(), $search_result->getTotal(), $colls);
// log array of collectionIds (from $options) for each databox
$collectionsReferencesByDatabox = $options->getCollectionsReferencesByDatabox();
foreach ($collectionsReferencesByDatabox as $sbid => $references) {
$databox = $this->findDataboxById($sbid);
$collectionsIds = array_map(function(CollectionReference $ref){return $ref->getCollectionId();}, $references);
$this->getSearchEngineLogger()->log($databox, $search_result->getUserQuery(), $search_result->getTotal(), $collectionsIds);
}
$this->getSearchEngine()->clearCache();

View File

@@ -1,20 +0,0 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2016 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Controller;
/**
* Class LazyLocator
* @package Alchemy\Phrasea\Controller
* @deprecated Use Alchemy\Phrasea\Core\LazyLocator
*/
class LazyLocator extends \Alchemy\Phrasea\Core\LazyLocator
{
// Stub left for BC
}

View File

@@ -12,18 +12,112 @@ namespace Alchemy\Phrasea\Controller\Prod;
use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Application\Helper\SearchEngineAware;
use Alchemy\Phrasea\Cache\Exception;
use Alchemy\Phrasea\Collection\Reference\CollectionReference;
use Alchemy\Phrasea\Controller\Controller;
use Alchemy\Phrasea\Core\Configuration\DisplaySettingService;
use Alchemy\Phrasea\SearchEngine\Elastic\Search\QueryContextFactory;
use Alchemy\Phrasea\SearchEngine\Elastic\Structure\Structure;
use Alchemy\Phrasea\SearchEngine\Elastic\ElasticSearchEngine;
use Alchemy\Phrasea\SearchEngine\Elastic\Structure\GlobalStructure;
use Alchemy\Phrasea\SearchEngine\SearchEngineOptions;
use Alchemy\Phrasea\SearchEngine\SearchEngineResult;
use Alchemy\Phrasea\Utilities\StringHelper;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use unicode;
class QueryController extends Controller
{
use SearchEngineAware;
public function completion(Request $request)
{
/** @var unicode $unicode */
$query = (string) $request->request->get('fake_qry');
$selStart = (int) $request->request->get('_selectionStart');
$selEnd = (int) $request->request->get('_selectionEnd');
// move the selection back to find the begining of the "word"
for(;;) {
$c = '';
if($selStart>0) {
$c = mb_substr($query, $selStart-1, 1);
}
if(in_array($c, ['', ' ', '"'])) {
break;
}
$selStart--;
}
// move the selection up to find the end of the "word"
for(;;) {
$c = mb_substr($query, $selEnd, 1);
if(in_array($c, ['', ' ', '"'])) {
break;
}
$selEnd++;
}
$before = mb_substr($query, 0, $selStart);
$word = mb_substr($query, $selStart, $selEnd-$selStart);
$after = mb_substr($query, $selEnd);
// since the query comes from a submited form, normalize crlf,cr,lf ...
$word = StringHelper::crlfNormalize($word);
$options = SearchEngineOptions::fromRequest($this->app, $request);
$search_engine_structure = GlobalStructure::createFromDataboxes(
$this->app->getDataboxes(),
Structure::WITH_EVERYTHING & ~(Structure::STRUCTURE_WITH_FLAGS | Structure::FIELD_WITH_FACETS | Structure::FIELD_WITH_THESAURUS)
);
$query_context_factory = new QueryContextFactory(
$search_engine_structure,
array_keys($this->app['locales.available']),
$this->app['locale']
);
$engine = new ElasticSearchEngine(
$this->app,
$search_engine_structure,
$this->app['elasticsearch.client'],
$query_context_factory,
$this->app['elasticsearch.facets_response.factory'],
$this->app['elasticsearch.options']
);
$autocomplete = $engine->autocomplete($word, $options);
$completions = [];
foreach($autocomplete['text'] as $text) {
$completions[] = [
'label' => $text,
'value' => [
'before' => $before,
'word' => $word,
'after' => $after,
'completion' => $text,
'completed' => $before . $text . $after
]
];
}
foreach($autocomplete['byField'] as $fieldName=>$values) {
foreach($values as $value) {
$completions[] = [
'label' => $value['query'],
'value' => [
'before' => $before,
'word' => $word,
'after' => $after,
'completion' => $value['query'],
'completed' => $before . $value['query'] . $after
]
];
}
}
return $this->app->json($completions);
}
/**
* Query Phraseanet to fetch records
*
@@ -68,14 +162,12 @@ class QueryController extends Controller
$userManipulator->setUserSetting($user, 'start_page_query', $query);
}
foreach ($options->getDataboxes() as $databox) {
$collections = array_map(function (\collection $collection) {
return $collection->get_coll_id();
}, array_filter($options->getCollections(), function (\collection $collection) use ($databox) {
return $collection->get_databox()->get_sbas_id() == $databox->get_sbas_id();
}));
$this->getSearchEngineLogger()->log($databox, $result->getUserQuery(), $result->getTotal(), $collections);
// log array of collectionIds (from $options) for each databox
$collectionsReferencesByDatabox = $options->getCollectionsReferencesByDatabox();
foreach ($collectionsReferencesByDatabox as $sbid => $references) {
$databox = $this->findDataboxById($sbid);
$collectionsIds = array_map(function(CollectionReference $ref){return $ref->getCollectionId();}, $references);
$this->getSearchEngineLogger()->log($databox, $result->getUserQuery(), $result->getTotal(), $collectionsIds);
}
$proposals = $firstPage ? $result->getProposals() : false;

View File

@@ -13,7 +13,7 @@ namespace Alchemy\Phrasea\ControllerProvider\Admin;
use Alchemy\Phrasea\Application as PhraseaApplication;
use Alchemy\Phrasea\Controller\Admin\CollectionController;
use Alchemy\Phrasea\Controller\LazyLocator;
use Alchemy\Phrasea\Core\LazyLocator;
use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait;
use Silex\Application;
use Silex\ControllerProviderInterface;

View File

@@ -13,7 +13,7 @@ namespace Alchemy\Phrasea\ControllerProvider\Admin;
use Alchemy\Phrasea\Application as PhraseaApplication;
use Alchemy\Phrasea\Controller\Admin\DashboardController;
use Alchemy\Phrasea\Controller\LazyLocator;
use Alchemy\Phrasea\Core\LazyLocator;
use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait;
use Silex\Application;
use Silex\ControllerCollection;

View File

@@ -13,7 +13,7 @@ namespace Alchemy\Phrasea\ControllerProvider\Admin;
use Alchemy\Phrasea\Application as PhraseaApplication;
use Alchemy\Phrasea\Controller\Admin\DataboxController;
use Alchemy\Phrasea\Controller\LazyLocator;
use Alchemy\Phrasea\Core\LazyLocator;
use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait;
use Alchemy\Phrasea\Security\Firewall;
use Silex\Application;

View File

@@ -12,7 +12,7 @@
namespace Alchemy\Phrasea\ControllerProvider\Admin;
use Alchemy\Phrasea\Controller\Admin\UserController;
use Alchemy\Phrasea\Controller\LazyLocator;
use Alchemy\Phrasea\Core\LazyLocator;
use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait;
use Silex\Application;
use Silex\ControllerProviderInterface;

View File

@@ -13,7 +13,7 @@ namespace Alchemy\Phrasea\ControllerProvider\Api;
use Alchemy\Phrasea\Application as PhraseaApplication;
use Alchemy\Phrasea\Controller\Api\V1Controller;
use Alchemy\Phrasea\Controller\LazyLocator;
use Alchemy\Phrasea\Core\LazyLocator;
use Alchemy\Phrasea\Core\Configuration\PropertyAccess;
use Alchemy\Phrasea\Core\Event\Listener\OAuthListener;
use Silex\Application;

View File

@@ -13,7 +13,7 @@ use Alchemy\Phrasea\Application as PhraseaApplication;
use Alchemy\Phrasea\Controller\Api\BasketController;
use Alchemy\Phrasea\Controller\Api\LazaretController;
use Alchemy\Phrasea\Controller\Api\SearchController;
use Alchemy\Phrasea\Controller\LazyLocator;
use Alchemy\Phrasea\Core\LazyLocator;
use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait;
use Alchemy\Phrasea\Core\Configuration\PropertyAccess;
use Alchemy\Phrasea\Core\Event\Listener\OAuthListener;

View File

@@ -13,7 +13,7 @@ namespace Alchemy\Phrasea\ControllerProvider;
use Alchemy\Phrasea\Application as PhraseaApplication;
use Alchemy\Phrasea\Controller\DatafileController;
use Alchemy\Phrasea\Controller\LazyLocator;
use Alchemy\Phrasea\Core\LazyLocator;
use Silex\Application;
use Silex\ControllerProviderInterface;
use Silex\ServiceProviderInterface;

View File

@@ -12,7 +12,7 @@
namespace Alchemy\Phrasea\ControllerProvider;
use Alchemy\Phrasea\Application as PhraseaApplication;
use Alchemy\Phrasea\Controller\LazyLocator;
use Alchemy\Phrasea\Core\LazyLocator;
use Alchemy\Phrasea\Controller\PermalinkController;
use Alchemy\Phrasea\Core\Event\Listener\OAuthListener;
use Silex\Application;

View File

@@ -12,7 +12,7 @@
namespace Alchemy\Phrasea\ControllerProvider\Prod;
use Alchemy\Phrasea\Application as PhraseaApplication;
use Alchemy\Phrasea\Controller\LazyLocator;
use Alchemy\Phrasea\Core\LazyLocator;
use Alchemy\Phrasea\Controller\Prod\DoDownloadController;
use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait;
use Silex\Application;

View File

@@ -12,7 +12,7 @@
namespace Alchemy\Phrasea\ControllerProvider\Prod;
use Alchemy\Phrasea\Application as PhraseaApplication;
use Alchemy\Phrasea\Controller\LazyLocator;
use Alchemy\Phrasea\Core\LazyLocator;
use Alchemy\Phrasea\Controller\Prod\EditController;
use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait;
use Silex\Application;

View File

@@ -12,7 +12,7 @@
namespace Alchemy\Phrasea\ControllerProvider\Prod;
use Alchemy\Phrasea\Application as PhraseaApplication;
use Alchemy\Phrasea\Controller\LazyLocator;
use Alchemy\Phrasea\Core\LazyLocator;
use Alchemy\Phrasea\Controller\Prod\ExportController;
use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait;
use Alchemy\Phrasea\Core\Event\Listener\OAuthListener;

View File

@@ -12,7 +12,7 @@
namespace Alchemy\Phrasea\ControllerProvider\Prod;
use Alchemy\Phrasea\Application as PhraseaApplication;
use Alchemy\Phrasea\Controller\LazyLocator;
use Alchemy\Phrasea\Core\LazyLocator;
use Alchemy\Phrasea\Controller\Prod\LazaretController;
use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait;
use Silex\Application;

View File

@@ -12,7 +12,7 @@
namespace Alchemy\Phrasea\ControllerProvider\Prod;
use Alchemy\Phrasea\Application as PhraseaApplication;
use Alchemy\Phrasea\Controller\LazyLocator;
use Alchemy\Phrasea\Core\LazyLocator;
use Alchemy\Phrasea\Controller\Prod\PushController;
use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait;
use Silex\Application;

View File

@@ -12,7 +12,7 @@
namespace Alchemy\Phrasea\ControllerProvider\Prod;
use Alchemy\Phrasea\Application as PhraseaApplication;
use Alchemy\Phrasea\Controller\LazyLocator;
use Alchemy\Phrasea\Core\LazyLocator;
use Alchemy\Phrasea\Controller\Prod\QueryController;
use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait;
use Silex\Application;
@@ -45,6 +45,8 @@ class Query implements ControllerProviderInterface, ServiceProviderInterface
$controllers->post('/', 'controller.prod.query:query')
->bind('prod_query');
$controllers->post('/completion/', 'controller.prod.query:completion');
$controllers->post('/answer-train/', 'controller.prod.query:queryAnswerTrain')
->bind('preview_answer_train');

View File

@@ -12,7 +12,7 @@
namespace Alchemy\Phrasea\ControllerProvider\Prod;
use Alchemy\Phrasea\Application as PhraseaApplication;
use Alchemy\Phrasea\Controller\LazyLocator;
use Alchemy\Phrasea\Core\LazyLocator;
use Alchemy\Phrasea\Controller\Prod\RecordController;
use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait;
use Silex\Application;

View File

@@ -12,7 +12,7 @@
namespace Alchemy\Phrasea\ControllerProvider\Prod;
use Alchemy\Phrasea\Application as PhraseaApplication;
use Alchemy\Phrasea\Controller\LazyLocator;
use Alchemy\Phrasea\Core\LazyLocator;
use Alchemy\Phrasea\Controller\Prod\StoryController;
use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait;
use Silex\Application;

View File

@@ -12,7 +12,7 @@
namespace Alchemy\Phrasea\ControllerProvider\Prod;
use Alchemy\Phrasea\Application as PhraseaApplication;
use Alchemy\Phrasea\Controller\LazyLocator;
use Alchemy\Phrasea\Core\LazyLocator;
use Alchemy\Phrasea\Controller\Prod\ToolsController;
use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait;
use Silex\Application;

View File

@@ -12,7 +12,7 @@
namespace Alchemy\Phrasea\ControllerProvider\Prod;
use Alchemy\Phrasea\Application as PhraseaApplication;
use Alchemy\Phrasea\Controller\LazyLocator;
use Alchemy\Phrasea\Core\LazyLocator;
use Alchemy\Phrasea\Controller\Prod\TooltipController;
use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait;
use Silex\Application;

View File

@@ -12,7 +12,7 @@
namespace Alchemy\Phrasea\ControllerProvider\Prod;
use Alchemy\Phrasea\Application as PhraseaApplication;
use Alchemy\Phrasea\Controller\LazyLocator;
use Alchemy\Phrasea\Core\LazyLocator;
use Alchemy\Phrasea\Controller\Prod\UploadController;
use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait;
use Silex\Application;

View File

@@ -12,7 +12,7 @@
namespace Alchemy\Phrasea\ControllerProvider\Prod;
use Alchemy\Phrasea\Application as PhraseaApplication;
use Alchemy\Phrasea\Controller\LazyLocator;
use Alchemy\Phrasea\Core\LazyLocator;
use Alchemy\Phrasea\Controller\Prod\UsrListController;
use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait;
use Silex\Application;

View File

@@ -12,7 +12,7 @@
namespace Alchemy\Phrasea\ControllerProvider\Prod;
use Alchemy\Phrasea\Application as PhraseaApplication;
use Alchemy\Phrasea\Controller\LazyLocator;
use Alchemy\Phrasea\Core\LazyLocator;
use Alchemy\Phrasea\Controller\Prod\WorkzoneController;
use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait;
use Silex\Application;

View File

@@ -12,7 +12,7 @@
namespace Alchemy\Phrasea\ControllerProvider\Root;
use Alchemy\Phrasea\Application as PhraseaApplication;
use Alchemy\Phrasea\Controller\LazyLocator;
use Alchemy\Phrasea\Core\LazyLocator;
use Alchemy\Phrasea\Controller\Root\AccountController;
use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait;
use Silex\Application;

View File

@@ -12,7 +12,7 @@
namespace Alchemy\Phrasea\ControllerProvider\Root;
use Alchemy\Phrasea\Application as PhraseaApplication;
use Alchemy\Phrasea\Controller\LazyLocator;
use Alchemy\Phrasea\Core\LazyLocator;
use Alchemy\Phrasea\Controller\Root\LoginController;
use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait;
use Silex\Application;

View File

@@ -12,7 +12,7 @@
namespace Alchemy\Phrasea\ControllerProvider\Root;
use Alchemy\Phrasea\Application as PhraseaApplication;
use Alchemy\Phrasea\Controller\LazyLocator;
use Alchemy\Phrasea\Core\LazyLocator;
use Alchemy\Phrasea\Controller\Root\RSSFeedController;
use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait;
use Silex\Application;

View File

@@ -12,7 +12,7 @@
namespace Alchemy\Phrasea\ControllerProvider\Root;
use Alchemy\Phrasea\Application as PhraseaApplication;
use Alchemy\Phrasea\Controller\LazyLocator;
use Alchemy\Phrasea\Core\LazyLocator;
use Alchemy\Phrasea\Controller\Root\SessionController;
use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait;
use Silex\Application;

View File

@@ -13,7 +13,7 @@ namespace Alchemy\Phrasea\Core\Event\Subscriber;
use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Application\Helper\NotifierAware;
use Alchemy\Phrasea\Controller\LazyLocator;
use Alchemy\Phrasea\Core\LazyLocator;
use Alchemy\Phrasea\Model\Entities\User;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

View File

@@ -12,7 +12,7 @@
namespace Alchemy\Phrasea\Core\Provider;
use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Controller\LazyLocator;
use Alchemy\Phrasea\Core\LazyLocator;
use Alchemy\Phrasea\Model\Manager\UserManager;
use Alchemy\Phrasea\Model\Manipulator\ACLManipulator;
use Alchemy\Phrasea\Model\Manipulator\ApiAccountManipulator;

View File

@@ -11,7 +11,7 @@
namespace Alchemy\Phrasea\Core\Provider;
use Alchemy\Phrasea\Controller\LazyLocator;
use Alchemy\Phrasea\Core\LazyLocator;
use Alchemy\Phrasea\Core\Event\Subscriber\OrderSubscriber;
use Alchemy\Phrasea\Model\Entities\Order;
use Alchemy\Phrasea\Order\ValidationNotifier\MailNotifier;

View File

@@ -11,7 +11,7 @@
namespace Alchemy\Phrasea\Core\Provider;
use Alchemy\Phrasea\Controller\LazyLocator;
use Alchemy\Phrasea\Core\LazyLocator;
use Alchemy\Phrasea\Core\Event\Subscriber\ContentNegotiationSubscriber;
use Alchemy\Phrasea\Core\Event\Subscriber\CookiesDisablerSubscriber;
use Alchemy\Phrasea\Core\Event\Subscriber\LogoutSubscriber;

View File

@@ -11,7 +11,7 @@
namespace Alchemy\Phrasea\Core\Provider;
use Alchemy\Phrasea\Controller\LazyLocator;
use Alchemy\Phrasea\Core\LazyLocator;
use Alchemy\Phrasea\SearchEngine\Elastic\DataboxFetcherFactory;
use Alchemy\Phrasea\SearchEngine\Elastic\ElasticsearchOptions;
use Alchemy\Phrasea\SearchEngine\Elastic\Index;
@@ -76,6 +76,7 @@ class SearchEngineServiceProvider implements ServiceProviderInterface
if ($type !== SearchEngineInterface::TYPE_ELASTICSEARCH) {
throw new InvalidArgumentException(sprintf('Invalid search engine type "%s".', $type));
}
/** @var ElasticsearchOptions $options */
$options = $app['elasticsearch.options'];
@@ -83,7 +84,6 @@ class SearchEngineServiceProvider implements ServiceProviderInterface
$app,
$app['search_engine.structure'],
$app['elasticsearch.client'],
$options->getIndexName(),
$app['query_context.factory'],
$app['elasticsearch.facets_response.factory'],
$options

View File

@@ -10,7 +10,7 @@
namespace Alchemy\Phrasea\Core\Provider;
use Alchemy\Phrasea\Controller\LazyLocator;
use Alchemy\Phrasea\Core\LazyLocator;
use Alchemy\Phrasea\Model\Serializer\CaptionSerializer;
use Alchemy\Phrasea\Model\Serializer\ESRecordSerializer;
use Silex\Application;

View File

@@ -11,7 +11,7 @@
namespace Alchemy\Phrasea\Core\Provider;
use Alchemy\Phrasea\Controller\LazyLocator;
use Alchemy\Phrasea\Core\LazyLocator;
use Alchemy\Phrasea\TaskManager\Job\FtpJob;
use Alchemy\Phrasea\TaskManager\Job\ArchiveJob;
use Alchemy\Phrasea\TaskManager\Job\BridgeJob;

View File

@@ -2,7 +2,7 @@
namespace Alchemy\Phrasea\Core\Provider;
use Alchemy\Phrasea\Controller\LazyLocator;
use Alchemy\Phrasea\Core\LazyLocator;
use Alchemy\Phrasea\Core\Event\Subscriber\CacheStatisticsSubscriber;
use Alchemy\Phrasea\Core\Profiler\CacheDataCollector;
use Alchemy\Phrasea\Core\Profiler\TraceableCache;

View File

@@ -10,7 +10,7 @@
namespace Alchemy\Phrasea\Databox\Caption;
use Alchemy\Phrasea\Controller\LazyLocator;
use Alchemy\Phrasea\Core\LazyLocator;
use Alchemy\Phrasea\Databox\ClosureDataboxBoundRepositoryFactory;
use Alchemy\Phrasea\Databox\DataboxBoundRepositoryProvider;
use Alchemy\Phrasea\Databox\DataboxConnectionProvider;

View File

@@ -27,12 +27,12 @@ class DataboxFieldFactory
}
/**
* @param array $raw
* @param array $row
* @return databox_field
*/
public function create(array $raw)
public function create(array $row)
{
return new databox_field($this->app, $this->databox, $raw);
return new databox_field($this->app, $this->databox, $row);
}
/**
@@ -43,8 +43,8 @@ class DataboxFieldFactory
{
$instances = [];
foreach ($rows as $index => $raw) {
$instances[$index] = new databox_field($this->app, $this->databox, $raw);
foreach ($rows as $index => $row) {
$instances[$index] = new databox_field($this->app, $this->databox, $row);
}
return $instances;

View File

@@ -13,7 +13,7 @@ namespace Alchemy\Phrasea\Helper\User;
use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Application\Helper\NotifierAware;
use Alchemy\Phrasea\Controller\LazyLocator;
use Alchemy\Phrasea\Core\LazyLocator;
use Alchemy\Phrasea\Exception\InvalidArgumentException;
use Alchemy\Phrasea\Model\Entities\User;
use Alchemy\Phrasea\Notification\Mail\MailSuccessEmailUpdate;

View File

@@ -12,7 +12,7 @@ namespace Alchemy\Phrasea\Helper\User;
use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Application\Helper\NotifierAware;
use Alchemy\Phrasea\Controller\LazyLocator;
use Alchemy\Phrasea\Core\LazyLocator;
use Alchemy\Phrasea\Helper\Helper;
use Alchemy\Phrasea\Notification\Receiver;
use Alchemy\Phrasea\Notification\Mail\MailRequestPasswordSetup;

View File

@@ -289,6 +289,7 @@ class User
/**
* @param string $login
* @return $this
*/
public function setLogin($login)
{
@@ -307,6 +308,7 @@ class User
/**
* @param string $email
* @return $this
*/
public function setEmail($email)
{
@@ -326,6 +328,7 @@ class User
/**
*
* @param string $password
* @return $this
*/
public function setPassword($password)
{
@@ -344,6 +347,7 @@ class User
/**
* @param string $nonce
* @return $this
*/
public function setNonce($nonce)
{
@@ -362,6 +366,7 @@ class User
/**
* @param boolean $saltedPassword
* @return $this
*/
public function setSaltedPassword($saltedPassword)
{
@@ -380,6 +385,7 @@ class User
/**
* @param string $firstName
* @return $this
*/
public function setFirstName($firstName)
{
@@ -399,6 +405,7 @@ class User
/**
*
* @param string $lastName
* @return $this
*/
public function setLastName($lastName)
{
@@ -452,6 +459,7 @@ class User
/**
* @param string $address
* @return $this
*/
public function setAddress($address)
{
@@ -470,6 +478,7 @@ class User
/**
* @param string $city
* @return $this
*/
public function setCity($city)
{
@@ -488,6 +497,7 @@ class User
/**
* @param string $country
* @return $this
*/
public function setCountry($country)
{
@@ -506,6 +516,7 @@ class User
/**
* @param string $zipCode
* @return $this
*/
public function setZipCode($zipCode)
{
@@ -524,6 +535,7 @@ class User
/**
* @param integer $geonameId
* @return $this
*/
public function setGeonameId($geonameId)
{
@@ -546,6 +558,7 @@ class User
/**
* @param string $locale
* @return $this
*
* @throws InvalidArgumentException
*/
@@ -570,6 +583,7 @@ class User
/**
* @param string $timezone
* @return $this
*/
public function setTimezone($timezone)
{
@@ -588,6 +602,7 @@ class User
/**
* @param string $job
* @return $this
*/
public function setJob($job)
{
@@ -606,6 +621,7 @@ class User
/**
* @param string $activity
* @return $this
*/
public function setActivity($activity)
{
@@ -624,6 +640,7 @@ class User
/**
* @param string $company
* @return $this
*/
public function setCompany($company)
{
@@ -642,6 +659,7 @@ class User
/**
* @param string $phone
* @return $this
*/
public function setPhone($phone)
{
@@ -660,6 +678,7 @@ class User
/**
* @param string $fax
* @return $this
*/
public function setFax($fax)
{
@@ -678,6 +697,7 @@ class User
/**
* @param boolean $admin
* @return $this
*/
public function setAdmin($admin)
{
@@ -696,6 +716,7 @@ class User
/**
* @param boolean $guest
* @return $this
*/
public function setGuest($guest)
{
@@ -714,6 +735,7 @@ class User
/**
* @param boolean $mailNotifications
* @return $this
*/
public function setMailNotificationsActivated($mailNotifications)
{
@@ -732,6 +754,7 @@ class User
/**
* @param boolean $requestNotifications
* @return $this
*/
public function setRequestNotificationsActivated($requestNotifications)
{
@@ -750,6 +773,7 @@ class User
/**
* @param boolean $ldapCreated
* @return $this
*/
public function setLdapCreated($ldapCreated)
{
@@ -768,6 +792,7 @@ class User
/**
* @param User $owner
* @return $this
*/
public function setTemplateOwner(User $owner)
{
@@ -786,6 +811,7 @@ class User
/**
* @param User $lastAppliedTemplate
* @return $this
*/
public function setLastAppliedTemplate(User $lastAppliedTemplate)
{
@@ -804,6 +830,7 @@ class User
/**
* @param string $pushList
* @return $this
*/
public function setPushList($pushList)
{
@@ -822,6 +849,7 @@ class User
/**
* @param boolean $canChangeProfil
* @return $this
*/
public function setCanChangeProfil($canChangeProfil)
{
@@ -840,6 +868,7 @@ class User
/**
* @param boolean $canChangeFtpProfil
* @return $this
*/
public function setCanChangeFtpProfil($canChangeFtpProfil)
{
@@ -858,6 +887,7 @@ class User
/**
* @param \DateTime $lastConnection
* @return $this
*/
public function setLastConnection(\DateTime $lastConnection)
{
@@ -876,6 +906,7 @@ class User
/**
* @param boolean $mailLocked
* @return $this
*/
public function setMailLocked($mailLocked)
{
@@ -922,6 +953,7 @@ class User
/**
* @param \Datetime $created
* @return $this
*/
public function setCreated(\Datetime $created)
{
@@ -932,6 +964,7 @@ class User
/**
* @param \Datetime $updated
* @return $this
*/
public function setUpdated(\Datetime $updated)
{

View File

@@ -11,6 +11,7 @@
namespace Alchemy\Phrasea\SearchEngine\Elastic;
use Alchemy\Phrasea\Collection\Reference\CollectionReference;
use Alchemy\Phrasea\Exception\LogicException;
use Alchemy\Phrasea\SearchEngine\Elastic\Indexer\RecordIndexer;
use Alchemy\Phrasea\SearchEngine\Elastic\Search\AggregationHelper;
@@ -55,7 +56,15 @@ class ElasticSearchEngine implements SearchEngineInterface
*/
private $context_factory;
public function __construct(Application $app, Structure $structure, Client $client, $indexName, QueryContextFactory $context_factory, Closure $facetsResponseFactory, ElasticsearchOptions $options)
/**
* @param Application $app
* @param Structure $structure
* @param Client $client
* @param QueryContextFactory $context_factory
* @param callable $facetsResponseFactory
* @param ElasticsearchOptions $options
*/
public function __construct(Application $app, Structure $structure, Client $client, QueryContextFactory $context_factory, Closure $facetsResponseFactory, ElasticsearchOptions $options)
{
$this->app = $app;
$this->structure = $structure;
@@ -64,11 +73,7 @@ class ElasticSearchEngine implements SearchEngineInterface
$this->facetsResponseFactory = $facetsResponseFactory;
$this->options = $options;
if ('' === trim($indexName)) {
throw new \InvalidArgumentException('The provided index name is invalid.');
}
$this->indexName = $indexName;
$this->indexName = $options->getIndexName();
}
@@ -306,7 +311,7 @@ class ElasticSearchEngine implements SearchEngineInterface
$query['ast'] = $query_compiler->parse($string)->dump();
$query['query_main'] = $recordQuery;
$query['query'] = $params['body'];
$query['query_string'] = json_encode($params['body']);
$query['query_string'] = json_encode($params['body'], JSON_PRETTY_PRINT);
return new SearchEngineResult(
$options,
@@ -366,7 +371,34 @@ class ElasticSearchEngine implements SearchEngineInterface
*/
public function autocomplete($query, SearchEngineOptions $options)
{
throw new RuntimeException('Elasticsearch engine currently does not support auto-complete.');
$params = $this->createCompletionParams($query, $options);
$res = $this->client->suggest($params);
$ret = [
'text' => [],
'byField' => []
];
foreach(array_keys($params['body']) as $fname) {
$t = [];
foreach($res[$fname] as $suggest) { // don't know why there is a sub-array level
foreach($suggest['options'] as $option) {
$text = $option['text'];
if(!in_array($text, $ret['text'])) {
$ret['text'][] = $text;
}
$t[] = [
'label' => $text,
'query' => $fname.':'.$text
];
}
}
if(!empty($t)) {
$ret['byField'][$fname] = $t;
}
}
return $ret;
}
/**
@@ -390,6 +422,40 @@ class ElasticSearchEngine implements SearchEngineInterface
{
}
private function createCompletionParams($query, SearchEngineOptions $options)
{
$body = [];
$context = [
'record_type' => $options->getSearchType() === SearchEngineOptions::RECORD_RECORD ?
SearchEngineInterface::GEM_TYPE_RECORD : SearchEngineInterface::GEM_TYPE_STORY
];
$base_ids = $options->getBasesIds();
if (count($base_ids) > 0) {
$context['base_id'] = $base_ids;
}
$search_context = $this->context_factory->createContext($options);
$fields = $search_context->getUnrestrictedFields();
foreach($fields as $field) {
if($field->getType() == FieldMapping::TYPE_STRING) {
$k = '' . $field->getName();
$body[$k] = [
'text' => $query,
'completion' => [
'field' => "caption." . $field->getName() . ".suggest",
'context' => &$context
]
];
}
}
return [
'index' => $this->indexName,
'body' => $body
];
}
private function createRecordQueryParams($ESQuery, SearchEngineOptions $options, \record_adapter $record = null)
{
$params = [
@@ -502,9 +568,9 @@ class ElasticSearchEngine implements SearchEngineInterface
$filters[]['term']['type'] = $type;
}
$collections = $options->getCollections();
if (count($collections) > 0) {
$filters[]['terms']['base_id'] = array_keys($collections);
$bases = $options->getBasesIds();
if (count($bases) > 0) {
$filters[]['terms']['base_id'] = $bases;
}
if (count($options->getStatus()) > 0) {
@@ -645,12 +711,12 @@ class ElasticSearchEngine implements SearchEngineInterface
{
$filters = [];
$collections = $options->getCollections();
$bases = $options->getBasesIds();
$collectionsWoRules = [];
$collectionsWoRules['terms']['base_id'] = [];
foreach ($aclRules as $baseId => $flagsRules) {
if(!array_key_exists($baseId, $collections)) {
if(!in_array($baseId, $bases)) {
// no need to add a filter if the collection is not searched
continue;
}

View File

@@ -20,9 +20,10 @@ class FieldMapping
const DATE_FORMAT_CAPTION_PHP = 'Y/m/d'; // PHP format
// Core types
const TYPE_STRING = 'string';
const TYPE_BOOLEAN = 'boolean';
const TYPE_DATE = 'date';
const TYPE_STRING = 'string';
const TYPE_BOOLEAN = 'boolean';
const TYPE_DATE = 'date';
const TYPE_COMPLETION = 'completion';
// Number core types
const TYPE_FLOAT = 'float';
@@ -47,7 +48,8 @@ class FieldMapping
self::TYPE_SHORT,
self::TYPE_BYTE,
self::TYPE_IP,
self::TYPE_OBJECT
self::TYPE_OBJECT,
self::TYPE_COMPLETION
);
/**

View File

@@ -52,8 +52,10 @@ class RecordIndex implements MappingProvider
// Database name (still indexed for facets)
$mapping->addStringField('databox_name')->disableAnalysis();
// Unique collection ID
$mapping->addIntegerField('base_id');
// Unique base ID
//$mapping->addIntegerField('base_id')->enableIndexing();
$mapping->addStringField('base_id')->disableAnalysis(); // must be a string to match completion context ?
// Useless collection ID (local to databox)
$mapping->addIntegerField('collection_id')->disableIndexing();
// Collection name (still indexed for facets)
@@ -64,6 +66,7 @@ class RecordIndex implements MappingProvider
$mapping->addStringField('original_name')->disableIndexing();
$mapping->addStringField('mime')->disableAnalysis();
$mapping->addStringField('type')->disableAnalysis();
$mapping->addStringField('record_type')->disableAnalysis();
$mapping->addIntegerField('width')->disableIndexing();

View File

@@ -0,0 +1,49 @@
<?php
/*
* This file is part of phrasea-4.0.
*
* (c) Alchemy <info@alchemy.fr>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\SearchEngine\Elastic\Mapping;
use Alchemy\Phrasea\SearchEngine\Elastic\FieldMapping;
class CompletionFieldMapping extends FieldMapping
{
/**
* @param string $name
*/
public function __construct($name)
{
parent::__construct($name, 'completion');
}
/**
* @return array
*/
protected function getProperties()
{
return [
'context' => [
'base_id' => [
'type' => 'category',
'path' => 'base_id',
'default' => ''
],
'record_type' => [
'type' => 'category',
'path' => 'record_type',
'default' => ''
]
],
// 'analyzer' => 'simple',
// 'search_analyzer' => 'simple',
// 'payloads' => false
];
}
}

View File

@@ -30,9 +30,9 @@ class ComplexMapping extends FieldMapping
throw new \LogicException(sprintf('There is already a "%s" multi field.', $child->getName()));
}
if ($child->getType() !== $this->getType() && $this->getType() !== self::TYPE_OBJECT) {
throw new \LogicException('Child field type must match parent type.');
}
// if ($child->getType() !== $this->getType() && $this->getType() !== self::TYPE_OBJECT) {
// throw new \LogicException('Child field type must match parent type.');
// }
return $this->children[$child->getName()] = $child;
}

View File

@@ -30,6 +30,10 @@ class FieldToFieldMappingConverter
$fieldMapping->disableIndexing();
} else {
$fieldMapping->addChild((new StringFieldMapping('raw'))->enableRawIndexing());
$child = new CompletionFieldMapping('suggest');
$fieldMapping->addChild($child);
$fieldMapping->addAnalyzedChildren($locales);
$fieldMapping->enableTermVectors(true);
}

View File

@@ -46,6 +46,9 @@ class QueryContext
return new static($this->structure, $this->locales, $this->queryLocale, $fields);
}
/**
* @return Field[]
*/
public function getUnrestrictedFields()
{
// TODO Restore search optimization by using "caption_all" field
@@ -63,6 +66,10 @@ class QueryContext
return $this->filterFields($this->structure->getAllFields());
}
/**
* @param Field[] $fields
* @return Field[]
*/
private function filterFields(array $fields)
{
if ($this->fields !== null) {

View File

@@ -45,25 +45,29 @@ class Field implements Typed
private $used_by_collections;
public static function createFromLegacyField(databox_field $field)
public static function createFromLegacyField(databox_field $field, $with = Structure::WITH_EVERYTHING)
{
$type = self::getTypeFromLegacy($field);
$databox = $field->get_databox();
// Thesaurus concept inference
$xpath = $field->get_tbranch();
if ($type === FieldMapping::TYPE_STRING && !empty($xpath)) {
$roots = ThesaurusHelper::findConceptsByXPath($databox, $xpath);
} else {
$roots = null;
$roots = null;
if(($with & Structure::FIELD_WITH_THESAURUS) && $type === FieldMapping::TYPE_STRING) {
// Thesaurus concept inference
$xpath = $field->get_tbranch();
if (!empty($xpath)) {
$roots = ThesaurusHelper::findConceptsByXPath($databox, $xpath);
}
}
// Facet (enable + optional limit)
$facet = $field->getFacetValuesLimit();
if ($facet === databox_field::FACET_DISABLED) {
$facet = self::FACET_DISABLED;
} elseif ($facet === databox_field::FACET_NO_LIMIT) {
$facet = self::FACET_NO_LIMIT;
$facet = self::FACET_DISABLED;
if($with & Structure::FIELD_WITH_FACETS) {
// Facet (enable + optional limit)
$facet = $field->getFacetValuesLimit();
if ($facet === databox_field::FACET_DISABLED) {
$facet = self::FACET_DISABLED;
} elseif ($facet === databox_field::FACET_NO_LIMIT) {
$facet = self::FACET_NO_LIMIT;
}
}
return new self($field->get_name(), $type, [

View File

@@ -46,20 +46,26 @@ final class GlobalStructure implements Structure
/**
* @param \databox[] $databoxes
* @param int $what bitmask of what should be included in this structure, in fields, ...
*
* @return GlobalStructure
*/
public static function createFromDataboxes(array $databoxes)
public static function createFromDataboxes(array $databoxes, $what = self::WITH_EVERYTHING)
{
$fields = [];
$flags = [];
foreach ($databoxes as $databox) {
foreach ($databox->get_meta_structure() as $fieldStructure) {
$fields[] = Field::createFromLegacyField($fieldStructure);
if($what & self::STRUCTURE_WITH_FIELDS) {
foreach ($databox->get_meta_structure() as $fieldStructure) {
$fields[] = Field::createFromLegacyField($fieldStructure, $what);
}
}
foreach ($databox->getStatusStructure() as $status) {
$flags[] = Flag::createFromLegacyStatus($status);
if($what & self::STRUCTURE_WITH_FLAGS) {
foreach ($databox->getStatusStructure() as $status) {
$flags[] = Flag::createFromLegacyStatus($status);
}
}
}

View File

@@ -135,13 +135,12 @@ final class LimitedStructure implements Structure
]);
}
/**
* @return int[] // base_id's
*/
private function allowedCollections()
{
// Get all collections (base_id) with allowed private field access (user rights are computed in options object)
$allowed_collections = [];
foreach ($this->search_options->getBusinessFieldsOn() as $collection) {
$allowed_collections[] = $collection->get_base_id();
}
return $allowed_collections;
return $this->search_options->getBusinessFieldsOn();
}
}

View File

@@ -12,6 +12,12 @@ namespace Alchemy\Phrasea\SearchEngine\Elastic\Structure;
interface Structure
{
const STRUCTURE_WITH_FIELDS = 0x10;
const STRUCTURE_WITH_FLAGS = 0x20;
const FIELD_WITH_THESAURUS = 0x01;
const FIELD_WITH_FACETS = 0x02;
const WITH_EVERYTHING = 0xFF;
/**
* @return Field[]
*/

View File

@@ -15,10 +15,12 @@ use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Authentication\ACLProvider;
use Alchemy\Phrasea\Authentication\Authenticator;
use Alchemy\Phrasea\Collection\CollectionRepository;
use Alchemy\Phrasea\Collection\Reference\CollectionReferenceCollection;
use Alchemy\Phrasea\Collection\Reference\CollectionReference;
use Alchemy\Phrasea\Collection\Reference\DbalCollectionReferenceRepository;
use Assert\Assertion;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use databox_descriptionStructure;
class SearchEngineOptions
{
@@ -38,104 +40,25 @@ class SearchEngineOptions
const SORT_MODE_ASC = 'asc';
const SORT_MODE_DESC = 'desc';
private static $serializable_properties = [
'record_type',
'search_type',
'collections',
'fields',
'status',
'date_min',
'date_max',
'date_fields',
'i18n',
'stemming',
'sort_by',
'sort_ord',
'business_fields',
'max_results',
'first_result',
];
/**
* @param Application $app
* @return callable[]
*/
private static function getHydrateMethods(Application $app)
{
$fieldNormalizer = function ($value) use ($app) {
return array_map(function ($serialized) use ($app) {
$data = explode('_', $serialized, 2);
return $app->findDataboxById($data[0])->get_meta_structure()->get_element($data[1]);
}, $value);
};
$collectionNormalizer = function ($value) use ($app) {
$references = new CollectionReferenceCollection($app['repo.collection-references']->findMany($value));
$collections = [];
foreach ($references->groupByDataboxIdAndCollectionId() as $databoxId => $indexes) {
/** @var CollectionRepository $repository */
$repository = $app['repo.collections-registry']->getRepositoryByDatabox($databoxId);
foreach ($indexes as $collectionId => $index) {
$coll = $repository->find($collectionId);
$collections[$coll->get_base_id()] = $coll;
}
}
return $collections;
};
$optionSetter = function ($setter) {
return function ($value, SearchEngineOptions $options) use ($setter) {
$options->{$setter}($value);
};
};
return [
'record_type' => $optionSetter('setRecordType'),
'search_type' => $optionSetter('setSearchType'),
'status' => $optionSetter('setStatus'),
'date_min' => function ($value, SearchEngineOptions $options) {
$options->setMinDate($value ? \DateTime::createFromFormat(DATE_ATOM, $value) : null);
},
'date_max' => function ($value, SearchEngineOptions $options) {
$options->setMaxDate($value ? \DateTime::createFromFormat(DATE_ATOM, $value) : null);
},
'i18n' => function ($value, SearchEngineOptions $options) {
if ($value) {
$options->setLocale($value);
}
},
'stemming' => $optionSetter('setStemming'),
'date_fields' => function ($value, SearchEngineOptions $options) use ($fieldNormalizer) {
$options->setDateFields($fieldNormalizer($value));
},
'fields' => function ($value, SearchEngineOptions $options) use ($fieldNormalizer) {
$options->setFields($fieldNormalizer($value));
},
'collections' => function ($value, SearchEngineOptions $options) use ($collectionNormalizer) {
$options->onCollections($collectionNormalizer($value));
},
'business_fields' => function ($value, SearchEngineOptions $options) use ($collectionNormalizer) {
$options->allowBusinessFieldsOn($collectionNormalizer($value));
},
'first_result' => $optionSetter('setFirstResult'),
'max_results' => $optionSetter('setMaxResults'),
];
}
/** @var DbalCollectionReferenceRepository $dbalCollectionReferenceRepository */
private $collectionReferenceRepository;
/** @var string */
protected $record_type = self::TYPE_ALL;
protected $search_type = self::RECORD_RECORD;
/** @var \collection[] */
protected $collections = [];
/** @var null|\databox[] */
private $databoxes;
/** @var null|int[] bases ids where searching is done */
private $basesIds = null;
/** @var null|CollectionReference[][] */
private $collectionsReferencesByDatabox = null;
/** @var null|\int[] */
private $databoxesIds;
/** @var \databox_field[] */
protected $fields = [];
protected $status = [];
/** @var \DateTime */
@@ -152,6 +75,8 @@ class SearchEngineOptions
/** @var string */
protected $sort_ord = self::SORT_MODE_DESC;
/** @var int[] */
protected $business_fields = [];
/**
@@ -164,6 +89,24 @@ class SearchEngineOptions
*/
private $first_result = 0;
private static $serializable_properties = [
'record_type',
'search_type',
'basesIds',
'fields',
'status',
'date_min',
'date_max',
'date_fields',
'i18n',
'stemming',
'sort_by',
'sort_ord',
'business_fields',
'max_results',
'first_result'
];
/**
* Defines locale code to use for query
*
@@ -205,14 +148,14 @@ class SearchEngineOptions
}
/**
* Allows business fields query on the given collections
* Allows business fields query on the given bases
*
* @param \collection[] $collection An array of collection
* @param int[] $basesIds
* @return $this
*/
public function allowBusinessFieldsOn(array $collection)
public function allowBusinessFieldsOn(array $basesIds)
{
$this->business_fields = $collection;
$this->business_fields = $basesIds;
return $this;
}
@@ -230,10 +173,10 @@ class SearchEngineOptions
}
/**
* Returns an array of collection on which business fields are allowed to
* Returns an array of bases ids on which business fields are allowed to
* search on
*
* @return \collection[] An array of collection
* @return int[]
*/
public function getBusinessFieldsOn()
{
@@ -316,48 +259,33 @@ class SearchEngineOptions
}
/**
* Set the collections where to search for
* Set the bases where to search for
*
* @param \collection[] $collections An array of collection
* @param int[] $basesIds An array of ids
* @return $this
*/
public function onCollections(array $collections)
public function onBasesIds(array $basesIds)
{
$this->collections = $collections;
$this->basesIds = $basesIds;
// Defer databox retrieval
$this->databoxes = null;
$this->databoxesIds = null;
return $this;
}
/**
* Returns the collections on which the search occurs
* Returns the bases ids on which the search occurs
*
* @return \collection[] An array of collection
* @return int[]
*/
public function getCollections()
public function getBasesIds()
{
return $this->collections;
}
/**
* Returns an array containing all the databoxes where the search will
* happen
*
* @return \databox[]
*/
public function getDataboxes()
{
if (null === $this->databoxes) {
$databoxes = [];
foreach ($this->collections as $collection) {
$databoxes[$collection->get_databox()->get_sbas_id()] = $collection->get_databox();
}
$this->databoxes = array_values($databoxes);
if($this->basesIds === null) {
throw new \LogicException('onBasesIds() must be called before getBasesIds()');
}
return $this->databoxes;
return $this->basesIds;
}
/**
@@ -429,13 +357,16 @@ class SearchEngineOptions
return $this;
}
/** @return string */
/**
* @return string
*/
public function getRecordType()
{
return $this->record_type;
}
/**
* @param \DateTime $min_date
* @return $this
*/
public function setMinDate(\DateTime $min_date = null)
@@ -449,7 +380,8 @@ class SearchEngineOptions
return $this;
}
/** @return \DateTime
/**
* @return \DateTime
*/
public function getMinDate()
{
@@ -471,7 +403,9 @@ class SearchEngineOptions
return $this;
}
/** @return \DateTime */
/**
* @return \DateTime
*/
public function getMaxDate()
{
return $this->date_max;
@@ -494,89 +428,6 @@ class SearchEngineOptions
return $this->date_fields;
}
public function serialize()
{
$ret = [];
foreach (self::$serializable_properties as $key) {
$value = $this->{$key};
if ($value instanceof \DateTime) {
$value = $value->format(DATE_ATOM);
}
if (in_array($key, ['date_fields', 'fields'])) {
$value = array_map(function (\databox_field $field) {
return $field->get_databox()->get_sbas_id() . '_' . $field->get_id();
}, $value);
}
if (in_array($key, ['collections', 'business_fields'])) {
$value = array_map(function (\collection $collection) {
return $collection->get_base_id();
}, $value);
}
$ret[$key] = $value;
}
return \p4string::jsonencode($ret);
}
/**
*
* @param Application $app
* @param string $serialized
*
* @return $this
*
* @throws \InvalidArgumentException
* @throws \RuntimeException
*/
public static function hydrate(Application $app, $serialized)
{
$serialized = json_decode($serialized, true);
if (!is_array($serialized)) {
throw new \InvalidArgumentException('SearchEngineOptions data are corrupted');
}
$options = new static();
$options->disallowBusinessFields();
$methods = self::getHydrateMethods($app);
$sort_by = null;
$methods['sort_by'] = function ($value) use (&$sort_by) {
$sort_by = $value;
};
$sort_ord = null;
$methods['sort_ord'] = function ($value) use (&$sort_ord) {
$sort_ord = $value;
};
foreach ($serialized as $key => $value) {
if (!isset($methods[$key])) {
throw new \RuntimeException(sprintf('Unable to handle key `%s`', $key));
}
if ($value instanceof \stdClass) {
$value = (array)$value;
}
$callable = $methods[$key];
$callable($value, $options);
}
if ($sort_by) {
if ($sort_ord) {
$options->setSort($sort_by, $sort_ord);
} else {
$options->setSort($sort_by);
}
}
return $options;
}
/**
* Creates options based on a Symfony Request object
*
@@ -587,99 +438,21 @@ class SearchEngineOptions
*/
public static function fromRequest(Application $app, Request $request)
{
/** @var Authenticator $authenticator */
$authenticator = $app->getAuthenticator();
$isAuthenticated = $authenticator->isAuthenticated();
$options = new static();
$options->collectionReferenceRepository = $app['repo.collection-references'];
$options->disallowBusinessFields();
$options->setLocale($app['locale']);
/** @var Authenticator $authenticator */
$authenticator = $app->getAuthenticator();
$isAuthenticated = $authenticator->isAuthenticated();
/** @var ACLProvider $aclProvider */
$aclProvider = $app['acl'];
$acl = $isAuthenticated ? $aclProvider->get($authenticator->getUser()) : null;
$selected_bases = $request->get('bases');
if (is_array($selected_bases)) {
$bas = [];
foreach ($selected_bases as $bas_id) {
try {
$bas[$bas_id] = \collection::getByBaseId($app, $bas_id);
} catch (\Exception_Databox_CollectionNotFound $e) {
// Ignore
}
}
} elseif (!$isAuthenticated) {
$bas = $app->getOpenCollections();
} else {
$bas = $acl->get_granted_base();
}
// Filter out not found collections
$bas = array_filter($bas);
if ($acl) {
$filter = function (\collection $collection) use ($acl) {
return $acl->has_access_to_base($collection->get_base_id());
};
} else {
$openCollections = $app->getOpenCollections();
$filter = function (\collection $collection) use ($openCollections) {
return in_array($collection, $openCollections);
};
}
/** @var \collection[] $bas */
$bas = array_filter($bas, $filter);
if (!empty($selected_bases) && empty($bas)) {
throw new BadRequestHttpException('No collections match your criteria');
}
$options->onCollections($bas);
if ($isAuthenticated && $acl->has_right(\ACL::CANMODIFRECORD)) {
$bf = array_filter($bas, function (\collection $collection) use ($acl) {
return $acl->has_right_on_base($collection->get_base_id(), \ACL::CANMODIFRECORD);
});
$options->allowBusinessFieldsOn($bf);
}
$status = is_array($request->get('status')) ? $request->get('status') : [];
$fields = is_array($request->get('fields')) ? $request->get('fields') : [];
if (empty($fields)) {
// Select all fields (business included)
foreach ($options->getDataboxes() as $databox) {
foreach ($databox->get_meta_structure() as $field) {
$fields[] = $field->get_name();
}
}
$fields = array_unique($fields);
}
$databoxFields = [];
$databoxes = $options->getDataboxes();
foreach ($databoxes as $databox) {
$metaStructure = $databox->get_meta_structure();
foreach ($fields as $field) {
try {
$databoxField = $metaStructure->get_element_by_name($field);
} catch (\Exception $e) {
continue;
}
if ($databoxField) {
$databoxFields[] = $databoxField;
}
}
}
$options->setFields($databoxFields);
$options->setStatus($status);
$options->setSearchType($request->get('search_type'));
$options->setRecordType($request->get('record_type'));
$options->setSort($request->get('sort'), $request->get('ord', SearchEngineOptions::SORT_MODE_DESC));
$options->setStemming((Boolean) $request->get('stemme'));
$min_date = $max_date = null;
if ($request->get('date_min')) {
@@ -688,33 +461,106 @@ class SearchEngineOptions
if ($request->get('date_max')) {
$max_date = \DateTime::createFromFormat('Y/m/d H:i:s', $request->get('date_max') . ' 23:59:59');
}
$options->setMinDate($min_date);
$options->setMaxDate($max_date);
$status = is_array($request->get('status')) ? $request->get('status') : [];
$options->setStatus($status);
/** @var ACLProvider $aclProvider */
$aclProvider = $app['acl'];
$acl = $isAuthenticated ? $aclProvider->get($authenticator->getUser()) : null;
if ($acl) {
$searchableBaseIds = $acl->getSearchableBasesIds();
if (is_array($request->get('bases'))) {
$selected_bases = array_map(function($bid){return (int)$bid;}, $request->get('bases'));
$searchableBaseIds = array_values(array_intersect($searchableBaseIds, $selected_bases));
if (empty($searchableBaseIds)) {
throw new BadRequestHttpException('No collections match your criteria');
}
}
$options->onBasesIds($searchableBaseIds);
if ($acl->has_right(\ACL::CANMODIFRECORD)) {
/** @var int[] $bf */
$bf = array_filter($searchableBaseIds, function ($baseId) use ($acl) {
return $acl->has_right_on_base($baseId, \ACL::CANMODIFRECORD);
});
$options->allowBusinessFieldsOn($bf);
}
}
else {
$options->onBasesIds([]);
}
/** @var \databox[] $databoxes */
$databoxes = [];
foreach($options->getCollectionsReferencesByDatabox() as $sbid=>$refs) {
$databoxes[] = $app->findDataboxById($sbid);
}
$queryFields = is_array($request->get('fields')) ? $request->get('fields') : [];
if (empty($queryFields)) {
// Select all fields (business included)
foreach ($databoxes as $databox) {
foreach ($databox->get_meta_structure() as $field) {
$queryFields[] = $field->get_name();
}
}
}
$queryFields = array_unique($queryFields);
$queryDateFields = array_unique(explode('|', $request->get('date_field')));
$databoxFields = [];
$databoxDateFields = [];
foreach ($databoxes as $databox) {
$metaStructure = $databox->get_meta_structure();
foreach (explode('|', $request->get('date_field')) as $field) {
foreach ($queryFields as $fieldName) {
try {
$databoxField = $metaStructure->get_element_by_name($field);
if( ($databoxField = $metaStructure->get_element_by_name($fieldName, databox_descriptionStructure::STRICT_COMPARE)) ) {
$databoxFields[] = $databoxField;
}
} catch (\Exception $e) {
continue;
// no-op
}
if ($databoxField) {
$databoxDateFields[] = $databoxField;
}
foreach ($queryDateFields as $fieldName) {
try {
if( ($databoxField = $metaStructure->get_element_by_name($fieldName, databox_descriptionStructure::STRICT_COMPARE)) ) {
$databoxDateFields[] = $databoxField;
}
} catch (\Exception $e) {
// no-op
}
}
}
$options->setFields($databoxFields);
$options->setDateFields($databoxDateFields);
$options->setSort($request->get('sort'), $request->get('ord', SearchEngineOptions::SORT_MODE_DESC));
$options->setStemming((Boolean) $request->get('stemme'));
return $options;
}
public function getCollectionsReferencesByDatabox()
{
if($this->collectionsReferencesByDatabox === null) {
$this->collectionsReferencesByDatabox = [];
$refs = $this->collectionReferenceRepository->findMany($this->getBasesIds());
foreach($refs as $ref) {
$sbid = $ref->getDataboxId();
if(!array_key_exists($sbid, $this->collectionsReferencesByDatabox)) {
$this->collectionsReferencesByDatabox[$sbid] = [];
}
$this->collectionsReferencesByDatabox[$sbid][] = $ref;
}
}
return $this->collectionsReferencesByDatabox;
}
public function setMaxResults($max_results)
{
Assertion::greaterOrEqualThan($max_results, 0);
@@ -745,4 +591,133 @@ class SearchEngineOptions
{
return $this->first_result;
}
/**
* @param Application $app
* @return callable[]
*/
private static function getHydrateMethods(Application $app)
{
$fieldNormalizer = function ($value) use ($app) {
return array_map(function ($serialized) use ($app) {
$data = explode('_', $serialized, 2);
return $app->findDataboxById($data[0])->get_meta_structure()->get_element($data[1]);
}, $value);
};
$optionSetter = function ($setter) {
return function ($value, SearchEngineOptions $options) use ($setter) {
$options->{$setter}($value);
};
};
return [
'record_type' => $optionSetter('setRecordType'),
'search_type' => $optionSetter('setSearchType'),
'status' => $optionSetter('setStatus'),
'date_min' => function ($value, SearchEngineOptions $options) {
$options->setMinDate($value ? \DateTime::createFromFormat(DATE_ATOM, $value) : null);
},
'date_max' => function ($value, SearchEngineOptions $options) {
$options->setMaxDate($value ? \DateTime::createFromFormat(DATE_ATOM, $value) : null);
},
'i18n' => function ($value, SearchEngineOptions $options) {
if ($value) {
$options->setLocale($value);
}
},
'stemming' => $optionSetter('setStemming'),
'date_fields' => function ($value, SearchEngineOptions $options) use ($fieldNormalizer) {
$options->setDateFields($fieldNormalizer($value));
},
'fields' => function ($value, SearchEngineOptions $options) use ($fieldNormalizer) {
$options->setFields($fieldNormalizer($value));
},
'basesIds' => function ($value, SearchEngineOptions $options) {
$options->onBasesIds($value);
},
//'business_fields' => function ($value, SearchEngineOptions $options) use ($collectionNormalizer) {
// $options->allowBusinessFieldsOn($collectionNormalizer($value));
//},
'business_fields' => function ($value, SearchEngineOptions $options) {
$options->allowBusinessFieldsOn($value);
},
'first_result' => $optionSetter('setFirstResult'),
'max_results' => $optionSetter('setMaxResults'),
];
}
public function serialize()
{
$ret = [];
foreach (self::$serializable_properties as $key) {
$value = $this->{$key};
if ($value instanceof \DateTime) {
$value = $value->format(DATE_ATOM);
}
if (in_array($key, ['date_fields', 'fields'])) {
$value = array_map(function (\databox_field $field) {
return $field->get_databox()->get_sbas_id() . '_' . $field->get_id();
}, $value);
}
$ret[$key] = $value;
}
return \p4string::jsonencode($ret);
}
/**
*
* @param Application $app
* @param string $serialized
*
* @return $this
*
* @throws \InvalidArgumentException
* @throws \RuntimeException
*/
public static function hydrate(Application $app, $serialized)
{
$serialized = json_decode($serialized, true);
if (!is_array($serialized)) {
throw new \InvalidArgumentException('SearchEngineOptions data are corrupted');
}
$options = new static();
$options->disallowBusinessFields();
$methods = self::getHydrateMethods($app);
$sort_by = null;
$methods['sort_by'] = function ($value) use (&$sort_by) {
$sort_by = $value;
};
$sort_ord = null;
$methods['sort_ord'] = function ($value) use (&$sort_ord) {
$sort_ord = $value;
};
foreach ($serialized as $key => $value) {
if (!isset($methods[$key])) {
throw new \RuntimeException(sprintf('Unable to handle key `%s`', $key));
}
if ($value instanceof \stdClass) {
$value = (array)$value;
}
$callable = $methods[$key];
$callable($value, $options);
}
if ($sort_by) {
if ($sort_ord) {
$options->setSort($sort_by, $sort_ord);
} else {
$options->setSort($sort_by);
}
}
return $options;
}
}

View File

@@ -10,7 +10,9 @@
*/
use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Collection\Reference\CollectionReference;
use Alchemy\Phrasea\Collection\Reference\CollectionReferenceCollection;
use Alchemy\Phrasea\Collection\Reference\DbalCollectionReferenceRepository;
use Alchemy\Phrasea\Core\Event\Acl\AccessPeriodChangedEvent;
use Alchemy\Phrasea\Core\Event\Acl\AccessToBaseGrantedEvent;
use Alchemy\Phrasea\Core\Event\Acl\AccessToBaseRevokedEvent;
@@ -775,6 +777,41 @@ class ACL implements cache_cacheableInterface
return $ret;
}
/**
* @return array baseIds where user can search
*/
public function getSearchableBasesIds()
{
static $ret = null;
if($ret === null) {
$this->load_rights_bas();
foreach ($this->_rights_bas as $baseId => $rights) {
if ($this->has_access_to_base($baseId) && !$this->is_limited($baseId)) {
$ret[] = $baseId;
}
}
}
return $ret;
}
/**
* @return CollectionReference[] CollectionsReferences where the user can search;
*/
public function getSearchableBasesReferences()
{
static $ret = null;
if($ret == null) {
/** @var DbalCollectionReferenceRepository $dbalCollectionReferenceRepository */
$dbalCollectionReferenceRepository = $this->app['repo.collection-references'];
$ret = $dbalCollectionReferenceRepository->findMany($this->getSearchableBasesIds());
}
return $ret;
}
/**
* Return an array of databox (key=sbas_id) which are granted, with
* optionnal filter by rights

View File

@@ -888,7 +888,7 @@ class databox extends base implements ThumbnailedElement
/** @var \Alchemy\Phrasea\Databox\Field\DataboxFieldRepository $fieldRepository */
$fieldRepository = $this->app['repo.fields.factory']($this);
$this->meta_struct = new databox_descriptionStructure($fieldRepository->findAll());
$this->meta_struct = new databox_descriptionStructure($fieldRepository->findAll(), $this->app['unicode']);
return $this->meta_struct;
}

View File

@@ -17,18 +17,26 @@ class databox_descriptionStructure implements IteratorAggregate, Countable
*/
protected $elements = [];
/** @var unicode */
private $unicode;
const STRICT_COMPARE = 1;
const SLUG_COMPARE = 2;
/**
* Cache array for the get element by name function
*
* @var array<string,int>|null
* @var int[]|null
*/
protected $cache_name_id;
/**
* @param databox_field[] $fields
* @param unicode $unicode
*/
public function __construct($fields = [])
public function __construct($fields, unicode $unicode)
{
$this->unicode = $unicode;
Assertion::allIsInstanceOf($fields, databox_field::class);
foreach ($fields as $field) {
@@ -95,9 +103,11 @@ class databox_descriptionStructure implements IteratorAggregate, Countable
/**
* @param string $name
* @param int $compareMode // use STRICT_COMPARE if the name already comes from phrasea (faster)
*
* @return databox_field|null
*/
public function get_element_by_name($name)
public function get_element_by_name($name, $compareMode=self::SLUG_COMPARE)
{
if (null === $this->cache_name_id) {
$this->cache_name_id = [];
@@ -107,7 +117,9 @@ class databox_descriptionStructure implements IteratorAggregate, Countable
}
}
$name = databox_field::generateName($name);
if($compareMode == self::SLUG_COMPARE) {
$name = databox_field::generateName($name, $this->unicode);
}
return isset($this->cache_name_id[$name])
? $this->elements[$this->cache_name_id[$name]]

View File

@@ -32,7 +32,7 @@ class databox_field implements cache_cacheableInterface
protected $databox;
/** DO NOT IMPORT, makes PHPSTORM HANG. PHPExiftool\Driver\TagInterface */
protected $tag;
private $tag;
protected $name;
protected $indexable;
@@ -79,12 +79,12 @@ class databox_field implements cache_cacheableInterface
/**
* @var databox_Field_DCESAbstract|null
*/
protected $dces_element;
private $dces_element;
/**
* @var ControlProviderInterface|null
*/
protected $Vocabulary;
protected $vocabulary_control;
/**
* @var string|null
@@ -95,8 +95,9 @@ class databox_field implements cache_cacheableInterface
* @var bool
*/
protected $VocabularyRestriction = false;
protected $on_error = false;
private $on_error = false;
protected $original_src;
protected $original_dces;
protected $aggregable;
const TYPE_TEXT = "text";
@@ -146,13 +147,11 @@ class databox_field implements cache_cacheableInterface
$this->id = (int)$row['id'];
$this->name = $row['name'];
$this->original_src = $row['src'];
$this->tag = in_array($row['src'], ['', 'Phraseanet:no-source'], true)
? new NoSource($this->name)
: self::loadClassFromTagName($row['src'], false);
if ($row['src'] !== '' && $row['src'] !== $this->tag->getTagname()) {
$this->on_error = true;
}
$this->original_dces = $row['dces_element'];
$this->tag = false; // lazy loaded on this->get_tag(), will become an object
$this->dces_element = false; // loazy loaded on this->get_dces_element(), will become an object or null
$this->on_error = false; // lazy calculated on this->is_on_error()
$this->vocabulary_control = false; // lazy loaded
foreach (['en', 'fr', 'de', 'nl'] as $code) {
$this->labels[$code] = $row['label_' . $code];
@@ -171,16 +170,9 @@ class databox_field implements cache_cacheableInterface
$this->VocabularyType = $row['VocabularyControlType'];
$this->VocabularyRestriction = (bool)$row['RestrictToVocabularyControl'];
if (isset($row['dces_element'])) {
$class = self::$knownDCES[$row['dces_element']];
$this->dces_element = new $class();
}
$this->separator = self::checkMultiSeparator($row['separator'], $this->multi);
$this->thumbtitle = $row['thumbtitle'];
$this->loadVocabulary();
}
/**
@@ -188,7 +180,7 @@ class databox_field implements cache_cacheableInterface
*/
public function getVocabularyControl()
{
return $this->Vocabulary;
return $this->vocabulary_control;
}
/**
@@ -196,7 +188,12 @@ class databox_field implements cache_cacheableInterface
*/
public function isVocabularyRestricted()
{
return $this->VocabularyRestriction;
// lazy load
if($this->vocabulary_control === false) {
$this->loadVocabulary();
}
return $this->vocabulary_control;
}
/**
@@ -322,7 +319,7 @@ class databox_field implements cache_cacheableInterface
$params = [
':name' => $this->name,
':source' => $this->tag->getTagname(),
':source' => $this->get_tag()->getTagname(),
':indexable' => $this->indexable ? '1' : '0',
':readonly' => $this->readonly ? '1' : '0',
':required' => $this->required ? '1' : '0',
@@ -335,8 +332,8 @@ class databox_field implements cache_cacheableInterface
':tbranch' => $this->tbranch,
':position' => $this->position,
':thumbtitle' => $this->thumbtitle,
':VocabularyControlType' => $this->Vocabulary ? $this->Vocabulary->getType() : null,
':RestrictVocab' => $this->Vocabulary ? ($this->VocabularyRestriction ? '1' : '0') : '0',
':VocabularyControlType' => $this->getVocabularyControl() ? $this->getVocabularyControl()->getType() : null,
':RestrictVocab' => $this->getVocabularyControl() ? ($this->VocabularyRestriction ? '1' : '0') : '0',
':id' => $this->id,
':label_en' => isset($this->labels['en']) ? $this->labels['en'] : null,
':label_fr' => isset($this->labels['fr']) ? $this->labels['fr'] : null,
@@ -374,7 +371,7 @@ class databox_field implements cache_cacheableInterface
$nodes_parent->item(0)->replaceChild($meta, $old_meta);
}
}
$meta->setAttribute('src', $this->tag->getTagname());
$meta->setAttribute('src', $this->get_tag()->getTagname());
$meta->setAttribute('index', $this->indexable ? '1' : '0');
$meta->setAttribute('readonly', $this->readonly ? '1' : '0');
$meta->setAttribute('required', $this->required ? '1' : '0');
@@ -444,15 +441,16 @@ class databox_field implements cache_cacheableInterface
}
/**
*
* @param string $name
* @param string $name
* @return databox_field
*
* @throws Exception_InvalidArgument
*/
public function set_name($name)
{
$previous_name = $this->name;
$name = self::generateName($name);
$name = self::generateName($name, $this->app['unicode']);
if ($name === '') {
throw new \Exception_InvalidArgument();
@@ -513,6 +511,13 @@ class databox_field implements cache_cacheableInterface
*/
public function get_tag()
{
// lazy loading
if ($this->tag === false) {
$this->tag = in_array($this->original_src, ['', 'Phraseanet:no-source'], true)
? new NoSource($this->name)
: self::loadClassFromTagName($this->original_src, false);
}
return $this->tag;
}
@@ -521,6 +526,16 @@ class databox_field implements cache_cacheableInterface
*/
public function get_dces_element()
{
// lazy loading
if ($this->dces_element === false) {
if (array_key_exists($this->original_dces, self::$knownDCES)) {
$class = self::$knownDCES[$this->original_dces];
$this->dces_element = new $class();
} else {
$this->dces_element = null;
}
}
return $this->dces_element;
}
@@ -579,12 +594,12 @@ class databox_field implements cache_cacheableInterface
/**
* Set a vocabulary
*
* @param ControlProviderInterface $vocabulary
* @param ControlProviderInterface $vocabulary_control
* @return \databox_field
*/
public function setVocabularyControl(ControlProviderInterface $vocabulary = null)
public function setVocabularyControl(ControlProviderInterface $vocabulary_control = null)
{
$this->Vocabulary = $vocabulary;
$this->vocabulary_control = $vocabulary_control;
return $this;
}
@@ -864,7 +879,7 @@ class databox_field implements cache_cacheableInterface
*/
public function is_on_error()
{
return $this->on_error;
return $this->original_src !== '' && $this->original_src !== $this->get_tag()->getTagname();
}
public function toArray()
@@ -874,7 +889,7 @@ class databox_field implements cache_cacheableInterface
'sbas-id' => $this->sbas_id,
'labels' => $this->labels,
'name' => $this->name,
'tag' => $this->tag->getTagname(),
'tag' => $this->get_tag()->getTagname(),
'business' => $this->Business,
'aggregable' => $this->aggregable,
'type' => $this->type,
@@ -887,8 +902,8 @@ class databox_field implements cache_cacheableInterface
'readonly' => $this->readonly,
'multi' => $this->multi,
'indexable' => $this->indexable,
'dces-element' => $this->dces_element ? $this->dces_element->get_label() : null,
'vocabulary-type' => $this->Vocabulary ? $this->Vocabulary->getType() : null,
'dces-element' => $this->get_dces_element() ? $this->get_dces_element()->get_label() : null,
'vocabulary-type' => $this->getVocabularyControl() ? $this->getVocabularyControl()->getType() : null,
'vocabulary-restricted' => $this->VocabularyRestriction,
];
}
@@ -926,7 +941,7 @@ class databox_field implements cache_cacheableInterface
null, 0, 0, 0,
1, :sorter, '')";
$name = self::generateName($name);
$name = self::generateName($name, $app['unicode']);
if ($name === '') {
throw new \Exception_InvalidArgument();
@@ -942,10 +957,8 @@ class databox_field implements cache_cacheableInterface
return $databox->get_meta_structure()->get_element($id);
}
public static function generateName($name)
public static function generateName($name, unicode $unicode_processor)
{
$unicode_processor = new unicode();
$name = $unicode_processor->remove_nonazAZ09($name, false, false);
return $unicode_processor->remove_first_digits($name);
@@ -959,7 +972,7 @@ class databox_field implements cache_cacheableInterface
$vars = [];
foreach ($this as $key => $value) {
if (in_array($key, ['databox', 'app', 'Vocabulary']))
if (in_array($key, ['databox', 'app', 'vocabulary_control']))
continue;
$vars[] = $key;
}
@@ -1020,7 +1033,7 @@ class databox_field implements cache_cacheableInterface
}
try {
$this->Vocabulary = $this->app['vocabularies'][$this->VocabularyType];
$this->vocabulary_control = $this->app['vocabularies'][$this->VocabularyType];
} catch (\InvalidArgumentException $e) {
// Could not find Vocabulary
}

View File

@@ -1529,6 +1529,49 @@ $(document).ready(function () {
}
});
$("#EDIT_query").autocomplete({
delay: 200,
minLength: 2,
source: function (request, response) {
var inp = document.getElementById("EDIT_query");
var data={
'_selectionStart': inp.selectionStart,
'_selectionEnd': inp.selectionEnd
};
var a = $("#searchForm").serializeArray();
for(var i=0; i<a.length; i++) {
var k = a[i].name;
var v = a[i].value;
if(k.substring(k.length-2) == "[]") {
if(data[k] == undefined) {
data[k] = [];
}
data[k].push(v);
}
else {
data[k] = v;
}
}
$.ajax({
url: '/prod/query/completion/',
dataType: "json",
method: "post",
data: data,
success: function (data) {
response(data);
}
});
},
focus: function(event, ui) {
event.preventDefault();
},
select: function (event, ui) {
$("#EDIT_query").val(ui.item.value.completed);
return false;
}
});
$('input.input_select_copy').on('focus', function () {
$(this).select();
});

View File

@@ -48,7 +48,8 @@ class QueryTest extends \PhraseanetAuthenticatedWebTestCase
$this->authenticate($app);
$options = new SearchEngineOptions();
$options->onCollections($app->getAclForUser($app->getAuthenticatedUser())->get_granted_base());
$searchableBasesIds = $app->getAclForUser($app->getAuthenticatedUser())->getSearchableBasesIds();
$options->onBasesIds($searchableBasesIds);
$serializedOptions = $options->serialize();
$response = $this->request('POST', '/prod/query/answer-train/', [

View File

@@ -103,7 +103,8 @@ class RecordsTest extends \PhraseanetAuthenticatedWebTestCase
$options = new SearchEngineOptions();
$acl = $app->getAclForUser($app->getAuthenticatedUser());
$options->onCollections($acl->get_granted_base());
$searchableBasesIds = $acl->getSearchableBasesIds();
$options->onBasesIds($searchableBasesIds);
$serializedOptions = $options->serialize();
$response = $this->XMLHTTPRequest('POST', '/prod/records/', [

View File

@@ -3,6 +3,7 @@
namespace Alchemy\Tests\Phrasea\SearchEngine;
use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Collection\Reference\CollectionReference;
use Alchemy\Phrasea\SearchEngine\SearchEngineOptions;
use Symfony\Component\HttpFoundation\Request;
@@ -20,14 +21,13 @@ class SearchEngineOptionsTest extends \PhraseanetTestCase
/** @var Application $app */
$app = self::$DI['app'];
/** @var \collection $collection */
$collection = self::$DI['collection'];
$collections[$collection->get_base_id()] = $collection;
$collection = $this->getCollection();
$options = new SearchEngineOptions($app);
$options->onCollections($collections);
$options->onBasesIds([$collection->get_base_id()]);
$options->setRecordType(SearchEngineOptions::TYPE_ALL);
$options->setSearchType(SearchEngineOptions::RECORD_RECORD);
$options->allowBusinessFieldsOn($collections);
$options->allowBusinessFieldsOn([$collection->get_base_id()]);
foreach ($collection->get_databox()->get_meta_structure() as $field) {
$options->setFields([$field]);
@@ -57,6 +57,9 @@ class SearchEngineOptionsTest extends \PhraseanetTestCase
$app = self::$DI['app'];
$this->authenticate($app);
/** @var \collection $collection */
$collection = self::$DI['collection'];
$sbid = $collection->get_sbas_id();
foreach ($this->provideRequestData() as $pack) {
list ($query, $request, $field, $dateField) = $pack;
@@ -65,9 +68,12 @@ class SearchEngineOptionsTest extends \PhraseanetTestCase
$options = SearchEngineOptions::fromRequest($app, $httpRequest);
// Check done this way because returned array can be indexed differently
$collections = $options->getCollections();
$this->assertCount(1, $collections);
$this->assertContains(self::$DI['collection'], $collections);
$collectionsReferences = $options->getCollectionsReferencesByDatabox();
$this->assertCount(1, $collectionsReferences);
$this->assertCount(1, $collectionsReferences[$sbid]);
/** @var CollectionReference $collRef */
$collRef = $collectionsReferences[$sbid][0];
$this->assertEquals($collection->get_base_id(), $collRef->getBaseId());
$this->assertEquals([$field], $options->getFields());
$this->assertEquals('video', $options->getRecordType());
$this->assertEquals('1', $options->getSearchType());
@@ -99,7 +105,7 @@ class SearchEngineOptionsTest extends \PhraseanetTestCase
$options = SearchEngineOptions::fromRequest(self::$DI['app'], $httpRequest);
$this->assertEquals([], $options->getCollections());
$this->assertEquals([], $options->getCollectionsReferencesByDatabox());
$this->assertEquals([], $options->getFields());
$this->assertEquals('video', $options->getRecordType());
$this->assertEquals('1', $options->getSearchType());
@@ -119,7 +125,7 @@ class SearchEngineOptionsTest extends \PhraseanetTestCase
{
$options = SearchEngineOptions::fromRequest(self::$DI['app'], new Request());
$this->assertEquals([], $options->getCollections());
$this->assertEquals([], $options->getCollectionsReferencesByDatabox());
$this->assertEquals([], $options->getFields());
$this->assertEquals(null, $options->getRecordType());
$this->assertEquals('0', $options->getSearchType());

View File

@@ -33,7 +33,7 @@ class LimitedStructureTest extends \PHPUnit_Framework_TestCase
{
$wrapped = $this->prophesize(Structure::class);
$options = $this->prophesize(SearchEngineOptions::class);
$options->getBusinessFieldsOn()->willReturn([$this->getCollectionStub(2)]);
$options->getBusinessFieldsOn()->willReturn([2]);
$structure = new LimitedStructure($wrapped->reveal(), $options->reveal());
$wrapped->get('foo')
@@ -58,10 +58,7 @@ class LimitedStructureTest extends \PHPUnit_Framework_TestCase
public function testGetAllFields()
{
$options = $this->prophesize(SearchEngineOptions::class);
$options->getBusinessFieldsOn()->willReturn([
$this->getCollectionStub(1),
$this->getCollectionStub(3)
]);
$options->getBusinessFieldsOn()->willReturn([1, 3]);
$wrapped = $this->prophesize(Structure::class);
$structure = new LimitedStructure($wrapped->reveal(), $options->reveal());

View File

@@ -5,6 +5,7 @@ use Alchemy\Phrasea\Authentication\ACLProvider;
use Alchemy\Phrasea\Border\File;
use Alchemy\Phrasea\Cache\Manager as CacheManager;
use Alchemy\Phrasea\CLI;
use Alchemy\Phrasea\Collection\Reference\CollectionReference;
use Alchemy\Phrasea\Model\Entities\Session;
use Alchemy\Phrasea\Model\Entities\User;
use Alchemy\Phrasea\SearchEngine\SearchEngineInterface;
@@ -199,6 +200,12 @@ abstract class PhraseanetTestCase extends WebTestCase
return collection::getByBaseId($DI['app'], self::$fixtureIds['collection']['coll']);
});
self::$DI['collectionReference'] = self::$DI->share(function ($DI) {
/** @var \Alchemy\Phrasea\Collection\Reference\DbalCollectionReferenceRepository $repo */
$repo = self::$DI['app']['repo.collection-references'];
return $repo->find(self::$fixtureIds['collection']['coll']);
});
self::$DI['collection_no_access'] = self::$DI->share(function ($DI) {
return collection::getByBaseId($DI['app'], self::$fixtureIds['collection']['coll_no_access']);
});
@@ -329,6 +336,14 @@ abstract class PhraseanetTestCase extends WebTestCase
return self::$DI['collection'];
}
/**
* @return CollectionReference
*/
public function getCollectionReference()
{
return self::$DI['collectionReference'];
}
public static function tearDownAfterClass()
{
gc_collect_cycles();

View File

@@ -8,7 +8,7 @@ class databox_descriptionStructureTest extends \PhraseanetTestCase
{
public function testToArray()
{
$structure = new \databox_descriptionStructure();
$structure = new \databox_descriptionStructure([], new unicode());
$array = ['name1' => 'value1', 'name2' => 'value2'];

View File

@@ -279,8 +279,13 @@ class media_subdefTest extends \PhraseanetTestCase
self::$objectPresent->rotate(90, self::$DI['app']['media-alchemyst'], self::$DI['app']['mediavorus']);
$this->assertEquals($width_before, self::$objectPresent->get_height());
$this->assertEquals($height_before, self::$objectPresent->get_width());
// because rotate may cause round errors we check with +-1?
$this->assertGreaterThanOrEqual($width_before-1, self::$objectPresent->get_height());
$this->assertLessThanOrEqual($width_before+1, self::$objectPresent->get_height());
$this->assertGreaterThanOrEqual($height_before-1, self::$objectPresent->get_width());
$this->assertLessThanOrEqual($height_before+1, self::$objectPresent->get_width());
}
/**