diff options
Diffstat (limited to 'library/WT')
38 files changed, 968 insertions, 2089 deletions
diff --git a/library/WT/Controller/AdvancedSearch.php b/library/WT/Controller/AdvancedSearch.php index cba844cd74..586db82939 100644 --- a/library/WT/Controller/AdvancedSearch.php +++ b/library/WT/Controller/AdvancedSearch.php @@ -2,7 +2,7 @@ // Controller for the advanced search page // // webtrees: Web based Family History software -// Copyright (C) 2012 webtrees development team. +// Copyright (C) 2013 webtrees development team. // // Derived from PhpGedView // Copyright (C) 2002 to 2009 PGV Development Team. All rights reserved. @@ -202,7 +202,7 @@ class WT_Controller_AdvancedSearch extends WT_Controller_Search { } // Dynamic SQL query, plus bind variables - $sql="SELECT DISTINCT 'INDI' AS type, ind.i_id AS xref, ind.i_file AS ged_id, ind.i_gedcom AS gedrec FROM `##individuals` ind"; + $sql="SELECT DISTINCT ind.i_id AS xref, ind.i_file AS gedcom_id, ind.i_gedcom AS gedcom FROM `##individuals` ind"; $bind=array(); // Join the following tables @@ -486,13 +486,13 @@ class WT_Controller_AdvancedSearch extends WT_Controller_Search { $bind[]=$value; } } - $rows=WT_DB::prepare($sql)->execute($bind)->fetchAll(PDO::FETCH_ASSOC); + $rows=WT_DB::prepare($sql)->execute($bind)->fetchAll(); foreach ($rows as $row) { - $person=WT_Person::getInstance($row); + $person=WT_Individual::getInstance($row->xref, $row->gedcom_id, $row->gedcom); // Check for XXXX:PLAC fields, which were only partially matched by SQL foreach ($this->fields as $n=>$field) { if ($this->values[$n] && preg_match('/^('.WT_REGEX_TAG.'):PLAC$/', $field, $match)) { - if (!preg_match('/\n1 '.$match[1].'(\n[2-9].*)*\n2 PLAC .*'.preg_quote($this->values[$n], '/').'/i', $person->getGedcomRecord())) { + if (!preg_match('/\n1 '.$match[1].'(\n[2-9].*)*\n2 PLAC .*'.preg_quote($this->values[$n], '/').'/i', $person->getGedcom())) { continue 2; } } diff --git a/library/WT/Controller/Ancestry.php b/library/WT/Controller/Ancestry.php index 6228418cdc..23bafdd5b5 100644 --- a/library/WT/Controller/Ancestry.php +++ b/library/WT/Controller/Ancestry.php @@ -2,7 +2,7 @@ // Controller for the ancestry chart // // webtrees: Web based Family History software -// Copyright (C) 2012 webtrees development team. +// Copyright (C) 2013 webtrees development team. // // Derived from PhpGedView // Copyright (C) 2002 to 2009 PGV Development Team. All rights reserved. @@ -74,7 +74,7 @@ class WT_Controller_Ancestry extends WT_Controller_Chart { $pbwidth = $bwidth+12; $pbheight = $bheight+14; - if ($this->root && $this->root->canDisplayName()) { + if ($this->root && $this->root->canShowName()) { $this->setPageTitle( /* I18N: %s is an individual’s name */ WT_I18N::translate('Ancestors of %s', $this->root->getFullName()) diff --git a/library/WT/Controller/Chart.php b/library/WT/Controller/Chart.php index 6e54c135d7..ce9f1d9726 100644 --- a/library/WT/Controller/Chart.php +++ b/library/WT/Controller/Chart.php @@ -35,14 +35,14 @@ class WT_Controller_Chart extends WT_Controller_Page { $this->rootid = safe_GET_xref('rootid'); if ($this->rootid) { - $this->root = WT_Person::getInstance($this->rootid); + $this->root = WT_Individual::getInstance($this->rootid); } else { // Missing rootid parameter? Do something. $this->root = $this->getSignificantIndividual(); $this->rootid = $this->root->getXref(); } - if (!$this->root || !$this->root->canDisplayName()) { + if (!$this->root || !$this->root->canShowName()) { header($_SERVER['SERVER_PROTOCOL'].' 403 Forbidden'); $this->error_message=WT_I18N::translate('This individual does not exist or you do not have permission to view it.'); $this->rootid=null; diff --git a/library/WT/Controller/Compact.php b/library/WT/Controller/Compact.php index d8b051e248..5bda1695b1 100644 --- a/library/WT/Controller/Compact.php +++ b/library/WT/Controller/Compact.php @@ -2,7 +2,7 @@ // Controller for the compact chart // // webtrees: Web based Family History software -// Copyright (C) 2012 webtrees development team. +// Copyright (C) 2013 webtrees development team. // // Derived from PhpGedView // Copyright (C) 2002 to 2009 PGV Development Team. All rights reserved. @@ -41,7 +41,7 @@ class WT_Controller_Compact extends WT_Controller_Chart { // Extract the request parameters $this->show_thumbs=safe_GET_bool('show_thumbs'); - if ($this->root && $this->root->canDisplayName()) { + if ($this->root && $this->root->canShowName()) { $this->setPageTitle( /* I18N: %s is an individual’s name */ WT_I18N::translate('Compact tree of %s', $this->root->getFullName()) @@ -55,9 +55,9 @@ class WT_Controller_Compact extends WT_Controller_Chart { function sosa_person($n) { global $SHOW_HIGHLIGHT_IMAGES; - $indi=WT_Person::getInstance($this->treeid[$n]); + $indi=WT_Individual::getInstance($this->treeid[$n]); - if ($indi && $indi->canDisplayName()) { + if ($indi && $indi->canShowName()) { $name=$indi->getFullName(); $addname=$indi->getAddName(); @@ -72,7 +72,7 @@ class WT_Controller_Compact extends WT_Controller_Chart { if ($addname) $html .= '<br>' . $addname; $html .= '</a>'; $html .= '<br>'; - if ($indi->canDisplayDetails()) { + if ($indi->canShow()) { $html.='<div class="details1">'.$indi->getLifeSpan().'</div>'; } } else { @@ -115,7 +115,7 @@ class WT_Controller_Compact extends WT_Controller_Chart { } if ($pid) { - $indi=WT_Person::getInstance($pid); + $indi=WT_Individual::getInstance($pid); $title=WT_I18N::translate('Compact tree of %s', $indi->getFullName()); $text = '<a class="icon-'.$arrow_dir.'arrow" title="'.strip_tags($title).'" href="?rootid='.$pid; if ($this->show_thumbs) $text .= "&show_thumbs=".$this->show_thumbs; diff --git a/library/WT/Controller/Descendancy.php b/library/WT/Controller/Descendancy.php index f9d07c6977..9ee2c3d733 100644 --- a/library/WT/Controller/Descendancy.php +++ b/library/WT/Controller/Descendancy.php @@ -2,7 +2,7 @@ // Controller for the descendancy chart // // webtrees: Web based Family History software -// Copyright (C) 2012 webtrees development team. +// Copyright (C) 2013 webtrees development team. // // Derived from PhpGedView // Copyright (C) 2002 to 2009 PGV Development Team. All rights reserved. @@ -92,7 +92,7 @@ class WT_Controller_Descendancy extends WT_Controller_Chart { $this->cellwidth=(strlen($this->name)*14); } - if ($this->root && $this->root->canDisplayName()) { + if ($this->root && $this->root->canShowName()) { $this->setPageTitle( /* I18N: %s is an individual’s name */ WT_I18N::translate('Descendants of %s', $this->root->getFullName()) @@ -199,7 +199,7 @@ class WT_Controller_Descendancy extends WT_Controller_Chart { $spouse=$family->getSpouse($person); if (!$spouse) { // One parent families have no spouse - $spouse=new WT_Person(''); + $spouse=new WT_Individual(''); } // print marriage info @@ -244,7 +244,7 @@ class WT_Controller_Descendancy extends WT_Controller_Chart { } else { // Distinguish between no children (NCHI 0) and no recorded // children (no CHIL records) - if (strpos($family->getGedcomRecord(), '\n1 NCHI 0')) { + if (strpos($family->getGedcom(), '\n1 NCHI 0')) { echo WT_Gedcom_Tag::getLabel('NCHI').': '.count($children); } else { echo WT_I18N::translate('No children'); diff --git a/library/WT/Controller/Family.php b/library/WT/Controller/Family.php index 68151a0d35..686627562b 100644 --- a/library/WT/Controller/Family.php +++ b/library/WT/Controller/Family.php @@ -2,7 +2,7 @@ // Controller for the family page // // webtrees: Web based Family History software -// Copyright (C) 2012 webtrees development team. +// Copyright (C) 2013 webtrees development team. // // Derived from PhpGedView // Copyright (C) 2002 to 2010 PGV Development Team. All rights reserved. @@ -32,46 +32,14 @@ require_once WT_ROOT.'includes/functions/functions_print_facts.php'; require_once WT_ROOT.'includes/functions/functions_import.php'; class WT_Controller_Family extends WT_Controller_GedcomRecord { - var $diff_record; - var $record = null; - var $user = null; - var $display = false; - var $famrec = ''; - var $title = ''; - public function __construct() { global $Dbwidth, $bwidth, $pbwidth, $pbheight, $bheight; - $bwidth = $Dbwidth; - $pbwidth = $bwidth + 12; + $bwidth = $Dbwidth; + $pbwidth = $bwidth + 12; $pbheight = $bheight + 14; - $xref = safe_GET_xref('famid'); - - $gedrec = find_family_record($xref, WT_GED_ID); - - if (empty($gedrec)) { - $gedrec = "0 @".$xref."@ FAM\n"; - } - - if (find_family_record($xref, WT_GED_ID) || find_updated_record($xref, WT_GED_ID)!==null) { - $this->record = new WT_Family($gedrec); - $this->record->ged_id=WT_GED_ID; // This record is from a file - } else if (!$this->record) { - parent::__construct(); - return; - } - - $xref=$this->record->getXref(); // Correct upper/lower case mismatch - - //-- if the user can edit and there are changes then get the new changes - if (WT_USER_CAN_EDIT) { - $newrec = find_updated_record($xref, WT_GED_ID); - if (!empty($newrec)) { - $this->diff_record = new WT_Family($newrec); - $this->diff_record->setChanged(true); - $this->record->diffMerge($this->diff_record); - } - } + $xref = safe_GET_xref('famid'); + $this->record = WT_Family::getInstance($xref); parent::__construct(); } @@ -98,7 +66,7 @@ class WT_Controller_Family extends WT_Controller_GedcomRecord { // $tags is an array of HUSB/WIFE/CHIL function getTimelineIndis($tags) { - preg_match_all('/\n1 (?:'.implode('|', $tags).') @('.WT_REGEX_XREF.')@/', $this->record->getGedcomRecord(), $matches); + preg_match_all('/\n1 (?:'.implode('|', $tags).') @('.WT_REGEX_XREF.')@/', $this->record->getGedcom(), $matches); foreach ($matches[1] as &$match) { $match='pids[]='.$match; } @@ -111,7 +79,7 @@ class WT_Controller_Family extends WT_Controller_GedcomRecord { function getEditMenu() { $SHOW_GEDCOM_RECORD=get_gedcom_setting(WT_GED_ID, 'SHOW_GEDCOM_RECORD'); - if (!$this->record || $this->record->isMarkedDeleted()) { + if (!$this->record || $this->record->isOld()) { return null; } @@ -138,21 +106,6 @@ class WT_Controller_Family extends WT_Controller_GedcomRecord { } } - // edit/view raw gedcom - if (WT_USER_IS_ADMIN || $SHOW_GEDCOM_RECORD) { - $submenu = new WT_Menu(WT_I18N::translate('Edit raw GEDCOM record'), '#', 'menu-fam-editraw'); - $submenu->addOnclick("return edit_raw('".$this->record->getXref()."');"); - $menu->addSubmenu($submenu); - } elseif ($SHOW_GEDCOM_RECORD) { - $submenu = new WT_Menu(WT_I18N::translate('View GEDCOM Record'), '#', 'menu-fam-viewraw'); - if (WT_USER_CAN_EDIT) { - $submenu->addOnclick("return show_gedcom_record('new');"); - } else { - $submenu->addOnclick("return show_gedcom_record();"); - } - $menu->addSubmenu($submenu); - } - // delete if (WT_USER_CAN_EDIT) { $submenu = new WT_Menu(WT_I18N::translate('Delete'), '#', 'menu-fam-del'); @@ -202,7 +155,6 @@ class WT_Controller_Family extends WT_Controller_GedcomRecord { foreach ($indifacts as $fact) { print_fact($fact, $this->record); } - print_main_media($this->record->getXref()); } else { echo '<tr><td class="messagebox" colspan="2">', WT_I18N::translate('No facts for this family.'), '</td></tr>'; } diff --git a/library/WT/Controller/Familybook.php b/library/WT/Controller/Familybook.php index e75a46b6a6..c509a10af4 100644 --- a/library/WT/Controller/Familybook.php +++ b/library/WT/Controller/Familybook.php @@ -2,7 +2,7 @@ // Controller for the familybook chart // // webtrees: Web based Family History software -// Copyright (C) 2012 webtrees development team. +// Copyright (C) 2013 webtrees development team. // // Derived from PhpGedView // Copyright (C) 2002 to 2009 PGV Development Team. All rights reserved. @@ -64,7 +64,7 @@ class WT_Controller_Familybook extends WT_Controller_Chart { // Validate parameters if (!empty($rootid)) $this->pid = $rootid; $rootid=$this->rootid; - $this->hourPerson = WT_Person::getInstance($this->pid); + $this->hourPerson = WT_Individual::getInstance($this->pid); if (!$this->hourPerson) { $this->hourPerson=$this->getSignificantIndividual(); $this->pid=$this->hourPerson->getXref(); @@ -75,7 +75,7 @@ class WT_Controller_Familybook extends WT_Controller_Chart { $bheight = $cbheight; } $bhalfheight = $bheight / 2; - if ($this->root && $this->root->canDisplayName()) { + if ($this->root && $this->root->canShowName()) { $this->setPageTitle( /* I18N: %s is an individual’s name */ WT_I18N::translate('Family book of %s', $this->root->getFullName()) @@ -334,7 +334,7 @@ class WT_Controller_Familybook extends WT_Controller_Chart { */ function max_descendency_generations($pid, $depth) { if ($depth > $this->generations) return $depth; - $person = WT_Person::getInstance($pid); + $person = WT_Individual::getInstance($pid); if (is_null($person)) return $depth; $maxdc = $depth; foreach ($person->getSpouseFamilies() as $family) { @@ -360,7 +360,7 @@ class WT_Controller_Familybook extends WT_Controller_Chart { } function print_family_book($person, $descent) { global $firstrun; - if ($descent==0 || !$person->canDisplayName()) { + if ($descent==0 || !$person->canShowName()) { return; } $families=$person->getSpouseFamilies(); diff --git a/library/WT/Controller/Fanchart.php b/library/WT/Controller/Fanchart.php index 2b86dab1d6..ea6edf7c12 100644 --- a/library/WT/Controller/Fanchart.php +++ b/library/WT/Controller/Fanchart.php @@ -2,7 +2,7 @@ // Controller for the fan chart // // webtrees: Web based Family History software -// Copyright (C) 2012 webtrees development team. +// Copyright (C) 2013 webtrees development team. // // Derived from PhpGedView // Copyright (C) 2002 to 2009 PGV Development Team. All rights reserved. @@ -46,7 +46,7 @@ class WT_Controller_Fanchart extends WT_Controller_Chart { $this->fan_width =safe_GET_integer('fan_width', 50, 300, 100); $this->generations=safe_GET_integer('generations', 2, 9, $default_generations); - if ($this->root && $this->root->canDisplayName()) { + if ($this->root && $this->root->canShowName()) { $this->setPageTitle( /* I18N: http://en.wikipedia.org/wiki/Family_tree#Fan_chart - %s is an individual’s name */ WT_I18N::translate('Fan chart of %s', $this->root->getFullName()) @@ -211,7 +211,7 @@ class WT_Controller_Fanchart extends WT_Controller_Chart { while ($sosa >= $p2) { $pid=$treeid[$sosa]; if ($pid) { - $person =WT_Person::getInstance($pid); + $person =WT_Individual::getInstance($pid); $name =$person->getFullName(); $addname=$person->getAddName(); @@ -234,8 +234,8 @@ class WT_Controller_Fanchart extends WT_Controller_Chart { $text .= $person->getLifeSpan(); - $text = unhtmlentities($text); $text = strip_tags($text); + $text = htmlspecialchars_decode($text); // split and center text by lines $wmax = (int)($angle*7/$fanChart['size']*$scale); diff --git a/library/WT/Controller/GedcomRecord.php b/library/WT/Controller/GedcomRecord.php index 18c64bd9fa..233c7fbaac 100644 --- a/library/WT/Controller/GedcomRecord.php +++ b/library/WT/Controller/GedcomRecord.php @@ -29,6 +29,22 @@ class WT_Controller_GedcomRecord extends WT_Controller_Page { public $record; // individual, source, repository, etc. public function __construct() { + // Automatically fix broken links + if ($this->record && $this->record->canEdit()) { + $broken_links=0; + foreach ($this->record->getFacts('HUSB|WIFE|CHIL|FAMS|FAMC|SOUR|REPO|OBJE') as $fact) { // Not NOTE! + if (!$fact->isOld() && $fact->getTarget() === null) { + $this->record->updateFact($fact->getFactId(), null, false); + WT_FlashMessages::addMessage(/* I18N: %s are names of records, such as sources, repositories or individuals */ WT_I18N::translate('The link from “%1$s” to “%2$s” has been deleted.', $this->record->getFullName(), $fact->getValue())); + $broken_links = true; + } + } + if ($broken_links) { + // Reload the updated family + $this->record = WT_GedcomRecord::getInstance($this->record->getXref()); + } + } + parent::__construct(); // We want robots to index this page @@ -37,7 +53,7 @@ class WT_Controller_GedcomRecord extends WT_Controller_Page { // Set a page title if ($this->record) { $this->setCanonicalUrl($this->record->getHtmlUrl()); - if ($this->record->canDisplayName()) { + if ($this->record->canShowName()) { // e.g. "John Doe" or "1881 Census of Wales" $this->setPageTitle($this->record->getFullName()); } else { diff --git a/library/WT/Controller/Hourglass.php b/library/WT/Controller/Hourglass.php index 7dee4869e3..01285b296b 100644 --- a/library/WT/Controller/Hourglass.php +++ b/library/WT/Controller/Hourglass.php @@ -2,7 +2,7 @@ // Controller for the hourglass chart // // webtrees: Web based Family History software -// Copyright (C) 2012 webtrees development team. +// Copyright (C) 2013 webtrees development team. // // Derived from PhpGedView // Copyright (C) 2002 to 2009 PGV Development Team. All rights reserved. @@ -90,7 +90,7 @@ class WT_Controller_Hourglass extends WT_Controller_Chart { $bhalfheight = (int)($bheight / 2); // Validate parameters - $this->hourPerson = WT_Person::getInstance($this->pid); + $this->hourPerson = WT_Individual::getInstance($this->pid); if (!$this->hourPerson) { $this->hourPerson=$this->getSignificantIndividual(); $this->pid=$this->hourPerson->getXref(); @@ -347,7 +347,7 @@ class WT_Controller_Hourglass extends WT_Controller_Chart { // For the root person, print a down arrow that allows changing the root of tree if ($showNav && $count==1) { // NOTE: If statement OK - if ($person->canDisplayName()) { + if ($person->canShowName()) { // -- print left arrow for decendants so that we can move down the tree $famids = $person->getSpouseFamilies(); //-- make sure there is more than 1 child in the family with parents @@ -435,7 +435,7 @@ class WT_Controller_Hourglass extends WT_Controller_Chart { */ function max_descendency_generations($pid, $depth) { if ($depth > $this->generations) return $depth; - $person = WT_Person::getInstance($pid); + $person = WT_Individual::getInstance($pid); if (is_null($person)) return $depth; $maxdc = $depth; foreach ($person->getSpouseFamilies() as $family) { diff --git a/library/WT/Controller/Individual.php b/library/WT/Controller/Individual.php index 26cf33b4ec..c09304fa32 100644 --- a/library/WT/Controller/Individual.php +++ b/library/WT/Controller/Individual.php @@ -32,58 +32,29 @@ require_once WT_ROOT.'includes/functions/functions_print_facts.php'; require_once WT_ROOT.'includes/functions/functions_import.php'; class WT_Controller_Individual extends WT_Controller_GedcomRecord { - var $name_count = 0; - var $total_names = 0; - var $SEX_COUNT = 0; - var $Fam_Navigator = 'YES'; - var $NAME_LINENUM = null; - var $SEX_LINENUM = null; - var $globalfacts = null; + public $name_count = 0; + public $total_names = 0; + public $tabs; function __construct() { - global $USE_RIN, $MAX_ALIVE_AGE, $SEARCH_SPIDER; - global $DEFAULT_PIN_STATE, $DEFAULT_SB_CLOSED_STATE; - global $Fam_Navigator; - - $xref = safe_GET_xref('pid'); - - $gedrec = find_person_record($xref, WT_GED_ID); - - if ($USE_RIN && $gedrec==false) { - $xref = find_rin_id($xref); - $gedrec = find_person_record($xref, WT_GED_ID); - } - if (empty($gedrec)) { - $gedrec = "0 @".$xref."@ INDI\n"; - } + global $USE_RIN; - if (find_person_record($xref, WT_GED_ID) || find_updated_record($xref, WT_GED_ID)!==null) { - $this->record = new WT_Person($gedrec); - $this->record->ged_id=WT_GED_ID; // This record is from a file - } else if (!$this->record) { - parent::__construct(); - return; - } + $xref = safe_GET_xref('pid'); + $this->record = WT_Individual::getInstance($xref); - //-- if the user can edit and there are changes then get the new changes - if (WT_USER_CAN_EDIT || WT_USER_CAN_ACCEPT) { - $newrec = find_updated_record($xref, WT_GED_ID); - if (!empty($newrec)) { - $diff_record = new WT_Person($newrec); - $diff_record->setChanged(true); - $this->record->diffMerge($diff_record); - } + if (!$this->record && $USE_RIN) { + $rin = find_rin_id($xref); + $this->record = WT_Individual::getInstance($rin); } - $this->tabs=WT_Module::getActiveTabs(); - - // Our parent needs $this->record parent::__construct(); + $this->tabs = WT_Module::getActiveTabs(); + // If we can display the details, add them to the page header - if ($this->record && $this->record->canDisplayDetails()) { - $this->setPageTitle($this->record->getFullName().' '.$this->record->getLifespan()); + if ($this->record && $this->record->canShow()) { + $this->setPageTitle($this->record->getFullName() . ' ' . $this->record->getLifespan()); } } @@ -147,29 +118,33 @@ class WT_Controller_Individual extends WT_Controller_GedcomRecord { * @see individual.php * @param Event $event the event object */ - function print_name_record(WT_Event $event) { + function print_name_record(WT_Fact $event) { if (!$event->canShow()) { return false; } - $factrec = $event->getGedComRecord(); - $linenum = $event->getLineNumber(); + $factrec = $event->getGedcom(); // Create a dummy record, so we can extract the formatted NAME value from the event. - $dummy=new WT_Person('0 @'.$event->getParentObject()->getXref()."@ INDI\n1 DEAT Y\n".$factrec); + $dummy=new WT_Individual( + 'xref', + "0 @xref@ INDI\n1 DEAT Y\n".$factrec, + null, + WT_GED_ID + ); $all_names=$dummy->getAllNames(); $primary_name=$all_names[0]; $this->name_count++; if ($this->name_count >1) { echo '<h3 class="name_two">',$dummy->getFullName(), '</h3>'; } //Other names accordion element - echo '<div class="indi_name_details"'; - if ($event->getIsOld()) { - echo " class=\"namered\""; + echo '<div class="indi_name_details'; + if ($event->isOld()) { + echo ' old'; } - if ($event->getIsNew()) { - echo " class=\"nameblue\""; + if ($event->isNew()) { + echo ' new'; } - echo ">"; + echo '">'; echo '<div class="name1">'; echo '<dl><dt class="label">', WT_I18N::translate('Name'), '</dt>'; @@ -184,9 +159,9 @@ class WT_Controller_Individual extends WT_Controller_GedcomRecord { } } } - if ($this->record->canEdit() && !$event->getIsOld()) { - echo "<div class=\"deletelink\"><a class=\"font9 deleteicon\" href=\"#\" onclick=\"return delete_fact('".$this->record->getXref()."', ".$linenum.", '', '".WT_I18N::translate('Are you sure you want to delete this fact?')."');\" title=\"".WT_I18N::translate('Delete name')."\"><span class=\"link_text\">".WT_I18N::translate('Delete name')."</span></a></div>"; - echo "<div class=\"editlink\"><a href=\"#\" class=\"font9 editicon\" onclick=\"edit_name('".$this->record->getXref()."', ".$linenum."); return false;\" title=\"".WT_I18N::translate('Edit name')."\"><span class=\"link_text\">".WT_I18N::translate('Edit name')."</span></a></div>"; + if ($this->record->canEdit() && !$event->isOld()) { + echo "<div class=\"deletelink\"><a class=\"font9 deleteicon\" href=\"#\" onclick=\"return delete_fact('".WT_I18N::translate('Are you sure you want to delete this fact?')."', '".$this->record->getXref()."', '".$event->getFactId()."');\" title=\"".WT_I18N::translate('Delete name')."\"><span class=\"link_text\">".WT_I18N::translate('Delete name')."</span></a></div>"; + echo "<div class=\"editlink\"><a href=\"#\" class=\"font9 editicon\" onclick=\"edit_name('".$this->record->getXref()."', '".$event->getFactId()."'); return false;\" title=\"".WT_I18N::translate('Edit name')."\"><span class=\"link_text\">".WT_I18N::translate('Edit name')."</span></a></div>"; } echo '</dd>'; echo '</dl>'; @@ -243,50 +218,45 @@ class WT_Controller_Individual extends WT_Controller_GedcomRecord { * @see individual.php * @param Event $event the Event object */ - function print_sex_record(WT_Event $event) { - global $sex; - - if (!$event->canShow()) return false; - $factrec = $event->getGedComRecord(); - $sex = $event->getDetail(); + function print_sex_record(WT_Fact $event) { + $sex = $event->getValue(); if (empty($sex)) $sex = 'U'; - echo '<span id="sex"'; - echo ' class="'; - if ($event->getIsOld()) { - echo 'namered '; - } - if ($event->getIsNew()) { - echo 'nameblue '; - } - switch ($sex) { - case 'M': - echo 'male_gender"'; - if ($this->record->canEdit() && !$event->getIsOld()) { - echo ' title="', WT_I18N::translate('Male'), ' - ', WT_I18N::translate('Edit'), '"'; - echo ' onclick="edit_record(\''.$this->record->getXref().'\', '.$event->getLineNumber().'); return false;"> '; - } else { - echo ' title="', WT_I18N::translate('Male'), '"> '; - } - break; - case 'F': - echo 'female_gender"'; - if ($this->record->canEdit() && !$event->getIsOld()) { - echo ' title="', WT_I18N::translate('Female'), ' - ', WT_I18N::translate('Edit'), '"'; - echo ' onclick="edit_record(\''.$this->record->getXref().'\', '.$event->getLineNumber().'); return false;"> '; - } else { - echo ' title="', WT_I18N::translate('Female'), '"> '; - } - break; - case 'U': - echo 'unknown_gender"'; - if ($this->record->canEdit() && !$event->getIsOld()) { - echo ' title="', WT_I18N::translate_c('unknown gender', 'Unknown'), ' - ', WT_I18N::translate('Edit'), '"'; - echo ' onclick="edit_record(\''.$this->record->getXref().'\', '.$event->getLineNumber().'); return false;"> '; - } else { - echo ' title="', WT_I18N::translate_c('unknown gender', 'Unknown'), '"> '; - } - break; - } + echo '<span id="sex" class="'; + if ($event->isOld()) { + echo 'old'; + } + if ($event->isNew()) { + echo 'new'; + } + switch ($sex) { + case 'M': + echo ' male_gender"'; + if ($event->canEdit()) { + echo ' title="', WT_I18N::translate('Male'), ' - ', WT_I18N::translate('Edit'), '"'; + echo ' onclick="edit_record(\''.$this->record->getXref().'\', \''.$event->getFactId().'\'); return false;">'; + } else { + echo ' title="', WT_I18N::translate('Male'), '">'; + } + break; + case 'F': + echo ' female_gender"'; + if ($event->canEdit()) { + echo ' title="', WT_I18N::translate('Female'), ' - ', WT_I18N::translate('Edit'), '"'; + echo ' onclick="edit_record(\''.$this->record->getXref().'\', \''.$event->getFactId().'\'); return false;">'; + } else { + echo ' title="', WT_I18N::translate('Female'), '">'; + } + break; + case 'U': + echo ' unknown_gender"'; + if ($event->canEdit()) { + echo ' title="', WT_I18N::translate_c('unknown gender', 'Unknown'), ' - ', WT_I18N::translate('Edit'), '"'; + echo ' onclick="edit_record(\''.$this->record->getXref().'\', \''.$event->getFactId().'\'); return false;">'; + } else { + echo ' title="', WT_I18N::translate_c('unknown gender', 'Unknown'), '">'; + } + break; + } echo '</span>'; } /** @@ -295,39 +265,41 @@ class WT_Controller_Individual extends WT_Controller_GedcomRecord { function getEditMenu() { $SHOW_GEDCOM_RECORD=get_gedcom_setting(WT_GED_ID, 'SHOW_GEDCOM_RECORD'); - if (!$this->record || $this->record->isMarkedDeleted()) { + if (!$this->record || $this->record->isOld()) { return null; } // edit menu $menu = new WT_Menu(WT_I18N::translate('Edit'), '#', 'menu-indi'); $menu->addLabel($menu->label, 'down'); - $this->getGlobalFacts(); // sets NAME_LINENUM and SEX_LINENUM. individual.php doesn't do it early enough for us.... - // What behaviour shall we give the main menu? If we leave it blank, the framework // will copy the first submenu - which may be edit-raw or delete. // As a temporary solution, make it edit the name - if (WT_USER_CAN_EDIT && $this->NAME_LINENUM) { - $menu->addOnclick("return edit_name('".$this->record->getXref()."', ".$this->NAME_LINENUM.");"); - } else { - $menu->addOnclick("return false;"); - } - + $menu->addOnclick("return false;"); if (WT_USER_CAN_EDIT) { - //--make sure the totals are correct + foreach ($this->record->getFacts() as $fact) { + if ($fact->getTag()=='NAME' && $fact->canShow() && $fact->canEdit()) + $menu->addOnclick("return edit_name('".$this->record->getXref() . "', '" . $fact->getFactId() . "');"); + break; + } + $submenu = new WT_Menu(WT_I18N::translate('Add new Name'), '#', 'menu-indi-addname'); $submenu->addOnclick("return add_name('".$this->record->getXref()."');"); $menu->addSubmenu($submenu); - if ($this->SEX_COUNT<2) { - $submenu = new WT_Menu(WT_I18N::translate('Edit gender'), '#', 'menu-indi-editsex'); - if ($this->SEX_LINENUM=="new") { - $submenu->addOnclick("return add_new_record('".$this->record->getXref()."', 'SEX');"); - } else { - $submenu->addOnclick("return edit_record('".$this->record->getXref()."', ".$this->SEX_LINENUM.");"); + $has_sex_record = false; + $submenu = new WT_Menu(WT_I18N::translate('Edit gender'), '#', 'menu-indi-editsex'); + foreach ($this->record->getFacts() as $fact) { + if ($fact->getTag()=='SEX' && $fact->canShow() && $fact->canEdit()) { + $submenu->addOnclick("return edit_record('" . $this->record->getXref() . "', '" . $fact->getFactId() . "');"); + $has_sex_record = true; + break; } - $menu->addSubmenu($submenu); } + if (!$has_sex_record) { + $submenu->addOnclick("return add_new_record('" . $this->record->getXref() . "', 'SEX');"); + } + $menu->addSubmenu($submenu); if (count($this->record->getSpouseFamilies())>1) { $submenu = new WT_Menu(WT_I18N::translate('Re-order families'), '#', 'menu-indi-orderfam'); @@ -336,21 +308,6 @@ class WT_Controller_Individual extends WT_Controller_GedcomRecord { } } - // edit/view raw gedcom - if (WT_USER_IS_ADMIN || $SHOW_GEDCOM_RECORD) { - $submenu = new WT_Menu(WT_I18N::translate('Edit raw GEDCOM record'), '#', 'menu-indi-editraw'); - $submenu->addOnclick("return edit_raw('".$this->record->getXref()."');"); - $menu->addSubmenu($submenu); - } elseif ($SHOW_GEDCOM_RECORD) { - $submenu = new WT_Menu(WT_I18N::translate('View GEDCOM Record'), '#', 'menu-indi-viewraw'); - if (WT_USER_CAN_EDIT) { - $submenu->addOnclick("return show_gedcom_record('new');"); - } else { - $submenu->addOnclick("return show_gedcom_record();"); - } - $menu->addSubmenu($submenu); - } - // delete if (WT_USER_CAN_EDIT) { $submenu = new WT_Menu(WT_I18N::translate('Delete'), '#', 'menu-indi-del'); @@ -372,48 +329,7 @@ class WT_Controller_Individual extends WT_Controller_GedcomRecord { return $menu; } - /** - * get global facts - * global facts are NAME and SEX - * @return array return the array of global facts - */ - function getGlobalFacts() { - if ($this->globalfacts==null) { - $this->globalfacts = $this->record->getGlobalFacts(); - foreach ($this->globalfacts as $key => $value) { - $fact = $value->getTag(); - if ($fact=="SEX") { - $this->SEX_COUNT++; - $this->SEX_LINENUM = $value->getLineNumber(); - } - if ($fact=="NAME") { - $this->total_names++; - if ($this->NAME_LINENUM==null && !$value->getIsOld()) { - // This is the "primary" name and is edited from the menu - // Subsequent names get their own edit links - $this->NAME_LINENUM = $value->getLineNumber(); - } - } - } - } - return $this->globalfacts; - } - /** - * get the individual facts shown on tab 1 - * @return array - */ - function getIndiFacts() { - $indifacts = $this->record->getIndiFacts(); - sort_facts($indifacts); - return $indifacts; - } - /** - * get the other facts shown on tab 2 - * @return array - */ - function getOtherFacts() { - $otherfacts = $this->record->getOtherFacts(); - return $otherfacts; + function add_asso_facts() { } /** @@ -514,22 +430,10 @@ class WT_Controller_Individual extends WT_Controller_GedcomRecord { $newwife = null; $newchildren = array(); $delchildren = array(); - $children = array(); - $husb = null; - $wife = null; - if (!$family->getChanged()) { - $husb = $family->getHusband(); - $wife = $family->getWife(); - $children = $family->getChildren(); - } - //-- step families : set the label for the common parent - if ($type=="step-parents") { - $fams = $this->record->getChildFamilies(); - foreach ($fams as $key=>$fam) { - if ($fam->hasParent($husb)) $labels["father"] = get_relationship_name_from_path('fat', null, null); - if ($fam->hasParent($wife)) $labels["mother"] = get_relationship_name_from_path('mot', null, null); - } - } + $husb = $family->getHusband(); + $wife = $family->getWife(); + $children = $family->getChildren(); + //-- set the label for the husband if (!is_null($husb)) { $label = $labels["parent"]; @@ -560,80 +464,6 @@ class WT_Controller_Individual extends WT_Controller_GedcomRecord { } $wife->setLabel($label); } - if (WT_USER_CAN_EDIT || WT_USER_CAN_ACCEPT) { - $newfamily = $family->getUpdatedFamily(); - if (!is_null($newfamily)) { - $newhusb = $newfamily->getHusband(); - //-- check if the husband in the family has changed - if (!is_null($newhusb) && !$newhusb->equals($husb)) { - $label = $labels["parent"]; - $sex = $newhusb->getSex(); - if ($sex=="F") { - $label = $labels["mother"]; - } - if ($sex=="M") { - $label = $labels["father"]; - } - if ($newhusb->getXref()==$this->record->getXref()) { - $label = '<i class="icon-selected"></i>'; - } - $newhusb->setLabel($label); - } - else $newhusb = null; - $newwife = $newfamily->getWife(); - //-- check if the wife in the family has changed - if (!is_null($newwife) && !$newwife->equals($wife)) { - $label = $labels["parent"]; - $sex = $newwife->getSex(); - if ($sex=="F") { - $label = $labels["mother"]; - } - if ($sex=="M") { - $label = $labels["father"]; - } - if ($newwife->getXref()==$this->record->getXref()) { - $label = '<i class="icon-selected"></i>'; - } - $newwife->setLabel($label); - } - else $newwife = null; - //-- check for any new children - $merged_children = array(); - $new_children = $newfamily->getChildren(); - $num = count($children); - for ($i=0; $i<$num; $i++) { - $child = $children[$i]; - if (!is_null($child)) { - $found = false; - foreach ($new_children as $key=>$newchild) { - if (!is_null($newchild)) { - if ($child->equals($newchild)) { - $found = true; - break; - } - } - } - if (!$found) $delchildren[] = $child; - else $merged_children[] = $child; - } - } - foreach ($new_children as $key=>$newchild) { - if (!is_null($newchild)) { - $found = false; - foreach ($children as $key1=>$child) { - if (!is_null($child)) { - if ($child->equals($newchild)) { - $found = true; - break; - } - } - } - if (!$found) $newchildren[] = $newchild; - } - } - $children = $merged_children; - } - } //-- set the labels for the children $num = count($children); for ($i=0; $i<$num; $i++) { @@ -650,7 +480,7 @@ class WT_Controller_Individual extends WT_Controller_GedcomRecord { $label = '<i class="icon-selected"></i>'; } if ($include_pedi==true) { - $famcrec = get_sub_record(1, "1 FAMC @".$family->getXref()."@", $children[$i]->getGedcomRecord()); + $famcrec = get_sub_record(1, "1 FAMC @".$family->getXref()."@", $children[$i]->getGedcom()); $pedi = get_gedcom_value("PEDI", 2, $famcrec); if ($pedi) { $label.='<br>('.WT_Gedcom_Code_Pedi::getValue($pedi, $children[$i]).')'; diff --git a/library/WT/Controller/Lifespan.php b/library/WT/Controller/Lifespan.php index 60c6664289..4c4f325d30 100644 --- a/library/WT/Controller/Lifespan.php +++ b/library/WT/Controller/Lifespan.php @@ -122,7 +122,7 @@ class WT_Controller_Lifespan extends WT_Controller_Page { } } } elseif ($newpid) { - $person=WT_Person::getInstance($newpid); + $person=WT_Individual::getInstance($newpid); $this->addFamily($person, $addfam); } elseif (!$this->pids) { $this->addFamily($this->getSignificantIndividual(), false); @@ -138,13 +138,13 @@ class WT_Controller_Lifespan extends WT_Controller_Page { foreach ($this->pids as $key => $value) { if ($value != $remove) { $this->pids[$key] = $value; - $person = WT_Person::getInstance($value); + $person = WT_Individual::getInstance($value); // list of linked records includes families as well as individuals. if ($person) { $bdate = $person->getEstimatedBirthDate(); $ddate = $person->getEstimatedDeathDate(); //--Checks to see if the details of that person can be viewed - if ($bdate->isOK() && $person->canDisplayDetails()) { + if ($bdate->isOK() && $person->canShow()) { $this->people[] = $person; } } @@ -169,7 +169,7 @@ class WT_Controller_Lifespan extends WT_Controller_Page { $bdate = $person->getEstimatedBirthDate(); $ddate = $person->getEstimatedDeathDate(); //--Checks to see if the details of that person can be viewed - if ($bdate->isOK() && $person->canDisplayDetails()) { + if ($bdate->isOK() && $person->canShow()) { $this->people[] = $person; } } @@ -424,7 +424,7 @@ class WT_Controller_Lifespan extends WT_Controller_Page { $evntwdth = $eventwidth."%"; //-- if the fact is a generic EVENt then get the qualifying TYPE if ($fact=="EVEN") { - $fact = $val->getType(); + $fact = $val->getAttribute('TYPE'); } $place = $val->getPlace(); $trans = WT_Gedcom_Tag::getLabel($fact); @@ -532,18 +532,18 @@ class WT_Controller_Lifespan extends WT_Controller_Page { $endjd =WT_Date_Gregorian::YMDtoJD($endyear+1, 1, 1)-1; $sql= - "SELECT DISTINCT 'INDI' AS type, i_id AS xref, i_file AS ged_id, i_gedcom AS gedrec". + "SELECT DISTINCT i_id AS xref, i_file AS gedcom_id, i_gedcom AS gedcom". " FROM `##individuals`". " JOIN `##dates` ON i_id=d_gid AND i_file=d_file". " WHERE i_file=? AND d_julianday1 BETWEEN ? AND ?"; $rows=WT_DB::prepare($sql) ->execute(array(WT_GED_ID, $startjd, $endjd)) - ->fetchAll(PDO::FETCH_ASSOC); + ->fetchAll(); $list=array(); foreach ($rows as $row) { - $list[]=WT_Person::getInstance($row); + $list[]=WT_Individual::getInstance($row->xref, $row->gedcom_id, $row->gedcom); } return $list; } diff --git a/library/WT/Controller/Media.php b/library/WT/Controller/Media.php index 562bf8aabe..c9fbf39547 100644 --- a/library/WT/Controller/Media.php +++ b/library/WT/Controller/Media.php @@ -2,7 +2,7 @@ // Controller for the media page // // webtrees: Web based Family History software -// Copyright (C) 2012 webtrees development team. +// Copyright (C) 2013 webtrees development team. // // Derived from PhpGedView // Copyright (C) 2002 to 2009 PGV Development Team. All rights reserved. @@ -34,35 +34,8 @@ require_once WT_ROOT.'includes/functions/functions_import.php'; class WT_Controller_Media extends WT_Controller_GedcomRecord { public function __construct() { - $xref = safe_GET_xref('mid'); - - $gedrec=find_media_record($xref, WT_GED_ID); - if (WT_USER_CAN_EDIT) { - $newrec=find_updated_record($xref, WT_GED_ID); - } else { - $newrec=null; - } - - if ($gedrec===null) { - if ($newrec===null) { - // Nothing to see here. - parent::__construct(); - return; - } else { - // Create a dummy record from the first line of the new record. - // We need it for diffMerge(), getXref(), etc. - list($gedrec)=explode("\n", $newrec); - } - } - - $this->record = new WT_Media($gedrec); - - // If there are pending changes, merge them in. - if ($newrec!==null) { - $diff_record=new WT_Media($newrec); - $diff_record->setChanged(true); - $this->record->diffMerge($diff_record); - } + $xref = safe_GET_xref('mid'); + $this->record = WT_Media::getInstance($xref); parent::__construct(); } @@ -73,7 +46,7 @@ class WT_Controller_Media extends WT_Controller_GedcomRecord { function getEditMenu() { $SHOW_GEDCOM_RECORD=get_gedcom_setting(WT_GED_ID, 'SHOW_GEDCOM_RECORD'); - if (!$this->record || $this->record->isMarkedDeleted()) { + if (!$this->record || $this->record->isOld()) { return null; } @@ -107,21 +80,6 @@ class WT_Controller_Media extends WT_Controller_GedcomRecord { $menu->addSubmenu($submenu); } - // edit/view raw gedcom - if (WT_USER_IS_ADMIN || $SHOW_GEDCOM_RECORD) { - $submenu = new WT_Menu(WT_I18N::translate('Edit raw GEDCOM record'), '#', 'menu-obje-editraw'); - $submenu->addOnclick("return edit_raw('".$this->record->getXref()."');"); - $menu->addSubmenu($submenu); - } elseif ($SHOW_GEDCOM_RECORD) { - $submenu = new WT_Menu(WT_I18N::translate('View GEDCOM Record'), '#', 'menu-obje-viewraw'); - if (WT_USER_CAN_EDIT || WT_USER_CAN_ACCEPT) { - $submenu->addOnclick("return show_gedcom_record('new');"); - } else { - $submenu->addOnclick("return show_gedcom_record();"); - } - $menu->addSubmenu($submenu); - } - // delete if (WT_USER_CAN_EDIT) { $submenu = new WT_Menu(WT_I18N::translate('Delete'), '#', 'menu-obje-del'); @@ -153,17 +111,17 @@ class WT_Controller_Media extends WT_Controller_GedcomRecord { * @return array */ function getFacts($includeFileName=true) { - $facts = $this->record->getFacts(array()); + $facts = $this->record->getFacts(); // Add some dummy facts to show additional information if ($this->record->fileExists()) { // get height and width of image, when available $imgsize = $this->record->getImageAttributes(); if (!empty($imgsize['WxH'])) { - $facts[] = new WT_Event('1 __IMAGE_SIZE__ '.$imgsize['WxH'], $this->record, 0); + $facts[] = new WT_Fact('1 __IMAGE_SIZE__ '.$imgsize['WxH'], $this->record, 0); } //Prints the file size - $facts[] = new WT_Event('1 __FILE_SIZE__ '.$this->record->getFilesize(), $this->record, 0); + $facts[] = new WT_Fact('1 __FILE_SIZE__ '.$this->record->getFilesize(), $this->record, 0); } sort_facts($facts); diff --git a/library/WT/Controller/Note.php b/library/WT/Controller/Note.php index 01fad484c8..003fd45acd 100644 --- a/library/WT/Controller/Note.php +++ b/library/WT/Controller/Note.php @@ -2,7 +2,7 @@ // Controller for the shared note page // // webtrees: Web based Family History software -// Copyright (C) 2012 webtrees development team. +// Copyright (C) 2013 webtrees development team. // // Derived from PhpGedView // Copyright (C) 2009 PGV Development Team. All rights reserved. @@ -33,35 +33,8 @@ require_once WT_ROOT.'includes/functions/functions_import.php'; class WT_Controller_Note extends WT_Controller_GedcomRecord { public function __construct() { - $xref=safe_GET_xref('nid'); - - $gedrec=find_other_record($xref, WT_GED_ID); - if (WT_USER_CAN_EDIT) { - $newrec=find_updated_record($xref, WT_GED_ID); - } else { - $newrec=null; - } - - if ($gedrec===null) { - if ($newrec===null) { - // Nothing to see here. - parent::__construct(); - return; - } else { - // Create a dummy record from the first line of the new record. - // We need it for diffMerge(), getXref(), etc. - list($gedrec)=explode("\n", $newrec); - } - } - - $this->record = new WT_Note($gedrec); - - // If there are pending changes, merge them in. - if ($newrec!==null) { - $diff_record=new WT_Note($newrec); - $diff_record->setChanged(true); - $this->record->diffMerge($diff_record); - } + $xref = safe_GET_xref('nid'); + $this->record = WT_Note::getInstance($xref); parent::__construct(); } @@ -72,7 +45,7 @@ class WT_Controller_Note extends WT_Controller_GedcomRecord { function getEditMenu() { $SHOW_GEDCOM_RECORD=get_gedcom_setting(WT_GED_ID, 'SHOW_GEDCOM_RECORD'); - if (!$this->record || $this->record->isMarkedDeleted()) { + if (!$this->record || $this->record->isOld()) { return null; } @@ -85,21 +58,6 @@ class WT_Controller_Note extends WT_Controller_GedcomRecord { $menu->addSubmenu($submenu); } - // edit/view raw gedcom - if (WT_USER_IS_ADMIN || $SHOW_GEDCOM_RECORD) { - $submenu = new WT_Menu(WT_I18N::translate('Edit raw GEDCOM record'), '#', 'menu-note-editraw'); - $submenu->addOnclick("return edit_raw('".$this->record->getXref()."');"); - $menu->addSubmenu($submenu); - } elseif ($SHOW_GEDCOM_RECORD) { - $submenu = new WT_Menu(WT_I18N::translate('View GEDCOM Record'), '#', 'menu-note-viewraw'); - if (WT_USER_CAN_EDIT) { - $submenu->addOnclick("return show_gedcom_record('new');"); - } else { - $submenu->addOnclick("return show_gedcom_record();"); - } - $menu->addSubmenu($submenu); - } - // delete if (WT_USER_CAN_EDIT) { $submenu = new WT_Menu(WT_I18N::translate('Delete'), '#', 'menu-note-del'); diff --git a/library/WT/Controller/Page.php b/library/WT/Controller/Page.php index 55a6b55cdc..d2fe6031db 100644 --- a/library/WT/Controller/Page.php +++ b/library/WT/Controller/Page.php @@ -163,7 +163,6 @@ class WT_Controller_Page extends WT_Controller_Base { var browserType = "'.$BROWSERTYPE.'"; var WT_SCRIPT_NAME = "'.WT_SCRIPT_NAME.'"; var WT_LOCALE = "'.WT_LOCALE.'"; - var accesstime = '.WT_TIMESTAMP.'; ', self::JS_PRIORITY_HIGH); // Temporary fix for access to main menu hover elements on android/blackberry touch devices @@ -220,16 +219,16 @@ class WT_Controller_Page extends WT_Controller_Base { static $individual; // Only query the DB once. if (!$individual && WT_USER_ROOT_ID) { - $individual=WT_Person::getInstance(WT_USER_ROOT_ID); + $individual=WT_Individual::getInstance(WT_USER_ROOT_ID); } if (!$individual && WT_USER_GEDCOM_ID) { - $individual=WT_Person::getInstance(WT_USER_GEDCOM_ID); + $individual=WT_Individual::getInstance(WT_USER_GEDCOM_ID); } if (!$individual) { - $individual=WT_Person::getInstance(get_gedcom_setting(WT_GED_ID, 'PEDIGREE_ROOT_ID')); + $individual=WT_Individual::getInstance(get_gedcom_setting(WT_GED_ID, 'PEDIGREE_ROOT_ID')); } if (!$individual) { - $individual=WT_Person::getInstance( + $individual=WT_Individual::getInstance( WT_DB::prepare( "SELECT MIN(i_id) FROM `##individuals` WHERE i_file=?" )->execute(array(WT_GED_ID))->fetchOne() @@ -237,7 +236,7 @@ class WT_Controller_Page extends WT_Controller_Base { } if (!$individual) { // always return a record - $individual=new WT_Person('0 @I@ INDI'); + $individual=new WT_Individual('I', '0 @I@ INDI', null, WT_GED_ID); } return $individual; } @@ -252,7 +251,7 @@ class WT_Controller_Page extends WT_Controller_Base { } } // always return a record - return new WT_Family('0 @F@ FAM'); + return new WT_Family('F', '0 @F@ FAM', null, WT_GED_ID); } public function getSignificantSurname() { return ''; diff --git a/library/WT/Controller/Pedigree.php b/library/WT/Controller/Pedigree.php index 65bb3174f0..5133aea959 100644 --- a/library/WT/Controller/Pedigree.php +++ b/library/WT/Controller/Pedigree.php @@ -2,7 +2,7 @@ // Controller for the pedigree chart // // webtrees: Web based Family History software -// Copyright (C) 2012 webtrees development team. +// Copyright (C) 2013 webtrees development team. // // Derived from PhpGedView // Copyright (C) 2002 to 2009 PGV Development Team. All rights reserved. @@ -85,7 +85,7 @@ class WT_Controller_Pedigree extends WT_Controller_Chart { $show_full = $this->show_full; $talloffset = $this->talloffset; - if ($this->root && $this->root->canDisplayName()) { + if ($this->root && $this->root->canShowName()) { $this->setPageTitle( /* I18N: %s is an individual’s name */ WT_I18N::translate('Pedigree tree of %s', $this->root->getFullName()) diff --git a/library/WT/Controller/Repository.php b/library/WT/Controller/Repository.php index 7af4c8c139..2c409a6110 100644 --- a/library/WT/Controller/Repository.php +++ b/library/WT/Controller/Repository.php @@ -2,7 +2,7 @@ // Controller for the repository page // // webtrees: Web based Family History software -// Copyright (C) 2012 webtrees development team. +// Copyright (C) 2013 webtrees development team. // // Derived from PhpGedView // Copyright (C) 2002 to 2010 PGV Development Team. All rights reserved. @@ -33,35 +33,8 @@ require_once WT_ROOT.'includes/functions/functions_import.php'; class WT_Controller_Repository extends WT_Controller_GedcomRecord { public function __construct() { - $xref = safe_GET_xref('rid'); - - $gedrec=find_other_record($xref, WT_GED_ID); - if (WT_USER_CAN_EDIT) { - $newrec=find_updated_record($xref, WT_GED_ID); - } else { - $newrec=null; - } - - if ($gedrec===null) { - if ($newrec===null) { - // Nothing to see here. - parent::__construct(); - return; - } else { - // Create a dummy record from the first line of the new record. - // We need it for diffMerge(), getXref(), etc. - list($gedrec)=explode("\n", $newrec); - } - } - - $this->record = new WT_Repository($gedrec); - - // If there are pending changes, merge them in. - if ($newrec!==null) { - $diff_record=new WT_Repository($newrec); - $diff_record->setChanged(true); - $this->record->diffMerge($diff_record); - } + $xref = safe_GET_xref('rid'); + $this->record = WT_Repository::getInstance($xref); parent::__construct(); } @@ -72,7 +45,7 @@ class WT_Controller_Repository extends WT_Controller_GedcomRecord { function getEditMenu() { $SHOW_GEDCOM_RECORD=get_gedcom_setting(WT_GED_ID, 'SHOW_GEDCOM_RECORD'); - if (!$this->record || $this->record->isMarkedDeleted()) { + if (!$this->record || $this->record->isOld()) { return null; } @@ -85,21 +58,6 @@ class WT_Controller_Repository extends WT_Controller_GedcomRecord { $menu->addSubmenu($submenu); } - // edit/view raw gedcom - if (WT_USER_IS_ADMIN || $SHOW_GEDCOM_RECORD) { - $submenu = new WT_Menu(WT_I18N::translate('Edit raw GEDCOM record'), '#', 'menu-repo-editraw'); - $submenu->addOnclick("return edit_raw('".$this->record->getXref()."');"); - $menu->addSubmenu($submenu); - } elseif ($SHOW_GEDCOM_RECORD) { - $submenu = new WT_Menu(WT_I18N::translate('View GEDCOM Record'), '#', 'menu-repo-viewraw'); - if (WT_USER_CAN_EDIT) { - $submenu->addOnclick("return show_gedcom_record('new');"); - } else { - $submenu->addOnclick("return show_gedcom_record();"); - } - $menu->addSubmenu($submenu); - } - // delete if (WT_USER_CAN_EDIT) { $submenu = new WT_Menu(WT_I18N::translate('Delete'), '#', 'menu-repo-del'); diff --git a/library/WT/Controller/Search.php b/library/WT/Controller/Search.php index 90a83891a1..ac67d6a0c7 100644 --- a/library/WT/Controller/Search.php +++ b/library/WT/Controller/Search.php @@ -285,7 +285,7 @@ class WT_Controller_Search extends WT_Controller_Page { // Then see if an ID is typed in. If so, we might want to jump there. if (isset ($this->query)) { $record=WT_GedcomRecord::getInstance($this->query); - if ($record && $record->canDisplayDetails()) { + if ($record && $record->canShow()) { header('Location: '.WT_SERVER_NAME.WT_SCRIPT_PATH.$record->getRawUrl()); exit; } @@ -357,7 +357,7 @@ class WT_Controller_Search extends WT_Controller_Page { // If ID cannot be displayed, continue to the search page. if (count($this->myindilist)==1 && !$this->myfamlist && !$this->mysourcelist && !$this->mynotelist) { $indi=$this->myindilist[0]; - if ($indi->canDisplayName()) { + if ($indi->canShowName()) { Zend_Session::writeClose(); header('Location: '.WT_SERVER_NAME.WT_SCRIPT_PATH.$indi->getRawUrl()); exit; @@ -365,7 +365,7 @@ class WT_Controller_Search extends WT_Controller_Page { } if (!$this->myindilist && count($this->myfamlist)==1 && !$this->mysourcelist && !$this->mynotelist) { $fam=$this->myfamlist[0]; - if ($fam->canDisplayName()) { + if ($fam->canShowName()) { Zend_Session::writeClose(); header('Location: '.WT_SERVER_NAME.WT_SCRIPT_PATH.$fam->getRawUrl()); exit; @@ -373,7 +373,7 @@ class WT_Controller_Search extends WT_Controller_Page { } if (!$this->myindilist && !$this->myfamlist && count($this->mysourcelist)==1 && !$this->mynotelist) { $sour=$this->mysourcelist[0]; - if ($sour->canDisplayName()) { + if ($sour->canShowName()) { Zend_Session::writeClose(); header('Location: '.WT_SERVER_NAME.WT_SCRIPT_PATH.$sour->getRawUrl()); exit; @@ -381,7 +381,7 @@ class WT_Controller_Search extends WT_Controller_Page { } if (!$this->myindilist && !$this->myfamlist && !$this->mysourcelist && count($this->mynotelist)==1) { $note=$this->mynotelist[0]; - if ($note->canDisplayName()) { + if ($note->canShowName()) { Zend_Session::writeClose(); header('Location: '.WT_SERVER_NAME.WT_SCRIPT_PATH.$note->getRawUrl()); exit; @@ -443,7 +443,7 @@ class WT_Controller_Search extends WT_Controller_Page { } //-- if the record changed replace the record otherwise remove it from the search results if ($newRecord != $oldRecord) { - replace_gedrec($individual->getXref(), WT_GED_ID, $newRecord); + $individual->updateRecord($newRecord, true); } else { unset($this->myindilist[$id]); } @@ -465,7 +465,7 @@ class WT_Controller_Search extends WT_Controller_Page { } //-- if the record changed replace the record otherwise remove it from the search results if ($newRecord != $oldRecord) { - replace_gedrec($family->getXref(), WT_GED_ID, $newRecord); + $family->updateRecord($newRecord, true); } else { unset($this->myfamlist[$id]); } @@ -490,7 +490,7 @@ class WT_Controller_Search extends WT_Controller_Page { } //-- if the record changed replace the record otherwise remove it from the search results if ($newRecord != $oldRecord) { - replace_gedrec($source->getXref(), WT_GED_ID, $newRecord); + $source->updateRecord($newRecord, true); } else { unset($this->mysourcelist[$id]); } @@ -506,7 +506,7 @@ class WT_Controller_Search extends WT_Controller_Page { } //-- if the record changed replace the record otherwise remove it from the search results if ($newRecord != $oldRecord) { - replace_gedrec($note->getXref(), WT_GED_ID, $newRecord); + $noteource->updateRecord($newRecord, true); } else { unset($this->mynotelist[$id]); } @@ -557,10 +557,10 @@ class WT_Controller_Search extends WT_Controller_Page { if ($this->showasso == "on") { foreach ($this->myindilist as $indi) { - foreach (fetch_linked_indi($indi->getXref(), 'ASSO', $indi->getGedId()) as $asso) { + foreach (fetch_linked_indi($indi->getXref(), 'ASSO', $indi->getGedcomId()) as $asso) { $this->myindilist[]=$asso; } - foreach (fetch_linked_fam($indi->getXref(), 'ASSO', $indi->getGedId()) as $asso) { + foreach (fetch_linked_fam($indi->getXref(), 'ASSO', $indi->getGedcomId()) as $asso) { $this->myfamlist[]=$asso; } } @@ -603,7 +603,7 @@ class WT_Controller_Search extends WT_Controller_Page { foreach ($this->sgeds as $ged_id=>$gedcom) { $datalist = array(); foreach ($this->myindilist as $individual) { - if ($individual->getGedId()==$ged_id) { + if ($individual->getGedcomId()==$ged_id) { $datalist[]=$individual; } } @@ -627,7 +627,7 @@ class WT_Controller_Search extends WT_Controller_Page { foreach ($this->sgeds as $ged_id=>$gedcom) { $datalist = array(); foreach ($this->myfamlist as $family) { - if ($family->getGedId()==$ged_id) { + if ($family->getGedcomId()==$ged_id) { $datalist[]=$family; } } @@ -651,7 +651,7 @@ class WT_Controller_Search extends WT_Controller_Page { foreach ($this->sgeds as $ged_id=>$gedcom) { $datalist = array(); foreach ($this->mysourcelist as $source) { - if ($source->getGedId()==$ged_id) { + if ($source->getGedcomId()==$ged_id) { $datalist[]=$source; } } @@ -675,7 +675,7 @@ class WT_Controller_Search extends WT_Controller_Page { foreach ($this->sgeds as $ged_id=>$gedcom) { $datalist = array(); foreach ($this->mynotelist as $note) { - if ($note->getGedId()==$ged_id) { + if ($note->getGedcomId()==$ged_id) { $datalist[]=$note; } } diff --git a/library/WT/Controller/Source.php b/library/WT/Controller/Source.php index f2825493d4..dff23a7558 100644 --- a/library/WT/Controller/Source.php +++ b/library/WT/Controller/Source.php @@ -2,7 +2,7 @@ // Controller for the source page // // webtrees: Web based Family History software -// Copyright (C) 2012 webtrees development team. +// Copyright (C) 2013 webtrees development team. // // Derived from PhpGedView // Copyright (C) 2002 to 2010 PGV Development Team. All rights reserved. @@ -33,35 +33,8 @@ require_once WT_ROOT.'includes/functions/functions_import.php'; class WT_Controller_Source extends WT_Controller_GedcomRecord { public function __construct() { - $xref=safe_GET_xref('sid'); - - $gedrec=find_source_record($xref, WT_GED_ID); - if (WT_USER_CAN_EDIT) { - $newrec=find_updated_record($xref, WT_GED_ID); - } else { - $newrec=null; - } - - if ($gedrec===null) { - if ($newrec===null) { - // Nothing to see here. - parent::__construct(); - return; - } else { - // Create a dummy record from the first line of the new record. - // We need it for diffMerge(), getXref(), etc. - list($gedrec)=explode("\n", $newrec); - } - } - - $this->record = new WT_Source($gedrec); - - // If there are pending changes, merge them in. - if ($newrec!==null) { - $diff_record=new WT_Source($newrec); - $diff_record->setChanged(true); - $this->record->diffMerge($diff_record); - } + $xref = safe_GET_xref('sid'); + $this->record = WT_Source::getInstance($xref); parent::__construct(); } @@ -72,7 +45,7 @@ class WT_Controller_Source extends WT_Controller_GedcomRecord { function getEditMenu() { $SHOW_GEDCOM_RECORD=get_gedcom_setting(WT_GED_ID, 'SHOW_GEDCOM_RECORD'); - if (!$this->record || $this->record->isMarkedDeleted()) { + if (!$this->record || $this->record->isOld()) { return null; } @@ -85,21 +58,6 @@ class WT_Controller_Source extends WT_Controller_GedcomRecord { $menu->addSubmenu($submenu); } - // edit/view raw gedcom - if (WT_USER_IS_ADMIN || $SHOW_GEDCOM_RECORD) { - $submenu = new WT_Menu(WT_I18N::translate('Edit raw GEDCOM record'), '#', 'menu-sour-editraw'); - $submenu->addOnclick("return edit_raw('".$this->record->getXref()."');"); - $menu->addSubmenu($submenu); - } elseif ($SHOW_GEDCOM_RECORD) { - $submenu = new WT_Menu(WT_I18N::translate('View GEDCOM Record'), '#', 'menu-sour-viewraw'); - if (WT_USER_CAN_EDIT) { - $submenu->addOnclick("return show_gedcom_record('new');"); - } else { - $submenu->addOnclick("return show_gedcom_record();"); - } - $menu->addSubmenu($submenu); - } - // delete if (WT_USER_CAN_EDIT) { $submenu = new WT_Menu(WT_I18N::translate('Delete'), '#', 'menu-sour-del'); diff --git a/library/WT/Controller/Timeline.php b/library/WT/Controller/Timeline.php index 85f82ea2f7..349a843561 100644 --- a/library/WT/Controller/Timeline.php +++ b/library/WT/Controller/Timeline.php @@ -71,7 +71,7 @@ class WT_Controller_Timeline extends WT_Controller_Page { foreach ($this->pids as $value) { if ($value!=$remove) { $newpids[] = $value; - $person = WT_Person::getInstance($value); + $person = WT_Individual::getInstance($value); if ($person) { $this->people[] = $person; } @@ -81,7 +81,7 @@ class WT_Controller_Timeline extends WT_Controller_Page { $this->pidlinks = ""; /* @var $indi Person */ foreach ($this->people as $p=>$indi) { - if (!is_null($indi) && $indi->canDisplayDetails()) { + if (!is_null($indi) && $indi->canShow()) { //-- setup string of valid pids for links $this->pidlinks .= "pids%5B%5D=".$indi->getXref()."&"; $bdate = $indi->getBirthDate(); @@ -95,8 +95,14 @@ class WT_Controller_Timeline extends WT_Controller_Page { } } // find all the fact information - $indi->add_family_facts(false); - foreach ($indi->getIndiFacts() as $event) { + $facts = $indi->getFacts(); + foreach ($indi->getSpouseFamilies() as $family) { + foreach ($family->getFacts() as $fact) { + $fact->spouse = $family->getSpouse($indi); + $facts[] = $fact; + } + } + foreach ($facts as $event) { //-- get the fact type $fact = $event->getTag(); if (!in_array($fact, $this->nonfacts)) { @@ -137,8 +143,8 @@ class WT_Controller_Timeline extends WT_Controller_Page { $printed = false; for ($i=0; $i<count($this->people); $i++) { if (!is_null($this->people[$i])) { - if (!$this->people[$i]->canDisplayDetails()) { - if ($this->people[$i]->canDisplayName()) { + if (!$this->people[$i]->canShow()) { + if ($this->people[$i]->canShowName()) { echo " <a href=\"".$this->people[$i]->getHtmlUrl()."\">".$this->people[$i]->getFullName()."</a>"; print_privacy_error(); echo "<br>"; @@ -153,15 +159,15 @@ class WT_Controller_Timeline extends WT_Controller_Page { } } - function print_time_fact(WT_Event $event) { + function print_time_fact(WT_Fact $event) { global $basexoffset, $baseyoffset, $factcount, $TEXT_DIRECTION, $WT_IMAGES, $SHOW_PEDIGREE_PLACES, $placements; /* @var $event Event */ - $factrec = $event->getGedComRecord(); + $factrec = $event->getGedcom(); $fact = $event->getTag(); - $desc = $event->getDetail(); + $desc = $event->getValue(); if ($fact=="EVEN" || $fact=="FACT") { - $fact = $event->getType(); + $fact = $event->getAttribute('TYPE'); } //-- check if this is a family fact $gdate=$event->getDate(); @@ -201,11 +207,11 @@ class WT_Controller_Timeline extends WT_Controller_Page { echo ": 3px;\">"; $col = $event->temp % 6; echo "</td><td valign=\"top\" class=\"person".$col."\">"; - if (count($this->pids) > 6) echo $event->getParentObject()->getFullName()." - "; - $record=$event->getParentObject(); + if (count($this->pids) > 6) echo $event->getParent()->getFullName()." - "; + $record=$event->getParent(); echo $event->getLabel(); echo " -- "; - if ($record instanceof WT_Person) { + if ($record instanceof WT_Individual) { echo format_fact_date($event, $record, false, false); } elseif ($record instanceof WT_Family) { echo $gdate->Display(false); @@ -242,7 +248,11 @@ class WT_Controller_Timeline extends WT_Controller_Page { } } //-- print spouse name for marriage events - $spouse = $event->getSpouse(); + if (isset($event->spouse)) { + $spouse = $event->spouse; + } else { + $spouse = null; + } if ($spouse) { for ($p=0; $p<count($this->pids); $p++) { if ($this->pids[$p]==$spouse->getXref()) break; @@ -252,7 +262,7 @@ class WT_Controller_Timeline extends WT_Controller_Page { if ($spouse->getXref()!=$this->pids[$p]) { echo ' <a href="', $spouse->getHtmlUrl(), '">', $spouse->getFullName(), '</a>'; } else { - echo ' <a href="', $event->getParentObject()->getHtmlUrl(), '">', $event->getParentObject()->getFullName(), '</a>'; + echo ' <a href="', $event->getParent()->getHtmlUrl(), '">', $event->getParent()->getFullName(), '</a>'; } } echo "</td></tr></table>"; @@ -284,7 +294,7 @@ class WT_Controller_Timeline extends WT_Controller_Page { public function getSignificantIndividual() { if ($this->pids) { - return WT_Person::getInstance($this->pids[0]); + return WT_Individual::getInstance($this->pids[0]); } else { return parent::getSignificantIndividual(); } diff --git a/library/WT/Event.php b/library/WT/Fact.php index da786f8d86..8655c76fef 100644 --- a/library/WT/Event.php +++ b/library/WT/Fact.php @@ -2,7 +2,7 @@ // Class that defines an event details object // // webtrees: Web based Family History software -// Copyright (C) 2012 webtrees development team. +// Copyright (C) 2013 webtrees development team. // // Derived from PhpGedView // Copyright (C) 2008 PGV Development Team. All rights reserved. @@ -28,109 +28,83 @@ if (!defined('WT_WEBTREES')) { exit; } -class WT_Event { -// These objects need further refinement in their implementations and parsing -// var $address = null; -// var $notes = array(); //[0..*]: string -// var $sourceCitations = array(); //[0..*]: SourceCitation -// var $multimediaLinks = array(); //[0..*]: MultimediaLink +class WT_Fact { + private $fact_id = null; // Unique identifier for this fact + private $parent = null; // The GEDCOM record from which this fact is taken. + private $gedcom = null; // The raw GEDCOM data for this fact + private $tag = null; // The GEDCOM tag for this record - var $lineNumber = null; - var $canShow = null; - var $state = ""; - var $type = NULL; - var $tag = NULL; - var $date = NULL; - var $place = null; - var $gedcomRecord = null; - var $resn = null; - var $dest = false; - var $label = null; - var $parentObject = null; - var $detail = NULL; - var $values = NULL; - var $sortOrder = 0; - var $sortDate = NULL; - //-- temporary state variable that can be used by other scripts - var $temp = NULL; + private $is_old = false; // Is this a pending record? + private $is_new = false; // Is this a pending record? - // Is this an old/new pending record? - private $is_old = false; - private $is_new = false; + private $date = null; // The WT_Date object for the "2 DATE ..." attribute + private $place = null; // The WT_Place object for the "2 PLAC ..." attribute - // For family facts on individual pages - who is the significant spouse. - private $spouse; + // Temporary(!) variables that are used by other scripts + public $temp = null; // Timeline controller + public $sortOrder = 0; // sort_facts() - /** - * Get the value for the first given GEDCOM tag - * - * @param string $code - * @return string - */ - function getValue($code) { - if (is_null($this->values)) { - $this->values=array(); - preg_match_all('/\n2 ('.WT_REGEX_TAG.') (.+)/', $this->gedcomRecord, $matches, PREG_SET_ORDER); - foreach ($matches as $match) { - // If this is a link, remove the "@" - if (preg_match('/^@'.WT_REGEX_XREF.'@$/', $match[2])) { - $this->values[$match[1]]=trim($match[2], "@"); - } else { - $this->values[$match[1]]=$match[2]; - } - } - } - if (array_key_exists($code, $this->values)) { - return $this->values[$code]; + // Create an event objects from a gedcom fragment. + // We need the parent object (to check privacy) and a (pseudo) fact ID to + // identify the fact within the record. + function __construct($gedcom, WT_GedcomRecord $parent, $fact_id) { + if (preg_match('/^1 ('.WT_REGEX_TAG.')/', $gedcom, $match)) { + $this->gedcom = $gedcom; + $this->parent = $parent; + $this->fact_id = $fact_id; + $this->tag = $match[1]; + } else { + // TODO need to rewrite code that passes dummy data to this function + //throw new Exception('Invalid GEDCOM data passed to WT_Fact::_construct('.$gedcom.')'); } - return null; } - // Create an event objects from a gedcom fragment. - // We also need to know the parent (to check privacy, etc.) and - // the line number (from the original, privacy-filtered) gedcom - // record, to allow editing - function __construct($subrecord, $parent, $lineNumber) { - if (preg_match('/^1 ('.WT_REGEX_TAG.') ?(.*)((\n2 CONT.*)*)/', $subrecord, $match)) { - $this->tag =$match[1]; - $this->detail=$match[2]; - // Some detail records contain multiple lines - if ($match[3]) { - $this->detail.=str_replace(array("\n2 CONT ", "\n2 CONT"), "\n", $match[3]); - } + // Get the value of level 1 data in the fact + // Allow for multi-line values + function getValue() { + if (preg_match('/^1 (?:' . $this->tag . ') ?(.*(?:(?:\n2 CONT .*)*))/', $this->gedcom, $match)) { + return str_replace("\n2 CONT ", "\n", $match[1]); } else { - // We are not ready for this yet. - // throw new Exception('Invalid GEDCOM data passed to WT_Event::_construct('.$subrecord.')'); + return null; } - $this->gedcomRecord=$subrecord; - $this->parentObject=$parent; - $this->lineNumber =$lineNumber; } - function setState($s) { - $this->state = $s; + // Get the record to which this fact links + function getTarget() { + $xref = trim($this->getValue(), '@'); + switch ($this->tag) { + case 'FAMC': + case 'FAMS': + return WT_Family::getInstance($xref); + case 'HUSB': + case 'WIFE': + case 'CHIL': + return WT_Individual::getInstance($xref); + case 'SOUR': + return WT_Source::getInstance($xref); + case 'OBJE': + return WT_Media::getInstance($xref); + case 'REPO': + return WT_Repository::getInstance($xref); + case 'NOTE': + return WT_Note::getInstance($xref); + default: + return WT_GedcomRecord::getInstance($xref); + } } - function getState() { - return $this->state; + // Get the value of level 2 data in the fact + function getAttribute($tag) { + if (preg_match('/\n2 (?:' . $tag . ') ?(.*(?:(?:\n3 CONT .*)*)*)/', $this->gedcom, $match)) { + return str_replace("\n2 CONT ", "\n", $match[1]); + } else { + return null; + } } - /** - * Check whether or not this event can be shown - * - * @return boolean - */ + // Do the privacy rules allow us to display this fact to the current user function canShow() { - if (is_null($this->canShow)) { - if (empty($this->gedcomRecord)) { - $this->canShow = false; - } elseif (!is_null($this->parentObject)) { - $this->canShow = canDisplayFact($this->parentObject->getXref(), $this->parentObject->getGedId(), $this->gedcomRecord); - } else { - $this->canShow = true; - } - } - return $this->canShow; + return canDisplayFact($this->parent->getXref(), $this->parent->getGedcomId(), $this->gedcom); } // Check whether this fact is protected against edit @@ -138,92 +112,52 @@ class WT_Event { // Managers can edit anything // Members cannot edit RESN, CHAN and locked records return - $this->parentObject && $this->parentObject->canEdit() && ( + $this->parent->canEdit() && !$this->isOld() && ( WT_USER_GEDCOM_ADMIN || - WT_USER_CAN_EDIT && strpos($this->gedcomRecord, "\n2 RESN locked")===false && $this->getTag()!='RESN' && $this->getTag()!='CHAN' + WT_USER_CAN_EDIT && strpos($this->gedcom, "\n2 RESN locked")===false && $this->getTag()!='RESN' && $this->getTag()!='CHAN' ); } - /** - * The 4 character event type specified by GEDCom. - * - * @return string - */ - function getType() { - if (is_null($this->type)) - $this->type=$this->getValue('TYPE'); - return $this->type; - } - - /** - * The place where the event occured. - * - * @return string - */ + // The place where the event occured. function getPlace() { - if (is_null($this->place)) { - $this->place=$this->getValue('PLAC'); + if ($this->place === null) { + $this->place = $this->getAttribute('PLAC'); } return $this->place; } - // For family facts on individual pages, we need to know the spouse - public function setSpouse(WT_Person $spouse=null) { - $this->spouse=$spouse; - } - public function getSpouse() { - return $this->spouse; - } - // We can call this function many times, especially when sorting, // so keep a copy of the date. function getDate() { - if ($this->date===null) { - $this->date=new WT_Date($this->getValue('DATE')); + if ($this->date === null) { + $this->date = new WT_Date($this->getAttribute('DATE')); } - return $this->date; } - /** - * The remaining unparsed GEDCom record - * - * @return string - */ - function getGedcomRecord() { - return $this->gedcomRecord; + // The raw GEDCOM data for this fact + function getGedcom() { + return $this->gedcom; } - /** - * The line number, or line of occurrence in the GEDCom record. - * - * @return unknown - */ - function getLineNumber() { - return $this->lineNumber; + // Unique identifier for the fact + function getFactId() { + return $this->fact_id; } - /** - * - */ + // What sort of fact is this? function getTag() { return $this->tag; } - /** - * The Person/Family record where this WT_Event came from - * - * @return GedcomRecord - */ - function getParentObject() { - return $this->parentObject; + // Used to convert a real fact (e.g. BIRT) into a close-relative’s fact (e.g. _BIRT_CHIL) + function setTag($tag) { + $this->tag = $tag; } - /** - * - */ - function getDetail() { - return $this->detail; + // The Person/Family record where this WT_Fact came from + function getParent() { + return $this->parent; } function getLabel($abbreviate=false) { @@ -239,42 +173,39 @@ class WT_Event { } // no break - drop into next case default: - return WT_Gedcom_Tag::getLabel($this->tag, $this->parentObject); + return WT_Gedcom_Tag::getLabel($this->tag, $this->parent); } } } + // Is this a pending edit? public function setIsOld() { - $this->is_old=true; - $this->is_new=false; + $this->is_old = true; + $this->is_new = false; } - public function getIsOld() { + public function isOld() { return $this->is_old; } public function setIsNew() { - $this->is_new=true; - $this->is_old=false; + $this->is_new = true; + $this->is_old = false; } - public function getIsNew() { + public function isNew() { return $this->is_new; } - /** - * Print a simple fact version of this event - * - * @param boolean $return whether to print or return - * @param boolean $anchor whether to add anchor to date and place - */ + // Print a simple fact version of this event function print_simple_fact($return=false, $anchor=false) { - global $SHOW_PEDIGREE_PLACES, $ABBREVIATE_CHART_LABELS; + global $ABBREVIATE_CHART_LABELS; + + $value = $this->getValue(); - if (!$this->canShow()) return ""; $data = '<span class="details_label">'.$this->getLabel($ABBREVIATE_CHART_LABELS).'</span>'; // Don't display "yes", because format_fact_date() does this for us. (Should it?) - if ($this->detail && $this->detail!='Y') { - $data .= ' <span dir="auto">'.htmlspecialchars($this->detail).'</span>'; + if ($value && $value != 'Y') { + $data .= ' <span dir="auto">' . htmlspecialchars($value) . '</span>'; } - $data .= ' '.format_fact_date($this, $this->getParentObject(), $anchor, false); + $data .= ' '.format_fact_date($this, $this->getParent(), $anchor, false); $data .= ' '.format_fact_place($this, $anchor, false, false); $data .= '<br>'; if ($return) { @@ -300,13 +231,7 @@ class WT_Event { } } - /** - * Static Helper functions to sort events - * - * @param WT_Event $a - * @param WT_Event $b - * @return int - */ + // Static Helper functions to sort events static function CompareDate($a, $b) { if ($a->getDate()->isOK() && $b->getDate()->isOK()) { // If both events have dates, compare by date @@ -326,13 +251,7 @@ class WT_Event { } } - /** - * Static method to Compare two events by their type - * - * @param WT_Event $a - * @param WT_Event $b - * @return int - */ + // Static method to Compare two events by their type static function CompareType($a, $b) { global $factsort; @@ -398,7 +317,7 @@ class WT_Event { // Facts from same families stay grouped together // Keep MARR and DIV from the same families from mixing with events from other FAMs // Use the original order in which the facts were added - if ($a->parentObject instanceof WT_Family && $b->parentObject instanceof WT_Family && !$a->parentObject->equals($b->parentObject)) { + if ($a->parent instanceof WT_Family && $b->parent instanceof WT_Family && !$a->parent->equals($b->parent)) { return $a->sortOrder - $b->sortOrder; } @@ -423,13 +342,13 @@ class WT_Event { //-- don't let dated after DEAT/BURI facts sort non-dated facts before DEAT/BURI //-- treat dated after BURI facts as BURI instead - if ($a->getValue('DATE')!=NULL && $factsort[$atag]>$factsort['BURI'] && $factsort[$atag]<$factsort['CHAN']) $atag='BURI'; - if ($b->getValue('DATE')!=NULL && $factsort[$btag]>$factsort['BURI'] && $factsort[$btag]<$factsort['CHAN']) $btag='BURI'; + if ($a->getAttribute('DATE')!=NULL && $factsort[$atag]>$factsort['BURI'] && $factsort[$atag]<$factsort['CHAN']) $atag='BURI'; + if ($b->getAttribute('DATE')!=NULL && $factsort[$btag]>$factsort['BURI'] && $factsort[$btag]<$factsort['CHAN']) $btag='BURI'; $ret = $factsort[$atag]-$factsort[$btag]; //-- if facts are the same then put dated facts before non-dated facts if ($ret==0) { - if ($a->getValue('DATE')!=NULL && $b->getValue('DATE')==NULL) return -1; - if ($b->getValue('DATE')!=NULL && $a->getValue('DATE')==NULL) return 1; + if ($a->getAttribute('DATE')!=NULL && $b->getAttribute('DATE')==NULL) return -1; + if ($b->getAttribute('DATE')!=NULL && $a->getAttribute('DATE')==NULL) return 1; //-- if no sorting preference, then keep original ordering $ret = $a->sortOrder - $b->sortOrder; } diff --git a/library/WT/Family.php b/library/WT/Family.php index cc7876451c..16193de7fa 100644 --- a/library/WT/Family.php +++ b/library/WT/Family.php @@ -30,6 +30,7 @@ if (!defined('WT_WEBTREES')) { class WT_Family extends WT_GedcomRecord { const RECORD_TYPE = 'FAM'; + const SQL_FETCH = "SELECT f_gedcom FROM `##families` WHERE f_id=? AND f_file=?"; const URL_PREFIX = 'family.php?famid='; private $husb = null; @@ -37,23 +38,15 @@ class WT_Family extends WT_GedcomRecord { private $marriage = null; // Create a Family object from either raw GEDCOM data or a database row - function __construct($data) { - if (is_array($data)) { - // Construct from a row from the database - if (preg_match('/^1 HUSB @(.+)@/m', $data['gedrec'], $match)) { - $this->husb=WT_Person::getInstance($match[1]); - } - if (preg_match('/^1 WIFE @(.+)@/m', $data['gedrec'], $match)) { - $this->wife=WT_Person::getInstance($match[1]); - } - } else { - // Construct from raw GEDCOM data - if (preg_match('/^1 HUSB @(.+)@/m', $data, $match)) { - $this->husb=WT_Person::getInstance($match[1]); - } - if (preg_match('/^1 WIFE @(.+)@/m', $data, $match)) { - $this->wife=WT_Person::getInstance($match[1]); - } + function __construct($xref, $gedcom, $pending, $gedcom_id) { + parent::__construct($xref, $gedcom, $pending, $gedcom_id); + + // TODO: fetch these from WT_Fact objects + if (preg_match('/^1 HUSB @(.+)@/m', $gedcom.$pending, $match)) { + $this->husb = WT_Individual::getInstance($match[1]); + } + if (preg_match('/^1 WIFE @(.+)@/m', $gedcom.$pending, $match)) { + $this->wife = WT_Individual::getInstance($match[1]); } // Make sure husb/wife are the right way round. @@ -61,7 +54,6 @@ class WT_Family extends WT_GedcomRecord { list($this->husb, $this->wife)=array($this->wife, $this->husb); } - parent::__construct($data); } // Generate a private version of this record @@ -70,10 +62,10 @@ class WT_Family extends WT_GedcomRecord { $rec='0 @'.$this->xref.'@ FAM'; // Just show the 1 CHIL/HUSB/WIFE tag, not any subtags, which may contain private data - preg_match_all('/\n1 (?:CHIL|HUSB|WIFE) @('.WT_REGEX_XREF.')@/', $this->_gedrec, $matches, PREG_SET_ORDER); + preg_match_all('/\n1 (?:CHIL|HUSB|WIFE) @('.WT_REGEX_XREF.')@/', $this->gedcom, $matches, PREG_SET_ORDER); foreach ($matches as $match) { - $rela=WT_Person::getInstance($match[1]); - if ($rela && ($SHOW_PRIVATE_RELATIONSHIPS || $rela->canDisplayDetails($access_level))) { + $rela=WT_Individual::getInstance($match[1]); + if ($rela && ($SHOW_PRIVATE_RELATIONSHIPS || $rela->canShow($access_level))) { $rec.=$match[0]; } } @@ -81,16 +73,14 @@ class WT_Family extends WT_GedcomRecord { } // Fetch the record from the database - protected static function fetchGedcomRecord($xref, $ged_id) { + protected static function fetchGedcomRecord($xref, $gedcom_id) { static $statement=null; if ($statement===null) { - $statement=WT_DB::prepare( - "SELECT 'FAM' AS type, f_id AS xref, f_file AS ged_id, f_gedcom AS gedrec ". - "FROM `##families` WHERE f_id=? AND f_file=?" - ); + $statement=WT_DB::prepare("SELECT f_gedcom FROM `##families` WHERE f_id=? AND f_file=?"); } - return $statement->execute(array($xref, $ged_id))->fetchOneRow(PDO::FETCH_ASSOC); + + return $statement->execute(array($xref, $gedcom_id))->fetchOne(); } /** @@ -109,12 +99,12 @@ class WT_Family extends WT_GedcomRecord { } // Implement family-specific privacy logic - protected function _canDisplayDetailsByType($access_level) { + protected function _canShowByType($access_level) { // Hide a family if any member is private - preg_match_all('/\n1 (?:CHIL|HUSB|WIFE) @('.WT_REGEX_XREF.')@/', $this->_gedrec, $matches); + preg_match_all('/\n1 (?:CHIL|HUSB|WIFE) @('.WT_REGEX_XREF.')@/', $this->gedcom, $matches); foreach ($matches[1] as $match) { - $person=WT_Person::getInstance($match); - if ($person && !$person->canDisplayDetails($access_level)) { + $person=WT_Individual::getInstance($match); + if ($person && !$person->canShow($access_level)) { return false; } } @@ -122,7 +112,7 @@ class WT_Family extends WT_GedcomRecord { } // Can the name of this record be shown? - public function canDisplayName($access_level=WT_USER_ACCESS_LEVEL) { + public function canShowName($access_level=WT_USER_ACCESS_LEVEL) { // We can always see the name (Husband-name + Wife-name), however, // the name will often be "private + private" return true; @@ -137,10 +127,10 @@ class WT_Family extends WT_GedcomRecord { if (is_null($this->wife) || is_null($this->husb)) { return null; } - if ($this->wife->equals($person) && $this->husb->canDisplayDetails($access_level)) { + if ($this->wife->equals($person) && $this->husb->canShow($access_level)) { return $this->husb; } - if ($this->husb->equals($person) && $this->wife->canDisplayDetails($access_level)) { + if ($this->husb->equals($person) && $this->wife->canShow($access_level)) { return $this->wife; } return null; @@ -148,10 +138,10 @@ class WT_Family extends WT_GedcomRecord { function getSpouses($access_level=WT_USER_ACCESS_LEVEL) { $spouses=array(); - if ($this->husb && $this->husb->canDisplayDetails($access_level)) { + if ($this->husb && $this->husb->canShow($access_level)) { $spouses[]=$this->husb; } - if ($this->wife && $this->wife->canDisplayDetails($access_level)) { + if ($this->wife && $this->wife->canShow($access_level)) { $spouses[]=$this->wife; } return $spouses; @@ -165,10 +155,10 @@ class WT_Family extends WT_GedcomRecord { global $SHOW_PRIVATE_RELATIONSHIPS; $children=array(); - preg_match_all('/\n1 CHIL @('.WT_REGEX_XREF.')@/', $this->_gedrec, $match); + preg_match_all('/\n1 CHIL @('.WT_REGEX_XREF.')@/', $this->gedcom, $match); foreach ($match[1] as $pid) { - $child=WT_Person::getInstance($pid); - if ($child && ($SHOW_PRIVATE_RELATIONSHIPS || $child->canDisplayDetails($access_level))) { + $child=WT_Individual::getInstance($pid); + if ($child && ($SHOW_PRIVATE_RELATIONSHIPS || $child->canShow($access_level))) { $children[]=$child; } } @@ -186,69 +176,23 @@ class WT_Family extends WT_GedcomRecord { */ function getNumberOfChildren() { - $nchi1=(int)get_gedcom_value('NCHI', 1, $this->getGedcomRecord()); - $nchi2=(int)get_gedcom_value('NCHI', 2, $this->getGedcomRecord()); + $nchi1=(int)get_gedcom_value('NCHI', 1, $this->getGedcom()); + $nchi2=(int)get_gedcom_value('NCHI', 2, $this->getGedcom()); $nchi3=count($this->getChildren()); return max($nchi1, $nchi2, $nchi3); } /** - * get updated Family - * If there is an updated family record in the gedcom file - * return a new family object for it - */ - function getUpdatedFamily() { - if ($this->getChanged()) { - return $this; - } - if (WT_USER_CAN_EDIT && $this->canDisplayDetails()) { - $newrec = find_updated_record($this->xref, $this->ged_id); - if (!is_null($newrec)) { - $newfamily = new WT_Family($newrec); - $newfamily->setChanged(true); - return $newfamily; - } - } - return null; - } - /** - * check if this family has the given person - * as a parent in the family - * @param Person $person - */ - function hasParent($person) { - if (is_null($person)) return false; - if ($person->equals($this->husb)) return true; - if ($person->equals($this->wife)) return true; - return false; - } - /** - * check if this family has the given person - * as a child in the family - * @param Person $person - */ - function hasChild($person) { - if ($person) { - foreach ($this->getChildren() as $child) { - if ($person->equals($child)) { - return true; - } - } - } - return false; - } - - /** * parse marriage record */ function _parseMarriageRecord() { - $this->marriage = new WT_Event(get_sub_record(1, '1 MARR', $this->getGedcomRecord()), $this, 0); + $this->marriage = new WT_Fact(get_sub_record(1, '1 MARR', $this->getGedcom()), $this, 0); } /** * get the marriage event * - * @return WT_Event + * @return WT_Fact */ function getMarriage() { if (is_null($this->marriage)) $this->_parseMarriageRecord(); @@ -261,17 +205,17 @@ class WT_Family extends WT_GedcomRecord { */ function getMarriageRecord() { if (is_null($this->marriage)) $this->_parseMarriageRecord(); - return $this->marriage->getGedcomRecord(); + return $this->marriage->getGedcom(); } // Return whether or not this family ended in a divorce or was never married. // Note that this is calculated using unprivatized data, so we can // always distinguish spouses from ex-spouses. function isDivorced() { - return (bool)preg_match('/\n1 ('.WT_EVENTS_DIV.')( Y|\n)/', $this->_gedrec); + return (bool)preg_match('/\n1 ('.WT_EVENTS_DIV.')( Y|\n)/', $this->gedcom); } function isNotMarried() { - return (bool)preg_match('/\n1 _NMR( Y|\n)/', $this->_gedrec); + return (bool)preg_match('/\n1 _NMR( Y|\n)/', $this->gedcom); } /** @@ -279,7 +223,7 @@ class WT_Family extends WT_GedcomRecord { * @return string */ function getMarriageDate() { - if (!$this->canDisplayDetails()) { + if (!$this->canShow()) { return new WT_Date(''); } if (is_null($this->marriage)) { @@ -299,7 +243,7 @@ class WT_Family extends WT_GedcomRecord { */ function getMarriageType() { if (is_null($this->marriage)) $this->_parseMarriageRecord(); - return $this->marriage->getType(); + return $this->marriage->getAttribute('TYPE'); } /** @@ -313,7 +257,7 @@ class WT_Family extends WT_GedcomRecord { // Get all the dates/places for marriages - for the FAM lists function getAllMarriageDates() { - if ($this->canDisplayDetails()) { + if ($this->canShow()) { foreach (explode('|', WT_EVENTS_MARR) as $event) { if ($array=$this->getAllEventDates($event)) { return $array; @@ -323,7 +267,7 @@ class WT_Family extends WT_GedcomRecord { return array(); } function getAllMarriagePlaces() { - if ($this->canDisplayDetails()) { + if ($this->canShow()) { foreach (explode('|', WT_EVENTS_MARR) as $event) { if ($array=$this->getAllEventPlaces($event)) { return $array; @@ -336,8 +280,8 @@ class WT_Family extends WT_GedcomRecord { // Get an array of structures containing all the names in the record public function getAllNames() { if (is_null($this->_getAllNames)) { - $husb=$this->husb ? $this->husb : new WT_Person('1 SEX M'); - $wife=$this->wife ? $this->wife : new WT_Person('1 SEX F'); + $husb=$this->husb ? $this->husb : new WT_Individual('M', '1 SEX M', null, $this->gedcom_id); + $wife=$this->wife ? $this->wife : new WT_Individual('F', '1 SEX F', null, $this->gedcom_id); // Check the script used by each name, so we can match cyrillic with cyrillic, greek with greek, etc. $husb_names=$husb->getAllNames(); foreach ($husb_names as $n=>$husb_name) { diff --git a/library/WT/Gedcom/Code/Adop.php b/library/WT/Gedcom/Code/Adop.php index 5a1d9edd79..4b10b4dbcb 100644 --- a/library/WT/Gedcom/Code/Adop.php +++ b/library/WT/Gedcom/Code/Adop.php @@ -2,7 +2,7 @@ // Functions and logic for GEDCOM "PEDI" codes // // webtrees: Web based Family History software -// Copyright (C) 2011 webtrees development team. +// Copyright (C) 2013 webtrees development team. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -31,7 +31,7 @@ class WT_Gedcom_Code_Adop { // Translate a code, for an (optional) record public static function getValue($type, $record=null) { - if ($record instanceof WT_Person) { + if ($record instanceof WT_Individual) { $sex=$record->getSex(); } else { $sex='U'; diff --git a/library/WT/Gedcom/Code/Name.php b/library/WT/Gedcom/Code/Name.php index a5ad95f06f..20470b12ed 100644 --- a/library/WT/Gedcom/Code/Name.php +++ b/library/WT/Gedcom/Code/Name.php @@ -2,7 +2,7 @@ // Functions and logic for GEDCOM "NAME" codes // // webtrees: Web based Family History software -// Copyright (C) 2011 webtrees development team. +// Copyright (C) 2013 webtrees development team. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -31,7 +31,7 @@ class WT_Gedcom_Code_Name { // Translate a code, for an (optional) record public static function getValue($type, $record=null) { - if ($record instanceof WT_Person) { + if ($record instanceof WT_Individual) { $sex=$record->getSex(); } else { $sex='U'; diff --git a/library/WT/Gedcom/Code/Pedi.php b/library/WT/Gedcom/Code/Pedi.php index 9b8a835ce1..783c59b4f1 100644 --- a/library/WT/Gedcom/Code/Pedi.php +++ b/library/WT/Gedcom/Code/Pedi.php @@ -2,7 +2,7 @@ // Functions and logic for GEDCOM "PEDI" codes // // webtrees: Web based Family History software -// Copyright (C) 2012 webtrees development team. +// Copyright (C) 2013 webtrees development team. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -31,7 +31,7 @@ class WT_Gedcom_Code_Pedi { // Translate a code, for an optional record public static function getValue($type, $record=null) { - if ($record instanceof WT_Person) { + if ($record instanceof WT_Individual) { $sex=$record->getSex(); } else { $sex='U'; diff --git a/library/WT/Gedcom/Code/Rela.php b/library/WT/Gedcom/Code/Rela.php index d4faa8f49c..0f53c835b8 100644 --- a/library/WT/Gedcom/Code/Rela.php +++ b/library/WT/Gedcom/Code/Rela.php @@ -2,7 +2,7 @@ // Functions and logic for GEDCOM "RELA" codes // // webtrees: Web based Family History software -// Copyright (C) 2011 webtrees development team. +// Copyright (C) 2013 webtrees development team. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -39,7 +39,7 @@ class WT_Gedcom_Code_Rela { // Translate a code, for an (optional) record public static function getValue($type, $record=null) { - if ($record instanceof WT_Person) { + if ($record instanceof WT_Individual) { $sex=$record->getSex(); } else { $sex='U'; diff --git a/library/WT/Gedcom/Tag.php b/library/WT/Gedcom/Tag.php index 83a62af317..d79b92b753 100644 --- a/library/WT/Gedcom/Tag.php +++ b/library/WT/Gedcom/Tag.php @@ -2,7 +2,7 @@ // Static GEDCOM data for Tags // // webtrees: Web based Family History software -// Copyright (C) 2012 webtrees development team. +// Copyright (C) 2013 webtrees development team. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -102,7 +102,7 @@ class WT_Gedcom_Tag { // Translate a tag, for an (optional) record public static function getLabel($tag, $record=null) { - if ($record instanceof WT_Person) { + if ($record instanceof WT_Individual) { $sex=$record->getSex(); } else { $sex='U'; @@ -879,12 +879,6 @@ class WT_Gedcom_Tag { return $facts; } - // Get a list of reference facts that will be displayed in the "Extra information" sidebar module, and at the same time excluded from the personal_facts module - public static function getReferenceFacts() { - return array('CHAN', 'IDNO', 'RFN', 'AFN', 'REFN', 'RIN', '_UID', 'SSN'); - } - - ////////////////////////////////////////////////////////////////////////////// // Definitions for Object, File, Format, Types ////////////////////////////////////////////////////////////////////////////// diff --git a/library/WT/GedcomRecord.php b/library/WT/GedcomRecord.php index 2b67f6caa4..67fbca8730 100644 --- a/library/WT/GedcomRecord.php +++ b/library/WT/GedcomRecord.php @@ -30,305 +30,265 @@ if (!defined('WT_WEBTREES')) { class WT_GedcomRecord { const RECORD_TYPE = 'UNKNOWN'; + const SQL_FETCH = "SELECT o_gedcom FROM `##other` WHERE o_id=? AND o_file=?"; const URL_PREFIX = 'gedrecord.php?pid='; - protected $xref =null; // The record identifier - public $ged_id =null; // The gedcom file, only set if this record comes from the database - protected $_gedrec =null; // Raw gedcom text (unprivatised) - private $gedrec =null; // Raw gedcom text (privatised) - protected $facts =null; - protected $changeEvent=null; - private $disp_public=null; // Can we display details of this record to WT_PRIV_PUBLIC - private $disp_user =null; // Can we display details of this record to WT_PRIV_USER - private $disp_none =null; // Can we display details of this record to WT_PRIV_NONE - private $changed =false; // Is this a new record, pending approval + protected $xref = null; // The record identifier + protected $gedcom_id = null; // The gedcom file + protected $gedcom = null; // GEDCOM data (before any pending edits) + protected $pending = null; // GEDCOM data (after any pending edits) - // Cached results from various functions. - protected $_getAllNames =null; - protected $_getPrimaryName =null; - protected $_getSecondaryName=null; + protected $facts = null; // Array of WT_Fact objects (from $gedcom/$pending) - // Create a GedcomRecord object from either raw GEDCOM data or a database row - public function __construct($data) { - if (is_array($data)) { - // Construct from a row from the database - $this->xref =$data['xref']; - $this->ged_id =$data['ged_id']; - $this->_gedrec=$data['gedrec']; - } else { - // Construct from raw GEDCOM data - $this->_gedrec=$data; - if (preg_match('/^0 (?:@('.WT_REGEX_XREF.')@ )?('.WT_REGEX_TAG.')/', $data, $match)) { - $this->xref=$match[1]; - $this->ged_id=WT_GED_ID; - } - } - } + private $disp_public = null; // Can we display details of this record to WT_PRIV_PUBLIC + private $disp_user = null; // Can we display details of this record to WT_PRIV_USER + private $disp_none = null; // Can we display details of this record to WT_PRIV_NONE - // Get an instance of a GedcomRecord. We either specify - // an XREF (in the current gedcom), or we can provide a row - // from the database (if we anticipate the record hasn't - // been fetched previously). - static public function getInstance($data) { - global $gedcom_record_cache, $GEDCOM; - static $pending_record_cache; + // Cached results from various functions. + protected $_getAllNames = null; + protected $_getPrimaryName = null; + protected $_getSecondaryName = null; + + // Allow getInstance() to return references to existing objects + private static $gedcom_record_cache; + // Fetch all pending edits in one database query + private static $pending_record_cache; - $is_pending=false; // Did this record come from a pending edit + // Create a GedcomRecord object from raw GEDCOM data. + // $gedcom is an empty string for new/pending records + // $pending is null for a record with no pending edits + // $pending is an empty string for records with pending deletions + public function __construct($xref, $gedcom, $pending, $gedcom_id) { + $this->xref = $xref; + $this->gedcom = $gedcom; + $this->pending = $pending; + $this->gedcom_id = $gedcom_id; - if (is_array($data)) { - $ged_id=$data['ged_id']; - $pid =$data['xref']; + // Split the record into facts + if ($gedcom) { + $gedcom_facts = preg_split('/\n(?=1)/s', $gedcom); + array_shift($gedcom_facts); + } else { + $gedcom_facts = array(); + } + if ($pending) { + $pending_facts = preg_split('/\n(?=1)/s', $pending); + array_shift($pending_facts); } else { - $ged_id=get_id_from_gedcom($GEDCOM); - $pid =$data; + $pending_facts = array(); } - // Check the cache first - if (isset($gedcom_record_cache[$pid][$ged_id])) { - return $gedcom_record_cache[$pid][$ged_id]; + $this->facts = array(); + + foreach ($gedcom_facts as $gedcom_fact) { + $fact = new WT_Fact($gedcom_fact, $this, md5($gedcom_fact)); + if ($pending !== null && !in_array($gedcom_fact, $pending_facts)) { + $fact->setIsOld(); + } + $this->facts[] = $fact; + } + foreach ($pending_facts as $pending_fact) { + if (!in_array($pending_fact, $gedcom_facts)) { + $fact = new WT_Fact($pending_fact, $this, md5($pending_fact)); + $fact->setIsNew(); + $this->facts[] = $fact; + } } + } - // Look for the record in the database - if (!is_array($data)) { - $data=static::fetchGedcomRecord($pid, $ged_id); + // Get an instance of a GedcomRecord object. For single records, + // we just receive the XREF. For bulk records (such as lists + // and search results) we can receive the GEDCOM data as well. + static public function getInstance($xref, $gedcom_id=WT_GED_ID, $gedcom=null) { + // Is this record already in the cache? + if (isset(self::$gedcom_record_cache[$xref][$gedcom_id])) { + return self::$gedcom_record_cache[$xref][$gedcom_id]; + } - // If we can edit, then we also need to be able to see pending records. - // Otherwise relationship privacy rules will not allow us to see - // newly added records. - if (WT_USER_CAN_EDIT) { - if (!isset($pending_record_cache[$ged_id])) { - // Fetch all pending records in one database query - $pending_record_cache[$ged_id]=array(); - $rows = WT_DB::prepare( - "SELECT xref, new_gedcom FROM `##change` WHERE status='pending' AND gedcom_id=?" - )->execute(array($ged_id))->fetchAll(); - foreach ($rows as $row) { - $pending_record_cache[$ged_id][$row->xref] = $row->new_gedcom; - } - } + // Do we need to fetch the record from the database? + if ($gedcom === null) { + $gedcom = static::fetchGedcomRecord($xref, $gedcom_id); + } - if (isset($pending_record_cache[$ged_id][$pid])) { - // A pending edit exists for this record - $tmp = $pending_record_cache[$ged_id][$pid]; - // $tmp can be an empty string, indicating the record has - // a pending deletion. Ignore this, as we handle pending - // deletions separately. - if ($tmp) { - $is_pending=true; - $data=$tmp; - } + // If we can edit, then we also need to be able to see pending records. + if (WT_USER_CAN_EDIT) { + if (!isset(self::$pending_record_cache[$gedcom_id])) { + // Fetch all pending records in one database query + self::$pending_record_cache[$gedcom_id]=array(); + $rows = WT_DB::prepare( + "SELECT xref, new_gedcom FROM `##change` WHERE status='pending' AND gedcom_id=?" + )->execute(array($gedcom_id))->fetchAll(); + foreach ($rows as $row) { + self::$pending_record_cache[$gedcom_id][$row->xref] = $row->new_gedcom; } } - // If we still didn't find it, it doesn't exist - if (!$data) { - return null; + if (isset(self::$pending_record_cache[$gedcom_id][$xref])) { + // A pending edit exists for this record + $pending = self::$pending_record_cache[$gedcom_id][$xref]; + } else { + $pending = null; } + } else { + // There are no pending changes for this record + $pending = null; + } + + // No such record exists + if ($gedcom === null && $pending === null) { + return null; } // Create the object - if (is_array($data)) { - $type=$data['type']; - } elseif (preg_match('/^0 @'.WT_REGEX_XREF.'@ ('.WT_REGEX_TAG.')/', $data, $match)) { - $type=$match[1]; + if (preg_match('/^0 @' . WT_REGEX_XREF . '@ (' . WT_REGEX_TAG . ')/', $gedcom.$pending, $match)) { + $type = $match[1]; } else { - $type=''; + throw new Exception('Unrecognised GEDCOM record: ' . $gedcom); } + switch($type) { case 'INDI': - $object=new WT_Person($data); + $record = new WT_Individual($xref, $gedcom, $pending, $gedcom_id); break; case 'FAM': - $object=new WT_Family($data); + $record = new WT_Family($xref, $gedcom, $pending, $gedcom_id); break; case 'SOUR': - $object=new WT_Source($data); + $record = new WT_Source($xref, $gedcom, $pending, $gedcom_id); break; case 'OBJE': - $object=new WT_Media($data); + $record = new WT_Media($xref, $gedcom, $pending, $gedcom_id); break; case 'REPO': - $object=new WT_Repository($data); + $record = new WT_Repository($xref, $gedcom, $pending, $gedcom_id); break; case 'NOTE': - $object=new WT_Note($data); + $record = new WT_Note($xref, $gedcom, $pending, $gedcom_id); break; default: - $object=new WT_GedcomRecord($data); - break; - } - - // This is an object from the database, so indicate which gedcom it comes from. - $object->ged_id=$ged_id; - - if ($is_pending) { - $object->setChanged(true); + throw new Exception('No support for GEDCOM record type: ' . $type); } // Store it in the cache - $gedcom_record_cache[$object->xref][$object->ged_id]=&$object; - return $object; + self::$gedcom_record_cache[$xref][$gedcom_id] = $record; + + return $record; } - private static function fetchGedcomRecord($xref, $ged_id) { + private static function fetchGedcomRecord($xref, $gedcom_id) { static $statement=null; // We don't know what type of object this is. Try each one in turn. - $row=WT_Person::fetchGedcomRecord($xref, $ged_id); - if ($row) { - return $row; + $data = WT_Individual::fetchGedcomRecord($xref, $gedcom_id); + if ($data) { + return $data; } - $row=WT_Family::fetchGedcomRecord($xref, $ged_id); - if ($row) { - return $row; + $data = WT_Family::fetchGedcomRecord($xref, $gedcom_id); + if ($data) { + return $data; } - $row=WT_Source::fetchGedcomRecord($xref, $ged_id); - if ($row) { - return $row; + $data = WT_Source::fetchGedcomRecord($xref, $gedcom_id); + if ($data) { + return $data; } - $row=WT_Repository::fetchGedcomRecord($xref, $ged_id); - if ($row) { - return $row; + $data = WT_Repository::fetchGedcomRecord($xref, $gedcom_id); + if ($data) { + return $data; } - $row=WT_Media::fetchGedcomRecord($xref, $ged_id); - if ($row) { - return $row; + $data = WT_Media::fetchGedcomRecord($xref, $gedcom_id); + if ($data) { + return $data; } - $row=WT_Note::fetchGedcomRecord($xref, $ged_id); - if ($row) { - return $row; + $data = WT_Note::fetchGedcomRecord($xref, $gedcom_id); + if ($data) { + return $data; } // Some other type of record... if (is_null($statement)) { - $statement=WT_DB::prepare( - "SELECT o_type AS type, o_id AS xref, o_file AS ged_id, o_gedcom AS gedrec ". - "FROM `##other` WHERE o_id=? AND o_file=? AND o_type NOT IN ('REPO', 'NOTE')" - ); + $statement=WT_DB::prepare("SELECT o_gedcom FROM `##other` WHERE o_id=? AND o_file=?"); } - return $statement->execute(array($xref, $ged_id))->fetchOneRow(PDO::FETCH_ASSOC); + return $statement->execute(array($xref, $gedcom_id))->fetchOne(); } - /** - * get the xref - * @return string returns the person ID - */ + // XREF public function getXref() { return $this->xref; } - /** - * get the gedcom file - * @return string returns the person ID - */ - public function getGedId() { - return $this->ged_id; + + // GEDCOM ID + public function getGedcomId() { + return $this->gedcom_id; } - /** - * get gedcom record - */ - public function getGedcomRecord() { - if ($this->gedrec===null) { - list($this->gedrec)=$this->privatizeGedcom(WT_USER_ACCESS_LEVEL); + // Application code should access data via WT_Fact objects + public function getGedcom() { + if ($this->pending === null) { + return $this->gedcom; + } else { + return $this->pending; } - return $this->gedrec; - } - /** - * set gedcom record - */ - public function setGedcomRecord($gcRec) { - $this->gedrec = $gcRec; } - /** - * set if this is a changed record from the gedcom file - * @param boolean $changed - */ - public function setChanged($changed) { - $this->changed = $changed; + + // Does this record have a pending change? + public function isNew() { + return $this->pending !== null; } - /** - * get if this is a changed record from the gedcom file - * @return boolean - */ - public function getChanged() { - return $this->changed; + + // Does this record have a pending deletion? + public function isOld() { + return $this->pending === ''; } - /** - * check if this object is equal to the given object - * @param GedcomRecord $obj - */ + // Are two records the same? public function equals($obj) { - return !is_null($obj) && $this->xref==$obj->getXref(); + return $obj && $this->xref==$obj->getXref(); } - // Generate a URL to this record, suitable for use in HTML + // Generate a URL to this record, suitable for use in HTML, etc. public function getHtmlUrl() { - return self::_getLinkUrl(static::URL_PREFIX, '&'); + return $this->_getLinkUrl(static::URL_PREFIX, '&'); } // Generate a URL to this record, suitable for use in javascript, HTTP headers, etc. public function getRawUrl() { - return self::_getLinkUrl(static::URL_PREFIX, '&'); + return $this->_getLinkUrl(static::URL_PREFIX, '&'); } - private function _getLinkUrl($link, $separator) { - if ($this->ged_id) { - // If the record was created from the database, we know the gedcom - return $link.$this->getXref().$separator.'ged='.rawurlencode(get_gedcom_from_id($this->ged_id)); - } else { - // If the record was created from a text string, assume the current gedcom - return $link.$this->getXref().$separator.'ged='.WT_GEDURL; - } - } - - /** - * return an absolute url for linking to this record from another site - * - */ + // Generate an absolute URL for this record, suitable for sitemap.xml, RSS feeds, etc. public function getAbsoluteLinkUrl() { - return WT_SERVER_NAME.WT_SCRIPT_PATH.$this->getHtmlUrl(); + return WT_SERVER_NAME . WT_SCRIPT_PATH . $this->getHtmlUrl(); } - /** - * check if this record has been marked for deletion - * @return boolean - */ - public function isMarkedDeleted() { - $tmp=WT_DB::prepare( - "SELECT new_gedcom". - " FROM `##change`". - " WHERE status='pending' AND gedcom_id=? AND xref=?". - " ORDER BY change_id desc". - " LIMIT 1" - )->execute(array($this->ged_id, $this->xref))->fetchOne(); - - return $tmp===''; + private function _getLinkUrl($link, $separator) { + if ($this->gedcom_id == WT_GED_ID) { + return $link . $this->getXref() . $separator . 'ged=' . WT_GEDURL; + } else { + return $link . $this->getXref() . $separator . 'ged=' . rawurlencode(get_gedcom_from_id($this->gedcom_id)); + } } // Work out whether this record can be shown to a user with a given access level - private function _canDisplayDetails($access_level) { - global $person_privacy, $HIDE_LIVE_PEOPLE, $PRIVACY_CHECKS; + private function _canShow($access_level) { + global $person_privacy, $HIDE_LIVE_PEOPLE; - //-- keep a count of how many times we have checked for privacy - ++$PRIVACY_CHECKS; // This setting would better be called "$ENABLE_PRIVACY" if (!$HIDE_LIVE_PEOPLE) { return true; } // We should always be able to see our own record (unless an admin is applying download restrictions) - if ($this->getXref()==WT_USER_GEDCOM_ID && $this->getGedId()==WT_GED_ID && $access_level==WT_USER_ACCESS_LEVEL) { + if ($this->getXref()==WT_USER_GEDCOM_ID && $this->getGedcomId()==WT_GED_ID && $access_level==WT_USER_ACCESS_LEVEL) { return true; } // Does this record have a RESN? - if (strpos($this->_gedrec, "\n1 RESN confidential")) { + if (strpos($this->gedcom, "\n1 RESN confidential")) { return WT_PRIV_NONE>=$access_level; } - if (strpos($this->_gedrec, "\n1 RESN privacy")) { + if (strpos($this->gedcom, "\n1 RESN privacy")) { return WT_PRIV_USER>=$access_level; } - if (strpos($this->_gedrec, "\n1 RESN none")) { + if (strpos($this->gedcom, "\n1 RESN none")) { return true; } @@ -343,11 +303,11 @@ class WT_GedcomRecord { } // Different types of record have different privacy rules - return $this->_canDisplayDetailsByType($access_level); + return $this->_canShowByType($access_level); } // Each object type may have its own special rules, and re-implement this function. - protected function _canDisplayDetailsByType($access_level) { + protected function _canShowByType($access_level) { global $global_facts; if (isset($global_facts[static::RECORD_TYPE])) { @@ -360,23 +320,23 @@ class WT_GedcomRecord { } // Can the details of this record be shown? - public function canDisplayDetails($access_level=WT_USER_ACCESS_LEVEL) { + public function canShow($access_level=WT_USER_ACCESS_LEVEL) { // CACHING: this function can take three different parameters, // and therefore needs three different caches for the result. switch ($access_level) { case WT_PRIV_PUBLIC: // visitor if ($this->disp_public===null) { - $this->disp_public=$this->_canDisplayDetails(WT_PRIV_PUBLIC); + $this->disp_public=$this->_canShow(WT_PRIV_PUBLIC); } return $this->disp_public; case WT_PRIV_USER: // member if ($this->disp_user===null) { - $this->disp_user=$this->_canDisplayDetails(WT_PRIV_USER); + $this->disp_user=$this->_canShow(WT_PRIV_USER); } return $this->disp_user; case WT_PRIV_NONE: // admin if ($this->disp_none===null) { - $this->disp_none=$this->_canDisplayDetails(WT_PRIV_NONE); + $this->disp_none=$this->_canShow(WT_PRIV_NONE); } return $this->disp_none; case WT_PRIV_HIDE: // hidden from admins @@ -390,15 +350,13 @@ class WT_GedcomRecord { } // Can the name of this record be shown? - public function canDisplayName($access_level=WT_USER_ACCESS_LEVEL) { - return $this->canDisplayDetails($access_level); + public function canShowName($access_level=WT_USER_ACCESS_LEVEL) { + return $this->canShow($access_level); } // Can we edit this record? - // We use the unprivatized _gedrec as we must take account - // of the RESN tag, even if we are not permitted to see it. public function canEdit() { - return WT_USER_GEDCOM_ADMIN || WT_USER_CAN_EDIT && strpos($this->_gedrec, "\n1 RESN locked")===false; + return WT_USER_GEDCOM_ADMIN || WT_USER_CAN_EDIT && strpos($this->gedcom, "\n1 RESN locked")===false; } // Remove private data from the raw gedcom record. @@ -408,28 +366,25 @@ class WT_GedcomRecord { if ($access_level==WT_PRIV_HIDE) { // We may need the original record, for example when downloading a GEDCOM or clippings cart - return array($this->_gedrec, ''); - } elseif ($this->canDisplayDetails($access_level)) { + return array($this->gedcom, ''); + } elseif ($this->canShow($access_level)) { // The record is not private, but the individual facts may be. // Include the entire first line (for NOTE records) - list($gedrec)=explode("\n", $this->_gedrec, 2); + list($gedrec)=explode("\n", $this->gedcom, 2); - $private_gedrec=''; // Check each of the sub facts for access - preg_match_all('/\n1 .*(?:\n[2-9].*)*/', $this->_gedrec, $matches); + preg_match_all('/\n1 .*(?:\n[2-9].*)*/', $this->gedcom, $matches); foreach ($matches[0] as $match) { - if (canDisplayFact($this->xref, $this->ged_id, $match, $access_level)) { + if (canDisplayFact($this->xref, $this->gedcom_id, $match, $access_level)) { $gedrec.=$match; - } else { - $private_gedrec.=$match; } } - return array($gedrec, $private_gedrec); + return $gedrec; } else { // We cannot display the details, but we may be able to display // limited data, such as links to other records. - return array($this->createPrivateGedcomRecord($access_level), ''); + return $this->createPrivateGedcomRecord($access_level); } } @@ -440,10 +395,10 @@ class WT_GedcomRecord { // Convert a name record into sortable and full/display versions. This default // should be OK for simple record types. INDI/FAM records will need to redefine it. - protected function _addName($type, $value, $gedrec) { + protected function _addName($type, $value, $gedcom) { $this->_getAllNames[]=array( 'type'=>$type, - 'sort'=>preg_replace('/([0-9]+)/e', 'substr("000000000\\1", -10)', $value), + 'sort'=>preg_replace_callback('/([0-9]+)/', function($matches) { return str_pad($matches[0], 10, '0', STR_PAD_LEFT); }, $value), 'full'=>'<span dir="auto">'.htmlspecialchars($value).'</span>', // This is used for display 'fullNN'=>$value, // This goes into the database ); @@ -462,10 +417,10 @@ class WT_GedcomRecord { if (is_null($this->_getAllNames)) { $this->_getAllNames=array(); - if ($this->canDisplayName()) { + if ($this->canShowName()) { $sublevel=$level+1; $subsublevel=$sublevel+1; - if (preg_match_all("/^{$level} ({$fact}) (.+)((\n[{$sublevel}-9].+)*)/m", $this->getGedcomRecord(), $matches, PREG_SET_ORDER)) { + if (preg_match_all("/^{$level} ({$fact}) (.+)((\n[{$sublevel}-9].+)*)/m", $this->getGedcom(), $matches, PREG_SET_ORDER)) { foreach ($matches as $match) { // Treat 1 NAME / 2 TYPE married the same as _MARNM if ($match[1]=='NAME' && strpos($match[3], "\n2 TYPE married")!==false) { @@ -581,20 +536,20 @@ class WT_GedcomRecord { // Allow native PHP functions such as array_intersect() to work with objects public function __toString() { - return $this->xref.'@'.$this->ged_id; + return $this->xref.'@'.$this->gedcom_id; } // Static helper function to sort an array of objects by name // Records whose names cannot be displayed are sorted at the end. static function Compare($x, $y) { - if ($x->canDisplayName()) { - if ($y->canDisplayName()) { + if ($x->canShowName()) { + if ($y->canShowName()) { return utf8_strcasecmp($x->getSortName(), $y->getSortName()); } else { return -1; // only $y is private } } else { - if ($y->canDisplayName()) { + if ($y->canShowName()) { return 1; // only $x is private } else { return 0; // both $x and $y private @@ -611,8 +566,8 @@ class WT_GedcomRecord { return $tmp; } else { if ( - preg_match('/^\d\d:\d\d:\d\d/', get_gedcom_value('DATE:TIME', 2, $chan_x->getGedcomRecord()).':00', $match_x) && - preg_match('/^\d\d:\d\d:\d\d/', get_gedcom_value('DATE:TIME', 2, $chan_y->getGedcomRecord()).':00', $match_y) + preg_match('/^\d\d:\d\d:\d\d/', get_gedcom_value('DATE:TIME', 2, $chan_x->getGedcom()).':00', $match_x) && + preg_match('/^\d\d:\d\d:\d\d/', get_gedcom_value('DATE:TIME', 2, $chan_y->getGedcom()).':00', $match_y) ) { return strcmp($match_x[0], $match_y[0]); } else { @@ -623,22 +578,22 @@ class WT_GedcomRecord { // Get variants of the name public function getFullName() { - if ($this->canDisplayName()) { - $tmp=$this->getAllNames(); + if ($this->canShowName()) { + $tmp = $this->getAllNames(); return $tmp[$this->getPrimaryName()]['full']; } else { return WT_I18N::translate('Private'); } } public function getSortName() { - // The sortable name is never displayed, no need to call canDisplayName() - $tmp=$this->getAllNames(); + // The sortable name is never displayed, no need to call canShowName() + $tmp = $this->getAllNames(); return $tmp[$this->getPrimaryName()]['sort']; } // Get the fullname in an alternative character set public function getAddName() { - if ($this->canDisplayName() && $this->getPrimaryName()!=$this->getSecondaryName()) { - $all_names=$this->getAllNames(); + if ($this->canShowName() && $this->getPrimaryName()!=$this->getSecondaryName()) { + $all_names = $this->getAllNames(); return $all_names[$this->getSecondaryName()]['full']; } else { return null; @@ -672,7 +627,7 @@ class WT_GedcomRecord { // Extract/format the first fact from a list of facts. public function format_first_major_fact($facts, $style) { - foreach ($this->getAllFactsByType(explode('|', $facts)) as $event) { + foreach ($this->getFacts($facts) as $event) { // Only display if it has a date or place (or both) if (($event->getDate()->isOK() || $event->getPlace()) && $event->canShow()) { switch ($style) { @@ -688,22 +643,22 @@ class WT_GedcomRecord { // Fetch the records that link to this one public function fetchLinkedIndividuals() { - return fetch_linked_indi($this->getXref(), static::RECORD_TYPE, $this->ged_id); + return fetch_linked_indi($this->getXref(), static::RECORD_TYPE, $this->gedcom_id); } public function fetchLinkedFamilies() { - return fetch_linked_fam($this->getXref(), static::RECORD_TYPE, $this->ged_id); + return fetch_linked_fam($this->getXref(), static::RECORD_TYPE, $this->gedcom_id); } public function fetchLinkedNotes() { - return fetch_linked_note($this->getXref(), static::RECORD_TYPE, $this->ged_id); + return fetch_linked_note($this->getXref(), static::RECORD_TYPE, $this->gedcom_id); } public function fetchLinkedSources() { - return fetch_linked_sour($this->getXref(), static::RECORD_TYPE, $this->ged_id); + return fetch_linked_sour($this->getXref(), static::RECORD_TYPE, $this->gedcom_id); } public function fetchLinkedRepositories() { - return fetch_linked_repo($this->getXref(), static::RECORD_TYPE, $this->ged_id); + return fetch_linked_repo($this->getXref(), static::RECORD_TYPE, $this->gedcom_id); } public function fetchLinkedMedia() { - return fetch_linked_obje($this->getXref(), static::RECORD_TYPE, $this->ged_id); + return fetch_linked_obje($this->getXref(), static::RECORD_TYPE, $this->gedcom_id); } // Get all attributes (e.g. DATE or PLAC) from an event (e.g. BIRT or MARR). @@ -712,154 +667,48 @@ class WT_GedcomRecord { // calendars, place-names in both latin and hebrew character sets, etc. // It also allows us to combine dates/places from different events in the summaries. public function getAllEventDates($event) { - $dates=array(); - foreach ($this->getAllFactsByType($event) as $event) { + $dates = array(); + foreach ($this->getFacts($event) as $event) { if ($event->getDate()->isOK()) { - $dates[]=$event->getDate(); + $dates[] = $event->getDate(); } } return $dates; } public function getAllEventPlaces($event) { - $places=array(); - foreach ($this->getAllFactsByType($event) as $event) { - if (preg_match_all('/\n(?:2 PLAC|3 (?:ROMN|FONE|_HEB)) +(.+)/', $event->getGedcomRecord(), $ged_places)) { + $places = array(); + foreach ($this->getFacts($event) as $event) { + if (preg_match_all('/\n(?:2 PLAC|3 (?:ROMN|FONE|_HEB)) +(.+)/', $event->getGedcom(), $ged_places)) { foreach ($ged_places[1] as $ged_place) { - $places[]=$ged_place; + $places[] = $ged_place; } } } return $places; } - // Get the first WT_Event for the given fact type + // Get the first WT_Fact for the given fact type public function getFactByType($tag) { foreach ($this->getFacts() as $fact) { - if ($fact->getTag()==$tag) { + if ($fact->getTag() == $tag) { return $fact; } } return null; } - // Return an array of events that match the given types - public function getAllFactsByType($tags) { - if (is_string($tags)) { - $tags = array($tags); - } - $facts = array(); - foreach ($tags as $tag) { - foreach ($this->getFacts() as $fact) { - if ($fact->getTag()==$tag) { - $facts[]=$fact; - } - } - } - return $facts; - } - - /** - * returns an array of all of the facts - * @return Array - */ - public function getFacts() { - $this->parseFacts(); - return $this->facts; - } - - /** - * Get the CHAN event for this record - * - * @return WT_Event - */ - public function getChangeEvent() { - if (is_null($this->changeEvent)) { - $this->changeEvent = $this->getFactByType('CHAN'); - } - return $this->changeEvent; - } - - /** - * Parse the facts from the record - */ - public function parseFacts() { - //-- only run this function once - if (!is_null($this->facts) && is_array($this->facts)) { - return; - } - $this->facts=array(); - //-- don't run this function if privacy does not allow viewing of details - if (!$this->canDisplayDetails()) { - return; - } - //-- find all the fact information - $indilines = explode("\n", $this->getGedcomRecord()); // -- find the number of lines in the individuals record - $lct = count($indilines); - $factrec = ''; // -- complete fact record - $line = ''; // -- temporary line buffer - $linenum=1; - for ($i=1; $i<=$lct; $i++) { - if ($i<$lct) { - $line = $indilines[$i]; - } else { - $line=' '; - } - if (empty($line)) { - $line=' '; - } - if ($i==$lct||$line{0}==1) { - if ($i>1) { - $this->facts[] = new WT_Event($factrec, $this, $linenum); - } - $factrec = $line; - $linenum = $i; - } - else $factrec .= "\n".$line; - } - } - - /** - * Merge the facts from another GedcomRecord object into this object - * for generating a diff view - * @param GedcomRecord $diff the record to compare facts with - */ - public function diffMerge($diff) { - if (is_null($diff)) { - return; - } - $this->parseFacts(); - $diff->parseFacts(); - - //-- update old facts - foreach ($this->facts as $key=>$event) { - $found = false; - foreach ($diff->facts as $indexval => $newevent) { - $newfact = $newevent->getGedcomRecord(); - $newfact=preg_replace("/\\\/", '/', $newfact); - if (trim($newfact)==trim($event->getGedcomRecord())) { - $found = true; - break; - } - } - if (!$found) { - $this->facts[$key]->setIsOld(); - } - } - //-- look for new facts - foreach ($diff->facts as $key=>$newevent) { - $found = false; - foreach ($this->facts as $indexval => $event) { - $newfact = $newevent->getGedcomRecord(); - $newfact=preg_replace("/\\\/", '/', $newfact); - if (trim($newfact)==trim($event->getGedcomRecord())) { - $found = true; - break; + // The facts and events for this record + public function getFacts($filter=null) { + if ($filter === null) { + return $this->facts; + } else { + $facts=array(); + foreach ($this->facts as $fact) { + if (preg_match('/^' . $filter . '$/', $fact->getTag())) { + $facts[] = $fact; } } - if (!$found) { - $newevent->setIsNew(); - $this->facts[]=$newevent; - } + return $facts; } } @@ -871,26 +720,18 @@ class WT_GedcomRecord { $srec = $srec[0]; return get_gedcom_value('DATE', 2, $srec); } - public function getEventSource($event) { - $srec = $this->getAllEvents($event); - if (!$srec) { - return ''; - } - $srec = $srec[0]; - return get_sub_record('SOUR', 2, $srec); - } ////////////////////////////////////////////////////////////////////////////// // Get the last-change timestamp for this record, either as a formatted string // (for display) or as a unix timestamp (for sorting) ////////////////////////////////////////////////////////////////////////////// public function LastChangeTimestamp($sorting=false) { - $chan = $this->getChangeEvent(); + $chan = $this->getFactByType('CHAN'); if ($chan) { // The record does have a CHAN event $d = $chan->getDate()->MinDate(); - if (preg_match('/^(\d\d):(\d\d):(\d\d)/', get_gedcom_value('DATE:TIME', 2, $chan->getGedcomRecord()).':00', $match)) { + if (preg_match('/^(\d\d):(\d\d):(\d\d)/', get_gedcom_value('DATE:TIME', 2, $chan->getGedcom()).':00', $match)) { $t=mktime((int)$match[1], (int)$match[2], (int)$match[3], (int)$d->Format('%n'), (int)$d->Format('%j'), (int)$d->Format('%Y')); } else { $t=mktime(0, 0, 0, (int)$d->Format('%n'), (int)$d->Format('%j'), (int)$d->Format('%Y')); @@ -914,16 +755,192 @@ class WT_GedcomRecord { // Get the last-change user for this record ////////////////////////////////////////////////////////////////////////////// public function LastChangeUser() { - $chan = $this->getChangeEvent(); + $chan = $this->getFactByType('CHAN'); if (is_null($chan)) { return ' '; } - $chan_user = $chan->getValue('_WT_USER'); + $chan_user = $chan->getAttribute('_WT_USER'); if (empty($chan_user)) { return ' '; } return $chan_user; } + + ////////////////////////////////////////////////////////////////////////////// + // CRUD operations + ////////////////////////////////////////////////////////////////////////////// + + // Replace a (possibly empty) fact with a new (possibly empty) fact. + // This allows create/update/delete of individual facts + public function updateFact($fact_id, $gedcom, $update_chan) { + if (strpos("\r", $gedcom)!==false) { + // MSDOS line endings will break things in horrible ways + throw new Exception('Evil line endings found in WT_GedcomRecord::updateRecord(' . $gedcom . ')'); + } + if ($this->pending==='') { + throw new Exception('Cannot edit a deleted record'); + } + if ($gedcom && !preg_match('/^1 ' . WT_REGEX_TAG . '/', $gedcom)) { + throw new Exception('Invalid GEDCOM data passed to WT_GedcomRecord::updateFact()'); + } + + if ($this->pending) { + $old_gedcom = $this->pending; + } else { + $old_gedcom = $this->gedcom; + } + + $new_gedcom = '0 @' . $this->getXref() . '@ ' . static::RECORD_TYPE; + $old_chan = $this->getFactByType('CHAN'); + // Replacing (or deleting) an existing fact + foreach ($this->getFacts() as $fact) { + if ($fact->getFactId() == $fact_id) { + if ($gedcom) { + $new_gedcom .= "\n" . $gedcom; + } + } elseif ($fact->getTag()!='CHAN' || !$update_chan) { + $new_gedcom .= "\n" . $fact->getGedcom(); + } + } + if ($update_chan) { + $new_gedcom .= "\n1 CHAN\n2 DATE " . date('d M Y') . "\n3 TIME " . date('H:i:s') . "\n2 _WT_USER " . WT_USER_NAME; + } + + // Adding a new fact + if (!$fact_id) { + $new_gedcom .= "\n" . $gedcom; + } + + if ($new_gedcom != $old_gedcom) { + // Save the changes + WT_DB::prepare( + "INSERT INTO `##change` (gedcom_id, xref, old_gedcom, new_gedcom, user_id) VALUES (?, ?, ?, ?, ?)" + )->execute(array( + $this->gedcom_id, + $this->xref, + $old_gedcom, + $new_gedcom, + WT_USER_ID + )); + + // Clear the cache + self::$gedcom_record_cache = null; + self::$pending_record_cache = null; + + if (get_user_setting(WT_USER_ID, 'auto_accept')) { + accept_all_changes($xref, $ged_id); + } + } + } + + static public function createRecord($gedcom, $gedcom_id) { + if (preg_match('/^0 @(' . WT_REGEX_XREF . ')@ (' . WT_REGEX_TAG . ')/', $gedcom, $match)) { + $xref = $match[1]; + $type = $match[2]; + } else { + throw new Exception('Invalid argument to WT_GedcomRecord::createRecord(' . $gedcom . ')'); + } + if (strpos("\r", $gedcom)!==false) { + // MSDOS line endings will break things in horrible ways + throw new Exception('Evil line endings found in WT_GedcomRecord::createRecord(' . $gedcom . ')'); + } + + // webtrees creates XREFs containing digits. Anything else (e.g. “new”) is just a placeholder. + if (!preg_match('/\d/', $xref)) { + $xref = get_new_xref($type); + $gedcom = preg_replace('/^0 @(' . WT_REGEX_XREF . ')@/', '0 @' . $xref . '@', $gedcom); + } + + // Create a change record, if not already present + if (!preg_match('/\n1 CHAN/', $gedcom)) { + $gedcom .= "\n1 CHAN\n2 DATE " . date('d M Y') . "\n3 TIME " . date('H:i:s') . "\n2 _WT_USER " . WT_USER_NAME; + } + + // Create a pending change + WT_DB::prepare( + "INSERT INTO `##change` (gedcom_id, xref, old_gedcom, new_gedcom, user_id) VALUES (?, ?, '', ?, ?)" + )->execute(array( + $gedcom_id, + $xref, + $gedcom, + $gedcom_id + )); + + // Accept this pending change + if (get_user_setting(WT_USER_ID, 'auto_accept')) { + accept_all_changes($this->xref, $this->gedcom_id); + } + + // Clear this record from the cache + self::$pending_record_cache = null; + + AddToLog('Create: ' . $type . ' ' . $xref, 'edit'); + + // Return the newly created record + return WT_GedcomRecord::getInstance($xref); + } + + private static function readRecord($xref, $gedcom_id) { + return WT_DB::prepare(static::SQL_FETCH)->execute(array($xref, $gedcom_id))->fetchOne(); + } + + public function updateRecord($gedcom, $update_chan) { + if (strpos("\r", $gedcom)!==false) { + // MSDOS line endings will break things in horrible ways + throw new Exception('Evil line endings found in WT_GedcomRecord::updateRecord(' . $gedcom . ')'); + } + + // Update the CHAN record + if ($update_chan) { + $gedcom = preg_replace('/\n1 CHAN(\n[2-9].*)*/', '', $gedcom); + $gedcom .= "\n1 CHAN\n2 DATE " . date('d M Y') . "\n3 TIME " . date('H:i:s') . "\n2 _WT_USER " . WT_USER_NAME; + } + + // Create a pending change + WT_DB::prepare( + "INSERT INTO `##change` (gedcom_id, xref, old_gedcom, new_gedcom, user_id) VALUES (?, ?, ?, ?, ?)" + )->execute(array( + $this->gedcom_id, + $this->xref, + $this->getGedcom(), + $gedcom, + WT_USER_ID + )); + + // Accept this pending change + if (get_user_setting(WT_USER_ID, 'auto_accept')) { + accept_all_changes($this->xref, $this->gedcom_id); + } + + // Clear the cache + self::$gedcom_record_cache = null; + self::$pending_record_cache = null; + + AddToLog('Update: ' . self::RECORD_TYPE . ' ' . $this->xref, 'edit'); + } + + public function deleteRecord() { + // Create a pending change + WT_DB::prepare( + "INSERT INTO `##change` (gedcom_id, xref, old_gedcom, new_gedcom, user_id) VALUES (?, ?, ?, '', ?)" + )->execute(array( + $this->gedcom_id, + $this->xref, + $this->getGedcom(), + WT_USER_ID + )); + + // Accept this pending change + if (get_user_setting(WT_USER_ID, 'auto_accept')) { + accept_all_changes($this->xref, $this->gedcom_id); + } + + // Clear the cache + self::$gedcom_record_cache = null; + self::$pending_record_cache = null; + + AddToLog('Delete: ' . self::RECORD_TYPE . ' ' . $this->xref, 'edit'); + } } diff --git a/library/WT/Person.php b/library/WT/Individual.php index a2ab1229af..babefa9fbe 100644 --- a/library/WT/Person.php +++ b/library/WT/Individual.php @@ -1,5 +1,5 @@ <?php -// Class file for a person +// Class file for an individual // // webtrees: Web based Family History software // Copyright (C) 2013 webtrees development team. @@ -28,15 +28,11 @@ if (!defined('WT_WEBTREES')) { exit; } -class WT_Person extends WT_GedcomRecord { +class WT_Individual extends WT_GedcomRecord { const RECORD_TYPE = 'INDI'; + const SQL_FETCH = "SELECT i_gedcom FROM `##individuals` WHERE i_id=? AND i_file=?"; const URL_PREFIX = 'individual.php?pid='; - var $indifacts = array(); - var $otherfacts = array(); - var $globalfacts = array(); - var $mediafacts = array(); - var $facts_parsed = false; var $label = ''; var $highlightedimage = null; var $file = ''; @@ -59,21 +55,21 @@ class WT_Person extends WT_GedcomRecord { private $_getEstimatedDeathDate=null; // Can the name of this record be shown? - public function canDisplayName($access_level=WT_USER_ACCESS_LEVEL) { + public function canShowName($access_level=WT_USER_ACCESS_LEVEL) { global $SHOW_LIVING_NAMES; - return $SHOW_LIVING_NAMES>=$access_level || $this->canDisplayDetails($access_level); + return $SHOW_LIVING_NAMES>=$access_level || $this->canShow($access_level); } // Implement person-specific privacy logic - protected function _canDisplayDetailsByType($access_level) { + protected function _canShowByType($access_level) { global $SHOW_DEAD_PEOPLE, $KEEP_ALIVE_YEARS_BIRTH, $KEEP_ALIVE_YEARS_DEATH; // Dead people... if ($SHOW_DEAD_PEOPLE>=$access_level && $this->isDead()) { $keep_alive=false; if ($KEEP_ALIVE_YEARS_BIRTH) { - preg_match_all('/\n1 (?:'.WT_EVENTS_BIRT.').*(?:\n[2-9].*)*(?:\n2 DATE (.+))/', $this->_gedrec, $matches, PREG_SET_ORDER); + preg_match_all('/\n1 (?:'.WT_EVENTS_BIRT.').*(?:\n[2-9].*)*(?:\n2 DATE (.+))/', $this->gedcom, $matches, PREG_SET_ORDER); foreach ($matches as $match) { $date=new WT_Date($match[1]); if ($date->isOK() && $date->gregorianYear()+$KEEP_ALIVE_YEARS_BIRTH > date('Y')) { @@ -83,7 +79,7 @@ class WT_Person extends WT_GedcomRecord { } } if ($KEEP_ALIVE_YEARS_DEATH) { - preg_match_all('/\n1 (?:'.WT_EVENTS_DEAT.').*(?:\n[2-9].*)*(?:\n2 DATE (.+))/', $this->_gedrec, $matches, PREG_SET_ORDER); + preg_match_all('/\n1 (?:'.WT_EVENTS_DEAT.').*(?:\n[2-9].*)*(?:\n2 DATE (.+))/', $this->gedcom, $matches, PREG_SET_ORDER); foreach ($matches as $match) { $date=new WT_Date($match[1]); if ($date->isOK() && $date->gregorianYear()+$KEEP_ALIVE_YEARS_DEATH > date('Y')) { @@ -97,8 +93,8 @@ class WT_Person extends WT_GedcomRecord { } } // Consider relationship privacy (unless an admin is applying download restrictions) - if (WT_USER_GEDCOM_ID && WT_USER_PATH_LENGTH && $this->getGedId()==WT_GED_ID && $access_level=WT_USER_ACCESS_LEVEL) { - $self = WT_Person::getInstance(WT_USER_GEDCOM_ID); + if (WT_USER_GEDCOM_ID && WT_USER_PATH_LENGTH && $this->getGedcomId()==WT_GED_ID && $access_level=WT_USER_ACCESS_LEVEL) { + $self = WT_Individual::getInstance(WT_USER_GEDCOM_ID); if ($self) { return get_relationship($this, $self, true, WT_USER_PATH_LENGTH)!==false; } @@ -114,9 +110,9 @@ class WT_Person extends WT_GedcomRecord { $rec='0 @'.$this->xref.'@ INDI'; if ($SHOW_LIVING_NAMES>=$access_level) { // Show all the NAME tags, including subtags - preg_match_all('/\n1 NAME.*(?:\n[2-9].*)*/', $this->_gedrec, $matches); + preg_match_all('/\n1 NAME.*(?:\n[2-9].*)*/', $this->gedcom, $matches); foreach ($matches[0] as $match) { - if (canDisplayFact($this->xref, $this->ged_id, $match, $access_level)) { + if (canDisplayFact($this->xref, $this->gedcom_id, $match, $access_level)) { $rec.=$match; } } @@ -124,31 +120,29 @@ class WT_Person extends WT_GedcomRecord { $rec.="\n1 NAME ".WT_I18N::translate('Private'); } // Just show the 1 FAMC/FAMS tag, not any subtags, which may contain private data - preg_match_all('/\n1 (?:FAMC|FAMS) @('.WT_REGEX_XREF.')@/', $this->_gedrec, $matches, PREG_SET_ORDER); + preg_match_all('/\n1 (?:FAMC|FAMS) @('.WT_REGEX_XREF.')@/', $this->gedcom, $matches, PREG_SET_ORDER); foreach ($matches as $match) { $rela=WT_Family::getInstance($match[1]); - if ($rela && ($SHOW_PRIVATE_RELATIONSHIPS || $rela->canDisplayDetails($access_level))) { + if ($rela && ($SHOW_PRIVATE_RELATIONSHIPS || $rela->canShow($access_level))) { $rec.=$match[0]; } } // Don't privatize sex. - if (preg_match('/\n1 SEX [MFU]/', $this->_gedrec, $match)) { + if (preg_match('/\n1 SEX [MFU]/', $this->gedcom, $match)) { $rec.=$match[0]; } return $rec; } // Fetch the record from the database - protected static function fetchGedcomRecord($xref, $ged_id) { + protected static function fetchGedcomRecord($xref, $gedcom_id) { static $statement=null; if ($statement===null) { - $statement=WT_DB::prepare( - "SELECT 'INDI' AS type, i_id AS xref, i_file AS ged_id, i_gedcom AS gedrec ". - "FROM `##individuals` WHERE i_id=? AND i_file=?" - ); + $statement=WT_DB::prepare("SELECT i_gedcom FROM `##individuals` WHERE i_id=? AND i_file=?"); } - return $statement->execute(array($xref, $ged_id))->fetchOneRow(PDO::FETCH_ASSOC); + + return $statement->execute(array($xref, $gedcom_id))->fetchOne(); } // Static helper function to sort an array of people by birth date @@ -167,12 +161,12 @@ class WT_Person extends WT_GedcomRecord { global $MAX_ALIVE_AGE; // "1 DEAT Y" or "1 DEAT/2 DATE" or "1 DEAT/2 PLAC" - if (preg_match('/\n1 (?:'.WT_EVENTS_DEAT.')(?: Y|(?:\n[2-9].+)*\n2 (DATE|PLAC) )/', $this->_gedrec)) { + if (preg_match('/\n1 (?:'.WT_EVENTS_DEAT.')(?: Y|(?:\n[2-9].+)*\n2 (DATE|PLAC) )/', $this->gedcom)) { return true; } // If any event occured more than $MAX_ALIVE_AGE years ago, then assume the person is dead - if (preg_match_all('/\n2 DATE (.+)/', $this->_gedrec, $date_matches)) { + if (preg_match_all('/\n2 DATE (.+)/', $this->gedcom, $date_matches)) { foreach ($date_matches[1] as $date_match) { $date=new WT_Date($date_match); if ($date->isOK() && $date->MaxJD() <= WT_SERVER_JD - 365*$MAX_ALIVE_AGE) { @@ -181,7 +175,7 @@ class WT_Person extends WT_GedcomRecord { } // The individual has one or more dated events. All are less than $MAX_ALIVE_AGE years ago. // If one of these is a birth, the person must be alive. - if (preg_match('/\n1 BIRT(?:\n[2-9].+)*\n2 DATE /', $this->_gedrec)) { + if (preg_match('/\n1 BIRT(?:\n[2-9].+)*\n2 DATE /', $this->gedcom)) { return false; } } @@ -192,7 +186,7 @@ class WT_Person extends WT_GedcomRecord { foreach ($this->getChildFamilies(WT_PRIV_HIDE) as $family) { foreach ($family->getSpouses(WT_PRIV_HIDE) as $parent) { // Assume parents are no more than 45 years older than their children - preg_match_all('/\n2 DATE (.+)/', $parent->_gedrec, $date_matches); + preg_match_all('/\n2 DATE (.+)/', $parent->gedcom, $date_matches); foreach ($date_matches[1] as $date_match) { $date=new WT_Date($date_match); if ($date->isOK() && $date->MaxJD() <= WT_SERVER_JD - 365*($MAX_ALIVE_AGE+45)) { @@ -204,7 +198,7 @@ class WT_Person extends WT_GedcomRecord { // Check spouses foreach ($this->getSpouseFamilies(WT_PRIV_HIDE) as $family) { - preg_match_all('/\n2 DATE (.+)/', $family->_gedrec, $date_matches); + preg_match_all('/\n2 DATE (.+)/', $family->gedcom, $date_matches); foreach ($date_matches[1] as $date_match) { $date=new WT_Date($date_match); // Assume marriage occurs after age of 10 @@ -215,7 +209,7 @@ class WT_Person extends WT_GedcomRecord { // Check spouse dates $spouse=$family->getSpouse($this, WT_PRIV_HIDE); if ($spouse) { - preg_match_all('/\n2 DATE (.+)/', $spouse->_gedrec, $date_matches); + preg_match_all('/\n2 DATE (.+)/', $spouse->gedcom, $date_matches); foreach ($date_matches[1] as $date_match) { $date=new WT_Date($date_match); // Assume max age difference between spouses of 40 years @@ -226,7 +220,7 @@ class WT_Person extends WT_GedcomRecord { } // Check child dates foreach ($family->getChildren(WT_PRIV_HIDE) as $child) { - preg_match_all('/\n2 DATE (.+)/', $child->_gedrec, $date_matches); + preg_match_all('/\n2 DATE (.+)/', $child->gedcom, $date_matches); // Assume children born after age of 15 foreach ($date_matches[1] as $date_match) { $date=new WT_Date($date_match); @@ -237,7 +231,7 @@ class WT_Person extends WT_GedcomRecord { // Check grandchildren foreach ($child->getSpouseFamilies(WT_PRIV_HIDE) as $child_family) { foreach ($child_family->getChildren(WT_PRIV_HIDE) as $grandchild) { - preg_match_all('/\n2 DATE (.+)/', $grandchild->_gedrec, $date_matches); + preg_match_all('/\n2 DATE (.+)/', $grandchild->gedcom, $date_matches); // Assume grandchildren born after age of 30 foreach ($date_matches[1] as $date_match) { $date=new WT_Date($date_match); @@ -265,10 +259,10 @@ class WT_Person extends WT_GedcomRecord { $objectC = null; // Iterate over all of the media items for the person - preg_match_all('/\n(\d) OBJE @(' . WT_REGEX_XREF . ')@/', $this->getGedcomRecord(), $matches, PREG_SET_ORDER); + preg_match_all('/\n(\d) OBJE @(' . WT_REGEX_XREF . ')@/', $this->getGedcom(), $matches, PREG_SET_ORDER); foreach ($matches as $match) { $media = WT_Media::getInstance($match[2]); - if (!$media || !$media->canDisplayDetails() || $media->isExternal()) { + if (!$media || !$media->canShow() || $media->isExternal()) { continue; } $level = $match[1]; @@ -325,7 +319,7 @@ class WT_Person extends WT_GedcomRecord { */ function getBirthDate() { if (is_null($this->_getBirthDate)) { - if ($this->canDisplayDetails()) { + if ($this->canShow()) { foreach ($this->getAllBirthDates() as $date) { if ($date->isOK()) { $this->_getBirthDate=$date; @@ -348,7 +342,7 @@ class WT_Person extends WT_GedcomRecord { */ function getBirthPlace() { if (is_null($this->_getBirthPlace)) { - if ($this->canDisplayDetails()) { + if ($this->canShow()) { foreach ($this->getAllBirthPlaces() as $place) { if ($place) { $this->_getBirthPlace=$place; @@ -371,7 +365,7 @@ class WT_Person extends WT_GedcomRecord { */ function getCensBirthPlace() { if (is_null($this->_getBirthPlace)) { - if ($this->canDisplayDetails()) { + if ($this->canShow()) { foreach ($this->getAllBirthPlaces() as $place) { if ($place) { $this->_getBirthPlace=$place; @@ -408,7 +402,7 @@ class WT_Person extends WT_GedcomRecord { */ function getDeathDate($estimate = true) { if (is_null($this->_getDeathDate)) { - if ($this->canDisplayDetails()) { + if ($this->canShow()) { foreach ($this->getAllDeathDates() as $date) { if ($date->isOK()) { $this->_getDeathDate=$date; @@ -431,7 +425,7 @@ class WT_Person extends WT_GedcomRecord { */ function getDeathPlace() { if (is_null($this->_getDeathPlace)) { - if ($this->canDisplayDetails()) { + if ($this->canShow()) { foreach ($this->getAllDeathPlaces() as $place) { if ($place) { $this->_getDeathPlace=$place; @@ -498,7 +492,7 @@ class WT_Person extends WT_GedcomRecord { // Get all the dates/places for births/deaths - for the INDI lists function getAllBirthDates() { if (is_null($this->_getAllBirthDates)) { - if ($this->canDisplayDetails()) { + if ($this->canShow()) { foreach (explode('|', WT_EVENTS_BIRT) as $event) { if ($this->_getAllBirthDates=$this->getAllEventDates($event)) { break; @@ -512,7 +506,7 @@ class WT_Person extends WT_GedcomRecord { } function getAllBirthPlaces() { if (is_null($this->_getAllBirthPlaces)) { - if ($this->canDisplayDetails()) { + if ($this->canShow()) { foreach (explode('|', WT_EVENTS_BIRT) as $event) { if ($this->_getAllBirthPlaces=$this->getAllEventPlaces($event)) { break; @@ -526,7 +520,7 @@ class WT_Person extends WT_GedcomRecord { } function getAllDeathDates() { if (is_null($this->_getAllDeathDates)) { - if ($this->canDisplayDetails()) { + if ($this->canShow()) { foreach (explode('|', WT_EVENTS_DEAT) as $event) { if ($this->_getAllDeathDates=$this->getAllEventDates($event)) { break; @@ -540,7 +534,7 @@ class WT_Person extends WT_GedcomRecord { } function getAllDeathPlaces() { if (is_null($this->_getAllDeathPlaces)) { - if ($this->canDisplayDetails()) { + if ($this->canShow()) { foreach (explode('|', WT_EVENTS_DEAT) as $event) { if ($this->_getAllDeathPlaces=$this->getAllEventPlaces($event)) { break; @@ -664,7 +658,7 @@ class WT_Person extends WT_GedcomRecord { // the privatize-gedcom function, and we are allowed to know this. function getSex() { if (is_null($this->sex)) { - if (preg_match('/\n1 SEX ([MF])/', $this->_gedrec, $match)) { + if (preg_match('/\n1 SEX ([MF])/', $this->gedcom, $match)) { $this->sex=$match[1]; } else { $this->sex='U'; @@ -753,7 +747,7 @@ class WT_Person extends WT_GedcomRecord { if ($access_level==WT_PRIV_HIDE) { // special case, (temporary - cannot make this generic as other code depends on the private cached values) $families=array(); - preg_match_all('/\n1 FAMS @('.WT_REGEX_XREF.')@/', $this->_gedrec, $match); + preg_match_all('/\n1 FAMS @('.WT_REGEX_XREF.')@/', $this->gedcom, $match); foreach ($match[1] as $pid) { $family=WT_Family::getInstance($pid); if ($family) { @@ -765,10 +759,10 @@ class WT_Person extends WT_GedcomRecord { if ($this->_spouseFamilies===null) { $this->_spouseFamilies=array(); - preg_match_all('/\n1 FAMS @('.WT_REGEX_XREF.')@/', $this->_gedrec, $match); + preg_match_all('/\n1 FAMS @('.WT_REGEX_XREF.')@/', $this->gedcom, $match); foreach ($match[1] as $pid) { $family=WT_Family::getInstance($pid); - if ($family && ($SHOW_PRIVATE_RELATIONSHIPS || $family->canDisplayDetails($access_level))) { + if ($family && ($SHOW_PRIVATE_RELATIONSHIPS || $family->canShow($access_level))) { $this->_spouseFamilies[]=$family; } } @@ -794,7 +788,7 @@ class WT_Person extends WT_GedcomRecord { // Get a count of the children for this individual function getNumberOfChildren() { - if (preg_match('/\n1 NCHI (\d+)(?:\n|$)/', $this->getGedcomRecord(), $match)) { + if (preg_match('/\n1 NCHI (\d+)(?:\n|$)/', $this->getGedcom(), $match)) { return $match[1]; } else { $children=array(); @@ -814,7 +808,7 @@ class WT_Person extends WT_GedcomRecord { if ($access_level==WT_PRIV_HIDE) { // special case, (temporary - cannot make this generic as other code depends on the private cached values) $families=array(); - preg_match_all('/\n1 FAMC @('.WT_REGEX_XREF.')@/', $this->_gedrec, $match); + preg_match_all('/\n1 FAMC @('.WT_REGEX_XREF.')@/', $this->gedcom, $match); foreach ($match[1] as $pid) { $family=WT_Family::getInstance($pid); if ($family) { @@ -826,10 +820,10 @@ class WT_Person extends WT_GedcomRecord { if ($this->_childFamilies===null) { $this->_childFamilies=array(); - preg_match_all('/\n1 FAMC @('.WT_REGEX_XREF.')@/', $this->_gedrec, $match); + preg_match_all('/\n1 FAMC @('.WT_REGEX_XREF.')@/', $this->gedcom, $match); foreach ($match[1] as $pid) { $family=WT_Family::getInstance($pid); - if ($family && ($SHOW_PRIVATE_RELATIONSHIPS || $family->canDisplayDetails($access_level))) { + if ($family && ($SHOW_PRIVATE_RELATIONSHIPS || $family->canShow($access_level))) { $this->_childFamilies[]=$family; } } @@ -852,19 +846,19 @@ class WT_Person extends WT_GedcomRecord { // If there is more than one FAMC record, choose the preferred parents: // a) records with '2 _PRIMARY' foreach ($families as $famid=>$fam) { - if (preg_match("/\n1 FAMC @{$famid}@\n(?:[2-9].*\n)*(?:2 _PRIMARY Y)/", $this->getGedcomRecord())) { + if (preg_match("/\n1 FAMC @{$famid}@\n(?:[2-9].*\n)*(?:2 _PRIMARY Y)/", $this->getGedcom())) { return $fam; } } // b) records with '2 PEDI birt' foreach ($families as $famid=>$fam) { - if (preg_match("/\n1 FAMC @{$famid}@\n(?:[2-9].*\n)*(?:2 PEDI birth)/", $this->getGedcomRecord())) { + if (preg_match("/\n1 FAMC @{$famid}@\n(?:[2-9].*\n)*(?:2 PEDI birth)/", $this->getGedcom())) { return $fam; } } // c) records with no '2 PEDI' foreach ($families as $famid=>$fam) { - if (!preg_match("/\n1 FAMC @{$famid}@\n(?:[2-9].*\n)*(?:2 PEDI)/", $this->getGedcomRecord())) { + if (!preg_match("/\n1 FAMC @{$famid}@\n(?:[2-9].*\n)*(?:2 PEDI)/", $this->getGedcom())) { return $fam; } } @@ -877,7 +871,7 @@ class WT_Person extends WT_GedcomRecord { * @return string FAMC:PEDI value [ adopted | birth | foster | sealing ] */ function getChildFamilyPedigree($famid) { - $subrec = get_sub_record(1, '1 FAMC @'.$famid.'@', $this->getGedcomRecord()); + $subrec = get_sub_record(1, '1 FAMC @'.$famid.'@', $this->getGedcom()); $pedi = get_gedcom_value('PEDI', 2, $subrec); // birth=default => return an empty string return ($pedi=='birth') ? '' : $pedi; @@ -925,35 +919,9 @@ class WT_Person extends WT_GedcomRecord { return $step_families; } - /** - * get global facts - * @return array - */ - function getGlobalFacts() { - $this->parseFacts(); - return $this->globalfacts; - } - /** - * get indi facts - * @return array - */ - function getIndiFacts() { - $this->parseFacts(); - return $this->indifacts; - } - - /** - * get other facts - * @return array - */ - function getOtherFacts() { - $this->parseFacts(); - return $this->otherfacts; - } - // A label for a parental family group function getChildFamilyLabel(WT_Family $family) { - if (preg_match('/\n1 FAMC @'.$family->getXref().'@(?:\n[2-9].*)*\n2 PEDI (.+)/', $this->getGedcomRecord(), $match)) { + if (preg_match('/\n1 FAMC @'.$family->getXref().'@(?:\n[2-9].*)*\n2 PEDI (.+)/', $this->getGedcom(), $match)) { // A specified pedigree return WT_Gedcom_Code_Pedi::getChildFamilyLabel($match[1]); } else { @@ -1001,8 +969,9 @@ class WT_Person extends WT_GedcomRecord { } } // It should not be possible to get here - throw new Exception('Invalid family in WT_Person::getStepFamilyLabel(' . $family . ')'); + throw new Exception('Invalid family in WT_Individual::getStepFamilyLabel(' . $family . ')'); } + /** * get the correct label for a family * @param Family $family the family to get the label for @@ -1025,595 +994,6 @@ class WT_Person extends WT_GedcomRecord { // I18N: %s is the spouse name return WT_I18N::translate('Family with %s', $spouse); } - /** - * get updated Person - * If there is an updated individual record in the gedcom file - * return a new person object for it - * @return Person - */ - function getUpdatedPerson() { - if ($this->getChanged()) { - return null; - } - if (WT_USER_CAN_EDIT && $this->canDisplayDetails()) { - $newrec = find_updated_record($this->xref, $this->ged_id); - if (!is_null($newrec)) { - $new = new WT_Person($newrec); - $new->setChanged(true); - return $new; - } - } - return null; - } - /** - * Parse the facts from the individual record - */ - function parseFacts() { - parent::parseFacts(); - //-- only run this function once - if ($this->facts_parsed) return; - //-- don't run this function if privacy does not allow viewing of details - if (!$this->canDisplayDetails()) return; - $sexfound = false; - //-- run the parseFacts() method from the parent class - $this->facts_parsed = true; - - //-- sort the fact info into different categories for people - foreach ($this->facts as $f=>$event) { - $fact = $event->getTag(); - if ($fact=='NAME') { - // -- handle special name fact case - $this->globalfacts[] = $event; - } elseif ($fact=='SOUR') { - // -- handle special source fact case - $this->otherfacts[] = $event; - } elseif ($fact=='NOTE') { - // -- handle special note fact case - $this->otherfacts[] = $event; - } elseif ($fact=='SEX') { - // -- handle special sex case - $this->globalfacts[] = $event; - $sexfound = true; - } elseif ($fact=='OBJE') { - } else { - $this->indifacts[] = $event; - } - } - //-- add a new sex fact if one was not found - if (!$sexfound) { - $this->globalfacts[] = new WT_Event('1 SEX U', $this, 'new'); - } - } - /** - * add facts from the family record - * @param boolean $otherfacts whether or not to add other related facts such as parents facts, associated people facts, and historical facts - */ - function add_family_facts($otherfacts = true) { - global $GEDCOM, $nonfacts, $nonfamfacts; - - if (!isset($nonfacts)) $nonfacts = array(); - if (!isset($nonfamfacts)) $nonfamfacts = array(); - - if (!$this->canDisplayDetails()) return; - $this->parseFacts(); - //-- Get the facts from the family with spouse (FAMS) - foreach ($this->getSpouseFamilies() as $family) { - $updfamily = $family->getUpdatedFamily(); //-- updated family ? - $spouse = $family->getSpouse($this); - - if ($updfamily) { - $family->diffMerge($updfamily); - } - $facts = $family->getFacts(); - $hasdiv = false; - /* @var $event WT_Event */ - foreach ($facts as $event) { - $fact = $event->getTag(); - if ($fact=='DIV') $hasdiv = true; - // -- handle special source fact case - if ($fact!='SOUR' && $fact!='NOTE' && $fact!='CHAN' && $fact!='_UID' && $fact!='RIN') { - if (!in_array($fact, $nonfacts) && !in_array($fact, $nonfamfacts)) { - $event->setSpouse($spouse); - if ($fact!='OBJE') { - $this->indifacts[]=$event; - } else { - $this->otherfacts[]=$event; - } - } - } - } - if ($otherfacts) { - if (!$hasdiv && !is_null($spouse)) $this->add_spouse_facts($spouse, $family->getGedcomRecord()); - $this->add_children_facts($family, '_CHIL', ''); - } - } - if ($otherfacts) { - $this->add_parents_facts($this, 1); - $this->add_historical_facts(); - $this->add_asso_facts(); - } - } - - // Add parents' (and parents' relatives') events to individual facts array - function add_parents_facts($person, $sosa) { - global $SHOW_RELATIVES_EVENTS; - - switch ($sosa) { - case 1: - foreach ($person->getChildFamilies() as $family) { - // Add siblings - $this->add_children_facts($family, '_SIBL', ''); - foreach ($family->getSpouses() as $spouse) { - foreach ($spouse->getSpouseFamilies() as $sfamily) { - if (!$family->equals($sfamily)) { - // Add half-siblings - $this->add_children_facts($sfamily, '_HSIB', 'par'); - } - } - // Add grandparents - $this->add_parents_facts($spouse, $spouse->getSex()=='F' ? 3 : 2); - } - } - - $rela=''; - break; - case 2: - $rela='fat'; - break; - case 3: - $rela='mot'; - break; - } - - // Only include events between birth and death - $bDate=$this->getEstimatedBirthDate(); - $dDate=$this->getEstimatedDeathDate(); - - foreach ($person->getChildFamilies() as $famid=>$family) { - foreach ($family->getSpouses() as $parent) { - if (strstr($SHOW_RELATIVES_EVENTS, '_DEAT'.($sosa==1 ? '_PARE' : '_GPAR'))) { - foreach ($parent->getAllFactsByType(explode('|', WT_EVENTS_DEAT)) as $sEvent) { - if ($sEvent->getDate()->isOK() && WT_Date::Compare($bDate, $sEvent->getDate())<=0 && WT_Date::Compare($sEvent->getDate(), $dDate)<=0) { - switch ($sosa) { - case 1: - // Convert the event to a close relatives event - $tmp_rec=preg_replace('/^1 ('.WT_EVENTS_DEAT.')/', '1 _$1_PARE ', $sEvent->getGedcomRecord()); // Full - $tmp_rec="1 _".$sEvent->getTag()."_PARE\n2 DATE ".$sEvent->getValue('DATE')."\n2 PLAC ".$sEvent->getValue('PLAC'); // Abbreviated - break; - case 2: - // Convert the event to a close relatives event - $tmp_rec=preg_replace('/^1 ('.WT_EVENTS_DEAT.')/', '1 _$1_GPA1 ', $sEvent->getGedcomRecord()); // Full - $tmp_rec="1 _".$sEvent->getTag()."_GPA1\n2 DATE ".$sEvent->getValue('DATE')."\n2 PLAC ".$sEvent->getValue('PLAC'); // Abbreviated - break; - case 3: - // Convert the event to a close relatives event - $tmp_rec=preg_replace('/^1 ('.WT_EVENTS_DEAT.')/', '1 _$1_GPA2 ', $sEvent->getGedcomRecord()); // Full - $tmp_rec="1 _".$sEvent->getTag()."_GPA2\n2 DATE ".$sEvent->getValue('DATE')."\n2 PLAC ".$sEvent->getValue('PLAC'); // Abbreviated - break; - } - // Create a new event - $this->indifacts[]=new WT_Event($tmp_rec."\n2 _ASSO @".$parent->getXref()."@", $parent, 0); - } - } - } - } - - if ($sosa==1 && strstr($SHOW_RELATIVES_EVENTS, '_MARR_PARE')) { - // add father/mother marriages - foreach ($family->getSpouses() as $parent) { - foreach ($parent->getSpouseFamilies() as $sfamily) { - foreach ($sfamily->getAllFactsByType(explode('|', WT_EVENTS_MARR)) as $sEvent) { - if ($sEvent->getDate()->isOK() && WT_Date::Compare($bDate, $sEvent->getDate())<=0 && WT_Date::Compare($sEvent->getDate(), $dDate)<=0) { - if ($sfamily->equals($family)) { - if ($parent->getSex()=='F') { - // show current family marriage only once - continue; - } - // marriage of parents (to each other) - // Convert the event to a close relatives event - $tmp_rec=preg_replace('/^1 ('.WT_EVENTS_MARR.')/', '1 _$1_FAMC ', $sEvent->getGedcomRecord()); // Full - $tmp_rec="1 _".$sEvent->getTag()."_FAMC\n2 DATE ".$sEvent->getValue('DATE')."\n2 PLAC ".$sEvent->getValue('PLAC'); // Abbreviated - } else { - // marriage of a parent (to another spouse) - // Convert the event to a close relatives event - $tmp_rec=preg_replace('/^1 ('.WT_EVENTS_MARR.')/', '1 _$1_PARE ', $sEvent->getGedcomRecord()); // Full - $tmp_rec="1 _".$sEvent->getTag()."_PARE\n2 DATE ".$sEvent->getValue('DATE')."\n2 PLAC ".$sEvent->getValue('PLAC'); // Abbreviated - } - // Add links to both spouses - foreach ($sfamily->getSpouses() as $spouse) { - $tmp_rec .= "\n2 _ASSO @" . $spouse->getXref() . '@'; - } - // Create a new event - $tmp = new WT_Event($tmp_rec, $sfamily, 0); - if (!$sfamily->equals($family)) { - $tmp->setSpouse($parent); - } - $this->indifacts[]=$tmp; - } - } - } - } - } - } - } - - /** - * add children events to individual facts array - * - * @param string $family Family object - * @param string $option Family level indicator - * @param string $relation Relationship path indicator - * @return records added to indifacts array - */ - function add_children_facts($family, $option, $relation) { - global $SHOW_RELATIVES_EVENTS; - - // Deal with recursion. - switch ($option) { - case '_CHIL': - // Add grandchildren - foreach ($family->getChildren() as $child) { - foreach ($child->getSpouseFamilies() as $cfamily) { - switch ($child->getSex()) { - case 'M': - $this->add_children_facts($cfamily, '_GCHI', 'son'); - break; - case 'F': - $this->add_children_facts($cfamily, '_GCHI', 'dau'); - break; - case 'U': - $this->add_children_facts($cfamily, '_GCHI', 'chi'); - break; - } - } - } - break; - } - - // For each child in the family - foreach ($family->getChildren() as $child) { - if ($child->getXref()==$this->getXref()) { - // We are not our own sibling! - continue; - } - // add child's birth - if (strpos($SHOW_RELATIVES_EVENTS, '_BIRT'.str_replace('_HSIB', '_SIBL', $option))!==false) { - foreach ($child->getAllFactsByType(explode('|', WT_EVENTS_BIRT)) as $sEvent) { - $sgdate=$sEvent->getDate(); - // Always show _BIRT_CHIL, even if the dates are not known - if ($option=='_CHIL' || $sgdate->isOK() && WT_Date::Compare($this->getEstimatedBirthDate(), $sgdate)<=0 && WT_Date::Compare($sgdate, $this->getEstimatedDeathDate())<=0) { - if ($option=='_GCHI' && $relation=='dau') { - // Convert the event to a close relatives event. - $tmp_rec=preg_replace('/^1 ('.WT_EVENTS_BIRT.')/', '1 _$1_GCH1', $sEvent->getGedcomRecord()); // Full - $tmp_rec="1 _".$sEvent->getTag()."_GCH1\n2 DATE ".$sEvent->getValue('DATE')."\n2 PLAC ".$sEvent->getValue('PLAC'); // Abbreviated - } elseif ($option=='_GCHI' && $relation=='son') { - // Convert the event to a close relatives event. - $tmp_rec=preg_replace('/^1 ('.WT_EVENTS_BIRT.')/', '1 _$1_GCH2', $sEvent->getGedcomRecord()); // Full - $tmp_rec="1 _".$sEvent->getTag()."_GCH2\n2 DATE ".$sEvent->getValue('DATE')."\n2 PLAC ".$sEvent->getValue('PLAC'); // Abbreviated - } else { - // Convert the event to a close relatives event. - $tmp_rec=preg_replace('/^1 ('.WT_EVENTS_BIRT.')/', '1 _$1'.$option, $sEvent->getGedcomRecord()); // Full - $tmp_rec="1 _".$sEvent->getTag().$option."\n2 DATE ".$sEvent->getValue('DATE')."\n2 PLAC ".$sEvent->getValue('PLAC'); // Abbreviated - } - $event=new WT_Event($tmp_rec."\n2 _ASSO @".$child->getXref()."@", $child, 0); - if (!in_array($event, $this->indifacts)) { - $this->indifacts[]=$event; - } - } - } - } - // add child's death - if (strpos($SHOW_RELATIVES_EVENTS, '_DEAT'.str_replace('_HSIB', '_SIBL', $option))!==false) { - foreach ($child->getAllFactsByType(explode('|', WT_EVENTS_DEAT)) as $sEvent) { - $sgdate=$sEvent->getDate(); - $srec = $sEvent->getGedcomRecord(); - if ($sgdate->isOK() && WT_Date::Compare($this->getEstimatedBirthDate(), $sgdate)<=0 && WT_Date::Compare($sgdate, $this->getEstimatedDeathDate())<=0) { - if ($option=='_GCHI' && $relation=='dau') { - // Convert the event to a close relatives event. - $tmp_rec=preg_replace('/^1 ('.WT_EVENTS_DEAT.')/', '1 _$1_GCH1', $sEvent->getGedcomRecord()); // Full - $tmp_rec="1 _".$sEvent->getTag()."_GCH1\n2 DATE ".$sEvent->getValue('DATE')."\n2 PLAC ".$sEvent->getValue('PLAC'); // Abbreviated - } elseif ($option=='_GCHI' && $relation=='son') { - // Convert the event to a close relatives event. - $tmp_rec=preg_replace('/^1 ('.WT_EVENTS_DEAT.')/', '1 _$1_GCH2', $sEvent->getGedcomRecord()); // Full - $tmp_rec="1 _".$sEvent->getTag()."_GCH2\n2 DATE ".$sEvent->getValue('DATE')."\n2 PLAC ".$sEvent->getValue('PLAC'); // Abbreviated - } else { - // Convert the event to a close relatives event. - $tmp_rec=preg_replace('/^1 ('.WT_EVENTS_DEAT.')/', '1 _$1'.$option, $sEvent->getGedcomRecord()); // Full - $tmp_rec="1 _".$sEvent->getTag().$option."\n2 DATE ".$sEvent->getValue('DATE')."\n2 PLAC ".$sEvent->getValue('PLAC'); // Abbreviated - } - $event=new WT_Event($tmp_rec."\n2 _ASSO @".$child->getXref()."@", $child, 0); - if (!in_array($event, $this->indifacts)) { - $this->indifacts[]=$event; - } - } - } - } - // add child's marriage - if (strstr($SHOW_RELATIVES_EVENTS, '_MARR'.str_replace('_HSIB', '_SIBL', $option))) { - foreach ($child->getSpouseFamilies() as $sfamily) { - foreach ($sfamily->getAllFactsByType(explode('|', WT_EVENTS_MARR)) as $sEvent) { - $sgdate=$sEvent->getDate(); - if ($sgdate->isOK() && WT_Date::Compare($this->getEstimatedBirthDate(), $sgdate)<=0 && WT_Date::Compare($sgdate, $this->getEstimatedDeathDate())<=0) { - if ($option=='_GCHI' && $relation=='dau') { - // Convert the event to a close relatives event. - $tmp_rec=preg_replace('/^1 ('.WT_EVENTS_MARR.')/', '1 _$1_GCH1', $sEvent->getGedcomRecord()); - $tmp_rec="1 _".$sEvent->getTag()."_GCH1\n2 DATE ".$sEvent->getValue('DATE')."\n2 PLAC ".$sEvent->getValue('PLAC'); // Abbreviated - } elseif ($option=='_GCHI' && $relation=='son') { - // Convert the event to a close relatives event. - $tmp_rec=preg_replace('/^1 ('.WT_EVENTS_MARR.')/', '1 _$1_GCH2', $sEvent->getGedcomRecord()); - $tmp_rec="1 _".$sEvent->getTag()."_GCH2\n2 DATE ".$sEvent->getValue('DATE')."\n2 PLAC ".$sEvent->getValue('PLAC'); // Abbreviated - } else { - // Convert the event to a close relatives event. - $tmp_rec=preg_replace('/^1 ('.WT_EVENTS_MARR.')/', '1 _$1'.$option, $sEvent->getGedcomRecord()); - $tmp_rec="1 _".$sEvent->getTag().$option."\n2 DATE ".$sEvent->getValue('DATE')."\n2 PLAC ".$sEvent->getValue('PLAC'); // Abbreviated - } - // Add links to both spouses - foreach ($sfamily->getSpouses() as $spouse) { - $tmp_rec .= "\n2 _ASSO @" . $spouse->getXref() . '@'; - } - // Create a new event - $tmp = new WT_Event($tmp_rec, $sfamily, 0); - $tmp->setSpouse($child); - $this->indifacts[]=$tmp; - } - } - } - } - } - } - /** - * add spouse events to individual facts array - * - * bdate = indi birth date record - * ddate = indi death date record - * - * @param string $spouse Person object - * @param string $famrec family Gedcom record - * @return records added to indifacts array - */ - function add_spouse_facts($spouse, $famrec='') { - global $SHOW_RELATIVES_EVENTS; - - // do not show if divorced - if (preg_match('/\n1 (?:'.WT_EVENTS_DIV.')\b/', $famrec)) { - return; - } - // Only include events between birth and death - $bDate=$this->getEstimatedBirthDate(); - $dDate=$this->getEstimatedDeathDate(); - - // add spouse death - if ($spouse && strstr($SHOW_RELATIVES_EVENTS, '_DEAT_SPOU')) { - foreach ($spouse->getAllFactsByType(explode('|', WT_EVENTS_DEAT)) as $sEvent) { - $sdate=$sEvent->getDate(); - if ($sdate->isOK() && WT_Date::Compare($this->getEstimatedBirthDate(), $sdate)<=0 && WT_Date::Compare($sdate, $this->getEstimatedDeathDate())<=0) { - // Convert the event to a close relatives event. - $tmp_rec=preg_replace('/^1 ('.WT_EVENTS_DEAT.')/', '1 _$1_SPOU ', $sEvent->getGedcomRecord()); // Full - $tmp_rec="1 _".$sEvent->getTag()."_SPOU\n2 DATE ".$sEvent->getValue('DATE')."\n2 PLAC ".$sEvent->getValue('PLAC'); // Abbreviated - // Create a new event - $this->indifacts[]=new WT_Event($tmp_rec."\n2 _ASSO @".$spouse->getXref()."@", $spouse, 0); - } - } - } - } - - /** - * add historical events to individual facts array - * - * @return records added to indifacts array - * - * Historical facts are imported from optional language file : histo.xx.php - * where xx is language code - * This file should contain records similar to : - * - * $histo[]="1 EVEN\n2 TYPE History\n2 DATE 11 NOV 1918\n2 NOTE WW1 Armistice"; - * $histo[]="1 EVEN\n2 TYPE History\n2 DATE 8 MAY 1945\n2 NOTE WW2 Armistice"; - * etc... - * - */ - function add_historical_facts() { - global $SHOW_RELATIVES_EVENTS; - if (!$SHOW_RELATIVES_EVENTS) return; - - // Only include events between birth and death - $bDate=$this->getEstimatedBirthDate(); - $dDate=$this->getEstimatedDeathDate(); - if (!$bDate->isOK()) return; - - if (file_exists(WT_Site::preference('INDEX_DIRECTORY').'histo.'.WT_LOCALE.'.php')) { - require WT_Site::preference('INDEX_DIRECTORY').'histo.'.WT_LOCALE.'.php'; - foreach ($histo as $indexval=>$hrec) { - $sdate=new WT_Date(get_gedcom_value('DATE', 2, $hrec)); - if ($sdate->isOK() && WT_Date::Compare($this->getEstimatedBirthDate(), $sdate)<=0 && WT_Date::Compare($sdate, $this->getEstimatedDeathDate())<=0) { - $event = new WT_Event($hrec, null, -1); - $this->indifacts[] = $event; - } - } - } - } - /** - * add events where pid is an ASSOciate - * - * @return records added to indifacts array - * - */ - function add_asso_facts() { - $associates=array_merge( - fetch_linked_indi($this->getXref(), 'ASSO', $this->ged_id), - fetch_linked_indi($this->getXref(), '_ASSO', $this->ged_id), - fetch_linked_fam ($this->getXref(), 'ASSO', $this->ged_id), - fetch_linked_fam ($this->getXref(), '_ASSO', $this->ged_id) - ); - foreach ($associates as $associate) { - foreach ($associate->getFacts() as $event) { - $srec = $event->getGedcomRecord(); - foreach (array('ASSO', '_ASSO') as $asso_tag) { - $arec = get_sub_record(2, '2 ' . $asso_tag . ' @' . $this->getXref() . '@', $srec); - if ($arec) { - // Extract the important details from the fact - $factrec='1 '.$event->getTag(); - if (preg_match('/\n2 DATE .*/', $srec, $match)) { - $factrec.=$match[0]; - } - if (preg_match('/\n2 PLAC .*/', $srec, $match)) { - $factrec.=$match[0]; - } - if ($associate instanceof WT_Family) { - foreach ($associate->getSpouses() as $spouse) { - $factrec.="\n2 $asso_tag @".$spouse->getXref().'@'; - } - } else { - $factrec.="\n2 $asso_tag @".$associate->getXref().'@'; - // CHR/BAPM events are commonly used. Generate the reverse relationship - if (preg_match('/^(?:BAPM|CHR)$/', $event->getTag()) && preg_match('/3 RELA god(?:parent|mother|father)/', $event->getGedcomRecord())) { - switch ($associate->getSex()) { - case 'M': - $factrec.="\n3 RELA godson"; - break; - case 'F': - $factrec.="\n3 RELA goddaughter"; - break; - case 'U': - $factrec.="\n3 RELA godchild"; - break; - } - } - } - $this->indifacts[] = new WT_Event($factrec, $associate, 0); - } - } - } - } - } - - /** - * Merge the facts from another Person object into this object - * for generating a diff view - * @param Person $diff the person to compare facts with - */ - function diffMerge($diff) { - if (is_null($diff)) return; - $this->parseFacts(); - $diff->parseFacts(); - //-- loop through new facts and add them to the list if they are any changes - //-- compare new and old facts of the Personal Fact and Details tab 1 - for ($i=0; $i<count($this->indifacts); $i++) { - $found=false; - $oldfactrec = $this->indifacts[$i]->getGedcomRecord(); - foreach ($diff->indifacts as $newfact) { - $newfactrec = $newfact->getGedcomRecord(); - //-- remove all whitespace for comparison - $tnf = preg_replace('/\s+/', ' ', $newfactrec); - $tif = preg_replace('/\s+/', ' ', $oldfactrec); - if ($tnf==$tif) { - $this->indifacts[$i] = $newfact; //-- make sure the correct linenumber is used - $found=true; - break; - } - } - //-- fact was deleted? - if (!$found) { - $this->indifacts[$i]->setIsOld(); - } - } - //-- check for any new facts being added - foreach ($diff->indifacts as $newfact) { - $found=false; - foreach ($this->indifacts as $fact) { - $tif = preg_replace('/\s+/', ' ', $fact->getGedcomRecord()); - $tnf = preg_replace('/\s+/', ' ', $newfact->getGedcomRecord()); - if ($tif==$tnf) { - $found=true; - break; - } - } - if (!$found) { - $newfact->setIsNew(); - $this->indifacts[]=$newfact; - } - } - //-- compare new and old facts of the Notes Sources and Media tab 2 - for ($i=0; $i<count($this->otherfacts); $i++) { - $found=false; - foreach ($diff->otherfacts as $newfact) { - if (trim($newfact->getGedcomRecord())==trim($this->otherfacts[$i]->getGedcomRecord())) { - $this->otherfacts[$i] = $newfact; //-- make sure the correct linenumber is used - $found=true; - break; - } - } - if (!$found) { - $this->otherfacts[$i]->setIsOld(); - } - } - foreach ($diff->otherfacts as $indexval => $newfact) { - $found=false; - foreach ($this->otherfacts as $indexval => $fact) { - if (trim($fact->getGedcomRecord())==trim($newfact->getGedcomRecord())) { - $found=true; - break; - } - } - if (!$found) { - $newfact->setIsNew(); - $this->otherfacts[]=$newfact; - } - } - - //-- compare new and old facts of the Global facts - for ($i=0; $i<count($this->globalfacts); $i++) { - $found=false; - foreach ($diff->globalfacts as $indexval => $newfact) { - if (trim($newfact->getGedcomRecord())==trim($this->globalfacts[$i]->getGedcomRecord())) { - $this->globalfacts[$i] = $newfact; //-- make sure the correct linenumber is used - $found=true; - break; - } - } - if (!$found) { - $this->globalfacts[$i]->setIsOld(); - } - } - foreach ($diff->globalfacts as $indexval => $newfact) { - $found=false; - foreach ($this->globalfacts as $indexval => $fact) { - if (trim($fact->getGedcomRecord())==trim($newfact->getGedcomRecord())) { - $found=true; - break; - } - } - if (!$found) { - $newfact->setIsNew(); - $this->globalfacts[]=$newfact; - } - } - - foreach ($diff->getChildFamilies() as $diff_family) { - $exists=false; - foreach ($this->getChildFamilies() as $family) { - if ($family->equals($diff_family)) { - $exists=true; - break; - } - } - if (!$exists) { - $this->_childFamilies[]=$diff_family; - } - } - - foreach ($diff->getSpouseFamilies() as $diff_family) { - $exists=false; - foreach ($this->getSpouseFamilies() as $family) { - if ($family->equals($diff_family)) { - $exists=true; - break; - } - } - if (!$exists) { - $this->_spouseFamilies[]=$diff_family; - } - } - } /** * get primary parents names for this person @@ -1677,19 +1057,19 @@ class WT_Person extends WT_GedcomRecord { // 1 NAME Carlos /Vasquez y Sante/ // 2 GIVN Carlos // 2 SURN Vasquez,Sante - protected function _addName($type, $full, $gedrec) { + protected function _addName($type, $full, $gedcom) { global $UNKNOWN_NN, $UNKNOWN_PN; //////////////////////////////////////////////////////////////////////////// // Extract the structured name parts - use for "sortable" names and indexes //////////////////////////////////////////////////////////////////////////// - $sublevel=1+(int)$gedrec[0]; - $NPFX=preg_match("/\n{$sublevel} NPFX (.+)/", $gedrec, $match) ? $match[1] : ''; - $GIVN=preg_match("/\n{$sublevel} GIVN (.+)/", $gedrec, $match) ? $match[1] : ''; - $SURN=preg_match("/\n{$sublevel} SURN (.+)/", $gedrec, $match) ? $match[1] : ''; - $NSFX=preg_match("/\n{$sublevel} NSFX (.+)/", $gedrec, $match) ? $match[1] : ''; - $NICK=preg_match("/\n{$sublevel} NICK (.+)/", $gedrec, $match) ? $match[1] : ''; + $sublevel=1+(int)$gedcom[0]; + $NPFX=preg_match("/\n{$sublevel} NPFX (.+)/", $gedcom, $match) ? $match[1] : ''; + $GIVN=preg_match("/\n{$sublevel} GIVN (.+)/", $gedcom, $match) ? $match[1] : ''; + $SURN=preg_match("/\n{$sublevel} SURN (.+)/", $gedcom, $match) ? $match[1] : ''; + $NSFX=preg_match("/\n{$sublevel} NSFX (.+)/", $gedcom, $match) ? $match[1] : ''; + $NICK=preg_match("/\n{$sublevel} NICK (.+)/", $gedcom, $match) ? $match[1] : ''; // SURN is an comma-separated list of surnames... if ($SURN) { @@ -1867,7 +1247,7 @@ class WT_Person extends WT_GedcomRecord { } else { $char = ($bwidth/6.5); } - if ($this->canDisplayName()) { + if ($this->canShowName()) { $tmp=$this->getAllNames(); $givn = $tmp[$this->getPrimaryName()]['givn']; $surn = $tmp[$this->getPrimaryName()]['surname']; diff --git a/library/WT/Media.php b/library/WT/Media.php index e370da631b..23643184df 100644 --- a/library/WT/Media.php +++ b/library/WT/Media.php @@ -30,62 +30,55 @@ if (!defined('WT_WEBTREES')) { class WT_Media extends WT_GedcomRecord { const RECORD_TYPE = 'OBJE'; + const SQL_FETCH = "SELECT m_gedcom FROM `##media` WHERE m_id=? AND m_file=?"; const URL_PREFIX = 'mediaviewer.php?mid='; public $title = null; // TODO: these should be private, with getTitle() and getFilename() functions public $file = null; // Create a Media object from either raw GEDCOM data or a database row - public function __construct($data) { - parent::__construct($data); + public function __construct($xref, $gedcom, $pending, $gedcom_id) { + parent::__construct($xref, $gedcom, $pending, $gedcom_id); - if (is_array($data)) { - // Construct from a row from the database - $this->file =$data['m_filename']; - $this->title=$data['m_titl']; + // TODO get this data from WT_Fact objects + if (preg_match('/\n1 FILE (.+)/', $gedcom.$pending, $match)) { + $this->file = $match[1]; } else { - // Construct from raw GEDCOM data - if (preg_match('/\n1 FILE (.+)/', $data, $match)) { - $this->file = $match[1]; - } else { - $this->file = ''; - } - if (preg_match('/\n\d TITL (.+)/', $data, $match)) { - $this->title = $match[1]; - } else { - $this->title = $this->file; - } + $this->file = ''; + } + if (preg_match('/\n\d TITL (.+)/', $gedcom.$pending, $match)) { + $this->title = $match[1]; + } else { + $this->title = $this->file; } } // Implement media-specific privacy logic ... - protected function _canDisplayDetailsByType($access_level) { + protected function _canShowByType($access_level) { // Hide media objects if they are attached to private records $linked_ids=WT_DB::prepare( "SELECT l_from FROM `##link` WHERE l_to=? AND l_file=?" - )->execute(array($this->xref, $this->ged_id))->fetchOneColumn(); + )->execute(array($this->xref, $this->gedcom_id))->fetchOneColumn(); foreach ($linked_ids as $linked_id) { $linked_record=WT_GedcomRecord::getInstance($linked_id); - if ($linked_record && !$linked_record->canDisplayDetails($access_level)) { + if ($linked_record && !$linked_record->canShow($access_level)) { return false; } } // ... otherwise apply default behaviour - return parent::_canDisplayDetailsByType($access_level); + return parent::_canShowByType($access_level); } // Fetch the record from the database - protected static function fetchGedcomRecord($xref, $ged_id) { + protected static function fetchGedcomRecord($xref, $gedcom_id) { static $statement=null; if ($statement===null) { - $statement=WT_DB::prepare( - "SELECT 'OBJE' AS type, m_id AS xref, m_file AS ged_id, m_gedcom AS gedrec, m_titl, m_filename". - " FROM `##media` WHERE m_id=? AND m_file=?" - ); + $statement=WT_DB::prepare("SELECT m_gedcom FROM `##media` WHERE m_id=? AND m_file=?"); } - return $statement->execute(array($xref, $ged_id))->fetchOneRow(PDO::FETCH_ASSOC); + + return $statement->execute(array($xref, $gedcom_id))->fetchOne(); } /** @@ -93,7 +86,7 @@ class WT_Media extends WT_GedcomRecord { * @return string */ public function getNote() { - return get_gedcom_value('NOTE', 1, $this->getGedcomRecord()); + return get_gedcom_value('NOTE', 1, $this->getGedcom()); } /** @@ -246,13 +239,13 @@ class WT_Media extends WT_GedcomRecord { * @return string */ public function getMediaType() { - $mediaType = strtolower(get_gedcom_value('FORM:TYPE', 2, $this->getGedcomRecord())); + $mediaType = strtolower(get_gedcom_value('FORM:TYPE', 2, $this->getGedcom())); return $mediaType; } // Is this object marked as a highlighted image? public function isPrimary() { - if (preg_match('/\n\d _PRIM ([YN])/', $this->getGedcomRecord(), $match)) { + if (preg_match('/\n\d _PRIM ([YN])/', $this->getGedcom(), $match)) { return $match[1]; } else { return ''; @@ -341,7 +334,7 @@ class WT_Media extends WT_GedcomRecord { $downloadstr = ($download) ? '&dl=1' : ''; return 'mediafirewall.php?mid=' . $this->getXref() . $thumbstr . $downloadstr . - '&ged=' . rawurlencode(get_gedcom_from_id($this->ged_id)) . + '&ged=' . rawurlencode(get_gedcom_from_id($this->gedcom_id)) . '&cb=' . $this->getEtag($which); } @@ -425,7 +418,7 @@ class WT_Media extends WT_GedcomRecord { // If this object has no name, what do we call it? public function getFallBackName() { - if ($this->canDisplayDetails()) { + if ($this->canShow()) { return basename($this->file); } else { return $this->getXref(); @@ -434,7 +427,7 @@ class WT_Media extends WT_GedcomRecord { // Get an array of structures containing all the names in the record public function getAllNames() { - if (strpos($this->getGedcomRecord(), "\n1 TITL ")) { + if (strpos($this->getGedcom(), "\n1 TITL ")) { // Earlier gedcom versions had level 1 titles return parent::_getAllNames('TITL', 1); } else { diff --git a/library/WT/MenuBar.php b/library/WT/MenuBar.php index 1cc5d647b7..0798f4cafc 100644 --- a/library/WT/MenuBar.php +++ b/library/WT/MenuBar.php @@ -2,7 +2,7 @@ // System for generating menus. // // webtrees: Web based Family History software -// Copyright (C) 2012 webtrees development team. +// Copyright (C) 2013 webtrees development team. // // Derived from PhpGedView // Copyright (C) 2002 to 2010 PGV Development Team. All rights reserved. @@ -235,8 +235,8 @@ class WT_MenuBar { // Add a submenu showing relationship from this person to each of our favorites foreach (user_favorites_WT_Module::getFavorites(WT_USER_ID) as $favorite) { if ($favorite['type']=='INDI' && $favorite['gedcom_id']==WT_GED_ID) { - $person=WT_Person::getInstance($favorite['gid']); - if ($person instanceof WT_Person) { + $person=WT_Individual::getInstance($favorite['gid']); + if ($person instanceof WT_Individual) { $subsubmenu = new WT_Menu( $person->getFullName(), 'relationship.php?pid1='.$person->getXref().'&pid2='.$pid2.'&ged='.WT_GEDURL, @@ -517,7 +517,7 @@ class WT_MenuBar { case 'OBJE': case 'NOTE': $obj=WT_GedcomRecord::getInstance($favorite['gid']); - if ($obj && $obj->canDisplayName()) { + if ($obj && $obj->canShowName()) { $submenu=new WT_Menu($obj->getFullName(), $obj->getHtmlUrl()); $menu->addSubMenu($submenu); } diff --git a/library/WT/Note.php b/library/WT/Note.php index 0f1cedafa0..c9524b286f 100644 --- a/library/WT/Note.php +++ b/library/WT/Note.php @@ -30,23 +30,33 @@ if (!defined('WT_WEBTREES')) { class WT_Note extends WT_GedcomRecord { const RECORD_TYPE = 'NOTE'; + const SQL_FETCH = "SELECT o_gedcom FROM `##other` WHERE o_id=? AND o_file=?"; const URL_PREFIX = 'note.php?nid='; + // Get the text contents of the note + public function getNote() { + if (preg_match('/^0 @' . WT_REGEX_TAG . '@ NOTE ?(.*(?:\n1 CONT .*)*)/', $this->gedcom, $match)) { + return str_replace("\n1 CONT ", "\n", $match[1]); + } else { + return null; + } + } + // Implement note-specific privacy logic - protected function _canDisplayDetailsByType($access_level) { + protected function _canShowByType($access_level) { // Hide notes if they are attached to private records $linked_ids=WT_DB::prepare( "SELECT l_from FROM `##link` WHERE l_to=? AND l_file=?" - )->execute(array($this->xref, $this->ged_id))->fetchOneColumn(); + )->execute(array($this->xref, $this->gedcom_id))->fetchOneColumn(); foreach ($linked_ids as $linked_id) { $linked_record=WT_GedcomRecord::getInstance($linked_id); - if ($linked_record && !$linked_record->canDisplayDetails($access_level)) { + if ($linked_record && !$linked_record->canShow($access_level)) { return false; } } // Apply default behaviour - return parent::_canDisplayDetailsByType($access_level); + return parent::_canShowByType($access_level); } // Generate a private version of this record @@ -55,16 +65,14 @@ class WT_Note extends WT_GedcomRecord { } // Fetch the record from the database - protected static function fetchGedcomRecord($xref, $ged_id) { + protected static function fetchGedcomRecord($xref, $gedcom_id) { static $statement=null; if ($statement===null) { - $statement=WT_DB::prepare( - "SELECT o_type AS type, o_id AS xref, o_file AS ged_id, o_gedcom AS gedrec ". - "FROM `##other` WHERE o_id=? AND o_file=? AND o_type='NOTE'" - ); + $statement=WT_DB::prepare("SELECT o_gedcom FROM `##other` WHERE o_id=? AND o_file=? AND o_type='NOTE'"); } - return $statement->execute(array($xref, $ged_id))->fetchOneRow(PDO::FETCH_ASSOC); + + return $statement->execute(array($xref, $gedcom_id))->fetchOne(); } // The 'name' of a note record is the first line. This can be diff --git a/library/WT/Query/Media.php b/library/WT/Query/Media.php index 91c1b4a91c..241513846d 100644 --- a/library/WT/Query/Media.php +++ b/library/WT/Query/Media.php @@ -67,7 +67,7 @@ class WT_Query_Media { public static function mediaList($folder, $subfolders, $sort, $filter) { // All files in the folder, plus external files $sql = - "SELECT 'OBJE' AS type, m_id AS xref, m_file AS ged_id, m_gedcom AS gedrec, m_titl, m_filename" . + "SELECT m_id AS xref, m_file AS gedcom_id, m_gedcom AS gedcom" . " FROM `##media`" . " WHERE m_file=?"; $args = array( @@ -114,11 +114,11 @@ class WT_Query_Media { throw new Exception('Bad argument (sort=', $sort, ') in WT_Query_Media::mediaList()'); } - $rows = WT_DB::prepare($sql)->execute($args)->fetchAll(PDO::FETCH_ASSOC); + $rows = WT_DB::prepare($sql)->execute($args)->fetchAll(); $list = array(); foreach ($rows as $row) { - $media = WT_Media::getInstance($row); - if ($media->canDisplayDetails()) { + $media = WT_Media::getInstance($row->xref, $row->gedcom_id, $row->gedcom); + if ($media->canShow()) { $list[] = $media; } } diff --git a/library/WT/Query/Name.php b/library/WT/Query/Name.php index 4e04895d48..01a674dbb1 100644 --- a/library/WT/Query/Name.php +++ b/library/WT/Query/Name.php @@ -387,7 +387,7 @@ class WT_Query_Name { // To search for names with no surnames, use $salpha="," public static function individuals($surn, $salpha, $galpha, $marnm, $fams, $ged_id) { $sql= - "SELECT 'INDI' AS type, i_id AS xref, i_file AS ged_id, i_gedcom AS gedrec, n_full ". + "SELECT i_id AS xref, i_file AS gedcom_id, i_gedcom AS gedcom, n_full ". "FROM `##individuals` ". "JOIN `##name` ON (n_id=i_id AND n_file=i_file) ". ($fams ? "JOIN `##link` ON (n_id=l_from AND n_file=l_file AND l_type='FAMS') " : ""). @@ -413,12 +413,12 @@ class WT_Query_Name { $sql.=" ORDER BY CASE n_surn WHEN '@N.N.' THEN 1 ELSE 0 END, n_surn COLLATE '".WT_I18N::$collation."', CASE n_givn WHEN '@P.N.' THEN 1 ELSE 0 END, n_givn COLLATE '".WT_I18N::$collation."'"; $list=array(); - $rows=WT_DB::prepare($sql)->fetchAll(PDO::FETCH_ASSOC); + $rows=WT_DB::prepare($sql)->fetchAll(); foreach ($rows as $row) { - $person=WT_Person::getInstance($row); + $person=WT_Individual::getInstance($row->xref, $row->gedcom_id, $row->gedcom); // The name from the database may be private - check the filtered list... foreach ($person->getAllNames() as $n=>$name) { - if ($name['fullNN']==$row['n_full']) { + if ($name['fullNN']==$row->n_full) { $person->setPrimaryName($n); // We need to clone $person, as we may have multiple references to the // same person in this list, and the "primary name" would otherwise diff --git a/library/WT/Report/Base.php b/library/WT/Report/Base.php index 30e3cd9828..e39b81b338 100644 --- a/library/WT/Report/Base.php +++ b/library/WT/Report/Base.php @@ -458,7 +458,7 @@ class Element { $t = str_replace(array("<br>", " "), array("\n", " "), $t); if (!WT_RNEW) { $t = strip_tags($t); - $t = unhtmlentities($t); + $t = htmlspecialchars_decode($t); } $this->text .= $t; @@ -975,7 +975,7 @@ class Footnote extends Element { $t = str_replace(array("<br>", " "), array("\n", " "), $t); if (!WT_RNEW) { $t = strip_tags($t); - $t = unhtmlentities($t); + $t = htmlspecialchars_decode($t); } $this->text .= $t; return 0; @@ -1669,7 +1669,7 @@ function GedcomSHandler($attrs) { $newgedrec = ""; if (count($tags)<2) { $tmp=WT_GedcomRecord::getInstance($attrs['id']); - $newgedrec=$tmp ? $tmp->getGedcomRecord() : ''; + $newgedrec=$tmp ? $tmp->getGedcom() : ''; } if (empty($newgedrec)) { $tgedrec = $gedrec; @@ -1680,14 +1680,14 @@ function GedcomSHandler($attrs) { $newgedrec = $vars[$match[1]]['gedcom']; } else { $tmp=WT_GedcomRecord::getInstance($match[1]); - $newgedrec=$tmp ? $tmp->getGedcomRecord() : ''; + $newgedrec=$tmp ? $tmp->getGedcom() : ''; } } else { if (preg_match("/@(.+)/", $tag, $match)) { $gmatch = array(); if (preg_match("/\d $match[1] @([^@]+)@/", $tgedrec, $gmatch)) { $tmp=WT_GedcomRecord::getInstance($gmatch[1]); - $newgedrec=$tmp ? $tmp->getGedcomRecord() : ''; + $newgedrec=$tmp ? $tmp->getGedcom() : ''; $tgedrec = $newgedrec; } else { $newgedrec = ""; @@ -1942,7 +1942,7 @@ function GetPersonNameSHandler($attrs) { if (is_null($record)) { return; } - if (!$record->canDisplayName()) { + if (!$record->canShowName()) { $currentElement->addText(WT_I18N::translate('Private')); } else { $name = $record->getFullName(); @@ -2189,12 +2189,7 @@ function RepeatTagEHandler() { // Save original values array_push($parserStack, $parser); $oldgedrec = $gedrec; - // PHP 5.2.3 has a bug with foreach (), so don't use that here, while 5.2.3 is on the market - // while () has the fastest execution speed - $count = count($repeats); - $i = 0; - while ($i < $count) { - $gedrec = $repeats[$i]; + foreach ($repeats as $gedrec) { //-- start the sax parser $repeat_parser = xml_parser_create(); $parser = $repeat_parser; @@ -2211,7 +2206,6 @@ function RepeatTagEHandler() { exit; } xml_parser_free($repeat_parser); - $i++; } // Restore original values $gedrec = $oldgedrec; @@ -2334,28 +2328,21 @@ function FactsSHandler($attrs) { $tag = $vars[$match[1]]['id']; } + $record = WT_GedcomRecord::getInstance($id); if (empty($attrs['diff']) && !empty($id)) { - $record = WT_GedcomRecord::getInstance($id); $facts = $record->getFacts(); - if (!is_array($facts)) { - $facts = array($facts); - } sort_facts($facts); $repeats = array(); $nonfacts=explode(',', $tag); foreach ($facts as $event) { if (!in_array($event->getTag(), $nonfacts)) { - $repeats[]=$event->getGedComRecord(); + $repeats[]=$event->getGedcom(); } } } else { - $record = new WT_GedcomRecord($gedrec); - $oldrecord = WT_GedcomRecord::getInstance($record->getXref()); - $oldrecord->diffMerge($record); - $facts = $oldrecord->getFacts(); - foreach ($facts as $fact) { - if ($fact->getIsNew() && $fact->getTag()<>'CHAN') { - $repeats[]=$fact->getGedcomRecord(); + foreach ($record->getFacts as $fact) { + if ($fact->isNew() && $fact->getTag()<>'CHAN') { + $repeats[]=$fact->getGedcom(); } } } @@ -2604,7 +2591,7 @@ function FootnoteSHandler($attrs) { $id = $match[2]; } $record=WT_GedcomRecord::GetInstance($id); - if ($record && $record->canDisplayDetails()) { + if ($record && $record->canShow()) { array_push($printDataStack, $printData); $printData = true; $style = ""; @@ -2665,7 +2652,7 @@ function AgeAtDeathSHandler() { $id = ""; $match = array(); if (preg_match("/0 @(.+)@/", $gedrec, $match)) { - $person=WT_Person::getInstance($match[1]); + $person=WT_Individual::getInstance($match[1]); // Recorded age $fact_age=get_gedcom_value('AGE', 2, $gedrec); if ($fact_age=='') { @@ -2776,11 +2763,11 @@ function HighlightedImageSHandler($attrs) { if (!empty($attrs['width'])) $width = (int)$attrs['width']; if (!empty($attrs['height'])) $height = (int)$attrs['height']; - $person=WT_Person::getInstance($id); + $person=WT_Individual::getInstance($id); $mediaobject = $person->findHighlightedMedia(); if ($mediaobject) { $attributes=$mediaobject->getImageAttributes('thumb'); - if (in_array($attributes['ext'], array('GIF','JPG','PNG','SWF','PSD','BMP','TIFF','TIFF','JPC','JP2','JPX','JB2','SWC','IFF','WBMP','XBM')) && $mediaobject->canDisplayDetails() && $mediaobject->fileExists('thumb')) { + if (in_array($attributes['ext'], array('GIF','JPG','PNG','SWF','PSD','BMP','TIFF','TIFF','JPC','JP2','JPX','JB2','SWC','IFF','WBMP','XBM')) && $mediaobject->canShow() && $mediaobject->fileExists('thumb')) { if (($width>0) and ($height==0)) { $perc = $width / $attributes['adjW']; $height= round($attributes['adjH']*$perc); @@ -2848,7 +2835,7 @@ function ImageSHandler($attrs) { if (preg_match("/\d OBJE @(.+)@/", $gedrec, $match)) { $mediaobject=WT_Media::getInstance($match[1], WT_GED_ID); $attributes=$mediaobject->getImageAttributes('thumb'); - if (in_array($attributes['ext'], array('GIF','JPG','PNG','SWF','PSD','BMP','TIFF','TIFF','JPC','JP2','JPX','JB2','SWC','IFF','WBMP','XBM')) && $mediaobject->canDisplayDetails() && $mediaobject->fileExists('thumb')) { + if (in_array($attributes['ext'], array('GIF','JPG','PNG','SWF','PSD','BMP','TIFF','TIFF','JPC','JP2','JPX','JB2','SWC','IFF','WBMP','XBM')) && $mediaobject->canShow() && $mediaobject->fileExists('thumb')) { if (($width>0) and ($height==0)) { $perc = $width / $attributes['adjW']; $height= round($attributes['adjH']*$perc); @@ -2972,7 +2959,7 @@ function ListSHandler($attrs) { switch ($listname) { case "pending": $rows=WT_DB::prepare( - "SELECT CASE new_gedcom WHEN '' THEN old_gedcom ELSE new_gedcom END AS gedcom". + "SELECT xref, gedcom_id, CASE new_gedcom WHEN '' THEN old_gedcom ELSE new_gedcom END AS gedcom". " FROM `##change`". " WHERE (xref, change_id) IN (". " SELECT xref, MAX(change_id)". @@ -2983,7 +2970,7 @@ function ListSHandler($attrs) { )->execute(array(WT_GED_ID))->fetchAll(); $list=array(); foreach ($rows as $row) { - $list[]=new WT_GedcomRecord($row->gedcom); + $list[] = WT_GedcomRecord::getInstance($row->xref, $row->gedcom_id, $row->gedcom); } break; case "individual": @@ -2995,7 +2982,7 @@ function ListSHandler($attrs) { foreach ($attrs as $attr=>$value) { if ((strpos($attr, "filter")===0) && $value) { // Substitute global vars - $value=preg_replace('/\$(\w+)/e', '$vars["\\1"]["id"]', $value); + $value=preg_replace_callback('/\$(\w+)/', function($matches) use ($vars) { return $vars[$matches[1]]['id']; }, $value); // Convert the various filters into SQL if (preg_match('/^(\w+):DATE (LTE|GTE) (.+)$/', $value, $match)) { $sql_join[]="JOIN `##dates` AS {$attr} ON ({$attr}.d_file={$sql_col_prefix}file AND {$attr}.d_gid={$sql_col_prefix}id)"; @@ -3171,7 +3158,7 @@ function ListSHandler($attrs) { if ($filters) { foreach ($list as $key=>$record) { foreach ($filters as $filter) { - if (!preg_match("/".$filter."/i", $record->getGedcomRecord())) { + if (!preg_match("/".$filter."/i", $record->getGedcom())) { unset($list[$key]); break; } @@ -3182,7 +3169,7 @@ function ListSHandler($attrs) { $mylist = array(); foreach ($list as $indi) { $key=$indi->getXref(); - $grec=$indi->getGedcomRecord(); + $grec=$indi->getGedcom(); $keep = true; foreach ($filters2 as $filter) { if ($keep) { @@ -3247,10 +3234,10 @@ function ListSHandler($attrs) { uasort($list, array("WT_GedcomRecord", "CompareChanDate")); break; case "BIRT:DATE": - uasort($list, array("WT_Person", "CompareBirtDate")); + uasort($list, array("WT_Individual", "CompareBirtDate")); break; case "DEAT:DATE": - uasort($list, array("WT_Person", "CompareDeatDate")); + uasort($list, array("WT_Individual", "CompareDeatDate")); break; case "MARR:DATE": uasort($list, array("WT_Family", "CompareMarrDate")); @@ -3315,8 +3302,8 @@ function ListEHandler() { $list_total = count($list); $list_private = 0; foreach ($list as $record) { - if ($record->canDisplayDetails()) { - $gedrec = $record->getGedcomRecord(); + if ($record->canShow()) { + $gedrec = $record->getGedcom(); //-- start the sax parser $repeat_parser = xml_parser_create(); $parser = $repeat_parser; @@ -3411,7 +3398,7 @@ function RelativesSHandler($attrs) { } $list = array(); - $person = WT_Person::getInstance($id); + $person = WT_Individual::getInstance($id); if (!empty($person)) { $list[$id] = $person; switch ($group) { @@ -3558,7 +3545,7 @@ function RelativesEHandler() { continue; // key can be something like "empty7" } $tmp=WT_GedcomRecord::getInstance($key); - $gedrec = $tmp->getGedcomRecord(); + $gedrec = $tmp->getGedcom(); //-- start the sax parser $repeat_parser = xml_parser_create(); $parser = $repeat_parser; diff --git a/library/WT/Repository.php b/library/WT/Repository.php index c104238a68..e1e6fefd17 100644 --- a/library/WT/Repository.php +++ b/library/WT/Repository.php @@ -30,19 +30,18 @@ if (!defined('WT_WEBTREES')) { class WT_Repository extends WT_GedcomRecord { const RECORD_TYPE = 'REPO'; + const SQL_FETCH = "SELECT o_gedcom FROM `##other` WHERE o_id=? AND o_file=?"; const URL_PREFIX = 'repo.php?rid='; // Fetch the record from the database - protected static function fetchGedcomRecord($xref, $ged_id) { + protected static function fetchGedcomRecord($xref, $gedcom_id) { static $statement=null; if ($statement===null) { - $statement=WT_DB::prepare( - "SELECT o_type AS type, o_id AS xref, o_file AS ged_id, o_gedcom AS gedrec ". - "FROM `##other` WHERE o_id=? AND o_file=?" - ); + $statement=WT_DB::prepare("SELECT o_gedcom FROM `##other` WHERE o_id=? AND o_file=?"); } - return $statement->execute(array($xref, $ged_id))->fetchOneRow(PDO::FETCH_ASSOC); + + return $statement->execute(array($xref, $gedcom_id))->fetchOne(); } // Generate a private version of this record diff --git a/library/WT/Source.php b/library/WT/Source.php index 3664e4af69..67c42c7793 100644 --- a/library/WT/Source.php +++ b/library/WT/Source.php @@ -30,21 +30,22 @@ if (!defined('WT_WEBTREES')) { class WT_Source extends WT_GedcomRecord { const RECORD_TYPE = 'SOUR'; + const SQL_FETCH = "SELECT s_gedcom FROM `##sources` WHERE s_id=? AND s_file=?"; const URL_PREFIX = 'source.php?sid='; // Implement source-specific privacy logic - protected function _canDisplayDetailsByType($access_level) { + protected function _canShowByType($access_level) { // Hide sources if they are attached to private repositories ... - preg_match_all('/\n1 REPO @(.+)@/', $this->_gedrec, $matches); + preg_match_all('/\n1 REPO @(.+)@/', $this->gedcom, $matches); foreach ($matches[1] as $match) { $repo=WT_Repository::getInstance($match); - if ($repo && !$repo->canDisplayDetails($access_level)) { + if ($repo && !$repo->canShow($access_level)) { return false; } } // ... otherwise apply default behaviour - return parent::_canDisplayDetailsByType($access_level); + return parent::_canShowByType($access_level); } // Generate a private version of this record @@ -53,20 +54,18 @@ class WT_Source extends WT_GedcomRecord { } // Fetch the record from the database - protected static function fetchGedcomRecord($xref, $ged_id) { + protected static function fetchGedcomRecord($xref, $gedcom_id) { static $statement=null; if ($statement===null) { - $statement=WT_DB::prepare( - "SELECT 'SOUR' AS type, s_id AS xref, s_file AS ged_id, s_gedcom AS gedrec ". - "FROM `##sources` WHERE s_id=? AND s_file=?" - ); + $statement=WT_DB::prepare("SELECT s_gedcom FROM `##sources` WHERE s_id=? AND s_file=?"); } - return $statement->execute(array($xref, $ged_id))->fetchOneRow(PDO::FETCH_ASSOC); + + return $statement->execute(array($xref, $gedcom_id))->fetchOne(); } public function getAuth() { - return get_gedcom_value('AUTH', 1, $this->getGedcomRecord()); + return get_gedcom_value('AUTH', 1, $this->getGedcom()); } // Get an array of structures containing all the names in the record diff --git a/library/WT/Stats.php b/library/WT/Stats.php index 3f538e1651..43bae5f13d 100644 --- a/library/WT/Stats.php +++ b/library/WT/Stats.php @@ -254,7 +254,7 @@ class WT_Stats { } function gedcomRootID() { - $root = WT_Person::getInstance(get_gedcom_setting(WT_GED_ID, 'PEDIGREE_ROOT_ID')); + $root = WT_Individual::getInstance(get_gedcom_setting(WT_GED_ID, 'PEDIGREE_ROOT_ID')); $root = substr($root, 0, stripos($root, "@") ); return $root; } @@ -842,7 +842,7 @@ class WT_Stats { switch($type) { default: case 'full': - if ($record->canDisplayDetails()) { + if ($record->canShow()) { $result=$record->format_list('span', false, $record->getFullName()); } else { $result=WT_I18N::translate('This information is private and cannot be shown.'); @@ -996,7 +996,7 @@ class WT_Stats { $surn_countries=array(); $indis = WT_Query_Name::individuals(utf8_strtoupper($surname), '', '', false, false, WT_GED_ID); foreach ($indis as $person) { - if (preg_match_all('/^2 PLAC (?:.*, *)*(.*)/m', $person->getGedcomRecord(), $matches)) { + if (preg_match_all('/^2 PLAC (?:.*, *)*(.*)/m', $person->getGedcom(), $matches)) { // webtrees uses 3 letter country codes and localised country names, but google uses 2 letter codes. foreach ($matches[1] as $country) { $country=trim($country); @@ -1377,11 +1377,11 @@ class WT_Stats { ); if (!isset($rows[0])) {return '';} $row = $rows[0]; - $person=WT_Person::getInstance($row['id']); + $person=WT_Individual::getInstance($row['id']); switch($type) { default: case 'full': - if ($person->canDisplayName()) { + if ($person->canShowName()) { $result=$person->format_list('span', false, $person->getFullName()); } else { $result= WT_I18N::translate('This information is private and cannot be shown.'); @@ -1435,7 +1435,7 @@ class WT_Stats { if (!isset($rows[0])) {return '';} $top10 = array(); foreach ($rows as $row) { - $person = WT_Person::getInstance($row['deathdate']); + $person = WT_Individual::getInstance($row['deathdate']); $age = $row['age']; if ((int)($age/365.25)>0) { $age = (int)($age/365.25).'y'; @@ -1445,7 +1445,7 @@ class WT_Stats { $age = $age.'d'; } $age = get_age_at_event($age, true); - if ($person->canDisplayDetails()) { + if ($person->canShow()) { if ($type == 'list') { $top10[]="<li><a href=\"".$person->getHtmlUrl()."\">".$person->getFullName()."</a> (".$age.")"."</li>"; } else { @@ -1502,7 +1502,7 @@ class WT_Stats { if (!isset($rows)) {return 0;} $top10 = array(); foreach ($rows as $row) { - $person=WT_Person::getInstance($row['id']); + $person=WT_Individual::getInstance($row['id']); $age = (WT_CLIENT_JD-$row['age']); if ((int)($age/365.25)>0) { $age = (int)($age/365.25).'y'; @@ -1776,7 +1776,7 @@ class WT_Stats { switch($type) { default: case 'full': - if ($record->canDisplayDetails()) { + if ($record->canShow()) { $result=$record->format_list('span', false, $record->getFullName()); } else { $result=WT_I18N::translate('This information is private and cannot be shown.'); @@ -1871,11 +1871,11 @@ class WT_Stats { if (!isset($rows[0])) {return '';} $row=$rows[0]; if (isset($row['famid'])) $family=WT_Family::getInstance($row['famid']); - if (isset($row['i_id'])) $person=WT_Person::getInstance($row['i_id']); + if (isset($row['i_id'])) $person=WT_Individual::getInstance($row['i_id']); switch($type) { default: case 'full': - if ($family->canDisplayDetails()) { + if ($family->canShow()) { $result=$family->format_list('span', false, $person->getFullName()); } else { $result=WT_I18N::translate('This information is private and cannot be shown.'); @@ -1990,7 +1990,7 @@ class WT_Stats { $husb = $family->getHusband(); $wife = $family->getWife(); if (($husb->getAllDeathDates() && $wife->getAllDeathDates()) || !$husb->isDead() || !$wife->isDead()) { - if ($family->canDisplayDetails()) { + if ($family->canShow()) { if ($type == 'list') { $top10[] = "<li><a href=\"".$family->getHtmlUrl()."\">".$family->getFullName()."</a> (".$age.")"."</li>"; } else { @@ -2054,7 +2054,7 @@ class WT_Stats { $age = $age.'d'; } $age = get_age_at_event($age, true); - if ($family->canDisplayDetails()) { + if ($family->canShow()) { if ($type == 'list') { $top10[] = "<li><a href=\"".$family->getHtmlUrl()."\">".$family->getFullName()."</a> (".$age.")"."</li>"; } else { @@ -2102,11 +2102,11 @@ class WT_Stats { ); if (!isset($rows[0])) {return '';} $row=$rows[0]; - if (isset($row['id'])) $person=WT_Person::getInstance($row['id']); + if (isset($row['id'])) $person=WT_Individual::getInstance($row['id']); switch($type) { default: case 'full': - if ($person->canDisplayDetails()) { + if ($person->canShow()) { $result=$person->format_list('span', false, $person->getFullName()); } else { $result=WT_I18N::translate('This information is private and cannot be shown.'); @@ -2523,7 +2523,7 @@ class WT_Stats { switch($type) { default: case 'full': - if ($family->canDisplayDetails()) { + if ($family->canShow()) { $result=$family->format_list('span', false, $family->getFullName()); } else { $result = WT_I18N::translate('This information is private and cannot be shown.'); @@ -2556,7 +2556,7 @@ class WT_Stats { $top10 = array(); for ($c = 0; $c < $total; $c++) { $family=WT_Family::getInstance($rows[$c]['id']); - if ($family->canDisplayDetails()) { + if ($family->canShow()) { if ($type == 'list') { $top10[]= '<li><a href="'.$family->getHtmlUrl().'">'.$family->getFullName().'</a> - '. @@ -2618,10 +2618,10 @@ class WT_Stats { if ($one) $dist = array(); foreach ($rows as $fam) { $family = WT_Family::getInstance($fam['family']); - $child1 = WT_Person::getInstance($fam['ch1']); - $child2 = WT_Person::getInstance($fam['ch2']); + $child1 = WT_Individual::getInstance($fam['ch1']); + $child2 = WT_Individual::getInstance($fam['ch2']); if ($type == 'name') { - if ($child1->canDisplayDetails() && $child2->canDisplayDetails()) { + if ($child1->canShow() && $child2->canShow()) { $return = '<a href="'.$child2->getHtmlUrl().'">'.$child2->getFullName().'</a> '; $return .= WT_I18N::translate('and').' '; $return .= '<a href="'.$child1->getHtmlUrl().'">'.$child1->getFullName().'</a>'; @@ -2645,7 +2645,7 @@ class WT_Stats { } if ($type == 'list') { if ($one && !in_array($fam['family'], $dist)) { - if ($child1->canDisplayDetails() && $child2->canDisplayDetails()) { + if ($child1->canShow() && $child2->canShow()) { $return = "<li>"; $return .= "<a href=\"".$child2->getHtmlUrl()."\">".$child2->getFullName()."</a> "; $return .= WT_I18N::translate('and')." "; @@ -2656,7 +2656,7 @@ class WT_Stats { $top10[] = $return; $dist[] = $fam['family']; } - } else if (!$one && $child1->canDisplayDetails() && $child2->canDisplayDetails()) { + } else if (!$one && $child1->canShow() && $child2->canShow()) { $return = "<li>"; $return .= "<a href=\"".$child2->getHtmlUrl()."\">".$child2->getFullName()."</a> "; $return .= WT_I18N::translate('and')." "; @@ -2667,7 +2667,7 @@ class WT_Stats { $top10[] = $return; } } else { - if ($child1->canDisplayDetails() && $child2->canDisplayDetails()) { + if ($child1->canShow() && $child2->canShow()) { $return = $child2->format_list('span', false, $child2->getFullName()); $return .= "<br>".WT_I18N::translate('and')."<br>"; $return .= $child1->format_list('span', false, $child1->getFullName()); @@ -2830,14 +2830,14 @@ class WT_Stats { $chl = array(); foreach ($rows as $row) { $family=WT_Family::getInstance($row['id']); - if ($family->canDisplayDetails()) { + if ($family->canShow()) { if ($tot==0) { $per = 0; } else { $per = round(100 * $row['tot'] / $tot, 0); } $chd .= self::_array_to_extended_encoding(array($per)); - $chl[] = strip_tags(unhtmlentities($family->getFullName())).' - '.WT_I18N::number($row['tot']); + $chl[] = htmlspecialchars_decode(strip_tags($family->getFullName())).' - '.WT_I18N::number($row['tot']); } } $chl = rawurlencode(join('|', $chl)); @@ -2968,7 +2968,7 @@ class WT_Stats { $top10 = array(); foreach ($rows as $row) { $family=WT_Family::getInstance($row['family']); - if ($family->canDisplayDetails()) { + if ($family->canShow()) { if ($type == 'list') { $top10[] = "<li><a href=\"".$family->getHtmlUrl()."\">".$family->getFullName()."</a></li>"; } else { @@ -3085,7 +3085,7 @@ class WT_Stats { $top10 = array(); foreach ($rows as $row) { $family=WT_Family::getInstance($row['id']); - if ($family->canDisplayDetails()) { + if ($family->canShow()) { if ($type == 'list') { $top10[]= '<li><a href="'.$family->getHtmlUrl().'">'.$family->getFullName().'</a> - '. |
