Merge branch 'hoa-compiler' into elastic-indexer

Conflicts:
	lib/Alchemy/Phrasea/SearchEngine/Elastic/ElasticSearchEngine.php
This commit is contained in:
Mathieu Darse
2014-12-03 19:42:41 +01:00
23 changed files with 1380 additions and 137 deletions

7
Makefile Normal file
View File

@@ -0,0 +1,7 @@
config:
@php bin/console compile:configuration
watch:
@echo 'config/configuration.yml' | entr make config
.PHONY: config watch

View File

@@ -14,6 +14,7 @@ namespace KonsoleKommander;
use Alchemy\Phrasea\Command\Plugin\ListPlugin; use Alchemy\Phrasea\Command\Plugin\ListPlugin;
use Alchemy\Phrasea\Command\Setup\H264ConfigurationDumper; use Alchemy\Phrasea\Command\Setup\H264ConfigurationDumper;
use Alchemy\Phrasea\Command\Setup\H264MappingGenerator; use Alchemy\Phrasea\Command\Setup\H264MappingGenerator;
use Alchemy\Phrasea\Command\SearchEngine\Debug\QueryParseCommand;
use Alchemy\Phrasea\Command\SearchEngine\IndexCreateCommand; use Alchemy\Phrasea\Command\SearchEngine\IndexCreateCommand;
use Alchemy\Phrasea\Command\SearchEngine\IndexDropCommand; use Alchemy\Phrasea\Command\SearchEngine\IndexDropCommand;
use Alchemy\Phrasea\Command\SearchEngine\IndexFull; use Alchemy\Phrasea\Command\SearchEngine\IndexFull;
@@ -127,6 +128,7 @@ if ($cli['search_engine.type'] === SearchEngineInterface::TYPE_ELASTICSEARCH) {
$cli->command(new IndexCreateCommand()); $cli->command(new IndexCreateCommand());
$cli->command(new IndexDropCommand()); $cli->command(new IndexDropCommand());
$cli->command(new IndexPopulateCommand()); $cli->command(new IndexPopulateCommand());
$cli->command(new QueryParseCommand());
} }
$cli->command(new WebsocketServer('ws-server:run')); $cli->command(new WebsocketServer('ws-server:run'));

View File

@@ -73,7 +73,8 @@
"vierbergenlars/php-semver" : "~2.1", "vierbergenlars/php-semver" : "~2.1",
"zend/gdata" : "~1.12.1", "zend/gdata" : "~1.12.1",
"doctrine/migrations" : "1.0.x-dev@dev", "doctrine/migrations" : "1.0.x-dev@dev",
"willdurand/negotiation" : "~1.3" "willdurand/negotiation" : "~1.3",
"hoa/compiler": "2.14.09.23"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit" : "~3.7", "phpunit/phpunit" : "~3.7",
@@ -83,7 +84,9 @@
"behat/mink-extension" : "~1.0", "behat/mink-extension" : "~1.0",
"behat/mink-goutte-driver" : "~1.0", "behat/mink-goutte-driver" : "~1.0",
"behat/mink-selenium2-driver" : "~1.0", "behat/mink-selenium2-driver" : "~1.0",
"fabpot/goutte" : "~1.0" "fabpot/goutte" : "~1.0",
"hoa/dispatcher": "0.14.09.23",
"hoa/console": "2.14.09.23"
}, },
"autoload": { "autoload": {
"psr-0": { "psr-0": {

766
composer.lock generated
View File

@@ -4,22 +4,16 @@
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"hash": "69bf40de460d2f7a3407f1b905dde913", "hash": "73cfb65537610dfd0edc9cf6485c4ebb",
"packages": [ "packages": [
{ {
"name": "alchemy-fr/tcpdf-clone", "name": "alchemy-fr/tcpdf-clone",
"version": "6.0.039", "version": "6.0.039",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/alchemy-fr/tcpdf-clone.git", "url": "https://github.com/alchemy-fr/tcpdf-clone",
"reference": "2ba0248a7187f1626df6c128750650416267f0e7" "reference": "2ba0248a7187f1626df6c128750650416267f0e7"
}, },
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/alchemy-fr/tcpdf-clone/zipball/2ba0248a7187f1626df6c128750650416267f0e7",
"reference": "2ba0248a7187f1626df6c128750650416267f0e7",
"shasum": ""
},
"require": { "require": {
"php": ">=5.3.0" "php": ">=5.3.0"
}, },
@@ -66,10 +60,6 @@
"qrcode", "qrcode",
"tcpdf" "tcpdf"
], ],
"support": {
"source": "https://github.com/alchemy-fr/tcpdf-clone/tree/6.0.039",
"issues": "https://github.com/alchemy-fr/tcpdf-clone/issues"
},
"time": "2013-10-13 16:11:17" "time": "2013-10-13 16:11:17"
}, },
{ {
@@ -113,7 +103,7 @@
"homepage": "http://www.lickmychip.com/" "homepage": "http://www.lickmychip.com/"
}, },
{ {
"name": "nlegoff", "name": "Nicolas Le Goff",
"email": "legoff.n@gmail.com" "email": "legoff.n@gmail.com"
}, },
{ {
@@ -301,7 +291,7 @@
} }
}, },
"notification-url": "https://packagist.org/downloads/", "notification-url": "https://packagist.org/downloads/",
"time": "2014-07-07 16:25:07" "time": "2014-07-07 14:01:51"
}, },
{ {
"name": "alchemy/task-manager", "name": "alchemy/task-manager",
@@ -372,12 +362,12 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/alchemy-fr/Zippy.git", "url": "https://github.com/alchemy-fr/Zippy.git",
"reference": "08008f82957b7dc2b54574b506687b33ecfe0589" "reference": "d2f5e88f2436b9c1294e8819d951822abe39e9a7"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/alchemy-fr/Zippy/zipball/08008f82957b7dc2b54574b506687b33ecfe0589", "url": "https://api.github.com/repos/alchemy-fr/Zippy/zipball/d2f5e88f2436b9c1294e8819d951822abe39e9a7",
"reference": "08008f82957b7dc2b54574b506687b33ecfe0589", "reference": "d2f5e88f2436b9c1294e8819d951822abe39e9a7",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -426,7 +416,7 @@
"tar", "tar",
"zip" "zip"
], ],
"time": "2014-09-03 08:10:41" "time": "2014-05-05 13:39:00"
}, },
{ {
"name": "cboden/ratchet", "name": "cboden/ratchet",
@@ -747,7 +737,7 @@
{ {
"name": "Johannes Schmitt", "name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com", "email": "schmittjoh@gmail.com",
"homepage": "https://github.com/schmittjoh", "homepage": "http://jmsyst.com",
"role": "Developer of wrapped JMSSerializerBundle" "role": "Developer of wrapped JMSSerializerBundle"
} }
], ],
@@ -935,8 +925,7 @@
{ {
"name": "Jonathan Wage", "name": "Jonathan Wage",
"email": "jonwage@gmail.com", "email": "jonwage@gmail.com",
"homepage": "http://www.jwage.com/", "homepage": "http://www.jwage.com/"
"role": "Creator"
}, },
{ {
"name": "Guilherme Blanco", "name": "Guilherme Blanco",
@@ -954,7 +943,7 @@
{ {
"name": "Johannes Schmitt", "name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com", "email": "schmittjoh@gmail.com",
"homepage": "https://github.com/schmittjoh", "homepage": "http://jmsyst.com",
"role": "Developer of wrapped JMSSerializerBundle" "role": "Developer of wrapped JMSSerializerBundle"
} }
], ],
@@ -1008,7 +997,7 @@
{ {
"name": "Johannes Schmitt", "name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com", "email": "schmittjoh@gmail.com",
"homepage": "https://github.com/schmittjoh", "homepage": "http://jmsyst.com",
"role": "Developer of wrapped JMSSerializerBundle" "role": "Developer of wrapped JMSSerializerBundle"
} }
], ],
@@ -1026,12 +1015,12 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/doctrine/migrations.git", "url": "https://github.com/doctrine/migrations.git",
"reference": "1a9dffa64e33fdc10f4b4c3f5d7230b74d4a1021" "reference": "4256449c5e2603a6b6ee5a78c7c4521d4d4430b8"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/doctrine/migrations/zipball/1a9dffa64e33fdc10f4b4c3f5d7230b74d4a1021", "url": "https://api.github.com/repos/doctrine/migrations/zipball/4256449c5e2603a6b6ee5a78c7c4521d4d4430b8",
"reference": "1a9dffa64e33fdc10f4b4c3f5d7230b74d4a1021", "reference": "4256449c5e2603a6b6ee5a78c7c4521d4d4430b8",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1062,12 +1051,14 @@
], ],
"authors": [ "authors": [
{ {
"name": "Benjamin Eberlei", "name": "Jonathan Wage",
"email": "kontakt@beberlei.de" "email": "jonwage@gmail.com",
"homepage": "http://www.jwage.com/",
"role": "Creator"
}, },
{ {
"name": "Jonathan Wage", "name": "Benjamin Eberlei",
"email": "jonwage@gmail.com" "email": "kontakt@beberlei.de"
} }
], ],
"description": "Database Schema migrations using Doctrine DBAL", "description": "Database Schema migrations using Doctrine DBAL",
@@ -1076,7 +1067,7 @@
"database", "database",
"migrations" "migrations"
], ],
"time": "2014-08-18 18:03:07" "time": "2014-07-09 07:58:02"
}, },
{ {
"name": "doctrine/orm", "name": "doctrine/orm",
@@ -1213,13 +1204,13 @@
"version": "v1.0.0", "version": "v1.0.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/igorw/evenement.git", "url": "https://github.com/igorw/evenement",
"reference": "fa966683e7df3e5dd5929d984a44abfbd6bafe8d" "reference": "v1.0.0"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/igorw/evenement/zipball/fa966683e7df3e5dd5929d984a44abfbd6bafe8d", "url": "https://github.com/igorw/evenement/zipball/v1.0.0",
"reference": "fa966683e7df3e5dd5929d984a44abfbd6bafe8d", "reference": "v1.0.0",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1246,7 +1237,7 @@
"keywords": [ "keywords": [
"event-dispatcher" "event-dispatcher"
], ],
"time": "2012-05-30 15:01:08" "time": "2012-05-30 08:01:08"
}, },
{ {
"name": "facebook/php-sdk", "name": "facebook/php-sdk",
@@ -1299,12 +1290,12 @@
"version": "v2.3.9", "version": "v2.3.9",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/Atlantic18/DoctrineExtensions.git", "url": "https://github.com/l3pp4rd/DoctrineExtensions.git",
"reference": "35adcaae1a3f50d0d5b73aa50ed8fd28ee35ce54" "reference": "35adcaae1a3f50d0d5b73aa50ed8fd28ee35ce54"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/Atlantic18/DoctrineExtensions/zipball/35adcaae1a3f50d0d5b73aa50ed8fd28ee35ce54", "url": "https://api.github.com/repos/l3pp4rd/DoctrineExtensions/zipball/35adcaae1a3f50d0d5b73aa50ed8fd28ee35ce54",
"reference": "35adcaae1a3f50d0d5b73aa50ed8fd28ee35ce54", "reference": "35adcaae1a3f50d0d5b73aa50ed8fd28ee35ce54",
"shasum": "" "shasum": ""
}, },
@@ -1372,7 +1363,7 @@
"tree", "tree",
"uploadable" "uploadable"
], ],
"time": "2014-01-12 16:34:06" "time": "2013-08-18 07:18:44"
}, },
{ {
"name": "goodby/csv", "name": "goodby/csv",
@@ -1429,7 +1420,7 @@
"export", "export",
"import" "import"
], ],
"time": "2013-11-22 19:10:34" "time": "2014-01-12 16:34:06"
}, },
{ {
"name": "guzzle/guzzle", "name": "guzzle/guzzle",
@@ -1523,6 +1514,433 @@
], ],
"time": "2014-08-11 04:32:36" "time": "2014-08-11 04:32:36"
}, },
{
"name": "hoa/compiler",
"version": "2.14.09.23",
"target-dir": "Hoa/Compiler",
"source": {
"type": "git",
"url": "https://github.com/hoaproject/Compiler.git",
"reference": "51cdc8b21d13f2fcaa3f3a0d114247534849f8cb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/hoaproject/Compiler/zipball/51cdc8b21d13f2fcaa3f3a0d114247534849f8cb",
"reference": "51cdc8b21d13f2fcaa3f3a0d114247534849f8cb",
"shasum": ""
},
"require": {
"hoa/core": "~2.0",
"hoa/file": "~0.0",
"hoa/iterator": "~0.0",
"hoa/math": "~0.0",
"hoa/visitor": "~0.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.x-dev"
}
},
"autoload": {
"psr-0": {
"Hoa\\Compiler": "."
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Ivan Enderlin",
"email": "ivan.enderlin@hoa-project.net"
},
{
"name": "Hoa community",
"homepage": "http://hoa-project.net/"
}
],
"description": "The Hoa\\Compiler library.",
"homepage": "http://hoa-project.net/",
"keywords": [
"algebraic",
"ast",
"compiler",
"context-free",
"coverage",
"exhaustive",
"grammar",
"isotropic",
"language",
"lexer",
"library",
"ll1",
"llk",
"parser",
"pp",
"random",
"regular",
"rule",
"sampler",
"syntax",
"token",
"trace",
"uniform"
],
"time": "2014-09-23 09:50:46"
},
{
"name": "hoa/core",
"version": "2.14.09.23",
"target-dir": "Hoa/Core",
"source": {
"type": "git",
"url": "https://github.com/hoaproject/Core.git",
"reference": "e50354e69e451478223d1d0c1ce4f5d741ea7576"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/hoaproject/Core/zipball/e50354e69e451478223d1d0c1ce4f5d741ea7576",
"reference": "e50354e69e451478223d1d0c1ce4f5d741ea7576",
"shasum": ""
},
"require": {
"ext-spl": "*",
"php": ">=5.4.0"
},
"suggest": {
"ext-mbstring": "ext/mbstring must be present (or a third implementation).",
"hoa/console": "To use the `hoa` script.",
"hoa/dispatcher": "To use the `hoa` script.",
"hoa/router": "To use the `hoa` script."
},
"bin": [
"Bin/hoa"
],
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.x-dev"
}
},
"autoload": {
"psr-0": {
"Hoa\\Core": "."
},
"files": [
"Core.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Ivan Enderlin",
"email": "ivan.enderlin@hoa-project.net"
},
{
"name": "Hoa community",
"homepage": "http://hoa-project.net/"
}
],
"description": "The Hoa\\Core library.",
"homepage": "http://hoa-project.net/",
"keywords": [
"consistency",
"core",
"data",
"event",
"library",
"listener",
"parameter",
"protocol"
],
"time": "2014-09-23 09:45:22"
},
{
"name": "hoa/file",
"version": "0.14.09.23",
"target-dir": "Hoa/File",
"source": {
"type": "git",
"url": "https://github.com/hoaproject/File.git",
"reference": "a39f62a28256180606115416cf27774966cf73e9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/hoaproject/File/zipball/a39f62a28256180606115416cf27774966cf73e9",
"reference": "a39f62a28256180606115416cf27774966cf73e9",
"shasum": ""
},
"require": {
"hoa/core": "~2.0",
"hoa/iterator": "~0.0",
"hoa/stream": "~0.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "0.x-dev"
}
},
"autoload": {
"psr-0": {
"Hoa\\File": "."
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Ivan Enderlin",
"email": "ivan.enderlin@hoa-project.net"
},
{
"name": "Hoa community",
"homepage": "http://hoa-project.net/"
}
],
"description": "The Hoa\\File library.",
"homepage": "http://hoa-project.net/",
"keywords": [
"Socket",
"directory",
"file",
"finder",
"library",
"link",
"temporary"
],
"time": "2014-09-23 09:50:42"
},
{
"name": "hoa/iterator",
"version": "0.14.09.23",
"target-dir": "Hoa/Iterator",
"source": {
"type": "git",
"url": "https://github.com/hoaproject/Iterator.git",
"reference": "1ca570cab25ca359a1a9f4b4c449d49771fc6a5e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/hoaproject/Iterator/zipball/1ca570cab25ca359a1a9f4b4c449d49771fc6a5e",
"reference": "1ca570cab25ca359a1a9f4b4c449d49771fc6a5e",
"shasum": ""
},
"require": {
"hoa/core": "~2.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "0.x-dev"
}
},
"autoload": {
"psr-0": {
"Hoa\\Iterator": "."
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Ivan Enderlin",
"email": "ivan.enderlin@hoa-project.net"
},
{
"name": "Hoa community",
"homepage": "http://hoa-project.net/"
}
],
"description": "The Hoa\\Iterator library.",
"homepage": "http://hoa-project.net/",
"keywords": [
"iterator",
"library"
],
"time": "2014-09-23 09:50:40"
},
{
"name": "hoa/math",
"version": "0.14.09.23",
"target-dir": "Hoa/Math",
"source": {
"type": "git",
"url": "https://github.com/hoaproject/Math.git",
"reference": "b52764f602095b4595658f581a504f039cef8d56"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/hoaproject/Math/zipball/b52764f602095b4595658f581a504f039cef8d56",
"reference": "b52764f602095b4595658f581a504f039cef8d56",
"shasum": ""
},
"require": {
"hoa/compiler": "~2.0",
"hoa/core": "~2.0",
"hoa/iterator": "~0.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "0.x-dev"
}
},
"autoload": {
"psr-0": {
"Hoa\\Math": "."
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Ivan Enderlin",
"email": "ivan.enderlin@hoa-project.net"
},
{
"name": "Hoa community",
"homepage": "http://hoa-project.net/"
}
],
"description": "The Hoa\\Math library.",
"homepage": "http://hoa-project.net/",
"keywords": [
"arrangement",
"combination",
"combinatorics",
"counting",
"library",
"math",
"permutation",
"sampler",
"set"
],
"time": "2014-09-23 14:02:37"
},
{
"name": "hoa/stream",
"version": "0.14.09.23",
"target-dir": "Hoa/Stream",
"source": {
"type": "git",
"url": "https://github.com/hoaproject/Stream.git",
"reference": "eaf9bfeb633b8a6bf0fba55e9c035db431024869"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/hoaproject/Stream/zipball/eaf9bfeb633b8a6bf0fba55e9c035db431024869",
"reference": "eaf9bfeb633b8a6bf0fba55e9c035db431024869",
"shasum": ""
},
"require": {
"hoa/core": "~2.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "0.x-dev"
}
},
"autoload": {
"psr-0": {
"Hoa\\Stream": "."
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Ivan Enderlin",
"email": "ivan.enderlin@hoa-project.net"
},
{
"name": "Hoa community",
"homepage": "http://hoa-project.net/"
}
],
"description": "The Hoa\\Stream library.",
"homepage": "http://hoa-project.net/",
"keywords": [
"Context",
"bucket",
"composite",
"filter",
"in",
"library",
"out",
"protocol",
"stream",
"wrapper"
],
"time": "2014-09-23 09:50:38"
},
{
"name": "hoa/visitor",
"version": "0.14.09.23",
"target-dir": "Hoa/Visitor",
"source": {
"type": "git",
"url": "https://github.com/hoaproject/Visitor.git",
"reference": "071523b6677466979e57a9f9ef61a46b76221935"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/hoaproject/Visitor/zipball/071523b6677466979e57a9f9ef61a46b76221935",
"reference": "071523b6677466979e57a9f9ef61a46b76221935",
"shasum": ""
},
"require": {
"hoa/core": "~2.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "0.x-dev"
}
},
"autoload": {
"psr-0": {
"Hoa\\Visitor": "."
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Ivan Enderlin",
"email": "ivan.enderlin@hoa-project.net"
},
{
"name": "Hoa community",
"homepage": "http://hoa-project.net/"
}
],
"description": "The Hoa\\Visitor library.",
"homepage": "http://hoa-project.net/",
"keywords": [
"library",
"structure",
"visit",
"visitor"
],
"time": "2014-09-23 09:50:51"
},
{ {
"name": "igorw/get-in", "name": "igorw/get-in",
"version": "v1.0.2", "version": "v1.0.2",
@@ -1596,7 +2014,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-develop": "0.7-dev" "dev-develop": "0.6-dev"
} }
}, },
"autoload": { "autoload": {
@@ -1623,7 +2041,7 @@
"image processing" "image processing"
], ],
"support": { "support": {
"source": "https://github.com/nlegoff/Imagine/tree/flatten-layer" "source": "https://github.com/alchemy-fr/Imagine/tree/0.6.1-flatten-layer"
}, },
"time": "2014-10-08 16:23:33" "time": "2014-10-08 16:23:33"
}, },
@@ -1932,9 +2350,9 @@
], ],
"authors": [ "authors": [
{ {
"name": "Johannes Schmitt", "name": "Johannes M. Schmitt",
"email": "schmittjoh@gmail.com", "email": "schmittjoh@gmail.com",
"homepage": "https://github.com/schmittjoh", "homepage": "http://jmsyst.com",
"role": "Developer of wrapped JMSSerializerBundle" "role": "Developer of wrapped JMSSerializerBundle"
} }
], ],
@@ -2249,7 +2667,7 @@
], ],
"authors": [ "authors": [
{ {
"name": "Steve Clay", "name": "Stephen Clay",
"email": "steve@mrclay.org", "email": "steve@mrclay.org",
"homepage": "http://www.mrclay.org/", "homepage": "http://www.mrclay.org/",
"role": "Developer" "role": "Developer"
@@ -2435,21 +2853,21 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/romainneutron/Imagine-Silex-Service-Provider.git", "url": "https://github.com/romainneutron/Imagine-Silex-Service-Provider.git",
"reference": "a8a7862ae90419f2b23746cd8436c2310e4eb084" "reference": "0.1.2"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/romainneutron/Imagine-Silex-Service-Provider/zipball/a8a7862ae90419f2b23746cd8436c2310e4eb084", "url": "https://api.github.com/repos/romainneutron/Imagine-Silex-Service-Provider/zipball/0.1.2",
"reference": "a8a7862ae90419f2b23746cd8436c2310e4eb084", "reference": "0.1.2",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"imagine/imagine": "*", "imagine/imagine": "*",
"php": ">=5.3.3", "php": ">=5.3.3",
"silex/silex": "~1.0" "silex/silex": ">=1.0,<2.0"
}, },
"require-dev": { "require-dev": {
"symfony/browser-kit": "~2.0" "symfony/browser-kit": ">=2.0,<3.0"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@@ -2963,7 +3381,7 @@
"metadata" "metadata"
], ],
"support": { "support": {
"source": "https://github.com/alchemy-fr/PHPExiftool/tree/dev" "source": "https://github.com/alchemy-fr/PHPExiftool/tree/0.4.1-mwg-metadata-copy"
}, },
"time": "2014-10-08 16:09:02" "time": "2014-10-08 16:09:02"
}, },
@@ -3001,9 +3419,9 @@
], ],
"authors": [ "authors": [
{ {
"name": "Johannes Schmitt", "name": "Johannes M. Schmitt",
"email": "schmittjoh@gmail.com", "email": "schmittjoh@gmail.com",
"homepage": "https://github.com/schmittjoh", "homepage": "http://jmsyst.com",
"role": "Developer of wrapped JMSSerializerBundle" "role": "Developer of wrapped JMSSerializerBundle"
} }
], ],
@@ -3560,7 +3978,7 @@
}, },
{ {
"name": "Phraseanet Team", "name": "Phraseanet Team",
"email": "info@alchemy.fr", "email": "support@alchemy.fr",
"homepage": "http://www.phraseanet.com/" "homepage": "http://www.phraseanet.com/"
} }
], ],
@@ -3607,9 +4025,7 @@
"authors": [ "authors": [
{ {
"name": "Fabien Potencier", "name": "Fabien Potencier",
"email": "fabien@symfony.com", "email": "fabien@symfony.com"
"homepage": "http://fabien.potencier.org",
"role": "Lead Developer"
}, },
{ {
"name": "Chris Corbyn" "name": "Chris Corbyn"
@@ -4522,6 +4938,242 @@
], ],
"time": "2014-10-09 15:52:51" "time": "2014-10-09 15:52:51"
}, },
{
"name": "hoa/console",
"version": "2.14.09.23",
"target-dir": "Hoa/Console",
"source": {
"type": "git",
"url": "https://github.com/hoaproject/Console.git",
"reference": "8466f74ddb5bd323357fe5464629c948a1fd8d25"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/hoaproject/Console/zipball/8466f74ddb5bd323357fe5464629c948a1fd8d25",
"reference": "8466f74ddb5bd323357fe5464629c948a1fd8d25",
"shasum": ""
},
"require": {
"hoa/core": "~2.0",
"hoa/stream": "~0.0",
"hoa/string": "~2.0"
},
"suggest": {
"ext-pcntl": "To enable hoa://Event/Console/Window:resize.",
"hoa/dispatcher": "To use the console kit.",
"hoa/router": "To use the console kit."
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.x-dev"
}
},
"autoload": {
"psr-0": {
"Hoa\\Console": "."
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Ivan Enderlin",
"email": "ivan.enderlin@hoa-project.net"
},
{
"name": "Hoa community",
"homepage": "http://hoa-project.net/"
}
],
"description": "The Hoa\\Console library.",
"homepage": "http://hoa-project.net/",
"keywords": [
"autocompletion",
"chrome",
"cli",
"console",
"cursor",
"getoption",
"library",
"option",
"parser",
"processus",
"readline",
"terminfo",
"tput",
"window"
],
"time": "2014-09-23 14:17:08"
},
{
"name": "hoa/dispatcher",
"version": "0.14.09.23",
"target-dir": "Hoa/Dispatcher",
"source": {
"type": "git",
"url": "https://github.com/hoaproject/Dispatcher.git",
"reference": "82924823fa9cedad9775f1ab4d51075e980ac2c6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/hoaproject/Dispatcher/zipball/82924823fa9cedad9775f1ab4d51075e980ac2c6",
"reference": "82924823fa9cedad9775f1ab4d51075e980ac2c6",
"shasum": ""
},
"require": {
"hoa/core": "~2.0"
},
"suggest": {
"hoa/router": "Provide routers.",
"hoa/view": "Provide view interface."
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "0.x-dev"
}
},
"autoload": {
"psr-0": {
"Hoa\\Dispatcher": "."
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Ivan Enderlin",
"email": "ivan.enderlin@hoa-project.net"
},
{
"name": "Hoa community",
"homepage": "http://hoa-project.net/"
}
],
"description": "The Hoa\\Dispatcher library.",
"homepage": "http://hoa-project.net/",
"keywords": [
"dispatcher",
"kit",
"library"
],
"time": "2014-09-23 14:12:43"
},
{
"name": "hoa/router",
"version": "2.14.09.23",
"target-dir": "Hoa/Router",
"source": {
"type": "git",
"url": "https://github.com/hoaproject/Router.git",
"reference": "8937785aecf7ca3b6dbd5f668eb97e15c672758d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/hoaproject/Router/zipball/8937785aecf7ca3b6dbd5f668eb97e15c672758d",
"reference": "8937785aecf7ca3b6dbd5f668eb97e15c672758d",
"shasum": ""
},
"require": {
"hoa/core": "~2.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.x-dev"
}
},
"autoload": {
"psr-0": {
"Hoa\\Router": "."
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Ivan Enderlin",
"email": "ivan.enderlin@hoa-project.net"
},
{
"name": "Hoa community",
"homepage": "http://hoa-project.net/"
}
],
"description": "The Hoa\\Router library.",
"homepage": "http://hoa-project.net/",
"keywords": [
"cli",
"http",
"library",
"router"
],
"time": "2014-09-23 09:50:57"
},
{
"name": "hoa/string",
"version": "2.14.09.23",
"target-dir": "Hoa/String",
"source": {
"type": "git",
"url": "https://github.com/hoaproject/String.git",
"reference": "c385ffb1382d919c63ab97acd6f62058179c5f2a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/hoaproject/String/zipball/c385ffb1382d919c63ab97acd6f62058179c5f2a",
"reference": "c385ffb1382d919c63ab97acd6f62058179c5f2a",
"shasum": ""
},
"require": {
"ext-iconv": "*",
"hoa/core": "~2.0"
},
"suggest": {
"ext-intl": "To get a better Hoa\\String::toAscii() and Hoa\\String::compareTo()."
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.x-dev"
}
},
"autoload": {
"psr-0": {
"Hoa\\String": "."
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Ivan Enderlin",
"email": "ivan.enderlin@hoa-project.net"
},
{
"name": "Hoa community",
"homepage": "http://hoa-project.net/"
}
],
"description": "The Hoa\\String library.",
"homepage": "http://hoa-project.net/",
"keywords": [
"library",
"search",
"string",
"unicode"
],
"time": "2014-09-23 09:55:55"
},
{ {
"name": "instaclick/php-webdriver", "name": "instaclick/php-webdriver",
"version": "1.4.0", "version": "1.4.0",

90
grammar/arithmetic.pp Normal file
View File

@@ -0,0 +1,90 @@
//
// Hoa
//
//
// @license
//
// New BSD License
//
// Copyright © 2007-2014, Ivan Enderlin. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the Hoa nor the names of its contributors may be
// used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Grammar \Hoa\Math\Arithmetic.
//
// Provide a grammar for arithmetic expressions.
//
// @author Stéphane Py <py.stephane1@gmail.com>
// @author Sébastien Houze <s@verylastroom.com>
// @author Ivan Enderlin <ivan.enderlin@hoa-project.net>
// @copyright Copyright © 2007-2014 Stéphane Py, Sébastien Houze, Ivan Enderlin.
// @license New BSD License
//
%skip space \s
%token bracket_ \(
%token _bracket \)
%token comma ,
%token number (0|[1-9]\d*)(\.\d+)?([eE][\+\-]?\d+)?
%token plus \+
%token minus \-|
%token times \*|×
%token div /|÷
%token constant [A-Z_]+[A-Z0-9_]+
%token id \w+
expression:
primary() ( ::plus:: #addition expression() )?
primary:
secondary() ( ::minus:: #substraction expression() )?
secondary:
ternary() ( ::times:: #multiplication expression() )?
ternary:
term() ( ::div:: #division expression() )?
term:
( ::bracket_:: expression() ::_bracket:: #group )
| number()
| constant()
| variable()
| ( ::minus:: #negative | ::plus:: ) term()
| function()
number:
<number>
constant:
<constant>
#variable:
<id>
#function:
<id> ::bracket_::
( expression() ( ::comma:: expression() )* )?
::_bracket::

36
grammar/json.pp Normal file
View File

@@ -0,0 +1,36 @@
%skip space \s
%token true true
%token false false
%token null null
%token quote_ " -> string
%token string:escaped \\(["\\/bfnrt]|u[0-9a-fA-F]{4})
%token string:string [^"\\]+
%token string:_quote " -> default
%token brace_ {
%token _brace }
%token bracket_ \[
%token _bracket \]
%token colon :
%token comma ,
%token number \-?(0|[1-9]\d*)(\.\d+)?([eE][\+\-]?\d+)?
value:
<true> | <false> | <null> | string() | object() | array() | number()
string:
::quote_::
<string>
::_quote::
number:
<number>
#object:
::brace_:: pair() ( ::comma:: pair() )* ::_brace::
#pair:
string() ::colon:: value()
#array:
::bracket_:: value() ( ::comma:: value() )* ::_bracket::

47
grammar/query.pp Normal file
View File

@@ -0,0 +1,47 @@
%skip space \s
%token bracket_ \(
%token _bracket \)
%token quote_ " -> string
%token string:string [^"]+
%token string:_quote " -> default
%token in IN
%token and AND
%token or OR
%token except EXCEPT
%token word [^\s\(\)]+
// relative order of precedence is NOT > XOR > AND > OR
#query:
primary()
primary:
secondary() ( ::except:: #except primary() )?
secondary:
ternary() ( ::or:: #or primary() )?
ternary:
quaternary() ( ::and:: #and primary() )?
quaternary:
term() ( ::in:: #in word() )?
term:
( ::bracket_:: primary() ::_bracket:: ) | text()
#text:
( word() | keyword() | symbol() )+
word:
<word> | string()
string:
::quote_:: <string> ::_quote::
keyword:
<in> | <except> | <and> | <or>
symbol:
::bracket_:: | ::_bracket::

View File

@@ -0,0 +1,80 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2014 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Command\SearchEngine\Debug;
use Alchemy\Phrasea\Command\Command;
use Alchemy\Phrasea\SearchEngine\Elastic\Indexer;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
class QueryParseCommand extends Command
{
protected function configure()
{
$this
->setName('searchengine:query:parse')
->setDescription('Debug a search query')
->addArgument(
'query',
InputArgument::REQUIRED,
'The query to debug'
)
->addOption(
'compiler-dump',
'd',
InputOption::VALUE_NONE,
'Output underlying compiler AST before visitor processing'
)
->addOption(
'no-compiler-postprocessing',
'p',
InputOption::VALUE_NONE,
'Prevent AST optimization before visitor processing'
)
->addOption(
'raw',
null,
InputOption::VALUE_NONE,
'Only output query dump'
)
;
}
protected function doExecute(InputInterface $input, OutputInterface $output)
{
$string = $input->getArgument('query');
$raw = $input->getOption('raw');
if (!$raw) {
$output->writeln(sprintf('Parsing search query: <comment>%s</comment>', $string));
$output->writeln(str_repeat('-', 20));
}
$postprocessing = !$input->getOption('no-compiler-postprocessing');
$parser = $this->container['query_parser'];
if ($input->getOption('compiler-dump')) {
$dump = $parser->dump($string, $postprocessing);
} else {
$query = $parser->parse($string, $postprocessing);
$dump = $query->dump();
}
if (!$raw) {
$output->writeln($dump);
} else {
$output->write($dump);
}
}
}

View File

@@ -18,10 +18,13 @@ use Alchemy\Phrasea\SearchEngine\Elastic\ElasticSearchEngine;
use Alchemy\Phrasea\SearchEngine\Elastic\Indexer; use Alchemy\Phrasea\SearchEngine\Elastic\Indexer;
use Alchemy\Phrasea\SearchEngine\Elastic\Indexer\RecordIndexer; use Alchemy\Phrasea\SearchEngine\Elastic\Indexer\RecordIndexer;
use Alchemy\Phrasea\SearchEngine\Elastic\Indexer\TermIndexer; use Alchemy\Phrasea\SearchEngine\Elastic\Indexer\TermIndexer;
use Alchemy\Phrasea\SearchEngine\Elastic\Search\QueryParser;
use Alchemy\Phrasea\SearchEngine\Elastic\Thesaurus; use Alchemy\Phrasea\SearchEngine\Elastic\Thesaurus;
use Alchemy\Phrasea\SearchEngine\Phrasea\PhraseaEngine; use Alchemy\Phrasea\SearchEngine\Phrasea\PhraseaEngine;
use Alchemy\Phrasea\SearchEngine\Phrasea\PhraseaEngineSubscriber; use Alchemy\Phrasea\SearchEngine\Phrasea\PhraseaEngineSubscriber;
use Elasticsearch\Client; use Elasticsearch\Client;
use Hoa\Compiler\Llk\Llk;
use Hoa\File\Read;
use Monolog\Handler\RotatingFileHandler; use Monolog\Handler\RotatingFileHandler;
use Monolog\Logger; use Monolog\Logger;
use Silex\Application; use Silex\Application;
@@ -126,6 +129,21 @@ class SearchEngineServiceProvider implements ServiceProviderInterface
$app['elasticsearch.options']['index'] $app['elasticsearch.options']['index']
); );
}); });
$app['query_parser.grammar_path'] = function ($app) {
$configPath = ['registry', 'searchengine', 'query-grammar-path'];
$grammarPath = $app['conf']->get($configPath, 'grammar/query.pp');
$projectRoot = '../../../../..';
return realpath(implode('/', [__DIR__, $projectRoot, $grammarPath]));
};
$app['query_parser'] = $app->share(function ($app) {
$grammarPath = $app['query_parser.grammar_path'];
$parser = Llk::load(new Read($grammarPath));
return new QueryParser($parser);
});
} }
public function boot(Application $app) public function boot(Application $app)

View File

@@ -2,48 +2,19 @@
namespace Alchemy\Phrasea\SearchEngine\Elastic\AST; namespace Alchemy\Phrasea\SearchEngine\Elastic\AST;
class AndExpression extends Node class AndExpression extends BinaryOperator
{ {
protected $members = array(); protected $operator = 'AND';
public function __construct(Node $left, Node $right)
{
$this->members[] = $left;
$this->members[] = $right;
}
public function getMembers()
{
return $this->members;
}
public function getQuery($fields = ['_all']) public function getQuery($fields = ['_all'])
{ {
$rules = array(); $left = $this->left->getQuery($fields);
foreach ($this->members as $member) { $right = $this->right->getQuery($fields);
$rules[] = $member->getQuery($fields);
}
return array( return array(
'bool' => array( 'bool' => array(
'must' => count($rules) > 1 ? $rules : $rules[0] 'must' => array($left, $right)
) )
); );
} }
public function __toString()
{
return sprintf('(%s)', implode(' AND ', $this->members));
}
public function isFullTextOnly()
{
foreach ($this->members as $member) {
if (!$member->isFullTextOnly()) {
return false;
}
}
return true;
}
} }

View File

@@ -0,0 +1,27 @@
<?php
namespace Alchemy\Phrasea\SearchEngine\Elastic\AST;
abstract class BinaryOperator extends Node
{
protected $left;
protected $right;
protected $operator = 'BIN_OP';
public function __construct(Node $left, Node $right)
{
$this->left = $left;
$this->right = $right;
}
public function __toString()
{
return sprintf('(%s %s %s)', $this->left, $this->operator, $this->right);
}
public function isFullTextOnly()
{
return $this->left->isFullTextOnly()
&& $this->right->isFullTextOnly();
}
}

View File

@@ -0,0 +1,21 @@
<?php
namespace Alchemy\Phrasea\SearchEngine\Elastic\AST;
class ExceptExpression extends BinaryOperator
{
protected $operator = 'EXCEPT';
public function getQuery($fields = ['_all'])
{
$left = $this->left->getQuery($fields);
$right = $this->right->getQuery($fields);
return array(
'bool' => array(
'must' => $left,
'must_not' => $right
)
);
}
}

View File

@@ -2,7 +2,7 @@
namespace Alchemy\Phrasea\SearchEngine\Elastic\AST; namespace Alchemy\Phrasea\SearchEngine\Elastic\AST;
class KeywordNode extends Node class FieldNode extends Node
{ {
protected $keyword; protected $keyword;

View File

@@ -7,9 +7,9 @@ class InExpression extends Node
protected $field; protected $field;
protected $expression; protected $expression;
public function __construct(KeywordNode $keyword, $expression) public function __construct(FieldNode $field, $expression)
{ {
$this->field = $keyword; $this->field = $field;
$this->expression = $expression; $this->expression = $expression;
} }

View File

@@ -2,48 +2,19 @@
namespace Alchemy\Phrasea\SearchEngine\Elastic\AST; namespace Alchemy\Phrasea\SearchEngine\Elastic\AST;
class OrExpression extends Node class OrExpression extends BinaryOperator
{ {
protected $members = array(); protected $operator = 'OR';
public function __construct(Node $left, Node $right)
{
$this->members[] = $left;
$this->members[] = $right;
}
public function getMembers()
{
return $this->members;
}
public function getQuery($fields = ['_all']) public function getQuery($fields = ['_all'])
{ {
$rules = array(); $left = $this->left->getQuery($fields);
foreach ($this->members as $member) { $right = $this->right->getQuery($fields);
$rules[] = $member->getQuery($fields);
}
return array( return array(
'bool' => array( 'bool' => array(
'should' => count($rules) > 1 ? $rules : $rules[0] 'should' => array($left, $right)
) )
); );
} }
public function __toString()
{
return sprintf('(%s)', implode(' OR ', $this->members));
}
public function isFullTextOnly()
{
foreach ($this->members as $member) {
if (!$member->isFullTextOnly()) {
return false;
}
}
return true;
}
} }

View File

@@ -8,9 +8,10 @@ class QuotedTextNode extends TextNode
{ {
return array( return array(
'multi_match' => array( 'multi_match' => array(
'type' => 'phrase',
'fields' => $fields, 'fields' => $fields,
'query' => $this->text, 'query' => $this->text,
'operator' => 'and' // 'operator' => 'and'
) )
); );
} }

View File

@@ -30,4 +30,9 @@ class TextNode extends Node
{ {
return true; return true;
} }
public function getText()
{
return $this->text;
}
} }

View File

@@ -13,6 +13,7 @@ namespace Alchemy\Phrasea\SearchEngine\Elastic;
use Alchemy\Phrasea\SearchEngine\Elastic\Indexer\RecordIndexer; use Alchemy\Phrasea\SearchEngine\Elastic\Indexer\RecordIndexer;
use Alchemy\Phrasea\SearchEngine\Elastic\Indexer\TermIndexer; use Alchemy\Phrasea\SearchEngine\Elastic\Indexer\TermIndexer;
use Alchemy\Phrasea\SearchEngine\Elastic\Search\SearchQuery;
use Alchemy\Phrasea\SearchEngine\SearchEngineInterface; use Alchemy\Phrasea\SearchEngine\SearchEngineInterface;
use Alchemy\Phrasea\SearchEngine\SearchEngineOptions; use Alchemy\Phrasea\SearchEngine\SearchEngineOptions;
use Alchemy\Phrasea\SearchEngine\SearchEngineResult; use Alchemy\Phrasea\SearchEngine\SearchEngineResult;
@@ -270,8 +271,8 @@ class ElasticSearchEngine implements SearchEngineInterface
public function query($string, $offset, $perPage, SearchEngineOptions $options = null) public function query($string, $offset, $perPage, SearchEngineOptions $options = null)
{ {
$options = $options ?: new SearchEngineOptions(); $options = $options ?: new SearchEngineOptions();
$parser = new QueryParser();
$ast = $parser->parse($string); $searchQuery = $this->app['query_parser']->parse($string);
// Contains the full thesaurus paths to search on // Contains the full thesaurus paths to search on
$pathsToFilter = []; $pathsToFilter = [];
@@ -279,9 +280,9 @@ class ElasticSearchEngine implements SearchEngineInterface
$collectFields = []; $collectFields = [];
// Only search in thesaurus for full text search // Only search in thesaurus for full text search
if ($ast->isFullTextOnly()) { if ($searchQuery->isFullTextOnly()) {
$termFields = $this->expendToAnalyzedFieldsNames('value', null, $this->app['locale']); $termFields = $this->expendToAnalyzedFieldsNames('value', null, $this->app['locale']);
$termsQuery = $ast->getQuery($termFields); $termsQuery = $searchQuery->getElasticsearchQuery($termFields);
$params = $this->createTermQueryParams($termsQuery, $options); $params = $this->createTermQueryParams($termsQuery, $options);
$terms = $this->doExecute('search', $params); $terms = $this->doExecute('search', $params);
@@ -313,7 +314,7 @@ class ElasticSearchEngine implements SearchEngineInterface
$recordQuery = [ $recordQuery = [
'bool' => [ 'bool' => [
'should' => [ 'should' => [
$ast->getQuery($recordFields) $searchQuery->getElasticsearchQuery($recordFields)
] ]
] ]
]; ];
@@ -376,7 +377,7 @@ class ElasticSearchEngine implements SearchEngineInterface
$results[] = new \record_adapter($this->app, $databoxId, $recordId, $n++); $results[] = new \record_adapter($this->app, $databoxId, $recordId, $n++);
} }
$query['_ast'] = (string) $ast; $query['_ast'] = $searchQuery->dump();
$query['_paths'] = $pathsToFilter; $query['_paths'] = $pathsToFilter;
$query['_richFields'] = $collectFields; $query['_richFields'] = $collectFields;
$query['query'] = json_encode($params); $query['query'] = json_encode($params);

View File

@@ -0,0 +1,16 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2014 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\SearchEngine\Elastic\Exception;
class QueryException extends Exception
{
}

View File

@@ -0,0 +1,18 @@
<?php
namespace Alchemy\Phrasea\SearchEngine\Elastic\Search;
class NodeTypes
{
// Tree node types
const QUERY = '#query';
const IN_EXPR = '#in';
const AND_EXPR = '#and';
const OR_EXPR = '#or';
const EXCEPT_EXPR = '#except';
const FIELD = '#field';
const TEXT = '#text';
// Token types for leaf nodes
const TOKEN_WORD = 'word';
const TOKEN_STRING = 'string';
}

View File

@@ -0,0 +1,37 @@
<?php
namespace Alchemy\Phrasea\SearchEngine\Elastic\Search;
use Alchemy\Phrasea\SearchEngine\Elastic\AST\Node;
use Alchemy\Phrasea\SearchEngine\Elastic\AST\AndOperator;
use Hoa\Compiler\Llk\TreeNode;
class Query
{
private $root;
public function __construct(Node $root)
{
$this->root = $root;
}
/*
* This method seems weird to me, the implementation returns true when the
* query doesn't contain IN statements, but that doesn't define a full text
* search.
*/
public function isFullTextOnly()
{
return $this->root->isFullTextOnly();
}
public function getElasticsearchQuery($fields = array())
{
return $this->root->getQuery($fields);
}
public function dump()
{
return $this->root->__toString();
}
}

View File

@@ -0,0 +1,108 @@
<?php
namespace Alchemy\Phrasea\SearchEngine\Elastic\Search;
use Alchemy\Phrasea\SearchEngine\Elastic\AST;
use Alchemy\Phrasea\SearchEngine\Elastic\Exception\QueryException;
use Hoa\Compiler\Exception\Exception as CompilerException;
use Hoa\Compiler\Llk\Parser;
use Hoa\Compiler\Llk\TreeNode;
use Hoa\Compiler\Visitor\Dump as DumpVisitor;
use Hoa\Visitor\Visit;
class QueryParser
{
private $parser;
private static $leftAssociativeOperators = array(
NodeTypes::AND_EXPR,
NodeTypes::OR_EXPR,
NodeTypes::EXCEPT_EXPR
);
public function __construct(Parser $parser)
{
$this->parser = $parser;
}
/**
* Creates a Query object from a string
*/
public function parse($string, $postprocessing = true)
{
return $this->visitString($string, new QueryVisitor(), $postprocessing);
}
public function dump($string, $postprocessing = true)
{
return $this->visitString($string, new DumpVisitor(), $postprocessing);
}
private function visitString($string, Visit $visitor, $postprocessing = true)
{
try {
$ast = $this->parser->parse($string);
} catch (CompilerException $e) {
throw new QueryException('Provided query is not valid', 0, $e);
}
if ($postprocessing) {
$this->fixOperatorAssociativity($ast);
}
return $visitor->visit($ast);
}
/**
* Walks the tree to restore left-associativity of some operators
*
* @param TreeNode $root AST root node
*/
private function fixOperatorAssociativity(TreeNode &$root)
{
switch ($root->getChildrenNumber()) {
case 0:
// Leaf nodes can't be rotated, and have no childs
return;
case 2:
// We only want to rotate tree contained in the left associative
// subset of operators
$rootType = $root->getId();
if (!in_array($rootType, self::$leftAssociativeOperators)) {
break;
}
// Do not break operator precedence
$pivot = $root->getChild(1);
if ($pivot->getId() !== $rootType) {
break;
}
$this->leftRotateTree($root);
break;
}
// Recursively fix tree branches
$children = $root->getChildren();
foreach ($children as $index => $_) {
$this->fixOperatorAssociativity($children[$index]);
}
$root->setChildren($children);
}
private function leftRotateTree(TreeNode &$root)
{
// Pivot = Root.Left
$pivot = $root->getChild(1);
// Root.Right = Pivot.Left
$children = $root->getChildren();
$children[1] = $pivot->getChild(0); // Pivot, rotation side
$root->setChildren($children);
// Pivot.Left = Root
$children = $pivot->getChildren();
$children[0] = $root;
$pivot->setChildren($children);
// Root = Pivot
$root = $pivot;
}
}

View File

@@ -0,0 +1,132 @@
<?php
namespace Alchemy\Phrasea\SearchEngine\Elastic\Search;
use Alchemy\Phrasea\SearchEngine\Elastic\AST;
use Hoa\Visitor\Element;
use Hoa\Visitor\Visit;
class QueryVisitor implements Visit
{
public function visit(Element $element, &$handle = null, $eldnah = null)
{
if (null !== $value = $element->getValue()) {
return $this->visitToken($value['token'], $value['value']);
}
return $this->visitNode($element);
}
private function visitToken($token, $value)
{
switch ($token) {
case NodeTypes::TOKEN_WORD:
return new AST\TextNode($value);
case NodeTypes::TOKEN_STRING:
return new AST\QuotedTextNode($value);
default:
// Generic handling off other tokens for unresctricted text
return new AST\TextNode($value);
}
}
private function visitNode(Element $element)
{
switch ($element->getId()) {
case NodeTypes::QUERY:
return $this->visitQuery($element);
case NodeTypes::IN_EXPR:
return $this->visitInNode($element);
case NodeTypes::AND_EXPR:
return $this->visitAndNode($element);
case NodeTypes::OR_EXPR:
return $this->visitOrNode($element);
case NodeTypes::EXCEPT_EXPR:
return $this->visitExceptNode($element);
case NodeTypes::TEXT:
return $this->visitText($element);
default:
throw new \Exception(sprintf('Unknown node type "%s".', $element->getId()));
}
}
private function visitQuery(Element $element)
{
foreach ($element->getChildren() as $child) {
$root = $child->accept($this);
}
return new Query($root);
}
private function visitInNode(Element $element)
{
if ($element->getChildrenNumber() !== 2) {
throw new \Exception('IN expression can only have 2 childs.');
}
$expression = $element->getChild(0)->accept($this);
$field = new AST\FieldNode($element->getChild(1)->getValue()['value']);
return new AST\InExpression($field, $expression);
}
private function visitAndNode(Element $element)
{
return $this->handleBinaryOperator($element, function($left, $right) {
return new AST\AndExpression($left, $right);
});
}
private function visitOrNode(Element $element)
{
return $this->handleBinaryOperator($element, function($left, $right) {
return new AST\OrExpression($left, $right);
});
}
private function visitExceptNode(Element $element)
{
return $this->handleBinaryOperator($element, function($left, $right) {
return new AST\ExceptExpression($left, $right);
});
}
private function handleBinaryOperator(Element $element, \Closure $factory)
{
if ($element->getChildrenNumber() !== 2) {
throw new \Exception('Binary expression can only have 2 childs.');
}
$left = $element->getChild(0)->accept($this);
$right = $element->getChild(1)->accept($this);
return $factory($left, $right);
}
private function visitText(Element $element)
{
$root = null;
foreach ($element->getChildren() as $child) {
$node = $child->accept($this);
if ($root) {
// Merge text nodes together, but not with quoted ones
if ($root instanceof AST\TextNode &&
!$root instanceof AST\QuotedTextNode &&
!$node instanceof AST\QuotedTextNode) {
$root = new AST\TextNode(sprintf('%s %s', $root->getText(), $node->getText()));
} else {
$root = new AST\AndExpression($root, $node);
}
} else {
$root = $node;
}
}
return $root;
}
}