/** * @param \Rx\ObservableInterface $observable * @param \Rx\ObserverInterface $observer * @param \Rx\SchedulerInterface $scheduler * @return \Rx\DisposableInterface */ public function __invoke(ObservableInterface $observable, ObserverInterface $observer, SchedulerInterface $scheduler = null) { $isDisposed = false; $disposable = new CompositeDisposable(); $onError = function (\Exception $e) use(&$isDisposed, $observer, $observable, $scheduler, $disposable) { if ($isDisposed) { return; } try { /** @var Observable $result */ $result = call_user_func($this->errorSelector, $e, $observable); $subscription = $result->subscribe($observer, $scheduler); $disposable->add($subscription); } catch (\Exception $e) { $observer->onError($e); } }; $callbackObserver = new CallbackObserver([$observer, "onNext"], $onError, [$observer, "onCompleted"]); $subscription = $observable->subscribe($callbackObserver, $scheduler); $disposable->add($subscription); $disposable->add(new CallbackDisposable(function () use(&$isDisposed) { $isDisposed = true; })); return $disposable; }
public function __invoke(ObservableInterface $observable, ObserverInterface $observer, SchedulerInterface $scheduler = null) { $singleDisposable = new SingleAssignmentDisposable(); $disposable = new CompositeDisposable(); $disposable->add($singleDisposable); $callbackObserver = new CallbackObserver(function (Observable $x) use($disposable, $scheduler, $observer) { if ($this->hasCurrent) { return; } $this->hasCurrent = true; $inner = new SingleAssignmentDisposable(); $disposable->add($inner); $innerSub = $x->subscribe(new CallbackObserver([$observer, "onNext"], [$observer, "onError"], function () use($disposable, $inner, $observer) { $disposable->remove($inner); $this->hasCurrent = false; if ($this->isStopped && $disposable->count() === 1) { $observer->onCompleted(); } }), $scheduler); $inner->setDisposable($innerSub); }, [$observer, 'onError'], function () use($disposable, $observer) { $this->isStopped = true; if (!$this->hasCurrent && $disposable->count() === 1) { $observer->onCompleted(); } }); $singleDisposable->setDisposable($observable->subscribe($callbackObserver, $scheduler)); return $disposable; }
public function scheduleRecursive($action) { if (!is_callable($action)) { throw new InvalidArgumentException("Action should be a callable."); } $group = new CompositeDisposable(); $scheduler = $this; $recursiveAction = null; $recursiveAction = function () use($action, &$scheduler, &$group, &$recursiveAction) { $action(function () use(&$scheduler, &$group, &$recursiveAction) { $isAdded = false; $isDone = true; $d = $scheduler->schedule(function () use(&$isAdded, &$isDone, &$group, &$recursiveAction, &$d) { if (is_callable($recursiveAction)) { $recursiveAction(); } else { throw new \Exception("recursiveAction is not callable"); } if ($isAdded) { $group->remove($d); } else { $isDone = true; } }); if (!$isDone) { $group->add($d); $isAdded = true; } }); }; $group->add($this->schedule($recursiveAction)); return $group; }
/** * @inheritDoc */ public function __invoke(ObservableInterface $observable, ObserverInterface $observer, SchedulerInterface $scheduler = null) { if ($this->scheduler !== null) { $scheduler = $this->scheduler; } if ($scheduler === null) { throw new \Exception("You must use a scheduler that support non-zero delay."); } $lastScheduledTime = 0; $disposable = new CompositeDisposable(); $sourceDisposable = new EmptyDisposable(); $sourceDisposable = $observable->subscribe(new CallbackObserver(function ($x) use($scheduler, $observer, &$lastScheduledTime, $disposable) { $schedDisp = $scheduler->schedule(function () use($x, $observer, &$schedDisp, $disposable) { $observer->onNext($x); $disposable->remove($schedDisp); }, $this->delay); $disposable->add($schedDisp); }, function ($err) use($scheduler, $observer, &$lastScheduledTime, $disposable, &$sourceDisposable) { $disposable->remove($sourceDisposable); $sourceDisposable->dispose(); $observer->onError($err); }, function () use($scheduler, $observer, $disposable, &$sourceDisposable) { $disposable->remove($sourceDisposable); $sourceDisposable->dispose(); $schedDisp = $scheduler->schedule(function () use($observer, &$schedDisp, $disposable) { $observer->onCompleted(); $disposable->remove($schedDisp); }, $this->delay); $disposable->add($schedDisp); }), $scheduler); $disposable->add($sourceDisposable); return $disposable; }
/** * @param \Rx\ObservableInterface $observable * @param \Rx\ObserverInterface $observer * @param \Rx\SchedulerInterface $scheduler * @return \Rx\DisposableInterface */ public function __invoke(ObservableInterface $observable, ObserverInterface $observer, SchedulerInterface $scheduler = null) { $group = new CompositeDisposable(); $isStopped = false; $sourceSubscription = new SingleAssignmentDisposable(); $group->add($sourceSubscription); $callbackObserver = new CallbackObserver(function (ObservableInterface $innerSource) use(&$group, &$isStopped, $observer, &$scheduler) { $innerSubscription = new SingleAssignmentDisposable(); $group->add($innerSubscription); $innerSubscription->setDisposable($innerSource->subscribe(new CallbackObserver(function ($nextValue) use($observer) { $observer->onNext($nextValue); }, function ($error) use($observer) { $observer->onError($error); }, function () use(&$group, &$innerSubscription, &$isStopped, $observer) { $group->remove($innerSubscription); if ($isStopped && $group->count() === 1) { $observer->onCompleted(); } }), $scheduler)); }, [$observer, 'onError'], function () use(&$group, &$isStopped, $observer) { $isStopped = true; if ($group->count() === 1) { $observer->onCompleted(); } }); $subscription = $this->sources->subscribe($callbackObserver, $scheduler); $sourceSubscription->setDisposable($subscription); return $group; }
public function subscribe(ObserverInterface $observer, SchedulerInterface $scheduler = null) { $value = $this->value; $scheduler = $scheduler ?: new ImmediateScheduler(); $disposable = new CompositeDisposable(); $disposable->add($scheduler->schedule(function () use($observer, $value) { $observer->onNext($value); })); $disposable->add($scheduler->schedule(function () use($observer) { $observer->onCompleted(); })); return $disposable; }
public function subscribe(ObserverInterface $observer) { $this->subscriptions[] = new Subscription($this->scheduler->getClock()); $index = count($this->subscriptions) - 1; $currentObservable = $this; $disposable = new CompositeDisposable(); $scheduler = $this->scheduler; $isDisposed = false; foreach ($this->messages as $message) { $notification = $message->getValue(); $time = $message->getTime(); $schedule = function ($innerNotification) use(&$disposable, &$currentObservable, $observer, $scheduler, $time, &$isDisposed) { $disposable->add($scheduler->scheduleRelativeWithState(null, $time, function () use($observer, $innerNotification, &$isDisposed) { if (!$isDisposed) { $innerNotification->accept($observer); } return new EmptyDisposable(); })); }; $schedule($notification); } $subscriptions =& $this->subscriptions; return new CallbackDisposable(function () use(&$currentObservable, $index, $observer, $scheduler, &$subscriptions, &$isDisposed) { $isDisposed = true; $subscriptions[$index] = new Subscription($subscriptions[$index]->getSubscribed(), $scheduler->getClock()); }); }
/** * @inheritDoc */ public function __invoke(ObservableInterface $observable, ObserverInterface $observer, SchedulerInterface $scheduler = null) { $callbackObserver = new CallbackObserver(function (Observable $innerObservable) { $this->observables[] = $innerObservable; }, [$observer, 'onError'], function () use($observer, $scheduler) { if (count($this->observables) === 0) { $observer->onCompleted(); return; } foreach ($this->observables as $i => $innerObs) { $subscription = $this->subscribeToResult($innerObs, $scheduler, $observer, $i); $this->subscriptions[] = $subscription; $this->innerSubscription->add($subscription); } $this->observables = null; }); $subscription = $observable->subscribe($callbackObserver, $scheduler); return new BinaryDisposable($subscription, $this->innerSubscription); }
/** * @param ObservableInterface $observable * @param ObserverInterface $observer * @param SchedulerInterface|null $scheduler * @return CompositeDisposable */ public function __invoke(ObservableInterface $observable, ObserverInterface $observer, SchedulerInterface $scheduler = null) { $subscription = $observable->subscribe(new CallbackObserver(function (ObservableInterface $innerObservable) use($observable, $observer, $scheduler) { try { if ($this->startBuffering === true) { $this->buffer[] = $innerObservable; return; } $onCompleted = function () use(&$subscribeToInner, $observer) { $this->disposable->remove($this->innerDisposable); $this->innerDisposable->dispose(); $this->innerCompleted = true; $obs = array_shift($this->buffer); if (empty($this->buffer)) { $this->startBuffering = false; } if ($obs) { $subscribeToInner($obs); } elseif ($this->sourceCompleted === true) { $observer->onCompleted(); } }; $subscribeToInner = function ($observable) use($observer, $scheduler, &$onCompleted) { $callbackObserver = new CallbackObserver([$observer, 'onNext'], [$observer, 'onError'], $onCompleted); $this->innerCompleted = false; $this->startBuffering = true; $this->innerDisposable = $observable->subscribe($callbackObserver, $scheduler); $this->disposable->add($this->innerDisposable); }; $subscribeToInner($innerObservable); } catch (\Exception $e) { $observer->onError($e); } }, [$observer, 'onError'], function () use($observer) { $this->sourceCompleted = true; if ($this->innerCompleted === true) { $observer->onCompleted(); } }), $scheduler); $this->disposable->add($subscription); return $this->disposable; }
/** * @inheritDoc */ public function __invoke(ObservableInterface $observable, ObserverInterface $observer, SchedulerInterface $scheduler = null) { $errors = new Subject(); $disposable = new CompositeDisposable(); $sourceDisposable = new EmptyDisposable(); $innerCompleted = false; $sourceError = false; try { $when = call_user_func($this->notificationHandler, $errors->asObservable()); } catch (\Exception $e) { $observer->onError($e); return; } $subscribeToSource = function () use($observer, $disposable, $observable, &$sourceError, $errors, &$sourceDisposable, $scheduler, &$innerCompleted) { $sourceError = false; $sourceDisposable = $observable->subscribe(new CallbackObserver([$observer, 'onNext'], function ($err) use(&$sourceError, $errors, $disposable, &$sourceDisposable, &$innerCompleted, $observer) { $sourceError = true; $disposable->remove($sourceDisposable); $sourceDisposable->dispose(); if ($innerCompleted) { $observer->onCompleted(); return; } $errors->onNext($err); }, [$observer, 'onCompleted']), $scheduler); $disposable->add($sourceDisposable); }; $whenDisposable = $when->subscribe(new CallbackObserver(function ($x) use($subscribeToSource, &$sourceError) { if ($sourceError) { $sourceError = false; $subscribeToSource(); } }, [$observer, 'onError'], function () use(&$innerCompleted, &$sourceError, $observer) { $innerCompleted = true; if ($sourceError) { $observer->onCompleted(); } }), $scheduler); $disposable->add($whenDisposable); $subscribeToSource(); return $disposable; }
public function scheduleRecursive(callable $action) { if (!is_callable($action)) { throw new InvalidArgumentException("Action should be a callable."); } $goAgain = true; $disposable = new CompositeDisposable(); $recursiveAction = function () use($action, &$goAgain, $disposable) { while ($goAgain) { $goAgain = false; $disposable->add($this->schedule(function () use($action, &$goAgain, $disposable) { return $action(function () use(&$goAgain, $action) { $goAgain = true; }); })); } }; $disposable->add($this->schedule($recursiveAction)); return $disposable; }
/** * @param \Rx\ObservableInterface $observable * @param \Rx\ObserverInterface $observer * @param \Rx\SchedulerInterface $scheduler * @return \Rx\DisposableInterface */ public function __invoke(ObservableInterface $observable, ObserverInterface $observer, SchedulerInterface $scheduler = null) { $disposed = false; $disposable = new CompositeDisposable(); $selectObserver = new CallbackObserver(function ($nextValue) use($observer, &$disposed) { $value = null; try { $value = call_user_func_array($this->selector, [$nextValue]); } catch (\Exception $e) { $observer->onError($e); } if (!$disposed) { $observer->onNext($value); } }, [$observer, 'onError'], [$observer, 'onCompleted']); $disposable->add(new CallbackDisposable(function () use(&$disposed) { $disposed = true; })); $disposable->add($observable->subscribe($selectObserver, $scheduler)); return $disposable; }
/** * @inheritDoc */ public function __invoke(ObservableInterface $observable, ObserverInterface $observer, SchedulerInterface $scheduler = null) { $outerDisposable = new SerialDisposable(); $this->disposable->add($outerDisposable); $subscribe = function () use($outerDisposable, $observable, $observer, $scheduler, &$subscribe) { $this->sourceComplete = false; $outerSubscription = $observable->subscribe(new CallbackObserver([$observer, "onNext"], [$observer, "onError"], function () use($observer, &$subscribe, $outerDisposable) { $this->sourceComplete = true; if (!$this->repeat) { $observer->onCompleted(); return; } $outerDisposable->setDisposable(new EmptyDisposable()); $this->completions->onNext(++$this->count); }), $scheduler); $outerDisposable->setDisposable($outerSubscription); }; $notifierDisposable = $this->notifier->subscribe(new CallbackObserver(function () use(&$subscribe, $scheduler) { $subscribe(); }, function ($ex) use($observer) { $this->repeat = false; $observer->onError($ex); }, function () use($observer) { $this->repeat = false; if ($this->sourceComplete) { $observer->onCompleted(); } }), $scheduler); $this->disposable->add($notifierDisposable); try { $handled = call_user_func($this->notificationHandler, $this->completions->asObservable()); $handledDisposable = $handled->subscribe($this->notifier, $scheduler); $this->disposable->add($handledDisposable); } catch (\Exception $e) { $observer->onError($e); return new EmptyDisposable(); } $subscribe(); return $this->disposable; }
/** * @param \Rx\ObservableInterface $observable * @param \Rx\ObserverInterface $observer * @param \Rx\SchedulerInterface $scheduler * @return \Rx\DisposableInterface */ public function __invoke(ObservableInterface $observable, ObserverInterface $observer, SchedulerInterface $scheduler = null) { array_unshift($this->observables, $observable); $observables =& $this->observables; $compositeDisposable = new CompositeDisposable(); $hasValue = []; $values = array_keys($observables); $count = count($observables); $waitingToComplete = $count; $waitingForValues = $count; foreach ($observables as $key => $o) { $hasValue[$key] = false; $cbObserver = new CallbackObserver(function ($value) use($count, &$hasValue, $key, &$values, $observer, &$waitingForValues, &$waitingToComplete) { // If an observable has completed before it has emitted, we need to complete right away if ($waitingForValues > $waitingToComplete) { $observer->onCompleted(); return; } if ($waitingForValues > 0 && !$hasValue[$key]) { $hasValue[$key] = true; $waitingForValues--; } $values[$key] = $value; if ($waitingForValues === 0) { try { $result = call_user_func_array($this->resultSelector, $values); $observer->onNext($result); } catch (\Exception $e) { $observer->onError($e); } } }, [$observer, 'onError'], function () use(&$waitingToComplete, $observer) { $waitingToComplete--; if ($waitingToComplete === 0) { $observer->onCompleted(); } }); $subscription = $o->subscribe($cbObserver, $scheduler); $compositeDisposable->add($subscription); } return $compositeDisposable; }
/** * @inheritDoc */ public function __invoke(ObservableInterface $observable, ObserverInterface $observer, SchedulerInterface $scheduler = null) { array_unshift($this->sources, $observable); $this->numberOfSources = count($this->sources); $disposable = new CompositeDisposable(); $this->completesRemaining = $this->numberOfSources; for ($i = 0; $i < $this->numberOfSources; $i++) { $this->queues[$i] = new \SplQueue(); $this->completed[$i] = false; } for ($i = 0; $i < $this->numberOfSources; $i++) { $source = $this->sources[$i]; $cbObserver = new CallbackObserver(function ($x) use($i, $observer, $scheduler) { // if there is another item in the sequence after one of the other source // observables completes, we need to complete at this time to match the // behavior of RxJS if ($this->completesRemaining < $this->numberOfSources) { // check for completed and empty queues for ($j = 0; $j < $this->numberOfSources; $j++) { if ($this->completed[$j] && count($this->queues[$j]) === 0) { $observer->onCompleted(); return; } } } $this->queues[$i]->enqueue($x); for ($j = 0; $j < $this->numberOfSources; $j++) { if ($this->queues[$j]->isEmpty()) { return; } } $params = []; for ($j = 0; $j < $this->numberOfSources; $j++) { $params[] = $this->queues[$j]->dequeue(); } try { $observer->onNext(call_user_func_array($this->resultSelector, $params)); } catch (\Exception $e) { $observer->onError($e); } }, function ($e) use($observer) { $observer->onError($e); }, function () use($i, $observer) { $this->completesRemaining--; $this->completed[$i] = true; if ($this->completesRemaining === 0) { $observer->onCompleted(); } }); $subscription = $source->subscribe($cbObserver, $scheduler); $disposable->add($subscription); } return $disposable; }
/** * @test */ public function clear_disposes_all_contained_disposables_but_not_the_composite_disposable() { $disposed1 = false; $disposed2 = false; $d1 = new CallbackDisposable(function () use(&$disposed1) { $disposed1 = true; }); $d2 = new CallbackDisposable(function () use(&$disposed2) { $disposed2 = true; }); $disposable = new CompositeDisposable(array($d1, $d2)); $disposable->clear(); $this->assertTrue($disposed1); $this->assertTrue($disposed2); $disposed3 = false; $d3 = new CallbackDisposable(function () use(&$disposed3) { $disposed3 = true; }); $disposable->add($d3); $this->assertFalse($disposed3); }
/** * @param \Rx\ObservableInterface $observable * @param \Rx\ObserverInterface $observer * @param \Rx\SchedulerInterface $scheduler * @return \Rx\DisposableInterface */ public function __invoke(ObservableInterface $observable, ObserverInterface $observer, SchedulerInterface $scheduler = null) { $map = []; $groupDisposable = new CompositeDisposable(); $refCountDisposable = new RefCountDisposable($groupDisposable); $keySelector = $this->keySelector; $elementSelector = $this->elementSelector; $durationSelector = $this->durationSelector; $keySerializer = $this->keySerializer; $sourceEmits = true; $callbackObserver = new CallbackObserver(function ($value) use(&$map, $keySelector, $elementSelector, $durationSelector, $observer, $keySerializer, $groupDisposable, $refCountDisposable, $scheduler, &$sourceEmits) { try { $key = $keySelector($value); $serializedKey = $keySerializer($key); } catch (Exception $e) { foreach ($map as $groupObserver) { $groupObserver->onError($e); } $observer->onError($e); return; } $fireNewMapEntry = false; try { if (!isset($map[$serializedKey])) { $map[$serializedKey] = new Subject(); $fireNewMapEntry = true; } $writer = $map[$serializedKey]; } catch (Exception $e) { foreach ($map as $groupObserver) { $groupObserver->onError($e); } $observer->onError($e); return; } if ($fireNewMapEntry) { $group = new GroupedObservable($key, $writer, $refCountDisposable); $durationGroup = new GroupedObservable($key, $writer); try { $duration = $durationSelector($durationGroup); } catch (\Exception $e) { foreach ($map as $groupObserver) { $groupObserver->onError($e); } $observer->onError($e); return; } if ($sourceEmits) { $observer->onNext($group); } $md = new SingleAssignmentDisposable(); $groupDisposable->add($md); $expire = function () use(&$map, &$md, $serializedKey, &$writer, &$groupDisposable) { if (isset($map[$serializedKey])) { unset($map[$serializedKey]); $writer->onCompleted(); } $groupDisposable->remove($md); }; $callbackObserver = new CallbackObserver(function () { }, function (Exception $exception) use($map, $observer) { foreach ($map as $writer) { $writer->onError($exception); } $observer->onError($exception); }, function () use($expire) { $expire(); }); $subscription = $duration->take(1)->subscribe($callbackObserver, $scheduler); $md->setDisposable($subscription); } try { $element = $elementSelector($value); } catch (Exception $exception) { foreach ($map as $writer) { $writer->onError($exception); } $observer->onError($exception); return; } $writer->onNext($element); }, function (Exception $error) use(&$map, $observer) { foreach ($map as $writer) { $writer->onError($error); } $observer->onError($error); }, function () use(&$map, $observer) { foreach ($map as $writer) { $writer->onCompleted(); } $observer->onCompleted(); }); $subscription = $observable->subscribe($callbackObserver, $scheduler); $groupDisposable->add($subscription); $sourceDisposable = new CallbackDisposable(function () use($refCountDisposable, &$sourceEmits) { $sourceEmits = false; $refCountDisposable->dispose(); }); return $sourceDisposable; }
public function groupByUntil($keySelector, $elementSelector = null, $durationSelector = null, $keySerializer = null) { $currentObservable = $this; if (!is_callable($keySelector)) { throw new InvalidArgumentException('Key selector should be a callable.'); } if (null === $elementSelector) { $elementSelector = function ($elem) { return $elem; }; } else { if (!is_callable($elementSelector)) { throw new InvalidArgumentException('Element selector should be a callable.'); } } if (null === $durationSelector) { $durationSelector = function ($x) { return $x; }; } else { if (!is_callable($durationSelector)) { throw new InvalidArgumentException('Duration selector should be a callable.'); } } if (null === $keySerializer) { $keySerializer = function ($x) { return $x; }; } else { if (!is_callable($keySerializer)) { throw new InvalidArgumentException('Key serializer should be a callable.'); } } return new AnonymousObservable(function ($observer, $scheduler) use($currentObservable, $keySelector, $elementSelector, $durationSelector, $keySerializer) { $map = array(); $groupDisposable = new CompositeDisposable(); $refCountDisposable = new RefCountDisposable($groupDisposable); $groupDisposable->add($currentObservable->subscribeCallback(function ($value) use(&$map, $keySelector, $elementSelector, $durationSelector, $observer, $keySerializer, $groupDisposable, $refCountDisposable) { try { $key = $keySelector($value); $serializedKey = $keySerializer($key); } catch (Exception $e) { foreach ($map as $groupObserver) { $groupObserver->onError($e); } $observer->onError($e); return; } $fireNewMapEntry = false; try { if (!isset($map[$serializedKey])) { $map[$serializedKey] = new Subject(); $fireNewMapEntry = true; } $writer = $map[$serializedKey]; } catch (Exception $e) { foreach ($map as $groupObserver) { $groupObserver->onError($e); } $observer->onError($e); return; } if ($fireNewMapEntry) { $group = new GroupedObservable($key, $writer, $refCountDisposable); $durationGroup = new GroupedObservable($key, $writer); try { $duration = $durationSelector($durationGroup); } catch (Exception $e) { foreach ($map as $groupObserver) { $groupObserver->onError($e); } $observer->onError($e); return; } $observer->onNext($group); $md = new SingleAssignmentDisposable(); $groupDisposable->add($md); $expire = function () use(&$map, &$md, $serializedKey, &$writer, &$groupDisposable) { if (isset($map[$serializedKey])) { unset($map[$serializedKey]); $writer->onCompleted(); } $groupDisposable->remove($md); }; $md->setDisposable($duration->take(1)->subscribeCallback(function () { }, function (Exception $exception) use($map, $observer) { foreach ($map as $writer) { $writer->onError($exception); } $observer->onError($exception); }, function () use($expire) { $expire(); })); } try { $element = $elementSelector($value); } catch (Exception $exception) { foreach ($map as $writer) { $writer->onError($exception); } $observer->onError($exception); return; } $writer->onNext($element); }, function (Exception $error) use(&$map, $observer) { foreach ($map as $writer) { $writer->onError($error); } $observer->onError($error); }, function () use(&$map, $observer) { foreach ($map as $writer) { $writer->onCompleted(); } $observer->onCompleted(); }, $scheduler)); return $refCountDisposable; }); }