File tree Expand file tree Collapse file tree 3 files changed +100
-0
lines changed
src/Illuminate/Collections Expand file tree Collapse file tree 3 files changed +100
-0
lines changed Original file line number Diff line number Diff line change 4
4
5
5
use ArrayIterator ;
6
6
use Closure ;
7
+ use DateInterval ;
8
+ use DateTimeImmutable ;
7
9
use DateTimeInterface ;
8
10
use Generator ;
9
11
use Illuminate \Contracts \Support \CanBeEscapedWhenCastToString ;
@@ -1763,6 +1765,42 @@ public function values()
1763
1765
});
1764
1766
}
1765
1767
1768
+ /**
1769
+ * Run the given callback every time the interval has passed.
1770
+ *
1771
+ * @return static<TKey, TValue>
1772
+ */
1773
+ public function withHeartbeat (DateInterval |int $ interval , callable $ callback )
1774
+ {
1775
+ $ seconds = is_int ($ interval ) ? $ interval : $ this ->intervalSeconds ($ interval );
1776
+
1777
+ return new static (function () use ($ seconds , $ callback ) {
1778
+ $ start = $ this ->now ();
1779
+
1780
+ foreach ($ this as $ key => $ value ) {
1781
+ $ now = $ this ->now ();
1782
+
1783
+ if (($ now - $ start ) >= $ seconds ) {
1784
+ $ callback ();
1785
+
1786
+ $ start = $ now ;
1787
+ }
1788
+
1789
+ yield $ key => $ value ;
1790
+ }
1791
+ });
1792
+ }
1793
+
1794
+ /**
1795
+ * Get the total seconds from the given interval.
1796
+ */
1797
+ protected function intervalSeconds (DateInterval $ interval ): int
1798
+ {
1799
+ $ start = new DateTimeImmutable ();
1800
+
1801
+ return $ start ->add ($ interval )->getTimestamp () - $ start ->getTimestamp ();
1802
+ }
1803
+
1766
1804
/**
1767
1805
* Zip the collection together with one or more arrays.
1768
1806
*
Original file line number Diff line number Diff line change @@ -1706,6 +1706,21 @@ public function testWhereStrictIsLazy()
1706
1706
});
1707
1707
}
1708
1708
1709
+ public function testWithHeartbeatIsLazy ()
1710
+ {
1711
+ $ this ->assertDoesNotEnumerate (function ($ collection ) {
1712
+ $ collection ->withHeartbeat (1 , function () {
1713
+ // Heartbeat callback
1714
+ });
1715
+ });
1716
+
1717
+ $ this ->assertEnumeratesOnce (function ($ collection ) {
1718
+ $ collection ->withHeartbeat (1 , function () {
1719
+ // Heartbeat callback
1720
+ })->all ();
1721
+ });
1722
+ }
1723
+
1709
1724
public function testWrapIsLazy ()
1710
1725
{
1711
1726
$ this ->assertDoesNotEnumerate (function ($ collection ) {
Original file line number Diff line number Diff line change @@ -447,4 +447,51 @@ public function testDot()
447
447
448
448
$ this ->assertEquals ($ expected , $ dotted ->all ());
449
449
}
450
+
451
+ public function testWithHeartbeat ()
452
+ {
453
+ $ start = Carbon::create (2000 , 1 , 1 );
454
+ $ after2Minutes = $ start ->copy ()->addMinutes (2 );
455
+ $ after5Minutes = $ start ->copy ()->addMinutes (5 );
456
+ $ after7Minutes = $ start ->copy ()->addMinutes (7 );
457
+ $ after11Minutes = $ start ->copy ()->addMinutes (11 );
458
+
459
+ Carbon::setTestNow ($ start );
460
+
461
+ $ output = new Collection ();
462
+
463
+ $ numbers = LazyCollection::range (1 , 10 )
464
+
465
+ // Move the clock to possibly trigger the heartbeat...
466
+ ->tapEach (fn ($ number ) => Carbon::setTestNow (
467
+ match ($ number ) {
468
+ 3 => $ after2Minutes ,
469
+ 4 => $ after5Minutes ,
470
+ 6 => $ after7Minutes ,
471
+ 9 => $ after11Minutes ,
472
+ default => Carbon::now (),
473
+ }
474
+ ))
475
+
476
+ // Push the current date to `output` when heartbeat is triggered...
477
+ ->withHeartbeat (Duration::minutes (5 ), fn () => $ output [] = Carbon::now ())
478
+
479
+ // Push every number onto `output` as it's enumerated...
480
+ ->tapEach (fn ($ number ) => $ output [] = $ number )->all ();
481
+
482
+ $ this ->assertEquals (range (1 , 10 ), $ numbers );
483
+
484
+ $ this ->assertEquals (
485
+ [
486
+ 1 , 2 , 3 ,
487
+ $ after5Minutes ,
488
+ 4 , 5 , 6 , 7 , 8 ,
489
+ $ after11Minutes ,
490
+ 9 , 10 ,
491
+ ],
492
+ $ output ->all (),
493
+ );
494
+
495
+ Carbon::setTestNow ();
496
+ }
450
497
}
You can’t perform that action at this time.
0 commit comments