1<?php 2// src/groupedextensions.php -- HotCRP extensible groups 3// Copyright (c) 2006-2018 Eddie Kohler; see LICENSE. 4 5class GroupedExtensions { 6 private $_subgroups; 7 static private $next_placeholder; 8 9 function _add_json($fj) { 10 if (!isset($fj->name)) { 11 $fj->name = "__" . self::$next_placeholder . "__"; 12 ++self::$next_placeholder; 13 } 14 if (!isset($fj->group)) { 15 if (($pos = strrpos($fj->name, "/")) !== false) 16 $fj->group = substr($fj->name, 0, $pos); 17 else 18 $fj->group = $fj->name; 19 } 20 if (!isset($fj->synonym)) 21 $fj->synonym = []; 22 else if (is_string($fj->synonym)) 23 $fj->synonym = [$fj->synonym]; 24 if (!isset($fj->anchorid) 25 && !str_starts_with($fj->name, "__") 26 && ($pos = strpos($fj->name, "/")) !== false) { 27 $x = substr($fj->name, $pos + 1); 28 $fj->anchorid = preg_replace('/\A[^A-Za-z]+|[^A-Za-z0-9_:.]+/', "-", strtolower($x)); 29 } 30 $this->_subgroups[] = $fj; 31 return true; 32 } 33 function __construct(Contact $user, $args /* ... */) { 34 self::$next_placeholder = 1; 35 $this->_subgroups = []; 36 foreach (func_get_args() as $i => $arg) { 37 if ($i > 0 && $arg) 38 expand_json_includes_callback($arg, [$this, "_add_json"]); 39 } 40 usort($this->_subgroups, "Conf::xt_priority_compare"); 41 $sgs = []; 42 foreach ($this->_subgroups as $gj) { 43 if ($user->conf->xt_allowed($gj, $user)) { 44 if (isset($sgs[$gj->name])) { 45 $pgj = $sgs[$gj->name]; 46 if (isset($pgj->merge) && $pgj->merge) { 47 unset($pgj->merge); 48 $sgs[$gj->name] = object_replace_recursive($gj, $pgj); 49 } 50 } else 51 $sgs[$gj->name] = $gj; 52 } 53 } 54 $this->_subgroups = []; 55 foreach ($sgs as $name => $gj) { 56 if (Conf::xt_enabled($gj)) 57 $this->_subgroups[$name] = $gj; 58 } 59 uasort($this->_subgroups, function ($aj, $bj) { 60 if ($aj->group !== $bj->group) { 61 if (isset($this->_subgroups[$aj->group])) 62 $aj = $this->_subgroups[$aj->group]; 63 if (isset($this->_subgroups[$bj->group])) 64 $bj = $this->_subgroups[$bj->group]; 65 } 66 return Conf::xt_position_compare($aj, $bj); 67 }); 68 } 69 function get($name) { 70 if (isset($this->_subgroups[$name])) 71 return $this->_subgroups[$name]; 72 foreach ($this->_subgroups as $gj) { 73 if (in_array($name, $gj->synonym)) 74 return $gj; 75 } 76 return null; 77 } 78 function canonical_group($name) { 79 $gj = $this->get($name); 80 return $gj ? $gj->group : false; 81 } 82 function members($name) { 83 if ((string) $name === "") 84 return $this->groups(); 85 if (($subgroup = str_ends_with($name, "/*"))) 86 $name = substr($name, 0, -2); 87 if (($gj = $this->get($name))) 88 $name = $gj->name; 89 return array_filter($this->_subgroups, function ($gj) use ($name, $subgroup) { 90 return $gj->name === $name ? !$subgroup : $gj->group === $name; 91 }); 92 } 93 function all() { 94 return $this->_subgroups; 95 } 96 function groups() { 97 return array_filter($this->_subgroups, function ($gj) { 98 return $gj->name === $gj->group; 99 }); 100 } 101 static function render_heading($gj, &$last_title = null, 102 $h = 3, $className = null) { 103 if (isset($gj->title) 104 && $gj->title !== $last_title 105 && $gj->group !== $gj->name) { 106 echo '<h', $h; 107 if ($className) 108 echo ' class="', $className, '"'; 109 if (isset($gj->anchorid)) 110 echo ' id="', htmlspecialchars($gj->anchorid), '"'; 111 echo '>', $gj->title, "</h$h>\n"; 112 $last_title = $gj->title; 113 } 114 } 115} 116