@@ -193,10 +193,6 @@ public function createAudit(string $type, Model $model): bool
193193
194194 $ audit = $ this ->requireAuditRecord ($ audit );
195195
196- if (!$ this ->hasAuditModelStorage ($ audit )) {
197- return true ;
198- }
199-
200196 // Populate core audit metadata
201197 $ audit ->setModel ($ model ::class);
202198 $ audit ->setTable ($ model ->getSource ());
@@ -224,52 +220,49 @@ public function createAudit(string $type, Model $model): bool
224220 if ($ this ->isAuditDetailEnabled ()) {
225221 $ details = [];
226222 $ detailClass = $ this ->auditDetailClass ;
227- $ detailPrototype = $ this ->requireAuditDetailRecord (new $ detailClass ());
228-
229- if ($ this ->hasAuditModelStorage ($ detailPrototype )) {
230- foreach ($ columns as $ column ) {
231- $ map = $ columnMap [$ column ] ?? $ column ;
232- $ type = $ columnTypes [$ column ] ?? null ;
233-
234- $ before = $ this ->normalizeValue ($ snapshot [$ map ] ?? null , $ type );
235- $ after = $ this ->normalizeValue ($ model ->readAttribute ($ map ), $ type );
236-
237- // Skip unchanged fields on update
238- if (
239- $ event === 'update ' &&
240- $ changed !== null &&
241- $ snapshot !== null &&
242- ($ before === $ after || !in_array ($ map , $ changed , true ))
243- ) {
244- continue ;
245- }
246-
247- $ detail = $ this ->requireAuditDetailRecord (new $ detailClass ());
248-
249- $ detail ->setColumn ($ column );
250- $ detail ->setBefore ($ before );
251- $ detail ->setAfter ($ after );
252-
253- // Legacy compatibility fields
254- $ detail ->assign ([
255- 'model ' => $ audit ->getModel (),
256- 'table ' => $ audit ->getTable (),
257- 'primary ' => $ audit ->getPrimary (),
258- 'event ' => $ event ,
259- 'map ' => $ map ,
260- ]);
261-
262- $ details [] = $ detail ;
263- }
264223
265- if ($ details !== []) {
266- $ audit ->assign (['AuditDetailList ' => $ details ]);
224+ foreach ($ columns as $ column ) {
225+ $ map = $ columnMap [$ column ] ?? $ column ;
226+ $ type = $ columnTypes [$ column ] ?? null ;
227+
228+ $ before = $ this ->normalizeValue ($ snapshot [$ map ] ?? null , $ type );
229+ $ after = $ this ->normalizeValue ($ model ->readAttribute ($ map ), $ type );
230+
231+ // Skip unchanged fields on update
232+ if (
233+ $ event === 'update ' &&
234+ $ changed !== null &&
235+ $ snapshot !== null &&
236+ ($ before === $ after || !in_array ($ map , $ changed , true ))
237+ ) {
238+ continue ;
267239 }
240+
241+ $ detail = $ this ->requireAuditDetailRecord (new $ detailClass ());
242+
243+ $ detail ->setColumn ($ column );
244+ $ detail ->setBefore ($ before );
245+ $ detail ->setAfter ($ after );
246+
247+ // Legacy compatibility fields
248+ $ detail ->assign ([
249+ 'model ' => $ audit ->getModel (),
250+ 'table ' => $ audit ->getTable (),
251+ 'primary ' => $ audit ->getPrimary (),
252+ 'event ' => $ event ,
253+ 'map ' => $ map ,
254+ ]);
255+
256+ $ details [] = $ detail ;
257+ }
258+
259+ if ($ details !== []) {
260+ $ audit ->assign (['AuditDetailList ' => $ details ]);
268261 }
269262 }
270263
271264 // Persist audit (and details via relationship)
272- $ saved = $ audit -> save ( );
265+ $ saved = $ this -> saveAuditRecord ( $ audit );
273266
274267 // Propagate audit validation errors back to the source model
275268 foreach ($ audit ->getMessages () as $ message ) {
@@ -341,24 +334,20 @@ protected function requireAuditRecord(mixed $audit): AuditInterface&Model
341334 }
342335
343336 /**
344- * Return true when the configured audit model has backing metadata .
337+ * Save the audit record unless audit storage is explicitly absent .
345338 *
346339 * Missing audit tables are optional in some applications, so a concrete
347- * `TableNotInDatabase` skips audit creation. An unavailable local database
348- * is not the same signal; let the normal save path or test double decide
349- * instead of silently disabling audit .
340+ * `TableNotInDatabase` skips audit creation. The guard is intentionally at
341+ * the save boundary so fake/custom audit models that override persistence
342+ * still run normally .
350343 */
351- protected function hasAuditModelStorage ( Model $ model ): bool
344+ protected function saveAuditRecord ( AuditInterface & Model $ audit ): bool
352345 {
353346 try {
354- $ model -> getModelsMetaData ()-> getAttributes ( $ model );
347+ return $ audit -> save ( );
355348 } catch (TableNotInDatabase ) {
356- return false ;
357- } catch (\PDOException ) {
358349 return true ;
359350 }
360-
361- return true ;
362351 }
363352
364353 /**
0 commit comments