Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 78
0.00% covered (danger)
0.00%
0 / 9
CRAP
0.00% covered (danger)
0.00%
0 / 1
ImageSideloadTaskManager
0.00% covered (danger)
0.00%
0 / 78
0.00% covered (danger)
0.00%
0 / 9
462
0.00% covered (danger)
0.00%
0 / 1
 add_to_queue
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
12
 get_queue
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 set_queue
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 get_status
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 set_status
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 process_next_task
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 1
12
 process_queue
0.00% covered (danger)
0.00%
0 / 20
0.00% covered (danger)
0.00%
0 / 1
42
 clear_queue
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 get_stats
0.00% covered (danger)
0.00%
0 / 13
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2
3namespace NewfoldLabs\WP\Module\Onboarding\TaskManagers;
4
5use NewfoldLabs\WP\Module\Onboarding\Tasks\ImageSideloadTask;
6
7/**
8 * Task Manager for Image Sideloading
9 *
10 * Manages a queue of ImageSideloadTask objects and processes them in FIFO order.
11 */
12class ImageSideloadTaskManager {
13
14    /**
15     * Option name for storing the queue
16     *
17     * @var string
18     */
19    const QUEUE_OPTION = 'nfd_module_onboarding_image_sideload_queue';
20
21    /**
22     * Option name for storing the processing status
23     *
24     * @var string
25     */
26    const STATUS_OPTION = 'nfd_module_onboarding_image_sideload_status';
27
28    /**
29     * Add a task to the queue
30     *
31     * @param ImageSideloadTask $task The task to add
32     * @return bool True on success, false on failure
33     */
34    public static function add_to_queue( ImageSideloadTask $task ) {
35        $queue = self::get_queue();
36
37        // Check if task already exists
38        $task_id = $task->get_id();
39        foreach ( $queue as $existing_task ) {
40            if ( $existing_task['id'] === $task_id ) {
41                return false; // Task already exists
42            }
43        }
44
45        // Add task to queue (FIFO - add to end)
46        $queue[] = array(
47            'id'      => $task_id,
48            'post_id' => $task->get_post_id(),
49            'urls'    => $task->get_image_urls(),
50            'status'  => 'pending',
51            'created' => time(),
52        );
53
54        self::set_queue( $queue );
55        return true;
56    }
57
58    /**
59     * Get the current queue
60     *
61     * @return array
62     */
63    public static function get_queue() {
64        $queue = get_option( self::QUEUE_OPTION, array() );
65        if ( ! is_array( $queue ) ) {
66            $queue = array();
67        }
68        return $queue;
69    }
70
71    /**
72     * Set the queue
73     *
74     * @param array $queue The queue to set
75     * @return void
76     */
77    public static function set_queue( $queue ) {
78        update_option( self::QUEUE_OPTION, $queue );
79    }
80
81    /**
82     * Get the processing status
83     *
84     * @return string
85     */
86    public static function get_status() {
87        return get_option( self::STATUS_OPTION, 'idle' );
88    }
89
90    /**
91     * Set the processing status
92     *
93     * @param string $status The status to set
94     * @return void
95     */
96    public static function set_status( $status ) {
97        update_option( self::STATUS_OPTION, $status );
98    }
99
100    /**
101     * Process the next task in the queue
102     *
103     * @return bool|\WP_Error True if task was processed, false if queue is empty, WP_Error on failure
104     */
105    public static function process_next_task() {
106        $queue = self::get_queue();
107
108        if ( empty( $queue ) ) {
109            self::set_status( 'idle' );
110            return false;
111        }
112
113        // Get the next task
114        $task_data = array_shift( $queue );
115
116        // Mark as processing
117        $task_data['status']  = 'processing';
118        $task_data['started'] = time();
119
120        // Create task object and execute
121        $task   = new ImageSideloadTask( $task_data['post_id'], $task_data['urls'] );
122        $result = $task->execute();
123
124        if ( is_wp_error( $result ) ) {
125            // Mark as failed
126            $task_data['status']    = 'failed';
127            $task_data['error']     = $result->get_error_message();
128            $task_data['completed'] = time();
129
130            // Add back to queue for retry
131            $queue[] = $task_data;
132
133            self::set_queue( $queue );
134            self::set_status( 'processing' );
135
136            return $result;
137        }
138
139        // Mark as completed
140        $task_data['status']    = 'completed';
141        $task_data['completed'] = time();
142
143        self::set_queue( $queue );
144        self::set_status( 'processing' );
145
146        return true;
147    }
148
149    /**
150     * Process the entire queue
151     *
152     * @param int $max_tasks Maximum number of tasks to process in one run (default: 5)
153     * @return array Array with 'processed' and 'remaining' counts
154     */
155    public static function process_queue( $max_tasks = 5 ) {
156        $processed     = 0;
157        $queue         = self::get_queue();
158        $initial_count = count( $queue );
159
160        self::set_status( 'processing' );
161
162        while ( $processed < $max_tasks && ! empty( $queue ) ) {
163            $result = self::process_next_task();
164
165            if ( false === $result ) {
166                break; // Queue is empty
167            }
168
169            if ( is_wp_error( $result ) ) {
170                // Continue processing other tasks even if one fails
171                $processed++;
172                continue;
173            }
174
175            $processed++;
176        }
177
178        $remaining = count( self::get_queue() );
179
180        if ( 0 === $remaining ) {
181            self::set_status( 'idle' );
182        }
183
184        return array(
185            'processed' => $processed,
186            'remaining' => $remaining,
187            'total'     => $initial_count,
188        );
189    }
190
191    /**
192     * Clear the queue
193     *
194     * @return void
195     */
196    public static function clear_queue() {
197        self::set_queue( array() );
198        self::set_status( 'idle' );
199    }
200
201    /**
202     * Get queue statistics
203     *
204     * @return array
205     */
206    public static function get_stats() {
207        $queue = self::get_queue();
208        $stats = array(
209            'total'      => count( $queue ),
210            'pending'    => 0,
211            'processing' => 0,
212            'completed'  => 0,
213            'failed'     => 0,
214        );
215
216        foreach ( $queue as $task ) {
217            $status = $task['status'] ?? 'pending';
218            if ( isset( $stats[ $status ] ) ) {
219                $stats[ $status ]++;
220            }
221        }
222
223        return $stats;
224    }
225}