1a6f13a4aSGreg Roach<?php 2a6f13a4aSGreg Roach/** 3a6f13a4aSGreg Roach * webtrees: online genealogy 4a6f13a4aSGreg Roach * Copyright (C) 2015 webtrees development team 5a6f13a4aSGreg Roach * This program is free software: you can redistribute it and/or modify 6a6f13a4aSGreg Roach * it under the terms of the GNU General Public License as published by 7a6f13a4aSGreg Roach * the Free Software Foundation, either version 3 of the License, or 8a6f13a4aSGreg Roach * (at your option) any later version. 9a6f13a4aSGreg Roach * This program is distributed in the hope that it will be useful, 10a6f13a4aSGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of 11a6f13a4aSGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12a6f13a4aSGreg Roach * GNU General Public License for more details. 13a6f13a4aSGreg Roach * You should have received a copy of the GNU General Public License 14a6f13a4aSGreg Roach * along with this program. If not, see <http://www.gnu.org/licenses/>. 15a6f13a4aSGreg Roach */ 1676692c8bSGreg Roachnamespace Fisharebest\Webtrees\Report; 1776692c8bSGreg Roach 18a6f13a4aSGreg Roachuse Fisharebest\Webtrees\Auth; 19a6f13a4aSGreg Roachuse Fisharebest\Webtrees\Database; 20a6f13a4aSGreg Roachuse Fisharebest\Webtrees\Date; 21a6f13a4aSGreg Roachuse Fisharebest\Webtrees\Family; 223d7a8a4cSGreg Roachuse Fisharebest\Webtrees\Functions\Functions; 233d7a8a4cSGreg Roachuse Fisharebest\Webtrees\Functions\FunctionsDate; 24a6f13a4aSGreg Roachuse Fisharebest\Webtrees\GedcomRecord; 25a6f13a4aSGreg Roachuse Fisharebest\Webtrees\GedcomTag; 26a6f13a4aSGreg Roachuse Fisharebest\Webtrees\I18N; 27a6f13a4aSGreg Roachuse Fisharebest\Webtrees\Individual; 28d1286247SGreg Roachuse Fisharebest\Webtrees\Log; 29a6f13a4aSGreg Roachuse Fisharebest\Webtrees\Media; 30729ce104SGreg Roachuse Fisharebest\Webtrees\Note; 31a6f13a4aSGreg Roachuse Fisharebest\Webtrees\Place; 32a6f13a4aSGreg Roach 33a6f13a4aSGreg Roach/** 34a6f13a4aSGreg Roach * Class ReportParserGenerate - parse a report.xml file and generate the report. 35a6f13a4aSGreg Roach */ 36a6f13a4aSGreg Roachclass ReportParserGenerate extends ReportParserBase { 37a6f13a4aSGreg Roach /** @var bool Are we collecting data from <Footnote> elements */ 38a6f13a4aSGreg Roach private $process_footnote = true; 39a6f13a4aSGreg Roach 40a6f13a4aSGreg Roach /** @var bool Are we currently outputing data? */ 41a6f13a4aSGreg Roach private $print_data = false; 42a6f13a4aSGreg Roach 43a6f13a4aSGreg Roach /** @var bool[] Push-down stack of $print_data */ 44a6f13a4aSGreg Roach private $print_data_stack = array(); 45a6f13a4aSGreg Roach 4676692c8bSGreg Roach /** @var int Are we processing GEDCOM data */ 47a6f13a4aSGreg Roach private $process_gedcoms = 0; 48a6f13a4aSGreg Roach 4976692c8bSGreg Roach /** @var int Are we processing conditionals */ 50a6f13a4aSGreg Roach private $process_ifs = 0; 51a6f13a4aSGreg Roach 5276692c8bSGreg Roach /** @var int Are we processing repeats*/ 53a6f13a4aSGreg Roach private $process_repeats = 0; 54a6f13a4aSGreg Roach 55a6f13a4aSGreg Roach /** @var int Quantity of data to repeat during loops */ 56a6f13a4aSGreg Roach private $repeat_bytes = 0; 57a6f13a4aSGreg Roach 58a6f13a4aSGreg Roach /** @var array[] Repeated data when iterating over loops */ 59a6f13a4aSGreg Roach private $repeats = array(); 60a6f13a4aSGreg Roach 61a6f13a4aSGreg Roach /** @var array[] Nested repeating data */ 62a6f13a4aSGreg Roach private $repeats_stack = array(); 63a6f13a4aSGreg Roach 64e8e7866bSGreg Roach /** @var ReportBase[] Nested repeating data */ 65e8e7866bSGreg Roach private $wt_report_stack = array(); 66e8e7866bSGreg Roach 67e8e7866bSGreg Roach /** @var resource Nested repeating data */ 68e8e7866bSGreg Roach private $parser; 69e8e7866bSGreg Roach 70e8e7866bSGreg Roach /** @var resource[] Nested repeating data */ 71e8e7866bSGreg Roach private $parser_stack = array(); 72e8e7866bSGreg Roach 73a6f13a4aSGreg Roach /** @var string The current GEDCOM record */ 74a6f13a4aSGreg Roach private $gedrec = ''; 75a6f13a4aSGreg Roach 76a6f13a4aSGreg Roach /** @var string[] Nested GEDCOM records */ 77a6f13a4aSGreg Roach private $gedrec_stack = array(); 78a6f13a4aSGreg Roach 79a6f13a4aSGreg Roach /** @var ReportBaseElement The currently processed element */ 80a6f13a4aSGreg Roach private $current_element; 81a6f13a4aSGreg Roach 82a6f13a4aSGreg Roach /** @var ReportBaseElement The currently processed element */ 83a6f13a4aSGreg Roach private $footnote_element; 84a6f13a4aSGreg Roach 85a6f13a4aSGreg Roach /** @var string The GEDCOM fact currently being processed */ 86a6f13a4aSGreg Roach private $fact = ''; 87a6f13a4aSGreg Roach 88a6f13a4aSGreg Roach /** @var string The GEDCOM value currently being processed */ 89a6f13a4aSGreg Roach private $desc = ''; 90a6f13a4aSGreg Roach 91a6f13a4aSGreg Roach /** @var string The GEDCOM type currently being processed */ 92a6f13a4aSGreg Roach private $type = ''; 93a6f13a4aSGreg Roach 94a6f13a4aSGreg Roach /** @var int The current generational level */ 95a6f13a4aSGreg Roach private $generation = 1; 96a6f13a4aSGreg Roach 97a6f13a4aSGreg Roach /** @var array Source data for processing lists */ 98a6f13a4aSGreg Roach private $list = array(); 99a6f13a4aSGreg Roach 100a6f13a4aSGreg Roach /** @var int Number of items in lists */ 101a6f13a4aSGreg Roach private $list_total = 0; 102a6f13a4aSGreg Roach 103a6f13a4aSGreg Roach /** @var int Number of items filtered from lists */ 104a6f13a4aSGreg Roach private $list_private = 0; 105a6f13a4aSGreg Roach 106e8e7866bSGreg Roach /** @var ReportBase A factory for creating report elements */ 107e8e7866bSGreg Roach private $report_root; 108e8e7866bSGreg Roach 109e8e7866bSGreg Roach /** @var ReportBase Nested report elements */ 110e8e7866bSGreg Roach private $wt_report; 111e8e7866bSGreg Roach 112*aa22a75eSGreg Roach /** @todo This attribute is public to support the PHP5.3 closure workaround. */ 113d1286247SGreg Roach /** @var string[][] Variables defined in the report at run-time */ 114*aa22a75eSGreg Roach public $vars; 115d1286247SGreg Roach 11676692c8bSGreg Roach /** 11776692c8bSGreg Roach * Create a parser for a report 11876692c8bSGreg Roach * 11976692c8bSGreg Roach * @param string $report The XML filename 12076692c8bSGreg Roach * @param ReportBase $report_root 12176692c8bSGreg Roach * @param string[][] $vars 12276692c8bSGreg Roach */ 12382759250SGreg Roach public function __construct($report, ReportBase $report_root = null, array $vars = array()) { 124e8e7866bSGreg Roach $this->report_root = $report_root; 125e8e7866bSGreg Roach $this->wt_report = $report_root; 126a6f13a4aSGreg Roach $this->current_element = new ReportBaseElement; 127d1286247SGreg Roach $this->vars = $vars; 128a6f13a4aSGreg Roach parent::__construct($report); 129a6f13a4aSGreg Roach } 130a6f13a4aSGreg Roach 131a6f13a4aSGreg Roach /** 132a6f13a4aSGreg Roach * XML start element handler 133a6f13a4aSGreg Roach * 134a6f13a4aSGreg Roach * This function is called whenever a starting element is reached 135a6f13a4aSGreg Roach * The element handler will be called if found, otherwise it must be HTML 136a6f13a4aSGreg Roach * 137a6f13a4aSGreg Roach * @param resource $parser the resource handler for the XML parser 138a6f13a4aSGreg Roach * @param string $name the name of the XML element parsed 139a6f13a4aSGreg Roach * @param array $attrs an array of key value pairs for the attributes 140a6f13a4aSGreg Roach */ 1418edd1043SGreg Roach protected function startElement($parser, $name, $attrs) { 142a6f13a4aSGreg Roach $newattrs = array(); 143a6f13a4aSGreg Roach 144a6f13a4aSGreg Roach foreach ($attrs as $key => $value) { 145a6f13a4aSGreg Roach if (preg_match("/^\\$(\w+)$/", $value, $match)) { 146d1286247SGreg Roach if ((isset($this->vars[$match[1]]['id'])) && (!isset($this->vars[$match[1]]['gedcom']))) { 147d1286247SGreg Roach $value = $this->vars[$match[1]]['id']; 148a6f13a4aSGreg Roach } 149a6f13a4aSGreg Roach } 150a6f13a4aSGreg Roach $newattrs[$key] = $value; 151a6f13a4aSGreg Roach } 152a6f13a4aSGreg Roach $attrs = $newattrs; 153a6f13a4aSGreg Roach if ($this->process_footnote && ($this->process_ifs === 0 || $name === "if") && ($this->process_gedcoms === 0 || $name === "Gedcom") && ($this->process_repeats === 0 || $name === "Facts" || $name === "RepeatTag")) { 154a6f13a4aSGreg Roach $start_method = $name . 'StartHandler'; 155a6f13a4aSGreg Roach $end_method = $name . 'EndHandler'; 156a6f13a4aSGreg Roach if (method_exists($this, $start_method)) { 157a6f13a4aSGreg Roach $this->$start_method($attrs); 158a6f13a4aSGreg Roach } elseif (!method_exists($this, $end_method)) { 159a6f13a4aSGreg Roach $this->htmlStartHandler($name, $attrs); 160a6f13a4aSGreg Roach } 161a6f13a4aSGreg Roach } 162a6f13a4aSGreg Roach } 163a6f13a4aSGreg Roach 164a6f13a4aSGreg Roach /** 165a6f13a4aSGreg Roach * XML end element handler 166a6f13a4aSGreg Roach * 167a6f13a4aSGreg Roach * This function is called whenever an ending element is reached 168a6f13a4aSGreg Roach * The element handler will be called if found, otherwise it must be HTML 169a6f13a4aSGreg Roach * 170a6f13a4aSGreg Roach * @param resource $parser the resource handler for the XML parser 171a6f13a4aSGreg Roach * @param string $name the name of the XML element parsed 172a6f13a4aSGreg Roach */ 1738edd1043SGreg Roach protected function endElement($parser, $name) { 174a6f13a4aSGreg Roach if (($this->process_footnote || $name === "Footnote") && ($this->process_ifs === 0 || $name === "if") && ($this->process_gedcoms === 0 || $name === "Gedcom") && ($this->process_repeats === 0 || $name === "Facts" || $name === "RepeatTag" || $name === "List" || $name === "Relatives")) { 175a6f13a4aSGreg Roach $start_method = $name . 'StartHandler'; 176a6f13a4aSGreg Roach $end_method = $name . 'EndHandler'; 177a6f13a4aSGreg Roach if (method_exists($this, $end_method)) { 178a6f13a4aSGreg Roach $this->$end_method(); 179a6f13a4aSGreg Roach } elseif (!method_exists($this, $start_method)) { 180a6f13a4aSGreg Roach $this->htmlEndHandler($name); 181a6f13a4aSGreg Roach } 182a6f13a4aSGreg Roach } 183a6f13a4aSGreg Roach } 184a6f13a4aSGreg Roach 185a6f13a4aSGreg Roach /** 186a6f13a4aSGreg Roach * XML character data handler 187a6f13a4aSGreg Roach * 188a6f13a4aSGreg Roach * @param resource $parser the resource handler for the XML parser 189a6f13a4aSGreg Roach * @param string $data the name of the XML element parsed 190a6f13a4aSGreg Roach */ 1918edd1043SGreg Roach protected function characterData($parser, $data) { 192e8e7866bSGreg Roach if ($this->print_data && $this->process_gedcoms === 0 && $this->process_ifs === 0 && $this->process_repeats === 0) { 193a6f13a4aSGreg Roach $this->current_element->addText($data); 194a6f13a4aSGreg Roach } 195a6f13a4aSGreg Roach } 196a6f13a4aSGreg Roach 197a6f13a4aSGreg Roach /** 19876692c8bSGreg Roach * XML <style> 199a6f13a4aSGreg Roach * 200a6f13a4aSGreg Roach * @param array $attrs an array of key value pairs for the attributes 201a6f13a4aSGreg Roach */ 2028edd1043SGreg Roach private function styleStartHandler($attrs) { 203a6f13a4aSGreg Roach if (empty($attrs['name'])) { 204a6f13a4aSGreg Roach throw new \DomainException('REPORT ERROR Style: The "name" of the style is missing or not set in the XML file.'); 205a6f13a4aSGreg Roach } 206a6f13a4aSGreg Roach 207a6f13a4aSGreg Roach // array Style that will be passed on 208a6f13a4aSGreg Roach $s = array(); 209a6f13a4aSGreg Roach 210a6f13a4aSGreg Roach // string Name af the style 211a6f13a4aSGreg Roach $s['name'] = $attrs['name']; 212a6f13a4aSGreg Roach 213a6f13a4aSGreg Roach // string Name of the DEFAULT font 214e8e7866bSGreg Roach $s['font'] = $this->wt_report->defaultFont; 215a6f13a4aSGreg Roach if (!empty($attrs['font'])) { 216a6f13a4aSGreg Roach $s['font'] = $attrs['font']; 217a6f13a4aSGreg Roach } 218a6f13a4aSGreg Roach 219a6f13a4aSGreg Roach // int The size of the font in points 220e8e7866bSGreg Roach $s['size'] = $this->wt_report->defaultFontSize; 221a6f13a4aSGreg Roach if (!empty($attrs['size'])) { 222a6f13a4aSGreg Roach $s['size'] = (int) $attrs['size']; 223a6f13a4aSGreg Roach } // Get it as int to ignore all decimal points or text (if any text then int(0)) 224a6f13a4aSGreg Roach 225a6f13a4aSGreg Roach // string B: bold, I: italic, U: underline, D: line trough, The default value is regular. 226a6f13a4aSGreg Roach $s['style'] = ""; 227a6f13a4aSGreg Roach if (!empty($attrs['style'])) { 228a6f13a4aSGreg Roach $s['style'] = $attrs['style']; 229a6f13a4aSGreg Roach } 230a6f13a4aSGreg Roach 231e8e7866bSGreg Roach $this->wt_report->addStyle($s); 232a6f13a4aSGreg Roach } 233a6f13a4aSGreg Roach 234a6f13a4aSGreg Roach /** 23576692c8bSGreg Roach * XML <Doc> 236a6f13a4aSGreg Roach * 237a6f13a4aSGreg Roach * Sets up the basics of the document proparties 238a6f13a4aSGreg Roach * 239a6f13a4aSGreg Roach * @param array $attrs an array of key value pairs for the attributes 240a6f13a4aSGreg Roach */ 2418edd1043SGreg Roach private function docStartHandler($attrs) { 242e8e7866bSGreg Roach $this->parser = $this->xml_parser; 243a6f13a4aSGreg Roach 244a6f13a4aSGreg Roach // Custom page width 245a6f13a4aSGreg Roach if (!empty($attrs['customwidth'])) { 246e8e7866bSGreg Roach $this->wt_report->pagew = (int) $attrs['customwidth']; 247a6f13a4aSGreg Roach } // Get it as int to ignore all decimal points or text (if any text then int(0)) 248a6f13a4aSGreg Roach // Custom Page height 249a6f13a4aSGreg Roach if (!empty($attrs['customheight'])) { 250e8e7866bSGreg Roach $this->wt_report->pageh = (int) $attrs['customheight']; 251a6f13a4aSGreg Roach } // Get it as int to ignore all decimal points or text (if any text then int(0)) 252a6f13a4aSGreg Roach 253a6f13a4aSGreg Roach // Left Margin 254a6f13a4aSGreg Roach if (isset($attrs['leftmargin'])) { 255a6f13a4aSGreg Roach if ($attrs['leftmargin'] === "0") { 256e8e7866bSGreg Roach $this->wt_report->leftmargin = 0; 257a6f13a4aSGreg Roach } elseif (!empty($attrs['leftmargin'])) { 258e8e7866bSGreg Roach $this->wt_report->leftmargin = (int) $attrs['leftmargin']; // Get it as int to ignore all decimal points or text (if any text then int(0)) 259a6f13a4aSGreg Roach } 260a6f13a4aSGreg Roach } 261a6f13a4aSGreg Roach // Right Margin 262a6f13a4aSGreg Roach if (isset($attrs['rightmargin'])) { 263a6f13a4aSGreg Roach if ($attrs['rightmargin'] === "0") { 264e8e7866bSGreg Roach $this->wt_report->rightmargin = 0; 265a6f13a4aSGreg Roach } elseif (!empty($attrs['rightmargin'])) { 266e8e7866bSGreg Roach $this->wt_report->rightmargin = (int) $attrs['rightmargin']; // Get it as int to ignore all decimal points or text (if any text then int(0)) 267a6f13a4aSGreg Roach } 268a6f13a4aSGreg Roach } 269a6f13a4aSGreg Roach // Top Margin 270a6f13a4aSGreg Roach if (isset($attrs['topmargin'])) { 271a6f13a4aSGreg Roach if ($attrs['topmargin'] === "0") { 272e8e7866bSGreg Roach $this->wt_report->topmargin = 0; 273a6f13a4aSGreg Roach } elseif (!empty($attrs['topmargin'])) { 274e8e7866bSGreg Roach $this->wt_report->topmargin = (int) $attrs['topmargin']; // Get it as int to ignore all decimal points or text (if any text then int(0)) 275a6f13a4aSGreg Roach } 276a6f13a4aSGreg Roach } 277a6f13a4aSGreg Roach // Bottom Margin 278a6f13a4aSGreg Roach if (isset($attrs['bottommargin'])) { 279a6f13a4aSGreg Roach if ($attrs['bottommargin'] === "0") { 280e8e7866bSGreg Roach $this->wt_report->bottommargin = 0; 281a6f13a4aSGreg Roach } elseif (!empty($attrs['bottommargin'])) { 282e8e7866bSGreg Roach $this->wt_report->bottommargin = (int) $attrs['bottommargin']; // Get it as int to ignore all decimal points or text (if any text then int(0)) 283a6f13a4aSGreg Roach } 284a6f13a4aSGreg Roach } 285a6f13a4aSGreg Roach // Header Margin 286a6f13a4aSGreg Roach if (isset($attrs['headermargin'])) { 287a6f13a4aSGreg Roach if ($attrs['headermargin'] === "0") { 288e8e7866bSGreg Roach $this->wt_report->headermargin = 0; 289a6f13a4aSGreg Roach } elseif (!empty($attrs['headermargin'])) { 290e8e7866bSGreg Roach $this->wt_report->headermargin = (int) $attrs['headermargin']; // Get it as int to ignore all decimal points or text (if any text then int(0)) 291a6f13a4aSGreg Roach } 292a6f13a4aSGreg Roach } 293a6f13a4aSGreg Roach // Footer Margin 294a6f13a4aSGreg Roach if (isset($attrs['footermargin'])) { 295a6f13a4aSGreg Roach if ($attrs['footermargin'] === "0") { 296e8e7866bSGreg Roach $this->wt_report->footermargin = 0; 297a6f13a4aSGreg Roach } elseif (!empty($attrs['footermargin'])) { 298e8e7866bSGreg Roach $this->wt_report->footermargin = (int) $attrs['footermargin']; // Get it as int to ignore all decimal points or text (if any text then int(0)) 299a6f13a4aSGreg Roach } 300a6f13a4aSGreg Roach } 301a6f13a4aSGreg Roach 302a6f13a4aSGreg Roach // Page Orientation 303a6f13a4aSGreg Roach if (!empty($attrs['orientation'])) { 304a6f13a4aSGreg Roach if ($attrs['orientation'] == "landscape") { 305e8e7866bSGreg Roach $this->wt_report->orientation = "landscape"; 306a6f13a4aSGreg Roach } elseif ($attrs['orientation'] == "portrait") { 307e8e7866bSGreg Roach $this->wt_report->orientation = "portrait"; 308a6f13a4aSGreg Roach } 309a6f13a4aSGreg Roach } 310a6f13a4aSGreg Roach // Page Size 311a6f13a4aSGreg Roach if (!empty($attrs['pageSize'])) { 312e8e7866bSGreg Roach $this->wt_report->pageFormat = strtoupper($attrs['pageSize']); 313a6f13a4aSGreg Roach } 314a6f13a4aSGreg Roach 315a6f13a4aSGreg Roach // Show Generated By... 316a6f13a4aSGreg Roach if (isset($attrs['showGeneratedBy'])) { 317a6f13a4aSGreg Roach if ($attrs['showGeneratedBy'] === "0") { 318e8e7866bSGreg Roach $this->wt_report->showGenText = false; 319a6f13a4aSGreg Roach } elseif ($attrs['showGeneratedBy'] === "1") { 320e8e7866bSGreg Roach $this->wt_report->showGenText = true; 321a6f13a4aSGreg Roach } 322a6f13a4aSGreg Roach } 323a6f13a4aSGreg Roach 324e8e7866bSGreg Roach $this->wt_report->setup(); 325a6f13a4aSGreg Roach } 326a6f13a4aSGreg Roach 327a6f13a4aSGreg Roach /** 32876692c8bSGreg Roach * XML </Doc> 329a6f13a4aSGreg Roach */ 3308edd1043SGreg Roach private function docEndHandler() { 331e8e7866bSGreg Roach $this->wt_report->run(); 332a6f13a4aSGreg Roach } 333a6f13a4aSGreg Roach 334a6f13a4aSGreg Roach /** 33576692c8bSGreg Roach * XML <Header> 336a6f13a4aSGreg Roach */ 3378edd1043SGreg Roach private function headerStartHandler() { 338a6f13a4aSGreg Roach // Clear the Header before any new elements are added 339e8e7866bSGreg Roach $this->wt_report->clearHeader(); 340e8e7866bSGreg Roach $this->wt_report->setProcessing("H"); 341a6f13a4aSGreg Roach } 342a6f13a4aSGreg Roach 343a6f13a4aSGreg Roach /** 34476692c8bSGreg Roach * XML <PageHeader> 345a6f13a4aSGreg Roach */ 3468edd1043SGreg Roach private function pageHeaderStartHandler() { 347a6f13a4aSGreg Roach array_push($this->print_data_stack, $this->print_data); 348a6f13a4aSGreg Roach $this->print_data = false; 349e8e7866bSGreg Roach array_push($this->wt_report_stack, $this->wt_report); 350e8e7866bSGreg Roach $this->wt_report = $this->report_root->createPageHeader(); 351a6f13a4aSGreg Roach } 352a6f13a4aSGreg Roach 353a6f13a4aSGreg Roach /** 35476692c8bSGreg Roach * XML <pageHeaderEndHandler> 355a6f13a4aSGreg Roach */ 3568edd1043SGreg Roach private function pageHeaderEndHandler() { 357a6f13a4aSGreg Roach $this->print_data = array_pop($this->print_data_stack); 358e8e7866bSGreg Roach $this->current_element = $this->wt_report; 359e8e7866bSGreg Roach $this->wt_report = array_pop($this->wt_report_stack); 360e8e7866bSGreg Roach $this->wt_report->addElement($this->current_element); 361a6f13a4aSGreg Roach } 362a6f13a4aSGreg Roach 363a6f13a4aSGreg Roach /** 36476692c8bSGreg Roach * XML <bodyStartHandler> 365a6f13a4aSGreg Roach */ 3668edd1043SGreg Roach private function bodyStartHandler() { 367e8e7866bSGreg Roach $this->wt_report->setProcessing("B"); 368a6f13a4aSGreg Roach } 369a6f13a4aSGreg Roach 370a6f13a4aSGreg Roach /** 37176692c8bSGreg Roach * XML <footerStartHandler> 372a6f13a4aSGreg Roach */ 3738edd1043SGreg Roach private function footerStartHandler() { 374e8e7866bSGreg Roach $this->wt_report->setProcessing("F"); 375a6f13a4aSGreg Roach } 376a6f13a4aSGreg Roach 377a6f13a4aSGreg Roach /** 37876692c8bSGreg Roach * XML <Cell> 379a6f13a4aSGreg Roach * 380a6f13a4aSGreg Roach * @param array $attrs an array of key value pairs for the attributes 381a6f13a4aSGreg Roach */ 3828edd1043SGreg Roach private function cellStartHandler($attrs) { 383a6f13a4aSGreg Roach // string The text alignment of the text in this box. 384a6f13a4aSGreg Roach $align = ""; 385a6f13a4aSGreg Roach if (!empty($attrs['align'])) { 386a6f13a4aSGreg Roach $align = $attrs['align']; 387a6f13a4aSGreg Roach // RTL supported left/right alignment 388a6f13a4aSGreg Roach if ($align == "rightrtl") { 389e8e7866bSGreg Roach if ($this->wt_report->rtl) { 390a6f13a4aSGreg Roach $align = "left"; 391a6f13a4aSGreg Roach } else { 392a6f13a4aSGreg Roach $align = "right"; 393a6f13a4aSGreg Roach } 394a6f13a4aSGreg Roach } elseif ($align == "leftrtl") { 395e8e7866bSGreg Roach if ($this->wt_report->rtl) { 396a6f13a4aSGreg Roach $align = "right"; 397a6f13a4aSGreg Roach } else { 398a6f13a4aSGreg Roach $align = "left"; 399a6f13a4aSGreg Roach } 400a6f13a4aSGreg Roach } 401a6f13a4aSGreg Roach } 402a6f13a4aSGreg Roach 403a6f13a4aSGreg Roach // string The color to fill the background of this cell 404a6f13a4aSGreg Roach $bgcolor = ""; 405a6f13a4aSGreg Roach if (!empty($attrs['bgcolor'])) { 406a6f13a4aSGreg Roach $bgcolor = $attrs['bgcolor']; 407a6f13a4aSGreg Roach } 408a6f13a4aSGreg Roach 409a6f13a4aSGreg Roach // int Whether or not the background should be painted 410a6f13a4aSGreg Roach $fill = 1; 411a6f13a4aSGreg Roach if (isset($attrs['fill'])) { 412a6f13a4aSGreg Roach if ($attrs['fill'] === "0") { 413a6f13a4aSGreg Roach $fill = 0; 414a6f13a4aSGreg Roach } elseif ($attrs['fill'] === "1") { 415a6f13a4aSGreg Roach $fill = 1; 416a6f13a4aSGreg Roach } 417a6f13a4aSGreg Roach } 418a6f13a4aSGreg Roach 419a6f13a4aSGreg Roach $reseth = true; 420a6f13a4aSGreg Roach // boolean if true reset the last cell height (default true) 421a6f13a4aSGreg Roach if (isset($attrs['reseth'])) { 422a6f13a4aSGreg Roach if ($attrs['reseth'] === "0") { 423a6f13a4aSGreg Roach $reseth = false; 424a6f13a4aSGreg Roach } elseif ($attrs['reseth'] === "1") { 425a6f13a4aSGreg Roach $reseth = true; 426a6f13a4aSGreg Roach } 427a6f13a4aSGreg Roach } 428a6f13a4aSGreg Roach 429a6f13a4aSGreg Roach // mixed Whether or not a border should be printed around this box 430a6f13a4aSGreg Roach $border = 0; 431a6f13a4aSGreg Roach if (!empty($attrs['border'])) { 432a6f13a4aSGreg Roach $border = $attrs['border']; 433a6f13a4aSGreg Roach } 434a6f13a4aSGreg Roach // string Border color in HTML code 435a6f13a4aSGreg Roach $bocolor = ""; 436a6f13a4aSGreg Roach if (!empty($attrs['bocolor'])) { 437a6f13a4aSGreg Roach $bocolor = $attrs['bocolor']; 438a6f13a4aSGreg Roach } 439a6f13a4aSGreg Roach 440a6f13a4aSGreg Roach // int Cell height (expressed in points) The starting height of this cell. If the text wraps the height will automatically be adjusted. 441a6f13a4aSGreg Roach $height = 0; 442a6f13a4aSGreg Roach if (!empty($attrs['height'])) { 443a6f13a4aSGreg Roach $height = (int) $attrs['height']; 444a6f13a4aSGreg Roach } 445a6f13a4aSGreg Roach // int Cell width (expressed in points) Setting the width to 0 will make it the width from the current location to the right margin. 446a6f13a4aSGreg Roach $width = 0; 447a6f13a4aSGreg Roach if (!empty($attrs['width'])) { 448a6f13a4aSGreg Roach $width = (int) $attrs['width']; 449a6f13a4aSGreg Roach } 450a6f13a4aSGreg Roach 451a6f13a4aSGreg Roach // int Stretch carachter mode 452a6f13a4aSGreg Roach $stretch = 0; 453a6f13a4aSGreg Roach if (!empty($attrs['stretch'])) { 454a6f13a4aSGreg Roach $stretch = (int) $attrs['stretch']; 455a6f13a4aSGreg Roach } 456a6f13a4aSGreg Roach 457a6f13a4aSGreg Roach // mixed Position the left corner of this box on the page. The default is the current position. 458a6f13a4aSGreg Roach $left = "."; 459a6f13a4aSGreg Roach if (isset($attrs['left'])) { 460a6f13a4aSGreg Roach if ($attrs['left'] === ".") { 461a6f13a4aSGreg Roach $left = "."; 462a6f13a4aSGreg Roach } elseif (!empty($attrs['left'])) { 463a6f13a4aSGreg Roach $left = (int) $attrs['left']; 464a6f13a4aSGreg Roach } elseif ($attrs['left'] === "0") { 465a6f13a4aSGreg Roach $left = 0; 466a6f13a4aSGreg Roach } 467a6f13a4aSGreg Roach } 468a6f13a4aSGreg Roach // mixed Position the top corner of this box on the page. the default is the current position 469a6f13a4aSGreg Roach $top = "."; 470a6f13a4aSGreg Roach if (isset($attrs['top'])) { 471a6f13a4aSGreg Roach if ($attrs['top'] === ".") { 472a6f13a4aSGreg Roach $top = "."; 473a6f13a4aSGreg Roach } elseif (!empty($attrs['top'])) { 474a6f13a4aSGreg Roach $top = (int) $attrs['top']; 475a6f13a4aSGreg Roach } elseif ($attrs['top'] === "0") { 476a6f13a4aSGreg Roach $top = 0; 477a6f13a4aSGreg Roach } 478a6f13a4aSGreg Roach } 479a6f13a4aSGreg Roach 480a6f13a4aSGreg Roach // string The name of the Style that should be used to render the text. 481a6f13a4aSGreg Roach $style = ""; 482a6f13a4aSGreg Roach if (!empty($attrs['style'])) { 483a6f13a4aSGreg Roach $style = $attrs['style']; 484a6f13a4aSGreg Roach } 485a6f13a4aSGreg Roach 486a6f13a4aSGreg Roach // string Text color in html code 487a6f13a4aSGreg Roach $tcolor = ""; 488a6f13a4aSGreg Roach if (!empty($attrs['tcolor'])) { 489a6f13a4aSGreg Roach $tcolor = $attrs['tcolor']; 490a6f13a4aSGreg Roach } 491a6f13a4aSGreg Roach 492a6f13a4aSGreg Roach // int Indicates where the current position should go after the call. 493a6f13a4aSGreg Roach $ln = 0; 494a6f13a4aSGreg Roach if (isset($attrs['newline'])) { 495a6f13a4aSGreg Roach if (!empty($attrs['newline'])) { 496a6f13a4aSGreg Roach $ln = (int) $attrs['newline']; 497a6f13a4aSGreg Roach } elseif ($attrs['newline'] === "0") { 498a6f13a4aSGreg Roach $ln = 0; 499a6f13a4aSGreg Roach } 500a6f13a4aSGreg Roach } 501a6f13a4aSGreg Roach 502a6f13a4aSGreg Roach if ($align == "left") { 503a6f13a4aSGreg Roach $align = "L"; 504a6f13a4aSGreg Roach } elseif ($align == "right") { 505a6f13a4aSGreg Roach $align = "R"; 506a6f13a4aSGreg Roach } elseif ($align == "center") { 507a6f13a4aSGreg Roach $align = "C"; 508a6f13a4aSGreg Roach } elseif ($align == "justify") { 509a6f13a4aSGreg Roach $align = "J"; 510a6f13a4aSGreg Roach } 511a6f13a4aSGreg Roach 512a6f13a4aSGreg Roach array_push($this->print_data_stack, $this->print_data); 513a6f13a4aSGreg Roach $this->print_data = true; 514a6f13a4aSGreg Roach 515e8e7866bSGreg Roach $this->current_element = $this->report_root->createCell( 516a6f13a4aSGreg Roach $width, 517a6f13a4aSGreg Roach $height, 518a6f13a4aSGreg Roach $border, 519a6f13a4aSGreg Roach $align, 520a6f13a4aSGreg Roach $bgcolor, 521a6f13a4aSGreg Roach $style, 522a6f13a4aSGreg Roach $ln, 523a6f13a4aSGreg Roach $top, 524a6f13a4aSGreg Roach $left, 525a6f13a4aSGreg Roach $fill, 526a6f13a4aSGreg Roach $stretch, 527a6f13a4aSGreg Roach $bocolor, 528a6f13a4aSGreg Roach $tcolor, 529a6f13a4aSGreg Roach $reseth 530a6f13a4aSGreg Roach ); 531a6f13a4aSGreg Roach } 532a6f13a4aSGreg Roach 533a6f13a4aSGreg Roach /** 53476692c8bSGreg Roach * XML </Cell> 535a6f13a4aSGreg Roach */ 5368edd1043SGreg Roach private function cellEndHandler() { 537a6f13a4aSGreg Roach $this->print_data = array_pop($this->print_data_stack); 538e8e7866bSGreg Roach $this->wt_report->addElement($this->current_element); 539a6f13a4aSGreg Roach } 540a6f13a4aSGreg Roach 541a6f13a4aSGreg Roach /** 542a6f13a4aSGreg Roach * XML <Now /> element handler 543a6f13a4aSGreg Roach */ 5448edd1043SGreg Roach private function nowStartHandler() { 5453d7a8a4cSGreg Roach $g = FunctionsDate::timestampToGedcomDate(WT_TIMESTAMP + WT_TIMESTAMP_OFFSET); 546a6f13a4aSGreg Roach $this->current_element->addText($g->display()); 547a6f13a4aSGreg Roach } 548a6f13a4aSGreg Roach 549a6f13a4aSGreg Roach /** 550a6f13a4aSGreg Roach * XML <PageNum /> element handler 551a6f13a4aSGreg Roach */ 5528edd1043SGreg Roach private function pageNumStartHandler() { 553a6f13a4aSGreg Roach $this->current_element->addText("#PAGENUM#"); 554a6f13a4aSGreg Roach } 555a6f13a4aSGreg Roach 556a6f13a4aSGreg Roach /** 557a6f13a4aSGreg Roach * XML <TotalPages /> element handler 558a6f13a4aSGreg Roach */ 5598edd1043SGreg Roach private function totalPagesStartHandler() { 560a6f13a4aSGreg Roach $this->current_element->addText("{{:ptp:}}"); 561a6f13a4aSGreg Roach } 562a6f13a4aSGreg Roach 563a6f13a4aSGreg Roach /** 564a6f13a4aSGreg Roach * Called at the start of an element. 565a6f13a4aSGreg Roach * 566a6f13a4aSGreg Roach * @param array $attrs an array of key value pairs for the attributes 567a6f13a4aSGreg Roach */ 5688edd1043SGreg Roach private function gedcomStartHandler($attrs) { 569d1286247SGreg Roach global $WT_TREE; 570a6f13a4aSGreg Roach 571a6f13a4aSGreg Roach if ($this->process_gedcoms > 0) { 572a6f13a4aSGreg Roach $this->process_gedcoms++; 573a6f13a4aSGreg Roach 574a6f13a4aSGreg Roach return; 575a6f13a4aSGreg Roach } 576a6f13a4aSGreg Roach 577a6f13a4aSGreg Roach $tag = $attrs['id']; 578a6f13a4aSGreg Roach $tag = str_replace("@fact", $this->fact, $tag); 579a6f13a4aSGreg Roach $tags = explode(":", $tag); 580a6f13a4aSGreg Roach $newgedrec = ''; 581a6f13a4aSGreg Roach if (count($tags) < 2) { 582a6f13a4aSGreg Roach $tmp = GedcomRecord::getInstance($attrs['id'], $WT_TREE); 583a6f13a4aSGreg Roach $newgedrec = $tmp ? $tmp->privatizeGedcom(Auth::accessLevel($WT_TREE)) : ''; 584a6f13a4aSGreg Roach } 585a6f13a4aSGreg Roach if (empty($newgedrec)) { 586a6f13a4aSGreg Roach $tgedrec = $this->gedrec; 587a6f13a4aSGreg Roach $newgedrec = ''; 588a6f13a4aSGreg Roach foreach ($tags as $tag) { 589a6f13a4aSGreg Roach if (preg_match("/\\$(.+)/", $tag, $match)) { 590d1286247SGreg Roach if (isset($this->vars[$match[1]]['gedcom'])) { 591d1286247SGreg Roach $newgedrec = $this->vars[$match[1]]['gedcom']; 592a6f13a4aSGreg Roach } else { 593a6f13a4aSGreg Roach $tmp = GedcomRecord::getInstance($match[1], $WT_TREE); 594a6f13a4aSGreg Roach $newgedrec = $tmp ? $tmp->privatizeGedcom(Auth::accessLevel($WT_TREE)) : ''; 595a6f13a4aSGreg Roach } 596a6f13a4aSGreg Roach } else { 597a6f13a4aSGreg Roach if (preg_match("/@(.+)/", $tag, $match)) { 598a6f13a4aSGreg Roach $gmatch = array(); 599a6f13a4aSGreg Roach if (preg_match("/\d $match[1] @([^@]+)@/", $tgedrec, $gmatch)) { 600a6f13a4aSGreg Roach $tmp = GedcomRecord::getInstance($gmatch[1], $WT_TREE); 601a6f13a4aSGreg Roach $newgedrec = $tmp ? $tmp->privatizeGedcom(Auth::accessLevel($WT_TREE)) : ''; 602a6f13a4aSGreg Roach $tgedrec = $newgedrec; 603a6f13a4aSGreg Roach } else { 604a6f13a4aSGreg Roach $newgedrec = ''; 605a6f13a4aSGreg Roach break; 606a6f13a4aSGreg Roach } 607a6f13a4aSGreg Roach } else { 608a6f13a4aSGreg Roach $temp = explode(" ", trim($tgedrec)); 609a6f13a4aSGreg Roach $level = $temp[0] + 1; 6103d7a8a4cSGreg Roach $newgedrec = Functions::getSubRecord($level, "$level $tag", $tgedrec); 611a6f13a4aSGreg Roach $tgedrec = $newgedrec; 612a6f13a4aSGreg Roach } 613a6f13a4aSGreg Roach } 614a6f13a4aSGreg Roach } 615a6f13a4aSGreg Roach } 616a6f13a4aSGreg Roach if (!empty($newgedrec)) { 617a6f13a4aSGreg Roach array_push($this->gedrec_stack, array($this->gedrec, $this->fact, $this->desc)); 618a6f13a4aSGreg Roach $this->gedrec = $newgedrec; 619a6f13a4aSGreg Roach if (preg_match("/(\d+) (_?[A-Z0-9]+) (.*)/", $this->gedrec, $match)) { 620a6f13a4aSGreg Roach $this->fact = $match[2]; 621a6f13a4aSGreg Roach $this->desc = trim($match[3]); 622a6f13a4aSGreg Roach } 623a6f13a4aSGreg Roach } else { 624a6f13a4aSGreg Roach $this->process_gedcoms++; 625a6f13a4aSGreg Roach } 626a6f13a4aSGreg Roach } 627a6f13a4aSGreg Roach 628a6f13a4aSGreg Roach /** 629a6f13a4aSGreg Roach * Called at the end of an element. 630a6f13a4aSGreg Roach */ 6318edd1043SGreg Roach private function gedcomEndHandler() { 632a6f13a4aSGreg Roach if ($this->process_gedcoms > 0) { 633a6f13a4aSGreg Roach $this->process_gedcoms--; 634a6f13a4aSGreg Roach } else { 635a6f13a4aSGreg Roach list($this->gedrec, $this->fact, $this->desc) = array_pop($this->gedrec_stack); 636a6f13a4aSGreg Roach } 637a6f13a4aSGreg Roach } 638a6f13a4aSGreg Roach 639a6f13a4aSGreg Roach /** 64076692c8bSGreg Roach * XML <textBoxStartHandler> 641a6f13a4aSGreg Roach * 642a6f13a4aSGreg Roach * @param array $attrs an array of key value pairs for the attributes 643a6f13a4aSGreg Roach */ 6448edd1043SGreg Roach private function textBoxStartHandler($attrs) { 645a6f13a4aSGreg Roach // string Background color code 646a6f13a4aSGreg Roach $bgcolor = ""; 647a6f13a4aSGreg Roach if (!empty($attrs['bgcolor'])) { 648a6f13a4aSGreg Roach $bgcolor = $attrs['bgcolor']; 649a6f13a4aSGreg Roach } 650a6f13a4aSGreg Roach 651a6f13a4aSGreg Roach // boolean Wether or not fill the background color 652a6f13a4aSGreg Roach $fill = true; 653a6f13a4aSGreg Roach if (isset($attrs['fill'])) { 654a6f13a4aSGreg Roach if ($attrs['fill'] === "0") { 655a6f13a4aSGreg Roach $fill = false; 656a6f13a4aSGreg Roach } elseif ($attrs['fill'] === "1") { 657a6f13a4aSGreg Roach $fill = true; 658a6f13a4aSGreg Roach } 659a6f13a4aSGreg Roach } 660a6f13a4aSGreg Roach 661a6f13a4aSGreg Roach // var boolean Whether or not a border should be printed around this box. 0 = no border, 1 = border. Default is 0 662a6f13a4aSGreg Roach $border = false; 663a6f13a4aSGreg Roach if (isset($attrs['border'])) { 664a6f13a4aSGreg Roach if ($attrs['border'] === "1") { 665a6f13a4aSGreg Roach $border = true; 666a6f13a4aSGreg Roach } elseif ($attrs['border'] === "0") { 667a6f13a4aSGreg Roach $border = false; 668a6f13a4aSGreg Roach } 669a6f13a4aSGreg Roach } 670a6f13a4aSGreg Roach 671a6f13a4aSGreg Roach // int The starting height of this cell. If the text wraps the height will automatically be adjusted 672a6f13a4aSGreg Roach $height = 0; 673a6f13a4aSGreg Roach if (!empty($attrs['height'])) { 674a6f13a4aSGreg Roach $height = (int) $attrs['height']; 675a6f13a4aSGreg Roach } 676a6f13a4aSGreg Roach // int Setting the width to 0 will make it the width from the current location to the margin 677a6f13a4aSGreg Roach $width = 0; 678a6f13a4aSGreg Roach if (!empty($attrs['width'])) { 679a6f13a4aSGreg Roach $width = (int) $attrs['width']; 680a6f13a4aSGreg Roach } 681a6f13a4aSGreg Roach 682a6f13a4aSGreg Roach // mixed Position the left corner of this box on the page. The default is the current position. 683a6f13a4aSGreg Roach $left = "."; 684a6f13a4aSGreg Roach if (isset($attrs['left'])) { 685a6f13a4aSGreg Roach if ($attrs['left'] === ".") { 686a6f13a4aSGreg Roach $left = "."; 687a6f13a4aSGreg Roach } elseif (!empty($attrs['left'])) { 688a6f13a4aSGreg Roach $left = (int) $attrs['left']; 689a6f13a4aSGreg Roach } elseif ($attrs['left'] === "0") { 690a6f13a4aSGreg Roach $left = 0; 691a6f13a4aSGreg Roach } 692a6f13a4aSGreg Roach } 693a6f13a4aSGreg Roach // mixed Position the top corner of this box on the page. the default is the current position 694a6f13a4aSGreg Roach $top = "."; 695a6f13a4aSGreg Roach if (isset($attrs['top'])) { 696a6f13a4aSGreg Roach if ($attrs['top'] === ".") { 697a6f13a4aSGreg Roach $top = "."; 698a6f13a4aSGreg Roach } elseif (!empty($attrs['top'])) { 699a6f13a4aSGreg Roach $top = (int) $attrs['top']; 700a6f13a4aSGreg Roach } elseif ($attrs['top'] === "0") { 701a6f13a4aSGreg Roach $top = 0; 702a6f13a4aSGreg Roach } 703a6f13a4aSGreg Roach } 704a6f13a4aSGreg Roach // boolean After this box is finished rendering, should the next section of text start immediately after the this box or should it start on a new line under this box. 0 = no new line, 1 = force new line. Default is 0 705a6f13a4aSGreg Roach $newline = false; 706a6f13a4aSGreg Roach if (isset($attrs['newline'])) { 707a6f13a4aSGreg Roach if ($attrs['newline'] === "1") { 708a6f13a4aSGreg Roach $newline = true; 709a6f13a4aSGreg Roach } elseif ($attrs['newline'] === "0") { 710a6f13a4aSGreg Roach $newline = false; 711a6f13a4aSGreg Roach } 712a6f13a4aSGreg Roach } 713a6f13a4aSGreg Roach // boolean 714a6f13a4aSGreg Roach $pagecheck = true; 715a6f13a4aSGreg Roach if (isset($attrs['pagecheck'])) { 716a6f13a4aSGreg Roach if ($attrs['pagecheck'] === "0") { 717a6f13a4aSGreg Roach $pagecheck = false; 718a6f13a4aSGreg Roach } elseif ($attrs['pagecheck'] === "1") { 719a6f13a4aSGreg Roach $pagecheck = true; 720a6f13a4aSGreg Roach } 721a6f13a4aSGreg Roach } 722a6f13a4aSGreg Roach // boolean Cell padding 723a6f13a4aSGreg Roach $padding = true; 724a6f13a4aSGreg Roach if (isset($attrs['padding'])) { 725a6f13a4aSGreg Roach if ($attrs['padding'] === "0") { 726a6f13a4aSGreg Roach $padding = false; 727a6f13a4aSGreg Roach } elseif ($attrs['padding'] === "1") { 728a6f13a4aSGreg Roach $padding = true; 729a6f13a4aSGreg Roach } 730a6f13a4aSGreg Roach } 731a6f13a4aSGreg Roach // boolean Reset this box Height 732a6f13a4aSGreg Roach $reseth = false; 733a6f13a4aSGreg Roach if (isset($attrs['reseth'])) { 734a6f13a4aSGreg Roach if ($attrs['reseth'] === "1") { 735a6f13a4aSGreg Roach $reseth = true; 736a6f13a4aSGreg Roach } elseif ($attrs['reseth'] === "0") { 737a6f13a4aSGreg Roach $reseth = false; 738a6f13a4aSGreg Roach } 739a6f13a4aSGreg Roach } 740a6f13a4aSGreg Roach 741a6f13a4aSGreg Roach // string Style of rendering 742a6f13a4aSGreg Roach $style = ""; 743a6f13a4aSGreg Roach 744a6f13a4aSGreg Roach array_push($this->print_data_stack, $this->print_data); 745a6f13a4aSGreg Roach $this->print_data = false; 746a6f13a4aSGreg Roach 747e8e7866bSGreg Roach array_push($this->wt_report_stack, $this->wt_report); 748e8e7866bSGreg Roach $this->wt_report = $this->report_root->createTextBox( 749a6f13a4aSGreg Roach $width, 750a6f13a4aSGreg Roach $height, 751a6f13a4aSGreg Roach $border, 752a6f13a4aSGreg Roach $bgcolor, 753a6f13a4aSGreg Roach $newline, 754a6f13a4aSGreg Roach $left, 755a6f13a4aSGreg Roach $top, 756a6f13a4aSGreg Roach $pagecheck, 757a6f13a4aSGreg Roach $style, 758a6f13a4aSGreg Roach $fill, 759a6f13a4aSGreg Roach $padding, 760a6f13a4aSGreg Roach $reseth 761a6f13a4aSGreg Roach ); 762a6f13a4aSGreg Roach } 763a6f13a4aSGreg Roach 764a6f13a4aSGreg Roach /** 76576692c8bSGreg Roach * XML <textBoxEndHandler> 766a6f13a4aSGreg Roach */ 7678edd1043SGreg Roach private function textBoxEndHandler() { 768a6f13a4aSGreg Roach $this->print_data = array_pop($this->print_data_stack); 769e8e7866bSGreg Roach $this->current_element = $this->wt_report; 770e8e7866bSGreg Roach $this->wt_report = array_pop($this->wt_report_stack); 771e8e7866bSGreg Roach $this->wt_report->addElement($this->current_element); 772a6f13a4aSGreg Roach } 773a6f13a4aSGreg Roach 774a6f13a4aSGreg Roach /** 77576692c8bSGreg Roach * XLM <Text>. 77676692c8bSGreg Roach * 777a6f13a4aSGreg Roach * @param array $attrs an array of key value pairs for the attributes 778a6f13a4aSGreg Roach */ 7798edd1043SGreg Roach private function textStartHandler($attrs) { 780a6f13a4aSGreg Roach array_push($this->print_data_stack, $this->print_data); 781a6f13a4aSGreg Roach $this->print_data = true; 782a6f13a4aSGreg Roach 783a6f13a4aSGreg Roach // string The name of the Style that should be used to render the text. 784a6f13a4aSGreg Roach $style = ""; 785a6f13a4aSGreg Roach if (!empty($attrs['style'])) { 786a6f13a4aSGreg Roach $style = $attrs['style']; 787a6f13a4aSGreg Roach } 788a6f13a4aSGreg Roach 789a6f13a4aSGreg Roach // string The color of the text - Keep the black color as default 790a6f13a4aSGreg Roach $color = ""; 791a6f13a4aSGreg Roach if (!empty($attrs['color'])) { 792a6f13a4aSGreg Roach $color = $attrs['color']; 793a6f13a4aSGreg Roach } 794a6f13a4aSGreg Roach 795e8e7866bSGreg Roach $this->current_element = $this->report_root->createText($style, $color); 796a6f13a4aSGreg Roach } 797a6f13a4aSGreg Roach 798a6f13a4aSGreg Roach /** 79976692c8bSGreg Roach * XML </Text> 800a6f13a4aSGreg Roach */ 8018edd1043SGreg Roach private function textEndHandler() { 802a6f13a4aSGreg Roach $this->print_data = array_pop($this->print_data_stack); 803e8e7866bSGreg Roach $this->wt_report->addElement($this->current_element); 804a6f13a4aSGreg Roach } 805a6f13a4aSGreg Roach 806a6f13a4aSGreg Roach /** 80776692c8bSGreg Roach * XML <GetPersonName/> 80876692c8bSGreg Roach * 809a6f13a4aSGreg Roach * Get the name 810a6f13a4aSGreg Roach * 1. id is empty - current GEDCOM record 811a6f13a4aSGreg Roach * 2. id is set with a record id 812a6f13a4aSGreg Roach * 813a6f13a4aSGreg Roach * @param array $attrs an array of key value pairs for the attributes 814a6f13a4aSGreg Roach */ 8158edd1043SGreg Roach private function getPersonNameStartHandler($attrs) { 816d1286247SGreg Roach global $WT_TREE; 817a6f13a4aSGreg Roach 818a6f13a4aSGreg Roach $id = ""; 819a6f13a4aSGreg Roach $match = array(); 820a6f13a4aSGreg Roach if (empty($attrs['id'])) { 821a6f13a4aSGreg Roach if (preg_match("/0 @(.+)@/", $this->gedrec, $match)) { 822a6f13a4aSGreg Roach $id = $match[1]; 823a6f13a4aSGreg Roach } 824a6f13a4aSGreg Roach } else { 825a6f13a4aSGreg Roach if (preg_match("/\\$(.+)/", $attrs['id'], $match)) { 826d1286247SGreg Roach if (isset($this->vars[$match[1]]['id'])) { 827d1286247SGreg Roach $id = $this->vars[$match[1]]['id']; 828a6f13a4aSGreg Roach } 829a6f13a4aSGreg Roach } else { 830a6f13a4aSGreg Roach if (preg_match("/@(.+)/", $attrs['id'], $match)) { 831a6f13a4aSGreg Roach $gmatch = array(); 832a6f13a4aSGreg Roach if (preg_match("/\d $match[1] @([^@]+)@/", $this->gedrec, $gmatch)) { 833a6f13a4aSGreg Roach $id = $gmatch[1]; 834a6f13a4aSGreg Roach } 835a6f13a4aSGreg Roach } else { 836a6f13a4aSGreg Roach $id = $attrs['id']; 837a6f13a4aSGreg Roach } 838a6f13a4aSGreg Roach } 839a6f13a4aSGreg Roach } 840a6f13a4aSGreg Roach if (!empty($id)) { 841a6f13a4aSGreg Roach $record = GedcomRecord::getInstance($id, $WT_TREE); 842a6f13a4aSGreg Roach if (is_null($record)) { 843a6f13a4aSGreg Roach return; 844a6f13a4aSGreg Roach } 845a6f13a4aSGreg Roach if (!$record->canShowName()) { 846a6f13a4aSGreg Roach $this->current_element->addText(I18N::translate('Private')); 847a6f13a4aSGreg Roach } else { 848a6f13a4aSGreg Roach $name = $record->getFullName(); 849a6f13a4aSGreg Roach $name = preg_replace( 850a6f13a4aSGreg Roach array('/<span class="starredname">/', '/<\/span><\/span>/', '/<\/span>/'), 851a6f13a4aSGreg Roach array('«', '', '»'), 852a6f13a4aSGreg Roach $name 853a6f13a4aSGreg Roach ); 854a6f13a4aSGreg Roach $name = strip_tags($name); 855a6f13a4aSGreg Roach if (!empty($attrs['truncate'])) { 856a6f13a4aSGreg Roach if (mb_strlen($name) > $attrs['truncate']) { 857a6f13a4aSGreg Roach $name = preg_replace("/\(.*\) ?/", '', $name); //removes () and text inbetween - what about ", [ and { etc? 858a6f13a4aSGreg Roach $words = preg_split('/[, -]+/', $name); // names separated with space, comma or hyphen - any others? 859a6f13a4aSGreg Roach $name = $words[count($words) - 1]; 860a6f13a4aSGreg Roach for ($i = count($words) - 2; $i >= 0; $i--) { 861a6f13a4aSGreg Roach $len = mb_strlen($name); 862a6f13a4aSGreg Roach for ($j = count($words) - 3; $j >= 0; $j--) { 863a6f13a4aSGreg Roach $len += mb_strlen($words[$j]); 864a6f13a4aSGreg Roach } 865a6f13a4aSGreg Roach if ($len > $attrs['truncate']) { 866a6f13a4aSGreg Roach $first_letter = mb_substr($words[$i], 0, 1); 867a6f13a4aSGreg Roach // Do not show " of nick-names 868a6f13a4aSGreg Roach if ($first_letter != "\"") { 869a6f13a4aSGreg Roach $name = mb_substr($words[$i], 0, 1) . '. ' . $name; 870a6f13a4aSGreg Roach } 871a6f13a4aSGreg Roach } else { 872a6f13a4aSGreg Roach $name = $words[$i] . ' ' . $name; 873a6f13a4aSGreg Roach } 874a6f13a4aSGreg Roach } 875a6f13a4aSGreg Roach } 876a6f13a4aSGreg Roach } else { 877a6f13a4aSGreg Roach $addname = $record->getAddName(); 878a6f13a4aSGreg Roach $addname = preg_replace( 879a6f13a4aSGreg Roach array('/<span class="starredname">/', '/<\/span><\/span>/', '/<\/span>/'), 880a6f13a4aSGreg Roach array('«', '', '»'), 881a6f13a4aSGreg Roach $addname 882a6f13a4aSGreg Roach ); 883a6f13a4aSGreg Roach $addname = strip_tags($addname); 884a6f13a4aSGreg Roach if (!empty($addname)) { 885a6f13a4aSGreg Roach $name .= " " . $addname; 886a6f13a4aSGreg Roach } 887a6f13a4aSGreg Roach } 888a6f13a4aSGreg Roach $this->current_element->addText(trim($name)); 889a6f13a4aSGreg Roach } 890a6f13a4aSGreg Roach } 891a6f13a4aSGreg Roach } 892a6f13a4aSGreg Roach 893a6f13a4aSGreg Roach /** 89476692c8bSGreg Roach * XML <GedcomValue/> 895a6f13a4aSGreg Roach * 896a6f13a4aSGreg Roach * @param array $attrs an array of key value pairs for the attributes 897a6f13a4aSGreg Roach */ 8988edd1043SGreg Roach private function gedcomValueStartHandler($attrs) { 899a6f13a4aSGreg Roach global $WT_TREE; 900a6f13a4aSGreg Roach 901a6f13a4aSGreg Roach $id = ""; 902a6f13a4aSGreg Roach $match = array(); 903a6f13a4aSGreg Roach if (preg_match("/0 @(.+)@/", $this->gedrec, $match)) { 904a6f13a4aSGreg Roach $id = $match[1]; 905a6f13a4aSGreg Roach } 906a6f13a4aSGreg Roach 907a6f13a4aSGreg Roach if (isset($attrs['newline']) && $attrs['newline'] == "1") { 908a6f13a4aSGreg Roach $useBreak = "1"; 909a6f13a4aSGreg Roach } else { 910a6f13a4aSGreg Roach $useBreak = "0"; 911a6f13a4aSGreg Roach } 912a6f13a4aSGreg Roach 913a6f13a4aSGreg Roach $tag = $attrs['tag']; 914a6f13a4aSGreg Roach if (!empty($tag)) { 915a6f13a4aSGreg Roach if ($tag == "@desc") { 916a6f13a4aSGreg Roach $value = $this->desc; 917a6f13a4aSGreg Roach $value = trim($value); 918a6f13a4aSGreg Roach $this->current_element->addText($value); 919a6f13a4aSGreg Roach } 920a6f13a4aSGreg Roach if ($tag == "@id") { 921a6f13a4aSGreg Roach $this->current_element->addText($id); 922a6f13a4aSGreg Roach } else { 923a6f13a4aSGreg Roach $tag = str_replace("@fact", $this->fact, $tag); 924a6f13a4aSGreg Roach if (empty($attrs['level'])) { 925a6f13a4aSGreg Roach $temp = explode(" ", trim($this->gedrec)); 926a6f13a4aSGreg Roach $level = $temp[0]; 927a6f13a4aSGreg Roach if ($level == 0) { 928a6f13a4aSGreg Roach $level++; 929a6f13a4aSGreg Roach } 930a6f13a4aSGreg Roach } else { 931a6f13a4aSGreg Roach $level = $attrs['level']; 932a6f13a4aSGreg Roach } 933a6f13a4aSGreg Roach $tags = preg_split('/[: ]/', $tag); 9343d7a8a4cSGreg Roach $value = $this->getGedcomValue($tag, $level, $this->gedrec); 935a6f13a4aSGreg Roach switch (end($tags)) { 936a6f13a4aSGreg Roach case 'DATE': 937a6f13a4aSGreg Roach $tmp = new Date($value); 938a6f13a4aSGreg Roach $value = $tmp->display(); 939a6f13a4aSGreg Roach break; 940a6f13a4aSGreg Roach case 'PLAC': 941a6f13a4aSGreg Roach $tmp = new Place($value, $WT_TREE); 942a6f13a4aSGreg Roach $value = $tmp->getShortName(); 943a6f13a4aSGreg Roach break; 944a6f13a4aSGreg Roach } 945a6f13a4aSGreg Roach if ($useBreak == "1") { 946a6f13a4aSGreg Roach // Insert <br> when multiple dates exist. 947a6f13a4aSGreg Roach // This works around a TCPDF bug that incorrectly wraps RTL dates on LTR pages 948a6f13a4aSGreg Roach $value = str_replace('(', '<br>(', $value); 949a6f13a4aSGreg Roach $value = str_replace('<span dir="ltr"><br>', '<br><span dir="ltr">', $value); 950a6f13a4aSGreg Roach $value = str_replace('<span dir="rtl"><br>', '<br><span dir="rtl">', $value); 951a6f13a4aSGreg Roach if (substr($value, 0, 6) == '<br>') { 952a6f13a4aSGreg Roach $value = substr($value, 6); 953a6f13a4aSGreg Roach } 954a6f13a4aSGreg Roach } 955a6f13a4aSGreg Roach $this->current_element->addText($value); 956a6f13a4aSGreg Roach } 957a6f13a4aSGreg Roach } 958a6f13a4aSGreg Roach } 959a6f13a4aSGreg Roach 960a6f13a4aSGreg Roach /** 96176692c8bSGreg Roach * XML <RepeatTag> 962a6f13a4aSGreg Roach * 963a6f13a4aSGreg Roach * @param array $attrs an array of key value pairs for the attributes 964a6f13a4aSGreg Roach */ 9658edd1043SGreg Roach private function repeatTagStartHandler($attrs) { 966a6f13a4aSGreg Roach $this->process_repeats++; 967a6f13a4aSGreg Roach if ($this->process_repeats > 1) { 968a6f13a4aSGreg Roach return; 969a6f13a4aSGreg Roach } 970a6f13a4aSGreg Roach 971a6f13a4aSGreg Roach array_push($this->repeats_stack, array($this->repeats, $this->repeat_bytes)); 972a6f13a4aSGreg Roach $this->repeats = array(); 973e8e7866bSGreg Roach $this->repeat_bytes = xml_get_current_line_number($this->parser); 974a6f13a4aSGreg Roach 975a6f13a4aSGreg Roach $tag = ""; 976a6f13a4aSGreg Roach if (isset($attrs['tag'])) { 977a6f13a4aSGreg Roach $tag = $attrs['tag']; 978a6f13a4aSGreg Roach } 979a6f13a4aSGreg Roach if (!empty($tag)) { 980a6f13a4aSGreg Roach if ($tag == "@desc") { 981a6f13a4aSGreg Roach $value = $this->desc; 982a6f13a4aSGreg Roach $value = trim($value); 983a6f13a4aSGreg Roach $this->current_element->addText($value); 984a6f13a4aSGreg Roach } else { 985a6f13a4aSGreg Roach $tag = str_replace("@fact", $this->fact, $tag); 986a6f13a4aSGreg Roach $tags = explode(":", $tag); 987a6f13a4aSGreg Roach $temp = explode(" ", trim($this->gedrec)); 988a6f13a4aSGreg Roach $level = $temp[0]; 989a6f13a4aSGreg Roach if ($level == 0) { 990a6f13a4aSGreg Roach $level++; 991a6f13a4aSGreg Roach } 992a6f13a4aSGreg Roach $subrec = $this->gedrec; 993a6f13a4aSGreg Roach $t = $tag; 994a6f13a4aSGreg Roach $count = count($tags); 995a6f13a4aSGreg Roach $i = 0; 996a6f13a4aSGreg Roach while ($i < $count) { 997a6f13a4aSGreg Roach $t = $tags[$i]; 998a6f13a4aSGreg Roach if (!empty($t)) { 999a6f13a4aSGreg Roach if ($i < ($count - 1)) { 10003d7a8a4cSGreg Roach $subrec = Functions::getSubRecord($level, "$level $t", $subrec); 1001a6f13a4aSGreg Roach if (empty($subrec)) { 1002a6f13a4aSGreg Roach $level--; 10033d7a8a4cSGreg Roach $subrec = Functions::getSubRecord($level, "@ $t", $this->gedrec); 1004a6f13a4aSGreg Roach if (empty($subrec)) { 1005a6f13a4aSGreg Roach return; 1006a6f13a4aSGreg Roach } 1007a6f13a4aSGreg Roach } 1008a6f13a4aSGreg Roach } 1009a6f13a4aSGreg Roach $level++; 1010a6f13a4aSGreg Roach } 1011a6f13a4aSGreg Roach $i++; 1012a6f13a4aSGreg Roach } 1013a6f13a4aSGreg Roach $level--; 1014a6f13a4aSGreg Roach $count = preg_match_all("/$level $t(.*)/", $subrec, $match, PREG_SET_ORDER); 1015a6f13a4aSGreg Roach $i = 0; 1016a6f13a4aSGreg Roach while ($i < $count) { 10173d7a8a4cSGreg Roach $this->repeats[] = Functions::getSubRecord($level, "$level $t", $subrec, $i + 1); 1018a6f13a4aSGreg Roach $i++; 1019a6f13a4aSGreg Roach } 1020a6f13a4aSGreg Roach } 1021a6f13a4aSGreg Roach } 1022a6f13a4aSGreg Roach } 1023a6f13a4aSGreg Roach 1024a6f13a4aSGreg Roach /** 102576692c8bSGreg Roach * XML </ RepeatTag> 1026a6f13a4aSGreg Roach */ 10278edd1043SGreg Roach private function repeatTagEndHandler() { 1028e8e7866bSGreg Roach global $report; 1029a6f13a4aSGreg Roach 1030a6f13a4aSGreg Roach $this->process_repeats--; 1031a6f13a4aSGreg Roach if ($this->process_repeats > 0) { 1032a6f13a4aSGreg Roach return; 1033a6f13a4aSGreg Roach } 1034a6f13a4aSGreg Roach 1035a6f13a4aSGreg Roach // Check if there is anything to repeat 1036a6f13a4aSGreg Roach if (count($this->repeats) > 0) { 1037a6f13a4aSGreg Roach // No need to load them if not used... 1038a6f13a4aSGreg Roach 1039a6f13a4aSGreg Roach $lineoffset = 0; 1040a6f13a4aSGreg Roach foreach ($this->repeats_stack as $rep) { 1041a6f13a4aSGreg Roach $lineoffset += $rep[1]; 1042a6f13a4aSGreg Roach } 1043a6f13a4aSGreg Roach //-- read the xml from the file 1044a6f13a4aSGreg Roach $lines = file($report); 1045a6f13a4aSGreg Roach while (strpos($lines[$lineoffset + $this->repeat_bytes], "<RepeatTag") === false) { 1046a6f13a4aSGreg Roach $lineoffset--; 1047a6f13a4aSGreg Roach } 1048a6f13a4aSGreg Roach $lineoffset++; 1049a6f13a4aSGreg Roach $reportxml = "<tempdoc>\n"; 1050a6f13a4aSGreg Roach $line_nr = $lineoffset + $this->repeat_bytes; 1051a6f13a4aSGreg Roach // RepeatTag Level counter 1052a6f13a4aSGreg Roach $count = 1; 1053a6f13a4aSGreg Roach while (0 < $count) { 1054a6f13a4aSGreg Roach if (strstr($lines[$line_nr], "<RepeatTag") !== false) { 1055a6f13a4aSGreg Roach $count++; 1056a6f13a4aSGreg Roach } elseif (strstr($lines[$line_nr], "</RepeatTag") !== false) { 1057a6f13a4aSGreg Roach $count--; 1058a6f13a4aSGreg Roach } 1059a6f13a4aSGreg Roach if (0 < $count) { 1060a6f13a4aSGreg Roach $reportxml .= $lines[$line_nr]; 1061a6f13a4aSGreg Roach } 1062a6f13a4aSGreg Roach $line_nr++; 1063a6f13a4aSGreg Roach } 1064a6f13a4aSGreg Roach // No need to drag this 1065a6f13a4aSGreg Roach unset($lines); 1066a6f13a4aSGreg Roach $reportxml .= "</tempdoc>\n"; 1067a6f13a4aSGreg Roach // Save original values 1068e8e7866bSGreg Roach array_push($this->parser_stack, $this->parser); 1069a6f13a4aSGreg Roach $oldgedrec = $this->gedrec; 1070a6f13a4aSGreg Roach foreach ($this->repeats as $gedrec) { 1071a6f13a4aSGreg Roach $this->gedrec = $gedrec; 1072a6f13a4aSGreg Roach $repeat_parser = xml_parser_create(); 1073e8e7866bSGreg Roach $this->parser = $repeat_parser; 1074a6f13a4aSGreg Roach xml_parser_set_option($repeat_parser, XML_OPTION_CASE_FOLDING, false); 1075a6f13a4aSGreg Roach xml_set_element_handler($repeat_parser, array($this, 'startElement'), array($this, 'endElement')); 1076a6f13a4aSGreg Roach xml_set_character_data_handler($repeat_parser, array($this, 'characterData')); 1077a6f13a4aSGreg Roach if (!xml_parse($repeat_parser, $reportxml, true)) { 1078a6f13a4aSGreg Roach throw new \DomainException(sprintf( 1079a6f13a4aSGreg Roach 'RepeatTagEHandler XML error: %s at line %d', 1080a6f13a4aSGreg Roach xml_error_string(xml_get_error_code($repeat_parser)), 1081a6f13a4aSGreg Roach xml_get_current_line_number($repeat_parser) 1082a6f13a4aSGreg Roach )); 1083a6f13a4aSGreg Roach } 1084a6f13a4aSGreg Roach xml_parser_free($repeat_parser); 1085a6f13a4aSGreg Roach } 1086a6f13a4aSGreg Roach // Restore original values 1087a6f13a4aSGreg Roach $this->gedrec = $oldgedrec; 1088e8e7866bSGreg Roach $this->parser = array_pop($this->parser_stack); 1089a6f13a4aSGreg Roach } 1090a6f13a4aSGreg Roach list($this->repeats, $this->repeat_bytes) = array_pop($this->repeats_stack); 1091a6f13a4aSGreg Roach } 1092a6f13a4aSGreg Roach 1093a6f13a4aSGreg Roach /** 1094a6f13a4aSGreg Roach * Variable lookup 1095a6f13a4aSGreg Roach * 1096a6f13a4aSGreg Roach * Retrieve predefined variables : 1097a6f13a4aSGreg Roach * 1098a6f13a4aSGreg Roach * @ desc GEDCOM fact description, example: 1099a6f13a4aSGreg Roach * 1 EVEN This is a description 1100a6f13a4aSGreg Roach * @ fact GEDCOM fact tag, such as BIRT, DEAT etc. 1101a6f13a4aSGreg Roach * $ I18N::translate('....') 1102a6f13a4aSGreg Roach * $ language_settings[] 1103a6f13a4aSGreg Roach * 1104a6f13a4aSGreg Roach * @param array $attrs an array of key value pairs for the attributes 1105a6f13a4aSGreg Roach */ 11068edd1043SGreg Roach private function varStartHandler($attrs) { 1107a6f13a4aSGreg Roach if (empty($attrs['var'])) { 1108e8e7866bSGreg Roach throw new \DomainException('REPORT ERROR var: The attribute "var=" is missing or not set in the XML file on line: ' . xml_get_current_line_number($this->parser)); 1109a6f13a4aSGreg Roach } 1110a6f13a4aSGreg Roach 1111a6f13a4aSGreg Roach $var = $attrs['var']; 1112a6f13a4aSGreg Roach // SetVar element preset variables 1113d1286247SGreg Roach if (!empty($this->vars[$var]['id'])) { 1114d1286247SGreg Roach $var = $this->vars[$var]['id']; 1115a6f13a4aSGreg Roach } else { 1116a6f13a4aSGreg Roach $tfact = $this->fact; 1117a6f13a4aSGreg Roach if (($this->fact === "EVEN" || $this->fact === "FACT") && $this->type !== " ") { 1118a6f13a4aSGreg Roach // Use : 1119a6f13a4aSGreg Roach // n TYPE This text if string 1120a6f13a4aSGreg Roach $tfact = $this->type; 1121a6f13a4aSGreg Roach } 1122a6f13a4aSGreg Roach $var = str_replace(array("@fact", "@desc"), array(GedcomTag::getLabel($tfact), $this->desc), $var); 1123a6f13a4aSGreg Roach if (preg_match('/^I18N::number\((.+)\)$/', $var, $match)) { 1124a6f13a4aSGreg Roach $var = I18N::number($match[1]); 1125a6f13a4aSGreg Roach } elseif (preg_match('/^I18N::translate\(\'(.+)\'\)$/', $var, $match)) { 1126a6f13a4aSGreg Roach $var = I18N::translate($match[1]); 1127a4956c0eSGreg Roach } elseif (preg_match('/^I18N::translateContext\(\'(.+)\', *\'(.+)\'\)$/', $var, $match)) { 1128a6f13a4aSGreg Roach $var = I18N::translateContext($match[1], $match[2]); 1129a6f13a4aSGreg Roach } 1130a6f13a4aSGreg Roach } 1131a6f13a4aSGreg Roach // Check if variable is set as a date and reformat the date 1132a6f13a4aSGreg Roach if (isset($attrs['date'])) { 1133a6f13a4aSGreg Roach if ($attrs['date'] === "1") { 1134a6f13a4aSGreg Roach $g = new Date($var); 1135a6f13a4aSGreg Roach $var = $g->display(); 1136a6f13a4aSGreg Roach } 1137a6f13a4aSGreg Roach } 1138a6f13a4aSGreg Roach $this->current_element->addText($var); 11392836aa05SGreg Roach $this->text = $var; // Used for title/descriptio 1140a6f13a4aSGreg Roach } 1141a6f13a4aSGreg Roach 1142a6f13a4aSGreg Roach /** 114376692c8bSGreg Roach * XML <Facts> 114476692c8bSGreg Roach * 1145a6f13a4aSGreg Roach * @param array $attrs an array of key value pairs for the attributes 1146a6f13a4aSGreg Roach */ 11478edd1043SGreg Roach private function factsStartHandler($attrs) { 1148d1286247SGreg Roach global $WT_TREE; 1149a6f13a4aSGreg Roach 1150a6f13a4aSGreg Roach $this->process_repeats++; 1151a6f13a4aSGreg Roach if ($this->process_repeats > 1) { 1152a6f13a4aSGreg Roach return; 1153a6f13a4aSGreg Roach } 1154a6f13a4aSGreg Roach 1155a6f13a4aSGreg Roach array_push($this->repeats_stack, array($this->repeats, $this->repeat_bytes)); 1156a6f13a4aSGreg Roach $this->repeats = array(); 1157e8e7866bSGreg Roach $this->repeat_bytes = xml_get_current_line_number($this->parser); 1158a6f13a4aSGreg Roach 1159a6f13a4aSGreg Roach $id = ""; 1160a6f13a4aSGreg Roach $match = array(); 1161a6f13a4aSGreg Roach if (preg_match("/0 @(.+)@/", $this->gedrec, $match)) { 1162a6f13a4aSGreg Roach $id = $match[1]; 1163a6f13a4aSGreg Roach } 1164a6f13a4aSGreg Roach $tag = ""; 1165a6f13a4aSGreg Roach if (isset($attrs['ignore'])) { 1166a6f13a4aSGreg Roach $tag .= $attrs['ignore']; 1167a6f13a4aSGreg Roach } 1168a6f13a4aSGreg Roach if (preg_match("/\\$(.+)/", $tag, $match)) { 1169d1286247SGreg Roach $tag = $this->vars[$match[1]]['id']; 1170a6f13a4aSGreg Roach } 1171a6f13a4aSGreg Roach 1172a6f13a4aSGreg Roach $record = GedcomRecord::getInstance($id, $WT_TREE); 1173a6f13a4aSGreg Roach if (empty($attrs['diff']) && !empty($id)) { 1174a6f13a4aSGreg Roach $facts = $record->getFacts(); 11753d7a8a4cSGreg Roach Functions::sortFacts($facts); 1176a6f13a4aSGreg Roach $this->repeats = array(); 1177a6f13a4aSGreg Roach $nonfacts = explode(',', $tag); 1178a6f13a4aSGreg Roach foreach ($facts as $event) { 1179a6f13a4aSGreg Roach if (!in_array($event->getTag(), $nonfacts)) { 1180a6f13a4aSGreg Roach $this->repeats[] = $event->getGedcom(); 1181a6f13a4aSGreg Roach } 1182a6f13a4aSGreg Roach } 1183a6f13a4aSGreg Roach } else { 1184a6f13a4aSGreg Roach foreach ($record->getFacts() as $fact) { 1185a6f13a4aSGreg Roach if ($fact->isPendingAddition() && $fact->getTag() !== 'CHAN') { 1186a6f13a4aSGreg Roach $this->repeats[] = $fact->getGedcom(); 1187a6f13a4aSGreg Roach } 1188a6f13a4aSGreg Roach } 1189a6f13a4aSGreg Roach } 1190a6f13a4aSGreg Roach } 1191a6f13a4aSGreg Roach 1192a6f13a4aSGreg Roach /** 119376692c8bSGreg Roach * XML </Facts> 1194a6f13a4aSGreg Roach */ 11958edd1043SGreg Roach private function factsEndHandler() { 1196e8e7866bSGreg Roach global $report; 1197a6f13a4aSGreg Roach 1198a6f13a4aSGreg Roach $this->process_repeats--; 1199a6f13a4aSGreg Roach if ($this->process_repeats > 0) { 1200a6f13a4aSGreg Roach return; 1201a6f13a4aSGreg Roach } 1202a6f13a4aSGreg Roach 1203a6f13a4aSGreg Roach // Check if there is anything to repeat 1204a6f13a4aSGreg Roach if (count($this->repeats) > 0) { 1205a6f13a4aSGreg Roach 1206e8e7866bSGreg Roach $line = xml_get_current_line_number($this->parser) - 1; 1207a6f13a4aSGreg Roach $lineoffset = 0; 1208a6f13a4aSGreg Roach foreach ($this->repeats_stack as $rep) { 1209a6f13a4aSGreg Roach $lineoffset += $rep[1]; 1210a6f13a4aSGreg Roach } 1211a6f13a4aSGreg Roach 1212a6f13a4aSGreg Roach //-- read the xml from the file 1213a6f13a4aSGreg Roach $lines = file($report); 1214a6f13a4aSGreg Roach while ($lineoffset + $this->repeat_bytes > 0 && strpos($lines[$lineoffset + $this->repeat_bytes], '<Facts ') === false) { 1215a6f13a4aSGreg Roach $lineoffset--; 1216a6f13a4aSGreg Roach } 1217a6f13a4aSGreg Roach $lineoffset++; 1218a6f13a4aSGreg Roach $reportxml = "<tempdoc>\n"; 1219a6f13a4aSGreg Roach $i = $line + $lineoffset; 1220a6f13a4aSGreg Roach $line_nr = $this->repeat_bytes + $lineoffset; 1221a6f13a4aSGreg Roach while ($line_nr < $i) { 1222a6f13a4aSGreg Roach $reportxml .= $lines[$line_nr]; 1223a6f13a4aSGreg Roach $line_nr++; 1224a6f13a4aSGreg Roach } 1225a6f13a4aSGreg Roach // No need to drag this 1226a6f13a4aSGreg Roach unset($lines); 1227a6f13a4aSGreg Roach $reportxml .= "</tempdoc>\n"; 1228a6f13a4aSGreg Roach // Save original values 1229e8e7866bSGreg Roach array_push($this->parser_stack, $this->parser); 1230a6f13a4aSGreg Roach $oldgedrec = $this->gedrec; 1231a6f13a4aSGreg Roach $count = count($this->repeats); 1232a6f13a4aSGreg Roach $i = 0; 1233a6f13a4aSGreg Roach while ($i < $count) { 1234a6f13a4aSGreg Roach $this->gedrec = $this->repeats[$i]; 1235a6f13a4aSGreg Roach $this->fact = ''; 1236a6f13a4aSGreg Roach $this->desc = ''; 1237a6f13a4aSGreg Roach if (preg_match('/1 (\w+)(.*)/', $this->gedrec, $match)) { 1238a6f13a4aSGreg Roach $this->fact = $match[1]; 1239a6f13a4aSGreg Roach if ($this->fact === 'EVEN' || $this->fact === 'FACT') { 1240a6f13a4aSGreg Roach $tmatch = array(); 1241a6f13a4aSGreg Roach if (preg_match('/2 TYPE (.+)/', $this->gedrec, $tmatch)) { 1242a6f13a4aSGreg Roach $this->type = trim($tmatch[1]); 1243a6f13a4aSGreg Roach } else { 1244a6f13a4aSGreg Roach $this->type = ' '; 1245a6f13a4aSGreg Roach } 1246a6f13a4aSGreg Roach } 1247a6f13a4aSGreg Roach $this->desc = trim($match[2]); 12483d7a8a4cSGreg Roach $this->desc .= Functions::getCont(2, $this->gedrec); 1249a6f13a4aSGreg Roach } 1250a6f13a4aSGreg Roach $repeat_parser = xml_parser_create(); 1251e8e7866bSGreg Roach $this->parser = $repeat_parser; 1252a6f13a4aSGreg Roach xml_parser_set_option($repeat_parser, XML_OPTION_CASE_FOLDING, false); 1253a6f13a4aSGreg Roach xml_set_element_handler($repeat_parser, array($this, 'startElement'), array($this, 'endElement')); 1254a6f13a4aSGreg Roach xml_set_character_data_handler($repeat_parser, array($this, 'characterData')); 1255a6f13a4aSGreg Roach if (!xml_parse($repeat_parser, $reportxml, true)) { 1256a6f13a4aSGreg Roach throw new \DomainException(sprintf( 1257a6f13a4aSGreg Roach 'FactsEHandler XML error: %s at line %d', 1258a6f13a4aSGreg Roach xml_error_string(xml_get_error_code($repeat_parser)), 1259a6f13a4aSGreg Roach xml_get_current_line_number($repeat_parser) 1260a6f13a4aSGreg Roach )); 1261a6f13a4aSGreg Roach } 1262a6f13a4aSGreg Roach xml_parser_free($repeat_parser); 1263a6f13a4aSGreg Roach $i++; 1264a6f13a4aSGreg Roach } 1265a6f13a4aSGreg Roach // Restore original values 1266e8e7866bSGreg Roach $this->parser = array_pop($this->parser_stack); 1267a6f13a4aSGreg Roach $this->gedrec = $oldgedrec; 1268a6f13a4aSGreg Roach } 1269a6f13a4aSGreg Roach list($this->repeats, $this->repeat_bytes) = array_pop($this->repeats_stack); 1270a6f13a4aSGreg Roach } 1271a6f13a4aSGreg Roach 1272a6f13a4aSGreg Roach /** 1273a6f13a4aSGreg Roach * Setting upp or changing variables in the XML 1274d1286247SGreg Roach * The XML variable name and value is stored in $this->vars 1275a6f13a4aSGreg Roach * 1276a6f13a4aSGreg Roach * @param array $attrs an array of key value pairs for the attributes 1277a6f13a4aSGreg Roach */ 12788edd1043SGreg Roach private function setVarStartHandler($attrs) { 1279a6f13a4aSGreg Roach if (empty($attrs['name'])) { 1280a6f13a4aSGreg Roach throw new \DomainException('REPORT ERROR var: The attribute "name" is missing or not set in the XML file'); 1281a6f13a4aSGreg Roach } 1282a6f13a4aSGreg Roach 1283a6f13a4aSGreg Roach $name = $attrs['name']; 1284a6f13a4aSGreg Roach $value = $attrs['value']; 1285a6f13a4aSGreg Roach $match = array(); 1286a6f13a4aSGreg Roach // Current GEDCOM record strings 1287a6f13a4aSGreg Roach if ($value == "@ID") { 1288a6f13a4aSGreg Roach if (preg_match("/0 @(.+)@/", $this->gedrec, $match)) { 1289a6f13a4aSGreg Roach $value = $match[1]; 1290a6f13a4aSGreg Roach } 1291a6f13a4aSGreg Roach } elseif ($value == "@fact") { 1292a6f13a4aSGreg Roach $value = $this->fact; 1293a6f13a4aSGreg Roach } elseif ($value == "@desc") { 1294a6f13a4aSGreg Roach $value = $this->desc; 1295a6f13a4aSGreg Roach } elseif ($value == "@generation") { 1296a6f13a4aSGreg Roach $value = $this->generation; 1297a6f13a4aSGreg Roach } elseif (preg_match("/@(\w+)/", $value, $match)) { 1298a6f13a4aSGreg Roach $gmatch = array(); 1299a6f13a4aSGreg Roach if (preg_match("/\d $match[1] (.+)/", $this->gedrec, $gmatch)) { 1300a6f13a4aSGreg Roach $value = str_replace("@", "", trim($gmatch[1])); 1301a6f13a4aSGreg Roach } 1302a6f13a4aSGreg Roach } 1303a6f13a4aSGreg Roach if (preg_match("/\\$(\w+)/", $name, $match)) { 1304d1286247SGreg Roach $name = $this->vars["'" . $match[1] . "'"]['id']; 1305a6f13a4aSGreg Roach } 1306a6f13a4aSGreg Roach $count = preg_match_all("/\\$(\w+)/", $value, $match, PREG_SET_ORDER); 1307a6f13a4aSGreg Roach $i = 0; 1308a6f13a4aSGreg Roach while ($i < $count) { 1309d1286247SGreg Roach $t = $this->vars[$match[$i][1]]['id']; 1310a6f13a4aSGreg Roach $value = preg_replace("/\\$" . $match[$i][1] . "/", $t, $value, 1); 1311a6f13a4aSGreg Roach $i++; 1312a6f13a4aSGreg Roach } 1313a6f13a4aSGreg Roach if (preg_match('/^I18N::number\((.+)\)$/', $value, $match)) { 1314a6f13a4aSGreg Roach $value = I18N::number($match[1]); 1315a6f13a4aSGreg Roach } elseif (preg_match('/^I18N::translate\(\'(.+)\'\)$/', $value, $match)) { 1316a6f13a4aSGreg Roach $value = I18N::translate($match[1]); 1317a4956c0eSGreg Roach } elseif (preg_match('/^I18N::translateContext\(\'(.+)\', *\'(.+)\'\)$/', $value, $match)) { 1318a6f13a4aSGreg Roach $value = I18N::translateContext($match[1], $match[2]); 1319a6f13a4aSGreg Roach } 1320a6f13a4aSGreg Roach // Arithmetic functions 1321a6f13a4aSGreg Roach if (preg_match("/(\d+)\s*([\-\+\*\/])\s*(\d+)/", $value, $match)) { 1322a6f13a4aSGreg Roach switch ($match[2]) { 1323a6f13a4aSGreg Roach case "+": 1324a6f13a4aSGreg Roach $t = $match[1] + $match[3]; 1325a6f13a4aSGreg Roach $value = preg_replace("/" . $match[1] . "\s*([\-\+\*\/])\s*" . $match[3] . "/", $t, $value); 1326a6f13a4aSGreg Roach break; 1327a6f13a4aSGreg Roach case "-": 1328a6f13a4aSGreg Roach $t = $match[1] - $match[3]; 1329a6f13a4aSGreg Roach $value = preg_replace("/" . $match[1] . "\s*([\-\+\*\/])\s*" . $match[3] . "/", $t, $value); 1330a6f13a4aSGreg Roach break; 1331a6f13a4aSGreg Roach case "*": 1332a6f13a4aSGreg Roach $t = $match[1] * $match[3]; 1333a6f13a4aSGreg Roach $value = preg_replace("/" . $match[1] . "\s*([\-\+\*\/])\s*" . $match[3] . "/", $t, $value); 1334a6f13a4aSGreg Roach break; 1335a6f13a4aSGreg Roach case "/": 1336a6f13a4aSGreg Roach $t = $match[1] / $match[3]; 1337a6f13a4aSGreg Roach $value = preg_replace("/" . $match[1] . "\s*([\-\+\*\/])\s*" . $match[3] . "/", $t, $value); 1338a6f13a4aSGreg Roach break; 1339a6f13a4aSGreg Roach } 1340a6f13a4aSGreg Roach } 1341a6f13a4aSGreg Roach if (strpos($value, "@") !== false) { 1342a6f13a4aSGreg Roach $value = ""; 1343a6f13a4aSGreg Roach } 1344d1286247SGreg Roach $this->vars[$name]['id'] = $value; 1345a6f13a4aSGreg Roach } 1346a6f13a4aSGreg Roach 1347a6f13a4aSGreg Roach /** 1348a6f13a4aSGreg Roach * XML <if > start element 1349a6f13a4aSGreg Roach * 1350a6f13a4aSGreg Roach * @param array $attrs an array of key value pairs for the attributes 1351a6f13a4aSGreg Roach */ 13528edd1043SGreg Roach private function ifStartHandler($attrs) { 1353a6f13a4aSGreg Roach if ($this->process_ifs > 0) { 1354a6f13a4aSGreg Roach $this->process_ifs++; 1355a6f13a4aSGreg Roach 1356a6f13a4aSGreg Roach return; 1357a6f13a4aSGreg Roach } 1358a6f13a4aSGreg Roach 1359a6f13a4aSGreg Roach $condition = $attrs['condition']; 136082759250SGreg Roach $condition = $this->substituteVars($condition, true); 1361a6f13a4aSGreg Roach $condition = str_replace(array(" LT ", " GT "), array("<", ">"), $condition); 1362a6f13a4aSGreg Roach // Replace the first accurance only once of @fact:DATE or in any other combinations to the current fact, such as BIRT 1363a6f13a4aSGreg Roach $condition = str_replace("@fact", $this->fact, $condition); 1364a6f13a4aSGreg Roach $match = array(); 1365a6f13a4aSGreg Roach $count = preg_match_all("/@([\w:\.]+)/", $condition, $match, PREG_SET_ORDER); 1366a6f13a4aSGreg Roach $i = 0; 1367a6f13a4aSGreg Roach while ($i < $count) { 1368a6f13a4aSGreg Roach $id = $match[$i][1]; 1369a6f13a4aSGreg Roach $value = '""'; 1370a6f13a4aSGreg Roach if ($id == "ID") { 1371a6f13a4aSGreg Roach if (preg_match("/0 @(.+)@/", $this->gedrec, $match)) { 1372a6f13a4aSGreg Roach $value = "'" . $match[1] . "'"; 1373a6f13a4aSGreg Roach } 1374a6f13a4aSGreg Roach } elseif ($id === "fact") { 1375a6f13a4aSGreg Roach $value = '"' . $this->fact . '"'; 1376a6f13a4aSGreg Roach } elseif ($id === "desc") { 1377a6f13a4aSGreg Roach $value = '"' . addslashes($this->desc) . '"'; 1378a6f13a4aSGreg Roach } elseif ($id === "generation") { 1379a6f13a4aSGreg Roach $value = '"' . $this->generation . '"'; 1380a6f13a4aSGreg Roach } else { 1381a6f13a4aSGreg Roach 1382a6f13a4aSGreg Roach $temp = explode(" ", trim($this->gedrec)); 1383a6f13a4aSGreg Roach $level = $temp[0]; 1384a6f13a4aSGreg Roach if ($level == 0) { 1385a6f13a4aSGreg Roach $level++; 1386a6f13a4aSGreg Roach } 13873d7a8a4cSGreg Roach $value = $this->getGedcomValue($id, $level, $this->gedrec); 1388a6f13a4aSGreg Roach if (empty($value)) { 1389a6f13a4aSGreg Roach $level++; 13903d7a8a4cSGreg Roach $value = $this->getGedcomValue($id, $level, $this->gedrec); 1391a6f13a4aSGreg Roach } 1392a6f13a4aSGreg Roach $value = preg_replace("/^@(" . WT_REGEX_XREF . ")@$/", "$1", $value); 1393a6f13a4aSGreg Roach $value = "\"" . addslashes($value) . "\""; 1394a6f13a4aSGreg Roach } 1395a6f13a4aSGreg Roach $condition = str_replace("@$id", $value, $condition); 1396a6f13a4aSGreg Roach $i++; 1397a6f13a4aSGreg Roach } 1398a6f13a4aSGreg Roach $condition = "return (bool) ($condition);"; 1399a6f13a4aSGreg Roach $ret = @eval($condition); 1400a6f13a4aSGreg Roach if (!$ret) { 1401a6f13a4aSGreg Roach $this->process_ifs++; 1402a6f13a4aSGreg Roach } 1403a6f13a4aSGreg Roach } 1404a6f13a4aSGreg Roach 1405a6f13a4aSGreg Roach /** 1406a6f13a4aSGreg Roach * XML <if /> end element 1407a6f13a4aSGreg Roach */ 14088edd1043SGreg Roach private function ifEndHandler() { 1409a6f13a4aSGreg Roach if ($this->process_ifs > 0) { 1410a6f13a4aSGreg Roach $this->process_ifs--; 1411a6f13a4aSGreg Roach } 1412a6f13a4aSGreg Roach } 1413a6f13a4aSGreg Roach 1414a6f13a4aSGreg Roach /** 1415a6f13a4aSGreg Roach * XML <Footnote > start element 1416a6f13a4aSGreg Roach * Collect the Footnote links 1417a6f13a4aSGreg Roach * GEDCOM Records that are protected by Privacy setting will be ignore 1418a6f13a4aSGreg Roach * 1419a6f13a4aSGreg Roach * @param array $attrs an array of key value pairs for the attributes 1420a6f13a4aSGreg Roach */ 14218edd1043SGreg Roach private function footnoteStartHandler($attrs) { 1422e8e7866bSGreg Roach global $WT_TREE; 1423a6f13a4aSGreg Roach 1424a6f13a4aSGreg Roach $id = ""; 1425a6f13a4aSGreg Roach if (preg_match("/[0-9] (.+) @(.+)@/", $this->gedrec, $match)) { 1426a6f13a4aSGreg Roach $id = $match[2]; 1427a6f13a4aSGreg Roach } 1428a6f13a4aSGreg Roach $record = GedcomRecord::GetInstance($id, $WT_TREE); 1429a6f13a4aSGreg Roach if ($record && $record->canShow()) { 1430a6f13a4aSGreg Roach array_push($this->print_data_stack, $this->print_data); 1431a6f13a4aSGreg Roach $this->print_data = true; 1432a6f13a4aSGreg Roach $style = ""; 1433a6f13a4aSGreg Roach if (!empty($attrs['style'])) { 1434a6f13a4aSGreg Roach $style = $attrs['style']; 1435a6f13a4aSGreg Roach } 1436a6f13a4aSGreg Roach $this->footnote_element = $this->current_element; 1437e8e7866bSGreg Roach $this->current_element = $this->report_root->createFootnote($style); 1438a6f13a4aSGreg Roach } else { 1439a6f13a4aSGreg Roach $this->print_data = false; 1440a6f13a4aSGreg Roach $this->process_footnote = false; 1441a6f13a4aSGreg Roach } 1442a6f13a4aSGreg Roach } 1443a6f13a4aSGreg Roach 1444a6f13a4aSGreg Roach /** 1445a6f13a4aSGreg Roach * XML <Footnote /> end element 1446a6f13a4aSGreg Roach * Print the collected Footnote data 1447a6f13a4aSGreg Roach */ 14488edd1043SGreg Roach private function footnoteEndHandler() { 1449a6f13a4aSGreg Roach if ($this->process_footnote) { 1450a6f13a4aSGreg Roach $this->print_data = array_pop($this->print_data_stack); 1451a6f13a4aSGreg Roach $temp = trim($this->current_element->getValue()); 1452a6f13a4aSGreg Roach if (strlen($temp) > 3) { 1453e8e7866bSGreg Roach $this->wt_report->addElement($this->current_element); 1454a6f13a4aSGreg Roach } 1455a6f13a4aSGreg Roach $this->current_element = $this->footnote_element; 1456a6f13a4aSGreg Roach } else { 1457a6f13a4aSGreg Roach $this->process_footnote = true; 1458a6f13a4aSGreg Roach } 1459a6f13a4aSGreg Roach } 1460a6f13a4aSGreg Roach 1461a6f13a4aSGreg Roach /** 1462a6f13a4aSGreg Roach * XML <FootnoteTexts /> element 1463a6f13a4aSGreg Roach */ 14648edd1043SGreg Roach private function footnoteTextsStartHandler() { 1465a6f13a4aSGreg Roach $temp = "footnotetexts"; 1466e8e7866bSGreg Roach $this->wt_report->addElement($temp); 1467a6f13a4aSGreg Roach } 1468a6f13a4aSGreg Roach 1469a6f13a4aSGreg Roach /** 1470a6f13a4aSGreg Roach * XML <AgeAtDeath /> element handler 1471a6f13a4aSGreg Roach */ 14728edd1043SGreg Roach private function ageAtDeathStartHandler() { 14733d7a8a4cSGreg Roach // This duplicates functionality in FunctionsPrint::format_fact_date() 1474a6f13a4aSGreg Roach global $factrec, $WT_TREE; 1475a6f13a4aSGreg Roach 1476a6f13a4aSGreg Roach $match = array(); 1477a6f13a4aSGreg Roach if (preg_match("/0 @(.+)@/", $this->gedrec, $match)) { 1478a6f13a4aSGreg Roach $person = Individual::getInstance($match[1], $WT_TREE); 1479a6f13a4aSGreg Roach // Recorded age 1480a6f13a4aSGreg Roach if (preg_match('/\n2 AGE (.+)/', $factrec, $match)) { 1481a6f13a4aSGreg Roach $fact_age = $match[1]; 1482a6f13a4aSGreg Roach } else { 1483a6f13a4aSGreg Roach $fact_age = ''; 1484a6f13a4aSGreg Roach } 1485a6f13a4aSGreg Roach if (preg_match('/\n2 HUSB\n3 AGE (.+)/', $factrec, $match)) { 1486a6f13a4aSGreg Roach $husb_age = $match[1]; 1487a6f13a4aSGreg Roach } else { 1488a6f13a4aSGreg Roach $husb_age = ''; 1489a6f13a4aSGreg Roach } 1490a6f13a4aSGreg Roach if (preg_match('/\n2 WIFE\n3 AGE (.+)/', $factrec, $match)) { 1491a6f13a4aSGreg Roach $wife_age = $match[1]; 1492a6f13a4aSGreg Roach } else { 1493a6f13a4aSGreg Roach $wife_age = ''; 1494a6f13a4aSGreg Roach } 1495a6f13a4aSGreg Roach 1496a6f13a4aSGreg Roach // Calculated age 1497a6f13a4aSGreg Roach $birth_date = $person->getBirthDate(); 1498a6f13a4aSGreg Roach // Can't use getDeathDate(), as this also gives BURI/CREM events, which 1499a6f13a4aSGreg Roach // wouldn't give the correct "days after death" result for people with 1500a6f13a4aSGreg Roach // no DEAT. 1501a6f13a4aSGreg Roach $death_event = $person->getFirstFact('DEAT'); 1502a6f13a4aSGreg Roach if ($death_event) { 1503a6f13a4aSGreg Roach $death_date = $death_event->getDate(); 1504a6f13a4aSGreg Roach } else { 1505a6f13a4aSGreg Roach $death_date = new Date(''); 1506a6f13a4aSGreg Roach } 1507a6f13a4aSGreg Roach $value = ''; 1508a6f13a4aSGreg Roach if (Date::compare($birth_date, $death_date) <= 0 || !$person->isDead()) { 1509a6f13a4aSGreg Roach $age = Date::getAgeGedcom($birth_date, $death_date); 1510a6f13a4aSGreg Roach // Only show calculated age if it differs from recorded age 1511a6f13a4aSGreg Roach if ($age != '' && $age != "0d") { 1512a6f13a4aSGreg Roach if ($fact_age != '' && $fact_age != $age || $fact_age == '' && $husb_age == '' && $wife_age == '' || $husb_age != '' && $person->getSex() == 'M' && $husb_age != $age || $wife_age != '' && $person->getSex() == 'F' && $wife_age != $age 1513a6f13a4aSGreg Roach ) { 15143d7a8a4cSGreg Roach $value = FunctionsDate::getAgeAtEvent($age, false); 1515a6f13a4aSGreg Roach $abbrev = substr($value, 0, strpos($value, ' ') + 5); 1516a6f13a4aSGreg Roach if ($value !== $abbrev) { 1517a6f13a4aSGreg Roach $value = $abbrev . '.'; 1518a6f13a4aSGreg Roach } 1519a6f13a4aSGreg Roach } 1520a6f13a4aSGreg Roach } 1521a6f13a4aSGreg Roach } 1522a6f13a4aSGreg Roach $this->current_element->addText($value); 1523a6f13a4aSGreg Roach } 1524a6f13a4aSGreg Roach } 1525a6f13a4aSGreg Roach 1526a6f13a4aSGreg Roach /** 1527a6f13a4aSGreg Roach * XML element Forced line break handler - HTML code 1528a6f13a4aSGreg Roach */ 15298edd1043SGreg Roach private function brStartHandler() { 1530a6f13a4aSGreg Roach if ($this->print_data && $this->process_gedcoms === 0) { 1531a6f13a4aSGreg Roach $this->current_element->addText('<br>'); 1532a6f13a4aSGreg Roach } 1533a6f13a4aSGreg Roach } 1534a6f13a4aSGreg Roach 1535a6f13a4aSGreg Roach /** 1536a6f13a4aSGreg Roach * XML <sp />element Forced space handler 1537a6f13a4aSGreg Roach */ 15388edd1043SGreg Roach private function spStartHandler() { 1539a6f13a4aSGreg Roach if ($this->print_data && $this->process_gedcoms === 0) { 1540a6f13a4aSGreg Roach $this->current_element->addText(' '); 1541a6f13a4aSGreg Roach } 1542a6f13a4aSGreg Roach } 1543a6f13a4aSGreg Roach 1544a6f13a4aSGreg Roach /** 154576692c8bSGreg Roach * XML <HighlightedImage/> 154676692c8bSGreg Roach * 1547a6f13a4aSGreg Roach * @param array $attrs an array of key value pairs for the attributes 1548a6f13a4aSGreg Roach */ 15498edd1043SGreg Roach private function highlightedImageStartHandler($attrs) { 1550e8e7866bSGreg Roach global $WT_TREE; 1551a6f13a4aSGreg Roach 1552a6f13a4aSGreg Roach $id = ''; 1553a6f13a4aSGreg Roach $match = array(); 1554a6f13a4aSGreg Roach if (preg_match("/0 @(.+)@/", $this->gedrec, $match)) { 1555a6f13a4aSGreg Roach $id = $match[1]; 1556a6f13a4aSGreg Roach } 1557a6f13a4aSGreg Roach 1558a6f13a4aSGreg Roach // mixed Position the top corner of this box on the page. the default is the current position 1559a6f13a4aSGreg Roach $top = '.'; 1560a6f13a4aSGreg Roach if (isset($attrs['top'])) { 1561a6f13a4aSGreg Roach if ($attrs['top'] === '0') { 1562a6f13a4aSGreg Roach $top = 0; 1563a6f13a4aSGreg Roach } elseif ($attrs['top'] === '.') { 1564a6f13a4aSGreg Roach $top = '.'; 1565a6f13a4aSGreg Roach } elseif (!empty($attrs['top'])) { 1566a6f13a4aSGreg Roach $top = (int) $attrs['top']; 1567a6f13a4aSGreg Roach } 1568a6f13a4aSGreg Roach } 1569a6f13a4aSGreg Roach 1570a6f13a4aSGreg Roach // mixed Position the left corner of this box on the page. the default is the current position 1571a6f13a4aSGreg Roach $left = '.'; 1572a6f13a4aSGreg Roach if (isset($attrs['left'])) { 1573a6f13a4aSGreg Roach if ($attrs['left'] === '0') { 1574a6f13a4aSGreg Roach $left = 0; 1575a6f13a4aSGreg Roach } elseif ($attrs['left'] === '.') { 1576a6f13a4aSGreg Roach $left = '.'; 1577a6f13a4aSGreg Roach } elseif (!empty($attrs['left'])) { 1578a6f13a4aSGreg Roach $left = (int) $attrs['left']; 1579a6f13a4aSGreg Roach } 1580a6f13a4aSGreg Roach } 1581a6f13a4aSGreg Roach 1582a6f13a4aSGreg Roach // string Align the image in left, center, right 1583a6f13a4aSGreg Roach $align = ''; 1584a6f13a4aSGreg Roach if (!empty($attrs['align'])) { 1585a6f13a4aSGreg Roach $align = $attrs['align']; 1586a6f13a4aSGreg Roach } 1587a6f13a4aSGreg Roach 1588a6f13a4aSGreg Roach // string Next Line should be T:next to the image, N:next line 1589a6f13a4aSGreg Roach $ln = ''; 1590a6f13a4aSGreg Roach if (!empty($attrs['ln'])) { 1591a6f13a4aSGreg Roach $ln = $attrs['ln']; 1592a6f13a4aSGreg Roach } 1593a6f13a4aSGreg Roach 1594a6f13a4aSGreg Roach $width = 0; 1595a6f13a4aSGreg Roach $height = 0; 1596a6f13a4aSGreg Roach if (!empty($attrs['width'])) { 1597a6f13a4aSGreg Roach $width = (int) $attrs['width']; 1598a6f13a4aSGreg Roach } 1599a6f13a4aSGreg Roach if (!empty($attrs['height'])) { 1600a6f13a4aSGreg Roach $height = (int) $attrs['height']; 1601a6f13a4aSGreg Roach } 1602a6f13a4aSGreg Roach 1603a6f13a4aSGreg Roach $person = Individual::getInstance($id, $WT_TREE); 1604a6f13a4aSGreg Roach $mediaobject = $person->findHighlightedMedia(); 1605a6f13a4aSGreg Roach if ($mediaobject) { 1606a6f13a4aSGreg Roach $attributes = $mediaobject->getImageAttributes('thumb'); 1607a6f13a4aSGreg Roach if (in_array( 1608a6f13a4aSGreg Roach $attributes['ext'], 1609a6f13a4aSGreg Roach array( 1610a6f13a4aSGreg Roach 'GIF', 1611a6f13a4aSGreg Roach 'JPG', 1612a6f13a4aSGreg Roach 'PNG', 1613a6f13a4aSGreg Roach 'SWF', 1614a6f13a4aSGreg Roach 'PSD', 1615a6f13a4aSGreg Roach 'BMP', 1616a6f13a4aSGreg Roach 'TIFF', 1617a6f13a4aSGreg Roach 'TIFF', 1618a6f13a4aSGreg Roach 'JPC', 1619a6f13a4aSGreg Roach 'JP2', 1620a6f13a4aSGreg Roach 'JPX', 1621a6f13a4aSGreg Roach 'JB2', 1622a6f13a4aSGreg Roach 'SWC', 1623a6f13a4aSGreg Roach 'IFF', 1624a6f13a4aSGreg Roach 'WBMP', 1625a6f13a4aSGreg Roach 'XBM', 1626a6f13a4aSGreg Roach ) 1627a6f13a4aSGreg Roach ) && $mediaobject->canShow() && $mediaobject->fileExists('thumb') 1628a6f13a4aSGreg Roach ) { 1629a6f13a4aSGreg Roach if ($width > 0 && $height == 0) { 1630a6f13a4aSGreg Roach $perc = $width / $attributes['adjW']; 1631a6f13a4aSGreg Roach $height = round($attributes['adjH'] * $perc); 1632a6f13a4aSGreg Roach } elseif ($height > 0 && $width == 0) { 1633a6f13a4aSGreg Roach $perc = $height / $attributes['adjH']; 1634a6f13a4aSGreg Roach $width = round($attributes['adjW'] * $perc); 1635a6f13a4aSGreg Roach } else { 1636a6f13a4aSGreg Roach $width = $attributes['adjW']; 1637a6f13a4aSGreg Roach $height = $attributes['adjH']; 1638a6f13a4aSGreg Roach } 1639e8e7866bSGreg Roach $image = $this->report_root->createImageFromObject($mediaobject, $left, $top, $width, $height, $align, $ln); 1640e8e7866bSGreg Roach $this->wt_report->addElement($image); 1641a6f13a4aSGreg Roach } 1642a6f13a4aSGreg Roach } 1643a6f13a4aSGreg Roach } 1644a6f13a4aSGreg Roach 1645a6f13a4aSGreg Roach /** 164676692c8bSGreg Roach * XML <Image/> 164776692c8bSGreg Roach * 1648a6f13a4aSGreg Roach * @param array $attrs an array of key value pairs for the attributes 1649a6f13a4aSGreg Roach */ 16508edd1043SGreg Roach private function imageStartHandler($attrs) { 1651e8e7866bSGreg Roach global $WT_TREE; 1652a6f13a4aSGreg Roach 1653a6f13a4aSGreg Roach // mixed Position the top corner of this box on the page. the default is the current position 1654a6f13a4aSGreg Roach $top = '.'; 1655a6f13a4aSGreg Roach if (isset($attrs['top'])) { 1656a6f13a4aSGreg Roach if ($attrs['top'] === "0") { 1657a6f13a4aSGreg Roach $top = 0; 1658a6f13a4aSGreg Roach } elseif ($attrs['top'] === '.') { 1659a6f13a4aSGreg Roach $top = '.'; 1660a6f13a4aSGreg Roach } elseif (!empty($attrs['top'])) { 1661a6f13a4aSGreg Roach $top = (int) $attrs['top']; 1662a6f13a4aSGreg Roach } 1663a6f13a4aSGreg Roach } 1664a6f13a4aSGreg Roach 1665a6f13a4aSGreg Roach // mixed Position the left corner of this box on the page. the default is the current position 1666a6f13a4aSGreg Roach $left = '.'; 1667a6f13a4aSGreg Roach if (isset($attrs['left'])) { 1668a6f13a4aSGreg Roach if ($attrs['left'] === '0') { 1669a6f13a4aSGreg Roach $left = 0; 1670a6f13a4aSGreg Roach } elseif ($attrs['left'] === '.') { 1671a6f13a4aSGreg Roach $left = '.'; 1672a6f13a4aSGreg Roach } elseif (!empty($attrs['left'])) { 1673a6f13a4aSGreg Roach $left = (int) $attrs['left']; 1674a6f13a4aSGreg Roach } 1675a6f13a4aSGreg Roach } 1676a6f13a4aSGreg Roach 1677a6f13a4aSGreg Roach // string Align the image in left, center, right 1678a6f13a4aSGreg Roach $align = ''; 1679a6f13a4aSGreg Roach if (!empty($attrs['align'])) { 1680a6f13a4aSGreg Roach $align = $attrs['align']; 1681a6f13a4aSGreg Roach } 1682a6f13a4aSGreg Roach 1683a6f13a4aSGreg Roach // string Next Line should be T:next to the image, N:next line 1684a6f13a4aSGreg Roach $ln = 'T'; 1685a6f13a4aSGreg Roach if (!empty($attrs['ln'])) { 1686a6f13a4aSGreg Roach $ln = $attrs['ln']; 1687a6f13a4aSGreg Roach } 1688a6f13a4aSGreg Roach 1689a6f13a4aSGreg Roach $width = 0; 1690a6f13a4aSGreg Roach $height = 0; 1691a6f13a4aSGreg Roach if (!empty($attrs['width'])) { 1692a6f13a4aSGreg Roach $width = (int) $attrs['width']; 1693a6f13a4aSGreg Roach } 1694a6f13a4aSGreg Roach if (!empty($attrs['height'])) { 1695a6f13a4aSGreg Roach $height = (int) $attrs['height']; 1696a6f13a4aSGreg Roach } 1697a6f13a4aSGreg Roach 1698a6f13a4aSGreg Roach $file = ''; 1699a6f13a4aSGreg Roach if (!empty($attrs['file'])) { 1700a6f13a4aSGreg Roach $file = $attrs['file']; 1701a6f13a4aSGreg Roach } 1702a6f13a4aSGreg Roach if ($file == "@FILE") { 1703a6f13a4aSGreg Roach $match = array(); 1704a6f13a4aSGreg Roach if (preg_match("/\d OBJE @(.+)@/", $this->gedrec, $match)) { 1705a6f13a4aSGreg Roach $mediaobject = Media::getInstance($match[1], $WT_TREE); 1706a6f13a4aSGreg Roach $attributes = $mediaobject->getImageAttributes('thumb'); 1707a6f13a4aSGreg Roach if (in_array( 1708a6f13a4aSGreg Roach $attributes['ext'], 1709a6f13a4aSGreg Roach array( 1710a6f13a4aSGreg Roach 'GIF', 1711a6f13a4aSGreg Roach 'JPG', 1712a6f13a4aSGreg Roach 'PNG', 1713a6f13a4aSGreg Roach 'SWF', 1714a6f13a4aSGreg Roach 'PSD', 1715a6f13a4aSGreg Roach 'BMP', 1716a6f13a4aSGreg Roach 'TIFF', 1717a6f13a4aSGreg Roach 'TIFF', 1718a6f13a4aSGreg Roach 'JPC', 1719a6f13a4aSGreg Roach 'JP2', 1720a6f13a4aSGreg Roach 'JPX', 1721a6f13a4aSGreg Roach 'JB2', 1722a6f13a4aSGreg Roach 'SWC', 1723a6f13a4aSGreg Roach 'IFF', 1724a6f13a4aSGreg Roach 'WBMP', 1725a6f13a4aSGreg Roach 'XBM', 1726a6f13a4aSGreg Roach ) 1727a6f13a4aSGreg Roach ) && $mediaobject->canShow() && $mediaobject->fileExists('thumb') 1728a6f13a4aSGreg Roach ) { 1729a6f13a4aSGreg Roach if ($width > 0 && $height == 0) { 1730a6f13a4aSGreg Roach $perc = $width / $attributes['adjW']; 1731a6f13a4aSGreg Roach $height = round($attributes['adjH'] * $perc); 1732a6f13a4aSGreg Roach } elseif ($height > 0 && $width == 0) { 1733a6f13a4aSGreg Roach $perc = $height / $attributes['adjH']; 1734a6f13a4aSGreg Roach $width = round($attributes['adjW'] * $perc); 1735a6f13a4aSGreg Roach } else { 1736a6f13a4aSGreg Roach $width = $attributes['adjW']; 1737a6f13a4aSGreg Roach $height = $attributes['adjH']; 1738a6f13a4aSGreg Roach } 1739e8e7866bSGreg Roach $image = $this->report_root->createImageFromObject($mediaobject, $left, $top, $width, $height, $align, $ln); 1740e8e7866bSGreg Roach $this->wt_report->addElement($image); 1741a6f13a4aSGreg Roach } 1742a6f13a4aSGreg Roach } 1743a6f13a4aSGreg Roach } else { 1744a6f13a4aSGreg Roach if (file_exists($file) && preg_match("/(jpg|jpeg|png|gif)$/i", $file)) { 1745a6f13a4aSGreg Roach $size = getimagesize($file); 1746a6f13a4aSGreg Roach if ($width > 0 && $height == 0) { 1747a6f13a4aSGreg Roach $perc = $width / $size[0]; 1748a6f13a4aSGreg Roach $height = round($size[1] * $perc); 1749a6f13a4aSGreg Roach } elseif ($height > 0 && $width == 0) { 1750a6f13a4aSGreg Roach $perc = $height / $size[1]; 1751a6f13a4aSGreg Roach $width = round($size[0] * $perc); 1752a6f13a4aSGreg Roach } else { 1753a6f13a4aSGreg Roach $width = $size[0]; 1754a6f13a4aSGreg Roach $height = $size[1]; 1755a6f13a4aSGreg Roach } 1756e8e7866bSGreg Roach $image = $this->report_root->createImage($file, $left, $top, $width, $height, $align, $ln); 1757e8e7866bSGreg Roach $this->wt_report->addElement($image); 1758a6f13a4aSGreg Roach } 1759a6f13a4aSGreg Roach } 1760a6f13a4aSGreg Roach } 1761a6f13a4aSGreg Roach 1762a6f13a4aSGreg Roach /** 1763a6f13a4aSGreg Roach * XML <Line> element handler 1764a6f13a4aSGreg Roach * 1765a6f13a4aSGreg Roach * @param array $attrs an array of key value pairs for the attributes 1766a6f13a4aSGreg Roach */ 17678edd1043SGreg Roach private function lineStartHandler($attrs) { 1768a6f13a4aSGreg Roach // Start horizontal position, current position (default) 1769a6f13a4aSGreg Roach $x1 = "."; 1770a6f13a4aSGreg Roach if (isset($attrs['x1'])) { 1771a6f13a4aSGreg Roach if ($attrs['x1'] === "0") { 1772a6f13a4aSGreg Roach $x1 = 0; 1773a6f13a4aSGreg Roach } elseif ($attrs['x1'] === ".") { 1774a6f13a4aSGreg Roach $x1 = "."; 1775a6f13a4aSGreg Roach } elseif (!empty($attrs['x1'])) { 1776a6f13a4aSGreg Roach $x1 = (int) $attrs['x1']; 1777a6f13a4aSGreg Roach } 1778a6f13a4aSGreg Roach } 1779a6f13a4aSGreg Roach // Start vertical position, current position (default) 1780a6f13a4aSGreg Roach $y1 = "."; 1781a6f13a4aSGreg Roach if (isset($attrs['y1'])) { 1782a6f13a4aSGreg Roach if ($attrs['y1'] === "0") { 1783a6f13a4aSGreg Roach $y1 = 0; 1784a6f13a4aSGreg Roach } elseif ($attrs['y1'] === ".") { 1785a6f13a4aSGreg Roach $y1 = "."; 1786a6f13a4aSGreg Roach } elseif (!empty($attrs['y1'])) { 1787a6f13a4aSGreg Roach $y1 = (int) $attrs['y1']; 1788a6f13a4aSGreg Roach } 1789a6f13a4aSGreg Roach } 1790a6f13a4aSGreg Roach // End horizontal position, maximum width (default) 1791a6f13a4aSGreg Roach $x2 = "."; 1792a6f13a4aSGreg Roach if (isset($attrs['x2'])) { 1793a6f13a4aSGreg Roach if ($attrs['x2'] === "0") { 1794a6f13a4aSGreg Roach $x2 = 0; 1795a6f13a4aSGreg Roach } elseif ($attrs['x2'] === ".") { 1796a6f13a4aSGreg Roach $x2 = "."; 1797a6f13a4aSGreg Roach } elseif (!empty($attrs['x2'])) { 1798a6f13a4aSGreg Roach $x2 = (int) $attrs['x2']; 1799a6f13a4aSGreg Roach } 1800a6f13a4aSGreg Roach } 1801a6f13a4aSGreg Roach // End vertical position 1802a6f13a4aSGreg Roach $y2 = "."; 1803a6f13a4aSGreg Roach if (isset($attrs['y2'])) { 1804a6f13a4aSGreg Roach if ($attrs['y2'] === "0") { 1805a6f13a4aSGreg Roach $y2 = 0; 1806a6f13a4aSGreg Roach } elseif ($attrs['y2'] === ".") { 1807a6f13a4aSGreg Roach $y2 = "."; 1808a6f13a4aSGreg Roach } elseif (!empty($attrs['y2'])) { 1809a6f13a4aSGreg Roach $y2 = (int) $attrs['y2']; 1810a6f13a4aSGreg Roach } 1811a6f13a4aSGreg Roach } 1812a6f13a4aSGreg Roach 1813e8e7866bSGreg Roach $line = $this->report_root->createLine($x1, $y1, $x2, $y2); 1814e8e7866bSGreg Roach $this->wt_report->addElement($line); 1815a6f13a4aSGreg Roach } 1816a6f13a4aSGreg Roach 1817a6f13a4aSGreg Roach /** 181876692c8bSGreg Roach * XML <List> 1819a6f13a4aSGreg Roach * 1820a6f13a4aSGreg Roach * @param array $attrs an array of key value pairs for the attributes 1821a6f13a4aSGreg Roach */ 18228edd1043SGreg Roach private function listStartHandler($attrs) { 1823d1286247SGreg Roach global $WT_TREE; 1824a6f13a4aSGreg Roach 1825a6f13a4aSGreg Roach $this->process_repeats++; 1826a6f13a4aSGreg Roach if ($this->process_repeats > 1) { 1827a6f13a4aSGreg Roach return; 1828a6f13a4aSGreg Roach } 1829a6f13a4aSGreg Roach 1830a6f13a4aSGreg Roach $match = array(); 1831a6f13a4aSGreg Roach if (isset($attrs['sortby'])) { 1832a6f13a4aSGreg Roach $sortby = $attrs['sortby']; 1833a6f13a4aSGreg Roach if (preg_match("/\\$(\w+)/", $sortby, $match)) { 1834d1286247SGreg Roach $sortby = $this->vars[$match[1]]['id']; 1835a6f13a4aSGreg Roach $sortby = trim($sortby); 1836a6f13a4aSGreg Roach } 1837a6f13a4aSGreg Roach } else { 1838a6f13a4aSGreg Roach $sortby = "NAME"; 1839a6f13a4aSGreg Roach } 1840a6f13a4aSGreg Roach 1841a6f13a4aSGreg Roach if (isset($attrs['list'])) { 1842a6f13a4aSGreg Roach $listname = $attrs['list']; 1843a6f13a4aSGreg Roach } else { 1844a6f13a4aSGreg Roach $listname = "individual"; 1845a6f13a4aSGreg Roach } 1846a6f13a4aSGreg Roach // Some filters/sorts can be applied using SQL, while others require PHP 1847a6f13a4aSGreg Roach switch ($listname) { 1848a6f13a4aSGreg Roach case "pending": 1849a6f13a4aSGreg Roach $rows = Database::prepare( 18505d0bc43dSGreg Roach "SELECT xref, CASE new_gedcom WHEN '' THEN old_gedcom ELSE new_gedcom END AS gedcom" . 18515d0bc43dSGreg Roach " FROM `##change`" . " WHERE (xref, change_id) IN (" . 18525d0bc43dSGreg Roach " SELECT xref, MAX(change_id)" . 18535d0bc43dSGreg Roach " FROM `##change`" . 18545d0bc43dSGreg Roach " WHERE status = 'pending' AND gedcom_id = :tree_id" . 18555d0bc43dSGreg Roach " GROUP BY xref" . 18565d0bc43dSGreg Roach " )" 18575d0bc43dSGreg Roach )->execute(array( 185876692c8bSGreg Roach 'tree_id' => $WT_TREE->getTreeId(), 18595d0bc43dSGreg Roach ))->fetchAll(); 1860a6f13a4aSGreg Roach $this->list = array(); 1861a6f13a4aSGreg Roach foreach ($rows as $row) { 1862a6f13a4aSGreg Roach $this->list[] = GedcomRecord::getInstance($row->xref, $WT_TREE, $row->gedcom); 1863a6f13a4aSGreg Roach } 1864a6f13a4aSGreg Roach break; 1865a6f13a4aSGreg Roach case 'individual': 1866a6f13a4aSGreg Roach $sql_select = "SELECT DISTINCT i_id AS xref, i_gedcom AS gedcom FROM `##individuals` "; 1867a6f13a4aSGreg Roach $sql_join = ""; 1868825006d2SGreg Roach $sql_where = " WHERE i_file = :tree_id"; 1869a6f13a4aSGreg Roach $sql_order_by = ""; 1870825006d2SGreg Roach $sql_params = array('tree_id' => $WT_TREE->getTreeId()); 1871a6f13a4aSGreg Roach foreach ($attrs as $attr => $value) { 1872a6f13a4aSGreg Roach if (strpos($attr, 'filter') === 0 && $value) { 187382759250SGreg Roach $value = $this->substituteVars($value, false); 1874a6f13a4aSGreg Roach // Convert the various filters into SQL 1875a6f13a4aSGreg Roach if (preg_match('/^(\w+):DATE (LTE|GTE) (.+)$/', $value, $match)) { 1876a6f13a4aSGreg Roach $sql_join .= " JOIN `##dates` AS {$attr} ON ({$attr}.d_file=i_file AND {$attr}.d_gid=i_id)"; 1877b0d2e743SGreg Roach $sql_where .= " AND {$attr}.d_fact = :{$attr}fact"; 18785d0bc43dSGreg Roach $sql_params[$attr . 'fact'] = $match[1]; 1879a6f13a4aSGreg Roach $date = new Date($match[3]); 1880a6f13a4aSGreg Roach if ($match[2] == "LTE") { 18815d0bc43dSGreg Roach $sql_where .= " AND {$attr}.d_julianday2 <= :{$attr}date"; 18825d0bc43dSGreg Roach $sql_params[$attr . 'date'] = $date->maximumJulianDay(); 1883a6f13a4aSGreg Roach } else { 18845d0bc43dSGreg Roach $sql_where .= " AND {$attr}.d_julianday1 >= :{$attr}date"; 18855d0bc43dSGreg Roach $sql_params[$attr . 'date'] = $date->minimumJulianDay(); 1886a6f13a4aSGreg Roach } 1887a6f13a4aSGreg Roach if ($sortby == $match[1]) { 1888a6f13a4aSGreg Roach $sortby = ""; 1889a6f13a4aSGreg Roach $sql_order_by .= ($sql_order_by ? ", " : " ORDER BY ") . "{$attr}.d_julianday1"; 1890a6f13a4aSGreg Roach } 1891a6f13a4aSGreg Roach unset($attrs[$attr]); // This filter has been fully processed 1892a6f13a4aSGreg Roach } elseif (preg_match('/^NAME CONTAINS (.*)$/', $value, $match)) { 1893a6f13a4aSGreg Roach // Do nothing, unless you have to 1894a6f13a4aSGreg Roach if ($match[1] != '' || $sortby == 'NAME') { 1895a6f13a4aSGreg Roach $sql_join .= " JOIN `##name` AS {$attr} ON (n_file=i_file AND n_id=i_id)"; 1896a6f13a4aSGreg Roach // Search the DB only if there is any name supplied 1897a6f13a4aSGreg Roach if ($match[1] != "") { 1898a6f13a4aSGreg Roach $names = explode(" ", $match[1]); 18995d0bc43dSGreg Roach foreach ($names as $n => $name) { 19005d0bc43dSGreg Roach $sql_where .= " AND {$attr}.n_full LIKE CONCAT('%', :{$attr}name{$n}, '%')"; 19015d0bc43dSGreg Roach $sql_params[$attr . 'name' . $n] = $name; 1902a6f13a4aSGreg Roach } 1903a6f13a4aSGreg Roach } 1904a6f13a4aSGreg Roach // Let the DB do the name sorting even when no name was entered 1905a6f13a4aSGreg Roach if ($sortby == "NAME") { 1906a6f13a4aSGreg Roach $sortby = ""; 1907a6f13a4aSGreg Roach $sql_order_by .= ($sql_order_by ? ", " : " ORDER BY ") . "{$attr}.n_sort"; 1908a6f13a4aSGreg Roach } 1909a6f13a4aSGreg Roach } 1910a6f13a4aSGreg Roach unset($attrs[$attr]); // This filter has been fully processed 1911a6f13a4aSGreg Roach } elseif (preg_match('/^REGEXP \/(.+)\//', $value, $match)) { 19125d0bc43dSGreg Roach $sql_where .= " AND i_gedcom REGEXP :{$attr}gedcom"; 1913b4e512fdSGreg Roach // PDO helpfully escapes backslashes for us, preventing us from matching "\n1 FACT" 1914b4e512fdSGreg Roach $sql_params[$attr . 'gedcom'] = str_replace('\n', "\n", $match[1]); 1915a6f13a4aSGreg Roach unset($attrs[$attr]); // This filter has been fully processed 1916a6f13a4aSGreg Roach } elseif (preg_match('/^(?:\w+):PLAC CONTAINS (.+)$/', $value, $match)) { 1917a6f13a4aSGreg Roach $sql_join .= " JOIN `##places` AS {$attr}a ON ({$attr}a.p_file = i_file)"; 1918a6f13a4aSGreg Roach $sql_join .= " JOIN `##placelinks` AS {$attr}b ON ({$attr}a.p_file = {$attr}b.pl_file AND {$attr}b.pl_p_id = {$attr}a.p_id AND {$attr}b.pl_gid = i_id)"; 19195d0bc43dSGreg Roach $sql_where .= " AND {$attr}a.p_place LIKE CONCAT('%', :{$attr}place, '%')"; 19205d0bc43dSGreg Roach $sql_params[$attr . 'place'] = $match[1]; 1921a6f13a4aSGreg Roach // Don't unset this filter. This is just initial filtering 1922a6f13a4aSGreg Roach } elseif (preg_match('/^(\w*):*(\w*) CONTAINS (.+)$/', $value, $match)) { 19235d0bc43dSGreg Roach $sql_where .= " AND i_gedcom LIKE CONCAT('%', :{$attr}contains1, '%', :{$attr}contains2, '%', :{$attr}contains3, '%')"; 19245d0bc43dSGreg Roach $sql_params[$attr . 'contains1'] = $match[1]; 19255d0bc43dSGreg Roach $sql_params[$attr . 'contains2'] = $match[2]; 19265d0bc43dSGreg Roach $sql_params[$attr . 'contains3'] = $match[3]; 1927a6f13a4aSGreg Roach // Don't unset this filter. This is just initial filtering 1928a6f13a4aSGreg Roach } 1929a6f13a4aSGreg Roach } 1930a6f13a4aSGreg Roach } 1931a6f13a4aSGreg Roach 1932a6f13a4aSGreg Roach $this->list = array(); 1933a6f13a4aSGreg Roach $rows = Database::prepare( 1934a6f13a4aSGreg Roach $sql_select . $sql_join . $sql_where . $sql_order_by 19355d0bc43dSGreg Roach )->execute($sql_params)->fetchAll(); 1936a6f13a4aSGreg Roach 1937a6f13a4aSGreg Roach foreach ($rows as $row) { 1938a6f13a4aSGreg Roach $this->list[] = Individual::getInstance($row->xref, $WT_TREE, $row->gedcom); 1939a6f13a4aSGreg Roach } 1940a6f13a4aSGreg Roach break; 1941a6f13a4aSGreg Roach 1942a6f13a4aSGreg Roach case 'family': 1943a6f13a4aSGreg Roach $sql_select = "SELECT DISTINCT f_id AS xref, f_gedcom AS gedcom FROM `##families`"; 1944a6f13a4aSGreg Roach $sql_join = ""; 1945825006d2SGreg Roach $sql_where = " WHERE f_file = :tree_id"; 1946a6f13a4aSGreg Roach $sql_order_by = ""; 1947825006d2SGreg Roach $sql_params = array('tree_id' => $WT_TREE->getTreeId()); 1948a6f13a4aSGreg Roach foreach ($attrs as $attr => $value) { 1949a6f13a4aSGreg Roach if (strpos($attr, 'filter') === 0 && $value) { 195082759250SGreg Roach $value = $this->substituteVars($value, false); 1951a6f13a4aSGreg Roach // Convert the various filters into SQL 1952a6f13a4aSGreg Roach if (preg_match('/^(\w+):DATE (LTE|GTE) (.+)$/', $value, $match)) { 1953b0d2e743SGreg Roach $sql_where .= " AND {$attr}.d_fact = :{$attr}fact"; 19545d0bc43dSGreg Roach $sql_params[$attr . 'fact'] = $match[1]; 1955a6f13a4aSGreg Roach $date = new Date($match[3]); 1956a6f13a4aSGreg Roach if ($match[2] == "LTE") { 19575d0bc43dSGreg Roach $sql_where .= " AND {$attr}.d_julianday2 <= :{$attr}date"; 19585d0bc43dSGreg Roach $sql_params[$attr . 'date'] = $date->maximumJulianDay(); 1959a6f13a4aSGreg Roach } else { 19605d0bc43dSGreg Roach $sql_where .= " AND {$attr}.d_julianday1 >= :{$attr}date"; 19615d0bc43dSGreg Roach $sql_params[$attr . 'date'] = $date->minimumJulianDay(); 1962a6f13a4aSGreg Roach } 1963a6f13a4aSGreg Roach if ($sortby == $match[1]) { 1964a6f13a4aSGreg Roach $sortby = ""; 1965a6f13a4aSGreg Roach $sql_order_by .= ($sql_order_by ? ", " : " ORDER BY ") . "{$attr}.d_julianday1"; 1966a6f13a4aSGreg Roach } 1967a6f13a4aSGreg Roach unset($attrs[$attr]); // This filter has been fully processed 1968a6f13a4aSGreg Roach } elseif (preg_match('/^REGEXP \/(.+)\//', $value, $match)) { 19695d0bc43dSGreg Roach $sql_where .= " AND f_gedcom REGEXP :{$attr}gedcom"; 1970b4e512fdSGreg Roach // PDO helpfully escapes backslashes for us, preventing us from matching "\n1 FACT" 1971b4e512fdSGreg Roach $sql_params[$attr . 'gedcom'] = str_replace('\n', "\n", $match[1]); 1972a6f13a4aSGreg Roach unset($attrs[$attr]); // This filter has been fully processed 1973a6f13a4aSGreg Roach } elseif (preg_match('/^NAME CONTAINS (.+)$/', $value, $match)) { 19745d0bc43dSGreg Roach // Do nothing, unless you have to 19755d0bc43dSGreg Roach if ($match[1] != '' || $sortby == 'NAME') { 19765d0bc43dSGreg Roach $sql_join .= " JOIN `##name` AS {$attr} ON n_file = f_file AND n_id IN (f_husb, f_wife)"; 19775d0bc43dSGreg Roach // Search the DB only if there is any name supplied 19785d0bc43dSGreg Roach if ($match[1] != "") { 19795d0bc43dSGreg Roach $names = explode(" ", $match[1]); 19805d0bc43dSGreg Roach foreach ($names as $n => $name) { 19815d0bc43dSGreg Roach $sql_where .= " AND {$attr}.n_full LIKE CONCAT('%', :{$attr}name{$n}, '%')"; 19825d0bc43dSGreg Roach $sql_params[$attr . 'name' . $n] = $name; 19835d0bc43dSGreg Roach } 19845d0bc43dSGreg Roach } 19855d0bc43dSGreg Roach // Let the DB do the name sorting even when no name was entered 1986a6f13a4aSGreg Roach if ($sortby == "NAME") { 1987a6f13a4aSGreg Roach $sortby = ""; 1988a6f13a4aSGreg Roach $sql_order_by .= ($sql_order_by ? ", " : " ORDER BY ") . "{$attr}.n_sort"; 1989a6f13a4aSGreg Roach } 19905d0bc43dSGreg Roach } 1991a6f13a4aSGreg Roach unset($attrs[$attr]); // This filter has been fully processed 19925d0bc43dSGreg Roach 1993a6f13a4aSGreg Roach } elseif (preg_match('/^(?:\w+):PLAC CONTAINS (.+)$/', $value, $match)) { 1994a6f13a4aSGreg Roach $sql_join .= " JOIN `##places` AS {$attr}a ON ({$attr}a.p_file=f_file)"; 1995a6f13a4aSGreg Roach $sql_join .= " JOIN `##placelinks` AS {$attr}b ON ({$attr}a.p_file={$attr}b.pl_file AND {$attr}b.pl_p_id={$attr}a.p_id AND {$attr}b.pl_gid=f_id)"; 19965d0bc43dSGreg Roach $sql_where .= " AND {$attr}a.p_place LIKE CONCAT('%', :{$attr}place, '%')"; 19975d0bc43dSGreg Roach $sql_params[$attr . 'place'] = $match[1]; 1998a6f13a4aSGreg Roach // Don't unset this filter. This is just initial filtering 1999a6f13a4aSGreg Roach } elseif (preg_match('/^(\w*):*(\w*) CONTAINS (.+)$/', $value, $match)) { 20005d0bc43dSGreg Roach $sql_where .= " AND f_gedcom LIKE CONCAT('%', :{$attr}contains1, '%', :{$attr}contains2, '%', :{$attr}contains3, '%')"; 20015d0bc43dSGreg Roach $sql_params[$attr . 'contains1'] = $match[1]; 20025d0bc43dSGreg Roach $sql_params[$attr . 'contains2'] = $match[2]; 20035d0bc43dSGreg Roach $sql_params[$attr . 'contains3'] = $match[3]; 2004a6f13a4aSGreg Roach // Don't unset this filter. This is just initial filtering 2005a6f13a4aSGreg Roach } 2006a6f13a4aSGreg Roach } 2007a6f13a4aSGreg Roach } 2008a6f13a4aSGreg Roach 2009a6f13a4aSGreg Roach $this->list = array(); 2010a6f13a4aSGreg Roach $rows = Database::prepare( 2011a6f13a4aSGreg Roach $sql_select . $sql_join . $sql_where . $sql_order_by 20125d0bc43dSGreg Roach )->execute($sql_params)->fetchAll(); 2013a6f13a4aSGreg Roach 2014a6f13a4aSGreg Roach foreach ($rows as $row) { 2015a6f13a4aSGreg Roach $this->list[] = Family::getInstance($row->xref, $WT_TREE, $row->gedcom); 2016a6f13a4aSGreg Roach } 2017a6f13a4aSGreg Roach break; 2018a6f13a4aSGreg Roach 2019a6f13a4aSGreg Roach default: 2020a6f13a4aSGreg Roach throw new \DomainException('Invalid list name: ' . $listname); 2021a6f13a4aSGreg Roach } 2022a6f13a4aSGreg Roach 2023a6f13a4aSGreg Roach $filters = array(); 2024a6f13a4aSGreg Roach $filters2 = array(); 2025a6f13a4aSGreg Roach if (isset($attrs['filter1']) && count($this->list) > 0) { 2026a6f13a4aSGreg Roach foreach ($attrs as $key => $value) { 2027a6f13a4aSGreg Roach if (preg_match("/filter(\d)/", $key)) { 2028a6f13a4aSGreg Roach $condition = $value; 2029a6f13a4aSGreg Roach if (preg_match("/@(\w+)/", $condition, $match)) { 2030a6f13a4aSGreg Roach $id = $match[1]; 2031a6f13a4aSGreg Roach $value = "''"; 2032a6f13a4aSGreg Roach if ($id == "ID") { 2033a6f13a4aSGreg Roach if (preg_match("/0 @(.+)@/", $this->gedrec, $match)) { 2034a6f13a4aSGreg Roach $value = "'" . $match[1] . "'"; 2035a6f13a4aSGreg Roach } 2036a6f13a4aSGreg Roach } elseif ($id == "fact") { 2037a6f13a4aSGreg Roach $value = "'" . $this->fact . "'"; 2038a6f13a4aSGreg Roach } elseif ($id == "desc") { 2039a6f13a4aSGreg Roach $value = "'" . $this->desc . "'"; 2040a6f13a4aSGreg Roach } else { 2041a6f13a4aSGreg Roach if (preg_match("/\d $id (.+)/", $this->gedrec, $match)) { 2042a6f13a4aSGreg Roach $value = "'" . str_replace("@", "", trim($match[1])) . "'"; 2043a6f13a4aSGreg Roach } 2044a6f13a4aSGreg Roach } 2045a6f13a4aSGreg Roach $condition = preg_replace("/@$id/", $value, $condition); 2046a6f13a4aSGreg Roach } 2047a6f13a4aSGreg Roach //-- handle regular expressions 2048a6f13a4aSGreg Roach if (preg_match("/([A-Z:]+)\s*([^\s]+)\s*(.+)/", $condition, $match)) { 2049a6f13a4aSGreg Roach $tag = trim($match[1]); 2050a6f13a4aSGreg Roach $expr = trim($match[2]); 2051a6f13a4aSGreg Roach $val = trim($match[3]); 2052a6f13a4aSGreg Roach if (preg_match("/\\$(\w+)/", $val, $match)) { 2053d1286247SGreg Roach $val = $this->vars[$match[1]]['id']; 2054a6f13a4aSGreg Roach $val = trim($val); 2055a6f13a4aSGreg Roach } 2056a6f13a4aSGreg Roach if ($val) { 2057a6f13a4aSGreg Roach $searchstr = ""; 2058a6f13a4aSGreg Roach $tags = explode(":", $tag); 2059a6f13a4aSGreg Roach //-- only limit to a level number if we are specifically looking at a level 2060a6f13a4aSGreg Roach if (count($tags) > 1) { 2061a6f13a4aSGreg Roach $level = 1; 2062a6f13a4aSGreg Roach foreach ($tags as $t) { 2063a6f13a4aSGreg Roach if (!empty($searchstr)) { 2064a6f13a4aSGreg Roach $searchstr .= "[^\n]*(\n[2-9][^\n]*)*\n"; 2065a6f13a4aSGreg Roach } 2066a6f13a4aSGreg Roach //-- search for both EMAIL and _EMAIL... silly double gedcom standard 2067a6f13a4aSGreg Roach if ($t == "EMAIL" || $t == "_EMAIL") { 2068a6f13a4aSGreg Roach $t = "_?EMAIL"; 2069a6f13a4aSGreg Roach } 2070a6f13a4aSGreg Roach $searchstr .= $level . " " . $t; 2071a6f13a4aSGreg Roach $level++; 2072a6f13a4aSGreg Roach } 2073a6f13a4aSGreg Roach } else { 2074a6f13a4aSGreg Roach if ($tag == "EMAIL" || $tag == "_EMAIL") { 2075a6f13a4aSGreg Roach $tag = "_?EMAIL"; 2076a6f13a4aSGreg Roach } 2077a6f13a4aSGreg Roach $t = $tag; 2078a6f13a4aSGreg Roach $searchstr = "1 " . $tag; 2079a6f13a4aSGreg Roach } 2080a6f13a4aSGreg Roach switch ($expr) { 2081a6f13a4aSGreg Roach case "CONTAINS": 2082a6f13a4aSGreg Roach if ($t == "PLAC") { 2083a6f13a4aSGreg Roach $searchstr .= "[^\n]*[, ]*" . $val; 2084a6f13a4aSGreg Roach } else { 2085a6f13a4aSGreg Roach $searchstr .= "[^\n]*" . $val; 2086a6f13a4aSGreg Roach } 2087a6f13a4aSGreg Roach $filters[] = $searchstr; 2088a6f13a4aSGreg Roach break; 2089a6f13a4aSGreg Roach default: 2090a6f13a4aSGreg Roach $filters2[] = array("tag" => $tag, "expr" => $expr, "val" => $val); 2091a6f13a4aSGreg Roach break; 2092a6f13a4aSGreg Roach } 2093a6f13a4aSGreg Roach } 2094a6f13a4aSGreg Roach } 2095a6f13a4aSGreg Roach } 2096a6f13a4aSGreg Roach } 2097a6f13a4aSGreg Roach } 2098a6f13a4aSGreg Roach //-- apply other filters to the list that could not be added to the search string 2099a6f13a4aSGreg Roach if ($filters) { 2100a6f13a4aSGreg Roach foreach ($this->list as $key => $record) { 2101a6f13a4aSGreg Roach foreach ($filters as $filter) { 2102a6f13a4aSGreg Roach if (!preg_match("/" . $filter . "/i", $record->privatizeGedcom(Auth::accessLevel($WT_TREE)))) { 2103a6f13a4aSGreg Roach unset($this->list[$key]); 2104a6f13a4aSGreg Roach break; 2105a6f13a4aSGreg Roach } 2106a6f13a4aSGreg Roach } 2107a6f13a4aSGreg Roach } 2108a6f13a4aSGreg Roach } 2109a6f13a4aSGreg Roach if ($filters2) { 2110a6f13a4aSGreg Roach $mylist = array(); 2111a6f13a4aSGreg Roach foreach ($this->list as $indi) { 2112a6f13a4aSGreg Roach $key = $indi->getXref(); 2113a6f13a4aSGreg Roach $grec = $indi->privatizeGedcom(Auth::accessLevel($WT_TREE)); 2114a6f13a4aSGreg Roach $keep = true; 2115a6f13a4aSGreg Roach foreach ($filters2 as $filter) { 2116a6f13a4aSGreg Roach if ($keep) { 2117a6f13a4aSGreg Roach $tag = $filter['tag']; 2118a6f13a4aSGreg Roach $expr = $filter['expr']; 2119a6f13a4aSGreg Roach $val = $filter['val']; 2120a6f13a4aSGreg Roach if ($val == "''") { 2121a6f13a4aSGreg Roach $val = ""; 2122a6f13a4aSGreg Roach } 2123a6f13a4aSGreg Roach $tags = explode(":", $tag); 2124a6f13a4aSGreg Roach $t = end($tags); 21253d7a8a4cSGreg Roach $v = $this->getGedcomValue($tag, 1, $grec); 2126a6f13a4aSGreg Roach //-- check for EMAIL and _EMAIL (silly double gedcom standard :P) 2127a6f13a4aSGreg Roach if ($t == "EMAIL" && empty($v)) { 2128a6f13a4aSGreg Roach $tag = str_replace("EMAIL", "_EMAIL", $tag); 2129a6f13a4aSGreg Roach $tags = explode(":", $tag); 2130a6f13a4aSGreg Roach $t = end($tags); 21313d7a8a4cSGreg Roach $v = Functions::getSubRecord(1, $tag, $grec); 2132a6f13a4aSGreg Roach } 2133a6f13a4aSGreg Roach 2134a6f13a4aSGreg Roach switch ($expr) { 2135a6f13a4aSGreg Roach case "GTE": 2136a6f13a4aSGreg Roach if ($t == "DATE") { 2137a6f13a4aSGreg Roach $date1 = new Date($v); 2138a6f13a4aSGreg Roach $date2 = new Date($val); 2139a6f13a4aSGreg Roach $keep = (Date::compare($date1, $date2) >= 0); 2140a6f13a4aSGreg Roach } elseif ($val >= $v) { 2141a6f13a4aSGreg Roach $keep = true; 2142a6f13a4aSGreg Roach } 2143a6f13a4aSGreg Roach break; 2144a6f13a4aSGreg Roach case "LTE": 2145a6f13a4aSGreg Roach if ($t == "DATE") { 2146a6f13a4aSGreg Roach $date1 = new Date($v); 2147a6f13a4aSGreg Roach $date2 = new Date($val); 2148a6f13a4aSGreg Roach $keep = (Date::compare($date1, $date2) <= 0); 2149a6f13a4aSGreg Roach } elseif ($val >= $v) { 2150a6f13a4aSGreg Roach $keep = true; 2151a6f13a4aSGreg Roach } 2152a6f13a4aSGreg Roach break; 2153a6f13a4aSGreg Roach default: 2154a6f13a4aSGreg Roach if ($v == $val) { 2155a6f13a4aSGreg Roach $keep = true; 2156a6f13a4aSGreg Roach } else { 2157a6f13a4aSGreg Roach $keep = false; 2158a6f13a4aSGreg Roach } 2159a6f13a4aSGreg Roach break; 2160a6f13a4aSGreg Roach } 2161a6f13a4aSGreg Roach } 2162a6f13a4aSGreg Roach } 2163a6f13a4aSGreg Roach if ($keep) { 2164a6f13a4aSGreg Roach $mylist[$key] = $indi; 2165a6f13a4aSGreg Roach } 2166a6f13a4aSGreg Roach } 2167a6f13a4aSGreg Roach $this->list = $mylist; 2168a6f13a4aSGreg Roach } 2169a6f13a4aSGreg Roach 2170a6f13a4aSGreg Roach switch ($sortby) { 2171a6f13a4aSGreg Roach case 'NAME': 2172a6f13a4aSGreg Roach uasort($this->list, '\Fisharebest\Webtrees\GedcomRecord::compare'); 2173a6f13a4aSGreg Roach break; 2174a6f13a4aSGreg Roach case 'CHAN': 2175a6f13a4aSGreg Roach uasort($this->list, function (GedcomRecord $x, GedcomRecord $y) { 2176a6f13a4aSGreg Roach return $y->lastChangeTimestamp(true) - $x->lastChangeTimestamp(true); 2177a6f13a4aSGreg Roach }); 2178a6f13a4aSGreg Roach break; 2179a6f13a4aSGreg Roach case 'BIRT:DATE': 2180a6f13a4aSGreg Roach uasort($this->list, '\Fisharebest\Webtrees\Individual::compareBirthDate'); 2181a6f13a4aSGreg Roach break; 2182a6f13a4aSGreg Roach case 'DEAT:DATE': 2183a6f13a4aSGreg Roach uasort($this->list, '\Fisharebest\Webtrees\Individual::compareDeathDate'); 2184a6f13a4aSGreg Roach break; 2185a6f13a4aSGreg Roach case 'MARR:DATE': 21865d0bc43dSGreg Roach uasort($this->list, '\Fisharebest\Webtrees\Family::compareMarrDate'); 2187a6f13a4aSGreg Roach break; 2188a6f13a4aSGreg Roach default: 2189a6f13a4aSGreg Roach // unsorted or already sorted by SQL 2190a6f13a4aSGreg Roach break; 2191a6f13a4aSGreg Roach } 2192a6f13a4aSGreg Roach 2193a6f13a4aSGreg Roach array_push($this->repeats_stack, array($this->repeats, $this->repeat_bytes)); 2194e8e7866bSGreg Roach $this->repeat_bytes = xml_get_current_line_number($this->parser) + 1; 2195a6f13a4aSGreg Roach } 2196a6f13a4aSGreg Roach 2197a6f13a4aSGreg Roach /** 219876692c8bSGreg Roach * XML <List> 2199a6f13a4aSGreg Roach */ 22008edd1043SGreg Roach private function listEndHandler() { 2201e8e7866bSGreg Roach global $report; 2202a6f13a4aSGreg Roach 2203a6f13a4aSGreg Roach $this->process_repeats--; 2204a6f13a4aSGreg Roach if ($this->process_repeats > 0) { 2205a6f13a4aSGreg Roach return; 2206a6f13a4aSGreg Roach } 2207a6f13a4aSGreg Roach 2208a6f13a4aSGreg Roach // Check if there is any list 2209a6f13a4aSGreg Roach if (count($this->list) > 0) { 2210a6f13a4aSGreg Roach $lineoffset = 0; 2211a6f13a4aSGreg Roach foreach ($this->repeats_stack as $rep) { 2212a6f13a4aSGreg Roach $lineoffset += $rep[1]; 2213a6f13a4aSGreg Roach } 2214a6f13a4aSGreg Roach //-- read the xml from the file 2215a6f13a4aSGreg Roach $lines = file($report); 2216a6f13a4aSGreg Roach while ((strpos($lines[$lineoffset + $this->repeat_bytes], "<List") === false) && (($lineoffset + $this->repeat_bytes) > 0)) { 2217a6f13a4aSGreg Roach $lineoffset--; 2218a6f13a4aSGreg Roach } 2219a6f13a4aSGreg Roach $lineoffset++; 2220a6f13a4aSGreg Roach $reportxml = "<tempdoc>\n"; 2221a6f13a4aSGreg Roach $line_nr = $lineoffset + $this->repeat_bytes; 2222a6f13a4aSGreg Roach // List Level counter 2223a6f13a4aSGreg Roach $count = 1; 2224a6f13a4aSGreg Roach while (0 < $count) { 2225a6f13a4aSGreg Roach if (strpos($lines[$line_nr], "<List") !== false) { 2226a6f13a4aSGreg Roach $count++; 2227a6f13a4aSGreg Roach } elseif (strpos($lines[$line_nr], "</List") !== false) { 2228a6f13a4aSGreg Roach $count--; 2229a6f13a4aSGreg Roach } 2230a6f13a4aSGreg Roach if (0 < $count) { 2231a6f13a4aSGreg Roach $reportxml .= $lines[$line_nr]; 2232a6f13a4aSGreg Roach } 2233a6f13a4aSGreg Roach $line_nr++; 2234a6f13a4aSGreg Roach } 2235a6f13a4aSGreg Roach // No need to drag this 2236a6f13a4aSGreg Roach unset($lines); 2237a6f13a4aSGreg Roach $reportxml .= "</tempdoc>"; 2238a6f13a4aSGreg Roach // Save original values 2239e8e7866bSGreg Roach array_push($this->parser_stack, $this->parser); 2240a6f13a4aSGreg Roach $oldgedrec = $this->gedrec; 2241a6f13a4aSGreg Roach 2242a6f13a4aSGreg Roach $this->list_total = count($this->list); 2243a6f13a4aSGreg Roach $this->list_private = 0; 2244a6f13a4aSGreg Roach foreach ($this->list as $record) { 2245a6f13a4aSGreg Roach if ($record->canShow()) { 2246a6f13a4aSGreg Roach $this->gedrec = $record->privatizeGedcom(Auth::accessLevel($record->getTree())); 2247a6f13a4aSGreg Roach //-- start the sax parser 2248a6f13a4aSGreg Roach $repeat_parser = xml_parser_create(); 2249e8e7866bSGreg Roach $this->parser = $repeat_parser; 2250a6f13a4aSGreg Roach xml_parser_set_option($repeat_parser, XML_OPTION_CASE_FOLDING, false); 2251a6f13a4aSGreg Roach xml_set_element_handler($repeat_parser, array($this, 'startElement'), array($this, 'endElement')); 2252a6f13a4aSGreg Roach xml_set_character_data_handler($repeat_parser, array($this, 'characterData')); 2253a6f13a4aSGreg Roach if (!xml_parse($repeat_parser, $reportxml, true)) { 2254a6f13a4aSGreg Roach throw new \DomainException(sprintf( 2255a6f13a4aSGreg Roach 'ListEHandler XML error: %s at line %d', 2256a6f13a4aSGreg Roach xml_error_string(xml_get_error_code($repeat_parser)), 2257a6f13a4aSGreg Roach xml_get_current_line_number($repeat_parser) 2258a6f13a4aSGreg Roach )); 2259a6f13a4aSGreg Roach } 2260a6f13a4aSGreg Roach xml_parser_free($repeat_parser); 2261a6f13a4aSGreg Roach } else { 2262a6f13a4aSGreg Roach $this->list_private++; 2263a6f13a4aSGreg Roach } 2264a6f13a4aSGreg Roach } 2265a6f13a4aSGreg Roach $this->list = array(); 2266e8e7866bSGreg Roach $this->parser = array_pop($this->parser_stack); 2267a6f13a4aSGreg Roach $this->gedrec = $oldgedrec; 2268a6f13a4aSGreg Roach } 2269a6f13a4aSGreg Roach list($this->repeats, $this->repeat_bytes) = array_pop($this->repeats_stack); 2270a6f13a4aSGreg Roach } 2271a6f13a4aSGreg Roach 2272a6f13a4aSGreg Roach /** 2273a6f13a4aSGreg Roach * XML <ListTotal> element handler 2274a6f13a4aSGreg Roach * 2275a6f13a4aSGreg Roach * Prints the total number of records in a list 2276a6f13a4aSGreg Roach * The total number is collected from 2277a6f13a4aSGreg Roach * List and Relatives 2278a6f13a4aSGreg Roach */ 22798edd1043SGreg Roach private function listTotalStartHandler() { 2280a6f13a4aSGreg Roach if ($this->list_private == 0) { 2281a6f13a4aSGreg Roach $this->current_element->addText($this->list_total); 2282a6f13a4aSGreg Roach } else { 2283a6f13a4aSGreg Roach $this->current_element->addText(($this->list_total - $this->list_private) . " / " . $this->list_total); 2284a6f13a4aSGreg Roach } 2285a6f13a4aSGreg Roach } 2286a6f13a4aSGreg Roach 2287a6f13a4aSGreg Roach /** 228876692c8bSGreg Roach * XML <Relatives> 228976692c8bSGreg Roach * 2290a6f13a4aSGreg Roach * @param array $attrs an array of key value pairs for the attributes 2291a6f13a4aSGreg Roach */ 22928edd1043SGreg Roach private function relativesStartHandler($attrs) { 2293d1286247SGreg Roach global $WT_TREE; 2294a6f13a4aSGreg Roach 2295a6f13a4aSGreg Roach $this->process_repeats++; 2296a6f13a4aSGreg Roach if ($this->process_repeats > 1) { 2297a6f13a4aSGreg Roach return; 2298a6f13a4aSGreg Roach } 2299a6f13a4aSGreg Roach 2300a6f13a4aSGreg Roach $sortby = "NAME"; 2301a6f13a4aSGreg Roach if (isset($attrs['sortby'])) { 2302a6f13a4aSGreg Roach $sortby = $attrs['sortby']; 2303a6f13a4aSGreg Roach } 2304a6f13a4aSGreg Roach $match = array(); 2305a6f13a4aSGreg Roach if (preg_match("/\\$(\w+)/", $sortby, $match)) { 2306d1286247SGreg Roach $sortby = $this->vars[$match[1]]['id']; 2307a6f13a4aSGreg Roach $sortby = trim($sortby); 2308a6f13a4aSGreg Roach } 2309a6f13a4aSGreg Roach 2310a6f13a4aSGreg Roach $maxgen = -1; 2311a6f13a4aSGreg Roach if (isset($attrs['maxgen'])) { 2312a6f13a4aSGreg Roach $maxgen = $attrs['maxgen']; 2313a6f13a4aSGreg Roach } 2314a6f13a4aSGreg Roach if ($maxgen == "*") { 2315a6f13a4aSGreg Roach $maxgen = -1; 2316a6f13a4aSGreg Roach } 2317a6f13a4aSGreg Roach 2318a6f13a4aSGreg Roach $group = "child-family"; 2319a6f13a4aSGreg Roach if (isset($attrs['group'])) { 2320a6f13a4aSGreg Roach $group = $attrs['group']; 2321a6f13a4aSGreg Roach } 2322a6f13a4aSGreg Roach if (preg_match("/\\$(\w+)/", $group, $match)) { 2323d1286247SGreg Roach $group = $this->vars[$match[1]]['id']; 2324a6f13a4aSGreg Roach $group = trim($group); 2325a6f13a4aSGreg Roach } 2326a6f13a4aSGreg Roach 2327a6f13a4aSGreg Roach $id = ""; 2328a6f13a4aSGreg Roach if (isset($attrs['id'])) { 2329a6f13a4aSGreg Roach $id = $attrs['id']; 2330a6f13a4aSGreg Roach } 2331a6f13a4aSGreg Roach if (preg_match("/\\$(\w+)/", $id, $match)) { 2332d1286247SGreg Roach $id = $this->vars[$match[1]]['id']; 2333a6f13a4aSGreg Roach $id = trim($id); 2334a6f13a4aSGreg Roach } 2335a6f13a4aSGreg Roach 2336a6f13a4aSGreg Roach $this->list = array(); 2337a6f13a4aSGreg Roach $person = Individual::getInstance($id, $WT_TREE); 2338a6f13a4aSGreg Roach if (!empty($person)) { 2339a6f13a4aSGreg Roach $this->list[$id] = $person; 2340a6f13a4aSGreg Roach switch ($group) { 2341a6f13a4aSGreg Roach case "child-family": 2342a6f13a4aSGreg Roach foreach ($person->getChildFamilies() as $family) { 2343a6f13a4aSGreg Roach $husband = $family->getHusband(); 2344a6f13a4aSGreg Roach $wife = $family->getWife(); 2345a6f13a4aSGreg Roach if (!empty($husband)) { 2346a6f13a4aSGreg Roach $this->list[$husband->getXref()] = $husband; 2347a6f13a4aSGreg Roach } 2348a6f13a4aSGreg Roach if (!empty($wife)) { 2349a6f13a4aSGreg Roach $this->list[$wife->getXref()] = $wife; 2350a6f13a4aSGreg Roach } 2351a6f13a4aSGreg Roach $children = $family->getChildren(); 2352a6f13a4aSGreg Roach foreach ($children as $child) { 2353a6f13a4aSGreg Roach if (!empty($child)) { 2354a6f13a4aSGreg Roach $this->list[$child->getXref()] = $child; 2355a6f13a4aSGreg Roach } 2356a6f13a4aSGreg Roach } 2357a6f13a4aSGreg Roach } 2358a6f13a4aSGreg Roach break; 2359a6f13a4aSGreg Roach case "spouse-family": 2360a6f13a4aSGreg Roach foreach ($person->getSpouseFamilies() as $family) { 2361a6f13a4aSGreg Roach $husband = $family->getHusband(); 2362a6f13a4aSGreg Roach $wife = $family->getWife(); 2363a6f13a4aSGreg Roach if (!empty($husband)) { 2364a6f13a4aSGreg Roach $this->list[$husband->getXref()] = $husband; 2365a6f13a4aSGreg Roach } 2366a6f13a4aSGreg Roach if (!empty($wife)) { 2367a6f13a4aSGreg Roach $this->list[$wife->getXref()] = $wife; 2368a6f13a4aSGreg Roach } 2369a6f13a4aSGreg Roach $children = $family->getChildren(); 2370a6f13a4aSGreg Roach foreach ($children as $child) { 2371a6f13a4aSGreg Roach if (!empty($child)) { 2372a6f13a4aSGreg Roach $this->list[$child->getXref()] = $child; 2373a6f13a4aSGreg Roach } 2374a6f13a4aSGreg Roach } 2375a6f13a4aSGreg Roach } 2376a6f13a4aSGreg Roach break; 2377a6f13a4aSGreg Roach case "direct-ancestors": 23783d7a8a4cSGreg Roach $this->addAncestors($this->list, $id, false, $maxgen); 2379a6f13a4aSGreg Roach break; 2380a6f13a4aSGreg Roach case "ancestors": 23813d7a8a4cSGreg Roach $this->addAncestors($this->list, $id, true, $maxgen); 2382a6f13a4aSGreg Roach break; 2383a6f13a4aSGreg Roach case "descendants": 2384a6f13a4aSGreg Roach $this->list[$id]->generation = 1; 23853d7a8a4cSGreg Roach $this->addDescendancy($this->list, $id, false, $maxgen); 2386a6f13a4aSGreg Roach break; 2387a6f13a4aSGreg Roach case "all": 23883d7a8a4cSGreg Roach $this->addAncestors($this->list, $id, true, $maxgen); 23893d7a8a4cSGreg Roach $this->addDescendancy($this->list, $id, true, $maxgen); 2390a6f13a4aSGreg Roach break; 2391a6f13a4aSGreg Roach } 2392a6f13a4aSGreg Roach } 2393a6f13a4aSGreg Roach 2394a6f13a4aSGreg Roach switch ($sortby) { 2395a6f13a4aSGreg Roach case 'NAME': 2396a6f13a4aSGreg Roach uasort($this->list, '\Fisharebest\Webtrees\GedcomRecord::compare'); 2397a6f13a4aSGreg Roach break; 2398a6f13a4aSGreg Roach case 'BIRT:DATE': 2399a6f13a4aSGreg Roach uasort($this->list, '\Fisharebest\Webtrees\Individual::compareBirthDate'); 2400a6f13a4aSGreg Roach break; 2401a6f13a4aSGreg Roach case 'DEAT:DATE': 2402a6f13a4aSGreg Roach uasort($this->list, '\Fisharebest\Webtrees\Individual::compareDeathDate'); 2403a6f13a4aSGreg Roach break; 2404a6f13a4aSGreg Roach case 'generation': 2405a6f13a4aSGreg Roach $newarray = array(); 2406a6f13a4aSGreg Roach reset($this->list); 2407a6f13a4aSGreg Roach $genCounter = 1; 2408a6f13a4aSGreg Roach while (count($newarray) < count($this->list)) { 2409a6f13a4aSGreg Roach foreach ($this->list as $key => $value) { 2410a6f13a4aSGreg Roach $this->generation = $value->generation; 2411a6f13a4aSGreg Roach if ($this->generation == $genCounter) { 2412a6f13a4aSGreg Roach $newarray[$key] = new \stdClass; 2413a6f13a4aSGreg Roach $newarray[$key]->generation = $this->generation; 2414a6f13a4aSGreg Roach } 2415a6f13a4aSGreg Roach } 2416a6f13a4aSGreg Roach $genCounter++; 2417a6f13a4aSGreg Roach } 2418a6f13a4aSGreg Roach $this->list = $newarray; 2419a6f13a4aSGreg Roach break; 2420a6f13a4aSGreg Roach default: 2421a6f13a4aSGreg Roach // unsorted 2422a6f13a4aSGreg Roach break; 2423a6f13a4aSGreg Roach } 2424a6f13a4aSGreg Roach array_push($this->repeats_stack, array($this->repeats, $this->repeat_bytes)); 2425e8e7866bSGreg Roach $this->repeat_bytes = xml_get_current_line_number($this->parser) + 1; 2426a6f13a4aSGreg Roach } 2427a6f13a4aSGreg Roach 2428a6f13a4aSGreg Roach /** 242976692c8bSGreg Roach * XML </ Relatives> 2430a6f13a4aSGreg Roach */ 24318edd1043SGreg Roach private function relativesEndHandler() { 2432e8e7866bSGreg Roach global $report, $WT_TREE; 2433a6f13a4aSGreg Roach 2434a6f13a4aSGreg Roach $this->process_repeats--; 2435a6f13a4aSGreg Roach if ($this->process_repeats > 0) { 2436a6f13a4aSGreg Roach return; 2437a6f13a4aSGreg Roach } 2438a6f13a4aSGreg Roach 2439a6f13a4aSGreg Roach // Check if there is any relatives 2440a6f13a4aSGreg Roach if (count($this->list) > 0) { 2441a6f13a4aSGreg Roach $lineoffset = 0; 2442a6f13a4aSGreg Roach foreach ($this->repeats_stack as $rep) { 2443a6f13a4aSGreg Roach $lineoffset += $rep[1]; 2444a6f13a4aSGreg Roach } 2445a6f13a4aSGreg Roach //-- read the xml from the file 2446a6f13a4aSGreg Roach $lines = file($report); 2447a6f13a4aSGreg Roach while ((strpos($lines[$lineoffset + $this->repeat_bytes], "<Relatives") === false) && (($lineoffset + $this->repeat_bytes) > 0)) { 2448a6f13a4aSGreg Roach $lineoffset--; 2449a6f13a4aSGreg Roach } 2450a6f13a4aSGreg Roach $lineoffset++; 2451a6f13a4aSGreg Roach $reportxml = "<tempdoc>\n"; 2452a6f13a4aSGreg Roach $line_nr = $lineoffset + $this->repeat_bytes; 2453a6f13a4aSGreg Roach // Relatives Level counter 2454a6f13a4aSGreg Roach $count = 1; 2455a6f13a4aSGreg Roach while (0 < $count) { 2456a6f13a4aSGreg Roach if (strpos($lines[$line_nr], "<Relatives") !== false) { 2457a6f13a4aSGreg Roach $count++; 2458a6f13a4aSGreg Roach } elseif (strpos($lines[$line_nr], "</Relatives") !== false) { 2459a6f13a4aSGreg Roach $count--; 2460a6f13a4aSGreg Roach } 2461a6f13a4aSGreg Roach if (0 < $count) { 2462a6f13a4aSGreg Roach $reportxml .= $lines[$line_nr]; 2463a6f13a4aSGreg Roach } 2464a6f13a4aSGreg Roach $line_nr++; 2465a6f13a4aSGreg Roach } 2466a6f13a4aSGreg Roach // No need to drag this 2467a6f13a4aSGreg Roach unset($lines); 2468a6f13a4aSGreg Roach $reportxml .= "</tempdoc>\n"; 2469a6f13a4aSGreg Roach // Save original values 2470e8e7866bSGreg Roach array_push($this->parser_stack, $this->parser); 2471a6f13a4aSGreg Roach $oldgedrec = $this->gedrec; 2472a6f13a4aSGreg Roach 2473a6f13a4aSGreg Roach $this->list_total = count($this->list); 2474a6f13a4aSGreg Roach $this->list_private = 0; 2475a6f13a4aSGreg Roach foreach ($this->list as $key => $value) { 2476a6f13a4aSGreg Roach if (isset($value->generation)) { 2477a6f13a4aSGreg Roach $this->generation = $value->generation; 2478a6f13a4aSGreg Roach } 2479a6f13a4aSGreg Roach $tmp = GedcomRecord::getInstance($key, $WT_TREE); 2480a6f13a4aSGreg Roach $this->gedrec = $tmp->privatizeGedcom(Auth::accessLevel($WT_TREE)); 2481a6f13a4aSGreg Roach 2482a6f13a4aSGreg Roach $repeat_parser = xml_parser_create(); 2483e8e7866bSGreg Roach $this->parser = $repeat_parser; 2484a6f13a4aSGreg Roach xml_parser_set_option($repeat_parser, XML_OPTION_CASE_FOLDING, false); 2485a6f13a4aSGreg Roach xml_set_element_handler($repeat_parser, array($this, 'startElement'), array($this, 'endElement')); 2486a6f13a4aSGreg Roach xml_set_character_data_handler($repeat_parser, array($this, 'characterData')); 2487a6f13a4aSGreg Roach 2488a6f13a4aSGreg Roach if (!xml_parse($repeat_parser, $reportxml, true)) { 2489a6f13a4aSGreg Roach throw new \DomainException(sprintf("RelativesEHandler XML error: %s at line %d", xml_error_string(xml_get_error_code($repeat_parser)), xml_get_current_line_number($repeat_parser))); 2490a6f13a4aSGreg Roach } 2491a6f13a4aSGreg Roach xml_parser_free($repeat_parser); 2492a6f13a4aSGreg Roach } 2493a6f13a4aSGreg Roach // Clean up the list array 2494a6f13a4aSGreg Roach $this->list = array(); 2495e8e7866bSGreg Roach $this->parser = array_pop($this->parser_stack); 2496a6f13a4aSGreg Roach $this->gedrec = $oldgedrec; 2497a6f13a4aSGreg Roach } 2498a6f13a4aSGreg Roach list($this->repeats, $this->repeat_bytes) = array_pop($this->repeats_stack); 2499a6f13a4aSGreg Roach } 2500a6f13a4aSGreg Roach 2501a6f13a4aSGreg Roach /** 2502a6f13a4aSGreg Roach * XML <Generation /> element handler 2503a6f13a4aSGreg Roach * 2504a6f13a4aSGreg Roach * Prints the number of generations 2505a6f13a4aSGreg Roach */ 25068edd1043SGreg Roach private function generationStartHandler() { 2507a6f13a4aSGreg Roach $this->current_element->addText($this->generation); 2508a6f13a4aSGreg Roach } 2509a6f13a4aSGreg Roach 2510a6f13a4aSGreg Roach /** 2511a6f13a4aSGreg Roach * XML <NewPage /> element handler 2512a6f13a4aSGreg Roach * 2513a6f13a4aSGreg Roach * Has to be placed in an element (header, pageheader, body or footer) 2514a6f13a4aSGreg Roach */ 25158edd1043SGreg Roach private function newPageStartHandler() { 2516a6f13a4aSGreg Roach $temp = "addpage"; 2517e8e7866bSGreg Roach $this->wt_report->addElement($temp); 2518a6f13a4aSGreg Roach } 2519a6f13a4aSGreg Roach 2520a6f13a4aSGreg Roach /** 252176692c8bSGreg Roach * XML <html> 252276692c8bSGreg Roach * 2523a6f13a4aSGreg Roach * @param string $tag HTML tag name 252476692c8bSGreg Roach * @param array[] $attrs an array of key value pairs for the attributes 2525a6f13a4aSGreg Roach */ 25268edd1043SGreg Roach private function htmlStartHandler($tag, $attrs) { 2527a6f13a4aSGreg Roach if ($tag === "tempdoc") { 2528a6f13a4aSGreg Roach return; 2529a6f13a4aSGreg Roach } 2530e8e7866bSGreg Roach array_push($this->wt_report_stack, $this->wt_report); 2531e8e7866bSGreg Roach $this->wt_report = $this->report_root->createHTML($tag, $attrs); 2532e8e7866bSGreg Roach $this->current_element = $this->wt_report; 2533a6f13a4aSGreg Roach 2534a6f13a4aSGreg Roach array_push($this->print_data_stack, $this->print_data); 2535a6f13a4aSGreg Roach $this->print_data = true; 2536a6f13a4aSGreg Roach } 2537a6f13a4aSGreg Roach 2538a6f13a4aSGreg Roach /** 253976692c8bSGreg Roach * XML </html> 254076692c8bSGreg Roach * 2541a6f13a4aSGreg Roach * @param string $tag 2542a6f13a4aSGreg Roach */ 25438edd1043SGreg Roach private function htmlEndHandler($tag) { 2544a6f13a4aSGreg Roach if ($tag === "tempdoc") { 2545a6f13a4aSGreg Roach return; 2546a6f13a4aSGreg Roach } 2547a6f13a4aSGreg Roach 2548a6f13a4aSGreg Roach $this->print_data = array_pop($this->print_data_stack); 2549e8e7866bSGreg Roach $this->current_element = $this->wt_report; 2550e8e7866bSGreg Roach $this->wt_report = array_pop($this->wt_report_stack); 2551e8e7866bSGreg Roach if (!is_null($this->wt_report)) { 2552e8e7866bSGreg Roach $this->wt_report->addElement($this->current_element); 2553a6f13a4aSGreg Roach } else { 2554e8e7866bSGreg Roach $this->wt_report = $this->current_element; 2555a6f13a4aSGreg Roach } 2556a6f13a4aSGreg Roach } 2557a6f13a4aSGreg Roach 2558a6f13a4aSGreg Roach /** 2559a6f13a4aSGreg Roach * Handle <Input> 2560a6f13a4aSGreg Roach */ 25618edd1043SGreg Roach private function inputStartHandler() { 2562a6f13a4aSGreg Roach // Dummy function, to prevent the default HtmlStartHandler() being called 2563a6f13a4aSGreg Roach } 2564a6f13a4aSGreg Roach 2565a6f13a4aSGreg Roach /** 2566a6f13a4aSGreg Roach * Handle </Input> 2567a6f13a4aSGreg Roach */ 25688edd1043SGreg Roach private function inputEndHandler() { 2569a6f13a4aSGreg Roach // Dummy function, to prevent the default HtmlEndHandler() being called 2570a6f13a4aSGreg Roach } 2571a6f13a4aSGreg Roach 2572a6f13a4aSGreg Roach /** 2573a6f13a4aSGreg Roach * Handle <Report> 2574a6f13a4aSGreg Roach */ 25758edd1043SGreg Roach private function reportStartHandler() { 2576a6f13a4aSGreg Roach // Dummy function, to prevent the default HtmlStartHandler() being called 2577a6f13a4aSGreg Roach } 2578a6f13a4aSGreg Roach 2579a6f13a4aSGreg Roach /** 2580a6f13a4aSGreg Roach * Handle </Report> 2581a6f13a4aSGreg Roach */ 25828edd1043SGreg Roach private function reportEndHandler() { 2583a6f13a4aSGreg Roach // Dummy function, to prevent the default HtmlEndHandler() being called 2584a6f13a4aSGreg Roach } 2585a6f13a4aSGreg Roach 2586a6f13a4aSGreg Roach /** 258776692c8bSGreg Roach * XML </titleEndHandler> 2588a6f13a4aSGreg Roach */ 25898edd1043SGreg Roach private function titleEndHandler() { 25902836aa05SGreg Roach $this->report_root->addTitle($this->text); 2591a6f13a4aSGreg Roach } 2592a6f13a4aSGreg Roach 2593a6f13a4aSGreg Roach /** 259476692c8bSGreg Roach * XML </descriptionEndHandler> 2595a6f13a4aSGreg Roach */ 25968edd1043SGreg Roach private function descriptionEndHandler() { 25972836aa05SGreg Roach $this->report_root->addDescription($this->text); 2598a6f13a4aSGreg Roach } 2599729ce104SGreg Roach 2600729ce104SGreg Roach /** 260176692c8bSGreg Roach * Create a list of all descendants. 260276692c8bSGreg Roach * 2603729ce104SGreg Roach * @param string[] $list 2604729ce104SGreg Roach * @param string $pid 2605729ce104SGreg Roach * @param bool $parents 2606729ce104SGreg Roach * @param int $generations 2607729ce104SGreg Roach */ 260882759250SGreg Roach private function addDescendancy(&$list, $pid, $parents = false, $generations = -1) { 2609729ce104SGreg Roach global $WT_TREE; 2610729ce104SGreg Roach 2611729ce104SGreg Roach $person = Individual::getInstance($pid, $WT_TREE); 2612729ce104SGreg Roach if ($person === null) { 2613729ce104SGreg Roach return; 2614729ce104SGreg Roach } 2615729ce104SGreg Roach if (!isset($list[$pid])) { 2616729ce104SGreg Roach $list[$pid] = $person; 2617729ce104SGreg Roach } 2618729ce104SGreg Roach if (!isset($list[$pid]->generation)) { 2619729ce104SGreg Roach $list[$pid]->generation = 0; 2620729ce104SGreg Roach } 2621729ce104SGreg Roach foreach ($person->getSpouseFamilies() as $family) { 2622729ce104SGreg Roach if ($parents) { 2623729ce104SGreg Roach $husband = $family->getHusband(); 2624729ce104SGreg Roach $wife = $family->getWife(); 2625729ce104SGreg Roach if ($husband) { 2626729ce104SGreg Roach $list[$husband->getXref()] = $husband; 2627729ce104SGreg Roach if (isset($list[$pid]->generation)) { 2628729ce104SGreg Roach $list[$husband->getXref()]->generation = $list[$pid]->generation - 1; 2629729ce104SGreg Roach } else { 2630729ce104SGreg Roach $list[$husband->getXref()]->generation = 1; 2631729ce104SGreg Roach } 2632729ce104SGreg Roach } 2633729ce104SGreg Roach if ($wife) { 2634729ce104SGreg Roach $list[$wife->getXref()] = $wife; 2635729ce104SGreg Roach if (isset($list[$pid]->generation)) { 2636729ce104SGreg Roach $list[$wife->getXref()]->generation = $list[$pid]->generation - 1; 2637729ce104SGreg Roach } else { 2638729ce104SGreg Roach $list[$wife->getXref()]->generation = 1; 2639729ce104SGreg Roach } 2640729ce104SGreg Roach } 2641729ce104SGreg Roach } 2642729ce104SGreg Roach $children = $family->getChildren(); 2643729ce104SGreg Roach foreach ($children as $child) { 2644729ce104SGreg Roach if ($child) { 2645729ce104SGreg Roach $list[$child->getXref()] = $child; 2646729ce104SGreg Roach if (isset($list[$pid]->generation)) { 2647729ce104SGreg Roach $list[$child->getXref()]->generation = $list[$pid]->generation + 1; 2648729ce104SGreg Roach } else { 2649729ce104SGreg Roach $list[$child->getXref()]->generation = 2; 2650729ce104SGreg Roach } 2651729ce104SGreg Roach } 2652729ce104SGreg Roach } 2653729ce104SGreg Roach if ($generations == -1 || $list[$pid]->generation + 1 < $generations) { 2654729ce104SGreg Roach foreach ($children as $child) { 26553d7a8a4cSGreg Roach $this->addDescendancy($list, $child->getXref(), $parents, $generations); // recurse on the childs family 2656729ce104SGreg Roach } 2657729ce104SGreg Roach } 2658729ce104SGreg Roach } 2659729ce104SGreg Roach } 2660729ce104SGreg Roach 2661729ce104SGreg Roach /** 266276692c8bSGreg Roach * Create a list of all ancestors. 266376692c8bSGreg Roach * 2664729ce104SGreg Roach * @param string[] $list 2665729ce104SGreg Roach * @param string $pid 2666729ce104SGreg Roach * @param bool $children 2667729ce104SGreg Roach * @param int $generations 2668729ce104SGreg Roach */ 266982759250SGreg Roach private function addAncestors(&$list, $pid, $children = false, $generations = -1) { 2670729ce104SGreg Roach global $WT_TREE; 2671729ce104SGreg Roach 2672729ce104SGreg Roach $genlist = array($pid); 2673729ce104SGreg Roach $list[$pid]->generation = 1; 2674729ce104SGreg Roach while (count($genlist) > 0) { 2675729ce104SGreg Roach $id = array_shift($genlist); 2676729ce104SGreg Roach if (strpos($id, 'empty') === 0) { 2677729ce104SGreg Roach continue; // id can be something like “empty7” 2678729ce104SGreg Roach } 2679729ce104SGreg Roach $person = Individual::getInstance($id, $WT_TREE); 2680729ce104SGreg Roach foreach ($person->getChildFamilies() as $family) { 2681729ce104SGreg Roach $husband = $family->getHusband(); 2682729ce104SGreg Roach $wife = $family->getWife(); 2683729ce104SGreg Roach if ($husband) { 2684729ce104SGreg Roach $list[$husband->getXref()] = $husband; 2685729ce104SGreg Roach $list[$husband->getXref()]->generation = $list[$id]->generation + 1; 2686729ce104SGreg Roach } 2687729ce104SGreg Roach if ($wife) { 2688729ce104SGreg Roach $list[$wife->getXref()] = $wife; 2689729ce104SGreg Roach $list[$wife->getXref()]->generation = $list[$id]->generation + 1; 2690729ce104SGreg Roach } 2691729ce104SGreg Roach if ($generations == -1 || $list[$id]->generation + 1 < $generations) { 2692729ce104SGreg Roach if ($husband) { 2693729ce104SGreg Roach array_push($genlist, $husband->getXref()); 2694729ce104SGreg Roach } 2695729ce104SGreg Roach if ($wife) { 2696729ce104SGreg Roach array_push($genlist, $wife->getXref()); 2697729ce104SGreg Roach } 2698729ce104SGreg Roach } 2699729ce104SGreg Roach if ($children) { 2700729ce104SGreg Roach foreach ($family->getChildren() as $child) { 2701729ce104SGreg Roach $list[$child->getXref()] = $child; 2702729ce104SGreg Roach if (isset($list[$id]->generation)) { 2703729ce104SGreg Roach $list[$child->getXref()]->generation = $list[$id]->generation; 2704729ce104SGreg Roach } else { 2705729ce104SGreg Roach $list[$child->getXref()]->generation = 1; 2706729ce104SGreg Roach } 2707729ce104SGreg Roach } 2708729ce104SGreg Roach } 2709729ce104SGreg Roach } 2710729ce104SGreg Roach } 2711729ce104SGreg Roach } 2712729ce104SGreg Roach 2713729ce104SGreg Roach /** 2714729ce104SGreg Roach * get gedcom tag value 2715729ce104SGreg Roach * 2716729ce104SGreg Roach * @param string $tag The tag to find, use : to delineate subtags 2717729ce104SGreg Roach * @param int $level The gedcom line level of the first tag to find, setting level to 0 will cause it to use 1+ the level of the incoming record 2718729ce104SGreg Roach * @param string $gedrec The gedcom record to get the value from 2719729ce104SGreg Roach * 2720729ce104SGreg Roach * @return string the value of a gedcom tag from the given gedcom record 2721729ce104SGreg Roach */ 272282759250SGreg Roach private function getGedcomValue($tag, $level, $gedrec) { 2723729ce104SGreg Roach global $WT_TREE; 2724729ce104SGreg Roach 2725729ce104SGreg Roach if (empty($gedrec)) { 2726729ce104SGreg Roach return ''; 2727729ce104SGreg Roach } 2728729ce104SGreg Roach $tags = explode(':', $tag); 2729729ce104SGreg Roach $origlevel = $level; 2730729ce104SGreg Roach if ($level == 0) { 2731729ce104SGreg Roach $level = $gedrec{0} + 1; 2732729ce104SGreg Roach } 2733729ce104SGreg Roach 2734729ce104SGreg Roach $subrec = $gedrec; 2735729ce104SGreg Roach foreach ($tags as $t) { 2736729ce104SGreg Roach $lastsubrec = $subrec; 27373d7a8a4cSGreg Roach $subrec = Functions::getSubRecord($level, "$level $t", $subrec); 2738729ce104SGreg Roach if (empty($subrec) && $origlevel == 0) { 2739729ce104SGreg Roach $level--; 27403d7a8a4cSGreg Roach $subrec = Functions::getSubRecord($level, "$level $t", $lastsubrec); 2741729ce104SGreg Roach } 2742729ce104SGreg Roach if (empty($subrec)) { 2743729ce104SGreg Roach if ($t == "TITL") { 27443d7a8a4cSGreg Roach $subrec = Functions::getSubRecord($level, "$level ABBR", $lastsubrec); 2745729ce104SGreg Roach if (!empty($subrec)) { 2746729ce104SGreg Roach $t = "ABBR"; 2747729ce104SGreg Roach } 2748729ce104SGreg Roach } 2749729ce104SGreg Roach if (empty($subrec)) { 2750729ce104SGreg Roach if ($level > 0) { 2751729ce104SGreg Roach $level--; 2752729ce104SGreg Roach } 27533d7a8a4cSGreg Roach $subrec = Functions::getSubRecord($level, "@ $t", $gedrec); 2754729ce104SGreg Roach if (empty($subrec)) { 2755729ce104SGreg Roach return ''; 2756729ce104SGreg Roach } 2757729ce104SGreg Roach } 2758729ce104SGreg Roach } 2759729ce104SGreg Roach $level++; 2760729ce104SGreg Roach } 2761729ce104SGreg Roach $level--; 2762729ce104SGreg Roach $ct = preg_match("/$level $t(.*)/", $subrec, $match); 2763729ce104SGreg Roach if ($ct == 0) { 2764729ce104SGreg Roach $ct = preg_match("/$level @.+@ (.+)/", $subrec, $match); 2765729ce104SGreg Roach } 2766729ce104SGreg Roach if ($ct == 0) { 2767729ce104SGreg Roach $ct = preg_match("/@ $t (.+)/", $subrec, $match); 2768729ce104SGreg Roach } 2769729ce104SGreg Roach if ($ct > 0) { 2770729ce104SGreg Roach $value = trim($match[1]); 2771729ce104SGreg Roach if ($t == 'NOTE' && preg_match('/^@(.+)@$/', $value, $match)) { 2772729ce104SGreg Roach $note = Note::getInstance($match[1], $WT_TREE); 2773729ce104SGreg Roach if ($note) { 2774729ce104SGreg Roach $value = $note->getNote(); 2775729ce104SGreg Roach } else { 2776729ce104SGreg Roach //-- set the value to the id without the @ 2777729ce104SGreg Roach $value = $match[1]; 2778729ce104SGreg Roach } 2779729ce104SGreg Roach } 2780729ce104SGreg Roach if ($level != 0 || $t != "NOTE") { 27813d7a8a4cSGreg Roach $value .= Functions::getCont($level + 1, $subrec); 2782729ce104SGreg Roach } 2783729ce104SGreg Roach 2784729ce104SGreg Roach return $value; 2785729ce104SGreg Roach } 2786729ce104SGreg Roach 2787729ce104SGreg Roach return ""; 2788729ce104SGreg Roach } 2789d1286247SGreg Roach 2790d1286247SGreg Roach /** 2791d1286247SGreg Roach * Replace variable identifiers with their values. 2792d1286247SGreg Roach * 2793d1286247SGreg Roach * @param string $expression An expression such as "$foo == 123" 279482759250SGreg Roach * @param bool $quote Whether to add quotation marks 2795d1286247SGreg Roach * 2796d1286247SGreg Roach * @return string 2797d1286247SGreg Roach */ 279882759250SGreg Roach private function substituteVars($expression, $quote) { 27995217901bSGreg Roach $that = $this; // PHP5.3 cannot access $this inside a closure 2800d1286247SGreg Roach return preg_replace_callback( 2801d1286247SGreg Roach '/\$(\w+)/', 28025217901bSGreg Roach function ($matches) use ($that, $quote) { 28035217901bSGreg Roach if (isset($that->vars[$matches[1]]['id'])) { 280482759250SGreg Roach if ($quote) { 28055217901bSGreg Roach return "'" . addcslashes($that->vars[$matches[1]]['id'], "'") . "'"; 280682759250SGreg Roach } else { 28075217901bSGreg Roach return $that->vars[$matches[1]]['id']; 280882759250SGreg Roach } 2809d1286247SGreg Roach } else { 2810d1286247SGreg Roach Log::addErrorLog(sprintf('Undefined variable $%s in report', $matches[1])); 28113d7a8a4cSGreg Roach 2812d1286247SGreg Roach return '$' . $matches[1]; 2813d1286247SGreg Roach } 2814d1286247SGreg Roach }, 2815d1286247SGreg Roach $expression 2816d1286247SGreg Roach ); 2817d1286247SGreg Roach } 2818a6f13a4aSGreg Roach} 2819