Aggregate Code Coverage for all tests
1 : <?php 2 : /** 3 : * PEAR2_Pyrus_PackageFile_v2_Dependencies 4 : * 5 : * PHP version 5 6 : * 7 : * @category PEAR2 8 : * @package PEAR2_Pyrus 9 : * @author Greg Beaver <cellog@php.net> 10 : * @copyright 2008 The PEAR Group 11 : * @license http://www.opensource.org/licenses/bsd-license.php New BSD License 12 : * @version SVN: $Id$ 13 : * @link http://svn.pear.php.net/wsvn/PEARSVN/Pyrus/ 14 : */ 15 : 16 : /** 17 : * Manage dependencies 18 : * 19 : * To be used like: 20 : * <code> 21 : * // reset deps 22 : * $pf->dependencies = null; 23 : * // for PHP dep 24 : * // defaults to min 25 : * $pf->dependencies->required->php = '5.3.0'; 26 : * $pf->dependencies->required->php = array('min' => '5.3.0', 'max' => '7.0.0', 27 : * 'exclude' => array('6.1.2')); 28 : * // for PEAR Installer dep 29 : * // defaults to min 30 : * $pf->dependencies->required->pearinstaller = '2.0.0'; 31 : * $pf->dependencies->required->pearinstaller = array('min' => '2.0.0'); 32 : * // for required/optional package deps or subpackage deps 33 : * $pf->dependencies->required->package['channel/PackageName'] = 34 : * array('min' => '1.1.0', 'max' => '1.2.0', 'recommended' => '1.1.1', 35 : * 'exclude' => array('1.1.0a1', '1.1.0a2')); 36 : * $pf->dependencies->optional->package['channel/PackageName'] = 37 : * array('min' => '1.1.0', 'max' => '1.2.0', 'recommended' => '1.1.1', 38 : * 'exclude' => array('1.1.0a1', '1.1.0a2')); 39 : * $pf->dependencies->required->subpackage['channel/PackageName'] = 40 : * array('min' => '1.1.0', 'max' => '1.2.0', 'recommended' => '1.1.1', 41 : * 'exclude' => array('1.1.0a1', '1.1.0a2')); 42 : * // for conflicting package dep 43 : * $pf->dependencies->required->subpackage['channel/PackageName'] = 44 : * array('min' => '1.1.0', 'max' => '1.2.0', 'recommended' => '1.1.1', 45 : * 'exclude' => array('1.1.0a1', '1.1.0a2'), 'conflicts' => ''); 46 : * // for PECL extension deps (optional or required same as packages) 47 : * $pf->dependencies->required->package['channel/PackageName'] = 48 : * array('min' => '1.1.0', 'max' => '1.2.0', 'recommended' => '1.1.1', 49 : * 'exclude' => array('1.1.0a1', '1.1.0a2'), 'providesextension' => 'packagename'); 50 : * // for extension deps (required or optional same as packages) 51 : * $pf->dependencies->required->extension['extension'] = 52 : * array('min' => '1.0.0', 'max' => '1.2.0', 'recommended' => '1.1.1'); 53 : * // for regular arch deps 54 : * $pf->dependencies->required->arch['i386'] = true // only works on i386 55 : * // for conflicting arch deps 56 : * $pf->dependencies->required->arch['*(ix|ux)'] = false // doesn't work on unix/linux 57 : * // for regular OS deps 58 : * $pf->dependencies->required->os['windows'] = true; // only works on windows 59 : * // for conflicting OS deps 60 : * $pf->dependencies->required->os['freebsd'] = false; // doesn't work on FreeBSD 61 : * 62 : * // dependency group setup 63 : * $group = $pf->dependencies->group['name']->hint('Install optional stuff as a group'); 64 : * $group->package['channel/PackageName1'] = array(); 65 : * $group->package['channel/PackageName2'] = array('min' => '1.2.0'); 66 : * $group->subpackage['channel/PackageName3'] = array('recommended' => '1.2.1'); 67 : * $group->extension['extension'] = array(); 68 : * </code> 69 : * 70 : * @category PEAR2 71 : * @package PEAR2_Pyrus 72 : * @author Greg Beaver <cellog@php.net> 73 : * @copyright 2008 The PEAR Group 74 : * @license http://www.opensource.org/licenses/bsd-license.php New BSD License 75 : * @link http://svn.pear.php.net/wsvn/PEARSVN/Pyrus/ 76 : */ 77 1 : class PEAR2_Pyrus_PackageFile_v2_Dependencies implements ArrayAccess, Iterator, Countable 78 : { 79 : private $_parent; 80 : private $_packageInfo; 81 : private $_required; 82 : private $_group = null; 83 : private $_package; 84 : private $_type; 85 : private $_pos = 0; 86 : private $_count = 0; 87 : private $_info = array(); 88 : function __construct(array &$parent, array &$packageInfo, $required = null, $type = null, 89 : $package = null, $group = null) 90 : { 91 1 : $this->_parent = &$parent; 92 1 : $this->_packageInfo = &$packageInfo; 93 1 : if (!$required) return; 94 1 : if (!in_array($required, array('required', 'optional', 'group'), true)) { 95 : throw new PEAR2_Pyrus_PackageFile_v2_Dependencies_Exception( 96 : 'Internal error: $required is not required/optional/group'); 97 : } 98 1 : $this->_required = $required; 99 1 : if (!isset($parent[$required])) { 100 1 : $parent[$required] = array(); 101 1 : $this->_packageInfo = &$parent; 102 1 : } 103 1 : if ($this->_required != 'group' && $group) { 104 : throw new PEAR2_Pyrus_PackageFile_v2_Dependencies_Exception( 105 : 'Internal error: $group passed into required dependency'); 106 1 : } elseif ($group) { 107 1 : if (!is_string($group)) { 108 : throw new PEAR2_Pyrus_PackageFile_v2_Dependencies_Exception( 109 : 'Internal error: $group must be a string'); 110 : } 111 1 : $this->_packageInfo = &$parent['group']; 112 1 : $this->_group = $group; 113 : // locate group in the xml and initialize if not present 114 1 : if (!count($this->_packageInfo)) { 115 1 : $this->_packageInfo = 116 1 : array('attribs' => array('name' => $group, 'hint' => '')); 117 1 : } elseif (!isset($this->_packageInfo[0])) { 118 1 : if ($this->_packageInfo['attribs']['name'] != $group) { 119 : $this->_packageInfo = array($this->_packageInfo, 120 : array('attribs' => array('name' => $group, 'hint' => ''))); 121 : $this->_packageInfo = &$this->_packageInfo[1]; 122 : } 123 1 : } else { 124 : $found = false; 125 : foreach ($this->_packageInfo as $i => $g) { 126 : if ($g['attribs']['name'] == $group) { 127 : $this->_packageInfo = &$this->_packageInfo[$i]; 128 : $found = true; 129 : break; 130 : } 131 : } 132 : if (!$found) { 133 : $this->_packageInfo[$i = count($this->_packageInfo)] = 134 : array('attribs' => array('name' => $group, 'hint' => '')); 135 : } 136 : } 137 1 : } elseif (!$type) { 138 1 : $this->_packageInfo = &$this->_packageInfo[$this->_required]; 139 1 : } 140 1 : if (!$type) { 141 1 : if (count($this->_packageInfo)) { 142 1 : if (isset($this->_packageInfo[0])) { 143 : $this->_count = count($this->_packageInfo); 144 : } else { 145 1 : $this->_count = 1; 146 : } 147 1 : } 148 1 : return; 149 : } 150 1 : if (!is_string($type)) { 151 : throw new PEAR2_Pyrus_PackageFile_v2_Dependencies_Exception( 152 : 'Internal error: $type is not a string, but is a ' . gettype($type)); 153 : } 154 1 : if ($required == 'required') { 155 : switch ($type) { 156 1 : case 'php' : 157 1 : case 'pearinstaller' : 158 1 : case 'package' : 159 1 : case 'subpackage' : 160 1 : case 'extension' : 161 1 : case 'arch' : 162 1 : case 'os' : 163 1 : $this->_type = $type; 164 1 : if (!isset($this->_packageInfo[$type])) { 165 1 : $this->_packageInfo[$type] = array(); 166 1 : } 167 1 : $this->_packageInfo = &$this->_packageInfo[$type]; 168 1 : break; 169 : default : 170 : throw new PEAR2_Pyrus_PackageFile_v2_Dependencies_Exception( 171 : 'Unknown dependency type ' . $type); 172 : } 173 1 : } else { 174 : switch ($type) { 175 1 : case 'package' : 176 1 : case 'subpackage' : 177 1 : case 'extension' : 178 1 : $this->_type = $type; 179 1 : if (!isset($this->_packageInfo[$type])) { 180 1 : $this->_packageInfo[$type] = array(); 181 1 : } 182 1 : $this->_packageInfo = &$this->_packageInfo[$type]; 183 1 : break; 184 : case 'php' : 185 : case 'pearinstaller' : 186 : case 'arch' : 187 : case 'os' : 188 : default : 189 : throw new PEAR2_Pyrus_PackageFile_v2_Dependencies_Exception( 190 : $type . ' dependency cannot be optional'); 191 : } 192 : } 193 1 : if (count($this->_packageInfo)) { 194 1 : if (isset($this->_packageInfo[0])) { 195 1 : $this->_count = count($this->_packageInfo); 196 1 : } else { 197 1 : $this->_count = 1; 198 : } 199 1 : } else { 200 1 : $this->_count = 0; 201 : } 202 1 : if (!$package) return; 203 : switch ($this->_type) { 204 : case 'php' : 205 : case 'pearinstaller' : 206 : throw new PEAR2_Pyrus_PackageFile_v2_Dependencies_Exception( 207 : 'Internal error: $package passed into ' . $type . ' dependency'); 208 : case 'package' : 209 : case 'subpackage' : 210 : $channel = explode('/', $package); 211 : $package = array_pop($channel); 212 : $channel = implode('/', $channel); 213 : $this->_info['name'] = $package; 214 : $this->_info['channel'] = $channel; 215 : $this->_package = true; 216 : break; 217 : case 'os' : 218 : case 'extension' : 219 : $this->_info['name'] = $package; 220 : $this->_package = true; 221 : break; 222 : case 'arch' : 223 : $this->_info['pattern'] = $package; 224 : $this->_package = true; 225 : break; 226 : } 227 : if (!isset($this->_packageInfo[0])) { 228 : $name = ($this->_type == 'arch') ? 'pattern' : 'name'; 229 : if ($this->_packageInfo[$name] != $package) { 230 : $this->_packageInfo = array($this->_packageInfo, array($name => $package)); 231 : $this->_packageInfo = &$this->_packageInfo[1]; 232 : } 233 : } else { 234 : foreach ($this->_packageInfo as $i => $dep) { 235 : if ($dep[$name] == $package) { 236 : $this->_packageInfo = &$this->_packageInfo[$i]; 237 : return; 238 : } 239 : } 240 : $this->_packageInfo[$i = count($this->_packageInfo)] = array($name => $package); 241 : $this->_packageInfo = &$this->_packageInfo[$i]; 242 : } 243 : } 244 : 245 : function __get($var) 246 : { 247 1 : if (!isset($this->_required)) { 248 1 : return new PEAR2_Pyrus_PackageFile_v2_Dependencies($this->_parent, 249 1 : $this->_packageInfo, $var); 250 : } 251 1 : if (!isset($this->_type)) { 252 1 : if (isset($this->_group)) { 253 1 : return new PEAR2_Pyrus_PackageFile_v2_Dependencies( 254 1 : $this->_parent, $this->_packageInfo, $this->_required, 255 1 : $var, null, $this->_group); 256 : } else { 257 1 : return new PEAR2_Pyrus_PackageFile_v2_Dependencies( 258 1 : $this->_parent, $this->_packageInfo, $this->_required, 259 1 : $var); 260 : } 261 : } 262 : if ($this->_type == 'group' && !isset($this->_group)) { 263 : throw new PEAR2_Pyrus_PackageFile_v2_Dependencies_Exception( 264 : 'Dependency group must be accessed like $pf->group[\'groupname\']'); 265 : } 266 : if (!isset($this->_package) && $this->_type != 'php' && $this->_type != 'pearinstaller') { 267 : return new PEAR2_Pyrus_PackageFile_v2_Dependencies( 268 : $this->_parent, $this->_packageInfo[$var], $this->_required, 269 : $this->_type, $var); 270 : } 271 : if (!isset($this->_packageInfo[$var])) { 272 : return null; 273 : } 274 : return $this->_packageInfo[$var]; 275 : } 276 : 277 : function __set($var, $value) 278 : { 279 : if (isset($this->_required) && $this->_required == 'required' 280 : && in_array($var, array('php', 'pearinstaller'), true)) { 281 : if (is_string($value)) { 282 : $value = array('min' => $value); 283 : } 284 : if (!is_array($value)) { 285 : throw new PEAR2_Pyrus_PackageFile_v2_Dependencies_Exception( 286 : $var . ' dependency must be an array, was a ' . gettype($value)); 287 : } 288 : $info = array(); 289 : foreach (array('min', 'max', 'exclude') as $index) { 290 : if (isset($value[$index])) { 291 : $info[$index] = $value[$index]; 292 : } 293 : } 294 : $this->_packageInfo[$var] = $info; 295 : return; 296 : } 297 : throw new PEAR2_Pyrus_PackageFile_v2_Dependencies_Exception( 298 : 'Cannot set ' . $var . ' directly'); 299 : } 300 : 301 : function current() 302 : { 303 : if (!$this->valid()) return null; 304 : if ($this->_required === 'group' && !isset($this->_group)) { 305 : if (!isset($this->_type)) { 306 : if (!isset($this->_packageInfo[0])) { 307 : return new PEAR2_Pyrus_PackageFile_v2_Dependencies( 308 : $this->_parent, $this->_packageInfo, $this->_required, 309 : $this->_type, null, $this->_packageInfo['attribs']['name']); 310 : } else { 311 : return new PEAR2_Pyrus_PackageFile_v2_Dependencies( 312 : $this->_parent, $this->_packageInfo, $this->_required, 313 : $this->_type, null, $this->_packageInfo[$this->_pos]['attribs']['name']); 314 : } 315 : } 316 : } 317 : if (!isset($this->_packageInfo[0])) { 318 : return $this->_packageInfo; 319 : } 320 : return $this->_packageInfo[$this->_pos]; 321 : } 322 : 323 : function next() 324 : { 325 : $this->_pos++; 326 : } 327 : 328 : function key() 329 : { 330 : if (!$this->valid()) return null; 331 : return $this->_pos; 332 : } 333 : 334 : function valid() 335 : { 336 : if (!$this->_count) { 337 : return false; 338 : } 339 : return $this->_pos < $this->_count; 340 : } 341 : 342 : function rewind() 343 : { 344 : $this->_pos = 0; 345 : } 346 : 347 : function count() 348 : { 349 : return $this->_count; 350 : } 351 : 352 : function hint($hint) 353 : { 354 1 : if ($this->_required !== 'group' || !$this->_group) { 355 : throw new PEAR2_Pyrus_PackageFile_v2_Dependencies_Exception( 356 : 'hint can only be set for dependency groups'); 357 : } 358 1 : $this->_packageInfo['attribs']['hint'] = $hint; 359 1 : return $this; 360 : } 361 : 362 : function offsetGet($var) 363 : { 364 1 : if ($this->_required == 'group' && !isset($this->_group)) { 365 1 : return new PEAR2_Pyrus_PackageFile_v2_Dependencies( 366 1 : $this->_parent, $this->_packageInfo, $this->_required, 367 1 : $this->_type, null, $var); 368 : } 369 : if (isset($this->_type) && in_array($this->_type, array('php', 'pearinstaller', 'arch', 'os'))) { 370 : return $this->_packageInfo[$var]; 371 : } 372 : return new PEAR2_Pyrus_PackageFile_v2_Dependencies( 373 : $this->_parent, $this->_packageInfo, $this->_required, 374 : $this->_type, $var, $this->_group); 375 : } 376 : 377 : function offsetSet($var, $value) 378 : { 379 1 : if (!isset($this->_required)) { 380 : throw new PEAR2_Pyrus_PackageFile_v2_Compatible_Exception( 381 : 'Cannot set ' . $var . ' directly, must specify required, optional, or group dependency first'); 382 : } 383 1 : if (isset($this->_type) && in_array($this->_type, array('package', 'subpackage'))) { 384 1 : if (!is_array($value)) { 385 : throw new PEAR2_Pyrus_PackageFile_v2_Dependencies_Exception( 386 : $this->_type . ' dependency must be an array, was a ' . gettype($value)); 387 : } 388 1 : $channel = explode('/', $var); 389 1 : $package = array_pop($channel); 390 1 : $channel = implode('/', $channel); 391 1 : $info = array('name' => $package, 'channel' => $channel); 392 1 : foreach (array('min', 'max', 'recommended', 'exclude', 'nodefault', 393 1 : 'conflicts', 'providesextension') as $index) { 394 1 : if (isset($value[$index])) { 395 1 : $info[$index] = $value[$index]; 396 1 : } 397 1 : } 398 1 : if (isset($this->_packageInfo[0])) { 399 1 : foreach ($this->_packageInfo as $i => $dep) { 400 1 : if ($dep['name'] === $package && $dep['channel'] === $channel) { 401 : $this->_packageInfo[$i] = $info; 402 : return; 403 : } 404 1 : } 405 1 : $this->_packageInfo[] = $info; 406 1 : } else { 407 1 : if (!count($this->_packageInfo)) { 408 1 : $this->_packageInfo = $info; 409 1 : return; 410 : } 411 1 : if ($this->_packageInfo['name'] === $package 412 1 : && $this->_packageInfo['channel'] === $channel) { 413 : $this->_packageInfo = $info; 414 : } else { 415 1 : $this->_packageInfo = array($this->_packageInfo, $info); 416 : } 417 : } 418 1 : return; 419 : } 420 1 : if (isset($this->_type) && $this->_type === 'extension') { 421 1 : if (!is_array($value)) { 422 : throw new PEAR2_Pyrus_PackageFile_v2_Dependencies_Exception( 423 : $this->_type . ' dependency must be an array, was a ' . gettype($value)); 424 : } 425 1 : $info = array('name' => $var); 426 1 : foreach (array('min', 'max', 'recommended', 'exclude', 'conflicts') as $index) { 427 1 : if (isset($value[$index])) { 428 1 : $info[$index] = $value[$index]; 429 1 : } 430 1 : } 431 1 : if (isset($this->_packageInfo[0])) { 432 : foreach ($this->_packageInfo as $i => $dep) { 433 : if ($dep['name'] === $var) { 434 : $this->_packageInfo[$i] = $info; 435 : return; 436 : } 437 : } 438 : $this->_packageInfo[] = $info; 439 : } else { 440 1 : if (!count($this->_packageInfo)) { 441 1 : $this->_packageInfo = $info; 442 1 : } elseif ($this->_packageInfo['name'] === $var) { 443 : $this->_packageInfo = $info; 444 : } else { 445 : $this->_packageInfo = array($this->_packageInfo, $info); 446 : } 447 : } 448 1 : return; 449 : } 450 : // $var is the os name or the arch name 451 : // $value is true or false, for defining required (true) or conflicts (false) 452 1 : if (isset($this->_type) && in_array($this->_type, array('arch', 'os'))) { 453 1 : $val = (bool) $value; 454 1 : $name = ($this->_type === 'arch' ? 'pattern' : 'name'); 455 1 : $info = array($name => $var); 456 1 : if (!$val) { 457 1 : $info['conflicts'] = ''; 458 1 : } 459 1 : if (isset($this->_packageInfo[0])) { 460 : foreach ($this->_packageInfo as $index => $dep) { 461 : if ($dep[$name] == $var) { 462 : $this->_packageInfo[$index] = $info; 463 : return; 464 : } 465 : } 466 : $this->_packageInfo[] = $info; 467 : } else { 468 1 : if (!count($this->_packageInfo) || $this->_packageInfo[$name] === $var) { 469 1 : $this->_packageInfo = $info; 470 1 : } else { 471 1 : $this->_packageInfo = array($this->_packageInfo, $info); 472 : } 473 : } 474 1 : } 475 1 : } 476 : 477 : /** 478 : * unimplemented 479 : * @param string $var 480 : */ 481 : function offsetUnset($var) 482 : { 483 : } 484 : 485 : /** 486 : * unimplemented 487 : * @param string $var 488 : * @return bool 489 : */ 490 : function offsetExists($var) 491 : { 492 : return isset($this->_packageInfo[$var]); 493 : } 494 1 : }