/** * @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; }
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; }
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; }
private function subscribeToResult(ObservableInterface $observable, SchedulerInterface $scheduler, ObserverInterface $observer, $outerIndex) { return $observable->subscribe(new CallbackObserver(function ($value) use($observer, $outerIndex) { if (!$this->hasFirst) { $this->hasFirst = true; foreach ($this->subscriptions as $i => $subscription) { if ($i !== $outerIndex) { $subscription->dispose(); unset($this->subscriptions[$i]); $this->innerSubscription->remove($subscription); } } } $observer->onNext($value); }, [$observer, 'onError'], [$observer, 'onCompleted']), $scheduler); }
/** * @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; }
/** * @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; }
/** * @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; }); }
/** * @test */ public function removing_a_disposable_that_is_not_contained_has_no_effect() { $disposable = new CompositeDisposable(array()); $disposed1 = false; $d1 = new CallbackDisposable(function () use(&$disposed1) { $disposed1 = true; }); $disposable->remove($d1); $this->assertFalse($disposed1); }