Структура данных "Семейное древо" - PullRequest
6 голосов
/ 22 июля 2010

Я ищу способ представления генеалогического дерева в PHP.Это означает, что дети должны будут наследовать от двух (или более) родителей.

Вот требования:

  • 1, 2 или более родителей
  • Бонусные баллы, если я могу прикрепить метаданные, например, фамилию или статус отношений

Вот моя неработающая попытка (к сожалению, без массивов в качестве ключей):

$tree = array(
    'uncle' => false, // no children
    array('mom', 'dad') => array(
        'me' => false,
        array('brother', 'sister-in-law') => array(
            'niece' => false
        )
    )
);

Вопрос в том, как мне представить семейное древо с этими требованиями?

Ответы [ 2 ]

20 голосов
/ 22 июля 2010

Вы не сможете сделать все это за один array(), как это. Вы можете настроить деревья таким образом, но для создания более сложных графиков с несколькими родителями и другими отношениями требуется несколько строк кода.

Это очень поможет, если вы добавите в это ОО. Давайте создадим класс Person, чтобы помочь управлять отношениями. По сути, у нас есть люди и их отношения с другими людьми, поэтому мы начнем там.

Персональный класс

Я представляю себе, что у каждого человека есть множество отношений. Этот массив сначала будет проиндексирован по типу отношений, например, «родители» или «дети». Тогда каждая запись будет массивом Person с.

class Person {
    var $name, $relations;

    function __construct($name) {
        $this->name      = $name;
        $this->relations = array();
    }

    function addRelation($type, $person) {
        if (!isset($this->relations[$type])) {
            $this->relations[$type] = array();
        }

        $this->relations[$type][] = $person;
    }

    // Looks up multiple relations, for example "parents".
    function getRelations($type) {
        if (!isset($this->relations[$type])) {
            return array();
        }

        return $this->relations[$type];
    }

    // Looks up a single relation, for example "spouse".
    function getRelation($type) {
        $relations = $this->getRelations($type);
        return empty($relations) ? null : $relations[0];
    }

    function __toString() {
        return $this->name;
    }

Дружественные сумматоры и геттеры

Используя вышеперечисленное в качестве основы, мы можем добавить некоторые более дружественные методы. В качестве иллюстрации мы рассмотрим отношения родитель / ребенок и супруги.

    function addParents($mom, $dad) {
        $mom->addChild($this);
        $dad->addChild($this);
    }

    function addChild($child) {
        $this ->addRelation('children', $child);
        $child->addRelation('parents',  $this);
    }

    function addSpouse($spouse) {
        $this  ->addRelation('spouse', $spouse);
        $spouse->addRelation('spouse', $this);
    }

    function getParents () { return $this->getRelations('parents');  }
    function getChildren() { return $this->getRelations('children'); }
    function getSpouse  () { return $this->getRelation ('spouse');   }
}

Создание людей

Теперь мы можем создать пару человек и установить их отношения. Давайте попробуем Билли и его родителей Джона и Джейн.

$john  = new Person('John');
$jane  = new Person('Jane');
$billy = new Person('Billy');

$john ->addSpouse ($jane);
$billy->addParents($jane, $john);

И мы можем проверить их отношения так:

echo "John is married to " . $john->getSpouse() . ".\n";
echo "Billy's parents are " . implode(" and ", $billy->getParents()) . ".\n";

Выход:

Джон женат на Джейн.
Родители Билли - Джейн и Джон.

Отображение родословной

Мы можем рекурсивно пройти по графику, если он станет больше. Вот пример функции обхода дерева, которая отображает элементарное генеалогическое дерево. Я добавил Сара, ее мужа Майка и их сына Бобби.

$john  = new Person('John');
$jane  = new Person('Jane');
$sara  = new Person('Sara');
$mike  = new Person('Mike');
$bobby = new Person('Bobby');
$billy = new Person('Billy');

$john ->addSpouse ($jane);
$sara ->addParents($jane, $john);
$sara ->addSpouse ($mike);
$bobby->addParents($sara, $mike);
$billy->addParents($jane, $john);

function displayFamilyTree($root, $prefix = "") {
    $parents = array($root);

    if ($root->getSpouse() != null) {
        $parents[] = $root->getSpouse();
    }

    echo $prefix . implode(" & ", $parents) . "\n";

    foreach ($root->getChildren() as $child) {
        displayFamilyTree($child, "....$prefix");
    }
}

displayFamilyTree($john);

Выход:

Джон и Джейн
.... Сара и Майк
........ Бобби
.... Билли


Редактировать: Вот комментарий @ Wrikken ниже, воспроизведенный для удобства чтения:

Об этом действительно. ИМХО, хотя добавьте дату «до» в каждое отношение (возможно, NULL для без конца). Происходят разводы, как и усыновление, и т. Д. Кроме того: я бы добавил обратные типы & ping-back к функции addRelation():

function addRelation($type, $person, $reverseType, $pingback = false) {
    if (!isset($this->relations[$type])) {
        $this->relations[$type] = array();
    }

    if (!in_array($person, $this->relations[$type], true)) {
        $this->relations[$type][] = $person;
    }

    if (!$pingback) {
        $person->addRelation($reverseType, $this, $type, true);
    }
}
1 голос
/ 03 июля 2015

GEDCOM - это открытая спецификация для обмена генеалогическими данными между различными программами генеалогии. Файл GEDCOM представляет собой простой текст (обычно ANSEL или ASCII), содержащий генеалогическую информацию об отдельных лицах и метаданные, связывающие эти записи вместе. Большинство генеалогических программ поддерживают импорт и / или экспорт в формат GEDCOM.

Основным преимуществом использования GEDCOM является то, что вы можете использовать настольные программы, такие как Aldfaer (только на голландском языке) , Gramps или Legacy Family Tree , а также онлайн-инструменты, такие как Geneanet , для создания или изменения вашего семейного дерева и сравнения его с семейными деревьями др.

Еще одним важным преимуществом использования формата GEDCOM является то, что в вашем распоряжении есть библиотеки на нескольких языках для сохранения и загрузки ваших данных. Примеры библиотек PHP: GEDCOM Import / Export-Filter , GenealogyGedcom или PHP GEDCOM .

Используя PHP GEDCOM, чтение и синтаксический анализ файла GEDCOM будут такими простыми:

$parser = new \PhpGedcom\Parser();
$gedcom = $parser->parse('gedcom.ged');

Основным недостатком использования GEDCOM является то, что формат данных GEDCOM строится вокруг ядерной семьи, что означает, что стандарт ограничен в поддержке нетрадиционных семейных структур, таких как однополые партнерства, смешанные семьи или совместное проживание. Хотя возможно расширение GEDCOM для поддержки этого типа отношений, совместимость между различными программами для таких расширений ограничена.

Еще одним существенным недостатком использования GEDCOM является то, что файлы GEDCOM являются монолитными. Если у вас есть набор данных из тысяч человек или вы хотите часто менять структуру данных, у вас могут возникнуть проблемы с производительностью. Особенно в этих случаях лучше хранить ваши данные в базе данных. Тем не менее, это не значит, что GEDCOM бесполезен. В этих случаях вы можете рассмотреть возможность использования схемы базы данных на основе формата GEDCOM, которая позволяет импортировать / экспортировать между вашей базой данных и форматом GEDCOM. Для этого также существуют библиотеки. Oxy-Gen будет примером.


Альтернативами GEDCOM могут быть Модель данных GenTech или Модель данных Gramps . Хотя они не так широко используются, как стандарт GEDCOM, они могут лучше соответствовать вашим потребностям.

Если вы хотите использовать модель данных Gramps, вы можете использовать, например. Экспортер PHP Gramps для экспорта ваших данных в базу данных SQLite. См. Также этот источник о том, как спроектировать базу данных так, чтобы она подходила для модели данных Gramps.

...