Example #1
0
 /**
  * @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;
 }
 /**
  * @test
  */
 public function it_returns_a_noop_disposable_if_primary_is_already_disposed()
 {
     $called = 0;
     $d = new CallbackDisposable(function () use(&$called) {
         $called++;
     });
     $r = new RefCountDisposable($d);
     $r->dispose();
     $this->assertEquals(1, $called);
     $d1 = $r->getDisposable();
     $d1->dispose();
     $r->dispose();
     $this->assertEquals(1, $called);
 }