. */ declare(strict_types=1); namespace Fisharebest\Webtrees\Report; use Fisharebest\Webtrees\Auth; use Fisharebest\Webtrees\Database; use Fisharebest\Webtrees\Date; use Fisharebest\Webtrees\Family; use Fisharebest\Webtrees\Filter; use Fisharebest\Webtrees\Functions\Functions; use Fisharebest\Webtrees\Functions\FunctionsDate; use Fisharebest\Webtrees\GedcomRecord; use Fisharebest\Webtrees\GedcomTag; use Fisharebest\Webtrees\I18N; use Fisharebest\Webtrees\Individual; use Fisharebest\Webtrees\Log; use Fisharebest\Webtrees\Media; use Fisharebest\Webtrees\Note; use Fisharebest\Webtrees\Place; use Fisharebest\Webtrees\Tree; use stdClass; use Symfony\Component\ExpressionLanguage\ExpressionFunction; use Symfony\Component\ExpressionLanguage\ExpressionLanguage; /** * Class ReportParserGenerate - parse a report.xml file and generate the report. */ class ReportParserGenerate extends ReportParserBase { /** @var bool Are we collecting data from elements */ private $process_footnote = true; /** @var bool Are we currently outputing data? */ private $print_data = false; /** @var bool[] Push-down stack of $print_data */ private $print_data_stack = []; /** @var int Are we processing GEDCOM data */ private $process_gedcoms = 0; /** @var int Are we processing conditionals */ private $process_ifs = 0; /** @var int Are we processing repeats */ private $process_repeats = 0; /** @var int Quantity of data to repeat during loops */ private $repeat_bytes = 0; /** @var string[] Repeated data when iterating over loops */ private $repeats = []; /** @var array[] Nested repeating data */ private $repeats_stack = []; /** @var AbstractReport[] Nested repeating data */ private $wt_report_stack = []; /** @var resource Nested repeating data */ private $parser; /** @var resource[] Nested repeating data */ private $parser_stack = []; /** @var string The current GEDCOM record */ private $gedrec = ''; /** @var string[] Nested GEDCOM records */ private $gedrec_stack = []; /** @var ReportBaseElement The currently processed element */ private $current_element; /** @var ReportBaseElement The currently processed element */ private $footnote_element; /** @var string The GEDCOM fact currently being processed */ private $fact = ''; /** @var string The GEDCOM value currently being processed */ private $desc = ''; /** @var string The GEDCOM type currently being processed */ private $type = ''; /** @var int The current generational level */ private $generation = 1; /** @var array Source data for processing lists */ private $list = []; /** @var int Number of items in lists */ private $list_total = 0; /** @var int Number of items filtered from lists */ private $list_private = 0; /** @var string The filename of the XML report */ protected $report; /** @var AbstractReport A factory for creating report elements */ private $report_root; /** @var AbstractReport Nested report elements */ private $wt_report; /** @var string[][] Variables defined in the report at run-time */ private $vars; /** @var Tree The current tree */ private $tree; /** * Create a parser for a report * * @param string $report The XML filename * @param AbstractReport $report_root * @param string[][] $vars * @param Tree $tree */ public function __construct(string $report, AbstractReport $report_root, array $vars, Tree $tree) { $this->report = $report; $this->report_root = $report_root; $this->wt_report = $report_root; $this->current_element = new ReportBaseElement(); $this->vars = $vars; $this->tree = $tree; parent::__construct($report); } /** * XML start element handler * This function is called whenever a starting element is reached * The element handler will be called if found, otherwise it must be HTML * * @param resource $parser the resource handler for the XML parser * @param string $name the name of the XML element parsed * @param array $attrs an array of key value pairs for the attributes * * @return void */ protected function startElement($parser, $name, $attrs) { $newattrs = []; foreach ($attrs as $key => $value) { if (preg_match("/^\\$(\w+)$/", $value, $match)) { if ((isset($this->vars[$match[1]]['id'])) && (!isset($this->vars[$match[1]]['gedcom']))) { $value = $this->vars[$match[1]]['id']; } } $newattrs[$key] = $value; } $attrs = $newattrs; if ($this->process_footnote && ($this->process_ifs === 0 || $name === 'if') && ($this->process_gedcoms === 0 || $name === 'Gedcom') && ($this->process_repeats === 0 || $name === 'Facts' || $name === 'RepeatTag')) { $start_method = $name . 'StartHandler'; $end_method = $name . 'EndHandler'; if (method_exists($this, $start_method)) { $this->$start_method($attrs); } elseif (!method_exists($this, $end_method)) { $this->htmlStartHandler($name, $attrs); } } } /** * XML end element handler * This function is called whenever an ending element is reached * The element handler will be called if found, otherwise it must be HTML * * @param resource $parser the resource handler for the XML parser * @param string $name the name of the XML element parsed * * @return void */ protected function endElement($parser, $name) { 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')) { $start_method = $name . 'StartHandler'; $end_method = $name . 'EndHandler'; if (method_exists($this, $end_method)) { $this->$end_method(); } elseif (!method_exists($this, $start_method)) { $this->htmlEndHandler($name); } } } /** * XML character data handler * * @param resource $parser the resource handler for the XML parser * @param string $data the name of the XML element parsed * * @return void */ protected function characterData($parser, $data) { if ($this->print_data && $this->process_gedcoms === 0 && $this->process_ifs === 0 && $this->process_repeats === 0) { $this->current_element->addText($data); } } /** * XML