_observers[$observer->getObserverName()][] = &$observer; } function notifyAll(&$event) { assert(is_a($event, 'FANamedObservableEvent')); $ret = FALSE; if (isset($this->_observers[$event->getEventName()])) { $it = &new FAArrayIterator($this->_observers[$event->getEventName()]); while ($it->next()) { $observer = &$it->current(); if ($ret = (bool)$observer->notify($event)) { break; } } } return $ret; } } class FADispatcher { var $_observers = array(); function addObserver(&$observer) { assert(is_a($observer, 'FAObserver')); $this->_observers[] = &$observer; } function notifyAll(&$event) { assert(is_a($event, 'FAObservableEvent')); $ret = FALSE; $it = &new FAArrayIterator($this->_observers); while ($it->next()) { $observer = &$it->current(); if ($ret = (bool)$observer->notify($event)) { break; } } return $ret; } } class FADependencyDispatcher extends FADispatcher { var $_unsatisfied = array(); function addObserver(&$observer) { assert(is_a($observer, 'FADependencyObserver')); $id = $observer->getObserverName(); $dependencies = $observer->getDependencies(); $satisfied = array(); $inserted = FALSE; foreach ($this->_observers as $pos => $current) { $name = $current->getObserverName(); if (isset($this->_unsatisfied[$name])) { // Check whether the new filter satisfies one of the current filter's // dependencies if (($key = array_search($id, $this->_unsatisfied[$name])) !== FALSE) { unset($this->_unsatisfied[$name][$key]); // Insert the filter if it has not already be inserted if (!$inserted) { // Insert the filter at the current position array_splice($this->_observers, $pos, 0, array(&$observer)); $inserted = TRUE; } } if (empty($this->_unsatisfied[$name])) unset($this->_unsatisfied[$name]); } // Check whether the current filter satisfies one of the new filter's // dependencies if (($key = array_search($name, $dependencies)) !== FALSE) { // Check for circular dependencies. ie: the new filter has already // been added to satisfy a dependency, but one of its dependencies // is after it if ($inserted) trigger_error("Circular dependency for $id and $name", E_USER_ERROR); else unset($dependencies[$key]); if ($name == $id && !$inserted && empty($dependencies)) { // Insert the filter after the current position array_splice($this->_observers, $pos + 1, 0, array(&$observer)); $inserted = TRUE; } } } // Add the filter if it has not yet been added if (!$inserted) $this->_observers[] = &$observer; if (!empty($dependencies)) $this->_unsatisfied[$id] = $dependencies; } function notifyAll(&$event) { if (!empty($this->_unsatisfied)) { $sep = ''; $unsatisfied = ''; foreach ($this->_unsatisfied as $filter => $unsatisfied) { $unsatisfied .= "$sep$filter: " . implode(', ', $unsatisfied); $sep = '; '; } trigger_error("Unsatisfied dependencies for filter(s) $unsatisfied", E_USER_ERROR); } return parent::notifyAll($event); } } class FAMixedDispatcher { var $_dependency; var $_global; var $_named; function FAMixedDispatcher() { $this->_dependency = &new FADependencyDispatcher; $this->_global = &new FADispatcher; $this->_named = &new FANamedDispatcher; } function addObserver(&$observer) { if (is_a($observer, 'FADependencyObserver')) { $this->_dependency->addObserver($observer); } elseif (is_a($observer, 'FANamedObserver')) { $this->_named->addObserver($observer); } else { $this->_global->addObserver($observer); } } function notifyAll(&$event) { $ret = FALSE; $ret = ($ret) ? $ret : $this->_dependency->notifyAll($event); $ret = ($ret) ? $ret : $this->_named->notifyAll($event); $ret = ($ret) ? $ret : $this->_global->notifyAll($event); return $ret; } } ?>