diff options
Diffstat (limited to 'app/Controller/LifespanController.php')
| -rw-r--r-- | app/Controller/LifespanController.php | 606 |
1 files changed, 606 insertions, 0 deletions
diff --git a/app/Controller/LifespanController.php b/app/Controller/LifespanController.php new file mode 100644 index 0000000000..83c353606f --- /dev/null +++ b/app/Controller/LifespanController.php @@ -0,0 +1,606 @@ +<?php +namespace Webtrees; + +/** + * webtrees: online genealogy + * Copyright (C) 2015 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 + * the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>. + */ + +use Fisharebest\ExtCalendar\GregorianCalendar; + +/** + * Class LifespanController - Controller for the timeline chart + */ +class LifespanController extends PageController { + var $pids = array(); + var $people = array(); + var $place = ''; + var $beginYear = 0; + var $endYear = 0; + var $scale = 2; + var $YrowLoc = 125; + var $minYear = 0; + + // The following colours are deliberately omitted from the $colors list: + // Blue, Red, Black, White, Green + var $colors = array('Aliceblue', 'Antiquewhite', 'Aqua', 'Aquamarine', 'Azure', 'Beige', 'Bisque', 'Blanchedalmond', 'Blueviolet', 'Brown', 'Burlywood', 'Cadetblue', 'Chartreuse', 'Chocolate', 'Coral', 'Cornflowerblue', 'Cornsilk', 'Crimson', 'Cyan', 'Darkcyan', 'Darkgoldenrod', 'Darkgray', 'Darkgreen', 'Darkkhaki', 'Darkmagenta', 'Darkolivegreen', 'Darkorange', 'Darkorchid', 'Darkred', 'Darksalmon', 'Darkseagreen', 'Darkslateblue', 'Darkturquoise', 'Darkviolet', 'Deeppink', 'Deepskyblue', 'Dimgray', 'Dodgerblue', 'Firebrick', 'Floralwhite', 'Forestgreen', 'Fuchsia', 'Gainsboro', 'Ghostwhite', 'Gold', 'Goldenrod', 'Gray', 'Greenyellow', 'Honeydew', 'Hotpink', 'Indianred', 'Ivory', 'Khaki', 'Lavender', 'Lavenderblush', 'Lawngreen', 'Lemonchiffon', 'Lightblue', 'Lightcoral', 'Lightcyan', 'Lightgoldenrodyellow', 'Lightgreen', 'Lightgrey', 'Lightpink', 'Lightsalmon', 'Lightseagreen', 'Lightskyblue', 'Lightslategray', 'Lightsteelblue', 'Lightyellow', 'Lime', 'Limegreen', 'Linen', 'Magenta', 'Maroon', 'Mediumaqamarine', ' Mediumblue', 'Mediumorchid', 'Mediumpurple', 'Mediumseagreen', 'Mediumslateblue', 'Mediumspringgreen', 'Mediumturquoise', 'Mediumvioletred', 'Mintcream', 'Mistyrose', 'Moccasin', 'Navajowhite', 'Oldlace', 'Olive', 'Olivedrab', 'Orange', 'Orangered', 'Orchid', 'Palegoldenrod', 'Palegreen', 'Paleturquoise', 'Palevioletred', 'Papayawhip', 'Peachpuff', 'Peru', 'Pink', 'Plum', 'Powderblue', 'Purple', 'Rosybrown', 'Royalblue', 'Saddlebrown', 'Salmon', 'Sandybrown', 'Seagreen', 'Seashell', 'Sienna', 'Silver', 'Skyblue', 'Slateblue', 'Slategray', 'Snow', 'Springgreen', 'Steelblue', 'Tan', 'Teal', 'Thistle', 'Tomato', 'Turquoise', 'Violet', 'Wheat', 'Whitesmoke', 'Yellow', 'YellowGreen'); + var $malecolorR = array(' 100', ' 110', ' 120', ' 130', ' 140', ' 150', ' 160', ' 170', ' 180', ' 190', ' 200', ' 210', ' 220', ' 230', ' 240', ' 250'); + var $malecolorG = array(' 100', ' 110', ' 120', ' 130', ' 140', ' 150', ' 160', ' 170', ' 180', ' 190', ' 200', ' 210', ' 220', ' 230', ' 240', ' 250'); + var $malecolorB = 255; + var $femalecolorR = 255; + var $femalecolorG = array(' 100', ' 110', ' 120', ' 130', ' 140', ' 150', ' 160', ' 170', ' 180', ' 190', ' 200', ' 210', ' 220', ' 230', ' 240', ' 250'); + var $femalecolorB = array('250', ' 240', ' 230', ' 220', ' 210', ' 200', ' 190', ' 180', ' 170', ' 160', ' 150', ' 140', ' 130', ' 120', ' 110', ' 100'); + var $color; + var $colorindex; + var $Fcolorindex; + var $Mcolorindex; + var $zoomfactor; + var $timelineMinYear; + var $timelineMaxYear; + var $birthMod; + var $deathMod; + var $endMod = 0; + var $modTest; + var $currentYear; + var $endDate; + var $startDate; + var $currentsex; + + private $nonfacts = array( + 'FAMS', 'FAMC', 'MAY', 'BLOB', 'OBJE', 'SEX', 'NAME', 'SOUR', 'NOTE', 'BAPL', 'ENDL', 'SLGC', 'SLGS', '_TODO', '_WT_OBJE_SORT', 'CHAN', 'HUSB', 'WIFE', 'CHIL', 'BIRT', 'DEAT', 'BURI' + ); + + /** + * Startup activity + */ + function __construct() { + global $WT_SESSION; + + parent::__construct(); + $this->setPageTitle(I18N::translate('Lifespans')); + + $this->colorindex = 0; + $this->Fcolorindex = 0; + $this->Mcolorindex = 0; + $this->zoomfactor = 10; + $this->color = '#0000FF'; + $this->currentYear = (int) date('Y'); + $this->deathMod = 0; + $this->endDate = $this->currentYear; + + // Request parameters + $newpid = Filter::get('newpid', WT_REGEX_XREF); + $remove = Filter::get('remove', WT_REGEX_XREF); + $pids = Filter::getArray('pids', WT_REGEX_XREF); + $clear = Filter::getBool('clear'); + $addfam = Filter::getBool('addFamily'); + $place = Filter::get('place'); + $beginYear = Filter::getInteger('beginYear', 0, $this->currentYear + 100, 0); + $endYear = Filter::getInteger('endYear', 0, $this->currentYear + 100, 0); + + $new_person = Individual::getInstance($newpid); + + if ($clear) { + // Empty list + $this->pids = array(); + } elseif ($pids) { + // List of specified records + $this->pids = $pids; + } elseif ($place) { + // All records found in a place + $wt_place = new Place($place, WT_GED_ID); + $this->pids = Database::prepare( + "SELECT DISTINCT pl_gid FROM `##placelinks` WHERE pl_p_id = ? AND pl_file = ?" + )->execute(array($wt_place->getPlaceId(), WT_GED_ID))->fetchOneColumn(); + $this->place = $place; + } else { + // Modify an existing list of records + if (is_array($WT_SESSION->timeline_pids)) { + $this->pids = $WT_SESSION->timeline_pids; + } else { + $this->pids = array(); + } + if ($remove) { + foreach ($this->pids as $key => $value) { + if ($value == $remove) { + unset($this->pids[$key]); + } + } + } elseif ($new_person) { + $this->addFamily($new_person, $addfam); + } elseif (!$this->pids) { + $this->addFamily($this->getSignificantIndividual(), false); + } + } + $WT_SESSION->timeline_pids = $this->pids; + + $this->beginYear = $beginYear; + $this->endYear = $endYear; + if ($beginYear == 0 || $endYear == 0) { + //-- cleanup user input + $this->pids = array_unique($this->pids); //removes duplicates + foreach ($this->pids as $key => $value) { + if ($value != $remove) { + $this->pids[$key] = $value; + $person = Individual::getInstance($value); + // list of linked records includes families as well as individuals. + if ($person) { + $bdate = $person->getEstimatedBirthDate(); + if ($bdate->isOK() && $person->canShow()) { + $this->people[] = $person; + } + } + } + } + } else { + //--Finds if the begin year and end year textboxes are not empty + //-- reset the people array when doing a year range search + $this->people = array(); + //Takes the begining year and end year passed by the postback and modifies them and uses them to populate + //the time line + + //Variables to restrict the person boxes to the year searched. + //--Searches for individuals who had an even between the year begin and end years + $indis = self::searchIndividualsInYearRange($beginYear, $endYear); + //--Populates an array of people that had an event within those years + + foreach ($indis as $person) { + if (empty($searchplace) || in_array($person->getXref(), $this->pids)) { + $bdate = $person->getEstimatedBirthDate(); + if ($bdate->isOK() && $person->canShow()) { + $this->people[] = $person; + } + } + } + $WT_SESSION->timeline_pids = null; + } + + // Sort the array in order of birth year + uasort($this->people, function(Individual $a, Individual $b) { + return Date::Compare($a->getEstimatedBirthDate(), $b->getEstimatedBirthDate()); + }); + //If there is people in the array posted back this if occurs + if (isset ($this->people[0])) { + //Find the maximum Death year and mimimum Birth year for each individual returned in the array. + $bdate = $this->people[0]->getEstimatedBirthDate(); + $ddate = $this->people[0]->getEstimatedDeathDate(); + $this->timelineMinYear = $bdate->gregorianYear(); + $this->timelineMaxYear = $ddate->gregorianYear() ? $ddate->gregorianYear() : date('Y'); + foreach ($this->people as $value) { + $bdate = $value->getEstimatedBirthDate(); + $ddate = $value->getEstimatedDeathDate(); + $this->timelineMinYear = min($this->timelineMinYear, $bdate->gregorianYear()); + $this->timelineMaxYear = max($this->timelineMaxYear, $ddate->gregorianYear() ? $ddate->gregorianYear() : date('Y')); + } + + if ($this->timelineMaxYear > $this->currentYear) { + $this->timelineMaxYear = $this->currentYear; + } + } else { + // Sets the default timeline length + $this->timelineMinYear = date("Y") - 101; + $this->timelineMaxYear = date("Y"); + } + } + + /** + * Add a person (and optionally their immediate family members) to the pids array + * + * @param Individual $person + * @param boolean $add_family + */ + private function addFamily(Individual $person, $add_family) { + $this->pids[] = $person->getXref(); + if ($add_family) { + foreach ($person->getSpouseFamilies() as $family) { + $spouse = $family->getSpouse($person); + if ($spouse) { + $this->pids[] = $spouse->getXref(); + foreach ($family->getChildren() as $child) { + $this->pids[] = $child->getXref(); + } + } + } + foreach ($person->getChildFamilies() as $family) { + foreach ($family->getSpouses() as $parent) { + $this->pids[] = $parent->getXref(); + } + foreach ($family->getChildren() as $sibling) { + if ($person !== $sibling) { + $this->pids[] = $sibling->getXref(); + } + } + } + } + } + + /** + * Sets the start year and end year to a factor of 5 + * + * @param integer $year + * @param integer $key + * + * @return integer + */ + private function modifyYear($year, $key) { + $temp = $year; + switch ($key) { + case 1 : // rounds beginning year + $this->birthMod = $year % 5; + $year = $year - $this->birthMod; + if ($temp == $year) { + $this->modTest = 0; + } else { + $this->modTest = 1; + } + break; + case 2 : // rounds end year + $this->deathMod = $year % 5; + // Only executed if the year needs to be modified + if ($this->deathMod > 0) { + $this->endMod = 5 - $this->deathMod; + } else { + $this->endMod = 0; + } + $year = $year + $this->endMod; + break; + } + + return $year; + } + + /** + * Prints the time line + * + * @param integer $startYear + * @param integer $endYear + */ + public function printTimeline($startYear, $endYear) { + $leftPosition = 14; //start point + $tickDistance = 50; //length of one timeline section + $top = 65; //top starting position + $yearSpan = 5; //default zoom level + $newStartYear = $this->modifyYear($startYear, 1); //starting date for timeline + $this->timelineMinYear = $newStartYear; + $newEndYear = $this->modifyYear($endYear, 2); //ending date for timeline + $totalYears = $newEndYear - $newStartYear; //length of timeline + $timelineTick = $totalYears / $yearSpan; //calculates the length of the timeline + + for ($i = 0; $i < $timelineTick; $i++) { + echo "<div class=\"sublinks_cell\" style=\"text-align: left; position: absolute; top: ", $top, "px; left: ", $leftPosition, "px; width: ", $tickDistance, "px;\">$newStartYear<i class=\"icon-lifespan-chunk\"></i></div>"; //onclick="zoomToggle('100px', '100px', '200px', '200px', this);" + $leftPosition += $tickDistance; + $newStartYear += $yearSpan; + } + echo "<div class=\"sublinks_cell\" style=\"text-align: left; position: absolute; top: ", $top, "px; left: ", $leftPosition, "px; width: ", $tickDistance, "px;\">$newStartYear</div>"; + } + + /** + * Method used to place the person boxes onto the timeline + * + * @param Individual[] $ar + * @param integer $top + * + * @return integer + */ + public function fillTimeline($ar, $top) { + global $maxX, $zindex; + + $zindex = count($ar); + + $rows = array(); + $modFix = 0; + if ($this->modTest == 1) { + $modFix = (9 * $this->birthMod); + } + //base case + if (count($ar) == 0) { + return $top; + } + $maxY = $top; + + foreach ($ar as $value) { + //Creates appropriate color scheme to show relationships + $this->currentsex = $value->getSex(); + if ($this->currentsex == "M") { + $this->Mcolorindex++; + if (!isset($this->malecolorR[$this->Mcolorindex])) { + $this->Mcolorindex = 0; + } + $this->malecolorR[$this->Mcolorindex]; + $this->Mcolorindex++; + if (!isset($this->malecolorG[$this->Mcolorindex])) { + $this->Mcolorindex = 0; + } + $this->malecolorG[$this->Mcolorindex]; + $red = dechex($this->malecolorR[$this->Mcolorindex]); + $green = dechex($this->malecolorR[$this->Mcolorindex]); + if (strlen($red) < 2) { + $red = "0" . $red; + } + if (strlen($green) < 2) { + $green = "0" . $green; + } + + $this->color = "#" . $red . $green . dechex($this->malecolorB); + } elseif ($this->currentsex == "F") { + $this->Fcolorindex++; + if (!isset($this->femalecolorG[$this->Fcolorindex])) { + $this->Fcolorindex = 0; + } + $this->femalecolorG[$this->Fcolorindex]; + $this->Fcolorindex++; + if (!isset($this->femalecolorB[$this->Fcolorindex])) { + $this->Fcolorindex = 0; + } + $this->femalecolorB[$this->Fcolorindex]; + $this->color = "#" . dechex($this->femalecolorR) . dechex($this->femalecolorG[$this->Fcolorindex]) . dechex($this->femalecolorB[$this->Fcolorindex]); + } else { + $this->color = $this->colors[$this->colorindex]; + } + + //set start position and size of person-box according to zoomfactor + $bdate = $value->getEstimatedBirthDate(); + $ddate = $value->getEstimatedDeathDate(); + $birthYear = $bdate->gregorianYear(); + $deathYear = $ddate->gregorianYear() ? $ddate->gregorianYear() : date('Y'); + + $width = ($deathYear - $birthYear) * $this->zoomfactor; + $height = 2 * $this->zoomfactor; + + $startPos = (($birthYear - $this->timelineMinYear) * $this->zoomfactor) + 14 + $modFix; + $minlength = mb_strlen(strip_tags($value->getFullName())) * $this->zoomfactor; + + if ($startPos > 15) { + $startPos = (($birthYear - $this->timelineMinYear) * $this->zoomfactor) + 15; + $width = (($deathYear - $birthYear) * $this->zoomfactor) - 2; + } + + //set minimum width for single year lifespans + if ($width < 10) { + $width = 10; + } + + $lifespan = "<span dir=\"ltr\">$birthYear-</span>"; + $deathReal = $value->getDeathDate()->isOK(); + $birthReal = $value->getBirthDate()->isOK(); + if ($value->isDead() && $deathReal) { + $lifespan .= "<span dir=\"ltr\">$deathYear</span>"; + } + $lifespannumeral = $deathYear - $birthYear; + + //-- calculate a good Y top value + $Y = $top; + $Z = $zindex; + $ready = false; + while (!$ready) { + if (!isset($rows[$Y])) { + $ready = true; + $rows[$Y]["x1"] = $startPos; + $rows[$Y]["x2"] = $startPos + $width; + $rows[$Y]["z"] = $zindex; + } else { + if ($rows[$Y]["x1"] > $startPos + $width) { + $ready = true; + $rows[$Y]["x1"] = $startPos; + $Z = $rows[$Y]["z"]; + } elseif ($rows[$Y]["x2"] < $startPos) { + $ready = true; + $rows[$Y]["x2"] = $startPos + $width; + $Z = $rows[$Y]["z"]; + } else { + //move down 25 pixels + if ($this->zoomfactor > 10) { + $Y += 25 + $this->zoomfactor; + } else { + $Y += 25; + } + } + } + } + + //Need to calculate each event and the spacing between them + // event1 distance will be event - birthyear that will be the distance. then each distance will chain off that + + //$event[][] = {"Cell 1 will hold events"}{"cell2 will hold time between that and the next value"}; + $facts = $value->getFacts(); + foreach ($value->getSpouseFamilies() as $family) { + foreach ($family->getFacts() as $fact) { + $facts[] = $fact; + } + } + $unparsedEvents = array(); + + foreach ($facts as $fact) { + if (!in_array($fact->getTag(), $this->nonfacts)) { + $unparsedEvents[] = $fact; + } + } + sort_facts($unparsedEvents); + + $eventinformation = Array(); + foreach ($unparsedEvents as $val) { + $date = $val->getDate(); + if (!empty($date)) { + $fact = $val->getTag(); + $yearsin = $date->date1->y - $birthYear; + if ($lifespannumeral == 0) { + $lifespannumeral = 1; + } + $eventwidth = ($yearsin / $lifespannumeral) * 100; // percent of the lifespan before the event occured used for determining div spacing + // figure out some schema + $evntwdth = $eventwidth . "%"; + //-- if the fact is a generic EVENt then get the qualifying TYPE + if ($fact == "EVEN") { + $fact = $val->getAttribute('TYPE'); + } + $trans = WT_Gedcom_Tag::getLabel($fact); + if (isset($eventinformation[$evntwdth])) { + $eventinformation[$evntwdth] .= '<br>' . $trans . '<br>' . strip_tags($date->Display()) . ' ' . $val->getPlace()->getFullName(); + } else { + $eventinformation[$evntwdth] = $fact . '-fact, ' . $trans . '<br>' . strip_tags($date->Display()) . ' ' . $val->getPlace()->getFullName(); + } + } + } + + $bdate = $value->getEstimatedBirthDate(); + $ddate = $value->getEstimatedDeathDate(); + if ($width > ($minlength + 110)) { + echo "<div id=\"bar_", $value->getXref(), "\" style=\"position: absolute; top:", $Y, "px; left:", $startPos, "px; width:", $width, "px; height:", $height, "px; background-color:", $this->color, "; border: solid blue 1px; z-index:$Z;\">"; + foreach ($eventinformation as $evtwidth => $val) { + echo "<div style=\"position:absolute; left:", $evtwidth, ";\"><a class=\"showit\" href=\"#\" style=\"top:-2px; font-size:10px;\"><b>"; + $text = explode("-fact, ", $val); + $fact = $text[0]; + echo '</b><span>', self::getAbbreviation($fact), '</span></a></div>'; + } + $indiName = $value->getFullName(); + echo '<table><tr><td width="15"><a class="showit" href="#"><b>'; + echo self::getAbbreviation('BIRT'); + echo '</b><span>', $value->getSexImage(), $indiName, '<br>', WT_Gedcom_Tag::getLabel('BIRT'), ' ', strip_tags($bdate->display()), ' ', $value->getBirthPlace(), '</span></a>', + '<td align="left" width="100%"><a href="', $value->getHtmlUrl(), '">', $value->getSexImage(), $indiName, ' ', $lifespan, ' </a></td>', + '<td width="15">'; + if ($value->isDead()) { + if ($deathReal || $value->isDead()) { + echo '<a class="showit" href="#"><b>'; + echo self::getAbbreviation('DEAT'); + if (!$deathReal) { + echo '*'; + } + echo '</b><span>' . $value->getSexImage() . $indiName . '<br>' . WT_Gedcom_Tag::getLabel('DEAT') . ' ' . strip_tags($ddate->display()) . ' ' . $value->getDeathPlace() . '</span></a>'; + } + } + echo '</td></tr></table>'; + echo '</div>'; + } else { + if ($width > $minlength + 5) { + echo '<div style="text-align: left; position: absolute; top:', $Y, 'px; left:', $startPos, 'px; width:', $width, 'px; height:', $height, 'px; background-color:', $this->color, '; border: solid blue 1px; z-index:', $Z, '">'; + foreach ($eventinformation as $evtwidth => $val) { + echo '<div style="position:absolute; left:', $evtwidth, ' "><a class="showit" href="#" style="top:-2px; font-size:10px;"><b>'; + $text = explode("-fact,", $val); + $fact = $text[0]; + echo '</b><span>' . self::getAbbreviation($fact) . '</span></a></div>'; + } + $indiName = $value->getFullName(); + echo '<table dir="ltr"><tr><td width="15"><a class="showit" href="#"><b>'; + echo self::getAbbreviation('BIRT'); + if (!$birthReal) { + echo '*'; + } + echo '</b><span>' . $value->getSexImage() . $indiName . '<br>' . WT_Gedcom_Tag::getLabel('BIRT') . ' ' . strip_tags($bdate->display(false)) . ' ' . $value->getBirthPlace() . '</span></a></td>' . '<td align="left" width="100%"><a href="' . $value->getHtmlUrl() . '">' . $value->getSexImage() . $indiName . '</a></td>' . + '<td width="15">'; + if ($value->isDead()) { + if ($deathReal || $value->isDead()) { + echo '<a class="showit" href="#"><b>'; + echo self::getAbbreviation('DEAT'); + if (!$deathReal) { + echo "*"; + } + echo '</b><span>' . $value->getSexImage() . $indiName . '<br>' . WT_Gedcom_Tag::getLabel('DEAT') . ' ' . strip_tags($ddate->display()) . ' ' . $value->getDeathPlace() . '</span></a>'; + } + } + echo '</td></tr></table>'; + echo '</div>'; + } else { + echo '<div style="text-align: left; position: absolute;top:', $Y, 'px; left:', $startPos, 'px;width:', $width, 'px; height:', $height, 'px; background-color:', $this->color, '; border: solid blue 1px; z-index:', $Z, '">'; + $indiName = $value->getFullName(); + echo '<a class="showit" href="' . $value->getHtmlUrl() . '"><b>'; + echo self::getAbbreviation('BIRT'); + echo '</b><span>' . $value->getSexImage() . $indiName . '<br>' . WT_Gedcom_Tag::getLabel('BIRT') . ' ' . strip_tags($bdate->display()) . ' ' . $value->getBirthPlace() . '<br>'; + foreach ($eventinformation as $val) { + $text = explode('-fact,', $val); + $val = $text[1]; + echo $val . "<br>"; + } + if ($value->isDead() && $deathReal) { + echo WT_Gedcom_Tag::getLabel('DEAT') . " " . strip_tags($ddate->display()) . " " . $value->getDeathPlace(); + } + echo '</span></a>'; + echo '</div>'; + } + } + $zindex--; + + if ($maxX < $startPos + $width) { + $maxX = $startPos + $width; + } + if ($maxY < $Y) { + $maxY = $Y; + } + } + + return $maxY; + } + + /** + * The significant individual on this page is the first one. + * + * @return Individual + */ + public function getSignificantIndividual() { + if ($this->people) { + return $this->people[0]; + } else { + return parent::getSignificantIndividual(); + } + } + + /** + * Search for people who had events in a given year range + * + * @param integer $startyear + * @param integer $endyear + * + * @return Individual[] + */ + private static function searchIndividualsInYearRange($startyear, $endyear) { + // At present, the lifespan chart is driven by Gregorian years. + // We ought to allow it to work with other calendars... + $gregorian_calendar = new GregorianCalendar; + + $startjd = $gregorian_calendar->ymdToJd($startyear, 1, 1); + $endjd = $gregorian_calendar->ymdToJd($endyear, 12, 31); + + $rows = Database::prepare( +"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 ?" + )->execute(array(WT_GED_ID, $startjd, $endjd))->fetchAll(); + + $list = array(); + foreach ($rows as $row) { + $list[] = Individual::getInstance($row->xref, $row->gedcom_id, $row->gedcom); + } + + return $list; + } + + /** + * Generate a very short abbreviation for birth/marriage/death + * + * @param string $tag + * + * @return string + */ + private static function getAbbreviation($tag) { + switch ($tag) { + case 'BIRT': + return I18N::translate_c('Abbreviation for birth', 'b.'); + case 'MARR': + return I18N::translate_c('Abbreviation for marriage', 'm.'); + case 'DEAT': + return I18N::translate_c('Abbreviation for death', 'd.'); + default: + return mb_substr(WT_Gedcom_Tag::getLabel($tag), 0, 1); // Just use the first letter of the full fact + } + } +} |
