[SearchEngine] Finalize search engine refactor

This commit is contained in:
Romain Neutron
2012-10-19 19:12:42 +02:00
parent 85155262c9
commit 133595635c
33 changed files with 498 additions and 172 deletions

View File

@@ -12,6 +12,7 @@
namespace Alchemy\Phrasea; namespace Alchemy\Phrasea;
use Alchemy\Phrasea\PhraseanetServiceProvider; use Alchemy\Phrasea\PhraseanetServiceProvider;
use Alchemy\Phrasea\Core\Event\Subscriber\Logout;
use Alchemy\Phrasea\Core\Provider\BrowserServiceProvider; use Alchemy\Phrasea\Core\Provider\BrowserServiceProvider;
use Alchemy\Phrasea\Core\Provider\BorderManagerServiceProvider; use Alchemy\Phrasea\Core\Provider\BorderManagerServiceProvider;
use Alchemy\Phrasea\Core\Provider\CacheServiceProvider; use Alchemy\Phrasea\Core\Provider\CacheServiceProvider;
@@ -197,11 +198,11 @@ class Application extends SilexApplication
$this->setupTwig(); $this->setupTwig();
$this['dispatcher']->addListener(KernelEvents::REQUEST, array($this, 'initPhrasea'), 256);
$this['dispatcher']->addListener(KernelEvents::REQUEST, array($this, 'addLocale'), 255); $this['dispatcher']->addListener(KernelEvents::REQUEST, array($this, 'addLocale'), 255);
$this['dispatcher']->addListener(KernelEvents::REQUEST, array($this, 'initSession'), 254); $this['dispatcher']->addListener(KernelEvents::REQUEST, array($this, 'initSession'), 254);
$this['dispatcher']->addListener(KernelEvents::RESPONSE, array($this, 'addUTF8Charset'), -128); $this['dispatcher']->addListener(KernelEvents::RESPONSE, array($this, 'addUTF8Charset'), -128);
$this['dispatcher']->addListener(KernelEvents::RESPONSE, array($this, 'disableCookiesIfRequired'), -256); $this['dispatcher']->addListener(KernelEvents::RESPONSE, array($this, 'disableCookiesIfRequired'), -256);
$this['dispatcher']->addSubscriber(new Logout());
$this['locale'] = $this->share(function(Application $app){ $this['locale'] = $this->share(function(Application $app){
return $app['phraseanet.registry']->get('GV_default_lng', 'en_GB'); return $app['phraseanet.registry']->get('GV_default_lng', 'en_GB');
@@ -239,15 +240,6 @@ class Application extends SilexApplication
} }
} }
public function initPhrasea(GetResponseEvent $event)
{
if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
return;
}
\phrasea::start($this['phraseanet.configuration']);
}
public function addUTF8Charset(FilterResponseEvent $event) public function addUTF8Charset(FilterResponseEvent $event)
{ {
if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) { if (HttpKernelInterface::MASTER_REQUEST !== $event->getRequestType()) {
@@ -401,17 +393,6 @@ class Application extends SilexApplication
$this['session']->clear(); $this['session']->clear();
$this['session']->set('usr_id', $user->get_id()); $this['session']->set('usr_id', $user->get_id());
if ($ses_id) {
phrasea_close_session($ses_id);
}
if (!phrasea_open_session($this['session']->get('phrasea_session_id'), $user->get_id())) {
if (!$ses_id = phrasea_create_session($user->get_id())) {
throw new \Exception_InternalServerError('Unable to create phrasea session');
}
$this['session']->set('phrasea_session_id', $ses_id);
}
$session = new \Entities\Session(); $session = new \Entities\Session();
$session->setBrowserName($this['browser']->getBrowser()) $session->setBrowserName($this['browser']->getBrowser())
->setBrowserVersion($this['browser']->getVersion()) ->setBrowserVersion($this['browser']->getVersion())
@@ -446,10 +427,6 @@ class Application extends SilexApplication
*/ */
public function closeAccount() public function closeAccount()
{ {
if ($this['session']->has('phrasea_session_id')) {
phrasea_close_session($this['session']->get('phrasea_session_id'));
}
$this['session']->clear(); $this['session']->clear();
$this->reinitUser(); $this->reinitUser();

View File

@@ -69,7 +69,7 @@ return call_user_func(function($environment = 'prod') {
$auth = new \Session_Authentication_None($user); $auth = new \Session_Authentication_None($user);
$app->openAccount($auth, $oauth2_adapter->get_ses_id()); $app->openAccount($auth, $oauth2_adapter->get_ses_id());
$oauth2_adapter->remember_this_ses_id($app['session']->get('phrasea_session_id')); $oauth2_adapter->remember_this_ses_id($app['session']->get('session_id'));
return; return;
}, 256); }, 256);

View File

@@ -214,7 +214,7 @@ class Upload implements ControllerProviderInterface
$postStatus = $postStatus[$collection->get_base_id()]; $postStatus = $postStatus[$collection->get_base_id()];
$status = ''; $status = '';
foreach (range(0, 63) as $i) { foreach (range(0, 31) as $i) {
$status .= isset($postStatus[$i]) ? ($postStatus[$i] ? '1' : '0') : '0'; $status .= isset($postStatus[$i]) ? ($postStatus[$i] ? '1' : '0') : '0';
} }
$packageFile->addAttribute(new Status($app, strrev($status))); $packageFile->addAttribute(new Status($app, strrev($status)));

View File

@@ -12,6 +12,8 @@
namespace Alchemy\Phrasea\Controller\Root; namespace Alchemy\Phrasea\Controller\Root;
use Alchemy\Phrasea\Application as PhraseaApplication; use Alchemy\Phrasea\Application as PhraseaApplication;
use Alchemy\Phrasea\Core\Event\LogoutEvent;
use Alchemy\Phrasea\Core\PhraseaEvents;
use Silex\Application; use Silex\Application;
use Silex\ControllerProviderInterface; use Silex\ControllerProviderInterface;
use Symfony\Component\HttpFoundation\Cookie; use Symfony\Component\HttpFoundation\Cookie;
@@ -704,14 +706,8 @@ class Login implements ControllerProviderInterface
*/ */
public function logout(PhraseaApplication $app, Request $request) public function logout(PhraseaApplication $app, Request $request)
{ {
$appRedirect = $request->query->get("app"); $app['dispatcher']->dispatch(PhraseaEvents::LOGOUT, new LogoutEvent($app));
/**
* Move to middleware
if ( ! $this->is_authenticated()) {
return;
}
*/
$app->closeAccount(); $app->closeAccount();
$response = new RedirectResponse("/login/?logged_out=user" . ($appRedirect ? sprintf("&redirect=%s", ltrim($appRedirect, '/')) : "")); $response = new RedirectResponse("/login/?logged_out=user" . ($appRedirect ? sprintf("&redirect=%s", ltrim($appRedirect, '/')) : ""));
@@ -885,19 +881,6 @@ class Login implements ControllerProviderInterface
$auth->set_captcha_challenge($captcha); $auth->set_captcha_challenge($captcha);
} }
$sql = "SELECT session_id FROM cache
WHERE lastaccess < DATE_SUB(NOW(), INTERVAL 1 MONTH)";
$stmt = $conn->prepare($sql);
$stmt->execute();
$rs = $stmt->fetchAll(\PDO::FETCH_ASSOC);
$stmt->closeCursor();
foreach ($rs as $row) {
phrasea_close_session($row['session_id']);
}
$date = new \DateTime('+' . (int) $app['phraseanet.registry']->get('GV_validation_reminder') . ' days'); $date = new \DateTime('+' . (int) $app['phraseanet.registry']->get('GV_validation_reminder') . ' days');
foreach ($app['EM'] foreach ($app['EM']
@@ -942,7 +925,7 @@ class Login implements ControllerProviderInterface
$user = $auth->signOn(); $user = $auth->signOn();
/** /**
* TODO NEUTRON move this to phrasea engine * @todo move this to phrasea engine
*/ */
$user->ACL()->inject_rights(); $user->ACL()->inject_rights();

View File

@@ -0,0 +1,30 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2012 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Core\Event;
use Alchemy\Phrasea\Application;
use Symfony\Component\EventDispatcher\Event as SfEvent;
class LogoutEvent extends SfEvent
{
private $app;
public function __construct(Application $app)
{
$this->app = $app;
}
public function getApplication()
{
return $this->app;
}
}

View File

@@ -0,0 +1,32 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2012 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Core\Event\Subscriber;
use Alchemy\Phrasea\Core\PhraseaEvents;
use Alchemy\Phrasea\Core\Event\LogoutEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class Logout implements EventSubscriberInterface
{
public function onLogout(LogoutEvent $event)
{
$app = $event->getApplication();
$app['phraseanet.SE']->clearCache();
}
public static function getSubscribedEvents()
{
return array(
PhraseaEvents::LOGOUT => 'onLogout',
);
}
}

View File

@@ -0,0 +1,17 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2012 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Alchemy\Phrasea\Core;
final class PhraseaEvents
{
const LOGOUT = 'phrasea.logout';
}

View File

@@ -34,4 +34,5 @@ class SearchEngineServiceProvider implements ServiceProviderInterface
public function boot(Application $app) public function boot(Application $app)
{ {
} }
} }

View File

@@ -232,7 +232,7 @@ class Edit extends \Alchemy\Phrasea\Helper\Helper
$nrows = 0; $nrows = 0;
for ($bit = 0; $bit < 64; $bit++) for ($bit = 0; $bit < 32; $bit++)
$tbits_and[$bit] = $tbits_xor[$bit] = array("nset" => 0); $tbits_and[$bit] = $tbits_xor[$bit] = array("nset" => 0);
foreach ($rs as $row) { foreach ($rs as $row) {
@@ -266,7 +266,7 @@ class Edit extends \Alchemy\Phrasea\Helper\Helper
$vand_and = $vand_or = $vxor_and = $vxor_or = "0000"; $vand_and = $vand_or = $vxor_and = $vxor_or = "0000";
for ($bit = 4; $bit < 64; $bit++) { for ($bit = 4; $bit < 32; $bit++) {
if (($tbits_and[$bit]["nset"] != 0 && $tbits_and[$bit]["nset"] != $nrows) || ($tbits_xor[$bit]["nset"] != 0 && $tbits_xor[$bit]["nset"] != $nrows)) { if (($tbits_and[$bit]["nset"] != 0 && $tbits_and[$bit]["nset"] != $nrows) || ($tbits_xor[$bit]["nset"] != 0 && $tbits_xor[$bit]["nset"] != $nrows)) {
if (isset($tbits_left[$bit]) && isset($tbits_right[$bit])) { if (isset($tbits_left[$bit]) && isset($tbits_right[$bit])) {
$tbits_left[$bit]["nset"] = 2; $tbits_left[$bit]["nset"] = 2;

View File

@@ -17,16 +17,16 @@ use Alchemy\Phrasea\SearchEngine\SearchEngineOptions;
use Alchemy\Phrasea\SearchEngine\SearchEngineResult; use Alchemy\Phrasea\SearchEngine\SearchEngineResult;
use Alchemy\Phrasea\Exception\RuntimeException; use Alchemy\Phrasea\Exception\RuntimeException;
use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
class PhraseaEngine implements SearchEngineInterface class PhraseaEngine implements SearchEngineInterface
{ {
private static $initialized = false; private $initialized;
/** /**
* *
* @var SearchEngineOptions * @var SearchEngineOptions
*/ */
private $options; private $options;
private $app;
private $queries = array(); private $queries = array();
private $arrayq = array(); private $arrayq = array();
private $colls = array(); private $colls = array();
@@ -44,6 +44,39 @@ class PhraseaEngine implements SearchEngineInterface
$this->options = new SearchEngineOptions(); $this->options = new SearchEngineOptions();
} }
public function initialize()
{
if ($this->initialized) {
return $this;
}
$choosenConnexion = $this->app['phraseanet.configuration']->getPhraseanet()->get('database');
$connexion = $this->app['phraseanet.configuration']->getConnexion($choosenConnexion);
$hostname = $connexion->get('host');
$port = (int) $connexion->get('port');
$user = $connexion->get('user');
$password = $connexion->get('password');
$dbname = $connexion->get('dbname');
if (!extension_loaded('phrasea2')) {
throw new RuntimeException('Phrasea extension is required');
}
if (!function_exists('phrasea_conn')) {
throw new RuntimeException('Phrasea extension requires upgrade');
}
if (phrasea_conn($hostname, $port, $user, $password, $dbname) !== true) {
throw new RuntimeException('Unable to initialize Phrasea connection');
}
$this->initialized = true;
return $this;
}
private function checkSession() private function checkSession()
{ {
if (!$this->app['phraseanet.user']) { if (!$this->app['phraseanet.user']) {
@@ -58,16 +91,6 @@ class PhraseaEngine implements SearchEngineInterface
} }
} }
private function initialize()
{
if(!self::$initialized) {
\phrasea::start($this->app['phraseanet.configuration']);
self::$initialized = true;
}
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
@@ -83,14 +106,13 @@ class PhraseaEngine implements SearchEngineInterface
public function configurationPanel() public function configurationPanel()
{ {
if ( ! $this->configurationPanel) { if (!$this->configurationPanel) {
$this->configurationPanel = new ConfigurationPanel($this); $this->configurationPanel = new ConfigurationPanel($this);
} }
return $this->configurationPanel; return $this->configurationPanel;
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
@@ -287,7 +309,7 @@ class PhraseaEngine implements SearchEngineInterface
} catch (Exception $e) { } catch (Exception $e) {
} }
$resultNumber ++; $resultNumber++;
} }
@@ -409,13 +431,13 @@ class PhraseaEngine implements SearchEngineInterface
$this->app['session']->get('phrasea_session_id'), ($record->get_number() + 1), 1, true, "[[em]]", "[[/em]]" $this->app['session']->get('phrasea_session_id'), ($record->get_number() + 1), 1, true, "[[em]]", "[[/em]]"
); );
if ( ! isset($res['results']) || ! is_array($res['results'])) { if (!isset($res['results']) || !is_array($res['results'])) {
return array(); return array();
} }
$rs = $res['results']; $rs = $res['results'];
$res = array_shift($rs); $res = array_shift($rs);
if ( ! isset($res['xml'])) { if (!isset($res['xml'])) {
return array(); return array();
} }
@@ -462,8 +484,8 @@ class PhraseaEngine implements SearchEngineInterface
if ($status) { if ($status) {
$requestStat = 'xxxx'; $requestStat = 'xxxx';
for ($i = 4; ($i <= 64); $i ++ ) { for ($i = 4; ($i <= 32); $i++) {
if ( ! isset($status[$i])) { if (!isset($status[$i])) {
$requestStat = 'x' . $requestStat; $requestStat = 'x' . $requestStat;
continue; continue;
} }
@@ -485,7 +507,9 @@ class PhraseaEngine implements SearchEngineInterface
} }
} }
if ($this->options->fields()) { if ($this->options->fields()) {
$this->queries[$sbas] .= ' IN (' . implode(' OR ', array_map(function(\databox_field $field){return $field->get_name();},$this->options->fields())) . ')'; $this->queries[$sbas] .= ' IN (' . implode(' OR ', array_map(function(\databox_field $field) {
return $field->get_name();
}, $this->options->fields())) . ')';
} }
if (($this->options->getMinDate() || $this->options->getMaxDate()) && $this->options->getDateFields()) { if (($this->options->getMinDate() || $this->options->getMaxDate()) && $this->options->getDateFields()) {
if ($this->options->getMinDate()) { if ($this->options->getMinDate()) {
@@ -562,5 +586,39 @@ class PhraseaEngine implements SearchEngineInterface
return $this; return $this;
} }
}
/**
* @inheritdoc
*/
public function clearCache()
{
if ($this->app['session']->has('phrasea_session_id')) {
$this->initialize();
phrasea_close_session($this->app['session']->get('phrasea_session_id'));
$this->app['session']->remove('phrasea_session_id');
}
}
/**
* @inheritdoc
*/
public function clearAllCache(\DateTime $date = null)
{
if (!$date) {
$date = new \DateTime();
}
$sql = "SELECT session_id FROM cache WHERE lastaccess <= :date";
$stmt = $this->app['phraseanet.appbox']->get_connection()->prepare($sql);
$stmt->execute(array(':date' => $date->format(DATE_ISO8601)));
$rs = $stmt->fetchAll(\PDO::FETCH_ASSOC);
$stmt->closeCursor();
foreach ($rs as $row) {
phrasea_close_session($row['session_id']);
}
return $this;
}
}

View File

@@ -153,5 +153,21 @@ interface SearchEngineInterface
* @return SearchEngineInterface * @return SearchEngineInterface
*/ */
public function resetCache(); public function resetCache();
/**
* Clear the cache of the SE for the current user (if applicable)
*
* @return SearchEngineInterface
*/
public function clearCache();
/**
* Clear all cache prior to the given date (if applicable)
*
* If no date provided, clear all entries
*
* @return SearchEngineInterface
*/
public function clearAllCache(\DateTime $date = null);
} }

View File

@@ -808,5 +808,21 @@ class SphinxSearchEngine implements SearchEngineInterface
return null; return null;
} }
/**
* @inheritdoc
*/
public function clearCache()
{
return $this;
}
/**
* @inheritdoc
*/
public function clearAllCache(\DateTime $date = null)
{
return $this;
}
} }

View File

@@ -149,8 +149,6 @@ class Installer
$user = \User_Adapter::create($this->app, $this->email, $this->password, $this->email, true); $user = \User_Adapter::create($this->app, $this->email, $this->password, $this->email, true);
$this->app['session']->set('usr_id', $user->get_id()); $this->app['session']->set('usr_id', $user->get_id());
\phrasea::start($this->app['phraseanet.configuration']);
} }
private function rollbackInstall() private function rollbackInstall()

View File

@@ -351,17 +351,17 @@ class ACL implements cache_cacheableInterface
* apply sb is substractive * apply sb is substractive
*/ */
$mand = substr( $mand = substr(
str_repeat('0', 64) str_repeat('0', 32)
. databox_status::dec2bin($this->app, $mask_and) . databox_status::dec2bin($this->app, $mask_and)
, -64 , -32
); );
$mxor = substr( $mxor = substr(
str_repeat('0', 64) str_repeat('0', 32)
. databox_status::dec2bin($this->app, $mask_xor) . databox_status::dec2bin($this->app, $mask_xor)
, -64 , -32
); );
$m = array('aa' => '', 'ao' => '', 'xa' => '', 'xo' => ''); $m = array('aa' => '', 'ao' => '', 'xa' => '', 'xo' => '');
for ($i = 0; $i < 64; $i++) { for ($i = 0; $i < 32; $i++) {
$ax = $mand[$i] . $mxor[$i]; $ax = $mand[$i] . $mxor[$i];
foreach ($m as $k => $v) { foreach ($m as $k => $v) {
@@ -1502,8 +1502,9 @@ class ACL implements cache_cacheableInterface
foreach ($datas as $name => $f) { foreach ($datas as $name => $f) {
$vhex[$name] = "0x"; $vhex[$name] = "0x";
while (strlen($datas[$name]) < 64) while (strlen($datas[$name]) < 32) {
$datas[$name] = "0" . $datas[$name]; $datas[$name] = "0" . $datas[$name];
}
} }
foreach ($datas as $name => $f) { foreach ($datas as $name => $f) {
while (strlen($datas[$name]) > 0) { while (strlen($datas[$name]) > 0) {

View File

@@ -702,7 +702,7 @@ class API_V1_adapter extends API_V1_Abstract
$behavior = null; $behavior = null;
break; break;
default: default:
throw new API_V1_exception_badrequest('Invalid forceBehavior value'); throw new API_V1_exception_badrequest(sprintf('Invalid forceBehavior value `%s`', $request->get('forceBehavior')));
break; break;
} }
@@ -1212,7 +1212,7 @@ class API_V1_adapter extends API_V1_Abstract
throw new API_V1_exception_badrequest(); throw new API_V1_exception_badrequest();
} }
foreach ($status as $n => $value) { foreach ($status as $n => $value) {
if ($n > 63 || $n < 4) { if ($n > 31 || $n < 4) {
throw new API_V1_exception_badrequest(); throw new API_V1_exception_badrequest();
} }
if (!in_array($value, array('0', '1'))) { if (!in_array($value, array('0', '1'))) {

View File

@@ -118,7 +118,7 @@ class Session_Logger
, :user_agent, :appli, :fonction, :company, :activity, :country)"; , :user_agent, :appli, :fonction, :company, :activity, :country)";
$params = array( $params = array(
':ses_id' => $app['session']->get('phrasea_session_id'), ':ses_id' => $app['session']->get('session_id'),
':usr_login' => $app['phraseanet.user'] ? $app['phraseanet.user']->get_login() : null, ':usr_login' => $app['phraseanet.user'] ? $app['phraseanet.user']->get_login() : null,
':site_id' => $app['phraseanet.registry']->get('GV_sit'), ':site_id' => $app['phraseanet.registry']->get('GV_sit'),
':usr_id' => $app['phraseanet.user'] ? $app['phraseanet.user']->get_id() : null, ':usr_id' => $app['phraseanet.user'] ? $app['phraseanet.user']->get_id() : null,
@@ -156,7 +156,7 @@ class Session_Logger
$params = array( $params = array(
':site' => $app['phraseanet.registry']->get('GV_sit') ':site' => $app['phraseanet.registry']->get('GV_sit')
, ':ses_id' => $app['session']->get('phrasea_session_id') , ':ses_id' => $app['session']->get('session_id')
); );
$stmt = $databox->get_connection()->prepare($sql); $stmt = $databox->get_connection()->prepare($sql);

View File

@@ -82,7 +82,7 @@ class databox_status
foreach ($sxe->statbits->bit as $sb) { foreach ($sxe->statbits->bit as $sb) {
$bit = (int) ($sb["n"]); $bit = (int) ($sb["n"]);
if ($bit < 4 && $bit > 63) if ($bit < 4 && $bit > 31)
continue; continue;
$this->status[$bit]["name"] = (string) ($sb); $this->status[$bit]["name"] = (string) ($sb);
@@ -518,7 +518,7 @@ class databox_status
$status = (string) $status; $status = (string) $status;
if ( ! ctype_digit($status)) { if ( ! ctype_digit($status)) {
throw new \Exception('Non-decimal value'); throw new \Exception(sprintf('`%s`is non-decimal value', $status));
} }
$conn = connection::getPDOConnection($app); $conn = connection::getPDOConnection($app);

View File

@@ -141,7 +141,7 @@ class patch_370a8 implements patchInterface
$st = explode('_', trim($sx->status0)); $st = explode('_', trim($sx->status0));
if (count($st) == 2) { if (count($st) == 2) {
$bit = (int) ($st[0]); $bit = (int) ($st[0]);
if ($bit >= 0 && $bit <= 63 && ($st[1] == '0' || $st[1] == '1')) { if ($bit >= 0 && $bit < 32 && ($st[1] == '0' || $st[1] == '1')) {
$from->appendChild($dom->createElement('status')) $from->appendChild($dom->createElement('status'))
->setAttribute('mask', $st[1] . str_repeat('x', $bit - 1)); ->setAttribute('mask', $st[1] . str_repeat('x', $bit - 1));
} else { } else {
@@ -171,7 +171,7 @@ class patch_370a8 implements patchInterface
$st = explode('_', trim($sx->status1)); $st = explode('_', trim($sx->status1));
if (count($st) == 2) { if (count($st) == 2) {
$bit = (int) ($st[0]); $bit = (int) ($st[0]);
if ($bit >= 0 && $bit <= 63 && ($st[1] == '0' || $st[1] == '1')) { if ($bit >= 0 && $bit < 32 && ($st[1] == '0' || $st[1] == '1')) {
$to->appendChild($dom->createElement('status')) $to->appendChild($dom->createElement('status'))
->setAttribute('mask', $st[1] . str_repeat('x', $bit - 1)); ->setAttribute('mask', $st[1] . str_repeat('x', $bit - 1));
} else { } else {

View File

@@ -0,0 +1,76 @@
<?php
/*
* This file is part of Phraseanet
*
* (c) 2005-2012 Alchemy
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\Border\Checker;
/**
*
* @license http://opensource.org/licenses/gpl-3.0 GPLv3
* @link www.phraseanet.com
*/
class patch_3802 implements patchInterface
{
/**
*
* @var string
*/
private $release = '3.8.0.a2';
/**
*
* @var Array
*/
private $concern = array(base::APPLICATION_BOX);
/**
*
* @return string
*/
public function get_release()
{
return $this->release;
}
public function require_all_upgrades()
{
return true;
}
/**
*
* @return Array
*/
public function concern()
{
return $this->concern;
}
/**
* @param base $appbox
*/
public function apply(base $appbox, Application $app)
{
$sql = "SHOW TABLE STATUS LIKE 'cache'";
$stmt = $app['phraseanet.appbox']->get_connection()->prepare($sql);
$stmt->execute();
$row = $stmt->fetch(\PDO::FETCH_ASSOC);
$stmt->closeCurosr();
if ($row['Auto_increment']) {
$sql = sprintf('ALTER TABLE Sessions AUTO_INCREMENT = %d', $row['Auto_increment']);
$app['phraseanet.appbox']->get_connection()->exec($sql);
}
return;
}
}

View File

@@ -586,7 +586,7 @@ class record_adapter implements record_Interface, cache_cacheableInterface
$status = $row['status']; $status = $row['status'];
$n = strlen($status); $n = strlen($status);
while ($n < 64) { while ($n < 32) {
$status = '0' . $status; $status = '0' . $status;
$n++; $n++;
} }

View File

@@ -520,7 +520,7 @@ class task_period_RecordMover extends task_appboxAbstract
$status = str_split($rec->get_status()); $status = str_split($rec->get_status());
foreach (str_split(strrev($row['sb'])) as $bit => $val) { foreach (str_split(strrev($row['sb'])) as $bit => $val) {
if ($val == '0' || $val == '1') { if ($val == '0' || $val == '1') {
$status[63 - $bit] = $val; $status[31 - $bit] = $val;
} }
} }
$status = implode('', $status); $status = implode('', $status);

View File

@@ -337,17 +337,6 @@ class task_period_ftp extends task_appboxAbstract
$this->logger->addDebug($line); $this->logger->addDebug($line);
if (($ses_id = phrasea_create_session($usr_id)) == null) {
$this->logger->addDebug("Unable to create session");
return;
}
if ( ! ($ph_session = phrasea_open_session($ses_id, $usr_id))) {
$this->logger->addDebug("Unable to open session");
phrasea_close_session($ses_id);
return;
}
try { try {
$ssl = ($ftp_export['ssl'] == '1'); $ssl = ($ftp_export['ssl'] == '1');
$ftp_client = $this->dependencyContainer['phraseanet.ftp.client']($ftp_server, 21, 300, $ssl, $this->proxy, $this->proxyport); $ftp_client = $this->dependencyContainer['phraseanet.ftp.client']($ftp_server, 21, 300, $ssl, $this->proxy, $this->proxyport);
@@ -541,7 +530,7 @@ class task_period_ftp extends task_appboxAbstract
unset($ftp_client); unset($ftp_client);
} }
$this->finalize($appbox, $id); $this->finalize($appbox, $id);
phrasea_close_session($ses_id); // phrasea_close_session($ses_id);
} }
protected function postProcessOneContent(appbox $appbox, Array $row) protected function postProcessOneContent(appbox $appbox, Array $row)

View File

@@ -615,7 +615,7 @@ class task_period_outofdate extends task_abstract
$sqlset[$i] = ''; $sqlset[$i] = '';
$x = 'status' . $i; $x = 'status' . $i;
@list($tostat, $statval) = explode('_', (string) ($this->sxTaskSettings->{$x})); @list($tostat, $statval) = explode('_', (string) ($this->sxTaskSettings->{$x}));
if ($tostat >= 4 && $tostat <= 63) { if ($tostat >= 4 && $tostat < 32) {
if ($statval == '0') { if ($statval == '0') {
$sqlset[$i] = 'status=status & ~(1<<' . $tostat . ')'; $sqlset[$i] = 'status=status & ~(1<<' . $tostat . ')';
$sqlwhere[$i] .= '(status & (1<<' . $tostat . ') = 0)'; $sqlwhere[$i] .= '(status & (1<<' . $tostat . ') = 0)';

View File

@@ -16,7 +16,7 @@
<th>{% trans 'status:: Affichable pour tous' %}</th> <th>{% trans 'status:: Affichable pour tous' %}</th>
</thead> </thead>
<tbody> <tbody>
{% for bit in range(4, 63) %} {% for bit in range(4, 31) %}
<tr> <tr>
<td> <td>
{{ bit }} {{ bit }}

View File

@@ -3,7 +3,7 @@
{% block content %} {% block content %}
{% for record in results.get_datas() %} {% for record in results.results() %}
{{record_format.block(record, highlight, searchEngine, 'IMGT', false)}} {{record_format.block(record, highlight, searchEngine, 'IMGT', false)}}
{% endfor %} {% endfor %}

View File

@@ -30,8 +30,7 @@ class ApplicationLightboxTest extends PhraseanetWebTestCaseAuthenticatedAbstract
public function testRouteSlash() public function testRouteSlash()
{ {
\phrasea::start(self::$DI['app']['phraseanet.configuration']); $auth = new Session_Authentication_None(self::$DI['user']);
$auth = new Session_Authentication_None(self::$DI['user'], self::$DI['app']['session']->get('phrasea_session_id'));
self::$DI['app']->openAccount($auth); self::$DI['app']->openAccount($auth);
$baskets = $this->insertFiveBasket(); $baskets = $this->insertFiveBasket();

View File

@@ -187,16 +187,16 @@ class ManagerTest extends \PhraseanetWebTestCaseAuthenticatedAbstract
$story = \record_adapter::createStory(self::$DI['app'], self::$DI['collection']); $story = \record_adapter::createStory(self::$DI['app'], self::$DI['collection']);
$file->addAttribute(new Attribute\Story($story)); $file->addAttribute(new Attribute\Story($story));
$status = '0'; $status = '';
foreach (range(1, 64) as $i) { foreach (range(0, 31) as $i) {
if ($i == 5) { if ($i == 4 || $i == 8) {
$status .= '1'; $status .= '1';
} else { } else {
$status .= '0'; $status .= '0';
} }
} }
$file->addAttribute(new Attribute\Status(self::$DI['app'], $status)); $file->addAttribute(new Attribute\Status(self::$DI['app'], strrev($status)));
$this->assertEquals(Manager::RECORD_CREATED, $this->object->process($this->session, $file, $postProcessRecord, Manager::FORCE_RECORD)); $this->assertEquals(Manager::RECORD_CREATED, $this->object->process($this->session, $file, $postProcessRecord, Manager::FORCE_RECORD));
@@ -214,8 +214,11 @@ class ManagerTest extends \PhraseanetWebTestCaseAuthenticatedAbstract
$this->fail('Unable to find story in parents'); $this->fail('Unable to find story in parents');
} }
$this->assertEquals(64, strlen($record->get_status())); $status = strrev($record->get_status());
$this->assertEquals('1', substr($record->get_status(), 0, 1));
$this->assertEquals(32, strlen($status));
$this->assertEquals('1', substr($status, 4, 1));
$this->assertEquals('1', substr($status, 8, 1));
foreach ($tofetch as $name => $values) { foreach ($tofetch as $name => $values) {
@@ -287,7 +290,7 @@ class ManagerTest extends \PhraseanetWebTestCaseAuthenticatedAbstract
$file->addAttribute(new Attribute\Story(self::$DI['record_story_1'])); $file->addAttribute(new Attribute\Story(self::$DI['record_story_1']));
$status = '1'; $status = '1';
foreach (range(1, 63) as $i) { foreach (range(1, 31) as $i) {
$status .= '0'; $status .= '0';
} }
@@ -338,7 +341,7 @@ class ManagerTest extends \PhraseanetWebTestCaseAuthenticatedAbstract
$this->fail('Status is not found'); $this->fail('Status is not found');
} }
$this->assertEquals(64, strlen($status_found)); $this->assertEquals(32, strlen($status_found));
$this->assertEquals('1', substr($status_found, 0, 1)); $this->assertEquals('1', substr($status_found, 0, 1));
foreach ($tofetchField as $name => $values) { foreach ($tofetchField as $name => $values) {

View File

@@ -1,5 +1,7 @@
<?php <?php
namespace Alchemy\Phrasea\Controller\Prod;
require_once __DIR__ . '/../../../../PhraseanetWebTestCaseAuthenticatedAbstract.class.inc'; require_once __DIR__ . '/../../../../PhraseanetWebTestCaseAuthenticatedAbstract.class.inc';
use Alchemy\Phrasea\Controller\Prod\Query; use Alchemy\Phrasea\Controller\Prod\Query;
@@ -7,7 +9,22 @@ use Symfony\Component\HttpFoundation\Request;
class QueryTest extends \PhraseanetWebTestCaseAuthenticatedAbstract class QueryTest extends \PhraseanetWebTestCaseAuthenticatedAbstract
{ {
protected $client;
/**
* @covers Alchemy\Phrasea\Controller\Prod\Query::query
*/
public function testQuery()
{
$route = '/prod/query/';
self::$DI['client']->request('POST', $route);
$response = self::$DI['client']->getResponse();
$this->assertEquals('application/json', $response->headers->get('Content-type'));
$data = json_decode($response->getContent(), true);
$this->assertInternalType('array', $data);
}
/** /**
* @covers Alchemy\Phrasea\Controller\Prod\Query::queryAnswerTrain * @covers Alchemy\Phrasea\Controller\Prod\Query::queryAnswerTrain

View File

@@ -36,5 +36,87 @@ class PhraseaEngineTest extends SearchEngineAbstractTest
{ {
$this->markTestSkipped('Phrasea does not support `storyid=` request'); $this->markTestSkipped('Phrasea does not support `storyid=` request');
} }
public function testClearAllCache()
{
self::$searchEngine->initialize();
foreach (range(1, 10) as $i) {
phrasea_create_session(self::$DI['app']['phraseanet.user']->get_id());
}
$sql = 'SELECT session_id FROM cache';
$stmt = self::$DI['app']['phraseanet.appbox']->get_connection()->prepare($sql);
$stmt->execute();
$rs = $stmt->fetchAll(\PDO::FETCH_ASSOC);
$stmt->closeCursor();
$n = count($rs);
$sql = 'UPDATE cache SET lastaccess = :date WHERE session_id = :session_id';
$stmt = self::$DI['app']['phraseanet.appbox']->get_connection()->prepare($sql);
$date = new \DateTime('-2 months');
foreach ($rs as $row) {
$stmt->execute(array(
':date' => $date->format(DATE_ISO8601),
':session_id' => $row['session_id'],
));
break;
}
$date = new \DateTime('-1 months');
self::$searchEngine->clearAllCache($date);
$sql = 'SELECT session_id FROM cache';
$stmt = self::$DI['app']['phraseanet.appbox']->get_connection()->prepare($sql);
$stmt->execute();
$rs = $stmt->fetchAll(\PDO::FETCH_ASSOC);
$stmt->closeCursor();
$this->assertEquals($n - 1, count($rs));
self::$searchEngine->clearAllCache();
$sql = 'SELECT session_id FROM cache';
$stmt = self::$DI['app']['phraseanet.appbox']->get_connection()->prepare($sql);
$stmt->execute();
$rs = $stmt->fetchAll(\PDO::FETCH_ASSOC);
$stmt->closeCursor();
$this->assertEquals(0, count($rs));
}
public function testClearCache()
{
self::$searchEngine->initialize();
self::$searchEngine->clearAllCache();
$first_id = phrasea_create_session(self::$DI['app']['phraseanet.user']->get_id());
$phrasea_ses_id = phrasea_create_session(self::$DI['app']['phraseanet.user']->get_id());
$this->assertNotEquals($first_id, $phrasea_ses_id);
$this->assertGreaterThan(0, $phrasea_ses_id);
self::$DI['app']['session']->set('phrasea_session_id', $phrasea_ses_id);
self::$searchEngine->clearCache();
$sql = 'SELECT session_id FROM cache';
$stmt = self::$DI['app']['phraseanet.appbox']->get_connection()->prepare($sql);
$stmt->execute();
$rs = $stmt->fetchAll(\PDO::FETCH_ASSOC);
$stmt->closeCursor();
$this->assertEquals(1, count($rs));
foreach ($rs as $row) {
$this->assertEquals($first_id, $row['session_id']);
}
}
} }

View File

@@ -89,12 +89,13 @@ class SphinxSearchEngineTest extends SearchEngineAbstractTest
$binaryFinder = new ExecutableFinder(); $binaryFinder = new ExecutableFinder();
$indexer = $binaryFinder->find('indexer'); $indexer = $binaryFinder->find('indexer');
$process = new Process($indexer . ' --all --rotate -c ' . self::$config);
$process->run();
$appbox = self::$DI['app']['phraseanet.appbox']; $appbox = self::$DI['app']['phraseanet.appbox'];
self::$searchEngine->buildSuggestions($appbox->get_databoxes(), self::$config, 0); self::$searchEngine->buildSuggestions($appbox->get_databoxes(), self::$config, 0);
$process = new Process($indexer . ' --all --rotate -c ' . self::$config);
$process->run();
usleep(500000);
$suggestions = self::$searchEngine->autoComplete('jean'); $suggestions = self::$searchEngine->autoComplete('jean');
$this->assertInstanceOf('\\Doctrine\\Common\\Collections\\ArrayCollection', $suggestions); $this->assertInstanceOf('\\Doctrine\\Common\\Collections\\ArrayCollection', $suggestions);

View File

@@ -41,7 +41,7 @@ class Session_LoggerTest extends PhraseanetPHPUnitAbstract
$sql = 'SELECT id FROM log $sql = 'SELECT id FROM log
WHERE sit_session = :ses_id AND usrid = :usr_id AND site = :site'; WHERE sit_session = :ses_id AND usrid = :usr_id AND site = :site';
$params = array( $params = array(
':ses_id' => self::$DI['app']['session']->get('phrasea_session_id') ':ses_id' => self::$DI['app']['session']->get('session_id')
, ':usr_id' => self::$DI['app']['phraseanet.user']->get_id() , ':usr_id' => self::$DI['app']['phraseanet.user']->get_id()
, ':site' => self::$DI['app']['phraseanet.registry']->get('GV_sit') , ':site' => self::$DI['app']['phraseanet.registry']->get('GV_sit')
); );
@@ -52,7 +52,7 @@ class Session_LoggerTest extends PhraseanetPHPUnitAbstract
$row = $stmt->fetch(PDO::FETCH_ASSOC); $row = $stmt->fetch(PDO::FETCH_ASSOC);
$this->assertEquals($this->object->get_id(), $row['id']); $this->assertEquals($this->object->get_id(), $row['id']);
$log_id = $this->object->get_id(); $log_id = $this->object->get_id();
$ses_id = self::$DI['app']['session']->get('phrasea_session_id'); $ses_id = self::$DI['app']['session']->get('session_id');
$usr_id = self::$DI['app']['phraseanet.user']->get_id(); $usr_id = self::$DI['app']['phraseanet.user']->get_id();
self::$DI['app']->closeAccount(); self::$DI['app']->closeAccount();

View File

@@ -197,7 +197,7 @@ class record_adapterTest extends PhraseanetPHPUnitAuthenticatedAbstract
public function testGet_sha256() public function testGet_sha256()
{ {
$this->assertNotNull(self::$DI['record_1']->get_sha256()); $this->assertNotNull(self::$DI['record_1']->get_sha256());
$this->assertRegExp('/[a-zA-Z0-9]{64}/', self::$DI['record_1']->get_sha256()); $this->assertRegExp('/[a-zA-Z0-9]{32}/', self::$DI['record_1']->get_sha256());
$this->assertNull(self::$DI['record_story_1']->get_sha256()); $this->assertNull(self::$DI['record_story_1']->get_sha256());
} }
@@ -208,7 +208,7 @@ class record_adapterTest extends PhraseanetPHPUnitAuthenticatedAbstract
public function testGet_status() public function testGet_status()
{ {
$this->assertRegExp('/[01]{64}/', self::$DI['record_1']->get_status()); $this->assertRegExp('/[01]{32}/', self::$DI['record_1']->get_status());
} }
public function testGet_subdef() public function testGet_subdef()

View File

@@ -9,6 +9,7 @@
*/ */
use Alchemy\Phrasea\Application; use Alchemy\Phrasea\Application;
use Alchemy\Phrasea\SearchEngine\SearchEngineOptions;
/** /**
* *
@@ -79,75 +80,106 @@ $mod_xy = $mod_col * $mod_row;
$tbases = array(); $tbases = array();
$options = new searchEngine_options(); $options = new SearchEngineOptions();
$options->disallowBusinessFields();
$parm['bas'] = is_array($parm['bas']) ? $parm['bas'] : array_keys($app['phraseanet.user']->ACL()->get_granted_base()); $bas = $app['phraseanet.user']->ACL()->get_granted_base();
if (is_array($parm['bas'])) {
$bas = array_map(function($base_id) use ($app) {
return \collection::get_from_base_id($app, $base_id);
}, $parm['bas']);
}
$databoxes = array();
foreach ($bas as $collection) {
if (!isset($databoxes[$collection->get_sbas_id()])) {
$databoxes[$collection->get_sbas_id()] = $collection->get_databox();
}
}
if ($app['phraseanet.user']->ACL()->has_right('modifyrecord')) { if ($app['phraseanet.user']->ACL()->has_right('modifyrecord')) {
$options->set_business_fields(array()); $BF = array_filter($bas, function($collection) use ($app) {
return $app['phraseanet.user']->ACL()->has_right_on_base($collection->get_base_id(), 'canmodifrecord');
});
$BF = array(); $options->allowBusinessFieldsOn($BF);
}
foreach ($app['phraseanet.user']->ACL()->get_granted_base(array('canmodifrecord')) as $collection) { $status = is_array($parm['status']) ? $parm['status'] : array();
if (count($parm['bas']) === 0 || in_array($collection->get_base_id(), $parm['bas'])) { $fields = is_array($parm['infield']) ? $parm['infield'] : array();
$BF[] = $collection->get_base_id();
$databoxFields = array();
foreach ($databoxes as $databox) {
foreach ($fields as $field) {
try {
$databoxField = $databox->get_meta_structure()->get_element_by_name($field);
} catch (\Exception $e) {
continue;
}
if ($databoxField) {
$databoxFields[] = $databoxField;
} }
} }
$options->set_business_fields($BF);
} else {
$options->set_business_fields(array());
} }
$options->set_bases($parm['bas'], $app['phraseanet.user']->ACL());
if ( ! is_array($parm['infield']))
$parm['infield'] = array();
foreach ($parm['infield'] as $offset => $value) { $options->setFields($databoxFields);
if (trim($value) === '') $options->setStatus($status);
unset($parm['infield'][$offset]); $options->onCollections($bas);
$options->setSearchType($parm['search_type']);
$options->setRecordType($parm['recordtype']);
$options->setMinDate($parm['datemin']);
$options->setMaxDate($parm['datemax']);
$databoxDateFields = array();
foreach ($databoxes as $databox) {
foreach (explode('|', $parm['datefield']) as $field) {
try {
$databoxField = $databox->get_meta_structure()->get_element_by_name($field);
} catch (\Exception $e) {
continue;
}
if ($databoxField) {
$databoxDateFields[] = $databoxField;
}
}
} }
$options->set_fields($parm['infield']);
if ( ! is_array($parm['status']))
$parm['status'] = array();
$options->set_status($parm['status']);
$options->set_search_type($parm['search_type']);
$options->set_record_type($parm['recordtype']);
$options->set_min_date($parm['datemin']);
$options->set_max_date($parm['datemax']);
$options->set_date_fields(explode('|', $parm['datefield']));
$options->set_sort($parm['sort'], $parm['ord']);
$options->set_use_stemming($parm['stemme']);
if ($parm['ord'] === NULL) if ($parm['ord'] === NULL)
$parm['ord'] = \searchEngine_options::SORT_MODE_DESC; $parm['ord'] = \searchEngine_options::SORT_MODE_DESC;
else else
$parm['ord'] = (int) $parm['ord']; $parm['ord'] = (int) $parm['ord'];
$options->setDateFields($databoxDateFields);
$options->setSort($parm['sort'], $parm['ord']);
$options->useStemming($parm['stemme']);
$form = serialize($options); $form = serialize($options);
$perPage = $mod_xy; $perPage = $mod_xy;
$search_engine = new searchEngine_adapter($app); $app['phraseanet.SE']->set_options($options);
$search_engine->set_options($options);
$firstPage = $parm['pag'] < 1;
if ($parm['pag'] < 1) { if ($parm['pag'] < 1) {
$search_engine->set_is_first_page(true); $app['phraseanet.SE']->resetCache();
$search_engine->reset_cache();
$parm['pag'] = 1; $parm['pag'] = 1;
} }
$result = $search_engine->query_per_page($parm['qry'], (int) $parm["pag"], $perPage); $result = $app['phraseanet.SE']->query($parm['qry'], (((int) $parm["pag"] - 1) * $perPage), $perPage);
$proposals = $firstPage ? $result->propositions() : false;
$npages = $result->total();
$page = $result->currentPage($perPage);
$proposals = $search_engine->is_first_page() ? $result->get_propositions() : false;
$npages = $result->get_total_pages();
$page = $result->get_current_page();
$ACL = $app['phraseanet.user']->ACL(); $ACL = $app['phraseanet.user']->ACL();
@@ -173,7 +205,7 @@ $history = queries::history($app['phraseanet.appbox'], $app['phraseanet.user']->
echo '<script language="javascript" type="text/javascript">$("#history").empty().append("' . str_replace('"', '\"', $history) . '")</script>'; echo '<script language="javascript" type="text/javascript">$("#history").empty().append("' . str_replace('"', '\"', $history) . '")</script>';
$nbanswers = $result->get_count_available_results(); $nbanswers = $result->available();
$longueur = strlen($parm['qry']); $longueur = strlen($parm['qry']);
$qrys = '<div>' . _('client::answers: rapport de questions par bases') . '</div>'; $qrys = '<div>' . _('client::answers: rapport de questions par bases') . '</div>';
@@ -190,7 +222,7 @@ $txt = "<b>" . substr($parm['qry'], 0, 36) . ($longueur > 36 ? "..." : "") . "</
}); });
</script> </script>
<?php <?php
$npages = $result->get_total_pages(); $npages = $result->totalPages($perPage);
$pages = ''; $pages = '';
$ecart = 3; $ecart = 3;
$max = (2 * $ecart) + 3; $max = (2 * $ecart) + 3;
@@ -266,11 +298,9 @@ if ($mod_col == 1)
else else
$layoutmode = "grid"; $layoutmode = "grid";
$count = $result->get_datas();
$i = 0; $i = 0;
if (count($result->get_datas()) > 0) { if (count($result->results()) > 0) {
?><div><table id="grid" cellpadding="0" cellspacing="0" border="0" style="xwidth:95%;"><?php ?><div><table id="grid" cellpadding="0" cellspacing="0" border="0" style="xwidth:95%;"><?php
if ($mod_col == 1) { // MODE LISTE if ($mod_col == 1) { // MODE LISTE
?><tr style="visibility:hidden"><td class="w160px" /><td /></tr><?php ?><tr style="visibility:hidden"><td class="w160px" /><td /></tr><?php
@@ -282,7 +312,7 @@ if (count($result->get_datas()) > 0) {
?></tr><?php ?></tr><?php
} }
foreach ($result->get_datas() as $record) { foreach ($result->results() as $record) {
/* @var $record record_adapter */ /* @var $record record_adapter */
$base_id = $record->get_base_id(); $base_id = $record->get_base_id();
$sbas_id = $record->get_sbas_id(); $sbas_id = $record->get_sbas_id();
@@ -427,7 +457,7 @@ if (count($result->get_datas()) > 0) {
<script type="text/javascript"> <script type="text/javascript">
$(document).ready(function(){ $(document).ready(function(){
p4.tot = <?php echo $result->get_count_available_results(); ?>; p4.tot = <?php echo $result->available(); ?>;
p4.tot_options = '<?php echo serialize($options) ?>'; p4.tot_options = '<?php echo serialize($options) ?>';
p4.tot_query = '<?php echo $parm['qry'] ?>'; p4.tot_query = '<?php echo $parm['qry'] ?>';