/**
  * Calculate the shortest paths - or all paths - between two individuals.
  *
  * @param Individual $individual1
  * @param Individual $individual2
  * @param int        $recursion   How many levels of recursion to use
  * @param boo;       $ancestor    Restrict to relationships via a common ancestor
  *
  * @return string[][]
  */
 public function calculateRelationships(Individual $individual1, Individual $individual2, $recursion, $ancestor = false)
 {
     $rows = Database::prepare("SELECT l_from, l_to FROM `##link` WHERE l_file = :tree_id AND l_type IN ('FAMS', 'FAMC')")->execute(array('tree_id' => $individual1->getTree()->getTreeId()))->fetchAll();
     // Optionally restrict the graph to the ancestors of the individuals.
     if ($ancestor) {
         $ancestors = $this->allAncestors($individual1->getXref(), $individual2->getXref(), $individual1->getTree()->getTreeId());
         $exclude = $this->excludeFamilies($individual1->getXref(), $individual2->getXref(), $individual1->getTree()->getTreeId());
     } else {
         $ancestors = array();
         $exclude = array();
     }
     $graph = array();
     foreach ($rows as $row) {
         if (!$ancestors || in_array($row->l_from, $ancestors) && !in_array($row->l_to, $exclude)) {
             $graph[$row->l_from][$row->l_to] = 1;
             $graph[$row->l_to][$row->l_from] = 1;
         }
     }
     $xref1 = $individual1->getXref();
     $xref2 = $individual2->getXref();
     $dijkstra = new Dijkstra($graph);
     $paths = $dijkstra->shortestPaths($xref1, $xref2);
     // Only process each exclusion list once;
     $excluded = array();
     $queue = array();
     foreach ($paths as $path) {
         // Insert the paths into the queue, with an exclusion list.
         $queue[] = array('path' => $path, 'exclude' => array());
         // While there are un-extended paths
         while (list(, $next) = each($queue)) {
             // For each family on the path
             for ($n = count($next['path']) - 2; $n >= 1; $n -= 2) {
                 $exclude = $next['exclude'];
                 if (count($exclude) >= $recursion) {
                     continue;
                 }
                 $exclude[] = $next['path'][$n];
                 sort($exclude);
                 $tmp = implode('-', $exclude);
                 if (in_array($tmp, $excluded)) {
                     continue;
                 } else {
                     $excluded[] = $tmp;
                 }
                 // Add any new path to the queue
                 foreach ($dijkstra->shortestPaths($xref1, $xref2, $exclude) as $new_path) {
                     $queue[] = array('path' => $new_path, 'exclude' => $exclude);
                 }
             }
         }
     }
     // Extract the paths from the queue, removing duplicates.
     $paths = array();
     foreach ($queue as $next) {
         $paths[implode('-', $next['path'])] = $next['path'];
     }
     return $paths;
 }
 /**
  * get edit menu
  */
 public function getEditMenu()
 {
     if (!$this->record || $this->record->isPendingDeletion()) {
         return null;
     }
     // edit menu
     $menu = new Menu(I18N::translate('Edit'), '#', 'menu-record');
     // edit raw
     if (Auth::isAdmin() || Auth::isEditor($this->record->getTree()) && $this->record->getTree()->getPreference('SHOW_GEDCOM_RECORD')) {
         $menu->addSubmenu(new Menu(I18N::translate('Edit raw GEDCOM'), '#', 'menu-record-editraw', array('onclick' => 'return edit_raw("' . $this->record->getXref() . '");')));
     }
     // delete
     if (Auth::isEditor($this->record->getTree())) {
         $menu->addSubmenu(new Menu(I18N::translate('Delete'), '#', 'menu-record-del', array('onclick' => 'return delete_record("' . I18N::translate('Are you sure you want to delete “%s”?', Filter::escapeJs(Filter::unescapeHtml($this->record->getFullName()))) . '", "' . $this->record->getXref() . '");')));
     }
     // add to favorites
     if (Module::getModuleByName('user_favorites')) {
         $menu->addSubmenu(new Menu(I18N::translate('Add to favorites'), '#', 'menu-record-addfav', array('onclick' => 'jQuery.post("module.php?mod=user_favorites&mod_action=menu-add-favorite" ,{xref:"' . $this->record->getXref() . '"},function(){location.reload();})')));
     }
     // Get the link for the first submenu and set it as the link for the main menu
     if ($menu->getSubmenus()) {
         $submenus = $menu->getSubmenus();
         $menu->setLink($submenus[0]->getLink());
         $menu->setAttrs($submenus[0]->getAttrs());
     }
     return $menu;
 }
Esempio n. 3
0
 /**
  * Return a menu item for this chart.
  * 
  * We can only do this if the GD2 library is installed with TrueType support.	 	 
  *
  * @return Menu|null
  */
 public function getChartMenu(Individual $individual)
 {
     if (function_exists('imagettftext')) {
         return new Menu($this->getTitle(), 'fanchart.php?rootid=' . $individual->getXref() . '&ged=' . $individual->getTree()->getNameUrl(), 'menu-chart-fanchart', array('rel' => 'nofollow'));
     } else {
         return null;
     }
 }
 /**
  * Startup activity
  */
 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|REPO') as $fact) {
             if (!$fact->isPendingDeletion() && $fact->getTarget() === null) {
                 $this->record->deleteFact($fact->getFactId(), false);
                 FlashMessages::addMessage(I18N::translate('The link from “%1$s” to “%2$s” has been deleted.', $this->record->getFullName(), $fact->getValue()));
                 $broken_links = true;
             }
         }
         foreach ($this->record->getFacts('NOTE|SOUR|OBJE') as $fact) {
             // These can be links or inline.  Only delete links.
             if (!$fact->isPendingDeletion() && $fact->getTarget() === null && preg_match('/^@.*@$/', $fact->getValue())) {
                 $this->record->deleteFact($fact->getFactId(), false);
                 FlashMessages::addMessage(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 = GedcomRecord::getInstance($this->record->getXref(), $this->record->getTree());
         }
     }
     parent::__construct();
     // We want robots to index this page
     $this->setMetaRobots('index,follow');
     // Set a page title
     if ($this->record) {
         if ($this->record->canShowName()) {
             // e.g. "John Doe" or "1881 Census of Wales"
             $this->setPageTitle($this->record->getFullName());
         } else {
             // e.g. "Individual" or "Source"
             $record = $this->record;
             $this->setPageTitle(GedcomTag::getLabel($record::RECORD_TYPE));
         }
     } else {
         // No such record
         $this->setPageTitle(I18N::translate('Private'));
     }
 }
 /**
  * Return a menu item for this chart.
  *
  * @param Individual $individual
  *
  * @return Menu|null
  */
 public function getChartMenu(Individual $individual)
 {
     $tree = $individual->getTree();
     $gedcomid = $tree->getUserPreference(Auth::user(), 'gedcomid');
     if ($gedcomid) {
         return new Menu(I18N::translate('Relationship to me'), 'relationship.php?pid1=' . $gedcomid . '&pid2=' . $individual->getXref() . '&ged=' . $tree->getNameUrl(), 'menu-chart-relationship', array('rel' => 'nofollow'));
     } else {
         return new Menu(I18N::translate('Relationships'), 'relationship.php?pid1=' . $individual->getXref() . '&ged=' . $tree->getNameUrl(), 'menu-chart-relationship', array('rel' => 'nofollow'));
     }
 }
 /**
  * get edit menu
  */
 public function getEditMenu()
 {
     if (!$this->record || $this->record->isPendingDeletion()) {
         return null;
     }
     // edit menu
     $menu = new Menu(I18N::translate('Edit'), '#', 'menu-record');
     // edit raw
     if (Auth::isAdmin() || Auth::isEditor($this->record->getTree()) && $this->record->getTree()->getPreference('SHOW_GEDCOM_RECORD')) {
         $menu->addSubmenu(new Menu(I18N::translate('Edit the raw GEDCOM'), '#', 'menu-record-editraw', array('onclick' => 'return edit_raw("' . $this->record->getXref() . '");')));
     }
     // delete
     if (Auth::isEditor($this->record->getTree())) {
         $menu->addSubmenu(new Menu(I18N::translate('Delete'), '#', 'menu-record-del', array('onclick' => 'return delete_record("' . I18N::translate('Are you sure you want to delete “%s”?', Filter::escapeJs(Filter::unescapeHtml($this->record->getFullName()))) . '", "' . $this->record->getXref() . '");')));
     }
     return $menu;
 }
Esempio n. 7
0
 /**
  * Does an individual (or their spouse-families) have any facts with places?
  *
  * @param Individual $individual
  *
  * @return bool
  */
 private function checkMapData(Individual $individual)
 {
     $statement = Database::prepare("SELECT COUNT(*) FROM `##placelinks` WHERE pl_gid = :xref AND pl_file = :tree_id");
     $args = array('xref' => $individual->getXref(), 'tree_id' => $individual->getTree()->getTreeId());
     if ($statement->execute($args)->fetchOne()) {
         return true;
     }
     foreach ($individual->getSpouseFamilies() as $family) {
         $args['xref'] = $family->getXref();
         if ($statement->execute($args)->fetchOne()) {
             return true;
         }
     }
     return false;
 }
 /**
  * Return a menu item for this chart.
  *
  * @return Menu|null
  */
 public function getChartMenu(Individual $individual)
 {
     return new Menu($this->getTitle(), 'compact.php?rootid=' . $individual->getXref() . '&ged=' . $individual->getTree()->getNameUrl(), 'menu-chart-compact', array('rel' => 'nofollow'));
 }
 /**
  * Get any historical events.
  *
  * @param Individual $person
  *
  * @return Fact[]
  */
 private static function historicalFacts(Individual $person)
 {
     $SHOW_RELATIVES_EVENTS = $person->getTree()->getPreference('SHOW_RELATIVES_EVENTS');
     $facts = array();
     if ($SHOW_RELATIVES_EVENTS) {
         // Only include events between birth and death
         $birt_date = $person->getEstimatedBirthDate();
         $deat_date = $person->getEstimatedDeathDate();
         if (file_exists(Site::getPreference('INDEX_DIRECTORY') . 'histo.' . WT_LOCALE . '.php')) {
             $histo = array();
             require Site::getPreference('INDEX_DIRECTORY') . 'histo.' . WT_LOCALE . '.php';
             foreach ($histo as $hist) {
                 // Earlier versions of the WIKI encouraged people to use HTML entities,
                 // rather than UTF8 encoding.
                 $hist = html_entity_decode($hist, ENT_QUOTES, 'UTF-8');
                 $fact = new Fact($hist, $person, 'histo');
                 $sdate = $fact->getDate();
                 if ($sdate->isOK() && Date::compare($birt_date, $sdate) <= 0 && Date::compare($sdate, $deat_date) <= 0) {
                     $facts[] = $fact;
                 }
             }
         }
     }
     return $facts;
 }
Esempio n. 10
0
 /**
  * Create part of an individual box
  *
  * @param Individual $individual
  *
  * @return string
  */
 protected function individualBoxSexSymbol(Individual $individual)
 {
     if ($individual->getTree()->getPreference('PEDIGREE_SHOW_GENDER')) {
         return $individual->sexImage('large');
     } else {
         return '';
     }
 }
Esempio n. 11
0
 /**
  * Get the thumbnail image for the given person
  *
  * @param Individual $individual
  *
  * @return string
  */
 private function getThumbnail(Individual $individual)
 {
     if ($individual->getTree()->getPreference('SHOW_HIGHLIGHT_IMAGES')) {
         return $individual->displayImage();
     } else {
         return '';
     }
 }
Esempio n. 12
0
 /**
  * Return a menu item for this chart.
  *
  * @return Menu|null
  */
 public function getChartMenu(Individual $individual)
 {
     return new Menu($this->getTitle(), 'statistics.php?ged=' . $individual->getTree()->getNameUrl(), 'menu-chart-statistics', array('rel' => 'nofollow'));
 }
Esempio n. 13
0
 /**
  * Return a menu item for this chart.
  *
  * @return Menu|null
  */
 public function getChartMenu(Individual $individual)
 {
     return new Menu($this->getTitle(), 'module.php?mod=tree&amp;mod_action=treeview&amp;rootid=' . $individual->getXref() . '&amp;ged=' . $individual->getTree()->getNameUrl(), 'menu-chart-tree', array('rel' => 'nofollow'));
 }
Esempio n. 14
0
 /**
  * Return a menu item for this chart.
  *
  * @return Menu|null
  */
 public function getChartMenu(Individual $individual)
 {
     return new Menu($this->getTitle(), 'timeline.php?pids%5B%5D=' . $individual->getXref() . '&amp;ged=' . $individual->getTree()->getNameUrl(), 'menu-chart-timeline', array('rel' => 'nofollow'));
 }