public function pageBody() { $tmp_dir = WT_DATA_DIR . 'ftv_pdf_tmp/'; define('_JPGRAPH_PATH', $tmp_dir); define('_MPDF_TEMP_PATH', $tmp_dir); define('_MPDF_TTFONTDATAPATH', $tmp_dir); require_once WT_MODULES_DIR . $this->getName() . '/mpdf/mpdf.php'; $stylesheet = file_get_contents($this->directory . '/css/style.css'); $stylesheet_rtl = file_get_contents($this->directory . '/css/style-rtl.css'); $html = Filter::post('pdfContent'); $header = '<header>=== ' . $this->tree()->getTitleHtml() . ' ===</header>'; $footer = '<footer>' . '<table><tr>' . '<td class="left">' . WT_BASE_URL . '</td>' . '<td class="center">{DATE d-m-Y}</td>' . '<td class="right">{PAGENO}</td>' . '</tr></table>' . '</footer>'; $mpdf = new mPDF(); $mpdf->simpleTables = true; $mpdf->shrink_tables_to_fit = 1; $mpdf->autoScriptToLang = true; $mpdf->baseScript = 1; $mpdf->autoVietnamese = true; $mpdf->autoArabic = true; $mpdf->autoLangToFont = true; if (I18N::direction() === 'rtl') { $mpdf->SetDirectionality('rtl'); $mpdf->WriteHTML($stylesheet_rtl, 1); } else { $mpdf->WriteHTML($stylesheet, 1); } $mpdf->setAutoTopMargin = 'stretch'; $mpdf->setAutoBottomMargin = 'stretch'; $mpdf->autoMarginPadding = 5; $admin = User::find($this->tree()->getPreference('WEBMASTER_USER_ID'))->getRealName(); $mpdf->setCreator($this->getTitle() . ' - a webtrees module by justcarmen.nl'); $mpdf->SetTitle(Filter::get('title')); $mpdf->setAuthor($admin); $mpdf->SetHTMLHeader($header); $mpdf->setHTMLFooter($footer); $html_chunks = explode("\n", $html); $chunks = count($html_chunks); $i = 1; foreach ($html_chunks as $html_chunk) { // write html body parts only (option 2); if ($i === 1) { // first chunk (initialize all buffers - init=true) $mpdf->WriteHTML($html_chunk, 2, true, false); } elseif ($i === $chunks) { // last chunck (close all buffers - close=true) $mpdf->WriteHTML($html_chunk, 2, false, true); } else { // all other parts (keep the buffer open) $mpdf->WriteHTML($html_chunk, 2, false, false); } $i++; } $index = ' <pagebreak type="next-odd" /> <h2>' . I18N::translate('Index') . '</h2> <columns column-count="2" column-gap="5" /> <indexinsert usedivletters="on" links="on" collation="' . WT_LOCALE . '.utf8" collationgroup="' . I18N::collation() . '" />'; $mpdf->writeHTML($index); $mpdf->Output($tmp_dir . Filter::get('title') . '.pdf', 'F'); }
public function pageBody() { $cache_dir = WT_DATA_DIR . 'ftv_cache/'; define("_JPGRAPH_PATH", $cache_dir); define("_MPDF_TEMP_PATH", $cache_dir); define('_MPDF_TTFONTDATAPATH', $cache_dir); require_once WT_MODULES_DIR . $this->getName() . '/packages/mpdf60/mpdf.php'; $tmpfile = $cache_dir . 'fancy-treeview-tmp.txt'; if (file_exists($cache_dir) && is_readable($tmpfile)) { $stylesheet = file_get_contents($this->directory . '/css/pdf/style.css'); $stylesheet_rtl = file_get_contents($this->directory . '/css/pdf/style-rtl.css'); $html = file_get_contents($tmpfile); $header = '<header>=== ' . $this->tree->getTitleHtml() . ' ===</header>'; $footer = '<footer>' . '<table><tr>' . '<td class="left">' . WT_BASE_URL . '</td>' . '<td class="center">{DATE d-m-Y}</td>' . '<td class="right">{PAGENO}</td>' . '</tr></table>' . '</footer>'; $mpdf = new mPDF(); $mpdf->simpleTables = true; $mpdf->shrink_tables_to_fit = 1; $mpdf->autoScriptToLang = true; if (I18N::direction() === 'rtl') { $mpdf->SetDirectionality('rtl'); } if (I18N::direction() === 'rtl') { $mpdf->WriteHTML($stylesheet_rtl, 1); } else { $mpdf->WriteHTML($stylesheet, 1); } $mpdf->setAutoTopMargin = 'stretch'; $mpdf->setAutoBottomMargin = 'stretch'; $mpdf->autoMarginPadding = 5; $admin = User::find($this->tree->getPreference('WEBMASTER_USER_ID'))->getRealName(); $mpdf->setCreator($this->getTitle() . ' - a webtrees module by justcarmen.nl'); $mpdf->SetTitle(Filter::get('title')); $mpdf->setAuthor($admin); $mpdf->SetHTMLHeader($header); $mpdf->setHTMLFooter($footer); $html_chunks = explode("\n", $html); $chunks = count($html_chunks); $i = 1; foreach ($html_chunks as $html_chunk) { if ($i === 1) { $mpdf->WriteHTML($html_chunk, 2, true, false); } elseif ($i === $chunks) { $mpdf->WriteHTML($html_chunk, 2, false, false); } else { $mpdf->WriteHTML($html_chunk, 2, false, true); } $i++; } $index = ' <pagebreak type="next-odd" /> <h2>' . I18N::translate('Index') . '</h2> <columns column-count="2" column-gap="5" /> <indexinsert usedivletters="on" links="on" collation="' . WT_LOCALE . '.utf8" collationgroup="' . I18N::collation() . '" />'; $mpdf->writeHTML($index); $mpdf->Output(Filter::get('title') . '.pdf', 'D'); } else { echo $this->addMessage('alert', 'danger', false, I18N::translate('Error: the pdf file could not be generated.')); } }
/** * Fetch a list of individuals with specified names * * To search for unknown names, use $surn="@N.N.", $salpha="@" or $galpha="@" * To search for names with no surnames, use $salpha="," * * @param Tree $tree only fetch individuals from this tree * @param string $surn if set, only fetch people with this surname * @param string $salpha if set, only fetch surnames starting with this letter * @param string $galpha if set, only fetch given names starting with this letter * @param bool $marnm if set, include married names * @param bool $fams if set, only fetch individuals with FAMS records * * @return Individual[] */ public static function individuals(Tree $tree, $surn, $salpha, $galpha, $marnm, $fams) { $sql = "SELECT i_id AS xref, i_gedcom AS gedcom, n_full " . "FROM `##individuals` " . "JOIN `##name` ON n_id = i_id AND n_file = i_file " . ($fams ? "JOIN `##link` ON n_id = l_from AND n_file = l_file AND l_type = 'FAMS' " : "") . "WHERE n_file = :tree_id " . ($marnm ? "" : "AND n_type != '_MARNM'"); $args = array('tree_id' => $tree->getTreeId()); if ($surn) { $sql .= " AND n_surn COLLATE :collate_1 = :surn"; $args['collate_1'] = I18N::collation(); $args['surn'] = $surn; } elseif ($salpha === ',') { $sql .= " AND n_surn = ''"; } elseif ($salpha === '@') { $sql .= " AND n_surn = '@N.N.'"; } elseif ($salpha) { $sql .= " AND " . self::getInitialSql('n_surn', $salpha); } else { // All surnames $sql .= " AND n_surn NOT IN ('', '@N.N.')"; } if ($galpha) { $sql .= " AND " . self::getInitialSql('n_givn', $galpha); } $sql .= " ORDER BY CASE n_surn WHEN '@N.N.' THEN 1 ELSE 0 END, n_surn COLLATE :collate_2, CASE n_givn WHEN '@P.N.' THEN 1 ELSE 0 END, n_givn COLLATE :collate_3"; $args['collate_2'] = I18N::collation(); $args['collate_3'] = I18N::collation(); $list = array(); $rows = Database::prepare($sql)->execute($args)->fetchAll(); foreach ($rows as $row) { $person = Individual::getInstance($row->xref, $tree, $row->gedcom); // The name from the database may be private - check the filtered list... foreach ($person->getAllNames() as $n => $name) { if ($name['fullNN'] == $row->n_full) { $person->setPrimaryName($n); // We need to clone $person, as we may have multiple references to the // same person in this list, and the "primary name" would otherwise // be shared amongst all of them. $list[] = clone $person; break; } } } return $list; }
/** * Search for individuals in a tree. * * @param Tree $tree Search this tree * @param string $query Search for this text * * @return string */ private function search(Tree $tree, $query) { if (strlen($query) < 2) { return ''; } $rows = Database::prepare("SELECT i_id AS xref, i_gedcom AS gedcom" . " FROM `##individuals`, `##name`" . " WHERE (i_id LIKE CONCAT('%', :query_1, '%') OR n_sort LIKE CONCAT('%', :query_2, '%'))" . " AND i_id = n_id AND i_file = n_file AND i_file = :tree_id" . " ORDER BY n_sort COLLATE :collation" . " LIMIT 50")->execute(array('query_1' => $query, 'query_2' => $query, 'tree_id' => $tree->getTreeId(), 'collation' => I18N::collation()))->fetchAll(); $out = '<ul>'; foreach ($rows as $row) { $person = Individual::getInstance($row->xref, $tree, $row->gedcom); if ($person->canShowName()) { $out .= '<li><a href="' . $person->getHtmlUrl() . '">' . $person->getSexImage() . ' ' . $person->getFullName() . ' '; if ($person->canShow()) { $bd = $person->getLifeSpan(); if (!empty($bd)) { $out .= ' (' . $bd . ')'; } } $out .= '</a></li>'; } } $out .= '</ul>'; return $out; }
/** * Count the surnames. * * @param string[] $params * * @return string */ public function totalSurnames($params = array()) { if ($params) { $qs = implode(',', array_fill(0, count($params), '?')); $opt = "IN ({$qs})"; $vars = $params; $distinct = ''; } else { $opt = "IS NOT NULL"; $vars = ''; $distinct = 'DISTINCT'; } $vars[] = $this->tree->getTreeId(); $total = Database::prepare("SELECT SQL_CACHE COUNT({$distinct} n_surn COLLATE '" . I18N::collation() . "')" . " FROM `##name`" . " WHERE n_surn COLLATE '" . I18N::collation() . "' {$opt} AND n_file=?")->execute($vars)->fetchOne(); return I18N::number($total); }
/** * Find all of the places in the hierarchy * * @param int $parent_id * @param bool $inactive * * @return array[] */ private function getPlaceListLocation($parent_id, $inactive = false) { if ($inactive) { $rows = Database::prepare("SELECT pl_id, pl_place, pl_lati, pl_long, pl_zoom, pl_icon" . " FROM `##placelocation`" . " WHERE pl_parent_id = :parent_id" . " ORDER BY pl_place COLLATE :collation")->execute(array('parent_id' => $parent_id, 'collation' => I18N::collation()))->fetchAll(); } else { $rows = Database::prepare("SELECT DISTINCT pl_id, pl_place, pl_lati, pl_long, pl_zoom, pl_icon" . " FROM `##placelocation`" . " INNER JOIN `##places` ON `##placelocation`.pl_place=`##places`.p_place" . " WHERE pl_parent_id = :parent_id" . " ORDER BY pl_place COLLATE :collation")->execute(array('parent_id' => $parent_id, 'collation' => I18N::collation()))->fetchAll(); } $placelist = array(); foreach ($rows as $row) { $placelist[] = array('place_id' => $row->pl_id, 'place' => $row->pl_place, 'lati' => $row->pl_lati, 'long' => $row->pl_long, 'zoom' => $row->pl_zoom, 'icon' => $row->pl_icon); } return $placelist; }
/** * Autocomplete search for families. * * @param Tree $tree Search this tree * @param string $query Search for this text * * @return string */ private function search(Tree $tree, $query) { if (strlen($query) < 2) { return ''; } $rows = Database::prepare("SELECT i_id AS xref" . " FROM `##individuals`, `##name`" . " WHERE (i_id LIKE CONCAT('%', :query_1, '%') OR n_sort LIKE CONCAT('%', :query_2, '%'))" . " AND i_id = n_id AND i_file = n_file AND i_file = :tree_id" . " ORDER BY n_sort COLLATE :collation" . " LIMIT 50")->execute(array('query_1' => $query, 'query_2' => $query, 'tree_id' => $tree->getTreeId(), 'collation' => I18N::collation()))->fetchAll(); $ids = array(); foreach ($rows as $row) { $ids[] = $row->xref; } $vars = array(); if (empty($ids)) { //-- no match : search for FAM id $where = "f_id LIKE CONCAT('%', ?, '%')"; $vars[] = $query; } else { //-- search for spouses $qs = implode(',', array_fill(0, count($ids), '?')); $where = "(f_husb IN ({$qs}) OR f_wife IN ({$qs}))"; $vars = array_merge($vars, $ids, $ids); } $vars[] = $tree->getTreeId(); $rows = Database::prepare("SELECT f_id AS xref, f_file AS gedcom_id, f_gedcom AS gedcom FROM `##families` WHERE {$where} AND f_file=?")->execute($vars)->fetchAll(); $out = '<ul>'; foreach ($rows as $row) { $family = Family::getInstance($row->xref, $tree, $row->gedcom); if ($family->canShowName()) { $out .= '<li><a href="' . $family->getHtmlUrl() . '">' . $family->getFullName() . ' '; if ($family->canShow()) { $marriage_year = $family->getMarriageYear(); if ($marriage_year) { $out .= ' (' . $marriage_year . ')'; } } $out .= '</a></li>'; } } $out .= '</ul>'; return $out; }
/** * Find repositories linked to this record. * * @param string $link * * @return Repository[] */ public function linkedRepositories($link) { $rows = Database::prepare("SELECT o_id AS xref, o_gedcom AS gedcom" . " FROM `##other`" . " JOIN `##link` ON o_file = l_file AND o_id = l_from" . " LEFT JOIN `##name` ON o_file = n_file AND o_id = n_id AND n_num = 0" . " WHERE o_file = :tree_id AND o_type = 'REPO' AND l_type = :link AND l_to = :xref" . " ORDER BY n_sort COLLATE :collation")->execute(array('tree_id' => $this->tree->getTreeId(), 'link' => $link, 'xref' => $this->xref, 'collation' => I18N::collation()))->fetchAll(); $list = array(); foreach ($rows as $row) { $record = Repository::getInstance($row->xref, $this->tree, $row->gedcom); if ($record->canShowName()) { $list[] = $record; } } return $list; }
/** * Search the repositories * * @param string[] $query Search terms * @param Tree[] $trees The trees to search * * @return Repository[] */ public static function searchRepositories(array $query, array $trees) { // Convert the query into a regular expression $queryregex = array(); $sql = "SELECT o_id AS xref, o_file AS gedcom_id, o_gedcom AS gedcom FROM `##other` WHERE o_type = 'REPO'"; $args = array(); foreach ($query as $n => $q) { $queryregex[] = preg_quote(I18N::strtoupper($q), '/'); $sql .= " AND o_gedcom COLLATE :collate_" . $n . " LIKE CONCAT('%', :query_" . $n . ", '%')"; $args['collate_' . $n] = I18N::collation(); $args['query_' . $n] = Filter::escapeLike($q); } $sql .= " AND o_file IN ("; foreach ($trees as $n => $tree) { $sql .= $n ? ", " : ""; $sql .= ":tree_id_" . $n; $args['tree_id_' . $n] = $tree->getTreeId(); } $sql .= ")"; $list = array(); $rows = Database::prepare($sql)->execute($args)->fetchAll(); foreach ($rows as $row) { // SQL may have matched on private data or gedcom tags, so check again against privatized data. $record = Repository::getInstance($row->xref, Tree::findById($row->gedcom_id), $row->gedcom); // Ignore non-genealogy data $gedrec = preg_replace('/\\n\\d (_UID|_WT_USER|FILE|FORM|TYPE|CHAN|REFN|RESN) .*/', '', $record->getGedcom()); // Ignore links and tags $gedrec = preg_replace('/\\n\\d ' . WT_REGEX_TAG . '( @' . WT_REGEX_XREF . '@)?/', '', $gedrec); // Ignore tags $gedrec = preg_replace('/\\n\\d ' . WT_REGEX_TAG . ' ?/', '', $gedrec); // Re-apply the filtering $gedrec = I18N::strtoupper($gedrec); foreach ($queryregex as $regex) { if (!preg_match('/' . $regex . '/', $gedrec)) { continue 2; } } $list[] = $record; } $list = array_filter($list, function (Repository $x) { return $x->canShowName(); }); return $list; }