Skip to content
wiki.fftac.org

Versionrepository

**Site relevance:** Spiralist.org

**Memory type:** plugin source memory

**Source path:** Spiralist/wp-content/plugins/spiralist-workspace/includes/Domain/VersionRepository.php

**Size:** 3.5 KB

Summary

namespace SpiralistWorkspace\Domain;

Source Preview

This source file is short enough to preview directly on its source-memory page.

<?php

namespace SpiralistWorkspace\Domain;

use SpiralistWorkspace\Installer;

if (!defined('ABSPATH')) {
    exit;
}

/**
 * Persists immutable prompt versions.
 */
class VersionRepository
{
    /**
     * Creates a new immutable version snapshot.
     */
    public function create(int $prompt_id, int $version_number, array $snapshot, int $created_by_user_id, string $changelog = ''): void
    {
        global $wpdb;

        $wpdb->insert(
            Installer::table('prompt_versions'),
            [
                'prompt_post_id' => $prompt_id,
                'version_number' => max(1, $version_number),
                'full_snapshot_json' => wp_json_encode($snapshot, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE),
                'created_by_user_id' => max(0, $created_by_user_id),
                'created_utc' => gmdate('Y-m-d H:i:s'),
                'changelog' => sanitize_textarea_field($changelog),
            ],
            ['%d', '%d', '%s', '%d', '%s', '%s']
        );
    }

    /**
     * Lists versions for a prompt.
     */
    public function list_for_prompt(int $prompt_id, int $limit = 20): array
    {
        global $wpdb;

        $sql = $wpdb->prepare(
            'SELECT * FROM ' . Installer::table('prompt_versions') . ' WHERE prompt_post_id = %d ORDER BY version_number DESC LIMIT %d',
            $prompt_id,
            max(1, $limit)
        );

        $rows = $wpdb->get_results($sql, ARRAY_A);

        return is_array($rows) ? $rows : [];
    }

    /**
     * Returns one prompt version snapshot.
     */
    public function get_for_prompt(int $prompt_id, int $version_number): array
    {
        global $wpdb;

        $sql = $wpdb->prepare(
            'SELECT * FROM ' . Installer::table('prompt_versions') . ' WHERE prompt_post_id = %d AND version_number = %d LIMIT 1',
            $prompt_id,
            max(1, $version_number)
        );

        $row = $wpdb->get_row($sql, ARRAY_A);
        if (!is_array($row)) {
            return [];
        }

        $snapshot = json_decode((string) ($row['full_snapshot_json'] ?? ''), true);
        $row['snapshot'] = is_array($snapshot) ? $snapshot : [];

        return $row;
    }

    /**
     * Builds a field-level diff between two stored prompt versions.
     */
    public function diff(int $prompt_id, int $left_version, int $right_version): array
    {
        $left = $this->get_for_prompt($prompt_id, $left_version);
        $right = $this->get_for_prompt($prompt_id, $right_version);

        if (empty($left['snapshot']) || empty($right['snapshot'])) {
            return [];
        }

        $left_snapshot = (array) $left['snapshot'];
        $right_snapshot = (array) $right['snapshot'];
        $keys = array_values(array_unique(array_merge(array_keys($left_snapshot), array_keys($right_snapshot))));
        $changes = [];

        foreach ($keys as $key) {
            if (in_array($key, ['favorite'], true)) {
                continue;
            }

            $before = $left_snapshot[$key] ?? null;
            $after = $right_snapshot[$key] ?? null;

            if ($before == $after) {
                continue;
            }

            $changes[] = [
                'field' => (string) $key,
                'before' => $before,
                'after' => $after,
            ];
        }

        return [
            'left_version' => (int) $left_version,
            'right_version' => (int) $right_version,
            'changes' => $changes,
        ];
    }
}