Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 52
0.00% covered (danger)
0.00%
0 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 1
PluginInstallTaskManager
0.00% covered (danger)
0.00%
0 / 52
0.00% covered (danger)
0.00%
0 / 7
342
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 add_thirty_seconds_schedule
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 install
0.00% covered (danger)
0.00%
0 / 22
0.00% covered (danger)
0.00%
0 / 1
30
 add_to_queue
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
12
 remove_from_queue
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
12
 complete
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 reset_install_status
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace NewfoldLabs\WP\Module\Installer\TaskManagers;
4
5use NewfoldLabs\WP\Module\Installer\Data\Options;
6use NewfoldLabs\WP\Module\Installer\Tasks\PluginInstallTask;
7use NewfoldLabs\WP\Module\Installer\Models\PriorityQueue;
8
9/**
10 * Manages the execution of PluginInstallTasks.
11 */
12class PluginInstallTaskManager extends AbstractTaskManager {
13
14    /**
15     * The name of the queue, might be prefixed.
16     *
17     * @var string
18     */
19    protected static $queue_name = 'plugin_install_queue';
20
21    /**
22     * The name of the Hook.
23     *
24     * @var string
25     */
26    protected static $hook_name = 'nfd_module_installer_plugin_install_cron';
27
28    /**
29     * Schedules the crons.
30     */
31    public function __construct() {
32        parent::__construct();
33
34        // Thirty seconds cron hook
35        add_action( self::$hook_name, array( $this, 'install' ) );
36
37        if ( ! wp_next_scheduled( self::$hook_name ) ) {
38            wp_schedule_event( time(), 'thirty_seconds', self::$hook_name );
39        }
40    }
41
42
43    /**
44     * Adds a 30 second cron schedule.
45     *
46     * @param array $schedules The existing cron schedule.
47     * @return array
48     */
49    public function add_thirty_seconds_schedule( $schedules ) {
50        if ( ! array_key_exists( 'thirty_seconds', $schedules ) || 30 !== $schedules['thirty_seconds']['interval'] ) {
51            $schedules['thirty_seconds'] = array(
52                'interval' => 30,
53                'display'  => __( 'Once Every Thirty Seconds', 'wp-module-installer' ),
54            );
55        }
56
57        return $schedules;
58    }
59
60    /**
61     * Queue out a PluginInstallTask with the highest priority in the plugin install queue and execute it.
62     *
63     * @void
64     */
65    public function install() {
66        /*
67        Get the plugins queued up to be installed, the PluginInstall task gets
68        converted to an associative array before storing it in the option.
69        */
70        $plugins = \get_option( Options::get_option_name( self::$queue_name ), array() );
71
72        /*
73        Conversion of the max heap to an array will always place the PluginInstallTask with the highest
74        priority at the beginning of the array
75        */
76        $plugin_to_install = array_shift( $plugins );
77
78        if ( ! $plugin_to_install ) {
79            self::complete();
80
81            return;
82        }
83
84        // Update the plugin install queue.
85        \update_option( Options::get_option_name( self::$queue_name ), $plugins );
86
87        // Recreate the PluginInstall task from the associative array.
88        $plugin_install_task = new PluginInstallTask(
89            $plugin_to_install['slug'],
90            $plugin_to_install['activate'],
91            $plugin_to_install['priority'],
92            $plugin_to_install['retries']
93        );
94
95        // Update status to the current slug being installed.
96        \update_option( Options::get_option_name( 'plugins_init_status' ), $plugin_install_task->get_slug() );
97
98        // Execute the PluginInstall Task.
99        $status = $plugin_install_task->execute();
100        if ( \is_wp_error( $status ) ) {
101
102            // If there is an error, then increase the retry count for the task.
103            $plugin_install_task->increment_retries();
104
105            // Get Latest Value of the install queue
106            $plugins = \get_option( Options::get_option_name( self::$queue_name ), array() );
107
108            /*
109            If the number of retries have not exceeded the limit
110            then re-queue the task at the end of the queue to be retried.
111            */
112            if ( $plugin_install_task->get_retries() <= self::$retry_limit ) {
113                array_push( $plugins, $plugin_install_task->to_array() );
114
115                // Update the plugin install queue.
116                \update_option( Options::get_option_name( self::$queue_name ), $plugins );
117            }
118        }
119
120        // If there are no more plugins to be installed then change the status to complete.
121        if ( empty( $plugins ) ) {
122            self::complete();
123        }
124    }
125
126    /**
127     * Adds a new PluginInstallTask to the Plugin Install queue.
128     * The Task will be inserted at an appropriate position in the queue based on it's priority.
129     *
130     * @param PluginInstallTask $plugin_install_task The task to be inserted.
131     * @return array|false
132     */
133    public static function add_to_queue( PluginInstallTask $plugin_install_task ) {
134        /*
135        Get the plugins queued up to be installed, the PluginInstall task gets
136        converted to an associative array before storing it in the option.
137        */
138        $plugins = \get_option( Options::get_option_name( self::$queue_name ), array() );
139
140        $queue = new PriorityQueue();
141        foreach ( $plugins as $queued_plugin ) {
142            /*
143            Check if there is an already existing PluginInstallTask in the queue
144            for a given slug.
145            */
146            if ( $queued_plugin['slug'] !== $plugin_install_task->get_slug() ) {
147                $queue->insert( $queued_plugin, $queued_plugin['priority'] );
148            }
149        }
150
151        // Insert a new PluginInstallTask at the appropriate position in the queue.
152        $queue->insert(
153            $plugin_install_task->to_array(),
154            $plugin_install_task->get_priority()
155        );
156
157        return \update_option( Options::get_option_name( self::$queue_name ), $queue->to_array() );
158    }
159
160    /**
161     * Removes a PluginInstallTask from the queue.
162     *
163     * @param string $plugin The slug of the task to remove.
164     * @return array
165     */
166    public static function remove_from_queue( $plugin ) {
167        /*
168        Get the plugins queued up to be installed, the PluginInstall task gets
169        converted to an associative array before storing it in the option.
170        */
171        $plugins = \get_option( Options::get_option_name( self::$queue_name ), array() );
172
173        $queue = new PriorityQueue();
174        foreach ( $plugins as $queued_plugin ) {
175            /*
176            If the Plugin slug does not match add it back to the queue.
177            */
178            if ( $queued_plugin['slug'] !== $plugin ) {
179                $queue->insert( $queued_plugin, $queued_plugin['priority'] );
180            }
181        }
182
183        return \update_option( Options::get_option_name( self::$queue_name ), $queue->to_array() );
184    }
185
186
187    /**
188     * Clear all the hook scheduling and update the status option
189     *
190     * @return bool
191     */
192    private static function complete() {
193        wp_clear_scheduled_hook( 'nfd_module_installer_plugin_install_cron' );
194        return \update_option( Options::get_option_name( 'plugins_init_status' ), 'completed' );
195    }
196
197    /**
198     * Reset the Plugin install status and the queue.
199     *
200     * @return void
201     */
202    public static function reset_install_status() {
203        \delete_option( Options::get_option_name( 'plugins_init_status' ) );
204        \delete_option( Options::get_option_name( 'plugin_install_queue' ) );
205    }
206}