husb = WT_Individual::getInstance($match[1]); } if (!$this->husb) { $this->husb = new WT_Individual('M', '0 @M@ INDI', null, $gedcom_id); } if (preg_match('/^1 WIFE @(.+)@/m', $gedcom.$pending, $match)) { $this->wife = WT_Individual::getInstance($match[1]); } if (!$this->wife) { $this->wife = new WT_Individual('F', '0 @F@ INDI', null, $gedcom_id); } // Make sure husb/wife are the right way round. if ($this->husb->getSex()=='F' || $this->wife->getSex()=='M') { list($this->husb, $this->wife) = array($this->wife, $this->husb); } } // Generate a private version of this record protected function createPrivateGedcomRecord($access_level) { global $SHOW_PRIVATE_RELATIONSHIPS; $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->gedcom, $matches, PREG_SET_ORDER); foreach ($matches as $match) { $rela=WT_Individual::getInstance($match[1]); if ($rela && ($SHOW_PRIVATE_RELATIONSHIPS || $rela->canShow($access_level))) { $rec.=$match[0]; } } return $rec; } // Fetch the record from the database protected static function fetchGedcomRecord($xref, $gedcom_id) { static $statement=null; if ($statement===null) { $statement=WT_DB::prepare("SELECT f_gedcom FROM `##families` WHERE f_id=? AND f_file=?"); } return $statement->execute(array($xref, $gedcom_id))->fetchOne(); } /** * get the husband's person object * @return Person */ function getHusband() { return $this->husb; } /** * get the wife's person object * @return Person */ function getWife() { return $this->wife; } // Implement family-specific privacy logic protected function _canShowByType($access_level) { // Hide a family if any member is private preg_match_all('/\n1 (?:CHIL|HUSB|WIFE) @('.WT_REGEX_XREF.')@/', $this->gedcom, $matches); foreach ($matches[1] as $match) { $person=WT_Individual::getInstance($match); if ($person && !$person->canShow($access_level)) { return false; } } return true; } // Can the name of this record be shown? 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; } // Find the spouse of a person - or create a dummy person if this family // record is missing one of the spouses. function getSpouse(WT_Individual $person, $access_level=WT_USER_ACCESS_LEVEL) { if ($person->equals($this->getWife())) { return $this->getHusband(); } else { return $this->getWife(); } } function getSpouses($access_level=WT_USER_ACCESS_LEVEL) { return array($this->husb, $this->wife); } /** * get the children * @return array array of children Persons */ function getChildren($access_level=WT_USER_ACCESS_LEVEL) { global $SHOW_PRIVATE_RELATIONSHIPS; $children=array(); preg_match_all('/\n1 CHIL @('.WT_REGEX_XREF.')@/', $this->gedcom, $match); foreach ($match[1] as $pid) { $child=WT_Individual::getInstance($pid); if ($child && ($SHOW_PRIVATE_RELATIONSHIPS || $child->canShow($access_level))) { $children[]=$child; } } return $children; } // Static helper function to sort an array of families by marriage date static function CompareMarrDate($x, $y) { return WT_Date::Compare($x->getMarriageDate(), $y->getMarriageDate()); } // Number of children - for the individual list function getNumberOfChildren() { $nchi = count($this->getChildren()); foreach ($this->getFacts('NCHI') as $fact) { $nchi = max($nchi, (int)$fact->getValue()); } return $nchi; } /** * get the marriage event * * @return WT_Fact */ function getMarriage() { return $this->getFactByType('MARR'); } // 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->gedcom); } function isNotMarried() { return (bool)preg_match('/\n1 _NMR( Y|\n)/', $this->gedcom); } /** * get marriage date * @return string */ function getMarriageDate() { $marriage = $this->getMarriage(); if ($marriage && $marriage->canShow()) { return $marriage->getDate(); } else { return new WT_Date(''); } } // Get the marriage year - displayed on lists of families function getMarriageYear() { return $this->getMarriageDate()->MinDate()->y; } /** * get the type for this marriage * @return string */ function getMarriageType() { $marriage = $this->getMarriage(); if ($marriage && $marriage->canShow()) { return $marriage->getAttribute('TYPE'); } else { return null; } } /** * get the marriage place * @return string */ function getMarriagePlace() { $marriage = $this->getMarriage(); return $marriage->getPlace(); } // Get all the dates/places for marriages - for the FAM lists function getAllMarriageDates() { if ($this->canShow()) { foreach (explode('|', WT_EVENTS_MARR) as $event) { if ($array=$this->getAllEventDates($event)) { return $array; } } } return array(); } function getAllMarriagePlaces() { if ($this->canShow()) { foreach (explode('|', WT_EVENTS_MARR) as $event) { if ($array=$this->getAllEventPlaces($event)) { return $array; } } } return array(); } // Get an array of structures containing all the names in the record public function getAllNames() { if (is_null($this->_getAllNames)) { // Check the script used by each name, so we can match cyrillic with cyrillic, greek with greek, etc. $husb_names=$this->husb->getAllNames(); foreach ($husb_names as $n=>$husb_name) { $husb_names[$n]['script']=utf8_script($husb_name['full']); } $wife_names=$this->wife->getAllNames(); foreach ($wife_names as $n=>$wife_name) { $wife_names[$n]['script']=utf8_script($wife_name['full']); } // Add the matched names first foreach ($husb_names as $husb_name) { foreach ($wife_names as $wife_name) { if ($husb_name['type']!='_MARNM' && $wife_name['type']!='_MARNM' && $husb_name['script']==$wife_name['script']) { $this->_getAllNames[]=array( 'type'=>$husb_name['type'], 'sort'=>$husb_name['sort'].' + '.$wife_name['sort'], 'full'=>$husb_name['full'].' + '.$wife_name['full'], // No need for a fullNN entry - we do not currently store FAM names in the database ); } } } // Add the unmatched names second (there may be no matched names) foreach ($husb_names as $husb_name) { foreach ($wife_names as $wife_name) { if ($husb_name['type']!='_MARNM' && $wife_name['type']!='_MARNM' && $husb_name['script']!=$wife_name['script']) { $this->_getAllNames[]=array( 'type'=>$husb_name['type'], 'sort'=>$husb_name['sort'].' + '.$wife_name['sort'], 'full'=>$husb_name['full'].' + '.$wife_name['full'], // No need for a fullNN entry - we do not currently store FAM names in the database ); } } } } return $this->_getAllNames; } // Extra info to display when displaying this record in a list of // selection items or favorites. function format_list_details() { return $this->format_first_major_fact(WT_EVENTS_MARR, 1). $this->format_first_major_fact(WT_EVENTS_DIV, 1); } }