@@ -144,6 +144,90 @@ public function testCanDehydrateAndHydrateComponentWithTestCases(callable $testF
144144
145145 public function provideDehydrationHydrationTests (): iterable
146146 {
147+ yield 'onUpdated: exception if method not exists ' => [function () {
148+ return HydrationTest::create (new class () {
149+ #[LiveProp(writable: true , onUpdated: 'onFirstNameUpdated ' )]
150+ public string $ firstName ;
151+ })
152+ ->mountWith (['firstName ' => 'Ryan ' ])
153+ ->userUpdatesProps (['firstName ' => 'Victor ' ])
154+ ->expectsExceptionDuringHydration (\Exception::class, '/onFirstNameUpdated\(\)" specified as LiveProp "onUpdated" hook does not exist/ ' );
155+ }];
156+
157+ yield 'onUpdated: with scalar value ' => [function () {
158+ return HydrationTest::create (new class () {
159+ #[LiveProp(writable: true , onUpdated: 'onFirstNameUpdated ' )]
160+ public string $ firstName ;
161+
162+ public function onFirstNameUpdated ($ oldValue )
163+ {
164+ if ('Victor ' === $ this ->firstName ) {
165+ $ this ->firstName = 'Revert to ' .$ oldValue ;
166+ }
167+ }
168+ })
169+ ->mountWith (['firstName ' => 'Ryan ' ])
170+ ->userUpdatesProps (['firstName ' => 'Victor ' ])
171+ ->assertObjectAfterHydration (function (object $ object ) {
172+ $ this ->assertSame ('Revert to Ryan ' , $ object ->firstName );
173+ });
174+ }];
175+
176+ yield 'onUpdated: set to an array ' => [function () {
177+ $ product = create (ProductFixtureEntity::class, [
178+ 'name ' => 'Chicken ' ,
179+ ])->object ();
180+
181+ return HydrationTest::create (new class () {
182+ #[LiveProp(writable: ['name ' ], onUpdated: ['name ' => 'onNameUpdated ' ])]
183+ public ProductFixtureEntity $ product ;
184+
185+ public function onNameUpdated ($ oldValue )
186+ {
187+ if ('Rabbit ' === $ this ->product ->name ) {
188+ $ this ->product ->name = 'Revert to ' .$ oldValue ;
189+ }
190+ }
191+ })
192+ ->mountWith (['product ' => $ product ])
193+ ->userUpdatesProps (['product.name ' => 'Rabbit ' ])
194+ ->assertObjectAfterHydration (function (object $ object ) {
195+ $ this ->assertSame ('Revert to Chicken ' , $ object ->product ->name );
196+ });
197+ }];
198+
199+ yield 'onUpdated: with IDENTITY ' => [function () {
200+ $ entityOriginal = create (Entity1::class)->object ();
201+ $ entityNext = create (Entity1::class)->object ();
202+ \assert ($ entityOriginal instanceof Entity1);
203+ \assert ($ entityNext instanceof Entity1);
204+
205+ return HydrationTest::create (new class () {
206+ #[LiveProp(writable: [LiveProp::IDENTITY ], onUpdated: [LiveProp::IDENTITY => 'onEntireEntityUpdated ' ])]
207+ public Entity1 $ entity1 ;
208+
209+ public function onEntireEntityUpdated ($ oldValue )
210+ {
211+ // Sanity check
212+ if ($ this ->entity1 === $ oldValue ) {
213+ throw new \Exception ('Old value is the same entity?! ' );
214+ }
215+ if (2 === $ this ->entity1 ->id ) {
216+ // Revert the value
217+ $ this ->entity1 = $ oldValue ;
218+ }
219+ }
220+ })
221+ ->mountWith (['entity1 ' => $ entityOriginal ])
222+ ->userUpdatesProps (['entity1 ' => $ entityNext ->id ])
223+ ->assertObjectAfterHydration (function (object $ object ) use ($ entityOriginal ) {
224+ $ this ->assertSame (
225+ $ entityOriginal ->id ,
226+ $ object ->entity1 ->id
227+ );
228+ });
229+ }];
230+
147231 yield 'string: (de)hydrates correctly ' => [function () {
148232 return HydrationTest::create (new class () {
149233 #[LiveProp()]
0 commit comments