99use  Lkrms \Sync \Catalog \HydrationPolicy ;
1010use  Lkrms \Sync \Catalog \SyncOperation ;
1111use  Lkrms \Sync \Concept \SyncProvider ;
12+ use  Lkrms \Sync \Exception \SyncEntityRecursionException ;
1213use  Lkrms \Sync \Exception \SyncInvalidFilterException ;
1314
1415/** 
15-  * The context within which a  sync entity is  instantiated by a provider 
16+  * The context within which sync entities are  instantiated by a provider 
1617 * 
1718 * @extends IProviderContext<ISyncProvider,ISyncEntity> 
1819 */ 
@@ -62,7 +63,7 @@ interface ISyncContext extends IProviderContext
6263     * @param SyncOperation::* $operation 
6364     * @param mixed ...$args Sync operation arguments, NOT including the 
6465     * {@see ISyncContext} argument. 
65-      * @return $this  
66+      * @return static  
6667     */ 
6768    public  function  withArgs ($ operation , ...$ args );
6869
@@ -76,14 +77,14 @@ public function withArgs($operation, ...$args);
7677     * @see ISyncContext::applyFilterPolicy() 
7778     * 
7879     * @param (callable(ISyncContext, ?bool &$returnEmpty, array{}|null &$empty): void)|null $callback 
79-      * @return $this  
80+      * @return static  
8081     */ 
8182    public  function  withFilterPolicyCallback (?callable  $ callback );
8283
8384    /** 
8485     * Reject entities from the local entity store 
8586     * 
86-      * @return $this  
87+      * @return static  
8788     */ 
8889    public  function  online ();
8990
@@ -93,7 +94,7 @@ public function online();
9394     * An exception is thrown if the local entity store is unable to satisfy 
9495     * subsequent entity requests. 
9596     * 
96-      * @return $this  
97+      * @return static  
9798     */ 
9899    public  function  offline ();
99100
@@ -103,15 +104,15 @@ public function offline();
103104     * 
104105     * This is the default behaviour. 
105106     * 
106-      * @return $this  
107+      * @return static  
107108     */ 
108109    public  function  offlineFirst ();
109110
110111    /** 
111112     * Apply the given deferral policy to the context 
112113     * 
113114     * @param DeferralPolicy::* $policy 
114-      * @return $this  
115+      * @return static  
115116     */ 
116117    public  function  withDeferralPolicy ($ policy );
117118
@@ -123,14 +124,33 @@ public function withDeferralPolicy($policy);
123124     * change to an entity and its subclasses. 
124125     * @param array<int<1,max>>|int<1,max>|null $depth Limit the scope of the 
125126     * change to entities at a given `$depth` from the current context. 
126-      * @return $this  
127+      * @return static  
127128     */ 
128129    public  function  withHydrationPolicy (
129130        int  $ policy ,
130131        ?string  $ entity  = null ,
131132        $ depth  = null 
132133    );
133134
135+     /** 
136+      * Push the entity propagating the context onto the stack after checking if 
137+      * it is already present 
138+      * 
139+      * {@see ISyncContext::maybeThrowRecursionException()} fails with an 
140+      * exception if `$entity` is already in the stack. 
141+      * 
142+      * @return static 
143+      */ 
144+     public  function  pushWithRecursionCheck (ISyncEntity   $ entity );
145+ 
146+     /** 
147+      * Throw an exception if recursion is detected 
148+      * 
149+      * @throws SyncEntityRecursionException if 
150+      * {@see ISyncContext::pushWithRecursionCheck()} detected recursion. 
151+      */ 
152+     public  function  maybeThrowRecursionException (): void ;
153+ 
134154    /** 
135155     * Run the unclaimed filter policy callback 
136156     * 
@@ -163,7 +183,7 @@ public function withHydrationPolicy(
163183     * 
164184     * @param array{}|null $empty 
165185     */ 
166-     public  function  applyFilterPolicy (?bool  &$ returnEmpty , &$ empty ): void ;
186+     public  function  applyFilterPolicy (?bool  &$ returnEmpty , ? array   &$ empty ): void ;
167187
168188    /** 
169189     * Get the filters passed to the context via optional sync operation 
@@ -196,7 +216,7 @@ public function getFilter(string $key, bool $orValue = true);
196216     * 
197217     * Unlike other {@see ISyncContext} methods, 
198218     * {@see ISyncContext::claimFilter()} modifies the object it is called on 
199-      * instead of returning a modified clone . 
219+      * instead of returning a modified instance . 
200220     * 
201221     * If `$orValue` is `true` and a value for `$key` has been applied to the 
202222     * context via {@see IProviderContext::withValue()}, it is returned if there 
0 commit comments