Skip to content

Fix fatal error on servers without PHP calendar extension#229

Merged
parhumm merged 3 commits intodevelopmentfrom
fix/issue-228-jddayofweek-calendar-extension
Mar 16, 2026
Merged

Fix fatal error on servers without PHP calendar extension#229
parhumm merged 3 commits intodevelopmentfrom
fix/issue-228-jddayofweek-calendar-extension

Conversation

@ParhamTehrani
Copy link
Copy Markdown
Contributor

@ParhamTehrani ParhamTehrani commented Mar 16, 2026

Summary

Replace jddayofweek() with a pure-PHP array-based day name lookup to avoid dependency on the optional PHP ext-calendar extension. This fixes dashboard crashes on Synology NAS, Alpine containers, and minimal PHP builds.

Closes #228

Changes

File: src/Helpers/DataBuckets.php

  1. Line 107: Add (int) cast to get_option('start_of_week', 1) for type safety (WP stores options as strings)
  2. Line 108: Add $dayNames array — pure-PHP replacement for jddayofweek()
  3. Line 119: Replace jddayofweek($startOfWeek - 1, 1) with ($dayNames[$startOfWeek] ?? 'Monday') — eliminates ext-calendar dependency with safe fallback for corrupted values

Verification

  • CTO-verified via 3v4l.org: jddayofweek() fails on ALL PHP 7.1.20+ through 8.5.3 without ext-calendar
  • All 7 start_of_week values (0–6) produce identical day names to original jddayofweek() call
  • DateTime::modify() only accepts English day names — no i18n impact
  • ?? 'Monday' fallback prevents Undefined array key warning on corrupted options (PHP 8.0+) and DateMalformedStringException (PHP 8.3+)

Type of change

  • Fix - Fixes an existing bug

Summary by CodeRabbit

  • Refactor
    • Improved week-sequencing logic for more robust and consistent determination of week start days, enhancing label generation across weeks.

Replace jddayofweek() with a pure PHP array-based day name lookup
to avoid dependency on the optional PHP calendar extension. This
fixes dashboard crashes on Synology NAS, Alpine containers, and
minimal PHP builds.

Fixes #228
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 16, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 52248472-dbf4-42db-9104-56fa6b268ad7

📥 Commits

Reviewing files that changed from the base of the PR and between b06d7d2 and c835568.

📒 Files selected for processing (1)
  • src/Helpers/DataBuckets.php
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/Helpers/DataBuckets.php

📝 Walkthrough

Walkthrough

Adds a private DAY_NAMES constant and replaces the jddayofweek() call in initSeqWeek() with an integer-cast startOfWeek and a lookup into DAY_NAMES (fallback 'Monday'), changing how the week-start advance is computed to remove reliance on ext-calendar.

Changes

Cohort / File(s) Summary
DataBuckets — week-start logic
src/Helpers/DataBuckets.php
Added private const DAY_NAMES = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday']; cast $startOfWeek to (int); replaced jddayofweek(...) usage with DAY_NAMES[$startOfWeek] lookup (fallback to 'Monday') and used that value in $start->modify('next ...').

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~8 minutes

Poem

🐰 I traded a call that caused a fright,
For simple names to set the week just right.
No missing extension, no fatal stumble,
The charts can hop and never crumble. ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: replacing jddayofweek() to eliminate the fatal error dependency on the PHP calendar extension.
Linked Issues check ✅ Passed The PR implements the core coding requirement from issue #228: replacing jddayofweek() with a pure-PHP day-name array lookup and safe fallback to resolve the fatal error on systems without ext-calendar.
Out of Scope Changes check ✅ Passed All changes are directly in scope: adding DAY_NAMES constant and replacing jddayofweek() with array lookup in initSeqWeek() method, both necessary to fix issue #228.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/issue-228-jddayofweek-calendar-extension
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Tip

CodeRabbit can enforce grammar and style rules using `languagetool`.

Configure the reviews.tools.languagetool setting to enable/disable rules and categories. Refer to the LanguageTool Community to learn more.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/Helpers/DataBuckets.php (1)

107-108: Good fix – removes ext-calendar dependency and corrects Sunday handling.

The array-based lookup correctly maps WordPress's start_of_week values (0=Sunday through 6=Saturday) to day names. This also fixes a latent bug in the original code where jddayofweek($startOfWeek - 1, 1) would receive -1 when start_of_week=0 (Sunday), resulting in undefined behavior.

Consider adding defensive bounds checking to prevent an undefined array key warning in PHP 8+ if the option value is ever corrupted:

🛡️ Optional defensive validation
 $startOfWeek = (int) get_option('start_of_week', 1);
+$startOfWeek = max(0, min(6, $startOfWeek)); // Clamp to valid range
 $dayNames    = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Helpers/DataBuckets.php` around lines 107 - 108, The current lookup uses
$startOfWeek and $dayNames but lacks validation, so if
get_option('start_of_week') returns an out-of-range or corrupted value you may
hit an undefined array key; clamp or validate $startOfWeek to an integer in the
0..6 range before using it (e.g., coerce to int, then if <0 set to 0, if >6 set
to 6 or fall back to a default) so the $dayNames lookup is always safe; update
the code around the $startOfWeek and $dayNames usage to perform this bounds
check and use the sanitized value for indexing.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/Helpers/DataBuckets.php`:
- Around line 107-108: The current lookup uses $startOfWeek and $dayNames but
lacks validation, so if get_option('start_of_week') returns an out-of-range or
corrupted value you may hit an undefined array key; clamp or validate
$startOfWeek to an integer in the 0..6 range before using it (e.g., coerce to
int, then if <0 set to 0, if >6 set to 6 or fall back to a default) so the
$dayNames lookup is always safe; update the code around the $startOfWeek and
$dayNames usage to perform this bounds check and use the sanitized value for
indexing.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a2856f5b-1687-4145-ab92-a56157207ee6

📥 Commits

Reviewing files that changed from the base of the PR and between f622cf6 and 4c3ea1b.

📒 Files selected for processing (1)
  • src/Helpers/DataBuckets.php

Copy link
Copy Markdown
Contributor

@parhumm parhumm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Against Implementation Plan (#228)

Gap Found: Missing defensive fallback

Line 119: $dayNames[$startOfWeek] is missing the ?? 'Monday' null coalescing fallback from the implementation plan.

Risk: If start_of_week option is corrupted (outside 0–6 range), bare array access triggers:

  • PHP 8.0–8.2: Warning: Undefined array key + empty string passed to DateTime::modify()
  • PHP 8.3+: DateMalformedStringException fatal error — the exact same class of crash this PR is fixing

Fix:

// Current (PR):
$start->modify('next ' . $dayNames[$startOfWeek]);

// Should be:
$start->modify('next ' . ($dayNames[$startOfWeek] ?? 'Monday'));

The ?? 'Monday' fallback matches the default value in get_option('start_of_week', 1) and costs nothing in the happy path.

Other Notes

  • PR template: "Fix" checkbox not checked
  • CHANGELOG.md not updated (required by PR template)

Review based on implementation plan — verified across PHP 7.4–8.5, i18n safe, single call site.

parhumm added 2 commits March 16, 2026 10:35
Add ?? 'Monday' null coalescing fallback to $dayNames[$startOfWeek]
to prevent Undefined array key warning (PHP 8.0+) and
DateMalformedStringException (PHP 8.3+) when start_of_week option
is corrupted to a value outside 0-6 range.

Refs #228
Move inline $dayNames array to private const DAY_NAMES to avoid
re-allocation on every initSeqWeek() call.

Refs #228
@parhumm
Copy link
Copy Markdown
Contributor

parhumm commented Mar 16, 2026

E2E Test Results — Post-Fix Verification

Branch: fix/issue-228-jddayofweek-calendar-extension
PR: #229
Env: Local by Flywheel, PHP 8.x, Playwright 1.58.2
Plugins: wp-slimstat + wp-slimstat-pro (both active)

Results: 24 passed, 1 skipped

Spec Tests Result
overview-charts-accuracy.spec.ts 14 All passed
adminbar-chart-consistency.spec.ts 4 passed, 1 skipped (skip: free-only test when Pro active)
adminbar-realtime-refresh.spec.ts 6 All passed

Coverage

  • All dashboard views render without fatal errors
  • Chart containers render with data (SVG/canvas elements present)
  • Date range > 7 days (28-day, 30-day, custom ranges) — triggers weekly granularity
  • No PHP errors/warnings detected on any page
  • AJAX slimstat_get_adminbar_stats returns valid chart data
  • Chart data values are non-negative integers
  • Comparison chart toggle does not break dashboard
  • Empty stats handled gracefully (zero state renders)

Verification Checklist Update

  • Charts render without fatal errors (date range > 7 days)
  • Chart bucket counts and labels render correctly
  • No PHP errors/warnings in debug log
  • E2E: overview-charts-accuracy.spec.ts passes
  • E2E: adminbar-chart-consistency.spec.ts passes
  • E2E: adminbar-realtime-refresh.spec.ts passes
  • Grep confirms no remaining jddayofweek or ext-calendar usage

Commits Tested

  1. 4c3ea1bb — Original PR: replace jddayofweek() with $dayNames array + (int) cast
  2. b06d7d2d — Add ?? 'Monday' defensive fallback for corrupted start_of_week
  3. c835568a — Move $dayNames to private const DAY_NAMES class constant

Tested via wp-slimstat-qa-e2e skill (jaan.to plugin)

Copy link
Copy Markdown
Contributor

@parhumm parhumm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR Review: APPROVE

Verdict: No security, performance, standards, or compatibility issues found.

Changes Summary

Change Line Purpose
private const DAY_NAMES class level Pure-PHP day name lookup (replaces ext-calendar dependency)
(int) get_option(...) 109 Type safety — WP stores options as strings
self::DAY_NAMES[$startOfWeek] ?? 'Monday' 120 Defensive fallback for corrupted start_of_week values

Review Checklist

  • Security: No user input handling, no DB queries, no output — N/A
  • Performance: Day names moved to private const — zero per-call allocation
  • Standards: (int) cast matches Chart.php:309 pattern; null coalescing is PHP 7.0+
  • Backward Compat: PHP 7.4+ safe; no hook/API changes; no schema changes
  • i18n: DateTime::modify() requires English day names — hardcoded English is correct, not a localization gap
  • Add-on Impact: No public method or hook changes — zero impact on Pro or third-party addons

Manual QA Checklist

Prerequisites: WordPress with Slimstat active, date range > 7 days on dashboard

  • Navigate to Slimstat → Overview — charts render without errors
  • Navigate to Slimstat → Access Log — page renders without errors
  • Navigate to Slimstat → Reports — page renders without errors
  • Navigate to Slimstat → World Map — page renders without errors
  • Navigate to Slimstat → Settings — page renders without errors
  • Change Settings → General → Week Starts On to Sunday (0) → reload Slimstat dashboard → charts render correctly
  • Change Week Starts On to Monday (1) → reload → charts render correctly
  • Change Week Starts On to Saturday (6) → reload → charts render correctly
  • Set date range to Last 28 days → weekly chart buckets display correctly
  • Set date range to Last 30 days → weekly chart buckets display correctly
  • Set a custom date range spanning 2+ weeks → chart renders correctly
  • Enable comparison chart toggle → no errors
  • Check wp-content/debug.log — no PHP warnings or errors from DataBuckets.php
  • Admin bar chart widget renders and updates via AJAX without errors

Review via wp-pr-review skill (jaan.to plugin) — E2E results: 24/24 passed

@parhumm parhumm merged commit ff99f5d into development Mar 16, 2026
1 check passed
@parhumm parhumm deleted the fix/issue-228-jddayofweek-calendar-extension branch March 16, 2026 10:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants