FieldChain.inc 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. <?php
  2. /**
  3. * @file
  4. * Contains the FieldChain class.
  5. */
  6. /**
  7. * @class
  8. * A doubly linked list of FieldInstance objects.
  9. */
  10. class FieldChain implements SeekableIterator {
  11. protected $chain = array();
  12. protected $index = 0;
  13. /**
  14. * Magic post-unserialization callback. Provides every field in the chain
  15. * with a reference to its parent (if any) and child (if any), effectively
  16. * turning the chain into a doubly linked list.
  17. */
  18. public function __wakeup() {
  19. foreach ($this->chain as $field) {
  20. if (isset($parent)) {
  21. $field->parent($parent)->child($field);
  22. }
  23. $parent = $field;
  24. }
  25. }
  26. /**
  27. * Represents this chain as a machine-readable string, separating the fields
  28. * with a T_PAAMAYIM_NEKUDOTAYIM (or, as we call it on planet Earth, a
  29. * double colon).
  30. */
  31. public function __toString() {
  32. $key = array();
  33. foreach ($this->chain as $field) {
  34. $key[] = $field->__toString();
  35. }
  36. return implode('::', $key);
  37. }
  38. /**
  39. * Prepends a field instance to this chain. If $completed is passed, we'll
  40. * try to find the parents of the instance and recurse upwards, building
  41. * a tree of "routes" to the instance.
  42. */
  43. public function addField(FieldInstance $field, array &$completed = NULL) {
  44. array_unshift($this->chain, $field);
  45. $this->__wakeup();
  46. if (isset($completed)) {
  47. $parents = $field->getParents();
  48. if ($parents) {
  49. foreach ($parents as $parent) {
  50. $branch = clone $this;
  51. $branch->addField($parent, $completed);
  52. }
  53. }
  54. else {
  55. $completed[] = $this;
  56. }
  57. }
  58. }
  59. /**
  60. * Returns the last field in the chain.
  61. */
  62. public function end() {
  63. return end($this->chain);
  64. }
  65. /**
  66. * Implements SeekableIterator::seek().
  67. */
  68. public function seek($position) {
  69. if ($position >= 0 && $position < sizeof($this->chain)) {
  70. $this->index = $position;
  71. }
  72. else {
  73. throw new OutOfBoundsException(t('Cannot seek to invalid position %position.', array('%position' => $position)));
  74. }
  75. }
  76. /**
  77. * Implements Iterator::current().
  78. */
  79. public function current() {
  80. return $this->chain[$this->index];
  81. }
  82. /**
  83. * Implements Iterator::key().
  84. */
  85. public function key() {
  86. return $this->current()->__toString();
  87. }
  88. /**
  89. * Implements Iterator::next().
  90. */
  91. public function next() {
  92. $this->index++;
  93. }
  94. /**
  95. * Implements Iterator::rewind().
  96. */
  97. public function rewind() {
  98. $this->index = 0;
  99. }
  100. /**
  101. * Implements Iterator::valid().
  102. */
  103. public function valid() {
  104. return ($this->index < sizeof($this->chain));
  105. }
  106. }