PluginProbe
Force Refresh / 3.2.0
Force Refresh v3.2.0
3.2.1 3.2.0 3.1.2 3.1.1 3.1.0 trunk 1.0.0 1.1.0 1.1.1 1.1.2 1.2.0 2.0.0 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.10.0 2.10.1 2.10.2 2.11.0 2.11.1 2.12.0 All 54 releases
force-refresh / includes / services / classes / class-eol-storage-service.php

class-eol-storage-service.php in Force Refresh 3.2.0, at includes/services/classes/class-eol-storage-service.php

161 lines 4.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Service for retrieving end-of-life dates from the endoflife.date API.
4 *
5 * @package ForceRefresh
6 */
7
8 namespace JordanLeven\Plugins\ForceRefresh\Services;
9
10 /**
11 * Class for EOL storage services.
12 */
13 class Eol_Storage_Service {
14
15 const TRANSIENT_TTL = DAY_IN_SECONDS;
16 const API_BASE = 'https://endoflife.date/api';
17 const PRODUCT_PHP = 'php';
18 // phpcs:ignore WordPress.WP.CapitalPDangit.MisspelledInText -- endoflife.date expects the lowercase product slug.
19 const PRODUCT_WORDPRESS = 'wordpress';
20
21 /**
22 * Returns the EOL date string for the current PHP version.
23 *
24 * @param string $version The full version string (e.g. '7.4.33').
25 *
26 * @return string|null The EOL date (e.g. '2022-11-28'), or null if not found.
27 */
28 public static function get_eol_date_php( string $version ): ?string {
29 return self::get_eol_date( self::PRODUCT_PHP, $version );
30 }
31
32 /**
33 * Returns the EOL date string for the current WordPress version.
34 *
35 * @param string $version The full version string (e.g. '6.8.1').
36 *
37 * @return string|null The EOL date (e.g. '2022-11-28'), or null if not found.
38 */
39 public static function get_eol_date_wordpress( string $version ): ?string {
40 return self::get_eol_date( self::PRODUCT_WORDPRESS, $version );
41 }
42
43 /**
44 * Returns the EOL date string for a given product and version, or null if not found.
45 *
46 * Matches the major.minor cycle from the full version string against the
47 * endoflife.date API response. Results are cached via WordPress transients
48 * for 24 hours.
49 *
50 * @param string $product The product slug (e.g. 'php').
51 * @param string $version The full version string (e.g. '7.4.33').
52 *
53 * @return string|null The EOL date (e.g. '2022-11-28'), or null if not found.
54 */
55 private static function get_eol_date( string $product, string $version ): ?string {
56 $cycle = self::get_cycle_from_version( $version );
57
58 if ( null === $cycle ) {
59 return null;
60 }
61
62 return self::find_eol_date_for_cycle( self::get_product_data( $product ), $cycle );
63 }
64
65 /**
66 * Extract the major.minor cycle from a version string.
67 *
68 * @param string $version The full version string.
69 *
70 * @return string|null The extracted cycle, or null if the version is invalid.
71 */
72 private static function get_cycle_from_version( string $version ): ?string {
73 if ( ! preg_match( '/^(\d+\.\d+)/', $version, $matches ) ) {
74 return null;
75 }
76
77 return $matches[1];
78 }
79
80 /**
81 * Get cached product data or fetch and cache it when missing.
82 *
83 * @param string $product The product slug.
84 *
85 * @return array The normalized product data.
86 */
87 private static function get_product_data( string $product ): array {
88 $transient_key = self::get_transient_key( $product );
89 $data = get_transient( $transient_key );
90
91 if ( false !== $data ) {
92 return self::normalize_product_data( $data );
93 }
94
95 $data = self::fetch_product_data( $product );
96 set_transient( $transient_key, $data, self::TRANSIENT_TTL );
97
98 return $data;
99 }
100
101 /**
102 * Fetch product data from the remote EOL API.
103 *
104 * @param string $product The product slug.
105 *
106 * @return array The normalized product data.
107 */
108 private static function fetch_product_data( string $product ): array {
109 $response = wp_remote_get( self::API_BASE . '/' . $product . '.json' );
110
111 if ( is_wp_error( $response ) ) {
112 return array();
113 }
114
115 $body = wp_remote_retrieve_body( $response );
116 $data = json_decode( $body, true );
117
118 return self::normalize_product_data( $data );
119 }
120
121 /**
122 * Normalize product data into a consistent array shape.
123 *
124 * @param mixed $data The raw product data.
125 *
126 * @return array The normalized product data.
127 */
128 private static function normalize_product_data( $data ): array {
129 return is_array( $data ) ? $data : array();
130 }
131
132 /**
133 * Find the EOL date for a given major.minor cycle.
134 *
135 * @param array $data The product lifecycle data.
136 * @param string $cycle The major.minor cycle to match.
137 *
138 * @return string|null The EOL date, or null if not found.
139 */
140 private static function find_eol_date_for_cycle( array $data, string $cycle ): ?string {
141 foreach ( $data as $entry ) {
142 if ( isset( $entry['cycle'] ) && $entry['cycle'] === $cycle ) {
143 return $entry['eol'] ?? null;
144 }
145 }
146
147 return null;
148 }
149
150 /**
151 * Build the transient key used for a product.
152 *
153 * @param string $product The product slug.
154 *
155 * @return string The transient key.
156 */
157 private static function get_transient_key( string $product ): string {
158 return 'force_refresh_eol_' . $product;
159 }
160 }
161