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 44
55use ArrayIterator ;
66use Closure ;
7+ use DateInterval ;
8+ use DateTimeImmutable ;
79use DateTimeInterface ;
810use Generator ;
911use Illuminate \Contracts \Support \CanBeEscapedWhenCastToString ;
@@ -1763,6 +1765,42 @@ public function values()
17631765 });
17641766 }
17651767
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+
17661804 /**
17671805 * Zip the collection together with one or more arrays.
17681806 *
Original file line number Diff line number Diff line change @@ -1706,6 +1706,21 @@ public function testWhereStrictIsLazy()
17061706 });
17071707 }
17081708
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+
17091724 public function testWrapIsLazy ()
17101725 {
17111726 $ this ->assertDoesNotEnumerate (function ($ collection ) {
Original file line number Diff line number Diff line change @@ -447,4 +447,51 @@ public function testDot()
447447
448448 $ this ->assertEquals ($ expected , $ dotted ->all ());
449449 }
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+ }
450497}
You can’t perform that action at this time.
0 commit comments