summaryrefslogtreecommitdiff
path: root/library/WT/Family.php
diff options
context:
space:
mode:
Diffstat (limited to 'library/WT/Family.php')
-rw-r--r--library/WT/Family.php430
1 files changed, 430 insertions, 0 deletions
diff --git a/library/WT/Family.php b/library/WT/Family.php
new file mode 100644
index 0000000000..f64034be22
--- /dev/null
+++ b/library/WT/Family.php
@@ -0,0 +1,430 @@
+<?php
+/**
+ * Class file for a Family
+ *
+ * webtrees: Web based Family History software
+ * Copyright (C) 2010 webtrees development team.
+ *
+ * Derived from PhpGedView
+ * Copyright (C) 2002 to 2009 PGV Development Team. All rights reserved.
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * @package webtrees
+ * @subpackage DataModel
+ * @version $Id$
+ */
+
+if (!defined('WT_WEBTREES')) {
+ header('HTTP/1.0 403 Forbidden');
+ exit;
+}
+
+define('WT_WT_FAMILY_PHP', '');
+
+class WT_Family extends WT_GedcomRecord {
+ private $husb = null;
+ private $wife = null;
+ private $children = array();
+ private $childrenIds = array();
+ private $marriage = null;
+ private $children_loaded = false;
+ private $numChildren = false;
+ private $_isDivorced = null;
+ private $_isNotMarried = 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 ($data['f_husb']) {
+ $this->husb=WT_Person::getInstance($data['f_husb']);
+ }
+ if ($data['f_wife']) {
+ $this->wife=WT_Person::getInstance($data['f_wife']);
+ }
+ if (preg_match_all('/\n1 CHIL @('.WT_REGEX_XREF.')@/', $data['gedrec'], $matches)) {
+ $this->childrenIds=$matches[1];
+ }
+ $this->numChildren=$data['f_numchil'];
+ // Check for divorce, etc. *before* we privatize the data so
+ // we can correctly label spouses/ex-spouses/partners
+ $this->_isDivorced=(bool)preg_match('/\n1 ('.WT_EVENTS_DIV.')( Y|\n)/', $data['gedrec']);
+ $this->_isNotMarried=(bool)preg_match('/\n1 _NMR( Y|\n)/', $data['gedrec']);
+ } 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]);
+ }
+ if (preg_match_all('/^1 CHIL @(.+)@/m', $data, $match)) {
+ $this->childrenIds=$match[1];
+ }
+ if (preg_match('/^1 NCHI (\d+)/m', $data, $match)) {
+ $this->numChildren=$match[1];
+ } else {
+ $this->numChildren=count($this->childrenIds);
+ }
+ // Check for divorce, etc. *before* we privatize the data so
+ // we can correctly label spouses/ex-spouses/partners
+ $this->_isDivorced=(bool)preg_match('/\n1 ('.WT_EVENTS_DIV.')( Y|\n)/', $data);
+ $this->_isNotMarried=(bool)preg_match('/\n1 _NMR( Y|\n)/', $data);
+ }
+
+ // 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)=array($this->wife, $this->husb);
+ }
+
+ parent::__construct($data);
+ }
+
+ /**
+ * get the husbands ID
+ * @return string
+ */
+ function getHusbId() {
+ if (!is_null($this->husb)) return $this->husb->getXref();
+ else return '';
+ }
+
+ /**
+ * get the wife ID
+ * @return string
+ */
+ function getWifeId() {
+ if (!is_null($this->wife)) return $this->wife->getXref();
+ else return '';
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * return the spouse of the given person
+ * @param Person $person
+ * @return Person
+ */
+ function &getSpouse(&$person) {
+ if (is_null($this->wife) or is_null($this->husb)) return null;
+ if ($this->wife->equals($person)) return $this->husb;
+ if ($this->husb->equals($person)) return $this->wife;
+ return null;
+ }
+
+ /**
+ * return the spouse id of the given person id
+ * @param string $pid
+ * @return string
+ */
+ function getSpouseId($pid) {
+ if (is_null($this->wife) or is_null($this->husb)) return null;
+ if ($this->wife->getXref()==$pid) return $this->husb->getXref();
+ if ($this->husb->getXref()==$pid) return $this->wife->getXref();
+ return null;
+ }
+
+ /**
+ * get the children
+ * @return array array of children Persons
+ */
+ function getChildren() {
+ if (!$this->children_loaded) $this->loadChildren();
+ return $this->children;
+ }
+
+ /**
+ * get the children ids
+ * @return array array of children ids
+ */
+ function getChildrenIds() {
+ if (!$this->children_loaded) $this->loadChildren();
+ return $this->childrenIds;
+ }
+
+ // Static helper function to sort an array of families by marriage date
+ static function CompareMarrDate($x, $y) {
+ return GedcomDate::Compare($x->getMarriageDate(), $y->getMarriageDate());
+ }
+
+ /**
+ * Load the children from the database
+ * We used to load the children when the family was created, but that has performance issues
+ * because we often don't need all the children
+ * now, children are only loaded as needed
+ */
+ function loadChildren() {
+ if ($this->children_loaded) return;
+ $this->childrenIds = array();
+ $this->numChildren = preg_match_all('/\n1 CHIL @('.WT_REGEX_XREF.')@/', $this->gedrec, $smatch, PREG_SET_ORDER);
+ for ($i=0; $i<$this->numChildren; $i++) {
+ $this->childrenIds[] = $smatch[$i][1];
+ }
+ foreach ($this->childrenIds as $t=>$chil) {
+ $child=WT_Person::getInstance($chil);
+ if ($child) {
+ $this->children[] = $child;
+ }
+ }
+ $this->children_loaded = true;
+ }
+
+ /**
+ * get the number of children in this family
+ * @return int the number of children
+ */
+ function getNumberOfChildren() {
+
+ $nchi1=(int)get_gedcom_value('NCHI', 1, $this->gedrec);
+ $nchi2=(int)get_gedcom_value('NCHI', 2, $this->gedrec);
+ $nchi3=preg_match_all('/\n1 CHIL @(.*)@/', $this->gedrec, $smatch);
+ return $this->numChildren=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 (is_null($person)) return false;
+ $this->loadChildren();
+ foreach ($this->children as $key=>$child) {
+ if ($person->equals($child)) return true;
+ }
+ return false;
+ }
+
+ /**
+ * parse marriage record
+ */
+ function _parseMarriageRecord() {
+ $this->marriage = new Event(trim(get_sub_record(1, '1 MARR', $this->gedrec)), -1);
+ $this->marriage->setParentObject($this);
+ }
+
+ /**
+ * get the marriage event
+ *
+ * @return Event
+ */
+ function getMarriage() {
+ if (is_null($this->marriage)) $this->_parseMarriageRecord();
+ return $this->marriage;
+ }
+
+ /**
+ * get marriage record
+ * @return string
+ */
+ function getMarriageRecord() {
+ if (is_null($this->marriage)) $this->_parseMarriageRecord();
+ return $this->marriage->getGedcomRecord();
+ }
+
+ // Return whether or not this family ended in a divorce or was never married.
+ // Note that this is calculated prior to privatizing the data, so we can
+ // always distinguish spouses from ex-spouses. This apparant leaking of
+ // private data was discussed and agreed on the pgv forum.
+ function isDivorced() {
+ return $this->_isDivorced;
+ }
+ function isNotMarried() {
+ return $this->_isNotMarried;
+ }
+
+ /**
+ * get marriage date
+ * @return string
+ */
+ function getMarriageDate() {
+ if (!$this->canDisplayDetails()) {
+ return new GedcomDate('');
+ }
+ if (is_null($this->marriage)) {
+ $this->_parseMarriageRecord();
+ }
+ return $this->marriage->getDate();
+ }
+
+ /**
+ * get the marriage year
+ * @return string
+ */
+ function getMarriageYear($est = true, $cal = '') {
+ // TODO - change the design to use julian days, not gregorian years.
+ $mdate = $this->getMarriageDate();
+ $mdate = $mdate->MinDate();
+ if ($cal) $mdate = $mdate->convert_to_cal($cal);
+ return $mdate->y;
+ }
+
+ /**
+ * get the marriage month
+ * @return string
+ */
+ function getMarriageMonth($est = true, $cal = '') {
+ // TODO - change the design to use julian days, not gregorian years.
+ $mdate = $this->getMarriageDate();
+ $mdate=$mdate->MinDate();
+ if ($cal) $mdate = $mdate->convert_to_cal($cal);
+ return $mdate->m;
+ }
+
+ /**
+ * get the type for this marriage
+ * @return string
+ */
+ function getMarriageType() {
+ if (is_null($this->marriage)) $this->_parseMarriageRecord();
+ return $this->marriage->getType();
+ }
+
+ /**
+ * 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->canDisplayDetails()) {
+ foreach (explode('|', WT_EVENTS_MARR) as $event) {
+ if ($array=$this->getAllEventDates($event)) {
+ return $array;
+ }
+ }
+ }
+ return array();
+ }
+ function getAllMarriagePlaces() {
+ if ($this->canDisplayDetails()) {
+ foreach (explode('|', WT_EVENTS_MARR) as $event) {
+ if ($array=$this->getAllEventPlaces($event)) {
+ return $array;
+ }
+ }
+ }
+ return array();
+ }
+
+ // Generate a URL to this record, suitable for use in HTML
+ public function getHtmlUrl() {
+ return parent::_getLinkUrl('family.php?famid=', '&amp;');
+ }
+ // Generate a URL to this record, suitable for use in javascript, HTTP headers, etc.
+ public function getRawUrl() {
+ return parent::_getLinkUrl('family.php?famid=', '&');
+ }
+
+ // 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');
+ // 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) {
+ $husb_names[$n]['script']=utf8_script($husb_name['surn']);
+ }
+ $wife_names=$wife->getAllNames();
+ foreach ($wife_names as $n=>$wife_name) {
+ $wife_names[$n]['script']=utf8_script($wife_name['surn']);
+ }
+ // 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'],
+ 'full'=>$husb_name['full'].' + '.$wife_name['full'],
+ 'list'=>$husb_name['list'].$husb->getSexImage().'<br />'.$wife_name['list'].$wife->getSexImage(),
+ 'sort'=>$husb_name['sort'].' + '.$wife_name['sort'],
+ );
+ }
+ }
+ }
+ // 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'],
+ 'full'=>$husb_name['full'].' + '.$wife_name['full'],
+ 'list'=>$husb_name['list'].$husb->getSexImage().'<br />'.$wife_name['list'].$wife->getSexImage(),
+ 'sort'=>$husb_name['sort'].' + '.$wife_name['sort'],
+ );
+ }
+ }
+ }
+ }
+ 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);
+ }
+}