@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
at upstream/main 266 lines 7.1 kB view raw
1<?php 2 3/** 4 * Interface to the static resource map, which is a graph of available 5 * resources, resource dependencies, and packaging information. You generally do 6 * not need to invoke it directly; instead, you call higher-level Celerity APIs 7 * and it uses the resource map to satisfy your requests. 8 */ 9final class CelerityResourceMap extends Phobject { 10 11 private static $instances = array(); 12 13 private $resources; 14 private $symbolMap; 15 private $requiresMap; 16 private $packageMap; 17 private $nameMap; 18 private $hashMap; 19 private $componentMap; 20 21 public function __construct(CelerityResources $resources) { 22 $this->resources = $resources; 23 24 $map = $resources->loadMap(); 25 $this->symbolMap = idx($map, 'symbols', array()); 26 $this->requiresMap = idx($map, 'requires', array()); 27 $this->packageMap = idx($map, 'packages', array()); 28 $this->nameMap = idx($map, 'names', array()); 29 30 // We derive these reverse maps at runtime. 31 32 $this->hashMap = array_flip($this->nameMap); 33 $this->componentMap = array(); 34 foreach ($this->packageMap as $package_name => $symbols) { 35 foreach ($symbols as $symbol) { 36 $this->componentMap[$symbol] = $package_name; 37 } 38 } 39 } 40 41 public static function getNamedInstance($name) { 42 if (empty(self::$instances[$name])) { 43 $resources_list = CelerityPhysicalResources::getAll(); 44 if (empty($resources_list[$name])) { 45 throw new Exception( 46 pht( 47 'No resource source exists with name "%s"!', 48 $name)); 49 } 50 51 $instance = new CelerityResourceMap($resources_list[$name]); 52 self::$instances[$name] = $instance; 53 } 54 55 return self::$instances[$name]; 56 } 57 58 public function getNameMap() { 59 return $this->nameMap; 60 } 61 62 public function getSymbolMap() { 63 return $this->symbolMap; 64 } 65 66 public function getRequiresMap() { 67 return $this->requiresMap; 68 } 69 70 public function getPackageMap() { 71 return $this->packageMap; 72 } 73 74 public function getPackagedNamesForSymbols(array $symbols) { 75 $resolved = $this->resolveResources($symbols); 76 return $this->packageResources($resolved); 77 } 78 79 private function resolveResources(array $symbols) { 80 $map = array(); 81 foreach ($symbols as $symbol) { 82 if (!empty($map[$symbol])) { 83 continue; 84 } 85 $this->resolveResource($map, $symbol); 86 } 87 88 return $map; 89 } 90 91 private function resolveResource(array &$map, $symbol) { 92 if (empty($this->symbolMap[$symbol])) { 93 throw new Exception( 94 pht( 95 'Attempting to resolve unknown resource, "%s".', 96 $symbol)); 97 } 98 99 $hash = $this->symbolMap[$symbol]; 100 101 $map[$symbol] = $hash; 102 103 if (isset($this->requiresMap[$hash])) { 104 $requires = $this->requiresMap[$hash]; 105 } else { 106 $requires = array(); 107 } 108 109 foreach ($requires as $required_symbol) { 110 if (!empty($map[$required_symbol])) { 111 continue; 112 } 113 $this->resolveResource($map, $required_symbol); 114 } 115 } 116 117 private function packageResources(array $resolved_map) { 118 $packaged = array(); 119 $handled = array(); 120 foreach ($resolved_map as $symbol => $hash) { 121 if (isset($handled[$symbol])) { 122 continue; 123 } 124 125 if (empty($this->componentMap[$symbol])) { 126 $packaged[] = $this->hashMap[$hash]; 127 } else { 128 $package_name = $this->componentMap[$symbol]; 129 $packaged[] = $package_name; 130 131 $package_symbols = $this->packageMap[$package_name]; 132 foreach ($package_symbols as $package_symbol) { 133 $handled[$package_symbol] = true; 134 } 135 } 136 } 137 138 return $packaged; 139 } 140 141 public function getResourceDataForName($resource_name) { 142 return $this->resources->getResourceData($resource_name); 143 } 144 145 public function getResourceNamesForPackageName($package_name) { 146 $package_symbols = idx($this->packageMap, $package_name); 147 if (!$package_symbols) { 148 return null; 149 } 150 151 $resource_names = array(); 152 foreach ($package_symbols as $symbol) { 153 $resource_names[] = $this->hashMap[$this->symbolMap[$symbol]]; 154 } 155 156 return $resource_names; 157 } 158 159 160 /** 161 * Get the epoch timestamp of the last modification time of a symbol. 162 * 163 * @param string $name Resource symbol to lookup. 164 * @return int Epoch timestamp of last resource modification. 165 */ 166 public function getModifiedTimeForName($name) { 167 if ($this->isPackageResource($name)) { 168 $names = array(); 169 foreach ($this->packageMap[$name] as $symbol) { 170 $names[] = $this->getResourceNameForSymbol($symbol); 171 } 172 } else { 173 $names = array($name); 174 } 175 176 $mtime = 0; 177 foreach ($names as $name) { 178 $mtime = max($mtime, $this->resources->getResourceModifiedTime($name)); 179 } 180 181 return $mtime; 182 } 183 184 185 /** 186 * Return the absolute URI for the resource associated with a symbol. This 187 * method is fairly low-level and ignores packaging. 188 * 189 * @param string $symbol Resource symbol to lookup. 190 * @return string|null Resource URI, or null if the symbol is unknown. 191 */ 192 public function getURIForSymbol($symbol) { 193 $hash = idx($this->symbolMap, $symbol); 194 return $this->getURIForHash($hash); 195 } 196 197 198 /** 199 * Return the absolute URI for the resource associated with a resource name. 200 * This method is fairly low-level and ignores packaging. 201 * 202 * @param string $name Resource name to lookup. 203 * @return string|null Resource URI, or null if the name is unknown. 204 */ 205 public function getURIForName($name) { 206 $hash = idx($this->nameMap, $name); 207 return $this->getURIForHash($hash); 208 } 209 210 211 public function getHashForName($name) { 212 return idx($this->nameMap, $name); 213 } 214 215 216 /** 217 * Return the absolute URI for a resource, identified by hash. 218 * This method is fairly low-level and ignores packaging. 219 * 220 * @param string $hash Resource hash to lookup. 221 * @return string|null Resource URI, or null if the hash is unknown. 222 */ 223 private function getURIForHash($hash) { 224 if ($hash === null) { 225 return null; 226 } 227 return $this->resources->getResourceURI($hash, $this->hashMap[$hash]); 228 } 229 230 231 /** 232 * Return the resource symbols required by a named resource. 233 * 234 * @param string $name Resource name to lookup. 235 * @return list<string>|null List of required symbols, or null if the name 236 * is unknown. 237 */ 238 public function getRequiredSymbolsForName($name) { 239 $hash = idx($this->nameMap, $name); 240 if ($hash === null) { 241 return null; 242 } 243 return idx($this->requiresMap, $hash, array()); 244 } 245 246 247 /** 248 * Return the resource name for a given symbol. 249 * 250 * @param string $symbol Resource symbol to lookup. 251 * @return string|null Resource name, or null if the symbol is unknown. 252 */ 253 public function getResourceNameForSymbol($symbol) { 254 $hash = idx($this->symbolMap, $symbol); 255 return idx($this->hashMap, $hash); 256 } 257 258 public function isPackageResource($name) { 259 return isset($this->packageMap[$name]); 260 } 261 262 public function getResourceTypeForName($name) { 263 return $this->resources->getResourceType($name); 264 } 265 266}