22
33namespace phpweb \Releases ;
44
5+ use DateInterval ;
56use DateTime ;
67use DateTimeImmutable ;
78use phpweb \Build \VarCache ;
9+ use phpweb \ProjectGlobals ;
810use function array_key_last ;
911use function array_reverse ;
1012use function get_active_branches ;
11- use function get_branch_bug_eol_date ;
12- use function get_branch_release_date ;
13- use function get_branch_security_eol_date ;
13+ use function version_compare ;
1414
1515/* have to force these files to be included */
1616require_once __DIR__ . '/../../include/version.inc ' ;
@@ -25,6 +25,9 @@ final class VersionData
2525 /** @var array<string, VersionData>|null */
2626 private static array |null $ _all = null ;
2727
28+ /** @var array|null */
29+ private static array |null $ _branchOverrides = null ;
30+
2831 public readonly int $ majorVersion ;
2932 public readonly int $ minorVersion ;
3033
@@ -87,16 +90,123 @@ private static function castDate(?DateTime $date): ?DateTimeImmutable
8790 return $ date ? DateTimeImmutable::createFromInterface ($ date ) : null ;
8891 }
8992
93+ /**
94+ * Version-level date overrides are sourced from branch-overrides.inc and serve
95+ * to correct variations where default calculations don't work, or the release
96+ * timelines have changed
97+ *
98+ * @var array{date?:string,stable?:string,security?:string}
99+ */
100+ protected array $ dateOverrides {
101+ get {
102+ return (self ::$ _branchOverrides
103+ ??= require ProjectGlobals::getIncludeDataPath () . '/branch-overrides.inc ' )[$ this ->label ]
104+ ?? [];
105+ }
106+ }
107+
108+ public ?PointReleaseData $ initialRelease {
109+ get {
110+ foreach ($ this ->releases as $ release ) {
111+ return $ release ;
112+ }
113+
114+ return null ;
115+ }
116+ }
117+
118+ public ?PointReleaseData $ finalRelease {
119+ get {
120+ foreach (array_reverse ($ this ->releases ) as $ release ) {
121+ return $ release ;
122+ }
123+
124+ return null ;
125+ }
126+ }
127+
90128 public ?DateTimeImmutable $ releaseDate {
91- get => $ this ->_releaseDate ??= self ::castDate (get_branch_release_date ($ this ->label ));
129+ get => $ this ->_releaseDate ??= (function () {
130+ $ date = $ this ->dateOverrides ['date ' ] ?? null ;
131+ if ($ date ) {
132+ return new DateTimeImmutable ($ date );
133+ }
134+
135+ foreach ($ this ->releases as $ release ) {
136+ $ date = $ release ->date ;
137+ if ($ date ) {
138+ return $ date ;
139+ }
140+ }
141+
142+ return null ;
143+ })();
92144 }
93145
146+ /**
147+ * Determines the date that this version runs out of bugfix support
148+ *
149+ * If not otherwise overridden:
150+ * - For [<8.2] - 2 years after the initial release
151+ * - Otherwise - 2 years after the initial release, extended until the end of the year.
152+ */
94153 public ?DateTimeImmutable $ bugfixEOL {
95- get => $ this ->_bugfixEOL ??= self ::castDate (get_branch_bug_eol_date ($ this ->label ));
154+ get => $ this ->_bugfixEOL ??= (function () {
155+ $ date = $ this ->dateOverrides ['stable ' ] ?? null ;
156+ if ($ date ) {
157+ return new DateTimeImmutable ($ date );
158+ }
159+
160+ /* date is based on 2 years after the initial release */
161+ $ date = $ this ->initialRelease ?->date?->add(new DateInterval ('P2Y ' ));
162+
163+ /* Versions before 8.2 do not extend the release cycle to the end of the year */
164+ if (version_compare ($ this ->label , '8.2 ' , '< ' )) {
165+ return $ date ;
166+ }
167+
168+ /* as of 8.2, the release window has been extended to the very end of the year for simplicity */
169+ return $ date ?->setDate($ date ->format ('Y ' ), 12 , 31 );
170+ })();
96171 }
97172
173+ /**
174+ * Determines the date that this version runs out of security support
175+ *
176+ * If not otherwise overridden
177+ * For [<5.3] - The date of the final release
178+ * For [<8.1] - 3 years after the initial release
179+ * Otherwise - 4 years after the initial release, extended until the end of the year
180+ */
98181 public ?DateTimeImmutable $ securityEOL {
99- get => $ this ->_securityEOL ??= self ::castDate (get_branch_security_eol_date ($ this ->label ));
182+ get => $ this ->_securityEOL ??= (function () {
183+ $ date = $ this ->dateOverrides ['security ' ] ?? null ;
184+ if ($ date ) {
185+ return new DateTimeImmutable ($ date );
186+ }
187+
188+ /* Versions before 5.3 are based solely on the final release date in */
189+ if (version_compare ($ this ->label , '5.3 ' , '< ' )) {
190+ return $ this ->finalRelease ?->date;
191+ }
192+
193+ /* all other calculations are based on the release date of the version */
194+ $ initialDate = $ this ->initialRelease ?->date;
195+ if (!$ initialDate ) {
196+ return null ;
197+ }
198+
199+ /* Versions before 8.1 have 3-year support since the initial release */
200+ if (version_compare ($ this ->label , '8.1 ' , '< ' )) {
201+ return $ initialDate ?->add(new DateInterval ('P3Y ' ));
202+ }
203+
204+ /* everything after 8.1 gets 4 years of security support */
205+ $ date = $ initialDate ?->add(new DateInterval ('P4Y ' ));
206+
207+ /* that has been extended until the end of the year */
208+ return $ date ?->setDate($ date ->format ('Y ' ), 12 , 31 );
209+ })();
100210 }
101211
102212 public string $ logoUrl {
@@ -116,6 +226,7 @@ private static function castDate(?DateTime $date): ?DateTimeImmutable
116226 get {
117227 if ($ this ->_pointReleases === null ) {
118228 $ releases = [];
229+
119230 foreach (ReleaseRawDataLoader::allReleasesForVersion ($ this ->label ) as $ label => $ data ) {
120231 $ releases [$ label ] = new PointReleaseData ($ label , $ data );
121232 }
0 commit comments