1010use Illuminate \Database \Eloquent \Collection as EloquentCollection ;
1111use Illuminate \Database \Eloquent \ModelNotFoundException ;
1212use Illuminate \Support \Facades \Date ;
13+ use Illuminate \Support \Facades \DB ;
1314use Illuminate \Support \Str ;
14- use InvalidArgumentException ;
1515use MongoDB \BSON \Binary ;
1616use MongoDB \BSON \ObjectID ;
1717use MongoDB \BSON \UTCDateTime ;
@@ -48,7 +48,7 @@ class ModelTest extends TestCase
4848 public function tearDown (): void
4949 {
5050 Carbon::setTestNow ();
51- User:: truncate ();
51+ DB :: connection ( ' mongodb ' )-> getCollection ( ' users ' )-> drop ();
5252 Soft::truncate ();
5353 Book::truncate ();
5454 Item::truncate ();
@@ -1048,19 +1048,34 @@ public function testNumericFieldName(): void
10481048 $ this ->assertEquals ([3 => 'two.three ' ], $ found [2 ]);
10491049 }
10501050
1051- public function testCreateOrFirst ()
1051+ #[TestWith([true ])]
1052+ #[TestWith([false ])]
1053+ public function testCreateOrFirst (bool $ transaction )
10521054 {
1055+ $ connection = DB ::connection ('mongodb ' );
1056+ $ connection
1057+ ->getCollection ('users ' )
1058+ ->createIndex (['email ' => 1 ], ['unique ' => true ]);
1059+
1060+ if ($ transaction ) {
1061+ $ connection ->beginTransaction ();
1062+ }
1063+
10531064 Carbon::setTestNow ('2010-06-22 ' );
10541065 $ createdAt = Carbon::now ()->getTimestamp ();
1066+ $ events = [];
1067+ self ::registerModelEvents (User::class, $ events );
10551068 $ user1 = User::createOrFirst (['email ' => 'john.doe@example.com ' ]);
10561069
10571070 $ this ->assertSame ('john.doe@example.com ' , $ user1 ->email );
10581071 $ this ->assertNull ($ user1 ->name );
10591072 $ this ->assertTrue ($ user1 ->wasRecentlyCreated );
10601073 $ this ->assertEquals ($ createdAt , $ user1 ->created_at ->getTimestamp ());
10611074 $ this ->assertEquals ($ createdAt , $ user1 ->updated_at ->getTimestamp ());
1075+ $ this ->assertEquals (['saving ' , 'creating ' , 'created ' , 'saved ' ], $ events );
10621076
10631077 Carbon::setTestNow ('2020-12-28 ' );
1078+ $ events = [];
10641079 $ user2 = User::createOrFirst (
10651080 ['email ' => 'john.doe@example.com ' ],
10661081 ['name ' => 'John Doe ' , 'birthday ' => new DateTime ('1987-05-28 ' )],
@@ -1073,7 +1088,17 @@ public function testCreateOrFirst()
10731088 $ this ->assertFalse ($ user2 ->wasRecentlyCreated );
10741089 $ this ->assertEquals ($ createdAt , $ user1 ->created_at ->getTimestamp ());
10751090 $ this ->assertEquals ($ createdAt , $ user1 ->updated_at ->getTimestamp ());
1091+ if ($ transaction ) {
1092+ // In a transaction, firstOrCreate is used instead.
1093+ // Since a document is found, "save" is not called.
1094+ $ this ->assertEquals ([], $ events );
1095+ } else {
1096+ // The "duplicate key error" exception interrupts the save process
1097+ // before triggering "created" and "saved". Consistent with Laravel
1098+ $ this ->assertEquals (['saving ' , 'creating ' ], $ events );
1099+ }
10761100
1101+ $ events = [];
10771102 $ user3 = User::createOrFirst (
10781103 ['email ' => 'jane.doe@example.com ' ],
10791104 ['name ' => 'Jane Doe ' , 'birthday ' => new DateTime ('1987-05-28 ' )],
@@ -1086,21 +1111,21 @@ public function testCreateOrFirst()
10861111 $ this ->assertTrue ($ user3 ->wasRecentlyCreated );
10871112 $ this ->assertEquals ($ createdAt , $ user1 ->created_at ->getTimestamp ());
10881113 $ this ->assertEquals ($ createdAt , $ user1 ->updated_at ->getTimestamp ());
1114+ $ this ->assertEquals (['saving ' , 'creating ' , 'created ' , 'saved ' ], $ events );
10891115
1116+ $ events = [];
10901117 $ user4 = User::createOrFirst (
10911118 ['name ' => 'Robert Doe ' ],
10921119 ['name ' => 'Maria Doe ' , 'email ' => 'maria.doe@example.com ' ],
10931120 );
10941121
10951122 $ this ->assertSame ('Maria Doe ' , $ user4 ->name );
10961123 $ this ->assertTrue ($ user4 ->wasRecentlyCreated );
1097- }
1124+ $ this -> assertEquals ([ ' saving ' , ' creating ' , ' created ' , ' saved ' ], $ events );
10981125
1099- public function testCreateOrFirstRequiresFilter ()
1100- {
1101- $ this ->expectException (InvalidArgumentException::class);
1102- $ this ->expectExceptionMessage ('You must provide attributes to check for duplicates ' );
1103- User::createOrFirst ([]);
1126+ if ($ transaction ) {
1127+ $ connection ->commit ();
1128+ }
11041129 }
11051130
11061131 #[TestWith([['_id ' => new ObjectID ()]])]
@@ -1116,6 +1141,8 @@ public function testUpdateOrCreate(array $criteria)
11161141
11171142 Carbon::setTestNow ('2010-01-01 ' );
11181143 $ createdAt = Carbon::now ()->getTimestamp ();
1144+ $ events = [];
1145+ self ::registerModelEvents (User::class, $ events );
11191146
11201147 // Create
11211148 $ user = User::updateOrCreate (
@@ -1127,11 +1154,12 @@ public function testUpdateOrCreate(array $criteria)
11271154 $ this ->assertEquals (new DateTime ('1987-05-28 ' ), $ user ->birthday );
11281155 $ this ->assertEquals ($ createdAt , $ user ->created_at ->getTimestamp ());
11291156 $ this ->assertEquals ($ createdAt , $ user ->updated_at ->getTimestamp ());
1130-
1157+ $ this -> assertEquals ([ ' saving ' , ' creating ' , ' created ' , ' saved ' ], $ events );
11311158 Carbon::setTestNow ('2010-02-01 ' );
11321159 $ updatedAt = Carbon::now ()->getTimestamp ();
11331160
11341161 // Update
1162+ $ events = [];
11351163 $ user = User::updateOrCreate (
11361164 $ criteria ,
11371165 ['birthday ' => new DateTime ('1990-01-12 ' ), 'foo ' => 'bar ' ],
@@ -1142,6 +1170,7 @@ public function testUpdateOrCreate(array $criteria)
11421170 $ this ->assertEquals (new DateTime ('1990-01-12 ' ), $ user ->birthday );
11431171 $ this ->assertEquals ($ createdAt , $ user ->created_at ->getTimestamp ());
11441172 $ this ->assertEquals ($ updatedAt , $ user ->updated_at ->getTimestamp ());
1173+ $ this ->assertEquals (['saving ' , 'updating ' , 'updated ' , 'saved ' ], $ events );
11451174
11461175 // Stored data
11471176 $ checkUser = User::where ($ criteria )->first ();
@@ -1159,13 +1188,26 @@ public function testCreateWithNullId()
11591188 $ this ->assertSame (1 , User::count ());
11601189 }
11611190
1162- public function testUpdateOrCreateWithNullId ()
1191+ /** @param class-string<Model> $modelClass */
1192+ private static function registerModelEvents (string $ modelClass , array &$ events ): void
11631193 {
1164- $ this ->expectException (InvalidArgumentException::class);
1165- $ this ->expectExceptionMessage ('You must provide attributes to check for duplicates ' );
1166- User::updateOrCreate (
1167- ['_id ' => null ],
1168- ['email ' => 'jane.doe@example.com ' ],
1169- );
1194+ $ modelClass ::creating (function () use (&$ events ) {
1195+ $ events [] = 'creating ' ;
1196+ });
1197+ $ modelClass ::created (function () use (&$ events ) {
1198+ $ events [] = 'created ' ;
1199+ });
1200+ $ modelClass ::updating (function () use (&$ events ) {
1201+ $ events [] = 'updating ' ;
1202+ });
1203+ $ modelClass ::updated (function () use (&$ events ) {
1204+ $ events [] = 'updated ' ;
1205+ });
1206+ $ modelClass ::saving (function () use (&$ events ) {
1207+ $ events [] = 'saving ' ;
1208+ });
1209+ $ modelClass ::saved (function () use (&$ events ) {
1210+ $ events [] = 'saved ' ;
1211+ });
11701212 }
11711213}
0 commit comments