Exceptions
5 years ago
Job
1 month ago
Action.php
2 years ago
BackgroundProcessingServiceProvider.php
11 months ago
Demo.php
4 years ago
FeatureDetection.php
3 months ago
Queue.php
3 months ago
QueueActionAware.php
6 months ago
QueueProcessor.php
4 months ago
WithQueueAwareness.php
1 month ago
Action.php
334 lines
| 1 | <?php |
| 2 | |
| 3 | /** |
| 4 | * Models the information about an Action stored in the Queue. |
| 5 | * |
| 6 | * @package WPStaging\Framework\BackgroundProcessing |
| 7 | */ |
| 8 | |
| 9 | namespace WPStaging\Framework\BackgroundProcessing; |
| 10 | |
| 11 | use BadMethodCallException; |
| 12 | use WPStaging\Framework\BackgroundProcessing\Exceptions\QueueException; |
| 13 | |
| 14 | /** |
| 15 | * Class Action |
| 16 | * |
| 17 | * @package WPStaging\Framework\BackgroundProcessing |
| 18 | * |
| 19 | * @property int $id The Action id, the unique, auto-increment value identifying its row. |
| 20 | * @property string $action The action name. |
| 21 | * @property string $jobId The Job the action belongs to. |
| 22 | * @property int $priority The Action priority, lower is executed first (like WP Filters API). |
| 23 | * @property array $args A set of arguments for the action. |
| 24 | * @property string $status The current Action status in the context of the Queue. |
| 25 | * @property string $claimedAt The date and time, in the site timezone, the Action was last claimed for processing. |
| 26 | * @property string $updatedAt The date and time, in the site timezone, the Action was last updated. |
| 27 | * @property mixed|null $custom Custom data attached to the Action. |
| 28 | */ |
| 29 | class Action |
| 30 | { |
| 31 | use WithQueueAwareness; |
| 32 | |
| 33 | /** |
| 34 | * The Action id, the unique, auto-increment value identifying its row. |
| 35 | * |
| 36 | * @var int |
| 37 | */ |
| 38 | private $id; |
| 39 | |
| 40 | /** |
| 41 | * The action name, it can be a string that will be processed as a WordPress action or |
| 42 | * another type of callable that will be called directly. |
| 43 | * |
| 44 | * @var string |
| 45 | */ |
| 46 | private $action; |
| 47 | |
| 48 | /** |
| 49 | * The name of the Job, or Group, the Action belongs to. |
| 50 | * |
| 51 | * @var string |
| 52 | */ |
| 53 | private $jobId; |
| 54 | |
| 55 | /** |
| 56 | * The Action priority, works like the WordPress Filter API priority where |
| 57 | * lower values are processed first. |
| 58 | * |
| 59 | * @var int |
| 60 | */ |
| 61 | public $priority; |
| 62 | |
| 63 | /** |
| 64 | * An optional array of arguments that will be passed to either the WordPress |
| 65 | * action fired by the Queue or as parameters for the invoked callable. |
| 66 | * |
| 67 | * @var array |
| 68 | */ |
| 69 | private $args; |
| 70 | |
| 71 | /** |
| 72 | * A string representing the Action status in the context of the Queue, e.g. ready |
| 73 | * or processing. |
| 74 | * |
| 75 | * @var string|null |
| 76 | */ |
| 77 | public $status; |
| 78 | |
| 79 | /** |
| 80 | * The string representing the date and time, in the site timezone, the Action was |
| 81 | * last claimed for processing. |
| 82 | * |
| 83 | * @var string|null |
| 84 | */ |
| 85 | private $claimedAt; |
| 86 | |
| 87 | /** |
| 88 | * The string representing the date and time, in the site timezone, the Action was |
| 89 | * last updated in any way. |
| 90 | * |
| 91 | * @var string|null |
| 92 | */ |
| 93 | public $updatedAt; |
| 94 | |
| 95 | /** |
| 96 | * Custom data attached to the Action. |
| 97 | * |
| 98 | * @var mixed|null |
| 99 | */ |
| 100 | private $custom; |
| 101 | |
| 102 | /** |
| 103 | * Response of the the Action. |
| 104 | * |
| 105 | * @var mixed|null |
| 106 | */ |
| 107 | private $response; |
| 108 | |
| 109 | /** |
| 110 | * Action constructor. |
| 111 | * |
| 112 | * @param int $id The Action id, its unique identifier in the Queue; `0` is a valid id |
| 113 | * for provisional Actions. |
| 114 | * @param string $action The Action name, it could be a string that will be used to fire a WP |
| 115 | * action, or a string in the format `<class>::<static-method>` that will |
| 116 | * cause that static method to be invoked directly with the Action arguments. |
| 117 | * @param array $args An optional set of arguments for the Action that will either be passed to the |
| 118 | * invoked WP action, or to the specified static method as parameters. |
| 119 | * @param string $jobId The Job, or Group, the Action belongs to. |
| 120 | * @param int $priority The Action priority in the context of the Queue, it works like the priority of |
| 121 | * filters in the WordPress Filter API: lower values are processed first. |
| 122 | * @param string|null $status The Action status in the context of the Queue, e.g. ready or processing. |
| 123 | * @param string|null $claimedAt The string representing the date and time, in the site timezone, the Action was last claimed |
| 124 | * for processing. |
| 125 | * @param string|null $updatedAt The string representing the date and time, in the site timezone, the Action was last updated. |
| 126 | * @param mixed|null $custom Custom data attached to the Action. |
| 127 | * |
| 128 | * @throws QueueException If any value used to build the Action is not valid. |
| 129 | */ |
| 130 | public function __construct( |
| 131 | $id, |
| 132 | $action, |
| 133 | array $args = [], |
| 134 | $jobId = 'default', |
| 135 | $priority = 0, |
| 136 | $status = null, |
| 137 | $claimedAt = null, |
| 138 | $updatedAt = null, |
| 139 | $custom = null, |
| 140 | $response = null |
| 141 | ) { |
| 142 | if (!is_numeric($id) && absint($id) == $id) { |
| 143 | throw new QueueException('Id MUST be a positive integer.'); |
| 144 | } |
| 145 | |
| 146 | if ((string)$action === '') { |
| 147 | throw new QueueException('Action MUST be a non-empty string.'); |
| 148 | } |
| 149 | |
| 150 | if ((string)$jobId === '') { |
| 151 | throw new QueueException('Job ID MUST be a non-empty string.'); |
| 152 | } |
| 153 | |
| 154 | $priority = is_numeric($priority) && (int)$priority == $priority ? |
| 155 | (int)$priority |
| 156 | : $this->getDefaultPriority(); |
| 157 | |
| 158 | $this->id = $id; |
| 159 | $this->action = $action; |
| 160 | $this->args = $args; |
| 161 | $this->jobId = $jobId; |
| 162 | $this->priority = $priority; |
| 163 | $this->status = $status; |
| 164 | $this->claimedAt = $claimedAt; |
| 165 | $this->updatedAt = $updatedAt; |
| 166 | $this->custom = $custom; |
| 167 | $this->response = $response; |
| 168 | } |
| 169 | |
| 170 | /** |
| 171 | * Builds, and returns, an Action instance from the raw data found in a database row. |
| 172 | * |
| 173 | * @param array<string,mixed> $dbRow The database row, as an associative array. |
| 174 | * |
| 175 | * @return Action A reference to an Action instance built on the row data. |
| 176 | * |
| 177 | * @throws QueueException If there's any issue validating any one of the row fields. |
| 178 | */ |
| 179 | public static function fromDbRow(array $dbRow) |
| 180 | { |
| 181 | $id = (int)$dbRow['id']; |
| 182 | $action = (string)$dbRow['action']; |
| 183 | $jobId = isset($dbRow['jobId']) ? (string)($dbRow['jobId']) : null; |
| 184 | $priority = isset($dbRow['priority']) ? (int)$dbRow['priority'] : self::getDefaultPriority(); |
| 185 | $args = isset($dbRow['args']) ? (array)maybe_unserialize($dbRow['args']) : []; |
| 186 | $status = isset($dbRow['status']) ? (string)$dbRow['status'] : Queue::STATUS_READY; |
| 187 | $claimedAt = isset($dbRow['claimed_at']) ? (string)$dbRow['claimed_at'] : null; |
| 188 | $updatedAt = isset($dbRow['updated_at']) ? (string)$dbRow['updated_at'] : null; |
| 189 | $custom = isset($dbRow['custom']) ? maybe_unserialize($dbRow['custom']) : null; |
| 190 | $response = isset($dbRow['response']) ? maybe_unserialize($dbRow['response']) : null; |
| 191 | |
| 192 | return new self($id, $action, $args, $jobId, $priority, $status, $claimedAt, $updatedAt, $custom, $response); |
| 193 | } |
| 194 | |
| 195 | /** |
| 196 | * Overrides the magic method to get private properties with a read-only API. |
| 197 | * |
| 198 | * @param string $name The name of the property to get. |
| 199 | * |
| 200 | * @return mixed The property value. |
| 201 | * |
| 202 | * @throws BadMethodCallException If the Action does not define the property. |
| 203 | */ |
| 204 | public function __get($name) |
| 205 | { |
| 206 | if (!property_exists($this, $name)) { |
| 207 | throw new BadMethodCallException("The Action object does not have an accessible property '{$name}'."); |
| 208 | } |
| 209 | |
| 210 | return isset($this->{$name}) ? $this->{$name} : null; |
| 211 | } |
| 212 | |
| 213 | /** |
| 214 | * Overrides the magic method to clearly signal the immutable nature of the Action object. |
| 215 | * |
| 216 | * @param string $name The name of the property to set. |
| 217 | * @param mixed $value The value that should be assigned to the property. |
| 218 | * |
| 219 | * @throws BadMethodCallException As Actions are immutable. |
| 220 | */ |
| 221 | public function __set($name, $value) |
| 222 | { |
| 223 | throw new BadMethodCallException("The Action object is immutable: its properties can be set only when building it."); |
| 224 | } |
| 225 | |
| 226 | /** |
| 227 | * Returns whether two Actions are the same in regard to relevant properties. |
| 228 | * |
| 229 | * @param Action $toCompare A reference to the Action instance this one should |
| 230 | * be compared to. |
| 231 | * @param array<string> $compareFieldsExclude A list of Action fields that should not be used in the |
| 232 | * comparison; by default all the Action properties will |
| 233 | * be used |
| 234 | * |
| 235 | * @return bool Whether this Action and the one it's being compared to are equals |
| 236 | * or not. |
| 237 | */ |
| 238 | public function equals(Action $toCompare, array $compareFieldsExclude = []) |
| 239 | { |
| 240 | $compareFields = array_diff( |
| 241 | ['id', 'action', 'jobId', 'priority', 'args', 'status'], |
| 242 | $compareFieldsExclude |
| 243 | ); |
| 244 | |
| 245 | foreach ($compareFields as $prop) { |
| 246 | if (!$this->{$prop} == $toCompare->{$prop}) { |
| 247 | return false; |
| 248 | } |
| 249 | } |
| 250 | |
| 251 | return true; |
| 252 | } |
| 253 | |
| 254 | /** |
| 255 | * Returns the associative array representation of the Action. |
| 256 | * |
| 257 | * @return array<string,string|int|array> A map from the Action current properties |
| 258 | * to their current values. |
| 259 | */ |
| 260 | public function toArray() |
| 261 | { |
| 262 | return [ |
| 263 | 'id' => $this->id, |
| 264 | 'action' => $this->action, |
| 265 | 'jobId' => $this->jobId, |
| 266 | 'priority' => $this->priority, |
| 267 | 'args' => $this->args, |
| 268 | 'status' => $this->status, |
| 269 | 'claimedAt' => $this->claimedAt, |
| 270 | 'updatedAt' => $this->updatedAt, |
| 271 | 'custom' => $this->custom, |
| 272 | 'response' => $this->response, |
| 273 | ]; |
| 274 | } |
| 275 | |
| 276 | /** |
| 277 | * Alters the Action instance with a set of alterations. Since the Action is immutable |
| 278 | * alteration will produce, in fact, a clone of it that will be returned. |
| 279 | * |
| 280 | * @param array<string,mixed> $alterations A map from the alteration keys to their |
| 281 | * values. |
| 282 | * |
| 283 | * @return Action A reference to a modified clone of the current Action. |
| 284 | */ |
| 285 | public function alter(array $alterations) |
| 286 | { |
| 287 | $clone = clone $this; |
| 288 | |
| 289 | foreach ($alterations as $key => $value) { |
| 290 | $clone->{$key} = $value; |
| 291 | } |
| 292 | |
| 293 | return $clone; |
| 294 | } |
| 295 | |
| 296 | /** |
| 297 | * Utility method to sort Action in functions or methods accepting |
| 298 | * sorting callbacks like `usort`. |
| 299 | * |
| 300 | * The method will sort Actions by priority, action and jobId, in |
| 301 | * ascending order. |
| 302 | * |
| 303 | * @param array<string,mixed>|Action $actionOne Either an Action instance |
| 304 | * or the array representation of an |
| 305 | * Action. |
| 306 | * @param array<string,mixed>|Action $actionTwo Either an Action instance |
| 307 | * or the array representation of an |
| 308 | * Action. |
| 309 | * |
| 310 | * @return int An integer sticking with `usort` expected value that will return `-1` |
| 311 | * if the first Action comes before the second, `0` if they are equal |
| 312 | * in all regards and `1` if the second Action comes before the first. |
| 313 | */ |
| 314 | public static function sort($actionOne, $actionTwo) |
| 315 | { |
| 316 | $objectOne = (object)$actionOne; |
| 317 | $objectTwo = (object)$actionTwo; |
| 318 | |
| 319 | if ($objectOne->priority !== $objectTwo->priority) { |
| 320 | return $objectOne->priority > $objectTwo->priority ? 1 : -1; |
| 321 | } |
| 322 | |
| 323 | if ($objectOne->action !== $objectTwo->action) { |
| 324 | return $objectOne->action > $objectTwo->action ? 1 : -1; |
| 325 | } |
| 326 | |
| 327 | if ($objectOne->jobId !== $objectTwo->jobId) { |
| 328 | return $objectOne->jobId > $objectTwo->jobId ? 1 : -1; |
| 329 | } |
| 330 | |
| 331 | return 0; |
| 332 | } |
| 333 | } |
| 334 |