示例#1
0
 /**
  * Computes descendent Lineage from a node.
  * Uses recursion to build the lineage tree
  * 
  * @param LineageNode $node
  * @return LineageNode Computed lineage
  */
 protected function buildLineage(LineageNode $node)
 {
     if ($node === null) {
         return;
     }
     $indi_surname = null;
     $indi_node = $node->getIndividual();
     if ($indi_node) {
         if (count($node->getFamiliesNodes()) == 0) {
             $indiSpouseFamilies = $indi_node->getSpouseFamilies();
             foreach ($indiSpouseFamilies as $indiSpouseFamily) {
                 $node->addFamily($indiSpouseFamily);
             }
         }
         $dindi_node = new \MyArtJaub\Webtrees\Individual($indi_node);
         $indi_surname = $dindi_node->getUnprotectedPrimarySurname();
         //Get the estimated birth place and put it in the place table
         $place = $dindi_node->getEstimatedBirthPlace(false);
         if ($place && strlen($place) > 0) {
             $place = trim($place);
             $node->getRootNode()->addPlace(new Place($place, $this->tree));
         }
         //Tag the individual as used
         $this->used_indis[$indi_node->getXref()] = true;
     }
     foreach ($node->getFamiliesNodes() as $family) {
         $spouse_surname = null;
         if ($indi_node && ($spouse = $family->getSpouse($indi_node))) {
             $dspouse = new \MyArtJaub\Webtrees\Individual($spouse);
             $spouse_surname = $dspouse->getUnprotectedPrimarySurname();
         }
         $children = $family->getChildren();
         $nbChildren = 0;
         $nbNatural = 0;
         foreach ($children as $child) {
             $dchild = new \MyArtJaub\Webtrees\Individual($child);
             $child_surname = $dchild->getUnprotectedPrimarySurname();
             if (!$dchild->isNewAddition()) {
                 $nbChildren++;
                 //If the root individual is the mother
                 if ($indi_node && I18N::strcasecmp($indi_node->getSex(), 'F') == 0) {
                     //Print only lineages of children with the same surname as their mother (supposing they are natural children)
                     if (!$spouse || $spouse_surname && I18N::strcasecmp($child_surname, $spouse_surname) != 0) {
                         if (I18N::strcasecmp($child_surname, $indi_surname) == 0) {
                             $nbNatural++;
                             $node_child = new LineageNode($child, $node->getRootNode());
                             $node_child = $this->buildLineage($node_child);
                             if ($node_child) {
                                 $node->addChild($family, $node_child);
                             }
                         }
                     }
                 } else {
                     //Print if the children does not bear the same name as his mother (and different from his father)
                     if (strlen($child_surname) == 0 || strlen($indi_surname) == 0 || strlen($spouse_surname) == 0 || I18N::strcasecmp($child_surname, $indi_surname) == 0 || I18N::strcasecmp($child_surname, $spouse_surname) != 0) {
                         $nbNatural++;
                         $node_child = new LineageNode($child, $node->getRootNode());
                         $node_child = $this->buildLineage($node_child);
                         if ($node_child) {
                             $node->addChild($family, $node_child);
                         }
                     } else {
                         $nbNatural++;
                         $node_child = new LineageNode($child, $node->getRootNode(), $child_surname);
                         if ($node_child) {
                             $node->addChild($family, $node_child);
                         }
                     }
                 }
             }
         }
         //Do not print other children
         if ($nbChildren - $nbNatural > 0) {
             $node->addChild($family, null);
         }
     }
     return $node;
 }
示例#2
0
 /**
  * Print a new fact box on details pages
  *
  * @param string $id the id of the person, family, source etc the fact will be added to
  * @param array $usedfacts an array of facts already used in this record
  * @param string $type the type of record INDI, FAM, SOUR etc
  */
 public static function printAddNewFact($id, $usedfacts, $type)
 {
     global $WT_TREE;
     // -- Add from clipboard
     if (is_array(Session::get('clipboard'))) {
         $newRow = true;
         foreach (array_reverse(Session::get('clipboard'), true) as $fact_id => $fact) {
             if ($fact["type"] == $type || $fact["type"] == 'all') {
                 if ($newRow) {
                     $newRow = false;
                     echo '<tr><td class="descriptionbox">';
                     echo I18N::translate('Add from clipboard'), '</td>';
                     echo '<td class="optionbox wrap"><form method="get" name="newFromClipboard" action="?" onsubmit="return false;">';
                     echo '<select id="newClipboardFact">';
                 }
                 echo '<option value="', Filter::escapeHtml($fact_id), '">', GedcomTag::getLabel($fact['fact']);
                 // TODO use the event class to store/parse the clipboard events
                 if (preg_match('/^2 DATE (.+)/m', $fact['factrec'], $match)) {
                     $tmp = new Date($match[1]);
                     echo '; ', $tmp->minimumDate()->format('%Y');
                 }
                 if (preg_match('/^2 PLAC ([^,\\n]+)/m', $fact['factrec'], $match)) {
                     echo '; ', $match[1];
                 }
                 echo '</option>';
             }
         }
         if (!$newRow) {
             echo '</select>';
             echo '&nbsp;&nbsp;<input type="button" value="', I18N::translate('Add'), "\" onclick=\"return paste_fact('{$id}', '#newClipboardFact');\"> ";
             echo '</form></td></tr>', "\n";
         }
     }
     // -- Add from pick list
     switch ($type) {
         case "INDI":
             $addfacts = preg_split("/[, ;:]+/", $WT_TREE->getPreference('INDI_FACTS_ADD'), -1, PREG_SPLIT_NO_EMPTY);
             $uniquefacts = preg_split("/[, ;:]+/", $WT_TREE->getPreference('INDI_FACTS_UNIQUE'), -1, PREG_SPLIT_NO_EMPTY);
             $quickfacts = preg_split("/[, ;:]+/", $WT_TREE->getPreference('INDI_FACTS_QUICK'), -1, PREG_SPLIT_NO_EMPTY);
             break;
         case "FAM":
             $addfacts = preg_split("/[, ;:]+/", $WT_TREE->getPreference('FAM_FACTS_ADD'), -1, PREG_SPLIT_NO_EMPTY);
             $uniquefacts = preg_split("/[, ;:]+/", $WT_TREE->getPreference('FAM_FACTS_UNIQUE'), -1, PREG_SPLIT_NO_EMPTY);
             $quickfacts = preg_split("/[, ;:]+/", $WT_TREE->getPreference('FAM_FACTS_QUICK'), -1, PREG_SPLIT_NO_EMPTY);
             break;
         case "SOUR":
             $addfacts = preg_split("/[, ;:]+/", $WT_TREE->getPreference('SOUR_FACTS_ADD'), -1, PREG_SPLIT_NO_EMPTY);
             $uniquefacts = preg_split("/[, ;:]+/", $WT_TREE->getPreference('SOUR_FACTS_UNIQUE'), -1, PREG_SPLIT_NO_EMPTY);
             $quickfacts = preg_split("/[, ;:]+/", $WT_TREE->getPreference('SOUR_FACTS_QUICK'), -1, PREG_SPLIT_NO_EMPTY);
             break;
         case "NOTE":
             $addfacts = preg_split("/[, ;:]+/", $WT_TREE->getPreference('NOTE_FACTS_ADD'), -1, PREG_SPLIT_NO_EMPTY);
             $uniquefacts = preg_split("/[, ;:]+/", $WT_TREE->getPreference('NOTE_FACTS_UNIQUE'), -1, PREG_SPLIT_NO_EMPTY);
             $quickfacts = preg_split("/[, ;:]+/", $WT_TREE->getPreference('NOTE_FACTS_QUICK'), -1, PREG_SPLIT_NO_EMPTY);
             break;
         case "REPO":
             $addfacts = preg_split("/[, ;:]+/", $WT_TREE->getPreference('REPO_FACTS_ADD'), -1, PREG_SPLIT_NO_EMPTY);
             $uniquefacts = preg_split("/[, ;:]+/", $WT_TREE->getPreference('REPO_FACTS_UNIQUE'), -1, PREG_SPLIT_NO_EMPTY);
             $quickfacts = preg_split("/[, ;:]+/", $WT_TREE->getPreference('REPO_FACTS_QUICK'), -1, PREG_SPLIT_NO_EMPTY);
             break;
         default:
             return;
     }
     $addfacts = array_merge(self::checkFactUnique($uniquefacts, $usedfacts, $type), $addfacts);
     $quickfacts = array_intersect($quickfacts, $addfacts);
     $translated_addfacts = array();
     foreach ($addfacts as $addfact) {
         $translated_addfacts[$addfact] = GedcomTag::getLabel($addfact);
     }
     uasort($translated_addfacts, function ($x, $y) {
         return I18N::strcasecmp(I18N::translate($x), I18N::translate($y));
     });
     echo '<tr><td class="descriptionbox">';
     echo I18N::translate('Fact or event');
     echo '</td>';
     echo '<td class="optionbox wrap">';
     echo '<form method="get" name="newfactform" action="?" onsubmit="return false;">';
     echo '<select id="newfact" name="newfact">';
     echo '<option value="" disabled selected>' . I18N::translate('&lt;select&gt;') . '</option>';
     foreach ($translated_addfacts as $fact => $fact_name) {
         echo '<option value="', $fact, '">', $fact_name, '</option>';
     }
     if ($type == 'INDI' || $type == 'FAM') {
         echo '<option value="FACT">', I18N::translate('Custom fact'), '</option>';
         echo '<option value="EVEN">', I18N::translate('Custom event'), '</option>';
     }
     echo '</select>';
     echo '<input type="button" value="', I18N::translate('Add'), '" onclick="add_record(\'' . $id . '\', \'newfact\');">';
     echo '<span class="quickfacts">';
     foreach ($quickfacts as $fact) {
         echo '<a href="#" onclick="add_new_record(\'' . $id . '\', \'' . $fact . '\');return false;">', GedcomTag::getLabel($fact), '</a>';
     }
     echo '</span></form>';
     echo '</td></tr>';
 }
 /**
  * Compare two tags, for sorting
  *
  * @param string $x
  * @param string $y
  *
  * @return int
  */
 public static function tagSort($x, $y)
 {
     list($x1) = explode(':', $x . ':');
     list($y1) = explode(':', $y . ':');
     $tmp = I18N::strcasecmp(GedcomTag::getLabel($x1), GedcomTag::getLabel($y1));
     if ($tmp) {
         return $tmp;
     } else {
         return I18N::strcasecmp(GedcomTag::getLabel($x), GedcomTag::getLabel($y));
     }
 }
示例#4
0
 /**
  * Sort a list events for the today/upcoming blocks
  *
  * @param array $a
  * @param array $b
  *
  * @return int
  */
 public static function eventSort($a, $b)
 {
     if ($a['jd'] == $b['jd']) {
         if ($a['anniv'] == $b['anniv']) {
             return I18N::strcasecmp($a['fact'], $b['fact']);
         } else {
             return $a['anniv'] - $b['anniv'];
         }
     } else {
         return $a['jd'] - $b['jd'];
     }
 }
示例#5
0
 /**
  * Themes menu.
  *
  * @return Menu|null
  */
 public function menuThemes()
 {
     if ($this->tree && Site::getPreference('ALLOW_USER_THEMES') && $this->tree->getPreference('ALLOW_THEME_DROPDOWN')) {
         $submenus = array();
         foreach (Theme::installedThemes() as $theme) {
             $class = 'menu-theme-' . $theme->themeId() . ($theme === $this ? ' active' : '');
             $submenus[] = new Menu($theme->themeName(), '#', $class, array('onclick' => 'return false;', 'data-theme' => $theme->themeId()));
         }
         usort($submenus, function (Menu $x, Menu $y) {
             return I18N::strcasecmp($x->getLabel(), $y->getLabel());
         });
         $menu = new Menu(I18N::translate('Theme'), '#', 'menu-theme', array(), $submenus);
         return $menu;
     } else {
         return null;
     }
 }
示例#6
0
    if ($tag) {
        $all_tags[$tag] = GedcomTag::getLabel($tag);
    }
}
uasort($all_tags, '\\Fisharebest\\Webtrees\\I18N::strcasecmp');
$resns = Database::prepare("SELECT default_resn_id, tag_type, xref, resn" . " FROM `##default_resn`" . " LEFT JOIN `##name` ON (gedcom_id=n_file AND xref=n_id AND n_num=0)" . " WHERE gedcom_id=?" . " ORDER BY xref IS NULL, n_sort, xref, tag_type")->execute(array($WT_TREE->getTreeId()))->fetchAll();
foreach ($resns as $resn) {
    $resn->record = GedcomRecord::getInstance($resn->xref, $WT_TREE);
    if ($resn->tag_type) {
        $resn->tag_label = GedcomTag::getLabel($resn->tag_type);
    } else {
        $resn->tag_label = '';
    }
}
usort($resns, function (\stdClass $x, \stdClass $y) {
    return I18N::strcasecmp($x->tag_label, $y->tag_label);
});
// We have two fields in one
$CALENDAR_FORMATS = explode('_and_', $WT_TREE->getPreference('CALENDAR_FORMAT') . '_and_');
// Split into separate fields
$relatives_events = explode(',', $WT_TREE->getPreference('SHOW_RELATIVES_EVENTS'));
switch (Filter::post('action')) {
    case 'privacy':
        foreach (Filter::postArray('delete', WT_REGEX_INTEGER) as $delete_resn) {
            Database::prepare("DELETE FROM `##default_resn` WHERE default_resn_id=?")->execute(array($delete_resn));
        }
        $xrefs = Filter::postArray('xref', WT_REGEX_XREF);
        $tag_types = Filter::postArray('tag_type', WT_REGEX_TAG);
        $resns = Filter::postArray('resn');
        foreach ($xrefs as $n => $xref) {
            $tag_type = $tag_types[$n];
示例#7
0
 /**
  * Scan the source code to find a list of all installed modules.
  *
  * During setup, new modules need a status of “enabled”.
  * In admin->modules, new modules need status of “disabled”.
  *
  * @param string $default_status
  *
  * @return AbstractModule[]
  */
 public static function getInstalledModules($default_status)
 {
     $modules = array();
     foreach (glob(WT_ROOT . WT_MODULES_DIR . '*/module.php') as $file) {
         try {
             $module = (include $file);
             if ($module instanceof AbstractModule) {
                 $modules[$module->getName()] = $module;
                 Database::prepare("INSERT IGNORE INTO `##module` (module_name, status, menu_order, sidebar_order, tab_order) VALUES (?, ?, ?, ?, ?)")->execute(array($module->getName(), $default_status, $module instanceof ModuleMenuInterface ? $module->defaultMenuOrder() : null, $module instanceof ModuleSidebarInterface ? $module->defaultSidebarOrder() : null, $module instanceof ModuleTabInterface ? $module->defaultTabOrder() : null));
                 // Set the default privcy for this module. Note that this also sets it for the
                 // default family tree, with a gedcom_id of -1
                 if ($module instanceof ModuleMenuInterface) {
                     Database::prepare("INSERT IGNORE INTO `##module_privacy` (module_name, gedcom_id, component, access_level)" . " SELECT ?, gedcom_id, 'menu', ?" . " FROM `##gedcom`")->execute(array($module->getName(), $module->defaultAccessLevel()));
                 }
                 if ($module instanceof ModuleSidebarInterface) {
                     Database::prepare("INSERT IGNORE INTO `##module_privacy` (module_name, gedcom_id, component, access_level)" . " SELECT ?, gedcom_id, 'sidebar', ?" . " FROM `##gedcom`")->execute(array($module->getName(), $module->defaultAccessLevel()));
                 }
                 if ($module instanceof ModuleTabInterface) {
                     Database::prepare("INSERT IGNORE INTO `##module_privacy` (module_name, gedcom_id, component, access_level)" . " SELECT ?, gedcom_id, 'tab', ?" . " FROM `##gedcom`")->execute(array($module->getName(), $module->defaultAccessLevel()));
                 }
                 if ($module instanceof ModuleBlockInterface) {
                     Database::prepare("INSERT IGNORE INTO `##module_privacy` (module_name, gedcom_id, component, access_level)" . " SELECT ?, gedcom_id, 'block', ?" . " FROM `##gedcom`")->execute(array($module->getName(), $module->defaultAccessLevel()));
                 }
                 if ($module instanceof ModuleChartInterface) {
                     Database::prepare("INSERT IGNORE INTO `##module_privacy` (module_name, gedcom_id, component, access_level)" . " SELECT ?, gedcom_id, 'chart', ?" . " FROM `##gedcom`")->execute(array($module->getName(), $module->defaultAccessLevel()));
                 }
                 if ($module instanceof ModuleReportInterface) {
                     Database::prepare("INSERT IGNORE INTO `##module_privacy` (module_name, gedcom_id, component, access_level)" . " SELECT ?, gedcom_id, 'report', ?" . " FROM `##gedcom`")->execute(array($module->getName(), $module->defaultAccessLevel()));
                 }
                 if ($module instanceof ModuleThemeInterface) {
                     Database::prepare("INSERT IGNORE INTO `##module_privacy` (module_name, gedcom_id, component, access_level)" . " SELECT ?, gedcom_id, 'theme', ?" . " FROM `##gedcom`")->execute(array($module->getName(), $module->defaultAccessLevel()));
                 }
             }
         } catch (\Exception $ex) {
             // Old or invalid module?
         }
     }
     uasort($modules, function (AbstractModule $x, AbstractModule $y) {
         return I18N::strcasecmp($x->getTitle(), $y->getTitle());
     });
     return $modules;
 }
示例#8
0
 /**
  * Static helper function to sort an array of objects by name
  * Records whose names cannot be displayed are sorted at the end.
  *
  * @param GedcomRecord $x
  * @param GedcomRecord $y
  *
  * @return int
  */
 public static function compare(GedcomRecord $x, GedcomRecord $y)
 {
     if ($x->canShowName()) {
         if ($y->canShowName()) {
             return I18N::strcasecmp($x->getSortName(), $y->getSortName());
         } else {
             return -1;
             // only $y is private
         }
     } else {
         if ($y->canShowName()) {
             return 1;
             // only $x is private
         } else {
             return 0;
             // both $x and $y private
         }
     }
 }
示例#9
0
use Fisharebest\Webtrees\Module\ModuleBlockInterface;
use Fisharebest\Webtrees\Module\ModuleChartInterface;
use Fisharebest\Webtrees\Module\ModuleConfigInterface;
use Fisharebest\Webtrees\Module\ModuleMenuInterface;
use Fisharebest\Webtrees\Module\ModuleReportInterface;
use Fisharebest\Webtrees\Module\ModuleSidebarInterface;
use Fisharebest\Webtrees\Module\ModuleTabInterface;
use Fisharebest\Webtrees\Module\ModuleThemeInterface;
define('WT_SCRIPT_NAME', 'admin_modules.php');
require 'includes/session.php';
$controller = new PageController();
$controller->restrictAccess(Auth::isAdmin())->setPageTitle(I18N::translate('Module administration'));
$modules = Module::getInstalledModules('disabled');
$module_status = Database::prepare("SELECT module_name, status FROM `##module`")->fetchAssoc();
uasort($modules, function (AbstractModule $x, AbstractModule $y) {
    return I18N::strcasecmp($x->getTitle(), $y->getTitle());
});
if (Filter::post('action') === 'update_mods' && Filter::checkCsrf()) {
    foreach ($modules as $module) {
        $new_status = Filter::post('status-' . $module->getName(), '[01]');
        if ($new_status !== null) {
            $new_status = $new_status ? 'enabled' : 'disabled';
            $old_status = $module_status[$module->getName()];
            if ($new_status !== $old_status) {
                Database::prepare("UPDATE `##module` SET status=? WHERE module_name=?")->execute(array($new_status, $module->getName()));
                if ($new_status === 'disabled') {
                    FlashMessages::addMessage(I18N::translate('The module “%s” has been disabled.', $module->getTitle()), 'success');
                } else {
                    FlashMessages::addMessage(I18N::translate('The module “%s” has been enabled.', $module->getTitle()), 'success');
                }
            }
 /**
  * AdminConfig@jsonTasksList
  */
 public function jsonTasksList()
 {
     global $WT_TREE;
     $controller = new JsonController();
     $controller->restrictAccess(Auth::isAdmin());
     // Generate an AJAX/JSON response for datatables to load a block of rows
     $search = Filter::postArray('search');
     if ($search) {
         $search = $search['value'];
     }
     $start = Filter::postInteger('start');
     $length = Filter::postInteger('length');
     $order = Filter::postArray('order');
     $order_by_name = false;
     foreach ($order as $key => &$value) {
         switch ($value['column']) {
             case 3:
                 $order_by_name = true;
                 unset($order[$key]);
                 break;
             case 4:
                 $value['column'] = 'majat_last_run';
                 break;
             case 4:
                 $value['column'] = 'majat_last_result';
                 break;
             default:
                 unset($order[$key]);
         }
     }
     $list = $this->provider->getFilteredTasksList($search, $order, $start, $length);
     if ($order_by_name) {
         usort($list, function (AbstractTask $a, AbstractTask $b) {
             return I18N::strcasecmp($a->getTitle(), $b->getTitle());
         });
     }
     $recordsFiltered = count($list);
     $recordsTotal = $this->provider->getTasksCount();
     $data = array();
     foreach ($list as $task) {
         $datum = array();
         $datum[0] = '
             <div class="btn-group">
                 <button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
                     <i class="fa fa-pencil"></i><span class="caret"></span>
                 </button>
                 <ul class="dropdown-menu" role="menu">
                    <li>
                         <a href="#" onclick="return set_admintask_status(\'' . $task->getName() . '\', ' . ($task->isEnabled() ? 'false' : 'true') . ');">
                             <i class="fa fa-fw ' . ($task->isEnabled() ? 'fa-times' : 'fa-check') . '"></i> ' . ($task->isEnabled() ? I18N::translate('Disable') : I18N::translate('Enable')) . '
                         </a>
                    </li>
                     <li>
                         <a href="module.php?mod=' . $this->module->getName() . '&mod_action=Task@edit&task=' . $task->getName() . '">
                             <i class="fa fa-fw fa-pencil"></i> ' . I18N::translate('Edit') . '
                         </a>
                    </li>
                 </ul>
             </div>';
         $datum[1] = $task->getName();
         $datum[2] = $task->isEnabled() ? '<i class="fa fa-check"></i><span class="sr-only">' . I18N::translate('Enabled') . '</span>' : '<i class="fa fa-times"></i><span class="sr-only">' . I18N::translate('Disabled') . '</span>';
         $datum[3] = $task->getTitle();
         $date_format = str_replace('%', '', I18N::dateFormat()) . ' H:i:s';
         $datum[4] = $task->getLastUpdated()->format($date_format);
         $datum[5] = $task->isLastRunSuccess() ? '<i class="fa fa-check"></i><span class="sr-only">' . I18N::translate('Yes') . '</span>' : '<i class="fa fa-times"></i><span class="sr-only">' . I18N::translate('No') . '</span>';
         $dtF = new \DateTime('@0');
         $dtT = new \DateTime('@' . $task->getFrequency() * 60);
         $datum[6] = $dtF->diff($dtT)->format(I18N::translate('%a d %h h %i m'));
         $datum[7] = $task->getRemainingOccurrences() > 0 ? I18N::number($task->getRemainingOccurrences()) : I18N::translate('Unlimited');
         $datum[8] = $task->isRunning() ? '<i class="fa fa-cog fa-spin fa-fw"></i><span class="sr-only">' . I18N::translate('Running') . '</span>' : '<i class="fa fa-times"></i><span class="sr-only">' . I18N::translate('Not running') . '</span>';
         if ($task->isEnabled() && !$task->isRunning()) {
             $datum[9] = '
 			    <button id="bt_runtask_' . $task->getName() . '" class="btn btn-primary" href="#" onclick="return run_admintask(\'' . $task->getName() . '\')">
 			         <div id="bt_runtasktext_' . $task->getName() . '"><i class="fa fa-cog fa-fw" ></i>' . I18N::translate('Run') . '</div>
 			    </button>';
         } else {
             $datum[9] = '';
         }
         $data[] = $datum;
     }
     $controller->pageHeader();
     $controller->encode(array('draw' => Filter::getInteger('draw'), 'recordsTotal' => $recordsTotal, 'recordsFiltered' => $recordsFiltered, 'data' => $data));
 }
示例#11
0
 /**
  * Get a list of all modules, enabled or not, which provide a specific function.
  *
  * We cannot currently use auto-loading for modules, as there may be user-defined
  * modules about which the auto-loader knows nothing.
  *
  * @param string $component The type of module, such as "tab", "report" or "menu"
  *
  * @return AbstractModule[]
  */
 public static function getAllModulesByComponent($component)
 {
     $module_names = Database::prepare("SELECT SQL_CACHE module_name" . " FROM `##module`" . " ORDER BY CASE :component WHEN 'menu' THEN menu_order WHEN 'sidebar' THEN sidebar_order WHEN 'tab' THEN tab_order ELSE 0 END, module_name")->execute(array('component' => $component))->fetchOneColumn();
     $array = array();
     foreach ($module_names as $module_name) {
         $interface = '\\Fisharebest\\Webtrees\\Module\\Module' . ucfirst($component) . 'Interface';
         $module = self::getModuleByName($module_name);
         if ($module instanceof $interface) {
             $array[$module_name] = $module;
         }
     }
     // The order of menus/sidebars/tabs is defined in the database. Others are sorted by name.
     if ($component !== 'menu' && $component !== 'sidebar' && $component !== 'tab') {
         uasort($array, function (AbstractModule $x, AbstractModule $y) {
             return I18N::strcasecmp($x->getTitle(), $y->getTitle());
         });
     }
     return $array;
 }