diff options
Diffstat (limited to 'app/Family.php')
| -rw-r--r-- | app/Family.php | 763 |
1 files changed, 394 insertions, 369 deletions
diff --git a/app/Family.php b/app/Family.php index f584b699b5..b9d12a2c2e 100644 --- a/app/Family.php +++ b/app/Family.php @@ -18,416 +18,441 @@ namespace Fisharebest\Webtrees; /** * A GEDCOM family (FAM) object. */ -class Family extends GedcomRecord { - const RECORD_TYPE = 'FAM'; - const ROUTE_NAME = 'family'; +class Family extends GedcomRecord +{ + const RECORD_TYPE = 'FAM'; + const ROUTE_NAME = 'family'; - /** @var Individual|null The husband (or first spouse for same-sex couples) */ - private $husb; + /** @var Individual|null The husband (or first spouse for same-sex couples) */ + private $husb; - /** @var Individual|null The wife (or second spouse for same-sex couples) */ - private $wife; + /** @var Individual|null The wife (or second spouse for same-sex couples) */ + private $wife; - /** - * Create a GedcomRecord object from raw GEDCOM data. - * - * @param string $xref - * @param string $gedcom an empty string for new/pending records - * @param string|null $pending null for a record with no pending edits, - * empty string for records with pending deletions - * @param Tree $tree - */ - public function __construct($xref, $gedcom, $pending, $tree) { - parent::__construct($xref, $gedcom, $pending, $tree); + /** + * Create a GedcomRecord object from raw GEDCOM data. + * + * @param string $xref + * @param string $gedcom an empty string for new/pending records + * @param string|null $pending null for a record with no pending edits, + * empty string for records with pending deletions + * @param Tree $tree + */ + public function __construct($xref, $gedcom, $pending, $tree) + { + parent::__construct($xref, $gedcom, $pending, $tree); - // Fetch family members - if (preg_match_all('/^1 (?:HUSB|WIFE|CHIL) @(.+)@/m', $gedcom . $pending, $match)) { - Individual::load($tree, $match[1]); - } + // Fetch family members + if (preg_match_all('/^1 (?:HUSB|WIFE|CHIL) @(.+)@/m', $gedcom . $pending, $match)) { + Individual::load($tree, $match[1]); + } - if (preg_match('/^1 HUSB @(.+)@/m', $gedcom . $pending, $match)) { - $this->husb = Individual::getInstance($match[1], $tree); - } - if (preg_match('/^1 WIFE @(.+)@/m', $gedcom . $pending, $match)) { - $this->wife = Individual::getInstance($match[1], $tree); - } + if (preg_match('/^1 HUSB @(.+)@/m', $gedcom . $pending, $match)) { + $this->husb = Individual::getInstance($match[1], $tree); + } + if (preg_match('/^1 WIFE @(.+)@/m', $gedcom . $pending, $match)) { + $this->wife = Individual::getInstance($match[1], $tree); + } - // Make sure husb/wife are the right way round. - if ($this->husb && $this->husb->getSex() === 'F' || $this->wife && $this->wife->getSex() === 'M') { - list($this->husb, $this->wife) = [$this->wife, $this->husb]; - } - } + // Make sure husb/wife are the right way round. + if ($this->husb && $this->husb->getSex() === 'F' || $this->wife && $this->wife->getSex() === 'M') { + list($this->husb, $this->wife) = [ + $this->wife, + $this->husb, + ]; + } + } - /** - * Get an instance of a family 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. - * - * @param string $xref - * @param Tree $tree - * @param string|null $gedcom - * - * @throws \Exception - * - * @return Family|null - */ - public static function getInstance($xref, Tree $tree, $gedcom = null) { - $record = parent::getInstance($xref, $tree, $gedcom); + /** + * Get an instance of a family 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. + * + * @param string $xref + * @param Tree $tree + * @param string|null $gedcom + * + * @throws \Exception + * + * @return Family|null + */ + public static function getInstance($xref, Tree $tree, $gedcom = null) + { + $record = parent::getInstance($xref, $tree, $gedcom); - if ($record instanceof Family) { - return $record; - } else { - return null; - } - } + if ($record instanceof Family) { + return $record; + } else { + return null; + } + } - /** - * Generate a private version of this record - * - * @param int $access_level - * - * @return string - */ - protected function createPrivateGedcomRecord($access_level) { - $SHOW_PRIVATE_RELATIONSHIPS = $this->tree->getPreference('SHOW_PRIVATE_RELATIONSHIPS'); + /** + * Generate a private version of this record + * + * @param int $access_level + * + * @return string + */ + protected function createPrivateGedcomRecord($access_level) + { + $SHOW_PRIVATE_RELATIONSHIPS = $this->tree->getPreference('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 = Individual::getInstance($match[1], $this->tree); - if ($rela && ($SHOW_PRIVATE_RELATIONSHIPS || $rela->canShow($access_level))) { - $rec .= $match[0]; - } - } + $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 = Individual::getInstance($match[1], $this->tree); + if ($rela && ($SHOW_PRIVATE_RELATIONSHIPS || $rela->canShow($access_level))) { + $rec .= $match[0]; + } + } - return $rec; - } + return $rec; + } - /** - * Fetch data from the database - * - * @param string $xref - * @param int $tree_id - * - * @return null|string - */ - protected static function fetchGedcomRecord($xref, $tree_id) { - return Database::prepare( - "SELECT f_gedcom FROM `##families` WHERE f_id = :xref AND f_file = :tree_id" - )->execute([ - 'xref' => $xref, - 'tree_id' => $tree_id, - ])->fetchOne(); - } + /** + * Fetch data from the database + * + * @param string $xref + * @param int $tree_id + * + * @return null|string + */ + protected static function fetchGedcomRecord($xref, $tree_id) + { + return Database::prepare( + "SELECT f_gedcom FROM `##families` WHERE f_id = :xref AND f_file = :tree_id" + )->execute([ + 'xref' => $xref, + 'tree_id' => $tree_id, + ])->fetchOne(); + } - /** - * Get the male (or first female) partner of the family - * - * @param $access_level int|null - * - * @return Individual|null - */ - public function getHusband($access_level = null) { - $SHOW_PRIVATE_RELATIONSHIPS = $this->tree->getPreference('SHOW_PRIVATE_RELATIONSHIPS'); + /** + * Get the male (or first female) partner of the family + * + * @param $access_level int|null + * + * @return Individual|null + */ + public function getHusband($access_level = null) + { + $SHOW_PRIVATE_RELATIONSHIPS = $this->tree->getPreference('SHOW_PRIVATE_RELATIONSHIPS'); - if ($this->husb && ($SHOW_PRIVATE_RELATIONSHIPS || $this->husb->canShowName($access_level))) { - return $this->husb; - } else { - return null; - } - } + if ($this->husb && ($SHOW_PRIVATE_RELATIONSHIPS || $this->husb->canShowName($access_level))) { + return $this->husb; + } else { + return null; + } + } - /** - * Get the female (or second male) partner of the family - * - * @param $access_level int|null - * - * @return Individual|null - */ - public function getWife($access_level = null) { - $SHOW_PRIVATE_RELATIONSHIPS = $this->tree->getPreference('SHOW_PRIVATE_RELATIONSHIPS'); + /** + * Get the female (or second male) partner of the family + * + * @param $access_level int|null + * + * @return Individual|null + */ + public function getWife($access_level = null) + { + $SHOW_PRIVATE_RELATIONSHIPS = $this->tree->getPreference('SHOW_PRIVATE_RELATIONSHIPS'); - if ($this->wife && ($SHOW_PRIVATE_RELATIONSHIPS || $this->wife->canShowName($access_level))) { - return $this->wife; - } else { - return null; - } - } + if ($this->wife && ($SHOW_PRIVATE_RELATIONSHIPS || $this->wife->canShowName($access_level))) { + return $this->wife; + } else { + return null; + } + } - /** - * Each object type may have its own special rules, and re-implement this function. - * - * @param int $access_level - * - * @return bool - */ - 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 = Individual::getInstance($match, $this->tree); - if ($person && !$person->canShow($access_level)) { - return false; - } - } + /** + * Each object type may have its own special rules, and re-implement this function. + * + * @param int $access_level + * + * @return bool + */ + 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 = Individual::getInstance($match, $this->tree); + if ($person && !$person->canShow($access_level)) { + return false; + } + } - return true; - } + return true; + } - /** - * Can the name of this record be shown? - * - * @param int|null $access_level - * - * @return bool - */ - public function canShowName($access_level = null) { - // We can always see the name (Husband-name + Wife-name), however, - // the name will often be "private + private" - return true; - } + /** + * Can the name of this record be shown? + * + * @param int|null $access_level + * + * @return bool + */ + public function canShowName($access_level = null) + { + // 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. - * - * @param Individual $person - * @param int|null $access_level - * - * @return Individual|null - */ - public function getSpouse(Individual $person, $access_level = null) { - if ($person === $this->wife) { - return $this->getHusband($access_level); - } else { - return $this->getWife($access_level); - } - } + /** + * Find the spouse of a person. + * + * @param Individual $person + * @param int|null $access_level + * + * @return Individual|null + */ + public function getSpouse(Individual $person, $access_level = null) + { + if ($person === $this->wife) { + return $this->getHusband($access_level); + } else { + return $this->getWife($access_level); + } + } - /** - * Get the (zero, one or two) spouses from this family. - * - * @param int|null $access_level - * - * @return Individual[] - */ - public function getSpouses($access_level = null) { - return array_filter([ - $this->getHusband($access_level), - $this->getWife($access_level), - ]); - } + /** + * Get the (zero, one or two) spouses from this family. + * + * @param int|null $access_level + * + * @return Individual[] + */ + public function getSpouses($access_level = null) + { + return array_filter([ + $this->getHusband($access_level), + $this->getWife($access_level), + ]); + } - /** - * Get a list of this family’s children. - * - * @param int|null $access_level - * - * @return Individual[] - */ - public function getChildren($access_level = null) { - if ($access_level === null) { - $access_level = Auth::accessLevel($this->tree); - } + /** + * Get a list of this family’s children. + * + * @param int|null $access_level + * + * @return Individual[] + */ + public function getChildren($access_level = null) + { + if ($access_level === null) { + $access_level = Auth::accessLevel($this->tree); + } - $SHOW_PRIVATE_RELATIONSHIPS = $this->tree->getPreference('SHOW_PRIVATE_RELATIONSHIPS'); + $SHOW_PRIVATE_RELATIONSHIPS = $this->tree->getPreference('SHOW_PRIVATE_RELATIONSHIPS'); - $children = []; - foreach ($this->getFacts('CHIL', false, $access_level, $SHOW_PRIVATE_RELATIONSHIPS) as $fact) { - $child = $fact->getTarget(); - if ($child && ($SHOW_PRIVATE_RELATIONSHIPS || $child->canShowName($access_level))) { - $children[] = $child; - } - } + $children = []; + foreach ($this->getFacts('CHIL', false, $access_level, $SHOW_PRIVATE_RELATIONSHIPS) as $fact) { + $child = $fact->getTarget(); + if ($child && ($SHOW_PRIVATE_RELATIONSHIPS || $child->canShowName($access_level))) { + $children[] = $child; + } + } - return $children; - } + return $children; + } - /** - * Static helper function to sort an array of families by marriage date - * - * @param Family $x - * @param Family $y - * - * @return int - */ - public static function compareMarrDate(Family $x, Family $y) { - return Date::compare($x->getMarriageDate(), $y->getMarriageDate()); - } + /** + * Static helper function to sort an array of families by marriage date + * + * @param Family $x + * @param Family $y + * + * @return int + */ + public static function compareMarrDate(Family $x, Family $y) + { + return Date::compare($x->getMarriageDate(), $y->getMarriageDate()); + } - /** - * Number of children - for the individual list - * - * @return int - */ - public function getNumberOfChildren() { - $nchi = count($this->getChildren()); - foreach ($this->getFacts('NCHI') as $fact) { - $nchi = max($nchi, (int) $fact->getValue()); - } + /** + * Number of children - for the individual list + * + * @return int + */ + public function getNumberOfChildren() + { + $nchi = count($this->getChildren()); + foreach ($this->getFacts('NCHI') as $fact) { + $nchi = max($nchi, (int)$fact->getValue()); + } - return $nchi; - } + return $nchi; + } - /** - * get the marriage event - * - * @return Fact - */ - public function getMarriage() { - return $this->getFirstFact('MARR'); - } + /** + * get the marriage event + * + * @return Fact + */ + public function getMarriage() + { + return $this->getFirstFact('MARR'); + } - /** - * Get marriage date - * - * @return Date - */ - public function getMarriageDate() { - $marriage = $this->getMarriage(); - if ($marriage) { - return $marriage->getDate(); - } else { - return new Date(''); - } - } + /** + * Get marriage date + * + * @return Date + */ + public function getMarriageDate() + { + $marriage = $this->getMarriage(); + if ($marriage) { + return $marriage->getDate(); + } else { + return new Date(''); + } + } - /** - * Get the marriage year - displayed on lists of families - * - * @return int - */ - public function getMarriageYear() { - return $this->getMarriageDate()->minimumDate()->y; - } + /** + * Get the marriage year - displayed on lists of families + * + * @return int + */ + public function getMarriageYear() + { + return $this->getMarriageDate()->minimumDate()->y; + } - /** - * Get the marriage place - * - * @return Place - */ - public function getMarriagePlace() { - $marriage = $this->getMarriage(); + /** + * Get the marriage place + * + * @return Place + */ + public function getMarriagePlace() + { + $marriage = $this->getMarriage(); - return $marriage->getPlace(); - } + return $marriage->getPlace(); + } - /** - * Get a list of all marriage dates - for the family lists. - * - * @return Date[] - */ - public function getAllMarriageDates() { - foreach (explode('|', WT_EVENTS_MARR) as $event) { - if ($array = $this->getAllEventDates($event)) { - return $array; - } - } + /** + * Get a list of all marriage dates - for the family lists. + * + * @return Date[] + */ + public function getAllMarriageDates() + { + foreach (explode('|', WT_EVENTS_MARR) as $event) { + if ($array = $this->getAllEventDates($event)) { + return $array; + } + } - return []; - } + return []; + } - /** - * Get a list of all marriage places - for the family lists. - * - * @return Place[] - */ - public function getAllMarriagePlaces() { - foreach (explode('|', WT_EVENTS_MARR) as $event) { - $places = $this->getAllEventPlaces($event); - if (!empty($places)) { - return $places; - } - } + /** + * Get a list of all marriage places - for the family lists. + * + * @return Place[] + */ + public function getAllMarriagePlaces() + { + foreach (explode('|', WT_EVENTS_MARR) as $event) { + $places = $this->getAllEventPlaces($event); + if (!empty($places)) { + return $places; + } + } - return []; - } + return []; + } - /** - * Derived classes should redefine this function, otherwise the object will have no name - * - * @return string[][] - */ - 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 = []; - if ($this->husb) { - $husb_names = array_filter($this->husb->getAllNames(), function (array $x) { - return $x['type'] !== '_MARNM'; - } ); - } - // If the individual only has married names, create a dummy birth name. - if (empty($husb_names)) { - $husb_names[] = [ - 'type' => 'BIRT', - 'sort' => '@N.N.', - 'full' => I18N::translateContext('Unknown given name', '…') . ' ' . I18N::translateContext('Unknown surname', '…'), - ]; - } - foreach ($husb_names as $n => $husb_name) { - $husb_names[$n]['script'] = I18N::textScript($husb_name['full']); - } + /** + * Derived classes should redefine this function, otherwise the object will have no name + * + * @return string[][] + */ + 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 = []; + if ($this->husb) { + $husb_names = array_filter($this->husb->getAllNames(), function (array $x) { + return $x['type'] !== '_MARNM'; + }); + } + // If the individual only has married names, create a dummy birth name. + if (empty($husb_names)) { + $husb_names[] = [ + 'type' => 'BIRT', + 'sort' => '@N.N.', + 'full' => I18N::translateContext('Unknown given name', '…') . ' ' . I18N::translateContext('Unknown surname', '…'), + ]; + } + foreach ($husb_names as $n => $husb_name) { + $husb_names[$n]['script'] = I18N::textScript($husb_name['full']); + } - $wife_names = []; - if ($this->wife) { - $wife_names = array_filter($this->wife->getAllNames(), function (array $x) { - return $x['type'] !== '_MARNM'; - } ); - } - // If the individual only has married names, create a dummy birth name. - if (empty($wife_names)) { - $wife_names[] = [ - 'type' => 'BIRT', - 'sort' => '@N.N.', - 'full' => I18N::translateContext('Unknown given name', '…') . ' ' . I18N::translateContext('Unknown surname', '…'), - ]; - } - foreach ($wife_names as $n => $wife_name) { - $wife_names[$n]['script'] = I18N::textScript($wife_name['full']); - } + $wife_names = []; + if ($this->wife) { + $wife_names = array_filter($this->wife->getAllNames(), function (array $x) { + return $x['type'] !== '_MARNM'; + }); + } + // If the individual only has married names, create a dummy birth name. + if (empty($wife_names)) { + $wife_names[] = [ + 'type' => 'BIRT', + 'sort' => '@N.N.', + 'full' => I18N::translateContext('Unknown given name', '…') . ' ' . I18N::translateContext('Unknown surname', '…'), + ]; + } + foreach ($wife_names as $n => $wife_name) { + $wife_names[$n]['script'] = I18N::textScript($wife_name['full']); + } - // Add the matched names first - foreach ($husb_names as $husb_name) { - foreach ($wife_names as $wife_name) { - if ($husb_name['script'] == $wife_name['script']) { - $this->_getAllNames[] = [ - '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 matched names first + foreach ($husb_names as $husb_name) { + foreach ($wife_names as $wife_name) { + if ($husb_name['script'] == $wife_name['script']) { + $this->_getAllNames[] = [ + '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['script'] != $wife_name['script']) { - $this->_getAllNames[] = [ - '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['script'] != $wife_name['script']) { + $this->_getAllNames[] = [ + '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; - } + return $this->_getAllNames; + } - /** - * This function should be redefined in derived classes to show any major - * identifying characteristics of this record. - * - * @return string - */ - public function formatListDetails() { - return - $this->formatFirstMajorFact(WT_EVENTS_MARR, 1) . - $this->formatFirstMajorFact(WT_EVENTS_DIV, 1); - } + /** + * This function should be redefined in derived classes to show any major + * identifying characteristics of this record. + * + * @return string + */ + public function formatListDetails() + { + return + $this->formatFirstMajorFact(WT_EVENTS_MARR, 1) . + $this->formatFirstMajorFact(WT_EVENTS_DIV, 1); + } } |
