diff --git a/lib/classes/module/console/taskrun.class.php b/lib/classes/module/console/taskrun.class.php index 61a48391f1..cce41dafd1 100644 --- a/lib/classes/module/console/taskrun.class.php +++ b/lib/classes/module/console/taskrun.class.php @@ -59,7 +59,7 @@ class module_console_taskrun extends Command { if ($this->task) { $this->task->log(sprintf("signal %s received", $signo)); - if ($signo == SIGTERM) { + if ($signo == SIGTERM || $signo == SIGINT) { $this->task->setRunning(false); } } @@ -113,7 +113,6 @@ class module_console_taskrun extends Command $logfile = __DIR__ . '/../../../../logs/task_' . $task_id . '.log'; $handler = new Handler\RotatingFileHandler($logfile, 10); $logger->pushHandler($handler); - $this->task = $task_manager->getTask($task_id, $logger); register_tick_function(array($this, 'tick_handler'), true); @@ -121,6 +120,8 @@ class module_console_taskrun extends Command if (function_exists('pcntl_signal')) { pcntl_signal(SIGTERM, array($this, 'sig_handler')); + pcntl_signal(SIGINT, array($this, 'sig_handler')); + // pcntl_signal(SIGKILL, array($this, 'sig_handler')); } try { diff --git a/lib/classes/task/abstract.class.php b/lib/classes/task/abstract.class.php index 4e466bb726..de54f355a7 100755 --- a/lib/classes/task/abstract.class.php +++ b/lib/classes/task/abstract.class.php @@ -97,7 +97,8 @@ abstract class task_abstract protected $taskid = NULL; protected $system = ''; // "DARWIN", "WINDOWS" , "LINUX"... protected $argt = array( - "--help" => array("set" => false, "values" => array(), "usage" => " (no help available)") + "--help" => array( + 'set' => false, "values" => array(), "usage" => " (no help available)") ); /** @@ -107,51 +108,45 @@ abstract class task_abstract */ public function getState() { + static $stmt = NULL; $conn = connection::getPDOConnection(); - $sql = 'SELECT status FROM task2 WHERE task_id = :taskid'; - $stmt = $conn->prepare($sql); + if ( ! $stmt) { + $sql = 'SELECT status FROM task2 WHERE task_id = :taskid'; + $stmt = $conn->prepare($sql); + } $stmt->execute(array(':taskid' => $this->taskid)); $row = $stmt->fetch(PDO::FETCH_ASSOC); $stmt->closeCursor(); if ( ! $row) { throw new Exception('Unknown task id'); } - + unset($conn); return $row['status']; } /** - * to be overwritten by tasks : echo text to be included in in task interface + * to be overwritten by tasks : ECHO text to be included in in task interface */ public function printInterfaceHEAD() { - return false; + } /** - * to be overwritten by tasks : echo javascript to be included in in task interface + * to be overwritten by tasks : ECHO javascript to be included in in task interface */ public function printInterfaceJS() { - return false; + } /** * * @return boolean */ - public function printInterfaceHTML() + public function hasInterfaceHTML() { - return false; - } - - /** - * - * @return boolean - */ - public function getGraphicForm() - { - return false; + return method_exists($this, "getInterfaceHTML"); } /** @@ -163,12 +158,12 @@ abstract class task_abstract public function setState($status) { $av_status = array( - self::STATE_STARTED - , self::STATE_TOSTOP - , self::STATE_STOPPED - , self::STATE_TORESTART - , self::STATE_TOSTART - , self::STATE_TODELETE + self::STATE_STARTED, + self::STATE_TOSTOP, + self::STATE_STOPPED, + self::STATE_TORESTART, + self::STATE_TOSTART, + self::STATE_TODELETE ); if ( ! in_array($status, $av_status)) { @@ -184,21 +179,30 @@ abstract class task_abstract $this->log(sprintf("task %d <- %s", $this->getID(), $status)); } - // 'active' means 'auto-start when scheduler starts' - public function setActive($boolean) + /** + * + * @param boolean $active 'active' means 'auto-start when scheduler starts' + * @return \task_abstract + */ + public function setActive($active) { $conn = connection::getPDOConnection(); $sql = 'UPDATE task2 SET active = :active WHERE task_id = :taskid'; $stmt = $conn->prepare($sql); - $stmt->execute(array(':active' => ($boolean ? '1' : '0'), ':taskid' => $this->getID())); + $stmt->execute(array(':active' => ($active ? '1' : '0'), ':taskid' => $this->getID())); $stmt->closeCursor(); - $this->active = ! ! $boolean; + $this->active = ! ! $active; return $this; } + /** + * + * @param string $title + * @return \task_abstract + */ public function setTitle($title) { $title = strip_tags($title); @@ -214,6 +218,12 @@ abstract class task_abstract return $this; } + /** + * + * @param string $settings xml settings as STRING + * @throws Exception_InvalidArgument if not proper xml + * @return \task_abstract + */ public function setSettings($settings) { if (@simplexml_load_string($settings) === FALSE) { @@ -230,8 +240,14 @@ abstract class task_abstract $this->settings = $settings; $this->loadSettings(simplexml_load_string($settings)); + + return $this; } + /** + * + * @return \task_abstract + */ public function resetCrashCounter() { $conn = connection::getPDOConnection(); @@ -246,11 +262,19 @@ abstract class task_abstract return $this; } + /** + * + * @return int + */ public function getCrashCounter() { return $this->crash_counter; } + /** + * + * @return int + */ public function incrementCrashCounter() { $conn = connection::getPDOConnection(); @@ -260,20 +284,32 @@ abstract class task_abstract $stmt->execute(array(':taskid' => $this->getID())); $stmt->closeCursor(); - return $this->crash_counter ++; + return ++ $this->crash_counter; } + /** + * + * @return string + */ public function getSettings() { return $this->settings; } - // 'active' means 'auto-start when scheduler starts' + /** + * + * @return boolean + * 'active' means 'auto-start when scheduler starts' + */ public function isActive() { return $this->active; } + /** + * + * @return int + */ public function getCompletedPercentage() { return $this->completed_percentage; @@ -319,15 +355,30 @@ abstract class task_abstract $this->active = ! ! $row['active']; $this->settings = $row['settings']; $this->runner = $row['runner']; - $this->completed_percentage = (integer) $row['completed']; - $this->loadSettings(simplexml_load_string($row['settings'])); + $this->completed_percentage = (int) $row['completed']; + $this->settings = $row['settings']; + + $sx = @simplexml_load_string($this->settings); + if ($sx) { + $this->loadSettings($sx); + } } + /** + * + * @return enum (self::RUNNER_MANUAL or self::RUNNER_SCHEDULER) + */ public function getRunner() { return $this->runner; } + /** + * + * @param enum $runner (self::RUNNER_MANUAL or self::RUNNER_SCHEDULER) + * @throws Exception_InvalidArgument + * @return \task_abstract + */ public function setRunner($runner) { if ($runner != self::RUNNER_MANUAL && $runner != self::RUNNER_SCHEDULER) { @@ -347,13 +398,22 @@ abstract class task_abstract $stmt = $conn->prepare($sql); $stmt->execute($params); $stmt->closeCursor(); + + return $this; } + /** + * + * @return string + */ public function getTitle() { return $this->title; } + /** + * + */ public function delete() { if ( ! $this->getPID()) { // do not delete a running task @@ -369,6 +429,9 @@ abstract class task_abstract } } + /** + * set last execution time to now() + */ public function setLastExecTime() { $conn = connection::getPDOConnection(); @@ -380,7 +443,7 @@ abstract class task_abstract /** * Return the last time the task was executed - * + * * @return null|\DateTime */ public function getLastExecTime() @@ -397,10 +460,16 @@ abstract class task_abstract if ($row['last_exec_time'] != '0000-00-00 00:00:00') { $time = new \DateTime($row['last_exec_time']); } - + return $time; } + /** + * + * @return variant + * pid (int) of the task, or NULL if the pid file + * NULL : the pid file is not locked (task no running) + */ public function getPID() { $pid = NULL; @@ -421,6 +490,11 @@ abstract class task_abstract return $pid; } + /** + * + * @param boolean $stat + * set to false to ask the task to quit its loop + */ public function setRunning($stat) { $this->running = $stat; @@ -445,6 +519,12 @@ abstract class task_abstract } } + /** + * sleep n seconds + * + * @param int $nsec + * @throws \InvalidArgumentException + */ protected function sleep($nsec) { $nsec = (integer) $nsec; @@ -455,16 +535,25 @@ abstract class task_abstract } } + /** + * + * @return string fullpath to the pid file for the task + */ private function getLockfilePath() { $core = \bootstrap::getCore(); $lockdir = $core->getRegistry()->get('GV_RootPath') . 'tmp/locks/'; - $lockfile = ($lockdir . 'task_' . $this->getID() . '.lock'); + $lockfilePath = ($lockdir . 'task_' . $this->getID() . '.lock'); - return($lockfile); + return($lockfilePath); } + /** + * + * @return resource file descriptor of the OPENED pid file + * @throws Exception if file is already locked (task running) + */ private function lockTask() { $lockfile = $this->getLockfilePath(); @@ -504,9 +593,12 @@ abstract class task_abstract try { $this->run2(); } catch (\Exception $exception) { - + } + if ($this->getState() === self::STATE_STARTED && $this->runner === self::RUNNER_MANUAL) + $this->setState(self::STATE_STOPPED); + // in any case, exception or not, the task is ending so unlock the pid file $this->unlockTask($lockFD); @@ -516,7 +608,11 @@ abstract class task_abstract } } - public function unlockTask($lockFD) + /** + * + * @param resource $lockFD file descriptor of the OPENED lock file + */ + private function unlockTask($lockFD) { flock($lockFD, LOCK_UN | LOCK_NB); ftruncate($lockFD, 0); @@ -563,9 +659,11 @@ abstract class task_abstract // post-process $this->postProcessOneContent($box, $row); + $rowsdone ++; + $current_memory = memory_get_usage(); if ($current_memory >> 20 >= $this->maxmegs) { - $this->log(sprintf("Max memory (%s M) reached (actual is %s M)", $this->maxmegs, $current_memory)); + $this->log(sprintf("Max memory (%s M) reached (actual is %.02f M)", $this->maxmegs, ($current_memory >> 10) / 1024)); $this->running = FALSE; $ret = self::STATE_MAXMEGSREACHED; } @@ -577,8 +675,7 @@ abstract class task_abstract } try { - $status = $this->getState(); - if ($status == self::STATE_TOSTOP) { + if ($this->getState() == self::STATE_TOSTOP) { $this->running = FALSE; $ret = self::STATE_TOSTOP; } @@ -592,11 +689,11 @@ abstract class task_abstract } // // if nothing was done, at least check the status - if (count($rs) == 0 && $this->running) { + if ($rowsdone == 0 && $this->running) { $current_memory = memory_get_usage(); if ($current_memory >> 20 >= $this->maxmegs) { - $this->log(sprintf("Max memory (%s M) reached (current is %s M)", $this->maxmegs, $current_memory)); + $this->log(sprintf("Max memory (%s M) reached (current is %.02f M)", $this->maxmegs, ($current_memory >> 10) / 1024)); $this->running = FALSE; $ret = self::STATE_MAXMEGSREACHED; } @@ -689,8 +786,8 @@ abstract class task_abstract /** * * @param appbox $appbox - * @param type $class_name - * @param type $settings + * @param string $class_name + * @param string $settings (xml string) * @return task_abstract */ public static function create(appbox $appbox, $class_name, $settings = null) @@ -741,11 +838,21 @@ abstract class task_abstract return($t); } + /** + * + * @return int id of the task + */ public function getID() { return $this->taskid; } + /** + * + * @param int $done + * @param int $todo + * @return \task_abstract + */ public function setProgress($done, $todo) { $p = ($todo > 0) ? ((100 * $done) / $todo) : -1; @@ -754,11 +861,14 @@ abstract class task_abstract $conn = connection::getPDOConnection(); $sql = 'UPDATE task2 SET completed = :p WHERE task_id = :taskid'; $stmt = $conn->prepare($sql); - $stmt->execute(array(':p' => $p, ':taskid' => $this->getID())); + $stmt->execute(array( + ':p' => $p, + ':taskid' => $this->getID() + )); $stmt->closeCursor(); $this->completed_percentage = $p; } catch (Exception $e) { - + } return $this; diff --git a/lib/classes/task/appboxAbstract.class.php b/lib/classes/task/appboxAbstract.class.php index fff2bb772b..b80d3fa771 100755 --- a/lib/classes/task/appboxAbstract.class.php +++ b/lib/classes/task/appboxAbstract.class.php @@ -84,6 +84,7 @@ abstract class task_appboxAbstract extends task_abstract switch ($process_ret) { case self::STATE_MAXMEGSREACHED: case self::STATE_MAXRECSDONE: + case self::STATE_OK: if ($this->getRunner() == self::RUNNER_SCHEDULER) { $this->setState(self::STATE_TORESTART); $this->running = FALSE; @@ -99,9 +100,6 @@ abstract class task_appboxAbstract extends task_abstract $this->setState(self::STATE_TODELETE); $this->running = FALSE; break; - - case self::STATE_OK: - break; } } // if(row) @@ -118,7 +116,7 @@ abstract class task_appboxAbstract extends task_abstract */ protected function process(appbox $appbox) { - $ret = self::STATE_OK; + $ret = self::STATE_OK; try { // get the records to process @@ -126,7 +124,6 @@ abstract class task_appboxAbstract extends task_abstract // process the records $ret = $this->processLoop($appbox, $rs); - } catch (Exception $e) { $this->log('Error : ' . $e->getMessage()); } diff --git a/lib/classes/task/databoxAbstract.class.php b/lib/classes/task/databoxAbstract.class.php index c735a599f3..01aee7f427 100755 --- a/lib/classes/task/databoxAbstract.class.php +++ b/lib/classes/task/databoxAbstract.class.php @@ -85,7 +85,7 @@ abstract class task_databoxAbstract extends task_abstract try { // get the records to process - $databox = databox::get_instance((int)$row['sbas_id']); + $databox = databox::get_instance((int) $row['sbas_id']); } catch (Exception $e) { $this->log(sprintf('Warning : can\' connect to sbas(%s)', $row['sbas_id'])); continue; @@ -111,6 +111,7 @@ abstract class task_databoxAbstract extends task_abstract switch ($process_ret) { case self::STATE_MAXMEGSREACHED: case self::STATE_MAXRECSDONE: + case self::STATE_OK: if ($this->getRunner() == self::RUNNER_SCHEDULER) { $this->setState(self::STATE_TORESTART); $this->running = FALSE; @@ -126,9 +127,6 @@ abstract class task_databoxAbstract extends task_abstract // DO NOT SUICIDE IN THE LOOP, may have to work on other sbas !!! $task_must_delete = TRUE; break; - - case self::STATE_OK: - break; } $this->flushRecordsSbas(); @@ -160,7 +158,6 @@ abstract class task_databoxAbstract extends task_abstract // process the records $ret = $this->processLoop($databox, $rs); - } catch (Exception $e) { $this->log('Error : ' . $e->getMessage()); } diff --git a/lib/classes/task/period/archive.class.php b/lib/classes/task/period/archive.class.php index 90a0861b7a..b3c41aaec2 100755 --- a/lib/classes/task/period/archive.class.php +++ b/lib/classes/task/period/archive.class.php @@ -212,20 +212,11 @@ class task_period_archive extends task_abstract } /** - * - * @return string - */ - public function getGraphicForm() - { - return true; - } - - /** - * printInterfaceHTML(..) : generer l'interface 'graphic view' + * getInterfaceHTML(..) : retourner l'interface 'graphic view' * * @return Void */ - public function printInterfaceHTML() + public function getInterfaceHTML() { $appbox = appbox::get_instance(\bootstrap::getCore()); @@ -264,9 +255,8 @@ class task_period_archive extends task_abstract  
list)); } -} \ No newline at end of file +} diff --git a/lib/classes/task/period/cindexer.class.php b/lib/classes/task/period/cindexer.class.php index e9656f9a4d..f6ea98a7de 100755 --- a/lib/classes/task/period/cindexer.class.php +++ b/lib/classes/task/period/cindexer.class.php @@ -261,20 +261,11 @@ class task_period_cindexer extends task_abstract return; } - /** - * - * @return string - */ - public function getGraphicForm() - { - return true; - } - /** * * @return return */ - public function printInterfaceHTML() + public function getInterfaceHTML() { $appname = 'phraseanet_indexer'; if (defined('PHP_WINDOWS_VERSION_BUILD')) { @@ -333,9 +324,8 @@ class task_period_cindexer extends task_abstract
cmd
@@ -167,9 +158,8 @@ class task_period_ftp extends task_appboxAbstract  

get_session(); @@ -417,9 +407,7 @@ class task_period_outofdate extends task_abstract
cmd
@@ -233,9 +228,8 @@ class task_period_subdef extends task_databoxAbstract
get_session(); @@ -327,9 +322,8 @@ class task_period_workflow01 extends task_databoxAbstract
cmd
get_parms( + "period", "logsql" + ); + $dom = new DOMDocument(); + $dom->preserveWhiteSpace = false; + $dom->formatOutput = true; + if ($dom->loadXML($oldxml)) { + $xmlchanged = false; + // foreach($parm2 as $pname=>$pvalue) + foreach (array( + "str:period", + "boo:logsql" + ) as $pname) { + $ptype = substr($pname, 0, 3); + $pname = substr($pname, 4); + $pvalue = $parm2[$pname]; + if (($ns = $dom->getElementsByTagName($pname)->item(0))) { + // le champ existait dans le xml, on supprime son ancienne valeur (tout le contenu) + while (($n = $ns->firstChild)) + $ns->removeChild($n); + } else { + // le champ n'existait pas dans le xml, on le cr�e + $dom->documentElement->appendChild($dom->createTextNode("\t")); + $ns = $dom->documentElement->appendChild($dom->createElement($pname)); + $dom->documentElement->appendChild($dom->createTextNode("\n")); + } + // on fixe sa valeur + switch ($ptype) { + case "str": + $ns->appendChild($dom->createTextNode($pvalue)); + break; + case "boo": + $ns->appendChild($dom->createTextNode($pvalue ? '1' : '0')); + break; + } + $xmlchanged = true; + } + } + return($dom->saveXML()); + } + + // ==================================================================== + // xml2graphic : must fill the graphic form (using js) from xml + // ==================================================================== + public function xml2graphic($xml, $form) + { + if (($sxml = simplexml_load_string($xml))) { // in fact XML IS always valid here... + // ... but we could check for safe values + if ((int) ($sxml->period) < 10) + $sxml->period = 10; + elseif ((int) ($sxml->period) > 1440) // 1 jour + $sxml->period = 1440; + + if ((string) ($sxml->delay) == '') + $sxml->delay = 0; + ?> + + + + + + +
+ Périodicité :  + + minutes +           +  log changes +
+
+
+
+ maxrecs = 1000; + $this->sxTaskSettings = @simplexml_load_string($this->getSettings()); + if ( ! $this->sxTaskSettings) + return array(); + + $ret = array(); + + $logsql = (int) ($this->sxTaskSettings->logsql) > 0; + + foreach ($this->sxTaskSettings->tasks->task as $sxtask) { + + if ( ! $this->running) { + break; + } + + $task = $this->calcSQL($sxtask); + + if ($logsql) { + $this->log(sprintf("playing task '%s' on base '%s'" + , $task['name'] + , $task['basename'] ? $task['basename'] : '')); + } + + try { + $connbas = connection::getPDOConnection($task['sbas_id']); + } catch (Exception $e) { + $this->log(sprintf("can't connect sbas %s", $task['sbas_id'])); + continue; + } + + $stmt = $connbas->prepare($task['sql']['real']['sql']); + if ($stmt->execute(array())) { + while ($this->running && ($row = $stmt->fetch(PDO::FETCH_ASSOC)) !== FALSE) { + + $tmp = array('sbas_id' => $task['sbas_id'], 'record_id' => $row['record_id'], 'action' => $task['action']); + + $rec = new record_adapter($task['sbas_id'], $row['record_id']); + switch ($task['action']) { + + case 'UPDATE': + + // change collection ? + if (($x = (int) ($sxtask->to->coll['id'])) > 0) { + $tmp['coll'] = $x; + } + + // change sb ? + if (($x = $sxtask->to->status['mask'])) { + $tmp['sb'] = $x; + } + $ret[] = $tmp; + break; + + case 'DELETE': + $tmp['deletechildren'] = false; + if ($sxtask['deletechildren'] && $rec->is_grouping()) { + $tmp['deletechildren'] = true; + } + $ret[] = $tmp; + break; + } + } + $stmt->closeCursor(); + } + } + + return $ret; + } + + protected function processOneContent(appbox $appbox, Array $row) + { + $logsql = (int) ($this->sxTaskSettings->logsql) > 0; + $dbox = databox::get_instance($row['sbas_id']); + $rec = new record_adapter($row['sbas_id'], $row['record_id']); + switch ($row['action']) { + + case 'UPDATE': + + // change collection ? + if (array_key_exists('coll', $row)) { + $coll = collection::get_from_coll_id($dbox, $row['coll']); +// $rec->move_to_collection($coll, $appbox); + if ($logsql) { + $this->log(sprintf("on sbas %s move rid %s to coll %s \n", $row['sbas_id'], $row['record_id'], $coll->get_coll_id())); + } + } + + // change sb ? + if (array_key_exists('sb', $row)) { + $status = str_split($rec->get_status()); + foreach (str_split(strrev($row['sb'])) as $bit => $val) { + if ($val == '0' || $val == '1') { + $status[63 - $bit] = $val; + } + } + $status = implode('', $status); +// $rec->set_binary_status($status); + if ($logsql) { + $this->log(sprintf("on sbas %s set rid %s status to %s \n", $row['sbas_id'], $row['record_id'], $status)); + } + } + break; + + case 'DELETE': + if ($row['deletechildren'] && $rec->is_grouping()) { + foreach ($rec->get_children() as $child) { +// $child->delete(); + if ($logsql) { + $this->log(sprintf("on sbas %s delete (grp child) rid %s \n", $row['sbas_id'], $child->get_record_id())); + } + } + } +// $rec->delete(); + if ($logsql) { + $this->log(sprintf("on sbas %s delete rid %s \n", $row['sbas_id'], $rec->get_record_id())); + } + break; + } + + return $this; + } + + protected function postProcessOneContent(appbox $appbox, Array $row) + { + return $this; + } + + private function calcSQL($sxtask, $playTest = false) + { + $appbox = appbox::get_instance(\bootstrap::getCore()); + + $sbas_id = (int) ($sxtask['sbas_id']); + + $ret = array( + 'name' => $sxtask['name'] ? (string) $sxtask['name'] : 'sans nom', + 'name_htmlencoded' => htmlentities($sxtask['name'] ? $sxtask['name'] : 'sans nom'), + 'sbas_id' => $sbas_id, + 'basename' => '', + 'basename_htmlencoded' => '', + 'action' => strtoupper($sxtask['action']), + 'sql' => NULL, + 'err' => '', + 'err_htmlencoded' => '', + ); + + try { + $dbox = $appbox->get_databox($sbas_id); + + $ret['basename'] = $dbox->get_viewname(); + $ret['basename_htmlencoded'] = htmlentities($ret['basename']); + switch ($ret['action']) { + case 'UPDATE': + $ret['sql'] = $this->calcUPDATE($sbas_id, $sxtask, $playTest); + break; + case 'DELETE': + $ret['sql'] = $this->calcDELETE($sbas_id, $sxtask, $playTest); + $ret['deletechildren'] = (int) ($sxtask['deletechildren']); + break; + default: + $ret['err'] = "bad action '" . $ret['action'] . "'"; + $ret['err_htmlencoded'] = htmlentities($ret['err']); + break; + } + } catch (Exception $e) { + $ret['err'] = "bad sbas '" . $sbas_id . "'"; + $ret['err_htmlencoded'] = htmlentities($ret['err']); + } + + return($ret); + } + /* + * compute entry for a UPDATE query + */ + + private function calcUPDATE($sbas_id, &$sxtask, $playTest) + { + $tws = array(); // NEGATION of updates, used to build the 'test' sql + // + // set coll_id ? + if (($x = (int) ($sxtask->to->coll['id'])) > 0) { + $tws[] = 'coll_id!=' . $x; + } + + // set status ? + $x = $sxtask->to->status['mask']; + $mx = str_replace(' ', '0', ltrim(str_replace(array('0', 'x'), array(' ', ' '), $x))); + $ma = str_replace(' ', '0', ltrim(str_replace(array('x', '0'), array(' ', '1'), $x))); + if ($mx && $ma) + $tws[] = '((status ^ 0b' . $mx . ') & 0b' . $ma . ')!=0'; + elseif ($mx) + $tws[] = '(status ^ 0b' . $mx . ')!=0'; + elseif ($ma) + $tws[] = '(status & 0b' . $ma . ')!=0'; + + // compute the 'where' clause + list($tw, $join) = $this->calcWhere($sbas_id, $sxtask); + + // ... complete the where to buid the TEST + if (count($tws) == 1) + $tw[] = $tws[0]; + elseif (count($tws) > 1) + $tw[] = '(' . implode(') OR (', $tws) . ')'; + if (count($tw) == 1) + $where = $tw[0]; + if (count($tw) > 1) + $where = '(' . implode(') AND (', $tw) . ')'; + + // build the TEST sql (select) + $sql_test = 'SELECT SQL_CALC_FOUND_ROWS record_id FROM record' . $join; + if (count($tw) > 0) + $sql_test .= ' WHERE ' . ((count($tw) == 1) ? $tw[0] : '(' . implode(') AND (', $tw) . ')'); + $sql_test .= ' LIMIT 10'; + + // build the real sql (select) + $sql = 'SELECT record_id FROM record' . $join; + if (count($tw) > 0) + $sql .= ' WHERE ' . ((count($tw) == 1) ? $tw[0] : '(' . implode(') AND (', $tw) . ')'); + + $ret = array( + 'real' => array( + 'sql' => $sql, + 'sql_htmlencoded' => htmlentities($sql), + ), + 'test' => array( + 'sql' => $sql_test, + 'sql_htmlencoded' => htmlentities($sql_test), + 'result' => NULL, + 'err' => NULL + ) + ); + + if ($playTest) { + $ret['test']['result'] = $this->playTest($sbas_id, $sql_test); + } + + return($ret); + } + /* + * compute entry for a DELETE task + */ + + private function calcDELETE($sbas_id, &$sxtask, $playTest) + { + // compute the 'where' clause + list($tw, $join) = $this->calcWhere($sbas_id, $sxtask); + + // build the TEST sql (select) + $sql_test = 'SELECT SQL_CALC_FOUND_ROWS record_id FROM record' . $join; + if (count($tw) > 0) + $sql_test .= ' WHERE ' . ((count($tw) == 1) ? $tw[0] : '(' . implode(') AND (', $tw) . ')'); + $sql_test .= ' LIMIT 10'; + + // build the real sql (select) + $sql = 'SELECT record_id FROM record' . $join; + if (count($tw) > 0) + $sql .= ' WHERE ' . ((count($tw) == 1) ? $tw[0] : '(' . implode(') AND (', $tw) . ')'); + + $ret = array( + 'real' => array( + 'sql' => $sql, + 'sql_htmlencoded' => htmlentities($sql), + ), + 'test' => array( + 'sql' => $sql_test, + 'sql_htmlencoded' => htmlentities($sql_test), + 'result' => NULL, + 'err' => NULL + ) + ); + + if ($playTest) { + $ret['test']['result'] = $this->playTest($sbas_id, $sql_test); + } + + return($ret); + } + /* + * compute the 'where' clause + * returns an array of clauses to be joined by 'and' + * and a 'join' to needed tables + */ + + private function calcWhere($sbas_id, &$sxtask) + { + $connbas = connection::getPDOConnection($sbas_id); + + $tw = array(); + $join = ''; + + $ijoin = 0; + + // criteria + if (($x = $sxtask->from->type['type']) !== NULL) { + switch (strtoupper($x)) { + case 'RECORD': + $tw[] = 'parent_record_id!=record_id'; + break; + case 'REGROUP': + $tw[] = 'parent_record_id=record_id'; + break; + } + } + + // criteria + foreach ($sxtask->from->text as $x) { + $ijoin ++; + $comp = strtoupper($x['compare']); + if (in_array($comp, array('<', '>', '<=', '>=', '=', '!='))) { + $s = 'p' . $ijoin . '.name=\'' . $x['field'] . '\' AND p' . $ijoin . '.value' . $comp; + $s .= '' . $connbas->quote($x['value']) . ''; + + $tw[] = $s; + $join .= ' INNER JOIN prop AS p' . $ijoin . ' USING(record_id)'; + } else { + // bad comparison operator + } + } + + // criteria + foreach ($sxtask->from->date as $x) { + $ijoin ++; + $s = 'p' . $ijoin . '.name=\'' . $x['field'] . '\' AND NOW()'; + $s .= strtoupper($x['direction']) == 'BEFORE' ? '<' : '>='; + $delta = (int) ($x['delta']); + if ($delta > 0) + $s .= '(p' . $ijoin . '.value+INTERVAL ' . $delta . ' DAY)'; + elseif ($delta < 0) + $s .= '(p' . $ijoin . '.value-INTERVAL ' . -$delta . ' DAY)'; + else + $s .= 'p' . $ijoin . '.value'; + + $tw[] = $s; + $join .= ' INNER JOIN prop AS p' . $ijoin . ' USING(record_id)'; + } + + // criteria + if (($x = $sxtask->from->coll) !== NULL) { + $tcoll = explode(',', $x['id']); + foreach ($tcoll as $i => $c) + $tcoll[$i] = (int) $c; + if ($x['compare'] == '=') { + if (count($tcoll) == 1) { + $tw[] = 'coll_id = ' . $tcoll[0]; + } else { + $tw[] = 'coll_id IN(' . implode(',', $tcoll) . ')'; + } + } elseif ($x['compare'] == '!=') { + if (count($tcoll) == 1) { + $tw[] = 'coll_id != ' . $tcoll[0]; + } else { + $tw[] = 'coll_id NOT IN(' . implode(',', $tcoll) . ')'; + } + } else { + // bad operator + } + } + + // criteria + $x = $sxtask->from->status['mask']; + $mx = str_replace(' ', '0', ltrim(str_replace(array('0', 'x'), array(' ', ' '), $x))); + $ma = str_replace(' ', '0', ltrim(str_replace(array('x', '0'), array(' ', '1'), $x))); + if ($mx && $ma) { + $tw[] = '((status^0b' . $mx . ')&0b' . $ma . ')=0'; + } elseif ($mx) { + $tw[] = '(status^0b' . $mx . ')=0'; + } elseif ($ma) { + $tw[] = '(status&0b' . $ma . ")=0"; + } + + if (count($tw) == 1) { + $where = $tw[0]; + } + if (count($tw) > 1) { + $where = '(' . implode(') AND (', $tw) . ')'; + } + + return(array($tw, $join)); + } + /* + * play a 'test' sql on sbas, return the number of records and the 10 first rids + */ + + private function playTest($sbas_id, $sql) + { + $connbas = connection::getPDOConnection($sbas_id); + $result = array('rids' => array(), 'err' => '', 'n' => null); + + $stmt = $connbas->prepare($sql); + if ($stmt->execute(array())) { + $result['n'] = $connbas->query("SELECT FOUND_ROWS()")->fetchColumn(); + while (($row = $stmt->fetch(PDO::FETCH_ASSOC))) { + $result['rids'][] = $row['record_id']; + } + $stmt->closeCursor(); + } else { + $result['err'] = $connbas->last_error(); + } + + return($result); + } + + public function facility() + { + $request = http_request::getInstance(); + + $parm2 = $request->get_parms( + 'ACT', 'xml' + ); + + $ret = array('tasks' => array()); + switch ($parm2['ACT']) { + case 'CALCTEST': + $sxml = simplexml_load_string($parm2['xml']); + foreach ($sxml->tasks->task as $sxtask) { + $ret['tasks'][] = $this->calcSQL($sxtask, false); + } + break; + case 'PLAYTEST': + $sxml = simplexml_load_string($parm2['xml']); + foreach ($sxml->tasks->task as $sxtask) { + $ret['tasks'][] = $this->calcSQL($sxtask, true); + } + break; + case 'CALCSQL': + $xml = $this->graphic2xml(''); + $sxml = simplexml_load_string($xml); + foreach ($sxml->tasks->task as $sxtask) { + $ret['tasks'][] = $this->calcSQL($sxtask, false); + } + break; + } + + print(json_encode($ret)); + } +} +?> diff --git a/lib/classes/task/period/writemeta.class.php b/lib/classes/task/period/writemeta.class.php index dcb0c6f7b9..ab76b0d8bf 100644 --- a/lib/classes/task/period/writemeta.class.php +++ b/lib/classes/task/period/writemeta.class.php @@ -170,12 +170,7 @@ class task_period_writemeta extends task_databoxAbstract get_session(); @@ -204,9 +199,8 @@ class task_period_writemeta extends task_databoxAbstract
- {% if task.printInterfaceHTML %} + {% if task.hasInterfaceHTML() %}
{% trans 'boutton::vue graphique' %}
{% endif %} -
+
{% trans 'boutton::vue xml' %}
- {% if task.getGraphicForm %} + {% if task.hasInterfaceHTML() %} +
- {% if task.printInterfaceHTML %} - {{task.printInterfaceHTML()|raw}} - {% else %} -
- {% endif %} + {{task.getInterfaceHTML()|raw}}
{% endif %} -
+
diff --git a/tests/task/period/task_period_archiveTest.php b/tests/task/period/task_period_archiveTest.php index 14388c3e7a..8bc80b43e6 100644 --- a/tests/task/period/task_period_archiveTest.php +++ b/tests/task/period/task_period_archiveTest.php @@ -76,22 +76,10 @@ class task_period_archiveTest extends \PhraseanetPHPUnitAbstract } /** - * @covers task_period_archive::getGraphicForm - * @todo Implement testGetGraphicForm(). + * @covers task_period_archive::getInterfaceHTML + * @todo Implement testGetInterfaceHTML(). */ - public function testGetGraphicForm() - { - // Remove the following lines when you implement this test. - $this->markTestIncomplete( - 'This test has not been implemented yet.' - ); - } - - /** - * @covers task_period_archive::printInterfaceHTML - * @todo Implement testPrintInterfaceHTML(). - */ - public function testPrintInterfaceHTML() + public function testGetInterfaceHTML() { // Remove the following lines when you implement this test. $this->markTestIncomplete( diff --git a/www/admin/task2.php b/www/admin/task2.php index f67686c317..3d1825e888 100644 --- a/www/admin/task2.php +++ b/www/admin/task2.php @@ -56,9 +56,8 @@ try { $zGraphicForm = 'graphicForm'; $hasGraphicMode = false; -if (method_exists($task, 'getGraphicForm')) { +if ($task->hasInterfaceHTML()) { $hasGraphicMode = true; - $zGraphicForm = $task->getGraphicForm(); } else { $parm['view'] = 'XML'; } @@ -67,15 +66,11 @@ function stripdoublequotes($value) { return str_replace(array("\r\n", "\r", "\n", "\""), array('', '', '', '\"'), $value); } -if ( ! $task->getGraphicForm()) { $parm['view'] = 'XML'; -} $core = \bootstrap::getCore(); $twig = $core->getTwig(); -if ( ! $task->getGraphicForm()) { $parm['view'] = 'XML'; -} echo $twig->render('admin/task.html', array('task' => $task, 'view' => $parm['view'])); diff --git a/www/admin/task2utils.php b/www/admin/task2utils.php index e378583708..7e14cd60d6 100644 --- a/www/admin/task2utils.php +++ b/www/admin/task2utils.php @@ -39,8 +39,8 @@ phrasea::headers(); $ztask = $task_manager->getTask($parm['__tid']); switch ($parm['__act']) { case 'FORM2XML': - if (method_exists($ztask, 'printInterfaceHTML')) { - if ($ztask->getGraphicForm()) { + if ($ztask->hasInterfaceHTML()) { + if (1) { $xml = p4string::MakeString($ztask->graphic2xml($parm['__xml']), "js"); } else { $xml = p4string::MakeString($parm['__xml'], "js"); @@ -61,9 +61,9 @@ phrasea::headers(); break; case 'XML2FORM': - if (method_exists($ztask, 'printInterfaceHTML')) { + if ($ztask->hasInterfaceHTML()) { if ((simplexml_load_string($parm['txtareaxml']))) { - if ($ztask->getGraphicForm()) { + if (1) { if (($msg = ($ztask->xml2graphic($parm['txtareaxml'], "parent.document.forms['graphicForm']"))) == "") { ?>