Completed
Push — master ( a88d8a...dfa187 )
by Glynn
02:01 queued 01:58
created

Plugin_State_Controller   A

Complexity

Total Complexity 15

Size/Duplication

Total Lines 149
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 15
eloc 38
c 2
b 0
f 0
dl 0
loc 149
rs 10

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A deactivation() 0 2 1
A has_events_for_state() 0 2 1
A uninstall() 0 2 1
A activation() 0 2 1
A event() 0 22 5
A get_events_for_state() 0 6 1
A finalise() 0 30 4
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * Interface for all classes which act on a plugin state change.
7
 * Update, Activation, Deactivation and Uninstalling.
8
 *
9
 * This interface should not be used directory, please see
10
 * those which extend. This is to offer a faux union type.
11
 *
12
 * @package PinkCrab\Plugin_Lifecycle
13
 * @author Glynn Quelch [email protected]
14
 * @since 0.0.1
15
 */
16
17
namespace PinkCrab\Plugin_Lifecycle;
18
19
use PinkCrab\Plugin_Lifecycle\State_Change_Queue;
20
use PinkCrab\Plugin_Lifecycle\State_Event\Deactivation;
21
use PinkCrab\Plugin_Lifecycle\Plugin_State_Change;
22
use PinkCrab\Plugin_Lifecycle\State_Event\Activation;
23
use PinkCrab\Perique\Interfaces\DI_Container;
24
use PinkCrab\Plugin_Lifecycle\State_Event\Uninstall;
25
26
class Plugin_State_Controller {
27
28
	/**
29
	 * Instance of DI_Container
30
	 *
31
	 * @var DI_Container
32
	 */
33
	protected DI_Container $container;
34
35
	/**
36
	 * Hold all events which are fired during the plugins
37
	 * life cycle.
38
	 *
39
	 * @var Plugin_State_Change[]
40
	 */
41
	protected $state_events = array();
42
43
	/**
44
	 * Holds the location of the plugin base file.
45
	 *
46
	 * @var string
47
	 */
48
	protected $plugin_base_file;
49
50
	public function __construct( DI_Container $container, string $plugin_base_file ) {
51
		$this->container        = $container;
52
		$this->plugin_base_file = $plugin_base_file;
53
	}
54
55
	/**
56
	 * Adds an event to the stack
57
	 *
58
	 * @param class-string<Plugin_State_Change> $state_event
0 ignored issues
show
Documentation Bug introduced by
The doc comment class-string<Plugin_State_Change> at position 0 could not be parsed: Unknown type name 'class-string' at position 0 in class-string<Plugin_State_Change>.
Loading history...
59
	 * @return self
60
	 * @throws Plugin_State_Exception If none Plugin_State_Change (string or object) passed or fails to create instance from valid class name.
61
	 */
62
	public function event( string $state_event ): self {
63
		// Cache the event class name.
64
		$state_event_string = $state_event;
65
66
		/* @phpstan-ignore-next-line, as this cannot be type hinted the check exists. */
67
		if ( ! is_subclass_of( $state_event, Plugin_State_Change::class ) ) {
68
			throw Plugin_State_Exception::invalid_state_change_event_type( $state_event );
69
		}
70
71
		try {
72
			/** @var Plugin_State_Change|null */
73
			$state_event = $this->container->create( $state_event );
74
		} catch ( \Throwable $th ) {
75
			throw Plugin_State_Exception::failed_to_create_state_change_event( $state_event_string );
76
		}
77
78
		// Throw exception if failed to create
79
		if ( null === $state_event || ! is_a( $state_event, Plugin_State_Change::class ) ) {
80
			throw Plugin_State_Exception::failed_to_create_state_change_event( $state_event_string );
81
		}
82
		$this->state_events[] = $state_event;
83
		return $this;
84
	}
85
86
	/**
87
	 * Registers all life cycle hooks.
88
	 *
89
	 * @return self
90
	 * @throws Plugin_State_Exception [103] failed_to_locate_calling_file()
91
	 */
92
	public function finalise(): self {
93
		$file = $this->plugin_base_file;
94
		// dump($file);
95
		// Activation hooks if need adding.
96
		if ( $this->has_events_for_state( Activation::class ) ) {
97
			register_activation_hook( $file, $this->activation() );
98
		}
99
100
		// Deactivation hooks.
101
		if ( $this->has_events_for_state( Deactivation::class ) ) {
102
			register_deactivation_hook( $file, $this->deactivation() );
103
		}
104
105
		// If we have an uninstall events, add then during activation.
106
		if ( $this->has_events_for_state( Uninstall::class ) ) {
107
			$callback = $this->uninstall();
108
109
			// Register the callback so itsits included (but wont run due to serialization issues).
110
			register_activation_hook(
111
				$file,
112
				static function() use ( $file, $callback ): void {
113
					register_uninstall_hook( $file, $callback );
114
				}
115
			);
116
117
			// Manually re-add the uninstall hook.
118
			add_action( 'uninstall_' . plugin_basename( $file ), $callback );
119
		}
120
121
		return $this;
122
	}
123
124
	/**
125
	 * Gets all events for a given state.
126
	 *
127
	 * @param string $state
128
	 * @return Plugin_State_Change[]
129
	 */
130
	private function get_events_for_state( string $state ): array {
131
		return array_filter(
132
			apply_filters( Plugin_Life_Cycle::EVENT_LIST, $this->state_events ),
133
			function( $e ) use ( $state ): bool {
134
				/* @phpstan-ignore-next-line */
135
				return is_subclass_of( $e, $state );
136
			}
137
		);
138
	}
139
140
	/**
141
	 * Checks if they are any events for a given state.
142
	 *
143
	 * @param string $state
144
	 * @return bool
145
	 */
146
	private function has_events_for_state( string $state ): bool {
147
		return count( $this->get_events_for_state( $state ) ) !== 0;
148
	}
149
150
	/**
151
	 * Returns an instance of the State_Change_Queue, populated with Activation events.
152
	 *
153
	 * @return State_Change_Queue
154
	 */
155
	public function activation(): State_Change_Queue {
156
		return new State_Change_Queue( ...$this->get_events_for_state( Activation::class ) );
157
	}
158
159
	/**
160
	 * Returns an instance of the State_Change_Queue, populated with Deactivation events.
161
	 *
162
	 * @return State_Change_Queue
163
	 */
164
	public function deactivation(): State_Change_Queue {
165
		return new State_Change_Queue( ...$this->get_events_for_state( Deactivation::class ) );
166
	}
167
168
	/**
169
	 * Returns an instance of the State_Change_Queue, populated with Uninstall events.
170
	 *
171
	 * @return State_Change_Queue
172
	 */
173
	public function uninstall(): State_Change_Queue {
174
		return new State_Change_Queue( ...$this->get_events_for_state( Uninstall::class ) );
175
	}
176
177
}
178