@@ -282,6 +282,115 @@ public function testToArrayDecryptsAllAttributes()
282282 $ this ->assertEquals ('123-456-7890 ' , $ array ['phone ' ]);
283283 $ this ->assertEquals ('123 Main St ' , $ array ['address ' ]);
284284 }
285+
286+ public function testCompactDecryptionFromRawDatabase ()
287+ {
288+ // Create a test table
289+ $ this ->app ['db ' ]->connection ()->getSchemaBuilder ()->create ('test_models ' , function ($ table ) {
290+ $ table ->increments ('id ' );
291+ $ table ->text ('address ' )->nullable ();
292+ $ table ->timestamps ();
293+ });
294+
295+ $ encryptionService = $ this ->app ->make (EncryptionService::class);
296+
297+ // Use reflection to access compact encryption
298+ $ reflection = new \ReflectionClass ($ encryptionService );
299+ $ compactEncryptMethod = $ reflection ->getMethod ('compactEncrypt ' );
300+ $ compactEncryptMethod ->setAccessible (true );
301+
302+ // Create a compact encrypted value similar to the user's issue
303+ $ originalValue = '123 Main Street ' ;
304+ $ compactEncrypted = $ compactEncryptMethod ->invokeArgs ($ encryptionService , [$ originalValue ]);
305+
306+ // Manually insert into database with compact encryption
307+ $ id = $ this ->app ['db ' ]->connection ()->table ('test_models ' )->insertGetId ([
308+ 'address ' => $ compactEncrypted ,
309+ 'created_at ' => now (),
310+ 'updated_at ' => now (),
311+ ]);
312+
313+ // Retrieve using Eloquent - this should trigger decryption
314+ $ model = TestEncryptableModel::find ($ id );
315+
316+ // Check that the value is properly decrypted when accessed
317+ $ this ->assertEquals ($ originalValue , $ model ->address );
318+
319+ // Check that accessing via __get also works
320+ $ this ->assertEquals ($ originalValue , $ model ->__get ('address ' ));
321+
322+ // Check that toArray() also works
323+ $ array = $ model ->toArray ();
324+ $ this ->assertEquals ($ originalValue , $ array ['address ' ]);
325+
326+ // Verify the raw database value is still compact encrypted
327+ $ rawData = $ this ->app ['db ' ]->connection ()->table ('test_models ' )->where ('id ' , $ id )->first ();
328+ $ this ->assertTrue (strpos ($ rawData ->address , 'c: ' ) === 0 );
329+ $ this ->assertNotEquals ($ originalValue , $ rawData ->address );
330+ }
331+
332+ public function testDecryptionWorksForRelationshipLoadedModels ()
333+ {
334+ // Create tables for user and addresses
335+ $ this ->app ['db ' ]->connection ()->getSchemaBuilder ()->create ('users ' , function ($ table ) {
336+ $ table ->increments ('id ' );
337+ $ table ->string ('name ' );
338+ $ table ->timestamps ();
339+ });
340+
341+ $ this ->app ['db ' ]->connection ()->getSchemaBuilder ()->create ('user_addresses ' , function ($ table ) {
342+ $ table ->increments ('id ' );
343+ $ table ->integer ('user_id ' );
344+ $ table ->text ('street_1 ' )->nullable ();
345+ $ table ->text ('street_2 ' )->nullable ();
346+ $ table ->timestamps ();
347+ });
348+
349+ $ encryptionService = $ this ->app ->make (EncryptionService::class);
350+ $ reflection = new \ReflectionClass ($ encryptionService );
351+ $ compactEncryptMethod = $ reflection ->getMethod ('compactEncrypt ' );
352+ $ compactEncryptMethod ->setAccessible (true );
353+
354+ // Create test data
355+ $ userId = $ this ->app ['db ' ]->connection ()->table ('users ' )->insertGetId ([
356+ 'name ' => 'Test User ' ,
357+ 'created_at ' => now (),
358+ 'updated_at ' => now (),
359+ ]);
360+
361+ // Insert address with compact encrypted street_1 and street_2
362+ $ street1Encrypted = $ compactEncryptMethod ->invokeArgs ($ encryptionService , ['123 Main Street ' ]);
363+ $ street2Encrypted = $ encryptionService ->encrypt ('Apt 4B ' ); // Regular encryption
364+
365+ $ addressId = $ this ->app ['db ' ]->connection ()->table ('user_addresses ' )->insertGetId ([
366+ 'user_id ' => $ userId ,
367+ 'street_1 ' => $ street1Encrypted ,
368+ 'street_2 ' => $ street2Encrypted ,
369+ 'created_at ' => now (),
370+ 'updated_at ' => now (),
371+ ]);
372+
373+ // Now simulate loading through a collection/relationship query
374+ // (which doesn't trigger the retrieved event)
375+ $ addresses = $ this ->app ['db ' ]->connection ()->table ('user_addresses ' )
376+ ->where ('user_id ' , $ userId )
377+ ->get ();
378+
379+ // Create model instances manually from the raw data (simulating relationship loading)
380+ $ addressData = $ addresses ->first ();
381+ $ address = new TestAddressModel ();
382+ $ address ->setRawAttributes ((array ) $ addressData );
383+ $ address ->exists = true ;
384+
385+ // Test that decryption works even when retrieved event didn't fire
386+ $ this ->assertEquals ('123 Main Street ' , $ address ->street_1 );
387+ $ this ->assertEquals ('Apt 4B ' , $ address ->street_2 );
388+
389+ // Test toArray() also works
390+ $ array = $ address ->toArray ();
391+ $ this ->assertEquals ('123 Main Street ' , $ array ['street_1 ' ]);
392+ $ this ->assertEquals ('Apt 4B ' , $ array ['street_2 ' ]);
393+ }
285394}
286395
287396class TestEncryptableModel extends Model
@@ -292,4 +401,14 @@ class TestEncryptableModel extends Model
292401 protected $ guarded = [];
293402
294403 protected $ encryptable = ['email ' , 'phone ' , 'address ' , 'company ' ];
404+ }
405+
406+ class TestAddressModel extends Model
407+ {
408+ use Encryptable;
409+
410+ protected $ table = 'user_addresses ' ;
411+ protected $ guarded = [];
412+
413+ protected $ encryptable = ['street_1 ' , 'street_2 ' ];
295414}
0 commit comments