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