13 use Symfony\Component\HttpFoundation\Request;
14 use Symfony\Component\HttpFoundation\Response;
23 const NAME =
'multicompare';
32 public function __construct()
34 parent::__construct(self::NAME, [
35 self::TITLE => _(
"Multi-Component Comparison"),
36 self::DEPENDENCIES => [
"browse",
"view"],
38 self::REQUIRES_LOGIN =>
true,
41 $this->uploadDao = $this->
getObject(
'dao.upload');
42 $this->agentDao = $this->
getObject(
'dao.agent');
47 private function createFilePickerMultiTable():
void
49 if ($this->
dbManager->existsTable(
'file_picker_multi')) {
53 "CREATE TABLE file_picker_multi (
54 file_picker_multi_pk serial NOT NULL PRIMARY KEY,
55 user_fk integer NOT NULL,
57 last_access_date date NOT NULL
75 $TreeInfo = $this->
dbManager->getSingleRow(
76 "SELECT ut.*, u.uploadtree_tablename, u.upload_filename
78 JOIN upload u ON u.upload_pk = ut.upload_fk
79 WHERE ut.uploadtree_pk = \$1",
80 [$uploadtree_pk], __METHOD__ .
'.bootstrap'
89 $tableName = $TreeInfo[
'uploadtree_tablename'];
90 if ($tableName !==
'uploadtree') {
91 $specific = $this->
dbManager->getSingleRow(
92 "SELECT lft, rgt, ufile_mode, ufile_name, pfile_fk, parent,
93 uploadtree_pk, upload_fk
94 FROM $tableName WHERE uploadtree_pk = \$1",
95 [$uploadtree_pk], __METHOD__ .
".$tableName"
98 $TreeInfo = array_merge($TreeInfo, $specific);
102 $upload_pk = intval($TreeInfo[
'upload_fk']);
103 $TreeInfo[
'display_name'] = !empty($TreeInfo[
'upload_filename'])
104 ? basename($TreeInfo[
'upload_filename'])
105 : $TreeInfo[
'ufile_name'];
112 $TreeInfo = array_merge($TreeInfo, $agentPks);
113 $TreeInfo[
'agent_pk'] = $TreeInfo[
'nomos_agent_pk'];
127 static $existsCache = [];
130 'nomos_pk' =>
'nomos_ars',
131 'monk_pk' =>
'monk_ars',
132 'ojo_pk' =>
'ojo_ars',
133 'copyright_pk' =>
'copyright_ars',
134 'ecc_pk' =>
'ecc_ars',
139 foreach ($agentDef as $alias => $table) {
140 if (!array_key_exists($table, $existsCache)) {
141 $existsCache[$table] = $this->
dbManager->existsTable($table);
143 if ($existsCache[$table]) {
144 $parts[] =
"(SELECT a.agent_fk FROM $table a"
145 .
" JOIN agent ON agent_pk=a.agent_fk"
146 .
" WHERE a.upload_fk=\$1 AND a.ars_success AND agent_enabled"
147 .
" ORDER BY agent_ts DESC LIMIT 1) AS $alias";
150 $parts[] =
"NULL::integer AS $alias";
155 $stmt = __METHOD__ .
'.' . $existMask;
156 $this->
dbManager->prepare($stmt,
"SELECT " . implode(
",\n", $parts));
157 $res = $this->
dbManager->execute($stmt, [$uploadPk]);
158 $row = $this->
dbManager->fetchArray($res) ?: [];
162 'nomos_agent_pk' => intval($row[
'nomos_pk'] ?? 0),
163 'monk_agent_pk' => intval($row[
'monk_pk'] ?? 0),
164 'ojo_agent_pk' => intval($row[
'ojo_pk'] ?? 0),
165 'copyright_agent_pk' => intval($row[
'copyright_pk'] ?? 0),
166 'ecc_agent_pk' => intval($row[
'ecc_pk'] ?? 0),
177 foreach ($items as $idx => $itemPk) {
179 "SELECT u.uploadtree_tablename
181 JOIN upload u ON u.upload_pk = ut.upload_fk
182 WHERE ut.uploadtree_pk = \$1",
183 [$itemPk], __METHOD__ .
'.table'
189 $children = GetNonArtifactChildren($itemPk, $row[
'uploadtree_tablename']);
201 private function AddDataStr(array $treeInfo, array &$children,
string $mode): void
203 if ($mode ===
'license') {
204 $licAgentPks = array_values(array_filter([
205 $treeInfo[
'nomos_agent_pk'],
206 $treeInfo[
'monk_agent_pk'],
207 $treeInfo[
'ojo_agent_pk'],
212 if (!empty($licAgentPks)) {
213 $pfileUniq = array_values(array_unique(array_filter(
214 array_map(
function ($c) {
215 return intval($c[
'pfile_fk'] ?? 0);
218 if (!empty($pfileUniq)) {
221 foreach ($licAgentPks as $apk) {
223 $agentPh[] =
'$' . count($params);
226 foreach ($pfileUniq as $pf) {
228 $pfilePh[] =
'$' . count($params);
230 $agentIn = implode(
',', $agentPh);
231 $pfileIn = implode(
',', $pfilePh);
232 $stmt = __METHOD__ .
".licbatch." . implode(
'_', $licAgentPks) .
".p" . count($pfileUniq);
234 "SELECT lf.pfile_fk, lr.rf_pk, lr.rf_shortname
235 FROM ONLY license_ref lr, license_file lf
236 WHERE lf.rf_fk = lr.rf_pk
237 AND lf.agent_fk IN ($agentIn)
238 AND lf.pfile_fk IN ($pfileIn)"
240 $res = $this->
dbManager->execute($stmt, $params);
241 while ($row = $this->
dbManager->fetchArray($res)) {
242 $pf = intval($row[
'pfile_fk']);
244 $licByPfile[$pf][intval($row[
'rf_pk'])] = $row[
'rf_shortname'];
250 foreach ($children as &$child) {
251 $pf = intval($child[
'pfile_fk'] ?? 0);
253 $dataarray = $licByPfile[$pf] ?? [];
257 foreach ($licAgentPks as $agentPk) {
259 $treeInfo[
'uploadtree_tablename']);
262 $child[
'dataarray'] = $dataarray;
263 $child[
'datastr'] = implode(
", ", $dataarray);
264 if (empty($child[
'datastr'])) {
265 $child[
'datastr'] =
"No_license_found";
266 $child[
'dataarray'] = [
"No_license_found" =>
"No_license_found"];
271 } elseif ($mode ===
'copyright' || $mode ===
'ecc') {
272 $table = ($mode ===
'ecc') ?
'ecc' :
'copyright';
273 $agentPk = ($mode ===
'ecc')
274 ? $treeInfo[
'ecc_agent_pk']
275 : $treeInfo[
'copyright_agent_pk'];
280 $pfileUniq = array_values(array_unique(array_filter(
281 array_map(
function ($c) {
282 return intval($c[
'pfile_fk'] ?? 0);
285 if (!empty($pfileUniq)) {
286 $params = [intval($agentPk)];
288 foreach ($pfileUniq as $pf) {
290 $pfilePh[] =
'$' . count($params);
292 $pfileIn = implode(
',', $pfilePh);
293 $stmt = __METHOD__ .
".$table.batch.p" . count($pfileUniq);
295 "SELECT pfile_fk, content FROM $table
296 WHERE agent_fk=\$1 AND pfile_fk IN ($pfileIn)
297 AND content IS NOT NULL AND content!=''
298 ORDER BY pfile_fk, content"
300 $res = $this->
dbManager->execute($stmt, $params);
301 while ($row = $this->
dbManager->fetchArray($res)) {
302 $pf = intval($row[
'pfile_fk']);
303 $dataByPfile[$pf][$row[
'content']] = $row[
'content'];
309 foreach ($children as &$child) {
310 $pf = intval($child[
'pfile_fk'] ?? 0);
311 $dataarray = $dataByPfile[$pf] ?? [];
312 $child[
'dataarray'] = $dataarray;
313 $child[
'datastr'] = implode(
", ", $dataarray);
321 private function FilterN(
string $filter, array &$Master,
int $N): void
353 foreach ($Master as $key => $row) {
355 foreach ($row as $child) {
356 if (!empty($child) && !empty($child[
'pfile_fk'])) {
357 $pfiles[] = $child[
'pfile_fk'];
360 if (count($pfiles) === $N && count(array_unique($pfiles)) === 1) {
361 unset($Master[$key]);
372 foreach ($Master as $key => $row) {
373 $present = array_filter($row, fn($c) => !empty($c));
374 if (count($present) !== $N) {
377 if (count(array_unique(array_column($present,
'ufile_name'))) === 1 &&
378 count(array_unique(array_column($present,
'datastr'))) === 1) {
379 unset($Master[$key]);
389 foreach ($Master as $key => $row) {
390 $present = array_filter($row, fn($c) => !empty($c));
391 if (count($present) !== $N) {
394 if (count(array_unique(array_column($present,
'fuzzyname'))) === 1 &&
395 count(array_unique(array_column($present,
'datastr'))) === 1) {
396 unset($Master[$key]);
408 foreach ($Master as $key => $row) {
409 $present = array_filter($row, fn($c) => !empty($c));
410 if (empty($present)) {
414 foreach ($present as $child) {
415 $ds = $child[
'datastr'];
416 if ($ds !==
'' && $ds !==
'No_license_found') {
422 unset($Master[$key]);
432 foreach ($Master as $key => $row) {
433 $present = array_filter($row, fn($c) => !empty($c));
434 if (count($present) !== $N) {
437 if (count(array_unique(array_column($present,
'datastr'))) === 1) {
438 unset($Master[$key]);
448 private function ChildElt(array $child,
int $colIdx, array $row,
449 array $treeInfoArray,
string $mode,
int $baseline): string
451 $dataarray = $child[
'dataarray'] ?? [];
455 $bIdx = $baseline - 1;
456 if (isset($row[$bIdx]) && !empty($row[$bIdx][
'dataarray'])) {
457 $refKeys = array_keys($row[$bIdx][
'dataarray']);
460 foreach ($row as $c => $other) {
461 if ($c === $colIdx || empty($other) || empty($other[
'dataarray'])) {
464 foreach (array_keys($other[
'dataarray']) as $k) {
468 $refKeys = array_unique($refKeys);
470 $refKeySet = array_flip($refKeys);
473 foreach ($dataarray as $k => $val) {
474 $missing = !empty($refKeys) && !isset($refKeySet[$k]);
476 $badges[] =
"<span class='badge badge-pill'"
477 .
" style='background-color:#ffd6cc;color:#333;font-weight:normal'>"
478 . htmlspecialchars($val) .
"</span>";
480 $badges[] =
"<span class='badge badge-pill badge-light border'>"
481 . htmlspecialchars($val) .
"</span>";
484 $dataStr = implode(
" ", $badges);
486 $ColStr =
"<td class='align-top py-1' id='c{$child['uploadtree_pk']}'>";
487 $ColStr .= $child[
'linkurl'] ?? htmlspecialchars($child[
'ufile_name']);
488 if (!empty($dataStr)) {
489 $ColStr .=
"<div class='mt-1 ml-1'>$dataStr</div>";
493 $agentPk = $treeInfoArray[$colIdx][
'agent_pk'] ?? 0;
494 $uploadtree_tablename = $treeInfoArray[$colIdx][
'uploadtree_tablename'] ??
'uploadtree';
495 $ColStr .=
"<td class='align-top py-1' style='white-space:nowrap'>";
496 $uniqueTagArray = [];
498 $child[
'upload_fk'], $child[
'uploadtree_pk'],
499 $agentPk, $child[
'pfile_fk'],
true,
500 $uniqueTagArray, $uploadtree_tablename
511 string $mode,
int $baseline,
string $view): string
513 $N = count($treeInfoArray);
515 if ($view ===
'matrix') {
516 return $this->FileMatrixRows($Master, $N);
520 foreach ($Master as $row) {
522 for ($c = 0; $c < $N; $c++) {
524 $parts[] =
"<td class='border-left border-success p-0' style='width:3px'></td>";
526 if (empty($row[$c])) {
527 $parts[] =
"<td class='text-muted py-1'>—</td><td></td>";
529 $parts[] = $this->
ChildElt($row[$c], $c, $row, $treeInfoArray, $mode, $baseline);
534 return implode(
"", $parts);
537 private function FileMatrixRows(array $Master,
int $N): string
540 foreach ($Master as $row) {
543 for ($c = 0; $c < $N && empty($firstName); $c++) {
544 if (!empty($row[$c])) {
545 $firstName = htmlspecialchars($row[$c][
'ufile_name']);
548 $parts[] =
"<td class='py-1'>$firstName</td>";
552 for ($c = 0; $c < $N; $c++) {
553 if (!empty($row[$c]) && !empty($row[$c][
'pfile_fk'])) {
554 $pfiles[] = $row[$c][
'pfile_fk'];
557 $allSameHash = count($pfiles) >= 2 && count(array_unique($pfiles)) === 1;
559 for ($c = 0; $c < $N; $c++) {
560 if (!empty($row[$c])) {
562 $parts[] = $allSameHash
563 ?
"<td class='text-center py-1'><span class='badge badge-light border text-muted' title='identical'>✔</span></td>"
564 :
"<td class='text-center py-1'><span class='badge badge-success' title='differs'>✔</span></td>";
566 $parts[] =
"<td class='text-center py-1 text-muted'>—</td>";
571 return implode(
"", $parts);
582 array $treeInfoArray,
string $mode): array
584 $uniqueFiles = array_fill(0, $N, 0);
585 $missingFiles = array_fill(0, $N, 0);
586 $uniqueEntries = array_fill(0, $N, []);
588 foreach ($Master as $row) {
591 for ($c = 0; $c < $N; $c++) {
592 if (!empty($row[$c])) {
593 $presentSet[$c] =
true;
596 $nPresent = count($presentSet);
598 for ($c = 0; $c < $N; $c++) {
599 if (!isset($presentSet[$c])) {
603 if ($nPresent === 1) {
604 $uniqueFiles[key($presentSet)]++;
609 foreach ($presentSet as $c => $_) {
610 foreach ($row[$c][
'dataarray'] ?? [] as $k => $val) {
611 $keyColCount[$k] = ($keyColCount[$k] ?? 0) + 1;
616 foreach ($presentSet as $c => $_) {
617 foreach ($row[$c][
'dataarray'] ?? [] as $k => $val) {
618 if ($keyColCount[$k] === 1) {
619 $uniqueEntries[$c][$k] = $val;
626 for ($c = 0; $c < $N; $c++) {
627 $uniqList = array_unique($uniqueEntries[$c]);
628 $uniqCount = count($uniqList);
629 $shown = array_map(
'htmlspecialchars', array_slice($uniqList, 0, 10));
631 'name' => htmlspecialchars($treeInfoArray[$c][
'display_name'] ?? (
"Col " . ($c + 1))),
632 'uniqueFiles' => $uniqueFiles[$c],
633 'missingFiles' => $missingFiles[$c],
634 'uniqueEntries' => $shown,
635 'moreCount' =>
max(0, $uniqCount - 10),
645 private function buildHistData(array $items, array $treeInfoArray,
string $mode): array
650 for ($c = 0; $c < $N; $c++) {
651 $treeInfo = $treeInfoArray[$c];
653 if ($mode ===
'license') {
654 $licAgentPks = array_values(array_filter([
655 $treeInfo[
'nomos_agent_pk'],
656 $treeInfo[
'monk_agent_pk'],
657 $treeInfo[
'ojo_agent_pk'],
659 if (empty($licAgentPks)) {
662 $lft = intval($treeInfo[
'lft']);
663 $rgt = intval($treeInfo[
'rgt']);
664 $upPk = intval($treeInfo[
'upload_fk']);
665 $table = $treeInfo[
'uploadtree_tablename'];
667 $params = [$lft, $rgt];
669 if ($table ===
'uploadtree_a' || $table ===
'uploadtree') {
671 $upClause =
"upload_fk=\$" . count($params) .
" AND ";
674 $agentPlaceholders = [];
675 foreach ($licAgentPks as $apk) {
677 $agentPlaceholders[] =
"\$" . count($params);
679 $agentIn = implode(
",", $agentPlaceholders);
680 $sql =
"SELECT rf_shortname AS entry, count(DISTINCT pfile_fk) AS cnt
681 FROM ONLY license_ref, license_file,
682 (SELECT DISTINCT(pfile_fk) AS PF FROM $table
683 WHERE {$upClause}{$table}.lft BETWEEN \$1 AND \$2) AS SS
684 WHERE PF=pfile_fk AND agent_fk IN ($agentIn) AND rf_fk=rf_pk
685 GROUP BY rf_shortname ORDER BY cnt DESC";
686 $stmt = __METHOD__ .
".lic.$table.$c." . implode(
"_", $licAgentPks);
688 $res = $this->
dbManager->execute($stmt, $params);
689 while ($row = $this->
dbManager->fetchArray($res)) {
690 $histData[$row[
'entry']][$c] = (int)$row[
'cnt'];
694 } elseif ($mode ===
'copyright' || $mode ===
'ecc') {
695 $table = ($mode ===
'ecc') ?
'ecc' :
'copyright';
696 $agentPk = ($mode ===
'ecc')
697 ? intval($treeInfo[
'ecc_agent_pk'])
698 : intval($treeInfo[
'copyright_agent_pk']);
702 $lft = intval($treeInfo[
'lft']);
703 $rgt = intval($treeInfo[
'rgt']);
704 $upPk = intval($treeInfo[
'upload_fk']);
705 $utbl = $treeInfo[
'uploadtree_tablename'];
707 $params = [$agentPk, $lft, $rgt];
709 if ($utbl ===
'uploadtree_a' || $utbl ===
'uploadtree') {
711 $upClause =
"AND UT.upload_fk=\$" . count($params);
713 $sql =
"SELECT C.content AS entry, count(*) AS cnt
715 INNER JOIN $utbl UT ON C.pfile_fk = UT.pfile_fk
717 AND C.content IS NOT NULL AND C.content!=''
718 AND UT.lft BETWEEN \$2 AND \$3
720 GROUP BY C.content ORDER BY cnt DESC LIMIT 100";
721 $stmt = __METHOD__ .
".$mode.$utbl.$c";
723 $res = $this->
dbManager->execute($stmt, $params);
724 while ($row = $this->
dbManager->fetchArray($res)) {
725 $histData[$row[
'entry']][$c] = (int)$row[
'cnt'];
732 uasort($histData,
function (array $a, array $b):
int {
733 return array_sum($b) - array_sum($a);
740 protected function handle(Request $request): Response
742 $this->createFilePickerMultiTable();
744 $itemsRaw = $request->get(
'items',
'');
746 if (!empty($itemsRaw)) {
747 $items = array_values(array_unique(array_filter(
748 array_map(
'intval', explode(
',', $itemsRaw)),
753 $filter = $request->get(
'filter',
'samehash');
754 $mode = $request->get(
'mode',
'license');
755 $view = $request->get(
'view',
'diff');
756 $baseline = (int)($request->get(
'baseline', 0));
757 $updcache = (int)($request->get(
'updcache', 0));
759 if (!in_array($mode, [
'license',
'copyright',
'ecc'])) {
762 if (!in_array($view, [
'diff',
'matrix'])) {
766 if (count($items) < 2) {
767 return $this->flushContent(
768 "<h3>" . _(
"Please select at least 2 components to compare.") .
"</h3>"
769 .
"<p><a href='javascript:history.back()'>" . _(
"Go back") .
"</a></p>"
773 foreach ($items as $idx => $itemPk) {
777 $permRow = $this->
dbManager->getSingleRow(
778 "SELECT upload_fk FROM uploadtree WHERE uploadtree_pk = \$1",
779 [$itemPk], __METHOD__ .
'.perm'
781 if (!$permRow || !$this->uploadDao->isAccessible($permRow[
'upload_fk'], Auth::getGroupId())) {
782 return $this->flushContent(
783 "<h2>" . _(
"Permission Denied") .
" (item " . ($idx + 1) .
")</h2>"
792 $freezeCol = (int)($request->get(
'freeze', 0));
793 $frozenItem = (int)($request->get(
'itemf', 0));
794 $clickedCol = (int)($request->get(
'col', -1));
795 if ($freezeCol > 0 && $frozenItem > 0 && ($freezeCol - 1) !== $clickedCol) {
796 $colIdx0 = $freezeCol - 1;
797 if (isset($items[$colIdx0])) {
798 $frozenUploadFk = $this->
dbManager->getSingleRow(
799 "SELECT upload_fk FROM uploadtree WHERE uploadtree_pk = \$1",
800 [$frozenItem], __METHOD__ .
'.freeze'
802 if ($frozenUploadFk && $this->uploadDao->isAccessible($frozenUploadFk, Auth::getGroupId())) {
803 $items[$colIdx0] = $frozenItem;
810 $cacheKey =
"?mod=" . self::NAME
811 .
"&items=" . implode(
",", $items)
812 .
"&filter=$filter&mode=$mode&view=$view&baseline=$baseline"
813 . ($freezeCol > 0 ?
"&freeze=$freezeCol&itemf=$frozenItem" :
"");
819 if (!empty($cached)) {
830 foreach ($items as $c => $itemPk) {
832 if (empty($treeInfo)) {
833 return $this->flushContent(
834 "<div class='alert alert-danger'>"
835 . sprintf(_(
"Could not load data for item %d. The item may have been deleted."), $itemPk)
840 if ($mode ===
'license') {
841 $agentPk = $treeInfo[
'nomos_agent_pk'] ?: $treeInfo[
'monk_agent_pk'] ?: $treeInfo[
'ojo_agent_pk'];
842 if ($agentPk == 0 && empty($ErrMsg)) {
844 _(
"No license scan data for component %d (%s). Schedule a nomos, monk, or ojo scan first."),
845 $c + 1, htmlspecialchars($treeInfo[
'display_name'])
848 } elseif ($mode ===
'copyright') {
849 $agentPk = $treeInfo[
'copyright_agent_pk'];
850 } elseif ($mode ===
'ecc') {
851 $agentPk = $treeInfo[
'ecc_agent_pk'];
853 $treeInfo[
'agent_pk'] = $agentPk;
854 $agentPks[$c] = $agentPk;
855 $treeInfoArray[$c] = $treeInfo;
858 if (!empty($ErrMsg)) {
859 return $this->flushContent(
"<div class='alert alert-warning'>$ErrMsg</div>");
863 foreach ($items as $c => $itemPk) {
864 $children = GetNonArtifactChildren($itemPk, $treeInfoArray[$c][
'uploadtree_tablename']);
866 $this->
AddDataStr($treeInfoArray[$c], $children, $mode);
867 $allChildren[$c] = $children;
872 FileListN($Master, $agentPks, $filter, self::NAME, $items, $mode, $baseline);
880 if ($view ===
'matrix') {
881 $tableRows = $this->
ItemComparisonRows($Master, $treeInfoArray, $mode, $baseline, $view);
882 $this->FilterN($filter, $Master, $N);
884 $this->FilterN($filter, $Master, $N);
885 $tableRows = $this->
ItemComparisonRows($Master, $treeInfoArray, $mode, $baseline, $view);
890 for ($c = 0; $c < $N; $c++) {
891 $tableName = $treeInfoArray[$c][
'uploadtree_tablename'] ??
'uploadtree';
892 $path =
Dir2Path($items[$c], $tableName);
893 $pathBanners[] =
Dir2BrowseDiffN($path, $filter, $c, self::NAME, $items, $mode, $baseline);
897 $histData = $this->
buildHistData($items, $treeInfoArray, $mode);
898 $colNames = array_map(
899 fn($ti) => htmlspecialchars($ti[
'display_name'] ??
''),
902 $modeLabel = $mode ===
'license' ? _(
"License")
903 : ($mode ===
'ecc' ? _(
"ECC") : _(
"Copyright"));
907 'none' => _(
"0. Remove nothing"),
908 'samehash' => _(
"1. Remove identical files (same hash)"),
909 'samelic' => _(
"2. Remove files with unchanged data"),
910 'samelicfuzzy' => _(
"2b. Same as 2 but fuzzy name match"),
911 'nolics' => _(
"3. Same as 2b + remove no-license files"),
912 'allsame' => _(
"4. Remove rows where all columns agree"),
914 $filterDescriptions = [
915 'none' => _(
"Show every file. Nothing is hidden."),
916 'samehash' => _(
"Hide files with identical content across all columns."),
917 'samelic' => _(
"Also hide files that share the same name and the same license/copyright data."),
918 'samelicfuzzy' => _(
"Like above, but uses fuzzy filename matching — ignores version numbers in filenames."),
919 'nolics' => _(
"Show only files where a license difference exists. Files with no license found are also hidden."),
920 'allsame' => _(
"Hide any row where every column reports identical data, regardless of filename."),
923 'license' => _(
"Licenses"),
924 'copyright' => _(
"Copyrights"),
929 'matrix' => _(
"Matrix"),
933 'pluginName' => self::NAME,
939 'baseline' => $baseline,
940 'freezeCol' => $freezeCol,
941 'frozenItem' => $frozenItem,
942 'filters' => $filters,
943 'filterDescriptions' => $filterDescriptions,
946 'treeInfoArray' => $treeInfoArray,
947 'summaryData' => $summaryData,
948 'pathBanners' => $pathBanners,
949 'tableRows' => $tableRows,
950 'histData' => $histData,
951 'colNames' => $colNames,
952 'modeLabel' => $modeLabel,
955 $response = $this->
render(
956 'multicompare.html.twig',
957 $this->mergeWithDefault($vars)
960 if (strlen($response->getContent()) > 0) {
Contains the constants and helpers for authentication of user.
render($templateName, $vars=null, $headers=null)
ChildElt(array $child, int $colIdx, array $row, array $treeInfoArray, string $mode, int $baseline)
filterSamehashN(array &$Master, int $N)
buildSummaryData(array $Master, int $N, array $treeInfoArray, string $mode)
filterSamelicN(array &$Master, int $N)
filterSamelicFuzzyN(array &$Master, int $N)
filterAllsame(array &$Master, int $N)
GetTreeInfo(int $uploadtree_pk)
normalizeComparisonRoots(array $items)
filterNolicsN(array &$Master)
ItemComparisonRows(array $Master, array $treeInfoArray, string $mode, int $baseline, string $view)
batchAgentPks(int $uploadPk)
AddDataStr(array $treeInfo, array &$children, string $mode)
buildHistData(array $items, array $treeInfoArray, string $mode)
ReportCacheGet($CacheKey)
This function is used by Output() to see if the requested report is in the report cache.
ReportCachePut($CacheKey, $CacheValue)
This function is used to write a record to the report cache. If the record already exists,...
ReportCachePurgeByKey($CacheKey)
Purge from the report cache the record with $CacheKey.
FuzzyName(&$Children)
Add fuzzyname and fuzzynameext to $Children.
Dir2Path($uploadtree_pk, $uploadtree_tablename='uploadtree')
Return the path (without artifacts) of an uploadtree_pk.
FileListLinks($upload_fk, $uploadtree_pk, $napk, $pfile_pk, $Recurse=True, &$UniqueTagArray=array(), $uploadtree_tablename="uploadtree", $wantTags=true)
Get list of links: [View][Info][Download]
GetFileLicenses($agent, $pfile_pk, $uploadtree_pk, $uploadtree_tablename='uploadtree', $duplicate="")
get all the licenses for a single file or uploadtree
Dir2BrowseDiffN(array $path, string $filter, int $colIdx, string $pluginName, array $items, string $mode, int $baseline)
Render the folder/path breadcrumb banner for one column.
NormalizeMultiCompareRoot(int $selectedItem, array $children)
Select the effective comparison root for a tree item.
MakeMasterN(array $ChildrenArrays)
Build the master array for N file lists using hashmap-based O(M·N) matching.
FileListN(array &$Master, array $agentPks, string $filter, string $pluginName, array $items, string $mode, int $baseline)
Attach linkurl to every cell in Master (N-way version of FileList()).
FUNCTION int max(int permGroup, int permPublic)
Get the maximum group privilege.
#define PERM_READ
Read-only permission.
fo_dbManager * dbManager
fo_dbManager object