store = $store; $this->findings = $findings; } /** * The state as it is now, in the shape of the logged after-state. * * @param ActivityRecord $record Logged change. * @return array{type: string, ref: string, findings: array, value: string|array|null} */ public function current_state( ActivityRecord $record ): array { $after = self::state( $record->after ); // Same key order as the logged state ({type, ref, findings} + {value}), because the // conflict check compares hashes of the JSON. return array( 'type' => $after['type'], 'ref' => $after['ref'], 'findings' => $after['findings'], 'value' => $this->store->read( $after['type'], $after['ref'] ), ); } /** * Writes the before-value back. * * @param ActivityRecord $record Logged change. */ public function undo( ActivityRecord $record ): Result { $before = self::state( $record->before ); if ( null === $before['value'] || ! $this->store->write( $before['type'], $before['ref'], $before['value'] ) ) { return Result::failure( 'write_failed', __( 'The original content could not be written back.', 'forensix-digital' ) ); } if ( null !== $this->findings && array() !== $before['findings'] ) { $this->findings->reopen( $before['findings'] ); } return Result::success( __( 'The original content is back.', 'forensix-digital' ) ); } /** * A logged state with known keys. * * @param mixed $state Logged state. * @return array{type: string, ref: string, value: string|array|null, findings: array} */ private static function state( mixed $state ): array { $state = is_array( $state ) ? $state : array(); $value = $state['value'] ?? null; return array( 'type' => is_string( $state['type'] ?? null ) ? $state['type'] : '', 'ref' => is_string( $state['ref'] ?? null ) ? $state['ref'] : '', 'value' => is_string( $value ) || is_array( $value ) ? $value : null, 'findings' => is_array( $state['findings'] ?? null ) ? array_values( array_map( 'intval', $state['findings'] ) ) : array(), ); } }