diff --git a/lib/Alchemy/Phrasea/Application.php b/lib/Alchemy/Phrasea/Application.php index 6d6c4c0a79..d9c5874c46 100644 --- a/lib/Alchemy/Phrasea/Application.php +++ b/lib/Alchemy/Phrasea/Application.php @@ -12,7 +12,6 @@ namespace Alchemy\Phrasea; use Alchemy\Geonames\GeonamesServiceProvider; -use Alchemy\Phrasea\ControllerProvider\Thesaurus\Thesaurus; use Alchemy\Phrasea\ControllerProvider\Thesaurus\Xmlhttp as ThesaurusXMLHttp; use Alchemy\Phrasea\Core\Event\Subscriber\BasketSubscriber; use Alchemy\Phrasea\Core\Event\Subscriber\BridgeSubscriber; @@ -281,6 +280,11 @@ class Application extends SilexApplication 'Alchemy\Phrasea\ControllerProvider\Admin\TaskManager' => [], 'Alchemy\Phrasea\ControllerProvider\Admin\Users' => [], 'Alchemy\Phrasea\ControllerProvider\Client\Root' => [], + 'Alchemy\Phrasea\ControllerProvider\Datafiles' => [], + 'Alchemy\Phrasea\ControllerProvider\Lightbox' => [], + 'Alchemy\Phrasea\ControllerProvider\MediaAccessor' => [], + 'Alchemy\Phrasea\ControllerProvider\Minifier' => [], + 'Alchemy\Phrasea\ControllerProvider\Permalink' => [], 'Alchemy\Phrasea\ControllerProvider\Prod\BasketProvider' => [], 'Alchemy\Phrasea\ControllerProvider\Prod\Bridge' => [], 'Alchemy\Phrasea\ControllerProvider\Prod\DoDownload' => [], @@ -315,14 +319,10 @@ class Application extends SilexApplication 'Alchemy\Phrasea\ControllerProvider\Root\Root' => [], 'Alchemy\Phrasea\ControllerProvider\Root\RSSFeeds' => [], 'Alchemy\Phrasea\ControllerProvider\Root\Session' => [], + 'Alchemy\Phrasea\ControllerProvider\Setup' => [], + 'Alchemy\Phrasea\ControllerProvider\Thesaurus\Thesaurus' => [], 'Alchemy\Phrasea\ControllerProvider\User\Notifications' => [], 'Alchemy\Phrasea\ControllerProvider\User\Preferences' => [], - 'Alchemy\Phrasea\ControllerProvider\Datafiles' => [], - 'Alchemy\Phrasea\ControllerProvider\Lightbox' => [], - 'Alchemy\Phrasea\ControllerProvider\MediaAccessor' => [], - 'Alchemy\Phrasea\ControllerProvider\Minifier' => [], - 'Alchemy\Phrasea\ControllerProvider\Permalink' => [], - 'Alchemy\Phrasea\ControllerProvider\Setup' => [], ]; foreach ($providers as $class => $values) { $this->register(new $class, $values); @@ -621,7 +621,6 @@ class Application extends SilexApplication */ public function bindRoutes() { - $this->mount('/thesaurus', new Thesaurus()); $this->mount('/xmlhttp', new ThesaurusXMLHttp()); $providers = [ @@ -677,6 +676,7 @@ class Application extends SilexApplication '/report/' => 'Alchemy\Phrasea\ControllerProvider\Report\Root', '/session/' => 'Alchemy\Phrasea\ControllerProvider\Root\Session', '/setup' => 'Alchemy\Phrasea\ControllerProvider\Setup', + '/thesaurus' => 'Alchemy\Phrasea\ControllerProvider\Thesaurus\Thesaurus', '/user/notifications/' => 'Alchemy\Phrasea\ControllerProvider\User\Notifications', '/user/preferences/' => 'Alchemy\Phrasea\ControllerProvider\User\Preferences', '/' => 'Alchemy\Phrasea\ControllerProvider\Root\Root', diff --git a/lib/Alchemy/Phrasea/Controller/Thesaurus/ThesaurusController.php b/lib/Alchemy/Phrasea/Controller/Thesaurus/ThesaurusController.php new file mode 100644 index 0000000000..6ffe8051e1 --- /dev/null +++ b/lib/Alchemy/Phrasea/Controller/Thesaurus/ThesaurusController.php @@ -0,0 +1,2869 @@ +get_connection(); + + $sql = "UPDATE record SET status=status & ~2"; + $stmt = $connbas->prepare($sql); + $stmt->execute(); + $stmt->closeCursor(); + */ + } + + public function accept(Application $app, Request $request) + { + if (null === $bid = $request->get("bid")) { + return new Response('Missing bid parameter', 400); + } + + $dom = $this->getXMLTerm($app, $bid, $request->get('src'), 'CT', $request->get('piv'), '0', null, '1', null); + + $cterm_found = (int) $dom->documentElement->getAttribute('found'); + + $fullpath_src = $fullpath_tgt = $nts = $cfield = $term_found = $acceptable = null; + + if ($cterm_found) { + $fullpath_src = $dom->getElementsByTagName("fullpath_html")->item(0)->firstChild->nodeValue; + + /** @var \DOMElement $node */ + $node = $dom->getElementsByTagName("ts_list")->item(0); + $nts = $node->getAttribute("nts"); + + /** @var \DOMElement $cfield */ + $cfield = $dom->getElementsByTagName("cfield")->item(0); + if ($cfield) { + if ($cfield->getAttribute("delbranch")) { + $cfield_t = '*'; + } else { + $cfield_t = $cfield->getAttribute("field"); + } + } else { + $cfield_t = null; + } + + $dom = $this->getXMLTerm($app, $bid, $request->get('tgt'), 'TH', $request->get('piv'), '0', null, '1', $cfield_t); + + $term_found = (int) $dom->documentElement->getAttribute('found'); + + if ($term_found) { + $fullpath_tgt = $dom->getElementsByTagName("fullpath_html")->item(0)->firstChild->nodeValue; + $acceptable = (int) $dom->getElementsByTagName("cfield")->item(0)->getAttribute("acceptable"); + } + } + + return $app['twig']->render('thesaurus/accept.html.twig', [ + 'dlg' => $request->get('dlg'), + 'bid' => $request->get('bid'), + 'piv' => $request->get('piv'), + 'src' => $request->get('src'), + 'tgt' => $request->get('tgt'), + 'cterm_found' => $cterm_found, + 'term_found' => $term_found, + 'cfield' => $cfield, + 'nts' => $nts, + 'fullpath_tgt' => $fullpath_tgt, + 'fullpath_src' => $fullpath_src, + 'acceptable' => $acceptable, + ]); + } + + public function exportText(Application $app, Request $request) + { + $tnodes = []; + $output = ''; + + if (null === $bid = $request->get("bid")) { + return new Response('Missing bid parameter', 400); + } + + if ($request->get("typ") == "TH" || $request->get("typ") == "CT") { + try { + /** @var \databox $databox */ + $databox = $app['phraseanet.appbox']->get_databox((int) $bid); + + if ($request->get("typ") == "TH") { + $domth = $databox->get_dom_thesaurus(); + } else { + $domth = $databox->get_dom_cterms(); + } + + if ($domth) { + $xpathth = new \DOMXPath($domth); + if ($request->get("id") == "T") { + $q = "/thesaurus"; + } elseif ($request->get("id") == "C") { + $q = "/cterms"; + } else { + $q = "//te[@id='" . $request->get("id") . "']"; + } + $this->export0($xpathth->query($q)->item(0), $tnodes, $output, $request->get('iln'), $request->get('ilg'), $request->get('osl')); + } + } catch (\Exception $e) { + + } + } + + return $app['twig']->render('thesaurus/export-text.html.twig', [ + 'output' => $output, + 'smp' => $request->get('smp'), + ]); + } + + private function printTNodes(&$output, &$tnodes, $iln, $ilg, $osl) + { + $numlig = $iln == "1"; + $ilg = $ilg == "1"; + $oneline = $osl == "1"; + + $ilig = 1; + foreach ($tnodes as $node) { + $tabs = str_repeat("\t", $node["depth"]); + switch ($node["type"]) { + case "ROOT": + if ($numlig) { + $output .= $ilig ++ . "\t"; + } + $output .= $tabs . $node["name"] . "\n"; + break; + case "TRASH": + if ($numlig) { + $output .= $ilig ++ . "\t"; + } + $output .= $tabs . "{TRASH}\n"; + break; + case "FIELD": + if ($numlig) { + $output .= $ilig ++ . "\t"; + } + $output .= $tabs . $node["name"] . "\n"; + break; + case "TERM": + $isyn = 0; + if ($oneline) { + if ($numlig) { + $output .= $ilig ++ . "\t"; + } + $output .= $tabs; + foreach ($node["syns"] as $syn) { + if ($isyn > 0) { + $output .= " ; "; + } + $output .= $syn["v"]; + if ($ilg) { + $output .= " [" . $syn["lng"] . "]"; + } + $isyn ++; + } + $output .= "\n"; + } else { + foreach ($node["syns"] as $syn) { + if ($numlig) { + $output .= $ilig ++ . "\t"; + } + $output .= $tabs; + + if ($isyn > 0) { + $output .= "; "; + } + + $output .= $syn["v"]; + + if ($ilg) { + $output .= " [" . $syn["lng"] . "]"; + } + $output .= "\n"; + $isyn ++; + } + } + break; + } + if (! $oneline) { + if ($numlig) { + $output .= $ilig ++ . "\t"; + } + $output .= "\n"; + } + } + } + + private function exportNode(\DOMElement $node, &$tnodes, $depth) + { + if ($node->nodeType == XML_ELEMENT_NODE) { + if (($nname = $node->nodeName) == "thesaurus" || $nname == "cterms") { + $tnodes[] = [ + "type" => "ROOT", + "depth" => $depth, + "name" => $nname, + "cdate" => $node->getAttribute("creation_date"), + "mdate" => $node->getAttribute("modification_date") + ]; + } elseif (($fld = $node->getAttribute("field"))) { + if ($node->getAttribute("delbranch")) { + $tnodes[] = [ + "type" => "TRASH", + "depth" => $depth, + "name" => $fld + ]; + } else { + $tnodes[] = [ + "type" => "FIELD", + "depth" => $depth, + "name" => $fld + ]; + } + } else { + $tsy = []; + for ($n = $node->firstChild; $n; $n = $n->nextSibling) { + if ($n->nodeName == "sy") { + $tsy[] = [ + "v" => $n->getAttribute("v"), + "lng" => $n->getAttribute("lng") + ]; + } + } + $tnodes[] = ["type" => "TERM", "depth" => $depth, "syns" => $tsy]; + } + } + } + + private function export0($znode, &$tnodes, &$output, $iln, $ilg, $osl) + { + $nodes = []; + $depth = 0; + + for ($node = $znode->parentNode; $node; $node = $node->parentNode) { + if ($node->nodeType == XML_ELEMENT_NODE) { + $nodes[$depth] = $node; + $depth++; + } + } + $nodes = array_reverse($nodes); + + foreach ($nodes as $depth => $node) { + $this->exportNode($node, $tnodes, $depth); + } + + $this->export($znode, $tnodes, count($nodes)); + $this->printTNodes($output, $tnodes, $iln, $ilg, $osl); + } + + private function export($node, &$tnodes, $depth = 0) + { + if ($node->nodeType == XML_ELEMENT_NODE) { + $this->exportNode($node, $tnodes, $depth); + } + for ($n = $node->firstChild; $n; $n = $n->nextSibling) { + if ($n->nodeName == "te") { + $this->export($n, $tnodes, $depth + 1); + } + } + } + + public function exportTextDialog(Application $app, Request $request) + { + return $app['twig']->render('thesaurus/export-text-dialog.html.twig', [ + 'dlg' => $request->get('dlg'), + 'bid' => $request->get('bid'), + 'typ' => $request->get('typ'), + 'piv' => $request->get('piv'), + 'id' => $request->get('id'), + ]); + } + + public function exportTopics(Application $app, Request $request) + { + $obr = explode(';', $request->get('obr')); + + $t_lng = []; + + if ($request->get('ofm') == 'tofiles') { + $t_lng = array_map(function ($code) { + $lng_code = explode('_', $code); + + return $lng_code[0]; + }, array_keys($app['locales.available'])); + } else { + $t_lng[] = $request->get('piv'); + } + + switch ($request->get('obrf')) { + case 'from_itf_closable': + $default_display = 'closed'; + $opened_display = 'opened'; + break; + case 'from_itf_static': + $default_display = 'closed'; + $opened_display = 'static'; + break; + case 'all_opened_closable': + $default_display = 'opened'; + $opened_display = ''; + break; + case 'all_opened_static': + $default_display = 'static'; + $opened_display = ''; + break; + default: + case 'all_closed': + $default_display = 'closed'; + $opened_display = ''; + break; + } + + $now = date('YmdHis'); + $lngs = []; + try { + /** @var \databox $databox */ + $databox = $app['phraseanet.appbox']->get_databox((int) $request->get("bid")); + if ($request->get("typ") == "TH") { + $domth = $databox->get_dom_thesaurus(); + } else { + $domth = $databox->get_dom_cterms(); + } + + if ($domth) { + $xpathth = new \DOMXPath($domth); + if ($request->get("id") == "T") { + $q = "/thesaurus"; + } elseif ($request->get("id") == "C") { + $q = "/cterms"; + } else { + $q = "//te[@id='" . $request->get("id") . "']"; + } + + if ($request->get('ofm') == 'toscreen') { + printf("
\n"); + } + + foreach ($t_lng as $lng) { + $dom = new \DOMDocument("1.0", "UTF-8"); + $dom->preserveWhiteSpace = false; + $dom->formatOutput = true; + $root = $dom->appendChild($dom->createElementNS('www.phraseanet.com', 'phraseanet:topics')); + + $root->appendChild($dom->createComment($app->trans('thesaurus:: fichier genere le %date%', ['%date%' => $now]))); + + $root->appendChild($dom->createElement('display')) + ->appendChild($dom->createElement('defaultview')) + ->appendChild($dom->createTextNode($default_display)); + + $this->export0Topics($app, $xpathth->query($q)->item(0), $dom, $root, $lng, $request->get("srt"), $request->get("sth"), $request->get("sand"), $opened_display, $obr); + + if ($request->get("ofm") == 'toscreen') { + $lngs[$lng] = str_replace(['&', '<', '>'], ['&', '<', '>'], $dom->saveXML()); + } elseif ($request->get("ofm") == 'tofiles') { + $fname = 'topics_' . $lng . '.xml'; + + @rename($app['root.path'] . '/config/topics/' . $fname, $app['root.path'] . '/config/topics/topics_' . $lng . '_BKP_' . $now . '.xml'); + + if ($dom->save($app['root.path'] . '/config/topics/' . $fname)) { + $lngs[$lng] = \p4string::MakeString($app->trans('thesaurus:: fichier genere : %filename%', ['%filename%' => $fname])); + } else { + $lngs[$lng] = \p4string::MakeString($app->trans('thesaurus:: erreur lors de l\'enregsitrement du fichier')); + } + } + } + } + } catch (\Exception $e) { + + } + + return $app['twig']->render('thesaurus/export-topics.html.twig', [ + 'lngs' => $lngs, + 'ofm' => $request->get('ofm'), + ]); + } + + private function export0Topics(Application $app, $znode, \DOMDocument $dom, \DOMNode $root, $lng, $srt, $sth, $sand, $opened_display, $obr) + { + $topics = $root->appendChild($dom->createElement('topics')); + $this->doExportTopics($app, $znode, $dom, $topics, '', $lng, $srt, $sth, $sand, $opened_display, $obr, 0); + } + + private function doExportTopics(Application $app, \DOMElement $node, \DOMDocument $dom, \DOMNode $topics, $prevQuery, $lng, $srt, $sth, $sand, $opened_display, $obr, $depth = 0) + { + $ntopics = 0; + if ($node->nodeType == XML_ELEMENT_NODE) { + /** @var \DOMElement[] $t_node */ + $t_node = []; + $t_label = []; + $t_sort = []; + $i = 0; + for ($n = $node->firstChild; $n; $n = $n->nextSibling) { + if ($n->nodeName == "te") { + $ntopics ++; + $label0 = $label = ""; + $query0 = $query = ""; + for ($n2 = $n->firstChild; $n2; $n2 = $n2->nextSibling) { + if ($n2->nodeName == "sy") { + if (! $query0) { + $query0 = $n2->getAttribute("w"); + if ($n2->getAttribute("k")) { + $query0 .= ( ' (' . $n2->getAttribute("k") . ')'); + } + $label0 = $n2->getAttribute("v"); + } + if ($n2->getAttribute("lng") == $lng) { + $query = $n2->getAttribute("w"); + if ($n2->getAttribute("k")) + $query .= ( ' (' . $n2->getAttribute("k") . ')'); + $label = $n2->getAttribute("v"); + break; + } + } + } + if (!$query) { + $query = $query0; + } + if (!$label) { + $label = $label0; + } + + $t_sort[$i] = $query; // tri sur w + $t_node[$i] = $n; + $t_label[$i] = $label; + + $i ++; + } + } + + if ($srt) { + natcasesort($t_sort); + } + + foreach ($t_sort as $i => $query) { + /** @var \DOMElement $topic */ + $topic = $topics->appendChild($dom->createElement('topic')); + if ($opened_display != '' && in_array($t_node[$i]->getAttribute('id'), $obr)) { + $topic->setAttribute('view', $opened_display); + } + $topic->appendChild($dom->createElement('label'))->appendChild($dom->createTextNode($t_label[$i])); + + $query = '"' . $query . '"'; + if ($sth) { + $query = '*:' . $query; + if ($sand) { + $query = '(' . $query . ')'; + } + } + + if ($sand && $prevQuery != '') { + $query = $prevQuery . ' ' . $app->trans('phraseanet::technique:: et') . ' ' . $query . ''; + } + + $topic->appendChild($dom->createElement('query'))->appendChild($dom->createTextNode('' . $query . '')); + + $topics2 = $dom->createElement('topics'); + + if ($this->doExportTopics($app, $t_node[$i], $dom, $topics2, $query, $lng, $srt, $sth, $sand, $opened_display, $obr, $depth + 1) > 0) { + $topic->appendChild($topics2); + } + } + } + + return $ntopics; + } + + public function exportTopicsDialog(Application $app, Request $request) + { + return $app['twig']->render('thesaurus/export-topics-dialog.html.twig', [ + 'bid' => $request->get('bid'), + 'piv' => $request->get('piv'), + 'typ' => $request->get('typ'), + 'dlg' => $request->get('dlg'), + 'id' => $request->get('id'), + 'obr' => $request->get('obr'), + ]); + } + + public function import(Application $app, Request $request) + { + set_time_limit(300); + + $err = ''; + + if (null === $bid = $request->get("bid")) { + return new Response('Missing bid parameter', 400); + } + + try { + /** @var \databox $databox */ + $databox = $app['phraseanet.appbox']->get_databox((int) $bid); + + $dom = $databox->get_dom_thesaurus(); + + if ($dom) { + if ($request->get('id') == '') { + // on importe un theaurus entier + /** @var \DOMElement $node */ + $node = $dom->documentElement; + while ($node->firstChild) { + $node->removeChild($node->firstChild); + } + + $cbad = []; + $cok = []; + for ($i = 0; $i < 32; $i ++) { + $cbad[] = chr($i); + $cok[] = '_'; + } + + $file = $request->files->get('fil')->getPathname(); + + if (($fp = fopen($file, 'rb'))) { + $iline = 0; + $curdepth = -1; + while ( ! $err && ! feof($fp) && ($line = fgets($fp)) !== FALSE) { + $iline ++; + if (trim($line) == '') { + continue; + } + for ($depth = 0; $line != '' && $line[0] == "\t"; $depth ++) { + $line = substr($line, 1); + } + if ($depth > $curdepth + 1) { + $err = $app->trans("over-indent at line %line%", ['%line%' => $iline]); + continue; + } + + $line = trim($line); + + if ( ! $this->checkEncoding($line, 'UTF-8')) { + $err = $app->trans("bad encoding at line %line%", ['%line%' => $iline]); + continue; + } + + $line = str_replace($cbad, $cok, ($oldline = $line)); + if ($line != $oldline) { + $err = $app->trans("bad character at line %line%", ['%line%' => $iline]); + continue; + } + + while ($curdepth >= $depth) { + $curdepth --; + $node = $node->parentNode; + } + $curdepth = $depth; + + $nid = (int) ($node->getAttribute('nextid')); + $pid = $node->getAttribute('id'); + + $te_id = ($pid ? ($pid . '.') : 'T') . $nid; + + $node->setAttribute('nextid', (string) ($nid + 1)); + + /** @var \DOMElement $te */ + $te = $node->appendChild($dom->createElement('te')); + $te->setAttribute('id', $te_id); + + $node = $te; + + $tsy = explode(';', $line); + $nsy = 0; + foreach ($tsy as $syn) { + $lng = $request->get('piv'); + $kon = ''; + + if (($ob = strpos($syn, '[')) !== false) { + if (($cb = strpos($syn, ']', $ob)) !== false) { + $lng = trim(substr($syn, $ob + 1, $cb - $ob - 1)); + $syn = substr($syn, 0, $ob) . substr($syn, $cb + 1); + } else { + $lng = trim(substr($syn, $ob + 1)); + $syn = substr($syn, 0, $ob); + } + + if (($ob = strpos($syn, '[')) !== false) { + if (($cb = strpos($syn, ']', $ob)) !== false) { + $syn = substr($syn, 0, $ob) . substr($syn, $cb + 1); + } else { + $syn = substr($syn, 0, $ob); + } + } + } + if (($ob = strpos($syn, '(')) !== false) { + if (($cb = strpos($syn, ')', $ob)) !== false) { + $kon = trim(substr($syn, $ob + 1, $cb - $ob - 1)); + $syn = substr($syn, 0, $ob) . substr($syn, $cb + 1); + } else { + $kon = trim(substr($syn, $ob + 1)); + $syn = substr($syn, 0, $ob); + } + } + + $syn = trim($syn); + + /** @var \DOMElement $sy */ + $sy = $node->appendChild($dom->createElement('sy')); + $sy->setAttribute('id', $te_id . '.' . $nsy); + $v = $syn; + if ($kon) { + $v .= ' (' . $kon . ')'; + } + $sy->setAttribute('v', $v); + $sy->setAttribute('w', $app['unicode']->remove_indexer_chars($syn)); + if ($kon) { + $sy->setAttribute('k', $app['unicode']->remove_indexer_chars($kon)); + } + $sy->setAttribute('lng', $lng); + + $nsy ++; + } + + $te->setAttribute('nextid', (string) $nsy); + } + + fclose($fp); + } + + } else { + // on importe dans une branche + $err = 'not implemented'; + } + + if (! $err) { + $databox->saveThesaurus($dom); + } + } + + if (! $err) { + $meta_struct = $databox->get_meta_structure(); + + foreach ($meta_struct->get_elements() as $meta_field) { + $meta_field->set_tbranch('')->save(); + } + + $dom = $databox->get_dom_cterms(); + if ($dom) { + $node = $dom->documentElement; + while ($node->firstChild) { + $node->removeChild($node->firstChild); + } + $databox->saveCterms($dom); + } + + $this->reindexAll($databox); + + /** @var EventDispatcherInterface $dispatcher */ + $dispatcher = $app['dispatcher']; + $dispatcher->dispatch( + PhraseaEvents::THESAURUS_IMPORTED, + new ThesaurusEvent\Imported($databox) + ); + } + } catch (\Exception $e) { + + } + + return $app['twig']->render('thesaurus/import.html.twig', ['err' => $err]); + } + + private function checkEncoding($string, $string_encoding) + { + $fs = $string_encoding == 'UTF-8' ? 'UTF-32' : $string_encoding; + $ts = $string_encoding == 'UTF-32' ? 'UTF-8' : $string_encoding; + + return $string === mb_convert_encoding(mb_convert_encoding($string, $fs, $ts), $ts, $fs); + } + + public function importDialog(Application $app, Request $request) + { + return $app['twig']->render('thesaurus/import-dialog.html.twig', [ + 'dlg' => $request->get('dlg'), + 'bid' => $request->get('bid'), + 'id' => $request->get('id'), + 'piv' => $request->get('piv'), + ]); + } + + public function indexThesaurus(Application $app, Request $request) + { + $sql = "SELECT" + . " sbas.sbas_id," + . " sbasusr.bas_manage AS bas_manage," + . " sbasusr.bas_modify_struct AS bas_modify_struct," + . " sbasusr.bas_modif_th AS bas_edit_thesaurus" + . " FROM" + . " (Users u INNER JOIN sbasusr" + . " ON u.id = :usr_id" + . " AND u.id = sbasusr.usr_id" + . " AND u.model_of IS NULL)" + . " INNER JOIN" + . " sbas ON sbas.sbas_id = sbasusr.sbas_id" + . " HAVING bas_edit_thesaurus > 0" + . " ORDER BY sbas.ord"; + + $bases = $languages = []; + + /** @var \appbox $appbox */ + $appbox = $app['phraseanet.appbox']; + $stmt = $appbox->get_connection()->prepare($sql); + $stmt->execute([':usr_id' => $app['authentication']->getUser()->getId()]); + $rs = $stmt->fetchAll(\PDO::FETCH_ASSOC); + $stmt->closeCursor(); + + foreach ($rs as $row) { + try { + $app['phraseanet.appbox']->get_databox($row['sbas_id'])->get_connection()->connect(); + } catch (\Exception $e) { + continue; + } + $bases[$row['sbas_id']] = \phrasea::sbas_labels($row['sbas_id'], $app); + } + + foreach ($app['locales.available'] as $lng_code => $lng) { + $lng_code = explode('_', $lng_code); + $languages[$lng_code[0]] = $lng; + } + + return $app['twig']->render('thesaurus/index.html.twig', [ + 'languages' => $languages, + 'bases' => $bases, + ]); + } + + public function linkFieldStep1(Application $app, Request $request) + { + if (null === $bid = $request->get("bid")) { + return new Response('Missing bid parameter', 400); + } + + $fullBranch = ""; + $fieldnames = []; + try { + /** @var \databox $databox */ + $databox = $app['phraseanet.appbox']->get_databox((int) $bid); + $domstruct = $databox->get_dom_structure(); + $domth = $databox->get_dom_thesaurus(); + + if ($domstruct && $domth) { + $xpathth = new \DOMXPath($domth); + $xpathstruct = new \DOMXPath($domstruct); + + if ($request->get('tid') !== "") { + $q = "//te[@id='" . $request->get('tid') . "']"; + } else { + $q = "//te[not(@id)]"; + } + + $nodes = $xpathth->query($q); + if ($nodes->length == 1) { + /** @var \DOMElement $n */ + for ($n = $nodes->item(0); $n && $n->nodeType == XML_ELEMENT_NODE && $n->getAttribute("id") !== ""; $n = $n->parentNode) { + /** @var \DOMElement $sy */ + $sy = $xpathth->query("sy", $n)->item(0); + $t = $sy ? $sy->getAttribute("v") : ""; + if (!$t) { + $t = "..."; + } + $fullBranch = " / " . $t . $fullBranch; + } + } + $nodes = $xpathstruct->query("/record/description/*"); + for ($i = 0; $i < $nodes->length; $i ++) { + /** @var \DOMElement $node */ + $node = $nodes->item($i); + $fieldname = $node->nodeName; + $tbranch = $node->getAttribute("tbranch"); + $ck = false; + if ($tbranch) { + // ce champ a deja un tbranch, est-ce qu'il pointe sur la branche selectionnee ? + $thnodes = $xpathth->query($tbranch); + for ($j = 0; $j < $thnodes->length; $j ++) { + $node = $thnodes->item($j); + if ($node->getAttribute("id") == $request->get('tid')) { + $ck = true; + } + } + } + $fieldnames[$fieldname] = $ck; + } + } + } catch (\Exception $e) { + + } + + return $app['twig']->render('thesaurus/link-field-step1.html.twig', [ + 'piv' => $request->get('piv'), + 'bid' => $request->get('bid'), + 'tid' => $request->get('tid'), + 'fullBranch' => $fullBranch, + 'fieldnames' => $fieldnames + ]); + } + + public function linkFieldStep2(Application $app, Request $request) + { + if (null === $bid = $request->get("bid")) { + return new Response('Missing bid parameter', 400); + } + + $oldlinks = []; + $needreindex = false; + + try { + /** @var \databox $databox */ + $databox = $app['phraseanet.appbox']->get_databox((int) $bid); + $domstruct = $databox->get_dom_structure(); + $domth = $databox->get_dom_thesaurus(); + + if ($domstruct && $domth) { + $xpathth = new \DOMXPath($domth); + $xpathstruct = new \DOMXPath($domstruct); + $nodes = $xpathstruct->query("/record/description/*"); + + for ($i = 0; $i < $nodes->length; $i ++) { + /** @var \DOMElement $node */ + $node = $nodes->item($i); + $fieldname = $node->nodeName; + + $oldbranch = $node->getAttribute("tbranch"); + $ck = false; + $tids = []; // les ids de branches liees e ce champ + if ($oldbranch) { + // ce champ a deja un tbranch, on balaye les branches auxquelles il est lie + $thnodes = $xpathth->query($oldbranch); + for ($j = 0; $j < $thnodes->length; $j ++) { + $node = $thnodes->item($j); + if ($node->getAttribute("id") == $request->get('tid')) { + // il etait deja lie a la branche selectionnee + $tids[$node->getAttribute("id")] = $node; + $ck = true; + } else { + // il etait lie e une autre branche + $tids[$node->getAttribute("id")] = $node; + } + } + } + + if (in_array($fieldname, $request->get('field', [])) != $ck) { + if ($ck) { + unset($tids[$request->get('tid')]); + } else { + $tids[$request->get('tid')] = $xpathth->query("/thesaurus//te[@id='" . \thesaurus::xquery_escape($request->get('tid')) . "']")->item(0); + } + $newtbranch = ""; + + foreach ($tids as $kitd => $node) { + if ($kitd === "") { + $newtbranch .= ( $newtbranch ? " | " : "") . "/thesaurus"; + } else { + $neb = ""; + while ($node && $node->nodeName == "te") { + $neb = "/te[@id='" . $node->getAttribute("id") . "']" . $neb; + $node = $node->parentNode; + } + $newtbranch .= ( $newtbranch ? " | " : "") . "/thesaurus" . $neb; + } + } + + $oldlinks[$fieldname] = [ + 'old_branch' => $oldbranch, + 'new_branch' => $newtbranch + ]; + + if ($newtbranch != "") { + $needreindex = true; + } + } + } + } + } catch (\Exception $e) { + + } + + return $app['twig']->render('thesaurus/link-field-step2.html.twig', [ + 'piv' => $request->get('piv'), + 'bid' => $request->get('bid'), + 'tid' => $request->get('tid'), + 'oldlinks' => $oldlinks, + 'need_reindex' => $needreindex, + ]); + } + + public function linkFieldStep3(Application $app, Request $request) + { + if (null === $bid = $request->get("bid")) { + return new Response('Missing bid parameter', 400); + } + + $candidates2del = []; + $ctchanged = false; + try { + /** @var \databox $databox */ + $databox = $app['phraseanet.appbox']->get_databox((int) $bid); + $meta_struct = $databox->get_meta_structure(); + $domct = $databox->get_dom_cterms(); + $domst = $databox->get_dom_structure(); + + if ($domct && $domst) { + $xpathct = new \DOMXPath($domct); + + foreach ($request->get("f2unlk", []) as $f2unlk) { + $q = "/cterms/te[@field='" . \thesaurus::xquery_escape($f2unlk) . "']"; + $nodes = $xpathct->query($q); + for ($i = 0; $i < $nodes->length; $i ++) { + $candidates2del[] = [ + "field" => $f2unlk, + "node" => $nodes->item($i) + ]; + } + + $field = $meta_struct->get_element_by_name($f2unlk); + if ($field) { + $field->set_tbranch('')->save(); + } + } + foreach ($candidates2del as $candidate2del) { + $candidate2del["node"]->parentNode->removeChild($candidate2del["node"]); + $ctchanged = true; + } + + foreach ($request->get("fbranch", []) as $fbranch) { + $p = strpos($fbranch, "<"); + if ($p > 1) { + $fieldname = substr($fbranch, 0, $p); + $tbranch = substr($fbranch, $p + 1); + $field = $meta_struct->get_element_by_name($fieldname); + if ($field) { + $field->set_tbranch($tbranch)->save(); + } + } + } + + if ($ctchanged) { + $databox->saveCterms($domct); + } + } + + if ($request->get("reindex")) { + $this->reindexAll($databox); + + /** @var EventDispatcherInterface $dispatcher */ + $dispatcher = $app['dispatcher']; + $dispatcher->dispatch( + PhraseaEvents::THESAURUS_FIELD_LINKED, + new ThesaurusEvent\FieldLinked($databox) + ); + } + } catch (\Exception $e) { + + } + + return $app['twig']->render('thesaurus/link-field-step3.html.twig', [ + 'field2del' => $request->get('f2unlk', []), + 'candidates2del' => $candidates2del, + 'branch2del' => $request->get('fbranch', []), + 'ctchanged' => $ctchanged, + 'reindexed' => $request->get('reindex'), + ]); + } + + private function fixThesaurus($app, \DOMDocument $domct, \DOMDocument $domth, Connection $connbas) + { + $version = $domth->documentElement->getAttribute("version"); + + if ('' === trim($version)) { + $version = '1.0.0'; + } + + while (class_exists($cls = "patchthesaurus_" . str_replace(".", "", $version))) { + + $last_version = $version; + $zcls = new $cls; + $version = $zcls->patch($version, $domct, $domth, $connbas, $app['unicode']); + + if ($version == $last_version) { + break; + } + } + + return $version; + } + + public function loadThesaurus(Application $app, Request $request) + { + if (null === $request->get("bid")) { + return new Response('Missing bid parameter', 400); + } + + $updated = false; + $validThesaurus = true; + $ctlist = []; + $name = \phrasea::sbas_labels($request->get('bid'), $app); + + try { + /** @var \databox $databox */ + $databox = $app['phraseanet.appbox']->get_databox((int) $request->get('bid')); + $connbas = $databox->get_connection(); + + $domct = $databox->get_dom_cterms(); + $domth = $databox->get_dom_thesaurus(); + $now = date("YmdHis"); + + if ( ! $domct && $request->get('repair') == 'on') { + $domct = new \DOMDocument(); + $domct->load(__DIR__ . "/../../../../conf.d/blank_cterms.xml"); + $domct->documentElement->setAttribute("creation_date", $now); + $databox->saveCterms($domct); + } + if ( ! $domth && $request->get('repair') == 'on') { + $domth = new \DOMDocument(); + $domth->load(__DIR__ . "/../../../../conf.d/blank_thesaurus.xml"); + $domth->documentElement->setAttribute("creation_date", $now); + $databox->saveThesaurus($domth); + } + + if ($domct && $domth) { + + $oldversion = $domth->documentElement->getAttribute("version"); + if ($this->fixThesaurus($app, $domct, $domth, $connbas) != $oldversion) { + $updated = true; + $databox->saveCterms($domct); + $databox->saveThesaurus($domth); + } + + for ($ct = $domct->documentElement->firstChild; $ct; $ct = $ct->nextSibling) { + if ($ct->nodeName == "te") { + $ctlist[] = [ + 'id' => $ct->getAttribute("id"), + 'field' => $ct->getAttribute("field") + ]; + } + } + } else { + $validThesaurus = false; + } + } catch (\Exception $e) { + + } + + return $app['twig']->render('thesaurus/load-thesaurus.html.twig', [ + 'bid' => $request->get('bid'), + 'name' => $name, + 'cterms' => $ctlist, + 'valid_thesaurus' => $validThesaurus, + 'updated' => $updated + ]); + } + + public function newTerm(Application $app, Request $request) + { + list($term, $context) = $this->splitTermAndContext($request->get("t")); + + $dom = $this->doSearchCandidate($app, $request->get('bid'), $request->get('pid'), $term, $context, $request->get('piv')); + + $xpath = new \DOMXPath($dom); + + $candidates = $xpath->query("/result/candidates_list/ct"); + + $nb_candidates_ok = $nb_candidates_bad = 0; + $flist_ok = $flist_bad = ""; + for ($i = 0; $i < $candidates->length; $i ++) { + /** @var \DOMElement $candidate */ + $candidate = $candidates->item($i); + if ($candidate->getAttribute("sourceok") == "1") { // && $candidates->item($i)->getAttribute("cid")) + $flist_ok .= ( $flist_ok ? ", " : "") . $candidate->getAttribute("field"); + $nb_candidates_ok ++; + } else { + $flist_bad .= ( $flist_bad ? ", " : "") . $candidate->getAttribute("field"); + $nb_candidates_bad ++; + } + } + $candidates_list = []; + for ($i = 0; $i < $candidates->length; $i ++) { + /** @var \DOMElement $candidate */ + $candidate = $candidates->item($i); + if ($candidate->getAttribute("sourceok") == "1") { + $candidates_list[] = array( + 'id' => $candidate->getAttribute("id"), + 'field' => $candidate->getAttribute("field"), + ); + } + } + + return $app['twig']->render('thesaurus/new-term.html.twig', [ + 'typ' => $request->get('typ'), + 'bid' => $request->get('bid'), + 'piv' => $request->get('piv'), + 'pid' => $request->get('pid'), + 'sylng' => $request->get('sylng'), + 'dlg' => $request->get('dlg'), + 'candidates' => $candidates_list, + 'term' => $term, + 'context' => $context, + 'nb_candidates_ok' => $nb_candidates_ok, + 'nb_candidates_bad' => $nb_candidates_bad, + ]); + } + + public function properties(Application $app, Request $request) + { + $dom = $this->getXMLTerm($app, $request->get('bid'), $request->get('id'), $request->get('typ'), $request->get('piv'), '0', null, '1', null); + $fullpath = $dom->getElementsByTagName("fullpath_html")->item(0)->firstChild->nodeValue; + $hits = $dom->getElementsByTagName("allhits")->item(0)->firstChild->nodeValue; + + $languages = $synonyms = []; + + $sy_list = $dom->getElementsByTagName("sy_list")->item(0); + /** @var \DOMElement $n */ + for ($n = $sy_list->firstChild; $n; $n = $n->nextSibling) { + $synonyms[] = [ + 'id' => $n->getAttribute("id"), + 'lng' => $n->getAttribute("lng"), + 't' => $n->getAttribute("t"), + 'hits' => $n->getAttribute("hits"), + ]; + } + + foreach ($app['locales.available'] as $code => $language) { + $lng_code = explode('_', $code); + $languages[$lng_code[0]] = $language; + } + + return $app['twig']->render('thesaurus/properties.html.twig', [ + 'typ' => $request->get('typ'), + 'bid' => $request->get('bid'), + 'piv' => $request->get('piv'), + 'id' => $request->get('id'), + 'dlg' => $request->get('dlg'), + 'languages' => $languages, + 'fullpath' => $fullpath, + 'hits' => $hits, + 'synonyms' => $synonyms, + ]); + } + + public function thesaurus(Application $app, Request $request) + { + $flags = $jsFlags = []; + + foreach ($app['locales.available'] as $code => $language) { + $lng_code = explode('_', $code); + $flags[$lng_code[0]] = $language; + $jsFlags[$lng_code[0]] = ['w' => 18, 'h' => 13]; + } + $jsFlags = json_encode($jsFlags); + + return $app['twig']->render('thesaurus/thesaurus.html.twig', [ + 'piv' => $request->get('piv'), + 'bid' => $request->get('bid'), + 'flags' => $flags, + 'jsFlags' => $jsFlags, + ]); + } + + /** + * @param Application $app + * @param Request $request + * @return Response + * + * rétablit un terme candidat rejeté (R) et tous ses enfants + * comme candidat (C) + * appelé par le menu contextuel sur candidat / kcterm_accept + */ + public function acceptXml(Application $app, Request $request) + { + $ret = new \DOMDocument("1.0", "UTF-8"); + $ret->preserveWhiteSpace = false; + + $root = $ret->appendChild($ret->createElement("result")); + $root->appendChild($ret->createCDATASection(var_export([ + "bid" => $request->get('bid'), + "id" => $request->get('id'), + "piv" => $request->get('piv'), + ], true))); + + $refresh_list = $root->appendChild($ret->createElement("refresh_list")); + + if (null === $bid = $request->get("bid")) { + return new Response('Missing bid parameter', 400); + } + + try { + /** @var \databox $databox */ + $databox = $app['phraseanet.appbox']->get_databox((int) $bid); + $databox->get_connection()->connect(); + + $dom = $databox->get_dom_cterms(); + $xpath = new \DOMXPath($dom); + $q = "/cterms//te[@id='" . $request->get('id') . "']"; + + /** @var \DOMElement $te */ + $te = $xpath->query($q)->item(0); + if ($te) { + $this->acceptBranch($app, $bid, $te); + + $databox->saveCterms($dom); + + /** @var \DOMElement $r */ + $r = $refresh_list->appendChild($ret->createElement("refresh")); + /** @var \DOMElement $p */ + $p = $te->parentNode; + $r->setAttribute("id", $p->getAttribute("id")); + $r->setAttribute("type", "CT"); + } + } catch (\Exception $e) { + + } + + return new Response($ret->saveXML(), 200, ['Content-Type' => 'text/xml']); + } + + /** + * transforme (R)ejected en (C)andidate sur un node et tous ses enfants + * @param Application $app + * @param $sbas_id + * @param \DOMElement $node + */ + private function acceptBranch(Application $app, $sbas_id, \DOMElement $node) + { + if (strlen($oldid = $node->getAttribute("id")) > 1) { + $node->setAttribute("id", $newid = ("C" . substr($oldid, 1))); + } + for ($n = $node->firstChild; $n; $n = $n->nextSibling) { + if ($n->nodeType == XML_ELEMENT_NODE) { + $this->acceptBranch($app, $sbas_id, $n); + } + } + } + + + + public function acceptCandidatesXml(Application $app, Request $request) + { + $ret = new \DOMDocument("1.0", "UTF-8"); + $ret->preserveWhiteSpace = false; + + $root = $ret->appendChild($ret->createElement("result")); + $root->appendChild($ret->createCDATASection(var_export([ + 'bid' => $request->get('bid'), + 'piv' => $request->get('piv'), + 'cid' => $request->get('cid'), + 'pid' => $request->get('pid'), + 'typ' => $request->get('typ'), + ], true))); + + $refresh_list = $root->appendChild($ret->createElement("refresh_list")); + + if (null === $bid = $request->get("bid")) { + return new Response('Missing bid parameter', 400); + } + + try { + /** @var \databox $databox */ + $databox = $app['phraseanet.appbox']->get_databox((int) $bid); + + $domct = $databox->get_dom_cterms(); + $domth = $databox->get_dom_thesaurus(); + + if ($domct !== false && $domth !== false) { + $xpathth = new \DOMXPath($domth); + + if ($request->get('pid') == "T") { + $q = "/thesaurus"; + } else { + $q = "/thesaurus//te[@id='" . $request->get('pid') . "']"; + } + + /** @var \DOMElement $parentnode */ + $parentnode = $xpathth->query($q)->item(0); + + if ($parentnode) { + $xpathct = new \DOMXPath($domct); + $ctchanged = $thchanged = false; + + $icid = 0; + foreach ($request->get("cid") as $cid) { + $q = "//te[@id='" . $cid . "']"; + + /** @var \DOMElement $ct */ + $ct = $xpathct->query($q)->item(0); + + if ($ct) { + if ($request->get("typ") == "TS") { + // importer tt la branche candidate comme nouveau ts + $nid = $parentnode->getAttribute("nextid"); + $parentnode->setAttribute("nextid", (int) $nid + 1); + + /** @var \DOMElement $te */ + $te = $domth->importNode($ct, true); + $chgids = []; + + if (($pid = $parentnode->getAttribute("id")) == "") { + $pid = "T" . $nid; + } else { + $pid .= "." . $nid; + } + + $this->renumerate($te, $pid, $chgids); + + /** @var \DOMElement $new_te */ + $new_te = $parentnode->appendChild($te); + + $databox->saveThesaurus($domth); + + /** @var EventDispatcherInterface $dispatcher */ + $dispatcher = $app['dispatcher']; + $dispatcher->dispatch( + PhraseaEvents::THESAURUS_CANDIDATE_ACCEPTED_AS_CONCEPT, + new ThesaurusEvent\CandidateAccepted($databox, $new_te->getAttribute('id')) + ); + $thchanged = true; + + /** @var \DOMElement $r */ + if ($icid == 0) { // on update la destination une seule fois + $r = $refresh_list->appendChild($ret->createElement("refresh")); + $r->setAttribute("id", $parentnode->getAttribute("id")); + $r->setAttribute("type", "TH"); + } + + $r = $refresh_list->appendChild($ret->createElement("refresh")); + $r->setAttribute("id", $ct->parentNode->getAttribute("id")); + $r->setAttribute("type", "CT"); + + $ct->parentNode->removeChild($ct); + + $ctchanged = true; + } elseif ($request->get("typ") == "SY") { + // importer tt le contenu de la branche sous la destination + for ($ct2 = $ct->firstChild; $ct2; $ct2 = $ct2->nextSibling) { + if ($ct2->nodeType != XML_ELEMENT_NODE) { + continue; + } + + $nid = $parentnode->getAttribute("nextid"); + $parentnode->setAttribute("nextid", (int) $nid + 1); + + /** @var \DOMElement $te */ + $te = $domth->importNode($ct2, true); + $chgids = []; + if (($pid = $parentnode->getAttribute("id")) == "") { + $pid = "T" . $nid; + } else { + $pid .= "." . $nid; + } + + $this->renumerate($te, $pid, $chgids); + /** @var \DOMElement $new_te */ + $new_te = $parentnode->appendChild($te); + + $databox->saveThesaurus($domth); + + /** @var EventDispatcherInterface $dispatcher */ + $dispatcher = $app['dispatcher']; + $dispatcher->dispatch( + PhraseaEvents::THESAURUS_CANDIDATE_ACCEPTED_AS_SYNONYM, + new ThesaurusEvent\CandidateAccepted($databox, $new_te->getAttribute('id')) + ); + $thchanged = true; + } + /** @var \DOMElement $r */ + if ($icid == 0) { // on update la destination une seule fois + $r = $refresh_list->appendChild($ret->createElement("refresh")); + $r->setAttribute("id", $parentnode->parentNode->getAttribute("id")); + $r->setAttribute("type", "TH"); + } + $r = $refresh_list->appendChild($ret->createElement("refresh")); + $r->setAttribute("id", $ct->parentNode->getAttribute("id")); + $r->setAttribute("type", "CT"); + + $ct->parentNode->removeChild($ct); + $ctchanged = true; + } + $icid ++; + } + } + if ($ctchanged) { + $databox->saveCterms($domct); + } + if ($thchanged) { + $this->reindexAll($databox); + } + } + } + } catch (\Exception $e) { + + } + + return new Response($ret->saveXML(), 200, ['Content-Type' => 'text/xml']); + } + + private function renumerate(\DOMElement $node, $id, &$chgids, $depth = 0) + { + $node->setAttribute("id", $id); + $nchild = 0; + for ($n = $node->firstChild; $n; $n = $n->nextSibling) { + if ($n->nodeType == XML_ELEMENT_NODE && ($n->nodeName == "te" || $n->nodeName == "sy")) { + $this->renumerate($n, $id . "." . $nchild, $chgids, $depth + 1); + $nchild ++; + } + } + $node->setAttribute("nextid", $nchild); + } + + public function changeSynonymLanguageXml(Application $app, Request $request) + { + $ret = new \DOMDocument("1.0", "UTF-8"); + $ret->preserveWhiteSpace = false; + + $root = $ret->appendChild($ret->createElement("result")); + $root->appendChild($ret->createCDATASection(var_export([ + 'bid' => $request->get('bid'), + 'piv' => $request->get('piv'), + 'newlng' => $request->get('cid'), + 'id' => $request->get('id'), + 'typ' => $request->get('typ'), + ], true))); + + if (null === $bid = $request->get("bid")) { + return new Response('Missing bid parameter', 400); + } + + try { + /** @var \databox $databox */ + $databox = $app['phraseanet.appbox']->get_databox((int) $bid); + + if ($request->get('typ') == "CT") { + $xqroot = "cterms"; + $dom = $databox->get_dom_cterms(); + } else { + $xqroot = "thesaurus"; + $dom = $databox->get_dom_thesaurus(); + } + + if ($dom) { + $xpath = new \DOMXPath($dom); + $q = "/$xqroot//sy[@id='" . $request->get('id') . "']"; + + /** @var \DOMElement $sy0 */ + $sy0 = $xpath->query($q)->item(0); + if ($sy0) { + $sy0->setAttribute("lng", $request->get('newlng')); + + if ($xqroot == "cterms") { + $databox->saveCterms($dom); + } elseif ($xqroot == "thesaurus") { + $databox->saveThesaurus($dom); + + /** @var EventDispatcherInterface $dispatcher */ + $dispatcher = $app['dispatcher']; + $dispatcher->dispatch( + PhraseaEvents::THESAURUS_SYNONYM_LNG_CHANGED, + new ThesaurusEvent\SynonymLngChanged($databox, $sy0->getAttribute('id')) + ); + + $this->reindexAll($databox); + } + + $ret = $this->getXMLTerm($app, $bid, $sy0->parentNode->getAttribute("id"), $request->get('typ'), $request->get('piv'), null, $request->get('id'), '1', null); + + $root = $ret->getElementsByTagName("result")->item(0); + $refresh_list = $root->appendChild($ret->createElement("refresh_list")); + + /** @var \DOMElement $r */ + $r = $refresh_list->appendChild($ret->createElement("refresh")); + $r->setAttribute("id", $sy0->parentNode->parentNode->getAttribute("id")); + $r->setAttribute("type", $request->get('typ')); + } + } + } catch (\Exception $e) { + + } + + return new Response($ret->saveXML(), 200, ['Content-Type' => 'text/xml']); + } + + public function changeSynonymPositionXml(Application $app, Request $request) + { + $ret = new \DOMDocument("1.0", "UTF-8"); + $ret->preserveWhiteSpace = false; + + $root = $ret->appendChild($ret->createElement("result")); + $root->appendChild($ret->createCDATASection(var_export([ + 'bid' => $request->get('bid'), + 'piv' => $request->get('piv'), + 'dir' => $request->get('dir'), + 'id' => $request->get('id'), + 'typ' => $request->get('typ'), + ], true))); + + if (null === $bid = $request->get("bid")) { + return new Response('Missing bid parameter', 400); + } + + $root->appendChild($ret->createElement("refresh_list")); + + try { + /** @var \databox $databox */ + $databox = $app['phraseanet.appbox']->get_databox((int) $bid); + + if ($request->get('typ') == "CT") { + $xqroot = "cterms"; + $dom = $databox->get_dom_cterms(); + } else { + $xqroot = "thesaurus"; + $dom = $databox->get_dom_thesaurus(); + } + + if ($dom) { + $xpath = new \DOMXPath($dom); + $q = "/$xqroot//sy[@id='" . $request->get('id') . "']"; + + /** @var \DOMElement $sy0 */ + $sy0 = $xpath->query($q)->item(0); + if ($sy0) { + if ($request->get('dir') == 1 && $sy0 && $sy0->previousSibling) { + $sy0->parentNode->insertBefore($sy0, $sy0->previousSibling); + } elseif ($request->get('dir') == -1 && $sy0 && $sy0->nextSibling) { + $sy0->parentNode->insertBefore($sy0->nextSibling, $sy0); + } + + if ($xqroot == "cterms") { + $databox->saveCterms($dom); + } elseif ($xqroot == "thesaurus") { + $databox->saveThesaurus($dom); + + /** @var EventDispatcherInterface $dispatcher */ + $dispatcher = $app['dispatcher']; + $dispatcher->dispatch( + PhraseaEvents::THESAURUS_SYNONYM_POSITION_CHANGED, + new ThesaurusEvent\SynonymPositionChanged($databox, $sy0->getAttribute('id')) + ); + + $this->reindexAll($databox); + } + + $ret = $this->getXMLTerm($app, $bid, $sy0->parentNode->getAttribute("id"), $request->get('typ'), $request->get('piv'), null, $request->get('id'), '1', null); + + $root = $ret->getElementsByTagName("result")->item(0); + $refresh_list = $root->appendChild($ret->createElement("refresh_list")); + + /** @var \DOMElement $r */ + $r = $refresh_list->appendChild($ret->createElement("refresh")); + $r->setAttribute("id", $sy0->parentNode->parentNode->getAttribute("id")); + $r->setAttribute("type", $request->get('typ')); + } + } + } catch (\Exception $e) { + + } + + return new Response($ret->saveXML(), 200, ['Content-Type' => 'text/xml']); + } + + /** + * @param Application $app + * @param Request $request + * @return Response + * + * supprime un synonyme + * appelé par le menu contextuel sur un synonyme, option "delete_sy" + * dans le dialog des properties sur un terme (properties.html.twig) + */ + public function removeSynonymXml(Application $app, Request $request) + { + $ret = new \DOMDocument("1.0", "UTF-8"); + $ret->preserveWhiteSpace = false; + + $root = $ret->appendChild($ret->createElement("result")); + $root->appendChild($ret->createCDATASection(var_export([ + 'bid' => $request->get('bid'), + 'id' => $request->get('id'), + 'piv' => $request->get('piv'), + 'typ' => $request->get('typ'), + ], true))); + + $refresh_list = $root->appendChild($ret->createElement("refresh_list")); + + if (null === $bid = $request->get("bid")) { + return new Response('Missing bid parameter', 400); + } + + try { + /** @var \databox $databox */ + $databox = $app['phraseanet.appbox']->get_databox((int) $bid); + $domct = $databox->get_dom_cterms(); + $dom = $databox->get_dom_thesaurus(); + + if ($request->get('typ') == "CT") { + $xqroot = "cterms"; + } else { + $xqroot = "thesaurus"; + } + + if ($dom && $domct) { + $xpath = new \DOMXPath($dom); + $q = "/$xqroot//sy[@id='" . $request->get('id') . "']"; + + /** @var \DOMElement $sy0 */ + $sy0 = $xpath->query($q)->item(0); + if ($sy0) { + $xpathct = new \DOMXPath($domct); + + // on cherche la branche 'deleted' dans les cterms + $nodes = $xpathct->query("/cterms/te[@delbranch='1']"); + if ( ! $nodes || ($nodes->length == 0)) { + // 'deleted' n'existe pas, on la cree + $id = $domct->documentElement->getAttribute("nextid"); + $domct->documentElement->setAttribute("nextid", (int) ($id) + 1); + /** @var \DOMElement $del */ + $del = $domct->documentElement->appendChild($domct->createElement("te")); + $del->setAttribute("id", "C" . $id); + $del->setAttribute("field", $app->trans('thesaurus:: corbeille')); + $del->setAttribute("nextid", "0"); + $del->setAttribute("delbranch", "1"); + + /** @var \DOMElement $r */ + $r = $refresh_list->appendChild($ret->createElement("refresh")); + $r->setAttribute("id", "C"); + $r->setAttribute("type", "CT"); + } else { + // 'deleted' existe + /** @var \DOMElement $del */ + $del = $nodes->item(0); + /** @var \DOMElement $r */ + $r = $refresh_list->appendChild($ret->createElement("refresh")); + $r->setAttribute("id", $del->getAttribute("id")); + $r->setAttribute("type", "CT"); + } + + // on cree une branche 'te' + $refrid = $sy0->parentNode->parentNode->getAttribute("id"); + $delid = $del->getAttribute("id"); + $delteid = (int) ($del->getAttribute("nextid")); + + $del->setAttribute("nextid", $delteid + 1); + /** @var \DOMElement $delte */ + $delte = $del->appendChild($domct->createElement("te")); + $delte->setAttribute("id", $delid . "." . $delteid); + $delte->setAttribute("nextid", "1"); + + /** @var \DOMElement $delsy */ + $delsy = $delte->appendChild($domct->createElement("sy")); + $delsy->setAttribute("id", $newid = ($delid . "." . $delteid . ".0")); + $delsy->setAttribute("lng", $sy0->getAttribute("lng")); + $delsy->setAttribute("v", $sy0->getAttribute("v")); + $delsy->setAttribute("w", $sy0->getAttribute("w")); + + if ($sy0->hasAttribute("k")) { + $delsy->setAttribute("k", $sy0->getAttribute("k")); + } + + $te = $sy0->parentNode; + $te->removeChild($sy0); + + $databox->saveCterms($domct); + if ($request->get('typ') == "CT") { + $r = $refresh_list->appendChild($ret->createElement("refresh")); + $r->setAttribute("type", "CT"); + if ($refrid) { + $r->setAttribute("id", $refrid); + } else { + $r->setAttribute("id", "C"); + } + } else { + $databox->saveThesaurus($dom); + + /** @var EventDispatcherInterface $dispatcher */ + $dispatcher = $app['dispatcher']; + $dispatcher->dispatch( + PhraseaEvents::THESAURUS_SYNONYM_TRASHED, + new ThesaurusEvent\ItemTrashed($databox, $te->getAttribute('id'), $delsy->getAttribute('id')) + ); + + $this->reindexAll($databox); + + $r = $refresh_list->appendChild($ret->createElement("refresh")); + $r->setAttribute("type", "TH"); + if ($refrid) { + $r->setAttribute("id", $refrid); + } else { + $r->setAttribute("id", "T"); + } + } + + $ret2 = $this->getXMLTerm($app, $request->get('bid'), $te->getAttribute("id"), $request->get('typ'), $request->get('piv'), null, null, '1', null); + + if ($sl = $ret2->getElementsByTagName("sy_list")->item(0)) { + $ret->importNode($sl, true); + } + } + } + } catch (\Exception $e) { + + } + + return new Response($ret->saveXML(), 200, ['Content-Type' => 'text/xml']); + } + + /** + * @param Application $app + * @param Request $request + * @return Response + * + * Supprime (déplace dans cterms/trash) toute une branche TE avec les SY et tous les TE enfants + * appelé par le menu contextuel sur terme, option "kterm_delete" + */ + public function removeSpecificTermXml(Application $app, Request $request) + { + $ret = new \DOMDocument("1.0", "UTF-8"); + $ret->preserveWhiteSpace = false; + + $root = $ret->appendChild($ret->createElement("result")); + $root->appendChild($ret->createCDATASection(var_export([ + 'bid' => $request->get('bid'), + 'id' => $request->get('id'), + 'piv' => $request->get('piv'), + ], true))); + + $refresh_list = $root->appendChild($ret->createElement("refresh_list")); + + if (null === $bid = $request->get("bid")) { + return new Response('Missing bid parameter', 400); + } + + try { + /** @var \databox $databox */ + $databox = $app['phraseanet.appbox']->get_databox((int) $bid); + $domth = $databox->get_dom_thesaurus(); + $domct = $databox->get_dom_cterms(); + + if ($domth && $domct) { + $xpathth = new \DOMXPath($domth); + $xpathct = new \DOMXPath($domct); + if ($request->get('id') !== "") { // secu pour pas exploser le thesaurus + $q = "/thesaurus//te[@id='" . $request->get('id') . "']"; + + $thnode = $xpathth->query($q)->item(0); + if ($thnode) { + /** @var \DOMElement $thnode_parent */ + $thnode_parent = $thnode->parentNode; + $chgids = []; + $pid = $thnode_parent->getAttribute("id"); + if ($pid === "") { + $pid = "T"; + } + + $nodes = $xpathct->query("/cterms/te[@delbranch='1']"); + if ( ! $nodes || ($nodes->length == 0)) { + $id = $domct->documentElement->getAttribute("nextid"); + + $domct->documentElement->setAttribute("nextid", (int) ($id) + 1); + /** @var \DOMElement $ct */ + $ct = $domct->documentElement->appendChild($domct->createElement("te")); + $ct->setAttribute("id", "C" . $id); + $ct->setAttribute("field", $app->trans('thesaurus:: corbeille')); + $ct->setAttribute("nextid", "0"); + $ct->setAttribute("delbranch", "1"); + + /** @var \DOMElement $r */ + $r = $refresh_list->appendChild($ret->createElement("refresh")); + $r->setAttribute("id", "C"); + $r->setAttribute("type", "CT"); + } else { + /** @var \DOMElement $ct */ + $ct = $nodes->item(0); + /** @var \DOMElement $r */ + $r = $refresh_list->appendChild($ret->createElement("refresh")); + $r->setAttribute("id", $ct->getAttribute("id")); + $r->setAttribute("type", "CT"); + } + $teid = (int) ($ct->getAttribute("nextid")); + $ct->setAttribute("nextid", $teid + 1); + + /** @var \DOMElement $newte */ + $newte = $ct->appendChild($domct->importNode($thnode, true)); + + $this->renumerate($newte, $ct->getAttribute("id") . "." . $teid, $chgids); + + $databox->saveThesaurus($domth); + + /** @var EventDispatcherInterface $dispatcher */ + $dispatcher = $app['dispatcher']; + $dispatcher->dispatch( + PhraseaEvents::THESAURUS_CONCEPT_TRASHED, + new ThesaurusEvent\ItemTrashed($databox, $thnode_parent->getAttribute('id'), $newte->getAttribute('id')) + ); + + $thnode_parent->removeChild($thnode); + + $databox->saveCterms($domct); + $this->reindexAll($databox); + + $r = $refresh_list->appendChild($ret->createElement("refresh")); + $r->setAttribute("id", $pid); + $r->setAttribute("type", "TH"); + } + } + } + } catch (\Exception $e) { + + } + + return new Response($ret->saveXML(), 200, ['Content-Type' => 'text/xml']); + } + + + public function getSynonymXml(Application $app, Request $request) + { + $ret = new \DOMDocument("1.0", "UTF-8"); + $ret->preserveWhiteSpace = false; + + $root = $ret->appendChild($ret->createElement("result")); + $root->appendChild($ret->createCDATASection(var_export([ + 'bid' => $request->get('bid'), + 'id' => $request->get('id'), + 'typ' => $request->get('typ'), + ], true))); + + if (null === $bid = $request->get("bid")) { + return new Response('Missing bid parameter', 400); + } + + try { + /** @var \databox $databox */ + $databox = $app['phraseanet.appbox']->get_databox((int) $bid); + + if ($request->get('typ') == "CT") { + $xqroot = "cterms"; + $dom = $databox->get_dom_cterms(); + } else { + $xqroot = "thesaurus"; + $dom = $databox->get_dom_thesaurus(); + } + + if ($dom) { + $xpath = new \DOMXPath($dom); + + if ($request->get('id') == "T") { + $q = "/thesaurus"; + } elseif ($request->get('id') == "C") { + $q = "/cterms"; + } else { + $q = "/$xqroot//sy[@id='" . $request->get('id') . "']"; + } + + $nodes = $xpath->query($q); + if ($nodes->length > 0) { + /** @var \DOMElement $node */ + $node = $nodes->item(0); + + $t = $node->getAttribute("v"); + if (($k = $node->getAttribute("k"))) { + $t .= " (" . $k . ")"; + } + + $fullpath_html = " / " . $t . ""; + $fullpath = " / " . $t; + + /** @var \DOMElement $sy */ + $sy = $root->appendchild($ret->createElement("sy")); + $sy->setAttribute("t", $t); + foreach (["v", "w", "k", "lng", "id"] as $a) { + if ($node->hasAttribute($a)) { + $sy->setAttribute($a, $node->getAttribute($a)); + } + } + + for ($depth = -1, $n = $node->parentNode->parentNode; $n; $n = $n->parentNode, $depth -- ) { + if ($n->nodeName == "te") { + if ($request->get('typ') == "CT" && ($fld = $n->getAttribute("field")) != "") { + $fullpath = " / " . $fld . $fullpath; + if ($depth == 0) { + $fullpath_html = " / " . $fld . "" . $fullpath_html; + } else { + $fullpath_html = " / " . $fld . $fullpath_html; + } + break; + } + $firstsy = $goodsy = null; + for ($n2 = $n->firstChild; $n2; $n2 = $n2->nextSibling) { + if ($n2->nodeName == "sy") { + $t = $n2->getAttribute("v"); + + if (! $firstsy) { + $firstsy = $t; + } + if ($n2->getAttribute("lng") == $request->get('piv')) { + $goodsy = $t; + break; + } + } + } + if (! $goodsy) { + $goodsy = $firstsy; + } + $fullpath = " / " . $goodsy . $fullpath; + $fullpath_html = " / " . $goodsy . $fullpath_html; + } + } + $fp = $root->appendchild($ret->createElement("fullpath")); + $fp->appendChild($ret->createTextNode($fullpath)); + + $fp = $root->appendchild($ret->createElement("fullpath_html")); + $fp->appendChild($ret->createTextNode($fullpath_html)); + + $n = $root->appendchild($ret->createElement("hits")); + $n->appendChild($ret->createTextNode('')); + } + } + } catch (\Exception $e) { + + } + + return new Response($ret->saveXML(), 200, ['Content-Type' => 'text/xml']); + } + + public function getTermXml(Application $app, Request $request) + { + return new Response( + $this->getXMLTerm($app, $request->get('bid'), $request->get('id'), $request->get('typ'), + $request->get('piv'), $request->get('sortsy'), $request->get('sel'), $request->get('nots'), + $request->get('acf'))->saveXML(), + 200, + ['Content-Type' => 'text/xml'] + ); + } + + /** + * @param Application $app + * @param $bid + * @param $id + * @param $typ + * @param $piv + * @param $sortsy + * @param $sel + * @param $nots + * @param $acf + * @return \DOMDocument + */ + private function getXMLTerm(Application $app, $bid, $id, $typ, $piv, $sortsy, $sel, $nots, $acf) + { + $ret = new \DOMDocument("1.0", "UTF-8"); + $ret->preserveWhiteSpace = false; + + /** @var \DOMElement $root */ + $root = $ret->appendChild($ret->createElement("result")); + $root->appendChild($ret->createCDATASection(var_export([ + "bid" => $bid, + "id" => $id, + "typ" => $typ, + "piv" => $piv, + "sortsy" => $sortsy, + "sel" => $sel, + "nots" => $nots, + "acf" => $acf, + ], true))); + + /** @var \DOMElement $cfield */ + $cfield = $root->appendChild($ret->createElement("cfield")); + /** @var \DOMElement $ts_list */ + $ts_list = $root->appendChild($ret->createElement("ts_list")); + $sy_list = $root->appendChild($ret->createElement("sy_list")); + + if ($bid !== null) { + try { + /** @var \databox $databox */ + $databox = $app['phraseanet.appbox']->get_databox((int) $bid); + + if ($typ == "CT") { + $xqroot = "cterms"; + $dom = $databox->get_dom_cterms(); + } else { + $xqroot = "thesaurus"; + $dom = $databox->get_dom_thesaurus(); + } + + $meta = $databox->get_meta_structure(); + + if ($dom) { + $xpath = new \DOMXPath($dom); + if ($typ == "TH" && $acf) { + $cfield->setAttribute("field", $acf); + + // on doit verifier si le terme demande est accessible e partir de ce champ acf + if ($acf == '*') { + // le champ "*" est la corbeille, il est toujours accepte + $cfield->setAttribute("acceptable", "1"); + } else { + if (($databox_field = $meta->get_element_by_name($acf)) instanceof \databox_field) { + $tbranch = $databox_field->get_tbranch(); + $q = "(" . $tbranch . ")/descendant-or-self::te[@id='" . $id . "']"; + + $nodes = $xpath->query($q); + $cfield->setAttribute("acceptable", ($nodes->length > 0) ? "1" : "0"); + } + } + } + + if ($id == "T") { + $q = "/thesaurus"; + } elseif ($id == "C") { + $q = "/cterms"; + } else { + $q = "/$xqroot//te[@id='" . $id . "']"; + } + + $nodes = $xpath->query($q); + $root->setAttribute('found', '' . $nodes->length); + if ($nodes->length > 0) { + $nts = 0; + $tts = []; + // on dresse la liste des termes specifiques avec comme cle le synonyme + // dans la langue pivot + for ($n = $nodes->item(0)->firstChild; $n; $n = $n->nextSibling) { + /** @var \DOMElement $n */ + if ($n->nodeName == "te") { + $nts ++; + if (! $nots) { + if ($typ == "CT" && $id == "C") { + $realksy = $allsy = $n->getAttribute("field"); + } else { + $allsy = ""; + $firstksy = null; + $realksy = null; + // on liste les sy pour fabriquer la cle + for ($n2 = $n->firstChild; $n2; $n2 = $n2->nextSibling) { + if ($n2->nodeName == "sy") { + $lng = $n2->getAttribute("lng"); + $t = $n2->getAttribute("v"); + $ksy = $n2->getAttribute("w"); + if (! $firstksy) { + $firstksy = $ksy; + } + if (! $realksy && $piv && $lng == $piv) { + $realksy = $ksy; + $allsy = $t . ($allsy ? " ; " : "") . $allsy; + } else { + $allsy .= ( $allsy ? " ; " : "") . $t; + } + } + } + if (! $realksy) { + $realksy = $firstksy; + } + } + if ($sortsy && $piv) { + for ($uniq = 0; $uniq < 9999; $uniq ++) { + if ( ! isset($tts[$realksy . "_" . $uniq])) { + break; + } + } + $tts[$realksy . "_" . $uniq] = [ + "id" => $n->getAttribute("id"), + "allsy" => $allsy, + "nchild" => $xpath->query("te", $n)->length + ]; + } else { + $tts[] = [ + "id" => $n->getAttribute("id"), + "allsy" => $allsy, + "nchild" => $xpath->query("te", $n)->length + ]; + } + } + } elseif ($n->nodeName == "sy") { + /** @var \DOMElement $sy */ + $sy = $sy_list->appendChild($ret->createElement("sy")); + + $sy->setAttribute("id", $n->getAttribute("id")); + $sy->setAttribute("v", $t = $n->getAttribute("v")); + $sy->setAttribute("w", $n->getAttribute("w")); + $sy->setAttribute("hits", ''); + $sy->setAttribute("lng", $lng = $n->getAttribute("lng")); + if (($k = $n->getAttribute("k"))) { + $sy->setAttribute("k", $k); + } + $sy->setAttribute("t", $t); + if ($n->getAttribute("id") == $sel) { + $sy->setAttribute("sel", "1"); + } + } + } + $ts_list->setAttribute("nts", $nts); + + if ($sortsy && $piv) { + ksort($tts, SORT_STRING); + } + foreach ($tts as $ts) { + /** @var \DOMElement $newts */ + $newts = $ts_list->appendChild($ret->createElement("ts")); + $newts->setAttribute("id", $ts["id"]); + $newts->setAttribute("nts", $ts["nchild"]); + $newts->appendChild($ret->createTextNode($ts["allsy"])); + } + + $fullpath_html = $fullpath = ""; + for ($depth = 0, $n = $nodes->item(0); $n; $n = $n->parentNode, $depth-- ) { + /** @var \DOMElement $n */ + if ($n->nodeName == "te") { + if ($typ == "CT" && ($fld = $n->getAttribute("field")) != "") { + // la source provient des candidats pour ce champ + + $cfield->setAttribute("field", $fld); + $cfield->setAttribute("delbranch", $n->getAttribute("delbranch")); + + $fullpath = " / " . $fld . $fullpath; + + if ($depth == 0) { + $fullpath_html = " / " . $fld . "" . $fullpath_html; + } else { + $fullpath_html = " / " . $fld . $fullpath_html; + } + break; + } + + $firstsy = $goodsy = null; + for ($n2 = $n->firstChild; $n2; $n2 = $n2->nextSibling) { + if ($n2->nodeName == "sy") { + $t = $n2->getAttribute("v"); + if (! $firstsy) { + $firstsy = $t; + } + if ($n2->getAttribute("lng") == $piv) { + $goodsy = $t; + break; + } + } + } + if (! $goodsy) { + $goodsy = $firstsy; + } + + $fullpath = " / " . $goodsy . $fullpath; + + if ($depth == 0) { + $fullpath_html = " / " . $goodsy . "" . $fullpath_html; + } else { + $fullpath_html = " / " . $goodsy . $fullpath_html; + } + } + } + if ($fullpath == "") { + $fullpath = "/"; + $fullpath_html = " / "; + } + $fp = $root->appendchild($ret->createElement("fullpath")); + $fp->appendChild($ret->createTextNode($fullpath)); + + $fp = $root->appendchild($ret->createElement("fullpath_html")); + $fp->appendChild($ret->createTextNode($fullpath_html)); + + $n = $root->appendchild($ret->createElement("hits")); + $n->appendChild($ret->createTextNode('')); + + $n = $root->appendchild($ret->createElement("allhits")); + $n->appendChild($ret->createTextNode('')); + } + } + } catch (\Exception $e) { + + } + } + + return $ret; + } + + public function killTermXml(Application $app, Request $request) + { + $ret = new \DOMDocument("1.0", "UTF-8"); + $ret->preserveWhiteSpace = false; + + $root = $ret->appendChild($ret->createElement("result")); + $root->appendChild($ret->createCDATASection(var_export([ + 'bid' => $request->get('bid'), + 'id' => $request->get('id'), + 'piv' => $request->get('piv'), + 'typ' => $request->get('typ'), + ], true))); + + $refresh_list = $root->appendChild($ret->createElement("refresh_list")); + + if (null === $bid = $request->get("bid")) { + return new Response('Missing bid parameter', 400); + } + + try { + /** @var \databox $databox */ + $databox = $app['phraseanet.appbox']->get_databox((int) $bid); + + if ($request->get('typ') == "CT") { + $xqroot = "cterms"; + $dom = $databox->get_dom_cterms(); + } else { + $xqroot = "thesaurus"; + $dom = $databox->get_dom_thesaurus(); + } + + if ($dom) { + $xpath = new \DOMXPath($dom); + $q = "/$xqroot//te[@id='" . $request->get('id') . "']"; + + /** @var \DOMElement $te */ + $te = $xpath->query($q)->item(0); + if ($te) { + $refrid = $te->parentNode->getAttribute("id"); + + $sy_evt_parm = $this->buildSynonymsFromTe($te); // to pass as event parameter + + $parent = $te->parentNode; + $parent->removeChild($te); + + if ($request->get('typ') == "CT") { + $databox->saveCterms($dom); + + /** @var \DOMElement $r */ + $r = $refresh_list->appendChild($ret->createElement("refresh")); + $r->setAttribute("type", "CT"); + $r->setAttribute("id", $refrid); + + } else { + + $databox->saveThesaurus($dom); + + /** @var EventDispatcherInterface $dispatcher */ + $dispatcher = $app['dispatcher']; + $dispatcher->dispatch( + PhraseaEvents::THESAURUS_CONCEPT_DELETED, + new ThesaurusEvent\ConceptDeleted($databox, $refrid, $sy_evt_parm) + ); + + $this->reindexAll($databox); + + /** @var \DOMElement $r */ + $r = $refresh_list->appendChild($ret->createElement("refresh")); + $r->setAttribute("type", "TH"); + if ($refrid) { + $r->setAttribute("id", $refrid); + } else { + $r->setAttribute("id", "T"); + } + } + + $ret2 = $this->getXMLTerm($app, $bid, $parent->getAttribute("id"), $request->get('typ'), $request->get('piv'), null, null, '1', null); + + if ($sl = $ret2->getElementsByTagName("sy_list")->item(0)) { + $ret->importNode($sl, true); + } + } + } + } catch (\Exception $e) { + + } + + return new Response($ret->saveXML(), 200, ['Content-Type' => 'text/xml']); + } + + public function newSynonymXml(Application $app, Request $request) + { + $ret = new \DOMDocument("1.0", "UTF-8"); + $ret->preserveWhiteSpace = false; + + $root = $ret->appendChild($ret->createElement("result")); + $root->appendChild($ret->createCDATASection(var_export([ + "bid" => $request->get('bid'), + "pid" => $request->get('pid'), + "piv" => $request->get('piv'), + "sylng" => $request->get('sylng'), + "t" => $request->get('t'), + "k" => $request->get('k'), + ], true))); + + $refresh_list = $root->appendChild($ret->createElement("refresh_list")); + + if (null === $bid = $request->get("bid")) { + return new Response('Missing bid parameter', 400); + } + + try { + /** @var \databox $databox */ + $databox = $app['phraseanet.appbox']->get_databox((int) $bid); + $domth = $databox->get_dom_thesaurus(); + + if ($domth) { + $xpathth = new \DOMXPath($domth); + if ($bid === "T") { + $q = "/thesaurus"; + } else { + $q = "/thesaurus//te[@id='" . $request->get('pid') . "']"; + } + + /** @var \DOMElement $te */ + $te = $xpathth->query($q)->item(0); + if ($te) { + $tenextid = (int) $te->getAttribute("nextid"); + $te->setAttribute("nextid", $tenextid + 1); + + /** @var \DOMElement $sy */ + $sy = $te->appendChild($domth->createElement("sy")); + $syid = $te->getAttribute("id") . "." . $tenextid; + $sy->setAttribute("id", $syid); + + if ($request->get('sylng')) { + $sy->setAttribute("lng", $request->get('sylng')); + } else { + $sy->setAttribute("lng", ""); + } + + list($v, $k) = $this->splitTermAndContext($request->get('t')); + + $k = trim($k) . trim($request->get('k')); + $w = $app['unicode']->remove_indexer_chars($v); + + if ($k) { + $v .= " (" . $k . ")"; + } + + $k = $app['unicode']->remove_indexer_chars($k); + + $sy->setAttribute("v", $v); + $sy->setAttribute("w", $w); + + if ($k) { + $sy->setAttribute("k", $k); + } + + $databox->saveThesaurus($domth); + + /** @var EventDispatcherInterface $dispatcher */ + $dispatcher = $app['dispatcher']; + $dispatcher->dispatch( + PhraseaEvents::THESAURUS_SYNONYM_ADDED, + new ThesaurusEvent\ItemAdded($databox, $syid) + ); + + $this->reindexAll($databox); + + /** @var \DOMElement $r */ + $r = $refresh_list->appendChild($ret->createElement("refresh")); + $r->setAttribute("type", "TH"); + $pid = $te->parentNode->getAttribute("id"); + + if ($pid == "") { + $pid = "T"; + } + + $r->setAttribute("id", $pid); + } + } + } catch (\Exception $e) { + + } + + return new Response($ret->saveXML(), 200, ['Content-Type' => 'text/xml']); + } + + public function newSpecificTermXml(Application $app, Request $request) + { + $ret = new \DOMDocument("1.0", "UTF-8"); + $ret->preserveWhiteSpace = false; + + $root = $ret->appendChild($ret->createElement("result")); + $root->appendChild($ret->createCDATASection(var_export([ + "bid" => $request->get('bid'), + "pid" => $request->get('pid'), + "t" => $request->get('t'), + "k" => $request->get('k'), + "sylng" => $request->get('sylng'), + "reindex" => $request->get('reindex'), + ], true))); + + $refresh_list = $root->appendChild($ret->createElement("refresh_list")); + + if (null === $bid = $request->get("bid")) { + return new Response('Missing bid parameter', 400); + } + + try { + /** @var \databox $databox */ + $databox = $app['phraseanet.appbox']->get_databox((int) $bid); + $domth = $databox->get_dom_thesaurus(); + + if ($domth) { + $xpathth = new \DOMXPath($domth); + + if ($request->get('pid') === "T") { + $q = "/thesaurus"; + } else { + $q = "/thesaurus//te[@id='" . $request->get('pid') . "']"; + } + + /** @var \DOMElement $parentnode */ + $parentnode = $xpathth->query($q)->item(0); + if ($parentnode) { + $nid = $parentnode->getAttribute("nextid"); + $parentnode->setAttribute("nextid", (int) $nid + 1); + /** @var \DOMElement $te */ + $te = $parentnode->appendChild($domth->createElement("te")); + + if ($request->get('pid') === "T") { + $te->setAttribute("id", $teid = "T" . ($nid)); + } else { + $te->setAttribute("id", $teid = ($request->get('pid') . "." . $nid)); + } + + $te->setAttribute("nextid", "1"); + /** @var \DOMElement $sy */ + $sy = $te->appendChild($domth->createElement("sy")); + $syid = $teid . ".0"; + $sy->setAttribute("id", $syid); + + if ($request->get('sylng')) { + $sy->setAttribute("lng", $request->get('sylng')); + } else { + $sy->setAttribute("lng", ""); + } + + list($v, $k) = $this->splitTermAndContext($request->get('t')); + $k = trim($k) . trim($request->get('k')); + + $w = $app['unicode']->remove_indexer_chars($v); + + if ($k) { + $v .= " (" . $k . ")"; + } + + $k = $app['unicode']->remove_indexer_chars($k); + + $sy->setAttribute("v", $v); + $sy->setAttribute("w", $w); + + if ($k) { + $sy->setAttribute("k", $k); + } + + $databox->saveThesaurus($domth); + + /** @var EventDispatcherInterface $dispatcher */ + $dispatcher = $app['dispatcher']; + $dispatcher->dispatch( + PhraseaEvents::THESAURUS_CONCEPT_ADDED, + new ThesaurusEvent\ItemAdded($databox, $syid) + ); + + if ($request->get('reindex') == "1") { + $this->reindexAll($databox); + } + + /** @var \DOMElement $r */ + $r = $refresh_list->appendChild($ret->createElement("refresh")); + $r->setAttribute("type", "TH"); + $r->setAttribute("id", $request->get('pid')); + } + } + } catch (\Exception $e) { + + } + + return new Response($ret->saveXML(), 200, ['Content-Type' => 'text/xml']); + } + + public function openBranchesXml(Application $app, Request $request) + { + $ret = new \DOMDocument("1.0", "UTF-8"); + $ret->preserveWhiteSpace = false; + + $root = $ret->appendChild($ret->createElement("result")); + $root->appendChild($ret->createCDATASection(var_export([ + "bid" => $request->get('bid'), + "id" => $request->get('id'), + "typ" => $request->get('typ'), + "t" => $request->get('t'), + "method" => $request->get('method'), + ], true))); + + /** @var \DOMElement $html */ + $html = $root->appendChild($ret->createElement("html")); + + if (null === $bid = $request->get("bid")) { + return new Response('Missing bid parameter', 400); + } + + try { + /** @var \databox $databox */ + $databox = $app['phraseanet.appbox']->get_databox((int) $bid); + if ($request->get('typ') == "CT") { + $xqroot = "cterms"; + $dom = $databox->get_dom_cterms(); + } else { + $xqroot = "thesaurus"; + $dom = $databox->get_dom_thesaurus(); + } + + if ($dom) { + $xpath = new \DOMXPath($dom); + + if ($request->get('id') == "T") { + $q = "/thesaurus"; + } elseif ($request->get('id') == "C") { + $q = "/cterms"; + } else { + $q = "/$xqroot//te[@id='" . $request->get('id') . "']"; + } + + /** @var \DOMElement $znode */ + $znode = $xpath->query($q)->item(0); + if ($znode) { + $q2 = "//sy"; + if ($request->get('t')) { + $t = $this->splitTermAndContext($request->get('t')); + switch ($request->get('method')) { + case "begins": + $q2 = "starts-with(@w, '" . \thesaurus::xquery_escape($app['unicode']->remove_indexer_chars($t[0])) . "')"; + if ($t[1]) { + $q2 .= " and starts-with(@k, '" . \thesaurus::xquery_escape($app['unicode']->remove_indexer_chars($t[1])) . "')"; + } + break; + case "contains": + $q2 = "contains(@w, '" . \thesaurus::xquery_escape($app['unicode']->remove_indexer_chars($t[0])) . "')"; + if ($t[1]) { + $q2 .= " and contains(@k, '" . \thesaurus::xquery_escape($app['unicode']->remove_indexer_chars($t[1])) . "')"; + } + break; + case "equal": + default: + $q2 = "(@w='" . \thesaurus::xquery_escape($app['unicode']->remove_indexer_chars($t[0])) . "')"; + if ($t[1]) { + $q2 .= " and (@k='" . \thesaurus::xquery_escape($app['unicode']->remove_indexer_chars($t[1])) . "')"; + } + break; + } + $q2 = "//sy[" . $q2 . "]"; + } + + $nodes = $xpath->query($q2, $znode); + for ($i = 0; $i < $nodes->length; $i ++) { + for ($n = $nodes->item($i)->parentNode; $n && $n->nodeType == XML_ELEMENT_NODE && $n->nodeName == "te"; $n = $n->parentNode) { + /** @var \DOMElement $n */ + $n->setAttribute("open", "1"); + } + } + + $this->getBranchHTML($request->get('typ'), $znode, $ret, $html, 0); + } + } + } catch (\Exception $e) { + + } + + return new Response($ret->saveXML(), 200, ['Content-Type' => 'text/xml']); + } + + private function getBranchHTML($type, \DOMElement $srcnode, \DOMDocument $dstdom, \DOMElement $dstnode, $depth) + { + $allsy = ""; + $nts = 0; + for ($n = $srcnode->firstChild; $n; $n = $n->nextSibling) { + if ($n->nodeType == XML_ELEMENT_NODE) { + if ($n->nodeName == "te") { + $nts ++; + if ($n->getAttribute("open")) { + $id = $n->getAttribute("id"); + /** @var \DOMElement $div_the */ + $div_the = $dstnode->appendChild($dstdom->createElement("div")); + $div_the->setAttribute("id", "THE_" . $id); + $div_the->setAttribute("class", "s_"); + + /** @var \DOMElement $u */ + $u = $div_the->appendChild($dstdom->createElement("u")); + $u->setAttribute("id", "THP_" . $id); + + /** @var \DOMElement $div_thb */ + $div_thb = $dstnode->appendChild($dstdom->createElement("div")); + $div_thb->setAttribute("id", "THB_" . $id); + + $t = $this->getBranchHTML($type, $n, $dstdom, $div_thb, $depth + 1); + if ($t["nts"] == 0) { + $u->setAttribute("class", "nots"); + $div_thb->setAttribute("class", "ob"); + } else { + $u->appendChild($dstdom->createTextNode("...")); + $div_thb->setAttribute("class", "hb"); + } + + $div_the->appendChild($dstdom->createTextNode($t["allsy"])); + } + } elseif ($n->nodeName == "sy") { + $t = $n->getAttribute("v"); + $allsy .= ( $allsy ? " ; " : "") . $t; + } + } + } + if ($allsy == "") { + if ($type == "TH") { + $allsy = "THESAURUS"; + } elseif ($type == "CT") { + $allsy = $srcnode->getAttribute("field"); + } + } + + return ["allsy" => $allsy, "nts" => $nts]; + } + + public function RejectXml(Application $app, Request $request) + { + $ret = new \DOMDocument("1.0", "UTF-8"); + $ret->preserveWhiteSpace = false; + + $root = $ret->appendChild($ret->createElement("result")); + $root->appendChild($ret->createCDATASection(var_export([ + 'bid' => $request->get('bid'), + 'id' => $request->get('id'), + 'piv' => $request->get('piv'), + ], true))); + + $refresh_list = $root->appendChild($ret->createElement("refresh_list")); + + if (null === $bid = $request->get("bid")) { + return new Response('Missing bid parameter', 400); + } + + try { + /** @var \databox $databox */ + $databox = $app['phraseanet.appbox']->get_databox((int) $bid); + $connbas = $databox->get_connection(); + + $dom = $databox->get_dom_cterms(); + + if ($dom) { + $xpath = new \DOMXPath($dom); + $q = "/cterms//te[@id='" . $request->get('id') . "']"; + + /** @var \DOMElement $te */ + $te = $xpath->query($q)->item(0); + if ($te) { + $this->doRejectBranch($connbas, $te); + + $databox->saveCterms($dom); + + /** @var \DOMElement $r */ + $r = $refresh_list->appendChild($ret->createElement("refresh")); + $r->setAttribute("id", $te->parentNode->getAttribute("id")); + $r->setAttribute("type", "CT"); + } + } + } catch (\Exception $e) { + + } + + return new Response($ret->saveXML(), 200, ['Content-Type' => 'text/xml']); + } + + private function doRejectBranch(Connection $connbas, \DOMElement $node) + { + if (strlen($oldid = $node->getAttribute("id")) > 1) { + $node->setAttribute("id", $newid = ("R" . substr($oldid, 1))); + } + for ($n = $node->firstChild; $n; $n = $n->nextSibling) { + if ($n->nodeType == XML_ELEMENT_NODE) { + $this->doRejectBranch($connbas, $n); + } + } + } + + public function searchCandidateXml(Application $app, Request $request) + { + if (null === $request->get("bid")) { + return new Response('Missing bid parameter', 400); + } + + $ret = $this->doSearchCandidate($app, $request->get('bid'), $request->get('pid'), $request->get('t'), $request->get('k'), $request->get('piv')); + + return new Response($ret->saveXML(), 200, ['Content-Type' => 'text/xml']); + } + + private function doSearchCandidate(Application $app, $bid, $pid, $t, $k, $piv) + { + $ret = new \DOMDocument("1.0", "UTF-8"); + $ret->preserveWhiteSpace = false; + + $root = $ret->appendChild($ret->createElement("result")); + $root->appendChild($ret->createCDATASection(var_export([ + "bid" => $bid, + "pid" => $pid, + "t" => $t, + "k" => $k, + "piv" => $piv, + ], true))); + + $ctlist = $root->appendChild($ret->createElement("candidates_list")); + + try { + /** @var \databox $databox */ + $databox = $app['phraseanet.appbox']->get_databox((int) $bid); + + $domstruct = $databox->get_dom_structure(); + $domth = $databox->get_dom_thesaurus(); + $domct = $databox->get_dom_cterms(); + + if ($domstruct && $domth && $domct) { + $xpathth = new \DOMXPath($domth); + $xpathct = new \DOMXPath($domct); + + // on cherche les champs d'ou peut provenir un candidat, en fct de l'endroit oe on veut inserer le nouveau terme + $fields = array(); + $xpathstruct = new \DOMXPath($domstruct); + $nodes = $xpathstruct->query("/record/description/*[@tbranch]"); + for ($i = 0; $i < $nodes->length; $i ++) { + /** @var \DOMElement $node */ + $node = $nodes->item($i); + $fieldname = $node->nodeName; + $tbranch = $node->getAttribute("tbranch"); + if ($pid != "") { + $q = "(" . $tbranch . ")/descendant-or-self::te[@id='" . $pid . "']"; + } else { + $q = "(" . $tbranch . ")/descendant-or-self::te[not(@id)]"; + } + + $fields[$fieldname] = [ + "name" => $fieldname, + "tbranch" => $tbranch, + "cid" => null, + "sourceok" => false + ]; + + if (! $tbranch) { + continue; + } + + $l = $xpathth->query($q)->length; + + if ($l > 0) { + // le pt d'insertion du nvo terme se trouve dans la tbranch du champ, + // donc ce champ peut etre source de candidats + $fields[$fieldname]["sourceok"] = true; + } else { + // le pt d'insertion du nvo terme ne se trouve PAS dans la tbranch du champ, + // donc ce champ ne peut pas etre source de candidats + } + } + // on considere que la source 'deleted' est toujours valide + $fields["[deleted]"] = [ + "name" => $app->trans('thesaurus:: corbeille'), + "tbranch" => null, + "cid" => null, + "sourceok" => true + ]; + + if (count($fields) > 0) { + $q = "@w='" . \thesaurus::xquery_escape($app['unicode']->remove_indexer_chars($t)) . "'"; + if ($k) { + if ($k != "*") { + $q .= " and @k='" . \thesaurus::xquery_escape($app['unicode']->remove_indexer_chars($k)) . "'"; + } + } else { + $q .= " and not(@k)"; + } + $q = "/cterms//te[./sy[$q]]"; + + $nodes = $xpathct->query($q); + // le terme peut etre present dans plusieurs candidats + for ($i = 0; $i < $nodes->length; $i ++) { + // on a trouve le terme dans les candidats, mais en provenance de quel champ ?.. on remonte au champ candidat + /** @var \DOMElement $node */ + $node = $nodes->item($i); + /** @var \DOMElement $n */ + for ($n = $nodes->item($i)->parentNode; $n && $n->parentNode && $n->parentNode->nodeName != "cterms"; $n = $n->parentNode) { + ; + } + if ($n && array_key_exists($f = $n->getAttribute("field"), $fields)) { + $fields[$f]["cid"] = $node->getAttribute("id"); + } + } + } + + foreach ($fields as $kfield => $field) { + if ($field["cid"] === null) { + continue; + } + /** @var \DOMElement $ct */ + $ct = $ctlist->appendChild($ret->createElement("ct")); + $ct->setAttribute("field", $field["name"]); + $ct->setAttribute("sourceok", $field["sourceok"] ? "1" : "0"); + if ($field["cid"] !== null) { + $ct->setAttribute("id", $field["cid"]); + } + } + } + } catch (\Exception $e) { + + } + + return $ret; + } + + + private function splitTermAndContext($word) + { + $term = trim($word); + $context = ""; + if (($po = strpos($term, "(")) !== false) { + if (($pc = strpos($term, ")", $po)) !== false) { + $context = trim(substr($term, $po + 1, $pc - $po - 1)); + $term = trim(substr($term, 0, $po)); + } + } + + return [$term, $context]; + } + + /** + * @param \DOMElement $sy + * @return ThesaurusEvent\SynonymParm|null + * + * helper to build event parameter + */ + private function buildSynonymFromSy(\DOMElement $sy) + { + if($sy->nodeName == 'sy') { + return new ThesaurusEvent\SynonymParm($sy->getAttribute('v'), $sy->getAttribute('lng')); + } + return null; + } + + /** + * @param \DOMElement $te + * @return array|null + * + * helper to build event parameter + */ + private function buildSynonymsFromTe(\DOMElement $te) + { + $ret = array(); + if(strtolower($te->nodeName) == 'te') { + foreach ($te->childNodes as $child) { + if($child->nodeType == XML_ELEMENT_NODE && $child->nodeName == 'sy') { + $ret[] = $this->buildSynonymFromSy($child); + } + } + return $ret; + } + return null; + } +} diff --git a/lib/Alchemy/Phrasea/ControllerProvider/Thesaurus/Thesaurus.php b/lib/Alchemy/Phrasea/ControllerProvider/Thesaurus/Thesaurus.php index 74fd20a880..f8c926e67a 100644 --- a/lib/Alchemy/Phrasea/ControllerProvider/Thesaurus/Thesaurus.php +++ b/lib/Alchemy/Phrasea/ControllerProvider/Thesaurus/Thesaurus.php @@ -11,29 +11,36 @@ namespace Alchemy\Phrasea\ControllerProvider\Thesaurus; -use Alchemy\Phrasea\Application; +use Alchemy\Phrasea\Application as PhraseaApplication; +use Alchemy\Phrasea\Controller\Thesaurus\ThesaurusController; use Alchemy\Phrasea\ControllerProvider\ControllerProviderTrait; -use Alchemy\Phrasea\Core\Event\Thesaurus as ThesaurusEvent; -use Alchemy\Phrasea\Core\PhraseaEvents; -use Doctrine\DBAL\Driver\Connection; +use Silex\Application; use Silex\ControllerProviderInterface; -use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\HttpFoundation\Response; -use Symfony\Component\EventDispatcher\EventDispatcherInterface; +use Silex\ServiceProviderInterface; - -class Thesaurus implements ControllerProviderInterface +class Thesaurus implements ControllerProviderInterface, ServiceProviderInterface { use ControllerProviderTrait; + public function register(Application $app) + { + $app['controller.thesaurus'] = $app->share(function (PhraseaApplication $app) { + return (new ThesaurusController($app)); + }); + } + + public function boot(Application $app) + { + // no-op + } + public function connect(\Silex\Application $app) { - $app['controller.thesaurus'] = $this; - $controllers = $this->createAuthenticatedCollection($app); + $firewall = $this->getFirewall($app); - $controllers->before(function () use ($app) { - $app['firewall']->requireAccessToModule('thesaurus'); + $controllers->before(function () use ($firewall) { + $firewall->requireAccessToModule('thesaurus'); }); $controllers->match('/', 'controller.thesaurus:indexThesaurus')->bind('thesaurus'); @@ -69,2850 +76,4 @@ class Thesaurus implements ControllerProviderInterface return $controllers; } - - private function reindexAll(\databox $databox) - { - /* - * nothing to do anymore since it will be done thru posted events - * - $connbas = $databox->get_connection(); - - $sql = "UPDATE record SET status=status & ~2"; - $stmt = $connbas->prepare($sql); - $stmt->execute(); - $stmt->closeCursor(); - */ - } - - public function accept(Application $app, Request $request) - { - if (null === $bid = $request->get("bid")) { - return new Response('Missing bid parameter', 400); - } - - $dom = $this->getXMLTerm($app, $bid, $request->get('src'), 'CT', $request->get('piv'), '0', null, '1', null); - - $cterm_found = (int) $dom->documentElement->getAttribute('found'); - - $fullpath_src = $fullpath_tgt = $nts = $cfield = $term_found = $acceptable = null; - - if ($cterm_found) { - $fullpath_src = $dom->getElementsByTagName("fullpath_html")->item(0)->firstChild->nodeValue; - - /** @var \DOMElement $node */ - $node = $dom->getElementsByTagName("ts_list")->item(0); - $nts = $node->getAttribute("nts"); - - /** @var \DOMElement $cfield */ - $cfield = $dom->getElementsByTagName("cfield")->item(0); - if ($cfield) { - if ($cfield->getAttribute("delbranch")) { - $cfield_t = '*'; - } else { - $cfield_t = $cfield->getAttribute("field"); - } - } else { - $cfield_t = null; - } - - $dom = $this->getXMLTerm($app, $bid, $request->get('tgt'), 'TH', $request->get('piv'), '0', null, '1', $cfield_t); - - $term_found = (int) $dom->documentElement->getAttribute('found'); - - if ($term_found) { - $fullpath_tgt = $dom->getElementsByTagName("fullpath_html")->item(0)->firstChild->nodeValue; - $acceptable = (int) $dom->getElementsByTagName("cfield")->item(0)->getAttribute("acceptable"); - } - } - - return $app['twig']->render('thesaurus/accept.html.twig', [ - 'dlg' => $request->get('dlg'), - 'bid' => $request->get('bid'), - 'piv' => $request->get('piv'), - 'src' => $request->get('src'), - 'tgt' => $request->get('tgt'), - 'cterm_found' => $cterm_found, - 'term_found' => $term_found, - 'cfield' => $cfield, - 'nts' => $nts, - 'fullpath_tgt' => $fullpath_tgt, - 'fullpath_src' => $fullpath_src, - 'acceptable' => $acceptable, - ]); - } - - public function exportText(Application $app, Request $request) - { - $tnodes = []; - $output = ''; - - if (null === $bid = $request->get("bid")) { - return new Response('Missing bid parameter', 400); - } - - if ($request->get("typ") == "TH" || $request->get("typ") == "CT") { - try { - /** @var \databox $databox */ - $databox = $app['phraseanet.appbox']->get_databox((int) $bid); - - if ($request->get("typ") == "TH") { - $domth = $databox->get_dom_thesaurus(); - } else { - $domth = $databox->get_dom_cterms(); - } - - if ($domth) { - $xpathth = new \DOMXPath($domth); - if ($request->get("id") == "T") { - $q = "/thesaurus"; - } elseif ($request->get("id") == "C") { - $q = "/cterms"; - } else { - $q = "//te[@id='" . $request->get("id") . "']"; - } - $this->export0($xpathth->query($q)->item(0), $tnodes, $output, $request->get('iln'), $request->get('ilg'), $request->get('osl')); - } - } catch (\Exception $e) { - - } - } - - return $app['twig']->render('thesaurus/export-text.html.twig', [ - 'output' => $output, - 'smp' => $request->get('smp'), - ]); - } - - private function printTNodes(&$output, &$tnodes, $iln, $ilg, $osl) - { - $numlig = $iln == "1"; - $ilg = $ilg == "1"; - $oneline = $osl == "1"; - - $ilig = 1; - foreach ($tnodes as $node) { - $tabs = str_repeat("\t", $node["depth"]); - switch ($node["type"]) { - case "ROOT": - if ($numlig) { - $output .= $ilig ++ . "\t"; - } - $output .= $tabs . $node["name"] . "\n"; - break; - case "TRASH": - if ($numlig) { - $output .= $ilig ++ . "\t"; - } - $output .= $tabs . "{TRASH}\n"; - break; - case "FIELD": - if ($numlig) { - $output .= $ilig ++ . "\t"; - } - $output .= $tabs . $node["name"] . "\n"; - break; - case "TERM": - $isyn = 0; - if ($oneline) { - if ($numlig) { - $output .= $ilig ++ . "\t"; - } - $output .= $tabs; - foreach ($node["syns"] as $syn) { - if ($isyn > 0) { - $output .= " ; "; - } - $output .= $syn["v"]; - if ($ilg) { - $output .= " [" . $syn["lng"] . "]"; - } - $isyn ++; - } - $output .= "\n"; - } else { - foreach ($node["syns"] as $syn) { - if ($numlig) { - $output .= $ilig ++ . "\t"; - } - $output .= $tabs; - - if ($isyn > 0) { - $output .= "; "; - } - - $output .= $syn["v"]; - - if ($ilg) { - $output .= " [" . $syn["lng"] . "]"; - } - $output .= "\n"; - $isyn ++; - } - } - break; - } - if (! $oneline) { - if ($numlig) { - $output .= $ilig ++ . "\t"; - } - $output .= "\n"; - } - } - } - - private function exportNode(\DOMElement $node, &$tnodes, $depth) - { - if ($node->nodeType == XML_ELEMENT_NODE) { - if (($nname = $node->nodeName) == "thesaurus" || $nname == "cterms") { - $tnodes[] = [ - "type" => "ROOT", - "depth" => $depth, - "name" => $nname, - "cdate" => $node->getAttribute("creation_date"), - "mdate" => $node->getAttribute("modification_date") - ]; - } elseif (($fld = $node->getAttribute("field"))) { - if ($node->getAttribute("delbranch")) { - $tnodes[] = [ - "type" => "TRASH", - "depth" => $depth, - "name" => $fld - ]; - } else { - $tnodes[] = [ - "type" => "FIELD", - "depth" => $depth, - "name" => $fld - ]; - } - } else { - $tsy = []; - for ($n = $node->firstChild; $n; $n = $n->nextSibling) { - if ($n->nodeName == "sy") { - $tsy[] = [ - "v" => $n->getAttribute("v"), - "lng" => $n->getAttribute("lng") - ]; - } - } - $tnodes[] = ["type" => "TERM", "depth" => $depth, "syns" => $tsy]; - } - } - } - - private function export0($znode, &$tnodes, &$output, $iln, $ilg, $osl) - { - $nodes = []; - $depth = 0; - - for ($node = $znode->parentNode; $node; $node = $node->parentNode) { - if ($node->nodeType == XML_ELEMENT_NODE) { - $nodes[$depth] = $node; - $depth++; - } - } - $nodes = array_reverse($nodes); - - foreach ($nodes as $depth => $node) { - $this->exportNode($node, $tnodes, $depth); - } - - $this->export($znode, $tnodes, count($nodes)); - $this->printTNodes($output, $tnodes, $iln, $ilg, $osl); - } - - private function export($node, &$tnodes, $depth = 0) - { - if ($node->nodeType == XML_ELEMENT_NODE) { - $this->exportNode($node, $tnodes, $depth); - } - for ($n = $node->firstChild; $n; $n = $n->nextSibling) { - if ($n->nodeName == "te") { - $this->export($n, $tnodes, $depth + 1); - } - } - } - - public function exportTextDialog(Application $app, Request $request) - { - return $app['twig']->render('thesaurus/export-text-dialog.html.twig', [ - 'dlg' => $request->get('dlg'), - 'bid' => $request->get('bid'), - 'typ' => $request->get('typ'), - 'piv' => $request->get('piv'), - 'id' => $request->get('id'), - ]); - } - - public function exportTopics(Application $app, Request $request) - { - $obr = explode(';', $request->get('obr')); - - $t_lng = []; - - if ($request->get('ofm') == 'tofiles') { - $t_lng = array_map(function ($code) { - $lng_code = explode('_', $code); - - return $lng_code[0]; - }, array_keys($app['locales.available'])); - } else { - $t_lng[] = $request->get('piv'); - } - - switch ($request->get('obrf')) { - case 'from_itf_closable': - $default_display = 'closed'; - $opened_display = 'opened'; - break; - case 'from_itf_static': - $default_display = 'closed'; - $opened_display = 'static'; - break; - case 'all_opened_closable': - $default_display = 'opened'; - $opened_display = ''; - break; - case 'all_opened_static': - $default_display = 'static'; - $opened_display = ''; - break; - default: - case 'all_closed': - $default_display = 'closed'; - $opened_display = ''; - break; - } - - $now = date('YmdHis'); - $lngs = []; - try { - /** @var \databox $databox */ - $databox = $app['phraseanet.appbox']->get_databox((int) $request->get("bid")); - if ($request->get("typ") == "TH") { - $domth = $databox->get_dom_thesaurus(); - } else { - $domth = $databox->get_dom_cterms(); - } - - if ($domth) { - $xpathth = new \DOMXPath($domth); - if ($request->get("id") == "T") { - $q = "/thesaurus"; - } elseif ($request->get("id") == "C") { - $q = "/cterms"; - } else { - $q = "//te[@id='" . $request->get("id") . "']"; - } - - if ($request->get('ofm') == 'toscreen') { - printf("\n"); - } - - foreach ($t_lng as $lng) { - $dom = new \DOMDocument("1.0", "UTF-8"); - $dom->preserveWhiteSpace = false; - $dom->formatOutput = true; - $root = $dom->appendChild($dom->createElementNS('www.phraseanet.com', 'phraseanet:topics')); - - $root->appendChild($dom->createComment($app->trans('thesaurus:: fichier genere le %date%', ['%date%' => $now]))); - - $root->appendChild($dom->createElement('display')) - ->appendChild($dom->createElement('defaultview')) - ->appendChild($dom->createTextNode($default_display)); - - $this->export0Topics($app, $xpathth->query($q)->item(0), $dom, $root, $lng, $request->get("srt"), $request->get("sth"), $request->get("sand"), $opened_display, $obr); - - if ($request->get("ofm") == 'toscreen') { - $lngs[$lng] = str_replace(['&', '<', '>'], ['&', '<', '>'], $dom->saveXML()); - } elseif ($request->get("ofm") == 'tofiles') { - $fname = 'topics_' . $lng . '.xml'; - - @rename($app['root.path'] . '/config/topics/' . $fname, $app['root.path'] . '/config/topics/topics_' . $lng . '_BKP_' . $now . '.xml'); - - if ($dom->save($app['root.path'] . '/config/topics/' . $fname)) { - $lngs[$lng] = \p4string::MakeString($app->trans('thesaurus:: fichier genere : %filename%', ['%filename%' => $fname])); - } else { - $lngs[$lng] = \p4string::MakeString($app->trans('thesaurus:: erreur lors de l\'enregsitrement du fichier')); - } - } - } - } - } catch (\Exception $e) { - - } - - return $app['twig']->render('thesaurus/export-topics.html.twig', [ - 'lngs' => $lngs, - 'ofm' => $request->get('ofm'), - ]); - } - - private function export0Topics(Application $app, $znode, \DOMDocument $dom, \DOMNode $root, $lng, $srt, $sth, $sand, $opened_display, $obr) - { - $topics = $root->appendChild($dom->createElement('topics')); - $this->doExportTopics($app, $znode, $dom, $topics, '', $lng, $srt, $sth, $sand, $opened_display, $obr, 0); - } - - private function doExportTopics(Application $app, \DOMElement $node, \DOMDocument $dom, \DOMNode $topics, $prevQuery, $lng, $srt, $sth, $sand, $opened_display, $obr, $depth = 0) - { - $ntopics = 0; - if ($node->nodeType == XML_ELEMENT_NODE) { - /** @var \DOMElement[] $t_node */ - $t_node = []; - $t_label = []; - $t_sort = []; - $i = 0; - for ($n = $node->firstChild; $n; $n = $n->nextSibling) { - if ($n->nodeName == "te") { - $ntopics ++; - $label0 = $label = ""; - $query0 = $query = ""; - for ($n2 = $n->firstChild; $n2; $n2 = $n2->nextSibling) { - if ($n2->nodeName == "sy") { - if (! $query0) { - $query0 = $n2->getAttribute("w"); - if ($n2->getAttribute("k")) { - $query0 .= ( ' (' . $n2->getAttribute("k") . ')'); - } - $label0 = $n2->getAttribute("v"); - } - if ($n2->getAttribute("lng") == $lng) { - $query = $n2->getAttribute("w"); - if ($n2->getAttribute("k")) - $query .= ( ' (' . $n2->getAttribute("k") . ')'); - $label = $n2->getAttribute("v"); - break; - } - } - } - if (!$query) { - $query = $query0; - } - if (!$label) { - $label = $label0; - } - - $t_sort[$i] = $query; // tri sur w - $t_node[$i] = $n; - $t_label[$i] = $label; - - $i ++; - } - } - - if ($srt) { - natcasesort($t_sort); - } - - foreach ($t_sort as $i => $query) { - /** @var \DOMElement $topic */ - $topic = $topics->appendChild($dom->createElement('topic')); - if ($opened_display != '' && in_array($t_node[$i]->getAttribute('id'), $obr)) { - $topic->setAttribute('view', $opened_display); - } - $topic->appendChild($dom->createElement('label'))->appendChild($dom->createTextNode($t_label[$i])); - - $query = '"' . $query . '"'; - if ($sth) { - $query = '*:' . $query; - if ($sand) { - $query = '(' . $query . ')'; - } - } - - if ($sand && $prevQuery != '') { - $query = $prevQuery . ' ' . $app->trans('phraseanet::technique:: et') . ' ' . $query . ''; - } - - $topic->appendChild($dom->createElement('query'))->appendChild($dom->createTextNode('' . $query . '')); - - $topics2 = $dom->createElement('topics'); - - if ($this->doExportTopics($app, $t_node[$i], $dom, $topics2, $query, $lng, $srt, $sth, $sand, $opened_display, $obr, $depth + 1) > 0) { - $topic->appendChild($topics2); - } - } - } - - return $ntopics; - } - - public function exportTopicsDialog(Application $app, Request $request) - { - return $app['twig']->render('thesaurus/export-topics-dialog.html.twig', [ - 'bid' => $request->get('bid'), - 'piv' => $request->get('piv'), - 'typ' => $request->get('typ'), - 'dlg' => $request->get('dlg'), - 'id' => $request->get('id'), - 'obr' => $request->get('obr'), - ]); - } - - public function import(Application $app, Request $request) - { - set_time_limit(300); - - $err = ''; - - if (null === $bid = $request->get("bid")) { - return new Response('Missing bid parameter', 400); - } - - try { - /** @var \databox $databox */ - $databox = $app['phraseanet.appbox']->get_databox((int) $bid); - - $dom = $databox->get_dom_thesaurus(); - - if ($dom) { - if ($request->get('id') == '') { - // on importe un theaurus entier - /** @var \DOMElement $node */ - $node = $dom->documentElement; - while ($node->firstChild) { - $node->removeChild($node->firstChild); - } - - $cbad = []; - $cok = []; - for ($i = 0; $i < 32; $i ++) { - $cbad[] = chr($i); - $cok[] = '_'; - } - - $file = $request->files->get('fil')->getPathname(); - - if (($fp = fopen($file, 'rb'))) { - $iline = 0; - $curdepth = -1; - while ( ! $err && ! feof($fp) && ($line = fgets($fp)) !== FALSE) { - $iline ++; - if (trim($line) == '') { - continue; - } - for ($depth = 0; $line != '' && $line[0] == "\t"; $depth ++) { - $line = substr($line, 1); - } - if ($depth > $curdepth + 1) { - $err = $app->trans("over-indent at line %line%", ['%line%' => $iline]); - continue; - } - - $line = trim($line); - - if ( ! $this->checkEncoding($line, 'UTF-8')) { - $err = $app->trans("bad encoding at line %line%", ['%line%' => $iline]); - continue; - } - - $line = str_replace($cbad, $cok, ($oldline = $line)); - if ($line != $oldline) { - $err = $app->trans("bad character at line %line%", ['%line%' => $iline]); - continue; - } - - while ($curdepth >= $depth) { - $curdepth --; - $node = $node->parentNode; - } - $curdepth = $depth; - - $nid = (int) ($node->getAttribute('nextid')); - $pid = $node->getAttribute('id'); - - $te_id = ($pid ? ($pid . '.') : 'T') . $nid; - - $node->setAttribute('nextid', (string) ($nid + 1)); - - /** @var \DOMElement $te */ - $te = $node->appendChild($dom->createElement('te')); - $te->setAttribute('id', $te_id); - - $node = $te; - - $tsy = explode(';', $line); - $nsy = 0; - foreach ($tsy as $syn) { - $lng = $request->get('piv'); - $kon = ''; - - if (($ob = strpos($syn, '[')) !== false) { - if (($cb = strpos($syn, ']', $ob)) !== false) { - $lng = trim(substr($syn, $ob + 1, $cb - $ob - 1)); - $syn = substr($syn, 0, $ob) . substr($syn, $cb + 1); - } else { - $lng = trim(substr($syn, $ob + 1)); - $syn = substr($syn, 0, $ob); - } - - if (($ob = strpos($syn, '[')) !== false) { - if (($cb = strpos($syn, ']', $ob)) !== false) { - $syn = substr($syn, 0, $ob) . substr($syn, $cb + 1); - } else { - $syn = substr($syn, 0, $ob); - } - } - } - if (($ob = strpos($syn, '(')) !== false) { - if (($cb = strpos($syn, ')', $ob)) !== false) { - $kon = trim(substr($syn, $ob + 1, $cb - $ob - 1)); - $syn = substr($syn, 0, $ob) . substr($syn, $cb + 1); - } else { - $kon = trim(substr($syn, $ob + 1)); - $syn = substr($syn, 0, $ob); - } - } - - $syn = trim($syn); - - /** @var \DOMElement $sy */ - $sy = $node->appendChild($dom->createElement('sy')); - $sy->setAttribute('id', $te_id . '.' . $nsy); - $v = $syn; - if ($kon) { - $v .= ' (' . $kon . ')'; - } - $sy->setAttribute('v', $v); - $sy->setAttribute('w', $app['unicode']->remove_indexer_chars($syn)); - if ($kon) { - $sy->setAttribute('k', $app['unicode']->remove_indexer_chars($kon)); - } - $sy->setAttribute('lng', $lng); - - $nsy ++; - } - - $te->setAttribute('nextid', (string) $nsy); - } - - fclose($fp); - } - - } else { - // on importe dans une branche - $err = 'not implemented'; - } - - if (! $err) { - $databox->saveThesaurus($dom); - } - } - - if (! $err) { - $meta_struct = $databox->get_meta_structure(); - - foreach ($meta_struct->get_elements() as $meta_field) { - $meta_field->set_tbranch('')->save(); - } - - $dom = $databox->get_dom_cterms(); - if ($dom) { - $node = $dom->documentElement; - while ($node->firstChild) { - $node->removeChild($node->firstChild); - } - $databox->saveCterms($dom); - } - - $this->reindexAll($databox); - - /** @var EventDispatcherInterface $dispatcher */ - $dispatcher = $app['dispatcher']; - $dispatcher->dispatch( - PhraseaEvents::THESAURUS_IMPORTED, - new ThesaurusEvent\Imported($databox) - ); - } - } catch (\Exception $e) { - - } - - return $app['twig']->render('thesaurus/import.html.twig', ['err' => $err]); - } - - private function checkEncoding($string, $string_encoding) - { - $fs = $string_encoding == 'UTF-8' ? 'UTF-32' : $string_encoding; - $ts = $string_encoding == 'UTF-32' ? 'UTF-8' : $string_encoding; - - return $string === mb_convert_encoding(mb_convert_encoding($string, $fs, $ts), $ts, $fs); - } - - public function importDialog(Application $app, Request $request) - { - return $app['twig']->render('thesaurus/import-dialog.html.twig', [ - 'dlg' => $request->get('dlg'), - 'bid' => $request->get('bid'), - 'id' => $request->get('id'), - 'piv' => $request->get('piv'), - ]); - } - - public function indexThesaurus(Application $app, Request $request) - { - $sql = "SELECT" - . " sbas.sbas_id," - . " sbasusr.bas_manage AS bas_manage," - . " sbasusr.bas_modify_struct AS bas_modify_struct," - . " sbasusr.bas_modif_th AS bas_edit_thesaurus" - . " FROM" - . " (Users u INNER JOIN sbasusr" - . " ON u.id = :usr_id" - . " AND u.id = sbasusr.usr_id" - . " AND u.model_of IS NULL)" - . " INNER JOIN" - . " sbas ON sbas.sbas_id = sbasusr.sbas_id" - . " HAVING bas_edit_thesaurus > 0" - . " ORDER BY sbas.ord"; - - $bases = $languages = []; - - /** @var \appbox $appbox */ - $appbox = $app['phraseanet.appbox']; - $stmt = $appbox->get_connection()->prepare($sql); - $stmt->execute([':usr_id' => $app['authentication']->getUser()->getId()]); - $rs = $stmt->fetchAll(\PDO::FETCH_ASSOC); - $stmt->closeCursor(); - - foreach ($rs as $row) { - try { - $app['phraseanet.appbox']->get_databox($row['sbas_id'])->get_connection()->connect(); - } catch (\Exception $e) { - continue; - } - $bases[$row['sbas_id']] = \phrasea::sbas_labels($row['sbas_id'], $app); - } - - foreach ($app['locales.available'] as $lng_code => $lng) { - $lng_code = explode('_', $lng_code); - $languages[$lng_code[0]] = $lng; - } - - return $app['twig']->render('thesaurus/index.html.twig', [ - 'languages' => $languages, - 'bases' => $bases, - ]); - } - - public function linkFieldStep1(Application $app, Request $request) - { - if (null === $bid = $request->get("bid")) { - return new Response('Missing bid parameter', 400); - } - - $fullBranch = ""; - $fieldnames = []; - try { - /** @var \databox $databox */ - $databox = $app['phraseanet.appbox']->get_databox((int) $bid); - $domstruct = $databox->get_dom_structure(); - $domth = $databox->get_dom_thesaurus(); - - if ($domstruct && $domth) { - $xpathth = new \DOMXPath($domth); - $xpathstruct = new \DOMXPath($domstruct); - - if ($request->get('tid') !== "") { - $q = "//te[@id='" . $request->get('tid') . "']"; - } else { - $q = "//te[not(@id)]"; - } - - $nodes = $xpathth->query($q); - if ($nodes->length == 1) { - /** @var \DOMElement $n */ - for ($n = $nodes->item(0); $n && $n->nodeType == XML_ELEMENT_NODE && $n->getAttribute("id") !== ""; $n = $n->parentNode) { - /** @var \DOMElement $sy */ - $sy = $xpathth->query("sy", $n)->item(0); - $t = $sy ? $sy->getAttribute("v") : ""; - if (!$t) { - $t = "..."; - } - $fullBranch = " / " . $t . $fullBranch; - } - } - $nodes = $xpathstruct->query("/record/description/*"); - for ($i = 0; $i < $nodes->length; $i ++) { - /** @var \DOMElement $node */ - $node = $nodes->item($i); - $fieldname = $node->nodeName; - $tbranch = $node->getAttribute("tbranch"); - $ck = false; - if ($tbranch) { - // ce champ a deja un tbranch, est-ce qu'il pointe sur la branche selectionnee ? - $thnodes = $xpathth->query($tbranch); - for ($j = 0; $j < $thnodes->length; $j ++) { - $node = $thnodes->item($j); - if ($node->getAttribute("id") == $request->get('tid')) { - $ck = true; - } - } - } - $fieldnames[$fieldname] = $ck; - } - } - } catch (\Exception $e) { - - } - - return $app['twig']->render('thesaurus/link-field-step1.html.twig', [ - 'piv' => $request->get('piv'), - 'bid' => $request->get('bid'), - 'tid' => $request->get('tid'), - 'fullBranch' => $fullBranch, - 'fieldnames' => $fieldnames - ]); - } - - public function linkFieldStep2(Application $app, Request $request) - { - if (null === $bid = $request->get("bid")) { - return new Response('Missing bid parameter', 400); - } - - $oldlinks = []; - $needreindex = false; - - try { - /** @var \databox $databox */ - $databox = $app['phraseanet.appbox']->get_databox((int) $bid); - $domstruct = $databox->get_dom_structure(); - $domth = $databox->get_dom_thesaurus(); - - if ($domstruct && $domth) { - $xpathth = new \DOMXPath($domth); - $xpathstruct = new \DOMXPath($domstruct); - $nodes = $xpathstruct->query("/record/description/*"); - - for ($i = 0; $i < $nodes->length; $i ++) { - /** @var \DOMElement $node */ - $node = $nodes->item($i); - $fieldname = $node->nodeName; - - $oldbranch = $node->getAttribute("tbranch"); - $ck = false; - $tids = []; // les ids de branches liees e ce champ - if ($oldbranch) { - // ce champ a deja un tbranch, on balaye les branches auxquelles il est lie - $thnodes = $xpathth->query($oldbranch); - for ($j = 0; $j < $thnodes->length; $j ++) { - $node = $thnodes->item($j); - if ($node->getAttribute("id") == $request->get('tid')) { - // il etait deja lie a la branche selectionnee - $tids[$node->getAttribute("id")] = $node; - $ck = true; - } else { - // il etait lie e une autre branche - $tids[$node->getAttribute("id")] = $node; - } - } - } - - if (in_array($fieldname, $request->get('field', [])) != $ck) { - if ($ck) { - unset($tids[$request->get('tid')]); - } else { - $tids[$request->get('tid')] = $xpathth->query("/thesaurus//te[@id='" . \thesaurus::xquery_escape($request->get('tid')) . "']")->item(0); - } - $newtbranch = ""; - - foreach ($tids as $kitd => $node) { - if ($kitd === "") { - $newtbranch .= ( $newtbranch ? " | " : "") . "/thesaurus"; - } else { - $neb = ""; - while ($node && $node->nodeName == "te") { - $neb = "/te[@id='" . $node->getAttribute("id") . "']" . $neb; - $node = $node->parentNode; - } - $newtbranch .= ( $newtbranch ? " | " : "") . "/thesaurus" . $neb; - } - } - - $oldlinks[$fieldname] = [ - 'old_branch' => $oldbranch, - 'new_branch' => $newtbranch - ]; - - if ($newtbranch != "") { - $needreindex = true; - } - } - } - } - } catch (\Exception $e) { - - } - - return $app['twig']->render('thesaurus/link-field-step2.html.twig', [ - 'piv' => $request->get('piv'), - 'bid' => $request->get('bid'), - 'tid' => $request->get('tid'), - 'oldlinks' => $oldlinks, - 'need_reindex' => $needreindex, - ]); - } - - public function linkFieldStep3(Application $app, Request $request) - { - if (null === $bid = $request->get("bid")) { - return new Response('Missing bid parameter', 400); - } - - $candidates2del = []; - $ctchanged = false; - try { - /** @var \databox $databox */ - $databox = $app['phraseanet.appbox']->get_databox((int) $bid); - $meta_struct = $databox->get_meta_structure(); - $domct = $databox->get_dom_cterms(); - $domst = $databox->get_dom_structure(); - - if ($domct && $domst) { - $xpathct = new \DOMXPath($domct); - - foreach ($request->get("f2unlk", []) as $f2unlk) { - $q = "/cterms/te[@field='" . \thesaurus::xquery_escape($f2unlk) . "']"; - $nodes = $xpathct->query($q); - for ($i = 0; $i < $nodes->length; $i ++) { - $candidates2del[] = [ - "field" => $f2unlk, - "node" => $nodes->item($i) - ]; - } - - $field = $meta_struct->get_element_by_name($f2unlk); - if ($field) { - $field->set_tbranch('')->save(); - } - } - foreach ($candidates2del as $candidate2del) { - $candidate2del["node"]->parentNode->removeChild($candidate2del["node"]); - $ctchanged = true; - } - - foreach ($request->get("fbranch", []) as $fbranch) { - $p = strpos($fbranch, "<"); - if ($p > 1) { - $fieldname = substr($fbranch, 0, $p); - $tbranch = substr($fbranch, $p + 1); - $field = $meta_struct->get_element_by_name($fieldname); - if ($field) { - $field->set_tbranch($tbranch)->save(); - } - } - } - - if ($ctchanged) { - $databox->saveCterms($domct); - } - } - - if ($request->get("reindex")) { - $this->reindexAll($databox); - - /** @var EventDispatcherInterface $dispatcher */ - $dispatcher = $app['dispatcher']; - $dispatcher->dispatch( - PhraseaEvents::THESAURUS_FIELD_LINKED, - new ThesaurusEvent\FieldLinked($databox) - ); - } - } catch (\Exception $e) { - - } - - return $app['twig']->render('thesaurus/link-field-step3.html.twig', [ - 'field2del' => $request->get('f2unlk', []), - 'candidates2del' => $candidates2del, - 'branch2del' => $request->get('fbranch', []), - 'ctchanged' => $ctchanged, - 'reindexed' => $request->get('reindex'), - ]); - } - - private function fixThesaurus($app, \DOMDocument $domct, \DOMDocument $domth, Connection $connbas) - { - $version = $domth->documentElement->getAttribute("version"); - - if ('' === trim($version)) { - $version = '1.0.0'; - } - - while (class_exists($cls = "patchthesaurus_" . str_replace(".", "", $version))) { - - $last_version = $version; - $zcls = new $cls; - $version = $zcls->patch($version, $domct, $domth, $connbas, $app['unicode']); - - if ($version == $last_version) { - break; - } - } - - return $version; - } - - public function loadThesaurus(Application $app, Request $request) - { - if (null === $request->get("bid")) { - return new Response('Missing bid parameter', 400); - } - - $updated = false; - $validThesaurus = true; - $ctlist = []; - $name = \phrasea::sbas_labels($request->get('bid'), $app); - - try { - /** @var \databox $databox */ - $databox = $app['phraseanet.appbox']->get_databox((int) $request->get('bid')); - $connbas = $databox->get_connection(); - - $domct = $databox->get_dom_cterms(); - $domth = $databox->get_dom_thesaurus(); - $now = date("YmdHis"); - - if ( ! $domct && $request->get('repair') == 'on') { - $domct = new \DOMDocument(); - $domct->load(__DIR__ . "/../../../../conf.d/blank_cterms.xml"); - $domct->documentElement->setAttribute("creation_date", $now); - $databox->saveCterms($domct); - } - if ( ! $domth && $request->get('repair') == 'on') { - $domth = new \DOMDocument(); - $domth->load(__DIR__ . "/../../../../conf.d/blank_thesaurus.xml"); - $domth->documentElement->setAttribute("creation_date", $now); - $databox->saveThesaurus($domth); - } - - if ($domct && $domth) { - - $oldversion = $domth->documentElement->getAttribute("version"); - if ($this->fixThesaurus($app, $domct, $domth, $connbas) != $oldversion) { - $updated = true; - $databox->saveCterms($domct); - $databox->saveThesaurus($domth); - } - - for ($ct = $domct->documentElement->firstChild; $ct; $ct = $ct->nextSibling) { - if ($ct->nodeName == "te") { - $ctlist[] = [ - 'id' => $ct->getAttribute("id"), - 'field' => $ct->getAttribute("field") - ]; - } - } - } else { - $validThesaurus = false; - } - } catch (\Exception $e) { - - } - - return $app['twig']->render('thesaurus/load-thesaurus.html.twig', [ - 'bid' => $request->get('bid'), - 'name' => $name, - 'cterms' => $ctlist, - 'valid_thesaurus' => $validThesaurus, - 'updated' => $updated - ]); - } - - public function newTerm(Application $app, Request $request) - { - list($term, $context) = $this->splitTermAndContext($request->get("t")); - - $dom = $this->doSearchCandidate($app, $request->get('bid'), $request->get('pid'), $term, $context, $request->get('piv')); - - $xpath = new \DOMXPath($dom); - - $candidates = $xpath->query("/result/candidates_list/ct"); - - $nb_candidates_ok = $nb_candidates_bad = 0; - $flist_ok = $flist_bad = ""; - for ($i = 0; $i < $candidates->length; $i ++) { - /** @var \DOMElement $candidate */ - $candidate = $candidates->item($i); - if ($candidate->getAttribute("sourceok") == "1") { // && $candidates->item($i)->getAttribute("cid")) - $flist_ok .= ( $flist_ok ? ", " : "") . $candidate->getAttribute("field"); - $nb_candidates_ok ++; - } else { - $flist_bad .= ( $flist_bad ? ", " : "") . $candidate->getAttribute("field"); - $nb_candidates_bad ++; - } - } - $candidates_list = []; - for ($i = 0; $i < $candidates->length; $i ++) { - /** @var \DOMElement $candidate */ - $candidate = $candidates->item($i); - if ($candidate->getAttribute("sourceok") == "1") { - $candidates_list[] = array( - 'id' => $candidate->getAttribute("id"), - 'field' => $candidate->getAttribute("field"), - ); - } - } - - return $app['twig']->render('thesaurus/new-term.html.twig', [ - 'typ' => $request->get('typ'), - 'bid' => $request->get('bid'), - 'piv' => $request->get('piv'), - 'pid' => $request->get('pid'), - 'sylng' => $request->get('sylng'), - 'dlg' => $request->get('dlg'), - 'candidates' => $candidates_list, - 'term' => $term, - 'context' => $context, - 'nb_candidates_ok' => $nb_candidates_ok, - 'nb_candidates_bad' => $nb_candidates_bad, - ]); - } - - public function properties(Application $app, Request $request) - { - $dom = $this->getXMLTerm($app, $request->get('bid'), $request->get('id'), $request->get('typ'), $request->get('piv'), '0', null, '1', null); - $fullpath = $dom->getElementsByTagName("fullpath_html")->item(0)->firstChild->nodeValue; - $hits = $dom->getElementsByTagName("allhits")->item(0)->firstChild->nodeValue; - - $languages = $synonyms = []; - - $sy_list = $dom->getElementsByTagName("sy_list")->item(0); - /** @var \DOMElement $n */ - for ($n = $sy_list->firstChild; $n; $n = $n->nextSibling) { - $synonyms[] = [ - 'id' => $n->getAttribute("id"), - 'lng' => $n->getAttribute("lng"), - 't' => $n->getAttribute("t"), - 'hits' => $n->getAttribute("hits"), - ]; - } - - foreach ($app['locales.available'] as $code => $language) { - $lng_code = explode('_', $code); - $languages[$lng_code[0]] = $language; - } - - return $app['twig']->render('thesaurus/properties.html.twig', [ - 'typ' => $request->get('typ'), - 'bid' => $request->get('bid'), - 'piv' => $request->get('piv'), - 'id' => $request->get('id'), - 'dlg' => $request->get('dlg'), - 'languages' => $languages, - 'fullpath' => $fullpath, - 'hits' => $hits, - 'synonyms' => $synonyms, - ]); - } - - public function thesaurus(Application $app, Request $request) - { - $flags = $jsFlags = []; - - foreach ($app['locales.available'] as $code => $language) { - $lng_code = explode('_', $code); - $flags[$lng_code[0]] = $language; - $jsFlags[$lng_code[0]] = ['w' => 18, 'h' => 13]; - } - $jsFlags = json_encode($jsFlags); - - return $app['twig']->render('thesaurus/thesaurus.html.twig', [ - 'piv' => $request->get('piv'), - 'bid' => $request->get('bid'), - 'flags' => $flags, - 'jsFlags' => $jsFlags, - ]); - } - - /** - * @param Application $app - * @param Request $request - * @return Response - * - * rétablit un terme candidat rejeté (R) et tous ses enfants - * comme candidat (C) - * appelé par le menu contextuel sur candidat / kcterm_accept - */ - public function acceptXml(Application $app, Request $request) - { - $ret = new \DOMDocument("1.0", "UTF-8"); - $ret->preserveWhiteSpace = false; - - $root = $ret->appendChild($ret->createElement("result")); - $root->appendChild($ret->createCDATASection(var_export([ - "bid" => $request->get('bid'), - "id" => $request->get('id'), - "piv" => $request->get('piv'), - ], true))); - - $refresh_list = $root->appendChild($ret->createElement("refresh_list")); - - if (null === $bid = $request->get("bid")) { - return new Response('Missing bid parameter', 400); - } - - try { - /** @var \databox $databox */ - $databox = $app['phraseanet.appbox']->get_databox((int) $bid); - $databox->get_connection()->connect(); - - $dom = $databox->get_dom_cterms(); - $xpath = new \DOMXPath($dom); - $q = "/cterms//te[@id='" . $request->get('id') . "']"; - - /** @var \DOMElement $te */ - $te = $xpath->query($q)->item(0); - if ($te) { - $this->acceptBranch($app, $bid, $te); - - $databox->saveCterms($dom); - - /** @var \DOMElement $r */ - $r = $refresh_list->appendChild($ret->createElement("refresh")); - /** @var \DOMElement $p */ - $p = $te->parentNode; - $r->setAttribute("id", $p->getAttribute("id")); - $r->setAttribute("type", "CT"); - } - } catch (\Exception $e) { - - } - - return new Response($ret->saveXML(), 200, ['Content-Type' => 'text/xml']); - } - - /** - * transforme (R)ejected en (C)andidate sur un node et tous ses enfants - * @param Application $app - * @param $sbas_id - * @param \DOMElement $node - */ - private function acceptBranch(Application $app, $sbas_id, \DOMElement $node) - { - if (strlen($oldid = $node->getAttribute("id")) > 1) { - $node->setAttribute("id", $newid = ("C" . substr($oldid, 1))); - } - for ($n = $node->firstChild; $n; $n = $n->nextSibling) { - if ($n->nodeType == XML_ELEMENT_NODE) { - $this->acceptBranch($app, $sbas_id, $n); - } - } - } - - - - public function acceptCandidatesXml(Application $app, Request $request) - { - $ret = new \DOMDocument("1.0", "UTF-8"); - $ret->preserveWhiteSpace = false; - - $root = $ret->appendChild($ret->createElement("result")); - $root->appendChild($ret->createCDATASection(var_export([ - 'bid' => $request->get('bid'), - 'piv' => $request->get('piv'), - 'cid' => $request->get('cid'), - 'pid' => $request->get('pid'), - 'typ' => $request->get('typ'), - ], true))); - - $refresh_list = $root->appendChild($ret->createElement("refresh_list")); - - if (null === $bid = $request->get("bid")) { - return new Response('Missing bid parameter', 400); - } - - try { - /** @var \databox $databox */ - $databox = $app['phraseanet.appbox']->get_databox((int) $bid); - - $domct = $databox->get_dom_cterms(); - $domth = $databox->get_dom_thesaurus(); - - if ($domct !== false && $domth !== false) { - $xpathth = new \DOMXPath($domth); - - if ($request->get('pid') == "T") { - $q = "/thesaurus"; - } else { - $q = "/thesaurus//te[@id='" . $request->get('pid') . "']"; - } - - /** @var \DOMElement $parentnode */ - $parentnode = $xpathth->query($q)->item(0); - - if ($parentnode) { - $xpathct = new \DOMXPath($domct); - $ctchanged = $thchanged = false; - - $icid = 0; - foreach ($request->get("cid") as $cid) { - $q = "//te[@id='" . $cid . "']"; - - /** @var \DOMElement $ct */ - $ct = $xpathct->query($q)->item(0); - - if ($ct) { - if ($request->get("typ") == "TS") { - // importer tt la branche candidate comme nouveau ts - $nid = $parentnode->getAttribute("nextid"); - $parentnode->setAttribute("nextid", (int) $nid + 1); - - /** @var \DOMElement $te */ - $te = $domth->importNode($ct, true); - $chgids = []; - - if (($pid = $parentnode->getAttribute("id")) == "") { - $pid = "T" . $nid; - } else { - $pid .= "." . $nid; - } - - $this->renumerate($te, $pid, $chgids); - - /** @var \DOMElement $new_te */ - $new_te = $parentnode->appendChild($te); - - $databox->saveThesaurus($domth); - - /** @var EventDispatcherInterface $dispatcher */ - $dispatcher = $app['dispatcher']; - $dispatcher->dispatch( - PhraseaEvents::THESAURUS_CANDIDATE_ACCEPTED_AS_CONCEPT, - new ThesaurusEvent\CandidateAccepted($databox, $new_te->getAttribute('id')) - ); - $thchanged = true; - - /** @var \DOMElement $r */ - if ($icid == 0) { // on update la destination une seule fois - $r = $refresh_list->appendChild($ret->createElement("refresh")); - $r->setAttribute("id", $parentnode->getAttribute("id")); - $r->setAttribute("type", "TH"); - } - - $r = $refresh_list->appendChild($ret->createElement("refresh")); - $r->setAttribute("id", $ct->parentNode->getAttribute("id")); - $r->setAttribute("type", "CT"); - - $ct->parentNode->removeChild($ct); - - $ctchanged = true; - } elseif ($request->get("typ") == "SY") { - // importer tt le contenu de la branche sous la destination - for ($ct2 = $ct->firstChild; $ct2; $ct2 = $ct2->nextSibling) { - if ($ct2->nodeType != XML_ELEMENT_NODE) { - continue; - } - - $nid = $parentnode->getAttribute("nextid"); - $parentnode->setAttribute("nextid", (int) $nid + 1); - - /** @var \DOMElement $te */ - $te = $domth->importNode($ct2, true); - $chgids = []; - if (($pid = $parentnode->getAttribute("id")) == "") { - $pid = "T" . $nid; - } else { - $pid .= "." . $nid; - } - - $this->renumerate($te, $pid, $chgids); - /** @var \DOMElement $new_te */ - $new_te = $parentnode->appendChild($te); - - $databox->saveThesaurus($domth); - - /** @var EventDispatcherInterface $dispatcher */ - $dispatcher = $app['dispatcher']; - $dispatcher->dispatch( - PhraseaEvents::THESAURUS_CANDIDATE_ACCEPTED_AS_SYNONYM, - new ThesaurusEvent\CandidateAccepted($databox, $new_te->getAttribute('id')) - ); - $thchanged = true; - } - /** @var \DOMElement $r */ - if ($icid == 0) { // on update la destination une seule fois - $r = $refresh_list->appendChild($ret->createElement("refresh")); - $r->setAttribute("id", $parentnode->parentNode->getAttribute("id")); - $r->setAttribute("type", "TH"); - } - $r = $refresh_list->appendChild($ret->createElement("refresh")); - $r->setAttribute("id", $ct->parentNode->getAttribute("id")); - $r->setAttribute("type", "CT"); - - $ct->parentNode->removeChild($ct); - $ctchanged = true; - } - $icid ++; - } - } - if ($ctchanged) { - $databox->saveCterms($domct); - } - if ($thchanged) { - $this->reindexAll($databox); - } - } - } - } catch (\Exception $e) { - - } - - return new Response($ret->saveXML(), 200, ['Content-Type' => 'text/xml']); - } - - private function renumerate(\DOMElement $node, $id, &$chgids, $depth = 0) - { - $node->setAttribute("id", $id); - $nchild = 0; - for ($n = $node->firstChild; $n; $n = $n->nextSibling) { - if ($n->nodeType == XML_ELEMENT_NODE && ($n->nodeName == "te" || $n->nodeName == "sy")) { - $this->renumerate($n, $id . "." . $nchild, $chgids, $depth + 1); - $nchild ++; - } - } - $node->setAttribute("nextid", $nchild); - } - - public function changeSynonymLanguageXml(Application $app, Request $request) - { - $ret = new \DOMDocument("1.0", "UTF-8"); - $ret->preserveWhiteSpace = false; - - $root = $ret->appendChild($ret->createElement("result")); - $root->appendChild($ret->createCDATASection(var_export([ - 'bid' => $request->get('bid'), - 'piv' => $request->get('piv'), - 'newlng' => $request->get('cid'), - 'id' => $request->get('id'), - 'typ' => $request->get('typ'), - ], true))); - - if (null === $bid = $request->get("bid")) { - return new Response('Missing bid parameter', 400); - } - - try { - /** @var \databox $databox */ - $databox = $app['phraseanet.appbox']->get_databox((int) $bid); - - if ($request->get('typ') == "CT") { - $xqroot = "cterms"; - $dom = $databox->get_dom_cterms(); - } else { - $xqroot = "thesaurus"; - $dom = $databox->get_dom_thesaurus(); - } - - if ($dom) { - $xpath = new \DOMXPath($dom); - $q = "/$xqroot//sy[@id='" . $request->get('id') . "']"; - - /** @var \DOMElement $sy0 */ - $sy0 = $xpath->query($q)->item(0); - if ($sy0) { - $sy0->setAttribute("lng", $request->get('newlng')); - - if ($xqroot == "cterms") { - $databox->saveCterms($dom); - } elseif ($xqroot == "thesaurus") { - $databox->saveThesaurus($dom); - - /** @var EventDispatcherInterface $dispatcher */ - $dispatcher = $app['dispatcher']; - $dispatcher->dispatch( - PhraseaEvents::THESAURUS_SYNONYM_LNG_CHANGED, - new ThesaurusEvent\SynonymLngChanged($databox, $sy0->getAttribute('id')) - ); - - $this->reindexAll($databox); - } - - $ret = $this->getXMLTerm($app, $bid, $sy0->parentNode->getAttribute("id"), $request->get('typ'), $request->get('piv'), null, $request->get('id'), '1', null); - - $root = $ret->getElementsByTagName("result")->item(0); - $refresh_list = $root->appendChild($ret->createElement("refresh_list")); - - /** @var \DOMElement $r */ - $r = $refresh_list->appendChild($ret->createElement("refresh")); - $r->setAttribute("id", $sy0->parentNode->parentNode->getAttribute("id")); - $r->setAttribute("type", $request->get('typ')); - } - } - } catch (\Exception $e) { - - } - - return new Response($ret->saveXML(), 200, ['Content-Type' => 'text/xml']); - } - - public function changeSynonymPositionXml(Application $app, Request $request) - { - $ret = new \DOMDocument("1.0", "UTF-8"); - $ret->preserveWhiteSpace = false; - - $root = $ret->appendChild($ret->createElement("result")); - $root->appendChild($ret->createCDATASection(var_export([ - 'bid' => $request->get('bid'), - 'piv' => $request->get('piv'), - 'dir' => $request->get('dir'), - 'id' => $request->get('id'), - 'typ' => $request->get('typ'), - ], true))); - - if (null === $bid = $request->get("bid")) { - return new Response('Missing bid parameter', 400); - } - - $root->appendChild($ret->createElement("refresh_list")); - - try { - /** @var \databox $databox */ - $databox = $app['phraseanet.appbox']->get_databox((int) $bid); - - if ($request->get('typ') == "CT") { - $xqroot = "cterms"; - $dom = $databox->get_dom_cterms(); - } else { - $xqroot = "thesaurus"; - $dom = $databox->get_dom_thesaurus(); - } - - if ($dom) { - $xpath = new \DOMXPath($dom); - $q = "/$xqroot//sy[@id='" . $request->get('id') . "']"; - - /** @var \DOMElement $sy0 */ - $sy0 = $xpath->query($q)->item(0); - if ($sy0) { - if ($request->get('dir') == 1 && $sy0 && $sy0->previousSibling) { - $sy0->parentNode->insertBefore($sy0, $sy0->previousSibling); - } elseif ($request->get('dir') == -1 && $sy0 && $sy0->nextSibling) { - $sy0->parentNode->insertBefore($sy0->nextSibling, $sy0); - } - - if ($xqroot == "cterms") { - $databox->saveCterms($dom); - } elseif ($xqroot == "thesaurus") { - $databox->saveThesaurus($dom); - - /** @var EventDispatcherInterface $dispatcher */ - $dispatcher = $app['dispatcher']; - $dispatcher->dispatch( - PhraseaEvents::THESAURUS_SYNONYM_POSITION_CHANGED, - new ThesaurusEvent\SynonymPositionChanged($databox, $sy0->getAttribute('id')) - ); - - $this->reindexAll($databox); - } - - $ret = $this->getXMLTerm($app, $bid, $sy0->parentNode->getAttribute("id"), $request->get('typ'), $request->get('piv'), null, $request->get('id'), '1', null); - - $root = $ret->getElementsByTagName("result")->item(0); - $refresh_list = $root->appendChild($ret->createElement("refresh_list")); - - /** @var \DOMElement $r */ - $r = $refresh_list->appendChild($ret->createElement("refresh")); - $r->setAttribute("id", $sy0->parentNode->parentNode->getAttribute("id")); - $r->setAttribute("type", $request->get('typ')); - } - } - } catch (\Exception $e) { - - } - - return new Response($ret->saveXML(), 200, ['Content-Type' => 'text/xml']); - } - - /** - * @param Application $app - * @param Request $request - * @return Response - * - * supprime un synonyme - * appelé par le menu contextuel sur un synonyme, option "delete_sy" - * dans le dialog des properties sur un terme (properties.html.twig) - */ - public function removeSynonymXml(Application $app, Request $request) - { - $ret = new \DOMDocument("1.0", "UTF-8"); - $ret->preserveWhiteSpace = false; - - $root = $ret->appendChild($ret->createElement("result")); - $root->appendChild($ret->createCDATASection(var_export([ - 'bid' => $request->get('bid'), - 'id' => $request->get('id'), - 'piv' => $request->get('piv'), - 'typ' => $request->get('typ'), - ], true))); - - $refresh_list = $root->appendChild($ret->createElement("refresh_list")); - - if (null === $bid = $request->get("bid")) { - return new Response('Missing bid parameter', 400); - } - - try { - /** @var \databox $databox */ - $databox = $app['phraseanet.appbox']->get_databox((int) $bid); - $domct = $databox->get_dom_cterms(); - $dom = $databox->get_dom_thesaurus(); - - if ($request->get('typ') == "CT") { - $xqroot = "cterms"; - } else { - $xqroot = "thesaurus"; - } - - if ($dom && $domct) { - $xpath = new \DOMXPath($dom); - $q = "/$xqroot//sy[@id='" . $request->get('id') . "']"; - - /** @var \DOMElement $sy0 */ - $sy0 = $xpath->query($q)->item(0); - if ($sy0) { - $xpathct = new \DOMXPath($domct); - - // on cherche la branche 'deleted' dans les cterms - $nodes = $xpathct->query("/cterms/te[@delbranch='1']"); - if ( ! $nodes || ($nodes->length == 0)) { - // 'deleted' n'existe pas, on la cree - $id = $domct->documentElement->getAttribute("nextid"); - $domct->documentElement->setAttribute("nextid", (int) ($id) + 1); - /** @var \DOMElement $del */ - $del = $domct->documentElement->appendChild($domct->createElement("te")); - $del->setAttribute("id", "C" . $id); - $del->setAttribute("field", $app->trans('thesaurus:: corbeille')); - $del->setAttribute("nextid", "0"); - $del->setAttribute("delbranch", "1"); - - /** @var \DOMElement $r */ - $r = $refresh_list->appendChild($ret->createElement("refresh")); - $r->setAttribute("id", "C"); - $r->setAttribute("type", "CT"); - } else { - // 'deleted' existe - /** @var \DOMElement $del */ - $del = $nodes->item(0); - /** @var \DOMElement $r */ - $r = $refresh_list->appendChild($ret->createElement("refresh")); - $r->setAttribute("id", $del->getAttribute("id")); - $r->setAttribute("type", "CT"); - } - - // on cree une branche 'te' - $refrid = $sy0->parentNode->parentNode->getAttribute("id"); - $delid = $del->getAttribute("id"); - $delteid = (int) ($del->getAttribute("nextid")); - - $del->setAttribute("nextid", $delteid + 1); - /** @var \DOMElement $delte */ - $delte = $del->appendChild($domct->createElement("te")); - $delte->setAttribute("id", $delid . "." . $delteid); - $delte->setAttribute("nextid", "1"); - - /** @var \DOMElement $delsy */ - $delsy = $delte->appendChild($domct->createElement("sy")); - $delsy->setAttribute("id", $newid = ($delid . "." . $delteid . ".0")); - $delsy->setAttribute("lng", $sy0->getAttribute("lng")); - $delsy->setAttribute("v", $sy0->getAttribute("v")); - $delsy->setAttribute("w", $sy0->getAttribute("w")); - - if ($sy0->hasAttribute("k")) { - $delsy->setAttribute("k", $sy0->getAttribute("k")); - } - - $te = $sy0->parentNode; - $te->removeChild($sy0); - - $databox->saveCterms($domct); - if ($request->get('typ') == "CT") { - $r = $refresh_list->appendChild($ret->createElement("refresh")); - $r->setAttribute("type", "CT"); - if ($refrid) { - $r->setAttribute("id", $refrid); - } else { - $r->setAttribute("id", "C"); - } - } else { - $databox->saveThesaurus($dom); - - /** @var EventDispatcherInterface $dispatcher */ - $dispatcher = $app['dispatcher']; - $dispatcher->dispatch( - PhraseaEvents::THESAURUS_SYNONYM_TRASHED, - new ThesaurusEvent\ItemTrashed($databox, $te->getAttribute('id'), $delsy->getAttribute('id')) - ); - - $this->reindexAll($databox); - - $r = $refresh_list->appendChild($ret->createElement("refresh")); - $r->setAttribute("type", "TH"); - if ($refrid) { - $r->setAttribute("id", $refrid); - } else { - $r->setAttribute("id", "T"); - } - } - - $ret2 = $this->getXMLTerm($app, $request->get('bid'), $te->getAttribute("id"), $request->get('typ'), $request->get('piv'), null, null, '1', null); - - if ($sl = $ret2->getElementsByTagName("sy_list")->item(0)) { - $ret->importNode($sl, true); - } - } - } - } catch (\Exception $e) { - - } - - return new Response($ret->saveXML(), 200, ['Content-Type' => 'text/xml']); - } - - /** - * @param Application $app - * @param Request $request - * @return Response - * - * Supprime (déplace dans cterms/trash) toute une branche TE avec les SY et tous les TE enfants - * appelé par le menu contextuel sur terme, option "kterm_delete" - */ - public function removeSpecificTermXml(Application $app, Request $request) - { - $ret = new \DOMDocument("1.0", "UTF-8"); - $ret->preserveWhiteSpace = false; - - $root = $ret->appendChild($ret->createElement("result")); - $root->appendChild($ret->createCDATASection(var_export([ - 'bid' => $request->get('bid'), - 'id' => $request->get('id'), - 'piv' => $request->get('piv'), - ], true))); - - $refresh_list = $root->appendChild($ret->createElement("refresh_list")); - - if (null === $bid = $request->get("bid")) { - return new Response('Missing bid parameter', 400); - } - - try { - /** @var \databox $databox */ - $databox = $app['phraseanet.appbox']->get_databox((int) $bid); - $domth = $databox->get_dom_thesaurus(); - $domct = $databox->get_dom_cterms(); - - if ($domth && $domct) { - $xpathth = new \DOMXPath($domth); - $xpathct = new \DOMXPath($domct); - if ($request->get('id') !== "") { // secu pour pas exploser le thesaurus - $q = "/thesaurus//te[@id='" . $request->get('id') . "']"; - - $thnode = $xpathth->query($q)->item(0); - if ($thnode) { - /** @var \DOMElement $thnode_parent */ - $thnode_parent = $thnode->parentNode; - $chgids = []; - $pid = $thnode_parent->getAttribute("id"); - if ($pid === "") { - $pid = "T"; - } - - $nodes = $xpathct->query("/cterms/te[@delbranch='1']"); - if ( ! $nodes || ($nodes->length == 0)) { - $id = $domct->documentElement->getAttribute("nextid"); - - $domct->documentElement->setAttribute("nextid", (int) ($id) + 1); - /** @var \DOMElement $ct */ - $ct = $domct->documentElement->appendChild($domct->createElement("te")); - $ct->setAttribute("id", "C" . $id); - $ct->setAttribute("field", $app->trans('thesaurus:: corbeille')); - $ct->setAttribute("nextid", "0"); - $ct->setAttribute("delbranch", "1"); - - /** @var \DOMElement $r */ - $r = $refresh_list->appendChild($ret->createElement("refresh")); - $r->setAttribute("id", "C"); - $r->setAttribute("type", "CT"); - } else { - /** @var \DOMElement $ct */ - $ct = $nodes->item(0); - /** @var \DOMElement $r */ - $r = $refresh_list->appendChild($ret->createElement("refresh")); - $r->setAttribute("id", $ct->getAttribute("id")); - $r->setAttribute("type", "CT"); - } - $teid = (int) ($ct->getAttribute("nextid")); - $ct->setAttribute("nextid", $teid + 1); - - /** @var \DOMElement $newte */ - $newte = $ct->appendChild($domct->importNode($thnode, true)); - - $this->renumerate($newte, $ct->getAttribute("id") . "." . $teid, $chgids); - - $databox->saveThesaurus($domth); - - /** @var EventDispatcherInterface $dispatcher */ - $dispatcher = $app['dispatcher']; - $dispatcher->dispatch( - PhraseaEvents::THESAURUS_CONCEPT_TRASHED, - new ThesaurusEvent\ItemTrashed($databox, $thnode_parent->getAttribute('id'), $newte->getAttribute('id')) - ); - - $thnode_parent->removeChild($thnode); - - $databox->saveCterms($domct); - $this->reindexAll($databox); - - $r = $refresh_list->appendChild($ret->createElement("refresh")); - $r->setAttribute("id", $pid); - $r->setAttribute("type", "TH"); - } - } - } - } catch (\Exception $e) { - - } - - return new Response($ret->saveXML(), 200, ['Content-Type' => 'text/xml']); - } - - - public function getSynonymXml(Application $app, Request $request) - { - $ret = new \DOMDocument("1.0", "UTF-8"); - $ret->preserveWhiteSpace = false; - - $root = $ret->appendChild($ret->createElement("result")); - $root->appendChild($ret->createCDATASection(var_export([ - 'bid' => $request->get('bid'), - 'id' => $request->get('id'), - 'typ' => $request->get('typ'), - ], true))); - - if (null === $bid = $request->get("bid")) { - return new Response('Missing bid parameter', 400); - } - - try { - /** @var \databox $databox */ - $databox = $app['phraseanet.appbox']->get_databox((int) $bid); - - if ($request->get('typ') == "CT") { - $xqroot = "cterms"; - $dom = $databox->get_dom_cterms(); - } else { - $xqroot = "thesaurus"; - $dom = $databox->get_dom_thesaurus(); - } - - if ($dom) { - $xpath = new \DOMXPath($dom); - - if ($request->get('id') == "T") { - $q = "/thesaurus"; - } elseif ($request->get('id') == "C") { - $q = "/cterms"; - } else { - $q = "/$xqroot//sy[@id='" . $request->get('id') . "']"; - } - - $nodes = $xpath->query($q); - if ($nodes->length > 0) { - /** @var \DOMElement $node */ - $node = $nodes->item(0); - - $t = $node->getAttribute("v"); - if (($k = $node->getAttribute("k"))) { - $t .= " (" . $k . ")"; - } - - $fullpath_html = " / " . $t . ""; - $fullpath = " / " . $t; - - /** @var \DOMElement $sy */ - $sy = $root->appendchild($ret->createElement("sy")); - $sy->setAttribute("t", $t); - foreach (["v", "w", "k", "lng", "id"] as $a) { - if ($node->hasAttribute($a)) { - $sy->setAttribute($a, $node->getAttribute($a)); - } - } - - for ($depth = -1, $n = $node->parentNode->parentNode; $n; $n = $n->parentNode, $depth -- ) { - if ($n->nodeName == "te") { - if ($request->get('typ') == "CT" && ($fld = $n->getAttribute("field")) != "") { - $fullpath = " / " . $fld . $fullpath; - if ($depth == 0) { - $fullpath_html = " / " . $fld . "" . $fullpath_html; - } else { - $fullpath_html = " / " . $fld . $fullpath_html; - } - break; - } - $firstsy = $goodsy = null; - for ($n2 = $n->firstChild; $n2; $n2 = $n2->nextSibling) { - if ($n2->nodeName == "sy") { - $t = $n2->getAttribute("v"); - - if (! $firstsy) { - $firstsy = $t; - } - if ($n2->getAttribute("lng") == $request->get('piv')) { - $goodsy = $t; - break; - } - } - } - if (! $goodsy) { - $goodsy = $firstsy; - } - $fullpath = " / " . $goodsy . $fullpath; - $fullpath_html = " / " . $goodsy . $fullpath_html; - } - } - $fp = $root->appendchild($ret->createElement("fullpath")); - $fp->appendChild($ret->createTextNode($fullpath)); - - $fp = $root->appendchild($ret->createElement("fullpath_html")); - $fp->appendChild($ret->createTextNode($fullpath_html)); - - $n = $root->appendchild($ret->createElement("hits")); - $n->appendChild($ret->createTextNode('')); - } - } - } catch (\Exception $e) { - - } - - return new Response($ret->saveXML(), 200, ['Content-Type' => 'text/xml']); - } - - public function getTermXml(Application $app, Request $request) - { - return new Response( - $this->getXMLTerm($app, $request->get('bid'), $request->get('id'), $request->get('typ'), - $request->get('piv'), $request->get('sortsy'), $request->get('sel'), $request->get('nots'), - $request->get('acf'))->saveXML(), - 200, - ['Content-Type' => 'text/xml'] - ); - } - - /** - * @param Application $app - * @param $bid - * @param $id - * @param $typ - * @param $piv - * @param $sortsy - * @param $sel - * @param $nots - * @param $acf - * @return \DOMDocument - */ - private function getXMLTerm(Application $app, $bid, $id, $typ, $piv, $sortsy, $sel, $nots, $acf) - { - $ret = new \DOMDocument("1.0", "UTF-8"); - $ret->preserveWhiteSpace = false; - - /** @var \DOMElement $root */ - $root = $ret->appendChild($ret->createElement("result")); - $root->appendChild($ret->createCDATASection(var_export([ - "bid" => $bid, - "id" => $id, - "typ" => $typ, - "piv" => $piv, - "sortsy" => $sortsy, - "sel" => $sel, - "nots" => $nots, - "acf" => $acf, - ], true))); - - /** @var \DOMElement $cfield */ - $cfield = $root->appendChild($ret->createElement("cfield")); - /** @var \DOMElement $ts_list */ - $ts_list = $root->appendChild($ret->createElement("ts_list")); - $sy_list = $root->appendChild($ret->createElement("sy_list")); - - if ($bid !== null) { - try { - /** @var \databox $databox */ - $databox = $app['phraseanet.appbox']->get_databox((int) $bid); - - if ($typ == "CT") { - $xqroot = "cterms"; - $dom = $databox->get_dom_cterms(); - } else { - $xqroot = "thesaurus"; - $dom = $databox->get_dom_thesaurus(); - } - - $meta = $databox->get_meta_structure(); - - if ($dom) { - $xpath = new \DOMXPath($dom); - if ($typ == "TH" && $acf) { - $cfield->setAttribute("field", $acf); - - // on doit verifier si le terme demande est accessible e partir de ce champ acf - if ($acf == '*') { - // le champ "*" est la corbeille, il est toujours accepte - $cfield->setAttribute("acceptable", "1"); - } else { - if (($databox_field = $meta->get_element_by_name($acf)) instanceof \databox_field) { - $tbranch = $databox_field->get_tbranch(); - $q = "(" . $tbranch . ")/descendant-or-self::te[@id='" . $id . "']"; - - $nodes = $xpath->query($q); - $cfield->setAttribute("acceptable", ($nodes->length > 0) ? "1" : "0"); - } - } - } - - if ($id == "T") { - $q = "/thesaurus"; - } elseif ($id == "C") { - $q = "/cterms"; - } else { - $q = "/$xqroot//te[@id='" . $id . "']"; - } - - $nodes = $xpath->query($q); - $root->setAttribute('found', '' . $nodes->length); - if ($nodes->length > 0) { - $nts = 0; - $tts = []; - // on dresse la liste des termes specifiques avec comme cle le synonyme - // dans la langue pivot - for ($n = $nodes->item(0)->firstChild; $n; $n = $n->nextSibling) { - /** @var \DOMElement $n */ - if ($n->nodeName == "te") { - $nts ++; - if (! $nots) { - if ($typ == "CT" && $id == "C") { - $realksy = $allsy = $n->getAttribute("field"); - } else { - $allsy = ""; - $firstksy = null; - $realksy = null; - // on liste les sy pour fabriquer la cle - for ($n2 = $n->firstChild; $n2; $n2 = $n2->nextSibling) { - if ($n2->nodeName == "sy") { - $lng = $n2->getAttribute("lng"); - $t = $n2->getAttribute("v"); - $ksy = $n2->getAttribute("w"); - if (! $firstksy) { - $firstksy = $ksy; - } - if (! $realksy && $piv && $lng == $piv) { - $realksy = $ksy; - $allsy = $t . ($allsy ? " ; " : "") . $allsy; - } else { - $allsy .= ( $allsy ? " ; " : "") . $t; - } - } - } - if (! $realksy) { - $realksy = $firstksy; - } - } - if ($sortsy && $piv) { - for ($uniq = 0; $uniq < 9999; $uniq ++) { - if ( ! isset($tts[$realksy . "_" . $uniq])) { - break; - } - } - $tts[$realksy . "_" . $uniq] = [ - "id" => $n->getAttribute("id"), - "allsy" => $allsy, - "nchild" => $xpath->query("te", $n)->length - ]; - } else { - $tts[] = [ - "id" => $n->getAttribute("id"), - "allsy" => $allsy, - "nchild" => $xpath->query("te", $n)->length - ]; - } - } - } elseif ($n->nodeName == "sy") { - /** @var \DOMElement $sy */ - $sy = $sy_list->appendChild($ret->createElement("sy")); - - $sy->setAttribute("id", $n->getAttribute("id")); - $sy->setAttribute("v", $t = $n->getAttribute("v")); - $sy->setAttribute("w", $n->getAttribute("w")); - $sy->setAttribute("hits", ''); - $sy->setAttribute("lng", $lng = $n->getAttribute("lng")); - if (($k = $n->getAttribute("k"))) { - $sy->setAttribute("k", $k); - } - $sy->setAttribute("t", $t); - if ($n->getAttribute("id") == $sel) { - $sy->setAttribute("sel", "1"); - } - } - } - $ts_list->setAttribute("nts", $nts); - - if ($sortsy && $piv) { - ksort($tts, SORT_STRING); - } - foreach ($tts as $ts) { - /** @var \DOMElement $newts */ - $newts = $ts_list->appendChild($ret->createElement("ts")); - $newts->setAttribute("id", $ts["id"]); - $newts->setAttribute("nts", $ts["nchild"]); - $newts->appendChild($ret->createTextNode($ts["allsy"])); - } - - $fullpath_html = $fullpath = ""; - for ($depth = 0, $n = $nodes->item(0); $n; $n = $n->parentNode, $depth-- ) { - /** @var \DOMElement $n */ - if ($n->nodeName == "te") { - if ($typ == "CT" && ($fld = $n->getAttribute("field")) != "") { - // la source provient des candidats pour ce champ - - $cfield->setAttribute("field", $fld); - $cfield->setAttribute("delbranch", $n->getAttribute("delbranch")); - - $fullpath = " / " . $fld . $fullpath; - - if ($depth == 0) { - $fullpath_html = " / " . $fld . "" . $fullpath_html; - } else { - $fullpath_html = " / " . $fld . $fullpath_html; - } - break; - } - - $firstsy = $goodsy = null; - for ($n2 = $n->firstChild; $n2; $n2 = $n2->nextSibling) { - if ($n2->nodeName == "sy") { - $t = $n2->getAttribute("v"); - if (! $firstsy) { - $firstsy = $t; - } - if ($n2->getAttribute("lng") == $piv) { - $goodsy = $t; - break; - } - } - } - if (! $goodsy) { - $goodsy = $firstsy; - } - - $fullpath = " / " . $goodsy . $fullpath; - - if ($depth == 0) { - $fullpath_html = " / " . $goodsy . "" . $fullpath_html; - } else { - $fullpath_html = " / " . $goodsy . $fullpath_html; - } - } - } - if ($fullpath == "") { - $fullpath = "/"; - $fullpath_html = " / "; - } - $fp = $root->appendchild($ret->createElement("fullpath")); - $fp->appendChild($ret->createTextNode($fullpath)); - - $fp = $root->appendchild($ret->createElement("fullpath_html")); - $fp->appendChild($ret->createTextNode($fullpath_html)); - - $n = $root->appendchild($ret->createElement("hits")); - $n->appendChild($ret->createTextNode('')); - - $n = $root->appendchild($ret->createElement("allhits")); - $n->appendChild($ret->createTextNode('')); - } - } - } catch (\Exception $e) { - - } - } - - return $ret; - } - - public function killTermXml(Application $app, Request $request) - { - $ret = new \DOMDocument("1.0", "UTF-8"); - $ret->preserveWhiteSpace = false; - - $root = $ret->appendChild($ret->createElement("result")); - $root->appendChild($ret->createCDATASection(var_export([ - 'bid' => $request->get('bid'), - 'id' => $request->get('id'), - 'piv' => $request->get('piv'), - 'typ' => $request->get('typ'), - ], true))); - - $refresh_list = $root->appendChild($ret->createElement("refresh_list")); - - if (null === $bid = $request->get("bid")) { - return new Response('Missing bid parameter', 400); - } - - try { - /** @var \databox $databox */ - $databox = $app['phraseanet.appbox']->get_databox((int) $bid); - - if ($request->get('typ') == "CT") { - $xqroot = "cterms"; - $dom = $databox->get_dom_cterms(); - } else { - $xqroot = "thesaurus"; - $dom = $databox->get_dom_thesaurus(); - } - - if ($dom) { - $xpath = new \DOMXPath($dom); - $q = "/$xqroot//te[@id='" . $request->get('id') . "']"; - - /** @var \DOMElement $te */ - $te = $xpath->query($q)->item(0); - if ($te) { - $refrid = $te->parentNode->getAttribute("id"); - - $sy_evt_parm = $this->buildSynonymsFromTe($te); // to pass as event parameter - - $parent = $te->parentNode; - $parent->removeChild($te); - - if ($request->get('typ') == "CT") { - $databox->saveCterms($dom); - - /** @var \DOMElement $r */ - $r = $refresh_list->appendChild($ret->createElement("refresh")); - $r->setAttribute("type", "CT"); - $r->setAttribute("id", $refrid); - - } else { - - $databox->saveThesaurus($dom); - - /** @var EventDispatcherInterface $dispatcher */ - $dispatcher = $app['dispatcher']; - $dispatcher->dispatch( - PhraseaEvents::THESAURUS_CONCEPT_DELETED, - new ThesaurusEvent\ConceptDeleted($databox, $refrid, $sy_evt_parm) - ); - - $this->reindexAll($databox); - - /** @var \DOMElement $r */ - $r = $refresh_list->appendChild($ret->createElement("refresh")); - $r->setAttribute("type", "TH"); - if ($refrid) { - $r->setAttribute("id", $refrid); - } else { - $r->setAttribute("id", "T"); - } - } - - $ret2 = $this->getXMLTerm($app, $bid, $parent->getAttribute("id"), $request->get('typ'), $request->get('piv'), null, null, '1', null); - - if ($sl = $ret2->getElementsByTagName("sy_list")->item(0)) { - $ret->importNode($sl, true); - } - } - } - } catch (\Exception $e) { - - } - - return new Response($ret->saveXML(), 200, ['Content-Type' => 'text/xml']); - } - - public function newSynonymXml(Application $app, Request $request) - { - $ret = new \DOMDocument("1.0", "UTF-8"); - $ret->preserveWhiteSpace = false; - - $root = $ret->appendChild($ret->createElement("result")); - $root->appendChild($ret->createCDATASection(var_export([ - "bid" => $request->get('bid'), - "pid" => $request->get('pid'), - "piv" => $request->get('piv'), - "sylng" => $request->get('sylng'), - "t" => $request->get('t'), - "k" => $request->get('k'), - ], true))); - - $refresh_list = $root->appendChild($ret->createElement("refresh_list")); - - if (null === $bid = $request->get("bid")) { - return new Response('Missing bid parameter', 400); - } - - try { - /** @var \databox $databox */ - $databox = $app['phraseanet.appbox']->get_databox((int) $bid); - $domth = $databox->get_dom_thesaurus(); - - if ($domth) { - $xpathth = new \DOMXPath($domth); - if ($bid === "T") { - $q = "/thesaurus"; - } else { - $q = "/thesaurus//te[@id='" . $request->get('pid') . "']"; - } - - /** @var \DOMElement $te */ - $te = $xpathth->query($q)->item(0); - if ($te) { - $tenextid = (int) $te->getAttribute("nextid"); - $te->setAttribute("nextid", $tenextid + 1); - - /** @var \DOMElement $sy */ - $sy = $te->appendChild($domth->createElement("sy")); - $syid = $te->getAttribute("id") . "." . $tenextid; - $sy->setAttribute("id", $syid); - - if ($request->get('sylng')) { - $sy->setAttribute("lng", $request->get('sylng')); - } else { - $sy->setAttribute("lng", ""); - } - - list($v, $k) = $this->splitTermAndContext($request->get('t')); - - $k = trim($k) . trim($request->get('k')); - $w = $app['unicode']->remove_indexer_chars($v); - - if ($k) { - $v .= " (" . $k . ")"; - } - - $k = $app['unicode']->remove_indexer_chars($k); - - $sy->setAttribute("v", $v); - $sy->setAttribute("w", $w); - - if ($k) { - $sy->setAttribute("k", $k); - } - - $databox->saveThesaurus($domth); - - /** @var EventDispatcherInterface $dispatcher */ - $dispatcher = $app['dispatcher']; - $dispatcher->dispatch( - PhraseaEvents::THESAURUS_SYNONYM_ADDED, - new ThesaurusEvent\ItemAdded($databox, $syid) - ); - - $this->reindexAll($databox); - - /** @var \DOMElement $r */ - $r = $refresh_list->appendChild($ret->createElement("refresh")); - $r->setAttribute("type", "TH"); - $pid = $te->parentNode->getAttribute("id"); - - if ($pid == "") { - $pid = "T"; - } - - $r->setAttribute("id", $pid); - } - } - } catch (\Exception $e) { - - } - - return new Response($ret->saveXML(), 200, ['Content-Type' => 'text/xml']); - } - - public function newSpecificTermXml(Application $app, Request $request) - { - $ret = new \DOMDocument("1.0", "UTF-8"); - $ret->preserveWhiteSpace = false; - - $root = $ret->appendChild($ret->createElement("result")); - $root->appendChild($ret->createCDATASection(var_export([ - "bid" => $request->get('bid'), - "pid" => $request->get('pid'), - "t" => $request->get('t'), - "k" => $request->get('k'), - "sylng" => $request->get('sylng'), - "reindex" => $request->get('reindex'), - ], true))); - - $refresh_list = $root->appendChild($ret->createElement("refresh_list")); - - if (null === $bid = $request->get("bid")) { - return new Response('Missing bid parameter', 400); - } - - try { - /** @var \databox $databox */ - $databox = $app['phraseanet.appbox']->get_databox((int) $bid); - $domth = $databox->get_dom_thesaurus(); - - if ($domth) { - $xpathth = new \DOMXPath($domth); - - if ($request->get('pid') === "T") { - $q = "/thesaurus"; - } else { - $q = "/thesaurus//te[@id='" . $request->get('pid') . "']"; - } - - /** @var \DOMElement $parentnode */ - $parentnode = $xpathth->query($q)->item(0); - if ($parentnode) { - $nid = $parentnode->getAttribute("nextid"); - $parentnode->setAttribute("nextid", (int) $nid + 1); - /** @var \DOMElement $te */ - $te = $parentnode->appendChild($domth->createElement("te")); - - if ($request->get('pid') === "T") { - $te->setAttribute("id", $teid = "T" . ($nid)); - } else { - $te->setAttribute("id", $teid = ($request->get('pid') . "." . $nid)); - } - - $te->setAttribute("nextid", "1"); - /** @var \DOMElement $sy */ - $sy = $te->appendChild($domth->createElement("sy")); - $syid = $teid . ".0"; - $sy->setAttribute("id", $syid); - - if ($request->get('sylng')) { - $sy->setAttribute("lng", $request->get('sylng')); - } else { - $sy->setAttribute("lng", ""); - } - - list($v, $k) = $this->splitTermAndContext($request->get('t')); - $k = trim($k) . trim($request->get('k')); - - $w = $app['unicode']->remove_indexer_chars($v); - - if ($k) { - $v .= " (" . $k . ")"; - } - - $k = $app['unicode']->remove_indexer_chars($k); - - $sy->setAttribute("v", $v); - $sy->setAttribute("w", $w); - - if ($k) { - $sy->setAttribute("k", $k); - } - - $databox->saveThesaurus($domth); - - /** @var EventDispatcherInterface $dispatcher */ - $dispatcher = $app['dispatcher']; - $dispatcher->dispatch( - PhraseaEvents::THESAURUS_CONCEPT_ADDED, - new ThesaurusEvent\ItemAdded($databox, $syid) - ); - - if ($request->get('reindex') == "1") { - $this->reindexAll($databox); - } - - /** @var \DOMElement $r */ - $r = $refresh_list->appendChild($ret->createElement("refresh")); - $r->setAttribute("type", "TH"); - $r->setAttribute("id", $request->get('pid')); - } - } - } catch (\Exception $e) { - - } - - return new Response($ret->saveXML(), 200, ['Content-Type' => 'text/xml']); - } - - public function openBranchesXml(Application $app, Request $request) - { - $ret = new \DOMDocument("1.0", "UTF-8"); - $ret->preserveWhiteSpace = false; - - $root = $ret->appendChild($ret->createElement("result")); - $root->appendChild($ret->createCDATASection(var_export([ - "bid" => $request->get('bid'), - "id" => $request->get('id'), - "typ" => $request->get('typ'), - "t" => $request->get('t'), - "method" => $request->get('method'), - ], true))); - - /** @var \DOMElement $html */ - $html = $root->appendChild($ret->createElement("html")); - - if (null === $bid = $request->get("bid")) { - return new Response('Missing bid parameter', 400); - } - - try { - /** @var \databox $databox */ - $databox = $app['phraseanet.appbox']->get_databox((int) $bid); - if ($request->get('typ') == "CT") { - $xqroot = "cterms"; - $dom = $databox->get_dom_cterms(); - } else { - $xqroot = "thesaurus"; - $dom = $databox->get_dom_thesaurus(); - } - - if ($dom) { - $xpath = new \DOMXPath($dom); - - if ($request->get('id') == "T") { - $q = "/thesaurus"; - } elseif ($request->get('id') == "C") { - $q = "/cterms"; - } else { - $q = "/$xqroot//te[@id='" . $request->get('id') . "']"; - } - - /** @var \DOMElement $znode */ - $znode = $xpath->query($q)->item(0); - if ($znode) { - $q2 = "//sy"; - if ($request->get('t')) { - $t = $this->splitTermAndContext($request->get('t')); - switch ($request->get('method')) { - case "begins": - $q2 = "starts-with(@w, '" . \thesaurus::xquery_escape($app['unicode']->remove_indexer_chars($t[0])) . "')"; - if ($t[1]) { - $q2 .= " and starts-with(@k, '" . \thesaurus::xquery_escape($app['unicode']->remove_indexer_chars($t[1])) . "')"; - } - break; - case "contains": - $q2 = "contains(@w, '" . \thesaurus::xquery_escape($app['unicode']->remove_indexer_chars($t[0])) . "')"; - if ($t[1]) { - $q2 .= " and contains(@k, '" . \thesaurus::xquery_escape($app['unicode']->remove_indexer_chars($t[1])) . "')"; - } - break; - case "equal": - default: - $q2 = "(@w='" . \thesaurus::xquery_escape($app['unicode']->remove_indexer_chars($t[0])) . "')"; - if ($t[1]) { - $q2 .= " and (@k='" . \thesaurus::xquery_escape($app['unicode']->remove_indexer_chars($t[1])) . "')"; - } - break; - } - $q2 = "//sy[" . $q2 . "]"; - } - - $nodes = $xpath->query($q2, $znode); - for ($i = 0; $i < $nodes->length; $i ++) { - for ($n = $nodes->item($i)->parentNode; $n && $n->nodeType == XML_ELEMENT_NODE && $n->nodeName == "te"; $n = $n->parentNode) { - /** @var \DOMElement $n */ - $n->setAttribute("open", "1"); - } - } - - $this->getBranchHTML($request->get('typ'), $znode, $ret, $html, 0); - } - } - } catch (\Exception $e) { - - } - - return new Response($ret->saveXML(), 200, ['Content-Type' => 'text/xml']); - } - - private function getBranchHTML($type, \DOMElement $srcnode, \DOMDocument $dstdom, \DOMElement $dstnode, $depth) - { - $allsy = ""; - $nts = 0; - for ($n = $srcnode->firstChild; $n; $n = $n->nextSibling) { - if ($n->nodeType == XML_ELEMENT_NODE) { - if ($n->nodeName == "te") { - $nts ++; - if ($n->getAttribute("open")) { - $id = $n->getAttribute("id"); - /** @var \DOMElement $div_the */ - $div_the = $dstnode->appendChild($dstdom->createElement("div")); - $div_the->setAttribute("id", "THE_" . $id); - $div_the->setAttribute("class", "s_"); - - /** @var \DOMElement $u */ - $u = $div_the->appendChild($dstdom->createElement("u")); - $u->setAttribute("id", "THP_" . $id); - - /** @var \DOMElement $div_thb */ - $div_thb = $dstnode->appendChild($dstdom->createElement("div")); - $div_thb->setAttribute("id", "THB_" . $id); - - $t = $this->getBranchHTML($type, $n, $dstdom, $div_thb, $depth + 1); - if ($t["nts"] == 0) { - $u->setAttribute("class", "nots"); - $div_thb->setAttribute("class", "ob"); - } else { - $u->appendChild($dstdom->createTextNode("...")); - $div_thb->setAttribute("class", "hb"); - } - - $div_the->appendChild($dstdom->createTextNode($t["allsy"])); - } - } elseif ($n->nodeName == "sy") { - $t = $n->getAttribute("v"); - $allsy .= ( $allsy ? " ; " : "") . $t; - } - } - } - if ($allsy == "") { - if ($type == "TH") { - $allsy = "THESAURUS"; - } elseif ($type == "CT") { - $allsy = $srcnode->getAttribute("field"); - } - } - - return ["allsy" => $allsy, "nts" => $nts]; - } - - public function RejectXml(Application $app, Request $request) - { - $ret = new \DOMDocument("1.0", "UTF-8"); - $ret->preserveWhiteSpace = false; - - $root = $ret->appendChild($ret->createElement("result")); - $root->appendChild($ret->createCDATASection(var_export([ - 'bid' => $request->get('bid'), - 'id' => $request->get('id'), - 'piv' => $request->get('piv'), - ], true))); - - $refresh_list = $root->appendChild($ret->createElement("refresh_list")); - - if (null === $bid = $request->get("bid")) { - return new Response('Missing bid parameter', 400); - } - - try { - /** @var \databox $databox */ - $databox = $app['phraseanet.appbox']->get_databox((int) $bid); - $connbas = $databox->get_connection(); - - $dom = $databox->get_dom_cterms(); - - if ($dom) { - $xpath = new \DOMXPath($dom); - $q = "/cterms//te[@id='" . $request->get('id') . "']"; - - /** @var \DOMElement $te */ - $te = $xpath->query($q)->item(0); - if ($te) { - $this->doRejectBranch($connbas, $te); - - $databox->saveCterms($dom); - - /** @var \DOMElement $r */ - $r = $refresh_list->appendChild($ret->createElement("refresh")); - $r->setAttribute("id", $te->parentNode->getAttribute("id")); - $r->setAttribute("type", "CT"); - } - } - } catch (\Exception $e) { - - } - - return new Response($ret->saveXML(), 200, ['Content-Type' => 'text/xml']); - } - - private function doRejectBranch(Connection $connbas, \DOMElement $node) - { - if (strlen($oldid = $node->getAttribute("id")) > 1) { - $node->setAttribute("id", $newid = ("R" . substr($oldid, 1))); - } - for ($n = $node->firstChild; $n; $n = $n->nextSibling) { - if ($n->nodeType == XML_ELEMENT_NODE) { - $this->doRejectBranch($connbas, $n); - } - } - } - - public function searchCandidateXml(Application $app, Request $request) - { - if (null === $request->get("bid")) { - return new Response('Missing bid parameter', 400); - } - - $ret = $this->doSearchCandidate($app, $request->get('bid'), $request->get('pid'), $request->get('t'), $request->get('k'), $request->get('piv')); - - return new Response($ret->saveXML(), 200, ['Content-Type' => 'text/xml']); - } - - private function doSearchCandidate(Application $app, $bid, $pid, $t, $k, $piv) - { - $ret = new \DOMDocument("1.0", "UTF-8"); - $ret->preserveWhiteSpace = false; - - $root = $ret->appendChild($ret->createElement("result")); - $root->appendChild($ret->createCDATASection(var_export([ - "bid" => $bid, - "pid" => $pid, - "t" => $t, - "k" => $k, - "piv" => $piv, - ], true))); - - $ctlist = $root->appendChild($ret->createElement("candidates_list")); - - try { - /** @var \databox $databox */ - $databox = $app['phraseanet.appbox']->get_databox((int) $bid); - - $domstruct = $databox->get_dom_structure(); - $domth = $databox->get_dom_thesaurus(); - $domct = $databox->get_dom_cterms(); - - if ($domstruct && $domth && $domct) { - $xpathth = new \DOMXPath($domth); - $xpathct = new \DOMXPath($domct); - - // on cherche les champs d'ou peut provenir un candidat, en fct de l'endroit oe on veut inserer le nouveau terme - $fields = array(); - $xpathstruct = new \DOMXPath($domstruct); - $nodes = $xpathstruct->query("/record/description/*[@tbranch]"); - for ($i = 0; $i < $nodes->length; $i ++) { - /** @var \DOMElement $node */ - $node = $nodes->item($i); - $fieldname = $node->nodeName; - $tbranch = $node->getAttribute("tbranch"); - if ($pid != "") { - $q = "(" . $tbranch . ")/descendant-or-self::te[@id='" . $pid . "']"; - } else { - $q = "(" . $tbranch . ")/descendant-or-self::te[not(@id)]"; - } - - $fields[$fieldname] = [ - "name" => $fieldname, - "tbranch" => $tbranch, - "cid" => null, - "sourceok" => false - ]; - - if (! $tbranch) { - continue; - } - - $l = $xpathth->query($q)->length; - - if ($l > 0) { - // le pt d'insertion du nvo terme se trouve dans la tbranch du champ, - // donc ce champ peut etre source de candidats - $fields[$fieldname]["sourceok"] = true; - } else { - // le pt d'insertion du nvo terme ne se trouve PAS dans la tbranch du champ, - // donc ce champ ne peut pas etre source de candidats - } - } - // on considere que la source 'deleted' est toujours valide - $fields["[deleted]"] = [ - "name" => $app->trans('thesaurus:: corbeille'), - "tbranch" => null, - "cid" => null, - "sourceok" => true - ]; - - if (count($fields) > 0) { - $q = "@w='" . \thesaurus::xquery_escape($app['unicode']->remove_indexer_chars($t)) . "'"; - if ($k) { - if ($k != "*") { - $q .= " and @k='" . \thesaurus::xquery_escape($app['unicode']->remove_indexer_chars($k)) . "'"; - } - } else { - $q .= " and not(@k)"; - } - $q = "/cterms//te[./sy[$q]]"; - - $nodes = $xpathct->query($q); - // le terme peut etre present dans plusieurs candidats - for ($i = 0; $i < $nodes->length; $i ++) { - // on a trouve le terme dans les candidats, mais en provenance de quel champ ?.. on remonte au champ candidat - /** @var \DOMElement $node */ - $node = $nodes->item($i); - /** @var \DOMElement $n */ - for ($n = $nodes->item($i)->parentNode; $n && $n->parentNode && $n->parentNode->nodeName != "cterms"; $n = $n->parentNode) { - ; - } - if ($n && array_key_exists($f = $n->getAttribute("field"), $fields)) { - $fields[$f]["cid"] = $node->getAttribute("id"); - } - } - } - - foreach ($fields as $kfield => $field) { - if ($field["cid"] === null) { - continue; - } - /** @var \DOMElement $ct */ - $ct = $ctlist->appendChild($ret->createElement("ct")); - $ct->setAttribute("field", $field["name"]); - $ct->setAttribute("sourceok", $field["sourceok"] ? "1" : "0"); - if ($field["cid"] !== null) { - $ct->setAttribute("id", $field["cid"]); - } - } - } - } catch (\Exception $e) { - - } - - return $ret; - } - - - private function splitTermAndContext($word) - { - $term = trim($word); - $context = ""; - if (($po = strpos($term, "(")) !== false) { - if (($pc = strpos($term, ")", $po)) !== false) { - $context = trim(substr($term, $po + 1, $pc - $po - 1)); - $term = trim(substr($term, 0, $po)); - } - } - - return [$term, $context]; - } - - /** - * @param \DOMElement $sy - * @return ThesaurusEvent\SynonymParm|null - * - * helper to build event parameter - */ - private function buildSynonymFromSy(\DOMElement $sy) - { - if($sy->nodeName == 'sy') { - return new ThesaurusEvent\SynonymParm($sy->getAttribute('v'), $sy->getAttribute('lng')); - } - return null; - } - - /** - * @param \DOMElement $te - * @return array|null - * - * helper to build event parameter - */ - private function buildSynonymsFromTe(\DOMElement $te) - { - $ret = array(); - if(strtolower($te->nodeName) == 'te') { - foreach ($te->childNodes as $child) { - if($child->nodeType == XML_ELEMENT_NODE && $child->nodeName == 'sy') { - $ret[] = $this->buildSynonymFromSy($child); - } - } - return $ret; - } - return null; - } }